summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/usb/ehci.c32
1 files changed, 21 insertions, 11 deletions
diff --git a/sys/dev/usb/ehci.c b/sys/dev/usb/ehci.c
index dad2e61ca11..73f3ec8997e 100644
--- a/sys/dev/usb/ehci.c
+++ b/sys/dev/usb/ehci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ehci.c,v 1.38 2005/03/07 11:12:04 pascoe Exp $ */
+/* $OpenBSD: ehci.c,v 1.39 2005/03/07 12:58:19 pascoe Exp $ */
/* $NetBSD: ehci.c,v 1.66 2004/06/30 03:11:56 mycroft Exp $ */
/*
@@ -761,7 +761,7 @@ ehci_idone(struct ehci_xfer *ex)
struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
ehci_soft_qtd_t *sqtd, *lsqtd;
u_int32_t status = 0, nstatus = 0;
- int actlen;
+ int actlen, cerr;
uint pkts_left;
DPRINTFN(/*12*/2, ("ehci_idone: ex=%p\n", ex));
@@ -833,12 +833,13 @@ ehci_idone(struct ehci_xfer *ex)
UGETW(xfer->pipe->endpoint->edesc->wMaxPacketSize);
epipe->nexttoggle ^= pkts_left % 2;
+ cerr = EHCI_QTD_GET_CERR(status);
status &= EHCI_QTD_STATERRS;
- DPRINTFN(/*10*/2, ("ehci_idone: len=%d, actlen=%d, status=0x%x\n",
- xfer->length, actlen, status));
+ DPRINTFN(/*10*/2, ("ehci_idone: len=%d, actlen=%d, cerr=%d, "
+ "status=0x%x\n", xfer->length, actlen, cerr, status));
xfer->actlen = actlen;
- if (status != 0) {
#ifdef EHCI_DEBUG
+ if (status != 0) {
char sbuf[128];
bitmask_snprintf((u_int32_t)status,
@@ -855,14 +856,23 @@ ehci_idone(struct ehci_xfer *ex)
ehci_dump_sqh(epipe->sqh);
ehci_dump_sqtds(ex->sqtdstart);
}
+ }
#endif
- if (status == EHCI_QTD_HALTED)
- xfer->status = USBD_STALLED;
- else
- xfer->status = USBD_IOERROR; /* more info XXX */
- } else {
+ /*
+ * XactErr with CErr > 0 indicates that there were one or more retries
+ * on the wire, but the transfer succeeded before the host controller
+ * gave up. Ignore the XactErr bit in this case, and determine the
+ * overall transfer status from the remaining bits.
+ */
+ if (status & EHCI_QTD_XACTERR && cerr > 0)
+ status &= ~EHCI_QTD_XACTERR;
+
+ if (status == 0)
xfer->status = USBD_NORMAL_COMPLETION;
- }
+ else if (status == EHCI_QTD_HALTED)
+ xfer->status = USBD_STALLED;
+ else
+ xfer->status = USBD_IOERROR; /* more info XXX */
usb_transfer_complete(xfer);
DPRINTFN(/*12*/2, ("ehci_idone: ex=%p done\n", ex));