diff options
Diffstat (limited to 'sys/dev/usb/controller/dwc_otg.c')
-rw-r--r-- | sys/dev/usb/controller/dwc_otg.c | 103 |
1 files changed, 42 insertions, 61 deletions
diff --git a/sys/dev/usb/controller/dwc_otg.c b/sys/dev/usb/controller/dwc_otg.c index 6c72399..d46d613 100644 --- a/sys/dev/usb/controller/dwc_otg.c +++ b/sys/dev/usb/controller/dwc_otg.c @@ -507,7 +507,6 @@ 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; @@ -517,32 +516,20 @@ dwc_otg_host_channel_wait(struct dwc_otg_td *td) /* get pointer to softc */ sc = DWC_OTG_PC2SC(td->pc); - if (sc->sc_chan_state[x].hcint & HCINT_HALTED_ONLY) { + if (sc->sc_chan_state[x].wait_sof == 0) { dwc_otg_clear_hcint(sc, x); - return (1); + return (1); /* done */ } 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++) { - uint32_t hcchar; - if (sc->sc_chan_state[x].allocated) continue; - - /* check if channel is enabled */ - hcchar = DWC_OTG_READ_4(sc, DOTG_HCCHAR(x)); - if (hcchar & (HCCHAR_CHENA | HCCHAR_CHDIS)) { - DPRINTF("CH=%d is BUSY\n", x); - continue; - } - - if (sc->sc_chan_state[x].last_frame == frame) + if (sc->sc_chan_state[x].wait_sof != 0) continue; sc->sc_chan_state[td->channel].allocated = 0; @@ -556,9 +543,8 @@ dwc_otg_host_channel_wait(struct dwc_otg_td *td) /* clear interrupts */ dwc_otg_clear_hcint(sc, x); - DPRINTF("CH=%d HCCHAR=0x%08x(0x%08x) " - "HCSPLT=0x%08x\n", x, td->hcchar, - hcchar, td->hcsplt); + DPRINTF("CH=%d HCCHAR=0x%08x " + "HCSPLT=0x%08x\n", x, td->hcchar, td->hcsplt); /* ack any pending messages */ if (sc->sc_last_rx_status != 0 && @@ -583,7 +569,6 @@ 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; @@ -601,23 +586,11 @@ 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; - if (sc->sc_chan_state[x].allocated) continue; - - /* check if channel is enabled */ - hcchar = DWC_OTG_READ_4(sc, DOTG_HCCHAR(x)); - if (hcchar & (HCCHAR_CHENA | HCCHAR_CHDIS)) { - DPRINTF("CH=%d is BUSY\n", x); - continue; - } - - if (sc->sc_chan_state[x].last_frame == frame) + if (sc->sc_chan_state[x].wait_sof != 0) continue; sc->sc_chan_state[x].allocated = 1; @@ -625,9 +598,8 @@ dwc_otg_host_channel_alloc(struct dwc_otg_td *td) /* clear interrupts */ dwc_otg_clear_hcint(sc, x); - DPRINTF("CH=%d HCCHAR=0x%08x(0x%08x) " - "HCSPLT=0x%08x\n", x, td->hcchar, - hcchar, td->hcsplt); + DPRINTF("CH=%d HCCHAR=0x%08x " + "HCSPLT=0x%08x\n", x, td->hcchar, td->hcsplt); /* set active channel */ sc->sc_active_rx_ep |= (1 << x); @@ -644,12 +616,18 @@ static void dwc_otg_host_channel_disable(struct dwc_otg_softc *sc, uint8_t x) { uint32_t hcchar; + if (sc->sc_chan_state[x].wait_sof != 0) + return; hcchar = DWC_OTG_READ_4(sc, DOTG_HCCHAR(x)); if (hcchar & (HCCHAR_CHENA | HCCHAR_CHDIS)) { + /* disable channel */ + DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(x), + 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); + sc->sc_chan_state[x].wait_sof = 2; + /* enable SOF interrupt */ + sc->sc_irq_mask |= GINTMSK_SOFMSK; + DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); } } @@ -736,16 +714,9 @@ dwc_otg_host_setup_tx(struct dwc_otg_td *td) if (hcint & (HCINT_ERRORS | HCINT_RETRY | HCINT_ACK | HCINT_NYET)) { - uint32_t hcchar; dwc_otg_host_channel_disable(sc, td->channel); - hcchar = DWC_OTG_READ_4(sc, DOTG_HCCHAR(td->channel)); - - if (!(hcchar & HCCHAR_CHENA)) { - hcint |= HCINT_HALTED_ONLY; - sc->sc_chan_state[td->channel].hcint = hcint; - } if (!(hcint & HCINT_ERRORS)) td->errcnt = 0; } @@ -1020,7 +991,7 @@ dwc_otg_host_rate_check(struct dwc_otg_td *td, td->tmr_val += td->tmr_res; } else if (td->did_nak != 0) { goto busy; - } + } if (ep_type == UE_ISOCHRONOUS) { td->toggle = 0; @@ -1088,12 +1059,6 @@ dwc_otg_host_data_rx(struct dwc_otg_td *td) dwc_otg_host_channel_disable(sc, td->channel); - hcchar = DWC_OTG_READ_4(sc, DOTG_HCCHAR(td->channel)); - - if (!(hcchar & HCCHAR_CHENA)) { - hcint |= HCINT_HALTED_ONLY; - sc->sc_chan_state[td->channel].hcint = hcint; - } if (!(hcint & HCINT_ERRORS)) td->errcnt = 0; } @@ -1170,6 +1135,8 @@ check_state: if (!dwc_otg_host_channel_wait(td)) break; + td->did_nak = 1; + if (td->hcsplt != 0) goto receive_spkt; else @@ -1202,6 +1169,9 @@ check_state: if (hcint & (HCINT_RETRY | HCINT_ERRORS)) { if (!dwc_otg_host_channel_wait(td)) break; + + td->did_nak = 1; + goto receive_spkt; } if (hcint & (HCINT_ACK | HCINT_NYET)) { @@ -1447,12 +1417,6 @@ dwc_otg_host_data_tx(struct dwc_otg_td *td) dwc_otg_host_channel_disable(sc, td->channel); - hcchar = DWC_OTG_READ_4(sc, DOTG_HCCHAR(td->channel)); - - if (!(hcchar & HCCHAR_CHENA)) { - hcint |= HCINT_HALTED_ONLY; - sc->sc_chan_state[td->channel].hcint = hcint; - } if (!(hcint & HCINT_ERRORS)) td->errcnt = 0; } @@ -1989,8 +1953,7 @@ repeat: temp = DWC_OTG_READ_4(sc, DOTG_HCINT(x)); if (temp != 0) { DWC_OTG_WRITE_4(sc, DOTG_HCINT(x), temp); - temp &= ~(HCINT_SOFTWARE_ONLY | - HCINT_HALTED_ONLY); + temp &= ~HCINT_SOFTWARE_ONLY; sc->sc_chan_state[x].hcint |= temp; } } @@ -2286,6 +2249,24 @@ dwc_otg_interrupt(struct dwc_otg_softc *sc) } } + /* check for SOF interrupt */ + if (status & GINTSTS_SOF) { + if (sc->sc_irq_mask & GINTMSK_SOFMSK) { + uint8_t x; + uint8_t y; + for (x = y = 0; x != sc->sc_host_ch_max; x++) { + if (sc->sc_chan_state[x].wait_sof != 0) { + if (--(sc->sc_chan_state[x].wait_sof) != 0) + y = 1; + } + } + if (y == 0) { + sc->sc_irq_mask &= ~GINTMSK_SOFMSK; + DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask); + } + } + } + /* poll FIFO(s) */ dwc_otg_interrupt_poll(sc); |