提交 83fbcdcc 编写于 作者: S Sarah Sharp 提交者: Greg Kroah-Hartman

USB: xhci: Handle babbling endpoints correctly.

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: NSarah Sharp <sarah.a.sharp@linux.intel.com>
Cc: stable <stable@kernel.org>
Signed-off-by: NGreg Kroah-Hartman <gregkh@suse.de>
上级 66d1eebc
...@@ -993,6 +993,16 @@ static int handle_tx_event(struct xhci_hcd *xhci, ...@@ -993,6 +993,16 @@ static int handle_tx_event(struct xhci_hcd *xhci,
xhci_warn(xhci, "WARN: short transfer on control ep\n"); xhci_warn(xhci, "WARN: short transfer on control ep\n");
status = -EREMOTEIO; status = -EREMOTEIO;
break; 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: case COMP_STALL:
/* Did we transfer part of the data (middle) phase? */ /* Did we transfer part of the data (middle) phase? */
if (event_trb != ep_ring->dequeue && if (event_trb != ep_ring->dequeue &&
...@@ -1137,7 +1147,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, ...@@ -1137,7 +1147,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
ep_ring->stopped_td = td; ep_ring->stopped_td = td;
ep_ring->stopped_trb = event_trb; ep_ring->stopped_trb = event_trb;
} else { } 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 /* The transfer is completed from the driver's
* perspective, but we need to issue a set dequeue * perspective, but we need to issue a set dequeue
* command for this stalled endpoint to move the dequeue * command for this stalled endpoint to move the dequeue
...@@ -1168,7 +1179,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, ...@@ -1168,7 +1179,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
* control endpoints). * control endpoints).
*/ */
if (usb_endpoint_xfer_control(&urb->ep->desc) || 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); kfree(td);
} }
urb->hcpriv = NULL; urb->hcpriv = NULL;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册