From 30681356d884250ffd2addc0557010fb9227f623 Mon Sep 17 00:00:00 2001 From: Roman Leonov Date: Wed, 8 May 2024 15:02:08 +0800 Subject: [PATCH] refactor(usbh): Updated USBH api for ENUM driver --- components/usb/hub.c | 23 +- components/usb/include/usb/usb_types_stack.h | 9 + components/usb/private_include/usbh.h | 93 +++++-- components/usb/usb_host.c | 4 +- components/usb/usbh.c | 244 +++++++++++-------- 5 files changed, 242 insertions(+), 131 deletions(-) diff --git a/components/usb/hub.c b/components/usb/hub.c index 2735ef5a46..a90b1f15c3 100644 --- a/components/usb/hub.c +++ b/components/usb/hub.c @@ -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(¶ms) != ESP_OK) { ESP_LOGE(HUB_DRIVER_TAG, "Failed to add device"); goto new_dev_err; } diff --git a/components/usb/include/usb/usb_types_stack.h b/components/usb/include/usb/usb_types_stack.h index 8b351063f4..bb2c290666 100644 --- a/components/usb/include/usb/usb_types_stack.h +++ b/components/usb/include/usb/usb_types_stack.h @@ -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 */ diff --git a/components/usb/private_include/usbh.h b/components/usb/private_include/usbh.h index a1b5b2a845..c4097ec107 100644 --- a/components/usb/private_include/usbh.h +++ b/components/usb/private_include/usbh.h @@ -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 diff --git a/components/usb/usb_host.c b/components/usb/usb_host.c index 7094839db6..47c312ccf4 100644 --- a/components/usb/usb_host.c +++ b/components/usb/usb_host.c @@ -863,7 +863,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; } @@ -905,7 +905,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); diff --git a/components/usb/usbh.c b/components/usb/usbh.c index b402e72a99..5d60bc543f 100644 --- a/components/usb/usbh.c +++ b/components/usb/usbh.c @@ -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) {