diff options
Diffstat (limited to 'drivers/usb/core/usb.c')
-rw-r--r-- | drivers/usb/core/usb.c | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index b0c0a993338..6b029cdb867 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -168,6 +168,10 @@ static void usb_release_dev(struct device *dev) udev = to_usb_device(dev); +#ifdef CONFIG_PM + cancel_delayed_work(&udev->autosuspend); + flush_scheduled_work(); +#endif usb_destroy_configuration(udev); usb_put_hcd(bus_to_hcd(udev->bus)); kfree(udev->product); @@ -176,6 +180,21 @@ static void usb_release_dev(struct device *dev) kfree(udev); } +#ifdef CONFIG_PM + +/* usb_autosuspend_work - callback routine to autosuspend a USB device */ +static void usb_autosuspend_work(void *_udev) +{ + struct usb_device *udev = _udev; + + mutex_lock_nested(&udev->pm_mutex, udev->level); + udev->auto_pm = 1; + usb_suspend_both(udev, PMSG_SUSPEND); + mutex_unlock(&udev->pm_mutex); +} + +#endif + /** * usb_alloc_dev - usb device constructor (usbcore-internal) * @parent: hub to which device is connected; null to allocate a root hub @@ -251,6 +270,10 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) dev->parent = parent; INIT_LIST_HEAD(&dev->filelist); +#ifdef CONFIG_PM + mutex_init(&dev->pm_mutex); + INIT_WORK(&dev->autosuspend, usb_autosuspend_work, dev); +#endif return dev; } |