diff --git a/components/usb/ext_hub.c b/components/usb/ext_hub.c index c771861b41..ef869d1dcd 100644 --- a/components/usb/ext_hub.c +++ b/components/usb/ext_hub.c @@ -1707,92 +1707,46 @@ esp_err_t ext_hub_port_get_speed(ext_hub_handle_t ext_hub_hdl, uint8_t port_num, // --------------------------- USB Chapter 11 ---------------------------------- // ----------------------------------------------------------------------------- -esp_err_t ext_hub_set_port_feature(ext_hub_handle_t ext_hub_hdl, uint8_t port_num, uint8_t feature) +esp_err_t ext_hub_class_request(ext_hub_handle_t ext_hub_hdl, ext_hub_request_data_t *data, void *user_arg) { EXT_HUB_ENTER_CRITICAL(); EXT_HUB_CHECK_FROM_CRIT(p_ext_hub_driver != NULL, ESP_ERR_NOT_ALLOWED); EXT_HUB_EXIT_CRITICAL(); + EXT_HUB_CHECK(data != NULL && ext_hub_hdl != NULL, ESP_ERR_INVALID_ARG); esp_err_t ret; - EXT_HUB_CHECK(ext_hub_hdl != NULL, ESP_ERR_INVALID_ARG); ext_hub_dev_t *ext_hub_dev = (ext_hub_dev_t *)ext_hub_hdl; usb_transfer_t *transfer = &ext_hub_dev->constant.ctrl_urb->transfer; - EXT_HUB_CHECK(port_num != 0 && port_num <= ext_hub_dev->constant.hub_desc->bNbrPorts, ESP_ERR_INVALID_SIZE); + EXT_HUB_CHECK(data->port_num != 0 && data->port_num <= ext_hub_dev->constant.hub_desc->bNbrPorts, ESP_ERR_INVALID_SIZE); EXT_HUB_CHECK(ext_hub_dev->single_thread.state == EXT_HUB_STATE_CONFIGURED || ext_hub_dev->single_thread.state == EXT_HUB_STATE_SUSPENDED, ESP_ERR_INVALID_STATE); - USB_SETUP_PACKET_INIT_SET_PORT_FEATURE((usb_setup_packet_t *)transfer->data_buffer, port_num, feature); - transfer->num_bytes = sizeof(usb_setup_packet_t); + switch (data->request) { + case USB_B_REQUEST_HUB_GET_PORT_STATUS: + USB_SETUP_PACKET_INIT_GET_PORT_STATUS((usb_setup_packet_t *)transfer->data_buffer, data->port_num); + transfer->num_bytes = sizeof(usb_setup_packet_t) + sizeof(usb_port_status_t); + ext_hub_dev->single_thread.stage = EXT_HUB_STAGE_CHECK_PORT_STATUS; + break; + case USB_B_REQUEST_HUB_SET_PORT_FEATURE: + USB_SETUP_PACKET_INIT_SET_PORT_FEATURE((usb_setup_packet_t *)transfer->data_buffer, data->port_num, data->feature); + transfer->num_bytes = sizeof(usb_setup_packet_t); + ext_hub_dev->single_thread.stage = EXT_HUB_STAGE_CHECK_PORT_FEATURE; + break; + case USB_B_REQUEST_HUB_CLEAR_FEATURE: + USB_SETUP_PACKET_INIT_CLEAR_PORT_FEATURE((usb_setup_packet_t *)transfer->data_buffer, data->port_num, data->feature); + transfer->num_bytes = sizeof(usb_setup_packet_t); + ext_hub_dev->single_thread.stage = EXT_HUB_STAGE_CHECK_PORT_FEATURE; + break; + default: + ESP_LOGE(EXT_HUB_TAG, "Request %X not supported", data->request); + return ESP_ERR_NOT_SUPPORTED; + } - ext_hub_dev->single_thread.stage = EXT_HUB_STAGE_CHECK_PORT_FEATURE; ret = usbh_dev_submit_ctrl_urb(ext_hub_dev->constant.dev_hdl, ext_hub_dev->constant.ctrl_urb); if (ret != ESP_OK) { - ESP_LOGE(EXT_HUB_TAG, "[%d:%d] Set port feature %#x, failed to submit ctrl urb: %s", - ext_hub_dev->constant.dev_addr, - port_num, - feature, - esp_err_to_name(ret)); - device_error(ext_hub_dev); - } - return ret; -} - -esp_err_t ext_hub_clear_port_feature(ext_hub_handle_t ext_hub_hdl, uint8_t port_num, uint8_t feature) -{ - EXT_HUB_ENTER_CRITICAL(); - EXT_HUB_CHECK_FROM_CRIT(p_ext_hub_driver != NULL, ESP_ERR_NOT_ALLOWED); - EXT_HUB_EXIT_CRITICAL(); - - esp_err_t ret; - EXT_HUB_CHECK(ext_hub_hdl != NULL, ESP_ERR_INVALID_ARG); - ext_hub_dev_t *ext_hub_dev = (ext_hub_dev_t *)ext_hub_hdl; - usb_transfer_t *transfer = &ext_hub_dev->constant.ctrl_urb->transfer; - - EXT_HUB_CHECK(port_num != 0 && port_num <= ext_hub_dev->constant.hub_desc->bNbrPorts, ESP_ERR_INVALID_SIZE); - EXT_HUB_CHECK(ext_hub_dev->single_thread.state == EXT_HUB_STATE_CONFIGURED || - ext_hub_dev->single_thread.state == EXT_HUB_STATE_SUSPENDED, ESP_ERR_INVALID_STATE); - - USB_SETUP_PACKET_INIT_CLEAR_PORT_FEATURE((usb_setup_packet_t *)transfer->data_buffer, port_num, feature); - transfer->num_bytes = sizeof(usb_setup_packet_t); - - ext_hub_dev->single_thread.stage = EXT_HUB_STAGE_CHECK_PORT_FEATURE; - ret = usbh_dev_submit_ctrl_urb(ext_hub_dev->constant.dev_hdl, ext_hub_dev->constant.ctrl_urb); - if (ret != ESP_OK) { - ESP_LOGE(EXT_HUB_TAG, "[%d:%d] Clear port feature %#x, failed to submit ctrl urb: %s", - ext_hub_dev->constant.dev_addr, - port_num, - feature, - esp_err_to_name(ret)); - device_error(ext_hub_dev); - } - return ret; -} - -esp_err_t ext_hub_get_port_status(ext_hub_handle_t ext_hub_hdl, uint8_t port_num) -{ - EXT_HUB_ENTER_CRITICAL(); - EXT_HUB_CHECK_FROM_CRIT(p_ext_hub_driver != NULL, ESP_ERR_NOT_ALLOWED); - EXT_HUB_EXIT_CRITICAL(); - - esp_err_t ret; - EXT_HUB_CHECK(ext_hub_hdl != NULL, ESP_ERR_INVALID_ARG); - ext_hub_dev_t *ext_hub_dev = (ext_hub_dev_t *)ext_hub_hdl; - usb_transfer_t *transfer = &ext_hub_dev->constant.ctrl_urb->transfer; - - EXT_HUB_CHECK(port_num != 0 && port_num <= ext_hub_dev->constant.hub_desc->bNbrPorts, ESP_ERR_INVALID_SIZE); - EXT_HUB_CHECK(ext_hub_dev->single_thread.state == EXT_HUB_STATE_CONFIGURED || - ext_hub_dev->single_thread.state == EXT_HUB_STATE_SUSPENDED, ESP_ERR_INVALID_STATE); - - USB_SETUP_PACKET_INIT_GET_PORT_STATUS((usb_setup_packet_t *)transfer->data_buffer, port_num); - transfer->num_bytes = sizeof(usb_setup_packet_t) + sizeof(usb_port_status_t); - - ext_hub_dev->single_thread.stage = EXT_HUB_STAGE_CHECK_PORT_STATUS; - ret = usbh_dev_submit_ctrl_urb(ext_hub_dev->constant.dev_hdl, ext_hub_dev->constant.ctrl_urb); - if (ret != ESP_OK) { - ESP_LOGE(EXT_HUB_TAG, "[%d:%d] Get port status, failed to submit ctrl urb: %s", - ext_hub_dev->constant.dev_addr, - port_num, + ESP_LOGE(EXT_HUB_TAG, "Request %X, port %d, feature %d: failed to submit ctrl urb: %s", + data->request, data->port_num, data->feature, esp_err_to_name(ret)); device_error(ext_hub_dev); } diff --git a/components/usb/ext_port.c b/components/usb/ext_port.c index efce9ed7de..e807dcbb38 100644 --- a/components/usb/ext_port.c +++ b/components/usb/ext_port.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -102,6 +102,8 @@ typedef struct { void *proc_req_cb_arg; /**< External Port process callback argument */ ext_port_event_cb_t event_cb; /**< External Port event callback */ void *event_cb_arg; /**< External Port event callback argument */ + ext_hub_request_cb_t hub_request_cb; /**< External Port Hub request callback */ + void *hub_request_cb_arg; /**< External Port Hub request callback argument */ } constant; /**< Constant members. Do not change after installation thus do not require a critical section or mutex */ } ext_port_driver_t; @@ -225,17 +227,25 @@ static inline bool port_has_finished_reset(ext_port_t *ext_port) * - ESP_ERR_INVALID_ARG: The parent hub handle couldn't be NULL * - ESP_ERR_INVALID_SIZE: The port number should be in a range: [1, .. , bNbrPort] * - ESP_ERR_INVALID_STATE: The parent hub device wasn't configured + * - ESP_ERR_NOT_SUPPORTED: The request type is not supported by the External Hub Driver * - ESP_OK: Status has been requested */ static esp_err_t port_request_status(ext_port_t* ext_port) { - esp_err_t ret = ext_hub_get_port_status(ext_port->constant.ext_hub_hdl, ext_port->constant.port_num); + ext_hub_request_data_t req_data = { + .request = USB_B_REQUEST_HUB_GET_PORT_STATUS, + .port_num = ext_port->constant.port_num, + }; + + esp_err_t ret = p_ext_port_driver->constant.hub_request_cb(ext_port->constant.ext_hub_hdl, + &req_data, + p_ext_port_driver->constant.hub_request_cb_arg); if (ret != ESP_OK) { return ret; } // Port is requesting status, lock the status ext_port->flags.status_lock = 1; - return ret; + return ESP_OK; } /** @@ -254,9 +264,15 @@ static esp_err_t port_request_status(ext_port_t* ext_port) */ static esp_err_t port_set_feature(ext_port_t *ext_port, const usb_hub_port_feature_t feature) { - esp_err_t ret = ext_hub_set_port_feature(ext_port->constant.ext_hub_hdl, - ext_port->constant.port_num, - feature); + ext_hub_request_data_t req_data = { + .request = USB_B_REQUEST_HUB_SET_PORT_FEATURE, + .port_num = ext_port->constant.port_num, + .feature = feature, + }; + + esp_err_t ret = p_ext_port_driver->constant.hub_request_cb(ext_port->constant.ext_hub_hdl, + &req_data, + p_ext_port_driver->constant.hub_request_cb_arg); if (ret != ESP_OK) { return ret; } @@ -293,9 +309,15 @@ static esp_err_t port_set_feature(ext_port_t *ext_port, const usb_hub_port_featu */ static esp_err_t port_clear_feature(ext_port_t *ext_port, const usb_hub_port_feature_t feature) { - esp_err_t ret = ext_hub_clear_port_feature(ext_port->constant.ext_hub_hdl, - ext_port->constant.port_num, - feature); + ext_hub_request_data_t req_data = { + .request = USB_B_REQUEST_HUB_CLEAR_FEATURE, + .port_num = ext_port->constant.port_num, + .feature = feature, + }; + + esp_err_t ret = p_ext_port_driver->constant.hub_request_cb(ext_port->constant.ext_hub_hdl, + &req_data, + p_ext_port_driver->constant.hub_request_cb_arg); if (ret != ESP_OK) { return ret; } @@ -684,7 +706,7 @@ static void handle_port_state(ext_port_t *ext_port) switch (curr_state) { case USB_PORT_STATE_NOT_CONFIGURED: new_state = USB_PORT_STATE_POWERED_OFF; - port_request_status(ext_port); + ESP_ERROR_CHECK(port_request_status(ext_port)); need_handling = true; break; case USB_PORT_STATE_POWERED_OFF: @@ -1302,6 +1324,10 @@ const ext_hub_port_driver_t ext_port_driver = { esp_err_t ext_port_install(const ext_port_driver_config_t *config) { EXT_PORT_CHECK(p_ext_port_driver == NULL, ESP_ERR_NOT_ALLOWED); + EXT_PORT_CHECK(config != NULL, ESP_ERR_INVALID_ARG); + EXT_PORT_CHECK(config->proc_req_cb != NULL, ESP_ERR_INVALID_ARG); + EXT_PORT_CHECK(config->event_cb != NULL, ESP_ERR_INVALID_ARG); + EXT_PORT_CHECK(config->hub_request_cb != NULL, ESP_ERR_INVALID_ARG); ext_port_driver_t *ext_port_drv = heap_caps_calloc(1, sizeof(ext_port_driver_t), MALLOC_CAP_DEFAULT); EXT_PORT_CHECK(ext_port_drv != NULL, ESP_ERR_NO_MEM); @@ -1311,6 +1337,8 @@ esp_err_t ext_port_install(const ext_port_driver_config_t *config) ext_port_drv->constant.proc_req_cb_arg = config->proc_req_cb_arg; ext_port_drv->constant.event_cb = config->event_cb; ext_port_drv->constant.event_cb_arg = config->event_cb_arg; + ext_port_drv->constant.hub_request_cb = config->hub_request_cb; + ext_port_drv->constant.hub_request_cb_arg = config->hub_request_cb_arg; TAILQ_INIT(&ext_port_drv->single_thread.pending_tailq); p_ext_port_driver = ext_port_drv; diff --git a/components/usb/hcd_dwc.c b/components/usb/hcd_dwc.c index af7de4a3e3..5197141d80 100644 --- a/components/usb/hcd_dwc.c +++ b/components/usb/hcd_dwc.c @@ -314,7 +314,7 @@ static inline bool _buffer_check_done(pipe_t *pipe) } #if (CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3) // The HW can't handle two transactions with preamble in one frame. - // TODO: IDF-15060 + // TODO: IDF-12986 if (pipe->ep_char.ls_via_fs_hub) { esp_rom_delay_us(1000); } @@ -1539,7 +1539,7 @@ static void pipe_set_ep_char(const hcd_pipe_config_t *pipe_config, usb_transfer_ ep_char->dev_addr = pipe_config->dev_addr; ep_char->ls_via_fs_hub = 0; if (pipe_idx > 0) { - // TODO: remove warning after IDF-15060 + // TODO: remove warning after IDF-12986 if (port_speed == USB_SPEED_FULL && pipe_config->dev_speed == USB_SPEED_LOW) { ESP_LOGW(HCD_DWC_TAG, "Low-speed, extra delay will be applied in ISR"); ep_char->ls_via_fs_hub = 1; diff --git a/components/usb/hub.c b/components/usb/hub.c index bfc8c4ad09..fe208b397e 100644 --- a/components/usb/hub.c +++ b/components/usb/hub.c @@ -536,6 +536,7 @@ esp_err_t hub_install(hub_config_t *hub_config, void **client_ret) ext_port_driver_config_t ext_port_config = { .proc_req_cb = ext_port_callback, .event_cb = ext_port_event_callback, + .hub_request_cb = ext_hub_class_request, }; ret = ext_port_install(&ext_port_config); if (ret != ESP_OK) { diff --git a/components/usb/private_include/ext_hub.h b/components/usb/private_include/ext_hub.h index 6b52b3d746..35ed928c09 100644 --- a/components/usb/private_include/ext_hub.h +++ b/components/usb/private_include/ext_hub.h @@ -34,6 +34,20 @@ typedef struct ext_hub_s *ext_hub_handle_t; */ typedef bool (*ext_hub_cb_t)(bool in_isr, void *user_arg); +/** + * @brief Specific data for Hub class specific request + */ +typedef struct { + usb_hub_class_request_t request; + uint8_t port_num; + uint8_t feature; +} ext_hub_request_data_t; + +/** + * @brief Callback used to indicate that the External Port driver requires a Hub class specific request + */ +typedef esp_err_t (*ext_hub_request_cb_t)(ext_hub_handle_t ext_hub_hdl, ext_hub_request_data_t *request_data, void *user_arg); + // ------------------------ External Port API typedefs ------------------------- /** @@ -273,54 +287,23 @@ esp_err_t ext_hub_port_get_speed(ext_hub_handle_t ext_hub_hdl, uint8_t port_num, // --------------------------- USB Chapter 11 ---------------------------------- /** - * @brief Set Port Feature request + * @brief USB Hub Class specific request * - * @param[in] ext_hub_hdl External Hub device handle - * @param[in] port_num Port number - * @param[in] feature Port Feature to set + * @note This function designed to be called from the External Port driver + * + * @param[in] ext_hub_hdl External Hub handle + * @param[in] data Request data + * @param[in] user_arg User argument * * @return - * - ESP_OK: Port's feature set successfully - * - ESP_ERR_NOT_ALLOWED: External Hub driver is not installed - * - ESP_ERR_INVALID_ARG: Invalid argument - * - ESP_ERR_INVALID_SIZE: External Hub port number out of the hub's range - * - ESP_ERR_INVALID_STATE: External Hub is not configured or suspended + * - ESP_ERR_NOT_ALLOWED if External Hub Driver is not installed + * - ESP_ERR_INVALID_ARG if invalid argument + * - ESP_ERR_INVALID_SIZE if port number is out of the hub's range + * - ESP_ERR_INVALID_STATE if the hub device wasn't configured + * - ESP_ERR_NOT_SUPPORTED if the request is not supported + * - ESP_OK if control transfer was successfully submitted */ -esp_err_t ext_hub_set_port_feature(ext_hub_handle_t ext_hub_hdl, uint8_t port_num, uint8_t feature); - -/** - * @brief Clear Port Feature request - * - * @param[in] ext_hub_hdl External Hub device handle - * @param[in] port_num Port number - * @param[in] feature Port Feature to clear - * - * @return - * - ESP_OK: Port's feature cleared successfully - * - ESP_ERR_NOT_ALLOWED: External Hub driver is not installed - * - ESP_ERR_INVALID_ARG: Invalid argument - * - ESP_ERR_INVALID_SIZE: External Hub port number out of the hub's range - * - ESP_ERR_INVALID_STATE: External Hub is not configured or suspended - */ -esp_err_t ext_hub_clear_port_feature(ext_hub_handle_t ext_hub_hdl, uint8_t port_num, uint8_t feature); - -/** - * @brief Get Port Status request - * - * Sends the request to retrieve port status data. - * Actual port status data could be requested by calling ext_hub_get_port_status() after request completion. - * - * @param[in] ext_hub_hdl External Hub device handle - * @param[in] port_num Port number - * - * @return - * - ESP_OK: Port's status obtained successfully - * - ESP_ERR_NOT_ALLOWED: External Hub driver is not installed - * - ESP_ERR_INVALID_ARG: Invalid argument - * - ESP_ERR_INVALID_SIZE: External Hub port number out of the hub's range - * - ESP_ERR_INVALID_STATE: External Hub is not configured or suspended - */ -esp_err_t ext_hub_get_port_status(ext_hub_handle_t ext_hub_hdl, uint8_t port_num); +esp_err_t ext_hub_class_request(ext_hub_handle_t ext_hub_hdl, ext_hub_request_data_t *data, void *user_arg); #ifdef __cplusplus } diff --git a/components/usb/private_include/ext_port.h b/components/usb/private_include/ext_port.h index 5795e41575..002bb68fe2 100644 --- a/components/usb/private_include/ext_port.h +++ b/components/usb/private_include/ext_port.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -72,6 +72,8 @@ typedef struct { void *proc_req_cb_arg; /**< External Port process callback argument */ ext_port_event_cb_t event_cb; /**< External Port event callback */ void *event_cb_arg; /**< External Port event callback argument */ + ext_hub_request_cb_t hub_request_cb; /**< External Port Hub request callback */ + void *hub_request_cb_arg; /**< External Port Hub request callback argument */ } ext_port_driver_config_t; /**