From stern@rowland.harvard.edu Wed Aug 30 12:47:21 2006 Date: Wed, 30 Aug 2006 15:47:18 -0400 (EDT) From: Alan Stern To: Greg KH cc: USB development list Subject: [PATCH 4/6] usbcore: non-hub-specific uses of autosuspend Message-ID: 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 | 12 ++++++++---- drivers/usb/core/generic.c | 7 ++----- drivers/usb/core/message.c | 10 +++++++--- drivers/usb/usb-skeleton.c | 11 +++++++++++ 4 files changed, 28 insertions(+), 12 deletions(-) --- gregkh-2.6.orig/drivers/usb/core/devio.c +++ gregkh-2.6/drivers/usb/core/devio.c @@ -558,12 +558,13 @@ static int usbdev_open(struct inode *ino dev = usbdev_lookup_minor(iminor(inode)); if (!dev) dev = inode->u.generic_ip; - 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; ps->file = file; spin_lock_init(&ps->lock); @@ -581,6 +582,8 @@ static int usbdev_open(struct inode *ino list_add_tail(&ps->list, &dev->filelist); file->private_data = ps; out: + if (ret) + kfree(ps); mutex_unlock(&usbfs_mutex); return ret; } @@ -604,6 +607,7 @@ static int usbdev_release(struct inode * releaseintf(ps, ifnum); } destroy_all_async(ps); + usb_autosuspend_device(dev, 1); usb_unlock_device(dev); usb_put_dev(dev); kfree(ps); --- gregkh-2.6.orig/drivers/usb/core/generic.c +++ gregkh-2.6/drivers/usb/core/generic.c @@ -172,14 +172,10 @@ static void generic_disconnect(struct us /* 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_dri .suspend = generic_suspend, .resume = generic_resume, #endif + .supports_autosuspend = 1, }; --- gregkh-2.6.orig/drivers/usb/core/message.c +++ gregkh-2.6/drivers/usb/core/message.c @@ -1366,9 +1366,6 @@ int usb_set_configuration(struct usb_dev 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; } --- gregkh-2.6.orig/drivers/usb/usb-skeleton.c +++ gregkh-2.6/drivers/usb/usb-skeleton.c @@ -90,6 +90,11 @@ static int skel_open(struct inode *inode 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 *in 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;