From ef7f6c7084b333c7524dcd297e0578d43733a2a2 Mon Sep 17 00:00:00 2001
From: Alan Stern <stern@rowland.harvard.edu>
Date: Thu, 5 Apr 2007 16:03:49 -0400
Subject: [PATCH] USB: more autosuspend timer stuff

This patch (as879) ties up some loose ends from an earlier patch.
These are things I didn't think to include at the time but which
clearly belonged there.

	If an autosuspend fails because driver activity races with
	the autosuspend call, restart the autosuspend timer.

	When a device is resumed by an external request, it counts
	as device activity and should update the last_busy time so
	that the next autoresume won't occur immediately.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/usb/core/driver.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index b9f7f90aef827..2619986e53000 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -983,7 +983,10 @@ static int autosuspend_check(struct usb_device *udev)
 
 #else
 
-#define autosuspend_check(udev)		0
+static inline int autosuspend_check(struct usb_device *udev)
+{
+	return 0;
+}
 
 #endif	/* CONFIG_USB_SUSPEND */
 
@@ -1041,7 +1044,6 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
 		if (status < 0)
 			goto done;
 	}
-	cancel_delayed_work(&udev->autosuspend);
 
 	/* Suspend all the interfaces and then udev itself */
 	if (udev->actconfig) {
@@ -1062,9 +1064,16 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
 			usb_resume_interface(intf);
 		}
 
+		/* Try another autosuspend when the interfaces aren't busy */
+		if (udev->auto_pm)
+			autosuspend_check(udev);
+
 	/* If the suspend succeeded, propagate it up the tree */
-	} else if (parent)
-		usb_autosuspend_device(parent);
+	} else {
+		cancel_delayed_work(&udev->autosuspend);
+		if (parent)
+			usb_autosuspend_device(parent);
+	}
 
  done:
 	// dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
@@ -1475,6 +1484,7 @@ int usb_external_resume_device(struct usb_device *udev)
 	usb_pm_lock(udev);
 	udev->auto_pm = 0;
 	status = usb_resume_both(udev);
+	udev->last_busy = jiffies;
 	usb_pm_unlock(udev);
 
 	/* Now that the device is awake, we can start trying to autosuspend
-- 
GitLab