Commit 5899f1e0 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

USB: change handling of negative autosuspend delays

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: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 088f7fec
...@@ -103,11 +103,21 @@ void usb_detect_quirks(struct usb_device *udev) ...@@ -103,11 +103,21 @@ void usb_detect_quirks(struct usb_device *udev)
dev_dbg(&udev->dev, "USB quirks for this device: %x\n", dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
udev->quirks); udev->quirks);
#ifdef CONFIG_USB_SUSPEND
/* By default, disable autosuspend for all devices. The hub driver /* By default, disable autosuspend for all devices. The hub driver
* will enable it for hubs. * will enable it for hubs.
*/ */
usb_disable_autosuspend(udev); 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 */ /* For the present, all devices default to USB-PERSIST enabled */
#if 0 /* was: #ifdef CONFIG_PM */ #if 0 /* was: #ifdef CONFIG_PM */
/* Hubs are automatically enabled for USB-PERSIST */ /* Hubs are automatically enabled for USB-PERSIST */
......
...@@ -346,7 +346,8 @@ set_autosuspend(struct device *dev, struct device_attribute *attr, ...@@ -346,7 +346,8 @@ set_autosuspend(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct usb_device *udev = to_usb_device(dev); 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 || if (sscanf(buf, "%d", &value) != 1 || value >= INT_MAX/HZ ||
value <= - INT_MAX/HZ) value <= - INT_MAX/HZ)
...@@ -354,13 +355,24 @@ set_autosuspend(struct device *dev, struct device_attribute *attr, ...@@ -354,13 +355,24 @@ set_autosuspend(struct device *dev, struct device_attribute *attr,
value *= HZ; value *= HZ;
usb_lock_device(udev); usb_lock_device(udev);
old_delay = udev->autosuspend_delay;
udev->autosuspend_delay = value; udev->autosuspend_delay = value;
if (value >= 0)
usb_try_autosuspend_device(udev); if (old_delay < 0) { /* Autosuspend wasn't allowed */
else { if (value >= 0)
if (usb_autoresume_device(udev) == 0)
usb_autosuspend_device(udev); 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); usb_unlock_device(udev);
return count; return count;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment