diff options
| author | skrll <skrll@NetBSD.org> | 2013-12-01 07:34:16 +0000 |
|---|---|---|
| committer | skrll <skrll@NetBSD.org> | 2013-12-01 07:34:16 +0000 |
| commit | 05b855e77930da68d22fa5f5e24aafea72c694c4 (patch) | |
| tree | 5fa7f6cf06925bbddd05c3e0effed5dc43f9a481 /sys/dev | |
| parent | be2f04c5a4bc03c83b95afaf446cc0df13e6b358 (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.c | 25 |
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)); |
