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 260603c4f0208d808c217e78beb6fe30b610d0f8
Author: Justin Hammond <[email protected]>
AuthorDate: Sat Aug 8 14:42:19 2026 +0800

    drivers/usbhost: Key an xHCI device by its port, not by the root port.
    
    The slot, the default control endpoint and the device context lived in
    struct xhci_rhport_s, and anything needing a device reached it as
    rhport->dev.  That holds only while every device is plugged straight into
    the controller; a hub puts several behind one root port, each with its own
    slot and context.
    
    Two keys replace it.  An endpoint records the slot it was opened on, so
    xhci_dev_from_ep() answers which device a transfer belongs to.  A hub port
    belongs to one device wherever it sits, so xhci_dev_from_hport() answers
    which device is on a port when there is no endpoint to ask yet.
    
    The functions converted here used both at once: xhci_ep0configure() issued
    Evaluate Context for epinfo->slot while filling in rhport->dev's context,
    and xhci_ctrl_xfer() reached the endpoint ring through the port and back.
    xhci_slot_init() read the speed and control ring through the port, which
    would fail quietly, since the slot context speed field has no valid zero
    and a low speed device behind a high speed hub does not share its speed.
    
    No functional change for a directly attached device: its port's slot and
    its endpoint's slot are the same, and its hub port is the root port's own.
    
    Assisted-by: Claude:claude-opus-5
    Signed-off-by: Justin Hammond <[email protected]>
---
 drivers/usbhost/usbhost_xhci.c | 112 ++++++++++++++++++++++++++++++-----------
 1 file changed, 84 insertions(+), 28 deletions(-)

diff --git a/drivers/usbhost/usbhost_xhci.c b/drivers/usbhost/usbhost_xhci.c
index 56d1642c24a..e09f01582c9 100644
--- a/drivers/usbhost/usbhost_xhci.c
+++ b/drivers/usbhost/usbhost_xhci.c
@@ -219,6 +219,13 @@ struct xhci_dev_s
   FAR struct xhci_input_dev_ctx_s *input;   /* Input Device Context. Input to 
xHC */
   FAR struct xhci_rhport_s        *rhport;  /* Root Hub Port associated with 
this device */
 
+  /* The port this device is attached to.  Several devices can share a root
+   * hub port once a hub is in between, so this, and not the port above, is
+   * what identifies a device to the class drivers.
+   */
+
+  FAR struct usbhost_hubport_s    *hport;
+
   /* Reference to allocated endpoints */
 
   FAR struct xhci_epinfo_s *epinfo[XHCI_MAX_ENDPOINTS];
@@ -1692,8 +1699,7 @@ static int xhci_slot_init(FAR struct usbhost_xhci_s *priv,
    */
 
   regval = XHCI_ST_CTX0_CTXENT_SET(1) |
-           XHCI_ST_CTX0_SPEED_SET(
-             xhci_speed_id(dev->rhport->hport.hport.speed));
+           XHCI_ST_CTX0_SPEED_SET(xhci_speed_id(dev->hport->speed));
 
 #ifdef CONFIG_USBHOST_HUB
   /* TODO:
@@ -1720,12 +1726,13 @@ static int xhci_slot_init(FAR struct usbhost_xhci_s 
*priv,
    * allocated.
    */
 
-  drdp = up_addrenv_va_to_pa(dev->rhport->ep0.td.ring);
+  DEBUGASSERT(dev->epinfo[0] != NULL);
+  drdp = up_addrenv_va_to_pa(dev->epinfo[0]->td.ring);
 
   /* Step 5. Initialize the Input default control Endpoint 0 Context */
 
-  DEBUGASSERT(dev->rhport != NULL);
-  if (dev->rhport->hport.hport.speed == USB_SPEED_HIGH)
+  DEBUGASSERT(dev->hport != NULL);
+  if (dev->hport->speed == USB_SPEED_HIGH)
     {
       /* For high-speed, we must use 64 bytes */
 
@@ -1848,6 +1855,7 @@ static int xhci_device_init(FAR struct usbhost_xhci_s 
*priv,
 
   rhport->ep0.slot = slot;
   dev->rhport      = rhport;
+  dev->hport       = &rhport->hport.hport;
   dev->slot        = slot;
   dev->epinfo[0]   = &rhport->ep0;
 
@@ -1931,6 +1939,7 @@ static int xhci_device_deinit(FAR struct usbhost_xhci_s 
*priv,
 
   /* Remove reference to a device slot */
 
+  rhport->dev->hport = NULL;
   rhport->dev = NULL;
 
   return OK;
@@ -2998,6 +3007,56 @@ xhci_out_slot(FAR struct xhci_dev_ctx_s *ctx)
   return (FAR struct xhci_slot_ctx_s *)ctx;
 }
 
+/****************************************************************************
+ * Name: xhci_dev_from_ep
+ *
+ * Description:
+ *   The device an endpoint belongs to.
+ *
+ *   An endpoint records the slot it was opened on, and the slot indexes the
+ *   device table, so this holds wherever the device sits.  The root hub port
+ *   does not: a class driver reaches the controller through the port it
+ *   descends from, and a hub puts several devices behind one such port.
+ *
+ ****************************************************************************/
+
+static inline FAR struct xhci_dev_s *
+xhci_dev_from_ep(FAR struct usbhost_xhci_s *priv,
+                 FAR struct xhci_epinfo_s *epinfo)
+{
+  DEBUGASSERT(epinfo->slot > 0 && epinfo->slot <= priv->no_slots);
+  return &priv->devs[epinfo->slot - 1];
+}
+
+/****************************************************************************
+ * Name: xhci_dev_from_hport
+ *
+ * Description:
+ *   The device attached to a hub port, or NULL if there is none.
+ *
+ *   Used where there is no endpoint to ask yet, which is the case when the
+ *   first one is being allocated.
+ *
+ ****************************************************************************/
+
+static FAR struct xhci_dev_s *
+xhci_dev_from_hport(FAR struct usbhost_xhci_s *priv,
+                    FAR struct usbhost_hubport_s *hport)
+{
+  uint8_t i;
+
+  for (i = 0; i < priv->no_slots; i++)
+    {
+      if (priv->devs[i].state != XHCI_SLOT_DISABLED &&
+          priv->devs[i].hport == hport)
+        {
+          return &priv->devs[i];
+        }
+    }
+
+  return NULL;
+}
+
 /****************************************************************************
  * Name: xhci_speed_id
  *
@@ -3876,42 +3935,44 @@ static int xhci_ep0configure(FAR struct 
usbhost_driver_s *drvr,
                              usbhost_ep_t ep0, uint8_t funcaddr,
                              uint8_t speed, uint16_t maxpacketsize)
 {
-  FAR struct xhci_rhport_s  *rhport = (FAR struct xhci_rhport_s *)drvr;
   FAR struct xhci_epinfo_s  *epinfo = (FAR struct xhci_epinfo_s *)ep0;
   FAR struct usbhost_xhci_s *priv   = XHCI_PRIV_FROM_DRVR(drvr);
+  FAR struct xhci_dev_s     *dev;
   uint64_t                   ctx;
   int                        ret;
 
   DEBUGASSERT(drvr != NULL && epinfo != NULL && maxpacketsize < 2048);
 
+  dev = xhci_dev_from_ep(priv, epinfo);
+
   ret = nxmutex_lock(&priv->lock);
   if (ret >= 0)
     {
       /* Update max packet size */
 
       FAR struct xhci_ep_ctx_s *ep0ctx =
-        xhci_in_ep(priv, rhport->dev->input, 0);
+        xhci_in_ep(priv, dev->input, 0);
 
       ep0ctx->ctx1 &= ~XHCI_EP_CTX1_MAXPKT_MASK;
       ep0ctx->ctx1 |= XHCI_EP_CTX1_MAXPKT(maxpacketsize);
 
       /* Add Slot Context and EP0 Context */
 
-      xhci_context_ctrl(priv, rhport->dev, 0,
+      xhci_context_ctrl(priv, dev, 0,
                         XHCI_IN_CTX1_A(XHCI_SLOT_FLAG) |
                         XHCI_IN_CTX1_A(XHCI_EP0_FLAG));
 
       /* Flush Device input context */
 
-      up_flush_dcache((uintptr_t)rhport->dev->input,
-                      (uintptr_t)rhport->dev->input +
+      up_flush_dcache((uintptr_t)dev->input,
+                      (uintptr_t)dev->input +
                       XHCI_INCTX_SIZE(priv));
 
       /* Free mutex before command execution */
 
       nxmutex_unlock(&priv->lock);
 
-      ctx = up_addrenv_va_to_pa(rhport->dev->input);
+      ctx = up_addrenv_va_to_pa(dev->input);
 
       uinfo("slot %d funcaddr %d speed %d maxpacket %d\n",
             epinfo->slot, funcaddr, speed, maxpacketsize);
@@ -4011,7 +4072,6 @@ static int xhci_epalloc(FAR struct usbhost_driver_s *drvr,
                         FAR usbhost_ep_t *ep)
 {
   FAR struct usbhost_xhci_s    *priv   = XHCI_PRIV_FROM_DRVR(drvr);
-  FAR struct xhci_rhport_s     *rhport = (FAR struct xhci_rhport_s *)drvr;
   FAR struct usbhost_hubport_s *hport;
   FAR struct xhci_epinfo_s     *epinfo;
   FAR struct xhci_dev_s        *dev;
@@ -4028,12 +4088,6 @@ static int xhci_epalloc(FAR struct usbhost_driver_s 
*drvr,
               && ep != NULL);
   hport = epdesc->hport;
 
-  /* Only the tracing alternative below and the hub logic further down use
-   * this, and a configuration may have neither.
-   */
-
-  UNUSED(hport);
-
   /* Terse output only if we are tracing */
 
 #ifdef CONFIG_USBHOST_TRACE
@@ -4073,16 +4127,16 @@ static int xhci_epalloc(FAR struct usbhost_driver_s 
*drvr,
 
   idx  = xhci_epno_get(epinfo);
   mask = XHCI_IN_CTX1_A(XHCI_EP_FLAG(idx));
-  dev  = rhport->dev;
+  dev  = xhci_dev_from_hport(priv, hport);
 
   /* There has to be a device to hang the endpoint off.  A port whose
    * enumeration failed is retried after its slot has been given back, so
-   * this can run for a root hub port with nothing behind it.
+   * this can run for a port with nothing behind it.
    */
 
   if (dev == NULL)
     {
-      uerr("no device on port %d\n", RHPNDX(rhport));
+      uerr("no device on port %d\n", hport->port);
       nxmutex_destroy(&epinfo->lock);
       nxsem_destroy(&epinfo->iocsem);
       kmm_free(epinfo);
@@ -4102,7 +4156,7 @@ static int xhci_epalloc(FAR struct usbhost_driver_s *drvr,
 
   /* Store slot ID for later */
 
-  epinfo->slot = rhport->slot;
+  epinfo->slot = dev->slot;
 
 #ifdef CONFIG_USBHOST_HUB
   if (hport->speed != USB_SPEED_HIGH)
@@ -4511,28 +4565,30 @@ static int xhci_ctrl_xfer(FAR struct usbhost_driver_s 
*drvr,
        * on control EP.
        */
 
-      xhci_ring_init(&rhport->dev->rhport->ep0.td, 0);
+      xhci_ring_init(&ep0info->td, 0);
 
       /* Issue SET_ADDRESS request */
 
       ret = xhci_address_set(priv, rhport, true);
       if (ret == OK)
         {
+          FAR struct xhci_dev_s *dev = xhci_dev_from_ep(priv, ep0info);
+
           /* The controller chose this address and wrote it into the
            * output context.  Invalidate before reading, or the stale
            * copy is used.
            */
 
-          up_invalidate_dcache((uintptr_t)rhport->dev->ctx,
-                               (uintptr_t)rhport->dev->ctx +
+          up_invalidate_dcache((uintptr_t)dev->ctx,
+                               (uintptr_t)dev->ctx +
                                XHCI_DEVCTX_SIZE(priv));
 
           /* Store USB Device Address assigned by xHCI */
 
           ep0info->devaddr =
-            XHCI_ST_CTX3_ADDR_GET(xhci_out_slot(rhport->dev->ctx)->ctx[3]);
-          xhci_in_slot(priv, rhport->dev->input)->ctx[3] =
-            xhci_out_slot(rhport->dev->ctx)->ctx[3];
+            XHCI_ST_CTX3_ADDR_GET(xhci_out_slot(dev->ctx)->ctx[3]);
+          xhci_in_slot(priv, dev->input)->ctx[3] =
+            xhci_out_slot(dev->ctx)->ctx[3];
         }
 
       nxmutex_unlock(&ep0info->lock);

Reply via email to