Skip to content

Commit

Permalink
Merge branch 'refactor/usb_host_enum_as_driver' into 'master'
Browse files Browse the repository at this point in the history
refactor(hub): ENUM Driver

Closes IDF-9523

See merge request espressif/esp-idf!29892
  • Loading branch information
roma-jam committed Jun 3, 2024
2 parents 137a9a0 + 0de6267 commit 8d3f4ca
Show file tree
Hide file tree
Showing 16 changed files with 1,729 additions and 769 deletions.
1 change: 1 addition & 0 deletions components/usb/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ set(priv_requires esp_driver_gpio esp_mm) # usb_phy driver relies on gpio drive

if(CONFIG_SOC_USB_OTG_SUPPORTED)
list(APPEND srcs "hcd_dwc.c"
"enum.c"
"hub.c"
"usb_helpers.c"
"usb_host.c"
Expand Down
1,364 changes: 1,364 additions & 0 deletions components/usb/enum.c

Large diffs are not rendered by default.

750 changes: 5 additions & 745 deletions components/usb/hub.c

Large diffs are not rendered by default.

159 changes: 159 additions & 0 deletions components/usb/private_include/enum.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once

#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include "hcd.h"
#include "usbh.h"
#include "usb/usb_types_stack.h"
#include "usb/usb_types_ch9.h"

#ifdef __cplusplus
extern "C" {
#endif

// ---------------------- Settings & Configuration -----------------------------
#ifdef CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK
#define ENABLE_ENUM_FILTER_CALLBACK 1
#endif // CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK

// -------------------------- Public Types -------------------------------------

// ---------------------------- Handles ----------------------------------------

/**
* @brief Handle of enumeration control object
*/
typedef struct enum_ctx_handle_s * enum_ctx_handle_t;

// ------------------------------ Events ---------------------------------------

/**
* @brief Event data object for Enumerator driver events
*/
typedef enum {
ENUM_EVENT_STARTED, /**< Enumeration of a device has started */
ENUM_EVENT_RESET_REQUIRED, /**< Enumerating device requires a reset */
ENUM_EVENT_COMPLETED, /**< Enumeration of a device has completed */
ENUM_EVENT_CANCELED, /**< Enumeration of a device was canceled */
} enum_event_t;

typedef struct {
enum_event_t event; /**< Enumerator driver event */
union {
struct {
unsigned int uid; /**< Device unique ID */
usb_device_handle_t parent_dev_hdl; /**< Parent of the enumerating device */
uint8_t parent_port_num; /**< Parent port number of the enumerating device */
} started; /**< ENUM_EVENT_STARTED specific data */

struct {
usb_device_handle_t parent_dev_hdl; /**< Parent of the enumerating device */
uint8_t parent_port_num; /**< Parent port number of the enumerating device */
} reset_req; /**< ENUM_EVENT_RESET_REQUIRED specific data */

struct {
usb_device_handle_t parent_dev_hdl; /**< Parent of the enumerating device */
uint8_t parent_port_num; /**< Parent port number of the enumerating device */
usb_device_handle_t dev_hdl; /**< Handle of the enumerating device */
uint8_t dev_addr; /**< Address of the enumerating device */
} complete; /**< ENUM_EVENT_COMPLETED specific data */

struct {
usb_device_handle_t parent_dev_hdl; /**< Parent of the enumerating device */
uint8_t parent_port_num; /**< Parent port number of the enumerating device */
} canceled; /**< ENUM_EVENT_CANCELED specific data */
};
} enum_event_data_t;

// ---------------------------- Callbacks --------------------------------------

/**
* @brief Callback used to indicate that the Enumerator has an event
*/
typedef void (*enum_event_cb_t)(enum_event_data_t *event_data, void *arg);

/**
* @brief Enum driver configuration
*/
typedef struct {
usb_proc_req_cb_t proc_req_cb; /**< Processing request callback */
void *proc_req_cb_arg; /**< Processing request callback argument */
enum_event_cb_t enum_event_cb; /**< Enum event callback */
void *enum_event_cb_arg; /**< Enum event callback argument */
#if ENABLE_ENUM_FILTER_CALLBACK
usb_host_enum_filter_cb_t enum_filter_cb; /**< Set device configuration callback */
void *enum_filter_cb_arg; /**< Set device configuration callback argument */
#endif // ENABLE_ENUM_FILTER_CALLBACK
} enum_config_t;

/**
* @brief Install Enumerator driver
*
* Entry:
* - USBH must already be installed
* - HUB must already be installed
*
* @param[in] enum_config Enumeration driver configuration
* @param[out] client_ret Unique pointer to identify Enum Driver as a USB Host client
* @return esp_err_t
*/
esp_err_t enum_install(enum_config_t *enum_config, void **client_ret);

/**
* @brief Uninstall Enumerator driver
*
* This must be called before uninstalling the HUB and USBH
*
* @return esp_err_t
*/
esp_err_t enum_uninstall(void);

/**
* @brief Start the enumeration process
*
* This will start the enumeration process for the device currently at address 0
*
* @param[in] uid Unique device ID
* @retval ESP_OK: Enumeration process started
* @retval ESP_ERR_NOT_FOUND: No device at address 0
*/
esp_err_t enum_start(unsigned int uid);

/**
* @brief Continue enumeration process
*
* This will continue the enumeration process. Typically called after the successful
* handling of a request from the Enumerator driver (such as ENUM_EVENT_RESET_REQUIRED)
*
* @param[in] uid Unique device ID
* @return esp_err_t
*/
esp_err_t enum_proceed(unsigned int uid);

/**
* @brief Cancel the enumeration process
*
* This will cancel enumeration process for device object under enumeration
*
* @return esp_err_t
*/
esp_err_t enum_cancel(unsigned int uid);

/**
* @brief Enumerator processing function
*
* Processing function that must be called repeatedly to process enumeration stages
*
* @return esp_err_t
*/
esp_err_t enum_process(void);

#ifdef __cplusplus
}
#endif
4 changes: 0 additions & 4 deletions components/usb/private_include/hub.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

#include <stdlib.h>
#include <stdint.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include "usb_private.h"
#include "usbh.h"
Expand Down Expand Up @@ -60,9 +59,6 @@ typedef struct {
void *proc_req_cb_arg; /**< Processing request callback argument */
hub_event_cb_t event_cb; /**< Hub event callback */
void *event_cb_arg; /**< Hub event callback argument */
#ifdef CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK
usb_host_enum_filter_cb_t enum_filter_cb; /**< Set device configuration callback */
#endif // CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK
} hub_config_t;

// ---------------------------------------------- Hub Driver Functions -------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions components/usb/private_include/usb_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ typedef struct urb_s urb_t;
typedef enum {
USB_PROC_REQ_SOURCE_USBH = 0x01,
USB_PROC_REQ_SOURCE_HUB = 0x02,
USB_PROC_REQ_SOURCE_ENUM = 0x03
} usb_proc_req_source_t;

/**
Expand Down
90 changes: 72 additions & 18 deletions components/usb/usb_host.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Warning: The USB Host Library API is still a beta version and may be subject to
#include "esp_log.h"
#include "esp_heap_caps.h"
#include "hub.h"
#include "enum.h"
#include "usbh.h"
#include "hcd.h"
#include "esp_private/usb_phy.h"
Expand All @@ -45,12 +46,9 @@ static portMUX_TYPE host_lock = portMUX_INITIALIZER_UNLOCKED;
} \
})

#define PROCESS_REQUEST_PENDING_FLAG_USBH 0x01
#define PROCESS_REQUEST_PENDING_FLAG_HUB 0x02

#ifdef CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK
#define ENABLE_ENUM_FILTER_CALLBACK
#endif // CONFIG_USB_HOST_ENABLE_ENUM_FILTER_CALLBACK
#define PROCESS_REQUEST_PENDING_FLAG_USBH (1 << 0)
#define PROCESS_REQUEST_PENDING_FLAG_HUB (1 << 1)
#define PROCESS_REQUEST_PENDING_FLAG_ENUM (1 << 2)

typedef struct ep_wrapper_s ep_wrapper_t;
typedef struct interface_s interface_t;
Expand Down Expand Up @@ -148,7 +146,8 @@ typedef struct {
SemaphoreHandle_t event_sem;
SemaphoreHandle_t mux_lock;
usb_phy_handle_t phy_handle; // Will be NULL if host library is installed with skip_phy_setup
void *hub_client; // Pointer to Hub driver (acting as a client). Used to reroute completed USBH control transfers
void *enum_client; // Pointer to Enum driver (acting as a client). Used to reroute completed USBH control transfers
void *hub_client; // Pointer to External Hub driver (acting as a client). Used to reroute completed USBH control transfers. NULL, when External Hub Driver not available.
} constant;
} host_lib_t;

Expand Down Expand Up @@ -219,6 +218,14 @@ static bool _unblock_lib(bool in_isr)
return yield;
}

static inline bool _is_internal_client(void *client)
{
if (p_host_lib_obj->constant.enum_client && (client == p_host_lib_obj->constant.enum_client)) {
return true;
}
return false;
}

static void send_event_msg_to_clients(const usb_host_client_event_msg_t *event_msg, bool send_to_all, uint8_t opened_dev_addr)
{
// Lock client list
Expand Down Expand Up @@ -263,6 +270,9 @@ static bool proc_req_callback(usb_proc_req_source_t source, bool in_isr, void *a
case USB_PROC_REQ_SOURCE_HUB:
p_host_lib_obj->dynamic.process_pending_flags |= PROCESS_REQUEST_PENDING_FLAG_HUB;
break;
case USB_PROC_REQ_SOURCE_ENUM:
p_host_lib_obj->dynamic.process_pending_flags |= PROCESS_REQUEST_PENDING_FLAG_ENUM;
break;
}
bool yield = _unblock_lib(in_isr);
HOST_EXIT_CRITICAL_SAFE();
Expand All @@ -277,8 +287,8 @@ static void usbh_event_callback(usbh_event_data_t *event_data, void *arg)
assert(event_data->ctrl_xfer_data.urb != NULL);
assert(event_data->ctrl_xfer_data.urb->usb_host_client != NULL);
// Redistribute completed control transfers to the clients that submitted them
if (event_data->ctrl_xfer_data.urb->usb_host_client == p_host_lib_obj->constant.hub_client) {
// Redistribute to Hub driver. Simply call the transfer callback
if (_is_internal_client(event_data->ctrl_xfer_data.urb->usb_host_client)) {
// Simply call the transfer callback
event_data->ctrl_xfer_data.urb->transfer.callback(&event_data->ctrl_xfer_data.urb->transfer);
} else {
client_t *client_obj = (client_t *)event_data->ctrl_xfer_data.urb->usb_host_client;
Expand Down Expand Up @@ -333,12 +343,16 @@ static void hub_event_callback(hub_event_data_t *event_data, void *arg)
{
switch (event_data->event) {
case HUB_EVENT_CONNECTED:
// Nothing to do, because enumeration still holding in Hub Driver
// Start enumeration process
enum_start(event_data->connected.uid);
break;
case HUB_EVENT_RESET_COMPLETED:
// Nothing to do, because enumeration still holding in Hub Driver
// Proceed enumeration process
ESP_ERROR_CHECK(enum_proceed(event_data->reset_completed.uid));
break;
case HUB_EVENT_DISCONNECTED:
// Cancel enumeration process
enum_cancel(event_data->disconnected.uid);
// We allow this to fail in case the device object was already freed
usbh_devs_remove(event_data->disconnected.uid);
break;
Expand All @@ -348,6 +362,30 @@ static void hub_event_callback(hub_event_data_t *event_data, void *arg)
}
}

static void enum_event_callback(enum_event_data_t *event_data, void *arg)
{
enum_event_t event = event_data->event;

switch (event) {
case ENUM_EVENT_STARTED:
// Enumeration process started
break;
case ENUM_EVENT_RESET_REQUIRED:
hub_port_reset(event_data->reset_req.parent_dev_hdl, event_data->reset_req.parent_port_num);
break;
case ENUM_EVENT_COMPLETED:
// Propagate a new device event
ESP_ERROR_CHECK(usbh_devs_new_dev_event(event_data->complete.dev_hdl));
break;
case ENUM_EVENT_CANCELED:
// Enumeration canceled
break;
default:
abort(); // Should never occur
break;
}
}

// ------------------- Client Related ----------------------

static bool endpoint_callback(usbh_ep_handle_t ep_hdl, usbh_ep_event_t ep_event, void *user_arg, bool in_isr)
Expand Down Expand Up @@ -399,6 +437,7 @@ esp_err_t usb_host_install(const usb_host_config_t *config)
- USB PHY
- HCD
- USBH
- Enum
- Hub
*/

Expand Down Expand Up @@ -440,20 +479,28 @@ esp_err_t usb_host_install(const usb_host_config_t *config)
goto usbh_err;
}

#ifdef ENABLE_ENUM_FILTER_CALLBACK
if (config->enum_filter_cb == NULL) {
ESP_LOGW(USB_HOST_TAG, "User callback to set USB device configuration is enabled, but not used");
}
// Install Enumeration driver
enum_config_t enum_config = {
.proc_req_cb = proc_req_callback,
.proc_req_cb_arg = NULL,
.enum_event_cb = enum_event_callback,
.enum_event_cb_arg = NULL,
#if ENABLE_ENUM_FILTER_CALLBACK
.enum_filter_cb = config->enum_filter_cb,
.enum_filter_cb_arg = NULL,
#endif // ENABLE_ENUM_FILTER_CALLBACK
};
ret = enum_install(&enum_config, &host_lib_obj->constant.enum_client);
if (ret != ESP_OK) {
goto enum_err;
}

// Install Hub
hub_config_t hub_config = {
.proc_req_cb = proc_req_callback,
.proc_req_cb_arg = NULL,
.event_cb = hub_event_callback,
.event_cb_arg = NULL,
#ifdef ENABLE_ENUM_FILTER_CALLBACK
.enum_filter_cb = config->enum_filter_cb,
#endif // ENABLE_ENUM_FILTER_CALLBACK
};
ret = hub_install(&hub_config, &host_lib_obj->constant.hub_client);
if (ret != ESP_OK) {
Expand All @@ -478,6 +525,8 @@ esp_err_t usb_host_install(const usb_host_config_t *config)
assign_err:
ESP_ERROR_CHECK(hub_uninstall());
hub_err:
ESP_ERROR_CHECK(enum_uninstall());
enum_err:
ESP_ERROR_CHECK(usbh_uninstall());
usbh_err:
ESP_ERROR_CHECK(hcd_uninstall());
Expand Down Expand Up @@ -520,11 +569,13 @@ esp_err_t usb_host_uninstall(void)
/*
Uninstall each layer of the Host stack (listed below) from the highest layer to the lowest
- Hub
- Enum
- USBH
- HCD
- USB PHY
*/
ESP_ERROR_CHECK(hub_uninstall());
ESP_ERROR_CHECK(enum_uninstall());
ESP_ERROR_CHECK(usbh_uninstall());
ESP_ERROR_CHECK(hcd_uninstall());
// If the USB PHY was setup, then delete it
Expand Down Expand Up @@ -571,6 +622,9 @@ esp_err_t usb_host_lib_handle_events(TickType_t timeout_ticks, uint32_t *event_f
if (process_pending_flags & PROCESS_REQUEST_PENDING_FLAG_HUB) {
ESP_ERROR_CHECK(hub_process());
}
if (process_pending_flags & PROCESS_REQUEST_PENDING_FLAG_ENUM) {
ESP_ERROR_CHECK(enum_process());
}

ret = ESP_OK;
// Set timeout_ticks to 0 so that we can check for events again without blocking
Expand Down
Binary file modified docs/_static/usb_host/stack-overview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 8d3f4ca

Please sign in to comment.