diff options
author | thompsa <thompsa@FreeBSD.org> | 2009-03-20 21:57:54 +0000 |
---|---|---|
committer | thompsa <thompsa@FreeBSD.org> | 2009-03-20 21:57:54 +0000 |
commit | ca147f2b35e362c05c7b73c7b8b6c6fc58a69744 (patch) | |
tree | 6fbd12d5f67db5e9aab7afad8815466e2de7d1f5 /sys | |
parent | 79c72751b7f97009077ff9f01b67a0794ce358eb (diff) | |
download | FreeBSD-src-ca147f2b35e362c05c7b73c7b8b6c6fc58a69744.zip FreeBSD-src-ca147f2b35e362c05c7b73c7b8b6c6fc58a69744.tar.gz |
MFp4 //depot/projects/usb @159479,159502,159516,159522,159529
Workaround for buggy USB hardware not handling new SETUP packet before STATUS
stage is complete, this allows xfers to endpoint0 to return a short frame.
Submitted by: Hans Petter Selasky
Reported by: me
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/usb/controller/at91dci.c | 75 | ||||
-rw-r--r-- | sys/dev/usb/controller/at91dci_atmelarm.c | 8 | ||||
-rw-r--r-- | sys/dev/usb/controller/atmegadci.c | 73 | ||||
-rw-r--r-- | sys/dev/usb/controller/atmegadci_atmelarm.c | 2 | ||||
-rw-r--r-- | sys/dev/usb/controller/ehci.c | 43 | ||||
-rw-r--r-- | sys/dev/usb/controller/ehci_ixp4xx.c | 2 | ||||
-rw-r--r-- | sys/dev/usb/controller/ehci_mbus.c | 2 | ||||
-rw-r--r-- | sys/dev/usb/controller/ehci_pci.c | 4 | ||||
-rw-r--r-- | sys/dev/usb/controller/musb_otg.c | 37 | ||||
-rw-r--r-- | sys/dev/usb/controller/musb_otg_atmelarm.c | 4 | ||||
-rw-r--r-- | sys/dev/usb/controller/ohci.c | 56 | ||||
-rw-r--r-- | sys/dev/usb/controller/ohci_atmelarm.c | 4 | ||||
-rw-r--r-- | sys/dev/usb/controller/ohci_pci.c | 4 | ||||
-rw-r--r-- | sys/dev/usb/controller/uhci.c | 70 | ||||
-rw-r--r-- | sys/dev/usb/controller/uhci_pci.c | 4 | ||||
-rw-r--r-- | sys/dev/usb/controller/uss820dci.c | 62 | ||||
-rw-r--r-- | sys/dev/usb/controller/uss820dci_atmelarm.c | 4 |
17 files changed, 285 insertions, 169 deletions
diff --git a/sys/dev/usb/controller/at91dci.c b/sys/dev/usb/controller/at91dci.c index ae18c28..3fc2953 100644 --- a/sys/dev/usb/controller/at91dci.c +++ b/sys/dev/usb/controller/at91dci.c @@ -887,8 +887,8 @@ at91dci_setup_standard_chain(struct usb2_xfer *xfer) temp.td = NULL; temp.td_next = xfer->td_start[0]; - temp.setup_alt_next = xfer->flags_int.short_frames_ok; temp.offset = 0; + temp.setup_alt_next = xfer->flags_int.short_frames_ok; sc = AT9100_DCI_BUS2SC(xfer->xroot->bus); ep_no = (xfer->endpoint & UE_ADDR); @@ -902,6 +902,12 @@ at91dci_setup_standard_chain(struct usb2_xfer *xfer) temp.len = xfer->frlengths[0]; temp.pc = xfer->frbuffers + 0; temp.short_pkt = temp.len ? 1 : 0; + /* check for last frame */ + if (xfer->nframes == 1) { + /* no STATUS stage yet, SETUP is last */ + if (xfer->flags_int.control_act) + temp.setup_alt_next = 0; + } at91dci_setup_standard_chain_sub(&temp); } @@ -933,7 +939,13 @@ at91dci_setup_standard_chain(struct usb2_xfer *xfer) x++; if (x == xfer->nframes) { - temp.setup_alt_next = 0; + if (xfer->flags_int.control_xfr) { + if (xfer->flags_int.control_act) { + temp.setup_alt_next = 0; + } + } else { + temp.setup_alt_next = 0; + } } if (temp.len == 0) { @@ -958,47 +970,46 @@ at91dci_setup_standard_chain(struct usb2_xfer *xfer) } } - /* always setup a valid "pc" pointer for status and sync */ - temp.pc = xfer->frbuffers + 0; - - /* check if we need to sync */ - if (need_sync && xfer->flags_int.control_xfr) { + /* check for control transfer */ + if (xfer->flags_int.control_xfr) { - /* we need a SYNC point after TX */ - temp.func = &at91dci_data_tx_sync; + /* always setup a valid "pc" pointer for status and sync */ + temp.pc = xfer->frbuffers + 0; temp.len = 0; temp.short_pkt = 0; + temp.setup_alt_next = 0; - at91dci_setup_standard_chain_sub(&temp); - } - /* check if we should append a status stage */ - if (xfer->flags_int.control_xfr && - !xfer->flags_int.control_act) { - - /* - * Send a DATA1 message and invert the current - * endpoint direction. - */ - if (xfer->endpoint & UE_DIR_IN) { - temp.func = &at91dci_data_rx; - need_sync = 0; - } else { - temp.func = &at91dci_data_tx; - need_sync = 1; - } - temp.len = 0; - temp.short_pkt = 0; - - at91dci_setup_standard_chain_sub(&temp); + /* check if we need to sync */ if (need_sync) { /* we need a SYNC point after TX */ temp.func = &at91dci_data_tx_sync; - temp.len = 0; - temp.short_pkt = 0; + at91dci_setup_standard_chain_sub(&temp); + } + + /* check if we should append a status stage */ + if (!xfer->flags_int.control_act) { + + /* + * Send a DATA1 message and invert the current + * endpoint direction. + */ + if (xfer->endpoint & UE_DIR_IN) { + temp.func = &at91dci_data_rx; + need_sync = 0; + } else { + temp.func = &at91dci_data_tx; + need_sync = 1; + } at91dci_setup_standard_chain_sub(&temp); + if (need_sync) { + /* we need a SYNC point after TX */ + temp.func = &at91dci_data_tx_sync; + at91dci_setup_standard_chain_sub(&temp); + } } } + /* must have at least one frame! */ td = temp.td; xfer->td_transfer_last = td; diff --git a/sys/dev/usb/controller/at91dci_atmelarm.c b/sys/dev/usb/controller/at91dci_atmelarm.c index 164f9bd..7f552d9 100644 --- a/sys/dev/usb/controller/at91dci_atmelarm.c +++ b/sys/dev/usb/controller/at91dci_atmelarm.c @@ -204,10 +204,10 @@ at91_udp_attach(device_t dev) #if (__FreeBSD_version >= 700031) err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (void *)at91dci_interrupt, sc, &sc->sc_dci.sc_intr_hdl); + NULL, (driver_intr_t *)at91dci_interrupt, sc, &sc->sc_dci.sc_intr_hdl); #else err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - (void *)at91dci_interrupt, sc, &sc->sc_dci.sc_intr_hdl); + (driver_intr_t *)at91dci_interrupt, sc, &sc->sc_dci.sc_intr_hdl); #endif if (err) { sc->sc_dci.sc_intr_hdl = NULL; @@ -215,10 +215,10 @@ at91_udp_attach(device_t dev) } #if (__FreeBSD_version >= 700031) err = bus_setup_intr(dev, sc->sc_vbus_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (void *)at91_vbus_poll, sc, &sc->sc_vbus_intr_hdl); + NULL, (driver_intr_t *)at91_vbus_poll, sc, &sc->sc_vbus_intr_hdl); #else err = bus_setup_intr(dev, sc->sc_vbus_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - (void *)at91_vbus_poll, sc, &sc->sc_vbus_intr_hdl); + (driver_intr_t *)at91_vbus_poll, sc, &sc->sc_vbus_intr_hdl); #endif if (err) { sc->sc_vbus_intr_hdl = NULL; diff --git a/sys/dev/usb/controller/atmegadci.c b/sys/dev/usb/controller/atmegadci.c index 55ab088..8eea576 100644 --- a/sys/dev/usb/controller/atmegadci.c +++ b/sys/dev/usb/controller/atmegadci.c @@ -791,8 +791,8 @@ atmegadci_setup_standard_chain(struct usb2_xfer *xfer) temp.td = NULL; temp.td_next = xfer->td_start[0]; - temp.setup_alt_next = xfer->flags_int.short_frames_ok; temp.offset = 0; + temp.setup_alt_next = xfer->flags_int.short_frames_ok; sc = ATMEGA_BUS2SC(xfer->xroot->bus); ep_no = (xfer->endpoint & UE_ADDR); @@ -806,6 +806,12 @@ atmegadci_setup_standard_chain(struct usb2_xfer *xfer) temp.len = xfer->frlengths[0]; temp.pc = xfer->frbuffers + 0; temp.short_pkt = temp.len ? 1 : 0; + /* check for last frame */ + if (xfer->nframes == 1) { + /* no STATUS stage yet, SETUP is last */ + if (xfer->flags_int.control_act) + temp.setup_alt_next = 0; + } atmegadci_setup_standard_chain_sub(&temp); } @@ -837,7 +843,13 @@ atmegadci_setup_standard_chain(struct usb2_xfer *xfer) x++; if (x == xfer->nframes) { - temp.setup_alt_next = 0; + if (xfer->flags_int.control_xfr) { + if (xfer->flags_int.control_act) { + temp.setup_alt_next = 0; + } + } else { + temp.setup_alt_next = 0; + } } if (temp.len == 0) { @@ -862,45 +874,42 @@ atmegadci_setup_standard_chain(struct usb2_xfer *xfer) } } - /* always setup a valid "pc" pointer for status and sync */ - temp.pc = xfer->frbuffers + 0; - - /* check if we need to sync */ - if (need_sync && xfer->flags_int.control_xfr) { - - /* we need a SYNC point after TX */ - temp.func = &atmegadci_data_tx_sync; - temp.len = 0; - temp.short_pkt = 0; - - atmegadci_setup_standard_chain_sub(&temp); - } - /* check if we should append a status stage */ - if (xfer->flags_int.control_xfr && - !xfer->flags_int.control_act) { + if (xfer->flags_int.control_xfr) { - /* - * Send a DATA1 message and invert the current - * endpoint direction. - */ - if (xfer->endpoint & UE_DIR_IN) { - temp.func = &atmegadci_data_rx; - need_sync = 0; - } else { - temp.func = &atmegadci_data_tx; - need_sync = 1; - } + /* always setup a valid "pc" pointer for status and sync */ + temp.pc = xfer->frbuffers + 0; temp.len = 0; temp.short_pkt = 0; + temp.setup_alt_next = 0; - atmegadci_setup_standard_chain_sub(&temp); + /* check if we need to sync */ if (need_sync) { /* we need a SYNC point after TX */ temp.func = &atmegadci_data_tx_sync; - temp.len = 0; - temp.short_pkt = 0; + atmegadci_setup_standard_chain_sub(&temp); + } + + /* check if we should append a status stage */ + if (!xfer->flags_int.control_act) { + + /* + * Send a DATA1 message and invert the current + * endpoint direction. + */ + if (xfer->endpoint & UE_DIR_IN) { + temp.func = &atmegadci_data_rx; + need_sync = 0; + } else { + temp.func = &atmegadci_data_tx; + need_sync = 1; + } atmegadci_setup_standard_chain_sub(&temp); + if (need_sync) { + /* we need a SYNC point after TX */ + temp.func = &atmegadci_data_tx_sync; + atmegadci_setup_standard_chain_sub(&temp); + } } } /* must have at least one frame! */ diff --git a/sys/dev/usb/controller/atmegadci_atmelarm.c b/sys/dev/usb/controller/atmegadci_atmelarm.c index 1fc929f..89d2588 100644 --- a/sys/dev/usb/controller/atmegadci_atmelarm.c +++ b/sys/dev/usb/controller/atmegadci_atmelarm.c @@ -113,7 +113,7 @@ atmegadci_attach(device_t dev) device_set_ivars(sc->sc_otg.sc_bus.bdev, &sc->sc_otg.sc_bus); err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (void *)atmegadci_interrupt, sc, &sc->sc_otg.sc_intr_hdl); + NULL, (driver_intr_t *)atmegadci_interrupt, sc, &sc->sc_otg.sc_intr_hdl); if (err) { sc->sc_otg.sc_intr_hdl = NULL; goto error; diff --git a/sys/dev/usb/controller/ehci.c b/sys/dev/usb/controller/ehci.c index b82fcd5..cc17d43 100644 --- a/sys/dev/usb/controller/ehci.c +++ b/sys/dev/usb/controller/ehci.c @@ -117,7 +117,7 @@ struct ehci_std_temp { uint8_t shortpkt; uint8_t auto_data_toggle; uint8_t setup_alt_next; - uint8_t short_frames_ok; + uint8_t last_frame; }; void @@ -1546,10 +1546,12 @@ ehci_setup_standard_chain_sub(struct ehci_std_temp *temp) uint32_t buf_offset; uint32_t average; uint32_t len_old; + uint32_t terminate; uint8_t shortpkt_old; uint8_t precompute; - qtd_altnext = htohc32(temp->sc, EHCI_LINK_TERMINATE); + terminate = htohc32(temp->sc, EHCI_LINK_TERMINATE); + qtd_altnext = terminate; td_alt_next = NULL; buf_offset = 0; shortpkt_old = temp->shortpkt; @@ -1696,14 +1698,17 @@ restart: precompute = 0; /* setup alt next pointer, if any */ - if (temp->short_frames_ok) { - if (temp->setup_alt_next) { - td_alt_next = td_next; - qtd_altnext = td_next->qtd_self; - } + if (temp->last_frame) { + td_alt_next = NULL; + qtd_altnext = terminate; } else { /* we use this field internally */ td_alt_next = td_next; + if (temp->setup_alt_next) { + qtd_altnext = td_next->qtd_self; + } else { + qtd_altnext = terminate; + } } /* restore */ @@ -1746,8 +1751,8 @@ ehci_setup_standard_chain(struct usb2_xfer *xfer, ehci_qh_t **qh_last) temp.td = NULL; temp.td_next = td; temp.qtd_status = 0; + temp.last_frame = 0; temp.setup_alt_next = xfer->flags_int.short_frames_ok; - temp.short_frames_ok = xfer->flags_int.short_frames_ok; if (xfer->flags_int.control_xfr) { if (xfer->pipe->toggle_next) { @@ -1780,7 +1785,14 @@ ehci_setup_standard_chain(struct usb2_xfer *xfer, ehci_qh_t **qh_last) temp.len = xfer->frlengths[0]; temp.pc = xfer->frbuffers + 0; temp.shortpkt = temp.len ? 1 : 0; - + /* check for last frame */ + if (xfer->nframes == 1) { + /* no STATUS stage yet, SETUP is last */ + if (xfer->flags_int.control_act) { + temp.last_frame = 1; + temp.setup_alt_next = 0; + } + } ehci_setup_standard_chain_sub(&temp); } x = 1; @@ -1798,7 +1810,16 @@ ehci_setup_standard_chain(struct usb2_xfer *xfer, ehci_qh_t **qh_last) x++; if (x == xfer->nframes) { - temp.setup_alt_next = 0; + if (xfer->flags_int.control_xfr) { + /* no STATUS stage yet, DATA is last */ + if (xfer->flags_int.control_act) { + temp.last_frame = 1; + temp.setup_alt_next = 0; + } + } else { + temp.last_frame = 1; + temp.setup_alt_next = 0; + } } /* keep previous data toggle and error count */ @@ -1855,6 +1876,8 @@ ehci_setup_standard_chain(struct usb2_xfer *xfer, ehci_qh_t **qh_last) temp.len = 0; temp.pc = NULL; temp.shortpkt = 0; + temp.last_frame = 1; + temp.setup_alt_next = 0; ehci_setup_standard_chain_sub(&temp); } diff --git a/sys/dev/usb/controller/ehci_ixp4xx.c b/sys/dev/usb/controller/ehci_ixp4xx.c index 5ce8e68..1ba32f6 100644 --- a/sys/dev/usb/controller/ehci_ixp4xx.c +++ b/sys/dev/usb/controller/ehci_ixp4xx.c @@ -189,7 +189,7 @@ ehci_ixp_attach(device_t self) err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (void *)(void *)ehci_interrupt, sc, &sc->sc_intr_hdl); + NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl); if (err) { device_printf(self, "Could not setup irq, %d\n", err); sc->sc_intr_hdl = NULL; diff --git a/sys/dev/usb/controller/ehci_mbus.c b/sys/dev/usb/controller/ehci_mbus.c index 31431a1..4dfbe9b 100644 --- a/sys/dev/usb/controller/ehci_mbus.c +++ b/sys/dev/usb/controller/ehci_mbus.c @@ -210,7 +210,7 @@ ehci_mbus_attach(device_t self) MV_USB_DEVICE_UNDERFLOW); err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (void *)(void *)ehci_interrupt, sc, &sc->sc_intr_hdl); + NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl); if (err) { device_printf(self, "Could not setup irq, %d\n", err); sc->sc_intr_hdl = NULL; diff --git a/sys/dev/usb/controller/ehci_pci.c b/sys/dev/usb/controller/ehci_pci.c index f739c3a..f1b48f2 100644 --- a/sys/dev/usb/controller/ehci_pci.c +++ b/sys/dev/usb/controller/ehci_pci.c @@ -338,10 +338,10 @@ ehci_pci_attach(device_t self) #if (__FreeBSD_version >= 700031) err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (void *)(void *)ehci_interrupt, sc, &sc->sc_intr_hdl); + NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl); #else err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - (void *)(void *)ehci_interrupt, sc, &sc->sc_intr_hdl); + (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl); #endif if (err) { device_printf(self, "Could not setup irq, %d\n", err); diff --git a/sys/dev/usb/controller/musb_otg.c b/sys/dev/usb/controller/musb_otg.c index 9ffafa3..6e41bc6 100644 --- a/sys/dev/usb/controller/musb_otg.c +++ b/sys/dev/usb/controller/musb_otg.c @@ -1132,8 +1132,8 @@ musbotg_setup_standard_chain(struct usb2_xfer *xfer) temp.td = NULL; temp.td_next = xfer->td_start[0]; - temp.setup_alt_next = xfer->flags_int.short_frames_ok; temp.offset = 0; + temp.setup_alt_next = xfer->flags_int.short_frames_ok; sc = MUSBOTG_BUS2SC(xfer->xroot->bus); ep_no = (xfer->endpoint & UE_ADDR); @@ -1180,7 +1180,13 @@ musbotg_setup_standard_chain(struct usb2_xfer *xfer) x++; if (x == xfer->nframes) { - temp.setup_alt_next = 0; + if (xfer->flags_int.control_xfr) { + if (xfer->flags_int.control_act) { + temp.setup_alt_next = 0; + } + } else { + temp.setup_alt_next = 0; + } } if (temp.len == 0) { @@ -1205,23 +1211,24 @@ musbotg_setup_standard_chain(struct usb2_xfer *xfer) } } - /* always setup a valid "pc" pointer for status and sync */ - temp.pc = xfer->frbuffers + 0; - - /* check if we should append a status stage */ - - if (xfer->flags_int.control_xfr && - !xfer->flags_int.control_act) { + /* check for control transfer */ + if (xfer->flags_int.control_xfr) { - /* - * Send a DATA1 message and invert the current - * endpoint direction. - */ - temp.func = &musbotg_setup_status; + /* always setup a valid "pc" pointer for status and sync */ + temp.pc = xfer->frbuffers + 0; temp.len = 0; temp.short_pkt = 0; + temp.setup_alt_next = 0; - musbotg_setup_standard_chain_sub(&temp); + /* check if we should append a status stage */ + if (!xfer->flags_int.control_act) { + /* + * Send a DATA1 message and invert the current + * endpoint direction. + */ + temp.func = &musbotg_setup_status; + musbotg_setup_standard_chain_sub(&temp); + } } /* must have at least one frame! */ td = temp.td; diff --git a/sys/dev/usb/controller/musb_otg_atmelarm.c b/sys/dev/usb/controller/musb_otg_atmelarm.c index 38fa304..267758d 100644 --- a/sys/dev/usb/controller/musb_otg_atmelarm.c +++ b/sys/dev/usb/controller/musb_otg_atmelarm.c @@ -130,10 +130,10 @@ musbotg_attach(device_t dev) #if (__FreeBSD_version >= 700031) err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (void *)musbotg_interrupt, sc, &sc->sc_otg.sc_intr_hdl); + NULL, (driver_intr_t *)musbotg_interrupt, sc, &sc->sc_otg.sc_intr_hdl); #else err = bus_setup_intr(dev, sc->sc_otg.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - (void *)musbotg_interrupt, sc, &sc->sc_otg.sc_intr_hdl); + (driver_intr_t *)musbotg_interrupt, sc, &sc->sc_otg.sc_intr_hdl); #endif if (err) { sc->sc_otg.sc_intr_hdl = NULL; diff --git a/sys/dev/usb/controller/ohci.c b/sys/dev/usb/controller/ohci.c index 9a25b3a..ad203e9 100644 --- a/sys/dev/usb/controller/ohci.c +++ b/sys/dev/usb/controller/ohci.c @@ -115,7 +115,7 @@ struct ohci_std_temp { uint16_t max_frame_size; uint8_t shortpkt; uint8_t setup_alt_next; - uint8_t short_frames_ok; + uint8_t last_frame; }; static struct ohci_hcca * @@ -1020,6 +1020,23 @@ ohci_check_transfer_sub(struct usb2_xfer *xfer) usb2_pc_cpu_flush(ed->page_cache); DPRINTFN(13, "xfer=%p following alt next\n", xfer); + + /* + * Make sure that the OHCI re-scans the schedule by + * writing the BLF and CLF bits: + */ + + if (xfer->xroot->udev->pwr_save.suspended) { + /* nothing to do */ + } else if (xfer->pipe->methods == &ohci_device_bulk_methods) { + ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); + + OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF); + } else if (xfer->pipe->methods == &ohci_device_ctrl_methods) { + ohci_softc_t *sc = OHCI_BUS2SC(xfer->xroot->bus); + + OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); + } } } @@ -1034,7 +1051,6 @@ static uint8_t ohci_check_transfer(struct usb2_xfer *xfer) { ohci_ed_t *ed; - uint32_t ed_flags; uint32_t ed_headp; uint32_t ed_tailp; @@ -1043,12 +1059,10 @@ ohci_check_transfer(struct usb2_xfer *xfer) ed = xfer->qh_start[xfer->flags_int.curr_dma_set]; usb2_pc_cpu_invalidate(ed->page_cache); - ed_flags = le32toh(ed->ed_flags); ed_headp = le32toh(ed->ed_headp); ed_tailp = le32toh(ed->ed_tailp); - if ((ed_flags & OHCI_ED_SKIP) || - (ed_headp & OHCI_HALTED) || + if ((ed_headp & OHCI_HALTED) || (((ed_headp ^ ed_tailp) & (~0xF)) == 0)) { if (xfer->pipe->methods == &ohci_device_isoc_methods) { /* isochronous transfer */ @@ -1379,10 +1393,9 @@ restart: precompute = 0; /* setup alt next pointer, if any */ - if (temp->short_frames_ok) { - if (temp->setup_alt_next) { - td_alt_next = td_next; - } + if (temp->last_frame) { + /* no alternate next */ + td_alt_next = NULL; } else { /* we use this field internally */ td_alt_next = td_next; @@ -1425,8 +1438,8 @@ ohci_setup_standard_chain(struct usb2_xfer *xfer, ohci_ed_t **ed_last) temp.td = NULL; temp.td_next = td; + temp.last_frame = 0; temp.setup_alt_next = xfer->flags_int.short_frames_ok; - temp.short_frames_ok = xfer->flags_int.short_frames_ok; methods = xfer->pipe->methods; @@ -1441,7 +1454,14 @@ ohci_setup_standard_chain(struct usb2_xfer *xfer, ohci_ed_t **ed_last) temp.len = xfer->frlengths[0]; temp.pc = xfer->frbuffers + 0; temp.shortpkt = temp.len ? 1 : 0; - + /* check for last frame */ + if (xfer->nframes == 1) { + /* no STATUS stage yet, SETUP is last */ + if (xfer->flags_int.control_act) { + temp.last_frame = 1; + temp.setup_alt_next = 0; + } + } ohci_setup_standard_chain_sub(&temp); /* @@ -1482,7 +1502,16 @@ ohci_setup_standard_chain(struct usb2_xfer *xfer, ohci_ed_t **ed_last) x++; if (x == xfer->nframes) { - temp.setup_alt_next = 0; + if (xfer->flags_int.control_xfr) { + /* no STATUS stage yet, DATA is last */ + if (xfer->flags_int.control_act) { + temp.last_frame = 1; + temp.setup_alt_next = 0; + } + } else { + temp.last_frame = 1; + temp.setup_alt_next = 0; + } } if (temp.len == 0) { @@ -1523,11 +1552,14 @@ ohci_setup_standard_chain(struct usb2_xfer *xfer, ohci_ed_t **ed_last) temp.len = 0; temp.pc = NULL; temp.shortpkt = 0; + temp.last_frame = 1; + temp.setup_alt_next = 0; ohci_setup_standard_chain_sub(&temp); } td = temp.td; + /* Ensure that last TD is terminating: */ td->td_next = htole32(OHCI_TD_NEXT_END); td->td_flags &= ~htole32(OHCI_TD_INTR_MASK); td->td_flags |= htole32(OHCI_TD_SET_DI(1)); diff --git a/sys/dev/usb/controller/ohci_atmelarm.c b/sys/dev/usb/controller/ohci_atmelarm.c index 34826e0..f8bbfcd 100644 --- a/sys/dev/usb/controller/ohci_atmelarm.c +++ b/sys/dev/usb/controller/ohci_atmelarm.c @@ -111,10 +111,10 @@ ohci_atmelarm_attach(device_t dev) #if (__FreeBSD_version >= 700031) err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (void *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl); + NULL, (driver_intr_t *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl); #else err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - (void *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl); + (driver_intr_t *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl); #endif if (err) { sc->sc_ohci.sc_intr_hdl = NULL; diff --git a/sys/dev/usb/controller/ohci_pci.c b/sys/dev/usb/controller/ohci_pci.c index fec8acd..d41df69 100644 --- a/sys/dev/usb/controller/ohci_pci.c +++ b/sys/dev/usb/controller/ohci_pci.c @@ -289,10 +289,10 @@ ohci_pci_attach(device_t self) #if (__FreeBSD_version >= 700031) err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (void *)(void *)ohci_interrupt, sc, &sc->sc_intr_hdl); + NULL, (driver_intr_t *)ohci_interrupt, sc, &sc->sc_intr_hdl); #else err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - (void *)(void *)ohci_interrupt, sc, &sc->sc_intr_hdl); + (driver_intr_t *)ohci_interrupt, sc, &sc->sc_intr_hdl); #endif if (err) { device_printf(self, "Could not setup irq, %d\n", err); diff --git a/sys/dev/usb/controller/uhci.c b/sys/dev/usb/controller/uhci.c index fcf1a4a..7ed55db 100644 --- a/sys/dev/usb/controller/uhci.c +++ b/sys/dev/usb/controller/uhci.c @@ -124,7 +124,7 @@ struct uhci_std_temp { uint16_t max_frame_size; uint8_t shortpkt; uint8_t setup_alt_next; - uint8_t short_frames_ok; + uint8_t last_frame; }; extern struct usb2_bus_methods uhci_bus_methods; @@ -1253,30 +1253,33 @@ uhci_check_transfer_sub(struct usb2_xfer *xfer) td_self = td->td_self; td_alt_next = td->alt_next; - if ((td->td_token ^ td_token) & htole32(UHCI_TD_SET_DT(1))) { + if (xfer->flags_int.control_xfr) + goto skip; /* don't touch the DT value! */ - /* - * The data toggle is wrong and - * we need to switch it ! - */ + if (!((td->td_token ^ td_token) & htole32(UHCI_TD_SET_DT(1)))) + goto skip; /* data toggle has correct value */ - while (1) { + /* + * The data toggle is wrong and we need to toggle it ! + */ + while (1) { - td->td_token ^= htole32(UHCI_TD_SET_DT(1)); - usb2_pc_cpu_flush(td->page_cache); + td->td_token ^= htole32(UHCI_TD_SET_DT(1)); + usb2_pc_cpu_flush(td->page_cache); - if (td == xfer->td_transfer_last) { - /* last transfer */ - break; - } - td = td->obj_next; + if (td == xfer->td_transfer_last) { + /* last transfer */ + break; + } + td = td->obj_next; - if (td->alt_next != td_alt_next) { - /* next frame */ - break; - } + if (td->alt_next != td_alt_next) { + /* next frame */ + break; } } +skip: + /* update the QH */ qh->qh_e_next = td_self; usb2_pc_cpu_flush(qh->page_cache); @@ -1631,10 +1634,8 @@ restart: precompute = 0; /* setup alt next pointer, if any */ - if (temp->short_frames_ok) { - if (temp->setup_alt_next) { - td_alt_next = td_next; - } + if (temp->last_frame) { + td_alt_next = NULL; } else { /* we use this field internally */ td_alt_next = td_next; @@ -1673,8 +1674,8 @@ uhci_setup_standard_chain(struct usb2_xfer *xfer) temp.td = NULL; temp.td_next = td; + temp.last_frame = 0; temp.setup_alt_next = xfer->flags_int.short_frames_ok; - temp.short_frames_ok = xfer->flags_int.short_frames_ok; uhci_mem_layout_init(&temp.ml, xfer); @@ -1707,7 +1708,14 @@ uhci_setup_standard_chain(struct usb2_xfer *xfer) temp.len = xfer->frlengths[0]; temp.ml.buf_pc = xfer->frbuffers + 0; temp.shortpkt = temp.len ? 1 : 0; - + /* check for last frame */ + if (xfer->nframes == 1) { + /* no STATUS stage yet, SETUP is last */ + if (xfer->flags_int.control_act) { + temp.last_frame = 1; + temp.setup_alt_next = 0; + } + } uhci_setup_standard_chain_sub(&temp); } x = 1; @@ -1725,7 +1733,16 @@ uhci_setup_standard_chain(struct usb2_xfer *xfer) x++; if (x == xfer->nframes) { - temp.setup_alt_next = 0; + if (xfer->flags_int.control_xfr) { + /* no STATUS stage yet, DATA is last */ + if (xfer->flags_int.control_act) { + temp.last_frame = 1; + temp.setup_alt_next = 0; + } + } else { + temp.last_frame = 1; + temp.setup_alt_next = 0; + } } /* * Keep previous data toggle, @@ -1780,11 +1797,14 @@ uhci_setup_standard_chain(struct usb2_xfer *xfer) temp.len = 0; temp.ml.buf_pc = NULL; temp.shortpkt = 0; + temp.last_frame = 1; + temp.setup_alt_next = 0; uhci_setup_standard_chain_sub(&temp); } td = temp.td; + /* Ensure that last TD is terminating: */ td->td_next = htole32(UHCI_PTR_T); /* set interrupt bit */ diff --git a/sys/dev/usb/controller/uhci_pci.c b/sys/dev/usb/controller/uhci_pci.c index 379841b..50a049c 100644 --- a/sys/dev/usb/controller/uhci_pci.c +++ b/sys/dev/usb/controller/uhci_pci.c @@ -323,10 +323,10 @@ uhci_pci_attach(device_t self) #if (__FreeBSD_version >= 700031) err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (void *)(void *)uhci_interrupt, sc, &sc->sc_intr_hdl); + NULL, (driver_intr_t *)uhci_interrupt, sc, &sc->sc_intr_hdl); #else err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - (void *)(void *)uhci_interrupt, sc, &sc->sc_intr_hdl); + (driver_intr_t *)uhci_interrupt, sc, &sc->sc_intr_hdl); #endif if (err) { diff --git a/sys/dev/usb/controller/uss820dci.c b/sys/dev/usb/controller/uss820dci.c index 8d8e0e4..0b0a074 100644 --- a/sys/dev/usb/controller/uss820dci.c +++ b/sys/dev/usb/controller/uss820dci.c @@ -836,8 +836,8 @@ uss820dci_setup_standard_chain(struct usb2_xfer *xfer) temp.td = NULL; temp.td_next = xfer->td_start[0]; - temp.setup_alt_next = xfer->flags_int.short_frames_ok; temp.offset = 0; + temp.setup_alt_next = xfer->flags_int.short_frames_ok; sc = USS820_DCI_BUS2SC(xfer->xroot->bus); ep_no = (xfer->endpoint & UE_ADDR); @@ -851,6 +851,12 @@ uss820dci_setup_standard_chain(struct usb2_xfer *xfer) temp.len = xfer->frlengths[0]; temp.pc = xfer->frbuffers + 0; temp.short_pkt = temp.len ? 1 : 0; + /* check for last frame */ + if (xfer->nframes == 1) { + /* no STATUS stage yet, SETUP is last */ + if (xfer->flags_int.control_act) + temp.setup_alt_next = 0; + } uss820dci_setup_standard_chain_sub(&temp); } @@ -878,7 +884,13 @@ uss820dci_setup_standard_chain(struct usb2_xfer *xfer) x++; if (x == xfer->nframes) { - temp.setup_alt_next = 0; + if (xfer->flags_int.control_xfr) { + if (xfer->flags_int.control_act) { + temp.setup_alt_next = 0; + } + } else { + temp.setup_alt_next = 0; + } } if (temp.len == 0) { @@ -903,37 +915,39 @@ uss820dci_setup_standard_chain(struct usb2_xfer *xfer) } } - /* always setup a valid "pc" pointer for status and sync */ - temp.pc = xfer->frbuffers + 0; - - /* check if we should append a status stage */ - - if (xfer->flags_int.control_xfr && - !xfer->flags_int.control_act) { + /* check for control transfer */ + if (xfer->flags_int.control_xfr) { uint8_t need_sync; - /* - * Send a DATA1 message and invert the current - * endpoint direction. - */ - if (xfer->endpoint & UE_DIR_IN) { - temp.func = &uss820dci_data_rx; - need_sync = 0; - } else { - temp.func = &uss820dci_data_tx; - need_sync = 1; - } + /* always setup a valid "pc" pointer for status and sync */ + temp.pc = xfer->frbuffers + 0; temp.len = 0; temp.short_pkt = 0; + temp.setup_alt_next = 0; - uss820dci_setup_standard_chain_sub(&temp); - if (need_sync) { - /* we need a SYNC point after TX */ - temp.func = &uss820dci_data_tx_sync; + /* check if we should append a status stage */ + if (!xfer->flags_int.control_act) { + + /* + * Send a DATA1 message and invert the current + * endpoint direction. + */ + if (xfer->endpoint & UE_DIR_IN) { + temp.func = &uss820dci_data_rx; + need_sync = 0; + } else { + temp.func = &uss820dci_data_tx; + need_sync = 1; + } temp.len = 0; temp.short_pkt = 0; uss820dci_setup_standard_chain_sub(&temp); + if (need_sync) { + /* we need a SYNC point after TX */ + temp.func = &uss820dci_data_tx_sync; + uss820dci_setup_standard_chain_sub(&temp); + } } } /* must have at least one frame! */ diff --git a/sys/dev/usb/controller/uss820dci_atmelarm.c b/sys/dev/usb/controller/uss820dci_atmelarm.c index 4cd0862..ac26956 100644 --- a/sys/dev/usb/controller/uss820dci_atmelarm.c +++ b/sys/dev/usb/controller/uss820dci_atmelarm.c @@ -170,10 +170,10 @@ uss820_atmelarm_attach(device_t dev) #if (__FreeBSD_version >= 700031) err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - NULL, (void *)uss820dci_interrupt, sc, &sc->sc_intr_hdl); + NULL, (driver_intr_t *)uss820dci_interrupt, sc, &sc->sc_intr_hdl); #else err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, - (void *)uss820dci_interrupt, sc, &sc->sc_intr_hdl); + (driver_intr_t *)uss820dci_interrupt, sc, &sc->sc_intr_hdl); #endif if (err) { sc->sc_intr_hdl = NULL; |