Skip to content

Conversation

@D-Veda
Copy link

@D-Veda D-Veda commented Dec 1, 2025

Dependencies:

This implementation contains all commits from #99775 & some necessary commits from #99097 and in addition:

  • Add CDC-ECM class driver usbh_cdc_ecm.c
  • Add ethernet network interface support for USB host
  • Add USB host support for sample samples/net/dhcpv4_client (CDC-ECM feature can be verified at board rd_rw612_bga )

It is fixed & improved the implementation in #99097:

  • Restructure driver to use proper Ethernet API with ETH_NET_DEVICE_DT_INST_DEFINE (better aligns with USB CDC-ECM design requirements)
  • Add network interface up/down state management
  • Implement automatic RX restart mechanism with error recovery
  • Add proper ZLP (Zero Length Packet) handling for bulk transfers
  • Use separate buffer pools for TX and RX data transfers
  • Add comprehensive CDC-ECM class requests (SET_ETHERNET_PACKET_FILTER, GET_ETHERNET_STATISTIC, SET_ETHERNET_MULTICAST_FILTERS, etc.)
  • Implement MAC address retrieval from USB string descriptors with multi-language support
  • Add support for fragmented network buffers with linearization

Josuah Demangeon and others added 30 commits December 1, 2025 16:09
Add a "struct usbh_status" that contains a bitmask of flags to keep
track of the global state of the host context, like done for the
device_next implementation.

Signed-off-by: Josuah Demangeon <[email protected]>
Add missing copyright notice for the linker script to help with
check_compliance.py.

Signed-off-by: Josuah Demangeon <[email protected]>
Add a "struct usbh_class_api" for the host implementation, and move all
the function poitners to it. Add more fields to "struct usbh_class_data".

Signed-off-by: Josuah Demangeon <[email protected]>
Add API wrappers around the function pointers in struct usbh_class_api,
while also documenting the USB host class internal API.

Signed-off-by: Josuah Demangeon <[email protected]>
Add functions to probe/remove all classes as part of a new usbh_class.c
and a matching usbh_class.h. These functions are called from the function
usbh_init_device_intl() in usbh_core.c to initialize every class upon
connection of a device. Every class driver provide filters to match the
interfaces of the device.

Co-authored-by: Aiden Hu <[email protected]>
Signed-off-by: Josuah Demangeon <[email protected]>
Move the UVC header with all the definitions from the UVC standard to
share it between USB host and device class implementation.

Signed-off-by: Josuah Demangeon <[email protected]>
Add tests making sure the USB Host class APIs introduced build
and run as expected.

Signed-off-by: Josuah Demangeon <[email protected]>
Add tests making sure the USB Host class APIs introduced build
and run as expected.

Signed-off-by: Josuah Demangeon <[email protected]>
Move the UVC header with all the definitions from the UVC standard to
share it between USB host and device class implementation.

Signed-off-by: Josuah Demangeon <[email protected]>
Move UVC helper functions to a file shared between UVC host and device.
The arrays are not visible anymore from either USB host or device, but
instead accessed through a front-end funciton.

Signed-off-by: Josuah Demangeon <[email protected]>
The USB control size field was wrong for UVC_PU_CONTRAST_CONTROL.
Correct it to the correct value from the standard.

Signed-off-by: Josuah Demangeon <[email protected]>
Loop through each of the VideoStreaming and VideoControl descriptor
to parse them. This is meant as a stub for the purpose of testing the
class API.

Signed-off-by: Josuah Demangeon <[email protected]>
Add a test to run the USB Video Class host support by using
the existing Zephyr USB Video Class device support.
This allows running implementing the host side from the device side.
A draft implementation of UVC is added leveraging this test.

Signed-off-by: Josuah Demangeon <[email protected]>
The public API file <zephyr/usb/class/usbd_uvc.h> lacked an include
to <zephyr/drivers/video.h> making it fail depending on the order of
the includes.

Signed-off-by: Josuah Demangeon <[email protected]>
Modify the USB device int sequence to read the device
descriptor only after setting a valid device address.

Signed-off-by: Santhosh Charles <[email protected]>
When hub is used, need to consider about multiple
devices are attached.

Signed-off-by: Aiden Hu <[email protected]>
add usbh_device_get_root and usbh_device_is_root
function to check root device

Signed-off-by: Aiden Hu <[email protected]>
For usb xfer, set endpoint type and interval by the
selected endpoint desc.

Signed-off-by: Aiden Hu <[email protected]>
Convert xfer's interval to actual value because
mcux_ep->interval is already calculated.

Signed-off-by: Aiden Hu <[email protected]>
maxPacketSize and numberPerUframe of pipe should
be set considering additional transactions.

Signed-off-by: Aiden Hu <[email protected]>
Add two functions:
usbh_connect_device() for device connection
usbh_disconnect_device() for device disconnection

These functions centralize the logic for device attach/detach,
including class probe and remove handling. They can be invoked
by the hub class as well as dev_connected_handler and
dev_removed_handler, improving code clarity and reuse.

Signed-off-by: Aiden Hu <[email protected]>
Add support for the USB CDC ECM (Ethernet Control Model) class to the
USB host subsystem. This implementation enables Ethernet functionality
for USB host.

Signed-off-by: Santhosh Charles <[email protected]>
Add devicetree binding file describing the USB Host CDC Ethernet
Control Model (ECM) implementation for Zephyr.

Signed-off-by: Santhosh Charles <[email protected]>
Introduce subsys/usb/common as a new directory intended to hold
sources and configuration that are shared between USB host and device
implementations. Integrate the new common directory into the build
system.

Signed-off-by: Santhosh Charles <[email protected]>
Signed-off-by: Josuah Demangeon <[email protected]>
Add missing include for usbh_class.h header file in usbh_core.c to fix
implicit declaration of function 'usbh_class_init_all' in usbh_core.c

Signed-off-by: Dv Alan <[email protected]>
Add usbh_req_desc_str() helper function to retrieve USB string
descriptors from a device. This function wraps the generic descriptor
request with proper handling for string descriptors, including memory
allocation, data copying, and endianness conversion for the bString
field.

Signed-off-by: Dv Alan <[email protected]>
Add Ethernet Statistics Feature Selector enumeration defining all
standard CDC ECM statistics counters (XMIT_OK, RCV_OK, etc.) as per
the USB CDC specification. Add CDC notification packet structure for
handling device notifications. Add CONNECTION_SPEED_CHANGE notification
code and Ethernet Power Management Pattern activation constants.

Signed-off-by: Dv Alan <[email protected]>
Complete rewrite of the USB host CDC-ECM (Ethernet Control Model) driver
with improved architecture and functionality:

- Restructure driver to use proper Ethernet API with
  ETH_NET_DEVICE_DT_INST_DEFINE
- Implement asynchronous RX handling using k_poll signals and dedicated
  thread
- Add support for fragmented network buffers with linearization
- Implement proper packet filter management (promiscuous, multicast,
  broadcast)
- Add support for connection speed change notifications and link
  capabilities
- Implement MAC address retrieval from USB string descriptors with
  multi-language support
- Add comprehensive CDC-ECM class requests (SET_ETHERNET_PACKET_FILTER,
  GET_ETHERNET_STATISTIC, SET_ETHERNET_MULTICAST_FILTERS, etc.)
- Use separate buffer pools for TX and RX data transfers
- Add proper ZLP (Zero Length Packet) handling for bulk transfers
- Implement automatic RX restart mechanism with error recovery
- Add network interface up/down state management
- Update Kconfig with configurable buffer counts and stack size
- Rename Kconfig file from Kconfig.cdc_ecm_host to Kconfig.cdc_ecm
- Change DT compatible from "zephyr,usbh-cdc-ecm" to
  "zephyr,cdc-ecm-host"
- Mark driver as EXPERIMENTAL in Kconfig

The rewritten driver provides better error handling, improved
performance through asynchronous operations, and more complete CDC-ECM
feature support.

Signed-off-by: Dv Alan <[email protected]>
Rename the CDC-ECM host device tree binding file from
zephyr,usbh-cdc-ecm.yaml to zephyr,cdc-ecm-host.yaml to align with
the updated compatible string used in the rewritten driver.

Update the binding description to clarify that each CDC-ECM instance
represents an ethernet interface visible to Zephyr's networking stack.

Remove the local-mac-address property as MAC address retrieval is now
handled directly from USB string descriptors in the driver
implementation.

Signed-off-by: Dv Alan <[email protected]>
@D-Veda D-Veda changed the title Usbh cdc ecm support subsys: usb: host: Add USB Host CDC ECM Class Support for Ethernet subsys: usb: host: support for usb host cdc-ecm class Dec 1, 2025
@jukkar jukkar removed their request for review December 1, 2025 10:15
@@ -0,0 +1,1157 @@
/*
Copy link
Member

Choose a reason for hiding this comment

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

this is a ethernet driver, so it belongs in drivers/ethernet/. I know there are already others there, but these should probably be moved too. I don't like ethernet drivers and its api be scattered all over the tree. (should be limited to the ethernet and wifi drivers and the net subsystem)

Copy link
Member

Choose a reason for hiding this comment

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

this is blocking

Copy link
Contributor

Choose a reason for hiding this comment

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

It seems like a bit of discussion would help to decide:

  • Where USB classes (host/device) that implement a driver API are implemented. This would imply most USB classes move, or it would be an exception just for CDC-ECM.

  • Whether source in drivers/ are allowed to call functions from subsystem/. I've not seen anything in the doc but suspect this could interest several parties to review which model to use.

How about pursuing with the implementation details in the meantime that the location of tes code is discussed?

Thank you for the review!

Copy link
Member

@maass-hamburg maass-hamburg Dec 3, 2025

Choose a reason for hiding this comment

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

Drivers are allowed to use subsystems.

For example there is the random subsystem subsys/random/, it implements /include/zephyr/random/random.h, which includes sys_rand_get(). Btw the random subsystem uses the entropy_driver_api, if that is selected to be the source of randomness.

For the ethernet drivers, we have a common dt prop zephyr,random-mac-address if that is set, the ethernet mac address is randomly generated with sys_rand_get() during the init of the ethernet driver.

Other example are sd cards in zephyr. (that might be similar enough to usb, as it also has a sd subsystem above the sdhc drivers and api)

The sd card or disk (dt compatible zephyr,sdmmc-disk, drivers/disk/sdmmc_subsys.c) implements the disk api (zephyr/drivers/disk.h) and uses the SD subsystem (subsys/sd) and that uses the sdhc drivers (include/zephyr/drivers/sdhc.h).

We also have drivers for a SDIO wifi card in tree, which uses the sd subsystem it is in
drivers/wifi/infineon/airoc_whd_hal_sdio.c and not in subsys/sd.

Even bigger: We have a crypto device api and one of the drivers is zephyr/drivers/crypto/crypto_mbedtls_shim.c and it is using mbedTLS, which even is a separate module.

Drivers can use anything what they need.

Another thing is control and ensuring quality. There is a reason we have Driver Areas in the maintainers.yml and that in addition to the vendor specific areas for their drivers.
For this PR I wasn't added because I'm the ethernet maintainer, no it was just because I'm also a collaborator for DHCP in the networking subsystem and it's sample got changed.

How about pursuing with the implementation details in the meantime that the location of tes code is discussed?

Sure

Copy link
Contributor

@josuah josuah Dec 3, 2025

Choose a reason for hiding this comment

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

Thank you for your overview of driver <-> subsystem dependencies. I think I heard this "subsystem/driver" split about a particular driver, not as a general guideline.

For this PR I wasn't added because I'm the ethernet maintainer, no it was just because I'm also a collaborator for DHCP in the networking subsystem and it's sample got changed.

Regardless the solution, there would need to make sure that MAINTAINERS.yml pings correctly everyone involved.

@D-Veda D-Veda marked this pull request as draft December 1, 2025 10:42
Refactor the CDC-ECM host driver to improve MAC address handling and
network interface lifecycle management:

- Remove eth_usbh_cdc_ecm_get_capabilities() of eth_usbh_cdc_ecm_api,
  since it is static information about the ethernet capability, usb
  host does not match it
- Remove manual net_if_up/down calls from probe and removed functions
- Remove net_mgmt call for setting MAC address
- Add upload_speed and download_speed fields to track connection speeds
- Add interface and carrier state checks in RX callback to discard
  packets when interface is down

Signed-off-by: Dv Alan <[email protected]>
@D-Veda D-Veda requested a review from maass-hamburg December 3, 2025 09:02
Comment on lines +103 to +113
err = usbh_init(&uhs_ctx);
if (err) {
LOG_ERR("Failed to initialize %s: %d", uhs_ctx.name, err);
return err;
}

err = usbh_enable(&uhs_ctx);
if (err) {
LOG_ERR("Failed to enable %s: %d", uhs_ctx.name, err);
return err;
}
Copy link
Member

Choose a reason for hiding this comment

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

this should be part of the ethernet drivers init. also don't forget to handle the return of -EALREADY which should not be treated as an error.

Comment on lines +8 to +11
usbh_cdc_ecm {
compatible = "zephyr,cdc-ecm-host";
status = "okay";
};
Copy link
Member

Choose a reason for hiding this comment

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

shouldn't this be child of a usb host controller? so it knows what host controller hhas to be init and started

Copy link
Contributor

Choose a reason for hiding this comment

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

Currently, the first USB host interface that is initialized inherits all the classes.
This is probably a design flaw of the WIP APIs...

What about letting classes independent from a physical interface? This way regardless which physical interface is used, the same classes can be assigned to one or the other whenever a device is connected and match the class.

That allows to support i.e. 3 CDC NCM devices OS-wise, rather than require 2 CDC NCM devices on the first root HUB and 2 CDC NCM devices on the second root HUB (resource sharing).

Copy link
Contributor

Choose a reason for hiding this comment

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

Root hub refers to the ports of single controller, so in that sense binding interface to controller would not have impact. But if you have multiple USB host controllers, then there would be a difference.

While quite often there is 1-to-1 relationship between USB host controller and root hub, there is nothing preventing USB host controller from having multiple root hubs. In other words, multiple USB Type-A ports can be used by single host controller.

Updates:

- Remove unnecessary loop and switch statement in connection speed
  change notification
- Add debug log in notification callback

Signed-off-by: Dv Alan <[email protected]>
@sonarqubecloud
Copy link

sonarqubecloud bot commented Dec 3, 2025

Quality Gate Failed Quality Gate failed

Failed conditions
E Reliability Rating on New Code (required ≥ C)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@josuah
Copy link
Contributor

josuah commented Dec 10, 2025

It is possible to have a "demo" branch with all the commits from API4 like now, but this "demo" branch will not be merged until a lot of dependencies are reviewed and merged.

Therefore, if you wished to have this PR merged soon, you might be interested in only using the minimum amount of dependencies, such as only API2 and not the commits from API3 and API4.

If you needed to also have a "demo" pull request with all the experimental features from API3 and API4, then you can have an additional pull request just for demo purpose that will not be merged.

Does it make sense? Feel free to ask clarifications here or on Discord.
Thank you!

@josuah
Copy link
Contributor

josuah commented Dec 10, 2025

API2 is currently being reviewed, as soon as it is merged, it should be possible to write this current PR on top of main directly.

Note that API2 recently got updated with new adjustments, including light API changes (suspend/resume removed). You might want to adjust this current PR to the latest API.

Thank you!

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants