usbcore: non-hub-specific uses of autosuspend
authorAlan Stern <stern@rowland.harvard.edu>
Wed, 30 Aug 2006 19:47:18 +0000 (15:47 -0400)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 27 Sep 2006 18:58:57 +0000 (11:58 -0700)
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 <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/core/devio.c
drivers/usb/core/generic.c
drivers/usb/core/message.c
drivers/usb/usb-skeleton.c

index 43c08724a2d891976d4f54e58f23e21f32eaa121..fd345ad810f813c7c6bba3a148575c024f08161f 100644 (file)
@@ -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);
index 5358e656477ca7296185db938937949715624da9..16332cc57946abb820f9570eecbfbf9c253959c9 100644 (file)
@@ -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,
 };
index 1580c81a0db76185bb493adfc9c302e0276865d6..28c6cf225780dc32d04b40d3f595107453edc3dd 100644 (file)
@@ -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;
 }
 
index 9b542a6ba978923de924d36105a0ca6dfce2cd9f..1b51d3187a95c8d99c87de153de5afed4a9831ea 100644 (file)
@@ -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;