aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2010-04-02 13:20:11 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-04-22 18:18:27 -0400
commit5f677f1d45b2bf08085bbba7394392dfa586fa8e (patch)
tree0eeec0555c343b11adaee5f9f418f58a083c6273 /drivers/usb/core
parent9a61d72602771906e11a5944e8571f8006387b39 (diff)
USB: fix remote wakeup settings during system sleep
This patch (as1363) changes the way USB remote wakeup is handled during system sleeps. It won't be enabled unless an interface driver specifically needs it. Also, it won't be enabled during the FREEZE or QUIESCE phases of hibernation, when the system doesn't respond to wakeup events anyway. Finally, if the device is already runtime-suspended with remote wakeup enabled, but wakeup is supposed to be disabled for the system sleep, the device gets woken up so that it can be suspended again with the proper wakeup setting. This will fix problems people have reported with certain USB webcams that generate wakeup requests when they shouldn't, and as a result cause system suspends to fail. See https://bugs.launchpad.net/ubuntu/+source/linux/+bug/515109 Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Tested-by: Erik Andrén <erik.andren@gmail.com> CC: <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/driver.c36
1 files changed, 35 insertions, 1 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 6a3b5cae3a6e..64b91d6c5a5d 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1263,13 +1263,47 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
1263 return status; 1263 return status;
1264} 1264}
1265 1265
1266static void choose_wakeup(struct usb_device *udev, pm_message_t msg)
1267{
1268 int w, i;
1269 struct usb_interface *intf;
1270
1271 /* Remote wakeup is needed only when we actually go to sleep.
1272 * For things like FREEZE and QUIESCE, if the device is already
1273 * autosuspended then its current wakeup setting is okay.
1274 */
1275 if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_QUIESCE) {
1276 if (udev->state != USB_STATE_SUSPENDED)
1277 udev->do_remote_wakeup = 0;
1278 return;
1279 }
1280
1281 /* If remote wakeup is permitted, see whether any interface drivers
1282 * actually want it.
1283 */
1284 w = 0;
1285 if (device_may_wakeup(&udev->dev) && udev->actconfig) {
1286 for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
1287 intf = udev->actconfig->interface[i];
1288 w |= intf->needs_remote_wakeup;
1289 }
1290 }
1291
1292 /* If the device is autosuspended with the wrong wakeup setting,
1293 * autoresume now so the setting can be changed.
1294 */
1295 if (udev->state == USB_STATE_SUSPENDED && w != udev->do_remote_wakeup)
1296 pm_runtime_resume(&udev->dev);
1297 udev->do_remote_wakeup = w;
1298}
1299
1266/* The device lock is held by the PM core */ 1300/* The device lock is held by the PM core */
1267int usb_suspend(struct device *dev, pm_message_t msg) 1301int usb_suspend(struct device *dev, pm_message_t msg)
1268{ 1302{
1269 struct usb_device *udev = to_usb_device(dev); 1303 struct usb_device *udev = to_usb_device(dev);
1270 1304
1271 do_unbind_rebind(udev, DO_UNBIND); 1305 do_unbind_rebind(udev, DO_UNBIND);
1272 udev->do_remote_wakeup = device_may_wakeup(&udev->dev); 1306 choose_wakeup(udev, msg);
1273 return usb_suspend_both(udev, msg); 1307 return usb_suspend_both(udev, msg);
1274} 1308}
1275 1309