]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'usb-3.3-rc4' into usb-next
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 23 Feb 2012 16:20:44 +0000 (08:20 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 23 Feb 2012 16:21:03 +0000 (08:21 -0800)
This is to pull in the xhci changes and the other fixes and device id
updates that were done in Linus's tree.

Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1  2 
drivers/usb/core/hub.c
drivers/usb/host/xhci-mem.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/storage/usb.c

diff --combined drivers/usb/core/hub.c
index 265c2f675d04295e031513fc32506752e7720a99,d4f062472796d8c2a6b07c023077060b29605518..72c51cdce9065d5765be7138e770a43dd7d24a4f
@@@ -62,6 -62,8 +62,8 @@@ struct usb_hub 
                                                        resumed */
        unsigned long           removed_bits[1]; /* ports with a "removed"
                                                        device present */
+       unsigned long           wakeup_bits[1]; /* ports that have signaled
+                                                       remote wakeup */
  #if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */
  #error event_bits[] is too short!
  #endif
@@@ -411,6 -413,29 +413,29 @@@ void usb_kick_khubd(struct usb_device *
                kick_khubd(hub);
  }
  
+ /*
+  * Let the USB core know that a USB 3.0 device has sent a Function Wake Device
+  * Notification, which indicates it had initiated remote wakeup.
+  *
+  * USB 3.0 hubs do not report the port link state change from U3 to U0 when the
+  * device initiates resume, so the USB core will not receive notice of the
+  * resume through the normal hub interrupt URB.
+  */
+ void usb_wakeup_notification(struct usb_device *hdev,
+               unsigned int portnum)
+ {
+       struct usb_hub *hub;
+       if (!hdev)
+               return;
+       hub = hdev_to_hub(hdev);
+       if (hub) {
+               set_bit(portnum, hub->wakeup_bits);
+               kick_khubd(hub);
+       }
+ }
+ EXPORT_SYMBOL_GPL(usb_wakeup_notification);
  
  /* completion function, fires on port status changes and various faults */
  static void hub_irq(struct urb *urb)
@@@ -705,26 -730,10 +730,26 @@@ static void hub_activate(struct usb_hu
        if (type == HUB_INIT3)
                goto init3;
  
 -      /* After a resume, port power should still be on.
 +      /* The superspeed hub except for root hub has to use Hub Depth
 +       * value as an offset into the route string to locate the bits
 +       * it uses to determine the downstream port number. So hub driver
 +       * should send a set hub depth request to superspeed hub after
 +       * the superspeed hub is set configuration in initialization or
 +       * reset procedure.
 +       *
 +       * After a resume, port power should still be on.
         * For any other type of activation, turn it on.
         */
        if (type != HUB_RESUME) {
 +              if (hdev->parent && hub_is_superspeed(hdev)) {
 +                      ret = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
 +                                      HUB_SET_DEPTH, USB_RT_HUB,
 +                                      hdev->level - 1, 0, NULL, 0,
 +                                      USB_CTRL_SET_TIMEOUT);
 +                      if (ret < 0)
 +                              dev_err(hub->intfdev,
 +                                              "set hub depth failed\n");
 +              }
  
                /* Speed up system boot by using a delayed_work for the
                 * hub's initial power-up delays.  This is pretty awkward
                        clear_port_feature(hub->hdev, port1,
                                        USB_PORT_FEAT_C_ENABLE);
                }
-               if (portchange & USB_PORT_STAT_C_LINK_STATE) {
-                       need_debounce_delay = true;
-                       clear_port_feature(hub->hdev, port1,
-                                       USB_PORT_FEAT_C_PORT_LINK_STATE);
-               }
                if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
                                hub_is_superspeed(hub->hdev)) {
                        need_debounce_delay = true;
                                set_bit(port1, hub->change_bits);
  
                } else if (portstatus & USB_PORT_STAT_ENABLE) {
+                       bool port_resumed = (portstatus &
+                                       USB_PORT_STAT_LINK_STATE) ==
+                               USB_SS_PORT_LS_U0;
                        /* The power session apparently survived the resume.
                         * If there was an overcurrent or suspend change
                         * (i.e., remote wakeup request), have khubd
-                        * take care of it.
+                        * take care of it.  Look at the port link state
+                        * for USB 3.0 hubs, since they don't have a suspend
+                        * change bit, and they don't set the port link change
+                        * bit on device-initiated resume.
                         */
-                       if (portchange)
+                       if (portchange || (hub_is_superspeed(hub->hdev) &&
+                                               port_resumed))
                                set_bit(port1, hub->change_bits);
  
                } else if (udev->persist_enabled) {
@@@ -1003,6 -1013,18 +1029,6 @@@ static int hub_configure(struct usb_hu
                goto fail;
        }
  
 -      if (hub_is_superspeed(hdev) && (hdev->parent != NULL)) {
 -              ret = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
 -                              HUB_SET_DEPTH, USB_RT_HUB,
 -                              hdev->level - 1, 0, NULL, 0,
 -                              USB_CTRL_SET_TIMEOUT);
 -
 -              if (ret < 0) {
 -                      message = "can't set hub depth";
 -                      goto fail;
 -              }
 -      }
 -
        /* Request the entire hub descriptor.
         * hub->descriptor can handle USB_MAXCHILDREN ports,
         * but the hub can/will return fewer bytes here.
@@@ -1293,14 -1315,8 +1319,8 @@@ static int hub_probe(struct usb_interfa
        desc = intf->cur_altsetting;
        hdev = interface_to_usbdev(intf);
  
-       /* Hubs have proper suspend/resume support.  USB 3.0 device suspend is
-        * different from USB 2.0/1.1 device suspend, and unfortunately we
-        * don't support it yet.  So leave autosuspend disabled for USB 3.0
-        * external hubs for now.  Enable autosuspend for USB 3.0 roothubs,
-        * since that isn't a "real" hub.
-        */
-       if (!hub_is_superspeed(hdev) || !hdev->parent)
-               usb_enable_autosuspend(hdev);
+       /* Hubs have proper suspend/resume support. */
+       usb_enable_autosuspend(hdev);
  
        if (hdev->level == MAX_TOPO_LEVEL) {
                dev_err(&intf->dev,
@@@ -1842,6 -1858,37 +1862,37 @@@ fail
        return err;
  }
  
+ static void set_usb_port_removable(struct usb_device *udev)
+ {
+       struct usb_device *hdev = udev->parent;
+       struct usb_hub *hub;
+       u8 port = udev->portnum;
+       u16 wHubCharacteristics;
+       bool removable = true;
+       if (!hdev)
+               return;
+       hub = hdev_to_hub(udev->parent);
+       wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
+       if (!(wHubCharacteristics & HUB_CHAR_COMPOUND))
+               return;
+       if (hub_is_superspeed(hdev)) {
+               if (hub->descriptor->u.ss.DeviceRemovable & (1 << port))
+                       removable = false;
+       } else {
+               if (hub->descriptor->u.hs.DeviceRemovable[port / 8] & (1 << (port % 8)))
+                       removable = false;
+       }
+       if (removable)
+               udev->removable = USB_DEVICE_REMOVABLE;
+       else
+               udev->removable = USB_DEVICE_FIXED;
+ }
  
  /**
   * usb_new_device - perform initial device setup (usbcore-internal)
@@@ -1900,6 -1947,15 +1951,15 @@@ int usb_new_device(struct usb_device *u
        announce_device(udev);
  
        device_enable_async_suspend(&udev->dev);
+       /*
+        * check whether the hub marks this port as non-removable. Do it
+        * now so that platform-specific data can override it in
+        * device_add()
+        */
+       if (udev->parent)
+               set_usb_port_removable(udev);
        /* Register the device.  The device driver is responsible
         * for configuring the device and invoking the add-device
         * notifier chain (used by usbfs and possibly others).
@@@ -2385,11 -2441,27 +2445,27 @@@ int usb_port_suspend(struct usb_device 
         * we don't explicitly enable it here.
         */
        if (udev->do_remote_wakeup) {
-               status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-                               USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
-                               USB_DEVICE_REMOTE_WAKEUP, 0,
-                               NULL, 0,
-                               USB_CTRL_SET_TIMEOUT);
+               if (!hub_is_superspeed(hub->hdev)) {
+                       status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                                       USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
+                                       USB_DEVICE_REMOTE_WAKEUP, 0,
+                                       NULL, 0,
+                                       USB_CTRL_SET_TIMEOUT);
+               } else {
+                       /* Assume there's only one function on the USB 3.0
+                        * device and enable remote wake for the first
+                        * interface. FIXME if the interface association
+                        * descriptor shows there's more than one function.
+                        */
+                       status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                                       USB_REQ_SET_FEATURE,
+                                       USB_RECIP_INTERFACE,
+                                       USB_INTRF_FUNC_SUSPEND,
+                                       USB_INTRF_FUNC_SUSPEND_RW |
+                                       USB_INTRF_FUNC_SUSPEND_LP,
+                                       NULL, 0,
+                                       USB_CTRL_SET_TIMEOUT);
+               }
                if (status) {
                        dev_dbg(&udev->dev, "won't remote wakeup, status %d\n",
                                        status);
@@@ -2679,6 -2751,7 +2755,7 @@@ static int hub_suspend(struct usb_inter
        struct usb_hub          *hub = usb_get_intfdata (intf);
        struct usb_device       *hdev = hub->hdev;
        unsigned                port1;
+       int                     status;
  
        /* Warn if children aren't already suspended */
        for (port1 = 1; port1 <= hdev->maxchild; port1++) {
                                return -EBUSY;
                }
        }
+       if (hub_is_superspeed(hdev) && hdev->do_remote_wakeup) {
+               /* Enable hub to send remote wakeup for all ports. */
+               for (port1 = 1; port1 <= hdev->maxchild; port1++) {
+                       status = set_port_feature(hdev,
+                                       port1 |
+                                       USB_PORT_FEAT_REMOTE_WAKE_CONNECT |
+                                       USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT |
+                                       USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT,
+                                       USB_PORT_FEAT_REMOTE_WAKE_MASK);
+               }
+       }
  
        dev_dbg(&intf->dev, "%s\n", __func__);
  
@@@ -3424,6 -3508,46 +3512,46 @@@ done
                hcd->driver->relinquish_port(hcd, port1);
  }
  
+ /* Returns 1 if there was a remote wakeup and a connect status change. */
+ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
+               u16 portstatus, u16 portchange)
+ {
+       struct usb_device *hdev;
+       struct usb_device *udev;
+       int connect_change = 0;
+       int ret;
+       hdev = hub->hdev;
+       udev = hdev->children[port-1];
+       if (!hub_is_superspeed(hdev)) {
+               if (!(portchange & USB_PORT_STAT_C_SUSPEND))
+                       return 0;
+               clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND);
+       } else {
+               if (!udev || udev->state != USB_STATE_SUSPENDED ||
+                                (portstatus & USB_PORT_STAT_LINK_STATE) !=
+                                USB_SS_PORT_LS_U0)
+                       return 0;
+       }
+       if (udev) {
+               /* TRSMRCY = 10 msec */
+               msleep(10);
+               usb_lock_device(udev);
+               ret = usb_remote_wakeup(udev);
+               usb_unlock_device(udev);
+               if (ret < 0)
+                       connect_change = 1;
+       } else {
+               ret = -ENODEV;
+               hub_port_disable(hub, port, 1);
+       }
+       dev_dbg(hub->intfdev, "resume on port %d, status %d\n",
+                       port, ret);
+       return connect_change;
+ }
  static void hub_events(void)
  {
        struct list_head *tmp;
        u16 portstatus;
        u16 portchange;
        int i, ret;
-       int connect_change;
+       int connect_change, wakeup_change;
  
        /*
         *  We restart the list every time to avoid a deadlock with
                        if (test_bit(i, hub->busy_bits))
                                continue;
                        connect_change = test_bit(i, hub->change_bits);
+                       wakeup_change = test_and_clear_bit(i, hub->wakeup_bits);
                        if (!test_and_clear_bit(i, hub->event_bits) &&
-                                       !connect_change)
+                                       !connect_change && !wakeup_change)
                                continue;
  
                        ret = hub_port_status(hub, i,
                                }
                        }
  
-                       if (portchange & USB_PORT_STAT_C_SUSPEND) {
-                               struct usb_device *udev;
+                       if (hub_handle_remote_wakeup(hub, i,
+                                               portstatus, portchange))
+                               connect_change = 1;
  
-                               clear_port_feature(hdev, i,
-                                       USB_PORT_FEAT_C_SUSPEND);
-                               udev = hdev->children[i-1];
-                               if (udev) {
-                                       /* TRSMRCY = 10 msec */
-                                       msleep(10);
-                                       usb_lock_device(udev);
-                                       ret = usb_remote_wakeup(hdev->
-                                                       children[i-1]);
-                                       usb_unlock_device(udev);
-                                       if (ret < 0)
-                                               connect_change = 1;
-                               } else {
-                                       ret = -ENODEV;
-                                       hub_port_disable(hub, i, 1);
-                               }
-                               dev_dbg (hub_dev,
-                                       "resume on port %d, status %d\n",
-                                       i, ret);
-                       }
-                       
                        if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
                                u16 status = 0;
                                u16 unused;
index 383fc857491c677fbaf6d0ab56b8cdff9cc415d2,6b70e7fb484c4c4ce33aace27b842f73dc097eab..8339d826ce58b967b754090af284eae78e6a2c66
@@@ -1126,42 -1126,26 +1126,42 @@@ static unsigned int xhci_parse_exponent
  }
  
  /*
 - * Convert bInterval expressed in frames (in 1-255 range) to exponent of
 + * Convert bInterval expressed in microframes (in 1-255 range) to exponent of
   * microframes, rounded down to nearest power of 2.
   */
 -static unsigned int xhci_parse_frame_interval(struct usb_device *udev,
 -              struct usb_host_endpoint *ep)
 +static unsigned int xhci_microframes_to_exponent(struct usb_device *udev,
 +              struct usb_host_endpoint *ep, unsigned int desc_interval,
 +              unsigned int min_exponent, unsigned int max_exponent)
  {
        unsigned int interval;
  
 -      interval = fls(8 * ep->desc.bInterval) - 1;
 -      interval = clamp_val(interval, 3, 10);
 -      if ((1 << interval) != 8 * ep->desc.bInterval)
 +      interval = fls(desc_interval) - 1;
 +      interval = clamp_val(interval, min_exponent, max_exponent);
 +      if ((1 << interval) != desc_interval)
                dev_warn(&udev->dev,
                         "ep %#x - rounding interval to %d microframes, ep desc says %d microframes\n",
                         ep->desc.bEndpointAddress,
                         1 << interval,
 -                       8 * ep->desc.bInterval);
 +                       desc_interval);
  
        return interval;
  }
  
 +static unsigned int xhci_parse_microframe_interval(struct usb_device *udev,
 +              struct usb_host_endpoint *ep)
 +{
 +      return xhci_microframes_to_exponent(udev, ep,
 +                      ep->desc.bInterval, 0, 15);
 +}
 +
 +
 +static unsigned int xhci_parse_frame_interval(struct usb_device *udev,
 +              struct usb_host_endpoint *ep)
 +{
 +      return xhci_microframes_to_exponent(udev, ep,
 +                      ep->desc.bInterval * 8, 3, 10);
 +}
 +
  /* Return the polling or NAK interval.
   *
   * The polling interval is expressed in "microframes".  If xHCI's Interval field
@@@ -1180,7 -1164,7 +1180,7 @@@ static unsigned int xhci_get_endpoint_i
                /* Max NAK rate */
                if (usb_endpoint_xfer_control(&ep->desc) ||
                    usb_endpoint_xfer_bulk(&ep->desc)) {
 -                      interval = ep->desc.bInterval;
 +                      interval = xhci_parse_microframe_interval(udev, ep);
                        break;
                }
                /* Fall through - SS and HS isoc/int have same decoding */
@@@ -2157,7 -2141,7 +2157,7 @@@ int xhci_mem_init(struct xhci_hcd *xhci
        unsigned int    val, val2;
        u64             val_64;
        struct xhci_segment     *seg;
-       u32 page_size;
+       u32 page_size, temp;
        int i;
  
        page_size = xhci_readl(xhci, &xhci->op_regs->page_size);
  
        INIT_LIST_HEAD(&xhci->lpm_failed_devs);
  
+       /* Enable USB 3.0 device notifications for function remote wake, which
+        * is necessary for allowing USB 3.0 devices to do remote wakeup from
+        * U3 (device suspend).
+        */
+       temp = xhci_readl(xhci, &xhci->op_regs->dev_notification);
+       temp &= ~DEV_NOTE_MASK;
+       temp |= DEV_NOTE_FWAKE;
+       xhci_writel(xhci, temp, &xhci->op_regs->dev_notification);
        return 0;
  
  fail:
index 08a5575724cd3f12b1a55966db21ac95e8495806,90721b49eed73c52d2a4f62010140723c5d810ca..ec9dc4e9a3ff9fa1bb070589f701f7e485e3702e
@@@ -136,8 -136,6 +136,8 @@@ static const struct usb_device_id id_ta
        { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */
        { USB_DEVICE(0x16DC, 0x0012) }, /* W-IE-NE-R Plein & Baus GmbH MPOD Multi Channel Power Supply */
        { USB_DEVICE(0x16DC, 0x0015) }, /* W-IE-NE-R Plein & Baus GmbH CML Control, Monitoring and Data Logger */
 +      { USB_DEVICE(0x17A8, 0x0001) }, /* Kamstrup Optical Eye/3-wire */
 +      { USB_DEVICE(0x17A8, 0x0005) }, /* Kamstrup M-Bus Master MultiPort 250D */
        { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */
        { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */
        { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
@@@ -286,7 -284,7 +286,7 @@@ static int cp210x_get_config(struct usb
  
        if (result != size) {
                dbg("%s - Unable to send config request, "
-                               "request=0x%x size=%d result=%d\n",
+                               "request=0x%x size=%d result=%d",
                                __func__, request, size, result);
                if (result > 0)
                        result = -EPROTO;
@@@ -340,7 -338,7 +340,7 @@@ static int cp210x_set_config(struct usb
  
        if ((size > 2 && result != size) || result < 0) {
                dbg("%s - Unable to send request, "
-                               "request=0x%x size=%d result=%d\n",
+                               "request=0x%x size=%d result=%d",
                                __func__, request, size, result);
                if (result > 0)
                        result = -EPROTO;
@@@ -683,13 -681,13 +683,13 @@@ static void cp210x_set_termios(struct t
                default:
                        dbg("cp210x driver does not "
                                        "support the number of bits requested,"
-                                       " using 8 bit mode\n");
+                                       " using 8 bit mode");
                                bits |= BITS_DATA_8;
                                break;
                }
                if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
                        dbg("Number of data bits requested "
-                                       "not supported by device\n");
+                                       "not supported by device");
        }
  
        if ((cflag     & (PARENB|PARODD|CMSPAR)) !=
                        }
                }
                if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
-                       dbg("Parity mode not supported "
-                                       "by device\n");
+                       dbg("Parity mode not supported by device");
        }
  
        if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) {
                }
                if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
                        dbg("Number of stop bits requested "
-                                       "not supported by device\n");
+                                       "not supported by device");
        }
  
        if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
index 75b838eff178ca743a3f53069ef2d515cb6f0b15,91d0dc6403606e9a75cf1b690260f4fda744b542..74f2c7746cc4d95993f1b70037622f18fa2fefc5
@@@ -165,7 -165,7 +165,7 @@@ static unsigned int product_5052_count
  /* the array dimension is the number of default entries plus */
  /* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */
  /* null entry */
 -static struct usb_device_id ti_id_table_3410[13+TI_EXTRA_VID_PID_COUNT+1] = {
 +static struct usb_device_id ti_id_table_3410[14+TI_EXTRA_VID_PID_COUNT+1] = {
        { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
        { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
        { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
        { USB_DEVICE(IBM_VENDOR_ID, IBM_4543_PRODUCT_ID) },
        { USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) },
        { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) },
 +      { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) },
  };
  
  static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = {
        { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) },
  };
  
 -static struct usb_device_id ti_id_table_combined[17+2*TI_EXTRA_VID_PID_COUNT+1] = {
 +static struct usb_device_id ti_id_table_combined[18+2*TI_EXTRA_VID_PID_COUNT+1] = {
        { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
        { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
        { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
        { USB_DEVICE(IBM_VENDOR_ID, IBM_4543_PRODUCT_ID) },
        { USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) },
        { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) },
 +      { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) },
        { }
  };
  
@@@ -1250,7 -1248,6 +1250,6 @@@ static void ti_bulk_out_callback(struc
  {
        struct ti_port *tport = urb->context;
        struct usb_serial_port *port = tport->tp_port;
-       struct device *dev = &urb->dev->dev;
        int status = urb->status;
  
        dbg("%s - port %d", __func__, port->number);
                wake_up_interruptible(&tport->tp_write_wait);
                return;
        default:
-               dev_err(dev, "%s - nonzero urb status, %d\n",
+               dev_err_console(port, "%s - nonzero urb status, %d\n",
                        __func__, status);
                tport->tp_tdev->td_urb_error = 1;
                wake_up_interruptible(&tport->tp_write_wait);
@@@ -1337,7 -1334,7 +1336,7 @@@ static void ti_send(struct ti_port *tpo
  
        result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
        if (result) {
-               dev_err(&port->dev, "%s - submit write urb failed, %d\n",
+               dev_err_console(port, "%s - submit write urb failed, %d\n",
                                                        __func__, result);
                tport->tp_write_urb_in_use = 0;
                /* TODO: reschedule ti_send */
index db51ba16dc0755d6b7876c115abd10eba6e876c7,58f56775ecde5910862aab47a76846d9c86cebcd..c18538e4a6db1e0adeb26437b3b6f2de38b6b38c
@@@ -125,6 -125,9 +125,9 @@@ static struct us_unusual_dev us_unusual
        { }             /* Terminating entry */
  };
  
+ static struct us_unusual_dev for_dynamic_ids =
+               USUAL_DEV(USB_SC_SCSI, USB_PR_BULK, 0);
  #undef UNUSUAL_DEV
  #undef COMPLIANT_DEV
  #undef USUAL_DEV
@@@ -788,19 -791,15 +791,19 @@@ static void quiesce_and_remove_host(str
        struct Scsi_Host *host = us_to_host(us);
  
        /* If the device is really gone, cut short reset delays */
 -      if (us->pusb_dev->state == USB_STATE_NOTATTACHED)
 +      if (us->pusb_dev->state == USB_STATE_NOTATTACHED) {
                set_bit(US_FLIDX_DISCONNECTING, &us->dflags);
 +              wake_up(&us->delay_wait);
 +      }
  
 -      /* Prevent SCSI-scanning (if it hasn't started yet)
 -       * and wait for the SCSI-scanning thread to stop.
 +      /* Prevent SCSI scanning (if it hasn't started yet)
 +       * or wait for the SCSI-scanning routine to stop.
         */
 -      set_bit(US_FLIDX_DONT_SCAN, &us->dflags);
 -      wake_up(&us->delay_wait);
 -      wait_for_completion(&us->scanning_done);
 +      cancel_delayed_work_sync(&us->scan_dwork);
 +
 +      /* Balance autopm calls if scanning was cancelled */
 +      if (test_bit(US_FLIDX_SCAN_PENDING, &us->dflags))
 +              usb_autopm_put_interface_no_suspend(us->pusb_intf);
  
        /* Removing the host will perform an orderly shutdown: caches
         * synchronized, disks spun down, etc.
@@@ -827,28 -826,53 +830,28 @@@ static void release_everything(struct u
        scsi_host_put(us_to_host(us));
  }
  
 -/* Thread to carry out delayed SCSI-device scanning */
 -static int usb_stor_scan_thread(void * __us)
 +/* Delayed-work routine to carry out SCSI-device scanning */
 +static void usb_stor_scan_dwork(struct work_struct *work)
  {
 -      struct us_data *us = (struct us_data *)__us;
 +      struct us_data *us = container_of(work, struct us_data,
 +                      scan_dwork.work);
        struct device *dev = &us->pusb_intf->dev;
  
 -      dev_dbg(dev, "device found\n");
 -
 -      set_freezable();
 +      dev_dbg(dev, "starting scan\n");
  
 -      /*
 -       * Wait for the timeout to expire or for a disconnect
 -       *
 -       * We can't freeze in this thread or we risk causing khubd to
 -       * fail to freeze, but we can't be non-freezable either. Nor can
 -       * khubd freeze while waiting for scanning to complete as it may
 -       * hold the device lock, causing a hang when suspending devices.
 -       * So instead of using wait_event_freezable(), explicitly test
 -       * for (DONT_SCAN || freezing) in interruptible wait and proceed
 -       * if any of DONT_SCAN, freezing or timeout has happened.
 -       */
 -      if (delay_use > 0) {
 -              dev_dbg(dev, "waiting for device to settle "
 -                              "before scanning\n");
 -              wait_event_interruptible_timeout(us->delay_wait,
 -                              test_bit(US_FLIDX_DONT_SCAN, &us->dflags) ||
 -                              freezing(current), delay_use * HZ);
 +      /* For bulk-only devices, determine the max LUN value */
 +      if (us->protocol == USB_PR_BULK && !(us->fflags & US_FL_SINGLE_LUN)) {
 +              mutex_lock(&us->dev_mutex);
 +              us->max_lun = usb_stor_Bulk_max_lun(us);
 +              mutex_unlock(&us->dev_mutex);
        }
 +      scsi_scan_host(us_to_host(us));
 +      dev_dbg(dev, "scan complete\n");
  
 -      /* If the device is still connected, perform the scanning */
 -      if (!test_bit(US_FLIDX_DONT_SCAN, &us->dflags)) {
 -
 -              /* For bulk-only devices, determine the max LUN value */
 -              if (us->protocol == USB_PR_BULK &&
 -                              !(us->fflags & US_FL_SINGLE_LUN)) {
 -                      mutex_lock(&us->dev_mutex);
 -                      us->max_lun = usb_stor_Bulk_max_lun(us);
 -                      mutex_unlock(&us->dev_mutex);
 -              }
 -              scsi_scan_host(us_to_host(us));
 -              dev_dbg(dev, "scan complete\n");
 -
 -              /* Should we unbind if no devices were detected? */
 -      }
 +      /* Should we unbind if no devices were detected? */
  
        usb_autopm_put_interface(us->pusb_intf);
 -      complete_and_exit(&us->scanning_done, 0);
 +      clear_bit(US_FLIDX_SCAN_PENDING, &us->dflags);
  }
  
  static unsigned int usb_stor_sg_tablesize(struct usb_interface *intf)
@@@ -895,7 -919,7 +898,7 @@@ int usb_stor_probe1(struct us_data **pu
        init_completion(&us->cmnd_ready);
        init_completion(&(us->notify));
        init_waitqueue_head(&us->delay_wait);
 -      init_completion(&us->scanning_done);
 +      INIT_DELAYED_WORK(&us->scan_dwork, usb_stor_scan_dwork);
  
        /* Associate the us_data structure with the USB device */
        result = associate_dev(us, intf);
@@@ -926,6 -950,7 +929,6 @@@ EXPORT_SYMBOL_GPL(usb_stor_probe1)
  /* Second part of general USB mass-storage probing */
  int usb_stor_probe2(struct us_data *us)
  {
 -      struct task_struct *th;
        int result;
        struct device *dev = &us->pusb_intf->dev;
  
                goto BadDevice;
        }
  
 -      /* Start up the thread for delayed SCSI-device scanning */
 -      th = kthread_create(usb_stor_scan_thread, us, "usb-stor-scan");
 -      if (IS_ERR(th)) {
 -              dev_warn(dev,
 -                              "Unable to start the device-scanning thread\n");
 -              complete(&us->scanning_done);
 -              quiesce_and_remove_host(us);
 -              result = PTR_ERR(th);
 -              goto BadDevice;
 -      }
 -
 +      /* Submit the delayed_work for SCSI-device scanning */
        usb_autopm_get_interface_no_resume(us->pusb_intf);
 -      wake_up_process(th);
 +      set_bit(US_FLIDX_SCAN_PENDING, &us->dflags);
  
 +      if (delay_use > 0)
 +              dev_dbg(dev, "waiting for device to settle before scanning\n");
 +      queue_delayed_work(system_freezable_wq, &us->scan_dwork,
 +                      delay_use * HZ);
        return 0;
  
        /* We come here if there are any problems */
@@@ -999,8 -1030,10 +1002,10 @@@ EXPORT_SYMBOL_GPL(usb_stor_disconnect)
  static int storage_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
  {
+       struct us_unusual_dev *unusual_dev;
        struct us_data *us;
        int result;
+       int size;
  
        /*
         * If libusual is configured, let it decide whether a standard
         * table, so we use the index of the id entry to find the
         * corresponding unusual_devs entry.
         */
-       result = usb_stor_probe1(&us, intf, id,
-                       (id - usb_storage_usb_ids) + us_unusual_dev_list);
+       size = ARRAY_SIZE(us_unusual_dev_list);
+       if (id >= usb_storage_usb_ids && id < usb_storage_usb_ids + size) {
+               unusual_dev = (id - usb_storage_usb_ids) + us_unusual_dev_list;
+       } else {
+               unusual_dev = &for_dynamic_ids;
+               US_DEBUGP("%s %s 0x%04x 0x%04x\n", "Use Bulk-Only transport",
+                       "with the Transparent SCSI protocol for dynamic id:",
+                       id->idVendor, id->idProduct);
+       }
+       result = usb_stor_probe1(&us, intf, id, unusual_dev);
        if (result)
                return result;
  
@@@ -1046,7 -1090,6 +1062,6 @@@ static struct usb_driver usb_storage_dr
        .id_table =     usb_storage_usb_ids,
        .supports_autosuspend = 1,
        .soft_unbind =  1,
-       .no_dynamic_id = 1,
  };
  
  static int __init usb_stor_init(void)