USB: EHCI: update toggle state for linked QHs
[deliverable/linux.git] / drivers / usb / host / ehci-hcd.c
index 2b72473544d31d798034ed5aa92cb555384a8055..99c75603ec87143eebe77e1d8794457a87c03980 100644 (file)
@@ -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)
This page took 0.027626 seconds and 5 git commands to generate.