summaryrefslogtreecommitdiffstats
path: root/src/drivers/usb
diff options
context:
space:
mode:
authorMichael Brown2015-03-23 16:59:51 +0100
committerMichael Brown2015-03-23 17:21:13 +0100
commit9e88194655c7d074fb7eeab834db97353c47282d (patch)
tree9b451e999176a2aa082e36f314b537f7d5dda41a /src/drivers/usb
parent[usb] Reset endpoints without waiting for a new transfer to be enqueued (diff)
downloadipxe-9e88194655c7d074fb7eeab834db97353c47282d.tar.gz
ipxe-9e88194655c7d074fb7eeab834db97353c47282d.tar.xz
ipxe-9e88194655c7d074fb7eeab834db97353c47282d.zip
[usb] Add clear_tt() hub method to clear transaction translator buffer
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/drivers/usb')
-rw-r--r--src/drivers/usb/ehci.c24
-rw-r--r--src/drivers/usb/usbhub.c30
-rw-r--r--src/drivers/usb/usbhub.h33
-rw-r--r--src/drivers/usb/xhci.c20
4 files changed, 105 insertions, 2 deletions
diff --git a/src/drivers/usb/ehci.c b/src/drivers/usb/ehci.c
index 4436c982..83635f45 100644
--- a/src/drivers/usb/ehci.c
+++ b/src/drivers/usb/ehci.c
@@ -1022,7 +1022,7 @@ static void ehci_endpoint_close ( struct usb_endpoint *ep ) {
/* No way to prevent hardware from continuing to
* access the memory, so leak it.
*/
- DBGC ( ehci, "EHCI %p %s endpoint %d could not unschedule: "
+ DBGC ( ehci, "EHCI %p %s endpoint %02x could not unschedule: "
"%s\n", ehci, usb->name, ep->address, strerror ( rc ) );
return;
}
@@ -1217,7 +1217,7 @@ static void ehci_endpoint_poll ( struct ehci_endpoint *endpoint ) {
*/
if ( status & EHCI_STATUS_HALTED ) {
rc = -EIO_STATUS ( status );
- DBGC ( ehci, "EHCI %p %s endpoint %d completion %d "
+ DBGC ( ehci, "EHCI %p %s endpoint %02x completion %d "
"failed (status %02x): %s\n", ehci, usb->name,
ep->address, index, status, strerror ( rc ) );
while ( ! iobuf )
@@ -1497,6 +1497,25 @@ static int ehci_hub_speed ( struct usb_hub *hub, struct usb_port *port ) {
}
/**
+ * Clear transaction translator buffer
+ *
+ * @v hub USB hub
+ * @v port USB 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 ) {
+ struct ehci_device *ehci = usb_hub_get_drvdata ( hub );
+
+ /* Should never be called; this is a root hub */
+ DBGC ( ehci, "EHCI %p port %d nonsensical CLEAR_TT for %s endpoint "
+ "%02x\n", ehci, port->address, ep->usb->name, ep->address );
+
+ return -ENOTSUP;
+}
+
+/**
* Poll for port status changes
*
* @v hub USB hub
@@ -1706,6 +1725,7 @@ static struct usb_host_operations ehci_operations = {
.enable = ehci_hub_enable,
.disable = ehci_hub_disable,
.speed = ehci_hub_speed,
+ .clear_tt = ehci_hub_clear_tt,
},
};
diff --git a/src/drivers/usb/usbhub.c b/src/drivers/usb/usbhub.c
index a2841089..6d0cdba4 100644
--- a/src/drivers/usb/usbhub.c
+++ b/src/drivers/usb/usbhub.c
@@ -338,6 +338,35 @@ static int hub_speed ( struct usb_hub *hub, struct usb_port *port ) {
return 0;
}
+/**
+ * Clear transaction translator buffer
+ *
+ * @v hub USB hub
+ * @v port USB port
+ * @v ep USB endpoint
+ * @ret rc Return status code
+ */
+static int hub_clear_tt ( struct usb_hub *hub, struct usb_port *port,
+ struct usb_endpoint *ep ) {
+ struct usb_hub_device *hubdev = usb_hub_get_drvdata ( hub );
+ struct usb_device *usb = hubdev->usb;
+ int rc;
+
+ /* Clear transaction translator buffer. All hubs must support
+ * single-TT operation; we simplify our code by supporting
+ * only this configuration.
+ */
+ if ( ( rc = usb_hub_clear_tt_buffer ( usb, ep->usb->address,
+ ep->address, ep->attributes,
+ USB_HUB_TT_SINGLE ) ) != 0 ) {
+ DBGC ( hubdev, "HUB %s port %d could not clear TT buffer: %s\n",
+ hubdev->name, port->address, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
/** USB hub operations */
static struct usb_hub_driver_operations hub_operations = {
.open = hub_open,
@@ -345,6 +374,7 @@ static struct usb_hub_driver_operations hub_operations = {
.enable = hub_enable,
.disable = hub_disable,
.speed = hub_speed,
+ .clear_tt = hub_clear_tt,
};
/**
diff --git a/src/drivers/usb/usbhub.h b/src/drivers/usb/usbhub.h
index 0713e5bc..d7d8f961 100644
--- a/src/drivers/usb/usbhub.h
+++ b/src/drivers/usb/usbhub.h
@@ -129,6 +129,11 @@ struct usb_hub_port_status {
( USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE | \
USB_REQUEST_TYPE ( 12 ) )
+/** Clear transaction translator buffer */
+#define USB_HUB_CLEAR_TT_BUFFER \
+ ( USB_DIR_OUT | USB_TYPE_CLASS | USB_HUB_RECIP_PORT | \
+ USB_REQUEST_TYPE ( 8 ) )
+
/**
* Get hub descriptor
*
@@ -214,6 +219,34 @@ usb_hub_set_hub_depth ( struct usb_device *usb, unsigned int depth ) {
return usb_control ( usb, USB_HUB_SET_HUB_DEPTH, depth, 0, NULL, 0 );
}
+/**
+ * Clear transaction translator buffer
+ *
+ * @v usb USB device
+ * @v device Device address
+ * @v endpoint Endpoint address
+ * @v attributes Endpoint attributes
+ * @v tt_port Transaction translator port (or 1 for single-TT hubs)
+ * @ret rc Return status code
+ */
+static inline __attribute__ (( always_inline )) int
+usb_hub_clear_tt_buffer ( struct usb_device *usb, unsigned int device,
+ unsigned int endpoint, unsigned int attributes,
+ unsigned int tt_port ) {
+ unsigned int value;
+
+ /* Calculate value */
+ value = ( ( ( endpoint & USB_ENDPOINT_MAX ) << 0 ) | ( device << 4 ) |
+ ( ( attributes & USB_ENDPOINT_ATTR_TYPE_MASK ) << 11 ) |
+ ( ( endpoint & USB_ENDPOINT_IN ) << 8 ) );
+
+ return usb_control ( usb, USB_HUB_CLEAR_TT_BUFFER, value,
+ tt_port, NULL, 0 );
+}
+
+/** Transaction translator port value for single-TT hubs */
+#define USB_HUB_TT_SINGLE 1
+
/** A USB hub device */
struct usb_hub_device {
/** Name */
diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c
index a940a73a..69d621d9 100644
--- a/src/drivers/usb/xhci.c
+++ b/src/drivers/usb/xhci.c
@@ -2992,6 +2992,25 @@ static int xhci_hub_speed ( struct usb_hub *hub, struct usb_port *port ) {
return 0;
}
+/**
+ * Clear transaction translator buffer
+ *
+ * @v hub USB hub
+ * @v port USB 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 ) {
+ struct ehci_device *ehci = usb_hub_get_drvdata ( hub );
+
+ /* Should never be called; this is a root hub */
+ DBGC ( ehci, "XHCI %p port %d nonsensical CLEAR_TT for %s endpoint "
+ "%02x\n", ehci, port->address, ep->usb->name, ep->address );
+
+ return -ENOTSUP;
+}
+
/******************************************************************************
*
* PCI interface
@@ -3025,6 +3044,7 @@ static struct usb_host_operations xhci_operations = {
.enable = xhci_hub_enable,
.disable = xhci_hub_disable,
.speed = xhci_hub_speed,
+ .clear_tt = xhci_hub_clear_tt,
},
};