summaryrefslogtreecommitdiffstats
path: root/kernel/drivers/usb/core/hub.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/drivers/usb/core/hub.c')
-rw-r--r--kernel/drivers/usb/core/hub.c84
1 files changed, 34 insertions, 50 deletions
diff --git a/kernel/drivers/usb/core/hub.c b/kernel/drivers/usb/core/hub.c
index 3b7151687..1e9a8c9aa 100644
--- a/kernel/drivers/usb/core/hub.c
+++ b/kernel/drivers/usb/core/hub.c
@@ -122,7 +122,7 @@ struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev)
return usb_get_intfdata(hdev->actconfig->interface[0]);
}
-static int usb_device_supports_lpm(struct usb_device *udev)
+int usb_device_supports_lpm(struct usb_device *udev)
{
/* USB 2.1 (and greater) devices indicate LPM support through
* their USB 2.0 Extended Capabilities BOS descriptor.
@@ -2616,9 +2616,6 @@ static bool use_new_scheme(struct usb_device *udev, int retry)
return USE_NEW_SCHEME(retry);
}
-static int hub_port_reset(struct usb_hub *hub, int port1,
- struct usb_device *udev, unsigned int delay, bool warm);
-
/* Is a USB 3.0 port in the Inactive or Compliance Mode state?
* Port worm reset is required to recover
*/
@@ -2706,44 +2703,6 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
return 0;
}
-static void hub_port_finish_reset(struct usb_hub *hub, int port1,
- struct usb_device *udev, int *status)
-{
- switch (*status) {
- case 0:
- /* TRSTRCY = 10 ms; plus some extra */
- msleep(10 + 40);
- if (udev) {
- struct usb_hcd *hcd = bus_to_hcd(udev->bus);
-
- update_devnum(udev, 0);
- /* The xHC may think the device is already reset,
- * so ignore the status.
- */
- if (hcd->driver->reset_device)
- hcd->driver->reset_device(hcd, udev);
- }
- /* FALL THROUGH */
- case -ENOTCONN:
- case -ENODEV:
- usb_clear_port_feature(hub->hdev,
- port1, USB_PORT_FEAT_C_RESET);
- if (hub_is_superspeed(hub->hdev)) {
- usb_clear_port_feature(hub->hdev, port1,
- USB_PORT_FEAT_C_BH_PORT_RESET);
- usb_clear_port_feature(hub->hdev, port1,
- USB_PORT_FEAT_C_PORT_LINK_STATE);
- usb_clear_port_feature(hub->hdev, port1,
- USB_PORT_FEAT_C_CONNECTION);
- }
- if (udev)
- usb_set_device_state(udev, *status
- ? USB_STATE_NOTATTACHED
- : USB_STATE_DEFAULT);
- break;
- }
-}
-
/* Handle port reset and port warm(BH) reset (for USB3 protocol ports) */
static int hub_port_reset(struct usb_hub *hub, int port1,
struct usb_device *udev, unsigned int delay, bool warm)
@@ -2767,13 +2726,10 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
* If the caller hasn't explicitly requested a warm reset,
* double check and see if one is needed.
*/
- status = hub_port_status(hub, port1,
- &portstatus, &portchange);
- if (status < 0)
- goto done;
-
- if (hub_port_warm_reset_required(hub, port1, portstatus))
- warm = true;
+ if (hub_port_status(hub, port1, &portstatus, &portchange) == 0)
+ if (hub_port_warm_reset_required(hub, port1,
+ portstatus))
+ warm = true;
}
clear_bit(port1, hub->warm_reset_bits);
@@ -2799,11 +2755,19 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
/* Check for disconnect or reset */
if (status == 0 || status == -ENOTCONN || status == -ENODEV) {
- hub_port_finish_reset(hub, port1, udev, &status);
+ usb_clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_RESET);
if (!hub_is_superspeed(hub->hdev))
goto done;
+ usb_clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_BH_PORT_RESET);
+ usb_clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_PORT_LINK_STATE);
+ usb_clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_CONNECTION);
+
/*
* If a USB 3.0 device migrates from reset to an error
* state, re-issue the warm reset.
@@ -2836,6 +2800,26 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
dev_err(&port_dev->dev, "Cannot enable. Maybe the USB cable is bad?\n");
done:
+ if (status == 0) {
+ /* TRSTRCY = 10 ms; plus some extra */
+ msleep(10 + 40);
+ if (udev) {
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ update_devnum(udev, 0);
+ /* The xHC may think the device is already reset,
+ * so ignore the status.
+ */
+ if (hcd->driver->reset_device)
+ hcd->driver->reset_device(hcd, udev);
+
+ usb_set_device_state(udev, USB_STATE_DEFAULT);
+ }
+ } else {
+ if (udev)
+ usb_set_device_state(udev, USB_STATE_NOTATTACHED);
+ }
+
if (!hub_is_superspeed(hub->hdev))
up_read(&ehci_cf_port_reset_rwsem);