From 86c07ae0cbe1a660de2dba724d1f39ba6923d03c Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 2 Apr 2010 13:20:11 -0400 Subject: [PATCH] --- yaml --- r: 190164 b: refs/heads/master c: 5f677f1d45b2bf08085bbba7394392dfa586fa8e h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/drivers/usb/core/driver.c | 36 ++++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/[refs] b/[refs] index 8c1e9ded7415..291d97748f6b 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 9a61d72602771906e11a5944e8571f8006387b39 +refs/heads/master: 5f677f1d45b2bf08085bbba7394392dfa586fa8e diff --git a/trunk/drivers/usb/core/driver.c b/trunk/drivers/usb/core/driver.c index 6a3b5cae3a6e..64b91d6c5a5d 100644 --- a/trunk/drivers/usb/core/driver.c +++ b/trunk/drivers/usb/core/driver.c @@ -1263,13 +1263,47 @@ static int usb_resume_both(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) { + if (udev->state != USB_STATE_SUSPENDED) + 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; + } + } + + /* If the device is autosuspended with the wrong wakeup setting, + * autoresume now so the setting can be changed. + */ + if (udev->state == USB_STATE_SUSPENDED && w != udev->do_remote_wakeup) + pm_runtime_resume(&udev->dev); + udev->do_remote_wakeup = w; +} + /* The device lock is held by the PM core */ int usb_suspend(struct device *dev, pm_message_t msg) { struct usb_device *udev = to_usb_device(dev); do_unbind_rebind(udev, DO_UNBIND); - udev->do_remote_wakeup = device_may_wakeup(&udev->dev); + choose_wakeup(udev, msg); return usb_suspend_both(udev, msg); }