From 01d883d44a1ca8dc77486635d428cba63e7fdadf Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 30 Aug 2006 15:47:18 -0400 Subject: [PATCH] usbcore: non-hub-specific uses of autosuspend This patch (as741) makes the non-hub parts of usbcore actually use the autosuspend facilities added by an earlier patch. Devices opened through usbfs are autoresumed and then autosuspended upon close. Likewise for usb-skeleton. Devices are autoresumed for usb_set_configuration. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 11 ++++++++--- drivers/usb/core/generic.c | 7 ++----- drivers/usb/core/message.c | 10 +++++++--- drivers/usb/usb-skeleton.c | 11 +++++++++++ 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 43c08724a2..fd345ad810 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -558,10 +558,12 @@ static int usbdev_open(struct inode *inode, struct file *file) dev = usbdev_lookup_minor(iminor(inode)); if (!dev) dev = inode->i_private; - if (!dev) { - kfree(ps); + if (!dev) goto out; - } + ret = usb_autoresume_device(dev, 1); + if (ret) + goto out; + usb_get_dev(dev); ret = 0; ps->dev = dev; @@ -581,6 +583,8 @@ static int usbdev_open(struct inode *inode, struct file *file) list_add_tail(&ps->list, &dev->filelist); file->private_data = ps; out: + if (ret) + kfree(ps); mutex_unlock(&usbfs_mutex); return ret; } @@ -604,6 +608,7 @@ static int usbdev_release(struct inode *inode, struct file *file) releaseintf(ps, ifnum); } destroy_all_async(ps); + usb_autosuspend_device(dev, 1); usb_unlock_device(dev); usb_put_dev(dev); kfree(ps); diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 5358e65647..16332cc579 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -172,14 +172,10 @@ static void generic_disconnect(struct usb_device *udev) /* if this is only an unbind, not a physical disconnect, then * unconfigure the device */ - if (udev->state == USB_STATE_CONFIGURED) + if (udev->actconfig) usb_set_configuration(udev, 0); usb_remove_sysfs_dev_files(udev); - - /* in case the call failed or the device was suspended */ - if (udev->state >= USB_STATE_CONFIGURED) - usb_disable_device(udev, 0); } #ifdef CONFIG_PM @@ -208,4 +204,5 @@ struct usb_device_driver usb_generic_driver = { .suspend = generic_suspend, .resume = generic_resume, #endif + .supports_autosuspend = 1, }; diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 1580c81a0d..28c6cf2257 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1366,9 +1366,6 @@ int usb_set_configuration(struct usb_device *dev, int configuration) if (cp && configuration == 0) dev_warn(&dev->dev, "config 0 descriptor??\n"); - if (dev->state == USB_STATE_SUSPENDED) - return -EHOSTUNREACH; - /* Allocate memory for new interfaces before doing anything else, * so that if we run out then nothing will have changed. */ n = nintf = 0; @@ -1403,6 +1400,11 @@ free_interfaces: configuration, -i); } + /* Wake up the device so we can send it the Set-Config request */ + ret = usb_autoresume_device(dev, 1); + if (ret) + goto free_interfaces; + /* if it's already configured, clear out old state first. * getting rid of old interfaces means unbinding their drivers. */ @@ -1422,6 +1424,7 @@ free_interfaces: dev->actconfig = cp; if (!cp) { usb_set_device_state(dev, USB_STATE_ADDRESS); + usb_autosuspend_device(dev, 1); goto free_interfaces; } usb_set_device_state(dev, USB_STATE_CONFIGURED); @@ -1490,6 +1493,7 @@ free_interfaces: usb_create_sysfs_intf_files (intf); } + usb_autosuspend_device(dev, 1); return 0; } diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 9b542a6ba9..1b51d3187a 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -90,6 +90,11 @@ static int skel_open(struct inode *inode, struct file *file) goto exit; } + /* prevent the device from being autosuspended */ + retval = usb_autopm_get_interface(interface); + if (retval) + goto exit; + /* increment our usage count for the device */ kref_get(&dev->kref); @@ -108,6 +113,12 @@ static int skel_release(struct inode *inode, struct file *file) if (dev == NULL) return -ENODEV; + /* allow the device to be autosuspended */ + mutex_lock(&dev->io_mutex); + if (dev->interface) + usb_autopm_put_interface(dev->interface); + mutex_unlock(&dev->io_mutex); + /* decrement the count on our device */ kref_put(&dev->kref, skel_delete); return 0; -- 2.39.5