NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: kern/42979: Data toggle issues in usb(4), slhci(4), uhci(4) and ehci(4)
The following reply was made to PR kern/42979; it has been noted by GNATS.
From: Yorick Hardy <yorickhardy%gmail.com@localhost>
To: gnats-bugs%NetBSD.org@localhost
Cc:
Subject: Re: kern/42979: Data toggle issues in usb(4), slhci(4), uhci(4) and
ehci(4)
Date: Sat, 24 Apr 2010 07:16:26 +0200
Updated patch to fix the ohci problem pointed out by
Jonathan Kollasch on current-users.
--
Kind regards,
Yorick Hardy
Index: sys/dev/ic/sl811hs.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/sl811hs.c,v
retrieving revision 1.25
diff -u -r1.25 sl811hs.c
--- sys/dev/ic/sl811hs.c 25 Nov 2009 14:28:50 -0000 1.25
+++ sys/dev/ic/sl811hs.c 20 Apr 2010 07:23:24 -0000
@@ -280,7 +280,7 @@
struct gcq ap; /* All pipes */
struct gcq to; /* Timeout list */
struct gcq xq; /* Xfer queues */
- unsigned int pflags; /* Pipe flags */
+ unsigned int *pflags; /* Pipe flags */
#define PF_GONE (0x01) /* Pipe is on disabled device */
#define PF_TOGGLE (0x02) /* Data toggle status */
#define PF_LS (0x04) /* Pipe is low speed */
@@ -433,6 +433,7 @@
void slhci_freem(struct usbd_bus *, usb_dma_t *);
struct usbd_xfer * slhci_allocx(struct usbd_bus *);
void slhci_freex(struct usbd_bus *, struct usbd_xfer *);
+void slhci_clear_all_toggle(struct usbd_bus *, struct usbd_device *);
usbd_status slhci_transfer(struct usbd_xfer *);
usbd_status slhci_start(struct usbd_xfer *);
@@ -685,6 +686,7 @@
slhci_freem,
slhci_allocx,
slhci_freex,
+ slhci_clear_all_toggle,
};
const struct usbd_pipe_methods slhci_pipe_methods = {
@@ -849,6 +851,15 @@
free(xfer, M_USB);
}
+void slhci_clear_all_toggle(struct usbd_bus *bus, struct usbd_device *dev)
+{
+ struct slhci_softc *sc = bus->hci_private;
+ int i;
+
+ for (i = 0; i < 2*USB_MAX_ENDPOINTS; i++)
+ sc->pflags[dev->address][i] &= ~PF_TOGGLE;
+}
+
usbd_status
slhci_transfer(struct usbd_xfer *xfer)
{
@@ -923,7 +934,7 @@
spipe->newlen[1] = min(xfer->length, max_packet);
if (spipe->ptype == PT_BULK || spipe->ptype == PT_INTR) {
- if (spipe->pflags & PF_TOGGLE)
+ if (*(spipe->pflags) & PF_TOGGLE)
spipe->control |= SL11_EPCTRL_DATATOGGLE;
spipe->tregs[LEN] = spipe->newlen[1];
if (spipe->tregs[LEN])
@@ -971,10 +982,10 @@
* same place shares constants. Index 0 is "short length" for bulk and
* ctrl data and 1 is "full length" for ctrl data (bulk/intr are
* already set to full length). */
- if (spipe->pflags & PF_LS) {
+ if (*(spipe->pflags) & PF_LS) {
/* Setting PREAMBLE for directly connnected LS devices will
* lock up the chip. */
- if (spipe->pflags & PF_PREAMBLE)
+ if (*(spipe->pflags) & PF_PREAMBLE)
spipe->control |= SL11_EPCTRL_PREAMBLE;
if (max_packet <= 8) {
spipe->bustime = SLHCI_LS_CONST +
@@ -1031,6 +1042,7 @@
usb_endpoint_descriptor_t *ed;
struct slhci_transfers *t;
unsigned int max_packet, pmaxpkt;
+ int epaddr;
dev = pipe->device;
sc = dev->bus->hci_private;
@@ -1041,7 +1053,13 @@
DLOG(D_TRACE, "slhci_open(addr=%d,ep=%d,rootaddr=%d)",
dev->address, ed->bEndpointAddress, t->rootaddr, 0);
- spipe->pflags = 0;
+ epaddr = UE_GET_ADDR(ed->bEndpointAddress);
+ if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT)
+ epaddr += USB_MAX_ENDPOINTS;
+
+ spipe->pflags = &(sc->pflags[dev->address][epaddr]);
+
+ *(spipe->pflags) &= PF_TOGGLE; /* clear all flags except toggle */
spipe->frame = 0;
spipe->lastframe = 0;
spipe->xfer = NULL;
@@ -1058,9 +1076,9 @@
max_packet = UGETW(ed->wMaxPacketSize);
if (dev->speed == USB_SPEED_LOW) {
- spipe->pflags |= PF_LS;
+ *(spipe->pflags) |= PF_LS;
if (dev->myhub->address != t->rootaddr) {
- spipe->pflags |= PF_PREAMBLE;
+ *(spipe->pflags) |= PF_PREAMBLE;
if (!slhci_try_lsvh)
return slhci_lock_call(sc, &slhci_lsvh_warn,
spipe, NULL);
@@ -1291,7 +1309,7 @@
DLOG(D_TRACE, "%s toggle spipe %p", pnames(spipe->ptype),
spipe,0,0);
- spipe->pflags &= ~PF_TOGGLE;
+ *(spipe->pflags) &= ~PF_TOGGLE;
#ifdef DIAGNOSTIC
if (spipe->xfer != NULL) {
@@ -2085,7 +2103,7 @@
status_setup:
/* CTRL_DATA swaps direction in PID then jumps here */
spipe->tregs[LEN] = 0;
- if (spipe->pflags & PF_LS)
+ if (*(spipe->pflags) & PF_LS)
spipe->bustime = SLHCI_LS_CONST;
else
spipe->bustime = SLHCI_FS_CONST;
@@ -2140,9 +2158,9 @@
* current setting will apply to the next
* transfer. */
if (spipe->control & SL11_EPCTRL_DATATOGGLE)
- spipe->pflags |= PF_TOGGLE;
+ *(spipe->pflags) |= PF_TOGGLE;
else
- spipe->pflags &= ~PF_TOGGLE;
+ *(spipe->pflags) &= ~PF_TOGGLE;
head = Q_CALLBACKS;
}
@@ -2373,7 +2391,7 @@
SLHCI_MAINLOCKASSERT(sc);
if (__predict_false(t->flags & F_DISABLED) ||
- __predict_false(spipe->pflags & PF_GONE)) {
+ __predict_false(*(spipe->pflags) & PF_GONE)) {
DLOG(D_MSG, "slhci_enter_xfer: DISABLED or GONE", 0,0,0,0);
spipe->xfer->status = USBD_CANCELLED;
}
@@ -2799,7 +2817,7 @@
/* Cancel all pipes. Note that not all of these may be on the
* callback queue yet; some could be in slhci_start, for example. */
FOREACH_AP(q, t, spipe) {
- spipe->pflags = PF_GONE;
+ *(spipe->pflags) = PF_GONE;
spipe->pipe.repeat = 0;
spipe->pipe.aborting = 1;
if (spipe->xfer != NULL)
@@ -2928,7 +2946,7 @@
t = &sc->sc_transfers;
max_packet = UGETW(spipe->pipe.endpoint->edesc->wMaxPacketSize);
- if (spipe->pflags & PF_LS)
+ if (*(spipe->pflags) & PF_LS)
bustime = SLHCI_LS_CONST + SLHCI_LS_DATA_TIME(max_packet);
else
bustime = SLHCI_FS_CONST + SLHCI_FS_DATA_TIME(max_packet);
@@ -3612,7 +3630,7 @@
"AP" : "", gcq_onlist(&spipe->to) ? "TO" : "",
gcq_onlist(&spipe->xq) ? "XQ" : "");
DDOLOG("spipe: xfer %p buffer %p pflags %#x ptype %s",
- spipe->xfer, spipe->buffer, spipe->pflags, pnames(spipe->ptype));
+ spipe->xfer, spipe->buffer, *(spipe->pflags), pnames(spipe->ptype));
}
void
Index: sys/dev/ic/sl811hsvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/sl811hsvar.h,v
retrieving revision 1.6
diff -u -r1.6 sl811hsvar.h
--- sys/dev/ic/sl811hsvar.h 12 May 2009 14:25:18 -0000 1.6
+++ sys/dev/ic/sl811hsvar.h 20 Apr 2010 07:23:24 -0000
@@ -83,6 +83,9 @@
uint8_t sc_ier; /* enabled interrupts */
uint8_t sc_stride; /* port stride */
+
+ /* Pipe flags for each endpoint for each device */
+ unsigned int pflags[USB_MAX_DEVICES][2*USB_MAX_ENDPOINTS];
};
/* last preinit arguments are: max current (in mA, not mA/2), port stride */
Index: sys/dev/usb/ehci.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/ehci.c,v
retrieving revision 1.166
diff -u -r1.166 ehci.c
--- sys/dev/usb/ehci.c 24 Feb 2010 22:38:09 -0000 1.166
+++ sys/dev/usb/ehci.c 20 Apr 2010 07:23:25 -0000
@@ -91,7 +91,6 @@
struct ehci_pipe {
struct usbd_pipe pipe;
- int nexttoggle;
ehci_soft_qh_t *sqh;
union {
@@ -120,6 +119,32 @@
} u;
};
+#define EHCI_NEXTTOGGLE(epipe) \
+ ((ehci_softc_t*)((epipe)->pipe.device->bus->hci_private)) \
+ ->nexttoggle[(epipe)->pipe.device->address]
+
+#define EHCI_PIPE_ENDPOINT_ADDR(epipe) \
+ UE_GET_ADDR((epipe)->pipe.endpoint->edesc->bEndpointAddress)
+
+#define EHCI_PIPE_ENDPOINT_DIR(epipe) \
+ UE_GET_DIR((epipe)->pipe.endpoint->edesc->bEndpointAddress)
+
+#define EHCI_NEXTTOGGLE_BIT(epipe) \
+ ((EHCI_PIPE_ENDPOINT_DIR(epipe) == UE_DIR_OUT) ? \
+ (0x00000001 << EHCI_PIPE_ENDPOINT_ADDR(epipe)) : \
+ (0x00010000 << EHCI_PIPE_ENDPOINT_ADDR(epipe)))
+
+#define EHCI_NEXTTOGGLE_SET(epipe) \
+ SET(EHCI_NEXTTOGGLE(epipe), EHCI_NEXTTOGGLE_BIT(epipe))
+
+#define EHCI_NEXTTOGGLE_ISSET(epipe) \
+ ISSET(EHCI_NEXTTOGGLE(epipe), EHCI_NEXTTOGGLE_BIT(epipe))
+
+#define EHCI_NEXTTOGGLE_GET(epipe) ((EHCI_NEXTTOGGLE_ISSET(epipe))?1:0)
+
+#define EHCI_NEXTTOGGLE_CLR(epipe) \
+ CLR(EHCI_NEXTTOGGLE(epipe), EHCI_NEXTTOGGLE_BIT(epipe))
+
Static usbd_status ehci_open(usbd_pipe_handle);
Static void ehci_poll(struct usbd_bus *);
Static void ehci_softintr(void *);
@@ -139,6 +164,9 @@
Static usbd_xfer_handle ehci_allocx(struct usbd_bus *);
Static void ehci_freex(struct usbd_bus *, usbd_xfer_handle);
+Static void ehci_clear_all_toggle(struct usbd_bus *,
+ struct usbd_device *);
+
Static usbd_status ehci_root_ctrl_transfer(usbd_xfer_handle);
Static usbd_status ehci_root_ctrl_start(usbd_xfer_handle);
Static void ehci_root_ctrl_abort(usbd_xfer_handle);
@@ -252,6 +280,7 @@
ehci_freem,
ehci_allocx,
ehci_freex,
+ ehci_clear_all_toggle,
};
Static const struct usbd_pipe_methods ehci_root_ctrl_methods = {
@@ -533,6 +562,10 @@
return (USBD_IOERROR);
}
+ /* initialize all data toggles to zero */
+ for (i = 0; i < USB_MAX_DEVICES; i++)
+ sc->nexttoggle[i] = 0;
+
/* Enable interrupts */
DPRINTFN(1,("ehci_init: enabling\n"));
EOWRITE4(sc, EHCI_USBINTR, sc->sc_eintrs);
@@ -953,7 +986,10 @@
ehci_dump_sqh(epipe->sqh);
ehci_dump_sqtds(ex->sqtdstart);
#endif
- epipe->nexttoggle = EHCI_QTD_GET_TOGGLE(nstatus);
+ if (EHCI_QTD_GET_TOGGLE(nstatus))
+ EHCI_NEXTTOGGLE_SET(epipe);
+ else
+ EHCI_NEXTTOGGLE_CLR(epipe);
}
DPRINTFN(/*10*/2, ("ehci_idone: len=%d, actlen=%d, status=0x%x\n",
@@ -1318,6 +1354,14 @@
}
Static void
+ehci_clear_all_toggle(struct usbd_bus *bus, struct usbd_device *dev)
+{
+ struct ehci_softc *sc = bus->hci_private;
+
+ sc->nexttoggle[dev->address] = 0;
+}
+
+Static void
ehci_device_clear_toggle(usbd_pipe_handle pipe)
{
struct ehci_pipe *epipe = (struct ehci_pipe *)pipe;
@@ -1328,7 +1372,7 @@
if (ehcidebug)
usbd_dump_pipe(pipe);
#endif
- epipe->nexttoggle = 0;
+ EHCI_NEXTTOGGLE_CLR(epipe);
}
Static void
@@ -1549,8 +1593,6 @@
if (sc->sc_dying)
return (USBD_IOERROR);
- epipe->nexttoggle = 0;
-
if (addr == sc->sc_addr) {
switch (ed->bEndpointAddress) {
case USB_CONTROL_ENDPOINT:
@@ -2597,7 +2639,7 @@
/* BYTES set below */
;
mps = UGETW(epipe->pipe.endpoint->edesc->wMaxPacketSize);
- tog = epipe->nexttoggle;
+ tog = EHCI_NEXTTOGGLE_GET(epipe);
qtdstatus |= EHCI_QTD_SET_TOGGLE(tog);
cur = ehci_alloc_sqtd(sc);
@@ -2702,7 +2744,10 @@
usb_syncmem(&cur->dma, cur->offs, sizeof(cur->qtd),
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
*ep = cur;
- epipe->nexttoggle = tog;
+ if (tog)
+ EHCI_NEXTTOGGLE_SET(epipe);
+ else
+ EHCI_NEXTTOGGLE_CLR(epipe);
DPRINTFN(10,("ehci_alloc_sqtd_chain: return sqtd=%p sqtdend=%p\n",
*sp, *ep));
@@ -2846,9 +2891,11 @@
ehci_soft_qtd_t *sqtd;
ehci_physaddr_t cur;
u_int32_t qhstatus;
+ u_int32_t nstatus;
int s;
int hit;
int wake;
+ int fixdt;
DPRINTF(("ehci_abort_xfer: xfer=%p pipe=%p\n", xfer, epipe));
@@ -2902,11 +2949,21 @@
sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status),
sizeof(sqh->qh.qh_qtd.qtd_status),
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
- for (sqtd = exfer->sqtdstart; ; sqtd = sqtd->nextqtd) {
+ for (sqtd = exfer->sqtdstart, fixdt = 1; ; sqtd = sqtd->nextqtd) {
usb_syncmem(&sqtd->dma,
sqtd->offs + offsetof(ehci_qtd_t, qtd_status),
sizeof(sqtd->qtd.qtd_status),
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
+ nstatus = le32toh(sqtd->qtd.qtd_status);
+ if (fixdt && (nstatus & EHCI_QTD_ACTIVE)
+ && ((sqtd != exfer->sqtdend->nextqtd)
+ || EHCI_QTD_GET_BYTES(nstatus))) {
+ if (EHCI_QTD_GET_TOGGLE(nstatus))
+ EHCI_NEXTTOGGLE_SET(epipe);
+ else
+ EHCI_NEXTTOGGLE_CLR(epipe);
+ fixdt = 0;
+ }
sqtd->qtd.qtd_status |= htole32(EHCI_QTD_HALTED);
usb_syncmem(&sqtd->dma,
sqtd->offs + offsetof(ehci_qtd_t, qtd_status),
@@ -3260,7 +3317,7 @@
ehci_soft_qtd_t *end;
/* Start toggle at 1. */
- epipe->nexttoggle = 1;
+ EHCI_NEXTTOGGLE_SET(epipe);
err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer,
&next, &end);
if (err)
Index: sys/dev/usb/ehcivar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/ehcivar.h,v
retrieving revision 1.36
diff -u -r1.36 ehcivar.h
--- sys/dev/usb/ehcivar.h 24 Feb 2010 22:38:09 -0000 1.36
+++ sys/dev/usb/ehcivar.h 20 Apr 2010 07:23:25 -0000
@@ -167,6 +167,9 @@
device_t sc_child; /* /dev/usb# device */
char sc_dying;
struct usb_dma_reserve sc_dma_reserve;
+
+ /* data toggles for each endpoint of each device */
+ u_int32_t nexttoggle[USB_MAX_DEVICES];
} ehci_softc_t;
#define EREAD1(sc, a) bus_space_read_1((sc)->iot, (sc)->ioh, (a))
Index: sys/dev/usb/uhci.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/uhci.c,v
retrieving revision 1.232
diff -u -r1.232 uhci.c
--- sys/dev/usb/uhci.c 24 Feb 2010 22:38:09 -0000 1.232
+++ sys/dev/usb/uhci.c 20 Apr 2010 07:23:26 -0000
@@ -91,7 +91,6 @@
struct uhci_pipe {
struct usbd_pipe pipe;
- int nexttoggle;
u_char aborting;
usbd_xfer_handle abortstart, abortend;
@@ -125,6 +124,32 @@
} u;
};
+#define UHCI_NEXTTOGGLE(upipe) \
+ ((uhci_softc_t*)((upipe)->pipe.device->bus->hci_private)) \
+ ->nexttoggle[(upipe)->pipe.device->address]
+
+#define UHCI_PIPE_ENDPOINT_ADDR(upipe) \
+ UE_GET_ADDR((upipe)->pipe.endpoint->edesc->bEndpointAddress)
+
+#define UHCI_PIPE_ENDPOINT_DIR(upipe) \
+ UE_GET_DIR((upipe)->pipe.endpoint->edesc->bEndpointAddress)
+
+#define UHCI_NEXTTOGGLE_BIT(upipe) \
+ ((UHCI_PIPE_ENDPOINT_DIR(upipe) == UE_DIR_OUT) ? \
+ (0x00000001 << UHCI_PIPE_ENDPOINT_ADDR(upipe)) : \
+ (0x00010000 << UHCI_PIPE_ENDPOINT_ADDR(upipe)))
+
+#define UHCI_NEXTTOGGLE_SET(upipe) \
+ SET(UHCI_NEXTTOGGLE(upipe), UHCI_NEXTTOGGLE_BIT(upipe))
+
+#define UHCI_NEXTTOGGLE_ISSET(upipe) \
+ ISSET(UHCI_NEXTTOGGLE(upipe), UHCI_NEXTTOGGLE_BIT(upipe))
+
+#define UHCI_NEXTTOGGLE_GET(upipe) ((UHCI_NEXTTOGGLE_ISSET(upipe))?1:0)
+
+#define UHCI_NEXTTOGGLE_CLR(upipe) \
+ CLR(UHCI_NEXTTOGGLE(upipe), UHCI_NEXTTOGGLE_BIT(upipe))
+
Static void uhci_globalreset(uhci_softc_t *);
Static usbd_status uhci_portreset(uhci_softc_t*, int);
Static void uhci_reset(uhci_softc_t *);
@@ -171,6 +196,9 @@
Static usbd_xfer_handle uhci_allocx(struct usbd_bus *);
Static void uhci_freex(struct usbd_bus *, usbd_xfer_handle);
+Static void uhci_clear_all_toggle(struct usbd_bus *,
+ struct usbd_device *);
+
Static usbd_status uhci_device_ctrl_transfer(usbd_xfer_handle);
Static usbd_status uhci_device_ctrl_start(usbd_xfer_handle);
Static void uhci_device_ctrl_abort(usbd_xfer_handle);
@@ -287,6 +315,7 @@
uhci_freem,
uhci_allocx,
uhci_freex,
+ uhci_clear_all_toggle,
};
const struct usbd_pipe_methods uhci_root_ctrl_methods = {
@@ -529,6 +558,10 @@
UHCICMD(sc, UHCI_CMD_MAXP); /* Assume 64 byte packets at frame end */
+ /* initialize all data toggles to zero */
+ for (i = 0; i < USB_MAX_DEVICES; i++)
+ sc->nexttoggle[i] = 0;
+
DPRINTFN(1,("uhci_init: enabling\n"));
err = uhci_run(sc, 1); /* and here we go... */
@@ -683,6 +716,14 @@
SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
}
+Static void
+uhci_clear_all_toggle(struct usbd_bus *bus, struct usbd_device *dev)
+{
+ struct uhci_softc *sc = bus->hci_private;
+
+ sc->nexttoggle[dev->address] = 0;
+}
+
/*
* Handle suspend/resume.
*
@@ -1564,8 +1605,12 @@
}
}
/* If there are left over TDs we need to update the toggle. */
- if (std != NULL)
- upipe->nexttoggle = UHCI_TD_GET_DT(le32toh(std->td.td_token));
+ if (std != NULL) {
+ if (UHCI_TD_GET_DT(le32toh(std->td.td_token)))
+ UHCI_NEXTTOGGLE_SET(upipe);
+ else
+ UHCI_NEXTTOGGLE_CLR(upipe);
+ }
status &= UHCI_TD_ERROR;
DPRINTFN(10, ("uhci_idone: actlen=%d, status=0x%x\n",
@@ -1884,10 +1929,13 @@
DPRINTFN(-1,("uhci_alloc_std_chain: ntd=0\n"));
return (USBD_NORMAL_COMPLETION);
}
- tog = upipe->nexttoggle;
+ tog = UHCI_NEXTTOGGLE_GET(upipe);
if (ntd % 2 == 0)
tog ^= 1;
- upipe->nexttoggle = tog ^ 1;
+ if (tog ^ 1)
+ UHCI_NEXTTOGGLE_SET(upipe);
+ else
+ UHCI_NEXTTOGGLE_CLR(upipe);
lastp = NULL;
lastlink = UHCI_PTR_T;
ntd--;
@@ -1928,7 +1976,7 @@
}
*sp = lastp;
DPRINTFN(10, ("uhci_alloc_std_chain: nexttog=%d\n",
- upipe->nexttoggle));
+ UHCI_NEXTTOGGLE_GET(upipe)));
return (USBD_NORMAL_COMPLETION);
}
@@ -1936,7 +1984,7 @@
uhci_device_clear_toggle(usbd_pipe_handle pipe)
{
struct uhci_pipe *upipe = (struct uhci_pipe *)pipe;
- upipe->nexttoggle = 0;
+ UHCI_NEXTTOGGLE_CLR(upipe);
}
void
@@ -2077,6 +2125,7 @@
uhci_soft_td_t *std;
int s;
int wake;
+ int fixdt;
DPRINTFN(1,("uhci_abort_xfer: xfer=%p, status=%d\n", xfer, status));
@@ -2120,11 +2169,18 @@
xfer->status = status; /* make software ignore it */
usb_uncallout(xfer->timeout_handle, uhci_timeout, ii);
DPRINTFN(1,("uhci_abort_xfer: stop ii=%p\n", ii));
- for (std = ii->stdstart; std != NULL; std = std->link.std) {
+ for (std = ii->stdstart, fixdt = 1; std != NULL; std = std->link.std) {
usb_syncmem(&std->dma,
std->offs + offsetof(uhci_td_t, td_status),
sizeof(std->td.td_status),
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
+ if (fixdt && (le32toh(std->td.td_status) & UHCI_TD_ACTIVE)) {
+ if (UHCI_TD_GET_DT(le32toh(std->td.td_token)))
+ UHCI_NEXTTOGGLE_SET(upipe);
+ else
+ UHCI_NEXTTOGGLE_CLR(upipe);
+ fixdt = 0;
+ }
std->td.td_status &= htole32(~(UHCI_TD_ACTIVE | UHCI_TD_IOC));
usb_syncmem(&std->dma,
std->offs + offsetof(uhci_td_t, td_status),
@@ -2409,7 +2465,7 @@
/* Set up data transaction */
if (len != 0) {
- upipe->nexttoggle = 1;
+ UHCI_NEXTTOGGLE_SET(upipe);
err = uhci_alloc_std_chain(upipe, sc, len, isread, xfer->flags,
&xfer->dmabuf, &data, &dataend);
if (err)
@@ -3183,7 +3239,6 @@
ed->bEndpointAddress, sc->sc_addr));
upipe->aborting = 0;
- upipe->nexttoggle = 0;
if (pipe->device->address == sc->sc_addr) {
switch (ed->bEndpointAddress) {
Index: sys/dev/usb/uhcivar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/uhcivar.h,v
retrieving revision 1.47
diff -u -r1.47 uhcivar.h
--- sys/dev/usb/uhcivar.h 24 Feb 2010 22:38:09 -0000 1.47
+++ sys/dev/usb/uhcivar.h 20 Apr 2010 07:23:26 -0000
@@ -181,6 +181,8 @@
#ifdef __NetBSD__
struct usb_dma_reserve sc_dma_reserve;
#endif
+ /* data toggles for each endpoint of each device */
+ u_int32_t nexttoggle[USB_MAX_DEVICES];
} uhci_softc_t;
usbd_status uhci_init(uhci_softc_t *);
Index: sys/dev/usb/usb_subr.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/usb_subr.c,v
retrieving revision 1.167
diff -u -r1.167 usb_subr.c
--- sys/dev/usb/usb_subr.c 12 Nov 2009 20:11:35 -0000 1.167
+++ sys/dev/usb/usb_subr.c 20 Apr 2010 07:23:26 -0000
@@ -698,6 +698,9 @@
}
}
+ /* this is a configuration event, so reset all data toggles */
+ dev->bus->methods->clear_all_toggle(dev->bus, dev);
+
return (USBD_NORMAL_COMPLETION);
bad:
Index: sys/dev/usb/usbdi.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/usbdi.c,v
retrieving revision 1.127
diff -u -r1.127 usbdi.c
--- sys/dev/usb/usbdi.c 16 Jan 2010 17:03:03 -0000 1.127
+++ sys/dev/usb/usbdi.c 20 Apr 2010 07:23:31 -0000
@@ -669,7 +669,14 @@
USETW(req.wValue, iface->idesc->bAlternateSetting);
USETW(req.wIndex, iface->idesc->bInterfaceNumber);
USETW(req.wLength, 0);
- return (usbd_do_request(iface->device, &req, 0));
+ err = usbd_do_request(iface->device, &req, 0);
+
+ /* this is a configuration event, so reset all data toggles */
+ if (!err)
+ iface->device->bus->methods
+ ->clear_all_toggle(iface->device->bus, iface->device);
+
+ return err;
}
int
Index: sys/dev/usb/usbdivar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/usbdivar.h,v
retrieving revision 1.91
diff -u -r1.91 usbdivar.h
--- sys/dev/usb/usbdivar.h 12 Nov 2009 20:11:35 -0000 1.91
+++ sys/dev/usb/usbdivar.h 20 Apr 2010 07:23:31 -0000
@@ -57,6 +57,8 @@
void (*freem)(struct usbd_bus *, usb_dma_t *);
struct usbd_xfer * (*allocx)(struct usbd_bus *);
void (*freex)(struct usbd_bus *, struct usbd_xfer *);
+ void (*clear_all_toggle)(struct usbd_bus *,
+ struct usbd_device *);
};
struct usbd_pipe_methods {
Index: ./sys/dev/usb/ohci.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/ohci.c,v
retrieving revision 1.206
diff -u -r1.206 ohci.c
--- ./sys/dev/usb/ohci.c 24 Feb 2010 22:38:09 -0000 1.206
+++ ./sys/dev/usb/ohci.c 24 Apr 2010 05:11:38 -0000
@@ -134,6 +134,9 @@
Static usbd_xfer_handle ohci_allocx(struct usbd_bus *);
Static void ohci_freex(struct usbd_bus *, usbd_xfer_handle);
+Static void ohci_clear_all_toggle(struct usbd_bus *,
+ struct usbd_device *);
+
Static usbd_status ohci_root_ctrl_transfer(usbd_xfer_handle);
Static usbd_status ohci_root_ctrl_start(usbd_xfer_handle);
Static void ohci_root_ctrl_abort(usbd_xfer_handle);
@@ -273,6 +276,7 @@
ohci_freem,
ohci_allocx,
ohci_freex,
+ ohci_clear_all_toggle,
};
Static const struct usbd_pipe_methods ohci_root_ctrl_methods = {
@@ -983,6 +987,18 @@
SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
}
+Static void
+ohci_clear_all_toggle(struct usbd_bus *bus, struct usbd_device *dev)
+{
+ struct ohci_softc *sc = bus->hci_private;
+ struct ohci_soft_ed *ed = sc->sc_bulk_head;
+ while (ed != NULL) {
+ if (OHCI_ED_GET_FA(ed->ed.ed_flags) == dev->address)
+ ed->ed.ed_headp &= HTOO32(~OHCI_TOGGLECARRY);
+ ed = ed->next;
+ }
+}
+
/*
* Shut down the controller when the system is going down.
*/
Home |
Main Index |
Thread Index |
Old Index