summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/core/driver.c32
1 files changed, 30 insertions, 2 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 5d80d5eea0b8..34fc7bbc0ad5 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1175,9 +1175,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
udev->state == USB_STATE_SUSPENDED)
goto done;
- udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
-
if (msg.event & PM_EVENT_AUTO) {
+ udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
status = autosuspend_check(udev, 0);
if (status < 0)
goto done;
@@ -1742,6 +1741,34 @@ int usb_external_resume_device(struct usb_device *udev, pm_message_t msg)
return status;
}
+static void choose_wakeup(struct usb_device *udev, pm_message_t msg)
+{
+ int w, i;
+ struct usb_interface *intf;
+
+ /* Remote wakeup is needed only when we actually go to sleep.
+ * For things like FREEZE and QUIESCE, if the device is already
+ * autosuspended then its current wakeup setting is okay.
+ */
+ if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_QUIESCE) {
+ udev->do_remote_wakeup = 0;
+ return;
+ }
+
+ /* If remote wakeup is permitted, see whether any interface drivers
+ * actually want it.
+ */
+ w = 0;
+ if (device_may_wakeup(&udev->dev) && udev->actconfig) {
+ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ intf = udev->actconfig->interface[i];
+ w |= intf->needs_remote_wakeup;
+ }
+ }
+
+ udev->do_remote_wakeup = w;
+}
+
int usb_suspend(struct device *dev, pm_message_t msg)
{
struct usb_device *udev;
@@ -1761,6 +1788,7 @@ int usb_suspend(struct device *dev, pm_message_t msg)
}
udev->skip_sys_resume = 0;
+ choose_wakeup(udev, msg);
return usb_external_suspend_device(udev, msg);
}