aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/drivers/bus/usb.c23
-rw-r--r--src/drivers/usb/ehci.c59
-rw-r--r--src/drivers/usb/xhci.c86
-rw-r--r--src/drivers/usb/xhci.h6
-rw-r--r--src/include/ipxe/usb.h23
5 files changed, 164 insertions, 33 deletions
diff --git a/src/drivers/bus/usb.c b/src/drivers/bus/usb.c
index 1b610379..f53f7461 100644
--- a/src/drivers/bus/usb.c
+++ b/src/drivers/bus/usb.c
@@ -1692,6 +1692,7 @@ struct usb_hub * alloc_usb_hub ( struct usb_bus *bus, struct usb_device *usb,
hub->protocol = usb->port->protocol;
hub->ports = ports;
hub->driver = driver;
+ hub->host = &bus->op->hub;
/* Initialise port list */
for ( i = 1 ; i <= hub->ports ; i++ ) {
@@ -1721,11 +1722,18 @@ int register_usb_hub ( struct usb_hub *hub ) {
/* Add to hub list */
list_add_tail ( &hub->list, &bus->hubs );
- /* Open hub */
+ /* Open hub (host controller) */
+ if ( ( rc = hub->host->open ( hub ) ) != 0 ) {
+ DBGC ( hub, "USB hub %s could not open: %s\n",
+ hub->name, strerror ( rc ) );
+ goto err_host_open;
+ }
+
+ /* Open hub (driver) */
if ( ( rc = hub->driver->open ( hub ) ) != 0 ) {
DBGC ( hub, "USB hub %s could not open: %s\n",
hub->name, strerror ( rc ) );
- goto err_open;
+ goto err_driver_open;
}
/* Delay to allow ports to stabilise */
@@ -1747,7 +1755,9 @@ int register_usb_hub ( struct usb_hub *hub ) {
return 0;
hub->driver->close ( hub );
- err_open:
+ err_driver_open:
+ hub->host->close ( hub );
+ err_host_open:
list_del ( &hub->list );
return rc;
}
@@ -1768,9 +1778,12 @@ void unregister_usb_hub ( struct usb_hub *hub ) {
usb_detached ( port );
}
- /* Close hub */
+ /* Close hub (driver) */
hub->driver->close ( hub );
+ /* Close hub (host controller) */
+ hub->host->close ( hub );
+
/* Cancel any pending port status changes */
for ( i = 1 ; i <= hub->ports ; i++ ) {
port = usb_port ( hub, i );
@@ -1839,7 +1852,7 @@ struct usb_bus * alloc_usb_bus ( struct device *dev, unsigned int ports,
bus->host = &bus->op->bus;
/* Allocate root hub */
- bus->hub = alloc_usb_hub ( bus, NULL, ports, &op->hub );
+ bus->hub = alloc_usb_hub ( bus, NULL, ports, &op->root );
if ( ! bus->hub )
goto err_alloc_hub;
diff --git a/src/drivers/usb/ehci.c b/src/drivers/usb/ehci.c
index f912de35..4bff3fef 100644
--- a/src/drivers/usb/ehci.c
+++ b/src/drivers/usb/ehci.c
@@ -1332,6 +1332,35 @@ static int ehci_device_address ( struct usb_device *usb ) {
/******************************************************************************
*
+ * Hub operations
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open hub
+ *
+ * @v hub USB hub
+ * @ret rc Return status code
+ */
+static int ehci_hub_open ( struct usb_hub *hub __unused ) {
+
+ /* Nothing to do */
+ return 0;
+}
+
+/**
+ * Close hub
+ *
+ * @v hub USB hub
+ */
+static void ehci_hub_close ( struct usb_hub *hub __unused ) {
+
+ /* Nothing to do */
+}
+
+/******************************************************************************
+ *
* Root hub operations
*
******************************************************************************
@@ -1343,7 +1372,7 @@ static int ehci_device_address ( struct usb_device *usb ) {
* @v hub USB hub
* @ret rc Return status code
*/
-static int ehci_hub_open ( struct usb_hub *hub ) {
+static int ehci_root_open ( struct usb_hub *hub ) {
struct usb_bus *bus = hub->bus;
struct ehci_device *ehci = usb_bus_get_hostdata ( bus );
uint32_t portsc;
@@ -1374,7 +1403,7 @@ static int ehci_hub_open ( struct usb_hub *hub ) {
*
* @v hub USB hub
*/
-static void ehci_hub_close ( struct usb_hub *hub ) {
+static void ehci_root_close ( struct usb_hub *hub ) {
struct ehci_device *ehci = usb_hub_get_drvdata ( hub );
/* Route all ports back to companion controllers */
@@ -1391,7 +1420,7 @@ static void ehci_hub_close ( struct usb_hub *hub ) {
* @v port USB port
* @ret rc Return status code
*/
-static int ehci_hub_enable ( struct usb_hub *hub, struct usb_port *port ) {
+static int ehci_root_enable ( struct usb_hub *hub, struct usb_port *port ) {
struct ehci_device *ehci = usb_hub_get_drvdata ( hub );
uint32_t portsc;
unsigned int line;
@@ -1449,7 +1478,7 @@ static int ehci_hub_enable ( struct usb_hub *hub, struct usb_port *port ) {
* @v port USB port
* @ret rc Return status code
*/
-static int ehci_hub_disable ( struct usb_hub *hub, struct usb_port *port ) {
+static int ehci_root_disable ( struct usb_hub *hub, struct usb_port *port ) {
struct ehci_device *ehci = usb_hub_get_drvdata ( hub );
uint32_t portsc;
@@ -1468,7 +1497,7 @@ static int ehci_hub_disable ( struct usb_hub *hub, struct usb_port *port ) {
* @v port USB port
* @ret rc Return status code
*/
-static int ehci_hub_speed ( struct usb_hub *hub, struct usb_port *port ) {
+static int ehci_root_speed ( struct usb_hub *hub, struct usb_port *port ) {
struct ehci_device *ehci = usb_hub_get_drvdata ( hub );
uint32_t portsc;
unsigned int speed;
@@ -1512,8 +1541,8 @@ static int ehci_hub_speed ( struct usb_hub *hub, struct usb_port *port ) {
* @v ep USB endpoint
* @ret rc Return status code
*/
-static int ehci_hub_clear_tt ( struct usb_hub *hub, struct usb_port *port,
- struct usb_endpoint *ep ) {
+static int ehci_root_clear_tt ( struct usb_hub *hub, struct usb_port *port,
+ struct usb_endpoint *ep ) {
struct ehci_device *ehci = usb_hub_get_drvdata ( hub );
/* Should never be called; this is a root hub */
@@ -1529,7 +1558,7 @@ static int ehci_hub_clear_tt ( struct usb_hub *hub, struct usb_port *port,
* @v hub USB hub
* @v port USB port
*/
-static void ehci_hub_poll ( struct usb_hub *hub, struct usb_port *port ) {
+static void ehci_root_poll ( struct usb_hub *hub, struct usb_port *port ) {
struct ehci_device *ehci = usb_hub_get_drvdata ( hub );
uint32_t portsc;
uint32_t change;
@@ -1692,7 +1721,7 @@ static void ehci_bus_poll ( struct usb_bus *bus ) {
/* Iterate over all ports looking for status changes */
for ( i = 1 ; i <= ehci->ports ; i++ )
- ehci_hub_poll ( hub, usb_port ( hub, i ) );
+ ehci_root_poll ( hub, usb_port ( hub, i ) );
}
/* Report fatal errors */
@@ -1730,10 +1759,14 @@ static struct usb_host_operations ehci_operations = {
.hub = {
.open = ehci_hub_open,
.close = ehci_hub_close,
- .enable = ehci_hub_enable,
- .disable = ehci_hub_disable,
- .speed = ehci_hub_speed,
- .clear_tt = ehci_hub_clear_tt,
+ },
+ .root = {
+ .open = ehci_root_open,
+ .close = ehci_root_close,
+ .enable = ehci_root_enable,
+ .disable = ehci_root_disable,
+ .speed = ehci_root_speed,
+ .clear_tt = ehci_root_clear_tt,
},
};
diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c
index 69d621d9..b6ce7444 100644
--- a/src/drivers/usb/xhci.c
+++ b/src/drivers/usb/xhci.c
@@ -1990,6 +1990,8 @@ static void xhci_address_device_input ( struct xhci_device *xhci,
slot_ctx->info = cpu_to_le32 ( XHCI_SLOT_INFO ( 1, 0, slot->psiv,
slot->route ) );
slot_ctx->port = slot->port;
+ slot_ctx->tt_id = slot->tt_id;
+ slot_ctx->tt_port = slot->tt_port;
/* Populate control endpoint context */
ep_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_EP0 ) );
@@ -2039,7 +2041,7 @@ static inline int xhci_address_device ( struct xhci_device *xhci,
* @v input Input context
*/
static void xhci_configure_endpoint_input ( struct xhci_device *xhci,
- struct xhci_slot *slot __unused,
+ struct xhci_slot *slot,
struct xhci_endpoint *endpoint,
void *input ) {
struct xhci_control_context *control_ctx;
@@ -2054,7 +2056,9 @@ static void xhci_configure_endpoint_input ( struct xhci_device *xhci,
/* Populate slot context */
slot_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_SLOT ));
slot_ctx->info = cpu_to_le32 ( XHCI_SLOT_INFO ( ( XHCI_CTX_END - 1 ),
- 0, 0, 0 ) );
+ ( slot->ports ? 1 : 0 ),
+ slot->psiv, 0 ) );
+ slot_ctx->ports = slot->ports;
/* Populate endpoint context */
ep_ctx = ( input + xhci_input_context_offset ( xhci, endpoint->ctx ) );
@@ -2587,7 +2591,9 @@ static int xhci_endpoint_stream ( struct usb_endpoint *ep,
*/
static int xhci_device_open ( struct usb_device *usb ) {
struct xhci_device *xhci = usb_bus_get_hostdata ( usb->port->hub->bus );
+ struct usb_port *tt = usb_transaction_translator ( usb );
struct xhci_slot *slot;
+ struct xhci_slot *tt_slot;
size_t len;
int type;
int id;
@@ -2621,6 +2627,11 @@ static int xhci_device_open ( struct usb_device *usb ) {
slot->xhci = xhci;
slot->usb = usb;
slot->id = id;
+ if ( tt ) {
+ tt_slot = usb_get_hostdata ( tt->hub->usb );
+ slot->tt_id = tt_slot->id;
+ slot->tt_port = tt->address;
+ }
/* Allocate a device context */
len = xhci_device_context_offset ( xhci, XHCI_CTX_END );
@@ -2819,6 +2830,51 @@ static void xhci_bus_poll ( struct usb_bus *bus ) {
/******************************************************************************
*
+ * Hub operations
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Open hub
+ *
+ * @v hub USB hub
+ * @ret rc Return status code
+ */
+static int xhci_hub_open ( struct usb_hub *hub ) {
+ struct xhci_slot *slot;
+
+ /* Do nothing if this is the root hub */
+ if ( ! hub->usb )
+ return 0;
+
+ /* Get device slot */
+ slot = usb_get_hostdata ( hub->usb );
+
+ /* Update device slot hub parameters. We don't inform the
+ * hardware of this information until the hub's interrupt
+ * endpoint is opened, since the only mechanism for so doing
+ * provided by the xHCI specification is a Configure Endpoint
+ * command, and we can't issue that command until we have a
+ * non-EP0 endpoint to configure.
+ */
+ slot->ports = hub->ports;
+
+ return 0;
+}
+
+/**
+ * Close hub
+ *
+ * @v hub USB hub
+ */
+static void xhci_hub_close ( struct usb_hub *hub __unused ) {
+
+ /* Nothing to do */
+}
+
+/******************************************************************************
+ *
* Root hub operations
*
******************************************************************************
@@ -2830,7 +2886,7 @@ static void xhci_bus_poll ( struct usb_bus *bus ) {
* @v hub USB hub
* @ret rc Return status code
*/
-static int xhci_hub_open ( struct usb_hub *hub ) {
+static int xhci_root_open ( struct usb_hub *hub ) {
struct usb_bus *bus = hub->bus;
struct xhci_device *xhci = usb_bus_get_hostdata ( bus );
struct usb_port *port;
@@ -2880,7 +2936,7 @@ static int xhci_hub_open ( struct usb_hub *hub ) {
*
* @v hub USB hub
*/
-static void xhci_hub_close ( struct usb_hub *hub ) {
+static void xhci_root_close ( struct usb_hub *hub ) {
/* Clear hub driver private data */
usb_hub_set_drvdata ( hub, NULL );
@@ -2893,7 +2949,7 @@ static void xhci_hub_close ( struct usb_hub *hub ) {
* @v port USB port
* @ret rc Return status code
*/
-static int xhci_hub_enable ( struct usb_hub *hub, struct usb_port *port ) {
+static int xhci_root_enable ( struct usb_hub *hub, struct usb_port *port ) {
struct xhci_device *xhci = usb_hub_get_drvdata ( hub );
uint32_t portsc;
unsigned int i;
@@ -2930,7 +2986,7 @@ static int xhci_hub_enable ( struct usb_hub *hub, struct usb_port *port ) {
* @v port USB port
* @ret rc Return status code
*/
-static int xhci_hub_disable ( struct usb_hub *hub, struct usb_port *port ) {
+static int xhci_root_disable ( struct usb_hub *hub, struct usb_port *port ) {
struct xhci_device *xhci = usb_hub_get_drvdata ( hub );
uint32_t portsc;
@@ -2950,7 +3006,7 @@ static int xhci_hub_disable ( struct usb_hub *hub, struct usb_port *port ) {
* @v port USB port
* @ret rc Return status code
*/
-static int xhci_hub_speed ( struct usb_hub *hub, struct usb_port *port ) {
+static int xhci_root_speed ( struct usb_hub *hub, struct usb_port *port ) {
struct xhci_device *xhci = usb_hub_get_drvdata ( hub );
uint32_t portsc;
unsigned int psiv;
@@ -3000,8 +3056,8 @@ static int xhci_hub_speed ( struct usb_hub *hub, struct usb_port *port ) {
* @v ep USB endpoint
* @ret rc Return status code
*/
-static int xhci_hub_clear_tt ( struct usb_hub *hub, struct usb_port *port,
- struct usb_endpoint *ep ) {
+static int xhci_root_clear_tt ( struct usb_hub *hub, struct usb_port *port,
+ struct usb_endpoint *ep ) {
struct ehci_device *ehci = usb_hub_get_drvdata ( hub );
/* Should never be called; this is a root hub */
@@ -3041,10 +3097,14 @@ static struct usb_host_operations xhci_operations = {
.hub = {
.open = xhci_hub_open,
.close = xhci_hub_close,
- .enable = xhci_hub_enable,
- .disable = xhci_hub_disable,
- .speed = xhci_hub_speed,
- .clear_tt = xhci_hub_clear_tt,
+ },
+ .root = {
+ .open = xhci_root_open,
+ .close = xhci_root_close,
+ .enable = xhci_root_enable,
+ .disable = xhci_root_disable,
+ .speed = xhci_root_speed,
+ .clear_tt = xhci_root_clear_tt,
},
};
diff --git a/src/drivers/usb/xhci.h b/src/drivers/usb/xhci.h
index 5abb5caa..c5da48de 100644
--- a/src/drivers/usb/xhci.h
+++ b/src/drivers/usb/xhci.h
@@ -1110,6 +1110,12 @@ struct xhci_slot {
unsigned int port;
/** Protocol speed ID */
unsigned int psiv;
+ /** Number of ports (if this device is a hub) */
+ unsigned int ports;
+ /** Transaction translator slot ID */
+ unsigned int tt_id;
+ /** Transaction translator port */
+ unsigned int tt_port;
/** Endpoints, indexed by context ID */
struct xhci_endpoint *endpoint[XHCI_CTX_END];
};
diff --git a/src/include/ipxe/usb.h b/src/include/ipxe/usb.h
index 6f67e061..b3803cd1 100644
--- a/src/include/ipxe/usb.h
+++ b/src/include/ipxe/usb.h
@@ -777,6 +777,8 @@ struct usb_hub {
/** List of hubs */
struct list_head list;
+ /** Host controller operations */
+ struct usb_hub_host_operations *host;
/** Driver operations */
struct usb_hub_driver_operations *driver;
/** Driver private data */
@@ -789,7 +791,22 @@ struct usb_hub {
struct usb_port port[0];
};
-/** USB hub operations */
+/** USB hub host controller operations */
+struct usb_hub_host_operations {
+ /** Open hub
+ *
+ * @v hub USB hub
+ * @ret rc Return status code
+ */
+ int ( * open ) ( struct usb_hub *hub );
+ /** Close hub
+ *
+ * @v hub USB hub
+ */
+ void ( * close ) ( struct usb_hub *hub );
+};
+
+/** USB hub driver operations */
struct usb_hub_driver_operations {
/** Open hub
*
@@ -940,8 +957,10 @@ struct usb_host_operations {
struct usb_device_host_operations device;
/** Bus operations */
struct usb_bus_host_operations bus;
+ /** Hub operations */
+ struct usb_hub_host_operations hub;
/** Root hub operations */
- struct usb_hub_driver_operations hub;
+ struct usb_hub_driver_operations root;
};
/**