[coreboot-gerrit] New patch to review for coreboot: 8af0779 libpayload: Port usb hub driver to use the generic code

Nico Huber (nico.huber@secunet.com) gerrit at coreboot.org
Thu Jun 13 14:46:33 CEST 2013


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

-gerrit

commit 8af077954795273cf58b504b90a328f5b75db55e
Author: Nico Huber <nico.huber at secunet.com>
Date:   Wed May 29 15:10:46 2013 +0200

    libpayload: Port usb hub driver to use the generic code
    
    This is mostly a rewrite, don't even try to read a diff.
    
    Tested with an internal rate matching hub on a QM77 board and three hubs
    integrated into DELL monitors.
    
    Change-Id: Ib12fa2aa90af4e0f37143d2ed92c4a1705b6d774
    Signed-off-by: Nico Huber <nico.huber at secunet.com>
---
 payloads/libpayload/Config.in            |   3 +-
 payloads/libpayload/drivers/usb/usbhub.c | 204 +++++++++++--------------------
 2 files changed, 74 insertions(+), 133 deletions(-)

diff --git a/payloads/libpayload/Config.in b/payloads/libpayload/Config.in
index 66d478d..0a29bd5 100644
--- a/payloads/libpayload/Config.in
+++ b/payloads/libpayload/Config.in
@@ -380,7 +380,8 @@ config USB_MSC
 
 config USB_GEN_HUB
 	bool
-	default n
+	default n if (!USB_HUB)
+	default y if (USB_HUB)
 
 endmenu
 
diff --git a/payloads/libpayload/drivers/usb/usbhub.c b/payloads/libpayload/drivers/usb/usbhub.c
index 90e08db..20e064e 100644
--- a/payloads/libpayload/drivers/usb/usbhub.c
+++ b/payloads/libpayload/drivers/usb/usbhub.c
@@ -1,7 +1,7 @@
 /*
  * This file is part of the libpayload project.
  *
- * Copyright (C) 2008-2010 coresystems GmbH
+ * Copyright (C) 2013 secunet Security Networks AG
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -28,170 +28,110 @@
  */
 
 #include <usb/usb.h>
+#include "generic_hub.h"
 
-// assume that host_to_device is overwritten if necessary
+/* assume that host_to_device is overwritten if necessary */
 #define DR_PORT gen_bmRequestType(host_to_device, class_type, other_recp)
-/* status bits */
+/* status (and status change) 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;
-	int *ports;
-	hub_descriptor_t *descriptor;
-} usbhub_inst_t;
-
-#define HUB_INST(dev) ((usbhub_inst_t*)(dev)->data)
-
-static void
-usb_hub_destroy (usbdev_t *dev)
+static int
+usb_hub_port_status_changed(usbdev_t *const dev, const int port)
 {
-	int i;
-
-	/* First, detach all devices behind this hub. */
-	int *const ports = HUB_INST (dev)->ports;
-	for (i = 1; i <= HUB_INST (dev)->num_ports; i++) {
-		if (ports[i] != -1) {
-			usb_detach_device(dev->controller, ports[i]);
-			ports[i] = -1;
-		}
-	}
-
-	free (HUB_INST (dev)->ports);
-	free (HUB_INST (dev)->descriptor);
-	free (HUB_INST (dev));
+	unsigned short buf[2] = { 0, 0 };
+	get_status (dev, port, DR_PORT, 4, buf);
+	clear_feature (dev, port, SEL_C_PORT_CONNECTION, DR_PORT);
+	return buf[1] & PORT_CONNECTION;
 }
 
-static void
-usb_hub_scanport (usbdev_t *dev, int port)
+static int
+usb_hub_port_connected(usbdev_t *const dev, const int port)
 {
-	int timeout;
-
-	unsigned short buf[2];
+	unsigned short buf[2] = { 0, 0 };
 	get_status (dev, port, DR_PORT, 4, buf);
-	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;
-	}
-
-	if (!(buf[0] & PORT_CONNECTION))
-		/* no device connected, nothing to do */
-		return;
-
-	/* 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)
-		usb_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)
-		usb_debug("Warning: usbhub: port enabling timed out.\n");
+	return buf[0] & PORT_CONNECTION;
+}
 
+static int
+usb_hub_port_in_reset(usbdev_t *const dev, const int port)
+{
+	unsigned short buf[2] = { 0, 0 };
 	get_status (dev, port, DR_PORT, 4, buf);
-	/* bit  10  9
-	 *      0   0  full speed
-	 *      0   1  low speed
-	 *      1   0  high speed
-	 */
-	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);
+	return buf[0] & PORT_RESET;
 }
 
 static int
-usb_hub_report_port_changes (usbdev_t *dev)
+usb_hub_port_enabled(usbdev_t *const dev, const int port)
 {
-	int port;
-	unsigned short buf[2];
-	for (port = 1; port <= HUB_INST (dev)->num_ports; port++) {
-		get_status (dev, port, DR_PORT, 4, buf);
-		if (buf[1] & C_PORT_CONNECTION)
-			return port;
-	}
-
-	// no change
-	return -1;
+	unsigned short buf[2] = { 0, 0 };
+	get_status (dev, port, DR_PORT, 4, buf);
+	return (buf[0] & PORT_ENABLE) != 0;
 }
 
-static void
-usb_hub_enable_port (usbdev_t *dev, int port)
+static int
+usb_hub_port_speed(usbdev_t *const dev, const int port)
 {
-	set_feature (dev, port, SEL_PORT_POWER, DR_PORT);
-	mdelay (20);
+	unsigned short buf[2] = { 0, 0 };
+	get_status (dev, port, DR_PORT, 4, buf);
+	if (buf[0] & PORT_ENABLE) {
+		/* bit  10  9
+		 *      0   0  full speed
+		 *      0   1  low speed
+		 *      1   0  high speed
+		 */
+		return (buf[0] >> 9) & 0x3;
+	} else {
+		return -1;
+	}
 }
 
-#if 0
-static void
-usb_hub_disable_port (usbdev_t *dev, int port)
+static int
+usb_hub_enable_port(usbdev_t *const dev, const int port)
 {
+	set_feature(dev, port, SEL_PORT_POWER, DR_PORT);
+	return 0;
 }
-#endif
 
-static void
-usb_hub_poll (usbdev_t *dev)
+static int
+usb_hub_start_port_reset(usbdev_t *const dev, const int port)
 {
-	int port;
-	while ((port = usb_hub_report_port_changes (dev)) != -1)
-		usb_hub_scanport (dev, port);
+	set_feature (dev, port, SEL_PORT_RESET, DR_PORT);
+	return 0;
 }
 
+static const generic_hub_ops_t usb_hub_ops = {
+	.hub_status_changed	= NULL,
+	.port_status_changed	= usb_hub_port_status_changed,
+	.port_connected		= usb_hub_port_connected,
+	.port_in_reset		= usb_hub_port_in_reset,
+	.port_enabled		= usb_hub_port_enabled,
+	.port_speed		= usb_hub_port_speed,
+	.enable_port		= usb_hub_enable_port,
+	.disable_port		= NULL,
+	.start_port_reset	= usb_hub_start_port_reset,
+	.reset_port		= generic_hub_resetport,
+};
+
 void
-usb_hub_init (usbdev_t *dev)
+usb_hub_init(usbdev_t *const dev)
 {
-	int i;
-	dev->destroy = usb_hub_destroy;
-	dev->poll = usb_hub_poll;
-
-	dev->data = malloc (sizeof (usbhub_inst_t));
-
-	if (!dev->data)
-		fatal("Not enough memory for USB hub.\n");
-
-	HUB_INST (dev)->descriptor = (hub_descriptor_t *) get_descriptor(dev,
-		gen_bmRequestType(device_to_host, class_type, dev_recp), 0x29, 0, 0);
-	HUB_INST (dev)->num_ports = HUB_INST (dev)->descriptor->bNbrPorts;
-	HUB_INST (dev)->ports =
-		malloc (sizeof (int) * (HUB_INST (dev)->num_ports + 1));
-	if (! HUB_INST (dev)->ports)
-		fatal("Not enough memory for USB hub ports.\n");
+	hub_descriptor_t *const descriptor = (hub_descriptor_t *)
+		get_descriptor(
+			dev,
+			gen_bmRequestType(device_to_host, class_type, dev_recp),
+			0x29, 0, 0);
+	if (!descriptor) {
+		usb_debug("usbhub: ERROR: Failed to fetch hub descriptor\n");
+		return;
+	}
+	const int num_ports = descriptor->bNbrPorts;
+	free(descriptor);
 
-	for (i = 1; i <= HUB_INST (dev)->num_ports; i++)
-		HUB_INST (dev)->ports[i] = -1;
-	for (i = 1; i <= HUB_INST (dev)->num_ports; i++)
-		usb_hub_enable_port (dev, i);
+	generic_hub_init(dev, num_ports, &usb_hub_ops);
 }



More information about the coreboot-gerrit mailing list