Skip to content

usbdev: re-assert soft connect in cdcecm/cdcncm disconnect()#19371

Open
ricardgb wants to merge 2 commits into
apache:masterfrom
ricardgb:usbdev-cdcecm-reconnect
Open

usbdev: re-assert soft connect in cdcecm/cdcncm disconnect()#19371
ricardgb wants to merge 2 commits into
apache:masterfrom
ricardgb:usbdev-cdcecm-reconnect

Conversation

@ricardgb

@ricardgb ricardgb commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary

USB device controller drivers invoke CLASS_DISCONNECT() on every USB bus reset, and a bus reset is the first step of normal host enumeration. Every other class driver (cdcacm, usbmsc, rndis) re-asserts DEV_CONNECT() at the end of its disconnect() handler ("perform the soft connect function so that we can be re-enumerated"), so on controllers that soft-disconnect around bus reset the pull-up glitch is microseconds long and invisible to the host. cdcecm_disconnect() and cdcncm_disconnect() did not, so the first bus reset of enumeration leaves a standalone CDC-ECM or CDC-NCM device soft-disconnected and it never appears on the host. On RP2040, rp2040_usbintr_busreset() explicitly drops the pull-up, so a standalone device never enumerates at all.

This mirrors the cdcacm behavior and performs the soft connect in both disconnect() methods, unless part of a composite device (composite.c already re-connects in its own disconnect handler).

Addresses the standalone CDC-ECM case of #15880 (root-cause analysis in this comment).

Impact

Standalone (non-composite) CDC-ECM and CDC-NCM devices become able to enumerate on controllers that call CLASS_DISCONNECT() on bus reset. Composite configurations are unaffected (the added call is guarded by !CONFIG_CDCECM_COMPOSITE / !CONFIG_CDCNCM_COMPOSITE). Other class drivers are unaffected; this makes cdcecm/cdcncm consistent with the existing cdcacm/usbmsc/rndis convention.

Testing

Validated on raspberrypi-pico (RP2040, arm-none-eabi-gcc 13.2, no new warnings):

  • CDC-ECM (standalone CONFIG_NET_CDCECM): before this change the device never appears on a Linux host (no enumeration at all); with this change it enumerates via cdc_ether and ICMP ping across the link runs at 0% loss (~0.5 ms RTT).
  • CDC-NCM (standalone CONFIG_NET_CDCNCM): before this change the device never attaches; with this change it enumerates and binds the host cdc_ncm driver. (Full NCM datapath on RP2040 is blocked by a separate, pre-existing interrupt-IN endpoint delivery issue that also affects other classes on this controller; under separate investigation.)

Disclosure

This root-cause analysis, patch, and hardware validation were performed by an AI agent (Claude Code, operated and directed by the submitter), and the result was reviewed by the submitter before posting.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AHJRvWeBMTHwzpwjaUg4HW

The USB device controller drivers invoke CLASS_DISCONNECT() on every
USB bus reset, and a bus reset is the first step of normal host
enumeration.  Every other class driver (cdcacm, usbmsc, rndis)
re-asserts DEV_CONNECT() at the end of its disconnect() handler so
that the device remains attached; cdcecm and cdcncm did not, so on
controllers that soft-disconnect around bus reset (e.g. rp2040, which
drops the pull-up in its bus-reset handler) a standalone CDC-ECM or
CDC-NCM device is left soft-disconnected by the first bus reset and
never enumerates on the host.

Mirror the cdcacm behavior and perform the soft connect in the
disconnect() methods, unless part of a composite device (composite.c
already re-connects in its own disconnect handler).

Fixes the standalone CDC-ECM case of issue apache#15880.

Validated on raspberrypi-pico (RP2040): with this change a standalone
CONFIG_NET_CDCECM device that previously never appeared on the host
enumerates via cdc_ether and pings with 0% loss.  cdcncm has the
identical defect and receives the identical fix.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AHJRvWeBMTHwzpwjaUg4HW
@github-actions github-actions Bot added Size: S The size of the change in this PR is small Area: USB labels Jul 8, 2026
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

@linguini1 linguini1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you include some logs to verify your test claims?

@ricardgb

ricardgb commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

Sure — here are before/after logs.

Setup: raspberrypi-pico (RP2040), Linux host. Built standalone CONFIG_NET_CDCECM (and separately CONFIG_NET_CDCNCM). The rp2040 board doesn't instantiate these classes by default, so I added a cdcecm_initialize() / cdcncm_initialize() call in the board bringup purely to exercise the driver (test scaffolding, not part of this PR). Relevant detail: rp2040_usbintr_busreset() drops the D+ pull-up on every bus reset, which is exactly what makes the missing re-connect fatal on this controller.

CDC-ECM — without the fix (baseline)

After the board is flashed and reboots into NuttX, the device never enumerates:

usb 3-1: USB disconnect, device number 55     # bootloader gone; board reboots into NuttX
                                               # ... and nothing further: the CDC-ECM device never appears
host: no cdc_ether interface
host: lsusb | grep -i cdc  ->  (no CDC device)

CDC-ECM — with the fix

usb 3-1: New USB device found, idVendor=0525, idProduct=a4a2, bcdDevice= 1.00
usb 3-1: Product: CDC/ECM Ethernet
usb 3-1: Manufacturer: NuttX
cdc_ether 3-1:1.0 usb0: register 'cdc_ether' at usb-0000:00:14.0-1, CDC Ethernet Device, 02:00:00:11:22:33
$ ping -c 4 192.168.7.1
64 bytes from 192.168.7.1: icmp_seq=1 ttl=64 time=0.959 ms
64 bytes from 192.168.7.1: icmp_seq=2 ttl=64 time=0.550 ms
64 bytes from 192.168.7.1: icmp_seq=3 ttl=64 time=0.585 ms
64 bytes from 192.168.7.1: icmp_seq=4 ttl=64 time=0.535 ms

--- 192.168.7.1 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3061ms
rtt min/avg/max/mdev = 0.535/0.657/0.959/0.175 ms

CDC-NCM — with the fix

Same one-liner in cdcncm_disconnect(). The device now enumerates and the host binds cdc_ncm (it previously never attached at all):

usb 3-1: New USB device found, idVendor=0525, idProduct=a4a2, bcdDevice= 1.00
usb 3-1: Product: CDC/NCM Ethernet
usb 3-1: Manufacturer: NuttX
cdc_ncm 3-1:1.0: MAC-Address: 02:00:00:11:22:33
cdc_ncm 3-1:1.0 usb0: register 'cdc_ncm' at usb-0000:00:14.0-1, CDC NCM (NO ZLP), 02:00:00:11:22:33

The NCM interface comes up NO-CARRIER due to the separate, pre-existing interrupt-IN endpoint issue on this controller that I noted in the PR description (out of scope here). The part this fix restores — enumeration and driver binding — works.


Disclosure: these logs, and the fix and its validation, were produced by an AI agent (Claude Code, operated and directed by me) and reviewed by me before posting.

@xiaoxiang781216

Copy link
Copy Markdown
Contributor

please fix:

746458f4ab usbdev: re-assert soft connect in cdcecm/cdcncm disconnect()
../nuttx/tools/checkpatch.sh -c -u -m -g  1fc6f2bac89771a6d4586789998d94e4cc1f20ef..HEAD
❌ Missing Signed-off-by
Used config files:
    1: .codespellrc
Some checks failed. For contributing guidelines, see:
  https://github.com/apache/nuttx/blob/master/CONTRIBUTING.md
Error: Process completed with exit code 1.

Comment thread drivers/usbdev/cdcecm.c
{
uinfo("\n");

/* Perform the soft connect function so that we will we can be

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/* Perform the soft connect function so that we will we can be
/* Perform the soft connect function so that we can be

Comment thread drivers/usbdev/cdcncm.c Outdated
Co-authored-by: Xiang Xiao <xiaoxiang781216@gmail.com>
@ricardgb

Copy link
Copy Markdown
Contributor Author

please fix:

746458f4ab usbdev: re-assert soft connect in cdcecm/cdcncm disconnect()
../nuttx/tools/checkpatch.sh -c -u -m -g  1fc6f2bac89771a6d4586789998d94e4cc1f20ef..HEAD
❌ Missing Signed-off-by
Used config files:
    1: .codespellrc
Some checks failed. For contributing guidelines, see:
  https://github.com/apache/nuttx/blob/master/CONTRIBUTING.md
Error: Process completed with exit code 1.

are you happy for me to squash your suggestion into my commit and re-sign both

@xiaoxiang781216

Copy link
Copy Markdown
Contributor

please fix:

746458f4ab usbdev: re-assert soft connect in cdcecm/cdcncm disconnect()
../nuttx/tools/checkpatch.sh -c -u -m -g  1fc6f2bac89771a6d4586789998d94e4cc1f20ef..HEAD
❌ Missing Signed-off-by
Used config files:
    1: .codespellrc
Some checks failed. For contributing guidelines, see:
  https://github.com/apache/nuttx/blob/master/CONTRIBUTING.md
Error: Process completed with exit code 1.

are you happy for me to squash your suggestion into my commit and re-sign both

yes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: USB Size: S The size of the change in this PR is small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants