diff options
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r-- | drivers/usb/core/hub.c | 44 |
1 files changed, 33 insertions, 11 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index bdeadc112d29..ddbf32d599cb 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -124,6 +124,10 @@ struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev) | |||
124 | 124 | ||
125 | int usb_device_supports_lpm(struct usb_device *udev) | 125 | int usb_device_supports_lpm(struct usb_device *udev) |
126 | { | 126 | { |
127 | /* Some devices have trouble with LPM */ | ||
128 | if (udev->quirks & USB_QUIRK_NO_LPM) | ||
129 | return 0; | ||
130 | |||
127 | /* USB 2.1 (and greater) devices indicate LPM support through | 131 | /* USB 2.1 (and greater) devices indicate LPM support through |
128 | * their USB 2.0 Extended Capabilities BOS descriptor. | 132 | * their USB 2.0 Extended Capabilities BOS descriptor. |
129 | */ | 133 | */ |
@@ -1031,10 +1035,20 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) | |||
1031 | unsigned delay; | 1035 | unsigned delay; |
1032 | 1036 | ||
1033 | /* Continue a partial initialization */ | 1037 | /* Continue a partial initialization */ |
1034 | if (type == HUB_INIT2) | 1038 | if (type == HUB_INIT2 || type == HUB_INIT3) { |
1035 | goto init2; | 1039 | device_lock(hub->intfdev); |
1036 | if (type == HUB_INIT3) | 1040 | |
1041 | /* Was the hub disconnected while we were waiting? */ | ||
1042 | if (hub->disconnected) { | ||
1043 | device_unlock(hub->intfdev); | ||
1044 | kref_put(&hub->kref, hub_release); | ||
1045 | return; | ||
1046 | } | ||
1047 | if (type == HUB_INIT2) | ||
1048 | goto init2; | ||
1037 | goto init3; | 1049 | goto init3; |
1050 | } | ||
1051 | kref_get(&hub->kref); | ||
1038 | 1052 | ||
1039 | /* The superspeed hub except for root hub has to use Hub Depth | 1053 | /* The superspeed hub except for root hub has to use Hub Depth |
1040 | * value as an offset into the route string to locate the bits | 1054 | * value as an offset into the route string to locate the bits |
@@ -1232,6 +1246,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) | |||
1232 | queue_delayed_work(system_power_efficient_wq, | 1246 | queue_delayed_work(system_power_efficient_wq, |
1233 | &hub->init_work, | 1247 | &hub->init_work, |
1234 | msecs_to_jiffies(delay)); | 1248 | msecs_to_jiffies(delay)); |
1249 | device_unlock(hub->intfdev); | ||
1235 | return; /* Continues at init3: below */ | 1250 | return; /* Continues at init3: below */ |
1236 | } else { | 1251 | } else { |
1237 | msleep(delay); | 1252 | msleep(delay); |
@@ -1253,6 +1268,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) | |||
1253 | /* Allow autosuspend if it was suppressed */ | 1268 | /* Allow autosuspend if it was suppressed */ |
1254 | if (type <= HUB_INIT3) | 1269 | if (type <= HUB_INIT3) |
1255 | usb_autopm_put_interface_async(to_usb_interface(hub->intfdev)); | 1270 | usb_autopm_put_interface_async(to_usb_interface(hub->intfdev)); |
1271 | |||
1272 | if (type == HUB_INIT2 || type == HUB_INIT3) | ||
1273 | device_unlock(hub->intfdev); | ||
1274 | |||
1275 | kref_put(&hub->kref, hub_release); | ||
1256 | } | 1276 | } |
1257 | 1277 | ||
1258 | /* Implement the continuations for the delays above */ | 1278 | /* Implement the continuations for the delays above */ |
@@ -4512,6 +4532,8 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, | |||
4512 | goto fail; | 4532 | goto fail; |
4513 | } | 4533 | } |
4514 | 4534 | ||
4535 | usb_detect_quirks(udev); | ||
4536 | |||
4515 | if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) { | 4537 | if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) { |
4516 | retval = usb_get_bos_descriptor(udev); | 4538 | retval = usb_get_bos_descriptor(udev); |
4517 | if (!retval) { | 4539 | if (!retval) { |
@@ -4710,7 +4732,6 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, | |||
4710 | if (status < 0) | 4732 | if (status < 0) |
4711 | goto loop; | 4733 | goto loop; |
4712 | 4734 | ||
4713 | usb_detect_quirks(udev); | ||
4714 | if (udev->quirks & USB_QUIRK_DELAY_INIT) | 4735 | if (udev->quirks & USB_QUIRK_DELAY_INIT) |
4715 | msleep(1000); | 4736 | msleep(1000); |
4716 | 4737 | ||
@@ -5326,9 +5347,6 @@ static int usb_reset_and_verify_device(struct usb_device *udev) | |||
5326 | if (udev->usb2_hw_lpm_enabled == 1) | 5347 | if (udev->usb2_hw_lpm_enabled == 1) |
5327 | usb_set_usb2_hardware_lpm(udev, 0); | 5348 | usb_set_usb2_hardware_lpm(udev, 0); |
5328 | 5349 | ||
5329 | bos = udev->bos; | ||
5330 | udev->bos = NULL; | ||
5331 | |||
5332 | /* Disable LPM and LTM while we reset the device and reinstall the alt | 5350 | /* Disable LPM and LTM while we reset the device and reinstall the alt |
5333 | * settings. Device-initiated LPM settings, and system exit latency | 5351 | * settings. Device-initiated LPM settings, and system exit latency |
5334 | * settings are cleared when the device is reset, so we have to set | 5352 | * settings are cleared when the device is reset, so we have to set |
@@ -5337,15 +5355,18 @@ static int usb_reset_and_verify_device(struct usb_device *udev) | |||
5337 | ret = usb_unlocked_disable_lpm(udev); | 5355 | ret = usb_unlocked_disable_lpm(udev); |
5338 | if (ret) { | 5356 | if (ret) { |
5339 | dev_err(&udev->dev, "%s Failed to disable LPM\n.", __func__); | 5357 | dev_err(&udev->dev, "%s Failed to disable LPM\n.", __func__); |
5340 | goto re_enumerate; | 5358 | goto re_enumerate_no_bos; |
5341 | } | 5359 | } |
5342 | ret = usb_disable_ltm(udev); | 5360 | ret = usb_disable_ltm(udev); |
5343 | if (ret) { | 5361 | if (ret) { |
5344 | dev_err(&udev->dev, "%s Failed to disable LTM\n.", | 5362 | dev_err(&udev->dev, "%s Failed to disable LTM\n.", |
5345 | __func__); | 5363 | __func__); |
5346 | goto re_enumerate; | 5364 | goto re_enumerate_no_bos; |
5347 | } | 5365 | } |
5348 | 5366 | ||
5367 | bos = udev->bos; | ||
5368 | udev->bos = NULL; | ||
5369 | |||
5349 | for (i = 0; i < SET_CONFIG_TRIES; ++i) { | 5370 | for (i = 0; i < SET_CONFIG_TRIES; ++i) { |
5350 | 5371 | ||
5351 | /* ep0 maxpacket size may change; let the HCD know about it. | 5372 | /* ep0 maxpacket size may change; let the HCD know about it. |
@@ -5442,10 +5463,11 @@ done: | |||
5442 | return 0; | 5463 | return 0; |
5443 | 5464 | ||
5444 | re_enumerate: | 5465 | re_enumerate: |
5445 | /* LPM state doesn't matter when we're about to destroy the device. */ | ||
5446 | hub_port_logical_disconnect(parent_hub, port1); | ||
5447 | usb_release_bos_descriptor(udev); | 5466 | usb_release_bos_descriptor(udev); |
5448 | udev->bos = bos; | 5467 | udev->bos = bos; |
5468 | re_enumerate_no_bos: | ||
5469 | /* LPM state doesn't matter when we're about to destroy the device. */ | ||
5470 | hub_port_logical_disconnect(parent_hub, port1); | ||
5449 | return -ENODEV; | 5471 | return -ENODEV; |
5450 | } | 5472 | } |
5451 | 5473 | ||