diff options
| author | mycroft <mycroft@NetBSD.org> | 2004-06-22 05:25:10 +0000 |
|---|---|---|
| committer | mycroft <mycroft@NetBSD.org> | 2004-06-22 05:25:10 +0000 |
| commit | 46d9c14fee1ae23cb2ddaebcc7521556bd911fc0 (patch) | |
| tree | 02447b49de5ee30c54083f9a3a7d3415d67d5db0 /sys/dev/usb | |
| parent | 3cc9c970a3d96a84498d2e5ded07cf52edbc915f (diff) | |
Set the data toggle correctly, and use EHCI_QTD_DTC. This fixes problems with
my ALi-based drive enclosure (it works now, rather than failing to attach).
Also seems to work with a GL811-based enclosure and an ASUS enclosure with a
CD-RW, on both Intel and NEC controllers.
Note: The ALi enclosure is currently very SLOW, due to some issue with taking
too long to notice that the QTD is complete. This requires more investigation.
Diffstat (limited to 'sys/dev/usb')
| -rw-r--r-- | sys/dev/usb/ehci.c | 55 | ||||
| -rw-r--r-- | sys/dev/usb/ehcireg.h | 4 |
2 files changed, 36 insertions, 23 deletions
diff --git a/sys/dev/usb/ehci.c b/sys/dev/usb/ehci.c index cb6094c3014..706a2bdcb23 100644 --- a/sys/dev/usb/ehci.c +++ b/sys/dev/usb/ehci.c @@ -1,4 +1,4 @@ -/* $NetBSD: ehci.c,v 1.54 2004/01/17 13:15:05 jdolecek Exp $ */ +/* $NetBSD: ehci.c,v 1.55 2004/06/22 05:25:10 mycroft Exp $ */ /* * Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -69,7 +69,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.54 2004/01/17 13:15:05 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.55 2004/06/22 05:25:10 mycroft Exp $"); #include "ohci.h" #include "uhci.h" @@ -109,6 +109,8 @@ int ehcidebug = 0; struct ehci_pipe { struct usbd_pipe pipe; + int nexttoggle; + ehci_soft_qh_t *sqh; union { ehci_soft_qtd_t *qtd; @@ -748,9 +750,7 @@ ehci_idone(struct ehci_xfer *ex) if (sqtd != NULL) { if (!(xfer->rqflags & URQ_REQUEST)) printf("ehci_idone: need toggle update\n"); -#if 0 - epipe->nexttoggle = EHCI_TD_GET_DT(le32toh(std->td.td_token)); -#endif + epipe->nexttoggle = EHCI_QTD_GET_TOGGLE(status); } status &= EHCI_QTD_STATERRS; @@ -1058,7 +1058,7 @@ ehci_device_clear_toggle(usbd_pipe_handle pipe) if (ehcidebug) usbd_dump_pipe(pipe); #endif - epipe->sqh->qh.qh_qtd.qtd_status &= htole32(~EHCI_QTD_TOGGLE); + epipe->nexttoggle = 0; } Static void @@ -1217,6 +1217,8 @@ ehci_open(usbd_pipe_handle pipe) if (sc->sc_dying) return (USBD_IOERROR); + epipe->nexttoggle = 0; + if (addr == sc->sc_addr) { switch (ed->bEndpointAddress) { case USB_CONTROL_ENDPOINT: @@ -1246,8 +1248,8 @@ ehci_open(usbd_pipe_handle pipe) sqh->qh.qh_endp = htole32( EHCI_QH_SET_ADDR(addr) | EHCI_QH_SET_ENDPT(ed->bEndpointAddress) | - EHCI_QH_SET_EPS(speed) | /* XXX */ - /* XXX EHCI_QH_DTC ? */ + EHCI_QH_SET_EPS(speed) | + EHCI_QH_DTC | EHCI_QH_SET_MPL(UGETW(ed->wMaxPacketSize)) | (speed != EHCI_QH_SPEED_HIGH && xfertype == UE_CONTROL ? EHCI_QH_CTL : 0) | @@ -2100,8 +2102,8 @@ ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc, ehci_soft_qtd_t *next, *cur; ehci_physaddr_t dataphys, dataphyspage, dataphyslastpage, nextphys; u_int32_t qtdstatus; - int len, curlen; - int i; + int len, curlen, mps; + int i, tog; usb_dma_t *dma = &xfer->dmabuf; DPRINTFN(alen<4*4096,("ehci_alloc_sqtd_chain: start len=%d\n", alen)); @@ -2109,14 +2111,21 @@ ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc, len = alen; dataphys = DMAADDR(dma, 0); dataphyslastpage = EHCI_PAGE(dataphys + len - 1); +#if 0 +printf("status=%08x toggle=%d\n", epipe->sqh->qh.qh_qtd.qtd_status, + epipe->nexttoggle); +#endif qtdstatus = htole32( EHCI_QTD_ACTIVE | EHCI_QTD_SET_PID(rd ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT) | EHCI_QTD_SET_CERR(3) /* IOC set below */ /* BYTES set below */ - /* XXX Data toggle */ ); + mps = UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize); + tog = epipe->nexttoggle; + if (tog) + qtdstatus |= EHCI_QTD_TOGGLE; cur = ehci_alloc_sqtd(sc); *sp = cur; @@ -2144,10 +2153,8 @@ ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc, curlen = len; } #endif - - /* XXX true for EHCI? */ /* the length must be a multiple of the max size */ - curlen -= curlen % UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize); + curlen -= curlen % mps; DPRINTFN(1,("ehci_alloc_sqtd_chain: multiple QTDs, " "curlen=%d\n", curlen)); #ifdef DIAGNOSTIC @@ -2192,6 +2199,12 @@ ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc, cur->len = curlen; DPRINTFN(10,("ehci_alloc_sqtd_chain: cbp=0x%08x end=0x%08x\n", dataphys, dataphys + curlen)); + /* adjust the toggle based on the number of packets in this + qtd */ + if (((curlen + mps - 1) / mps) & 1) { + tog ^= 1; + qtdstatus ^= EHCI_QTD_TOGGLE; + } if (len == 0) break; DPRINTFN(10,("ehci_alloc_sqtd_chain: extend chain\n")); @@ -2200,6 +2213,7 @@ ehci_alloc_sqtd_chain(struct ehci_pipe *epipe, ehci_softc_t *sc, } cur->qtd.qtd_status |= htole32(EHCI_QTD_IOC); *ep = cur; + epipe->nexttoggle = tog; DPRINTFN(10,("ehci_alloc_sqtd_chain: return sqtd=%p sqtdend=%p\n", *sp, *ep)); @@ -2515,26 +2529,24 @@ ehci_device_request(usbd_xfer_handle xfer) * This needs to go away since it slows down control transfers. * Removing it entails: * - fill the QH only once with addr & wMaxPacketSize - * - put the correct data toggles in the qtds and set DTC */ /* ehci_sync_hc(sc); */ /* Update device address and length since they may have changed. */ /* XXX This only needs to be done once, but it's too early in open. */ /* XXXX Should not touch ED here! */ sqh->qh.qh_endp = - (sqh->qh.qh_endp & htole32(~(EHCI_QH_ADDRMASK | EHCI_QG_MPLMASK))) | + (sqh->qh.qh_endp & htole32(~(EHCI_QH_ADDRMASK | EHCI_QH_MPLMASK))) | htole32( EHCI_QH_SET_ADDR(addr) | - /* EHCI_QH_DTC | */ EHCI_QH_SET_MPL(UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize)) ); - /* Clear toggle */ - sqh->qh.qh_qtd.qtd_status &= htole32(~EHCI_QTD_TOGGLE); /* Set up data transaction */ if (len != 0) { ehci_soft_qtd_t *end; + /* Start toggle at 1. */ + epipe->nexttoggle = 1; err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer, &next, &end); if (err) @@ -2542,14 +2554,14 @@ ehci_device_request(usbd_xfer_handle xfer) end->nextqtd = stat; end->qtd.qtd_next = end->qtd.qtd_altnext = htole32(stat->physaddr); - /* Start toggle at 1. */ - /*next->qtd.td_flags |= htole32(EHCI_QTD_TOGGLE);*/ } else { next = stat; } memcpy(KERNADDR(&epipe->u.ctl.reqdma, 0), req, sizeof *req); + /* Clear toggle */ + sqh->qh.qh_qtd.qtd_status &= htole32(~EHCI_QTD_TOGGLE); setup->qtd.qtd_status = htole32( EHCI_QTD_ACTIVE | EHCI_QTD_SET_PID(EHCI_QTD_PID_SETUP) | @@ -2567,6 +2579,7 @@ ehci_device_request(usbd_xfer_handle xfer) EHCI_QTD_ACTIVE | EHCI_QTD_SET_PID(isread ? EHCI_QTD_PID_OUT : EHCI_QTD_PID_IN) | EHCI_QTD_SET_CERR(3) | + EHCI_QTD_TOGGLE | EHCI_QTD_IOC ); stat->qtd.qtd_buffer[0] = 0; /* XXX not needed? */ diff --git a/sys/dev/usb/ehcireg.h b/sys/dev/usb/ehcireg.h index e4b4041d337..5570fbbdf2e 100644 --- a/sys/dev/usb/ehcireg.h +++ b/sys/dev/usb/ehcireg.h @@ -1,4 +1,4 @@ -/* $NetBSD: ehcireg.h,v 1.15 2004/06/12 16:02:42 mycroft Exp $ */ +/* $NetBSD: ehcireg.h,v 1.16 2004/06/22 05:25:10 mycroft Exp $ */ /* * Copyright (c) 2001 The NetBSD Foundation, Inc. @@ -257,7 +257,7 @@ typedef struct { #define EHCI_QH_HRECL 0x00008000 #define EHCI_QH_GET_MPL(x) (((x) >> 16) & 0x7ff) /* max packet len */ #define EHCI_QH_SET_MPL(x) ((x) << 16) -#define EHCI_QG_MPLMASK 0x07ff0000 +#define EHCI_QH_MPLMASK 0x07ff0000 #define EHCI_QH_GET_CTL(x) (((x) >> 27) & 0x01) /* control endpoint */ #define EHCI_QH_CTL 0x08000000 #define EHCI_QH_GET_NRL(x) (((x) >> 28) & 0x0f) /* NAK reload */ |
