Merge branch 'release-2.6.27' of git://git.kernel.org/pub/scm/linux/kernel/git/ak...
[pandora-kernel.git] / drivers / usb / core / driver.c
index 7c3aaa9..ddb54e1 100644 (file)
@@ -157,7 +157,7 @@ static int usb_probe_device(struct device *dev)
        struct usb_device *udev;
        int error = -ENODEV;
 
-       dev_dbg(dev, "%s\n", __FUNCTION__);
+       dev_dbg(dev, "%s\n", __func__);
 
        if (!is_usb_device(dev))        /* Sanity check */
                return error;
@@ -194,24 +194,25 @@ static int usb_probe_interface(struct device *dev)
        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 = to_usb_interface(dev);
        udev = interface_to_usbdev(intf);
+       intf->needs_binding = 0;
 
-       if (udev->authorized == 0) {
-               dev_err(&intf->dev, "Device is not authorized for usage\n");
-               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)
@@ -257,15 +258,16 @@ 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);
 
        driver->disconnect(intf);
 
        /* reset other interface state */
-       usb_set_interface(interface_to_usbdev(intf),
-                       intf->altsetting[0].desc.bInterfaceNumber,
-                       0);
+       usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0);
        usb_set_intfdata(intf, NULL);
 
        intf->condition = USB_INTERFACE_UNBOUND;
@@ -299,7 +301,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);
@@ -310,6 +312,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;
@@ -325,7 +328,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
@@ -370,7 +373,7 @@ void usb_driver_release_interface(struct usb_driver *driver,
        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)
@@ -398,7 +401,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) &&
@@ -534,15 +537,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)
 {
@@ -586,7 +589,7 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
        struct usb_device *usb_dev;
 
        /* 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))
                usb_dev = to_usb_device(dev);
@@ -596,11 +599,11 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
        }
 
        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;
        }
 
@@ -745,7 +748,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
@@ -769,7 +772,105 @@ 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.
+ *
+ * FIXME: The caller must block system sleep transitions.
+ */
+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 */
+       intf->needs_binding = 0;
+       rc = device_attach(&intf->dev);
+       if (rc < 0)
+               dev_warn(&intf->dev, "rebind failed: %d\n", rc);
+}
+
+#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.
+ * FIXME: For rebinds, the caller must block system sleep transitions.
+ */
+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) {
+
+       /* FIXME: The next line is needed because we are going to probe
+        * the interface, but as far as the PM core is concerned the
+        * interface is still suspended.  The problem wouldn't exist
+        * if we could rebind the interface during the interface's own
+        * resume() call, but at the time the usb_device isn't locked!
+        *
+        * The real solution will be to carry this out during the device's
+        * complete() callback.  Until that is implemented, we have to
+        * use this hack.
+        */
+//                                     intf->dev.power.sleeping = 0;
+
+                                       usb_rebind_intf(intf);
+                               }
+                               break;
+                       }
+               }
+       }
+}
 
 #ifdef CONFIG_PM
 
@@ -793,9 +894,7 @@ 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;
 }
 
@@ -807,8 +906,6 @@ static int usb_resume_device(struct usb_device *udev)
 
        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) {
@@ -823,11 +920,9 @@ static int usb_resume_device(struct usb_device *udev)
        status = udriver->resume(udev);
 
  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;
 }
 
@@ -846,7 +941,7 @@ static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg)
                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);
@@ -854,15 +949,15 @@ static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg)
                        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;
 }
 
@@ -881,10 +976,12 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
                goto done;
 
        /* Can't resume it if it doesn't have a driver. */
-       if (intf->condition == USB_INTERFACE_UNBOUND) {
-               status = -ENOTCONN;
+       if (intf->condition == USB_INTERFACE_UNBOUND)
+               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) {
@@ -894,7 +991,7 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
                                dev_err(&intf->dev, "%s error %d\n",
                                                "reset_resume", status);
                } else {
-                       // status = -EOPNOTSUPP;
+                       intf->needs_binding = 1;
                        dev_warn(&intf->dev, "no %s for driver %s?\n",
                                        "reset_resume", driver->name);
                }
@@ -905,19 +1002,18 @@ static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
                                dev_err(&intf->dev, "%s error %d\n",
                                                "resume", status);
                } else {
-                       // status = -EOPNOTSUPP;
+                       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);
 
-       /* FIXME: Unbind the driver and reprobe if the resume failed
-        * (not possible if auto_pm is set) */
+       /* Later we will unbind the driver and/or reprobe, if necessary */
        return status;
 }
 
@@ -934,7 +1030,6 @@ static int autosuspend_check(struct usb_device *udev, int reschedule)
         * 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)
@@ -1096,7 +1191,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
        }
 
  done:
-       dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+       dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
        return status;
 }
 
@@ -1175,13 +1270,9 @@ static int usb_resume_both(struct usb_device *udev)
                         * so if a root hub's controller is suspended
                         * then we're stuck. */
                        status = usb_resume_device(udev);
-               }
-       } else {
-
-               /* Needed for setting udev->dev.power.power_state.event,
-                * for possible debugging message, and for reset_resume. */
+               }
+       } else if (udev->reset_resume)
                status = usb_resume_device(udev);
-       }
 
        if (status == 0 && udev->actconfig) {
                for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
@@ -1191,8 +1282,9 @@ static int usb_resume_both(struct usb_device *udev)
        }
 
  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;
 }
 
@@ -1260,7 +1352,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);
 }
 
 /**
@@ -1280,7 +1372,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);
 }
 
 /**
@@ -1308,7 +1400,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;
 }
 
@@ -1380,7 +1472,7 @@ 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);
 
@@ -1424,7 +1516,7 @@ 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);
@@ -1446,7 +1538,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);
@@ -1477,6 +1569,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);
@@ -1504,6 +1597,7 @@ int usb_external_resume_device(struct usb_device *udev)
        status = usb_resume_both(udev);
        udev->last_busy = jiffies;
        usb_pm_unlock(udev);
+       do_unbind_rebind(udev, DO_REBIND);
 
        /* Now that the device is awake, we can start trying to autosuspend
         * it again. */
@@ -1521,9 +1615,14 @@ static int usb_suspend(struct device *dev, pm_message_t message)
        udev = to_usb_device(dev);
 
        /* If udev is already suspended, we can skip this suspend and
-        * we should also skip the upcoming system resume. */
+        * 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) {
-               udev->skip_sys_resume = 1;
+               if (udev->parent || udev->speed != USB_SPEED_HIGH)
+                       udev->skip_sys_resume = 1;
                return 0;
        }
 
@@ -1540,14 +1639,11 @@ static int usb_resume(struct device *dev)
        udev = to_usb_device(dev);
 
        /* If udev->skip_sys_resume is set then udev was already suspended
-        * when the system suspend started, so we don't want to resume
-        * udev during this system wakeup.  However a reset-resume counts
-        * as a wakeup event, so allow a reset-resume to occur if remote
-        * wakeup is enabled. */
-       if (udev->skip_sys_resume) {
-               if (!(udev->reset_resume && udev->do_remote_wakeup))
-                       return -EHOSTUNREACH;
-       }
+        * when the system sleep started, so we don't want to resume it
+        * during this system wakeup.
+        */
+       if (udev->skip_sys_resume)
+               return 0;
        return usb_external_resume_device(udev);
 }