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 b0182d3c0e7e29581d837c449076d11f41a36358
Author: raiden00pl <[email protected]>
AuthorDate: Thu Aug 6 15:01:56 2026 +0200

    arch/nrf5x: fix USBD data OUT packet loss when no read request is queued
    
    A packet received while the request queue was empty was silently dropped
    and the transfer deadlocked. Hold it in the endpoint buffer until the
    class driver submits a read request.
    
    Signed-off-by: raiden00pl <[email protected]>
    Assisted-by: Claude Code
---
 arch/arm/src/nrf52/nrf52_usbd.c | 24 ++++++++++++++++++++++--
 arch/arm/src/nrf53/nrf53_usbd.c | 24 ++++++++++++++++++++++--
 2 files changed, 44 insertions(+), 4 deletions(-)

diff --git a/arch/arm/src/nrf52/nrf52_usbd.c b/arch/arm/src/nrf52/nrf52_usbd.c
index 2d0398b082c..fbffcec17e1 100644
--- a/arch/arm/src/nrf52/nrf52_usbd.c
+++ b/arch/arm/src/nrf52/nrf52_usbd.c
@@ -280,6 +280,8 @@ struct nrf52_usbdev_s
   uint16_t                dmaepoutwait;  /* EP OUT waitning for DMA */
   uint16_t                epinflight;    /* EP IN packet armed, awaiting
                                           * host read (EPDATASTATUS) */
+  uint16_t                epoutpending;  /* EP OUT packet held in endpoint
+                                          * buffer, no read request yet */
 
   /* E0 SETUP data buffering.
    *
@@ -1464,8 +1466,14 @@ static void nrf52_epout_handle(struct nrf52_usbdev_s 
*priv,
       privreq = nrf52_rqpeek(privep);
       if (!privreq)
         {
+          /* The packet is already ACKed and held in the endpoint buffer.
+           * The host will not retransmit it, so keep it pending until the
+           * class driver submits a read request.
+           */
+
           usbtrace(TRACE_DEVERROR(NRF52_TRACEERR_EPOUTQEMPTY),
                    privep->epphy);
+          priv->epoutpending |= (1 << privep->epphy);
           return;
         }
 
@@ -1663,6 +1671,7 @@ static void nrf52_usbreset(struct nrf52_usbdev_s *priv)
   priv->dmaepinwait = 0;
   priv->dmaepoutwait = 0;
   priv->epinflight  = 0;
+  priv->epoutpending = 0;
 
   /* Disable all end points */
 
@@ -2632,9 +2641,20 @@ static int nrf52_ep_submit(struct usbdev_ep_s *ep, 
struct usbdev_req_s *req)
             {
               usbtrace(TRACE_OUTREQQUEUED(privep->epphy), privreq->req.len);
 
-              /* Allow OUT traffic on this endpoint */
+              if (privep->epphy != EP0 &&
+                  (priv->epoutpending & (1 << privep->epphy)) != 0)
+                {
+                  /* Consume the packet held in the endpoint buffer */
 
-              nrf52_epout_allow(privep);
+                  priv->epoutpending &= ~(1 << privep->epphy);
+                  nrf52_epout_handle(priv, privep);
+                }
+              else
+                {
+                  /* Allow OUT traffic on this endpoint */
+
+                  nrf52_epout_allow(privep);
+                }
             }
         }
     }
diff --git a/arch/arm/src/nrf53/nrf53_usbd.c b/arch/arm/src/nrf53/nrf53_usbd.c
index b6e5a30542d..b4b99d00990 100644
--- a/arch/arm/src/nrf53/nrf53_usbd.c
+++ b/arch/arm/src/nrf53/nrf53_usbd.c
@@ -280,6 +280,8 @@ struct nrf53_usbdev_s
   uint16_t                dmaepoutwait;  /* EP OUT waitning for DMA */
   uint16_t                epinflight;    /* EP IN packet armed, awaiting
                                           * host read (EPDATASTATUS) */
+  uint16_t                epoutpending;  /* EP OUT packet held in endpoint
+                                          * buffer, no read request yet */
 
   /* E0 SETUP data buffering.
    *
@@ -1464,8 +1466,14 @@ static void nrf53_epout_handle(struct nrf53_usbdev_s 
*priv,
       privreq = nrf53_rqpeek(privep);
       if (!privreq)
         {
+          /* The packet is already ACKed and held in the endpoint buffer.
+           * The host will not retransmit it, so keep it pending until the
+           * class driver submits a read request.
+           */
+
           usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_EPOUTQEMPTY),
                    privep->epphy);
+          priv->epoutpending |= (1 << privep->epphy);
           return;
         }
 
@@ -1663,6 +1671,7 @@ static void nrf53_usbreset(struct nrf53_usbdev_s *priv)
   priv->dmaepinwait = 0;
   priv->dmaepoutwait = 0;
   priv->epinflight  = 0;
+  priv->epoutpending = 0;
 
   /* Disable all end points */
 
@@ -2632,9 +2641,20 @@ static int nrf53_ep_submit(struct usbdev_ep_s *ep, 
struct usbdev_req_s *req)
             {
               usbtrace(TRACE_OUTREQQUEUED(privep->epphy), privreq->req.len);
 
-              /* Allow OUT traffic on this endpoint */
+              if (privep->epphy != EP0 &&
+                  (priv->epoutpending & (1 << privep->epphy)) != 0)
+                {
+                  /* Consume the packet held in the endpoint buffer */
 
-              nrf53_epout_allow(privep);
+                  priv->epoutpending &= ~(1 << privep->epphy);
+                  nrf53_epout_handle(priv, privep);
+                }
+              else
+                {
+                  /* Allow OUT traffic on this endpoint */
+
+                  nrf53_epout_allow(privep);
+                }
             }
         }
     }

Reply via email to