summaryrefslogtreecommitdiffstats
path: root/src/drivers/usb/xhci.c
diff options
context:
space:
mode:
authorMichael Brown2015-03-23 21:24:20 +0100
committerMichael Brown2015-03-23 21:24:20 +0100
commitf557794ab3ccae444653a25b889cc51d10e6f0c3 (patch)
tree2034d103fa624aec631180d201c3c4aa4a50607d /src/drivers/usb/xhci.c
parent[usb] Improve debug messages for failed control transactions (diff)
downloadipxe-f557794ab3ccae444653a25b889cc51d10e6f0c3.tar.gz
ipxe-f557794ab3ccae444653a25b889cc51d10e6f0c3.tar.xz
ipxe-f557794ab3ccae444653a25b889cc51d10e6f0c3.zip
[xhci] Support USB1 devices attached via transaction translators
xHCI provides a somewhat convoluted mechanism for specifying details of a transaction translator. Hubs must be marked as such in the device slot context. The only opportunity to do so is as part of a Configure Endpoint command, which can be executed only when opening the hub's interrupt endpoint. We add a mechanism for host controllers to intercept the opening of hub devices, providing xHCI with an opportunity to update the internal device slot structure for the corresponding USB device to indicate that the device is a hub. We then include the hub-specific details in the input context whenever any Configure Endpoint command is issued. When a device is opened, we record the device slot and port for its transaction translator (if any), and supply these as part of the Address Device command. Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/drivers/usb/xhci.c')
-rw-r--r--src/drivers/usb/xhci.c86
1 files changed, 73 insertions, 13 deletions
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,
},
};