summaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/hub.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r--drivers/usb/core/hub.c96
1 files changed, 53 insertions, 43 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 036c3dea855..68fc5219ca1 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -37,6 +37,13 @@
#define USB_PERSIST 0
#endif
+/* if we are in debug mode, always announce new devices */
+#ifdef DEBUG
+#ifndef CONFIG_USB_ANNOUNCE_NEW_DEVICES
+#define CONFIG_USB_ANNOUNCE_NEW_DEVICES
+#endif
+#endif
+
struct usb_hub {
struct device *intfdev; /* the "interface" device */
struct usb_device *hdev;
@@ -335,7 +342,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);
}
@@ -487,6 +494,7 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)
schedule_work (&tt->kevent);
spin_unlock_irqrestore (&tt->lock, flags);
}
+EXPORT_SYMBOL_GPL(usb_hub_tt_clear_buffer);
static void hub_power_on(struct usb_hub *hub)
{
@@ -522,9 +530,9 @@ static void hub_quiesce(struct usb_hub *hub)
/* (blocking) stop khubd and related activity */
usb_kill_urb(hub->urb);
if (hub->has_indicators)
- cancel_delayed_work(&hub->leds);
- if (hub->has_indicators || hub->tt.hub)
- flush_scheduled_work();
+ cancel_delayed_work_sync(&hub->leds);
+ if (hub->tt.hub)
+ cancel_work_sync(&hub->tt.kevent);
}
static void hub_activate(struct usb_hub *hub)
@@ -1027,8 +1035,10 @@ static void recursively_mark_NOTATTACHED(struct usb_device *udev)
if (udev->children[i])
recursively_mark_NOTATTACHED(udev->children[i]);
}
- if (udev->state == USB_STATE_SUSPENDED)
+ if (udev->state == USB_STATE_SUSPENDED) {
udev->discon_suspended = 1;
+ udev->active_duration -= jiffies;
+ }
udev->state = USB_STATE_NOTATTACHED;
}
@@ -1077,6 +1087,12 @@ void usb_set_device_state(struct usb_device *udev,
else
device_init_wakeup(&udev->dev, 0);
}
+ if (udev->state == USB_STATE_SUSPENDED &&
+ new_state != USB_STATE_SUSPENDED)
+ udev->active_duration -= jiffies;
+ else if (new_state == USB_STATE_SUSPENDED &&
+ udev->state != USB_STATE_SUSPENDED)
+ udev->active_duration += jiffies;
udev->state = new_state;
} else
recursively_mark_NOTATTACHED(udev);
@@ -1207,7 +1223,7 @@ void usb_disconnect(struct usb_device **pdev)
put_device(&udev->dev);
}
-#ifdef DEBUG
+#ifdef CONFIG_USB_ANNOUNCE_NEW_DEVICES
static void show_string(struct usb_device *udev, char *id, char *string)
{
if (!string)
@@ -1215,12 +1231,24 @@ static void show_string(struct usb_device *udev, char *id, char *string)
dev_printk(KERN_INFO, &udev->dev, "%s: %s\n", id, string);
}
+static void announce_device(struct usb_device *udev)
+{
+ dev_info(&udev->dev, "New USB device found, idVendor=%04x, idProduct=%04x\n",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct));
+ dev_info(&udev->dev, "New USB 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);
+}
#else
-static inline void show_string(struct usb_device *udev, char *id, char *string)
-{}
+static inline void announce_device(struct usb_device *udev) { }
#endif
-
#ifdef CONFIG_USB_OTG
#include "otg_whitelist.h"
#endif
@@ -1390,14 +1418,7 @@ int usb_new_device(struct usb_device *udev)
}
/* 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);
+ announce_device(udev);
return err;
fail:
@@ -2482,6 +2503,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
{
struct usb_device *hdev = hub->hdev;
struct device *hub_dev = hub->intfdev;
+ struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
int status, i;
@@ -2645,6 +2667,8 @@ loop:
done:
hub_port_disable(hub, port1, 1);
+ if (hcd->driver->relinquish_port && !hub->hdev->parent)
+ hcd->driver->relinquish_port(hcd, port1);
}
static void hub_events(void)
@@ -2946,7 +2970,7 @@ static int config_descriptors_changed(struct usb_device *udev)
if (len < le16_to_cpu(udev->config[index].desc.wTotalLength))
len = le16_to_cpu(udev->config[index].desc.wTotalLength);
}
- buf = kmalloc (len, GFP_KERNEL);
+ buf = kmalloc(len, GFP_NOIO);
if (buf == NULL) {
dev_err(&udev->dev, "no mem to re-read configs after reset\n");
/* assume the worst */
@@ -3093,7 +3117,7 @@ re_enumerate:
hub_port_logical_disconnect(parent_hub, port1);
return -ENODEV;
}
-EXPORT_SYMBOL(usb_reset_device);
+EXPORT_SYMBOL_GPL(usb_reset_device);
/**
* usb_reset_composite_device - warn interface drivers and perform a USB port reset
@@ -3110,16 +3134,12 @@ EXPORT_SYMBOL(usb_reset_device);
* 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().
- *
- * The interface locks are acquired during the pre_reset stage and released
- * during the post_reset stage. However if iface is not NULL and is
- * currently being probed, we assume that the caller already owns its
- * lock.
*/
int usb_reset_composite_device(struct usb_device *udev,
struct usb_interface *iface)
{
int ret;
+ int i;
struct usb_host_config *config = udev->actconfig;
if (udev->state == USB_STATE_NOTATTACHED ||
@@ -3136,16 +3156,11 @@ int usb_reset_composite_device(struct usb_device *udev,
iface = NULL;
if (config) {
- int i;
- struct usb_interface *cintf;
- struct usb_driver *drv;
-
for (i = 0; i < config->desc.bNumInterfaces; ++i) {
- cintf = config->interface[i];
- if (cintf != iface)
- down(&cintf->dev.sem);
- if (device_is_registered(&cintf->dev) &&
- cintf->dev.driver) {
+ struct usb_interface *cintf = config->interface[i];
+ struct usb_driver *drv;
+
+ if (cintf->dev.driver) {
drv = to_usb_driver(cintf->dev.driver);
if (drv->pre_reset)
(drv->pre_reset)(cintf);
@@ -3157,25 +3172,20 @@ int usb_reset_composite_device(struct usb_device *udev,
ret = usb_reset_device(udev);
if (config) {
- int i;
- struct usb_interface *cintf;
- struct usb_driver *drv;
-
for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) {
- cintf = config->interface[i];
- if (device_is_registered(&cintf->dev) &&
- cintf->dev.driver) {
+ struct usb_interface *cintf = config->interface[i];
+ struct usb_driver *drv;
+
+ if (cintf->dev.driver) {
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);
}
}
usb_autosuspend_device(udev);
return ret;
}
-EXPORT_SYMBOL(usb_reset_composite_device);
+EXPORT_SYMBOL_GPL(usb_reset_composite_device);