|
@@ -2498,6 +2498,21 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
|
|
|
#define HUB_LONG_RESET_TIME 200
|
|
#define HUB_LONG_RESET_TIME 200
|
|
|
#define HUB_RESET_TIMEOUT 800
|
|
#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,
|
|
static int hub_port_reset(struct usb_hub *hub, int port1,
|
|
|
struct usb_device *udev, unsigned int delay, bool warm);
|
|
struct usb_device *udev, unsigned int delay, bool warm);
|
|
|
|
|
|
|
@@ -3956,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.
|
|
/* Reset device, (re)assign address, get device descriptor.
|
|
|
* Device connection must be stable, no more debouncing needed.
|
|
* Device connection must be stable, no more debouncing needed.
|
|
|
* Returns device in USB_STATE_ADDRESS, except on error.
|
|
* Returns device in USB_STATE_ADDRESS, except on error.
|
|
@@ -4068,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.
|
|
* this area, and this is how Linux has done it for ages.
|
|
|
* Change it cautiously.
|
|
* 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,
|
|
* a 64-byte GET_DESCRIPTOR request. This is what Windows does,
|
|
|
* so it may help with some non-standards-compliant devices.
|
|
* so it may help with some non-standards-compliant devices.
|
|
|
* Otherwise we start with SET_ADDRESS and then try to read the
|
|
* Otherwise we start with SET_ADDRESS and then try to read the
|
|
@@ -4076,10 +4105,17 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
|
|
* value.
|
|
* value.
|
|
|
*/
|
|
*/
|
|
|
for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
|
|
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;
|
|
struct usb_device_descriptor *buf;
|
|
|
int r = 0;
|
|
int r = 0;
|
|
|
|
|
|
|
|
|
|
+ did_new_scheme = true;
|
|
|
|
|
+ retval = hub_enable_device(udev);
|
|
|
|
|
+ if (retval < 0)
|
|
|
|
|
+ goto fail;
|
|
|
|
|
+
|
|
|
#define GET_DESCRIPTOR_BUFSIZE 64
|
|
#define GET_DESCRIPTOR_BUFSIZE 64
|
|
|
buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
|
|
buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
|
|
|
if (!buf) {
|
|
if (!buf) {
|
|
@@ -4168,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,
|
|
* - read ep0 maxpacket even for high and low speed,
|
|
|
*/
|
|
*/
|
|
|
msleep(10);
|
|
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;
|
|
break;
|
|
|
}
|
|
}
|
|
|
|
|
|