[usb] Detect missed disconnections

The USB core will currently fail to detect disconnections if a new
device has attached by the time the port is examined in
usb_hotplug().

Fix by recording the fact that a disconnection has taken place
whenever the "connection status changed" (CSC) bit is observed to be
set.  (Whether the change represents a disconnection or a
reconnection, it indicates that the port has experienced some time of
being disconnected.)

Note that the time at which a disconnection can be detected varies by
hub type.  In particular: root hubs can observe the CSC bit when
polling, and so will record the disconnection before calling
usb_port_changed(), but USB hubs read the port status (and hence the
CSC bit) only during the call to hub_speed(), long after the call to
usb_port_changed().

Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
Michael Brown
2015-05-06 16:38:28 +01:00
parent b88ab14ba3
commit f6604627ff
5 changed files with 78 additions and 51 deletions

View File

@@ -1498,6 +1498,7 @@ static int ehci_root_speed ( struct usb_hub *hub, struct usb_port *port ) {
unsigned int speed;
unsigned int line;
int ccs;
int csc;
int ped;
/* Read port status */
@@ -1505,9 +1506,14 @@ static int ehci_root_speed ( struct usb_hub *hub, struct usb_port *port ) {
DBGC2 ( ehci, "EHCI %p port %d status is %08x\n",
ehci, port->address, portsc );
ccs = ( portsc & EHCI_PORTSC_CCS );
csc = ( portsc & EHCI_PORTSC_CSC );
ped = ( portsc & EHCI_PORTSC_PED );
line = EHCI_PORTSC_LINE_STATUS ( portsc );
/* Record disconnections and clear changes */
port->disconnected |= csc;
writel ( portsc, ehci->op + EHCI_OP_PORTSC ( port->address ) );
/* Determine port speed */
if ( ! ccs ) {
/* Port not connected */
@@ -1564,7 +1570,8 @@ static void ehci_root_poll ( struct usb_hub *hub, struct usb_port *port ) {
if ( ! change )
return;
/* Acknowledge changes */
/* Record disconnections and clear changes */
port->disconnected |= ( portsc & EHCI_PORTSC_CSC );
writel ( portsc, ehci->op + EHCI_OP_PORTSC ( port->address ) );
/* Report port status change */