summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/controller/dwc_otg.c
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2012-09-26 18:59:20 +0000
committerhselasky <hselasky@FreeBSD.org>2012-09-26 18:59:20 +0000
commit95d0e5a41c0eb872db91f775722408ca5411b19d (patch)
tree8d8495369429fdc4aefd9b45457bb63260565f7a /sys/dev/usb/controller/dwc_otg.c
parent085c4798a8326c7cdf744bd626bec7ccc28b8588 (diff)
downloadFreeBSD-src-95d0e5a41c0eb872db91f775722408ca5411b19d.zip
FreeBSD-src-95d0e5a41c0eb872db91f775722408ca5411b19d.tar.gz
Make sure the DWC OTG host mode channels are given enough time to disable.
Diffstat (limited to 'sys/dev/usb/controller/dwc_otg.c')
-rw-r--r--sys/dev/usb/controller/dwc_otg.c18
1 files changed, 17 insertions, 1 deletions
diff --git a/sys/dev/usb/controller/dwc_otg.c b/sys/dev/usb/controller/dwc_otg.c
index 59c4256..6c72399 100644
--- a/sys/dev/usb/controller/dwc_otg.c
+++ b/sys/dev/usb/controller/dwc_otg.c
@@ -507,6 +507,7 @@ static uint8_t
dwc_otg_host_channel_wait(struct dwc_otg_td *td)
{
struct dwc_otg_softc *sc;
+ uint16_t frame;
uint8_t x;
x = td->channel;
@@ -524,6 +525,8 @@ dwc_otg_host_channel_wait(struct dwc_otg_td *td)
if (x == 0)
return (0); /* wait */
+ frame = DWC_OTG_READ_4(sc, DOTG_HFNUM) & HFNUM_FRNUM_MASK;
+
/* find new disabled channel */
for (x = 1; x != sc->sc_host_ch_max; x++) {
@@ -539,6 +542,9 @@ dwc_otg_host_channel_wait(struct dwc_otg_td *td)
continue;
}
+ if (sc->sc_chan_state[x].last_frame == frame)
+ continue;
+
sc->sc_chan_state[td->channel].allocated = 0;
sc->sc_chan_state[x].allocated = 1;
@@ -577,6 +583,7 @@ static uint8_t
dwc_otg_host_channel_alloc(struct dwc_otg_td *td)
{
struct dwc_otg_softc *sc;
+ uint16_t frame;
uint8_t x;
uint8_t max_channel;
@@ -594,6 +601,8 @@ dwc_otg_host_channel_alloc(struct dwc_otg_td *td)
x = 1;
}
+ frame = DWC_OTG_READ_4(sc, DOTG_HFNUM) & HFNUM_FRNUM_MASK;
+
for (; x != max_channel; x++) {
uint32_t hcchar;
@@ -608,6 +617,9 @@ dwc_otg_host_channel_alloc(struct dwc_otg_td *td)
continue;
}
+ if (sc->sc_chan_state[x].last_frame == frame)
+ continue;
+
sc->sc_chan_state[x].allocated = 1;
/* clear interrupts */
@@ -633,8 +645,12 @@ dwc_otg_host_channel_disable(struct dwc_otg_softc *sc, uint8_t x)
{
uint32_t hcchar;
hcchar = DWC_OTG_READ_4(sc, DOTG_HCCHAR(x));
- if (hcchar & (HCCHAR_CHENA | HCCHAR_CHDIS))
+ if (hcchar & (HCCHAR_CHENA | HCCHAR_CHDIS)) {
+ /* don't re-use channel until next SOF is transmitted */
+ sc->sc_chan_state[x].last_frame =
+ DWC_OTG_READ_4(sc, DOTG_HFNUM) & HFNUM_FRNUM_MASK;
DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(x), HCCHAR_CHENA | HCCHAR_CHDIS);
+ }
}
static void
OpenPOWER on IntegriCloud