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); + } } } }
