summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorthompsa <thompsa@FreeBSD.org>2009-03-20 21:57:54 +0000
committerthompsa <thompsa@FreeBSD.org>2009-03-20 21:57:54 +0000
commitca147f2b35e362c05c7b73c7b8b6c6fc58a69744 (patch)
tree6fbd12d5f67db5e9aab7afad8815466e2de7d1f5 /sys
parent79c72751b7f97009077ff9f01b67a0794ce358eb (diff)
downloadFreeBSD-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.c75
-rw-r--r--sys/dev/usb/controller/at91dci_atmelarm.c8
-rw-r--r--sys/dev/usb/controller/atmegadci.c73
-rw-r--r--sys/dev/usb/controller/atmegadci_atmelarm.c2
-rw-r--r--sys/dev/usb/controller/ehci.c43
-rw-r--r--sys/dev/usb/controller/ehci_ixp4xx.c2
-rw-r--r--sys/dev/usb/controller/ehci_mbus.c2
-rw-r--r--sys/dev/usb/controller/ehci_pci.c4
-rw-r--r--sys/dev/usb/controller/musb_otg.c37
-rw-r--r--sys/dev/usb/controller/musb_otg_atmelarm.c4
-rw-r--r--sys/dev/usb/controller/ohci.c56
-rw-r--r--sys/dev/usb/controller/ohci_atmelarm.c4
-rw-r--r--sys/dev/usb/controller/ohci_pci.c4
-rw-r--r--sys/dev/usb/controller/uhci.c70
-rw-r--r--sys/dev/usb/controller/uhci_pci.c4
-rw-r--r--sys/dev/usb/controller/uss820dci.c62
-rw-r--r--sys/dev/usb/controller/uss820dci_atmelarm.c4
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;
OpenPOWER on IntegriCloud