USB: add API for userspace drivers to "claim" ports
[safe/jmp/linux-2.6] / drivers / usb / core / driver.c
index 6c62a6d..1bad4e5 100644 (file)
 #include "hcd.h"
 #include "usb.h"
 
-#define VERBOSE_DEBUG  0
-
-#if VERBOSE_DEBUG
-#define dev_vdbg       dev_dbg
-#else
-#define dev_vdbg(dev, fmt, args...)    do { } while (0)
-#endif
 
 #ifdef CONFIG_HOTPLUG
 
@@ -67,7 +60,7 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,
        dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
 
        spin_lock(&dynids->lock);
-       list_add_tail(&dynids->list, &dynid->node);
+       list_add_tail(&dynid->node, &dynids->list);
        spin_unlock(&dynids->lock);
 
        if (get_driver(driver)) {
@@ -98,8 +91,8 @@ static int usb_create_newid_file(struct usb_driver *usb_drv)
                goto exit;
 
        if (usb_drv->probe != NULL)
-               error = sysfs_create_file(&usb_drv->drvwrap.driver.kobj,
-                                         &driver_attr_new_id.attr);
+               error = driver_create_file(&usb_drv->drvwrap.driver,
+                                          &driver_attr_new_id);
 exit:
        return error;
 }
@@ -110,8 +103,8 @@ static void usb_remove_newid_file(struct usb_driver *usb_drv)
                return;
 
        if (usb_drv->probe != NULL)
-               sysfs_remove_file(&usb_drv->drvwrap.driver.kobj,
-                                 &driver_attr_new_id.attr);
+               driver_remove_file(&usb_drv->drvwrap.driver,
+                                  &driver_attr_new_id);
 }
 
 static void usb_free_dynids(struct usb_driver *usb_drv)
@@ -161,15 +154,10 @@ static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *in
 static int usb_probe_device(struct device *dev)
 {
        struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
-       struct usb_device *udev;
+       struct usb_device *udev = to_usb_device(dev);
        int error = -ENODEV;
 
-       dev_dbg(dev, "%s\n", __FUNCTION__);
-
-       if (!is_usb_device(dev))        /* Sanity check */
-               return error;
-
-       udev = to_usb_device(dev);
+       dev_dbg(dev, "%s\n", __func__);
 
        /* TODO: Add real matching code */
 
@@ -191,29 +179,47 @@ static int usb_unbind_device(struct device *dev)
        return 0;
 }
 
+/*
+ * Cancel any pending scheduled resets
+ *
+ * [see usb_queue_reset_device()]
+ *
+ * Called after unconfiguring / when releasing interfaces. See
+ * comments in __usb_queue_reset_device() regarding
+ * udev->reset_running.
+ */
+static void usb_cancel_queued_reset(struct usb_interface *iface)
+{
+       if (iface->reset_running == 0)
+               cancel_work_sync(&iface->reset_ws);
+}
 
 /* called from driver core with dev locked */
 static int usb_probe_interface(struct device *dev)
 {
        struct usb_driver *driver = to_usb_driver(dev->driver);
-       struct usb_interface *intf;
-       struct usb_device *udev;
+       struct usb_interface *intf = to_usb_interface(dev);
+       struct usb_device *udev = interface_to_usbdev(intf);
        const struct usb_device_id *id;
        int error = -ENODEV;
 
-       dev_dbg(dev, "%s\n", __FUNCTION__);
+       dev_dbg(dev, "%s\n", __func__);
 
-       if (is_usb_device(dev))         /* Sanity check */
-               return error;
+       intf->needs_binding = 0;
 
-       intf = to_usb_interface(dev);
-       udev = interface_to_usbdev(intf);
+       if (usb_device_is_owned(udev))
+               return -ENODEV;
+
+       if (udev->authorized == 0) {
+               dev_err(&intf->dev, "Device is not authorized for usage\n");
+               return -ENODEV;
+       }
 
        id = usb_match_id(intf, driver->id_table);
        if (!id)
                id = usb_match_dynamic_id(intf, driver);
        if (id) {
-               dev_dbg(dev, "%s - got id\n", __FUNCTION__);
+               dev_dbg(dev, "%s - got id\n", __func__);
 
                error = usb_autoresume_device(udev);
                if (error)
@@ -231,11 +237,19 @@ static int usb_probe_interface(struct device *dev)
                 */
                intf->pm_usage_cnt = !(driver->supports_autosuspend);
 
+               /* Carry out a deferred switch to altsetting 0 */
+               if (intf->needs_altsetting0) {
+                       usb_set_interface(udev, intf->altsetting[0].
+                                       desc.bInterfaceNumber, 0);
+                       intf->needs_altsetting0 = 0;
+               }
+
                error = driver->probe(intf, id);
                if (error) {
                        mark_quiesced(intf);
                        intf->needs_remote_wakeup = 0;
                        intf->condition = USB_INTERFACE_UNBOUND;
+                       usb_cancel_queued_reset(intf);
                } else
                        intf->condition = USB_INTERFACE_BOUND;
 
@@ -259,15 +273,31 @@ static int usb_unbind_interface(struct device *dev)
        udev = interface_to_usbdev(intf);
        error = usb_autoresume_device(udev);
 
-       /* release all urbs for this interface */
-       usb_disable_interface(interface_to_usbdev(intf), intf);
+       /* Terminate all URBs for this interface unless the driver
+        * supports "soft" unbinding.
+        */
+       if (!driver->soft_unbind)
+               usb_disable_interface(udev, intf, false);
 
        driver->disconnect(intf);
+       usb_cancel_queued_reset(intf);
 
-       /* reset other interface state */
-       usb_set_interface(interface_to_usbdev(intf),
-                       intf->altsetting[0].desc.bInterfaceNumber,
-                       0);
+       /* Reset other interface state.
+        * We cannot do a Set-Interface if the device is suspended or
+        * if it is prepared for a system sleep (since installing a new
+        * altsetting means creating new endpoint device entries).
+        * When either of these happens, defer the Set-Interface.
+        */
+       if (intf->cur_altsetting->desc.bAlternateSetting == 0) {
+               /* Already in altsetting 0 so skip Set-Interface.
+                * Just re-enable it without affecting the endpoint toggles.
+                */
+               usb_enable_interface(udev, intf, false);
+       } else if (!error && intf->dev.power.status == DPM_ON)
+               usb_set_interface(udev, intf->altsetting[0].
+                               desc.bInterfaceNumber, 0);
+       else
+               intf->needs_altsetting0 = 1;
        usb_set_intfdata(intf, NULL);
 
        intf->condition = USB_INTERFACE_UNBOUND;
@@ -301,7 +331,7 @@ static int usb_unbind_interface(struct device *dev)
  * lock.
  */
 int usb_driver_claim_interface(struct usb_driver *driver,
-                               struct usb_interface *iface, voidpriv)
+                               struct usb_interface *iface, void *priv)
 {
        struct device *dev = &iface->dev;
        struct usb_device *udev = interface_to_usbdev(iface);
@@ -312,6 +342,7 @@ int usb_driver_claim_interface(struct usb_driver *driver,
 
        dev->driver = &driver->drvwrap.driver;
        usb_set_intfdata(iface, priv);
+       iface->needs_binding = 0;
 
        usb_pm_lock(udev);
        iface->condition = USB_INTERFACE_BOUND;
@@ -327,7 +358,7 @@ int usb_driver_claim_interface(struct usb_driver *driver,
 
        return retval;
 }
-EXPORT_SYMBOL(usb_driver_claim_interface);
+EXPORT_SYMBOL_GPL(usb_driver_claim_interface);
 
 /**
  * usb_driver_release_interface - unbind a driver from an interface
@@ -347,7 +378,6 @@ void usb_driver_release_interface(struct usb_driver *driver,
                                        struct usb_interface *iface)
 {
        struct device *dev = &iface->dev;
-       struct usb_device *udev = interface_to_usbdev(iface);
 
        /* this should never happen, don't release something that's not ours */
        if (!dev->driver || dev->driver != &driver->drvwrap.driver)
@@ -356,23 +386,21 @@ void usb_driver_release_interface(struct usb_driver *driver,
        /* don't release from within disconnect() */
        if (iface->condition != USB_INTERFACE_BOUND)
                return;
+       iface->condition = USB_INTERFACE_UNBINDING;
 
-       /* don't release if the interface hasn't been added yet */
+       /* Release via the driver core only if the interface
+        * has already been registered
+        */
        if (device_is_registered(dev)) {
-               iface->condition = USB_INTERFACE_UNBINDING;
                device_release_driver(dev);
+       } else {
+               down(&dev->sem);
+               usb_unbind_interface(dev);
+               dev->driver = NULL;
+               up(&dev->sem);
        }
-
-       dev->driver = NULL;
-       usb_set_intfdata(iface, NULL);
-
-       usb_pm_lock(udev);
-       iface->condition = USB_INTERFACE_UNBOUND;
-       mark_quiesced(iface);
-       iface->needs_remote_wakeup = 0;
-       usb_pm_unlock(udev);
 }
-EXPORT_SYMBOL(usb_driver_release_interface);
+EXPORT_SYMBOL_GPL(usb_driver_release_interface);
 
 /* returns 0 if no match, 1 if match */
 int usb_match_device(struct usb_device *dev, const struct usb_device_id *id)
@@ -400,7 +428,7 @@ int usb_match_device(struct usb_device *dev, const struct usb_device_id *id)
                return 0;
 
        if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
-           (id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass))
+           (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
                return 0;
 
        if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
@@ -536,15 +564,15 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface,
           id->driver_info is the way to create an entry that
           indicates that the driver want to examine every
           device and interface. */
-       for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass ||
-              id->driver_info; id++) {
+       for (; id->idVendor || id->idProduct || id->bDeviceClass ||
+              id->bInterfaceClass || id->driver_info; id++) {
                if (usb_match_one_id(interface, id))
                        return id;
        }
 
        return NULL;
 }
-EXPORT_SYMBOL_GPL_FUTURE(usb_match_id);
+EXPORT_SYMBOL_GPL(usb_match_id);
 
 static int usb_device_match(struct device *dev, struct device_driver *drv)
 {
@@ -558,7 +586,7 @@ static int usb_device_match(struct device *dev, struct device_driver *drv)
                /* TODO: Add real matching code */
                return 1;
 
-       } else {
+       } else if (is_usb_interface(dev)) {
                struct usb_interface *intf;
                struct usb_driver *usb_drv;
                const struct usb_device_id *id;
@@ -583,32 +611,29 @@ static int usb_device_match(struct device *dev, struct device_driver *drv)
 }
 
 #ifdef CONFIG_HOTPLUG
-static int usb_uevent(struct device *dev, char **envp, int num_envp,
-                     char *buffer, int buffer_size)
+static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        struct usb_device *usb_dev;
-       int i = 0;
-       int length = 0;
-
-       if (!dev)
-               return -ENODEV;
 
        /* driver is often null here; dev_dbg() would oops */
-       pr_debug ("usb %s: uevent\n", dev->bus_id);
+       pr_debug("usb %s: uevent\n", dev_name(dev));
 
-       if (is_usb_device(dev))
+       if (is_usb_device(dev)) {
                usb_dev = to_usb_device(dev);
-       else {
+       } else if (is_usb_interface(dev)) {
                struct usb_interface *intf = to_usb_interface(dev);
+
                usb_dev = interface_to_usbdev(intf);
+       } else {
+               return 0;
        }
 
        if (usb_dev->devnum < 0) {
-               pr_debug ("usb %s: already deleted?\n", dev->bus_id);
+               pr_debug("usb %s: already deleted?\n", dev_name(dev));
                return -ENODEV;
        }
        if (!usb_dev->bus) {
-               pr_debug ("usb %s: bus removed?\n", dev->bus_id);
+               pr_debug("usb %s: bus removed?\n", dev_name(dev));
                return -ENODEV;
        }
 
@@ -617,51 +642,31 @@ static int usb_uevent(struct device *dev, char **envp, int num_envp,
         * all the device descriptors we don't tell them about.  Or
         * act as usermode drivers.
         */
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "DEVICE=/proc/bus/usb/%03d/%03d",
+       if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d",
                           usb_dev->bus->busnum, usb_dev->devnum))
                return -ENOMEM;
 #endif
 
        /* per-device configurations are common */
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "PRODUCT=%x/%x/%x",
+       if (add_uevent_var(env, "PRODUCT=%x/%x/%x",
                           le16_to_cpu(usb_dev->descriptor.idVendor),
                           le16_to_cpu(usb_dev->descriptor.idProduct),
                           le16_to_cpu(usb_dev->descriptor.bcdDevice)))
                return -ENOMEM;
 
        /* class-based driver binding models */
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "TYPE=%d/%d/%d",
+       if (add_uevent_var(env, "TYPE=%d/%d/%d",
                           usb_dev->descriptor.bDeviceClass,
                           usb_dev->descriptor.bDeviceSubClass,
                           usb_dev->descriptor.bDeviceProtocol))
                return -ENOMEM;
 
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "BUSNUM=%03d",
-                          usb_dev->bus->busnum))
-               return -ENOMEM;
-
-       if (add_uevent_var(envp, num_envp, &i,
-                          buffer, buffer_size, &length,
-                          "DEVNUM=%03d",
-                          usb_dev->devnum))
-               return -ENOMEM;
-
-       envp[i] = NULL;
        return 0;
 }
 
 #else
 
-static int usb_uevent(struct device *dev, char **envp,
-                     int num_envp, char *buffer, int buffer_size)
+static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
        return -ENODEV;
 }
@@ -773,7 +778,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
 
        return retval;
 }
-EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver);
+EXPORT_SYMBOL_GPL(usb_register_driver);
 
 /**
  * usb_deregister - unregister a USB interface driver
@@ -797,10 +802,95 @@ void usb_deregister(struct usb_driver *driver)
 
        usbfs_update_special();
 }
-EXPORT_SYMBOL_GPL_FUTURE(usb_deregister);
+EXPORT_SYMBOL_GPL(usb_deregister);
+
+/* Forced unbinding of a USB interface driver, either because
+ * it doesn't support pre_reset/post_reset/reset_resume or
+ * because it doesn't support suspend/resume.
+ *
+ * The caller must hold @intf's device's lock, but not its pm_mutex
+ * and not @intf->dev.sem.
+ */
+void usb_forced_unbind_intf(struct usb_interface *intf)
+{
+       struct usb_driver *driver = to_usb_driver(intf->dev.driver);
+
+       dev_dbg(&intf->dev, "forced unbind\n");
+       usb_driver_release_interface(driver, intf);
+
+       /* Mark the interface for later rebinding */
+       intf->needs_binding = 1;
+}
+
+/* Delayed forced unbinding of a USB interface driver and scan
+ * for rebinding.
+ *
+ * The caller must hold @intf's device's lock, but not its pm_mutex
+ * and not @intf->dev.sem.
+ *
+ * Note: Rebinds will be skipped if a system sleep transition is in
+ * progress and the PM "complete" callback hasn't occurred yet.
+ */
+void usb_rebind_intf(struct usb_interface *intf)
+{
+       int rc;
+
+       /* Delayed unbind of an existing driver */
+       if (intf->dev.driver) {
+               struct usb_driver *driver =
+                               to_usb_driver(intf->dev.driver);
+
+               dev_dbg(&intf->dev, "forced unbind\n");
+               usb_driver_release_interface(driver, intf);
+       }
+
+       /* Try to rebind the interface */
+       if (intf->dev.power.status == DPM_ON) {
+               intf->needs_binding = 0;
+               rc = device_attach(&intf->dev);
+               if (rc < 0)
+                       dev_warn(&intf->dev, "rebind failed: %d\n", rc);
+       }
+}
 
 #ifdef CONFIG_PM
 
+#define DO_UNBIND      0
+#define DO_REBIND      1
+
+/* Unbind drivers for @udev's interfaces that don't support suspend/resume,
+ * or rebind interfaces that have been unbound, according to @action.
+ *
+ * The caller must hold @udev's device lock.
+ */
+static void do_unbind_rebind(struct usb_device *udev, int action)
+{
+       struct usb_host_config  *config;
+       int                     i;
+       struct usb_interface    *intf;
+       struct usb_driver       *drv;
+
+       config = udev->actconfig;
+       if (config) {
+               for (i = 0; i < config->desc.bNumInterfaces; ++i) {
+                       intf = config->interface[i];
+                       switch (action) {
+                       case DO_UNBIND:
+                               if (intf->dev.driver) {
+                                       drv = to_usb_driver(intf->dev.driver);
+                                       if (!drv->suspend || !drv->resume)
+                                               usb_forced_unbind_intf(intf);
+                               }
+                               break;
+                       case DO_REBIND:
+                               if (intf->needs_binding)
+                                       usb_rebind_intf(intf);
+                               break;
+                       }
+               }
+       }
+}
+
 /* Caller has locked udev's pm_mutex */
 static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
 {
@@ -821,22 +911,18 @@ static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
        status = udriver->suspend(udev, msg);
 
  done:
-       dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
-       if (status == 0)
-               udev->dev.power.power_state.event = msg.event;
+       dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
        return status;
 }
 
 /* Caller has locked udev's pm_mutex */
-static int usb_resume_device(struct usb_device *udev)
+static int usb_resume_device(struct usb_device *udev, pm_message_t msg)
 {
        struct usb_device_driver        *udriver;
        int                             status = 0;
 
        if (udev->state == USB_STATE_NOTATTACHED)
                goto done;
-       if (udev->state != USB_STATE_SUSPENDED && !udev->reset_resume)
-               goto done;
 
        /* Can't resume it if it doesn't have a driver. */
        if (udev->dev.driver == NULL) {
@@ -848,60 +934,59 @@ static int usb_resume_device(struct usb_device *udev)
                udev->reset_resume = 1;
 
        udriver = to_usb_device_driver(udev->dev.driver);
-       status = udriver->resume(udev);
+       status = udriver->resume(udev, msg);
 
  done:
-       dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
-       if (status == 0) {
+       dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
+       if (status == 0)
                udev->autoresume_disabled = 0;
-               udev->dev.power.power_state.event = PM_EVENT_ON;
-       }
        return status;
 }
 
 /* Caller has locked intf's usb_device's pm mutex */
-static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg)
+static int usb_suspend_interface(struct usb_device *udev,
+               struct usb_interface *intf, pm_message_t msg)
 {
        struct usb_driver       *driver;
        int                     status = 0;
 
        /* with no hardware, USB interfaces only use FREEZE and ON states */
-       if (interface_to_usbdev(intf)->state == USB_STATE_NOTATTACHED ||
-                       !is_active(intf))
+       if (udev->state == USB_STATE_NOTATTACHED || !is_active(intf))
                goto done;
 
-       if (intf->condition == USB_INTERFACE_UNBOUND)   /* This can't happen */
+       /* This can happen; see usb_driver_release_interface() */
+       if (intf->condition == USB_INTERFACE_UNBOUND)
                goto done;
        driver = to_usb_driver(intf->dev.driver);
 
-       if (driver->suspend && driver->resume) {
+       if (driver->suspend) {
                status = driver->suspend(intf, msg);
                if (status == 0)
                        mark_quiesced(intf);
-               else if (!interface_to_usbdev(intf)->auto_pm)
+               else if (!(msg.event & PM_EVENT_AUTO))
                        dev_err(&intf->dev, "%s error %d\n",
                                        "suspend", status);
        } else {
-               // FIXME else if there's no suspend method, disconnect...
-               // Not possible if auto_pm is set...
-               dev_warn(&intf->dev, "no suspend for driver %s?\n",
-                               driver->name);
+               /* Later we will unbind the driver and reprobe */
+               intf->needs_binding = 1;
+               dev_warn(&intf->dev, "no %s for driver %s?\n",
+                               "suspend", driver->name);
                mark_quiesced(intf);
        }
 
  done:
-       dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
+       dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status);
        return status;
 }
 
 /* Caller has locked intf's usb_device's pm_mutex */
-static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
+static int usb_resume_interface(struct usb_device *udev,
+               struct usb_interface *intf, pm_message_t msg, int reset_resume)
 {
        struct usb_driver       *driver;
        int                     status = 0;
 
-       if (interface_to_usbdev(intf)->state == USB_STATE_NOTATTACHED ||
-                       is_active(intf))
+       if (udev->state == USB_STATE_NOTATTACHED || is_active(intf))
                goto done;
 
        /* Don't let autoresume interfere with unbinding */
@@ -910,43 +995,68 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
 
        /* Can't resume it if it doesn't have a driver. */
        if (intf->condition == USB_INTERFACE_UNBOUND) {
-               status = -ENOTCONN;
+
+               /* Carry out a deferred switch to altsetting 0 */
+               if (intf->needs_altsetting0 &&
+                               intf->dev.power.status == DPM_ON) {
+                       usb_set_interface(udev, intf->altsetting[0].
+                                       desc.bInterfaceNumber, 0);
+                       intf->needs_altsetting0 = 0;
+               }
                goto done;
        }
+
+       /* Don't resume if the interface is marked for rebinding */
+       if (intf->needs_binding)
+               goto done;
        driver = to_usb_driver(intf->dev.driver);
 
-       if (reset_resume && driver->post_reset)
-               driver->post_reset(intf, reset_resume);
-       else if (driver->resume) {
-               status = driver->resume(intf);
-               if (status)
-                       dev_err(&intf->dev, "%s error %d\n",
-                                       "resume", status);
-       } else
-               dev_warn(&intf->dev, "no resume for driver %s?\n",
-                               driver->name);
+       if (reset_resume) {
+               if (driver->reset_resume) {
+                       status = driver->reset_resume(intf);
+                       if (status)
+                               dev_err(&intf->dev, "%s error %d\n",
+                                               "reset_resume", status);
+               } else {
+                       intf->needs_binding = 1;
+                       dev_warn(&intf->dev, "no %s for driver %s?\n",
+                                       "reset_resume", driver->name);
+               }
+       } else {
+               if (driver->resume) {
+                       status = driver->resume(intf);
+                       if (status)
+                               dev_err(&intf->dev, "%s error %d\n",
+                                               "resume", status);
+               } else {
+                       intf->needs_binding = 1;
+                       dev_warn(&intf->dev, "no %s for driver %s?\n",
+                                       "resume", driver->name);
+               }
+       }
 
 done:
-       dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
-       if (status == 0)
+       dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status);
+       if (status == 0 && intf->condition == USB_INTERFACE_BOUND)
                mark_active(intf);
+
+       /* Later we will unbind the driver and/or reprobe, if necessary */
        return status;
 }
 
 #ifdef CONFIG_USB_SUSPEND
 
 /* Internal routine to check whether we may autosuspend a device. */
-static int autosuspend_check(struct usb_device *udev)
+static int autosuspend_check(struct usb_device *udev, int reschedule)
 {
        int                     i;
        struct usb_interface    *intf;
-       unsigned long           suspend_time;
+       unsigned long           suspend_time, j;
 
        /* For autosuspend, fail fast if anything is in use or autosuspend
         * is disabled.  Also fail if any interfaces require remote wakeup
         * but it isn't available.
         */
-       udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
        if (udev->pm_usage_cnt > 0)
                return -EBUSY;
        if (udev->autosuspend_delay < 0 || udev->autosuspend_disabled)
@@ -966,24 +1076,37 @@ static int autosuspend_check(struct usb_device *udev)
                                                "for autosuspend\n");
                                return -EOPNOTSUPP;
                        }
+
+                       /* Don't allow autosuspend if the device will need
+                        * a reset-resume and any of its interface drivers
+                        * doesn't include support.
+                        */
+                       if (udev->quirks & USB_QUIRK_RESET_RESUME) {
+                               struct usb_driver *driver;
+
+                               driver = to_usb_driver(intf->dev.driver);
+                               if (!driver->reset_resume ||
+                                   intf->needs_remote_wakeup)
+                                       return -EOPNOTSUPP;
+                       }
                }
        }
 
        /* If everything is okay but the device hasn't been idle for long
-        * enough, queue a delayed autosuspend request.
+        * enough, queue a delayed autosuspend request.  If the device
+        * _has_ been idle for long enough and the reschedule flag is set,
+        * likewise queue a delayed (1 second) autosuspend request.
         */
-       if (time_after(suspend_time, jiffies)) {
+       j = jiffies;
+       if (time_before(j, suspend_time))
+               reschedule = 1;
+       else
+               suspend_time = j + HZ;
+       if (reschedule) {
                if (!timer_pending(&udev->autosuspend.timer)) {
-
-                       /* The value of jiffies may change between the
-                        * time_after() comparison above and the subtraction
-                        * below.  That's okay; the system behaves sanely
-                        * when a timer is registered for the present moment
-                        * or for the past.
-                        */
                        queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
-                                       suspend_time - jiffies);
-                       }
+                               round_jiffies_up_relative(suspend_time - j));
+               }
                return -EAGAIN;
        }
        return 0;
@@ -991,7 +1114,7 @@ static int autosuspend_check(struct usb_device *udev)
 
 #else
 
-static inline int autosuspend_check(struct usb_device *udev)
+static inline int autosuspend_check(struct usb_device *udev, int reschedule)
 {
        return 0;
 }
@@ -1009,10 +1132,9 @@ static inline int autosuspend_check(struct usb_device *udev)
  * all the interfaces which were suspended are resumed so that they remain
  * in the same state as the device.
  *
- * If an autosuspend is in progress (@udev->auto_pm is set), the routine
- * checks first to make sure that neither the device itself or any of its
- * active interfaces is in use (pm_usage_cnt is greater than 0).  If they
- * are, the autosuspend fails.
+ * If an autosuspend is in progress the routine checks first to make sure
+ * that neither the device itself or any of its active interfaces is in use
+ * (pm_usage_cnt is greater than 0).  If they are, the autosuspend fails.
  *
  * If the suspend succeeds, the routine recursively queues an autosuspend
  * request for @udev's parent device, thereby propagating the change up
@@ -1047,8 +1169,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
 
        udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
 
-       if (udev->auto_pm) {
-               status = autosuspend_check(udev);
+       if (msg.event & PM_EVENT_AUTO) {
+               status = autosuspend_check(udev, 0);
                if (status < 0)
                        goto done;
        }
@@ -1057,47 +1179,56 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
        if (udev->actconfig) {
                for (; i < udev->actconfig->desc.bNumInterfaces; i++) {
                        intf = udev->actconfig->interface[i];
-                       status = usb_suspend_interface(intf, msg);
+                       status = usb_suspend_interface(udev, intf, msg);
                        if (status != 0)
                                break;
                }
        }
-       if (status == 0) {
-
-               /* Non-root devices don't need to do anything for FREEZE
-                * or PRETHAW. */
-               if (udev->parent && (msg.event == PM_EVENT_FREEZE ||
-                               msg.event == PM_EVENT_PRETHAW))
-                       goto done;
+       if (status == 0)
                status = usb_suspend_device(udev, msg);
-       }
 
        /* If the suspend failed, resume interfaces that did get suspended */
        if (status != 0) {
+               pm_message_t msg2;
+
+               msg2.event = msg.event ^ (PM_EVENT_SUSPEND | PM_EVENT_RESUME);
                while (--i >= 0) {
                        intf = udev->actconfig->interface[i];
-                       usb_resume_interface(intf, 0);
+                       usb_resume_interface(udev, intf, msg2, 0);
                }
 
                /* Try another autosuspend when the interfaces aren't busy */
-               if (udev->auto_pm)
-                       autosuspend_check(udev);
+               if (msg.event & PM_EVENT_AUTO)
+                       autosuspend_check(udev, status == -EBUSY);
 
-       /* If the suspend succeeded, propagate it up the tree */
+       /* If the suspend succeeded then prevent any more URB submissions,
+        * flush any outstanding URBs, and propagate the suspend up the tree.
+        */
        } else {
                cancel_delayed_work(&udev->autosuspend);
-               if (parent)
+               udev->can_submit = 0;
+               for (i = 0; i < 16; ++i) {
+                       usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
+                       usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
+               }
+
+               /* If this is just a FREEZE or a PRETHAW, udev might
+                * not really be suspended.  Only true suspends get
+                * propagated up the device tree.
+                */
+               if (parent && udev->state == USB_STATE_SUSPENDED)
                        usb_autosuspend_device(parent);
        }
 
  done:
-       dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+       dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
        return status;
 }
 
 /**
  * usb_resume_both - resume a USB device and its interfaces
  * @udev: the usb_device to resume
+ * @msg: Power Management message describing this state transition
  *
  * This is the central routine for resuming USB devices.  It calls the
  * the resume method for @udev and then calls the resume methods for all
@@ -1123,7 +1254,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
  *
  * This routine can run only in process context.
  */
-static int usb_resume_both(struct usb_device *udev)
+static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
 {
        int                     status = 0;
        int                     i;
@@ -1135,18 +1266,21 @@ static int usb_resume_both(struct usb_device *udev)
                status = -ENODEV;
                goto done;
        }
+       udev->can_submit = 1;
 
        /* Propagate the resume up the tree, if necessary */
        if (udev->state == USB_STATE_SUSPENDED) {
-               if (udev->auto_pm && udev->autoresume_disabled) {
+               if ((msg.event & PM_EVENT_AUTO) &&
+                               udev->autoresume_disabled) {
                        status = -EPERM;
                        goto done;
                }
                if (parent) {
                        status = usb_autoresume_device(parent);
                        if (status == 0) {
-                               status = usb_resume_device(udev);
-                               if (status) {
+                               status = usb_resume_device(udev, msg);
+                               if (status || udev->state ==
+                                               USB_STATE_NOTATTACHED) {
                                        usb_autosuspend_device(parent);
 
                                        /* It's possible usb_resume_device()
@@ -1167,29 +1301,23 @@ static int usb_resume_both(struct usb_device *udev)
                        /* We can't progagate beyond the USB subsystem,
                         * so if a root hub's controller is suspended
                         * then we're stuck. */
-                       if (udev->dev.parent->power.power_state.event !=
-                                       PM_EVENT_ON)
-                               status = -EHOSTUNREACH;
-                       else
-                               status = usb_resume_device(udev);
-               }
-       } else {
-
-               /* Needed for setting udev->dev.power.power_state.event,
-                * for possible debugging message, and for reset_resume. */
-               status = usb_resume_device(udev);
-       }
+                       status = usb_resume_device(udev, msg);
+               }
+       } else if (udev->reset_resume)
+               status = usb_resume_device(udev, msg);
 
        if (status == 0 && udev->actconfig) {
                for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
                        intf = udev->actconfig->interface[i];
-                       usb_resume_interface(intf, udev->reset_resume);
+                       usb_resume_interface(udev, intf, msg,
+                                       udev->reset_resume);
                }
        }
 
  done:
-       dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
-       udev->reset_resume = 0;
+       dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
+       if (!status)
+               udev->reset_resume = 0;
        return status;
 }
 
@@ -1206,17 +1334,17 @@ static int usb_autopm_do_device(struct usb_device *udev, int inc_usage_cnt)
        udev->auto_pm = 1;
        udev->pm_usage_cnt += inc_usage_cnt;
        WARN_ON(udev->pm_usage_cnt < 0);
+       if (inc_usage_cnt)
+               udev->last_busy = jiffies;
        if (inc_usage_cnt >= 0 && udev->pm_usage_cnt > 0) {
                if (udev->state == USB_STATE_SUSPENDED)
-                       status = usb_resume_both(udev);
+                       status = usb_resume_both(udev, PMSG_AUTO_RESUME);
                if (status != 0)
                        udev->pm_usage_cnt -= inc_usage_cnt;
                else if (inc_usage_cnt)
                        udev->last_busy = jiffies;
        } else if (inc_usage_cnt <= 0 && udev->pm_usage_cnt <= 0) {
-               if (inc_usage_cnt)
-                       udev->last_busy = jiffies;
-               status = usb_suspend_both(udev, PMSG_SUSPEND);
+               status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
        }
        usb_pm_unlock(udev);
        return status;
@@ -1231,6 +1359,19 @@ void usb_autosuspend_work(struct work_struct *work)
        usb_autopm_do_device(udev, 0);
 }
 
+/* usb_autoresume_work - callback routine to autoresume a USB device */
+void usb_autoresume_work(struct work_struct *work)
+{
+       struct usb_device *udev =
+               container_of(work, struct usb_device, autoresume);
+
+       /* Wake it up, let the drivers do their thing, and then put it
+        * back to sleep.
+        */
+       if (usb_autopm_do_device(udev, 1) == 0)
+               usb_autopm_do_device(udev, -1);
+}
+
 /**
  * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces
  * @udev: the usb_device to autosuspend
@@ -1257,7 +1398,7 @@ void usb_autosuspend_device(struct usb_device *udev)
 
        status = usb_autopm_do_device(udev, -1);
        dev_vdbg(&udev->dev, "%s: cnt %d\n",
-                       __FUNCTION__, udev->pm_usage_cnt);
+                       __func__, udev->pm_usage_cnt);
 }
 
 /**
@@ -1277,7 +1418,7 @@ void usb_try_autosuspend_device(struct usb_device *udev)
 {
        usb_autopm_do_device(udev, 0);
        dev_vdbg(&udev->dev, "%s: cnt %d\n",
-                       __FUNCTION__, udev->pm_usage_cnt);
+                       __func__, udev->pm_usage_cnt);
 }
 
 /**
@@ -1305,7 +1446,7 @@ int usb_autoresume_device(struct usb_device *udev)
 
        status = usb_autopm_do_device(udev, 1);
        dev_vdbg(&udev->dev, "%s: status %d cnt %d\n",
-                       __FUNCTION__, status, udev->pm_usage_cnt);
+                       __func__, status, udev->pm_usage_cnt);
        return status;
 }
 
@@ -1324,17 +1465,17 @@ static int usb_autopm_do_interface(struct usb_interface *intf,
        else {
                udev->auto_pm = 1;
                intf->pm_usage_cnt += inc_usage_cnt;
+               udev->last_busy = jiffies;
                if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) {
                        if (udev->state == USB_STATE_SUSPENDED)
-                               status = usb_resume_both(udev);
+                               status = usb_resume_both(udev,
+                                               PMSG_AUTO_RESUME);
                        if (status != 0)
                                intf->pm_usage_cnt -= inc_usage_cnt;
-                       else if (inc_usage_cnt)
+                       else
                                udev->last_busy = jiffies;
                } else if (inc_usage_cnt <= 0 && intf->pm_usage_cnt <= 0) {
-                       if (inc_usage_cnt)
-                               udev->last_busy = jiffies;
-                       status = usb_suspend_both(udev, PMSG_SUSPEND);
+                       status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
                }
        }
        usb_pm_unlock(udev);
@@ -1378,11 +1519,50 @@ void usb_autopm_put_interface(struct usb_interface *intf)
 
        status = usb_autopm_do_interface(intf, -1);
        dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
-                       __FUNCTION__, status, intf->pm_usage_cnt);
+                       __func__, status, intf->pm_usage_cnt);
 }
 EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
 
 /**
+ * usb_autopm_put_interface_async - decrement a USB interface's PM-usage counter
+ * @intf: the usb_interface whose counter should be decremented
+ *
+ * This routine does essentially the same thing as
+ * usb_autopm_put_interface(): it decrements @intf's usage counter and
+ * queues a delayed autosuspend request if the counter is <= 0.  The
+ * difference is that it does not acquire the device's pm_mutex;
+ * callers must handle all synchronization issues themselves.
+ *
+ * Typically a driver would call this routine during an URB's completion
+ * handler, if no more URBs were pending.
+ *
+ * This routine can run in atomic context.
+ */
+void usb_autopm_put_interface_async(struct usb_interface *intf)
+{
+       struct usb_device       *udev = interface_to_usbdev(intf);
+       int                     status = 0;
+
+       if (intf->condition == USB_INTERFACE_UNBOUND) {
+               status = -ENODEV;
+       } else {
+               udev->last_busy = jiffies;
+               --intf->pm_usage_cnt;
+               if (udev->autosuspend_disabled || udev->autosuspend_delay < 0)
+                       status = -EPERM;
+               else if (intf->pm_usage_cnt <= 0 &&
+                               !timer_pending(&udev->autosuspend.timer)) {
+                       queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
+                                       round_jiffies_up_relative(
+                                               udev->autosuspend_delay));
+               }
+       }
+       dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
+                       __func__, status, intf->pm_usage_cnt);
+}
+EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async);
+
+/**
  * usb_autopm_get_interface - increment a USB interface's PM-usage counter
  * @intf: the usb_interface whose counter should be incremented
  *
@@ -1422,12 +1602,43 @@ int usb_autopm_get_interface(struct usb_interface *intf)
 
        status = usb_autopm_do_interface(intf, 1);
        dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
-                       __FUNCTION__, status, intf->pm_usage_cnt);
+                       __func__, status, intf->pm_usage_cnt);
        return status;
 }
 EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
 
 /**
+ * usb_autopm_get_interface_async - increment a USB interface's PM-usage counter
+ * @intf: the usb_interface whose counter should be incremented
+ *
+ * This routine does much the same thing as
+ * usb_autopm_get_interface(): it increments @intf's usage counter and
+ * queues an autoresume request if the result is > 0.  The differences
+ * are that it does not acquire the device's pm_mutex (callers must
+ * handle all synchronization issues themselves), and it does not
+ * autoresume the device directly (it only queues a request).  After a
+ * successful call, the device will generally not yet be resumed.
+ *
+ * This routine can run in atomic context.
+ */
+int usb_autopm_get_interface_async(struct usb_interface *intf)
+{
+       struct usb_device       *udev = interface_to_usbdev(intf);
+       int                     status = 0;
+
+       if (intf->condition == USB_INTERFACE_UNBOUND)
+               status = -ENODEV;
+       else if (udev->autoresume_disabled)
+               status = -EPERM;
+       else if (++intf->pm_usage_cnt > 0 && udev->state == USB_STATE_SUSPENDED)
+               queue_work(ksuspend_usb_wq, &udev->autoresume);
+       dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
+                       __func__, status, intf->pm_usage_cnt);
+       return status;
+}
+EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async);
+
+/**
  * usb_autopm_set_interface - set a USB interface's autosuspend state
  * @intf: the usb_interface whose state should be set
  *
@@ -1444,7 +1655,7 @@ int usb_autopm_set_interface(struct usb_interface *intf)
 
        status = usb_autopm_do_interface(intf, 0);
        dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
-                       __FUNCTION__, status, intf->pm_usage_cnt);
+                       __func__, status, intf->pm_usage_cnt);
        return status;
 }
 EXPORT_SYMBOL_GPL(usb_autopm_set_interface);
@@ -1454,6 +1665,9 @@ EXPORT_SYMBOL_GPL(usb_autopm_set_interface);
 void usb_autosuspend_work(struct work_struct *work)
 {}
 
+void usb_autoresume_work(struct work_struct *work)
+{}
+
 #endif /* CONFIG_USB_SUSPEND */
 
 /**
@@ -1475,6 +1689,7 @@ int usb_external_suspend_device(struct usb_device *udev, pm_message_t msg)
 {
        int     status;
 
+       do_unbind_rebind(udev, DO_UNBIND);
        usb_pm_lock(udev);
        udev->auto_pm = 0;
        status = usb_suspend_both(udev, msg);
@@ -1485,6 +1700,7 @@ int usb_external_suspend_device(struct usb_device *udev, pm_message_t msg)
 /**
  * usb_external_resume_device - external resume of a USB device and its interfaces
  * @udev: the usb_device to resume
+ * @msg: Power Management message describing this state transition
  *
  * This routine handles external resume requests: ones not generated
  * internally by a USB driver (autoresume) but rather coming from the user
@@ -1493,15 +1709,17 @@ int usb_external_suspend_device(struct usb_device *udev, pm_message_t msg)
  *
  * The caller must hold @udev's device lock.
  */
-int usb_external_resume_device(struct usb_device *udev)
+int usb_external_resume_device(struct usb_device *udev, pm_message_t msg)
 {
        int     status;
 
        usb_pm_lock(udev);
        udev->auto_pm = 0;
-       status = usb_resume_both(udev);
+       status = usb_resume_both(udev, msg);
        udev->last_busy = jiffies;
        usb_pm_unlock(udev);
+       if (status == 0)
+               do_unbind_rebind(udev, DO_REBIND);
 
        /* Now that the device is awake, we can start trying to autosuspend
         * it again. */
@@ -1510,36 +1728,50 @@ int usb_external_resume_device(struct usb_device *udev)
        return status;
 }
 
-static int usb_suspend(struct device *dev, pm_message_t message)
+int usb_suspend(struct device *dev, pm_message_t msg)
 {
-       if (!is_usb_device(dev))        /* Ignore PM for interfaces */
+       struct usb_device       *udev;
+
+       udev = to_usb_device(dev);
+
+       /* If udev is already suspended, we can skip this suspend and
+        * we should also skip the upcoming system resume.  High-speed
+        * root hubs are an exception; they need to resume whenever the
+        * system wakes up in order for USB-PERSIST port handover to work
+        * properly.
+        */
+       if (udev->state == USB_STATE_SUSPENDED) {
+               if (udev->parent || udev->speed != USB_SPEED_HIGH)
+                       udev->skip_sys_resume = 1;
                return 0;
-       return usb_external_suspend_device(to_usb_device(dev), message);
+       }
+
+       udev->skip_sys_resume = 0;
+       return usb_external_suspend_device(udev, msg);
 }
 
-static int usb_resume(struct device *dev)
+int usb_resume(struct device *dev, pm_message_t msg)
 {
        struct usb_device       *udev;
+       int                     status;
 
-       if (!is_usb_device(dev))        /* Ignore PM for interfaces */
-               return 0;
        udev = to_usb_device(dev);
 
-       /* If autoresume is disabled then we also want to prevent resume
-        * during system wakeup.  However, a "persistent-device" reset-resume
-        * after power loss counts as a wakeup event.  So allow a
-        * reset-resume to occur if remote wakeup is enabled. */
-       if (udev->autoresume_disabled) {
-               if (!(udev->reset_resume && udev->do_remote_wakeup))
-                       return -EPERM;
-       }
-       return usb_external_resume_device(udev);
-}
-
-#else
+       /* If udev->skip_sys_resume is set then udev was already suspended
+        * when the system sleep started, so we don't want to resume it
+        * during this system wakeup.
+        */
+       if (udev->skip_sys_resume)
+               return 0;
+       status = usb_external_resume_device(udev, msg);
 
-#define usb_suspend    NULL
-#define usb_resume     NULL
+       /* Avoid PM error messages for devices disconnected while suspended
+        * as we'll display regular disconnect messages just a bit later.
+        */
+       if (status == -ENODEV)
+               return 0;
+       return status;
+}
 
 #endif /* CONFIG_PM */
 
@@ -1547,6 +1779,4 @@ struct bus_type usb_bus_type = {
        .name =         "usb",
        .match =        usb_device_match,
        .uevent =       usb_uevent,
-       .suspend =      usb_suspend,
-       .resume =       usb_resume,
 };