summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2009-08-27 14:36:03 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2009-10-05 09:32:49 -0700
commit9fa7825a00bb88d022a22d914646a1ce5e3ee5e0 (patch)
treecdcd8d8e0dc95467952a58046135c92443fac5a1
parentfed392f6ec5c09647298b23519e366b3526c55ac (diff)
USB: xhci: Handle babbling endpoints correctly.
commit 83fbcdcca03013bb5af130d6d91eba11e3d3269e upstream. The 0.95 xHCI spec says that non-control endpoints will be halted if a babble is detected on a transfer. The 0.96 xHCI spec says all types of endpoints will be halted when a babble is detected. Some hardware that claims to be 0.95 compliant halts the control endpoint anyway. When a babble is detected on a control endpoint, check the hardware's output endpoint context to see if the endpoint is marked as halted. If the control endpoint is halted, a reset endpoint command must be issued and the transfer ring dequeue pointer needs to be moved past the stopped transfer. Basically, we treat it as if the control endpoint had stalled. Handle bulk babbling endpoints as if we got a completion event with a stall completion code. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/host/xhci-ring.c16
1 files changed, 14 insertions, 2 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index e876fd372dd1..2eadf0693862 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -993,6 +993,16 @@ static int handle_tx_event(struct xhci_hcd *xhci,
xhci_warn(xhci, "WARN: short transfer on control ep\n");
status = -EREMOTEIO;
break;
+ case COMP_BABBLE:
+ /* The 0.96 spec says a babbling control endpoint
+ * is not halted. The 0.96 spec says it is. Some HW
+ * claims to be 0.95 compliant, but it halts the control
+ * endpoint anyway. Check if a babble halted the
+ * endpoint.
+ */
+ if (ep_ctx->ep_info != EP_STATE_HALTED)
+ break;
+ /* else fall through */
case COMP_STALL:
/* Did we transfer part of the data (middle) phase? */
if (event_trb != ep_ring->dequeue &&
@@ -1137,7 +1147,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
ep_ring->stopped_td = td;
ep_ring->stopped_trb = event_trb;
} else {
- if (GET_COMP_CODE(event->transfer_len) == COMP_STALL) {
+ if (trb_comp_code == COMP_STALL ||
+ trb_comp_code == COMP_BABBLE) {
/* The transfer is completed from the driver's
* perspective, but we need to issue a set dequeue
* command for this stalled endpoint to move the dequeue
@@ -1168,7 +1179,8 @@ td_cleanup:
* control endpoints).
*/
if (usb_endpoint_xfer_control(&urb->ep->desc) ||
- GET_COMP_CODE(event->transfer_len) != COMP_STALL) {
+ (trb_comp_code != COMP_STALL &&
+ trb_comp_code != COMP_BABBLE)) {
kfree(td);
}
urb->hcpriv = NULL;