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

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

702
 	unsigned int protocol;
702
 	unsigned int protocol;
703
 	/** Port speed */
703
 	/** Port speed */
704
 	unsigned int speed;
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
 	struct usb_device *usb;
712
 	struct usb_device *usb;
707
 	/** List of changed ports */
713
 	/** List of changed ports */
708
 	struct list_head list;
714
 	struct list_head list;

Loading…
Cancel
Save