USB: improve runtime remote wakeup settings
authorAlan Stern <stern@rowland.harvard.edu>
Fri, 2 Apr 2010 17:18:50 +0000 (13:18 -0400)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 20 May 2010 20:21:37 +0000 (13:21 -0700)
This patch (as1362) adjusts the way the USB autosuspend routines
handle remote-wakeup settings.  They aren't supposed to use
device_may_wakeup(); that test is intended only for system sleep, not
runtime power management.  Instead the code checks to see if any
interface drivers need remote wakeup; if they do then it is enabled,
provided the device is capable of it.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/core/driver.c

index edff55a325759b80fa6dcde9d9a998f413a0db8c..271e857be0fab02f82c8796710ea51ae1fd7aacc 100644 (file)
@@ -1486,9 +1486,6 @@ int usb_autoresume_device(struct usb_device *udev)
  * 0, a delayed autosuspend request for @intf's device is attempted.  The
  * attempt may fail (see autosuspend_check()).
  *
- * If the driver has set @intf->needs_remote_wakeup then autosuspend will
- * take place only if the device's remote-wakeup facility is enabled.
- *
  * This routine can run only in process context.
  */
 void usb_autopm_put_interface(struct usb_interface *intf)
@@ -1673,14 +1670,14 @@ EXPORT_SYMBOL_GPL(usb_autopm_get_interface_no_resume);
 /* Internal routine to check whether we may autosuspend a device. */
 static int autosuspend_check(struct usb_device *udev)
 {
-       int                     i;
+       int                     w, i;
        struct usb_interface    *intf;
        unsigned long           suspend_time, j;
 
        /* Fail if autosuspend is disabled, or any interfaces are in use, or
         * any interface drivers require remote wakeup but it isn't available.
         */
-       udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
+       w = 0;
        if (udev->actconfig) {
                for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
                        intf = udev->actconfig->interface[i];
@@ -1694,12 +1691,7 @@ static int autosuspend_check(struct usb_device *udev)
                                continue;
                        if (atomic_read(&intf->dev.power.usage_count) > 0)
                                return -EBUSY;
-                       if (intf->needs_remote_wakeup &&
-                                       !udev->do_remote_wakeup) {
-                               dev_dbg(&udev->dev, "remote wakeup needed "
-                                               "for autosuspend\n");
-                               return -EOPNOTSUPP;
-                       }
+                       w |= intf->needs_remote_wakeup;
 
                        /* Don't allow autosuspend if the device will need
                         * a reset-resume and any of its interface drivers
@@ -1715,6 +1707,11 @@ static int autosuspend_check(struct usb_device *udev)
                        }
                }
        }
+       if (w && !device_can_wakeup(&udev->dev)) {
+               dev_dbg(&udev->dev, "remote wakeup needed for autosuspend\n");
+               return -EOPNOTSUPP;
+       }
+       udev->do_remote_wakeup = w;
 
        /* If everything is okay but the device hasn't been idle for long
         * enough, queue a delayed autosuspend request.