summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorskrll <skrll@NetBSD.org>2013-12-01 07:34:16 +0000
committerskrll <skrll@NetBSD.org>2013-12-01 07:34:16 +0000
commit05b855e77930da68d22fa5f5e24aafea72c694c4 (patch)
tree5fa7f6cf06925bbddd05c3e0effed5dc43f9a481 /sys/dev
parentbe2f04c5a4bc03c83b95afaf446cc0df13e6b358 (diff)
In ehci_check_qh_intr don't treat a short control transfer as done if the
status phase is still inflight. Let the hardware complete it. PR/48358: Repeated low-speed USB control transfers returning short data fail on EHCI PR/46696: uhub disables port where USB keyboard attached
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/usb/ehci.c25
1 files changed, 21 insertions, 4 deletions
diff --git a/sys/dev/usb/ehci.c b/sys/dev/usb/ehci.c
index 8b1a9d997de..ccf7ef4235a 100644
--- a/sys/dev/usb/ehci.c
+++ b/sys/dev/usb/ehci.c
@@ -1,4 +1,4 @@
-/* $NetBSD: ehci.c,v 1.220 2013/12/01 07:28:47 skrll Exp $ */
+/* $NetBSD: ehci.c,v 1.221 2013/12/01 07:34:16 skrll Exp $ */
/*
* Copyright (c) 2004-2012 The NetBSD Foundation, Inc.
@@ -53,7 +53,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.220 2013/12/01 07:28:47 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.221 2013/12/01 07:34:16 skrll Exp $");
#include "ohci.h"
#include "uhci.h"
@@ -839,9 +839,26 @@ ehci_check_qh_intr(ehci_softc_t *sc, struct ehci_xfer *ex)
/* Any kind of error makes the xfer done. */
if (status & EHCI_QTD_HALTED)
goto done;
- /* We want short packets, and it is short: it's done */
- if (EHCI_QTD_GET_BYTES(status) != 0)
+ /* Handle short packets */
+ if (EHCI_QTD_GET_BYTES(status) != 0) {
+ usbd_pipe_handle pipe = ex->xfer.pipe;
+ usb_endpoint_descriptor_t *ed =
+ pipe->endpoint->edesc;
+ uint8_t xt = UE_GET_XFERTYPE(ed->bmAttributes);
+
+ /*
+ * If we get here for a control transfer then
+ * we need to let the hardware complete the
+ * status phase. That is, we're not done
+ * quite yet.
+ *
+ * Otherwise, we're done.
+ */
+ if (xt == UE_CONTROL) {
+ break;
+ }
goto done;
+ }
}
DPRINTFN(12, ("ehci_check_intr: ex=%p std=%p still active\n",
ex, ex->sqtdstart));