|
@@ -87,6 +87,16 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
|
|
|
|
|
|
static struct task_struct *khubd_task;
|
|
|
|
|
|
+/* multithreaded probe logic */
|
|
|
+static int multithread_probe =
|
|
|
+#ifdef CONFIG_USB_MULTITHREAD_PROBE
|
|
|
+ 1;
|
|
|
+#else
|
|
|
+ 0;
|
|
|
+#endif
|
|
|
+module_param(multithread_probe, bool, S_IRUGO);
|
|
|
+MODULE_PARM_DESC(multithread_probe, "Run each USB device probe in a new thread");
|
|
|
+
|
|
|
/* cycle leds on hubs that aren't blinking for attention */
|
|
|
static int blinkenlights = 0;
|
|
|
module_param (blinkenlights, bool, S_IRUGO);
|
|
@@ -1238,29 +1248,17 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
|
|
|
static int __usb_port_suspend(struct usb_device *, int port1);
|
|
|
#endif
|
|
|
|
|
|
-/**
|
|
|
- * 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.
|
|
|
- *
|
|
|
- * Returns 0 for success (device is configured and listed, with its
|
|
|
- * interfaces, in sysfs); 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)
|
|
|
+static int __usb_new_device(void *void_data)
|
|
|
{
|
|
|
+ struct usb_device *udev = void_data;
|
|
|
int err;
|
|
|
|
|
|
+ /* Lock ourself into memory in order to keep a probe sequence
|
|
|
+ * sleeping in a new thread from allowing us to be unloaded.
|
|
|
+ */
|
|
|
+ if (!try_module_get(THIS_MODULE))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
err = usb_get_configuration(udev);
|
|
|
if (err < 0) {
|
|
|
dev_err(&udev->dev, "can't read configurations, error %d\n",
|
|
@@ -1356,13 +1354,52 @@ int usb_new_device(struct usb_device *udev)
|
|
|
goto fail;
|
|
|
}
|
|
|
|
|
|
- return 0;
|
|
|
+exit:
|
|
|
+ module_put(THIS_MODULE);
|
|
|
+ return err;
|
|
|
|
|
|
fail:
|
|
|
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
|
|
|
- return err;
|
|
|
+ goto exit;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * 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.
|
|
|
+ *
|
|
|
+ * The return value for this function depends on if the
|
|
|
+ * multithread_probe variable is set or not. If it's set, it will
|
|
|
+ * return a if the probe thread was successfully created or not. If the
|
|
|
+ * variable is not set, it will return if the device is configured
|
|
|
+ * properly or not. interfaces, in sysfs); 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)
|
|
|
+{
|
|
|
+ struct task_struct *probe_task;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ if (multithread_probe) {
|
|
|
+ probe_task = kthread_run(__usb_new_device, udev,
|
|
|
+ "usb-probe-%s", udev->devnum);
|
|
|
+ if (IS_ERR(probe_task))
|
|
|
+ ret = PTR_ERR(probe_task);
|
|
|
+ } else
|
|
|
+ ret = __usb_new_device(udev);
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
|
|
|
static int hub_port_status(struct usb_hub *hub, int port1,
|
|
|
u16 *status, u16 *change)
|