aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/xhci-ring.c
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2010-05-06 16:40:08 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-05-20 16:21:30 -0400
commit1624ae1c19e227096ba85bfc389d9b99cb6f7dde (patch)
treefd6040fbcee96469b8878687b0ce8478b63d9098 /drivers/usb/host/xhci-ring.c
parente40152ee1e1c7a63f4777791863215e3faa37a86 (diff)
USB: xhci: Fix issue with set interface after stall.
When the USB core installs a new interface, it unconditionally clears the halts on all the endpoints on the new interface. Usually the xHCI host needs to know when an endpoint is reset, so it can change its internal endpoint state. In this case, it doesn't care, because the endpoints were never halted in the first place. To avoid issuing a redundant Reset Endpoint command, the xHCI driver looks at xhci_virt_ep->stopped_td to determine if the endpoint was actually halted. However, the functions that handle the stall never set that variable to NULL after it dealt with the stall. So if an endpoint stalled and a Reset Endpoint command completed, and then the class driver tried to install a new alternate setting, the xHCI driver would access the old xhci_virt_ep->stopped_td pointer. A similar problem occurs if the endpoint has been stopped to cancel a transfer. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/xhci-ring.c')
-rw-r--r--drivers/usb/host/xhci-ring.c7
1 files changed, 7 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 85d7e8f2085e..b520b37c0f36 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -578,6 +578,8 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
578 /* Otherwise just ring the doorbell to restart the ring */ 578 /* Otherwise just ring the doorbell to restart the ring */
579 ring_ep_doorbell(xhci, slot_id, ep_index); 579 ring_ep_doorbell(xhci, slot_id, ep_index);
580 } 580 }
581 ep->stopped_td = NULL;
582 ep->stopped_trb = NULL;
581 583
582 /* 584 /*
583 * Drop the lock and complete the URBs in the cancelled TD list. 585 * Drop the lock and complete the URBs in the cancelled TD list.
@@ -1061,8 +1063,13 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci,
1061 ep->ep_state |= EP_HALTED; 1063 ep->ep_state |= EP_HALTED;
1062 ep->stopped_td = td; 1064 ep->stopped_td = td;
1063 ep->stopped_trb = event_trb; 1065 ep->stopped_trb = event_trb;
1066
1064 xhci_queue_reset_ep(xhci, slot_id, ep_index); 1067 xhci_queue_reset_ep(xhci, slot_id, ep_index);
1065 xhci_cleanup_stalled_ring(xhci, td->urb->dev, ep_index); 1068 xhci_cleanup_stalled_ring(xhci, td->urb->dev, ep_index);
1069
1070 ep->stopped_td = NULL;
1071 ep->stopped_trb = NULL;
1072
1066 xhci_ring_cmd_db(xhci); 1073 xhci_ring_cmd_db(xhci);
1067} 1074}
1068 1075