Date: Sun, 6 Jan 2008 21:44:12 GMT From: Hans Petter Selasky <hselasky@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 132640 for review Message-ID: <200801062144.m06LiC0E074382@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=132640 Change 132640 by hselasky@hselasky_laptop001 on 2008/01/06 21:43:50 AT91 UDP bugfixes: o Remove "did_multi_buffer" flag. Multi bufring works regardless of this. o Create new routine, at9100_dci_reset_ep, that handles all endpoint reset. The reason for this is that the FIFO reset command does not release all the FIFO banks, so if we do not clear these ourselves we end up receiving ZLP's which can confuse the USB device drivers. Affected files ... .. //depot/projects/usb/src/sys/dev/usb/at9100_dci.c#12 edit .. //depot/projects/usb/src/sys/dev/usb/at9100_dci.h#4 edit Differences ... ==== //depot/projects/usb/src/sys/dev/usb/at9100_dci.c#12 (text+ko) ==== @@ -561,23 +561,13 @@ temp &= AT91_UDP_CSR_STALLSENT; if (csr & AT91_UDP_CSR_TXPKTRDY) { - /* check for double buffering */ - if (td->support_multi_buffer && - (!td->did_multi_buffer)) { - td->did_multi_buffer = 1; - - /* only set TXPKTRDY next time */ - temp |= AT91_UDP_CSR_TXPKTRDY; - - } else if (temp) { + if (temp) { /* write command */ AT91_CSR_ACK(csr, temp); bus_space_write_4(td->io_tag, td->io_hdl, td->status_reg, csr); - return (1); /* not complete */ - } else { - return (1); /* not complete */ } + return (1); /* not complete */ } else { /* clear TXCOMP and set TXPKTRDY */ temp |= (AT91_UDP_CSR_TXCOMP | @@ -673,19 +663,6 @@ bus_space_write_4(td->io_tag, td->io_hdl, td->status_reg, csr); -#if 0 - /* - * XXX The AT91 USB chip does not generate a second interrupt - * when we do double bufring, so there is no way of telling - * when the peer has actually received the data. Usually this - * is not a big problem. XXX - */ - if (td->did_multi_buffer) { - /* wait for the second and final interrupt */ - td->did_multi_buffer = 0; - goto repeat; - } -#endif return (0); /* complete */ not_complete: @@ -734,14 +711,10 @@ temp = 0; if (td->fifo_bank) temp |= 1; - if (td->did_multi_buffer) - temp |= 2; td = td->obj_next; xfer->td_transfer_cache = td; if (temp & 1) td->fifo_bank = 1; - if (temp & 2) - td->did_multi_buffer = 1; } return (1); /* not complete */ @@ -756,13 +729,6 @@ sc->sc_ep_flags[temp].fifo_bank = 0; } - /* update multi buffer flag */ - if (td->did_multi_buffer) { - sc->sc_ep_flags[temp].did_multi_buffer = 1; - } else { - sc->sc_ep_flags[temp].did_multi_buffer = 0; - } - /* compute all actual lengths */ at9100_dci_standard_done(xfer); @@ -927,7 +893,6 @@ td->remainder = temp->len; td->fifo_bank = 0; td->error = 0; - td->did_multi_buffer = 0; td->did_stall = 0; td->short_pkt = temp->short_pkt; td->alt_next = temp->setup_alt_next; @@ -1081,11 +1046,6 @@ td = xfer->td_transfer_first; td->fifo_bank = 1; } - /* setup the correct multi buffer flag */ - if (sc->sc_ep_flags[ep_no].did_multi_buffer) { - td = xfer->td_transfer_first; - td->did_multi_buffer = 1; - } return; } @@ -1342,28 +1302,77 @@ } static void -at9100_dci_clear_stall(struct usbd_device *udev, struct usbd_pipe *pipe) +at9100_dci_reset_ep(struct usbd_device *udev, uint8_t ep_no) { struct at9100_dci_softc *sc; - uint32_t rst_val; + const struct usbd_hw_ep_profile *pf; + uint32_t csr_val; + uint32_t temp; + uint8_t csr_reg; + uint8_t to; + + /* get softc */ + sc = AT9100_DCI_BUS2SC(udev->bus); + + /* get endpoint profile */ + at9100_dci_get_hw_ep_profile(udev, &pf, ep_no); + + /* reset FIFO */ + AT91_UDP_WRITE_4(sc, AT91_UDP_RST, AT91_UDP_RST_EP(ep_no)); + AT91_UDP_WRITE_4(sc, AT91_UDP_RST, 0); + + /* + * NOTE: One would assume that a FIFO reset would release the + * FIFO banks aswell, but it doesn't! We have to do this + * manually! + */ + csr_reg = AT91_UDP_CSR(ep_no); + + /* release FIFO banks, if any */ + for (to = 0; to != 2; to++) { + + /* get csr value */ + csr_val = AT91_UDP_READ_4(sc, csr_reg); + + if (csr_val & (AT91_UDP_CSR_RX_DATA_BK0 | + AT91_UDP_CSR_RX_DATA_BK1)) { + /* clear status bits */ + if (pf->support_multi_buffer) { + if (sc->sc_ep_flags[ep_no].fifo_bank) { + sc->sc_ep_flags[ep_no].fifo_bank = 0; + temp = AT91_UDP_CSR_RX_DATA_BK1; + } else { + sc->sc_ep_flags[ep_no].fifo_bank = 1; + temp = AT91_UDP_CSR_RX_DATA_BK0; + } + } else { + temp = (AT91_UDP_CSR_RX_DATA_BK0 | + AT91_UDP_CSR_RX_DATA_BK1); + } + } else { + temp = 0; + } + + /* clear FORCESTALL */ + temp |= AT91_UDP_CSR_STALLSENT; - mtx_assert(&(udev->bus->mtx), MA_OWNED); + AT91_CSR_ACK(csr_val, temp); + AT91_UDP_WRITE_4(sc, csr_reg, csr_val); + } + return; +} +static void +at9100_dci_clear_stall(struct usbd_device *udev, struct usbd_pipe *pipe) +{ DPRINTFN(4, "pipe=%p\n", pipe); - /* reset pipe state */ + mtx_assert(&(udev->bus->mtx), MA_OWNED); - sc = AT9100_DCI_BUS2SC(udev->bus); - rst_val = (pipe->edesc->bEndpointAddress & UE_ADDR); - sc->sc_ep_flags[rst_val].did_multi_buffer = 0; - rst_val = AT91_UDP_RST_EP(rst_val); + /* reset endpoint */ + at9100_dci_reset_ep(udev, + (pipe->edesc->bEndpointAddress & UE_ADDR)); - /* - * XXX Do we need some delay between setting and clearing - * reset ? - */ - AT91_UDP_WRITE_4(sc, AT91_UDP_RST, rst_val); - AT91_UDP_WRITE_4(sc, AT91_UDP_RST, 0); return; } @@ -1401,11 +1410,7 @@ AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(n), csr_val); /* reset endpoint */ - AT91_UDP_WRITE_4(sc, AT91_UDP_RST, AT91_UDP_RST_EP(n)); - AT91_UDP_WRITE_4(sc, AT91_UDP_RST, 0); - - /* reset "did_multi_buffer" */ - sc->sc_ep_flags[n].did_multi_buffer = 0; + at9100_dci_reset_ep(udev, n); } if (cd == NULL) { @@ -1486,10 +1491,6 @@ /* disable endpoint */ AT91_UDP_WRITE_4(sc, AT91_UDP_CSR(n), csr_val); - - /* reset endpoint */ - AT91_UDP_WRITE_4(sc, AT91_UDP_RST, AT91_UDP_RST_EP(n)); - AT91_UDP_WRITE_4(sc, AT91_UDP_RST, 0); } /* enable the interrupts we want */ @@ -1860,13 +1861,13 @@ .DeviceRemovable = {0}, /* port is removable */ }; -#define STRING_LANG \ +#define STRING_LANG \ 0x09, 0x04, /* American English */ -#define STRING_VENDOR \ +#define STRING_VENDOR \ 'A', 0, 'T', 0, 'M', 0, 'E', 0, 'L', 0 -#define STRING_PRODUCT \ +#define STRING_PRODUCT \ 'D', 0, 'C', 0, 'I', 0, ' ', 0, 'R', 0, \ 'o', 0, 'o', 0, 't', 0, ' ', 0, 'H', 0, \ 'U', 0, 'B', 0, ==== //depot/projects/usb/src/sys/dev/usb/at9100_dci.h#4 (text+ko) ==== @@ -149,7 +149,6 @@ uint8_t alt_next:1; uint8_t short_pkt:1; uint8_t support_multi_buffer:1; - uint8_t did_multi_buffer:1; uint8_t did_stall:1; }; @@ -182,7 +181,6 @@ struct at9100_ep_flags { uint8_t fifo_bank:1; /* hardware specific */ - uint8_t did_multi_buffer:1; /* hardware specific */ }; struct at9100_flags {
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200801062144.m06LiC0E074382>