@@ -2025,11 +2025,12 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
2025
2025
2026
2026
#define HUB_ROOT_RESET_TIME 50 /* times are in msec */
2027
2027
#define HUB_SHORT_RESET_TIME 10
2028
+ #define HUB_BH_RESET_TIME 50
2028
2029
#define HUB_LONG_RESET_TIME 200
2029
2030
#define HUB_RESET_TIMEOUT 500
2030
2031
2031
2032
static int hub_port_wait_reset (struct usb_hub * hub , int port1 ,
2032
- struct usb_device * udev , unsigned int delay )
2033
+ struct usb_device * udev , unsigned int delay , bool warm )
2033
2034
{
2034
2035
int delay_time , ret ;
2035
2036
u16 portstatus ;
@@ -2046,145 +2047,151 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
2046
2047
if (ret < 0 )
2047
2048
return ret ;
2048
2049
2049
- /* Device went away? */
2050
- if (!(portstatus & USB_PORT_STAT_CONNECTION ))
2051
- return - ENOTCONN ;
2052
-
2053
- /* bomb out completely if the connection bounced */
2054
- if ((portchange & USB_PORT_STAT_C_CONNECTION ))
2055
- return - ENOTCONN ;
2056
-
2057
- /* if we`ve finished resetting, then break out of the loop */
2058
- if (!(portstatus & USB_PORT_STAT_RESET ) &&
2059
- (portstatus & USB_PORT_STAT_ENABLE )) {
2060
- if (hub_is_wusb (hub ))
2061
- udev -> speed = USB_SPEED_WIRELESS ;
2062
- else if (hub_is_superspeed (hub -> hdev ))
2063
- udev -> speed = USB_SPEED_SUPER ;
2064
- else if (portstatus & USB_PORT_STAT_HIGH_SPEED )
2065
- udev -> speed = USB_SPEED_HIGH ;
2066
- else if (portstatus & USB_PORT_STAT_LOW_SPEED )
2067
- udev -> speed = USB_SPEED_LOW ;
2068
- else
2069
- udev -> speed = USB_SPEED_FULL ;
2070
- return 0 ;
2050
+ /*
2051
+ * Some buggy devices require a warm reset to be issued even
2052
+ * when the port appears not to be connected.
2053
+ */
2054
+ if (!warm ) {
2055
+ /* Device went away? */
2056
+ if (!(portstatus & USB_PORT_STAT_CONNECTION ))
2057
+ return - ENOTCONN ;
2058
+
2059
+ /* bomb out completely if the connection bounced */
2060
+ if ((portchange & USB_PORT_STAT_C_CONNECTION ))
2061
+ return - ENOTCONN ;
2062
+
2063
+ /* if we`ve finished resetting, then break out of
2064
+ * the loop
2065
+ */
2066
+ if (!(portstatus & USB_PORT_STAT_RESET ) &&
2067
+ (portstatus & USB_PORT_STAT_ENABLE )) {
2068
+ if (hub_is_wusb (hub ))
2069
+ udev -> speed = USB_SPEED_WIRELESS ;
2070
+ else if (hub_is_superspeed (hub -> hdev ))
2071
+ udev -> speed = USB_SPEED_SUPER ;
2072
+ else if (portstatus & USB_PORT_STAT_HIGH_SPEED )
2073
+ udev -> speed = USB_SPEED_HIGH ;
2074
+ else if (portstatus & USB_PORT_STAT_LOW_SPEED )
2075
+ udev -> speed = USB_SPEED_LOW ;
2076
+ else
2077
+ udev -> speed = USB_SPEED_FULL ;
2078
+ return 0 ;
2079
+ }
2080
+ } else {
2081
+ if (portchange & USB_PORT_STAT_C_BH_RESET )
2082
+ return 0 ;
2071
2083
}
2072
2084
2073
2085
/* switch to the long delay after two short delay failures */
2074
2086
if (delay_time >= 2 * HUB_SHORT_RESET_TIME )
2075
2087
delay = HUB_LONG_RESET_TIME ;
2076
2088
2077
2089
dev_dbg (hub -> intfdev ,
2078
- "port %d not reset yet, waiting %dms\n" ,
2079
- port1 , delay );
2090
+ "port %d not %sreset yet, waiting %dms\n" ,
2091
+ port1 , warm ? "warm " : "" , delay );
2080
2092
}
2081
2093
2082
2094
return - EBUSY ;
2083
2095
}
2084
2096
2097
+ static void hub_port_finish_reset (struct usb_hub * hub , int port1 ,
2098
+ struct usb_device * udev , int * status , bool warm )
2099
+ {
2100
+ switch (* status ) {
2101
+ case 0 :
2102
+ if (!warm ) {
2103
+ struct usb_hcd * hcd ;
2104
+ /* TRSTRCY = 10 ms; plus some extra */
2105
+ msleep (10 + 40 );
2106
+ update_devnum (udev , 0 );
2107
+ hcd = bus_to_hcd (udev -> bus );
2108
+ if (hcd -> driver -> reset_device ) {
2109
+ * status = hcd -> driver -> reset_device (hcd , udev );
2110
+ if (* status < 0 ) {
2111
+ dev_err (& udev -> dev , "Cannot reset "
2112
+ "HCD device state\n" );
2113
+ break ;
2114
+ }
2115
+ }
2116
+ }
2117
+ /* FALL THROUGH */
2118
+ case - ENOTCONN :
2119
+ case - ENODEV :
2120
+ clear_port_feature (hub -> hdev ,
2121
+ port1 , USB_PORT_FEAT_C_RESET );
2122
+ /* FIXME need disconnect() for NOTATTACHED device */
2123
+ if (warm ) {
2124
+ clear_port_feature (hub -> hdev , port1 ,
2125
+ USB_PORT_FEAT_C_BH_PORT_RESET );
2126
+ clear_port_feature (hub -> hdev , port1 ,
2127
+ USB_PORT_FEAT_C_PORT_LINK_STATE );
2128
+ } else {
2129
+ usb_set_device_state (udev , * status
2130
+ ? USB_STATE_NOTATTACHED
2131
+ : USB_STATE_DEFAULT );
2132
+ }
2133
+ break ;
2134
+ }
2135
+ }
2136
+
2137
+ /* Handle port reset and port warm(BH) reset (for USB3 protocol ports) */
2085
2138
static int hub_port_reset (struct usb_hub * hub , int port1 ,
2086
- struct usb_device * udev , unsigned int delay )
2139
+ struct usb_device * udev , unsigned int delay , bool warm )
2087
2140
{
2088
2141
int i , status ;
2089
- struct usb_hcd * hcd ;
2090
2142
2091
- hcd = bus_to_hcd (udev -> bus );
2092
- /* Block EHCI CF initialization during the port reset.
2093
- * Some companion controllers don't like it when they mix.
2094
- */
2095
- down_read (& ehci_cf_port_reset_rwsem );
2143
+ if (!warm ) {
2144
+ /* Block EHCI CF initialization during the port reset.
2145
+ * Some companion controllers don't like it when they mix.
2146
+ */
2147
+ down_read (& ehci_cf_port_reset_rwsem );
2148
+ } else {
2149
+ if (!hub_is_superspeed (hub -> hdev )) {
2150
+ dev_err (hub -> intfdev , "only USB3 hub support "
2151
+ "warm reset\n" );
2152
+ return - EINVAL ;
2153
+ }
2154
+ }
2096
2155
2097
2156
/* Reset the port */
2098
2157
for (i = 0 ; i < PORT_RESET_TRIES ; i ++ ) {
2099
- status = set_port_feature (hub -> hdev ,
2100
- port1 , USB_PORT_FEAT_RESET );
2101
- if (status )
2158
+ status = set_port_feature (hub -> hdev , port1 , (warm ?
2159
+ USB_PORT_FEAT_BH_PORT_RESET :
2160
+ USB_PORT_FEAT_RESET ));
2161
+ if (status ) {
2102
2162
dev_err (hub -> intfdev ,
2103
- "cannot reset port %d (err = %d)\n" ,
2104
- port1 , status );
2105
- else {
2106
- status = hub_port_wait_reset (hub , port1 , udev , delay );
2163
+ "cannot %sreset port %d (err = %d)\n" ,
2164
+ warm ? "warm " : "" , port1 , status );
2165
+ } else {
2166
+ status = hub_port_wait_reset (hub , port1 , udev , delay ,
2167
+ warm );
2107
2168
if (status && status != - ENOTCONN )
2108
2169
dev_dbg (hub -> intfdev ,
2109
2170
"port_wait_reset: err = %d\n" ,
2110
2171
status );
2111
2172
}
2112
2173
2113
2174
/* return on disconnect or reset */
2114
- switch (status ) {
2115
- case 0 :
2116
- /* TRSTRCY = 10 ms; plus some extra */
2117
- msleep (10 + 40 );
2118
- update_devnum (udev , 0 );
2119
- if (hcd -> driver -> reset_device ) {
2120
- status = hcd -> driver -> reset_device (hcd , udev );
2121
- if (status < 0 ) {
2122
- dev_err (& udev -> dev , "Cannot reset "
2123
- "HCD device state\n" );
2124
- break ;
2125
- }
2126
- }
2127
- /* FALL THROUGH */
2128
- case - ENOTCONN :
2129
- case - ENODEV :
2130
- clear_port_feature (hub -> hdev ,
2131
- port1 , USB_PORT_FEAT_C_RESET );
2132
- /* FIXME need disconnect() for NOTATTACHED device */
2133
- usb_set_device_state (udev , status
2134
- ? USB_STATE_NOTATTACHED
2135
- : USB_STATE_DEFAULT );
2175
+ if (status == 0 || status == - ENOTCONN || status == - ENODEV ) {
2176
+ hub_port_finish_reset (hub , port1 , udev , & status , warm );
2136
2177
goto done ;
2137
2178
}
2138
2179
2139
2180
dev_dbg (hub -> intfdev ,
2140
- "port %d not enabled, trying reset again...\n" ,
2141
- port1 );
2181
+ "port %d not enabled, trying %sreset again...\n" ,
2182
+ port1 , warm ? "warm " : "" );
2142
2183
delay = HUB_LONG_RESET_TIME ;
2143
2184
}
2144
2185
2145
2186
dev_err (hub -> intfdev ,
2146
2187
"Cannot enable port %i. Maybe the USB cable is bad?\n" ,
2147
2188
port1 );
2148
2189
2149
- done :
2150
- up_read (& ehci_cf_port_reset_rwsem );
2151
- return status ;
2152
- }
2153
-
2154
- /* Warm reset a USB3 protocol port */
2155
- static int hub_port_warm_reset (struct usb_hub * hub , int port )
2156
- {
2157
- int ret ;
2158
- u16 portstatus , portchange ;
2159
-
2160
- if (!hub_is_superspeed (hub -> hdev )) {
2161
- dev_err (hub -> intfdev , "only USB3 hub support warm reset\n" );
2162
- return - EINVAL ;
2163
- }
2164
-
2165
- /* Warm reset the port */
2166
- ret = set_port_feature (hub -> hdev ,
2167
- port , USB_PORT_FEAT_BH_PORT_RESET );
2168
- if (ret ) {
2169
- dev_err (hub -> intfdev , "cannot warm reset port %d\n" , port );
2170
- return ret ;
2171
- }
2172
-
2173
- msleep (20 );
2174
- ret = hub_port_status (hub , port , & portstatus , & portchange );
2175
-
2176
- if (portchange & USB_PORT_STAT_C_RESET )
2177
- clear_port_feature (hub -> hdev , port , USB_PORT_FEAT_C_RESET );
2178
-
2179
- if (portchange & USB_PORT_STAT_C_BH_RESET )
2180
- clear_port_feature (hub -> hdev , port ,
2181
- USB_PORT_FEAT_C_BH_PORT_RESET );
2182
-
2183
- if (portchange & USB_PORT_STAT_C_LINK_STATE )
2184
- clear_port_feature (hub -> hdev , port ,
2185
- USB_PORT_FEAT_C_PORT_LINK_STATE );
2190
+ done :
2191
+ if (!warm )
2192
+ up_read (& ehci_cf_port_reset_rwsem );
2186
2193
2187
- return ret ;
2194
+ return status ;
2188
2195
}
2189
2196
2190
2197
/* Check if a port is power on */
@@ -2814,7 +2821,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
2814
2821
2815
2822
/* Reset the device; full speed may morph to high speed */
2816
2823
/* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
2817
- retval = hub_port_reset (hub , port1 , udev , delay );
2824
+ retval = hub_port_reset (hub , port1 , udev , delay , false );
2818
2825
if (retval < 0 ) /* error or disconnect */
2819
2826
goto fail ;
2820
2827
/* success, speed is known */
@@ -2935,7 +2942,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
2935
2942
buf -> bMaxPacketSize0 ;
2936
2943
kfree (buf );
2937
2944
2938
- retval = hub_port_reset (hub , port1 , udev , delay );
2945
+ retval = hub_port_reset (hub , port1 , udev , delay , false );
2939
2946
if (retval < 0 ) /* error or disconnect */
2940
2947
goto fail ;
2941
2948
if (oldspeed != udev -> speed ) {
@@ -3556,7 +3563,8 @@ static void hub_events(void)
3556
3563
(portstatus & USB_PORT_STAT_LINK_STATE )
3557
3564
== USB_SS_PORT_LS_SS_INACTIVE ) {
3558
3565
dev_dbg (hub_dev , "warm reset port %d\n" , i );
3559
- hub_port_warm_reset (hub , i );
3566
+ hub_port_reset (hub , i , NULL ,
3567
+ HUB_BH_RESET_TIME , true);
3560
3568
}
3561
3569
3562
3570
if (connect_change )
0 commit comments