Merge branch 'refactor/usb_host_usbh_api_prereq_for_enum_driver' into 'master'

refactor(usbh): Updated USBH api for ENUM driver

Closes IDF-9723

See merge request espressif/esp-idf!29913
This commit is contained in:
Roman Leonov 2024-05-08 15:02:08 +08:00
commit 7b7b8680ca
5 changed files with 242 additions and 131 deletions

View File

@ -606,15 +606,15 @@ static bool enum_stage_transfer_check(enum_ctrl_t *enum_ctrl)
break;
} else {
// Fill the string descriptor into the device object
int select;
int str_index;
if (enum_ctrl->stage == ENUM_STAGE_CHECK_FULL_MANU_STR_DESC) {
select = 0;
str_index = 0;
} else if (enum_ctrl->stage == ENUM_STAGE_CHECK_FULL_PROD_STR_DESC) {
select = 1;
str_index = 1;
} else { // ENUM_STAGE_CHECK_FULL_PROD_STR_DESC
select = 2;
str_index = 2;
}
ESP_ERROR_CHECK(usbh_dev_set_str_desc(enum_ctrl->dev_hdl, str_desc, select));
ESP_ERROR_CHECK(usbh_dev_set_str_desc(enum_ctrl->dev_hdl, str_desc, str_index));
ret = true;
break;
}
@ -634,7 +634,7 @@ static void enum_stage_cleanup(enum_ctrl_t *enum_ctrl)
// Propagate a new device event
ESP_ERROR_CHECK(usbh_devs_new_dev_event(enum_ctrl->dev_hdl));
// We are done with using the device. Close it.
ESP_ERROR_CHECK(usbh_devs_close(enum_ctrl->dev_hdl));
ESP_ERROR_CHECK(usbh_dev_close(enum_ctrl->dev_hdl));
// Clear values in enum_ctrl
enum_ctrl->dev_hdl = NULL;
}
@ -644,7 +644,7 @@ static void enum_stage_cleanup_failed(enum_ctrl_t *enum_ctrl)
if (enum_ctrl->dev_hdl) {
// Close the device and unlock it as we done with enumeration
ESP_ERROR_CHECK(usbh_dev_enum_unlock(enum_ctrl->dev_hdl));
ESP_ERROR_CHECK(usbh_devs_close(enum_ctrl->dev_hdl));
ESP_ERROR_CHECK(usbh_dev_close(enum_ctrl->dev_hdl));
// We allow this to fail in case the device object was already freed
usbh_devs_remove(ENUM_DEV_UID);
}
@ -791,8 +791,15 @@ static void root_port_handle_events(hcd_port_handle_t root_port_hdl)
if (hcd_port_get_speed(p_hub_driver_obj->constant.root_port_hdl, &speed) != ESP_OK) {
goto new_dev_err;
}
// Allocate a new device. We use a fixed ENUM_DEV_UID for now since we only support a single device
if (usbh_devs_add(ENUM_DEV_UID, speed, p_hub_driver_obj->constant.root_port_hdl) != ESP_OK) {
usbh_dev_params_t params = {
.uid = ENUM_DEV_UID,
.speed = speed,
.root_port_hdl = p_hub_driver_obj->constant.root_port_hdl,
};
if (usbh_devs_add(&params) != ESP_OK) {
ESP_LOGE(HUB_DRIVER_TAG, "Failed to add device");
goto new_dev_err;
}

View File

@ -70,10 +70,19 @@ typedef struct usb_device_handle_s *usb_device_handle_t;
*/
typedef bool (*usb_host_enum_filter_cb_t)(const usb_device_desc_t *dev_desc, uint8_t *bConfigurationValue);
/**
* @brief Parent device information
*/
typedef struct {
usb_device_handle_t dev_hdl; /**< Device's parent handle */
uint8_t port_num; /**< Device's parent port number */
} usb_parent_dev_info_t;
/**
* @brief Basic information of an enumerated device
*/
typedef struct {
usb_parent_dev_info_t parent; /**< Device's parent information */
usb_speed_t speed; /**< Device's speed */
uint8_t dev_addr; /**< Device's address */
uint8_t bMaxPacketSize0; /**< The maximum packet size of the device's default endpoint */

View File

@ -59,6 +59,8 @@ typedef struct {
} dev_gone_data;
struct {
unsigned int dev_uid;
usb_device_handle_t parent_dev_hdl;
uint8_t port_num;
} dev_free_data;
};
} usbh_event_data_t;
@ -130,7 +132,18 @@ typedef struct {
void *event_cb_arg; /**< USBH event callback argument */
} usbh_config_t;
// -------------------------------------------- USBH Processing Functions ----------------------------------------------
/**
* @brief USBH device parameters used in usbh_devs_add()
*/
typedef struct {
unsigned int uid; /**< Unique ID assigned to the device */
usb_speed_t speed; /**< Device's speed */
hcd_port_handle_t root_port_hdl; /**< Handle of the port that the device is connected to */
usb_device_handle_t parent_dev_hdl; /**< Parent's device handle */
uint8_t parent_port_num; /**< Parent's port number */
} usbh_dev_params_t;
// ---------------------- USBH Processing Functions ----------------------------
/**
* @brief Installs the USBH driver
@ -169,7 +182,7 @@ esp_err_t usbh_uninstall(void);
*/
esp_err_t usbh_process(void);
// ---------------------------------------------- Device Pool Functions ------------------------------------------------
// ---------------------- Device Pool Functions --------------------------------
/**
* @brief Get the current number of devices
@ -206,12 +219,10 @@ esp_err_t usbh_devs_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *nu
* - Call usbh_dev_enum_lock() before enumerating the device via the various
* usbh_dev_set_...() functions.
*
* @param[in] uid Unique ID assigned to the device
* @param[in] dev_speed Device's speed
* @param[in] port_hdl Handle of the port that the device is connected to
* @param[in] params Device parameters, using for device creation
* @return esp_err_t
*/
esp_err_t usbh_devs_add(unsigned int uid, usb_speed_t dev_speed, hcd_port_handle_t port_hdl);
esp_err_t usbh_devs_add(usbh_dev_params_t *params);
/**
* @brief Indicates to the USBH that a device is gone
@ -221,6 +232,18 @@ esp_err_t usbh_devs_add(unsigned int uid, usb_speed_t dev_speed, hcd_port_handle
*/
esp_err_t usbh_devs_remove(unsigned int uid);
/**
* @brief Get a device's connection information
*
* @note Can be called without opening the device
*
* @param[in] uid Unique ID assigned to the device
* @param[out] parent_info Parent device handle
* @param[out] port_num Parent port number
* @return esp_err_t
*/
esp_err_t usbh_devs_get_parent_info(unsigned int uid, usb_parent_dev_info_t *parent_info);
/**
* @brief Mark that all devices should be freed at the next possible opportunity
*
@ -243,16 +266,6 @@ esp_err_t usbh_devs_mark_all_free(void);
*/
esp_err_t usbh_devs_open(uint8_t dev_addr, usb_device_handle_t *dev_hdl);
/**
* @brief CLose a device
*
* Device can be opened by calling usbh_devs_open()
*
* @param[in] dev_hdl Device handle
* @return esp_err_t
*/
esp_err_t usbh_devs_close(usb_device_handle_t dev_hdl);
/**
* @brief Trigger a USBH_EVENT_NEW_DEV event for the device
*
@ -263,14 +276,23 @@ esp_err_t usbh_devs_close(usb_device_handle_t dev_hdl);
*/
esp_err_t usbh_devs_new_dev_event(usb_device_handle_t dev_hdl);
// ------------------------------------------------ Device Functions ---------------------------------------------------
// ------------------------ Device Functions -----------------------------------
// ----------------------- Getters -------------------------
/**
* @brief Close a device
*
* @note Callers of this function must have opened the device via usbh_devs_open()
* *
* @param[in] dev_hdl Device handle
* @return esp_err_t
*/
esp_err_t usbh_dev_close(usb_device_handle_t dev_hdl);
// ------------------------------ Getters --------------------------------------
/**
* @brief Get a device's address
*
* @note Can be called without opening the device
* @note Callers of this function must have opened the device via usbh_devs_open()
*
* @param[in] dev_hdl Device handle
* @param[out] dev_addr Device's address
@ -281,8 +303,10 @@ esp_err_t usbh_dev_get_addr(usb_device_handle_t dev_hdl, uint8_t *dev_addr);
/**
* @brief Get a device's information
*
* @note Callers of this function must have opened the device via usbh_devs_open()
* @note It is possible that the device has not been enumerated yet, thus some
* fields may be NULL.
*
* @param[in] dev_hdl Device handle
* @param[out] dev_info Device information
* @return esp_err_t
@ -292,7 +316,7 @@ esp_err_t usbh_dev_get_info(usb_device_handle_t dev_hdl, usb_device_info_t *dev_
/**
* @brief Get a device's device descriptor
*
* - The device descriptor is cached when the device is created by the Hub driver
* The device descriptor is cached when the device is created by the Hub driver
*
* @note It is possible that the device has not been enumerated yet, thus the
* device descriptor could be NULL.
@ -305,6 +329,7 @@ esp_err_t usbh_dev_get_desc(usb_device_handle_t dev_hdl, const usb_device_desc_t
/**
* @brief Get a device's active configuration descriptor
*
* @note Callers of this function must have opened the device via usbh_devs_open()
* Simply returns a reference to the internally cached configuration descriptor
*
* @note It is possible that the device has not been enumerated yet, thus the
@ -315,11 +340,13 @@ esp_err_t usbh_dev_get_desc(usb_device_handle_t dev_hdl, const usb_device_desc_t
*/
esp_err_t usbh_dev_get_config_desc(usb_device_handle_t dev_hdl, const usb_config_desc_t **config_desc_ret);
// ----------------------- Setters -------------------------
// ------------------------------- Setters -------------------------------------
/**
* @brief Lock a device for enumeration
*
* @note Callers of this function must have opened the device via usbh_devs_open()
*
* - A device's enumeration lock must be set before any of its enumeration fields
* (e.g., address, device/config descriptors) can be set/updated.
* - The caller must be the sole opener of the device (see 'usbh_devs_open()')
@ -333,6 +360,8 @@ esp_err_t usbh_dev_enum_lock(usb_device_handle_t dev_hdl);
/**
* @brief Release a device's enumeration lock
*
* @note Callers of this function must have opened the device via usbh_devs_open()
*
* @param[in] dev_hdl Device handle
* @return esp_err_t
*/
@ -344,8 +373,11 @@ esp_err_t usbh_dev_enum_unlock(usb_device_handle_t dev_hdl);
* Typically called during enumeration after obtaining the first 8 bytes of the
* device's descriptor.
*
* @note Callers of this function must have opened the device via usbh_devs_open()
*
* @note The device's enumeration lock must be set before calling this function
* (see 'usbh_dev_enum_lock()')
*
* @param[in] dev_hdl Device handle
* @param[in] wMaxPacketSize Maximum packet size
* @return esp_err_t
@ -355,13 +387,15 @@ esp_err_t usbh_dev_set_ep0_mps(usb_device_handle_t dev_hdl, uint16_t wMaxPacketS
/**
* @brief Set a device's address
*
* Typically called during enumeration after a SET_ADDRESSS request has be
* Typically called during enumeration after a SET_ADDRESS request has been
* sent to the device.
*
* @note Callers of this function must have opened the device via usbh_devs_open()
*
* @note The device's enumeration lock must be set before calling this function
* (see 'usbh_dev_enum_lock()')
* @param[in] dev_hdl Device handle
* @param[in] dev_addr
* @param[in] dev_addr Device address to set
* @return esp_err_t
*/
esp_err_t usbh_dev_set_addr(usb_device_handle_t dev_hdl, uint8_t dev_addr);
@ -372,8 +406,11 @@ esp_err_t usbh_dev_set_addr(usb_device_handle_t dev_hdl, uint8_t dev_addr);
* Typically called during enumeration after obtaining the device's descriptor
* via a GET_DESCRIPTOR request.
*
* @note Callers of this function must have opened the device via usbh_devs_open()
*
* @note The device's enumeration lock must be set before calling this function
* (see 'usbh_dev_enum_lock()')
*
* @param[in] dev_hdl Device handle
* @param[in] device_desc Device descriptor to copy
* @return esp_err_t
@ -386,8 +423,11 @@ esp_err_t usbh_dev_set_desc(usb_device_handle_t dev_hdl, const usb_device_desc_t
* Typically called during enumeration after obtaining the device's configuration
* descriptor via a GET_DESCRIPTOR request.
*
* @note Callers of this function must have opened the device via usbh_devs_open()
*
* @note The device's enumeration lock must be set before calling this function
* (see 'usbh_dev_enum_lock()')
*
* @param[in] dev_hdl Device handle
* @param[in] config_desc_full Configuration descriptor to copy
* @return esp_err_t
@ -400,8 +440,11 @@ esp_err_t usbh_dev_set_config_desc(usb_device_handle_t dev_hdl, const usb_config
* Typically called during enumeration after obtaining one of the device's string
* descriptor via a GET_DESCRIPTOR request.
*
* @note Callers of this function must have opened the device via usbh_devs_open()
*
* @note The device's enumeration lock must be set before calling this function
* (see 'usbh_dev_enum_lock()')
*
* @param[in] dev_hdl Device handle
* @param[in] str_desc String descriptor to copy
* @param[in] select Select string descriptor. 0/1/2 for Manufacturer/Product/Serial
@ -410,7 +453,7 @@ esp_err_t usbh_dev_set_config_desc(usb_device_handle_t dev_hdl, const usb_config
*/
esp_err_t usbh_dev_set_str_desc(usb_device_handle_t dev_hdl, const usb_str_desc_t *str_desc, int select);
// ----------------------------------------------- Endpoint Functions -------------------------------------------------
// ----------------------- Endpoint Functions ----------------------------------
/**
* @brief Allocate an endpoint on a device
@ -482,7 +525,7 @@ esp_err_t usbh_ep_command(usbh_ep_handle_t ep_hdl, usbh_ep_cmd_t command);
*/
void *usbh_ep_get_context(usbh_ep_handle_t ep_hdl);
// ----------------------------------------------- Transfer Functions --------------------------------------------------
// ------------------------- Transfer Functions --------------------------------
/**
* @brief Submit a control transfer (URB) to a device

View File

@ -853,7 +853,7 @@ esp_err_t usb_host_device_open(usb_host_client_handle_t client_hdl, uint8_t dev_
return ret;
already_opened:
ESP_ERROR_CHECK(usbh_devs_close(dev_hdl));
ESP_ERROR_CHECK(usbh_dev_close(dev_hdl));
exit:
return ret;
}
@ -895,7 +895,7 @@ esp_err_t usb_host_device_close(usb_host_client_handle_t client_hdl, usb_device_
_clear_client_opened_device(client_obj, dev_addr);
HOST_EXIT_CRITICAL();
ESP_ERROR_CHECK(usbh_devs_close(dev_hdl));
ESP_ERROR_CHECK(usbh_dev_close(dev_hdl));
ret = ESP_OK;
exit:
xSemaphoreGive(p_host_lib_obj->constant.mux_lock);

View File

@ -40,78 +40,79 @@ typedef struct device_s device_t;
typedef struct {
struct {
usbh_ep_cb_t ep_cb;
void *ep_cb_arg;
hcd_pipe_handle_t pipe_hdl;
device_t *dev; // Pointer to the device object that this endpoint is contained in
const usb_ep_desc_t *ep_desc; // This just stores a pointer endpoint descriptor inside the device's "config_desc"
} constant;
usbh_ep_cb_t ep_cb; /**< Endpoint callback is called when transfer in complete or error occurred */
void *ep_cb_arg; /**< Endpoint callback argument */
hcd_pipe_handle_t pipe_hdl; /**< Endpoint HCD pipe handle */
device_t *dev; /**< Pointer to the device object that this endpoint is contained in */
const usb_ep_desc_t *ep_desc; /**< This just stores a pointer endpoint descriptor inside the device's "config_desc" */
} constant; /**< Constant members. Do not change after installation thus do not require a critical section or mutex */
} endpoint_t;
struct device_s {
// Dynamic members require a critical section
struct {
TAILQ_ENTRY(device_s) tailq_entry;
TAILQ_ENTRY(device_s) tailq_entry; /**< Entry for the device object tailq */
union {
struct {
uint32_t in_pending_list: 1;
uint32_t is_gone: 1; // Device is gone (disconnected or port error)
uint32_t waiting_free: 1; // Device object is awaiting to be freed
uint32_t enum_lock: 1; // Device is locked for enumeration. Enum information (e.g., address, device/config desc etc) may change
uint32_t reserved28: 28;
uint32_t in_pending_list: 1; /**< Device is in pending list */
uint32_t is_gone: 1; /**< Device is gone (disconnected or port error) */
uint32_t waiting_free: 1; /**< Device object is awaiting to be freed */
uint32_t enum_lock: 1; /**< Device is locked for enumeration. Enum information (e.g., address, device/config desc etc) may change */
uint32_t reserved28: 28; /**< Reserved */
};
uint32_t val;
uint32_t val; /**< Device flags value */
} flags;
uint32_t action_flags;
int num_ctrl_xfers_inflight;
usb_device_state_t state;
uint32_t open_count;
} dynamic;
// Mux protected members must be protected by the USBH mux_lock when accessed
uint32_t action_flags; /**< Device action flags */
int num_ctrl_xfers_inflight; /**< Amount of ongoing Control transfers */
usb_device_state_t state; /**< Device state */
uint32_t open_count; /**< Amount of clients which opened this device */
} dynamic; /**< Dynamic members. Require a critical section */
struct {
/*
- Endpoint object pointers for each possible non-default endpoint
- All OUT EPs are listed before IN EPs (i.e., EP_NUM_MIN OUT ... EP_NUM_MAX OUT ... EP_NUM_MIN IN ... EP_NUM_MAX)
*/
endpoint_t *endpoints[NUM_NON_DEFAULT_EP];
} mux_protected;
} mux_protected; /**< Mutex protected members. Must be protected by the USBH mux_lock when accessed */
// Constant members do not require a critical section
struct {
// Assigned on device allocation and remain constant for the device's lifetime
hcd_pipe_handle_t default_pipe;
hcd_port_handle_t port_hdl;
usb_speed_t speed;
unsigned int uid;
hcd_pipe_handle_t default_pipe; /**< Pipe handle for Control EP0 */
hcd_port_handle_t port_hdl; /**< HCD port handle */
usb_device_handle_t parent_dev_hdl; /**< Device's parent device handle. NULL if device is connected to the root port */
uint8_t parent_port_num; /**< Device's parent port number. 0 if device connected to the root port */
usb_speed_t speed; /**< Device's speed */
unsigned int uid; /**< Device's Unique ID */
/*
These fields are can only be changed when enum_lock is set, thus can be treated as constant
*/
uint8_t address;
usb_device_desc_t *desc;
usb_config_desc_t *config_desc;
usb_str_desc_t *str_desc_manu;
usb_str_desc_t *str_desc_product;
usb_str_desc_t *str_desc_ser_num;
} constant;
uint8_t address; /**< Device's bus address */
usb_device_desc_t *desc; /**< Device's descriptor pointer */
usb_config_desc_t *config_desc; /**< Device's configuration descriptor pointer. NULL if not configured. */
usb_str_desc_t *str_desc_manu; /**< Device's Manufacturer string descriptor pointer */
usb_str_desc_t *str_desc_product; /**< Device's Product string descriptor pointer */
usb_str_desc_t *str_desc_ser_num; /**< Device's Serial string descriptor pointer */
} constant; /**< Constant members. Do not change after installation thus do not require a critical section or mutex */
};
typedef struct {
// Dynamic members require a critical section
struct {
TAILQ_HEAD(tailhead_devs, device_s) devs_idle_tailq; // Tailq of all enum and configured devices
TAILQ_HEAD(tailhead_devs_cb, device_s) devs_pending_tailq; // Tailq of devices that need to have their cb called
} dynamic;
// Mux protected members must be protected by the USBH mux_lock when accessed
TAILQ_HEAD(tailhead_devs, device_s) devs_idle_tailq; /**< Tailq of all enum and configured devices */
TAILQ_HEAD(tailhead_devs_cb, device_s) devs_pending_tailq; /**< Tailq of devices that need to have their cb called */
} dynamic; /**< Dynamic members. Require a critical section */
struct {
uint8_t num_device; // Number of enumerated devices
} mux_protected;
// Constant members do no change after installation thus do not require a critical section
uint8_t num_device; /**< Current number of device objects */
} mux_protected; /**< Mutex protected members. Must be protected by the USBH mux_lock when accessed */
struct {
usb_proc_req_cb_t proc_req_cb;
void *proc_req_cb_arg;
usbh_event_cb_t event_cb;
void *event_cb_arg;
SemaphoreHandle_t mux_lock;
} constant;
usb_proc_req_cb_t proc_req_cb; /**< USB Host process request callback. Refer to proc_req_callback() in usb_host.c */
void *proc_req_cb_arg; /**< USB Host process request callback argument */
usbh_event_cb_t event_cb; /**< USBH event callback */
void *event_cb_arg; /**< USBH event callback argument */
SemaphoreHandle_t mux_lock; /**< Mutex for protected members */
} constant; /**< Constant members. Do not change after installation thus do not require a critical section or mutex */
} usbh_t;
static usbh_t *p_usbh_obj = NULL;
@ -147,7 +148,9 @@ static bool epN_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_
static bool _dev_set_actions(device_t *dev_obj, uint32_t action_flags);
// ----------------------------------------------------- Helpers -------------------------------------------------------
// -----------------------------------------------------------------------------
// ---------------------------- Helpers ----------------------------------------
// -----------------------------------------------------------------------------
static device_t *_find_dev_from_uid(unsigned int uid)
{
@ -305,7 +308,9 @@ static bool transfer_check_usb_compliance(usb_transfer_t *transfer, usb_transfer
return true;
}
// --------------------------------------------------- Allocation ------------------------------------------------------
// -----------------------------------------------------------------------------
// ----------------------------- Allocation ------------------------------------
// -----------------------------------------------------------------------------
static esp_err_t endpoint_alloc(device_t *dev_obj, const usb_ep_desc_t *ep_desc, usbh_ep_config_t *ep_config, endpoint_t **ep_obj_ret)
{
@ -358,10 +363,7 @@ static void endpoint_free(endpoint_t *ep_obj)
heap_caps_free(ep_obj);
}
static esp_err_t device_alloc(unsigned int uid,
usb_speed_t speed,
hcd_port_handle_t port_hdl,
device_t **dev_obj_ret)
static esp_err_t device_alloc(usbh_dev_params_t *params, device_t **dev_obj_ret)
{
device_t *dev_obj = heap_caps_calloc(1, sizeof(device_t), MALLOC_CAP_DEFAULT);
if (dev_obj == NULL) {
@ -375,22 +377,23 @@ static esp_err_t device_alloc(unsigned int uid,
.callback_arg = (void *)dev_obj,
.context = (void *)dev_obj,
.ep_desc = NULL, // No endpoint descriptor means we're allocating a pipe for EP0
.dev_speed = speed,
.dev_speed = params->speed,
.dev_addr = 0,
};
hcd_pipe_handle_t default_pipe_hdl;
ret = hcd_pipe_alloc(port_hdl, &pipe_config, &default_pipe_hdl);
ret = hcd_pipe_alloc(params->root_port_hdl, &pipe_config, &default_pipe_hdl);
if (ret != ESP_OK) {
goto err;
}
// Initialize device object
dev_obj->dynamic.state = USB_DEVICE_STATE_DEFAULT;
dev_obj->constant.default_pipe = default_pipe_hdl;
dev_obj->constant.port_hdl = port_hdl;
dev_obj->constant.speed = speed;
dev_obj->constant.uid = uid;
dev_obj->constant.port_hdl = params->root_port_hdl;
dev_obj->constant.parent_dev_hdl = params->parent_dev_hdl;
dev_obj->constant.parent_port_num = params->parent_port_num;
dev_obj->constant.speed = params->speed;
dev_obj->constant.uid = params->uid;
// Note: Enumeration related dev_obj->constant fields are initialized later using usbh_dev_set_...() functions
// Write-back device object
*dev_obj_ret = dev_obj;
ret = ESP_OK;
@ -407,11 +410,11 @@ static void device_free(device_t *dev_obj)
if (dev_obj == NULL) {
return;
}
// Device descriptor might not have been set yet
// Device descriptor might not have been allocated (in case of early enumeration failure)
if (dev_obj->constant.desc) {
heap_caps_free(dev_obj->constant.desc);
}
// Configuration descriptor might not have been set yet
// Configuration might not have been allocated (in case of early enumeration failure)
if (dev_obj->constant.config_desc) {
heap_caps_free(dev_obj->constant.config_desc);
}
@ -429,7 +432,9 @@ static void device_free(device_t *dev_obj)
heap_caps_free(dev_obj);
}
// ---------------------------------------------------- Callbacks ------------------------------------------------------
// -----------------------------------------------------------------------------
// -------------------------- Callbacks ----------------------------------------
// -----------------------------------------------------------------------------
static bool ep0_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_event, void *user_arg, bool in_isr)
{
@ -487,7 +492,9 @@ static bool epN_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_
in_isr);
}
// -------------------------------------------------- Event Related ----------------------------------------------------
// -----------------------------------------------------------------------------
// ------------------------- Event Related -------------------------------------
// -----------------------------------------------------------------------------
static bool _dev_set_actions(device_t *dev_obj, uint32_t action_flags)
{
@ -581,6 +588,8 @@ static inline void handle_free(device_t *dev_obj)
{
// Cache a copy of the device's address as we are about to free the device object
const unsigned int dev_uid = dev_obj->constant.uid;
usb_device_handle_t parent_dev_hdl = dev_obj->constant.parent_dev_hdl;
const uint8_t parent_port_num = dev_obj->constant.parent_port_num;
bool all_free;
ESP_LOGD(USBH_TAG, "Freeing device %d", dev_obj->constant.address);
@ -605,6 +614,8 @@ static inline void handle_free(device_t *dev_obj)
.event = USBH_EVENT_DEV_FREE,
.dev_free_data = {
.dev_uid = dev_uid,
.parent_dev_hdl = parent_dev_hdl,
.port_num = parent_port_num,
}
};
p_usbh_obj->constant.event_cb(&event_data, p_usbh_obj->constant.event_cb_arg);
@ -629,7 +640,9 @@ static inline void handle_prop_new_dev(device_t *dev_obj)
p_usbh_obj->constant.event_cb(&event_data, p_usbh_obj->constant.event_cb_arg);
}
// -------------------------------------------- USBH Processing Functions ----------------------------------------------
// -----------------------------------------------------------------------------
// ------------------------- USBH Processing Functions -------------------------
// -----------------------------------------------------------------------------
esp_err_t usbh_install(const usbh_config_t *usbh_config)
{
@ -766,7 +779,9 @@ esp_err_t usbh_process(void)
return ESP_OK;
}
// ---------------------------------------------- Device Pool Functions ------------------------------------------------
// -----------------------------------------------------------------------------
// ------------------------- Device Pool Functions -----------------------------
// -----------------------------------------------------------------------------
esp_err_t usbh_devs_num(int *num_devs_ret)
{
@ -825,14 +840,15 @@ esp_err_t usbh_devs_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *nu
return ESP_OK;
}
esp_err_t usbh_devs_add(unsigned int uid, usb_speed_t dev_speed, hcd_port_handle_t port_hdl)
esp_err_t usbh_devs_add(usbh_dev_params_t *params)
{
USBH_CHECK(port_hdl != NULL, ESP_ERR_INVALID_ARG);
USBH_CHECK(params != NULL, ESP_ERR_NOT_ALLOWED);
USBH_CHECK(params->root_port_hdl != NULL, ESP_ERR_INVALID_ARG);
esp_err_t ret;
device_t *dev_obj;
// Allocate a device object (initialized to address 0)
ret = device_alloc(uid, dev_speed, port_hdl, &dev_obj);
ret = device_alloc(params, &dev_obj);
if (ret != ESP_OK) {
return ret;
}
@ -842,7 +858,7 @@ esp_err_t usbh_devs_add(unsigned int uid, usb_speed_t dev_speed, hcd_port_handle
USBH_ENTER_CRITICAL();
// Check that there is not already a device with the same uid
if (_find_dev_from_uid(uid) != NULL) {
if (_find_dev_from_uid(params->uid) != NULL) {
ret = ESP_ERR_INVALID_ARG;
goto exit;
}
@ -860,6 +876,11 @@ exit:
USBH_EXIT_CRITICAL();
xSemaphoreGive(p_usbh_obj->constant.mux_lock);
if (ret != ESP_OK) {
// Free dev_obj for memory not to leak
device_free(dev_obj);
}
return ret;
}
@ -901,6 +922,27 @@ exit:
return ret;
}
esp_err_t usbh_devs_get_parent_info(unsigned int uid, usb_parent_dev_info_t *parent_info)
{
USBH_CHECK(parent_info, ESP_ERR_INVALID_ARG);
esp_err_t ret = ESP_FAIL;
device_t *dev_obj = NULL;
USBH_ENTER_CRITICAL();
dev_obj = _find_dev_from_uid(uid);
if (dev_obj == NULL) {
ret = ESP_ERR_NOT_FOUND;
goto exit;
} else {
parent_info->dev_hdl = dev_obj->constant.parent_dev_hdl;
parent_info->port_num = dev_obj->constant.parent_port_num;
ret = ESP_OK;
}
exit:
USBH_EXIT_CRITICAL();
return ret;
}
esp_err_t usbh_devs_mark_all_free(void)
{
USBH_ENTER_CRITICAL();
@ -971,7 +1013,30 @@ esp_err_t usbh_devs_open(uint8_t dev_addr, usb_device_handle_t *dev_hdl)
return ret;
}
esp_err_t usbh_devs_close(usb_device_handle_t dev_hdl)
esp_err_t usbh_devs_new_dev_event(usb_device_handle_t dev_hdl)
{
device_t *dev_obj = (device_t *)dev_hdl;
bool call_proc_req_cb = false;
USBH_ENTER_CRITICAL();
// Device must be in the configured state
USBH_CHECK_FROM_CRIT(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED, ESP_ERR_INVALID_STATE);
call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_PROP_NEW_DEV);
USBH_EXIT_CRITICAL();
// Call the processing request callback
if (call_proc_req_cb) {
p_usbh_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_USBH, false, p_usbh_obj->constant.proc_req_cb_arg);
}
return ESP_OK;
}
// -----------------------------------------------------------------------------
// ---------------------------- Device Functions -------------------------------
// -----------------------------------------------------------------------------
esp_err_t usbh_dev_close(usb_device_handle_t dev_hdl)
{
USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG);
device_t *dev_obj = (device_t *)dev_hdl;
@ -1000,28 +1065,9 @@ esp_err_t usbh_devs_close(usb_device_handle_t dev_hdl)
return ESP_OK;
}
esp_err_t usbh_devs_new_dev_event(usb_device_handle_t dev_hdl)
{
device_t *dev_obj = (device_t *)dev_hdl;
bool call_proc_req_cb = false;
USBH_ENTER_CRITICAL();
// Device must be in the configured state
USBH_CHECK_FROM_CRIT(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED, ESP_ERR_INVALID_STATE);
call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_PROP_NEW_DEV);
USBH_EXIT_CRITICAL();
// Call the processing request callback
if (call_proc_req_cb) {
p_usbh_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_USBH, false, p_usbh_obj->constant.proc_req_cb_arg);
}
return ESP_OK;
}
// ------------------------------------------------ Device Functions ---------------------------------------------------
// ----------------------- Getters -------------------------
// -----------------------------------------------------------------------------
// ---------------------------- Getters ----------------------------------------
// -----------------------------------------------------------------------------
esp_err_t usbh_dev_get_addr(usb_device_handle_t dev_hdl, uint8_t *dev_addr)
{
@ -1029,7 +1075,6 @@ esp_err_t usbh_dev_get_addr(usb_device_handle_t dev_hdl, uint8_t *dev_addr)
device_t *dev_obj = (device_t *)dev_hdl;
USBH_ENTER_CRITICAL();
USBH_CHECK_FROM_CRIT(dev_obj->constant.address > 0, ESP_ERR_INVALID_STATE);
*dev_addr = dev_obj->constant.address;
USBH_EXIT_CRITICAL();
@ -1041,6 +1086,8 @@ esp_err_t usbh_dev_get_info(usb_device_handle_t dev_hdl, usb_device_info_t *dev_
USBH_CHECK(dev_hdl != NULL && dev_info != NULL, ESP_ERR_INVALID_ARG);
device_t *dev_obj = (device_t *)dev_hdl;
dev_info->parent.dev_hdl = dev_obj->constant.parent_dev_hdl;
dev_info->parent.port_num = dev_obj->constant.parent_port_num;
dev_info->speed = dev_obj->constant.speed;
dev_info->dev_addr = dev_obj->constant.address;
// Device descriptor might not have been set yet
@ -1067,7 +1114,6 @@ esp_err_t usbh_dev_get_desc(usb_device_handle_t dev_hdl, const usb_device_desc_t
{
USBH_CHECK(dev_hdl != NULL && dev_desc_ret != NULL, ESP_ERR_INVALID_ARG);
device_t *dev_obj = (device_t *)dev_hdl;
*dev_desc_ret = dev_obj->constant.desc;
return ESP_OK;
}
@ -1082,7 +1128,9 @@ esp_err_t usbh_dev_get_config_desc(usb_device_handle_t dev_hdl, const usb_config
return ESP_OK;
}
// ----------------------- Setters -------------------------
// -----------------------------------------------------------------------------
// -------------------------------- Setters ------------------------------------
// -----------------------------------------------------------------------------
esp_err_t usbh_dev_enum_lock(usb_device_handle_t dev_hdl)
{
@ -1330,7 +1378,9 @@ err:
return ret;
}
// ----------------------------------------------- Endpoint Functions -------------------------------------------------
// -----------------------------------------------------------------------------
// ----------------------------- Endpoint Functions ----------------------------
// -----------------------------------------------------------------------------
esp_err_t usbh_ep_alloc(usb_device_handle_t dev_hdl, usbh_ep_config_t *ep_config, usbh_ep_handle_t *ep_hdl_ret)
{
@ -1460,7 +1510,9 @@ void *usbh_ep_get_context(usbh_ep_handle_t ep_hdl)
return hcd_pipe_get_context(ep_obj->constant.pipe_hdl);
}
// ----------------------------------------------- Transfer Functions --------------------------------------------------
// -----------------------------------------------------------------------------
// ------------------------ Transfer Functions ---------------------------------
// -----------------------------------------------------------------------------
esp_err_t usbh_dev_submit_ctrl_urb(usb_device_handle_t dev_hdl, urb_t *urb)
{