Skip to content

Conversation

@roma-jam
Copy link
Collaborator

@roma-jam roma-jam commented Sep 26, 2025

Description

Follow-up for: 35401#note_1958915

  • Isolated root port handling in HUB Driver
  • Changed root_port_hdl to static buffer of root_port_hdls[HUB_ROOT_PORTS] where HUB_ROOT_PORTS is configured statically, via #define (supports <= 4 by design, but can be increased)
  • Added peripheral map handling during USB Host lib install (install PHY to every peripheral port in peripheral map)

Limitation

  • All HCD ports are handled in a single thread (via usb_host_lib_handle_events())
  • Added TODO: Refactor HUB_PORTS_NUM: make them dynamically configurable by hub_config_t::port_map in usb_host.c

Related

N/A

Testing

Common usb host tests.


Checklist

Before submitting a Pull Request, please ensure the following:

  • 🚨 This PR does not introduce breaking changes.
  • All CI checks (GH Actions) pass.
  • Documentation is updated as needed.
  • Tests are updated or added as necessary.
  • Code is well-commented, especially in complex areas.
  • Git history is clean — commits are squashed to the minimum necessary.

@roma-jam roma-jam self-assigned this Sep 26, 2025
@roma-jam roma-jam changed the title feature(usb_host): Support multiple DWC OTG peripheral ports [WIP] feature(usb_host): Support multiple DWC OTG peripheral ports in Hub Driver [WIP] Sep 26, 2025
@roma-jam roma-jam force-pushed the feature/usb_host_multiple_root_ports branch from 47ba0b1 to 6e126f3 Compare September 26, 2025 12:55
@roma-jam roma-jam added Component: usb_host Issue affects usb_host component Status: In Progress Issue is being worked on and removed Status: In Progress Issue is being worked on labels Sep 26, 2025
@roma-jam roma-jam force-pushed the refactor/usb_host_cleanup_hub_parent_child_dependencies branch from 33e40ea to a6bb309 Compare September 29, 2025 09:04
@roma-jam roma-jam force-pushed the refactor/usb_host_cleanup_hub_parent_child_dependencies branch from a6bb309 to e928ef9 Compare September 29, 2025 09:08
@roma-jam roma-jam force-pushed the feature/usb_host_multiple_root_ports branch from 0da5710 to fbc08d7 Compare September 29, 2025 11:50
@roma-jam roma-jam changed the title feature(usb_host): Support multiple DWC OTG peripheral ports in Hub Driver [WIP] feature(usb_host): Support multiple DWC OTG peripheral ports in Hub Driver Sep 29, 2025
@roma-jam roma-jam marked this pull request as ready for review September 29, 2025 11:56
@cursor
Copy link

cursor bot commented Sep 29, 2025

You have run out of free Bugbot PR reviews for this billing cycle. This will reset on October 20.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@roma-jam roma-jam changed the title feature(usb_host): Support multiple DWC OTG peripheral ports in Hub Driver feature(usb_host): Support multiple DWC OTG peripheral ports in Host mode Sep 29, 2025
@roma-jam roma-jam marked this pull request as draft September 29, 2025 13:58
@roma-jam roma-jam force-pushed the feature/usb_host_multiple_root_ports branch from 415021a to dcf010b Compare September 29, 2025 14:43
@roma-jam roma-jam force-pushed the feature/usb_host_multiple_root_ports branch from dcf010b to 85b3cc0 Compare September 29, 2025 14:50
@roma-jam roma-jam marked this pull request as ready for review September 29, 2025 15:14
@roma-jam roma-jam added this to the usb_host v1.0.1 milestone Sep 29, 2025
Copy link
Collaborator

@peter-marcisovsky peter-marcisovsky left a comment

Choose a reason for hiding this comment

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

I presume, the suspend/resume feature will have to be supported for multiple peripherals.

*
* @return uint8_t Port number
*/
uint8_t hcd_port_get_number(hcd_port_handle_t port_hdl);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe you can add get_port_number to the function name? Right now, if you don't' look at the prefix hcd_port, the function name is just get_numer. But up to you.

Suggested change
uint8_t hcd_port_get_number(hcd_port_handle_t port_hdl);
uint8_t hcd_port_get_port_number(hcd_port_handle_t port_hdl);

* - ESP_ERR_INVALID_STATE: Hub driver is not installed, or root port is in other state than not powered
*/
esp_err_t hub_root_start(void);
esp_err_t hub_root_start(uint8_t port_idx);
Copy link
Collaborator

Choose a reason for hiding this comment

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

During the usb_host_install() we define peripheral map by esp_bit_defs.h, BIT0 and BIT1 respectively. Would it make sense to unify the peripherals selection?

esp_err_t usbh_dev_get_addr(usb_device_handle_t dev_hdl, uint8_t *dev_addr);

/**
* @brief Get the root port handle of a device
Copy link
Collaborator

Choose a reason for hiding this comment

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

In this context, the device is the external hub? Getting a root port handle of device is bit misleading term.

uint8_t hcd_port_get_number(hcd_port_handle_t port_hdl)
{
port_t *port = (port_t *)port_hdl;
return port->port_num;
Copy link
Collaborator

Choose a reason for hiding this comment

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

In (I think) all the functions in hcd_dwc.c, whenever we are working with port handle, we are using critical section. hcd_port_get_state() is a perfect example which matches this scenario.

SemaphoreHandle_t mux_lock;
usb_phy_handle_t phy_handle; // Will be NULL if host library is installed with skip_phy_setup
unsigned peripheral_map; // Peripheral map
usb_phy_handle_t phy_hdls[4 /* TODO: 1 */]; // Will be NULL if host library is installed with skip_phy_setup
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why 4, if we have only 2 USB-OTG peripherals?

// Start the root hub according to the peripheral map
for (unsigned idx = 0; idx < 4 /* TODO: 1 */; idx++) {
if (p_host_lib_obj->constant.peripheral_map & (BIT0 << idx)) {
ESP_ERROR_CHECK(hub_root_start(idx));
Copy link
Collaborator

Choose a reason for hiding this comment

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

You can also break form the cycle, once you find the correct peripheral.

Suggested change
ESP_ERROR_CHECK(hub_root_start(idx));
ESP_ERROR_CHECK(hub_root_start(idx));
break;

}
}

return ret;
Copy link
Collaborator

Choose a reason for hiding this comment

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

In case the usb_host_install() has not been called prior to the usb_host_lib_set_root_port_power() call, this function returns just ret, which would be undefined.
Since the for cycle never finds the peripheral map and the if (p_host_lib_obj->constant.peripheral_map & (BIT0 << idx)) is never executed.

You can consider declaring esp_err_t ret as esp_err_t ret = ESP_ERR_NOT_FOUND for example.

Maybe there will be similar unsafe condition, whenever using the similar for cycle for some further action based on peripheral map index.

static void root_port_handle_events(root_port_t *root_port)
{
hcd_port_handle_t root_port_hdl = root_port->constant.hdl;
uint8_t port_idx = hcd_port_get_number(root_port_hdl);
Copy link
Collaborator

Choose a reason for hiding this comment

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

You could use const to indicate the port_index is not changing in the function

Suggested change
uint8_t port_idx = hcd_port_get_number(root_port_hdl);
const uint8_t port_idx = hcd_port_get_number(root_port_hdl);

SemaphoreHandle_t mux_lock;
usb_phy_handle_t phy_handle; // Will be NULL if host library is installed with skip_phy_setup
unsigned peripheral_map; // Peripheral map
usb_phy_handle_t phy_hdls[4 /* TODO: 1 */]; // Will be NULL if host library is installed with skip_phy_setup
Copy link
Collaborator

Choose a reason for hiding this comment

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

Instead of hardcoding the USB instance count, could we use SOC_USB_OTG_PERIPH_NUM from soc/soc_caps.h? It’s defined per-SoC, so this stays portable across targets.

implement the bare minimum to control the root HCD port.
*/
/* Max support value based on the implementation: 4 */
#define HUB_ROOT_PORTS 2
Copy link
Collaborator

Choose a reason for hiding this comment

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

you can use soc_caps define instead

Suggested change
#define HUB_ROOT_PORTS 2
#define HUB_ROOT_PORTS SOC_USB_OTG_PERIPH_NUM

Copy link
Collaborator

@tore-espressif tore-espressif left a comment

Choose a reason for hiding this comment

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

@roma-jam Thank you for your work!
For this feature we were expecting some breaking changes. The is an incomplete list of what must be changed:

  1. usb_host_lib_set_root_port_power() should accept root port index. (or, alternatively, it can always power on/off both ports, but this can be too limiting)
  2. Following members of usb_host_config_t are specific to USB-DWC configuration, and therefore it should be possible to configure them for each peripheral separately:
  • root_power_unpowered
  • intr_flags
  • fifo_settings_custom

In case we want to avoid the breaking changes, we can just extend the API for dual host. Eg. introduce new function usb_host_install_dual() and usb_host_lib_set_root_power_dual().
This would make the code less cumbersome while providing the feature to users in a clear way.

We can discuss offline when you're ready

@roma-jam roma-jam force-pushed the refactor/usb_host_cleanup_hub_parent_child_dependencies branch 5 times, most recently from 1e9a582 to d9045f6 Compare October 10, 2025 13:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Component: usb_host Issue affects usb_host component

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants