ricardgb opened a new pull request, #19378:
URL: https://github.com/apache/nuttx/pull/19378
## Summary
Fixes three endpoint-handling bugs in the RP2040/RP2350 USB device driver
(`rp2040_usbdev.c`, and its line-for-line copy `rp23xx_usbdev.c`). Together
they
prevent CDC-NCM (and, for the second one, likely RNDIS) from working on these
controllers; with all three applied, a `CONFIG_NET_CDCNCM` gadget on a
Raspberry Pi Pico passes traffic in both directions with 0% packet loss.
The bugs were found by comparing the driver against the Pico SDK's TinyUSB
device controller driver (`dcd_rp2040.c` / `rp2040_usb.c`).
**1. Bulk OUT read length not clamped to the endpoint max packet size.**
`rp2040_epread()` armed the DPSRAM buffer-control register with the full
usbdev
request length. The buffer-control `LEN` field is only 10 bits (max 1023),
so a
class driver that posts a larger read request — cdcncm allocates a 16 KiB
NTB read
buffer — overflows `LEN` (`16384 & 0x3ff == 0`) and corrupts the neighbouring
control bits. The controller then completes the transfer immediately with
zero
bytes, forever, and no OUT data is ever received (cdcncm floods
`Wrong NTH SIGN, skblen 0`). The receive path already accumulates a request
across
multiple packets, so the buffer only ever needs to be armed for one max-size
packet. This matches the transmit path, which already chunks to
`ep.maxpacket`.
Bulk classes with small reads (cdcacm, usbmsc) were unaffected, which is why
the
defect only surfaced on cdcncm.
**2. An endpoint request resubmitted from its own completion callback is
armed
twice.** `rp2040_txcomplete()` / `rp2040_rxcomplete()` unconditionally
started the
next transfer after invoking a request's completion callback. When that
callback
resubmits a request on the same, now-idle endpoint — which cdcncm and rndis
do from
their notify/interrupt completion handlers — `rp2040_epsubmit()` already
armed the
hardware buffer, and the unconditional re-arm toggles the DATA0/DATA1 PID a
second
time. The host discards the packet as a stale retransmission, so e.g. the
cdcncm
`NETWORK_CONNECTION` / `SPEED_CHANGE` notifications never arrive and the
interface
stays `NO-CARRIER`. A per-request `armed` flag now guards the redundant
re-arm.
This is also the likely cause of the long-standing rndis control-response
`-110`
timeout on this controller.
**3. Buffer `AVAILABLE` bit written together with length/PID.** The RP2040
datasheet
§4.1.2.5.1 requires the `AVAILABLE` bit to be set *after* the rest of buffer
control
and after a short settle, because buffer control crosses into the USB clock
domain.
`rp2040_update_buffer_control()` wrote the whole word at once. Now it writes
the
control word with `AVAILABLE` cleared, waits ~12 CPU cycles, then sets
`AVAILABLE`
— the sequence the datasheet and the Pico SDK use.
## Impact
- **CDC-NCM** now works on RP2040/RP2350 (previously enumerated but never
passed
data). Likely also fixes **RNDIS** (bug 2).
- No functional change for bulk classes that already worked (cdcacm, usbmsc)
— their
read lengths already fit in `LEN` and they don't resubmit from completion
callbacks.
- Applies to both `rp2040_usbdev.c` and `rp23xx_usbdev.c` (RP2350), which is
a
byte-identical copy of the affected functions.
## Testing
Built and run on a Raspberry Pi Pico (RP2040), Linux host:
- **CDC-NCM, all three fixes:** `ping` 20/20 host→board and 4/4 board→host,
0% loss,
ARP resolves, board `REACHABLE`. Before the fixes the board received
nothing
(`Wrong NTH SIGN, skblen 0` flood).
- **Bug 2 in isolation** confirmed with `usbmon`: the cdcncm interrupt-IN
`SPEED_CHANGE` notification now completes and reaches the host
(`C Ii:3:NN:1 0:4 16 = a12a...`); previously it never did.
- **No regression** on cdcacm / usbmsc.
RP2350: the affected functions in `rp23xx_usbdev.c` are byte-identical to
their
RP2040 counterparts and the change compiles cleanly for
`raspberrypi-pico-2`, but it
was not separately re-tested on RP2350 silicon.
Host-side note for reviewers reproducing this: NuttX gadgets ship with the
Linux-gadget VID/PID `0525:a4a2`, which is also claimed by the host
`cdc_subset`
driver; if `cdc_subset` binds the data interface first you'll see
`cdc_ncm: failed to claim data intf`. Force NCM with
`echo 3-1:1.1 > /sys/bus/usb/drivers/cdc_subset/unbind; echo 3-1:1.0 >
/sys/bus/usb/drivers/cdc_ncm/bind`.
---
*Disclosure: this change — the code, its validation, and this description —
was
produced by an AI agent (Claude Code), operated and directed by me, and
reviewed by
me before submission.*
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]