Commit 271f9e68 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

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: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 32fe0198
...@@ -1540,9 +1540,21 @@ int usb_external_resume_device(struct usb_device *udev) ...@@ -1540,9 +1540,21 @@ int usb_external_resume_device(struct usb_device *udev)
static int usb_suspend(struct device *dev, pm_message_t message) static int usb_suspend(struct device *dev, pm_message_t message)
{ {
struct usb_device *udev;
if (!is_usb_device(dev)) /* Ignore PM for interfaces */ if (!is_usb_device(dev)) /* Ignore PM for interfaces */
return 0; 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) static int usb_resume(struct device *dev)
...@@ -1553,13 +1565,14 @@ static int usb_resume(struct device *dev) ...@@ -1553,13 +1565,14 @@ static int usb_resume(struct device *dev)
return 0; return 0;
udev = to_usb_device(dev); udev = to_usb_device(dev);
/* If autoresume is disabled then we also want to prevent resume /* If udev->skip_sys_resume is set then udev was already suspended
* during system wakeup. However, a "persistent-device" reset-resume * when the system suspend started, so we don't want to resume
* after power loss counts as a wakeup event. So allow a * udev during this system wakeup. However a reset-resume counts
* reset-resume to occur if remote wakeup is enabled. */ * as a wakeup event, so allow a reset-resume to occur if remote
if (udev->autoresume_disabled) { * wakeup is enabled. */
if (udev->skip_sys_resume) {
if (!(udev->reset_resume && udev->do_remote_wakeup)) if (!(udev->reset_resume && udev->do_remote_wakeup))
return -EPERM; return -EHOSTUNREACH;
} }
return usb_external_resume_device(udev); return usb_external_resume_device(udev);
} }
......
...@@ -430,6 +430,7 @@ struct usb_device { ...@@ -430,6 +430,7 @@ struct usb_device {
unsigned persist_enabled:1; /* USB_PERSIST enabled for this dev */ unsigned persist_enabled:1; /* USB_PERSIST enabled for this dev */
unsigned autosuspend_disabled:1; /* autosuspend and autoresume */ unsigned autosuspend_disabled:1; /* autosuspend and autoresume */
unsigned autoresume_disabled:1; /* disabled by the user */ unsigned autoresume_disabled:1; /* disabled by the user */
unsigned skip_sys_resume:1; /* skip the next system resume */
#endif #endif
}; };
#define to_usb_device(d) container_of(d, struct usb_device, dev) #define to_usb_device(d) container_of(d, struct usb_device, dev)
......
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