aboutsummaryrefslogtreecommitdiffstats
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.c32
1 files changed, 27 insertions, 5 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index e9ce6bb0b22d..cf7bbcb9a63c 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
/*
* USB hub driver.
*
@@ -7,7 +8,6 @@
* (C) Copyright 2001 Brad Hards (bhards@bigpond.net.au)
*
* Released under the GPLv2 only.
- * SPDX-License-Identifier: GPL-2.0
*/
#include <linux/kernel.h>
@@ -1482,7 +1482,7 @@ static int hub_configure(struct usb_hub *hub,
/* power budgeting mostly matters with bus-powered hubs,
* and battery-powered root hubs (may provide just 8 mA).
*/
- ret = usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus);
+ ret = usb_get_std_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus);
if (ret) {
message = "can't get hub status";
goto fail;
@@ -3279,7 +3279,7 @@ static int finish_port_resume(struct usb_device *udev)
*/
if (status == 0) {
devstatus = 0;
- status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
+ status = usb_get_std_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
/* If a normal resume failed, try doing a reset-resume */
if (status && !udev->reset_resume && udev->persist_enabled) {
@@ -3303,7 +3303,7 @@ static int finish_port_resume(struct usb_device *udev)
if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP))
status = usb_disable_remote_wakeup(udev);
} else {
- status = usb_get_status(udev, USB_RECIP_INTERFACE, 0,
+ status = usb_get_std_status(udev, USB_RECIP_INTERFACE, 0,
&devstatus);
if (!status && devstatus & (USB_INTRF_STAT_FUNC_RW_CAP
| USB_INTRF_STAT_FUNC_RW))
@@ -4183,6 +4183,19 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
return ret;
}
+/*
+ * usb_port_disable - disable a usb device's upstream port
+ * @udev: device to disable
+ * Context: @udev locked, must be able to sleep.
+ *
+ * Disables a USB device that isn't in active use.
+ */
+int usb_port_disable(struct usb_device *udev)
+{
+ struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);
+
+ return hub_port_disable(hub, udev->portnum, 0);
+}
/* USB 2.0 spec, 7.1.7.3 / fig 7-29:
*
@@ -4853,7 +4866,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
&& udev->bus_mA <= unit_load) {
u16 devstat;
- status = usb_get_status(udev, USB_RECIP_DEVICE, 0,
+ status = usb_get_std_status(udev, USB_RECIP_DEVICE, 0,
&devstat);
if (status) {
dev_dbg(&udev->dev, "get status %d ?\n", status);
@@ -4935,6 +4948,15 @@ loop:
usb_put_dev(udev);
if ((status == -ENOTCONN) || (status == -ENOTSUPP))
break;
+
+ /* When halfway through our retry count, power-cycle the port */
+ if (i == (SET_CONFIG_TRIES / 2) - 1) {
+ dev_info(&port_dev->dev, "attempt power cycle\n");
+ usb_hub_set_port_power(hdev, hub, port1, false);
+ msleep(2 * hub_power_on_good_delay(hub));
+ usb_hub_set_port_power(hdev, hub, port1, true);
+ msleep(hub_power_on_good_delay(hub));
+ }
}
if (hub->hdev->parent ||
!hcd->driver->port_handed_over ||