summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/usb/ehci.c55
-rw-r--r--sys/dev/usb/ehcireg.h4
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 */