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++ ) {
/* 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 */
return 0;
hub->driver->close ( hub );
- err_open:
+ err_driver_open:
+ hub->host->close ( hub );
+ err_host_open:
list_del ( &hub->list );
return rc;
}
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 );
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;
return rc;
}
+/******************************************************************************
+ *
+ * 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
* @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;
*
* @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 */
* @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;
* @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;
* @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;
* @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 */
* @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;
/* 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 */
.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,
},
};
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 ) );
* @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;
/* 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 ) );
*/
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;
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 );
xhci_event_poll ( xhci );
}
+/******************************************************************************
+ *
+ * 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
* @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;
*
* @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 );
* @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;
* @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;
* @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;
* @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 */
.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,
},
};
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];
};
/** 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 */
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
*
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;
};
/**