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 <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 43c0872..fd345ad 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -558,10 +558,12 @@
 		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 @@
 	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 @@
 			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 5358e65..16332cc 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -172,14 +172,10 @@
 
 	/* 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 @@
 	.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 1580c81..28c6cf2 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1366,9 +1366,6 @@
 	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 @@
 					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 @@
 	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 @@
 		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 9b542a6..1b51d31 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -90,6 +90,11 @@
 		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 @@
 	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;