ChangeSet 1.2181.4.44, 2005/03/21 22:27:09-08:00, [EMAIL PROTECTED]

        [PATCH] UHCI updates
        
        This is the second of five updates to the uhci-hcd driver:
        
                Reimplement the port reset function by splitting it into two
                parts like the other HC drivers do, where the second part is
                triggered by a port status request when the reset finishes.  Now
                the entire hub_control routine can run without sleeping and can
                hold the device spinlock.
        
        Signed-off-by: Alan Stern <[EMAIL PROTECTED]>
        Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>



 uhci-hcd.c |    2 +-
 uhci-hcd.h |    4 ++--
 uhci-hub.c |   46 ++++++++++++++++++++++++++++++----------------
 3 files changed, 33 insertions(+), 19 deletions(-)


diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
--- a/drivers/usb/host/uhci-hcd.c       2005-03-30 15:13:29 -08:00
+++ b/drivers/usb/host/uhci-hcd.c       2005-03-30 15:13:29 -08:00
@@ -149,7 +149,7 @@
        /* Poll for and perform state transitions */
        hc_state_transitions(uhci);
        if (unlikely(uhci->suspended_ports && uhci->state != UHCI_SUSPENDED))
-               uhci_check_resume(uhci);
+               uhci_check_ports(uhci);
 
        init_stall_timer(hcd);
 }
diff -Nru a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
--- a/drivers/usb/host/uhci-hcd.h       2005-03-30 15:13:29 -08:00
+++ b/drivers/usb/host/uhci-hcd.h       2005-03-30 15:13:29 -08:00
@@ -368,11 +368,11 @@
        int resume_detect;                      /* Need a Global Resume */
        unsigned int saved_framenumber;         /* Save during PM suspend */
 
-       /* Support for port suspend/resume */
+       /* Support for port suspend/resume/reset */
        unsigned long port_c_suspend;           /* Bit-arrays of ports */
        unsigned long suspended_ports;
        unsigned long resuming_ports;
-       unsigned long resume_timeout;           /* Time to stop signalling */
+       unsigned long ports_timeout;            /* Time to stop signalling */
 
        /* Main list of URB's currently controlled by this HC */
        struct list_head urb_list;              /* P: uhci->lock */
diff -Nru a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
--- a/drivers/usb/host/uhci-hub.c       2005-03-30 15:13:29 -08:00
+++ b/drivers/usb/host/uhci-hub.c       2005-03-30 15:13:29 -08:00
@@ -66,7 +66,6 @@
 
 /* UHCI controllers don't automatically stop resume signalling after 20 msec,
  * so we have to poll and check timeouts in order to take care of it.
- * FIXME:  Synchronize access to these fields by a spinlock.
  */
 static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
                unsigned long port_addr)
@@ -87,22 +86,37 @@
        }
 }
 
-static void uhci_check_resume(struct uhci_hcd *uhci)
+static void uhci_check_ports(struct uhci_hcd *uhci)
 {
        unsigned int port;
        unsigned long port_addr;
+       int status;
 
        for (port = 0; port < uhci->rh_numports; ++port) {
                port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;
-               if (unlikely(inw(port_addr) & USBPORTSC_RD)) {
+               status = inw(port_addr);
+               if (unlikely(status & USBPORTSC_PR)) {
+                       if (time_after_eq(jiffies, uhci->ports_timeout)) {
+                               CLR_RH_PORTSTAT(USBPORTSC_PR);
+                               udelay(10);
+
+                               /* If the port was enabled before, turning
+                                * reset on caused a port enable change.
+                                * Turning reset off causes a port connect
+                                * status change.  Clear these changes. */
+                               CLR_RH_PORTSTAT(USBPORTSC_CSC | USBPORTSC_PEC);
+                               SET_RH_PORTSTAT(USBPORTSC_PE);
+                       }
+               }
+               if (unlikely(status & USBPORTSC_RD)) {
                        if (!test_bit(port, &uhci->resuming_ports)) {
 
                                /* Port received a wakeup request */
                                set_bit(port, &uhci->resuming_ports);
-                               uhci->resume_timeout = jiffies +
+                               uhci->ports_timeout = jiffies +
                                                msecs_to_jiffies(20);
                        } else if (time_after_eq(jiffies,
-                                               uhci->resume_timeout)) {
+                                               uhci->ports_timeout)) {
                                uhci_finish_suspend(uhci, port, port_addr);
                        }
                }
@@ -118,7 +132,9 @@
        unsigned int port = wIndex - 1;
        unsigned long port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;
        u16 wPortChange, wPortStatus;
+       unsigned long flags;
 
+       spin_lock_irqsave(&uhci->lock, flags);
        switch (typeReq) {
 
        case GetHubStatus:
@@ -128,9 +144,7 @@
                if (port >= uhci->rh_numports)
                        goto err;
 
-               if (uhci->resuming_ports)
-                       uhci_check_resume(uhci);
-
+               uhci_check_ports(uhci);
                status = inw(port_addr);
 
                /* Intel controllers report the OverCurrent bit active on.
@@ -203,15 +217,12 @@
                        OK(0);
                case USB_PORT_FEAT_RESET:
                        SET_RH_PORTSTAT(USBPORTSC_PR);
-                       mdelay(50);     /* USB v1.1 7.1.7.3 */
-                       CLR_RH_PORTSTAT(USBPORTSC_PR);
-                       udelay(10);
 
                        /* Reset terminates Resume signalling */
                        uhci_finish_suspend(uhci, port, port_addr);
-                       SET_RH_PORTSTAT(USBPORTSC_PE);
-                       mdelay(10);
-                       CLR_RH_PORTSTAT(USBPORTSC_PEC|USBPORTSC_CSC);
+
+                       /* USB v2.0 7.1.7.5 */
+                       uhci->ports_timeout = jiffies + msecs_to_jiffies(50);
                        OK(0);
                case USB_PORT_FEAT_POWER:
                        /* UHCI has no power switching */
@@ -238,8 +249,6 @@
                        if (test_bit(port, &uhci->suspended_ports) &&
                                        !test_and_set_bit(port,
                                                &uhci->resuming_ports)) {
-                               uhci->resume_timeout = jiffies +
-                                               msecs_to_jiffies(20);
                                SET_RH_PORTSTAT(USBPORTSC_RD);
 
                                /* The controller won't allow RD to be set
@@ -249,6 +258,10 @@
                                if (!(inw(port_addr) & USBPORTSC_RD))
                                        uhci_finish_suspend(uhci, port,
                                                        port_addr);
+                               else
+                                       /* USB v2.0 7.1.7.7 */
+                                       uhci->ports_timeout = jiffies +
+                                               msecs_to_jiffies(20);
                        }
                        OK(0);
                case USB_PORT_FEAT_C_SUSPEND:
@@ -280,6 +293,7 @@
 err:
                retval = -EPIPE;
        }
+       spin_unlock_irqrestore(&uhci->lock, flags);
 
        return retval;
 }
-
To unsubscribe from this list: send the line "unsubscribe bk-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to