USB: change handling of negative autosuspend delays
authorAlan Stern <stern@rowland.harvard.edu>
Fri, 8 Jan 2010 17:57:02 +0000 (12:57 -0500)
committerGreg Kroah-Hartman <gregkh@suse.de>
Tue, 2 Mar 2010 22:54:11 +0000 (14:54 -0800)
This patch (as1327) changes the way negative autosuspend delays
prevent device from autosuspending.  The current code checks for
negative values explicitly in the autosuspend_check() routine.  The
updated code keeps things from getting that far by using
usb_autoresume_device() to increment the usage counter when a negative
delay is set, and by using usb_autosuspend_device() to decrement the
usage counter when a non-negative delay is set.

This complicates the set_autosuspend() attribute method code slightly,
but it will reduce the overall power management overhead.

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

index 4314f259524b16ed956c3f887c872b0742b9f648..f073c5cb4e7bc64e1c6f0b2f2f241592a6ebf151 100644 (file)
@@ -103,11 +103,21 @@ void usb_detect_quirks(struct usb_device *udev)
                dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
                                udev->quirks);
 
+#ifdef CONFIG_USB_SUSPEND
+
        /* By default, disable autosuspend for all devices.  The hub driver
         * will enable it for hubs.
         */
        usb_disable_autosuspend(udev);
 
+       /* Autosuspend can also be disabled if the initial autosuspend_delay
+        * is negative.
+        */
+       if (udev->autosuspend_delay < 0)
+               usb_autoresume_device(udev);
+
+#endif
+
        /* For the present, all devices default to USB-PERSIST enabled */
 #if 0          /* was: #ifdef CONFIG_PM */
        /* Hubs are automatically enabled for USB-PERSIST */
index 313e241f5cccd0a137a8696a8b5bb187a8d4725b..43c002e3a9aab2a819da74fd35f684f1ef5e83e2 100644 (file)
@@ -346,7 +346,8 @@ set_autosuspend(struct device *dev, struct device_attribute *attr,
                const char *buf, size_t count)
 {
        struct usb_device *udev = to_usb_device(dev);
-       int value;
+       int value, old_delay;
+       int rc;
 
        if (sscanf(buf, "%d", &value) != 1 || value >= INT_MAX/HZ ||
                        value <= - INT_MAX/HZ)
@@ -354,13 +355,24 @@ set_autosuspend(struct device *dev, struct device_attribute *attr,
        value *= HZ;
 
        usb_lock_device(udev);
+       old_delay = udev->autosuspend_delay;
        udev->autosuspend_delay = value;
-       if (value >= 0)
-               usb_try_autosuspend_device(udev);
-       else {
-               if (usb_autoresume_device(udev) == 0)
+
+       if (old_delay < 0) {    /* Autosuspend wasn't allowed */
+               if (value >= 0)
                        usb_autosuspend_device(udev);
+       } else {                /* Autosuspend was allowed */
+               if (value < 0) {
+                       rc = usb_autoresume_device(udev);
+                       if (rc < 0) {
+                               count = rc;
+                               udev->autosuspend_delay = old_delay;
+                       }
+               } else {
+                       usb_try_autosuspend_device(udev);
+               }
        }
+
        usb_unlock_device(udev);
        return count;
 }