ChangeSet 1.2086.3.4, 2004/11/11 19:03:13-08:00, [EMAIL PROTECTED]

[PATCH] USB: usb PM updates, root hub stuff (2/4)

Makes usbcore handle some suspend scenarios more consistently, especially
when talking with root hubs.

 - Use usb_device->state, not device->power.power_state.  (The driver model
   power_state is still needed for interfaces.)  With USB_SUSPEND=n, there
   are also cases where the HCD_STATE_SUSPENDED needs to be used instead
   of testing for USB_STATE_SUSPENDED.

 - Updates usb_device->state for root hubs during suspend/resume.

 - Fixes a locking bug (extra "up") that got merged recently, affecting
   CONFIG_USB_SUSPEND.

 - Recover one of the "HC died" cases better.

 - Root hub timer updates, handling various suspend transitions more
   consistently:  don't duplicate earlier submit checks, only work
   when hub is configured, address various submit/resume races.

Together, these help hubs work better regardless of whether USB_SUSPEND
has been enabled (that's the only way USB_STATE_SUSPENDED appears), and
whether or not the HCD is marked as suspended (or maybe Alan would
want to call that "half suspended").

Signed-off-by: David Brownell <[EMAIL PROTECTED]>
Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>


 drivers/usb/core/hcd.c |   42 ++++++++++++++++++++++++------------------
 drivers/usb/core/hub.c |   26 ++++++++++++++------------
 drivers/usb/core/usb.c |    8 ++++----
 3 files changed, 42 insertions(+), 34 deletions(-)


diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
--- a/drivers/usb/core/hcd.c    2004-11-12 15:03:27 -08:00
+++ b/drivers/usb/core/hcd.c    2004-11-12 15:03:27 -08:00
@@ -479,6 +479,11 @@
 /*
  * Root Hub interrupt transfers are synthesized with a timer.
  * Completions are called in_interrupt() but not in_irq().
+ *
+ * Note: some root hubs (including common UHCI based designs) can't
+ * correctly issue port change IRQs.  They're the ones that _need_ a
+ * timer; most other root hubs don't.  Some systems could save a
+ * lot of battery power by eliminating these root hub timer IRQs.
  */
 
 static void rh_report_status (unsigned long ptr);
@@ -488,10 +493,7 @@
        int     len = 1 + (urb->dev->maxchild / 8);
 
        /* rh_timer protected by hcd_data_lock */
-       if (hcd->rh_timer.data
-                       || urb->status != -EINPROGRESS
-                       || urb->transfer_buffer_length < len
-                       || !HCD_IS_RUNNING (hcd->state)) {
+       if (hcd->rh_timer.data || urb->transfer_buffer_length < len) {
                dev_dbg (hcd->self.controller,
                                "not queuing rh status urb, stat %d\n",
                                urb->status);
@@ -530,19 +532,19 @@
                return;
        }
 
-       if (!HCD_IS_SUSPENDED (hcd->state))
-               length = hcd->driver->hub_status_data (
-                                       hcd, urb->transfer_buffer);
-
        /* complete the status urb, or retrigger the timer */
        spin_lock (&hcd_data_lock);
-       if (length > 0) {
-               hcd->rh_timer.data = 0;
-               urb->actual_length = length;
-               urb->status = 0;
-               urb->hcpriv = NULL;
-       } else if (!urb->dev->dev.power.power_state)
-               mod_timer (&hcd->rh_timer, jiffies + HZ/4);
+       if (urb->dev->state == USB_STATE_CONFIGURED) {
+               length = hcd->driver->hub_status_data (
+                                       hcd, urb->transfer_buffer);
+               if (length > 0) {
+                       hcd->rh_timer.data = 0;
+                       urb->actual_length = length;
+                       urb->status = 0;
+                       urb->hcpriv = NULL;
+               } else
+                       mod_timer (&hcd->rh_timer, jiffies + HZ/4);
+       }
        spin_unlock (&hcd_data_lock);
        spin_unlock (&urb->lock);
 
@@ -1103,13 +1105,17 @@
        spin_lock_irqsave (&hcd_data_lock, flags);
        if (unlikely (urb->reject))
                status = -EPERM;
-       else if (HCD_IS_RUNNING (hcd->state) &&
-                       hcd->state != USB_STATE_QUIESCING) {
+       else switch (hcd->state) {
+       case USB_STATE_RUNNING:
+       case USB_STATE_RESUMING:
                usb_get_dev (urb->dev);
                list_add_tail (&urb->urb_list, &dev->urb_list);
                status = 0;
-       } else
+               break;
+       default:
                status = -ESHUTDOWN;
+               break;
+       }
        spin_unlock_irqrestore (&hcd_data_lock, flags);
        if (status) {
                INIT_LIST_HEAD (&urb->urb_list);
diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
--- a/drivers/usb/core/hub.c    2004-11-12 15:03:27 -08:00
+++ b/drivers/usb/core/hub.c    2004-11-12 15:03:27 -08:00
@@ -1373,7 +1373,10 @@
                        status = hub_port_wait_reset(hdev, port, udev, delay);
 
                /* return on disconnect or reset */
-               if (status == -ENOTCONN || status == 0) {
+               switch (status) {
+               case 0:
+               case -ENOTCONN:
+               case -ENODEV:
                        clear_port_feature(hdev,
                                port + 1, USB_PORT_FEAT_C_RESET);
                        /* FIXME need disconnect() for NOTATTACHED device */
@@ -1524,7 +1527,7 @@
        if (port < 0)
                return port;
 
-       if (udev->dev.power.power_state
+       if (udev->state == USB_STATE_SUSPENDED
                        || udev->state == USB_STATE_NOTATTACHED) {
                return 0;
        }
@@ -1595,16 +1598,16 @@
         */
        if (!udev->parent) {
                struct usb_bus  *bus = udev->bus;
-               if (bus && bus->op->hub_suspend)
+               if (bus && bus->op->hub_suspend) {
                        status = bus->op->hub_suspend (bus);
-               else
+                       if (status == 0)
+                               usb_set_device_state(udev,
+                                               USB_STATE_SUSPENDED);
+               } else
                        status = -EOPNOTSUPP;
        } else
                status = hub_port_suspend(udev->parent, port);
 
-       if (status == 0)
-               udev->dev.power.power_state = PM_SUSPEND_MEM;
-       up(&udev->serialize);
        return status;
 }
 EXPORT_SYMBOL(__usb_suspend_device);
@@ -1652,7 +1655,6 @@
 
        /* caller owns the udev device lock */
        dev_dbg(&udev->dev, "usb resume\n");
-       udev->dev.power.power_state = PM_SUSPEND_ON;
 
        /* usb ch9 identifies four variants of SUSPENDED, based on what
         * state the device resumes to.  Linux currently won't see the
@@ -1809,14 +1811,15 @@
         */
        if (!udev->parent) {
                struct usb_bus  *bus = udev->bus;
-               if (bus && bus->op->hub_resume)
+               if (bus && bus->op->hub_resume) {
                        status = bus->op->hub_resume (bus);
-               else
+               } else
                        status = -EOPNOTSUPP;
                if (status == 0) {
                        /* TRSMRCY = 10 msec */
                        msleep(10);
-                       status = hub_resume (bus->root_hub
+                       usb_set_device_state (udev, USB_STATE_CONFIGURED);
+                       status = hub_resume (udev
                                        ->actconfig->interface[0]);
                }
        } else if (udev->state == USB_STATE_SUSPENDED) {
@@ -1824,7 +1827,6 @@
                status = hub_port_resume(udev->parent, port);
        } else {
                status = 0;
-               udev->dev.power.power_state = PM_SUSPEND_ON;
        }
        if (status < 0) {
                dev_dbg(&udev->dev, "can't resume, status %d\n",
diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c    2004-11-12 15:03:27 -08:00
+++ b/drivers/usb/core/usb.c    2004-11-12 15:03:27 -08:00
@@ -1395,10 +1395,6 @@
        struct usb_interface *intf;
        struct usb_driver *driver;
 
-       /* there's only one USB suspend state */
-       if (dev->power.power_state)
-               return 0;
-
        if (dev->driver == &usb_generic_driver)
                return usb_suspend_device (to_usb_device(dev), state);
 
@@ -1408,6 +1404,10 @@
 
        intf = to_usb_interface(dev);
        driver = to_usb_driver(dev->driver);
+
+       /* there's only one USB suspend state */
+       if (intf->dev.power.power_state)
+               return 0;
 
        if (driver->suspend)
                return driver->suspend(intf, state);



-------------------------------------------------------
This SF.Net email is sponsored by: InterSystems CACHE
FREE OODBMS DOWNLOAD - A multidimensional database that combines
robust object and relational technologies, making it a perfect match
for Java, C++,COM, XML, ODBC and JDBC. www.intersystems.com/match8
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to