diff options
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r-- | drivers/usb/core/hub.c | 69 |
1 files changed, 51 insertions, 18 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 2f1c4b22ae1c..9dc72e53712f 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -358,7 +358,8 @@ static void usb_set_lpm_parameters(struct usb_device *udev) | |||
358 | } | 358 | } |
359 | 359 | ||
360 | /* USB 2.0 spec Section 11.24.4.5 */ | 360 | /* USB 2.0 spec Section 11.24.4.5 */ |
361 | static int get_hub_descriptor(struct usb_device *hdev, void *data) | 361 | static int get_hub_descriptor(struct usb_device *hdev, |
362 | struct usb_hub_descriptor *desc) | ||
362 | { | 363 | { |
363 | int i, ret, size; | 364 | int i, ret, size; |
364 | unsigned dtype; | 365 | unsigned dtype; |
@@ -374,10 +375,18 @@ static int get_hub_descriptor(struct usb_device *hdev, void *data) | |||
374 | for (i = 0; i < 3; i++) { | 375 | for (i = 0; i < 3; i++) { |
375 | ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0), | 376 | ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0), |
376 | USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, | 377 | USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, |
377 | dtype << 8, 0, data, size, | 378 | dtype << 8, 0, desc, size, |
378 | USB_CTRL_GET_TIMEOUT); | 379 | USB_CTRL_GET_TIMEOUT); |
379 | if (ret >= (USB_DT_HUB_NONVAR_SIZE + 2)) | 380 | if (hub_is_superspeed(hdev)) { |
381 | if (ret == size) | ||
382 | return ret; | ||
383 | } else if (ret >= USB_DT_HUB_NONVAR_SIZE + 2) { | ||
384 | /* Make sure we have the DeviceRemovable field. */ | ||
385 | size = USB_DT_HUB_NONVAR_SIZE + desc->bNbrPorts / 8 + 1; | ||
386 | if (ret < size) | ||
387 | return -EMSGSIZE; | ||
380 | return ret; | 388 | return ret; |
389 | } | ||
381 | } | 390 | } |
382 | return -EINVAL; | 391 | return -EINVAL; |
383 | } | 392 | } |
@@ -1048,6 +1057,9 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) | |||
1048 | 1057 | ||
1049 | portstatus = portchange = 0; | 1058 | portstatus = portchange = 0; |
1050 | status = hub_port_status(hub, port1, &portstatus, &portchange); | 1059 | status = hub_port_status(hub, port1, &portstatus, &portchange); |
1060 | if (status) | ||
1061 | goto abort; | ||
1062 | |||
1051 | if (udev || (portstatus & USB_PORT_STAT_CONNECTION)) | 1063 | if (udev || (portstatus & USB_PORT_STAT_CONNECTION)) |
1052 | dev_dbg(&port_dev->dev, "status %04x change %04x\n", | 1064 | dev_dbg(&port_dev->dev, "status %04x change %04x\n", |
1053 | portstatus, portchange); | 1065 | portstatus, portchange); |
@@ -1180,7 +1192,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) | |||
1180 | 1192 | ||
1181 | /* Scan all ports that need attention */ | 1193 | /* Scan all ports that need attention */ |
1182 | kick_hub_wq(hub); | 1194 | kick_hub_wq(hub); |
1183 | 1195 | abort: | |
1184 | if (type == HUB_INIT2 || type == HUB_INIT3) { | 1196 | if (type == HUB_INIT2 || type == HUB_INIT3) { |
1185 | /* Allow autosuspend if it was suppressed */ | 1197 | /* Allow autosuspend if it was suppressed */ |
1186 | disconnected: | 1198 | disconnected: |
@@ -1292,7 +1304,7 @@ static int hub_configure(struct usb_hub *hub, | |||
1292 | } | 1304 | } |
1293 | mutex_init(&hub->status_mutex); | 1305 | mutex_init(&hub->status_mutex); |
1294 | 1306 | ||
1295 | hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL); | 1307 | hub->descriptor = kzalloc(sizeof(*hub->descriptor), GFP_KERNEL); |
1296 | if (!hub->descriptor) { | 1308 | if (!hub->descriptor) { |
1297 | ret = -ENOMEM; | 1309 | ret = -ENOMEM; |
1298 | goto fail; | 1310 | goto fail; |
@@ -1300,13 +1312,19 @@ static int hub_configure(struct usb_hub *hub, | |||
1300 | 1312 | ||
1301 | /* Request the entire hub descriptor. | 1313 | /* Request the entire hub descriptor. |
1302 | * hub->descriptor can handle USB_MAXCHILDREN ports, | 1314 | * hub->descriptor can handle USB_MAXCHILDREN ports, |
1303 | * but the hub can/will return fewer bytes here. | 1315 | * but a (non-SS) hub can/will return fewer bytes here. |
1304 | */ | 1316 | */ |
1305 | ret = get_hub_descriptor(hdev, hub->descriptor); | 1317 | ret = get_hub_descriptor(hdev, hub->descriptor); |
1306 | if (ret < 0) { | 1318 | if (ret < 0) { |
1307 | message = "can't read hub descriptor"; | 1319 | message = "can't read hub descriptor"; |
1308 | goto fail; | 1320 | goto fail; |
1309 | } else if (hub->descriptor->bNbrPorts > USB_MAXCHILDREN) { | 1321 | } |
1322 | |||
1323 | maxchild = USB_MAXCHILDREN; | ||
1324 | if (hub_is_superspeed(hdev)) | ||
1325 | maxchild = min_t(unsigned, maxchild, USB_SS_MAXPORTS); | ||
1326 | |||
1327 | if (hub->descriptor->bNbrPorts > maxchild) { | ||
1310 | message = "hub has too many ports!"; | 1328 | message = "hub has too many ports!"; |
1311 | ret = -ENODEV; | 1329 | ret = -ENODEV; |
1312 | goto fail; | 1330 | goto fail; |
@@ -1980,7 +1998,7 @@ static void choose_devnum(struct usb_device *udev) | |||
1980 | struct usb_bus *bus = udev->bus; | 1998 | struct usb_bus *bus = udev->bus; |
1981 | 1999 | ||
1982 | /* be safe when more hub events are proceed in parallel */ | 2000 | /* be safe when more hub events are proceed in parallel */ |
1983 | mutex_lock(&bus->usb_address0_mutex); | 2001 | mutex_lock(&bus->devnum_next_mutex); |
1984 | if (udev->wusb) { | 2002 | if (udev->wusb) { |
1985 | devnum = udev->portnum + 1; | 2003 | devnum = udev->portnum + 1; |
1986 | BUG_ON(test_bit(devnum, bus->devmap.devicemap)); | 2004 | BUG_ON(test_bit(devnum, bus->devmap.devicemap)); |
@@ -1998,7 +2016,7 @@ static void choose_devnum(struct usb_device *udev) | |||
1998 | set_bit(devnum, bus->devmap.devicemap); | 2016 | set_bit(devnum, bus->devmap.devicemap); |
1999 | udev->devnum = devnum; | 2017 | udev->devnum = devnum; |
2000 | } | 2018 | } |
2001 | mutex_unlock(&bus->usb_address0_mutex); | 2019 | mutex_unlock(&bus->devnum_next_mutex); |
2002 | } | 2020 | } |
2003 | 2021 | ||
2004 | static void release_devnum(struct usb_device *udev) | 2022 | static void release_devnum(struct usb_device *udev) |
@@ -2068,6 +2086,12 @@ void usb_disconnect(struct usb_device **pdev) | |||
2068 | dev_info(&udev->dev, "USB disconnect, device number %d\n", | 2086 | dev_info(&udev->dev, "USB disconnect, device number %d\n", |
2069 | udev->devnum); | 2087 | udev->devnum); |
2070 | 2088 | ||
2089 | /* | ||
2090 | * Ensure that the pm runtime code knows that the USB device | ||
2091 | * is in the process of being disconnected. | ||
2092 | */ | ||
2093 | pm_runtime_barrier(&udev->dev); | ||
2094 | |||
2071 | usb_lock_device(udev); | 2095 | usb_lock_device(udev); |
2072 | 2096 | ||
2073 | hub_disconnect_children(udev); | 2097 | hub_disconnect_children(udev); |
@@ -2609,8 +2633,15 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, | |||
2609 | if (ret < 0) | 2633 | if (ret < 0) |
2610 | return ret; | 2634 | return ret; |
2611 | 2635 | ||
2612 | /* The port state is unknown until the reset completes. */ | 2636 | /* |
2613 | if (!(portstatus & USB_PORT_STAT_RESET)) | 2637 | * The port state is unknown until the reset completes. |
2638 | * | ||
2639 | * On top of that, some chips may require additional time | ||
2640 | * to re-establish a connection after the reset is complete, | ||
2641 | * so also wait for the connection to be re-established. | ||
2642 | */ | ||
2643 | if (!(portstatus & USB_PORT_STAT_RESET) && | ||
2644 | (portstatus & USB_PORT_STAT_CONNECTION)) | ||
2614 | break; | 2645 | break; |
2615 | 2646 | ||
2616 | /* switch to the long delay after two short delay failures */ | 2647 | /* switch to the long delay after two short delay failures */ |
@@ -4206,7 +4237,7 @@ static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev) | |||
4206 | struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); | 4237 | struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); |
4207 | int connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN; | 4238 | int connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN; |
4208 | 4239 | ||
4209 | if (!udev->usb2_hw_lpm_capable) | 4240 | if (!udev->usb2_hw_lpm_capable || !udev->bos) |
4210 | return; | 4241 | return; |
4211 | 4242 | ||
4212 | if (hub) | 4243 | if (hub) |
@@ -4274,7 +4305,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, | |||
4274 | if (oldspeed == USB_SPEED_LOW) | 4305 | if (oldspeed == USB_SPEED_LOW) |
4275 | delay = HUB_LONG_RESET_TIME; | 4306 | delay = HUB_LONG_RESET_TIME; |
4276 | 4307 | ||
4277 | mutex_lock(&hdev->bus->usb_address0_mutex); | 4308 | mutex_lock(hcd->address0_mutex); |
4278 | 4309 | ||
4279 | /* Reset the device; full speed may morph to high speed */ | 4310 | /* Reset the device; full speed may morph to high speed */ |
4280 | /* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */ | 4311 | /* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */ |
@@ -4560,7 +4591,7 @@ fail: | |||
4560 | hub_port_disable(hub, port1, 0); | 4591 | hub_port_disable(hub, port1, 0); |
4561 | update_devnum(udev, devnum); /* for disconnect processing */ | 4592 | update_devnum(udev, devnum); /* for disconnect processing */ |
4562 | } | 4593 | } |
4563 | mutex_unlock(&hdev->bus->usb_address0_mutex); | 4594 | mutex_unlock(hcd->address0_mutex); |
4564 | return retval; | 4595 | return retval; |
4565 | } | 4596 | } |
4566 | 4597 | ||
@@ -4642,7 +4673,8 @@ hub_power_remaining(struct usb_hub *hub) | |||
4642 | static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, | 4673 | static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, |
4643 | u16 portchange) | 4674 | u16 portchange) |
4644 | { | 4675 | { |
4645 | int status, i; | 4676 | int status = -ENODEV; |
4677 | int i; | ||
4646 | unsigned unit_load; | 4678 | unsigned unit_load; |
4647 | struct usb_device *hdev = hub->hdev; | 4679 | struct usb_device *hdev = hub->hdev; |
4648 | struct usb_hcd *hcd = bus_to_hcd(hdev->bus); | 4680 | struct usb_hcd *hcd = bus_to_hcd(hdev->bus); |
@@ -4846,9 +4878,10 @@ loop: | |||
4846 | 4878 | ||
4847 | done: | 4879 | done: |
4848 | hub_port_disable(hub, port1, 1); | 4880 | hub_port_disable(hub, port1, 1); |
4849 | if (hcd->driver->relinquish_port && !hub->hdev->parent) | 4881 | if (hcd->driver->relinquish_port && !hub->hdev->parent) { |
4850 | hcd->driver->relinquish_port(hcd, port1); | 4882 | if (status != -ENOTCONN && status != -ENODEV) |
4851 | 4883 | hcd->driver->relinquish_port(hcd, port1); | |
4884 | } | ||
4852 | } | 4885 | } |
4853 | 4886 | ||
4854 | /* Handle physical or logical connection change events. | 4887 | /* Handle physical or logical connection change events. |