aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-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