3 * Copyright (c) 2008 Hans Petter Selasky <hselasky@FreeBSD.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * This file contains the driver for the USS820 series USB Device
32 * NOTE: The datasheet does not document everything.
35 #ifdef USB_GLOBAL_INCLUDE_FILE
36 #include USB_GLOBAL_INCLUDE_FILE
38 #include <sys/stdint.h>
39 #include <sys/stddef.h>
40 #include <sys/param.h>
41 #include <sys/queue.h>
42 #include <sys/types.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
46 #include <sys/module.h>
48 #include <sys/mutex.h>
49 #include <sys/condvar.h>
50 #include <sys/sysctl.h>
52 #include <sys/unistd.h>
53 #include <sys/callout.h>
54 #include <sys/malloc.h>
57 #include <dev/usb/usb.h>
58 #include <dev/usb/usbdi.h>
60 #define USB_DEBUG_VAR uss820dcidebug
62 #include <dev/usb/usb_core.h>
63 #include <dev/usb/usb_debug.h>
64 #include <dev/usb/usb_busdma.h>
65 #include <dev/usb/usb_process.h>
66 #include <dev/usb/usb_transfer.h>
67 #include <dev/usb/usb_device.h>
68 #include <dev/usb/usb_hub.h>
69 #include <dev/usb/usb_util.h>
71 #include <dev/usb/usb_controller.h>
72 #include <dev/usb/usb_bus.h>
73 #endif /* USB_GLOBAL_INCLUDE_FILE */
75 #include <dev/usb/controller/uss820dci.h>
77 #define USS820_DCI_BUS2SC(bus) \
78 ((struct uss820dci_softc *)(((uint8_t *)(bus)) - \
79 ((uint8_t *)&(((struct uss820dci_softc *)0)->sc_bus))))
81 #define USS820_DCI_PC2SC(pc) \
82 USS820_DCI_BUS2SC(USB_DMATAG_TO_XROOT((pc)->tag_parent)->bus)
84 #define USS820_DCI_THREAD_IRQ \
85 (USS820_SSR_SUSPEND | USS820_SSR_RESUME | USS820_SSR_RESET)
88 static int uss820dcidebug = 0;
90 static SYSCTL_NODE(_hw_usb, OID_AUTO, uss820dci, CTLFLAG_RW, 0,
92 SYSCTL_INT(_hw_usb_uss820dci, OID_AUTO, debug, CTLFLAG_RWTUN,
93 &uss820dcidebug, 0, "uss820dci debug level");
96 #define USS820_DCI_INTR_ENDPT 1
100 static const struct usb_bus_methods uss820dci_bus_methods;
101 static const struct usb_pipe_methods uss820dci_device_bulk_methods;
102 static const struct usb_pipe_methods uss820dci_device_ctrl_methods;
103 static const struct usb_pipe_methods uss820dci_device_intr_methods;
104 static const struct usb_pipe_methods uss820dci_device_isoc_fs_methods;
106 static uss820dci_cmd_t uss820dci_setup_rx;
107 static uss820dci_cmd_t uss820dci_data_rx;
108 static uss820dci_cmd_t uss820dci_data_tx;
109 static uss820dci_cmd_t uss820dci_data_tx_sync;
110 static void uss820dci_device_done(struct usb_xfer *, usb_error_t);
111 static void uss820dci_do_poll(struct usb_bus *);
112 static void uss820dci_standard_done(struct usb_xfer *);
113 static void uss820dci_intr_set(struct usb_xfer *, uint8_t);
114 static void uss820dci_update_shared_1(struct uss820dci_softc *, uint8_t,
116 static void uss820dci_root_intr(struct uss820dci_softc *);
119 * Here is a list of what the USS820D chip can support. The main
120 * limitation is that the sum of the buffer sizes must be less than
123 static const struct usb_hw_ep_profile
124 uss820dci_ep_profile[] = {
127 .max_in_frame_size = 32,
128 .max_out_frame_size = 32,
130 .support_control = 1,
133 .max_in_frame_size = 64,
134 .max_out_frame_size = 64,
136 .support_multi_buffer = 1,
138 .support_interrupt = 1,
143 .max_in_frame_size = 8,
144 .max_out_frame_size = 8,
146 .support_multi_buffer = 1,
148 .support_interrupt = 1,
153 .max_in_frame_size = 256,
154 .max_out_frame_size = 256,
156 .support_multi_buffer = 1,
157 .support_isochronous = 1,
164 uss820dci_update_shared_1(struct uss820dci_softc *sc, uint8_t reg,
165 uint8_t keep_mask, uint8_t set_mask)
169 USS820_WRITE_1(sc, USS820_PEND, 1);
170 temp = USS820_READ_1(sc, reg);
173 USS820_WRITE_1(sc, reg, temp);
174 USS820_WRITE_1(sc, USS820_PEND, 0);
178 uss820dci_get_hw_ep_profile(struct usb_device *udev,
179 const struct usb_hw_ep_profile **ppf, uint8_t ep_addr)
182 *ppf = uss820dci_ep_profile + 0;
183 } else if (ep_addr < 5) {
184 *ppf = uss820dci_ep_profile + 1;
185 } else if (ep_addr < 7) {
186 *ppf = uss820dci_ep_profile + 2;
187 } else if (ep_addr == 7) {
188 *ppf = uss820dci_ep_profile + 3;
195 uss820dci_pull_up(struct uss820dci_softc *sc)
199 /* pullup D+, if possible */
201 if (!sc->sc_flags.d_pulled_up &&
202 sc->sc_flags.port_powered) {
203 sc->sc_flags.d_pulled_up = 1;
207 temp = USS820_READ_1(sc, USS820_MCSR);
208 temp |= USS820_MCSR_DPEN;
209 USS820_WRITE_1(sc, USS820_MCSR, temp);
214 uss820dci_pull_down(struct uss820dci_softc *sc)
218 /* pulldown D+, if possible */
220 if (sc->sc_flags.d_pulled_up) {
221 sc->sc_flags.d_pulled_up = 0;
225 temp = USS820_READ_1(sc, USS820_MCSR);
226 temp &= ~USS820_MCSR_DPEN;
227 USS820_WRITE_1(sc, USS820_MCSR, temp);
232 uss820dci_wakeup_peer(struct uss820dci_softc *sc)
234 if (!(sc->sc_flags.status_suspend)) {
237 DPRINTFN(0, "not supported\n");
241 uss820dci_set_address(struct uss820dci_softc *sc, uint8_t addr)
243 DPRINTFN(5, "addr=%d\n", addr);
245 USS820_WRITE_1(sc, USS820_FADDR, addr);
249 uss820dci_setup_rx(struct uss820dci_softc *sc, struct uss820dci_td *td)
251 struct usb_device_request req;
256 /* select the correct endpoint */
257 USS820_WRITE_1(sc, USS820_EPINDEX, td->ep_index);
259 /* read out FIFO status */
260 rx_stat = USS820_READ_1(sc, USS820_RXSTAT);
262 DPRINTFN(5, "rx_stat=0x%02x rem=%u\n", rx_stat, td->remainder);
264 if (!(rx_stat & USS820_RXSTAT_RXSETUP)) {
267 /* clear did stall */
270 /* clear stall and all I/O */
271 uss820dci_update_shared_1(sc, USS820_EPCON,
272 0xFF ^ (USS820_EPCON_TXSTL |
275 USS820_EPCON_TXOE), 0);
277 /* clear end overwrite flag */
278 uss820dci_update_shared_1(sc, USS820_RXSTAT,
279 0xFF ^ USS820_RXSTAT_EDOVW, 0);
281 /* get the packet byte count */
282 count = USS820_READ_1(sc, USS820_RXCNTL);
283 count |= (USS820_READ_1(sc, USS820_RXCNTH) << 8);
286 /* verify data length */
287 if (count != td->remainder) {
288 DPRINTFN(0, "Invalid SETUP packet "
289 "length, %d bytes\n", count);
290 goto setup_not_complete;
292 if (count != sizeof(req)) {
293 DPRINTFN(0, "Unsupported SETUP packet "
294 "length, %d bytes\n", count);
295 goto setup_not_complete;
298 bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
299 USS820_RXDAT * USS820_REG_STRIDE, (void *)&req, sizeof(req));
301 /* read out FIFO status */
302 rx_stat = USS820_READ_1(sc, USS820_RXSTAT);
304 if (rx_stat & (USS820_RXSTAT_EDOVW |
305 USS820_RXSTAT_STOVW)) {
306 DPRINTF("new SETUP packet received\n");
307 return (1); /* not complete */
309 /* clear receive setup bit */
310 uss820dci_update_shared_1(sc, USS820_RXSTAT,
311 0xFF ^ (USS820_RXSTAT_RXSETUP |
312 USS820_RXSTAT_EDOVW |
313 USS820_RXSTAT_STOVW), 0);
316 temp = USS820_READ_1(sc, USS820_RXCON);
317 temp |= USS820_RXCON_RXFFRC;
318 USS820_WRITE_1(sc, USS820_RXCON, temp);
320 /* copy data into real buffer */
321 usbd_copy_in(td->pc, 0, &req, sizeof(req));
323 td->offset = sizeof(req);
326 /* sneak peek the set address */
327 if ((req.bmRequestType == UT_WRITE_DEVICE) &&
328 (req.bRequest == UR_SET_ADDRESS)) {
329 sc->sc_dv_addr = req.wValue[0] & 0x7F;
331 sc->sc_dv_addr = 0xFF;
335 temp = USS820_READ_1(sc, USS820_TXCON);
336 temp |= USS820_TXCON_TXCLR;
337 USS820_WRITE_1(sc, USS820_TXCON, temp);
338 temp &= ~USS820_TXCON_TXCLR;
339 USS820_WRITE_1(sc, USS820_TXCON, temp);
341 return (0); /* complete */
346 temp = USS820_READ_1(sc, USS820_RXCON);
347 temp |= USS820_RXCON_RXFFRC;
348 USS820_WRITE_1(sc, USS820_RXCON, temp);
353 /* abort any ongoing transfer */
354 if (!td->did_stall) {
355 DPRINTFN(5, "stalling\n");
357 uss820dci_update_shared_1(sc, USS820_EPCON, 0xFF,
358 (USS820_EPCON_TXSTL | USS820_EPCON_RXSTL));
363 /* clear end overwrite flag, if any */
364 if (rx_stat & USS820_RXSTAT_RXSETUP) {
365 uss820dci_update_shared_1(sc, USS820_RXSTAT,
366 0xFF ^ (USS820_RXSTAT_EDOVW |
367 USS820_RXSTAT_STOVW |
368 USS820_RXSTAT_RXSETUP), 0);
370 return (1); /* not complete */
374 uss820dci_data_rx(struct uss820dci_softc *sc, struct uss820dci_td *td)
376 struct usb_page_search buf_res;
384 to = 2; /* don't loop forever! */
387 /* select the correct endpoint */
388 USS820_WRITE_1(sc, USS820_EPINDEX, td->ep_index);
390 /* check if any of the FIFO banks have data */
392 /* read out FIFO flag */
393 rx_flag = USS820_READ_1(sc, USS820_RXFLG);
394 /* read out FIFO status */
395 rx_stat = USS820_READ_1(sc, USS820_RXSTAT);
397 DPRINTFN(5, "rx_stat=0x%02x rx_flag=0x%02x rem=%u\n",
398 rx_stat, rx_flag, td->remainder);
400 if (rx_stat & (USS820_RXSTAT_RXSETUP |
401 USS820_RXSTAT_RXSOVW |
402 USS820_RXSTAT_EDOVW)) {
403 if (td->remainder == 0 && td->ep_index == 0) {
405 * We are actually complete and have
406 * received the next SETUP
408 DPRINTFN(5, "faking complete\n");
409 return (0); /* complete */
412 * USB Host Aborted the transfer.
415 return (0); /* complete */
417 /* check for errors */
418 if (rx_flag & (USS820_RXFLG_RXOVF |
419 USS820_RXFLG_RXURF)) {
420 DPRINTFN(5, "overflow or underflow\n");
421 /* should not happen */
423 return (0); /* complete */
426 if (!(rx_flag & (USS820_RXFLG_RXFIF0 |
427 USS820_RXFLG_RXFIF1))) {
429 /* read out EPCON register */
430 /* enable RX input */
431 if (!td->did_enable) {
432 uss820dci_update_shared_1(USS820_DCI_PC2SC(td->pc),
433 USS820_EPCON, 0xFF, USS820_EPCON_RXIE);
436 return (1); /* not complete */
438 /* get the packet byte count */
439 count = USS820_READ_1(sc, USS820_RXCNTL);
440 count |= (USS820_READ_1(sc, USS820_RXCNTH) << 8);
443 DPRINTFN(5, "count=0x%04x\n", count);
445 /* verify the packet byte count */
446 if (count != td->max_packet_size) {
447 if (count < td->max_packet_size) {
448 /* we have a short packet */
452 /* invalid USB packet */
454 return (0); /* we are complete */
457 /* verify the packet byte count */
458 if (count > td->remainder) {
459 /* invalid USB packet */
461 return (0); /* we are complete */
464 usbd_get_page(td->pc, td->offset, &buf_res);
466 /* get correct length */
467 if (buf_res.length > count) {
468 buf_res.length = count;
471 bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
472 USS820_RXDAT * USS820_REG_STRIDE, buf_res.buffer, buf_res.length);
474 /* update counters */
475 count -= buf_res.length;
476 td->offset += buf_res.length;
477 td->remainder -= buf_res.length;
481 rx_cntl = USS820_READ_1(sc, USS820_RXCON);
482 rx_cntl |= USS820_RXCON_RXFFRC;
483 USS820_WRITE_1(sc, USS820_RXCON, rx_cntl);
485 /* check if we are complete */
486 if ((td->remainder == 0) || got_short) {
488 /* we are complete */
491 /* else need to receive a zero length packet */
496 return (1); /* not complete */
500 uss820dci_data_tx(struct uss820dci_softc *sc, struct uss820dci_td *td)
502 struct usb_page_search buf_res;
509 /* select the correct endpoint */
510 USS820_WRITE_1(sc, USS820_EPINDEX, td->ep_index);
512 to = 2; /* don't loop forever! */
515 /* read out TX FIFO flags */
516 tx_flag = USS820_READ_1(sc, USS820_TXFLG);
518 DPRINTFN(5, "tx_flag=0x%02x rem=%u\n", tx_flag, td->remainder);
520 if (td->ep_index == 0) {
521 /* read out RX FIFO status last */
522 rx_stat = USS820_READ_1(sc, USS820_RXSTAT);
524 DPRINTFN(5, "rx_stat=0x%02x\n", rx_stat);
526 if (rx_stat & (USS820_RXSTAT_RXSETUP |
527 USS820_RXSTAT_RXSOVW |
528 USS820_RXSTAT_EDOVW)) {
530 * The current transfer was aborted by the USB
534 return (0); /* complete */
537 if (tx_flag & (USS820_TXFLG_TXOVF |
538 USS820_TXFLG_TXURF)) {
540 return (0); /* complete */
542 if (tx_flag & USS820_TXFLG_TXFIF0) {
543 if (tx_flag & USS820_TXFLG_TXFIF1) {
544 return (1); /* not complete */
547 if ((!td->support_multi_buffer) &&
548 (tx_flag & (USS820_TXFLG_TXFIF0 |
549 USS820_TXFLG_TXFIF1))) {
550 return (1); /* not complete */
552 count = td->max_packet_size;
553 if (td->remainder < count) {
554 /* we have a short packet */
556 count = td->remainder;
561 usbd_get_page(td->pc, td->offset, &buf_res);
563 /* get correct length */
564 if (buf_res.length > count) {
565 buf_res.length = count;
568 bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
569 USS820_TXDAT * USS820_REG_STRIDE, buf_res.buffer, buf_res.length);
571 /* update counters */
572 count -= buf_res.length;
573 td->offset += buf_res.length;
574 td->remainder -= buf_res.length;
577 /* post-write high packet byte count first */
578 USS820_WRITE_1(sc, USS820_TXCNTH, count_copy >> 8);
580 /* post-write low packet byte count last */
581 USS820_WRITE_1(sc, USS820_TXCNTL, count_copy);
584 * Enable TX output, which must happen after that we have written
585 * data into the FIFO. This is undocumented.
587 if (!td->did_enable) {
588 uss820dci_update_shared_1(USS820_DCI_PC2SC(td->pc),
589 USS820_EPCON, 0xFF, USS820_EPCON_TXOE);
592 /* check remainder */
593 if (td->remainder == 0) {
595 return (0); /* complete */
597 /* else we need to transmit a short packet */
602 return (1); /* not complete */
606 uss820dci_data_tx_sync(struct uss820dci_softc *sc, struct uss820dci_td *td)
611 /* select the correct endpoint */
612 USS820_WRITE_1(sc, USS820_EPINDEX, td->ep_index);
614 /* read out TX FIFO flag */
615 tx_flag = USS820_READ_1(sc, USS820_TXFLG);
617 if (td->ep_index == 0) {
618 /* read out RX FIFO status last */
619 rx_stat = USS820_READ_1(sc, USS820_RXSTAT);
621 DPRINTFN(5, "rx_stat=0x%02x rem=%u\n", rx_stat, td->remainder);
623 if (rx_stat & (USS820_RXSTAT_RXSETUP |
624 USS820_RXSTAT_RXSOVW |
625 USS820_RXSTAT_EDOVW)) {
626 DPRINTFN(5, "faking complete\n");
628 return (0); /* complete */
631 DPRINTFN(5, "tx_flag=0x%02x rem=%u\n", tx_flag, td->remainder);
633 if (tx_flag & (USS820_TXFLG_TXOVF |
634 USS820_TXFLG_TXURF)) {
636 return (0); /* complete */
638 if (tx_flag & (USS820_TXFLG_TXFIF0 |
639 USS820_TXFLG_TXFIF1)) {
640 return (1); /* not complete */
642 if (td->ep_index == 0 && sc->sc_dv_addr != 0xFF) {
643 /* write function address */
644 uss820dci_set_address(sc, sc->sc_dv_addr);
646 return (0); /* complete */
650 uss820dci_xfer_do_fifo(struct usb_xfer *xfer)
652 struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
653 struct uss820dci_td *td;
657 td = xfer->td_transfer_cache;
662 if ((td->func) (sc, td)) {
663 /* operation in progress */
666 if (((void *)td) == xfer->td_transfer_last) {
671 } else if (td->remainder > 0) {
673 * We had a short transfer. If there is no alternate
674 * next, stop processing !
681 * Fetch the next transfer descriptor.
684 xfer->td_transfer_cache = td;
689 /* compute all actual lengths */
690 xfer->td_transfer_cache = NULL;
691 sc->sc_xfer_complete = 1;
695 uss820dci_xfer_do_complete(struct usb_xfer *xfer)
697 struct uss820dci_td *td;
701 td = xfer->td_transfer_cache;
703 /* compute all actual lengths */
704 uss820dci_standard_done(xfer);
711 uss820dci_interrupt_poll_locked(struct uss820dci_softc *sc)
713 struct usb_xfer *xfer;
715 TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry)
716 uss820dci_xfer_do_fifo(xfer);
720 uss820dci_interrupt_complete_locked(struct uss820dci_softc *sc)
722 struct usb_xfer *xfer;
724 TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
725 if (uss820dci_xfer_do_complete(xfer))
731 uss820dci_wait_suspend(struct uss820dci_softc *sc, uint8_t on)
736 scr = USS820_READ_1(sc, USS820_SCR);
737 scratch = USS820_READ_1(sc, USS820_SCRATCH);
740 scr |= USS820_SCR_IE_SUSP;
741 scratch &= ~USS820_SCRATCH_IE_RESUME;
743 scr &= ~USS820_SCR_IE_SUSP;
744 scratch |= USS820_SCRATCH_IE_RESUME;
747 USS820_WRITE_1(sc, USS820_SCR, scr);
748 USS820_WRITE_1(sc, USS820_SCRATCH, scratch);
752 uss820dci_filter_interrupt(void *arg)
754 struct uss820dci_softc *sc = arg;
755 int retval = FILTER_HANDLED;
758 USB_BUS_SPIN_LOCK(&sc->sc_bus);
760 ssr = USS820_READ_1(sc, USS820_SSR);
761 uss820dci_update_shared_1(sc, USS820_SSR, USS820_DCI_THREAD_IRQ, 0);
763 if (ssr & USS820_DCI_THREAD_IRQ)
764 retval = FILTER_SCHEDULE_THREAD;
766 /* poll FIFOs, if any */
767 uss820dci_interrupt_poll_locked(sc);
769 if (sc->sc_xfer_complete != 0)
770 retval = FILTER_SCHEDULE_THREAD;
772 USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
778 uss820dci_interrupt(void *arg)
780 struct uss820dci_softc *sc = arg;
784 USB_BUS_LOCK(&sc->sc_bus);
785 USB_BUS_SPIN_LOCK(&sc->sc_bus);
787 ssr = USS820_READ_1(sc, USS820_SSR);
789 /* acknowledge all interrupts */
791 uss820dci_update_shared_1(sc, USS820_SSR, ~USS820_DCI_THREAD_IRQ, 0);
793 /* check for any bus state change interrupts */
795 if (ssr & USS820_DCI_THREAD_IRQ) {
799 if (ssr & USS820_SSR_RESET) {
800 sc->sc_flags.status_bus_reset = 1;
801 sc->sc_flags.status_suspend = 0;
802 sc->sc_flags.change_suspend = 0;
803 sc->sc_flags.change_connect = 1;
805 /* disable resume interrupt */
806 uss820dci_wait_suspend(sc, 1);
811 * If "RESUME" and "SUSPEND" is set at the same time
812 * we interpret that like "RESUME". Resume is set when
813 * there is at least 3 milliseconds of inactivity on
816 if (ssr & USS820_SSR_RESUME) {
817 if (sc->sc_flags.status_suspend) {
818 sc->sc_flags.status_suspend = 0;
819 sc->sc_flags.change_suspend = 1;
820 /* disable resume interrupt */
821 uss820dci_wait_suspend(sc, 1);
824 } else if (ssr & USS820_SSR_SUSPEND) {
825 if (!sc->sc_flags.status_suspend) {
826 sc->sc_flags.status_suspend = 1;
827 sc->sc_flags.change_suspend = 1;
828 /* enable resume interrupt */
829 uss820dci_wait_suspend(sc, 0);
835 DPRINTF("real bus interrupt 0x%02x\n", ssr);
837 /* complete root HUB interrupt endpoint */
838 uss820dci_root_intr(sc);
841 /* acknowledge all SBI interrupts */
842 uss820dci_update_shared_1(sc, USS820_SBI, 0, 0);
844 /* acknowledge all SBI1 interrupts */
845 uss820dci_update_shared_1(sc, USS820_SBI1, 0, 0);
847 if (sc->sc_xfer_complete != 0) {
848 sc->sc_xfer_complete = 0;
850 /* complete FIFOs, if any */
851 uss820dci_interrupt_complete_locked(sc);
853 USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
854 USB_BUS_UNLOCK(&sc->sc_bus);
858 uss820dci_setup_standard_chain_sub(struct uss820_std_temp *temp)
860 struct uss820dci_td *td;
862 /* get current Transfer Descriptor */
866 /* prepare for next TD */
867 temp->td_next = td->obj_next;
869 /* fill out the Transfer Descriptor */
870 td->func = temp->func;
872 td->offset = temp->offset;
873 td->remainder = temp->len;
876 td->did_stall = temp->did_stall;
877 td->short_pkt = temp->short_pkt;
878 td->alt_next = temp->setup_alt_next;
882 uss820dci_setup_standard_chain(struct usb_xfer *xfer)
884 struct uss820_std_temp temp;
885 struct uss820dci_softc *sc;
886 struct uss820dci_td *td;
890 DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n",
891 xfer->address, UE_GET_ADDR(xfer->endpointno),
892 xfer->sumlen, usbd_get_speed(xfer->xroot->udev));
894 temp.max_frame_size = xfer->max_frame_size;
896 td = xfer->td_start[0];
897 xfer->td_transfer_first = td;
898 xfer->td_transfer_cache = td;
904 temp.td_next = xfer->td_start[0];
906 temp.setup_alt_next = xfer->flags_int.short_frames_ok ||
907 xfer->flags_int.isochronous_xfr;
908 temp.did_stall = !xfer->flags_int.control_stall;
910 sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
911 ep_no = (xfer->endpointno & UE_ADDR);
913 /* check if we should prepend a setup message */
915 if (xfer->flags_int.control_xfr) {
916 if (xfer->flags_int.control_hdr) {
918 temp.func = &uss820dci_setup_rx;
919 temp.len = xfer->frlengths[0];
920 temp.pc = xfer->frbuffers + 0;
921 temp.short_pkt = temp.len ? 1 : 0;
922 /* check for last frame */
923 if (xfer->nframes == 1) {
924 /* no STATUS stage yet, SETUP is last */
925 if (xfer->flags_int.control_act)
926 temp.setup_alt_next = 0;
929 uss820dci_setup_standard_chain_sub(&temp);
936 if (x != xfer->nframes) {
937 if (xfer->endpointno & UE_DIR_IN) {
938 temp.func = &uss820dci_data_tx;
940 temp.func = &uss820dci_data_rx;
943 /* setup "pc" pointer */
944 temp.pc = xfer->frbuffers + x;
946 while (x != xfer->nframes) {
948 /* DATA0 / DATA1 message */
950 temp.len = xfer->frlengths[x];
954 if (x == xfer->nframes) {
955 if (xfer->flags_int.control_xfr) {
956 if (xfer->flags_int.control_act) {
957 temp.setup_alt_next = 0;
960 temp.setup_alt_next = 0;
965 /* make sure that we send an USB packet */
971 /* regular data transfer */
973 temp.short_pkt = (xfer->flags.force_short_xfer) ? 0 : 1;
976 uss820dci_setup_standard_chain_sub(&temp);
978 if (xfer->flags_int.isochronous_xfr) {
979 temp.offset += temp.len;
981 /* get next Page Cache pointer */
982 temp.pc = xfer->frbuffers + x;
986 /* check for control transfer */
987 if (xfer->flags_int.control_xfr) {
990 /* always setup a valid "pc" pointer for status and sync */
991 temp.pc = xfer->frbuffers + 0;
994 temp.setup_alt_next = 0;
996 /* check if we should append a status stage */
997 if (!xfer->flags_int.control_act) {
1000 * Send a DATA1 message and invert the current
1001 * endpoint direction.
1003 if (xfer->endpointno & UE_DIR_IN) {
1004 temp.func = &uss820dci_data_rx;
1007 temp.func = &uss820dci_data_tx;
1013 uss820dci_setup_standard_chain_sub(&temp);
1015 /* we need a SYNC point after TX */
1016 temp.func = &uss820dci_data_tx_sync;
1017 uss820dci_setup_standard_chain_sub(&temp);
1021 /* must have at least one frame! */
1023 xfer->td_transfer_last = td;
1027 uss820dci_timeout(void *arg)
1029 struct usb_xfer *xfer = arg;
1031 DPRINTF("xfer=%p\n", xfer);
1033 USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED);
1035 /* transfer is transferred */
1036 uss820dci_device_done(xfer, USB_ERR_TIMEOUT);
1040 uss820dci_intr_set(struct usb_xfer *xfer, uint8_t set)
1042 struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
1043 uint8_t ep_no = (xfer->endpointno & UE_ADDR);
1047 DPRINTFN(15, "endpoint 0x%02x\n", xfer->endpointno);
1050 ep_reg = USS820_SBIE1;
1052 ep_reg = USS820_SBIE;
1056 ep_no = 1 << (2 * ep_no);
1058 if (xfer->flags_int.control_xfr) {
1059 if (xfer->flags_int.control_hdr) {
1060 ep_no <<= 1; /* RX interrupt only */
1062 ep_no |= (ep_no << 1); /* RX and TX interrupt */
1065 if (!(xfer->endpointno & UE_DIR_IN)) {
1069 temp = USS820_READ_1(sc, ep_reg);
1075 USS820_WRITE_1(sc, ep_reg, temp);
1079 uss820dci_start_standard_chain(struct usb_xfer *xfer)
1081 struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
1085 USB_BUS_SPIN_LOCK(&sc->sc_bus);
1088 uss820dci_xfer_do_fifo(xfer);
1090 if (uss820dci_xfer_do_complete(xfer) == 0) {
1092 * Only enable the endpoint interrupt when we are
1093 * actually waiting for data, hence we are dealing
1094 * with level triggered interrupts !
1096 uss820dci_intr_set(xfer, 1);
1098 /* put transfer on interrupt queue */
1099 usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);
1101 /* start timeout, if any */
1102 if (xfer->timeout != 0) {
1103 usbd_transfer_timeout_ms(xfer,
1104 &uss820dci_timeout, xfer->timeout);
1107 USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
1111 uss820dci_root_intr(struct uss820dci_softc *sc)
1115 USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
1118 sc->sc_hub_idata[0] = 0x02; /* we only have one port */
1120 uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata,
1121 sizeof(sc->sc_hub_idata));
1125 uss820dci_standard_done_sub(struct usb_xfer *xfer)
1127 struct uss820dci_td *td;
1133 td = xfer->td_transfer_cache;
1136 len = td->remainder;
1138 if (xfer->aframes != xfer->nframes) {
1140 * Verify the length and subtract
1141 * the remainder from "frlengths[]":
1143 if (len > xfer->frlengths[xfer->aframes]) {
1146 xfer->frlengths[xfer->aframes] -= len;
1149 /* Check for transfer error */
1151 /* the transfer is finished */
1156 /* Check for short transfer */
1158 if (xfer->flags_int.short_frames_ok ||
1159 xfer->flags_int.isochronous_xfr) {
1160 /* follow alt next */
1167 /* the transfer is finished */
1175 /* this USB frame is complete */
1181 /* update transfer cache */
1183 xfer->td_transfer_cache = td;
1186 USB_ERR_STALLED : USB_ERR_NORMAL_COMPLETION);
1190 uss820dci_standard_done(struct usb_xfer *xfer)
1192 usb_error_t err = 0;
1194 DPRINTFN(13, "xfer=%p endpoint=%p transfer done\n",
1195 xfer, xfer->endpoint);
1199 xfer->td_transfer_cache = xfer->td_transfer_first;
1201 if (xfer->flags_int.control_xfr) {
1203 if (xfer->flags_int.control_hdr) {
1205 err = uss820dci_standard_done_sub(xfer);
1209 if (xfer->td_transfer_cache == NULL) {
1213 while (xfer->aframes != xfer->nframes) {
1215 err = uss820dci_standard_done_sub(xfer);
1218 if (xfer->td_transfer_cache == NULL) {
1223 if (xfer->flags_int.control_xfr &&
1224 !xfer->flags_int.control_act) {
1226 err = uss820dci_standard_done_sub(xfer);
1229 uss820dci_device_done(xfer, err);
1232 /*------------------------------------------------------------------------*
1233 * uss820dci_device_done
1235 * NOTE: this function can be called more than one time on the
1236 * same USB transfer!
1237 *------------------------------------------------------------------------*/
1239 uss820dci_device_done(struct usb_xfer *xfer, usb_error_t error)
1241 struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
1243 USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED);
1245 DPRINTFN(2, "xfer=%p, endpoint=%p, error=%d\n",
1246 xfer, xfer->endpoint, error);
1248 USB_BUS_SPIN_LOCK(&sc->sc_bus);
1250 if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) {
1251 uss820dci_intr_set(xfer, 0);
1253 /* dequeue transfer and start next transfer */
1254 usbd_transfer_done(xfer, error);
1256 USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
1260 uss820dci_xfer_stall(struct usb_xfer *xfer)
1262 uss820dci_device_done(xfer, USB_ERR_STALLED);
1266 uss820dci_set_stall(struct usb_device *udev,
1267 struct usb_endpoint *ep, uint8_t *did_stall)
1269 struct uss820dci_softc *sc;
1275 USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED);
1277 DPRINTFN(5, "endpoint=%p\n", ep);
1279 /* set FORCESTALL */
1280 sc = USS820_DCI_BUS2SC(udev->bus);
1281 ep_no = (ep->edesc->bEndpointAddress & UE_ADDR);
1282 ep_dir = (ep->edesc->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT));
1283 ep_type = (ep->edesc->bmAttributes & UE_XFERTYPE);
1285 if (ep_type == UE_CONTROL) {
1286 /* should not happen */
1289 USB_BUS_SPIN_LOCK(&sc->sc_bus);
1290 USS820_WRITE_1(sc, USS820_EPINDEX, ep_no);
1292 if (ep_dir == UE_DIR_IN) {
1293 temp = USS820_EPCON_TXSTL;
1295 temp = USS820_EPCON_RXSTL;
1297 uss820dci_update_shared_1(sc, USS820_EPCON, 0xFF, temp);
1298 USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
1302 uss820dci_clear_stall_sub(struct uss820dci_softc *sc,
1303 uint8_t ep_no, uint8_t ep_type, uint8_t ep_dir)
1307 if (ep_type == UE_CONTROL) {
1308 /* clearing stall is not needed */
1311 USB_BUS_SPIN_LOCK(&sc->sc_bus);
1313 /* select endpoint index */
1314 USS820_WRITE_1(sc, USS820_EPINDEX, ep_no);
1316 /* clear stall and disable I/O transfers */
1317 if (ep_dir == UE_DIR_IN) {
1318 temp = 0xFF ^ (USS820_EPCON_TXOE |
1319 USS820_EPCON_TXSTL);
1321 temp = 0xFF ^ (USS820_EPCON_RXIE |
1322 USS820_EPCON_RXSTL);
1324 uss820dci_update_shared_1(sc, USS820_EPCON, temp, 0);
1326 if (ep_dir == UE_DIR_IN) {
1327 /* reset data toggle */
1328 USS820_WRITE_1(sc, USS820_TXSTAT,
1329 USS820_TXSTAT_TXSOVW);
1332 temp = USS820_READ_1(sc, USS820_TXCON);
1333 temp |= USS820_TXCON_TXCLR;
1334 USS820_WRITE_1(sc, USS820_TXCON, temp);
1335 temp &= ~USS820_TXCON_TXCLR;
1336 USS820_WRITE_1(sc, USS820_TXCON, temp);
1339 /* reset data toggle */
1340 uss820dci_update_shared_1(sc, USS820_RXSTAT,
1341 0, USS820_RXSTAT_RXSOVW);
1344 temp = USS820_READ_1(sc, USS820_RXCON);
1345 temp |= USS820_RXCON_RXCLR;
1346 temp &= ~USS820_RXCON_RXFFRC;
1347 USS820_WRITE_1(sc, USS820_RXCON, temp);
1348 temp &= ~USS820_RXCON_RXCLR;
1349 USS820_WRITE_1(sc, USS820_RXCON, temp);
1351 USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
1355 uss820dci_clear_stall(struct usb_device *udev, struct usb_endpoint *ep)
1357 struct uss820dci_softc *sc;
1358 struct usb_endpoint_descriptor *ed;
1360 USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED);
1362 DPRINTFN(5, "endpoint=%p\n", ep);
1365 if (udev->flags.usb_mode != USB_MODE_DEVICE) {
1370 sc = USS820_DCI_BUS2SC(udev->bus);
1372 /* get endpoint descriptor */
1375 /* reset endpoint */
1376 uss820dci_clear_stall_sub(sc,
1377 (ed->bEndpointAddress & UE_ADDR),
1378 (ed->bmAttributes & UE_XFERTYPE),
1379 (ed->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT)));
1383 uss820dci_init(struct uss820dci_softc *sc)
1385 const struct usb_hw_ep_profile *pf;
1391 /* set up the bus structure */
1392 sc->sc_bus.usbrev = USB_REV_1_1;
1393 sc->sc_bus.methods = &uss820dci_bus_methods;
1395 USB_BUS_LOCK(&sc->sc_bus);
1397 /* we always have VBUS */
1398 sc->sc_flags.status_vbus = 1;
1400 /* reset the chip */
1401 USS820_WRITE_1(sc, USS820_SCR, USS820_SCR_SRESET);
1403 USS820_WRITE_1(sc, USS820_SCR, 0);
1405 /* wait for reset to complete */
1408 temp = USS820_READ_1(sc, USS820_MCSR);
1410 if (temp & USS820_MCSR_INIT) {
1414 USB_BUS_UNLOCK(&sc->sc_bus);
1415 return (USB_ERR_INVAL);
1417 /* wait a little for things to stabilise */
1422 uss820dci_pull_down(sc);
1424 /* wait 10ms for pulldown to stabilise */
1425 usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 100);
1427 /* check hardware revision */
1428 temp = USS820_READ_1(sc, USS820_REV);
1431 USB_BUS_UNLOCK(&sc->sc_bus);
1432 return (USB_ERR_INVAL);
1434 /* enable interrupts */
1435 USS820_WRITE_1(sc, USS820_SCR,
1437 USS820_SCR_IE_RESET |
1438 /* USS820_SCR_RWUPE | */
1439 USS820_SCR_IE_SUSP |
1442 /* enable interrupts */
1443 USS820_WRITE_1(sc, USS820_SCRATCH,
1444 USS820_SCRATCH_IE_RESUME);
1446 /* enable features */
1447 USS820_WRITE_1(sc, USS820_MCSR,
1448 USS820_MCSR_BDFEAT |
1451 sc->sc_flags.mcsr_feat = 1;
1453 /* disable interrupts */
1454 USS820_WRITE_1(sc, USS820_SBIE, 0);
1456 /* disable interrupts */
1457 USS820_WRITE_1(sc, USS820_SBIE1, 0);
1459 /* disable all endpoints */
1460 for (n = 0; n != USS820_EP_MAX; n++) {
1462 /* select endpoint */
1463 USS820_WRITE_1(sc, USS820_EPINDEX, n);
1465 /* disable endpoint */
1466 uss820dci_update_shared_1(sc, USS820_EPCON, 0, 0);
1470 * Initialise default values for some registers that cannot be
1471 * changed during operation!
1473 for (n = 0; n != USS820_EP_MAX; n++) {
1475 uss820dci_get_hw_ep_profile(NULL, &pf, n);
1477 /* the maximum frame sizes should be the same */
1478 if (pf->max_in_frame_size != pf->max_out_frame_size) {
1479 DPRINTF("Max frame size mismatch %u != %u\n",
1480 pf->max_in_frame_size, pf->max_out_frame_size);
1482 if (pf->support_isochronous) {
1483 if (pf->max_in_frame_size <= 64) {
1484 temp = (USS820_TXCON_FFSZ_16_64 |
1485 USS820_TXCON_TXISO |
1487 } else if (pf->max_in_frame_size <= 256) {
1488 temp = (USS820_TXCON_FFSZ_64_256 |
1489 USS820_TXCON_TXISO |
1491 } else if (pf->max_in_frame_size <= 512) {
1492 temp = (USS820_TXCON_FFSZ_8_512 |
1493 USS820_TXCON_TXISO |
1495 } else { /* 1024 bytes */
1496 temp = (USS820_TXCON_FFSZ_32_1024 |
1497 USS820_TXCON_TXISO |
1501 if ((pf->max_in_frame_size <= 8) &&
1502 (sc->sc_flags.mcsr_feat)) {
1503 temp = (USS820_TXCON_FFSZ_8_512 |
1505 } else if (pf->max_in_frame_size <= 16) {
1506 temp = (USS820_TXCON_FFSZ_16_64 |
1508 } else if ((pf->max_in_frame_size <= 32) &&
1509 (sc->sc_flags.mcsr_feat)) {
1510 temp = (USS820_TXCON_FFSZ_32_1024 |
1512 } else { /* 64 bytes */
1513 temp = (USS820_TXCON_FFSZ_64_256 |
1518 /* need to configure the chip early */
1520 USS820_WRITE_1(sc, USS820_EPINDEX, n);
1521 USS820_WRITE_1(sc, USS820_TXCON, temp);
1522 USS820_WRITE_1(sc, USS820_RXCON, temp);
1524 if (pf->support_control) {
1525 temp = USS820_EPCON_CTLEP |
1526 USS820_EPCON_RXSPM |
1528 USS820_EPCON_RXEPEN |
1530 USS820_EPCON_TXEPEN;
1532 temp = USS820_EPCON_RXEPEN | USS820_EPCON_TXEPEN;
1535 uss820dci_update_shared_1(sc, USS820_EPCON, 0, temp);
1538 USB_BUS_UNLOCK(&sc->sc_bus);
1540 /* catch any lost interrupts */
1542 uss820dci_do_poll(&sc->sc_bus);
1544 return (0); /* success */
1548 uss820dci_uninit(struct uss820dci_softc *sc)
1552 USB_BUS_LOCK(&sc->sc_bus);
1554 /* disable all interrupts */
1555 temp = USS820_READ_1(sc, USS820_SCR);
1556 temp &= ~USS820_SCR_T_IRQ;
1557 USS820_WRITE_1(sc, USS820_SCR, temp);
1559 sc->sc_flags.port_powered = 0;
1560 sc->sc_flags.status_vbus = 0;
1561 sc->sc_flags.status_bus_reset = 0;
1562 sc->sc_flags.status_suspend = 0;
1563 sc->sc_flags.change_suspend = 0;
1564 sc->sc_flags.change_connect = 1;
1566 uss820dci_pull_down(sc);
1567 USB_BUS_UNLOCK(&sc->sc_bus);
1571 uss820dci_suspend(struct uss820dci_softc *sc)
1577 uss820dci_resume(struct uss820dci_softc *sc)
1583 uss820dci_do_poll(struct usb_bus *bus)
1585 struct uss820dci_softc *sc = USS820_DCI_BUS2SC(bus);
1587 USB_BUS_LOCK(&sc->sc_bus);
1588 USB_BUS_SPIN_LOCK(&sc->sc_bus);
1589 uss820dci_interrupt_poll_locked(sc);
1590 uss820dci_interrupt_complete_locked(sc);
1591 USB_BUS_SPIN_UNLOCK(&sc->sc_bus);
1592 USB_BUS_UNLOCK(&sc->sc_bus);
1595 /*------------------------------------------------------------------------*
1596 * uss820dci bulk support
1597 *------------------------------------------------------------------------*/
1599 uss820dci_device_bulk_open(struct usb_xfer *xfer)
1605 uss820dci_device_bulk_close(struct usb_xfer *xfer)
1607 uss820dci_device_done(xfer, USB_ERR_CANCELLED);
1611 uss820dci_device_bulk_enter(struct usb_xfer *xfer)
1617 uss820dci_device_bulk_start(struct usb_xfer *xfer)
1620 uss820dci_setup_standard_chain(xfer);
1621 uss820dci_start_standard_chain(xfer);
1624 static const struct usb_pipe_methods uss820dci_device_bulk_methods =
1626 .open = uss820dci_device_bulk_open,
1627 .close = uss820dci_device_bulk_close,
1628 .enter = uss820dci_device_bulk_enter,
1629 .start = uss820dci_device_bulk_start,
1632 /*------------------------------------------------------------------------*
1633 * uss820dci control support
1634 *------------------------------------------------------------------------*/
1636 uss820dci_device_ctrl_open(struct usb_xfer *xfer)
1642 uss820dci_device_ctrl_close(struct usb_xfer *xfer)
1644 uss820dci_device_done(xfer, USB_ERR_CANCELLED);
1648 uss820dci_device_ctrl_enter(struct usb_xfer *xfer)
1654 uss820dci_device_ctrl_start(struct usb_xfer *xfer)
1657 uss820dci_setup_standard_chain(xfer);
1658 uss820dci_start_standard_chain(xfer);
1661 static const struct usb_pipe_methods uss820dci_device_ctrl_methods =
1663 .open = uss820dci_device_ctrl_open,
1664 .close = uss820dci_device_ctrl_close,
1665 .enter = uss820dci_device_ctrl_enter,
1666 .start = uss820dci_device_ctrl_start,
1669 /*------------------------------------------------------------------------*
1670 * uss820dci interrupt support
1671 *------------------------------------------------------------------------*/
1673 uss820dci_device_intr_open(struct usb_xfer *xfer)
1679 uss820dci_device_intr_close(struct usb_xfer *xfer)
1681 uss820dci_device_done(xfer, USB_ERR_CANCELLED);
1685 uss820dci_device_intr_enter(struct usb_xfer *xfer)
1691 uss820dci_device_intr_start(struct usb_xfer *xfer)
1694 uss820dci_setup_standard_chain(xfer);
1695 uss820dci_start_standard_chain(xfer);
1698 static const struct usb_pipe_methods uss820dci_device_intr_methods =
1700 .open = uss820dci_device_intr_open,
1701 .close = uss820dci_device_intr_close,
1702 .enter = uss820dci_device_intr_enter,
1703 .start = uss820dci_device_intr_start,
1706 /*------------------------------------------------------------------------*
1707 * uss820dci full speed isochronous support
1708 *------------------------------------------------------------------------*/
1710 uss820dci_device_isoc_fs_open(struct usb_xfer *xfer)
1716 uss820dci_device_isoc_fs_close(struct usb_xfer *xfer)
1718 uss820dci_device_done(xfer, USB_ERR_CANCELLED);
1722 uss820dci_device_isoc_fs_enter(struct usb_xfer *xfer)
1724 struct uss820dci_softc *sc = USS820_DCI_BUS2SC(xfer->xroot->bus);
1728 DPRINTFN(6, "xfer=%p next=%d nframes=%d\n",
1729 xfer, xfer->endpoint->isoc_next, xfer->nframes);
1731 /* get the current frame index - we don't need the high bits */
1733 nframes = USS820_READ_1(sc, USS820_SOFL);
1736 * check if the frame index is within the window where the
1737 * frames will be inserted
1739 temp = (nframes - xfer->endpoint->isoc_next) & USS820_SOFL_MASK;
1741 if ((xfer->endpoint->is_synced == 0) ||
1742 (temp < xfer->nframes)) {
1744 * If there is data underflow or the pipe queue is
1745 * empty we schedule the transfer a few frames ahead
1746 * of the current frame position. Else two isochronous
1747 * transfers might overlap.
1749 xfer->endpoint->isoc_next = (nframes + 3) & USS820_SOFL_MASK;
1750 xfer->endpoint->is_synced = 1;
1751 DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next);
1754 * compute how many milliseconds the insertion is ahead of the
1755 * current frame position:
1757 temp = (xfer->endpoint->isoc_next - nframes) & USS820_SOFL_MASK;
1760 * pre-compute when the isochronous transfer will be finished:
1762 xfer->isoc_time_complete =
1763 usb_isoc_time_expand(&sc->sc_bus, nframes) + temp +
1766 /* compute frame number for next insertion */
1767 xfer->endpoint->isoc_next += xfer->nframes;
1770 uss820dci_setup_standard_chain(xfer);
1774 uss820dci_device_isoc_fs_start(struct usb_xfer *xfer)
1776 /* start TD chain */
1777 uss820dci_start_standard_chain(xfer);
1780 static const struct usb_pipe_methods uss820dci_device_isoc_fs_methods =
1782 .open = uss820dci_device_isoc_fs_open,
1783 .close = uss820dci_device_isoc_fs_close,
1784 .enter = uss820dci_device_isoc_fs_enter,
1785 .start = uss820dci_device_isoc_fs_start,
1788 /*------------------------------------------------------------------------*
1789 * uss820dci root control support
1790 *------------------------------------------------------------------------*
1791 * Simulate a hardware HUB by handling all the necessary requests.
1792 *------------------------------------------------------------------------*/
1794 static const struct usb_device_descriptor uss820dci_devd = {
1795 .bLength = sizeof(struct usb_device_descriptor),
1796 .bDescriptorType = UDESC_DEVICE,
1797 .bcdUSB = {0x00, 0x02},
1798 .bDeviceClass = UDCLASS_HUB,
1799 .bDeviceSubClass = UDSUBCLASS_HUB,
1800 .bDeviceProtocol = UDPROTO_FSHUB,
1801 .bMaxPacketSize = 64,
1802 .bcdDevice = {0x00, 0x01},
1805 .bNumConfigurations = 1,
1808 static const struct usb_device_qualifier uss820dci_odevd = {
1809 .bLength = sizeof(struct usb_device_qualifier),
1810 .bDescriptorType = UDESC_DEVICE_QUALIFIER,
1811 .bcdUSB = {0x00, 0x02},
1812 .bDeviceClass = UDCLASS_HUB,
1813 .bDeviceSubClass = UDSUBCLASS_HUB,
1814 .bDeviceProtocol = UDPROTO_FSHUB,
1815 .bMaxPacketSize0 = 0,
1816 .bNumConfigurations = 0,
1819 static const struct uss820dci_config_desc uss820dci_confd = {
1821 .bLength = sizeof(struct usb_config_descriptor),
1822 .bDescriptorType = UDESC_CONFIG,
1823 .wTotalLength[0] = sizeof(uss820dci_confd),
1825 .bConfigurationValue = 1,
1826 .iConfiguration = 0,
1827 .bmAttributes = UC_SELF_POWERED,
1831 .bLength = sizeof(struct usb_interface_descriptor),
1832 .bDescriptorType = UDESC_INTERFACE,
1834 .bInterfaceClass = UICLASS_HUB,
1835 .bInterfaceSubClass = UISUBCLASS_HUB,
1836 .bInterfaceProtocol = 0,
1840 .bLength = sizeof(struct usb_endpoint_descriptor),
1841 .bDescriptorType = UDESC_ENDPOINT,
1842 .bEndpointAddress = (UE_DIR_IN | USS820_DCI_INTR_ENDPT),
1843 .bmAttributes = UE_INTERRUPT,
1844 .wMaxPacketSize[0] = 8,
1849 #define HSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) }
1851 static const struct usb_hub_descriptor_min uss820dci_hubd = {
1852 .bDescLength = sizeof(uss820dci_hubd),
1853 .bDescriptorType = UDESC_HUB,
1855 HSETW(.wHubCharacteristics, (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL)),
1856 .bPwrOn2PwrGood = 50,
1857 .bHubContrCurrent = 0,
1858 .DeviceRemovable = {0}, /* port is removable */
1861 #define STRING_VENDOR \
1864 #define STRING_PRODUCT \
1865 "D\0C\0I\0 \0R\0o\0o\0t\0 \0H\0U\0B"
1867 USB_MAKE_STRING_DESC(STRING_VENDOR, uss820dci_vendor);
1868 USB_MAKE_STRING_DESC(STRING_PRODUCT, uss820dci_product);
1871 uss820dci_roothub_exec(struct usb_device *udev,
1872 struct usb_device_request *req, const void **pptr, uint16_t *plength)
1874 struct uss820dci_softc *sc = USS820_DCI_BUS2SC(udev->bus);
1881 USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED);
1884 ptr = (const void *)&sc->sc_hub_temp;
1888 value = UGETW(req->wValue);
1889 index = UGETW(req->wIndex);
1891 /* demultiplex the control request */
1893 switch (req->bmRequestType) {
1894 case UT_READ_DEVICE:
1895 switch (req->bRequest) {
1896 case UR_GET_DESCRIPTOR:
1897 goto tr_handle_get_descriptor;
1899 goto tr_handle_get_config;
1901 goto tr_handle_get_status;
1907 case UT_WRITE_DEVICE:
1908 switch (req->bRequest) {
1909 case UR_SET_ADDRESS:
1910 goto tr_handle_set_address;
1912 goto tr_handle_set_config;
1913 case UR_CLEAR_FEATURE:
1914 goto tr_valid; /* nop */
1915 case UR_SET_DESCRIPTOR:
1916 goto tr_valid; /* nop */
1917 case UR_SET_FEATURE:
1923 case UT_WRITE_ENDPOINT:
1924 switch (req->bRequest) {
1925 case UR_CLEAR_FEATURE:
1926 switch (UGETW(req->wValue)) {
1927 case UF_ENDPOINT_HALT:
1928 goto tr_handle_clear_halt;
1929 case UF_DEVICE_REMOTE_WAKEUP:
1930 goto tr_handle_clear_wakeup;
1935 case UR_SET_FEATURE:
1936 switch (UGETW(req->wValue)) {
1937 case UF_ENDPOINT_HALT:
1938 goto tr_handle_set_halt;
1939 case UF_DEVICE_REMOTE_WAKEUP:
1940 goto tr_handle_set_wakeup;
1945 case UR_SYNCH_FRAME:
1946 goto tr_valid; /* nop */
1952 case UT_READ_ENDPOINT:
1953 switch (req->bRequest) {
1955 goto tr_handle_get_ep_status;
1961 case UT_WRITE_INTERFACE:
1962 switch (req->bRequest) {
1963 case UR_SET_INTERFACE:
1964 goto tr_handle_set_interface;
1965 case UR_CLEAR_FEATURE:
1966 goto tr_valid; /* nop */
1967 case UR_SET_FEATURE:
1973 case UT_READ_INTERFACE:
1974 switch (req->bRequest) {
1975 case UR_GET_INTERFACE:
1976 goto tr_handle_get_interface;
1978 goto tr_handle_get_iface_status;
1984 case UT_WRITE_CLASS_INTERFACE:
1985 case UT_WRITE_VENDOR_INTERFACE:
1989 case UT_READ_CLASS_INTERFACE:
1990 case UT_READ_VENDOR_INTERFACE:
1994 case UT_WRITE_CLASS_DEVICE:
1995 switch (req->bRequest) {
1996 case UR_CLEAR_FEATURE:
1998 case UR_SET_DESCRIPTOR:
1999 case UR_SET_FEATURE:
2006 case UT_WRITE_CLASS_OTHER:
2007 switch (req->bRequest) {
2008 case UR_CLEAR_FEATURE:
2009 goto tr_handle_clear_port_feature;
2010 case UR_SET_FEATURE:
2011 goto tr_handle_set_port_feature;
2012 case UR_CLEAR_TT_BUFFER:
2022 case UT_READ_CLASS_OTHER:
2023 switch (req->bRequest) {
2024 case UR_GET_TT_STATE:
2025 goto tr_handle_get_tt_state;
2027 goto tr_handle_get_port_status;
2033 case UT_READ_CLASS_DEVICE:
2034 switch (req->bRequest) {
2035 case UR_GET_DESCRIPTOR:
2036 goto tr_handle_get_class_descriptor;
2038 goto tr_handle_get_class_status;
2049 tr_handle_get_descriptor:
2050 switch (value >> 8) {
2055 len = sizeof(uss820dci_devd);
2056 ptr = (const void *)&uss820dci_devd;
2058 case UDESC_DEVICE_QUALIFIER:
2062 len = sizeof(uss820dci_odevd);
2063 ptr = (const void *)&uss820dci_odevd;
2069 len = sizeof(uss820dci_confd);
2070 ptr = (const void *)&uss820dci_confd;
2073 switch (value & 0xff) {
2074 case 0: /* Language table */
2075 len = sizeof(usb_string_lang_en);
2076 ptr = (const void *)&usb_string_lang_en;
2079 case 1: /* Vendor */
2080 len = sizeof(uss820dci_vendor);
2081 ptr = (const void *)&uss820dci_vendor;
2084 case 2: /* Product */
2085 len = sizeof(uss820dci_product);
2086 ptr = (const void *)&uss820dci_product;
2097 tr_handle_get_config:
2099 sc->sc_hub_temp.wValue[0] = sc->sc_conf;
2102 tr_handle_get_status:
2104 USETW(sc->sc_hub_temp.wValue, UDS_SELF_POWERED);
2107 tr_handle_set_address:
2108 if (value & 0xFF00) {
2111 sc->sc_rt_addr = value;
2114 tr_handle_set_config:
2118 sc->sc_conf = value;
2121 tr_handle_get_interface:
2123 sc->sc_hub_temp.wValue[0] = 0;
2126 tr_handle_get_tt_state:
2127 tr_handle_get_class_status:
2128 tr_handle_get_iface_status:
2129 tr_handle_get_ep_status:
2131 USETW(sc->sc_hub_temp.wValue, 0);
2135 tr_handle_set_interface:
2136 tr_handle_set_wakeup:
2137 tr_handle_clear_wakeup:
2138 tr_handle_clear_halt:
2141 tr_handle_clear_port_feature:
2145 DPRINTFN(9, "UR_CLEAR_PORT_FEATURE on port %d\n", index);
2148 case UHF_PORT_SUSPEND:
2149 uss820dci_wakeup_peer(sc);
2152 case UHF_PORT_ENABLE:
2153 sc->sc_flags.port_enabled = 0;
2157 case UHF_PORT_INDICATOR:
2158 case UHF_C_PORT_ENABLE:
2159 case UHF_C_PORT_OVER_CURRENT:
2160 case UHF_C_PORT_RESET:
2163 case UHF_PORT_POWER:
2164 sc->sc_flags.port_powered = 0;
2165 uss820dci_pull_down(sc);
2167 case UHF_C_PORT_CONNECTION:
2168 sc->sc_flags.change_connect = 0;
2170 case UHF_C_PORT_SUSPEND:
2171 sc->sc_flags.change_suspend = 0;
2174 err = USB_ERR_IOERROR;
2179 tr_handle_set_port_feature:
2183 DPRINTFN(9, "UR_SET_PORT_FEATURE\n");
2186 case UHF_PORT_ENABLE:
2187 sc->sc_flags.port_enabled = 1;
2189 case UHF_PORT_SUSPEND:
2190 case UHF_PORT_RESET:
2192 case UHF_PORT_INDICATOR:
2195 case UHF_PORT_POWER:
2196 sc->sc_flags.port_powered = 1;
2199 err = USB_ERR_IOERROR;
2204 tr_handle_get_port_status:
2206 DPRINTFN(9, "UR_GET_PORT_STATUS\n");
2211 if (sc->sc_flags.status_vbus) {
2212 uss820dci_pull_up(sc);
2214 uss820dci_pull_down(sc);
2217 /* Select FULL-speed and Device Side Mode */
2219 value = UPS_PORT_MODE_DEVICE;
2221 if (sc->sc_flags.port_powered) {
2222 value |= UPS_PORT_POWER;
2224 if (sc->sc_flags.port_enabled) {
2225 value |= UPS_PORT_ENABLED;
2227 if (sc->sc_flags.status_vbus &&
2228 sc->sc_flags.status_bus_reset) {
2229 value |= UPS_CURRENT_CONNECT_STATUS;
2231 if (sc->sc_flags.status_suspend) {
2232 value |= UPS_SUSPEND;
2234 USETW(sc->sc_hub_temp.ps.wPortStatus, value);
2238 if (sc->sc_flags.change_connect) {
2239 value |= UPS_C_CONNECT_STATUS;
2241 if (sc->sc_flags.change_suspend) {
2242 value |= UPS_C_SUSPEND;
2244 USETW(sc->sc_hub_temp.ps.wPortChange, value);
2245 len = sizeof(sc->sc_hub_temp.ps);
2248 tr_handle_get_class_descriptor:
2252 ptr = (const void *)&uss820dci_hubd;
2253 len = sizeof(uss820dci_hubd);
2257 err = USB_ERR_STALLED;
2266 uss820dci_xfer_setup(struct usb_setup_params *parm)
2268 const struct usb_hw_ep_profile *pf;
2269 struct uss820dci_softc *sc;
2270 struct usb_xfer *xfer;
2276 sc = USS820_DCI_BUS2SC(parm->udev->bus);
2277 xfer = parm->curr_xfer;
2280 * NOTE: This driver does not use any of the parameters that
2281 * are computed from the following values. Just set some
2282 * reasonable dummies:
2284 parm->hc_max_packet_size = 0x500;
2285 parm->hc_max_packet_count = 1;
2286 parm->hc_max_frame_size = 0x500;
2288 usbd_transfer_setup_sub(parm);
2291 * compute maximum number of TDs
2293 if (parm->methods == &uss820dci_device_ctrl_methods) {
2295 ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC */ ;
2297 } else if (parm->methods == &uss820dci_device_bulk_methods) {
2299 ntd = xfer->nframes + 1 /* SYNC */ ;
2301 } else if (parm->methods == &uss820dci_device_intr_methods) {
2303 ntd = xfer->nframes + 1 /* SYNC */ ;
2305 } else if (parm->methods == &uss820dci_device_isoc_fs_methods) {
2307 ntd = xfer->nframes + 1 /* SYNC */ ;
2315 * check if "usbd_transfer_setup_sub" set an error
2321 * allocate transfer descriptors
2330 ep_no = xfer->endpointno & UE_ADDR;
2331 uss820dci_get_hw_ep_profile(parm->udev, &pf, ep_no);
2334 /* should not happen */
2335 parm->err = USB_ERR_INVAL;
2344 parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1));
2346 for (n = 0; n != ntd; n++) {
2348 struct uss820dci_td *td;
2352 td = USB_ADD_BYTES(parm->buf, parm->size[0]);
2355 td->max_packet_size = xfer->max_packet_size;
2356 td->ep_index = ep_no;
2357 if (pf->support_multi_buffer &&
2358 (parm->methods != &uss820dci_device_ctrl_methods)) {
2359 td->support_multi_buffer = 1;
2361 td->obj_next = last_obj;
2365 parm->size[0] += sizeof(*td);
2368 xfer->td_start[0] = last_obj;
2372 uss820dci_xfer_unsetup(struct usb_xfer *xfer)
2378 uss820dci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc,
2379 struct usb_endpoint *ep)
2381 struct uss820dci_softc *sc = USS820_DCI_BUS2SC(udev->bus);
2383 DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d (%d)\n",
2385 edesc->bEndpointAddress, udev->flags.usb_mode,
2388 if (udev->device_index != sc->sc_rt_addr) {
2390 if (udev->speed != USB_SPEED_FULL) {
2394 switch (edesc->bmAttributes & UE_XFERTYPE) {
2396 ep->methods = &uss820dci_device_ctrl_methods;
2399 ep->methods = &uss820dci_device_intr_methods;
2401 case UE_ISOCHRONOUS:
2402 ep->methods = &uss820dci_device_isoc_fs_methods;
2405 ep->methods = &uss820dci_device_bulk_methods;
2415 uss820dci_set_hw_power_sleep(struct usb_bus *bus, uint32_t state)
2417 struct uss820dci_softc *sc = USS820_DCI_BUS2SC(bus);
2420 case USB_HW_POWER_SUSPEND:
2421 uss820dci_suspend(sc);
2423 case USB_HW_POWER_SHUTDOWN:
2424 uss820dci_uninit(sc);
2426 case USB_HW_POWER_RESUME:
2427 uss820dci_resume(sc);
2434 static const struct usb_bus_methods uss820dci_bus_methods =
2436 .endpoint_init = &uss820dci_ep_init,
2437 .xfer_setup = &uss820dci_xfer_setup,
2438 .xfer_unsetup = &uss820dci_xfer_unsetup,
2439 .get_hw_ep_profile = &uss820dci_get_hw_ep_profile,
2440 .xfer_stall = &uss820dci_xfer_stall,
2441 .set_stall = &uss820dci_set_stall,
2442 .clear_stall = &uss820dci_clear_stall,
2443 .roothub_exec = &uss820dci_roothub_exec,
2444 .xfer_poll = &uss820dci_do_poll,
2445 .set_hw_power_sleep = uss820dci_set_hw_power_sleep,