This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 9af654038104f4e8df4d4d71b088937c75acc815
Author: Justin Hammond <[email protected]>
AuthorDate: Sat Aug 8 14:42:38 2026 +0800

    drivers/usbhost: Describe a device behind a hub to the xHCI controller.
    
    A controller reaches a device by the path to it and, for a slow device,
    through the hub that translates for it.  Neither was described, so a
    device behind a hub was addressed as though it were on the root port.
    
    The route string is that path: each hub between the device and the root
    contributes a nibble holding the port the next thing down occupies, tier
    nearest the root in the lowest nibble.  Walking up from the device reaches
    the deepest tier first, so shifting left by a nibble each time leaves them
    in the order the field wants.  The walk stops after five, which is what
    the field holds and what USB allows, and a port above fifteen is clamped.
    
    Slot context dword 2 names the transaction translator carrying a low or
    full speed device behind a high speed hub.  It reports the hub by slot,
    where EHCI reports it by USB address, and it names the nearest high speed
    ancestor rather than the immediate parent, since a full speed hub below a
    high speed one is itself carried by the translator above it.  The think
    time comes from the hub descriptor by way of the hub class driver, in the
    same units.
    
    xhci_epalloc() carried a copy of sam_ehci.c's block, writing
    epinfo->hubaddr and epinfo->hubport, which is how EHCI describes a split
    transaction in its queue head.  This driver never read either field, and
    xHCI wants the information in the slot context.  Both fields and the code
    setting them are removed.
    
    Multi-TT is not set, for the reason given in the previous commit.
    
    No functional change: hubs cannot be enabled yet, and a device on a root
    port has neither hubs above it nor a translator.
    
    Assisted-by: Claude:claude-opus-5
    Signed-off-by: Justin Hammond <[email protected]>
---
 drivers/usbhost/usbhost_xhci.c | 162 ++++++++++++++++++++++++++++++++---------
 drivers/usbhost/usbhost_xhci.h |  21 ++++++
 2 files changed, 149 insertions(+), 34 deletions(-)

diff --git a/drivers/usbhost/usbhost_xhci.c b/drivers/usbhost/usbhost_xhci.c
index e09f01582c9..b99191349db 100644
--- a/drivers/usbhost/usbhost_xhci.c
+++ b/drivers/usbhost/usbhost_xhci.c
@@ -176,13 +176,6 @@ struct xhci_epinfo_s
 #endif
   struct xhci_ring_s td;           /* TD ring for this endpoint */
   uint8_t            slot;         /* Slot where this EP resides */
-
-  /* These fields are used in the split-transaction protocol. */
-
-  uint8_t           hubaddr;      /* USB device address of the high-speed hub 
below
-                                   * which a full/low-speed device is attached.
-                                   */
-  uint8_t           hubport;      /* The port on the above high-speed hub. */
 };
 
 /* This structure retains the state of one root hub port */
@@ -394,6 +387,11 @@ static int xhci_address_set(FAR struct usbhost_xhci_s 
*priv,
                             FAR struct xhci_rhport_s *rhport, bool setaddr);
 static int xhci_slot_init(FAR struct usbhost_xhci_s *priv,
                           FAR struct xhci_dev_s *dev);
+#ifdef CONFIG_USBHOST_HUB
+static uint32_t xhci_route_string(FAR struct usbhost_hubport_s *hport);
+static uint32_t xhci_slot_tt(FAR struct usbhost_xhci_s *priv,
+                             FAR struct xhci_dev_s *dev);
+#endif
 static int xhci_device_init(FAR struct usbhost_xhci_s *priv,
                             FAR struct xhci_rhport_s *rhport);
 static int xhci_device_deinit(FAR struct usbhost_xhci_s *priv,
@@ -1702,10 +1700,11 @@ static int xhci_slot_init(FAR struct usbhost_xhci_s 
*priv,
            XHCI_ST_CTX0_SPEED_SET(xhci_speed_id(dev->hport->speed));
 
 #ifdef CONFIG_USBHOST_HUB
+  regval |= XHCI_ST_CTX0_RTSTR_SET(xhci_route_string(dev->hport));
+
   /* TODO:
    *   1. Activate the transaction translator if required
    *   2. Configure hub bit in slot context if hub
-   *   3. configure route string
    */
 
 #  warning missing logic
@@ -1722,6 +1721,10 @@ static int xhci_slot_init(FAR struct usbhost_xhci_s 
*priv,
   regval |= XHCI_ST_CTX1_PORTS_SET(0);
   xhci_in_slot(priv, dev->input)->ctx[1] = htole32(regval);
 
+#ifdef CONFIG_USBHOST_HUB
+  xhci_in_slot(priv, dev->input)->ctx[2] = htole32(xhci_slot_tt(priv, dev));
+#endif
+
   /* Step 4. the Transfer Ring for the Default Control Endpoint is already
    * allocated.
    */
@@ -3039,6 +3042,58 @@ xhci_dev_from_ep(FAR struct usbhost_xhci_s *priv,
  *
  ****************************************************************************/
 
+#ifdef CONFIG_USBHOST_HUB
+/****************************************************************************
+ * Name: xhci_route_string
+ *
+ * Description:
+ *   The route string for a device, which is how the controller finds it.
+ *
+ *   Each hub between the root and the device contributes one nibble holding
+ *   the number of the port the next thing down is plugged into, with the
+ *   tier nearest the root in the lowest nibble.  A device on a root hub port
+ *   routes to zero, which is what the field means for "no hubs in between".
+ *
+ *   Reference:
+ *     - 8.9: Route String Field
+ *
+ ****************************************************************************/
+
+static uint32_t xhci_route_string(FAR struct usbhost_hubport_s *hport)
+{
+  uint32_t route = 0;
+  int      tier  = 0;
+
+  /* Walking up reaches the deepest tier first, and shifting what is already
+   * there left by a nibble each time leaves the tier nearest the root in the
+   * lowest one.  USB allows five tiers of hubs and the field holds exactly
+   * that many, so a chain longer than the bus permits stops here rather than
+   * writing over the speed field above it.
+   */
+
+  while (hport->parent != NULL && tier < 5)
+    {
+      uint8_t portno = hport->port + 1;
+
+      /* The nibble cannot express a port above fifteen.  A hub that large
+       * is legal, so clamp rather than let the number wrap into the tier
+       * below it.
+       */
+
+      if (portno > 15)
+        {
+          portno = 15;
+        }
+
+      route = (route << 4) | portno;
+      hport = hport->parent;
+      tier++;
+    }
+
+  return route;
+}
+#endif
+
 static FAR struct xhci_dev_s *
 xhci_dev_from_hport(FAR struct usbhost_xhci_s *priv,
                     FAR struct usbhost_hubport_s *hport)
@@ -3057,6 +3112,71 @@ xhci_dev_from_hport(FAR struct usbhost_xhci_s *priv,
   return NULL;
 }
 
+#ifdef CONFIG_USBHOST_HUB
+/****************************************************************************
+ * Name: xhci_slot_tt
+ *
+ * Description:
+ *   Slot context dword 2, naming the transaction translator that carries a
+ *   low or full speed device behind a high speed hub.  Zero when no
+ *   translator is involved, which is what the field means.
+ *
+ *   Reference:
+ *     - 6.2.2: Slot Context
+ *
+ ****************************************************************************/
+
+static uint32_t xhci_slot_tt(FAR struct usbhost_xhci_s *priv,
+                             FAR struct xhci_dev_s *dev)
+{
+  FAR struct usbhost_hubport_s *hport = dev->hport;
+  FAR struct xhci_dev_s        *tthub;
+
+  /* Only a low or full speed device is translated for. */
+
+  if (hport->speed == USB_SPEED_HIGH)
+    {
+      return 0;
+    }
+
+  /* The translator lives in the nearest high speed ancestor, which need not
+   * be the hub the device is plugged into: a full speed hub below a high
+   * speed one is itself carried by the translator above it.
+   */
+
+  while (hport->parent != NULL && hport->parent->speed != USB_SPEED_HIGH)
+    {
+      hport = hport->parent;
+    }
+
+  if (hport->parent == NULL)
+    {
+      /* Nothing high speed above, so the device is on a root hub port or
+       * the whole chain runs at its speed.  Either way there is no
+       * translator to name.
+       */
+
+      return 0;
+    }
+
+  tthub = xhci_dev_from_hport(priv, hport->parent);
+  if (tthub == NULL)
+    {
+      uerr("no device for the hub carrying port %d\n", hport->port);
+      return 0;
+    }
+
+  /* Think time is the hub's, reported by the hub class driver from the hub
+   * descriptor.  Both fields count in the same units, so the value carries
+   * across unchanged.
+   */
+
+  return XHCI_ST_CTX2_TTHSID_SET(tthub->slot) |
+         XHCI_ST_CTX2_TTPORT_SET(hport->port + 1) |
+         XHCI_ST_CTX2_TTT_SET(hport->parent->ttt);
+}
+#endif
+
 /****************************************************************************
  * Name: xhci_speed_id
  *
@@ -4158,32 +4278,6 @@ static int xhci_epalloc(FAR struct usbhost_driver_s 
*drvr,
 
   epinfo->slot = dev->slot;
 
-#ifdef CONFIG_USBHOST_HUB
-  if (hport->speed != USB_SPEED_HIGH)
-    {
-      /* A high speed hub exists between this device and the root hub
-       * otherwise we would not get here.
-       */
-
-      FAR struct usbhost_hubport_s *parent = hport->parent;
-
-      for (; parent->speed != USB_SPEED_HIGH; parent = hport->parent)
-        {
-          hport = parent;
-        }
-
-      if (parent->speed == USB_SPEED_HIGH)
-        {
-          epinfo->hubport = HPORT(hport);
-          epinfo->hubaddr = hport->parent->funcaddr;
-        }
-      else
-        {
-          return -EINVAL;
-        }
-    }
-#endif
-
   /* Get EP type */
 
   switch (epinfo->xfrtype)
diff --git a/drivers/usbhost/usbhost_xhci.h b/drivers/usbhost/usbhost_xhci.h
index 3339721895d..157e07a9db4 100644
--- a/drivers/usbhost/usbhost_xhci.h
+++ b/drivers/usbhost/usbhost_xhci.h
@@ -504,6 +504,8 @@
 
 #define XHCI_ST_CTX0_RTSTR_SHIFT     (0)                   /* Bits 0:19: Route 
String */
 #define XHCI_ST_CTX0_RTSTR_MASK      (0xfffff << XHCI_ST_CTX0_RTSTR_SHIFT)
+#define XHCI_ST_CTX0_RTSTR_SET(x)    (((x) << XHCI_ST_CTX0_RTSTR_SHIFT) & \
+                                      XHCI_ST_CTX0_RTSTR_MASK)
 #define XHCI_ST_CTX0_SPEED_SHIFT     (20)                  /* Bits 20:23: 
Speed */
 #define XHCI_ST_CTX0_SPEED_MASK      (0xf << XHCI_ST_CTX0_SPEED_SHIFT)
 #define XHCI_ST_CTX0_SPEED_SET(x)    (((x) << XHCI_ST_CTX0_SPEED_SHIFT) & \
@@ -535,6 +537,25 @@
 #define XHCI_ST_CTX1_PORTS_MASK      (0xff << XHCI_ST_CTX1_PORTS_SHIFT)
 #define XHCI_ST_CTX1_PORTS_SET(x)    (((x) << XHCI_ST_CTX1_PORTS_SHIFT) & 
XHCI_ST_CTX1_PORTS_MASK)
 
+/* Slot Context dword 2 describes the transaction translator that carries a
+ * low or full speed device sitting behind a high speed hub.  It names the
+ * nearest high speed ancestor, which is the hub whose TT does the work, and
+ * not the hub the device is plugged into if those differ.
+ */
+
+#define XHCI_ST_CTX2_TTHSID_SHIFT    (0)                  /* Bit 0-7: TT Hub 
Slot ID */
+#define XHCI_ST_CTX2_TTHSID_MASK     (0xff << XHCI_ST_CTX2_TTHSID_SHIFT)
+#define XHCI_ST_CTX2_TTHSID_SET(x)   (((x) << XHCI_ST_CTX2_TTHSID_SHIFT) & \
+                                      XHCI_ST_CTX2_TTHSID_MASK)
+#define XHCI_ST_CTX2_TTPORT_SHIFT    (8)                  /* Bit 8-15: TT Port 
Number */
+#define XHCI_ST_CTX2_TTPORT_MASK     (0xff << XHCI_ST_CTX2_TTPORT_SHIFT)
+#define XHCI_ST_CTX2_TTPORT_SET(x)   (((x) << XHCI_ST_CTX2_TTPORT_SHIFT) & \
+                                      XHCI_ST_CTX2_TTPORT_MASK)
+#define XHCI_ST_CTX2_TTT_SHIFT       (16)                 /* Bit 16-17: TT 
Think Time */
+#define XHCI_ST_CTX2_TTT_MASK        (0x3 << XHCI_ST_CTX2_TTT_SHIFT)
+#define XHCI_ST_CTX2_TTT_SET(x)      (((x) << XHCI_ST_CTX2_TTT_SHIFT) & \
+                                      XHCI_ST_CTX2_TTT_MASK)
+
 #define XHCI_ST_CTX3_ADDR_SHIFT      (0)                  /* Bit 0-7: USB 
Device Address */
 #define XHCI_ST_CTX3_ADDR_MASK       (0xff << XHCI_ST_CTX3_ADDR_SHIFT)
 #define XHCI_ST_CTX3_ADDR_SET(x)     (((x) << XHCI_ST_CTX3_ADDR_SHIFT) & 
XHCI_ST_CTX3_ADDR_MASK)

Reply via email to