usb-storage: Fix devices that cannot handle 32k transfers
[safe/jmp/linux-2.6] / drivers / usb / core / hub.c
index 77a6627..13b326a 100644 (file)
 #include "hcd.h"
 #include "hub.h"
 
+#ifdef CONFIG_USB_PERSIST
+#define        USB_PERSIST     1
+#else
+#define        USB_PERSIST     0
+#endif
+
 struct usb_hub {
        struct device           *intfdev;       /* the "interface" device */
        struct usb_device       *hdev;
@@ -119,6 +125,12 @@ MODULE_PARM_DESC(use_both_schemes,
                "try the other device initialization scheme if the "
                "first one fails");
 
+/* Mutual exclusion for EHCI CF initialization.  This interferes with
+ * port reset on some companion controllers.
+ */
+DECLARE_RWSEM(ehci_cf_port_reset_rwsem);
+EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
+
 
 static inline char *portspeed(int portstatus)
 {
@@ -323,7 +335,7 @@ static void kick_khubd(struct usb_hub *hub)
        to_usb_interface(hub->intfdev)->pm_usage_cnt = 1;
 
        spin_lock_irqsave(&hub_event_lock, flags);
-       if (!hub->disconnected & list_empty(&hub->event_list)) {
+       if (!hub->disconnected && list_empty(&hub->event_list)) {
                list_add_tail(&hub->event_list, &hub_event_list);
                wake_up(&khubd_wait);
        }
@@ -341,11 +353,11 @@ void usb_kick_khubd(struct usb_device *hdev)
 static void hub_irq(struct urb *urb)
 {
        struct usb_hub *hub = urb->context;
-       int status;
+       int status = urb->status;
        int i;
        unsigned long bits;
 
-       switch (urb->status) {
+       switch (status) {
        case -ENOENT:           /* synchronous unlink */
        case -ECONNRESET:       /* async unlink */
        case -ESHUTDOWN:        /* hardware going away */
@@ -353,10 +365,10 @@ static void hub_irq(struct urb *urb)
 
        default:                /* presumably an error */
                /* Cause a hub reset after 10 consecutive errors */
-               dev_dbg (hub->intfdev, "transfer --> %d\n", urb->status);
+               dev_dbg (hub->intfdev, "transfer --> %d\n", status);
                if ((++hub->nerrors < 10) || hub->error)
                        goto resubmit;
-               hub->error = urb->status;
+               hub->error = status;
                /* FALL THROUGH */
 
        /* let khubd handle things */
@@ -403,9 +415,10 @@ static void hub_tt_kevent (struct work_struct *work)
        struct usb_hub          *hub =
                container_of(work, struct usb_hub, tt.kevent);
        unsigned long           flags;
+       int                     limit = 100;
 
        spin_lock_irqsave (&hub->tt.lock, flags);
-       while (!list_empty (&hub->tt.clear_list)) {
+       while (--limit && !list_empty (&hub->tt.clear_list)) {
                struct list_head        *temp;
                struct usb_tt_clear     *clear;
                struct usb_device       *hdev = hub->hdev;
@@ -553,48 +566,68 @@ static int hub_hub_status(struct usb_hub *hub,
 static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
 {
        struct usb_device *hdev = hub->hdev;
-       int ret;
+       int ret = 0;
 
-       if (hdev->children[port1-1] && set_state) {
+       if (hdev->children[port1-1] && set_state)
                usb_set_device_state(hdev->children[port1-1],
                                USB_STATE_NOTATTACHED);
-       }
-       ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
+       if (!hub->error)
+               ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
        if (ret)
                dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
-                       port1, ret);
-
+                               port1, ret);
        return ret;
 }
 
+/*
+ * Disable a port and mark a logical connnect-change event, so that some
+ * time later khubd will disconnect() any existing usb_device on the port
+ * and will re-enumerate if there actually is a device attached.
+ */
+static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
+{
+       dev_dbg(hub->intfdev, "logical disconnect on port %d\n", port1);
+       hub_port_disable(hub, port1, 1);
+
+       /* FIXME let caller ask to power down the port:
+        *  - some devices won't enumerate without a VBUS power cycle
+        *  - SRP saves power that way
+        *  - ... new call, TBD ...
+        * That's easy if this hub can switch power per-port, and
+        * khubd reactivates the port later (timer, SRP, etc).
+        * Powerdown must be optional, because of reset/DFU.
+        */
+
+       set_bit(port1, hub->change_bits);
+       kick_khubd(hub);
+}
 
 /* caller has locked the hub device */
-static void hub_pre_reset(struct usb_interface *intf)
+static int hub_pre_reset(struct usb_interface *intf)
 {
        struct usb_hub *hub = usb_get_intfdata(intf);
        struct usb_device *hdev = hub->hdev;
-       int port1;
+       int i;
 
-       for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
-               if (hdev->children[port1 - 1]) {
-                       usb_disconnect(&hdev->children[port1 - 1]);
-                       if (hub->error == 0)
-                               hub_port_disable(hub, port1, 0);
-               }
+       /* Disconnect all the children */
+       for (i = 0; i < hdev->maxchild; ++i) {
+               if (hdev->children[i])
+                       usb_disconnect(&hdev->children[i]);
        }
        hub_quiesce(hub);
+       return 0;
 }
 
 /* caller has locked the hub device */
-static void hub_post_reset(struct usb_interface *intf)
+static int hub_post_reset(struct usb_interface *intf)
 {
        struct usb_hub *hub = usb_get_intfdata(intf);
 
-       hub_activate(hub);
        hub_power_on(hub);
+       hub_activate(hub);
+       return 0;
 }
 
-
 static int hub_configure(struct usb_hub *hub,
        struct usb_endpoint_descriptor *endpoint)
 {
@@ -1050,41 +1083,6 @@ void usb_set_device_state(struct usb_device *udev,
        spin_unlock_irqrestore(&device_state_lock, flags);
 }
 
-
-#ifdef CONFIG_PM
-
-/**
- * usb_root_hub_lost_power - called by HCD if the root hub lost Vbus power
- * @rhdev: struct usb_device for the root hub
- *
- * The USB host controller driver calls this function when its root hub
- * is resumed and Vbus power has been interrupted or the controller
- * has been reset.  The routine marks all the children of the root hub
- * as NOTATTACHED and marks logical connect-change events on their ports.
- */
-void usb_root_hub_lost_power(struct usb_device *rhdev)
-{
-       struct usb_hub *hub;
-       int port1;
-       unsigned long flags;
-
-       dev_warn(&rhdev->dev, "root hub lost power or was reset\n");
-
-       spin_lock_irqsave(&device_state_lock, flags);
-       hub = hdev_to_hub(rhdev);
-       for (port1 = 1; port1 <= rhdev->maxchild; ++port1) {
-               if (rhdev->children[port1 - 1]) {
-                       recursively_mark_NOTATTACHED(
-                                       rhdev->children[port1 - 1]);
-                       set_bit(port1, hub->change_bits);
-               }
-       }
-       spin_unlock_irqrestore(&device_state_lock, flags);
-}
-EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
-
-#endif /* CONFIG_PM */
-
 static void choose_address(struct usb_device *udev)
 {
        int             devnum;
@@ -1225,58 +1223,17 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
 
 #ifdef CONFIG_USB_OTG
 #include "otg_whitelist.h"
-static int __usb_port_suspend(struct usb_device *, int port1);
 #endif
 
 /**
- * usb_new_device - perform initial device setup (usbcore-internal)
+ * usb_configure_device_otg - FIXME (usbcore-internal)
  * @udev: newly addressed device (in ADDRESS state)
  *
- * This is called with devices which have been enumerated, but not yet
- * configured.  The device descriptor is available, but not descriptors
- * for any device configuration.  The caller must have locked either
- * the parent hub (if udev is a normal device) or else the
- * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to
- * udev has already been installed, but udev is not yet visible through
- * sysfs or other filesystem code.
- *
- * It will return if the device is configured properly or not.  Zero if
- * the interface was registered with the driver core; else a negative
- * errno value.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- *
- * Only the hub driver or root-hub registrar should ever call this.
+ * Do configuration for On-The-Go devices
  */
-int usb_new_device(struct usb_device *udev)
+static int usb_configure_device_otg(struct usb_device *udev)
 {
-       int err;
-
-       /* Determine quirks */
-       usb_detect_quirks(udev);
-
-       err = usb_get_configuration(udev);
-       if (err < 0) {
-               dev_err(&udev->dev, "can't read configurations, error %d\n",
-                       err);
-               goto fail;
-       }
-
-       /* read the standard strings and cache them if present */
-       udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
-       udev->manufacturer = usb_cache_string(udev,
-                       udev->descriptor.iManufacturer);
-       udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
-
-       /* Tell the world! */
-       dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
-                       "SerialNumber=%d\n",
-                       udev->descriptor.iManufacturer,
-                       udev->descriptor.iProduct,
-                       udev->descriptor.iSerialNumber);
-       show_string(udev, "Product", udev->product);
-       show_string(udev, "Manufacturer", udev->manufacturer);
-       show_string(udev, "SerialNumber", udev->serial);
+       int err = 0;
 
 #ifdef CONFIG_USB_OTG
        /*
@@ -1331,19 +1288,97 @@ int usb_new_device(struct usb_device *udev)
                 * (Includes HNP test device.)
                 */
                if (udev->bus->b_hnp_enable || udev->bus->is_b_host) {
-                       err = __usb_port_suspend(udev, udev->bus->otg_port);
+                       err = usb_port_suspend(udev);
                        if (err < 0)
                                dev_dbg(&udev->dev, "HNP fail, %d\n", err);
                }
-               err = -ENODEV;
+               err = -ENOTSUPP;
                goto fail;
        }
+fail:
 #endif
+       return err;
+}
+
+
+/**
+ * usb_configure_device - Detect and probe device intfs/otg (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is only called by usb_new_device() and usb_authorize_device()
+ * and FIXME -- all comments that apply to them apply here wrt to
+ * environment.
+ *
+ * If the device is WUSB and not authorized, we don't attempt to read
+ * the string descriptors, as they will be errored out by the device
+ * until it has been authorized.
+ */
+static int usb_configure_device(struct usb_device *udev)
+{
+       int err;
+
+       if (udev->config == NULL) {
+               err = usb_get_configuration(udev);
+               if (err < 0) {
+                       dev_err(&udev->dev, "can't read configurations, error %d\n",
+                               err);
+                       goto fail;
+               }
+       }
+       if (udev->wusb == 1 && udev->authorized == 0) {
+               udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+               udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+               udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+       }
+       else {
+               /* read the standard strings and cache them if present */
+               udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
+               udev->manufacturer = usb_cache_string(udev,
+                                                     udev->descriptor.iManufacturer);
+               udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
+       }
+       err = usb_configure_device_otg(udev);
+fail:
+       return err;
+}
+
+
+/**
+ * usb_new_device - perform initial device setup (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is called with devices which have been enumerated, but not yet
+ * configured.  The device descriptor is available, but not descriptors
+ * for any device configuration.  The caller must have locked either
+ * the parent hub (if udev is a normal device) or else the
+ * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to
+ * udev has already been installed, but udev is not yet visible through
+ * sysfs or other filesystem code.
+ *
+ * It will return if the device is configured properly or not.  Zero if
+ * the interface was registered with the driver core; else a negative
+ * errno value.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Only the hub driver or root-hub registrar should ever call this.
+ */
+int usb_new_device(struct usb_device *udev)
+{
+       int err;
 
+       usb_detect_quirks(udev);                /* Determine quirks */
+       err = usb_configure_device(udev);       /* detect & probe dev/intfs */
+       if (err < 0)
+               goto fail;
        /* export the usbdev device-node for libusb */
        udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
                        (((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
 
+       /* Increment the parent's count of unsuspended children */
+       if (udev->parent)
+               usb_autoresume_device(udev->parent);
+
        /* Register the device.  The device driver is responsible
         * for adding the device files to sysfs and for configuring
         * the device.
@@ -1354,18 +1389,107 @@ int usb_new_device(struct usb_device *udev)
                goto fail;
        }
 
-       /* Increment the parent's count of unsuspended children */
-       if (udev->parent)
-               usb_autoresume_device(udev->parent);
-
-exit:
+       /* Tell the world! */
+       dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
+               "SerialNumber=%d\n",
+               udev->descriptor.iManufacturer,
+               udev->descriptor.iProduct,
+               udev->descriptor.iSerialNumber);
+       show_string(udev, "Product", udev->product);
+       show_string(udev, "Manufacturer", udev->manufacturer);
+       show_string(udev, "SerialNumber", udev->serial);
        return err;
 
 fail:
        usb_set_device_state(udev, USB_STATE_NOTATTACHED);
-       goto exit;
+       return err;
 }
 
+
+/**
+ * usb_deauthorize_device - deauthorize a device (usbcore-internal)
+ * @usb_dev: USB device
+ *
+ * Move the USB device to a very basic state where interfaces are disabled
+ * and the device is in fact unconfigured and unusable.
+ *
+ * We share a lock (that we have) with device_del(), so we need to
+ * defer its call.
+ */
+int usb_deauthorize_device(struct usb_device *usb_dev)
+{
+       unsigned cnt;
+       usb_lock_device(usb_dev);
+       if (usb_dev->authorized == 0)
+               goto out_unauthorized;
+       usb_dev->authorized = 0;
+       usb_set_configuration(usb_dev, -1);
+       usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+       usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+       usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+       kfree(usb_dev->config);
+       usb_dev->config = NULL;
+       for (cnt = 0; cnt < usb_dev->descriptor.bNumConfigurations; cnt++)
+               kfree(usb_dev->rawdescriptors[cnt]);
+       usb_dev->descriptor.bNumConfigurations = 0;
+       kfree(usb_dev->rawdescriptors);
+out_unauthorized:
+       usb_unlock_device(usb_dev);
+       return 0;
+}
+
+
+int usb_authorize_device(struct usb_device *usb_dev)
+{
+       int result = 0, c;
+       usb_lock_device(usb_dev);
+       if (usb_dev->authorized == 1)
+               goto out_authorized;
+       kfree(usb_dev->product);
+       usb_dev->product = NULL;
+       kfree(usb_dev->manufacturer);
+       usb_dev->manufacturer = NULL;
+       kfree(usb_dev->serial);
+       usb_dev->serial = NULL;
+       result = usb_autoresume_device(usb_dev);
+       if (result < 0) {
+               dev_err(&usb_dev->dev,
+                       "can't autoresume for authorization: %d\n", result);
+               goto error_autoresume;
+       }
+       result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor));
+       if (result < 0) {
+               dev_err(&usb_dev->dev, "can't re-read device descriptor for "
+                       "authorization: %d\n", result);
+               goto error_device_descriptor;
+       }
+       usb_dev->authorized = 1;
+       result = usb_configure_device(usb_dev);
+       if (result < 0)
+               goto error_configure;
+       /* Choose and set the configuration.  This registers the interfaces
+        * with the driver core and lets interface drivers bind to them.
+        */
+       c = usb_choose_configuration(usb_dev);
+       if (c >= 0) {
+               result = usb_set_configuration(usb_dev, c);
+               if (result) {
+                       dev_err(&usb_dev->dev,
+                               "can't set config #%d, error %d\n", c, result);
+                       /* This need not be fatal.  The user can try to
+                        * set other configurations. */
+               }
+       }
+       dev_info(&usb_dev->dev, "authorized to connect\n");
+error_configure:
+error_device_descriptor:
+error_autoresume:
+out_authorized:
+       usb_unlock_device(usb_dev);     // complements locktree
+       return result;
+}
+
+
 static int hub_port_status(struct usb_hub *hub, int port1,
                               u16 *status, u16 *change)
 {
@@ -1432,9 +1556,9 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
                if (!(portstatus & USB_PORT_STAT_CONNECTION))
                        return -ENOTCONN;
 
-               /* bomb out completely if something weird happened */
+               /* bomb out completely if the connection bounced */
                if ((portchange & USB_PORT_STAT_C_CONNECTION))
-                       return -EINVAL;
+                       return -ENOTCONN;
 
                /* if we`ve finished resetting, then break out of the loop */
                if (!(portstatus & USB_PORT_STAT_RESET) &&
@@ -1467,6 +1591,11 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
 {
        int i, status;
 
+       /* Block EHCI CF initialization during the port reset.
+        * Some companion controllers don't like it when they mix.
+        */
+       down_read(&ehci_cf_port_reset_rwsem);
+
        /* Reset the port */
        for (i = 0; i < PORT_RESET_TRIES; i++) {
                status = set_port_feature(hub->hdev,
@@ -1488,6 +1617,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
                case 0:
                        /* TRSTRCY = 10 ms; plus some extra */
                        msleep(10 + 40);
+                       udev->devnum = 0;       /* Device now at address 0 */
                        /* FALL THROUGH */
                case -ENOTCONN:
                case -ENODEV:
@@ -1497,7 +1627,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
                        usb_set_device_state(udev, status
                                        ? USB_STATE_NOTATTACHED
                                        : USB_STATE_DEFAULT);
-                       return status;
+                       goto done;
                }
 
                dev_dbg (hub->intfdev,
@@ -1510,37 +1640,29 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
                "Cannot enable port %i.  Maybe the USB cable is bad?\n",
                port1);
 
+ done:
+       up_read(&ehci_cf_port_reset_rwsem);
        return status;
 }
 
-/*
- * Disable a port and mark a logical connnect-change event, so that some
- * time later khubd will disconnect() any existing usb_device on the port
- * and will re-enumerate if there actually is a device attached.
- */
-static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
-{
-       dev_dbg(hub->intfdev, "logical disconnect on port %d\n", port1);
-       hub_port_disable(hub, port1, 1);
-
-       /* FIXME let caller ask to power down the port:
-        *  - some devices won't enumerate without a VBUS power cycle
-        *  - SRP saves power that way
-        *  - ... new call, TBD ...
-        * That's easy if this hub can switch power per-port, and
-        * khubd reactivates the port later (timer, SRP, etc).
-        * Powerdown must be optional, because of reset/DFU.
-        */
-
-       set_bit(port1, hub->change_bits);
-       kick_khubd(hub);
-}
-
 #ifdef CONFIG_PM
 
 #ifdef CONFIG_USB_SUSPEND
 
 /*
+ * usb_port_suspend - suspend a usb device's upstream port
+ * @udev: device that's no longer in active use, not a root hub
+ * Context: must be able to sleep; device not locked; pm locks held
+ *
+ * Suspends a USB device that isn't in active use, conserving power.
+ * Devices may wake out of a suspend, if anything important happens,
+ * using the remote wakeup mechanism.  They may also be taken out of
+ * suspend by the host, using usb_port_resume().  It's also routine
+ * to disconnect devices while they are suspended.
+ *
+ * This only affects the USB hardware for a device; its interfaces
+ * (and, for hubs, child devices) must already have been suspended.
+ *
  * Selective port suspend reduces power; most suspended devices draw
  * less than 500 uA.  It's also used in OTG, along with remote wakeup.
  * All devices below the suspended port are also suspended.
@@ -1549,11 +1671,35 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
  * also support "remote wakeup", where the device can activate the USB
  * tree above them to deliver data, such as a keypress or packet.  In
  * some cases, this wakes the USB host.
+ *
+ * Suspending OTG devices may trigger HNP, if that's been enabled
+ * between a pair of dual-role devices.  That will change roles, such
+ * as from A-Host to A-Peripheral or from B-Host back to B-Peripheral.
+ *
+ * Devices on USB hub ports have only one "suspend" state, corresponding
+ * to ACPI D2, "may cause the device to lose some context".
+ * State transitions include:
+ *
+ *   - suspend, resume ... when the VBUS power link stays live
+ *   - suspend, disconnect ... VBUS lost
+ *
+ * Once VBUS drop breaks the circuit, the port it's using has to go through
+ * normal re-enumeration procedures, starting with enabling VBUS power.
+ * Other than re-initializing the hub (plug/unplug, except for root hubs),
+ * Linux (2.6) currently has NO mechanisms to initiate that:  no khubd
+ * timer, no SRP, no requests through sysfs.
+ *
+ * If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when
+ * the root hub for their bus goes into global suspend ... so we don't
+ * (falsely) update the device power state to say it suspended.
+ *
+ * Returns 0 on success, else negative errno.
  */
-static int hub_port_suspend(struct usb_hub *hub, int port1,
-               struct usb_device *udev)
+int usb_port_suspend(struct usb_device *udev)
 {
-       int     status;
+       struct usb_hub  *hub = hdev_to_hub(udev->parent);
+       int             port1 = udev->portnum;
+       int             status;
 
        // dev_dbg(hub->intfdev, "suspend port %d\n", port1);
 
@@ -1570,17 +1716,15 @@ static int hub_port_suspend(struct usb_hub *hub, int port1,
                                NULL, 0,
                                USB_CTRL_SET_TIMEOUT);
                if (status)
-                       dev_dbg(&udev->dev,
-                               "won't remote wakeup, status %d\n",
-                               status);
+                       dev_dbg(&udev->dev, "won't remote wakeup, status %d\n",
+                                       status);
        }
 
        /* see 7.1.7.6 */
        status = set_port_feature(hub->hdev, port1, USB_PORT_FEAT_SUSPEND);
        if (status) {
-               dev_dbg(hub->intfdev,
-                       "can't suspend port %d, status %d\n",
-                       port1, status);
+               dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n",
+                               port1, status);
                /* paranoia:  "should not happen" */
                (void) usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
                                USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE,
@@ -1598,85 +1742,24 @@ static int hub_port_suspend(struct usb_hub *hub, int port1,
 }
 
 /*
- * Devices on USB hub ports have only one "suspend" state, corresponding
- * to ACPI D2, "may cause the device to lose some context".
- * State transitions include:
- *
- *   - suspend, resume ... when the VBUS power link stays live
- *   - suspend, disconnect ... VBUS lost
- *
- * Once VBUS drop breaks the circuit, the port it's using has to go through
- * normal re-enumeration procedures, starting with enabling VBUS power.
- * Other than re-initializing the hub (plug/unplug, except for root hubs),
- * Linux (2.6) currently has NO mechanisms to initiate that:  no khubd
- * timer, no SRP, no requests through sysfs.
- *
- * If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when
- * the root hub for their bus goes into global suspend ... so we don't
- * (falsely) update the device power state to say it suspended.
- */
-static int __usb_port_suspend (struct usb_device *udev, int port1)
-{
-       int     status = 0;
-
-       /* caller owns the udev device lock */
-       if (port1 < 0)
-               return port1;
-
-       /* we change the device's upstream USB link,
-        * but root hubs have no upstream USB link.
-        */
-       if (udev->parent)
-               status = hub_port_suspend(hdev_to_hub(udev->parent), port1,
-                               udev);
-       else {
-               dev_dbg(&udev->dev, "usb %ssuspend\n",
-                               udev->auto_pm ? "auto-" : "");
-               usb_set_device_state(udev, USB_STATE_SUSPENDED);
-       }
-       return status;
-}
-
-/*
- * usb_port_suspend - suspend a usb device's upstream port
- * @udev: device that's no longer in active use
- * Context: must be able to sleep; device not locked; pm locks held
- *
- * Suspends a USB device that isn't in active use, conserving power.
- * Devices may wake out of a suspend, if anything important happens,
- * using the remote wakeup mechanism.  They may also be taken out of
- * suspend by the host, using usb_port_resume().  It's also routine
- * to disconnect devices while they are suspended.
- *
- * This only affects the USB hardware for a device; its interfaces
- * (and, for hubs, child devices) must already have been suspended.
- *
- * Suspending OTG devices may trigger HNP, if that's been enabled
- * between a pair of dual-role devices.  That will change roles, such
- * as from A-Host to A-Peripheral or from B-Host back to B-Peripheral.
- *
- * Returns 0 on success, else negative errno.
- */
-int usb_port_suspend(struct usb_device *udev)
-{
-       return __usb_port_suspend(udev, udev->portnum);
-}
-
-/*
  * If the USB "suspend" state is in use (rather than "global suspend"),
  * many devices will be individually taken out of suspend state using
- * special" resume" signaling.  These routines kick in shortly after
+ * special "resume" signaling.  This routine kicks in shortly after
  * hardware resume signaling is finished, either because of selective
  * resume (by host) or remote wakeup (by device) ... now see what changed
  * in the tree that's rooted at this device.
+ *
+ * If @udev->reset_resume is set then the device is reset before the
+ * status check is done.
  */
 static int finish_port_resume(struct usb_device *udev)
 {
-       int     status;
+       int     status = 0;
        u16     devstatus;
 
        /* caller owns the udev device lock */
-       dev_dbg(&udev->dev, "finish resume\n");
+       dev_dbg(&udev->dev, "finish %sresume\n",
+                       udev->reset_resume ? "reset-" : "");
 
        /* usb ch9 identifies four variants of SUSPENDED, based on what
         * state the device resumes to.  Linux currently won't see the
@@ -1687,22 +1770,31 @@ static int finish_port_resume(struct usb_device *udev)
                        ? USB_STATE_CONFIGURED
                        : USB_STATE_ADDRESS);
 
+       /* 10.5.4.5 says not to reset a suspended port if the attached
+        * device is enabled for remote wakeup.  Hence the reset
+        * operation is carried out here, after the port has been
+        * resumed.
+        */
+       if (udev->reset_resume)
+               status = usb_reset_device(udev);
+
        /* 10.5.4.5 says be sure devices in the tree are still there.
         * For now let's assume the device didn't go crazy on resume,
         * and device drivers will know about any resume quirks.
         */
-       status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
-       if (status >= 0)
-               status = (status == 2 ? 0 : -ENODEV);
+       if (status == 0) {
+               devstatus = 0;
+               status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
+               if (status >= 0)
+                       status = (status > 0 ? 0 : -ENODEV);
+       }
 
-       if (status)
-               dev_dbg(&udev->dev,
-                       "gone after usb resume? status %d\n",
-                       status);
-       else if (udev->actconfig) {
+       if (status) {
+               dev_dbg(&udev->dev, "gone after usb resume? status %d\n",
+                               status);
+       } else if (udev->actconfig) {
                le16_to_cpus(&devstatus);
-               if ((devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP))
-                               && udev->parent) {
+               if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) {
                        status = usb_control_msg(udev,
                                        usb_sndctrlpipe(udev, 0),
                                        USB_REQ_CLEAR_FEATURE,
@@ -1715,19 +1807,52 @@ static int finish_port_resume(struct usb_device *udev)
                                        "wakeup, status %d\n", status);
                }
                status = 0;
-
-       } else if (udev->devnum <= 0) {
-               dev_dbg(&udev->dev, "bogus resume!\n");
-               status = -EINVAL;
        }
        return status;
 }
 
-static int
-hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
+/*
+ * usb_port_resume - re-activate a suspended usb device's upstream port
+ * @udev: device to re-activate, not a root hub
+ * Context: must be able to sleep; device not locked; pm locks held
+ *
+ * This will re-activate the suspended device, increasing power usage
+ * while letting drivers communicate again with its endpoints.
+ * USB resume explicitly guarantees that the power session between
+ * the host and the device is the same as it was when the device
+ * suspended.
+ *
+ * If CONFIG_USB_PERSIST and @udev->reset_resume are both set then this
+ * routine won't check that the port is still enabled.  Furthermore,
+ * if @udev->reset_resume is set then finish_port_resume() above will
+ * reset @udev.  The end result is that a broken power session can be
+ * recovered and @udev will appear to persist across a loss of VBUS power.
+ *
+ * For example, if a host controller doesn't maintain VBUS suspend current
+ * during a system sleep or is reset when the system wakes up, all the USB
+ * power sessions below it will be broken.  This is especially troublesome
+ * for mass-storage devices containing mounted filesystems, since the
+ * device will appear to have disconnected and all the memory mappings
+ * to it will be lost.  Using the USB_PERSIST facility, the device can be
+ * made to appear as if it had not disconnected.
+ *
+ * This facility is inherently dangerous.  Although usb_reset_device()
+ * makes every effort to insure that the same device is present after the
+ * reset as before, it cannot provide a 100% guarantee.  Furthermore it's
+ * quite possible for a device to remain unaltered but its media to be
+ * changed.  If the user replaces a flash memory card while the system is
+ * asleep, he will have only himself to blame when the filesystem on the
+ * new card is corrupted and the system crashes.
+ *
+ * Returns 0 on success, else negative errno.
+ */
+int usb_port_resume(struct usb_device *udev)
 {
-       int     status;
-       u16     portchange, portstatus;
+       struct usb_hub  *hub = hdev_to_hub(udev->parent);
+       int             port1 = udev->portnum;
+       int             status;
+       u16             portchange, portstatus;
+       unsigned        mask_flags, want_flags;
 
        /* Skip the initial Clear-Suspend step for a remote wakeup */
        status = hub_port_status(hub, port1, &portstatus, &portchange);
@@ -1742,30 +1867,31 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
        status = clear_port_feature(hub->hdev,
                        port1, USB_PORT_FEAT_SUSPEND);
        if (status) {
-               dev_dbg(hub->intfdev,
-                       "can't resume port %d, status %d\n",
-                       port1, status);
+               dev_dbg(hub->intfdev, "can't resume port %d, status %d\n",
+                               port1, status);
        } else {
                /* drive resume for at least 20 msec */
-               if (udev)
-                       dev_dbg(&udev->dev, "usb %sresume\n",
-                                       udev->auto_pm ? "auto-" : "");
+               dev_dbg(&udev->dev, "usb %sresume\n",
+                               udev->auto_pm ? "auto-" : "");
                msleep(25);
 
-#define LIVE_FLAGS     ( USB_PORT_STAT_POWER \
-                       | USB_PORT_STAT_ENABLE \
-                       | USB_PORT_STAT_CONNECTION)
-
                /* Virtual root hubs can trigger on GET_PORT_STATUS to
                 * stop resume signaling.  Then finish the resume
                 * sequence.
                 */
                status = hub_port_status(hub, port1, &portstatus, &portchange);
-SuspendCleared:
-               if (status < 0
-                               || (portstatus & LIVE_FLAGS) != LIVE_FLAGS
-                               || (portstatus & USB_PORT_STAT_SUSPEND) != 0
-                               ) {
+
+ SuspendCleared:
+               if (USB_PERSIST && udev->reset_resume)
+                       want_flags = USB_PORT_STAT_POWER
+                                       | USB_PORT_STAT_CONNECTION;
+               else
+                       want_flags = USB_PORT_STAT_POWER
+                                       | USB_PORT_STAT_CONNECTION
+                                       | USB_PORT_STAT_ENABLE;
+               mask_flags = want_flags | USB_PORT_STAT_SUSPEND;
+
+               if (status < 0 || (portstatus & mask_flags) != want_flags) {
                        dev_dbg(hub->intfdev,
                                "port %d status %04x.%04x after resume, %d\n",
                                port1, portchange, portstatus, status);
@@ -1777,51 +1903,19 @@ SuspendCleared:
                                                USB_PORT_FEAT_C_SUSPEND);
                        /* TRSMRCY = 10 msec */
                        msleep(10);
-                       if (udev)
-                               status = finish_port_resume(udev);
                }
        }
-       if (status < 0)
-               hub_port_logical_disconnect(hub, port1);
 
        clear_bit(port1, hub->busy_bits);
        if (!hub->hdev->parent && !hub->busy_bits[0])
                usb_enable_root_hub_irq(hub->hdev->bus);
 
-       return status;
-}
-
-/*
- * usb_port_resume - re-activate a suspended usb device's upstream port
- * @udev: device to re-activate
- * Context: must be able to sleep; device not locked; pm locks held
- *
- * This will re-activate the suspended device, increasing power usage
- * while letting drivers communicate again with its endpoints.
- * USB resume explicitly guarantees that the power session between
- * the host and the device is the same as it was when the device
- * suspended.
- *
- * Returns 0 on success, else negative errno.
- */
-int usb_port_resume(struct usb_device *udev)
-{
-       int     status;
-
-       /* we change the device's upstream USB link,
-        * but root hubs have no upstream USB link.
-        */
-       if (udev->parent) {
-               // NOTE this fails if parent is also suspended...
-               status = hub_port_resume(hdev_to_hub(udev->parent),
-                               udev->portnum, udev);
-       } else {
-               dev_dbg(&udev->dev, "usb %sresume\n",
-                               udev->auto_pm ? "auto-" : "");
+       if (status == 0)
                status = finish_port_resume(udev);
-       }
-       if (status < 0)
+       if (status < 0) {
                dev_dbg(&udev->dev, "can't resume, status %d\n", status);
+               hub_port_logical_disconnect(hub, port1);
+       }
        return status;
 }
 
@@ -1848,21 +1942,16 @@ int usb_port_suspend(struct usb_device *udev)
        return 0;
 }
 
-static inline int
-finish_port_resume(struct usb_device *udev)
-{
-       return 0;
-}
-
-static inline int
-hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
-{
-       return 0;
-}
-
 int usb_port_resume(struct usb_device *udev)
 {
-       return 0;
+       int status = 0;
+
+       /* However we may need to do a reset-resume */
+       if (udev->reset_resume) {
+               dev_dbg(&udev->dev, "reset-resume\n");
+               status = usb_reset_device(udev);
+       }
+       return status;
 }
 
 static inline int remote_wakeup(struct usb_device *udev)
@@ -1883,14 +1972,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
                struct usb_device       *udev;
 
                udev = hdev->children [port1-1];
-               if (udev && msg.event == PM_EVENT_SUSPEND &&
-#ifdef CONFIG_USB_SUSPEND
-                               udev->state != USB_STATE_SUSPENDED
-#else
-                               udev->dev.power.power_state.event
-                                       == PM_EVENT_ON
-#endif
-                               ) {
+               if (udev && udev->can_submit) {
                        if (!hdev->auto_pm)
                                dev_dbg(&intf->dev, "port %d nyet suspended\n",
                                                port1);
@@ -1916,6 +1998,61 @@ static int hub_resume(struct usb_interface *intf)
        return 0;
 }
 
+static int hub_reset_resume(struct usb_interface *intf)
+{
+       struct usb_hub *hub = usb_get_intfdata(intf);
+       struct usb_device *hdev = hub->hdev;
+       int port1;
+
+       hub_power_on(hub);
+
+       for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
+               struct usb_device *child = hdev->children[port1-1];
+
+               if (child) {
+
+                       /* For "USB_PERSIST"-enabled children we must
+                        * mark the child device for reset-resume and
+                        * turn off the connect-change status to prevent
+                        * khubd from disconnecting it later.
+                        */
+                       if (USB_PERSIST && child->persist_enabled) {
+                               child->reset_resume = 1;
+                               clear_port_feature(hdev, port1,
+                                               USB_PORT_FEAT_C_CONNECTION);
+
+                       /* Otherwise we must disconnect the child,
+                        * but as we may not lock the child device here
+                        * we have to do a "logical" disconnect.
+                        */
+                       } else {
+                               hub_port_logical_disconnect(hub, port1);
+                       }
+               }
+       }
+
+       hub_activate(hub);
+       return 0;
+}
+
+/**
+ * usb_root_hub_lost_power - called by HCD if the root hub lost Vbus power
+ * @rhdev: struct usb_device for the root hub
+ *
+ * The USB host controller driver calls this function when its root hub
+ * is resumed and Vbus power has been interrupted or the controller
+ * has been reset.  The routine marks @rhdev as having lost power.  When
+ * the hub driver is resumed it will take notice; if CONFIG_USB_PERSIST
+ * is enabled then it will carry out power-session recovery, otherwise
+ * it will disconnect all the child devices.
+ */
+void usb_root_hub_lost_power(struct usb_device *rhdev)
+{
+       dev_warn(&rhdev->dev, "root hub lost power or was reset\n");
+       rhdev->reset_resume = 1;
+}
+EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
+
 #else  /* CONFIG_PM */
 
 static inline int remote_wakeup(struct usb_device *udev)
@@ -1923,8 +2060,9 @@ static inline int remote_wakeup(struct usb_device *udev)
        return 0;
 }
 
-#define hub_suspend NULL
-#define hub_resume NULL
+#define hub_suspend            NULL
+#define hub_resume             NULL
+#define hub_reset_resume       NULL
 #endif
 
 
@@ -1993,26 +2131,27 @@ static void ep0_reinit(struct usb_device *udev)
 {
        usb_disable_endpoint(udev, 0 + USB_DIR_IN);
        usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
-       udev->ep_in[0] = udev->ep_out[0] = &udev->ep0;
+       usb_enable_endpoint(udev, &udev->ep0);
 }
 
 #define usb_sndaddr0pipe()     (PIPE_CONTROL << 30)
 #define usb_rcvaddr0pipe()     ((PIPE_CONTROL << 30) | USB_DIR_IN)
 
-static int hub_set_address(struct usb_device *udev)
+static int hub_set_address(struct usb_device *udev, int devnum)
 {
        int retval;
 
-       if (udev->devnum == 0)
+       if (devnum <= 1)
                return -EINVAL;
        if (udev->state == USB_STATE_ADDRESS)
                return 0;
        if (udev->state != USB_STATE_DEFAULT)
                return -EINVAL;
        retval = usb_control_msg(udev, usb_sndaddr0pipe(),
-               USB_REQ_SET_ADDRESS, 0, udev->devnum, 0,
+               USB_REQ_SET_ADDRESS, 0, devnum, 0,
                NULL, 0, USB_CTRL_SET_TIMEOUT);
        if (retval == 0) {
+               udev->devnum = devnum;  /* Device now using proper address */
                usb_set_device_state(udev, USB_STATE_ADDRESS);
                ep0_reinit(udev);
        }
@@ -2039,6 +2178,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
        unsigned                delay = HUB_SHORT_RESET_TIME;
        enum usb_device_speed   oldspeed = udev->speed;
        char                    *speed, *type;
+       int                     devnum = udev->devnum;
 
        /* root hub ports have a slightly longer reset period
         * (from USB 2.0 spec, section 7.1.7.5)
@@ -2068,7 +2208,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
                goto fail;
        }
        oldspeed = udev->speed;
-  
+
        /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
         * it's fixed size except for full speed devices.
         * For Wireless USB devices, ep0 max packet is always 512 (tho
@@ -2109,7 +2249,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
        dev_info (&udev->dev,
                  "%s %s speed %sUSB device using %s and address %d\n",
                  (udev->config) ? "reset" : "new", speed, type,
-                 udev->bus->controller->driver->name, udev->devnum);
+                 udev->bus->controller->driver->name, devnum);
 
        /* Set up TT records, if needed  */
        if (hdev->tt) {
@@ -2196,7 +2336,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
                }
 
                for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
-                       retval = hub_set_address(udev);
+                       retval = hub_set_address(udev, devnum);
                        if (retval >= 0)
                                break;
                        msleep(200);
@@ -2204,7 +2344,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
                if (retval < 0) {
                        dev_err(&udev->dev,
                                "device not accepting address %d, error %d\n",
-                               udev->devnum, retval);
+                               devnum, retval);
                        goto fail;
                }
  
@@ -2257,8 +2397,10 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
        retval = 0;
 
 fail:
-       if (retval)
+       if (retval) {
                hub_port_disable(hub, port1, 0);
+               udev->devnum = devnum;  /* for disconnect processing */
+       }
        mutex_unlock(&usb_address0_mutex);
        return retval;
 }
@@ -2497,7 +2639,7 @@ loop:
                ep0_reinit(udev);
                release_address(udev);
                usb_put_dev(udev);
-               if (status == -ENOTCONN)
+               if ((status == -ENOTCONN) || (status == -ENOTSUPP))
                        break;
        }
  
@@ -2693,9 +2835,9 @@ static void hub_events(void)
                                clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
                                if (hubstatus & HUB_STATUS_LOCAL_POWER)
                                        /* FIXME: Is this always true? */
-                                       hub->limited_power = 0;
-                               else
                                        hub->limited_power = 1;
+                               else
+                                       hub->limited_power = 0;
                        }
                        if (hubchange & HUB_CHANGE_OVERCURRENT) {
                                dev_dbg (hub_dev, "overcurrent change\n");
@@ -2725,12 +2867,12 @@ loop:
 
 static int hub_thread(void *__unused)
 {
+       set_freezable();
        do {
                hub_events();
-               wait_event_interruptible(khubd_wait,
+               wait_event_freezable(khubd_wait,
                                !list_empty(&hub_event_list) ||
                                kthread_should_stop());
-               try_to_freeze();
        } while (!kthread_should_stop() || !list_empty(&hub_event_list));
 
        pr_debug("%s: khubd exiting\n", usbcore_name);
@@ -2753,6 +2895,7 @@ static struct usb_driver hub_driver = {
        .disconnect =   hub_disconnect,
        .suspend =      hub_suspend,
        .resume =       hub_resume,
+       .reset_resume = hub_reset_resume,
        .pre_reset =    hub_pre_reset,
        .post_reset =   hub_post_reset,
        .ioctl =        hub_ioctl,
@@ -2855,6 +2998,11 @@ static int config_descriptors_changed(struct usb_device *udev)
  * this from a driver probe() routine after downloading new firmware.
  * For calls that might not occur during probe(), drivers should lock
  * the device using usb_lock_device_for_reset().
+ *
+ * Locking exception: This routine may also be called from within an
+ * autoresume handler.  Such usage won't conflict with other tasks
+ * holding the device lock because these tasks should always call
+ * usb_autopm_resume_device(), thereby preventing any unwanted autoresume.
  */
 int usb_reset_device(struct usb_device *udev)
 {
@@ -2885,7 +3033,7 @@ int usb_reset_device(struct usb_device *udev)
                 * Other endpoints will be handled by re-enumeration. */
                ep0_reinit(udev);
                ret = hub_port_init(parent_hub, udev, port1, i);
-               if (ret >= 0)
+               if (ret >= 0 || ret == -ENOTCONN || ret == -ENODEV)
                        break;
        }
        clear_bit(port1, parent_hub->busy_bits);
@@ -3001,6 +3149,7 @@ int usb_reset_composite_device(struct usb_device *udev,
                                drv = to_usb_driver(cintf->dev.driver);
                                if (drv->pre_reset)
                                        (drv->pre_reset)(cintf);
+       /* FIXME: Unbind if pre_reset returns an error or isn't defined */
                        }
                }
        }
@@ -3019,6 +3168,7 @@ int usb_reset_composite_device(struct usb_device *udev,
                                drv = to_usb_driver(cintf->dev.driver);
                                if (drv->post_reset)
                                        (drv->post_reset)(cintf);
+       /* FIXME: Unbind if post_reset returns an error or isn't defined */
                        }
                        if (cintf != iface)
                                up(&cintf->dev.sem);