Lines 2664-2719
Link Here
|
2664 |
if ((portstatus & USB_PORT_STAT_RESET)) |
2664 |
if ((portstatus & USB_PORT_STAT_RESET)) |
2665 |
return -EBUSY; |
2665 |
return -EBUSY; |
2666 |
|
2666 |
|
2667 |
if (hub_port_warm_reset_required(hub, port1, portstatus)) |
2667 |
/* Some buggy devices require a warm reset to be issued even |
2668 |
return -ENOTCONN; |
2668 |
* when the port appears not to be connected. |
2669 |
|
|
|
2670 |
/* Device went away? */ |
2671 |
if (!(portstatus & USB_PORT_STAT_CONNECTION)) |
2672 |
return -ENOTCONN; |
2673 |
|
2674 |
/* bomb out completely if the connection bounced. A USB 3.0 |
2675 |
* connection may bounce if multiple warm resets were issued, |
2676 |
* but the device may have successfully re-connected. Ignore it. |
2677 |
*/ |
2669 |
*/ |
2678 |
if (!hub_is_superspeed(hub->hdev) && |
2670 |
if (!warm) { |
2679 |
(portchange & USB_PORT_STAT_C_CONNECTION)) |
2671 |
/* |
2680 |
return -ENOTCONN; |
2672 |
* Some buggy devices can cause an NEC host controller |
2681 |
|
2673 |
* to transition to the "Error" state after a hot port |
2682 |
if (!(portstatus & USB_PORT_STAT_ENABLE)) |
2674 |
* reset. This will show up as the port state in |
2683 |
return -EBUSY; |
2675 |
* "Inactive", and the port may also report a |
|
|
2676 |
* disconnect. Forcing a warm port reset seems to make |
2677 |
* the device work. |
2678 |
* |
2679 |
* See https://bugzilla.kernel.org/show_bug.cgi?id=41752 |
2680 |
*/ |
2681 |
if (hub_port_warm_reset_required(hub, port1, portstatus)) { |
2682 |
int ret; |
2683 |
|
2684 |
if ((portchange & USB_PORT_STAT_C_CONNECTION)) |
2685 |
usb_clear_port_feature(hub->hdev, port1, |
2686 |
USB_PORT_FEAT_C_CONNECTION); |
2687 |
if (portchange & USB_PORT_STAT_C_LINK_STATE) |
2688 |
usb_clear_port_feature(hub->hdev, port1, |
2689 |
USB_PORT_FEAT_C_PORT_LINK_STATE); |
2690 |
if (portchange & USB_PORT_STAT_C_RESET) |
2691 |
usb_clear_port_feature(hub->hdev, port1, |
2692 |
USB_PORT_FEAT_C_RESET); |
2693 |
dev_dbg(hub->intfdev, "hot reset failed, warm reset port %d\n", |
2694 |
port1); |
2695 |
ret = hub_port_reset(hub, port1, |
2696 |
udev, HUB_BH_RESET_TIME, |
2697 |
true); |
2698 |
if ((portchange & USB_PORT_STAT_C_CONNECTION)) |
2699 |
usb_clear_port_feature(hub->hdev, port1, |
2700 |
USB_PORT_FEAT_C_CONNECTION); |
2701 |
return ret; |
2702 |
} |
2703 |
/* Device went away? */ |
2704 |
if (!(portstatus & USB_PORT_STAT_CONNECTION)) |
2705 |
return -ENOTCONN; |
2706 |
|
2707 |
/* bomb out completely if the connection bounced */ |
2708 |
if ((portchange & USB_PORT_STAT_C_CONNECTION)) |
2709 |
return -ENOTCONN; |
2710 |
|
2711 |
if ((portstatus & USB_PORT_STAT_ENABLE)) { |
2712 |
if (!udev) |
2713 |
return 0; |
2714 |
|
2715 |
if (hub_is_wusb(hub)) |
2716 |
udev->speed = USB_SPEED_WIRELESS; |
2717 |
else if (hub_is_superspeed(hub->hdev)) |
2718 |
udev->speed = USB_SPEED_SUPER; |
2719 |
else if (portstatus & USB_PORT_STAT_HIGH_SPEED) |
2720 |
udev->speed = USB_SPEED_HIGH; |
2721 |
else if (portstatus & USB_PORT_STAT_LOW_SPEED) |
2722 |
udev->speed = USB_SPEED_LOW; |
2723 |
else |
2724 |
udev->speed = USB_SPEED_FULL; |
2725 |
return 0; |
2726 |
} |
2727 |
} else { |
2728 |
if (!(portstatus & USB_PORT_STAT_CONNECTION) || |
2729 |
hub_port_warm_reset_required(hub, port1, |
2730 |
portstatus)) |
2731 |
return -ENOTCONN; |
2684 |
|
2732 |
|
2685 |
if (!udev) |
|
|
2686 |
return 0; |
2733 |
return 0; |
2687 |
|
2734 |
} |
2688 |
if (hub_is_wusb(hub)) |
2735 |
return -EBUSY; |
2689 |
udev->speed = USB_SPEED_WIRELESS; |
|
|
2690 |
else if (hub_is_superspeed(hub->hdev)) |
2691 |
udev->speed = USB_SPEED_SUPER; |
2692 |
else if (portstatus & USB_PORT_STAT_HIGH_SPEED) |
2693 |
udev->speed = USB_SPEED_HIGH; |
2694 |
else if (portstatus & USB_PORT_STAT_LOW_SPEED) |
2695 |
udev->speed = USB_SPEED_LOW; |
2696 |
else |
2697 |
udev->speed = USB_SPEED_FULL; |
2698 |
return 0; |
2699 |
} |
2736 |
} |
2700 |
|
2737 |
|
2701 |
static void hub_port_finish_reset(struct usb_hub *hub, int port1, |
2738 |
static void hub_port_finish_reset(struct usb_hub *hub, int port1, |
2702 |
struct usb_device *udev, int *status) |
2739 |
struct usb_device *udev, int *status, bool warm) |
2703 |
{ |
2740 |
{ |
2704 |
switch (*status) { |
2741 |
switch (*status) { |
2705 |
case 0: |
2742 |
case 0: |
2706 |
/* TRSTRCY = 10 ms; plus some extra */ |
2743 |
if (!warm) { |
2707 |
msleep(10 + 40); |
2744 |
struct usb_hcd *hcd; |
2708 |
if (udev) { |
2745 |
/* TRSTRCY = 10 ms; plus some extra */ |
2709 |
struct usb_hcd *hcd = bus_to_hcd(udev->bus); |
2746 |
msleep(10 + 40); |
2710 |
|
2747 |
if (udev) { |
2711 |
update_devnum(udev, 0); |
2748 |
update_devnum(udev, 0); |
2712 |
/* The xHC may think the device is already reset, |
2749 |
hcd = bus_to_hcd(udev->bus); |
2713 |
* so ignore the status. |
2750 |
/* The xHC may think the device is already |
2714 |
*/ |
2751 |
* reset, so ignore the status. |
2715 |
if (hcd->driver->reset_device) |
2752 |
*/ |
2716 |
hcd->driver->reset_device(hcd, udev); |
2753 |
if (hcd->driver->reset_device) |
|
|
2754 |
hcd->driver->reset_device(hcd, udev); |
2755 |
} |
2717 |
} |
2756 |
} |
2718 |
/* FALL THROUGH */ |
2757 |
/* FALL THROUGH */ |
2719 |
case -ENOTCONN: |
2758 |
case -ENOTCONN: |
Lines 2725-2734
Link Here
|
2725 |
USB_PORT_FEAT_C_BH_PORT_RESET); |
2764 |
USB_PORT_FEAT_C_BH_PORT_RESET); |
2726 |
usb_clear_port_feature(hub->hdev, port1, |
2765 |
usb_clear_port_feature(hub->hdev, port1, |
2727 |
USB_PORT_FEAT_C_PORT_LINK_STATE); |
2766 |
USB_PORT_FEAT_C_PORT_LINK_STATE); |
2728 |
usb_clear_port_feature(hub->hdev, port1, |
|
|
2729 |
USB_PORT_FEAT_C_CONNECTION); |
2730 |
} |
2767 |
} |
2731 |
if (udev) |
2768 |
if (!warm && udev) |
2732 |
usb_set_device_state(udev, *status |
2769 |
usb_set_device_state(udev, *status |
2733 |
? USB_STATE_NOTATTACHED |
2770 |
? USB_STATE_NOTATTACHED |
2734 |
: USB_STATE_DEFAULT); |
2771 |
: USB_STATE_DEFAULT); |
Lines 2789-2822
Link Here
|
2789 |
status); |
2826 |
status); |
2790 |
} |
2827 |
} |
2791 |
|
2828 |
|
2792 |
/* Check for disconnect or reset */ |
2829 |
/* return on disconnect or reset */ |
2793 |
if (status == 0 || status == -ENOTCONN || status == -ENODEV) { |
2830 |
if (status == 0 || status == -ENOTCONN || status == -ENODEV) { |
2794 |
hub_port_finish_reset(hub, port1, udev, &status); |
2831 |
hub_port_finish_reset(hub, port1, udev, &status, warm); |
2795 |
|
2832 |
goto done; |
2796 |
if (!hub_is_superspeed(hub->hdev)) |
|
|
2797 |
goto done; |
2798 |
|
2799 |
/* |
2800 |
* If a USB 3.0 device migrates from reset to an error |
2801 |
* state, re-issue the warm reset. |
2802 |
*/ |
2803 |
if (hub_port_status(hub, port1, |
2804 |
&portstatus, &portchange) < 0) |
2805 |
goto done; |
2806 |
|
2807 |
if (!hub_port_warm_reset_required(hub, port1, |
2808 |
portstatus)) |
2809 |
goto done; |
2810 |
|
2811 |
/* |
2812 |
* If the port is in SS.Inactive or Compliance Mode, the |
2813 |
* hot or warm reset failed. Try another warm reset. |
2814 |
*/ |
2815 |
if (!warm) { |
2816 |
dev_dbg(&port_dev->dev, |
2817 |
"hot reset failed, warm reset\n"); |
2818 |
warm = true; |
2819 |
} |
2820 |
} |
2833 |
} |
2821 |
|
2834 |
|
2822 |
dev_dbg(&port_dev->dev, |
2835 |
dev_dbg(&port_dev->dev, |