mirror of
https://github.com/ipxe/ipxe
synced 2025-12-13 15:31:42 +03:00
[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:
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user