On Thu, 9 Nov 2017, Mike Looijmans wrote:

> Sometimes the USB device gets confused about the state of the initialization 
> and
> the connection fails. In particular, the device thinks that it's already set 
> up
> and running while the host thinks the device still needs to be configured. To
> work around this issue, power-cycle the hub's output to issue a sort of 
> "reset"
> to the device. This makes the device restart its state machine and then the
> initialization succeeds.
> 
> This fixes problems where the kernel reports a list of errors like this:
> 
> usb 1-1.3: device not accepting address 19, error -71
> 
> The end result is a non-functioning device. After this patch, the sequence
> becomes like this:
> 
> usb 1-1.3: new high-speed USB device number 18 using ci_hdrc
> usb 1-1.3: device not accepting address 18, error -71
> usb 1-1.3: new high-speed USB device number 19 using ci_hdrc
> usb 1-1.3: device not accepting address 19, error -71
> usb 1-1-port3: attempt power cycle
> usb 1-1.3: new high-speed USB device number 21 using ci_hdrc
> usb-storage 1-1.3:1.2: USB Mass Storage device detected
> 
> Signed-off-by: Mike Looijmans <[email protected]>
> ---
> v2: On feedback from Alan Stern:
>       No blank line changes
>       Don't further increase the retry count
>     Delay 2x the power-up delay (100ms minimum) instead of magic "800"
> 
>  drivers/usb/core/hub.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
> index e9ce6bb..8f7d942 100644
> --- a/drivers/usb/core/hub.c
> +++ b/drivers/usb/core/hub.c
> @@ -4935,6 +4935,15 @@ static void hub_port_connect(struct usb_hub *hub, int 
> port1, u16 portstatus,
>               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 ||

Acked-by: Alan Stern <[email protected]>

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to