Skip to content

Add USB CDC-ECM Host support#18815

Open
dlizewski wants to merge 2 commits intoapache:masterfrom
dlizewski:feature/dl.usbecm
Open

Add USB CDC-ECM Host support#18815
dlizewski wants to merge 2 commits intoapache:masterfrom
dlizewski:feature/dl.usbecm

Conversation

@dlizewski
Copy link
Copy Markdown

@dlizewski dlizewski commented Apr 27, 2026

Summary

  • Added support for USB CDC-ECM host class. This host class is used for many USB-Ethernet adaptors as well as USB modems.
  • I also added support to select different configurations since the USB-Ethernet adaptor I have only presents CDC-ECM as the 2nd configuration. I split this into a separate commit.
  • New configuration with functional demo at nucleo-h563zi:nshusbnet.

Impact

  • Added a new USB CDC-ECM host class.
  • Adds ability to sleect different USB configurations.
  • All changes behind Kconfigs so changes will only be seen if enabled.

Testing

  • I have tested with with a few Quectel Modems that support CDC-ECM as well as a USB Ethernet adaptor I had.
  • In the attached logs I used newly created nucleo-h563zi:nshusbnet configuration and connected the USB-Ethernet adaptor nucleo-h563zi:nshusbnet (A Realtek RTL8153 Gigabit Ethernet Adaptor with integrated hub). I then enabled the interface, set DHCP, verified it got an IP, then pinged 8.8.8.8 with no packet loss.

Commands run:

telnetd [4:100]
usbhost_enumerate: ERROR: usbhost_classbind failed -22

NuttShell (NSH) NuttX-12.13.0
nsh> ifconfig
eth0	Link encap:Ethernet HWaddr 4c:e1:73:42:27:5e at RUNNING mtu 1500
	inet addr:0.0.0.0 DRaddr:0.0.0.0 Mask:0.0.0.0

nsh> ifup eth0
ifup eth0...OK
nsh> ifconfig eth0 dhcp
nsh> ifconfig
eth0	Link encap:Ethernet HWaddr 4c:e1:73:42:27:5e at RUNNING mtu 1500
	inet addr:192.168.0.249 DRaddr:192.168.0.1 Mask:255.255.0.0

nsh> ping 8.8.8.8
PING 8.8.8.8 56 bytes of data
56 bytes from 8.8.8.8: icmp_seq=0 time=20.0 ms
56 bytes from 8.8.8.8: icmp_seq=1 time=10.0 ms
56 bytes from 8.8.8.8: icmp_seq=2 time=20.0 ms
56 bytes from 8.8.8.8: icmp_seq=3 time=10.0 ms
56 bytes from 8.8.8.8: icmp_seq=4 time=20.0 ms
56 bytes from 8.8.8.8: icmp_seq=5 time=10.0 ms
56 bytes from 8.8.8.8: icmp_seq=6 time=10.0 ms
56 bytes from 8.8.8.8: icmp_seq=7 time=20.0 ms
56 bytes from 8.8.8.8: icmp_seq=8 time=10.0 ms
56 bytes from 8.8.8.8: icmp_seq=9 time=20.0 ms
10 packets transmitted, 10 received, 0% packet loss, time 10100 ms
rtt min/avg/max/mdev = 10.000/15.000/20.000/5.000 ms

ecm_log.txt

@github-actions github-actions Bot added Size: XL The size of the change in this PR is very large. Consider breaking down the PR into smaller pieces. Area: USB Board: arm labels Apr 27, 2026
acassis
acassis previously approved these changes Apr 27, 2026
@cederom
Copy link
Copy Markdown
Contributor

cederom commented Apr 27, 2026

Wow, very cool, thank you @dlizewski, and congratulations on your first contribution to the NuttX RTOS :-)

Could you please provide also a documentation for the new functionality? :-)

Pozdrawiam :-)

@cederom
Copy link
Copy Markdown
Contributor

cederom commented Apr 28, 2026

Builds fine for me, but I have no board to test, tried on NUCLEO-H755ZI but I had problem flashing :-P

% uname -a
FreeBSD hexagon 14.4-RELEASE-p2 FreeBSD 14.4-RELEASE-p2 GENERIC amd64

% git checkout dlizewski/feature/dl.usbecm
HEAD is now at 38866d8497e drivers/usbhost/usbhost_cdcecm.c: Added support for Host CDC-ECM
hexagon% git log -1
commit 38866d8497e8c8c26e8f0e48b17f2954afe623dc (HEAD, dlizewski/feature/dl.usbecm)
Author: daniellizewski
Date:   Thu Apr 9 13:49:50 2026 -0400

    drivers/usbhost/usbhost_cdcecm.c: Added support for Host CDC-ECM

    Added support for USB host to use an USB CDC-ECM device.
    This class is used for usb-ethernet adapters as well as many modems.

    Signed-off-by: daniellizewski <daniellizewski@geotab.com>

% ./tools/configure.sh -B nucleo-h563zi:nshusbnet
  Copy files
  Select CONFIG_HOST_BSD=y
  Refreshing...
(..)
#
# configuration written to .config
#

hexagon% gmake -j
Create version.h
LN: platform/board to /XXX/nuttx/pr/nuttx-apps.git/platform/dummy
Register: telnetd
Register: ping
Register: dd
Register: nsh
Register: sh
LD: nuttx
Memory region         Used Size  Region Size  %age Used
           flash:      330308 B         2 MB     15.75%
            sram:       22656 B       256 KB      8.64%
CP: nuttx.bin
% openocd -f  interface/stlink.cfg -f target/stm32h7x.cfg -c 'program nuttx.bin 0x08000000; reset run; exit'
Open On-Chip Debugger 0.12.0
Licensed under GNU GPL v2
For bug reports, read
	http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'.
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
Info : clock speed 1800 kHz
Info : STLINK V3J15M6 (API v3) VID:PID 0483:3754
Info : Target voltage: 3.280690
Info : [stm32h7x.cpu0] Cortex-M7 r1p1 processor detected
Info : [stm32h7x.cpu0] target has 8 breakpoints, 4 watchpoints
Info : starting gdb server for stm32h7x.cpu0 on 3333
Info : Listening on port 3333 for gdb connections
[stm32h7x.cpu0] halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x08001fbc msp: 0x20006080
Info : Unable to match requested speed 4000 kHz, using 3300 kHz
Info : Unable to match requested speed 4000 kHz, using 3300 kHz
** Programming Started **
Info : Device: STM32H74x/75x
Info : flash size probed value 2048k
Info : STM32H7 flash has dual banks
Info : Bank (0) size is 1024 kb, base address is 0x08000000
Info : Padding image section 0 at 0x08050a44 with 28 bytes (bank write end alignment)
Warn : Adding extra erase range, 0x08050a60 .. 0x0805ffff
Error: error writing to flash at address 0x08000000 at offset 0x00000000
embedded:startup.tcl:1516: Error: ** Programming Failed **
in procedure 'program'
in procedure 'program_error' called at file "embedded:startup.tcl", line 1581
at file "embedded:startup.tcl", line 1516

cederom
cederom previously approved these changes Apr 28, 2026
Copy link
Copy Markdown
Contributor

@cederom cederom left a comment

Choose a reason for hiding this comment

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

Thank you @dlizewski :-)

Please add documentation in a free moment :-)

Comment thread drivers/usbhost/usbhost_enumerate.c Outdated
Comment thread drivers/usbhost/CMakeLists.txt Outdated
Comment thread drivers/usbhost/usbhost_cdcecm.c Outdated
Comment thread drivers/usbhost/usbhost_cdcecm.c Outdated
Comment thread drivers/usbhost/usbhost_cdcecm.c Outdated
uerr("ERROR: Transfer failed: %d\n", nbytes);
}

delay = MSEC2TICK(30);
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.

why delay

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This is following a pattern was taken from other drivers like the ACM and MBIM.

The idea is that normally we should not trigger a delay if we get data, but if for example the device we are talking to gets into a bad state or there are uncontrolled bus errors, then without a delay this might turn into a tight poll loop of error -> callback -> work -> error

* this case.
*/

delay = USBHOST_CDCECM_NTDELAY;
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.

why delay


bool registered; /* true if the device was registered */
bool bifup; /* true:ifup false:ifdown */
struct net_driver_s netdev; /* Interface understood by the network */
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.

why not use netdev upperhalf to simplify the code

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I based this off of nuttx_latest/nuttx/drivers/usbhost/usbhost_cdcmbim.c so maybe I inherited some bad patterns.

Can you please elaborate a little more on what you mean by that?

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.

here is an simple introduction doc: https://nuttx.apache.org/docs/latest/components/net/netdriver.html.
and code: https://github.com/apache/nuttx/blob/master/drivers/net/netdev_upperhalf.c
the idea is simple keeping the common code in upperhalf driver, so the lower half can focus on the hardware.
https://github.com/apache/nuttx/blob/master/drivers/net/e1000.c is an example.

Comment thread include/nuttx/usb/usbhost.h Outdated
FAR const struct usb_devdesc_s *devdesc,
FAR const struct usbhost_id_s *id)
{
if (id->vid == 0x0bda && id->pid == 0x8153)
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.

should we add a callback to usbhost_registry_s or usbhost_class_s to select

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The problem is that the configuration needs to be selected before the host drivers are called.

Right now the code is:

set config X
for each host driver {
  if(host matches){
    break
  }
}

The other approach I tried is to cycle the configs until we find a host driver that matches.
Something like:

for each config c {
  set config c
  for each host driver {
    if(host matches){
      goto exit
    }
  }
}

But I ran into some problems with certain host class drivers failing the 2nd time it was iniitalized for a given device. Likely a bug that could be solved if we think that is a better approach.

The other thing to note is that I dont really need this configuration selection. I added CDC-ECM since certain modems I need support ECM. On the modems they are configuration 0.

I added this configuration selection because the CDC-ECM USB-Ethernet adapters that I have present ECM as the 2nd interface and I wanted to provide testing logs using a standard off the shelf product.

But if we can accept logs from a custom board with modems (or a build where I temporarily hard-code it to 1 instead of 0) then I could revert the configuration selection portion until it is actually needed.

Added support for selecting a different USB configuration.
Certain USB devices offer different classes using different
configurations. This allows a board file to provide a callback
to select the proper configuration for a given USB device.

Signed-off-by: daniellizewski <daniellizewski@geotab.com>
Added support for USB host to use an USB CDC-ECM device.
This class is used for usb-ethernet adapters as well as many modems.

Signed-off-by: daniellizewski <daniellizewski@geotab.com>
@dlizewski dlizewski dismissed stale reviews from cederom and acassis via 40ea04c April 28, 2026 19:37
@github-actions github-actions Bot added Area: Documentation Improvements or additions to documentation and removed Area: USB labels Apr 28, 2026
@dlizewski
Copy link
Copy Markdown
Author

Wow, very cool, thank you @dlizewski, and congratulations on your first contribution to the NuttX RTOS :-)

Could you please provide also a documentation for the new functionality? :-)

Pozdrawiam :-)

Added docs for the new config and for CDC-ECM host driver

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

Labels

Area: Documentation Improvements or additions to documentation Board: arm Size: XL The size of the change in this PR is very large. Consider breaking down the PR into smaller pieces.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants