summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2007-10-10 16:30:12 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-10-12 14:55:34 -0700
commit271f9e68f3450ac8d1ff3bda36581f1ec0d0cc1f (patch)
tree245f6895f988086686fe338b0097fe9b99f1c9f9
parent32fe01985aa2cb2562f6fc171e526e279abe10db (diff)
USB: skip autosuspended devices during system resume
System suspends and hibernation are supposed to be as transparent as possible. By this reasoning, if a USB device is already autosuspended before the system sleep begins then it should remain autosuspended after the system wakes up. This patch (as1001) adds a skip_sys_resume flag to the usb_device structure and uses it to avoid waking up devices which were suspended when a system sleep began. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/core/driver.c27
-rw-r--r--include/linux/usb.h1
2 files changed, 21 insertions, 7 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 3f734240e0ec..8c1eac27f2de 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1540,9 +1540,21 @@ int usb_external_resume_device(struct usb_device *udev)
static int usb_suspend(struct device *dev, pm_message_t message)
{
+ struct usb_device *udev;
+
if (!is_usb_device(dev)) /* Ignore PM for interfaces */
return 0;
- return usb_external_suspend_device(to_usb_device(dev), message);
+ udev = to_usb_device(dev);
+
+ /* If udev is already suspended, we can skip this suspend and
+ * we should also skip the upcoming system resume. */
+ if (udev->state == USB_STATE_SUSPENDED) {
+ udev->skip_sys_resume = 1;
+ return 0;
+ }
+
+ udev->skip_sys_resume = 0;
+ return usb_external_suspend_device(udev, message);
}
static int usb_resume(struct device *dev)
@@ -1553,13 +1565,14 @@ static int usb_resume(struct device *dev)
return 0;
udev = to_usb_device(dev);
- /* If autoresume is disabled then we also want to prevent resume
- * during system wakeup. However, a "persistent-device" reset-resume
- * after power loss counts as a wakeup event. So allow a
- * reset-resume to occur if remote wakeup is enabled. */
- if (udev->autoresume_disabled) {
+ /* If udev->skip_sys_resume is set then udev was already suspended
+ * when the system suspend started, so we don't want to resume
+ * udev during this system wakeup. However a reset-resume counts
+ * as a wakeup event, so allow a reset-resume to occur if remote
+ * wakeup is enabled. */
+ if (udev->skip_sys_resume) {
if (!(udev->reset_resume && udev->do_remote_wakeup))
- return -EPERM;
+ return -EHOSTUNREACH;
}
return usb_external_resume_device(udev);
}
diff --git a/include/linux/usb.h b/include/linux/usb.h
index c10935fdc03a..c5c8f169d3cf 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -430,6 +430,7 @@ struct usb_device {
unsigned persist_enabled:1; /* USB_PERSIST enabled for this dev */
unsigned autosuspend_disabled:1; /* autosuspend and autoresume */
unsigned autoresume_disabled:1; /* disabled by the user */
+ unsigned skip_sys_resume:1; /* skip the next system resume */
#endif
};
#define to_usb_device(d) container_of(d, struct usb_device, dev)