forked from Minki/linux
usb: core: hub: Improved device recognition on remote wakeup
If hub_activate() is called before D+ has stabilized after remote wakeup, the following situation might occur: __ ___________________ / \ / D+ __/ \__/ Hub _______________________________ | ^ ^ ^ | | | | Host _____v__|___|___________|______ | | | | | | | \-- Interrupt Transfer (*3) | | \-- ClearPortFeature (*2) | \-- GetPortStatus (*1) \-- Host detects remote wakeup - D+ goes high, Host starts running by remote wakeup - D+ is not stable, goes low - Host requests GetPortStatus at (*1) and gets the following hub status: - Current Connect Status bit is 0 - Connect Status Change bit is 1 - D+ stabilizes, goes high - Host requests ClearPortFeature and thus Connect Status Change bit is cleared at (*2) - After waiting 100 ms, Host starts the Interrupt Transfer at (*3) - Since the Connect Status Change bit is 0, Hub returns NAK. In this case, port_event() is not called in hub_event() and Host cannot recognize device. To solve this issue, flag change_bits even if only Connect Status Change bit is 1 when got in the first GetPortStatus. This issue occurs rarely because it only if D+ changes during a very short time between GetPortStatus and ClearPortFeature. However, it is fatal if it occurs in embedded system. Signed-off-by: Keiya Nobuta <nobuta.keiya@fujitsu.com> Cc: stable <stable@vger.kernel.org> Acked-by: Alan Stern <stern@rowland.harvard.edu> Link: https://lore.kernel.org/r/20200109051448.28150-1-nobuta.keiya@fujitsu.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
b3a987b026
commit
9c06ac4c83
@ -1192,6 +1192,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
|
|||||||
* PORT_OVER_CURRENT is not. So check for any of them.
|
* PORT_OVER_CURRENT is not. So check for any of them.
|
||||||
*/
|
*/
|
||||||
if (udev || (portstatus & USB_PORT_STAT_CONNECTION) ||
|
if (udev || (portstatus & USB_PORT_STAT_CONNECTION) ||
|
||||||
|
(portchange & USB_PORT_STAT_C_CONNECTION) ||
|
||||||
(portstatus & USB_PORT_STAT_OVERCURRENT) ||
|
(portstatus & USB_PORT_STAT_OVERCURRENT) ||
|
||||||
(portchange & USB_PORT_STAT_C_OVERCURRENT))
|
(portchange & USB_PORT_STAT_C_OVERCURRENT))
|
||||||
set_bit(port1, hub->change_bits);
|
set_bit(port1, hub->change_bits);
|
||||||
|
Loading…
Reference in New Issue
Block a user