Browse Source

[usb] Handle port status changes received after failing to find a driver

Commit a60f2dd ("[usb] Try multiple USB device configurations")
changed the behaviour of register_usb() such that if no drivers are
found then the device will be closed and the memory used will be
freed.

If a port status change subsequently occurs while the device is still
physically attached, then usb_hotplug() will see this as a new device
having been attached, since there is no device recorded as being
currently attached to the port.  This can lead to spurious hotplug
events (or even endless loops of hotplug events, if the process of
opening and closing the device happens to generate a port status
change).

Fix by using a separate flag to indicate that a device is physically
attached (even if we have no corresponding struct usb_device).

Reported-by: Dan Ellis <Dan.Ellis@displaylink.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 9 years ago
parent
commit
6fe8f80418
2 changed files with 20 additions and 6 deletions
  1. 13
    5
      src/drivers/bus/usb.c
  2. 7
    1
      src/include/ipxe/usb.h

+ 13
- 5
src/drivers/bus/usb.c View File

@@ -1314,6 +1314,9 @@ static int usb_attached ( struct usb_port *port ) {
1314 1314
 	struct usb_device *usb;
1315 1315
 	int rc;
1316 1316
 
1317
+	/* Mark port as attached */
1318
+	port->attached = 1;
1319
+
1317 1320
 	/* Sanity checks */
1318 1321
 	assert ( port->usb == NULL );
1319 1322
 
@@ -1345,8 +1348,12 @@ static int usb_attached ( struct usb_port *port ) {
1345 1348
 static void usb_detached ( struct usb_port *port ) {
1346 1349
 	struct usb_device *usb = port->usb;
1347 1350
 
1348
-	/* Sanity checks */
1349
-	assert ( port->usb != NULL );
1351
+	/* Mark port as detached */
1352
+	port->attached = 0;
1353
+
1354
+	/* Do nothing if we have no USB device */
1355
+	if ( ! usb )
1356
+		return;
1350 1357
 
1351 1358
 	/* Unregister USB device */
1352 1359
 	unregister_usb ( usb );
@@ -1373,10 +1380,10 @@ static int usb_hotplug ( struct usb_port *port ) {
1373 1380
 	}
1374 1381
 
1375 1382
 	/* Handle attached/detached device as applicable */
1376
-	if ( port->speed && ! port->usb ) {
1383
+	if ( port->speed && ! port->attached ) {
1377 1384
 		/* Newly attached device */
1378 1385
 		return usb_attached ( port );
1379
-	} else if ( port->usb && ! port->speed ) {
1386
+	} else if ( port->attached && ! port->speed ) {
1380 1387
 		/* Newly detached device */
1381 1388
 		usb_detached ( port );
1382 1389
 		return 0;
@@ -1546,7 +1553,7 @@ void unregister_usb_hub ( struct usb_hub *hub ) {
1546 1553
 	/* Detach all devices */
1547 1554
 	for ( i = 1 ; i <= hub->ports ; i++ ) {
1548 1555
 		port = usb_port ( hub, i );
1549
-		if ( port->usb )
1556
+		if ( port->attached )
1550 1557
 			usb_detached ( port );
1551 1558
 	}
1552 1559
 
@@ -1576,6 +1583,7 @@ void free_usb_hub ( struct usb_hub *hub ) {
1576 1583
 	/* Sanity checks */
1577 1584
 	for ( i = 1 ; i <= hub->ports ; i++ ) {
1578 1585
 		port = usb_port ( hub, i );
1586
+		assert ( ! port->attached );
1579 1587
 		assert ( port->usb == NULL );
1580 1588
 		assert ( list_empty ( &port->list ) );
1581 1589
 	}

+ 7
- 1
src/include/ipxe/usb.h View File

@@ -702,7 +702,13 @@ struct usb_port {
702 702
 	unsigned int protocol;
703 703
 	/** Port speed */
704 704
 	unsigned int speed;
705
-	/** Currently attached device (if any) */
705
+	/** Port has an attached device */
706
+	int attached;
707
+	/** Currently attached device (if in use)
708
+	 *
709
+	 * Note that this field will be NULL if the attached device
710
+	 * has been freed (e.g. because there were no drivers found).
711
+	 */
706 712
 	struct usb_device *usb;
707 713
 	/** List of changed ports */
708 714
 	struct list_head list;

Loading…
Cancel
Save