]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[usb] Add clear_tt() hub method to clear transaction translator buffer
authorMichael Brown <mcb30@ipxe.org>
Mon, 23 Mar 2015 15:59:51 +0000 (15:59 +0000)
committerMichael Brown <mcb30@ipxe.org>
Mon, 23 Mar 2015 16:21:13 +0000 (16:21 +0000)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/drivers/usb/ehci.c
src/drivers/usb/usbhub.c
src/drivers/usb/usbhub.h
src/drivers/usb/xhci.c
src/include/ipxe/usb.h

index 4436c9825a66080db202f1f54eb4cee521dc4b9c..83635f457e0a0e2e039b35362b6d60061db0bf1a 100644 (file)
@@ -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 )
@@ -1496,6 +1496,25 @@ static int ehci_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 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
  *
@@ -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,
        },
 };
 
index a28410892de7cf0f905fa17493b8b15c8409f938..6d0cdba454f052d377fdd7e31f121d763264f503 100644 (file)
@@ -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,
 };
 
 /**
index 0713e5bcce6bbd087176a497a47354c30b455615..d7d8f9610563df1d40dc4e53db75052669961e9a 100644 (file)
@@ -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 */
index a940a73a5b1cb52d2f98a26804555c06181b1477..69d621d9ca3d52c12bc5732aa18b641c2760bae5 100644 (file)
@@ -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,
        },
 };
 
index 5b95c20c98799cd8daea314a109f965dbcbeab64..ee4004e9c69ffebd9e79f42746d2a51c13090595 100644 (file)
@@ -820,6 +820,15 @@ struct usb_hub_driver_operations {
         * @ret rc              Return status code
         */
        int ( * 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
+        */
+       int ( * clear_tt ) ( struct usb_hub *hub, struct usb_port *port,
+                            struct usb_endpoint *ep );
 };
 
 /**