diff options
Diffstat (limited to 'drivers/usb/core')
-rw-r--r-- | drivers/usb/core/driver.c | 86 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 5 | ||||
-rw-r--r-- | drivers/usb/core/usb.c | 1 | ||||
-rw-r--r-- | drivers/usb/core/usb.h | 1 |
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 */ | ||
1345 | void 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) | |||
1492 | EXPORT_SYMBOL_GPL(usb_autopm_put_interface); | 1505 | EXPORT_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 | */ | ||
1522 | void 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 | } | ||
1544 | EXPORT_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) | |||
1537 | EXPORT_SYMBOL_GPL(usb_autopm_get_interface); | 1589 | EXPORT_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 | */ | ||
1605 | int 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 | } | ||
1620 | EXPORT_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); | |||
1563 | void usb_autosuspend_work(struct work_struct *work) | 1646 | void usb_autosuspend_work(struct work_struct *work) |
1564 | {} | 1647 | {} |
1565 | 1648 | ||
1649 | void 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); | |||
45 | extern int usb_resume(struct device *dev); | 45 | extern int usb_resume(struct device *dev); |
46 | 46 | ||
47 | extern void usb_autosuspend_work(struct work_struct *work); | 47 | extern void usb_autosuspend_work(struct work_struct *work); |
48 | extern void usb_autoresume_work(struct work_struct *work); | ||
48 | extern int usb_port_suspend(struct usb_device *dev); | 49 | extern int usb_port_suspend(struct usb_device *dev); |
49 | extern int usb_port_resume(struct usb_device *dev); | 50 | extern int usb_port_resume(struct usb_device *dev); |
50 | extern int usb_external_suspend_device(struct usb_device *udev, | 51 | extern int usb_external_suspend_device(struct usb_device *udev, |