|
@@ -1030,12 +1030,14 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
|
|
|
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
|
|
struct ehci_qh *qh;
|
|
|
int eptype = usb_endpoint_type(&ep->desc);
|
|
|
+ int epnum = usb_endpoint_num(&ep->desc);
|
|
|
+ int is_out = usb_endpoint_dir_out(&ep->desc);
|
|
|
+ unsigned long flags;
|
|
|
|
|
|
if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT)
|
|
|
return;
|
|
|
|
|
|
- rescan:
|
|
|
- spin_lock_irq(&ehci->lock);
|
|
|
+ spin_lock_irqsave(&ehci->lock, flags);
|
|
|
qh = ep->hcpriv;
|
|
|
|
|
|
/* For Bulk and Interrupt endpoints we maintain the toggle state
|
|
@@ -1044,29 +1046,24 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
|
|
|
* the toggle bit in the QH.
|
|
|
*/
|
|
|
if (qh) {
|
|
|
+ usb_settoggle(qh->dev, epnum, is_out, 0);
|
|
|
if (!list_empty(&qh->qtd_list)) {
|
|
|
WARN_ONCE(1, "clear_halt for a busy endpoint\n");
|
|
|
- } else if (qh->qh_state == QH_STATE_IDLE) {
|
|
|
- qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
|
|
|
- } else {
|
|
|
- /* It's not safe to write into the overlay area
|
|
|
- * while the QH is active. Unlink it first and
|
|
|
- * wait for the unlink to complete.
|
|
|
+ } else if (qh->qh_state == QH_STATE_LINKED) {
|
|
|
+
|
|
|
+ /* The toggle value in the QH can't be updated
|
|
|
+ * while the QH is active. Unlink it now;
|
|
|
+ * re-linking will call qh_refresh().
|
|
|
*/
|
|
|
- if (qh->qh_state == QH_STATE_LINKED) {
|
|
|
- if (eptype == USB_ENDPOINT_XFER_BULK) {
|
|
|
- unlink_async(ehci, qh);
|
|
|
- } else {
|
|
|
- intr_deschedule(ehci, qh);
|
|
|
- (void) qh_schedule(ehci, qh);
|
|
|
- }
|
|
|
+ if (eptype == USB_ENDPOINT_XFER_BULK) {
|
|
|
+ unlink_async(ehci, qh);
|
|
|
+ } else {
|
|
|
+ intr_deschedule(ehci, qh);
|
|
|
+ (void) qh_schedule(ehci, qh);
|
|
|
}
|
|
|
- spin_unlock_irq(&ehci->lock);
|
|
|
- schedule_timeout_uninterruptible(1);
|
|
|
- goto rescan;
|
|
|
}
|
|
|
}
|
|
|
- spin_unlock_irq(&ehci->lock);
|
|
|
+ spin_unlock_irqrestore(&ehci->lock, flags);
|
|
|
}
|
|
|
|
|
|
static int ehci_get_frame (struct usb_hcd *hcd)
|