[PATCH 111/220] USB: change handling of negative autosuspend delays

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>

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@xxxxxxxxxxxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxx>
---
 drivers/usb/core/quirks.c |   10 ++++++++++
 drivers/usb/core/sysfs.c  |   22 +++++++++++++++++-----
 2 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 4314f25..f073c5c 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -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 */
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 313e241..43c002e 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -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;
 }
-- 
1.7.0.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux