diff options
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r-- | drivers/usb/core/hub.c | 29 |
1 files changed, 24 insertions, 5 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 93aa0e7..7f7b58f 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -24,6 +24,7 @@ #include <linux/kthread.h> #include <linux/mutex.h> #include <linux/freezer.h> +#include <linux/random.h> #include <asm/uaccess.h> #include <asm/byteorder.h> @@ -484,13 +485,16 @@ static void hub_tt_work(struct work_struct *work) int limit = 100; spin_lock_irqsave (&hub->tt.lock, flags); - while (--limit && !list_empty (&hub->tt.clear_list)) { + while (!list_empty(&hub->tt.clear_list)) { struct list_head *next; struct usb_tt_clear *clear; struct usb_device *hdev = hub->hdev; const struct hc_driver *drv; int status; + if (!hub->quiescing && --limit < 0) + break; + next = hub->tt.clear_list.next; clear = list_entry (next, struct usb_tt_clear, clear_list); list_del (&clear->clear_list); @@ -968,7 +972,7 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type) if (hub->has_indicators) cancel_delayed_work_sync(&hub->leds); if (hub->tt.hub) - cancel_work_sync(&hub->tt.clear_work); + flush_work_sync(&hub->tt.clear_work); } /* caller has locked the hub device */ @@ -1928,6 +1932,15 @@ int usb_new_device(struct usb_device *udev) #endif call_battery_notify(udev, 1); #endif + + if (udev->serial) + add_device_randomness(udev->serial, strlen(udev->serial)); + if (udev->product) + add_device_randomness(udev->product, strlen(udev->product)); + if (udev->manufacturer) + add_device_randomness(udev->manufacturer, + strlen(udev->manufacturer)); + device_enable_async_suspend(&udev->dev); /* Register the device. The device driver is responsible * for configuring the device and invoking the add-device @@ -2064,7 +2077,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub) #define HUB_ROOT_RESET_TIME 50 /* times are in msec */ #define HUB_SHORT_RESET_TIME 10 #define HUB_LONG_RESET_TIME 200 -#define HUB_RESET_TIMEOUT 500 +#define HUB_RESET_TIMEOUT 800 static int hub_port_wait_reset(struct usb_hub *hub, int port1, struct usb_device *udev, unsigned int delay) @@ -2438,7 +2451,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) static int finish_port_resume(struct usb_device *udev) { int status = 0; - u16 devstatus; + u16 devstatus = 0; /* caller owns the udev device lock */ dev_dbg(&udev->dev, "%s\n", @@ -2487,7 +2500,13 @@ static int finish_port_resume(struct usb_device *udev) if (status) { dev_dbg(&udev->dev, "gone after usb resume? status %d\n", status); - } else if (udev->actconfig) { + /* + * There are a few quirky devices which violate the standard + * by claiming to have remote wakeup enabled after a reset, + * which crash if the feature is cleared, hence check for + * udev->reset_resume + */ + } else if (udev->actconfig && !udev->reset_resume) { le16_to_cpus(&devstatus); if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { status = usb_control_msg(udev, |