struct usb_hub_status hub;
struct usb_port_status port;
} *status; /* buffer for status reports */
+ struct mutex status_mutex; /* for the status buffer */
int error; /* last reported error */
int nerrors; /* track consecutive errors */
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);
{
int ret;
+ mutex_lock(&hub->status_mutex);
ret = get_hub_status(hub->hdev, &hub->status->hub);
if (ret < 0)
dev_err (hub->intfdev,
*change = le16_to_cpu(hub->status->hub.wHubChange);
ret = 0;
}
+ mutex_unlock(&hub->status_mutex);
return ret;
}
ret = -ENOMEM;
goto fail;
}
+ mutex_init(&hub->status_mutex);
hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
if (!hub->descriptor) {
static int __usb_port_suspend(struct usb_device *, int port1);
#endif
-static int __usb_new_device(void *void_data)
+/**
+ * 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)
{
- struct usb_device *udev = void_data;
int err;
/* Lock ourself into memory in order to keep a probe sequence
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)
{
int ret;
+ mutex_lock(&hub->status_mutex);
ret = get_port_status(hub->hdev, port1, &hub->status->port);
if (ret < 4) {
dev_err (hub->intfdev,
*change = le16_to_cpu(hub->status->port.wPortChange);
ret = 0;
}
+ mutex_unlock(&hub->status_mutex);
return ret;
}
struct usb_hub *hub = usb_get_intfdata (intf);
struct usb_device *hdev = hub->hdev;
unsigned port1;
+ int status = 0;
/* fail if children aren't already suspended */
for (port1 = 1; port1 <= hdev->maxchild; port1++) {
dev_dbg(&intf->dev, "%s\n", __FUNCTION__);
+ /* stop khubd and related activity */
+ hub_quiesce(hub);
+
/* "global suspend" of the downstream HC-to-USB interface */
if (!hdev->parent) {
- struct usb_bus *bus = hdev->bus;
- if (bus) {
- int status = hcd_bus_suspend (bus);
-
- if (status != 0) {
- dev_dbg(&hdev->dev, "'global' suspend %d\n",
- status);
- return status;
- }
- } else
- return -EOPNOTSUPP;
+ status = hcd_bus_suspend(hdev->bus);
+ if (status != 0) {
+ dev_dbg(&hdev->dev, "'global' suspend %d\n", status);
+ hub_activate(hub);
+ }
}
-
- /* stop khubd and related activity */
- hub_quiesce(hub);
- return 0;
+ return status;
}
static int hub_resume(struct usb_interface *intf)