[coreboot] New patch to review for coreboot: 677206d libpayload: Bring USB hub driver to a working state

Nico Huber (nico.huber@secunet.com) gerrit at coreboot.org
Thu May 31 15:41:36 CEST 2012


Nico Huber (nico.huber at secunet.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1080

-gerrit

commit 677206d4a32112759afe93c36b9d4ed9931b0f2b
Author: Nico Huber <nico.huber at secunet.com>
Date:   Mon May 21 16:20:59 2012 +0200

    libpayload: Bring USB hub driver to a working state
    
    This adds proper device attachment and detachment detection and port enable-
    ment to the USB hub driver. Support for split transactions is still missing,
    so this works only with USB2.0 devices on hubs in USB2.0 mode and USB1.1
    devices on hubs in USB1.1 mode.
    
    Change-Id: I80bf03f3117116a60382b87a4f84366370649915
    Signed-off-by: Nico Huber <nico.huber at secunet.com>
---
 payloads/libpayload/drivers/usb/usbhub.c |   76 +++++++++++++++++++++--------
 1 files changed, 55 insertions(+), 21 deletions(-)

diff --git a/payloads/libpayload/drivers/usb/usbhub.c b/payloads/libpayload/drivers/usb/usbhub.c
index 08042a2..09ab9cc 100644
--- a/payloads/libpayload/drivers/usb/usbhub.c
+++ b/payloads/libpayload/drivers/usb/usbhub.c
@@ -31,8 +31,16 @@
 
 // assume that host_to_device is overwritten if necessary
 #define DR_PORT gen_bmRequestType(host_to_device, class_type, other_recp)
-#define PORT_RESET 0x4
-#define PORT_POWER 0x8
+/* status bits */
+#define PORT_CONNECTION 0x1
+#define PORT_ENABLE 0x2
+#define PORT_RESET 0x10
+/* status change bits */
+#define C_PORT_CONNECTION 0x1
+/* feature selectors (for setting / clearing features) */
+#define SEL_PORT_RESET 0x4
+#define SEL_PORT_POWER 0x8
+#define SEL_C_PORT_CONNECTION 0x10
 
 typedef struct {
 	int num_ports;
@@ -53,28 +61,54 @@ usb_hub_destroy (usbdev_t *dev)
 static void
 usb_hub_scanport (usbdev_t *dev, int port)
 {
-	unsigned short buf[2];
+	int timeout;
 
+	unsigned short buf[2];
 	get_status (dev, port, DR_PORT, 4, buf);
-	int portstatus = ((buf[0] & 1) == 0);
-	int datastatus = (HUB_INST (dev)->ports[port] == -1);
-	if (portstatus == datastatus)
-		return;		// no change - FIXME: read right fields for that test
-
-	if (!datastatus) {
-		int devno = HUB_INST (dev)->ports[port];
-		if (devno == -1)
-			fatal ("FATAL: illegal devno!\n");
+	if (!(buf[1] & C_PORT_CONNECTION))
+		/* no change */
+		return;
+
+	/* clear Port Connection status change */
+	clear_feature (dev, port, SEL_C_PORT_CONNECTION, DR_PORT);
+
+	int devno = HUB_INST (dev)->ports[port];
+	if (devno != -1) {
+		/* detach device, either because of re-/ or disconnect */
 		usb_detach_device(dev->controller, devno);
 		HUB_INST (dev)->ports[port] = -1;
-		return;
 	}
 
-	set_feature (dev, port, PORT_RESET, DR_PORT);
-	mdelay (20);
+	if (!(buf[0] & PORT_CONNECTION))
+		/* no device connected, nothing to do */
+		return;
 
-	get_status (dev, port, DR_PORT, 4, buf);
+	/* wait 100ms for port to become stable */
+	mdelay (100); // usb20 spec 9.1.2
 
+	/* reset port */
+	set_feature (dev, port, SEL_PORT_RESET, DR_PORT);
+	/* wait at least 10ms (usb2.0 spec 11.5.1.5: 10ms to 20ms) */
+	mdelay (10);
+	/* wait for hub to finish reset */
+	timeout = 30; /* time out after 10ms (spec) + 20ms (kindly) */
+	do {
+		get_status (dev, port, DR_PORT, 4, buf);
+		mdelay(1); timeout--;
+	} while ((buf[0] & PORT_RESET) && timeout);
+	if (!timeout)
+		debug("Warning: usbhub: port reset timed out.\n");
+
+	/* wait for port to be enabled. the hub is responsible for this */
+	timeout = 500; /* time out after 500ms */
+	do {
+		get_status (dev, port, DR_PORT, 4, buf);
+		mdelay(1); timeout--;
+	} while (!(buf[0] & PORT_ENABLE) && timeout);
+	if (!timeout)
+		debug("Warning: usbhub: port enabling timed out.\n");
+
+	get_status (dev, port, DR_PORT, 4, buf);
 	/* bit  10  9
 	 *      0   0  full speed
 	 *      0   1  low speed
@@ -83,6 +117,9 @@ usb_hub_scanport (usbdev_t *dev, int port)
 	int speed = ((buf[0] >> 9) & 3) ;
 
 	HUB_INST (dev)->ports[port] = usb_attach_device(dev->controller, dev->address, port, speed);
+
+	/* clear Port Connection status change */
+	clear_feature (dev, port, SEL_C_PORT_CONNECTION, DR_PORT);
 }
 
 static int
@@ -92,10 +129,7 @@ usb_hub_report_port_changes (usbdev_t *dev)
 	unsigned short buf[2];
 	for (port = 1; port <= HUB_INST (dev)->num_ports; port++) {
 		get_status (dev, port, DR_PORT, 4, buf);
-		// FIXME: proper change detection
-		int portstatus = ((buf[0] & 1) == 0);
-		int datastatus = (HUB_INST (dev)->ports[port] == -1);
-		if (portstatus != datastatus)
+		if (buf[1] & C_PORT_CONNECTION)
 			return port;
 	}
 
@@ -106,7 +140,7 @@ usb_hub_report_port_changes (usbdev_t *dev)
 static void
 usb_hub_enable_port (usbdev_t *dev, int port)
 {
-	set_feature (dev, port, PORT_POWER, DR_PORT);
+	set_feature (dev, port, SEL_PORT_POWER, DR_PORT);
 	mdelay (20);
 }
 




More information about the coreboot mailing list