aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2009-07-27 15:03:36 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-07-28 17:31:12 -0400
commit62889610f5591005bed9517360e17531684f72d0 (patch)
tree3fe063ec9a07d3cee20874fd0000be92fd0f8a9e /drivers/usb
parent8e595a5d30a5ee4bb745d4da6439d73ed7d91054 (diff)
USB: xhci: Handle short control packets correctly.
When there is a short packet on a control transfer, the xHCI host controller hardware will generate two events. The first event will be for the data stage TD with a completion code for a short packet. The second event will be for the status stage with a successful completion code. Before this patch, the xHCI driver would giveback the short control URB when it received the event for the data stage TD. Then it would become confused when it saw a status stage event for the endpoint for an URB it had already finished processing. Change the xHCI host controller driver to wait for the status stage event when it receives a short transfer completion code for a data stage TD. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/xhci-ring.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 588686fca471..5dd3b1fd71c0 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -892,15 +892,23 @@ static int handle_tx_event(struct xhci_hcd *xhci,
892 if (event_trb != ep_ring->dequeue) { 892 if (event_trb != ep_ring->dequeue) {
893 /* The event was for the status stage */ 893 /* The event was for the status stage */
894 if (event_trb == td->last_trb) { 894 if (event_trb == td->last_trb) {
895 td->urb->actual_length = 895 /* Did we already see a short data stage? */
896 td->urb->transfer_buffer_length; 896 if (td->urb->actual_length != 0)
897 status = -EREMOTEIO;
898 else
899 td->urb->actual_length =
900 td->urb->transfer_buffer_length;
897 } else { 901 } else {
898 /* Maybe the event was for the data stage? */ 902 /* Maybe the event was for the data stage? */
899 if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL) 903 if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL) {
900 /* We didn't stop on a link TRB in the middle */ 904 /* We didn't stop on a link TRB in the middle */
901 td->urb->actual_length = 905 td->urb->actual_length =
902 td->urb->transfer_buffer_length - 906 td->urb->transfer_buffer_length -
903 TRB_LEN(event->transfer_len); 907 TRB_LEN(event->transfer_len);
908 xhci_dbg(xhci, "Waiting for status stage event\n");
909 urb = NULL;
910 goto cleanup;
911 }
904 } 912 }
905 } 913 }
906 } else { 914 } else {