aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/driver.c86
-rw-r--r--drivers/usb/core/hub.c5
-rw-r--r--drivers/usb/core/usb.c1
-rw-r--r--drivers/usb/core/usb.h1
4 files changed, 91 insertions, 2 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 8c081308b0e..23b3c7e79d4 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1341,6 +1341,19 @@ void usb_autosuspend_work(struct work_struct *work)
1341 usb_autopm_do_device(udev, 0); 1341 usb_autopm_do_device(udev, 0);
1342} 1342}
1343 1343
1344/* usb_autoresume_work - callback routine to autoresume a USB device */
1345void usb_autoresume_work(struct work_struct *work)
1346{
1347 struct usb_device *udev =
1348 container_of(work, struct usb_device, autoresume);
1349
1350 /* Wake it up, let the drivers do their thing, and then put it
1351 * back to sleep.
1352 */
1353 if (usb_autopm_do_device(udev, 1) == 0)
1354 usb_autopm_do_device(udev, -1);
1355}
1356
1344/** 1357/**
1345 * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces 1358 * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces
1346 * @udev: the usb_device to autosuspend 1359 * @udev: the usb_device to autosuspend
@@ -1492,6 +1505,45 @@ void usb_autopm_put_interface(struct usb_interface *intf)
1492EXPORT_SYMBOL_GPL(usb_autopm_put_interface); 1505EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
1493 1506
1494/** 1507/**
1508 * usb_autopm_put_interface_async - decrement a USB interface's PM-usage counter
1509 * @intf: the usb_interface whose counter should be decremented
1510 *
1511 * This routine does essentially the same thing as
1512 * usb_autopm_put_interface(): it decrements @intf's usage counter and
1513 * queues a delayed autosuspend request if the counter is <= 0. The
1514 * difference is that it does not acquire the device's pm_mutex;
1515 * callers must handle all synchronization issues themselves.
1516 *
1517 * Typically a driver would call this routine during an URB's completion
1518 * handler, if no more URBs were pending.
1519 *
1520 * This routine can run in atomic context.
1521 */
1522void usb_autopm_put_interface_async(struct usb_interface *intf)
1523{
1524 struct usb_device *udev = interface_to_usbdev(intf);
1525 int status = 0;
1526
1527 if (intf->condition == USB_INTERFACE_UNBOUND) {
1528 status = -ENODEV;
1529 } else {
1530 udev->last_busy = jiffies;
1531 --intf->pm_usage_cnt;
1532 if (udev->autosuspend_disabled || udev->autosuspend_delay < 0)
1533 status = -EPERM;
1534 else if (intf->pm_usage_cnt <= 0 &&
1535 !timer_pending(&udev->autosuspend.timer)) {
1536 queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
1537 round_jiffies_relative(
1538 udev->autosuspend_delay));
1539 }
1540 }
1541 dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
1542 __func__, status, intf->pm_usage_cnt);
1543}
1544EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async);
1545
1546/**
1495 * usb_autopm_get_interface - increment a USB interface's PM-usage counter 1547 * usb_autopm_get_interface - increment a USB interface's PM-usage counter
1496 * @intf: the usb_interface whose counter should be incremented 1548 * @intf: the usb_interface whose counter should be incremented
1497 * 1549 *
@@ -1537,6 +1589,37 @@ int usb_autopm_get_interface(struct usb_interface *intf)
1537EXPORT_SYMBOL_GPL(usb_autopm_get_interface); 1589EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
1538 1590
1539/** 1591/**
1592 * usb_autopm_get_interface_async - increment a USB interface's PM-usage counter
1593 * @intf: the usb_interface whose counter should be incremented
1594 *
1595 * This routine does much the same thing as
1596 * usb_autopm_get_interface(): it increments @intf's usage counter and
1597 * queues an autoresume request if the result is > 0. The differences
1598 * are that it does not acquire the device's pm_mutex (callers must
1599 * handle all synchronization issues themselves), and it does not
1600 * autoresume the device directly (it only queues a request). After a
1601 * successful call, the device will generally not yet be resumed.
1602 *
1603 * This routine can run in atomic context.
1604 */
1605int usb_autopm_get_interface_async(struct usb_interface *intf)
1606{
1607 struct usb_device *udev = interface_to_usbdev(intf);
1608 int status = 0;
1609
1610 if (intf->condition == USB_INTERFACE_UNBOUND)
1611 status = -ENODEV;
1612 else if (udev->autoresume_disabled)
1613 status = -EPERM;
1614 else if (++intf->pm_usage_cnt > 0 && udev->state == USB_STATE_SUSPENDED)
1615 queue_work(ksuspend_usb_wq, &udev->autoresume);
1616 dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
1617 __func__, status, intf->pm_usage_cnt);
1618 return status;
1619}
1620EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async);
1621
1622/**
1540 * usb_autopm_set_interface - set a USB interface's autosuspend state 1623 * usb_autopm_set_interface - set a USB interface's autosuspend state
1541 * @intf: the usb_interface whose state should be set 1624 * @intf: the usb_interface whose state should be set
1542 * 1625 *
@@ -1563,6 +1646,9 @@ EXPORT_SYMBOL_GPL(usb_autopm_set_interface);
1563void usb_autosuspend_work(struct work_struct *work) 1646void usb_autosuspend_work(struct work_struct *work)
1564{} 1647{}
1565 1648
1649void usb_autoresume_work(struct work_struct *work)
1650{}
1651
1566#endif /* CONFIG_USB_SUSPEND */ 1652#endif /* CONFIG_USB_SUSPEND */
1567 1653
1568/** 1654/**
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index b19cbfcd51d..95fb3104ba4 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1374,8 +1374,9 @@ static void usb_stop_pm(struct usb_device *udev)
1374 usb_autosuspend_device(udev->parent); 1374 usb_autosuspend_device(udev->parent);
1375 usb_pm_unlock(udev); 1375 usb_pm_unlock(udev);
1376 1376
1377 /* Stop any autosuspend requests already submitted */ 1377 /* Stop any autosuspend or autoresume requests already submitted */
1378 cancel_rearming_delayed_work(&udev->autosuspend); 1378 cancel_delayed_work_sync(&udev->autosuspend);
1379 cancel_work_sync(&udev->autoresume);
1379} 1380}
1380 1381
1381#else 1382#else
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 400fa4cc9a3..44f2fc750b6 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -402,6 +402,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
402#ifdef CONFIG_PM 402#ifdef CONFIG_PM
403 mutex_init(&dev->pm_mutex); 403 mutex_init(&dev->pm_mutex);
404 INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work); 404 INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
405 INIT_WORK(&dev->autoresume, usb_autoresume_work);
405 dev->autosuspend_delay = usb_autosuspend_delay * HZ; 406 dev->autosuspend_delay = usb_autosuspend_delay * HZ;
406 dev->connect_time = jiffies; 407 dev->connect_time = jiffies;
407 dev->active_duration = -jiffies; 408 dev->active_duration = -jiffies;
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 9a1a45ac3ad..b60ebb4de1a 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -45,6 +45,7 @@ extern int usb_suspend(struct device *dev, pm_message_t msg);
45extern int usb_resume(struct device *dev); 45extern int usb_resume(struct device *dev);
46 46
47extern void usb_autosuspend_work(struct work_struct *work); 47extern void usb_autosuspend_work(struct work_struct *work);
48extern void usb_autoresume_work(struct work_struct *work);
48extern int usb_port_suspend(struct usb_device *dev); 49extern int usb_port_suspend(struct usb_device *dev);
49extern int usb_port_resume(struct usb_device *dev); 50extern int usb_port_resume(struct usb_device *dev);
50extern int usb_external_suspend_device(struct usb_device *udev, 51extern int usb_external_suspend_device(struct usb_device *udev,