summaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/hub.c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-12-16 08:46:03 -0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-12-16 08:46:03 -0800
commitd59abb9325ae5eb8fd28440d80f820b945887541 (patch)
tree6ba86796569a8b478a959c2c76c8bfb2bde34522 /drivers/usb/core/hub.c
parent319e2e3f63c348a9b66db4667efa73178e18b17d (diff)
parent3d724fa513cd1bd06d3457ccda36941f3606d048 (diff)
downloadlinux-d59abb9325ae5eb8fd28440d80f820b945887541.tar.bz2
Merge branch 3.13-rc4 into usb-next
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r--drivers/usb/core/hub.c85
1 files changed, 50 insertions, 35 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index bd9dc3504b51..162e94dbed53 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2235,17 +2235,13 @@ static int usb_enumerate_device(struct usb_device *udev)
return err;
}
}
- if (udev->wusb == 1 && udev->authorized == 0) {
- udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
- udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
- udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
- } else {
- /* read the standard strings and cache them if present */
- udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
- udev->manufacturer = usb_cache_string(udev,
- udev->descriptor.iManufacturer);
- udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
- }
+
+ /* read the standard strings and cache them if present */
+ udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
+ udev->manufacturer = usb_cache_string(udev,
+ udev->descriptor.iManufacturer);
+ udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
+
err = usb_enumerate_device_otg(udev);
if (err < 0)
return err;
@@ -2427,16 +2423,6 @@ int usb_deauthorize_device(struct usb_device *usb_dev)
usb_dev->authorized = 0;
usb_set_configuration(usb_dev, -1);
- kfree(usb_dev->product);
- usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
- kfree(usb_dev->manufacturer);
- usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
- kfree(usb_dev->serial);
- usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
-
- usb_destroy_configuration(usb_dev);
- usb_dev->descriptor.bNumConfigurations = 0;
-
out_unauthorized:
usb_unlock_device(usb_dev);
return 0;
@@ -2464,17 +2450,7 @@ int usb_authorize_device(struct usb_device *usb_dev)
goto error_device_descriptor;
}
- kfree(usb_dev->product);
- usb_dev->product = NULL;
- kfree(usb_dev->manufacturer);
- usb_dev->manufacturer = NULL;
- kfree(usb_dev->serial);
- usb_dev->serial = NULL;
-
usb_dev->authorized = 1;
- result = usb_enumerate_device(usb_dev);
- if (result < 0)
- goto error_enumerate;
/* Choose and set the configuration. This registers the interfaces
* with the driver core and lets interface drivers bind to them.
*/
@@ -2490,7 +2466,6 @@ int usb_authorize_device(struct usb_device *usb_dev)
}
dev_info(&usb_dev->dev, "authorized to connect\n");
-error_enumerate:
error_device_descriptor:
usb_autosuspend_device(usb_dev);
error_autoresume:
@@ -2523,6 +2498,21 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
#define HUB_LONG_RESET_TIME 200
#define HUB_RESET_TIMEOUT 800
+/*
+ * "New scheme" enumeration causes an extra state transition to be
+ * exposed to an xhci host and causes USB3 devices to receive control
+ * commands in the default state. This has been seen to cause
+ * enumeration failures, so disable this enumeration scheme for USB3
+ * devices.
+ */
+static bool use_new_scheme(struct usb_device *udev, int retry)
+{
+ if (udev->speed == USB_SPEED_SUPER)
+ return false;
+
+ 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);
@@ -3981,6 +3971,20 @@ static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev)
}
}
+static int hub_enable_device(struct usb_device *udev)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ if (!hcd->driver->enable_device)
+ return 0;
+ if (udev->state == USB_STATE_ADDRESS)
+ return 0;
+ if (udev->state != USB_STATE_DEFAULT)
+ return -EINVAL;
+
+ return hcd->driver->enable_device(hcd, udev);
+}
+
/* Reset device, (re)assign address, get device descriptor.
* Device connection must be stable, no more debouncing needed.
* Returns device in USB_STATE_ADDRESS, except on error.
@@ -4093,7 +4097,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
* this area, and this is how Linux has done it for ages.
* Change it cautiously.
*
- * NOTE: If USE_NEW_SCHEME() is true we will start by issuing
+ * NOTE: If use_new_scheme() is true we will start by issuing
* a 64-byte GET_DESCRIPTOR request. This is what Windows does,
* so it may help with some non-standards-compliant devices.
* Otherwise we start with SET_ADDRESS and then try to read the
@@ -4101,10 +4105,17 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
* value.
*/
for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
- if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) {
+ bool did_new_scheme = false;
+
+ if (use_new_scheme(udev, retry_counter)) {
struct usb_device_descriptor *buf;
int r = 0;
+ did_new_scheme = true;
+ retval = hub_enable_device(udev);
+ if (retval < 0)
+ goto fail;
+
#define GET_DESCRIPTOR_BUFSIZE 64
buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
if (!buf) {
@@ -4193,7 +4204,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
* - read ep0 maxpacket even for high and low speed,
*/
msleep(10);
- if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3))
+ /* use_new_scheme() checks the speed which may have
+ * changed since the initial look so we cache the result
+ * in did_new_scheme
+ */
+ if (did_new_scheme)
break;
}