summaryrefslogtreecommitdiffstats
path: root/kernel/drivers/usb/core
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/drivers/usb/core')
-rw-r--r--kernel/drivers/usb/core/devio.c2
-rw-r--r--kernel/drivers/usb/core/hcd.c7
-rw-r--r--kernel/drivers/usb/core/hub.c84
-rw-r--r--kernel/drivers/usb/core/usb.h1
4 files changed, 41 insertions, 53 deletions
diff --git a/kernel/drivers/usb/core/devio.c b/kernel/drivers/usb/core/devio.c
index 4b0448c26..986abde07 100644
--- a/kernel/drivers/usb/core/devio.c
+++ b/kernel/drivers/usb/core/devio.c
@@ -513,7 +513,7 @@ static void async_completed(struct urb *urb)
snoop(&urb->dev->dev, "urb complete\n");
snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length,
as->status, COMPLETE, NULL, 0);
- if ((urb->transfer_flags & URB_DIR_MASK) == USB_DIR_IN)
+ if ((urb->transfer_flags & URB_DIR_MASK) == URB_DIR_IN)
snoop_urb_data(urb, urb->actual_length);
if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
diff --git a/kernel/drivers/usb/core/hcd.c b/kernel/drivers/usb/core/hcd.c
index 69398f933..ab14f8471 100644
--- a/kernel/drivers/usb/core/hcd.c
+++ b/kernel/drivers/usb/core/hcd.c
@@ -1022,9 +1022,12 @@ static int register_root_hub(struct usb_hcd *hcd)
dev_name(&usb_dev->dev), retval);
return (retval < 0) ? retval : -EMSGSIZE;
}
- if (usb_dev->speed == USB_SPEED_SUPER) {
+
+ if (le16_to_cpu(usb_dev->descriptor.bcdUSB) >= 0x0201) {
retval = usb_get_bos_descriptor(usb_dev);
- if (retval < 0) {
+ if (!retval) {
+ usb_dev->lpm_capable = usb_device_supports_lpm(usb_dev);
+ } else if (usb_dev->speed == USB_SPEED_SUPER) {
mutex_unlock(&usb_bus_list_lock);
dev_dbg(parent_dev, "can't read %s bos descriptor %d\n",
dev_name(&usb_dev->dev), retval);
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);
diff --git a/kernel/drivers/usb/core/usb.h b/kernel/drivers/usb/core/usb.h
index 7eb1e2679..457255a33 100644
--- a/kernel/drivers/usb/core/usb.h
+++ b/kernel/drivers/usb/core/usb.h
@@ -65,6 +65,7 @@ extern int usb_hub_init(void);
extern void usb_hub_cleanup(void);
extern int usb_major_init(void);
extern void usb_major_cleanup(void);
+extern int usb_device_supports_lpm(struct usb_device *udev);
#ifdef CONFIG_PM