From b891aa044329a526f61faf0f99990ad1b2884941 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Tue, 9 May 2023 00:43:32 +0800 Subject: [PATCH 1/3] usb_host: Refactor USBH and USB Host Library calls to HCD This commit refactors the USBH and the USB Host Library in the following ways: - USBH now presents an abstraction of an endpoint (via usbh_ep_handle_t) - Added separate functions to enqueue/dequeue URBs to a particular endpoint - USB Host Library no longer calls HCD API directly. Calls USBH endpoint API instead. - Renamed "notif_cb" to "proc_req_cb" (Processing Request Callback) - This is to avoid confusion with FreerTOS task notifications and Host Library client event notifications. - The processing functions of each layer (i.e., "xxx_process()") request calls via the "proc_req_cb" - The main handling function (i.e., usb_host_lib_handle_events()) is responsible for calling the required "xxx_process()" of each layer --- components/usb/hcd_dwc.c | 10 + components/usb/hub.c | 20 +- components/usb/private_include/hcd.h | 13 +- components/usb/private_include/hub.h | 6 +- components/usb/private_include/usb_private.h | 20 +- components/usb/private_include/usbh.h | 157 +++- components/usb/usb_host.c | 325 ++++---- components/usb/usbh.c | 753 ++++++++++++------- 8 files changed, 819 insertions(+), 485 deletions(-) diff --git a/components/usb/hcd_dwc.c b/components/usb/hcd_dwc.c index 96671fbd05..5564cb760c 100644 --- a/components/usb/hcd_dwc.c +++ b/components/usb/hcd_dwc.c @@ -2045,6 +2045,16 @@ hcd_pipe_state_t hcd_pipe_get_state(hcd_pipe_handle_t pipe_hdl) return ret; } +unsigned int hcd_pipe_get_num_urbs(hcd_pipe_handle_t pipe_hdl) +{ + unsigned int ret; + pipe_t *pipe = (pipe_t *)pipe_hdl; + HCD_ENTER_CRITICAL(); + ret = pipe->num_urb_pending + pipe->num_urb_done; + HCD_EXIT_CRITICAL(); + return ret; +} + esp_err_t hcd_pipe_command(hcd_pipe_handle_t pipe_hdl, hcd_pipe_cmd_t command) { pipe_t *pipe = (pipe_t *)pipe_hdl; diff --git a/components/usb/hub.c b/components/usb/hub.c index 148c4820f7..5574921283 100644 --- a/components/usb/hub.c +++ b/components/usb/hub.c @@ -187,8 +187,8 @@ typedef struct { //Constant members do no change after installation thus do not require a critical section struct { hcd_port_handle_t root_port_hdl; - usb_notif_cb_t notif_cb; - void *notif_cb_arg; + usb_proc_req_cb_t proc_req_cb; + void *proc_req_cb_arg; } constant; } hub_driver_t; @@ -223,7 +223,7 @@ const char *HUB_DRIVER_TAG = "HUB"; * * - This callback is called from the context of the HCD, so any event handling should be deferred to hub_process() * - Under the current HCD implementation, this callback should only be ever be called in an ISR - * - This callback needs to call the notification to ensure hub_process() gets a chance to run + * - This callback needs to call proc_req_cb to ensure that hub_process() gets a chance to run * * @param port_hdl HCD port handle * @param port_event HCD port event @@ -237,7 +237,7 @@ static bool root_port_callback(hcd_port_handle_t port_hdl, hcd_port_event_t port * @brief HCD pipe callback for the default pipe of the device under enumeration * * - This callback is called from the context of the HCD, so any event handling should be deferred to hub_process() - * - This callback needs to call the notification to ensure hub_process() gets a chance to run + * - This callback needs to call proc_req_cb to ensure that hub_process() gets a chance to run * * @param pipe_hdl HCD pipe handle * @param pipe_event Pipe event @@ -251,7 +251,7 @@ static bool enum_dflt_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t * @brief USBH Hub driver request callback * * - This callback is called from the context of the USBH, so so any event handling should be deferred to hub_process() - * - This callback needs to call the notification to ensure hub_process() gets a chance to run + * - This callback needs to call proc_req_cb to ensure that hub_process() gets a chance to run * * @param port_hdl HCD port handle * @param hub_req Hub driver request @@ -756,7 +756,7 @@ static bool root_port_callback(hcd_port_handle_t port_hdl, hcd_port_event_t port p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ROOT_EVENT; HUB_DRIVER_EXIT_CRITICAL_SAFE(); assert(in_isr); //Currently, this callback should only ever be called from an ISR context - return p_hub_driver_obj->constant.notif_cb(USB_NOTIF_SOURCE_HUB, in_isr, p_hub_driver_obj->constant.notif_cb_arg);; + return p_hub_driver_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_HUB, in_isr, p_hub_driver_obj->constant.proc_req_cb_arg);; } static bool enum_dflt_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_event, void *user_arg, bool in_isr) @@ -765,7 +765,7 @@ static bool enum_dflt_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t HUB_DRIVER_ENTER_CRITICAL_SAFE(); p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT; HUB_DRIVER_EXIT_CRITICAL_SAFE(); - return p_hub_driver_obj->constant.notif_cb(USB_NOTIF_SOURCE_HUB, in_isr, p_hub_driver_obj->constant.notif_cb_arg); + return p_hub_driver_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_HUB, in_isr, p_hub_driver_obj->constant.proc_req_cb_arg); } static void usbh_hub_req_callback(hcd_port_handle_t port_hdl, usbh_hub_req_t hub_req, void *arg) @@ -788,7 +788,7 @@ static void usbh_hub_req_callback(hcd_port_handle_t port_hdl, usbh_hub_req_t hub } HUB_DRIVER_EXIT_CRITICAL(); - p_hub_driver_obj->constant.notif_cb(USB_NOTIF_SOURCE_HUB, false, p_hub_driver_obj->constant.notif_cb_arg); + p_hub_driver_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_HUB, false, p_hub_driver_obj->constant.proc_req_cb_arg); } // ---------------------- Handlers ------------------------- @@ -953,8 +953,8 @@ esp_err_t hub_install(hub_config_t *hub_config) hub_driver_obj->single_thread.enum_ctrl.stage = ENUM_STAGE_NONE; hub_driver_obj->single_thread.enum_ctrl.urb = enum_urb; hub_driver_obj->constant.root_port_hdl = port_hdl; - hub_driver_obj->constant.notif_cb = hub_config->notif_cb; - hub_driver_obj->constant.notif_cb_arg = hub_config->notif_cb_arg; + hub_driver_obj->constant.proc_req_cb = hub_config->proc_req_cb; + hub_driver_obj->constant.proc_req_cb_arg = hub_config->proc_req_cb_arg; HUB_DRIVER_ENTER_CRITICAL(); if (p_hub_driver_obj != NULL) { HUB_DRIVER_EXIT_CRITICAL(); diff --git a/components/usb/private_include/hcd.h b/components/usb/private_include/hcd.h index de0746461d..77380b8ddc 100644 --- a/components/usb/private_include/hcd.h +++ b/components/usb/private_include/hcd.h @@ -448,13 +448,24 @@ esp_err_t hcd_pipe_set_persist_reset(hcd_pipe_handle_t pipe_hdl); void *hcd_pipe_get_context(hcd_pipe_handle_t pipe_hdl); /** - * @brief Get the current sate of the pipe + * @brief Get the current state of the pipe * * @param pipe_hdl Pipe handle * @return hcd_pipe_state_t Current state of the pipe */ hcd_pipe_state_t hcd_pipe_get_state(hcd_pipe_handle_t pipe_hdl); +/** + * @brief Get the number of in-flight URBs in the pipe + * + * Returns the current number of URBs that have been enqueued (via hcd_urb_enqueue()) and have yet to be dequeued (via + * hcd_urb_dequeue()). + * + * @param pipe_hdl Pipe handle + * @return Number of in-flight URBs + */ +unsigned int hcd_pipe_get_num_urbs(hcd_pipe_handle_t pipe_hdl); + /** * @brief Execute a command on a particular pipe * diff --git a/components/usb/private_include/hub.h b/components/usb/private_include/hub.h index fad62817b8..1a8807bf51 100644 --- a/components/usb/private_include/hub.h +++ b/components/usb/private_include/hub.h @@ -22,8 +22,8 @@ extern "C" { * @brief Hub driver configuration */ typedef struct { - usb_notif_cb_t notif_cb; /**< Notification callback */ - void *notif_cb_arg; /**< Notification callback argument */ + usb_proc_req_cb_t proc_req_cb; /**< Processing request callback */ + void *proc_req_cb_arg; /**< Processing request callback argument */ } hub_config_t; // ---------------------------------------------- Hub Driver Functions ------------------------------------------------- @@ -77,7 +77,7 @@ esp_err_t hub_root_stop(void); * @brief Hub driver's processing function * * Hub driver handling function that must be called repeatdly to process the Hub driver's events. If blocking, the - * caller can block on the notification callback of source USB_NOTIF_SOURCE_HUB to run this function. + * caller can block on the notification callback of source USB_PROC_REQ_SOURCE_HUB to run this function. * * @return esp_err_t */ diff --git a/components/usb/private_include/usb_private.h b/components/usb/private_include/usb_private.h index aaa34a1667..1d177c5159 100644 --- a/components/usb/private_include/usb_private.h +++ b/components/usb/private_include/usb_private.h @@ -50,12 +50,24 @@ struct urb_s{ }; typedef struct urb_s urb_t; +/** + * @brief Processing request source + * + * Enum to indicate which layer of the USB Host stack requires processing. The main handling loop should then call that + * layer's processing function (i.e., xxx_process()). + */ typedef enum { - USB_NOTIF_SOURCE_USBH = 0x01, - USB_NOTIF_SOURCE_HUB = 0x02, -} usb_notif_source_t; + USB_PROC_REQ_SOURCE_USBH = 0x01, + USB_PROC_REQ_SOURCE_HUB = 0x02, +} usb_proc_req_source_t; -typedef bool (*usb_notif_cb_t)(usb_notif_source_t source, bool in_isr, void *context); +/** + * @brief Processing request callback + * + * Callback function provided to each layer of the USB Host stack so that each layer can request calls to their + * processing function. + */ +typedef bool (*usb_proc_req_cb_t)(usb_proc_req_source_t source, bool in_isr, void *context); // --------------------------------------------------- Allocation ------------------------------------------------------ diff --git a/components/usb/private_include/usbh.h b/components/usb/private_include/usbh.h index 35f0562130..1d033e4390 100644 --- a/components/usb/private_include/usbh.h +++ b/components/usb/private_include/usbh.h @@ -20,6 +20,13 @@ extern "C" { // ------------------------------------------------------ Types -------------------------------------------------------- +// ----------------------- Handles ------------------------- + +/** + * @brief Handle of a allocated endpoint + */ +typedef struct usbh_ep_handle_s * usbh_ep_handle_t; + // ----------------------- Events -------------------------- typedef enum { @@ -29,16 +36,18 @@ typedef enum { } usbh_event_t; /** - * @brief Hub driver requests + * @brief Endpoint events * - * Various requests of the Hub driver that the USBH can make. + * @note Optimization: Keep this identical to hcd_pipe_event_t */ typedef enum { - USBH_HUB_REQ_PORT_DISABLE, /**< Request that the Hub driver disable a particular port (occurs after a device - has been freed). Hub driver should respond with a USBH_HUB_EVENT_PORT_DISABLED */ - USBH_HUB_REQ_PORT_RECOVER, /**< Request that the Hub driver recovers a particular port (occurs after a gone - device has been freed). */ -} usbh_hub_req_t; + USBH_EP_EVENT_NONE, /**< The EP has no events (used to indicate no events when polling) */ + USBH_EP_EVENT_URB_DONE, /**< The EP has completed a URB. The URB can be dequeued */ + USBH_EP_EVENT_ERROR_XFER, /**< The EP encountered excessive errors when transferring a URB i.e., three three consecutive transaction errors (e.g., no ACK, bad CRC etc) */ + USBH_EP_EVENT_ERROR_URB_NOT_AVAIL, /**< The EP tried to execute a transfer but no URB was available */ + USBH_EP_EVENT_ERROR_OVERFLOW, /**< The EP received more data than requested. Usually a Packet babble error (i.e., an IN packet has exceeded the EP's MPS) */ + USBH_EP_EVENT_ERROR_STALL, /**< EP received a STALL response */ +} usbh_ep_event_t; /** * @brief Hub driver events for the USBH @@ -63,6 +72,31 @@ typedef enum { USBH_HUB_EVENT_PORT_DISABLED, /**< Previous USBH_HUB_REQ_PORT_DISABLE request completed */ } usbh_hub_event_t; +// ------------------ Requests/Commands -------------------- + +/** + * @brief Hub driver requests + * + * Various requests of the Hub driver that the USBH can make. + */ +typedef enum { + USBH_HUB_REQ_PORT_DISABLE, /**< Request that the Hub driver disable a particular port (occurs after a device + has been freed). Hub driver should respond with a USBH_HUB_EVENT_PORT_DISABLED */ + USBH_HUB_REQ_PORT_RECOVER, /**< Request that the Hub driver recovers a particular port (occurs after a gone + device has been freed). */ +} usbh_hub_req_t; + +/** + * @brief Endpoint commands + * + * @note Optimization: Keep this identical to hcd_pipe_cmd_t + */ +typedef enum { + USBH_EP_CMD_HALT, /**< Halt an active endpoint. Any currently executing URB will be canceled. Enqueued URBs are left untouched */ + USBH_EP_CMD_FLUSH, /**< Can only be called when halted. Will cause all enqueued URBs to be canceled */ + USBH_EP_CMD_CLEAR, /**< Causes a halted endpoint to become active again. Any enqueued URBs will being executing.*/ +} usbh_ep_cmd_t; + // ---------------------- Callbacks ------------------------ /** @@ -87,29 +121,37 @@ typedef void (*usbh_event_cb_t)(usb_device_handle_t dev_hdl, usbh_event_t usbh_e */ typedef void (*usbh_hub_req_cb_t)(hcd_port_handle_t port_hdl, usbh_hub_req_t hub_req, void *arg); +/** + * @brief Callback used to indicate an event on an endpoint + * + * Return whether to yield or not if called from an ISR. Always return false if not called from an ISR + */ +typedef bool (*usbh_ep_cb_t)(usbh_ep_handle_t ep_hdl, usbh_ep_event_t ep_event, void *arg, bool in_isr); + // ----------------------- Objects ------------------------- /** * @brief Configuration for an endpoint being allocated using usbh_ep_alloc() */ typedef struct { - const usb_ep_desc_t *ep_desc; /**< Endpoint descriptor */ - hcd_pipe_callback_t pipe_cb; /**< Endpoint's pipe callback */ - void *pipe_cb_arg; /**< Pipe callback argument */ - void *context; /**< Pipe context */ + uint8_t bInterfaceNumber; /**< Interface number */ + uint8_t bAlternateSetting; /**< Alternate setting number of the interface */ + uint8_t bEndpointAddress; /**< Endpoint address */ + usbh_ep_cb_t ep_cb; /**< Endpoint event callback */ + void *ep_cb_arg; /**< Endpoint callback argument */ + void *context; /**< Endpoint context */ } usbh_ep_config_t; /** * @brief USBH configuration used in usbh_install() */ typedef struct { - usb_notif_cb_t notif_cb; /**< Notification callback */ - void *notif_cb_arg; /**< Notification callback argument */ + usb_proc_req_cb_t proc_req_cb; /**< Processing request callback */ + void *proc_req_cb_arg; /**< Processing request callback argument */ usbh_ctrl_xfer_cb_t ctrl_xfer_cb; /**< Control transfer callback */ void *ctrl_xfer_cb_arg; /**< Control transfer callback argument */ usbh_event_cb_t event_cb; /**< USBH event callback */ void *event_cb_arg; /**< USBH event callback argument */ - hcd_config_t hcd_config; /**< HCD configuration */ } usbh_config_t; // ------------------------------------------------- USBH Functions ---------------------------------------------------- @@ -143,8 +185,8 @@ esp_err_t usbh_uninstall(void); * @brief USBH processing function * * - USBH processing function that must be called repeatedly to process USBH events - * - If blocking, the caller can block until a USB_NOTIF_SOURCE_USBH notification is received before running this - * function + * - If blocking, the caller can block until the proc_req_cb() is called with USB_PROC_REQ_SOURCE_USBH as the request + * source. The USB_PROC_REQ_SOURCE_USBH source indicates that this function should be called. * * @note This function can block * @return esp_err_t @@ -271,31 +313,84 @@ esp_err_t usbh_dev_submit_ctrl_urb(usb_device_handle_t dev_hdl, urb_t *urb); /** * @brief Allocate an endpoint on a device * - * Clients that have opened a device must call this function to allocate all endpoints in an interface that is claimed. - * The pipe handle of the endpoint is returned so that clients can use and control the pipe directly. + * This function allows clients to allocate a non-default endpoint (i.e., not EP0) on a connected device + * + * - A client must have opened the device using usbh_dev_open() before attempting to allocate an endpoint on the device + * - A client should call this function to allocate all endpoints in an interface that the client has claimed. + * - A client must allocate an endpoint using this function before attempting to communicate with it + * - Once the client allocates an endpoint, the client is now owns/manages the endpoint. No other client should use or + * deallocte the endpoint. * * @note This function can block - * @note Default pipes are owned by the USBH. For control transfers, use usbh_dev_submit_ctrl_urb() instead - * @note Device must be opened by the client first + * @note Default endpoints (EP0) are owned by the USBH. For control transfers, use usbh_dev_submit_ctrl_urb() instead * * @param[in] dev_hdl Device handle - * @param[in] ep_config - * @param[out] pipe_hdl_ret Pipe handle + * @param[in] ep_config Endpoint configuration + * @param[out] ep_hdl_ret Endpoint handle * @return esp_err_t */ -esp_err_t usbh_ep_alloc(usb_device_handle_t dev_hdl, usbh_ep_config_t *ep_config, hcd_pipe_handle_t *pipe_hdl_ret); +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); /** * @brief Free and endpoint on a device * - * Free an endpoint previously opened by usbh_ep_alloc() + * This function frees an endpoint previously allocated by the client using usbh_ep_alloc() + * + * - Only the client that allocated the endpoint should free it + * - The client must have halted and flushed the endpoint using usbh_ep_command() before attempting to free it + * - The client must ensure that there are no more function calls to the endpoint before freeing it * * @note This function can block - * @param[in] dev_hdl Device handle - * @param[in] bEndpointAddress Endpoint's address + * @param[in] ep_hdl Endpoint handle * @return esp_err_t */ -esp_err_t usbh_ep_free(usb_device_handle_t dev_hdl, uint8_t bEndpointAddress); +esp_err_t usbh_ep_free(usbh_ep_handle_t ep_hdl); + +/** + * @brief Get the handle of an endpoint using its address + * + * The endpoint must have been previously allocated using usbh_ep_alloc() + * + * @param[in] dev_hdl Device handle + * @param[in] bEndpointAddress Endpoint address + * @param[out] ep_hdl_ret Endpoint handle + * @return esp_err_t + */ +esp_err_t usbh_ep_get_handle(usb_device_handle_t dev_hdl, uint8_t bEndpointAddress, usbh_ep_handle_t *ep_hdl_ret); + +/** + * @brief Enqueue a URB to an endpoint + * + * The URB will remain enqueued until it completes (successfully or errors out). Use usbh_ep_dequeue_urb() to dequeue + * a completed URB. + * + * @param[in] ep_hdl Endpoint handle + * @param[in] urb URB to enqueue + * @return esp_err_t + */ +esp_err_t usbh_ep_enqueue_urb(usbh_ep_handle_t ep_hdl, urb_t *urb); + +/** + * @brief Dequeue a URB from an endpoint + * + * Dequeue a completed URB from an endpoint. The USBH_EP_EVENT_URB_DONE indicates that URBs can be dequeued + * + * @param[in] ep_hdl Endpoint handle + * @param[out] urb_ret Dequeued URB, or NULL if no more URBs to dequeue + * @return esp_err_t + */ +esp_err_t usbh_ep_dequeue_urb(usbh_ep_handle_t ep_hdl, urb_t **urb_ret); + +/** + * @brief Execute a command on a particular endpoint + * + * Endpoint commands allows executing a certain action on an endpoint (e.g., halting, flushing, clearing etc) + * + * @param[in] ep_hdl Endpoint handle + * @param[in] command Endpoint command + * @return esp_err_t + */ +esp_err_t usbh_ep_command(usbh_ep_handle_t ep_hdl, usbh_ep_cmd_t command); /** * @brief Get the context of an endpoint @@ -303,12 +398,10 @@ esp_err_t usbh_ep_free(usb_device_handle_t dev_hdl, uint8_t bEndpointAddress); * Get the context variable assigned to and endpoint on allocation. * * @note This function can block - * @param[in] dev_hdl Device handle - * @param[in] bEndpointAddress Endpoint's address - * @param[out] context_ret Context variable - * @return esp_err_t + * @param[in] ep_hdl Endpoint handle + * @return Endpoint context */ -esp_err_t usbh_ep_get_context(usb_device_handle_t dev_hdl, uint8_t bEndpointAddress, void **context_ret); +void *usbh_ep_get_context(usbh_ep_handle_t ep_hdl); // -------------------------------------------------- Hub Functions ---------------------------------------------------- diff --git a/components/usb/usb_host.c b/components/usb/usb_host.c index 5550711724..7e507a47f4 100644 --- a/components/usb/usb_host.c +++ b/components/usb/usb_host.c @@ -19,6 +19,7 @@ Warning: The USB Host Library API is still a beta version and may be subject to #include "esp_heap_caps.h" #include "hub.h" #include "usbh.h" +#include "hcd.h" #include "esp_private/usb_phy.h" #include "usb/usb_host.h" @@ -43,18 +44,17 @@ static portMUX_TYPE host_lock = portMUX_INITIALIZER_UNLOCKED; } \ }) -#define PROCESS_PENDING_FLAG_USBH 0x01 -#define PROCESS_PENDING_FLAG_HUB 0x02 -#define PROCESS_PENDING_FLAG_EVENT 0x04 +#define PROCESS_REQUEST_PENDING_FLAG_USBH 0x01 +#define PROCESS_REQUEST_PENDING_FLAG_HUB 0x02 -typedef struct endpoint_s endpoint_t; +typedef struct ep_wrapper_s ep_wrapper_t; typedef struct interface_s interface_t; typedef struct client_s client_t; -struct endpoint_s { +struct ep_wrapper_s { //Dynamic members require a critical section struct { - TAILQ_ENTRY(endpoint_s) tailq_entry; + TAILQ_ENTRY(ep_wrapper_s) tailq_entry; union { struct { uint32_t pending: 1; @@ -62,12 +62,11 @@ struct endpoint_s { }; } flags; uint32_t num_urb_inflight; - hcd_pipe_event_t last_event; + usbh_ep_event_t last_event; } dynamic; //Constant members do no change after claiming the interface thus do not require a critical section struct { - hcd_pipe_handle_t pipe_hdl; - const usb_ep_desc_t *ep_desc; + usbh_ep_handle_t ep_hdl; interface_t *intf_obj; } constant; }; @@ -82,7 +81,7 @@ struct interface_s { const usb_intf_desc_t *intf_desc; usb_device_handle_t dev_hdl; client_t *client_obj; - endpoint_t *endpoints[0]; + ep_wrapper_t *endpoints[0]; } constant; }; @@ -90,8 +89,8 @@ struct client_s { //Dynamic members require a critical section struct { TAILQ_ENTRY(client_s) tailq_entry; - TAILQ_HEAD(tailhead_pending_ep, endpoint_s) pending_ep_tailq; - TAILQ_HEAD(tailhead_idle_ep, endpoint_s) idle_ep_tailq; + TAILQ_HEAD(tailhead_pending_ep, ep_wrapper_s) pending_ep_tailq; + TAILQ_HEAD(tailhead_idle_ep, ep_wrapper_s) idle_ep_tailq; TAILQ_HEAD(tailhead_done_ctrl_xfers, urb_s) done_ctrl_xfer_tailq; union { struct { @@ -260,16 +259,16 @@ static void send_event_msg_to_clients(const usb_host_client_event_msg_t *event_m // ------------------- Library Related --------------------- -static bool notif_callback(usb_notif_source_t source, bool in_isr, void *arg) +static bool proc_req_callback(usb_proc_req_source_t source, bool in_isr, void *arg) { HOST_ENTER_CRITICAL_SAFE(); - //Store notification source + //Store the processing request source switch (source) { - case USB_NOTIF_SOURCE_USBH: - p_host_lib_obj->dynamic.process_pending_flags |= PROCESS_PENDING_FLAG_USBH; + case USB_PROC_REQ_SOURCE_USBH: + p_host_lib_obj->dynamic.process_pending_flags |= PROCESS_REQUEST_PENDING_FLAG_USBH; break; - case USB_NOTIF_SOURCE_HUB: - p_host_lib_obj->dynamic.process_pending_flags |= PROCESS_PENDING_FLAG_HUB; + case USB_PROC_REQ_SOURCE_HUB: + p_host_lib_obj->dynamic.process_pending_flags |= PROCESS_REQUEST_PENDING_FLAG_HUB; break; } bool yield = _unblock_lib(in_isr); @@ -333,19 +332,19 @@ static void dev_event_callback(usb_device_handle_t dev_hdl, usbh_event_t usbh_ev // ------------------- Client Related ---------------------- -static bool pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_event, void *user_arg, bool in_isr) +static bool endpoint_callback(usbh_ep_handle_t ep_hdl, usbh_ep_event_t ep_event, void *user_arg, bool in_isr) { - endpoint_t *ep_obj = (endpoint_t *)user_arg; - client_t *client_obj = (client_t *)ep_obj->constant.intf_obj->constant.client_obj; + ep_wrapper_t *ep_wrap = (ep_wrapper_t *)user_arg; + client_t *client_obj = (client_t *)ep_wrap->constant.intf_obj->constant.client_obj; HOST_ENTER_CRITICAL_SAFE(); //Store the event to be handled later. Note that we allow overwriting of events because more severe will halt the pipe prevent any further events. - ep_obj->dynamic.last_event = pipe_event; + ep_wrap->dynamic.last_event = ep_event; //Add the EP to the client's pending list if it's not in the list already - if (!ep_obj->dynamic.flags.pending) { - ep_obj->dynamic.flags.pending = 1; - TAILQ_REMOVE(&client_obj->dynamic.idle_ep_tailq, ep_obj, dynamic.tailq_entry); - TAILQ_INSERT_TAIL(&client_obj->dynamic.pending_ep_tailq, ep_obj, dynamic.tailq_entry); + if (!ep_wrap->dynamic.flags.pending) { + ep_wrap->dynamic.flags.pending = 1; + TAILQ_REMOVE(&client_obj->dynamic.idle_ep_tailq, ep_wrap, dynamic.tailq_entry); + TAILQ_INSERT_TAIL(&client_obj->dynamic.pending_ep_tailq, ep_wrap, dynamic.tailq_entry); } bool yield = _unblock_client(client_obj, in_isr); HOST_EXIT_CRITICAL_SAFE(); @@ -376,7 +375,16 @@ esp_err_t usb_host_install(const usb_host_config_t *config) TAILQ_INIT(&host_lib_obj->mux_protected.client_tailq); host_lib_obj->constant.event_sem = event_sem; host_lib_obj->constant.mux_lock = mux_lock; - //Setup the USB PHY if necessary (USB PHY driver will also enable the underlying Host Controller) + + /* + Install each layer of the Host stack (listed below) from the lowest layer to the highest + - USB PHY + - HCD + - USBH + - Hub + */ + + //Install USB PHY (if necessary). USB PHY driver will also enable the underlying Host Controller if (!config->skip_phy_setup) { //Host Library defaults to internal PHY usb_phy_config_t phy_config = { @@ -392,26 +400,34 @@ esp_err_t usb_host_install(const usb_host_config_t *config) goto phy_err; } } + + //Install HCD + hcd_config_t hcd_config = { + .intr_flags = config->intr_flags + }; + ret = hcd_install(&hcd_config); + if (ret != ESP_OK) { + goto hcd_err; + } + //Install USBH usbh_config_t usbh_config = { - .notif_cb = notif_callback, - .notif_cb_arg = NULL, + .proc_req_cb = proc_req_callback, + .proc_req_cb_arg = NULL, .ctrl_xfer_cb = ctrl_xfer_callback, .ctrl_xfer_cb_arg = NULL, .event_cb = dev_event_callback, .event_cb_arg = NULL, - .hcd_config = { - .intr_flags = config->intr_flags, - }, }; ret = usbh_install(&usbh_config); if (ret != ESP_OK) { goto usbh_err; } + //Install Hub hub_config_t hub_config = { - .notif_cb = notif_callback, - .notif_cb_arg = NULL, + .proc_req_cb = proc_req_callback, + .proc_req_cb_arg = NULL, }; ret = hub_install(&hub_config); if (ret != ESP_OK) { @@ -438,6 +454,8 @@ assign_err: hub_err: ESP_ERROR_CHECK(usbh_uninstall()); usbh_err: + ESP_ERROR_CHECK(hcd_uninstall()); +hcd_err: if (host_lib_obj->constant.phy_handle) { ESP_ERROR_CHECK(usb_del_phy(host_lib_obj->constant.phy_handle)); } @@ -466,19 +484,28 @@ esp_err_t usb_host_uninstall(void) //Stop the root hub ESP_ERROR_CHECK(hub_root_stop()); - //Uninstall Hub and USBH - ESP_ERROR_CHECK(hub_uninstall()); - ESP_ERROR_CHECK(usbh_uninstall()); + //Unassign the host library object HOST_ENTER_CRITICAL(); host_lib_t *host_lib_obj = p_host_lib_obj; p_host_lib_obj = NULL; HOST_EXIT_CRITICAL(); + /* + Uninstall each layer of the Host stack (listed below) from the highest layer to the lowest + - Hub + - USBH + - HCD + - USB PHY + */ + ESP_ERROR_CHECK(hub_uninstall()); + ESP_ERROR_CHECK(usbh_uninstall()); + ESP_ERROR_CHECK(hcd_uninstall()); //If the USB PHY was setup, then delete it if (host_lib_obj->constant.phy_handle) { ESP_ERROR_CHECK(usb_del_phy(host_lib_obj->constant.phy_handle)); } + //Free memory objects vSemaphoreDelete(host_lib_obj->constant.mux_lock); vSemaphoreDelete(host_lib_obj->constant.event_sem); @@ -508,10 +535,10 @@ esp_err_t usb_host_lib_handle_events(TickType_t timeout_ticks, uint32_t *event_f p_host_lib_obj->dynamic.flags.handling_events = 1; while (process_pending_flags) { HOST_EXIT_CRITICAL(); - if (process_pending_flags & PROCESS_PENDING_FLAG_USBH) { + if (process_pending_flags & PROCESS_REQUEST_PENDING_FLAG_USBH) { ESP_ERROR_CHECK(usbh_process()); } - if (process_pending_flags & PROCESS_PENDING_FLAG_HUB) { + if (process_pending_flags & PROCESS_REQUEST_PENDING_FLAG_HUB) { ESP_ERROR_CHECK(hub_process()); } HOST_ENTER_CRITICAL(); @@ -569,33 +596,34 @@ static void _handle_pending_ep(client_t *client_obj) //Handle each EP on the pending list while (!TAILQ_EMPTY(&client_obj->dynamic.pending_ep_tailq)) { //Get the next pending EP. - endpoint_t *ep_obj = TAILQ_FIRST(&client_obj->dynamic.pending_ep_tailq); - TAILQ_REMOVE(&client_obj->dynamic.pending_ep_tailq, ep_obj, dynamic.tailq_entry); - TAILQ_INSERT_TAIL(&client_obj->dynamic.idle_ep_tailq, ep_obj, dynamic.tailq_entry); - ep_obj->dynamic.flags.pending = 0; - hcd_pipe_event_t last_event = ep_obj->dynamic.last_event; + ep_wrapper_t *ep_wrap = TAILQ_FIRST(&client_obj->dynamic.pending_ep_tailq); + TAILQ_REMOVE(&client_obj->dynamic.pending_ep_tailq, ep_wrap, dynamic.tailq_entry); + TAILQ_INSERT_TAIL(&client_obj->dynamic.idle_ep_tailq, ep_wrap, dynamic.tailq_entry); + ep_wrap->dynamic.flags.pending = 0; + usbh_ep_event_t last_event = ep_wrap->dynamic.last_event; uint32_t num_urb_dequeued = 0; HOST_EXIT_CRITICAL(); //Handle pipe event switch (last_event) { - case HCD_PIPE_EVENT_ERROR_XFER: - case HCD_PIPE_EVENT_ERROR_URB_NOT_AVAIL: - case HCD_PIPE_EVENT_ERROR_OVERFLOW: - case HCD_PIPE_EVENT_ERROR_STALL: - //The pipe is now stalled. Flush all pending URBs - ESP_ERROR_CHECK(hcd_pipe_command(ep_obj->constant.pipe_hdl, HCD_PIPE_CMD_FLUSH)); + case USBH_EP_EVENT_ERROR_XFER: + case USBH_EP_EVENT_ERROR_URB_NOT_AVAIL: + case USBH_EP_EVENT_ERROR_OVERFLOW: + case USBH_EP_EVENT_ERROR_STALL: + //The endpoint is now stalled. Flush all pending URBs + ESP_ERROR_CHECK(usbh_ep_command(ep_wrap->constant.ep_hdl, USBH_EP_CMD_FLUSH)); //All URBs in this pipe are now retired waiting to be dequeued. Fall through to dequeue them __attribute__((fallthrough)); - case HCD_PIPE_EVENT_URB_DONE: { + case USBH_EP_EVENT_URB_DONE: { //Dequeue all URBs and run their transfer callback - urb_t *urb = hcd_urb_dequeue(ep_obj->constant.pipe_hdl); + urb_t *urb; + usbh_ep_dequeue_urb(ep_wrap->constant.ep_hdl, &urb); while (urb != NULL) { //Clear the transfer's inflight flag to indicate the transfer is no longer inflight urb->usb_host_inflight = false; urb->transfer.callback(&urb->transfer); num_urb_dequeued++; - urb = hcd_urb_dequeue(ep_obj->constant.pipe_hdl); + usbh_ep_dequeue_urb(ep_wrap->constant.ep_hdl, &urb); } break; } @@ -606,8 +634,8 @@ static void _handle_pending_ep(client_t *client_obj) HOST_ENTER_CRITICAL(); //Update the endpoint's number of URB's inflight - assert(num_urb_dequeued <= ep_obj->dynamic.num_urb_inflight); - ep_obj->dynamic.num_urb_inflight -= num_urb_dequeued; + assert(num_urb_dequeued <= ep_wrap->dynamic.num_urb_inflight); + ep_wrap->dynamic.num_urb_inflight -= num_urb_dequeued; } } @@ -920,52 +948,53 @@ esp_err_t usb_host_get_active_config_descriptor(usb_device_handle_t dev_hdl, con // ----------------------- Private ------------------------- -static esp_err_t endpoint_alloc(usb_device_handle_t dev_hdl, const usb_ep_desc_t *ep_desc, interface_t *intf_obj, endpoint_t **ep_obj_ret) +static esp_err_t ep_wrapper_alloc(usb_device_handle_t dev_hdl, const usb_ep_desc_t *ep_desc, interface_t *intf_obj, ep_wrapper_t **ep_wrap_ret) { - endpoint_t *ep_obj = heap_caps_calloc(1, sizeof(endpoint_t), MALLOC_CAP_DEFAULT); - if (ep_obj == NULL) { + ep_wrapper_t *ep_wrap = heap_caps_calloc(1, sizeof(ep_wrapper_t), MALLOC_CAP_DEFAULT); + if (ep_wrap == NULL) { return ESP_ERR_NO_MEM; } esp_err_t ret; + usbh_ep_handle_t ep_hdl; usbh_ep_config_t ep_config = { - .ep_desc = ep_desc, - .pipe_cb = pipe_callback, - .pipe_cb_arg = (void *)ep_obj, - .context = (void *)ep_obj, + .bInterfaceNumber = intf_obj->constant.intf_desc->bInterfaceNumber, + .bAlternateSetting = intf_obj->constant.intf_desc->bAlternateSetting, + .bEndpointAddress = ep_desc->bEndpointAddress, + .ep_cb = endpoint_callback, + .ep_cb_arg = (void *)ep_wrap, + .context = (void *)ep_wrap, }; - hcd_pipe_handle_t pipe_hdl; - ret = usbh_ep_alloc(dev_hdl, &ep_config, &pipe_hdl); + ret = usbh_ep_alloc(dev_hdl, &ep_config, &ep_hdl); if (ret != ESP_OK) { - goto ep_alloc_err; + goto alloc_err; } - //Initialize endpoint object - ep_obj->constant.pipe_hdl = pipe_hdl; - ep_obj->constant.ep_desc = ep_desc; - ep_obj->constant.intf_obj = intf_obj; + //Initialize endpoint wrapper item + ep_wrap->constant.ep_hdl = ep_hdl; + ep_wrap->constant.intf_obj = intf_obj; //Write back result - *ep_obj_ret = ep_obj; + *ep_wrap_ret = ep_wrap; ret = ESP_OK; return ret; -ep_alloc_err: - heap_caps_free(ep_obj); +alloc_err: + heap_caps_free(ep_wrap); return ret; } -static void endpoint_free(usb_device_handle_t dev_hdl, endpoint_t *ep_obj) +static void ep_wrapper_free(usb_device_handle_t dev_hdl, ep_wrapper_t *ep_wrap) { - if (ep_obj == NULL) { + if (ep_wrap == NULL) { return; } //Free the underlying endpoint - ESP_ERROR_CHECK(usbh_ep_free(dev_hdl, ep_obj->constant.ep_desc->bEndpointAddress)); - //Free the endpoint object - heap_caps_free(ep_obj); + ESP_ERROR_CHECK(usbh_ep_free(ep_wrap->constant.ep_hdl)); + //Free the endpoint wrapper item + heap_caps_free(ep_wrap); } static interface_t *interface_alloc(client_t *client_obj, usb_device_handle_t dev_hdl, const usb_intf_desc_t *intf_desc) { - interface_t *intf_obj = heap_caps_calloc(1, sizeof(interface_t) + (sizeof(endpoint_t *) * intf_desc->bNumEndpoints), MALLOC_CAP_DEFAULT); + interface_t *intf_obj = heap_caps_calloc(1, sizeof(interface_t) + (sizeof(ep_wrapper_t *) * intf_desc->bNumEndpoints), MALLOC_CAP_DEFAULT); if (intf_obj == NULL) { return NULL; } @@ -1011,18 +1040,18 @@ static esp_err_t interface_claim(client_t *client_obj, usb_device_handle_t dev_h ret = ESP_ERR_NOT_FOUND; goto ep_alloc_err; } - //Allocate the endpoint - endpoint_t *ep_obj; - ret = endpoint_alloc(dev_hdl, ep_desc, intf_obj, &ep_obj); + //Allocate the endpoint wrapper item + ep_wrapper_t *ep_wrap; + ret = ep_wrapper_alloc(dev_hdl, ep_desc, intf_obj, &ep_wrap); if (ret != ESP_OK) { goto ep_alloc_err; } //Fill the interface object with the allocated endpoints - intf_obj->constant.endpoints[i] = ep_obj; + intf_obj->constant.endpoints[i] = ep_wrap; } //Add interface object to client (safe because we have already taken the mutex) TAILQ_INSERT_TAIL(&client_obj->mux_protected.interface_tailq, intf_obj, mux_protected.tailq_entry); - //Add each endpoint to the client's endpoint list + //Add each endpoint wrapper item to the client's endpoint list HOST_ENTER_CRITICAL(); for (int i = 0; i < intf_desc->bNumEndpoints; i++) { TAILQ_INSERT_TAIL(&client_obj->dynamic.idle_ep_tailq, intf_obj->constant.endpoints[i], dynamic.tailq_entry); @@ -1035,7 +1064,7 @@ static esp_err_t interface_claim(client_t *client_obj, usb_device_handle_t dev_h ep_alloc_err: for (int i = 0; i < intf_desc->bNumEndpoints; i++) { - endpoint_free(dev_hdl, intf_obj->constant.endpoints[i]); + ep_wrapper_free(dev_hdl, intf_obj->constant.endpoints[i]); intf_obj->constant.endpoints[i] = NULL; } interface_free(intf_obj); @@ -1061,12 +1090,13 @@ static esp_err_t interface_release(client_t *client_obj, usb_device_handle_t dev } //Check that all endpoints in the interface are in a state to be freed + //Todo: Check that each EP is halted before allowing them to be freed (IDF-7273) HOST_ENTER_CRITICAL(); bool can_free = true; for (int i = 0; i < intf_obj->constant.intf_desc->bNumEndpoints; i++) { - endpoint_t *ep_obj = intf_obj->constant.endpoints[i]; + ep_wrapper_t *ep_wrap = intf_obj->constant.endpoints[i]; //Endpoint must not be on the pending list and must not have inflight URBs - if (ep_obj->dynamic.num_urb_inflight != 0 || ep_obj->dynamic.flags.pending) { + if (ep_wrap->dynamic.num_urb_inflight != 0 || ep_wrap->dynamic.flags.pending) { can_free = false; break; } @@ -1076,7 +1106,7 @@ static esp_err_t interface_release(client_t *client_obj, usb_device_handle_t dev ret = ESP_ERR_INVALID_STATE; goto exit; } - //Proceed to remove all endpoint objects from list + //Proceed to remove all endpoint wrapper items from the list for (int i = 0; i < intf_obj->constant.intf_desc->bNumEndpoints; i++) { TAILQ_REMOVE(&client_obj->dynamic.idle_ep_tailq, intf_obj->constant.endpoints[i], dynamic.tailq_entry); } @@ -1087,7 +1117,7 @@ static esp_err_t interface_release(client_t *client_obj, usb_device_handle_t dev //Free each endpoint in the interface for (int i = 0; i < intf_obj->constant.intf_desc->bNumEndpoints; i++) { - endpoint_free(dev_hdl, intf_obj->constant.endpoints[i]); + ep_wrapper_free(dev_hdl, intf_obj->constant.endpoints[i]); intf_obj->constant.endpoints[i] = NULL; } //Free the interface object itself @@ -1167,13 +1197,14 @@ esp_err_t usb_host_interface_release(usb_host_client_handle_t client_hdl, usb_de esp_err_t usb_host_endpoint_halt(usb_device_handle_t dev_hdl, uint8_t bEndpointAddress) { esp_err_t ret; - endpoint_t *ep_obj = NULL; - ret = usbh_ep_get_context(dev_hdl, bEndpointAddress, (void **)&ep_obj); + usbh_ep_handle_t ep_hdl; + + ret = usbh_ep_get_handle(dev_hdl, bEndpointAddress, &ep_hdl); if (ret != ESP_OK) { goto exit; } - assert(ep_obj != NULL); - ret = hcd_pipe_command(ep_obj->constant.pipe_hdl, HCD_PIPE_CMD_HALT); + ret = usbh_ep_command(ep_hdl, USBH_EP_CMD_HALT); + exit: return ret; } @@ -1181,13 +1212,14 @@ exit: esp_err_t usb_host_endpoint_flush(usb_device_handle_t dev_hdl, uint8_t bEndpointAddress) { esp_err_t ret; - endpoint_t *ep_obj = NULL; - ret = usbh_ep_get_context(dev_hdl, bEndpointAddress, (void **)&ep_obj); + usbh_ep_handle_t ep_hdl; + + ret = usbh_ep_get_handle(dev_hdl, bEndpointAddress, &ep_hdl); if (ret != ESP_OK) { goto exit; } - assert(ep_obj != NULL); - ret = hcd_pipe_command(ep_obj->constant.pipe_hdl, HCD_PIPE_CMD_FLUSH); + ret = usbh_ep_command(ep_hdl, USBH_EP_CMD_FLUSH); + exit: return ret; } @@ -1195,73 +1227,20 @@ exit: esp_err_t usb_host_endpoint_clear(usb_device_handle_t dev_hdl, uint8_t bEndpointAddress) { esp_err_t ret; - endpoint_t *ep_obj = NULL; - ret = usbh_ep_get_context(dev_hdl, bEndpointAddress, (void **)&ep_obj); + usbh_ep_handle_t ep_hdl; + + ret = usbh_ep_get_handle(dev_hdl, bEndpointAddress, &ep_hdl); if (ret != ESP_OK) { goto exit; } - assert(ep_obj != NULL); - ret = hcd_pipe_command(ep_obj->constant.pipe_hdl, HCD_PIPE_CMD_CLEAR); + ret = usbh_ep_command(ep_hdl, USBH_EP_CMD_CLEAR); + exit: return ret; } // ------------------------------------------------ Asynchronous I/O --------------------------------------------------- -// ----------------------- Private ------------------------- - -static bool transfer_check(usb_transfer_t *transfer, usb_transfer_type_t type, int mps, bool is_in) -{ - if (transfer->callback == NULL) { - ESP_LOGE(USB_HOST_TAG, "Transfer callback is NULL"); - return false; - } - //Check that the total transfer length does not exceed data buffer size - if (transfer->num_bytes > transfer->data_buffer_size) { - ESP_LOGE(USB_HOST_TAG, "Transfer num_bytes > data_buffer_size"); - return false; - } - if (type == USB_TRANSFER_TYPE_CTRL) { - //Check that num_bytes and wLength are set correctly - usb_setup_packet_t *setup_pkt = (usb_setup_packet_t *)transfer->data_buffer; - if (transfer->num_bytes != sizeof(usb_setup_packet_t) + setup_pkt->wLength) { - ESP_LOGE(USB_HOST_TAG, "Control transfer num_bytes wLength mismatch"); - return false; - } - } else if (type == USB_TRANSFER_TYPE_ISOCHRONOUS) { - //Check that there is at least one isochronous packet descriptor - if (transfer->num_isoc_packets <= 0) { - ESP_LOGE(USB_HOST_TAG, "ISOC transfer has 0 packet descriptors"); - return false; - } - //Check that sum of all packet lengths add up to transfer length - //If IN, check that each packet length is integer multiple of MPS - int total_num_bytes = 0; - bool mod_mps_all_zero = true; - for (int i = 0; i < transfer->num_isoc_packets; i++) { - total_num_bytes += transfer->isoc_packet_desc[i].num_bytes; - if (transfer->isoc_packet_desc[i].num_bytes % mps != 0) { - mod_mps_all_zero = false; - } - } - if (transfer->num_bytes != total_num_bytes) { - ESP_LOGE(USB_HOST_TAG, "ISOC transfer num_bytes not equal to total num_bytes of all packets"); - return false; - } - if (is_in && !mod_mps_all_zero) { - ESP_LOGE(USB_HOST_TAG, "ISOC IN transfer all packets num_bytes must be integer multiple of MPS"); - return false; - } - } else { - //Check that IN transfers are integer multiple of MPS - if (is_in && (transfer->num_bytes % mps != 0)) { - ESP_LOGE(USB_HOST_TAG, "IN transfer num_bytes must be integer multiple of MPS"); - return false; - } - } - return true; -} - // ----------------------- Public -------------------------- esp_err_t usb_host_transfer_alloc(size_t data_buffer_size, int num_isoc_packets, usb_transfer_t **transfer) @@ -1290,39 +1269,34 @@ esp_err_t usb_host_transfer_submit(usb_transfer_t *transfer) //Check that transfer and target endpoint are valid HOST_CHECK(transfer->device_handle != NULL, ESP_ERR_INVALID_ARG); //Target device must be set HOST_CHECK((transfer->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK) != 0, ESP_ERR_INVALID_ARG); - endpoint_t *ep_obj = NULL; + + usbh_ep_handle_t ep_hdl; + ep_wrapper_t *ep_wrap = NULL; urb_t *urb_obj = __containerof(transfer, urb_t, transfer); esp_err_t ret; - ret = usbh_ep_get_context(transfer->device_handle, transfer->bEndpointAddress, (void **)&ep_obj); + + ret = usbh_ep_get_handle(transfer->device_handle, transfer->bEndpointAddress, &ep_hdl); if (ret != ESP_OK) { goto err; } - assert(ep_obj != NULL); - HOST_CHECK(transfer_check(transfer, - USB_EP_DESC_GET_XFERTYPE(ep_obj->constant.ep_desc), - USB_EP_DESC_GET_MPS(ep_obj->constant.ep_desc), - transfer->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK), ESP_ERR_INVALID_ARG); + ep_wrap = usbh_ep_get_context(ep_hdl); + assert(ep_wrap != NULL); //Check that we are not submitting a transfer already inflight HOST_CHECK(!urb_obj->usb_host_inflight, ESP_ERR_NOT_FINISHED); urb_obj->usb_host_inflight = true; HOST_ENTER_CRITICAL(); - ep_obj->dynamic.num_urb_inflight++; + ep_wrap->dynamic.num_urb_inflight++; HOST_EXIT_CRITICAL(); - //Check if pipe is in a state to enqueue URBs - if (hcd_pipe_get_state(ep_obj->constant.pipe_hdl) != HCD_PIPE_STATE_ACTIVE) { - ret = ESP_ERR_INVALID_STATE; - goto hcd_err; - } - ret = hcd_urb_enqueue(ep_obj->constant.pipe_hdl, urb_obj); + + ret = usbh_ep_enqueue_urb(ep_hdl, urb_obj); if (ret != ESP_OK) { - goto hcd_err; + goto submit_err; } - ret = ESP_OK; return ret; -hcd_err: +submit_err: HOST_ENTER_CRITICAL(); - ep_obj->dynamic.num_urb_inflight--; + ep_wrap->dynamic.num_urb_inflight--; HOST_EXIT_CRITICAL(); urb_obj->usb_host_inflight = false; err: @@ -1332,17 +1306,12 @@ err: esp_err_t usb_host_transfer_submit_control(usb_host_client_handle_t client_hdl, usb_transfer_t *transfer) { HOST_CHECK(client_hdl != NULL && transfer != NULL, ESP_ERR_INVALID_ARG); - //Check that control transfer is valid HOST_CHECK(transfer->device_handle != NULL, ESP_ERR_INVALID_ARG); //Target device must be set - usb_device_handle_t dev_hdl = transfer->device_handle; - bool xfer_is_in = ((usb_setup_packet_t *)transfer->data_buffer)->bmRequestType & USB_BM_REQUEST_TYPE_DIR_IN; - usb_device_info_t dev_info; - ESP_ERROR_CHECK(usbh_dev_get_info(dev_hdl, &dev_info)); - HOST_CHECK(transfer_check(transfer, USB_TRANSFER_TYPE_CTRL, dev_info.bMaxPacketSize0, xfer_is_in), ESP_ERR_INVALID_ARG); //Control transfers must be targeted at EP 0 HOST_CHECK((transfer->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK) == 0, ESP_ERR_INVALID_ARG); + usb_device_handle_t dev_hdl = transfer->device_handle; urb_t *urb_obj = __containerof(transfer, urb_t, transfer); //Check that we are not submitting a transfer already inflight HOST_CHECK(!urb_obj->usb_host_inflight, ESP_ERR_NOT_FINISHED); diff --git a/components/usb/usbh.c b/components/usb/usbh.c index aad2f54def..d2bd9e4816 100644 --- a/components/usb/usbh.c +++ b/components/usb/usbh.c @@ -21,21 +21,35 @@ #include "usb/usb_helpers.h" #include "usb/usb_types_ch9.h" -//Device action flags. LISTED IN THE ORDER THEY SHOULD BE HANDLED IN within usbh_process(). Some actions are mutually exclusive -#define DEV_FLAG_ACTION_PIPE_HALT_AND_FLUSH 0x0001 //Halt all non-default pipes then flush them (called after a device gone is gone) -#define DEV_FLAG_ACTION_DEFAULT_PIPE_FLUSH 0x0002 //Retire all URBS in the default pipe -#define DEV_FLAG_ACTION_DEFAULT_PIPE_DEQUEUE 0x0004 //Dequeue all URBs from default pipe -#define DEV_FLAG_ACTION_DEFAULT_PIPE_CLEAR 0x0008 //Move the default pipe to the active state -#define DEV_FLAG_ACTION_SEND_GONE_EVENT 0x0010 //Send a USB_HOST_CLIENT_EVENT_DEV_GONE event -#define DEV_FLAG_ACTION_FREE 0x0020 //Free the device object -#define DEV_FLAG_ACTION_FREE_AND_RECOVER 0x0040 //Free the device object, but send a USBH_HUB_REQ_PORT_RECOVER request afterwards. -#define DEV_FLAG_ACTION_PORT_DISABLE 0x0080 //Request the hub driver to disable the port of the device -#define DEV_FLAG_ACTION_SEND_NEW 0x0100 //Send a new device event +#define EP_NUM_MIN 1 // The smallest possible non-default endpoint number +#define EP_NUM_MAX 16 // The largest possible non-default endpoint number +#define NUM_NON_DEFAULT_EP ((EP_NUM_MAX - 1) * 2) // The total number of non-default endpoints a device can have. -#define EP_NUM_MIN 1 -#define EP_NUM_MAX 16 +//Device action flags. LISTED IN THE ORDER THEY SHOULD BE HANDLED IN within usbh_process(). Some actions are mutually exclusive +typedef enum { + DEV_ACTION_EPn_HALT_FLUSH = (1 << 0), //Halt all non-default endpoints then flush them (called after a device gone is gone) + DEV_ACTION_EP0_FLUSH = (1 << 1), //Retire all URBS submitted to EP0 + DEV_ACTION_EP0_DEQUEUE = (1 << 2), //Dequeue all URBs from EP0 + DEV_ACTION_EP0_CLEAR = (1 << 3), //Move EP0 to the the active state + DEV_ACTION_PROP_GONE_EVT = (1 << 4), //Propagate a USBH_EVENT_DEV_GONE event + DEV_ACTION_FREE_AND_RECOVER = (1 << 5), //Free the device object, but send a USBH_HUB_REQ_PORT_RECOVER request afterwards. + DEV_ACTION_FREE = (1 << 6), //Free the device object + DEV_ACTION_PORT_DISABLE = (1 << 7), //Request the hub driver to disable the port of the device + DEV_ACTION_PROP_NEW = (1 << 8), //Propagate a USBH_EVENT_DEV_NEW event +} dev_action_t; 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; +} endpoint_t; + struct device_s { //Dynamic members require a critical section struct { @@ -58,10 +72,13 @@ struct device_s { } dynamic; //Mux protected members must be protected by the USBH mux_lock when accessed struct { - hcd_pipe_handle_t ep_in[EP_NUM_MAX - 1]; //IN EP owner contexts. -1 to exclude the default endpoint - hcd_pipe_handle_t ep_out[EP_NUM_MAX - 1]; //OUT EP owner contexts. -1 to exclude the default endpoint + /* + - 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; - //Constant members do no change after device allocation and enumeration thus do not require a critical section + //Constant members do not change after device allocation and enumeration thus do not require a critical section struct { hcd_pipe_handle_t default_pipe; hcd_port_handle_t port_hdl; @@ -87,8 +104,8 @@ typedef struct { } mux_protected; //Constant members do no change after installation thus do not require a critical section struct { - usb_notif_cb_t notif_cb; - void *notif_cb_arg; + usb_proc_req_cb_t proc_req_cb; + void *proc_req_cb_arg; usbh_hub_req_cb_t hub_req_cb; void *hub_req_cb_arg; usbh_event_cb_t event_cb; @@ -124,8 +141,173 @@ const char *USBH_TAG = "USBH"; } \ }) +// ------------------------------------------------- Forward Declare --------------------------------------------------- + +static bool ep0_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_event, void *user_arg, bool in_isr); + +static bool epN_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_event, void *user_arg, bool in_isr); + +static bool _dev_set_actions(device_t *dev_obj, uint32_t action_flags); + +// ----------------------------------------------------- Helpers ------------------------------------------------------- + +static inline bool check_ep_addr(uint8_t bEndpointAddress) +{ + /* + Check that the bEndpointAddress is valid + - Must be <= EP_NUM_MAX (e.g., 16) + - Must be >= EP_NUM_MIN (e.g., 1). + - EP0 is the owned/managed by USBH, thus must never by directly addressed by users (see USB 2.0 section 10.5.1.2) + */ + uint8_t addr = bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK; + return (addr >= EP_NUM_MIN) && (addr <= EP_NUM_MAX); +} + +static endpoint_t *get_ep_from_addr(device_t *dev_obj, uint8_t bEndpointAddress) +{ + /* + CALLER IS RESPONSIBLE FOR TAKING THE mux_lock + */ + + //Calculate index to the device's endpoint object list + int index; + // EP_NUM_MIN should map to an index of 0 + index = (bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK) - EP_NUM_MIN; + assert(index >= 0); // Endpoint address is not supported + if (bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK) { + //OUT EPs are listed before IN EPs, so add an offset + index += (EP_NUM_MAX - EP_NUM_MIN); + } + return dev_obj->mux_protected.endpoints[index]; +} + +static inline void set_ep_from_addr(device_t *dev_obj, uint8_t bEndpointAddress, endpoint_t *ep_obj) +{ + /* + CALLER IS RESPONSIBLE FOR TAKING THE mux_lock + */ + + //Calculate index to the device's endpoint object list + int index; + // EP_NUM_MIN should map to an index of 0 + index = (bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK) - EP_NUM_MIN; + assert(index >= 0); // Endpoint address is not supported + if (bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK) { + //OUT EPs are listed before IN EPs, so add an offset + index += (EP_NUM_MAX - EP_NUM_MIN); + } + dev_obj->mux_protected.endpoints[index] = ep_obj; +} + +static bool urb_check_args(urb_t *urb) +{ + if (urb->transfer.callback == NULL) { + ESP_LOGE(USBH_TAG, "usb_transfer_t callback is NULL"); + return false; + } + if (urb->transfer.num_bytes > urb->transfer.data_buffer_size) { + ESP_LOGE(USBH_TAG, "usb_transfer_t num_bytes > data_buffer_size"); + return false; + } + return true; +} + +static bool transfer_check_usb_compliance(usb_transfer_t *transfer, usb_transfer_type_t type, int mps, bool is_in) +{ + if (type == USB_TRANSFER_TYPE_CTRL) { + //Check that num_bytes and wLength are set correctly + usb_setup_packet_t *setup_pkt = (usb_setup_packet_t *)transfer->data_buffer; + if (transfer->num_bytes != sizeof(usb_setup_packet_t) + setup_pkt->wLength) { + ESP_LOGE(USBH_TAG, "usb_transfer_t num_bytes and usb_setup_packet_t wLength mismatch"); + return false; + } + } else if (type == USB_TRANSFER_TYPE_ISOCHRONOUS) { + //Check that there is at least one isochronous packet descriptor + if (transfer->num_isoc_packets <= 0) { + ESP_LOGE(USBH_TAG, "usb_transfer_t num_isoc_packets is 0"); + return false; + } + //Check that sum of all packet lengths add up to transfer length + //If IN, check that each packet length is integer multiple of MPS + int total_num_bytes = 0; + bool mod_mps_all_zero = true; + for (int i = 0; i < transfer->num_isoc_packets; i++) { + total_num_bytes += transfer->isoc_packet_desc[i].num_bytes; + if (transfer->isoc_packet_desc[i].num_bytes % mps != 0) { + mod_mps_all_zero = false; + } + } + if (transfer->num_bytes != total_num_bytes) { + ESP_LOGE(USBH_TAG, "ISOC transfer num_bytes != num_bytes of all packets"); + return false; + } + if (is_in && !mod_mps_all_zero) { + ESP_LOGE(USBH_TAG, "ISOC IN num_bytes not integer multiple of MPS"); + return false; + } + } else { + //Check that IN transfers are integer multiple of MPS + if (is_in && (transfer->num_bytes % mps != 0)) { + ESP_LOGE(USBH_TAG, "IN transfer num_bytes not integer multiple of MPS"); + return false; + } + } + return true; +} + // --------------------------------------------------- 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) +{ + esp_err_t ret; + endpoint_t *ep_obj; + hcd_pipe_handle_t pipe_hdl; + + ep_obj = heap_caps_calloc(1, sizeof(endpoint_t), MALLOC_CAP_DEFAULT); + if (ep_obj == NULL) { + return ESP_ERR_NO_MEM; + } + //Allocate the EP's underlying pipe + hcd_pipe_config_t pipe_config = { + .callback = epN_pipe_callback, + .callback_arg = (void *)ep_obj, + .context = ep_config->context, + .ep_desc = ep_desc, + .dev_speed = dev_obj->constant.speed, + .dev_addr = dev_obj->constant.address, + }; + ret = hcd_pipe_alloc(dev_obj->constant.port_hdl, &pipe_config, &pipe_hdl); + if (ret != ESP_OK) { + goto pipe_err; + } + //Initialize the endpoint object + ep_obj->constant.pipe_hdl = pipe_hdl; + ep_obj->constant.ep_cb = ep_config->ep_cb; + ep_obj->constant.ep_cb_arg = ep_config->ep_cb_arg; + ep_obj->constant.dev = dev_obj; + ep_obj->constant.ep_desc = ep_desc; + //Return the endpoint object + *ep_obj_ret = ep_obj; + + ret = ESP_OK; + return ret; + +pipe_err: + heap_caps_free(ep_obj); + return ret; +} + +static void endpoint_free(endpoint_t *ep_obj) +{ + if (ep_obj == NULL) { + return; + } + //Deallocate the EP's underlying pipe + ESP_ERROR_CHECK(hcd_pipe_free(ep_obj->constant.pipe_hdl)); + //Free the heap object + heap_caps_free(ep_obj); +} + static esp_err_t device_alloc(hcd_port_handle_t port_hdl, usb_speed_t speed, device_t **dev_obj_ret) { esp_err_t ret; @@ -135,12 +317,12 @@ static esp_err_t device_alloc(hcd_port_handle_t port_hdl, usb_speed_t speed, dev ret = ESP_ERR_NO_MEM; goto err; } - //Allocate default pipe. We set the pipe callback to NULL for now + //Allocate a pipe for EP0. We set the pipe callback to NULL for now hcd_pipe_config_t pipe_config = { .callback = NULL, .callback_arg = NULL, .context = (void *)dev_obj, - .ep_desc = NULL, //No endpoint descriptor means we're allocating a default pipe + .ep_desc = NULL, //No endpoint descriptor means we're allocating a pipe for EP0 .dev_speed = speed, .dev_addr = 0, }; @@ -190,44 +372,24 @@ static void device_free(device_t *dev_obj) heap_caps_free(dev_obj); } -// -------------------------------------------------- Event Related ---------------------------------------------------- +// ---------------------------------------------------- Callbacks ------------------------------------------------------ -static bool _dev_set_actions(device_t *dev_obj, uint32_t action_flags) -{ - if (action_flags == 0) { - return false; - } - bool call_notif_cb; - //Check if device is already on the callback list - if (!dev_obj->dynamic.flags.in_pending_list) { - //Move device form idle device list to callback device list - TAILQ_REMOVE(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry); - TAILQ_INSERT_TAIL(&p_usbh_obj->dynamic.devs_pending_tailq, dev_obj, dynamic.tailq_entry); - dev_obj->dynamic.action_flags |= action_flags; - dev_obj->dynamic.flags.in_pending_list = 1; - call_notif_cb = true; - } else { - call_notif_cb = false; - } - return call_notif_cb; -} - -static bool default_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_event, void *user_arg, bool in_isr) +static bool ep0_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_event, void *user_arg, bool in_isr) { uint32_t action_flags; device_t *dev_obj = (device_t *)user_arg; switch (pipe_event) { case HCD_PIPE_EVENT_URB_DONE: - //A control transfer completed on the default pipe. We need to dequeue it - action_flags = DEV_FLAG_ACTION_DEFAULT_PIPE_DEQUEUE; + //A control transfer completed on EP0's pipe . We need to dequeue it + action_flags = DEV_ACTION_EP0_DEQUEUE; break; case HCD_PIPE_EVENT_ERROR_XFER: case HCD_PIPE_EVENT_ERROR_URB_NOT_AVAIL: case HCD_PIPE_EVENT_ERROR_OVERFLOW: - //The default pipe has encountered an error. We need to retire all URBs, dequeue them, then make the pipe active again - action_flags = DEV_FLAG_ACTION_DEFAULT_PIPE_FLUSH | - DEV_FLAG_ACTION_DEFAULT_PIPE_DEQUEUE | - DEV_FLAG_ACTION_DEFAULT_PIPE_CLEAR; + //EP0's pipe has encountered an error. We need to retire all URBs, dequeue them, then make the pipe active again + action_flags = DEV_ACTION_EP0_FLUSH | + DEV_ACTION_EP0_DEQUEUE | + DEV_ACTION_EP0_CLEAR; if (in_isr) { ESP_EARLY_LOGE(USBH_TAG, "Dev %d EP 0 Error", dev_obj->constant.address); } else { @@ -235,8 +397,8 @@ static bool default_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t p } break; case HCD_PIPE_EVENT_ERROR_STALL: - //The default pipe encountered a "protocol stall". We just need to dequeue URBs then make the pipe active again - action_flags = DEV_FLAG_ACTION_DEFAULT_PIPE_DEQUEUE | DEV_FLAG_ACTION_DEFAULT_PIPE_CLEAR; + //EP0's pipe encountered a "protocol stall". We just need to dequeue URBs then make the pipe active again + action_flags = DEV_ACTION_EP0_DEQUEUE | DEV_ACTION_EP0_CLEAR; if (in_isr) { ESP_EARLY_LOGE(USBH_TAG, "Dev %d EP 0 STALL", dev_obj->constant.address); } else { @@ -249,36 +411,103 @@ static bool default_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t p } USBH_ENTER_CRITICAL_SAFE(); - bool call_notif_cb = _dev_set_actions(dev_obj, action_flags); + bool call_proc_req_cb = _dev_set_actions(dev_obj, action_flags); USBH_EXIT_CRITICAL_SAFE(); bool yield = false; - if (call_notif_cb) { - yield = p_usbh_obj->constant.notif_cb(USB_NOTIF_SOURCE_USBH, in_isr, p_usbh_obj->constant.notif_cb_arg); + if (call_proc_req_cb) { + yield = p_usbh_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_USBH, in_isr, p_usbh_obj->constant.proc_req_cb_arg); } return yield; } -static void handle_pipe_halt_and_flush(device_t *dev_obj) +static bool epN_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_event, void *user_arg, bool in_isr) +{ + endpoint_t *ep_obj = (endpoint_t *)user_arg; + return ep_obj->constant.ep_cb((usbh_ep_handle_t)ep_obj, + (usbh_ep_event_t)pipe_event, + ep_obj->constant.ep_cb_arg, + in_isr); +} + +// -------------------------------------------------- Event Related ---------------------------------------------------- + +static bool _dev_set_actions(device_t *dev_obj, uint32_t action_flags) +{ + if (action_flags == 0) { + return false; + } + bool call_proc_req_cb; + //Check if device is already on the callback list + if (!dev_obj->dynamic.flags.in_pending_list) { + //Move device form idle device list to callback device list + TAILQ_REMOVE(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry); + TAILQ_INSERT_TAIL(&p_usbh_obj->dynamic.devs_pending_tailq, dev_obj, dynamic.tailq_entry); + dev_obj->dynamic.action_flags |= action_flags; + dev_obj->dynamic.flags.in_pending_list = 1; + call_proc_req_cb = true; + } else { + call_proc_req_cb = false; + } + return call_proc_req_cb; +} + +static inline void handle_epn_halt_flush(device_t *dev_obj) { //We need to take the mux_lock to access mux_protected members xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); - //Halt then flush all non-default IN pipes - for (int i = 0; i < (EP_NUM_MAX - 1); i++) { - if (dev_obj->mux_protected.ep_in[i] != NULL) { - ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->mux_protected.ep_in[i], HCD_PIPE_CMD_HALT)); - ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->mux_protected.ep_in[i], HCD_PIPE_CMD_FLUSH)); - } - if (dev_obj->mux_protected.ep_out[i] != NULL) { - ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->mux_protected.ep_out[i], HCD_PIPE_CMD_HALT)); - ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->mux_protected.ep_out[i], HCD_PIPE_CMD_FLUSH)); + //Halt then flush all non-default EPs + for (int i = 0; i < NUM_NON_DEFAULT_EP; i++) { + if (dev_obj->mux_protected.endpoints[i] != NULL) { + ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->mux_protected.endpoints[i]->constant.pipe_hdl, HCD_PIPE_CMD_HALT)); + ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->mux_protected.endpoints[i]->constant.pipe_hdl, HCD_PIPE_CMD_FLUSH)); } } xSemaphoreGive(p_usbh_obj->constant.mux_lock); } -static bool handle_dev_free(device_t *dev_obj) +static inline void handle_ep0_flush(device_t *dev_obj) { + ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->constant.default_pipe, HCD_PIPE_CMD_HALT)); + ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->constant.default_pipe, HCD_PIPE_CMD_FLUSH)); +} + +static inline void handle_ep0_dequeue(device_t *dev_obj) +{ + //Empty URBs from EP0's pipe and call the control transfer callback + ESP_LOGD(USBH_TAG, "Default pipe device %d", dev_obj->constant.address); + int num_urbs = 0; + urb_t *urb = hcd_urb_dequeue(dev_obj->constant.default_pipe); + while (urb != NULL) { + num_urbs++; + p_usbh_obj->constant.ctrl_xfer_cb((usb_device_handle_t)dev_obj, urb, p_usbh_obj->constant.ctrl_xfer_cb_arg); + urb = hcd_urb_dequeue(dev_obj->constant.default_pipe); + } + USBH_ENTER_CRITICAL(); + dev_obj->dynamic.num_ctrl_xfers_inflight -= num_urbs; + USBH_EXIT_CRITICAL(); +} + +static inline void handle_ep0_clear(device_t *dev_obj) +{ + //We allow the pipe command to fail just in case the pipe becomes invalid mid command + hcd_pipe_command(dev_obj->constant.default_pipe, HCD_PIPE_CMD_CLEAR); +} + +static inline void handle_prop_gone_evt(device_t *dev_obj) +{ + //Flush EP0's pipe. Then propagate a USBH_EVENT_DEV_GONE event + ESP_LOGE(USBH_TAG, "Device %d gone", dev_obj->constant.address); + p_usbh_obj->constant.event_cb((usb_device_handle_t)dev_obj, USBH_EVENT_DEV_GONE, p_usbh_obj->constant.event_cb_arg); +} + +static void handle_free_and_recover(device_t *dev_obj, bool recover_port) +{ + //Cache a copy of the port handle as we are about to free the device object + bool all_free; + hcd_port_handle_t port_hdl = dev_obj->constant.port_hdl; + ESP_LOGD(USBH_TAG, "Freeing device %d", dev_obj->constant.address); + //We need to take the mux_lock to access mux_protected members xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); USBH_ENTER_CRITICAL(); @@ -291,10 +520,32 @@ static bool handle_dev_free(device_t *dev_obj) } USBH_EXIT_CRITICAL(); p_usbh_obj->mux_protected.num_device--; - bool all_free = (p_usbh_obj->mux_protected.num_device == 0); + all_free = (p_usbh_obj->mux_protected.num_device == 0); xSemaphoreGive(p_usbh_obj->constant.mux_lock); device_free(dev_obj); - return all_free; + + //If all devices have been freed, propagate a USBH_EVENT_DEV_ALL_FREE event + if (all_free) { + ESP_LOGD(USBH_TAG, "Device all free"); + p_usbh_obj->constant.event_cb((usb_device_handle_t)NULL, USBH_EVENT_DEV_ALL_FREE, p_usbh_obj->constant.event_cb_arg); + } + //Check if we need to recover the device's port + if (recover_port) { + p_usbh_obj->constant.hub_req_cb(port_hdl, USBH_HUB_REQ_PORT_RECOVER, p_usbh_obj->constant.hub_req_cb_arg); + } +} + +static inline void handle_port_disable(device_t *dev_obj) +{ + //Request that the HUB disables this device's port + ESP_LOGD(USBH_TAG, "Disable device port %d", dev_obj->constant.address); + p_usbh_obj->constant.hub_req_cb(dev_obj->constant.port_hdl, USBH_HUB_REQ_PORT_DISABLE, p_usbh_obj->constant.hub_req_cb_arg); +} + +static inline void handle_prop_new_evt(device_t *dev_obj) +{ + ESP_LOGD(USBH_TAG, "New device %d", dev_obj->constant.address); + p_usbh_obj->constant.event_cb((usb_device_handle_t)dev_obj, USBH_EVENT_DEV_NEW, p_usbh_obj->constant.event_cb_arg); } // ------------------------------------------------- USBH Functions ---------------------------------------------------- @@ -311,30 +562,25 @@ esp_err_t usbh_install(const usbh_config_t *usbh_config) SemaphoreHandle_t mux_lock = xSemaphoreCreateMutex(); if (usbh_obj == NULL || mux_lock == NULL) { ret = ESP_ERR_NO_MEM; - goto alloc_err; + goto err; } - //Install HCD - ret = hcd_install(&usbh_config->hcd_config); - if (ret != ESP_OK) { - goto hcd_install_err; - } - //Initialize usbh object + //Initialize USBH object TAILQ_INIT(&usbh_obj->dynamic.devs_idle_tailq); TAILQ_INIT(&usbh_obj->dynamic.devs_pending_tailq); - usbh_obj->constant.notif_cb = usbh_config->notif_cb; - usbh_obj->constant.notif_cb_arg = usbh_config->notif_cb_arg; + usbh_obj->constant.proc_req_cb = usbh_config->proc_req_cb; + usbh_obj->constant.proc_req_cb_arg = usbh_config->proc_req_cb_arg; usbh_obj->constant.event_cb = usbh_config->event_cb; usbh_obj->constant.event_cb_arg = usbh_config->event_cb_arg; usbh_obj->constant.ctrl_xfer_cb = usbh_config->ctrl_xfer_cb; usbh_obj->constant.ctrl_xfer_cb_arg = usbh_config->ctrl_xfer_cb_arg; usbh_obj->constant.mux_lock = mux_lock; - //Assign usbh object pointer + //Assign USBH object pointer USBH_ENTER_CRITICAL(); if (p_usbh_obj != NULL) { USBH_EXIT_CRITICAL(); ret = ESP_ERR_INVALID_STATE; - goto assign_err; + goto err; } p_usbh_obj = usbh_obj; USBH_EXIT_CRITICAL(); @@ -342,10 +588,7 @@ esp_err_t usbh_install(const usbh_config_t *usbh_config) ret = ESP_OK; return ret; -assign_err: - ESP_ERROR_CHECK(hcd_uninstall()); -hcd_install_err: -alloc_err: +err: if (mux_lock != NULL) { vSemaphoreDelete(mux_lock); } @@ -376,8 +619,7 @@ esp_err_t usbh_uninstall(void) USBH_EXIT_CRITICAL(); xSemaphoreGive(usbh_obj->constant.mux_lock); - //Uninstall HCD, free resources - ESP_ERROR_CHECK(hcd_uninstall()); + //Free resources vSemaphoreDelete(usbh_obj->constant.mux_lock); heap_caps_free(usbh_obj); ret = ESP_OK; @@ -392,7 +634,7 @@ esp_err_t usbh_process(void) { USBH_ENTER_CRITICAL(); USBH_CHECK_FROM_CRIT(p_usbh_obj != NULL, ESP_ERR_INVALID_STATE); - //Keep clearing devices with events + //Keep processing until all device's with pending events have been handled while (!TAILQ_EMPTY(&p_usbh_obj->dynamic.devs_pending_tailq)){ //Move the device back into the idle device list, device_t *dev_obj = TAILQ_FIRST(&p_usbh_obj->dynamic.devs_pending_tailq); @@ -409,37 +651,22 @@ esp_err_t usbh_process(void) USBH_EXIT_CRITICAL(); ESP_LOGD(USBH_TAG, "Processing actions 0x%"PRIx32"", action_flags); //Sanity check. If the device is being freed, there must not be any other action flags set - assert(!(action_flags & DEV_FLAG_ACTION_FREE) || action_flags == DEV_FLAG_ACTION_FREE); + assert(!(action_flags & DEV_ACTION_FREE) || action_flags == DEV_ACTION_FREE); - if (action_flags & DEV_FLAG_ACTION_PIPE_HALT_AND_FLUSH) { - handle_pipe_halt_and_flush(dev_obj); + if (action_flags & DEV_ACTION_EPn_HALT_FLUSH) { + handle_epn_halt_flush(dev_obj); } - if (action_flags & DEV_FLAG_ACTION_DEFAULT_PIPE_FLUSH) { - ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->constant.default_pipe, HCD_PIPE_CMD_HALT)); - ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->constant.default_pipe, HCD_PIPE_CMD_FLUSH)); + if (action_flags & DEV_ACTION_EP0_FLUSH) { + handle_ep0_flush(dev_obj); } - if (action_flags & DEV_FLAG_ACTION_DEFAULT_PIPE_DEQUEUE) { - //Empty URBs from default pipe and trigger a control transfer callback - ESP_LOGD(USBH_TAG, "Default pipe device %d", dev_obj->constant.address); - int num_urbs = 0; - urb_t *urb = hcd_urb_dequeue(dev_obj->constant.default_pipe); - while (urb != NULL) { - num_urbs++; - p_usbh_obj->constant.ctrl_xfer_cb((usb_device_handle_t)dev_obj, urb, p_usbh_obj->constant.ctrl_xfer_cb_arg); - urb = hcd_urb_dequeue(dev_obj->constant.default_pipe); - } - USBH_ENTER_CRITICAL(); - dev_obj->dynamic.num_ctrl_xfers_inflight -= num_urbs; - USBH_EXIT_CRITICAL(); + if (action_flags & DEV_ACTION_EP0_DEQUEUE) { + handle_ep0_dequeue(dev_obj); } - if (action_flags & DEV_FLAG_ACTION_DEFAULT_PIPE_CLEAR) { - //We allow the pipe command to fail just in case the pipe becomes invalid mid command - hcd_pipe_command(dev_obj->constant.default_pipe, HCD_PIPE_CMD_CLEAR); + if (action_flags & DEV_ACTION_EP0_CLEAR) { + handle_ep0_clear(dev_obj); } - if (action_flags & DEV_FLAG_ACTION_SEND_GONE_EVENT) { - //Flush the default pipe. Then do an event gone - ESP_LOGE(USBH_TAG, "Device %d gone", dev_obj->constant.address); - p_usbh_obj->constant.event_cb((usb_device_handle_t)dev_obj, USBH_EVENT_DEV_GONE, p_usbh_obj->constant.event_cb_arg); + if (action_flags & DEV_ACTION_PROP_GONE_EVT) { + handle_prop_gone_evt(dev_obj); } /* Note: We make these action flags mutually exclusive in case they happen in rapid succession. They are handled @@ -448,25 +675,14 @@ esp_err_t usbh_process(void) - New device event is requested followed immediately by a disconnection - Port disable requested followed immediately by a disconnection */ - if (action_flags & (DEV_FLAG_ACTION_FREE | DEV_FLAG_ACTION_FREE_AND_RECOVER)) { - //Cache a copy of the port handle as we are about to free the device object - hcd_port_handle_t port_hdl = dev_obj->constant.port_hdl; - ESP_LOGD(USBH_TAG, "Freeing device %d", dev_obj->constant.address); - if (handle_dev_free(dev_obj)) { - ESP_LOGD(USBH_TAG, "Device all free"); - p_usbh_obj->constant.event_cb((usb_device_handle_t)NULL, USBH_EVENT_DEV_ALL_FREE, p_usbh_obj->constant.event_cb_arg); - } - //Check if we need to recover the device's port - if (action_flags & DEV_FLAG_ACTION_FREE_AND_RECOVER) { - p_usbh_obj->constant.hub_req_cb(port_hdl, USBH_HUB_REQ_PORT_RECOVER, p_usbh_obj->constant.hub_req_cb_arg); - } - } else if (action_flags & DEV_FLAG_ACTION_PORT_DISABLE) { - //Request that the HUB disables this device's port - ESP_LOGD(USBH_TAG, "Disable device port %d", dev_obj->constant.address); - p_usbh_obj->constant.hub_req_cb(dev_obj->constant.port_hdl, USBH_HUB_REQ_PORT_DISABLE, p_usbh_obj->constant.hub_req_cb_arg); - } else if (action_flags & DEV_FLAG_ACTION_SEND_NEW) { - ESP_LOGD(USBH_TAG, "New device %d", dev_obj->constant.address); - p_usbh_obj->constant.event_cb((usb_device_handle_t)dev_obj, USBH_EVENT_DEV_NEW, p_usbh_obj->constant.event_cb_arg); + if (action_flags & DEV_ACTION_FREE_AND_RECOVER) { + handle_free_and_recover(dev_obj, true); + } else if (action_flags & DEV_ACTION_FREE) { + handle_free_and_recover(dev_obj, false); + } else if (action_flags & DEV_ACTION_PORT_DISABLE) { + handle_port_disable(dev_obj); + } else if (action_flags & DEV_ACTION_PROP_NEW) { + handle_prop_new_evt(dev_obj); } USBH_ENTER_CRITICAL(); /* --------------------------------------------------------------------- @@ -567,7 +783,7 @@ esp_err_t usbh_dev_close(usb_device_handle_t dev_hdl) USBH_ENTER_CRITICAL(); dev_obj->dynamic.ref_count--; - bool call_notif_cb = false; + bool call_proc_req_cb = false; if (dev_obj->dynamic.ref_count == 0) { //Sanity check. assert(dev_obj->dynamic.num_ctrl_xfers_inflight == 0); //There cannot be any control transfer inflight @@ -575,18 +791,18 @@ esp_err_t usbh_dev_close(usb_device_handle_t dev_hdl) if (dev_obj->dynamic.flags.is_gone) { //Device is already gone so it's port is already disabled. Trigger the USBH process to free the device dev_obj->dynamic.flags.waiting_free = 1; - call_notif_cb = _dev_set_actions(dev_obj, DEV_FLAG_ACTION_FREE_AND_RECOVER); //Port error occurred so we need to recover it + call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_FREE_AND_RECOVER); //Port error occurred so we need to recover it } else if (dev_obj->dynamic.flags.waiting_close) { //Device is still connected but is no longer needed. Trigger the USBH process to request device's port be disabled dev_obj->dynamic.flags.waiting_port_disable = 1; - call_notif_cb = _dev_set_actions(dev_obj, DEV_FLAG_ACTION_PORT_DISABLE); + call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_PORT_DISABLE); } //Else, there's nothing to do. Leave the device allocated } USBH_EXIT_CRITICAL(); - if (call_notif_cb) { - p_usbh_obj->constant.notif_cb(USB_NOTIF_SOURCE_USBH, false, p_usbh_obj->constant.notif_cb_arg); + 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; } @@ -599,7 +815,7 @@ esp_err_t usbh_dev_mark_all_free(void) disable it immediately. Note: We manually traverse the list because we need to add/remove items while traversing */ - bool call_notif_cb = false; + bool call_proc_req_cb = false; bool wait_for_free = false; for (int i = 0; i < 2; i++) { device_t *dev_obj_cur; @@ -617,7 +833,7 @@ esp_err_t usbh_dev_mark_all_free(void) if (dev_obj_cur->dynamic.ref_count == 0 && !dev_obj_cur->dynamic.flags.is_gone) { //Device is not opened as is not gone, so we can disable it now dev_obj_cur->dynamic.flags.waiting_port_disable = 1; - call_notif_cb |= _dev_set_actions(dev_obj_cur, DEV_FLAG_ACTION_PORT_DISABLE); + call_proc_req_cb |= _dev_set_actions(dev_obj_cur, DEV_ACTION_PORT_DISABLE); } else { //Device is still opened. Just mark it as waiting to be closed dev_obj_cur->dynamic.flags.waiting_close = 1; @@ -628,8 +844,8 @@ esp_err_t usbh_dev_mark_all_free(void) } USBH_EXIT_CRITICAL(); - if (call_notif_cb) { - p_usbh_obj->constant.notif_cb(USB_NOTIF_SOURCE_USBH, false, p_usbh_obj->constant.notif_cb_arg); + 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 (wait_for_free) ? ESP_ERR_NOT_FINISHED : ESP_OK; } @@ -716,6 +932,9 @@ esp_err_t usbh_dev_submit_ctrl_urb(usb_device_handle_t dev_hdl, urb_t *urb) { USBH_CHECK(dev_hdl != NULL && urb != NULL, ESP_ERR_INVALID_ARG); device_t *dev_obj = (device_t *)dev_hdl; + USBH_CHECK(urb_check_args(urb), ESP_ERR_INVALID_ARG); + bool xfer_is_in = ((usb_setup_packet_t *)urb->transfer.data_buffer)->bmRequestType & USB_BM_REQUEST_TYPE_DIR_IN; + USBH_CHECK(transfer_check_usb_compliance(&(urb->transfer), USB_TRANSFER_TYPE_CTRL, dev_obj->constant.desc->bMaxPacketSize0, xfer_is_in), ESP_ERR_INVALID_ARG); USBH_ENTER_CRITICAL(); USBH_CHECK_FROM_CRIT(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED, ESP_ERR_INVALID_STATE); @@ -744,141 +963,160 @@ hcd_err: // ----------------------------------------------- Interface Functions ------------------------------------------------- -esp_err_t usbh_ep_alloc(usb_device_handle_t dev_hdl, usbh_ep_config_t *ep_config, hcd_pipe_handle_t *pipe_hdl_ret) +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) { - USBH_CHECK(dev_hdl != NULL && ep_config != NULL && pipe_hdl_ret != NULL, ESP_ERR_INVALID_ARG); - device_t *dev_obj = (device_t *)dev_hdl; + USBH_CHECK(dev_hdl != NULL && ep_config != NULL && ep_hdl_ret != NULL, ESP_ERR_INVALID_ARG); + uint8_t bEndpointAddress = ep_config->bEndpointAddress; + USBH_CHECK(check_ep_addr(bEndpointAddress), ESP_ERR_INVALID_ARG); + esp_err_t ret; + device_t *dev_obj = (device_t *)dev_hdl; + endpoint_t *ep_obj; - //Allocate HCD pipe - hcd_pipe_config_t pipe_config = { - .callback = ep_config->pipe_cb, - .callback_arg = ep_config->pipe_cb_arg, - .context = ep_config->context, - .ep_desc = ep_config->ep_desc, - .dev_speed = dev_obj->constant.speed, - .dev_addr = dev_obj->constant.address, - }; - hcd_pipe_handle_t pipe_hdl; - ret = hcd_pipe_alloc(dev_obj->constant.port_hdl, &pipe_config, &pipe_hdl); - if (ret != ESP_OK) { - goto pipe_alloc_err; + //Find the endpoint descriptor from the device's current configuration descriptor + const usb_ep_desc_t *ep_desc = usb_parse_endpoint_descriptor_by_address(dev_obj->constant.config_desc, ep_config->bInterfaceNumber, ep_config->bAlternateSetting, ep_config->bEndpointAddress, NULL); + if (ep_desc == NULL) { + return ESP_ERR_NOT_FOUND; + } + //Allocate the endpoint object + ret = endpoint_alloc(dev_obj, ep_desc, ep_config, &ep_obj); + if (ret != ESP_OK) { + goto alloc_err; } - - bool is_in = ep_config->ep_desc->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK; - uint8_t addr = ep_config->ep_desc->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK; - bool assigned = false; //We need to take the mux_lock to access mux_protected members xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); USBH_ENTER_CRITICAL(); - //Check the device's state before we assign the pipes to the endpoint + //Check the device's state before we assign the a pipe to the allocated endpoint if (dev_obj->dynamic.state != USB_DEVICE_STATE_CONFIGURED) { USBH_EXIT_CRITICAL(); ret = ESP_ERR_INVALID_STATE; - goto assign_err; + goto dev_state_err; } USBH_EXIT_CRITICAL(); - //Assign the allocated pipe to the correct endpoint - if (is_in && dev_obj->mux_protected.ep_in[addr - 1] == NULL) { //Is an IN EP - dev_obj->mux_protected.ep_in[addr - 1] = pipe_hdl; - assigned = true; - } else if (!is_in && dev_obj->mux_protected.ep_out[addr - 1] == NULL) { //Is an OUT EP - dev_obj->mux_protected.ep_out[addr - 1] = pipe_hdl; - assigned = true; - } - xSemaphoreGive(p_usbh_obj->constant.mux_lock); - - if (!assigned) { + //Check if the endpoint has already been allocated + if (get_ep_from_addr(dev_obj, bEndpointAddress) == NULL) { + set_ep_from_addr(dev_obj, bEndpointAddress, ep_obj); + //Write back the endpoint handle + *ep_hdl_ret = (usbh_ep_handle_t)ep_obj; + ret = ESP_OK; + } else { + //Endpoint is already allocated ret = ESP_ERR_INVALID_STATE; - goto assign_err; - } - //Write back output - *pipe_hdl_ret = pipe_hdl; - ret = ESP_OK; - return ret; - -assign_err: - ESP_ERROR_CHECK(hcd_pipe_free(pipe_hdl)); -pipe_alloc_err: - return ret; -} - -esp_err_t usbh_ep_free(usb_device_handle_t dev_hdl, uint8_t bEndpointAddress) -{ - USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG); - device_t *dev_obj = (device_t *)dev_hdl; - - esp_err_t ret; - bool is_in = bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK; - uint8_t addr = bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK; - hcd_pipe_handle_t pipe_hdl; - - //We need to take the mux_lock to access mux_protected members - xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); - //Check if the EP was previously allocated. If so, set it to NULL - if (is_in) { - if (dev_obj->mux_protected.ep_in[addr - 1] != NULL) { - pipe_hdl = dev_obj->mux_protected.ep_in[addr - 1]; - dev_obj->mux_protected.ep_in[addr - 1] = NULL; - ret = ESP_OK; - } else { - ret = ESP_ERR_INVALID_STATE; - } - } else { - //EP must have been previously allocated - if (dev_obj->mux_protected.ep_out[addr - 1] != NULL) { - pipe_hdl = dev_obj->mux_protected.ep_out[addr - 1]; - dev_obj->mux_protected.ep_out[addr - 1] = NULL; - ret = ESP_OK; - } else { - ret = ESP_ERR_INVALID_STATE; - } } +dev_state_err: xSemaphoreGive(p_usbh_obj->constant.mux_lock); - if (ret == ESP_OK) { - ESP_ERROR_CHECK(hcd_pipe_free(pipe_hdl)); + //If the endpoint was not assigned, free it + if (ret != ESP_OK) { + endpoint_free(ep_obj); } +alloc_err: return ret; } -esp_err_t usbh_ep_get_context(usb_device_handle_t dev_hdl, uint8_t bEndpointAddress, void **context_ret) +esp_err_t usbh_ep_free(usbh_ep_handle_t ep_hdl) { - bool is_in = bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK; - uint8_t addr = bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK; - USBH_CHECK(dev_hdl != NULL && - addr >= EP_NUM_MIN && //Control endpoints are owned by the USBH - addr <= EP_NUM_MAX && - context_ret != NULL, - ESP_ERR_INVALID_ARG); + USBH_CHECK(ep_hdl != NULL, ESP_ERR_INVALID_ARG); esp_err_t ret; - device_t *dev_obj = (device_t *)dev_hdl; - hcd_pipe_handle_t pipe_hdl; + endpoint_t *ep_obj = (endpoint_t *)ep_hdl; + device_t *dev_obj = (device_t *)ep_obj->constant.dev; + uint8_t bEndpointAddress = ep_obj->constant.ep_desc->bEndpointAddress; - //We need to take the mux_lock to access mux_protected members - xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); - //Get the endpoint's corresponding pipe - if (is_in) { - pipe_hdl = dev_obj->mux_protected.ep_in[addr - 1]; - } else { - pipe_hdl = dev_obj->mux_protected.ep_out[addr - 1]; - } - //Check if the EP was allocated to begin with - if (pipe_hdl == NULL) { - ret = ESP_ERR_NOT_FOUND; + //Todo: Check that the EP's underlying pipe is halted before allowing the EP to be freed (IDF-7273) + //Check that the the EP's underlying pipe has no more in-flight URBs + if (hcd_pipe_get_num_urbs(ep_obj->constant.pipe_hdl) != 0) { + ret = ESP_ERR_INVALID_STATE; goto exit; } - //Return the context of the pipe - void *context = hcd_pipe_get_context(pipe_hdl); - *context_ret = context; - ret = ESP_OK; -exit: + + //We need to take the mux_lock to access mux_protected members + xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); + //Check if the endpoint was allocated on this device + if (ep_obj == get_ep_from_addr(dev_obj, bEndpointAddress)) { + //Clear the endpoint from the device's endpoint object list + set_ep_from_addr(dev_obj, bEndpointAddress, NULL); + ret = ESP_OK; + } else { + ret = ESP_ERR_NOT_FOUND; + } xSemaphoreGive(p_usbh_obj->constant.mux_lock); + + //Finally, we free the endpoint object + if (ret == ESP_OK) { + endpoint_free(ep_obj); + } +exit: return ret; } +esp_err_t usbh_ep_get_handle(usb_device_handle_t dev_hdl, uint8_t bEndpointAddress, usbh_ep_handle_t *ep_hdl_ret) +{ + USBH_CHECK(dev_hdl != NULL && ep_hdl_ret != NULL, ESP_ERR_INVALID_ARG); + USBH_CHECK(check_ep_addr(bEndpointAddress), ESP_ERR_INVALID_ARG); + + esp_err_t ret; + device_t *dev_obj = (device_t *)dev_hdl; + endpoint_t *ep_obj; + + //We need to take the mux_lock to access mux_protected members + xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); + ep_obj = get_ep_from_addr(dev_obj, bEndpointAddress); + xSemaphoreGive(p_usbh_obj->constant.mux_lock); + if (ep_obj) { + *ep_hdl_ret = (usbh_ep_handle_t)ep_obj; + ret = ESP_OK; + } else { + ret = ESP_ERR_NOT_FOUND; + } + + return ret; +} + +esp_err_t usbh_ep_enqueue_urb(usbh_ep_handle_t ep_hdl, urb_t *urb) +{ + USBH_CHECK(ep_hdl != NULL && urb != NULL, ESP_ERR_INVALID_ARG); + /* + Todo: Here would be a good place to check that the URB is filled correctly according to the USB 2.0 specification. + This is currently done by the USB host library layer, but is more appropriate here. + */ + endpoint_t *ep_obj = (endpoint_t *)ep_hdl; + + //Check that the EP's underlying pipe is in the active state before submitting the URB + if (hcd_pipe_get_state(ep_obj->constant.pipe_hdl) != HCD_PIPE_STATE_ACTIVE) { + return ESP_ERR_INVALID_STATE; + } + //Enqueue the URB to the EP's underlying pipe + return hcd_urb_enqueue(ep_obj->constant.pipe_hdl, urb); +} + +esp_err_t usbh_ep_dequeue_urb(usbh_ep_handle_t ep_hdl, urb_t **urb_ret) +{ + USBH_CHECK(ep_hdl != NULL && urb_ret != NULL, ESP_ERR_INVALID_ARG); + + endpoint_t *ep_obj = (endpoint_t *)ep_hdl; + //Enqueue the URB to the EP's underlying pipe + *urb_ret = hcd_urb_dequeue(ep_obj->constant.pipe_hdl); + return ESP_OK; +} + +esp_err_t usbh_ep_command(usbh_ep_handle_t ep_hdl, usbh_ep_cmd_t command) +{ + USBH_CHECK(ep_hdl != NULL, ESP_ERR_INVALID_ARG); + + endpoint_t *ep_obj = (endpoint_t *)ep_hdl; + //Send the command to the EP's underlying pipe + return hcd_pipe_command(ep_obj->constant.pipe_hdl, (hcd_pipe_cmd_t)command); +} + +void *usbh_ep_get_context(usbh_ep_handle_t ep_hdl) +{ + assert(ep_hdl); + endpoint_t *ep_obj = (endpoint_t *)ep_hdl; + return hcd_pipe_get_context(ep_obj->constant.pipe_hdl); +} + // -------------------------------------------------- Hub Functions ---------------------------------------------------- // ------------------- Device Related ---------------------- @@ -921,7 +1159,7 @@ esp_err_t usbh_hub_pass_event(usb_device_handle_t dev_hdl, usbh_hub_event_t hub_ USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG); device_t *dev_obj = (device_t *)dev_hdl; - bool call_notif_cb; + bool call_proc_req_cb; switch (hub_event) { case USBH_HUB_EVENT_PORT_ERROR: { USBH_ENTER_CRITICAL(); @@ -929,13 +1167,14 @@ esp_err_t usbh_hub_pass_event(usb_device_handle_t dev_hdl, usbh_hub_event_t hub_ //Check if the device can be freed now if (dev_obj->dynamic.ref_count == 0) { dev_obj->dynamic.flags.waiting_free = 1; - //Device is already waiting free so none of it's pipes will be in use. Can free immediately. - call_notif_cb = _dev_set_actions(dev_obj, DEV_FLAG_ACTION_FREE_AND_RECOVER); //Port error occurred so we need to recover it + //Device is already waiting free so none of it's EP's will be in use. Can free immediately. + call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_FREE_AND_RECOVER); //Port error occurred so we need to recover it } else { - call_notif_cb = _dev_set_actions(dev_obj, DEV_FLAG_ACTION_PIPE_HALT_AND_FLUSH | - DEV_FLAG_ACTION_DEFAULT_PIPE_FLUSH | - DEV_FLAG_ACTION_DEFAULT_PIPE_DEQUEUE | - DEV_FLAG_ACTION_SEND_GONE_EVENT); + call_proc_req_cb = _dev_set_actions(dev_obj, + DEV_ACTION_EPn_HALT_FLUSH | + DEV_ACTION_EP0_FLUSH | + DEV_ACTION_EP0_DEQUEUE | + DEV_ACTION_PROP_GONE_EVT); } USBH_EXIT_CRITICAL(); break; @@ -944,7 +1183,7 @@ esp_err_t usbh_hub_pass_event(usb_device_handle_t dev_hdl, usbh_hub_event_t hub_ USBH_ENTER_CRITICAL(); assert(dev_obj->dynamic.ref_count == 0); //At this stage, the device should have been closed by all users dev_obj->dynamic.flags.waiting_free = 1; - call_notif_cb = _dev_set_actions(dev_obj, DEV_FLAG_ACTION_FREE); + call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_FREE); USBH_EXIT_CRITICAL(); break; } @@ -952,8 +1191,8 @@ esp_err_t usbh_hub_pass_event(usb_device_handle_t dev_hdl, usbh_hub_event_t hub_ return ESP_ERR_INVALID_ARG; } - if (call_notif_cb) { - p_usbh_obj->constant.notif_cb(USB_NOTIF_SOURCE_USBH, false, p_usbh_obj->constant.notif_cb_arg); + 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; } @@ -1040,16 +1279,16 @@ esp_err_t usbh_hub_enum_done(usb_device_handle_t dev_hdl) dev_obj->dynamic.state = USB_DEVICE_STATE_CONFIGURED; //Add the device to list of devices, then trigger a device event TAILQ_INSERT_TAIL(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry); //Add it to the idle device list first - bool call_notif_cb = _dev_set_actions(dev_obj, DEV_FLAG_ACTION_SEND_NEW); + bool call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_PROP_NEW); USBH_EXIT_CRITICAL(); p_usbh_obj->mux_protected.num_device++; xSemaphoreGive(p_usbh_obj->constant.mux_lock); - //Update the default pipe callback - ESP_ERROR_CHECK(hcd_pipe_update_callback(dev_obj->constant.default_pipe, default_pipe_callback, (void *)dev_obj)); - //Call the notification callback - if (call_notif_cb) { - p_usbh_obj->constant.notif_cb(USB_NOTIF_SOURCE_USBH, false, p_usbh_obj->constant.notif_cb_arg); + //Update the EP0's underlying pipe's callback + ESP_ERROR_CHECK(hcd_pipe_update_callback(dev_obj->constant.default_pipe, ep0_pipe_callback, (void *)dev_obj)); + //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; } From a3e4e9c772917744506c1badf0a9b4a64cd0e872 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Mon, 8 May 2023 23:12:25 +0800 Subject: [PATCH 2/3] usb_host: Fix spelling errors --- components/usb/hcd_dwc.c | 4 ++-- components/usb/private_include/usbh.h | 4 ++-- components/usb/usb_host.c | 12 ++++++------ components/usb/usbh.c | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/components/usb/hcd_dwc.c b/components/usb/hcd_dwc.c index 5564cb760c..f929a4f847 100644 --- a/components/usb/hcd_dwc.c +++ b/components/usb/hcd_dwc.c @@ -229,7 +229,7 @@ typedef struct { * @brief Object representing a pipe in the HCD layer */ struct pipe_obj { - //URB queueing related + //URB queuing related TAILQ_HEAD(tailhead_urb_pending, urb_s) pending_urb_tailq; TAILQ_HEAD(tailhead_urb_done, urb_s) done_urb_tailq; int num_urb_pending; @@ -264,7 +264,7 @@ struct pipe_obj { struct { uint32_t waiting_halt: 1; uint32_t pipe_cmd_processing: 1; - uint32_t has_urb: 1; //Indicates there is at least one URB either pending, inflight, or done + uint32_t has_urb: 1; //Indicates there is at least one URB either pending, in-flight, or done uint32_t persist: 1; //indicates that this pipe should persist through a run-time port reset uint32_t reset_lock: 1; //Indicates that this pipe is undergoing a run-time reset uint32_t reserved27: 27; diff --git a/components/usb/private_include/usbh.h b/components/usb/private_include/usbh.h index 1d033e4390..3e01350897 100644 --- a/components/usb/private_include/usbh.h +++ b/components/usb/private_include/usbh.h @@ -319,7 +319,7 @@ esp_err_t usbh_dev_submit_ctrl_urb(usb_device_handle_t dev_hdl, urb_t *urb); * - A client should call this function to allocate all endpoints in an interface that the client has claimed. * - A client must allocate an endpoint using this function before attempting to communicate with it * - Once the client allocates an endpoint, the client is now owns/manages the endpoint. No other client should use or - * deallocte the endpoint. + * deallocate the endpoint. * * @note This function can block * @note Default endpoints (EP0) are owned by the USBH. For control transfers, use usbh_dev_submit_ctrl_urb() instead @@ -489,7 +489,7 @@ esp_err_t usbh_hub_enum_fill_config_desc(usb_device_handle_t dev_hdl, const usb_ * @note Must call in sequence * @param dev_hdl Device handle * @param str_desc Pointer to string descriptor - * @param select Select which string descriptor. 0/1/2 for Manufacturer/Product/Serial Number string descriptors respecitvely + * @param select Select which string descriptor. 0/1/2 for Manufacturer/Product/Serial Number string descriptors respectively * @return esp_err_t */ esp_err_t usbh_hub_enum_fill_str_desc(usb_device_handle_t dev_hdl, const usb_str_desc_t *str_desc, int select); diff --git a/components/usb/usb_host.c b/components/usb/usb_host.c index 7e507a47f4..a3ad4d603b 100644 --- a/components/usb/usb_host.c +++ b/components/usb/usb_host.c @@ -619,7 +619,7 @@ static void _handle_pending_ep(client_t *client_obj) urb_t *urb; usbh_ep_dequeue_urb(ep_wrap->constant.ep_hdl, &urb); while (urb != NULL) { - //Clear the transfer's inflight flag to indicate the transfer is no longer inflight + //Clear the transfer's in-flight flag to indicate the transfer is no longer in-flight urb->usb_host_inflight = false; urb->transfer.callback(&urb->transfer); num_urb_dequeued++; @@ -633,7 +633,7 @@ static void _handle_pending_ep(client_t *client_obj) } HOST_ENTER_CRITICAL(); - //Update the endpoint's number of URB's inflight + //Update the endpoint's number of URB's in-flight assert(num_urb_dequeued <= ep_wrap->dynamic.num_urb_inflight); ep_wrap->dynamic.num_urb_inflight -= num_urb_dequeued; } @@ -778,7 +778,7 @@ esp_err_t usb_host_client_handle_events(usb_host_client_handle_t client_hdl, Tic TAILQ_REMOVE(&client_obj->dynamic.done_ctrl_xfer_tailq, urb, tailq_entry); client_obj->dynamic.num_done_ctrl_xfer--; HOST_EXIT_CRITICAL(); - //Clear the transfer's inflight flag to indicate the transfer is no longer inflight + //Clear the transfer's in-flight flag to indicate the transfer is no longer in-flight urb->usb_host_inflight = false; //Call the transfer's callback urb->transfer.callback(&urb->transfer); @@ -1095,7 +1095,7 @@ static esp_err_t interface_release(client_t *client_obj, usb_device_handle_t dev bool can_free = true; for (int i = 0; i < intf_obj->constant.intf_desc->bNumEndpoints; i++) { ep_wrapper_t *ep_wrap = intf_obj->constant.endpoints[i]; - //Endpoint must not be on the pending list and must not have inflight URBs + //Endpoint must not be on the pending list and must not have in-flight URBs if (ep_wrap->dynamic.num_urb_inflight != 0 || ep_wrap->dynamic.flags.pending) { can_free = false; break; @@ -1281,7 +1281,7 @@ esp_err_t usb_host_transfer_submit(usb_transfer_t *transfer) } ep_wrap = usbh_ep_get_context(ep_hdl); assert(ep_wrap != NULL); - //Check that we are not submitting a transfer already inflight + //Check that we are not submitting a transfer already in-flight HOST_CHECK(!urb_obj->usb_host_inflight, ESP_ERR_NOT_FINISHED); urb_obj->usb_host_inflight = true; HOST_ENTER_CRITICAL(); @@ -1313,7 +1313,7 @@ esp_err_t usb_host_transfer_submit_control(usb_host_client_handle_t client_hdl, usb_device_handle_t dev_hdl = transfer->device_handle; urb_t *urb_obj = __containerof(transfer, urb_t, transfer); - //Check that we are not submitting a transfer already inflight + //Check that we are not submitting a transfer already in-flight HOST_CHECK(!urb_obj->usb_host_inflight, ESP_ERR_NOT_FINISHED); urb_obj->usb_host_inflight = true; //Save client handle into URB diff --git a/components/usb/usbh.c b/components/usb/usbh.c index d2bd9e4816..799ff2a5d4 100644 --- a/components/usb/usbh.c +++ b/components/usb/usbh.c @@ -786,7 +786,7 @@ esp_err_t usbh_dev_close(usb_device_handle_t dev_hdl) bool call_proc_req_cb = false; if (dev_obj->dynamic.ref_count == 0) { //Sanity check. - assert(dev_obj->dynamic.num_ctrl_xfers_inflight == 0); //There cannot be any control transfer inflight + assert(dev_obj->dynamic.num_ctrl_xfers_inflight == 0); //There cannot be any control transfer in-flight assert(!dev_obj->dynamic.flags.waiting_free); //This can only be set when ref count reaches 0 if (dev_obj->dynamic.flags.is_gone) { //Device is already gone so it's port is already disabled. Trigger the USBH process to free the device From ff8c4f79d2a00e158ac1e4cf6521d454d163347c Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Tue, 9 May 2023 00:53:27 +0800 Subject: [PATCH 3/3] usb_host: Run formatting script --- components/usb/hcd_dwc.c | 1230 +++++++++--------- components/usb/hub.c | 992 +++++++------- components/usb/include/usb/usb_host.h | 6 +- components/usb/include/usb/usb_types_ch9.h | 8 +- components/usb/include/usb/usb_types_stack.h | 4 +- components/usb/private_include/hcd.h | 4 +- components/usb/private_include/usb_private.h | 14 +- components/usb/private_include/usbh.h | 2 +- components/usb/usb_helpers.c | 104 +- components/usb/usb_host.c | 380 +++--- components/usb/usb_phy.c | 72 +- components/usb/usb_private.c | 4 +- components/usb/usbh.c | 388 +++--- 13 files changed, 1604 insertions(+), 1604 deletions(-) diff --git a/components/usb/hcd_dwc.c b/components/usb/hcd_dwc.c index f929a4f847..c43e3b698a 100644 --- a/components/usb/hcd_dwc.c +++ b/components/usb/hcd_dwc.c @@ -28,17 +28,17 @@ // --------------------- Constants ------------------------- -#define INIT_DELAY_MS 30 //A delay of at least 25ms to enter Host mode. Make it 30ms to be safe +#define INIT_DELAY_MS 30 // A delay of at least 25ms to enter Host mode. Make it 30ms to be safe #define DEBOUNCE_DELAY_MS CONFIG_USB_HOST_DEBOUNCE_DELAY_MS #define RESET_HOLD_MS CONFIG_USB_HOST_RESET_HOLD_MS #define RESET_RECOVERY_MS CONFIG_USB_HOST_RESET_RECOVERY_MS -#define RESUME_HOLD_MS 30 //Spec requires at least 20ms, Make it 30ms to be safe -#define RESUME_RECOVERY_MS 20 //Resume recovery of at least 10ms. Make it 20 ms to be safe. This will include the 3 LS bit times of the EOP +#define RESUME_HOLD_MS 30 // Spec requires at least 20ms, Make it 30ms to be safe +#define RESUME_RECOVERY_MS 20 // Resume recovery of at least 10ms. Make it 20 ms to be safe. This will include the 3 LS bit times of the EOP -#define CTRL_EP_MAX_MPS_LS 8 //Largest Maximum Packet Size for Low Speed control endpoints -#define CTRL_EP_MAX_MPS_FS 64 //Largest Maximum Packet Size for Full Speed control endpoints +#define CTRL_EP_MAX_MPS_LS 8 // Largest Maximum Packet Size for Low Speed control endpoints +#define CTRL_EP_MAX_MPS_FS 64 // Largest Maximum Packet Size for Full Speed control endpoints -#define NUM_PORTS 1 //The controller only has one port. +#define NUM_PORTS 1 // The controller only has one port. // ----------------------- Configs ------------------------- @@ -135,10 +135,10 @@ const fifo_mps_limits_t mps_limits_bias_ptx = { #define FRAME_LIST_LEN USB_HAL_FRAME_LIST_LEN_32 #define NUM_BUFFERS 2 -#define XFER_LIST_LEN_CTRL 3 //One descriptor for each stage -#define XFER_LIST_LEN_BULK 2 //One descriptor for transfer, one to support an extra zero length packet +#define XFER_LIST_LEN_CTRL 3 // One descriptor for each stage +#define XFER_LIST_LEN_BULK 2 // One descriptor for transfer, one to support an extra zero length packet #define XFER_LIST_LEN_INTR 32 -#define XFER_LIST_LEN_ISOC FRAME_LIST_LEN //Same length as the frame list makes it easier to schedule. Must be power of 2 +#define XFER_LIST_LEN_ISOC FRAME_LIST_LEN // Same length as the frame list makes it easier to schedule. Must be power of 2 // ------------------------ Flags -------------------------- @@ -148,10 +148,10 @@ const fifo_mps_limits_t mps_limits_bias_ptx = { * The URB object has a reserved_flags member for host stack's internal use. The following flags will be set in * reserved_flags in order to keep track of state of an URB within the HCD. */ -#define URB_HCD_STATE_IDLE 0 //The URB is not enqueued in an HCD pipe -#define URB_HCD_STATE_PENDING 1 //The URB is enqueued and pending execution -#define URB_HCD_STATE_INFLIGHT 2 //The URB is currently in flight -#define URB_HCD_STATE_DONE 3 //The URB has completed execution or is retired, and is waiting to be dequeued +#define URB_HCD_STATE_IDLE 0 // The URB is not enqueued in an HCD pipe +#define URB_HCD_STATE_PENDING 1 // The URB is enqueued and pending execution +#define URB_HCD_STATE_INFLIGHT 2 // The URB is currently in flight +#define URB_HCD_STATE_DONE 3 // The URB has completed execution or is retired, and is waiting to be dequeued #define URB_HCD_STATE_SET(reserved_flags, state) (reserved_flags = (reserved_flags & ~URB_HCD_STATE_MASK) | state) #define URB_HCD_STATE_GET(reserved_flags) (reserved_flags & URB_HCD_STATE_MASK) @@ -190,88 +190,88 @@ typedef struct { urb_t *urb; union { struct { - uint32_t data_stg_in: 1; //Data stage of the control transfer is IN - uint32_t data_stg_skip: 1; //Control transfer has no data stage - uint32_t cur_stg: 2; //Index of the current stage (e.g., 0 is setup stage, 2 is status stage) + uint32_t data_stg_in: 1; // Data stage of the control transfer is IN + uint32_t data_stg_skip: 1; // Control transfer has no data stage + uint32_t cur_stg: 2; // Index of the current stage (e.g., 0 is setup stage, 2 is status stage) uint32_t reserved28: 28; - } ctrl; //Control transfer related + } ctrl; // Control transfer related struct { - uint32_t zero_len_packet: 1; //Added a zero length packet, so transfer consists of 2 QTDs + uint32_t zero_len_packet: 1; // Added a zero length packet, so transfer consists of 2 QTDs uint32_t reserved31: 31; - } bulk; //Bulk transfer related + } bulk; // Bulk transfer related struct { - uint32_t num_qtds: 8; //Number of transfer descriptors filled (excluding zero length packet) - uint32_t zero_len_packet: 1; //Added a zero length packet, so true number descriptors is num_qtds + 1 + uint32_t num_qtds: 8; // Number of transfer descriptors filled (excluding zero length packet) + uint32_t zero_len_packet: 1; // Added a zero length packet, so true number descriptors is num_qtds + 1 uint32_t reserved23: 23; - } intr; //Interrupt transfer related + } intr; // Interrupt transfer related struct { - uint32_t num_qtds: 8; //Number of transfer descriptors filled (including NULL descriptors) - uint32_t interval: 8; //Interval (in number of SOF i.e., ms) - uint32_t start_idx: 8; //Index of the first transfer descriptor in the list - uint32_t next_start_idx: 8; //Index for the first descriptor of the next buffer + uint32_t num_qtds: 8; // Number of transfer descriptors filled (including NULL descriptors) + uint32_t interval: 8; // Interval (in number of SOF i.e., ms) + uint32_t start_idx: 8; // Index of the first transfer descriptor in the list + uint32_t next_start_idx: 8; // Index for the first descriptor of the next buffer } isoc; uint32_t val; } flags; union { struct { - uint32_t executing: 1; //The buffer is currently executing - uint32_t was_canceled: 1; //Buffer was done due to a cancellation (i.e., a halt request) + uint32_t executing: 1; // The buffer is currently executing + uint32_t was_canceled: 1; // Buffer was done due to a cancellation (i.e., a halt request) uint32_t reserved6: 6; - uint32_t stop_idx: 8; //The descriptor index when the channel was halted - hcd_pipe_event_t pipe_event: 8; //The pipe event when the buffer was done + uint32_t stop_idx: 8; // The descriptor index when the channel was halted + hcd_pipe_event_t pipe_event: 8; // The pipe event when the buffer was done uint32_t reserved8: 8; }; uint32_t val; - } status_flags; //Status flags for the buffer + } status_flags; // Status flags for the buffer } dma_buffer_block_t; /** * @brief Object representing a pipe in the HCD layer */ struct pipe_obj { - //URB queuing related + // URB queuing related TAILQ_HEAD(tailhead_urb_pending, urb_s) pending_urb_tailq; TAILQ_HEAD(tailhead_urb_done, urb_s) done_urb_tailq; int num_urb_pending; int num_urb_done; - //Multi-buffer control - dma_buffer_block_t *buffers[NUM_BUFFERS]; //Double buffering scheme + // Multi-buffer control + dma_buffer_block_t *buffers[NUM_BUFFERS]; // Double buffering scheme union { struct { - uint32_t buffer_num_to_fill: 2; //Number of buffers that can be filled - uint32_t buffer_num_to_exec: 2; //Number of buffers that are filled and need to be executed - uint32_t buffer_num_to_parse: 2;//Number of buffers completed execution and waiting to be parsed + uint32_t buffer_num_to_fill: 2; // Number of buffers that can be filled + uint32_t buffer_num_to_exec: 2; // Number of buffers that are filled and need to be executed + uint32_t buffer_num_to_parse: 2;// Number of buffers completed execution and waiting to be parsed uint32_t reserved2: 2; - uint32_t wr_idx: 1; //Index of the next buffer to fill. Bit width must allow NUM_BUFFERS to wrap automatically - uint32_t rd_idx: 1; //Index of the current buffer in-flight. Bit width must allow NUM_BUFFERS to wrap automatically - uint32_t fr_idx: 1; //Index of the next buffer to parse. Bit width must allow NUM_BUFFERS to wrap automatically - uint32_t buffer_is_executing: 1;//One of the buffers is in flight + uint32_t wr_idx: 1; // Index of the next buffer to fill. Bit width must allow NUM_BUFFERS to wrap automatically + uint32_t rd_idx: 1; // Index of the current buffer in-flight. Bit width must allow NUM_BUFFERS to wrap automatically + uint32_t fr_idx: 1; // Index of the next buffer to parse. Bit width must allow NUM_BUFFERS to wrap automatically + uint32_t buffer_is_executing: 1;// One of the buffers is in flight uint32_t reserved20: 20; }; uint32_t val; } multi_buffer_control; - //HAL related + // HAL related usb_dwc_hal_chan_t *chan_obj; usb_dwc_hal_ep_char_t ep_char; - //Port related - port_t *port; //The port to which this pipe is routed through - TAILQ_ENTRY(pipe_obj) tailq_entry; //TailQ entry for port's list of pipes - //Pipe status/state/events related + // Port related + port_t *port; // The port to which this pipe is routed through + TAILQ_ENTRY(pipe_obj) tailq_entry; // TailQ entry for port's list of pipes + // Pipe status/state/events related hcd_pipe_state_t state; hcd_pipe_event_t last_event; - volatile TaskHandle_t task_waiting_pipe_notif; //Task handle used for internal pipe events. Set by waiter, cleared by notifier + volatile TaskHandle_t task_waiting_pipe_notif; // Task handle used for internal pipe events. Set by waiter, cleared by notifier union { struct { uint32_t waiting_halt: 1; uint32_t pipe_cmd_processing: 1; - uint32_t has_urb: 1; //Indicates there is at least one URB either pending, in-flight, or done - uint32_t persist: 1; //indicates that this pipe should persist through a run-time port reset - uint32_t reset_lock: 1; //Indicates that this pipe is undergoing a run-time reset + uint32_t has_urb: 1; // Indicates there is at least one URB either pending, in-flight, or done + uint32_t persist: 1; // indicates that this pipe should persist through a run-time port reset + uint32_t reset_lock: 1; // Indicates that this pipe is undergoing a run-time reset uint32_t reserved27: 27; }; uint32_t val; } cs_flags; - //Pipe callback and context + // Pipe callback and context hcd_pipe_callback_t callback; void *callback_arg; void *context; @@ -283,33 +283,33 @@ struct pipe_obj { struct port_obj { usb_dwc_hal_context_t *hal; void *frame_list; - //Pipes routed through this port + // Pipes routed through this port TAILQ_HEAD(tailhead_pipes_idle, pipe_obj) pipes_idle_tailq; TAILQ_HEAD(tailhead_pipes_queued, pipe_obj) pipes_active_tailq; int num_pipes_idle; int num_pipes_queued; - //Port status, state, and events + // Port status, state, and events hcd_port_state_t state; usb_speed_t speed; hcd_port_event_t last_event; - volatile TaskHandle_t task_waiting_port_notif; //Task handle used for internal port events. Set by waiter, cleared by notifier + volatile TaskHandle_t task_waiting_port_notif; // Task handle used for internal port events. Set by waiter, cleared by notifier union { struct { - uint32_t event_pending: 1; //The port has an event that needs to be handled - uint32_t event_processing: 1; //The port is current processing (handling) an event - uint32_t cmd_processing: 1; //Used to indicate command handling is ongoing + uint32_t event_pending: 1; // The port has an event that needs to be handled + uint32_t event_processing: 1; // The port is current processing (handling) an event + uint32_t cmd_processing: 1; // Used to indicate command handling is ongoing uint32_t disable_requested: 1; - uint32_t conn_dev_ena: 1; //Used to indicate the port is connected to a device that has been reset + uint32_t conn_dev_ena: 1; // Used to indicate the port is connected to a device that has been reset uint32_t periodic_scheduling_enabled: 1; uint32_t reserved26: 26; }; uint32_t val; } flags; bool initialized; - //FIFO biasing related + // FIFO biasing related const usb_dwc_hal_fifo_config_t *fifo_config; const fifo_mps_limits_t *fifo_mps_limits; - //Port callback and context + // Port callback and context hcd_port_callback_t callback; void *callback_arg; SemaphoreHandle_t port_mux; @@ -320,13 +320,13 @@ struct port_obj { * @brief Object representing the HCD */ typedef struct { - //Ports (Hardware only has one) + // Ports (Hardware only has one) port_t *port_obj; intr_handle_t isr_hdl; } hcd_obj_t; static portMUX_TYPE hcd_lock = portMUX_INITIALIZER_UNLOCKED; -static hcd_obj_t *s_hcd_obj = NULL; //Note: "s_" is for the static pointer +static hcd_obj_t *s_hcd_obj = NULL; // Note: "s_" is for the static pointer // ------------------------------------------------- Forward Declare --------------------------------------------------- @@ -341,7 +341,7 @@ static hcd_obj_t *s_hcd_obj = NULL; //Note: "s_" is for the static pointer */ static inline bool _buffer_can_fill(pipe_t *pipe) { - //We can only fill if there are pending URBs and at least one unfilled buffer + // We can only fill if there are pending URBs and at least one unfilled buffer if (pipe->num_urb_pending > 0 && pipe->multi_buffer_control.buffer_num_to_fill > 0) { return true; } else { @@ -371,7 +371,7 @@ static void _buffer_fill(pipe_t *pipe); */ static inline bool _buffer_can_exec(pipe_t *pipe) { - //We can only execute if there is not already a buffer executing and if there are filled buffers awaiting execution + // We can only execute if there is not already a buffer executing and if there are filled buffers awaiting execution if (!pipe->multi_buffer_control.buffer_is_executing && pipe->multi_buffer_control.buffer_num_to_exec > 0) { return true; } else { @@ -404,7 +404,7 @@ static inline bool _buffer_check_done(pipe_t *pipe) if (pipe->ep_char.type != USB_PRIV_XFER_TYPE_CTRL) { return true; } - //Only control transfers need to be continued + // Only control transfers need to be continued dma_buffer_block_t *buffer_inflight = pipe->buffers[pipe->multi_buffer_control.rd_idx]; return (buffer_inflight->flags.ctrl.cur_stg == 2); } @@ -430,7 +430,7 @@ static void _buffer_exec_cont(pipe_t *pipe); */ static inline void _buffer_done(pipe_t *pipe, int stop_idx, hcd_pipe_event_t pipe_event, bool canceled) { - //Store the stop_idx and pipe_event for later parsing + // Store the stop_idx and pipe_event for later parsing dma_buffer_block_t *buffer_done = pipe->buffers[pipe->multi_buffer_control.rd_idx]; buffer_done->status_flags.executing = 0; buffer_done->status_flags.was_canceled = canceled; @@ -690,7 +690,7 @@ static bool _internal_pipe_event_notify(pipe_t *pipe, bool from_isr); static void _internal_port_event_wait(port_t *port) { - //There must NOT be another thread/task already waiting for an internal event + // There must NOT be another thread/task already waiting for an internal event assert(port->task_waiting_port_notif == NULL); port->task_waiting_port_notif = xTaskGetCurrentTaskHandle(); /* We need to loop as task notifications can come from anywhere. If we this @@ -698,7 +698,7 @@ static void _internal_port_event_wait(port_t *port) by the notifier. */ while (port->task_waiting_port_notif != NULL) { HCD_EXIT_CRITICAL(); - //Wait to be notified from ISR + // Wait to be notified from ISR ulTaskNotifyTake(pdTRUE, portMAX_DELAY); HCD_ENTER_CRITICAL(); } @@ -706,28 +706,28 @@ static void _internal_port_event_wait(port_t *port) static bool _internal_port_event_notify_from_isr(port_t *port) { - //There must be a thread/task waiting for an internal event + // There must be a thread/task waiting for an internal event assert(port->task_waiting_port_notif != NULL); TaskHandle_t task_to_unblock = port->task_waiting_port_notif; - //Clear task_waiting_port_notif to indicate to the waiter that the unblock was indeed an port event notification + // Clear task_waiting_port_notif to indicate to the waiter that the unblock was indeed an port event notification port->task_waiting_port_notif = NULL; - //Unblock the thread/task waiting for the notification + // Unblock the thread/task waiting for the notification BaseType_t xTaskWoken = pdFALSE; - //Note: We don't exit the critical section to be atomic. vTaskNotifyGiveFromISR() doesn't block anyways + // Note: We don't exit the critical section to be atomic. vTaskNotifyGiveFromISR() doesn't block anyways vTaskNotifyGiveFromISR(task_to_unblock, &xTaskWoken); return (xTaskWoken == pdTRUE); } static void _internal_pipe_event_wait(pipe_t *pipe) { - //There must NOT be another thread/task already waiting for an internal event + // There must NOT be another thread/task already waiting for an internal event assert(pipe->task_waiting_pipe_notif == NULL); pipe->task_waiting_pipe_notif = xTaskGetCurrentTaskHandle(); /* We need to loop as task notifications can come from anywhere. If we this was a pipe event notification, task_waiting_pipe_notif will have been cleared by the notifier. */ while (pipe->task_waiting_pipe_notif != NULL) { - //Wait to be unblocked by notified + // Wait to be unblocked by notified HCD_EXIT_CRITICAL(); ulTaskNotifyTake(pdTRUE, portMAX_DELAY); HCD_ENTER_CRITICAL(); @@ -736,16 +736,16 @@ static void _internal_pipe_event_wait(pipe_t *pipe) static bool _internal_pipe_event_notify(pipe_t *pipe, bool from_isr) { - //There must be a thread/task waiting for an internal event + // There must be a thread/task waiting for an internal event assert(pipe->task_waiting_pipe_notif != NULL); TaskHandle_t task_to_unblock = pipe->task_waiting_pipe_notif; - //Clear task_waiting_pipe_notif to indicate to the waiter that the unblock was indeed an pipe event notification + // Clear task_waiting_pipe_notif to indicate to the waiter that the unblock was indeed an pipe event notification pipe->task_waiting_pipe_notif = NULL; bool ret; if (from_isr) { BaseType_t xTaskWoken = pdFALSE; - //Note: We don't exit the critical section to be atomic. vTaskNotifyGiveFromISR() doesn't block anyways - //Unblock the thread/task waiting for the pipe notification + // Note: We don't exit the critical section to be atomic. vTaskNotifyGiveFromISR() doesn't block anyways + // Unblock the thread/task waiting for the pipe notification vTaskNotifyGiveFromISR(task_to_unblock, &xTaskWoken); ret = (xTaskWoken == pdTRUE); } else { @@ -771,57 +771,57 @@ static hcd_port_event_t _intr_hdlr_hprt(port_t *port, usb_dwc_hal_port_event_t h { hcd_port_event_t port_event = HCD_PORT_EVENT_NONE; switch (hal_port_event) { - case USB_DWC_HAL_PORT_EVENT_CONN: { - //Don't update state immediately, we still need to debounce. - port_event = HCD_PORT_EVENT_CONNECTION; - break; - } - case USB_DWC_HAL_PORT_EVENT_DISCONN: { - port->state = HCD_PORT_STATE_RECOVERY; - port_event = HCD_PORT_EVENT_DISCONNECTION; - port->flags.conn_dev_ena = 0; - break; - } - case USB_DWC_HAL_PORT_EVENT_ENABLED: { - usb_dwc_hal_port_enable(port->hal); //Initialize remaining host port registers - port->speed = (usb_dwc_hal_port_get_conn_speed(port->hal) == USB_PRIV_SPEED_FULL) ? USB_SPEED_FULL : USB_SPEED_LOW; - port->state = HCD_PORT_STATE_ENABLED; - port->flags.conn_dev_ena = 1; - //This was triggered by a command, so no event needs to be propagated. - break; - } - case USB_DWC_HAL_PORT_EVENT_DISABLED: { - port->flags.conn_dev_ena = 0; - //Disabled could be due to a disable request or reset request, or due to a port error - if (port->state != HCD_PORT_STATE_RESETTING) { //Ignore the disable event if it's due to a reset request - if (port->flags.disable_requested) { - //Disabled by request (i.e. by port command). Generate an internal event - port->state = HCD_PORT_STATE_DISABLED; - port->flags.disable_requested = 0; - *yield |= _internal_port_event_notify_from_isr(port); - } else { - //Disabled due to a port error - port->state = HCD_PORT_STATE_RECOVERY; - port_event = HCD_PORT_EVENT_ERROR; - } - } - break; - } - case USB_DWC_HAL_PORT_EVENT_OVRCUR: - case USB_DWC_HAL_PORT_EVENT_OVRCUR_CLR: { //Could occur if a quick overcurrent then clear happens - if (port->state != HCD_PORT_STATE_NOT_POWERED) { - //We need to power OFF the port to protect it - usb_dwc_hal_port_toggle_power(port->hal, false); + case USB_DWC_HAL_PORT_EVENT_CONN: { + // Don't update state immediately, we still need to debounce. + port_event = HCD_PORT_EVENT_CONNECTION; + break; + } + case USB_DWC_HAL_PORT_EVENT_DISCONN: { + port->state = HCD_PORT_STATE_RECOVERY; + port_event = HCD_PORT_EVENT_DISCONNECTION; + port->flags.conn_dev_ena = 0; + break; + } + case USB_DWC_HAL_PORT_EVENT_ENABLED: { + usb_dwc_hal_port_enable(port->hal); // Initialize remaining host port registers + port->speed = (usb_dwc_hal_port_get_conn_speed(port->hal) == USB_PRIV_SPEED_FULL) ? USB_SPEED_FULL : USB_SPEED_LOW; + port->state = HCD_PORT_STATE_ENABLED; + port->flags.conn_dev_ena = 1; + // This was triggered by a command, so no event needs to be propagated. + break; + } + case USB_DWC_HAL_PORT_EVENT_DISABLED: { + port->flags.conn_dev_ena = 0; + // Disabled could be due to a disable request or reset request, or due to a port error + if (port->state != HCD_PORT_STATE_RESETTING) { // Ignore the disable event if it's due to a reset request + if (port->flags.disable_requested) { + // Disabled by request (i.e. by port command). Generate an internal event + port->state = HCD_PORT_STATE_DISABLED; + port->flags.disable_requested = 0; + *yield |= _internal_port_event_notify_from_isr(port); + } else { + // Disabled due to a port error port->state = HCD_PORT_STATE_RECOVERY; - port_event = HCD_PORT_EVENT_OVERCURRENT; + port_event = HCD_PORT_EVENT_ERROR; } - port->flags.conn_dev_ena = 0; - break; } - default: { - abort(); - break; + break; + } + case USB_DWC_HAL_PORT_EVENT_OVRCUR: + case USB_DWC_HAL_PORT_EVENT_OVRCUR_CLR: { // Could occur if a quick overcurrent then clear happens + if (port->state != HCD_PORT_STATE_NOT_POWERED) { + // We need to power OFF the port to protect it + usb_dwc_hal_port_toggle_power(port->hal, false); + port->state = HCD_PORT_STATE_RECOVERY; + port_event = HCD_PORT_EVENT_OVERCURRENT; } + port->flags.conn_dev_ena = 0; + break; + } + default: { + abort(); + break; + } } return port_event; } @@ -843,64 +843,64 @@ static hcd_pipe_event_t _intr_hdlr_chan(pipe_t *pipe, usb_dwc_hal_chan_t *chan_o hcd_pipe_event_t event = HCD_PIPE_EVENT_NONE; switch (chan_event) { - case USB_DWC_HAL_CHAN_EVENT_CPLT: { - if (!_buffer_check_done(pipe)) { - _buffer_exec_cont(pipe); - break; - } - pipe->last_event = HCD_PIPE_EVENT_URB_DONE; - event = pipe->last_event; - //Mark the buffer as done - int stop_idx = usb_dwc_hal_chan_get_qtd_idx(chan_obj); - _buffer_done(pipe, stop_idx, pipe->last_event, false); - //First check if there is another buffer we can execute. But we only want to execute if there's still a valid device - if (_buffer_can_exec(pipe) && pipe->port->flags.conn_dev_ena) { - //If the next buffer is filled and ready to execute, execute it - _buffer_exec(pipe); - } - //Handle the previously done buffer - _buffer_parse(pipe); - //Check to see if we can fill another buffer. But we only want to fill if there is still a valid device - if (_buffer_can_fill(pipe) && pipe->port->flags.conn_dev_ena) { - //Now that we've parsed a buffer, see if another URB can be filled in its place - _buffer_fill(pipe); - } + case USB_DWC_HAL_CHAN_EVENT_CPLT: { + if (!_buffer_check_done(pipe)) { + _buffer_exec_cont(pipe); break; } - case USB_DWC_HAL_CHAN_EVENT_ERROR: { - //Get and store the pipe error event - usb_dwc_hal_chan_error_t chan_error = usb_dwc_hal_chan_get_error(chan_obj); - pipe->last_event = pipe_decode_error_event(chan_error); - event = pipe->last_event; - pipe->state = HCD_PIPE_STATE_HALTED; - //Mark the buffer as done with an error - int stop_idx = usb_dwc_hal_chan_get_qtd_idx(chan_obj); - _buffer_done(pipe, stop_idx, pipe->last_event, false); - //Parse the buffer - _buffer_parse(pipe); - break; + pipe->last_event = HCD_PIPE_EVENT_URB_DONE; + event = pipe->last_event; + // Mark the buffer as done + int stop_idx = usb_dwc_hal_chan_get_qtd_idx(chan_obj); + _buffer_done(pipe, stop_idx, pipe->last_event, false); + // First check if there is another buffer we can execute. But we only want to execute if there's still a valid device + if (_buffer_can_exec(pipe) && pipe->port->flags.conn_dev_ena) { + // If the next buffer is filled and ready to execute, execute it + _buffer_exec(pipe); } - case USB_DWC_HAL_CHAN_EVENT_HALT_REQ: { - assert(pipe->cs_flags.waiting_halt); - //We've halted a transfer, so we need to trigger the pipe callback - pipe->last_event = HCD_PIPE_EVENT_URB_DONE; - event = pipe->last_event; - //Halt request event is triggered when packet is successful completed. But just treat all halted transfers as errors - pipe->state = HCD_PIPE_STATE_HALTED; - int stop_idx = usb_dwc_hal_chan_get_qtd_idx(chan_obj); - _buffer_done(pipe, stop_idx, HCD_PIPE_EVENT_NONE, true); - //Parse the buffer - _buffer_parse(pipe); - //Notify the task waiting for the pipe halt - *yield |= _internal_pipe_event_notify(pipe, true); - break; + // Handle the previously done buffer + _buffer_parse(pipe); + // Check to see if we can fill another buffer. But we only want to fill if there is still a valid device + if (_buffer_can_fill(pipe) && pipe->port->flags.conn_dev_ena) { + // Now that we've parsed a buffer, see if another URB can be filled in its place + _buffer_fill(pipe); } - case USB_DWC_HAL_CHAN_EVENT_NONE: { - break; //Nothing to do - } - default: - abort(); - break; + break; + } + case USB_DWC_HAL_CHAN_EVENT_ERROR: { + // Get and store the pipe error event + usb_dwc_hal_chan_error_t chan_error = usb_dwc_hal_chan_get_error(chan_obj); + pipe->last_event = pipe_decode_error_event(chan_error); + event = pipe->last_event; + pipe->state = HCD_PIPE_STATE_HALTED; + // Mark the buffer as done with an error + int stop_idx = usb_dwc_hal_chan_get_qtd_idx(chan_obj); + _buffer_done(pipe, stop_idx, pipe->last_event, false); + // Parse the buffer + _buffer_parse(pipe); + break; + } + case USB_DWC_HAL_CHAN_EVENT_HALT_REQ: { + assert(pipe->cs_flags.waiting_halt); + // We've halted a transfer, so we need to trigger the pipe callback + pipe->last_event = HCD_PIPE_EVENT_URB_DONE; + event = pipe->last_event; + // Halt request event is triggered when packet is successful completed. But just treat all halted transfers as errors + pipe->state = HCD_PIPE_STATE_HALTED; + int stop_idx = usb_dwc_hal_chan_get_qtd_idx(chan_obj); + _buffer_done(pipe, stop_idx, HCD_PIPE_EVENT_NONE, true); + // Parse the buffer + _buffer_parse(pipe); + // Notify the task waiting for the pipe halt + *yield |= _internal_pipe_event_notify(pipe, true); + break; + } + case USB_DWC_HAL_CHAN_EVENT_NONE: { + break; // Nothing to do + } + default: + abort(); + break; } return event; } @@ -924,21 +924,21 @@ static void intr_hdlr_main(void *arg) HCD_ENTER_CRITICAL_ISR(); usb_dwc_hal_port_event_t hal_port_evt = usb_dwc_hal_decode_intr(port->hal); if (hal_port_evt == USB_DWC_HAL_PORT_EVENT_CHAN) { - //Channel event. Cycle through each pending channel + // Channel event. Cycle through each pending channel usb_dwc_hal_chan_t *chan_obj = usb_dwc_hal_get_chan_pending_intr(port->hal); while (chan_obj != NULL) { pipe_t *pipe = (pipe_t *)usb_dwc_hal_chan_get_context(chan_obj); hcd_pipe_event_t event = _intr_hdlr_chan(pipe, chan_obj, &yield); - //Run callback if a pipe event has occurred and the pipe also has a callback + // Run callback if a pipe event has occurred and the pipe also has a callback if (event != HCD_PIPE_EVENT_NONE && pipe->callback != NULL) { HCD_EXIT_CRITICAL_ISR(); yield |= pipe->callback((hcd_pipe_handle_t)pipe, event, pipe->callback_arg, true); HCD_ENTER_CRITICAL_ISR(); } - //Check for more channels with pending interrupts. Returns NULL if there are no more + // Check for more channels with pending interrupts. Returns NULL if there are no more chan_obj = usb_dwc_hal_get_chan_pending_intr(port->hal); } - } else if (hal_port_evt != USB_DWC_HAL_PORT_EVENT_NONE) { //Port event + } else if (hal_port_evt != USB_DWC_HAL_PORT_EVENT_NONE) { // Port event hcd_port_event_t port_event = _intr_hdlr_hprt(port, hal_port_evt, &yield); if (port_event != HCD_PORT_EVENT_NONE) { port->last_event = port_event; @@ -963,7 +963,7 @@ static port_t *port_obj_alloc(void) { port_t *port = calloc(1, sizeof(port_t)); usb_dwc_hal_context_t *hal = malloc(sizeof(usb_dwc_hal_context_t)); - void *frame_list = heap_caps_aligned_calloc(USB_DWC_HAL_FRAME_LIST_MEM_ALIGN, FRAME_LIST_LEN,sizeof(uint32_t), MALLOC_CAP_DMA); + void *frame_list = heap_caps_aligned_calloc(USB_DWC_HAL_FRAME_LIST_MEM_ALIGN, FRAME_LIST_LEN, sizeof(uint32_t), MALLOC_CAP_DMA); SemaphoreHandle_t port_mux = xSemaphoreCreateMutex(); if (port == NULL || hal == NULL || frame_list == NULL || port_mux == NULL) { free(port); @@ -1000,19 +1000,19 @@ esp_err_t hcd_install(const hcd_config_t *config) HCD_EXIT_CRITICAL(); esp_err_t err_ret; - //Allocate memory and resources for driver object and all port objects + // Allocate memory and resources for driver object and all port objects hcd_obj_t *p_hcd_obj_dmy = calloc(1, sizeof(hcd_obj_t)); if (p_hcd_obj_dmy == NULL) { return ESP_ERR_NO_MEM; } - //Allocate resources for each port (there's only one) + // Allocate resources for each port (there's only one) p_hcd_obj_dmy->port_obj = port_obj_alloc(); esp_err_t intr_alloc_ret = esp_intr_alloc(ETS_USB_INTR_SOURCE, - config->intr_flags | ESP_INTR_FLAG_INTRDISABLED, //The interrupt must be disabled until the port is initialized - intr_hdlr_main, - (void *)p_hcd_obj_dmy->port_obj, - &p_hcd_obj_dmy->isr_hdl); + config->intr_flags | ESP_INTR_FLAG_INTRDISABLED, // The interrupt must be disabled until the port is initialized + intr_hdlr_main, + (void *)p_hcd_obj_dmy->port_obj, + &p_hcd_obj_dmy->isr_hdl); if (p_hcd_obj_dmy->port_obj == NULL) { err_ret = ESP_ERR_NO_MEM; } @@ -1043,7 +1043,7 @@ err: esp_err_t hcd_uninstall(void) { HCD_ENTER_CRITICAL(); - //Check that all ports have been disabled (there's only one port) + // Check that all ports have been disabled (there's only one port) if (s_hcd_obj == NULL || s_hcd_obj->port_obj->initialized) { HCD_EXIT_CRITICAL(); return ESP_ERR_INVALID_STATE; @@ -1052,7 +1052,7 @@ esp_err_t hcd_uninstall(void) s_hcd_obj = NULL; HCD_EXIT_CRITICAL(); - //Free resources + // Free resources port_obj_free(p_hcd_obj_dmy->port_obj); esp_intr_free(p_hcd_obj_dmy->isr_hdl); free(p_hcd_obj_dmy); @@ -1066,12 +1066,12 @@ esp_err_t hcd_uninstall(void) static bool _port_persist_all_pipes(port_t *port) { if (port->num_pipes_queued > 0) { - //All pipes must be idle before we run-time reset + // All pipes must be idle before we run-time reset return false; } bool all_persist = true; pipe_t *pipe; - //Check that each pipe is persistent + // Check that each pipe is persistent TAILQ_FOREACH(pipe, &port->pipes_idle_tailq, tailq_entry) { if (!pipe->cs_flags.persist) { all_persist = false; @@ -1079,7 +1079,7 @@ static bool _port_persist_all_pipes(port_t *port) } } if (!all_persist) { - //At least one pipe is not persistent. All pipes must be freed or made persistent before we can reset + // At least one pipe is not persistent. All pipes must be freed or made persistent before we can reset return false; } TAILQ_FOREACH(pipe, &port->pipes_idle_tailq, tailq_entry) { @@ -1122,20 +1122,20 @@ static bool _port_check_all_pipes_halted(port_t *port) static bool _port_debounce(port_t *port) { if (port->state == HCD_PORT_STATE_NOT_POWERED) { - //Disconnect event due to power off, no need to debounce or update port state. + // Disconnect event due to power off, no need to debounce or update port state. return false; } HCD_EXIT_CRITICAL(); vTaskDelay(pdMS_TO_TICKS(DEBOUNCE_DELAY_MS)); HCD_ENTER_CRITICAL(); - //Check the post-debounce state of the bus (i.e., whether it's actually connected/disconnected) + // Check the post-debounce state of the bus (i.e., whether it's actually connected/disconnected) bool is_connected = usb_dwc_hal_port_check_if_connected(port->hal); if (is_connected) { port->state = HCD_PORT_STATE_DISABLED; } else { port->state = HCD_PORT_STATE_DISCONNECTED; } - //Disable debounce lock + // Disable debounce lock usb_dwc_hal_disable_debounce_lock(port->hal); return is_connected; } @@ -1145,7 +1145,7 @@ static bool _port_debounce(port_t *port) static esp_err_t _port_cmd_power_on(port_t *port) { esp_err_t ret; - //Port can only be powered on if it's currently unpowered + // Port can only be powered on if it's currently unpowered if (port->state == HCD_PORT_STATE_NOT_POWERED) { port->state = HCD_PORT_STATE_DISCONNECTED; usb_dwc_hal_port_init(port->hal); @@ -1160,12 +1160,12 @@ static esp_err_t _port_cmd_power_on(port_t *port) static esp_err_t _port_cmd_power_off(port_t *port) { esp_err_t ret; - //Port can only be unpowered if already powered + // Port can only be unpowered if already powered if (port->state != HCD_PORT_STATE_NOT_POWERED) { port->state = HCD_PORT_STATE_NOT_POWERED; usb_dwc_hal_port_deinit(port->hal); usb_dwc_hal_port_toggle_power(port->hal, false); - //If a device is currently connected, this should trigger a disconnect event + // If a device is currently connected, this should trigger a disconnect event ret = ESP_OK; } else { ret = ESP_ERR_INVALID_STATE; @@ -1176,42 +1176,42 @@ static esp_err_t _port_cmd_power_off(port_t *port) static esp_err_t _port_cmd_reset(port_t *port) { esp_err_t ret; - //Port can only a reset when it is in the enabled or disabled states (in case of new connection) + // Port can only a reset when it is in the enabled or disabled states (in case of new connection) if (port->state != HCD_PORT_STATE_ENABLED && port->state != HCD_PORT_STATE_DISABLED) { ret = ESP_ERR_INVALID_STATE; goto exit; } bool is_runtime_reset = (port->state == HCD_PORT_STATE_ENABLED) ? true : false; if (is_runtime_reset && !_port_persist_all_pipes(port)) { - //If this is a run time reset, check all pipes that are still allocated can persist the reset + // If this is a run time reset, check all pipes that are still allocated can persist the reset ret = ESP_ERR_INVALID_STATE; goto exit; } - //All pipes (if any_) are guaranteed to be persistent at this point. Proceed to resetting the bus + // All pipes (if any_) are guaranteed to be persistent at this point. Proceed to resetting the bus port->state = HCD_PORT_STATE_RESETTING; - //Put and hold the bus in the reset state. If the port was previously enabled, a disabled event will occur after this + // Put and hold the bus in the reset state. If the port was previously enabled, a disabled event will occur after this usb_dwc_hal_port_toggle_reset(port->hal, true); HCD_EXIT_CRITICAL(); vTaskDelay(pdMS_TO_TICKS(RESET_HOLD_MS)); HCD_ENTER_CRITICAL(); if (port->state != HCD_PORT_STATE_RESETTING) { - //The port state has unexpectedly changed + // The port state has unexpectedly changed ret = ESP_ERR_INVALID_RESPONSE; goto bailout; } - //Return the bus to the idle state and hold it for the required reset recovery time. Port enabled event should occur + // Return the bus to the idle state and hold it for the required reset recovery time. Port enabled event should occur usb_dwc_hal_port_toggle_reset(port->hal, false); HCD_EXIT_CRITICAL(); vTaskDelay(pdMS_TO_TICKS(RESET_RECOVERY_MS)); HCD_ENTER_CRITICAL(); if (port->state != HCD_PORT_STATE_ENABLED || !port->flags.conn_dev_ena) { - //The port state has unexpectedly changed + // The port state has unexpectedly changed ret = ESP_ERR_INVALID_RESPONSE; goto bailout; } - //Set FIFO sizes based on the selected biasing + // Set FIFO sizes based on the selected biasing usb_dwc_hal_set_fifo_size(port->hal, port->fifo_config); - //We start periodic scheduling only after a RESET command since SOFs only start after a reset + // We start periodic scheduling only after a RESET command since SOFs only start after a reset usb_dwc_hal_port_set_frame_list(port->hal, port->frame_list, FRAME_LIST_LEN); usb_dwc_hal_port_periodic_enable(port->hal); ret = ESP_OK; @@ -1226,12 +1226,12 @@ exit: static esp_err_t _port_cmd_bus_suspend(port_t *port) { esp_err_t ret; - //Port must have been previously enabled, and all pipes must already be halted + // Port must have been previously enabled, and all pipes must already be halted if (port->state == HCD_PORT_STATE_ENABLED && !_port_check_all_pipes_halted(port)) { ret = ESP_ERR_INVALID_STATE; goto exit; } - //All pipes are guaranteed halted at this point. Proceed to suspend the port + // All pipes are guaranteed halted at this point. Proceed to suspend the port usb_dwc_hal_port_suspend(port->hal); port->state = HCD_PORT_STATE_SUSPENDED; ret = ESP_OK; @@ -1242,21 +1242,21 @@ exit: static esp_err_t _port_cmd_bus_resume(port_t *port) { esp_err_t ret; - //Port can only be resumed if it was previously suspended + // Port can only be resumed if it was previously suspended if (port->state != HCD_PORT_STATE_SUSPENDED) { ret = ESP_ERR_INVALID_STATE; goto exit; } - //Put and hold the bus in the K state. + // Put and hold the bus in the K state. usb_dwc_hal_port_toggle_resume(port->hal, true); port->state = HCD_PORT_STATE_RESUMING; HCD_EXIT_CRITICAL(); vTaskDelay(pdMS_TO_TICKS(RESUME_HOLD_MS)); HCD_ENTER_CRITICAL(); - //Return and hold the bus to the J state (as port of the LS EOP) + // Return and hold the bus to the J state (as port of the LS EOP) usb_dwc_hal_port_toggle_resume(port->hal, false); if (port->state != HCD_PORT_STATE_RESUMING || !port->flags.conn_dev_ena) { - //Port state unexpectedly changed + // Port state unexpectedly changed ret = ESP_ERR_INVALID_RESPONSE; goto exit; } @@ -1264,7 +1264,7 @@ static esp_err_t _port_cmd_bus_resume(port_t *port) vTaskDelay(pdMS_TO_TICKS(RESUME_RECOVERY_MS)); HCD_ENTER_CRITICAL(); if (port->state != HCD_PORT_STATE_RESUMING || !port->flags.conn_dev_ena) { - //Port state unexpectedly changed + // Port state unexpectedly changed ret = ESP_ERR_INVALID_RESPONSE; goto exit; } @@ -1281,17 +1281,17 @@ static esp_err_t _port_cmd_disable(port_t *port) ret = ESP_ERR_INVALID_STATE; goto exit; } - //All pipes must be halted before disabling the port - if (!_port_check_all_pipes_halted(port)){ + // All pipes must be halted before disabling the port + if (!_port_check_all_pipes_halted(port)) { ret = ESP_ERR_INVALID_STATE; goto exit; } - //All pipes are guaranteed to be halted or freed at this point. Proceed to disable the port + // All pipes are guaranteed to be halted or freed at this point. Proceed to disable the port port->flags.disable_requested = 1; usb_dwc_hal_port_disable(port->hal); _internal_port_event_wait(port); if (port->state != HCD_PORT_STATE_DISABLED) { - //Port state unexpectedly changed + // Port state unexpectedly changed ret = ESP_ERR_INVALID_RESPONSE; goto exit; } @@ -1307,32 +1307,32 @@ esp_err_t hcd_port_init(int port_number, const hcd_port_config_t *port_config, h HCD_CHECK(port_number > 0 && port_config != NULL && port_hdl != NULL, ESP_ERR_INVALID_ARG); HCD_CHECK(port_number <= NUM_PORTS, ESP_ERR_NOT_FOUND); - //Get a pointer to the correct FIFO bias constant values + // Get a pointer to the correct FIFO bias constant values const usb_dwc_hal_fifo_config_t *fifo_config; const fifo_mps_limits_t *mps_limits; switch (port_config->fifo_bias) { - case HCD_PORT_FIFO_BIAS_BALANCED: - fifo_config = &fifo_config_default; - mps_limits = &mps_limits_default; - break; - case HCD_PORT_FIFO_BIAS_RX: - fifo_config = &fifo_config_bias_rx; - mps_limits = &mps_limits_bias_rx; - break; - case HCD_PORT_FIFO_BIAS_PTX: - fifo_config = &fifo_config_bias_ptx; - mps_limits = &mps_limits_bias_ptx; - break; - default: - fifo_config = NULL; - mps_limits = NULL; - abort(); - break; + case HCD_PORT_FIFO_BIAS_BALANCED: + fifo_config = &fifo_config_default; + mps_limits = &mps_limits_default; + break; + case HCD_PORT_FIFO_BIAS_RX: + fifo_config = &fifo_config_bias_rx; + mps_limits = &mps_limits_bias_rx; + break; + case HCD_PORT_FIFO_BIAS_PTX: + fifo_config = &fifo_config_bias_ptx; + mps_limits = &mps_limits_bias_ptx; + break; + default: + fifo_config = NULL; + mps_limits = NULL; + abort(); + break; } HCD_ENTER_CRITICAL(); HCD_CHECK_FROM_CRIT(s_hcd_obj != NULL && !s_hcd_obj->port_obj->initialized, ESP_ERR_INVALID_STATE); - //Port object memory and resources (such as the mutex) already be allocated. Just need to initialize necessary fields only + // Port object memory and resources (such as the mutex) already be allocated. Just need to initialize necessary fields only port_t *port_obj = s_hcd_obj->port_obj; TAILQ_INIT(&port_obj->pipes_idle_tailq); TAILQ_INIT(&port_obj->pipes_active_tailq); @@ -1345,13 +1345,13 @@ esp_err_t hcd_port_init(int port_number, const hcd_port_config_t *port_config, h port_obj->context = port_config->context; usb_dwc_hal_init(port_obj->hal); port_obj->initialized = true; - //Clear the frame list. We set the frame list register and enable periodic scheduling after a successful reset + // Clear the frame list. We set the frame list register and enable periodic scheduling after a successful reset memset(port_obj->frame_list, 0, FRAME_LIST_LEN * sizeof(uint32_t)); esp_intr_enable(s_hcd_obj->isr_hdl); *port_hdl = (hcd_port_handle_t)port_obj; HCD_EXIT_CRITICAL(); - vTaskDelay(pdMS_TO_TICKS(INIT_DELAY_MS)); //Need a short delay before host mode takes effect + vTaskDelay(pdMS_TO_TICKS(INIT_DELAY_MS)); // Need a short delay before host mode takes effect return ESP_OK; } @@ -1379,33 +1379,33 @@ esp_err_t hcd_port_command(hcd_port_handle_t port_hdl, hcd_port_cmd_t command) port_t *port = (port_t *)port_hdl; xSemaphoreTake(port->port_mux, portMAX_DELAY); HCD_ENTER_CRITICAL(); - if (port->initialized && !port->flags.event_pending) { //Port events need to be handled first before issuing a command + if (port->initialized && !port->flags.event_pending) { // Port events need to be handled first before issuing a command port->flags.cmd_processing = 1; switch (command) { - case HCD_PORT_CMD_POWER_ON: { - ret = _port_cmd_power_on(port); - break; - } - case HCD_PORT_CMD_POWER_OFF: { - ret = _port_cmd_power_off(port); - break; - } - case HCD_PORT_CMD_RESET: { - ret = _port_cmd_reset(port); - break; - } - case HCD_PORT_CMD_SUSPEND: { - ret = _port_cmd_bus_suspend(port); - break; - } - case HCD_PORT_CMD_RESUME: { - ret = _port_cmd_bus_resume(port); - break; - } - case HCD_PORT_CMD_DISABLE: { - ret = _port_cmd_disable(port); - break; - } + case HCD_PORT_CMD_POWER_ON: { + ret = _port_cmd_power_on(port); + break; + } + case HCD_PORT_CMD_POWER_OFF: { + ret = _port_cmd_power_off(port); + break; + } + case HCD_PORT_CMD_RESET: { + ret = _port_cmd_reset(port); + break; + } + case HCD_PORT_CMD_SUSPEND: { + ret = _port_cmd_bus_suspend(port); + break; + } + case HCD_PORT_CMD_RESUME: { + ret = _port_cmd_bus_resume(port); + break; + } + case HCD_PORT_CMD_DISABLE: { + ret = _port_cmd_disable(port); + break; + } } port->flags.cmd_processing = 0; } @@ -1429,7 +1429,7 @@ esp_err_t hcd_port_get_speed(hcd_port_handle_t port_hdl, usb_speed_t *speed) port_t *port = (port_t *)port_hdl; HCD_CHECK(speed != NULL, ESP_ERR_INVALID_ARG); HCD_ENTER_CRITICAL(); - //Device speed is only valid if there is device connected to the port that has been reset + // Device speed is only valid if there is device connected to the port that has been reset HCD_CHECK_FROM_CRIT(port->flags.conn_dev_ena, ESP_ERR_INVALID_STATE); usb_priv_speed_t hal_speed = usb_dwc_hal_port_get_conn_speed(port->hal); if (hal_speed == USB_PRIV_SPEED_FULL) { @@ -1452,20 +1452,20 @@ hcd_port_event_t hcd_port_handle_event(hcd_port_handle_t port_hdl) port->flags.event_processing = 1; ret = port->last_event; switch (ret) { - case HCD_PORT_EVENT_CONNECTION: { - if (_port_debounce(port)) { - ret = HCD_PORT_EVENT_CONNECTION; - } - break; - } - case HCD_PORT_EVENT_DISCONNECTION: - case HCD_PORT_EVENT_ERROR: - case HCD_PORT_EVENT_OVERCURRENT: { - break; - } - default: { - break; + case HCD_PORT_EVENT_CONNECTION: { + if (_port_debounce(port)) { + ret = HCD_PORT_EVENT_CONNECTION; } + break; + } + case HCD_PORT_EVENT_DISCONNECTION: + case HCD_PORT_EVENT_ERROR: + case HCD_PORT_EVENT_OVERCURRENT: { + break; + } + default: { + break; + } } port->flags.event_processing = 0; } else { @@ -1484,15 +1484,15 @@ esp_err_t hcd_port_recover(hcd_port_handle_t port_hdl) && port->num_pipes_idle == 0 && port->num_pipes_queued == 0 && port->flags.val == 0 && port->task_waiting_port_notif == NULL, ESP_ERR_INVALID_STATE); - //We are about to do a soft reset on the peripheral. Disable the peripheral throughout + // We are about to do a soft reset on the peripheral. Disable the peripheral throughout esp_intr_disable(s_hcd_obj->isr_hdl); usb_dwc_hal_core_soft_reset(port->hal); port->state = HCD_PORT_STATE_NOT_POWERED; port->last_event = HCD_PORT_EVENT_NONE; port->flags.val = 0; - //Soft reset wipes all registers so we need to reinitialize the HAL + // Soft reset wipes all registers so we need to reinitialize the HAL usb_dwc_hal_init(port->hal); - //Clear the frame list. We set the frame list register and enable periodic scheduling after a successful reset + // Clear the frame list. We set the frame list register and enable periodic scheduling after a successful reset memset(port->frame_list, 0, FRAME_LIST_LEN * sizeof(uint32_t)); esp_intr_enable(s_hcd_obj->isr_hdl); HCD_EXIT_CRITICAL(); @@ -1512,33 +1512,33 @@ void *hcd_port_get_context(hcd_port_handle_t port_hdl) esp_err_t hcd_port_set_fifo_bias(hcd_port_handle_t port_hdl, hcd_port_fifo_bias_t bias) { esp_err_t ret; - //Get a pointer to the correct FIFO bias constant values + // Get a pointer to the correct FIFO bias constant values const usb_dwc_hal_fifo_config_t *fifo_config; const fifo_mps_limits_t *mps_limits; switch (bias) { - case HCD_PORT_FIFO_BIAS_BALANCED: - fifo_config = &fifo_config_default; - mps_limits = &mps_limits_default; - break; - case HCD_PORT_FIFO_BIAS_RX: - fifo_config = &fifo_config_bias_rx; - mps_limits = &mps_limits_bias_rx; - break; - case HCD_PORT_FIFO_BIAS_PTX: - fifo_config = &fifo_config_bias_ptx; - mps_limits = &mps_limits_bias_ptx; - break; - default: - fifo_config = NULL; - mps_limits = NULL; - abort(); - break; + case HCD_PORT_FIFO_BIAS_BALANCED: + fifo_config = &fifo_config_default; + mps_limits = &mps_limits_default; + break; + case HCD_PORT_FIFO_BIAS_RX: + fifo_config = &fifo_config_bias_rx; + mps_limits = &mps_limits_bias_rx; + break; + case HCD_PORT_FIFO_BIAS_PTX: + fifo_config = &fifo_config_bias_ptx; + mps_limits = &mps_limits_bias_ptx; + break; + default: + fifo_config = NULL; + mps_limits = NULL; + abort(); + break; } - //Configure the new FIFO sizes and store the pointers + // Configure the new FIFO sizes and store the pointers port_t *port = (port_t *)port_hdl; xSemaphoreTake(port->port_mux, portMAX_DELAY); HCD_ENTER_CRITICAL(); - //Check that port is in the correct state to update FIFO sizes + // Check that port is in the correct state to update FIFO sizes if (port->initialized && !port->flags.event_pending && port->num_pipes_idle == 0 && port->num_pipes_queued == 0) { usb_dwc_hal_set_fifo_size(port->hal, fifo_config); port->fifo_config = fifo_config; @@ -1560,18 +1560,18 @@ static inline hcd_pipe_event_t pipe_decode_error_event(usb_dwc_hal_chan_error_t { hcd_pipe_event_t event = HCD_PIPE_EVENT_NONE; switch (chan_error) { - case USB_DWC_HAL_CHAN_ERROR_XCS_XACT: - event = HCD_PIPE_EVENT_ERROR_XFER; - break; - case USB_DWC_HAL_CHAN_ERROR_BNA: - event = HCD_PIPE_EVENT_ERROR_URB_NOT_AVAIL; - break; - case USB_DWC_HAL_CHAN_ERROR_PKT_BBL: - event = HCD_PIPE_EVENT_ERROR_OVERFLOW; - break; - case USB_DWC_HAL_CHAN_ERROR_STALL: - event = HCD_PIPE_EVENT_ERROR_STALL; - break; + case USB_DWC_HAL_CHAN_ERROR_XCS_XACT: + event = HCD_PIPE_EVENT_ERROR_XFER; + break; + case USB_DWC_HAL_CHAN_ERROR_BNA: + event = HCD_PIPE_EVENT_ERROR_URB_NOT_AVAIL; + break; + case USB_DWC_HAL_CHAN_ERROR_PKT_BBL: + event = HCD_PIPE_EVENT_ERROR_OVERFLOW; + break; + case USB_DWC_HAL_CHAN_ERROR_STALL: + event = HCD_PIPE_EVENT_ERROR_STALL; + break; } return event; } @@ -1589,7 +1589,7 @@ static dma_buffer_block_t *buffer_block_alloc(usb_transfer_type_t type) case USB_TRANSFER_TYPE_BULK: desc_list_len = XFER_LIST_LEN_BULK; break; - default: //USB_TRANSFER_TYPE_INTR: + default: // USB_TRANSFER_TYPE_INTR: desc_list_len = XFER_LIST_LEN_INTR; break; } @@ -1615,7 +1615,7 @@ static void buffer_block_free(dma_buffer_block_t *buffer) static bool pipe_args_usb_compliance_verification(const hcd_pipe_config_t *pipe_config, usb_speed_t port_speed, usb_transfer_type_t type) { - //Check if pipe can be supported + // Check if pipe can be supported if (port_speed == USB_SPEED_LOW && pipe_config->dev_speed == USB_SPEED_FULL) { ESP_LOGE(HCD_DWC_TAG, "Low speed port does not support full speed pipe"); return false; @@ -1629,40 +1629,40 @@ static bool pipe_args_usb_compliance_verification(const hcd_pipe_config_t *pipe_ return true; } -static bool pipe_alloc_hcd_support_verification(const usb_ep_desc_t * ep_desc, const fifo_mps_limits_t *mps_limits) +static bool pipe_alloc_hcd_support_verification(const usb_ep_desc_t *ep_desc, const fifo_mps_limits_t *mps_limits) { assert(ep_desc != NULL); usb_transfer_type_t type = USB_EP_DESC_GET_XFERTYPE(ep_desc); - //Check the pipe's interval is not zero + // Check the pipe's interval is not zero if ((type == USB_TRANSFER_TYPE_INTR || type == USB_TRANSFER_TYPE_ISOCHRONOUS) && - (ep_desc->bInterval == 0)) { + (ep_desc->bInterval == 0)) { ESP_LOGE(HCD_DWC_TAG, "bInterval value (%d) invalid for pipe type INTR/ISOC", - ep_desc->bInterval); + ep_desc->bInterval); return false; } - //Check if the pipe's interval is compatible with the periodic frame list's length + // Check if the pipe's interval is compatible with the periodic frame list's length if (type == USB_TRANSFER_TYPE_INTR && - (ep_desc->bInterval > FRAME_LIST_LEN)) { + (ep_desc->bInterval > FRAME_LIST_LEN)) { ESP_LOGE(HCD_DWC_TAG, "bInterval value (%d) of Interrupt pipe exceeds max supported limit", - ep_desc->bInterval); + ep_desc->bInterval); return false; } if (type == USB_TRANSFER_TYPE_ISOCHRONOUS && - ((1 << (ep_desc->bInterval - 1)) > FRAME_LIST_LEN)) { + ((1 << (ep_desc->bInterval - 1)) > FRAME_LIST_LEN)) { // (where 0 < 2^(bInterval - 1) <= FRAME_LIST_LEN) ESP_LOGE(HCD_DWC_TAG, "bInterval value (%d) of Isochronous pipe exceeds max supported limit", - ep_desc->bInterval); + ep_desc->bInterval); return false; } - //Check if pipe MPS exceeds HCD MPS limits (due to DWC FIFO sizing) + // Check if pipe MPS exceeds HCD MPS limits (due to DWC FIFO sizing) int limit; - if (USB_EP_DESC_GET_EP_DIR(ep_desc)) { //IN + if (USB_EP_DESC_GET_EP_DIR(ep_desc)) { // IN limit = mps_limits->in_mps; - } else { //OUT + } else { // OUT if (type == USB_TRANSFER_TYPE_CTRL || type == USB_TRANSFER_TYPE_BULK) { limit = mps_limits->non_periodic_out_mps; } else { @@ -1672,8 +1672,8 @@ static bool pipe_alloc_hcd_support_verification(const usb_ep_desc_t * ep_desc, c if (ep_desc->wMaxPacketSize > limit) { ESP_LOGE(HCD_DWC_TAG, "EP MPS (%d) exceeds supported limit (%d)", - ep_desc->wMaxPacketSize, - limit); + ep_desc->wMaxPacketSize, + limit); return false; } @@ -1682,26 +1682,26 @@ static bool pipe_alloc_hcd_support_verification(const usb_ep_desc_t * ep_desc, c static void pipe_set_ep_char(const hcd_pipe_config_t *pipe_config, usb_transfer_type_t type, bool is_default_pipe, int pipe_idx, usb_speed_t port_speed, usb_dwc_hal_ep_char_t *ep_char) { - //Initialize EP characteristics + // Initialize EP characteristics usb_priv_xfer_type_t hal_xfer_type; switch (type) { - case USB_TRANSFER_TYPE_CTRL: - hal_xfer_type = USB_PRIV_XFER_TYPE_CTRL; - break; - case USB_TRANSFER_TYPE_ISOCHRONOUS: - hal_xfer_type = USB_PRIV_XFER_TYPE_ISOCHRONOUS; - break; - case USB_TRANSFER_TYPE_BULK: - hal_xfer_type = USB_PRIV_XFER_TYPE_BULK; - break; - default: //USB_TRANSFER_TYPE_INTR - hal_xfer_type = USB_PRIV_XFER_TYPE_INTR; - break; + case USB_TRANSFER_TYPE_CTRL: + hal_xfer_type = USB_PRIV_XFER_TYPE_CTRL; + break; + case USB_TRANSFER_TYPE_ISOCHRONOUS: + hal_xfer_type = USB_PRIV_XFER_TYPE_ISOCHRONOUS; + break; + case USB_TRANSFER_TYPE_BULK: + hal_xfer_type = USB_PRIV_XFER_TYPE_BULK; + break; + default: // USB_TRANSFER_TYPE_INTR + hal_xfer_type = USB_PRIV_XFER_TYPE_INTR; + break; } ep_char->type = hal_xfer_type; if (is_default_pipe) { ep_char->bEndpointAddress = 0; - //Set the default pipe's MPS to the worst case MPS for the device's speed + // Set the default pipe's MPS to the worst case MPS for the device's speed ep_char->mps = (pipe_config->dev_speed == USB_SPEED_FULL) ? CTRL_EP_MAX_MPS_FS : CTRL_EP_MAX_MPS_LS; } else { ep_char->bEndpointAddress = pipe_config->ep_desc->bEndpointAddress; @@ -1709,7 +1709,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 = (port_speed == USB_SPEED_FULL && pipe_config->dev_speed == USB_SPEED_LOW); - //Calculate the pipe's interval in terms of USB frames + // Calculate the pipe's interval in terms of USB frames if (type == USB_TRANSFER_TYPE_INTR || type == USB_TRANSFER_TYPE_ISOCHRONOUS) { int interval_frames; if (type == USB_TRANSFER_TYPE_INTR) { @@ -1717,7 +1717,7 @@ static void pipe_set_ep_char(const hcd_pipe_config_t *pipe_config, usb_transfer_ } else { interval_frames = (1 << (pipe_config->ep_desc->bInterval - 1)); } - //Round down interval to nearest power of 2 + // Round down interval to nearest power of 2 if (interval_frames >= 32) { interval_frames = 32; } else if (interval_frames >= 16) { @@ -1732,9 +1732,9 @@ static void pipe_set_ep_char(const hcd_pipe_config_t *pipe_config, usb_transfer_ interval_frames = 1; } ep_char->periodic.interval = interval_frames; - //We are the Nth pipe to be allocated. Use N as a phase offset + // We are the Nth pipe to be allocated. Use N as a phase offset ep_char->periodic.phase_offset_frames = pipe_idx & (XFER_LIST_LEN_ISOC - 1); - }else { + } else { ep_char->periodic.interval = 0; ep_char->periodic.phase_offset_frames = 0; } @@ -1746,21 +1746,21 @@ static esp_err_t _pipe_cmd_halt(pipe_t *pipe) { esp_err_t ret; - //If pipe is already halted, just return. + // If pipe is already halted, just return. if (pipe->state == HCD_PIPE_STATE_HALTED) { ret = ESP_OK; goto exit; } - //If the pipe's port is invalid, we just mark the pipe as halted without needing to halt the underlying channel - if (pipe->port->flags.conn_dev_ena //Skip halting the underlying channel if the port is invalid - && !usb_dwc_hal_chan_request_halt(pipe->chan_obj)) { //Check if the channel is already halted - //Channel is not halted, we need to request and wait for a haltWe need to wait for channel to be halted. - pipe->cs_flags.waiting_halt = 1; - _internal_pipe_event_wait(pipe); - //State should have been updated in the ISR - assert(pipe->state == HCD_PIPE_STATE_HALTED); + // If the pipe's port is invalid, we just mark the pipe as halted without needing to halt the underlying channel + if (pipe->port->flags.conn_dev_ena // Skip halting the underlying channel if the port is invalid + && !usb_dwc_hal_chan_request_halt(pipe->chan_obj)) { // Check if the channel is already halted + // Channel is not halted, we need to request and wait for a haltWe need to wait for channel to be halted. + pipe->cs_flags.waiting_halt = 1; + _internal_pipe_event_wait(pipe); + // State should have been updated in the ISR + assert(pipe->state == HCD_PIPE_STATE_HALTED); } else { - //We are already halted, just need to update the state + // We are already halted, just need to update the state usb_dwc_hal_chan_mark_halted(pipe->chan_obj); pipe->state = HCD_PIPE_STATE_HALTED; } @@ -1772,42 +1772,42 @@ exit: static esp_err_t _pipe_cmd_flush(pipe_t *pipe) { esp_err_t ret; - //The pipe must be halted in order to be flushed + // The pipe must be halted in order to be flushed if (pipe->state != HCD_PIPE_STATE_HALTED) { ret = ESP_ERR_INVALID_STATE; goto exit; } - //If the port is still valid, we are canceling transfers. Otherwise, we are flushing due to a port error + // If the port is still valid, we are canceling transfers. Otherwise, we are flushing due to a port error bool canceled = pipe->port->flags.conn_dev_ena; bool call_pipe_cb; - //Flush any filled buffers + // Flush any filled buffers call_pipe_cb = _buffer_flush_all(pipe, canceled); - //Move all URBs from the pending tailq to the done tailq + // Move all URBs from the pending tailq to the done tailq if (pipe->num_urb_pending > 0) { - //Process all remaining pending URBs + // Process all remaining pending URBs urb_t *urb; TAILQ_FOREACH(urb, &pipe->pending_urb_tailq, tailq_entry) { - //Update the URB's current state + // Update the URB's current state urb->hcd_var = URB_HCD_STATE_DONE; - //URBs were never executed, Update the actual_num_bytes and status + // URBs were never executed, Update the actual_num_bytes and status urb->transfer.actual_num_bytes = 0; urb->transfer.status = (canceled) ? USB_TRANSFER_STATUS_CANCELED : USB_TRANSFER_STATUS_NO_DEVICE; if (pipe->ep_char.type == USB_PRIV_XFER_TYPE_ISOCHRONOUS) { - //Update the URB's isoc packet descriptors as well + // Update the URB's isoc packet descriptors as well for (int pkt_idx = 0; pkt_idx < urb->transfer.num_isoc_packets; pkt_idx++) { urb->transfer.isoc_packet_desc[pkt_idx].actual_num_bytes = 0; urb->transfer.isoc_packet_desc[pkt_idx].status = (canceled) ? USB_TRANSFER_STATUS_CANCELED : USB_TRANSFER_STATUS_NO_DEVICE; } } } - //Concatenated pending tailq to the done tailq + // Concatenated pending tailq to the done tailq TAILQ_CONCAT(&pipe->done_urb_tailq, &pipe->pending_urb_tailq, tailq_entry); pipe->num_urb_done += pipe->num_urb_pending; pipe->num_urb_pending = 0; call_pipe_cb = true; } if (call_pipe_cb) { - //One or more URBs can be dequeued as a result of the flush. We need to call the callback + // One or more URBs can be dequeued as a result of the flush. We need to call the callback HCD_EXIT_CRITICAL(); pipe->callback((hcd_pipe_handle_t)pipe, HCD_PIPE_EVENT_URB_DONE, pipe->callback_arg, false); HCD_ENTER_CRITICAL(); @@ -1820,20 +1820,20 @@ exit: static esp_err_t _pipe_cmd_clear(pipe_t *pipe) { esp_err_t ret; - //Pipe must be in the halted state in order to be made active, and there must be an enabled device on the port + // Pipe must be in the halted state in order to be made active, and there must be an enabled device on the port if (pipe->state != HCD_PIPE_STATE_HALTED || !pipe->port->flags.conn_dev_ena) { ret = ESP_ERR_INVALID_STATE; goto exit; } - //Update the pipe's state + // Update the pipe's state pipe->state = HCD_PIPE_STATE_ACTIVE; if (pipe->num_urb_pending > 0) { - //Fill as many buffers as possible + // Fill as many buffers as possible while (_buffer_can_fill(pipe)) { _buffer_fill(pipe); } } - //Execute any filled buffers + // Execute any filled buffers if (_buffer_can_exec(pipe)) { _buffer_exec(pipe); } @@ -1849,7 +1849,7 @@ esp_err_t hcd_pipe_alloc(hcd_port_handle_t port_hdl, const hcd_pipe_config_t *pi HCD_CHECK(port_hdl != NULL && pipe_config != NULL && pipe_hdl != NULL, ESP_ERR_INVALID_ARG); port_t *port = (port_t *)port_hdl; HCD_ENTER_CRITICAL(); - //Can only allocate a pipe if the target port is initialized and connected to an enabled device + // Can only allocate a pipe if the target port is initialized and connected to an enabled device HCD_CHECK_FROM_CRIT(port->initialized && port->flags.conn_dev_ena, ESP_ERR_INVALID_STATE); usb_speed_t port_speed = port->speed; const fifo_mps_limits_t *mps_limits = port->fifo_mps_limits; @@ -1868,19 +1868,19 @@ esp_err_t hcd_pipe_alloc(hcd_port_handle_t port_hdl, const hcd_pipe_config_t *pi } esp_err_t ret; - //Check if pipe configuration can be supported + // Check if pipe configuration can be supported if (!pipe_args_usb_compliance_verification(pipe_config, port_speed, type)) { return ESP_ERR_NOT_SUPPORTED; } - //Default pipes have a NULL ep_desc thus should skip the HCD support verification + // Default pipes have a NULL ep_desc thus should skip the HCD support verification if (!is_default && !pipe_alloc_hcd_support_verification(pipe_config->ep_desc, mps_limits)) { return ESP_ERR_NOT_SUPPORTED; } - //Allocate the pipe resources + // Allocate the pipe resources pipe_t *pipe = calloc(1, sizeof(pipe_t)); usb_dwc_hal_chan_t *chan_obj = calloc(1, sizeof(usb_dwc_hal_chan_t)); dma_buffer_block_t *buffers[NUM_BUFFERS] = {0}; - if (pipe == NULL|| chan_obj == NULL) { + if (pipe == NULL || chan_obj == NULL) { ret = ESP_ERR_NO_MEM; goto err; } @@ -1892,7 +1892,7 @@ esp_err_t hcd_pipe_alloc(hcd_port_handle_t port_hdl, const hcd_pipe_config_t *pi } } - //Initialize pipe object + // Initialize pipe object TAILQ_INIT(&pipe->pending_urb_tailq); TAILQ_INIT(&pipe->done_urb_tailq); for (int i = 0; i < NUM_BUFFERS; i++) { @@ -1909,7 +1909,7 @@ esp_err_t hcd_pipe_alloc(hcd_port_handle_t port_hdl, const hcd_pipe_config_t *pi pipe->callback_arg = pipe_config->callback_arg; pipe->context = pipe_config->context; - //Allocate channel + // Allocate channel HCD_ENTER_CRITICAL(); if (!port->initialized || !port->flags.conn_dev_ena) { HCD_EXIT_CRITICAL(); @@ -1923,7 +1923,7 @@ esp_err_t hcd_pipe_alloc(hcd_port_handle_t port_hdl, const hcd_pipe_config_t *pi goto err; } usb_dwc_hal_chan_set_ep_char(port->hal, pipe->chan_obj, &pipe->ep_char); - //Add the pipe to the list of idle pipes in the port object + // Add the pipe to the list of idle pipes in the port object TAILQ_INSERT_TAIL(&port->pipes_idle_tailq, pipe, tailq_entry); port->num_pipes_idle++; HCD_EXIT_CRITICAL(); @@ -1944,18 +1944,18 @@ esp_err_t hcd_pipe_free(hcd_pipe_handle_t pipe_hdl) { pipe_t *pipe = (pipe_t *)pipe_hdl; HCD_ENTER_CRITICAL(); - //Check that all URBs have been removed and pipe has no pending events + // Check that all URBs have been removed and pipe has no pending events HCD_CHECK_FROM_CRIT(!pipe->multi_buffer_control.buffer_is_executing && !pipe->cs_flags.has_urb && !pipe->cs_flags.reset_lock, ESP_ERR_INVALID_STATE); - //Remove pipe from the list of idle pipes (it must be in the idle list because it should have no queued URBs) + // Remove pipe from the list of idle pipes (it must be in the idle list because it should have no queued URBs) TAILQ_REMOVE(&pipe->port->pipes_idle_tailq, pipe, tailq_entry); pipe->port->num_pipes_idle--; usb_dwc_hal_chan_free(pipe->port->hal, pipe->chan_obj); HCD_EXIT_CRITICAL(); - //Free pipe resources + // Free pipe resources for (int i = 0; i < NUM_BUFFERS; i++) { buffer_block_free(pipe->buffers[i]); } @@ -1968,13 +1968,13 @@ esp_err_t hcd_pipe_update_mps(hcd_pipe_handle_t pipe_hdl, int mps) { pipe_t *pipe = (pipe_t *)pipe_hdl; HCD_ENTER_CRITICAL(); - //Check if pipe is in the correct state to be updated + // Check if pipe is in the correct state to be updated HCD_CHECK_FROM_CRIT(!pipe->cs_flags.pipe_cmd_processing && !pipe->cs_flags.has_urb && !pipe->cs_flags.reset_lock, ESP_ERR_INVALID_STATE); pipe->ep_char.mps = mps; - //Update the underlying channel's registers + // Update the underlying channel's registers usb_dwc_hal_chan_set_ep_char(pipe->port->hal, pipe->chan_obj, &pipe->ep_char); HCD_EXIT_CRITICAL(); return ESP_OK; @@ -1984,13 +1984,13 @@ esp_err_t hcd_pipe_update_dev_addr(hcd_pipe_handle_t pipe_hdl, uint8_t dev_addr) { pipe_t *pipe = (pipe_t *)pipe_hdl; HCD_ENTER_CRITICAL(); - //Check if pipe is in the correct state to be updated + // Check if pipe is in the correct state to be updated HCD_CHECK_FROM_CRIT(!pipe->cs_flags.pipe_cmd_processing && !pipe->cs_flags.has_urb && !pipe->cs_flags.reset_lock, ESP_ERR_INVALID_STATE); pipe->ep_char.dev_addr = dev_addr; - //Update the underlying channel's registers + // Update the underlying channel's registers usb_dwc_hal_chan_set_ep_char(pipe->port->hal, pipe->chan_obj, &pipe->ep_char); HCD_EXIT_CRITICAL(); return ESP_OK; @@ -2000,7 +2000,7 @@ esp_err_t hcd_pipe_update_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_callback { pipe_t *pipe = (pipe_t *)pipe_hdl; HCD_ENTER_CRITICAL(); - //Check if pipe is in the correct state to be updated + // Check if pipe is in the correct state to be updated HCD_CHECK_FROM_CRIT(!pipe->cs_flags.pipe_cmd_processing && !pipe->cs_flags.has_urb && !pipe->cs_flags.reset_lock, @@ -2015,7 +2015,7 @@ esp_err_t hcd_pipe_set_persist_reset(hcd_pipe_handle_t pipe_hdl) { pipe_t *pipe = (pipe_t *)pipe_hdl; HCD_ENTER_CRITICAL(); - //Check if pipe is in the correct state to be updated + // Check if pipe is in the correct state to be updated HCD_CHECK_FROM_CRIT(!pipe->cs_flags.pipe_cmd_processing && !pipe->cs_flags.has_urb && !pipe->cs_flags.reset_lock, @@ -2061,24 +2061,24 @@ esp_err_t hcd_pipe_command(hcd_pipe_handle_t pipe_hdl, hcd_pipe_cmd_t command) esp_err_t ret = ESP_OK; HCD_ENTER_CRITICAL(); - //Cannot execute pipe commands the pipe is already executing a command, or if the pipe or its port are no longer valid + // Cannot execute pipe commands the pipe is already executing a command, or if the pipe or its port are no longer valid if (pipe->cs_flags.reset_lock) { ret = ESP_ERR_INVALID_STATE; } else { pipe->cs_flags.pipe_cmd_processing = 1; switch (command) { - case HCD_PIPE_CMD_HALT: { - ret = _pipe_cmd_halt(pipe); - break; - } - case HCD_PIPE_CMD_FLUSH: { - ret = _pipe_cmd_flush(pipe); - break; - } - case HCD_PIPE_CMD_CLEAR: { - ret = _pipe_cmd_clear(pipe); - break; - } + case HCD_PIPE_CMD_HALT: { + ret = _pipe_cmd_halt(pipe); + break; + } + case HCD_PIPE_CMD_FLUSH: { + ret = _pipe_cmd_flush(pipe); + break; + } + case HCD_PIPE_CMD_CLEAR: { + ret = _pipe_cmd_clear(pipe); + break; + } } pipe->cs_flags.pipe_cmd_processing = 0; } @@ -2101,26 +2101,26 @@ hcd_pipe_event_t hcd_pipe_get_event(hcd_pipe_handle_t pipe_hdl) static inline void _buffer_fill_ctrl(dma_buffer_block_t *buffer, usb_transfer_t *transfer) { - //Get information about the control transfer by analyzing the setup packet (the first 8 bytes of the URB's data) + // Get information about the control transfer by analyzing the setup packet (the first 8 bytes of the URB's data) usb_setup_packet_t *setup_pkt = (usb_setup_packet_t *)transfer->data_buffer; bool data_stg_in = (setup_pkt->bmRequestType & USB_BM_REQUEST_TYPE_DIR_IN); bool data_stg_skip = (setup_pkt->wLength == 0); - //Fill setup stage + // Fill setup stage usb_dwc_hal_xfer_desc_fill(buffer->xfer_desc_list, 0, transfer->data_buffer, sizeof(usb_setup_packet_t), - USB_DWC_HAL_XFER_DESC_FLAG_SETUP | USB_DWC_HAL_XFER_DESC_FLAG_HOC); - //Fill data stage + USB_DWC_HAL_XFER_DESC_FLAG_SETUP | USB_DWC_HAL_XFER_DESC_FLAG_HOC); + // Fill data stage if (data_stg_skip) { - //Not data stage. Fill with an empty descriptor + // Not data stage. Fill with an empty descriptor usb_dwc_hal_xfer_desc_clear(buffer->xfer_desc_list, 1); } else { - //Fill data stage. Note that we still fill with transfer->num_bytes instead of setup_pkt->wLength as it's possible to require more bytes than wLength + // Fill data stage. Note that we still fill with transfer->num_bytes instead of setup_pkt->wLength as it's possible to require more bytes than wLength usb_dwc_hal_xfer_desc_fill(buffer->xfer_desc_list, 1, transfer->data_buffer + sizeof(usb_setup_packet_t), transfer->num_bytes - sizeof(usb_setup_packet_t), - ((data_stg_in) ? USB_DWC_HAL_XFER_DESC_FLAG_IN : 0) | USB_DWC_HAL_XFER_DESC_FLAG_HOC); + ((data_stg_in) ? USB_DWC_HAL_XFER_DESC_FLAG_IN : 0) | USB_DWC_HAL_XFER_DESC_FLAG_HOC); } - //Fill status stage (i.e., a zero length packet). If data stage is skipped, the status stage is always IN. + // Fill status stage (i.e., a zero length packet). If data stage is skipped, the status stage is always IN. usb_dwc_hal_xfer_desc_fill(buffer->xfer_desc_list, 2, NULL, 0, - ((data_stg_in && !data_stg_skip) ? 0 : USB_DWC_HAL_XFER_DESC_FLAG_IN) | USB_DWC_HAL_XFER_DESC_FLAG_HOC); - //Update buffer flags + ((data_stg_in && !data_stg_skip) ? 0 : USB_DWC_HAL_XFER_DESC_FLAG_IN) | USB_DWC_HAL_XFER_DESC_FLAG_HOC); + // Update buffer flags buffer->flags.ctrl.data_stg_in = data_stg_in; buffer->flags.ctrl.data_stg_skip = data_stg_skip; buffer->flags.ctrl.cur_stg = 0; @@ -2128,23 +2128,23 @@ static inline void _buffer_fill_ctrl(dma_buffer_block_t *buffer, usb_transfer_t static inline void _buffer_fill_bulk(dma_buffer_block_t *buffer, usb_transfer_t *transfer, bool is_in, int mps) { - //Only add a zero length packet if OUT, flag is set, and transfer length is multiple of EP's MPS - //Minor optimization: Do the mod operation last + // Only add a zero length packet if OUT, flag is set, and transfer length is multiple of EP's MPS + // Minor optimization: Do the mod operation last bool zero_len_packet = !is_in && (transfer->flags & USB_TRANSFER_FLAG_ZERO_PACK) && (transfer->num_bytes % mps == 0); if (is_in) { usb_dwc_hal_xfer_desc_fill(buffer->xfer_desc_list, 0, transfer->data_buffer, transfer->num_bytes, - USB_DWC_HAL_XFER_DESC_FLAG_IN | USB_DWC_HAL_XFER_DESC_FLAG_HOC); - } else { //OUT + USB_DWC_HAL_XFER_DESC_FLAG_IN | USB_DWC_HAL_XFER_DESC_FLAG_HOC); + } else { // OUT if (zero_len_packet) { - //Adding a zero length packet, so two descriptors are used. + // Adding a zero length packet, so two descriptors are used. usb_dwc_hal_xfer_desc_fill(buffer->xfer_desc_list, 0, transfer->data_buffer, transfer->num_bytes, 0); usb_dwc_hal_xfer_desc_fill(buffer->xfer_desc_list, 1, NULL, 0, USB_DWC_HAL_XFER_DESC_FLAG_HOC); } else { - //Zero length packet not required. One descriptor is enough + // Zero length packet not required. One descriptor is enough usb_dwc_hal_xfer_desc_fill(buffer->xfer_desc_list, 0, transfer->data_buffer, transfer->num_bytes, USB_DWC_HAL_XFER_DESC_FLAG_HOC); } } - //Update buffer flags + // Update buffer flags buffer->flags.bulk.zero_len_packet = zero_len_packet; } @@ -2152,40 +2152,40 @@ static inline void _buffer_fill_intr(dma_buffer_block_t *buffer, usb_transfer_t { int num_qtds; int mod_mps = transfer->num_bytes % mps; - //Only add a zero length packet if OUT, flag is set, and transfer length is multiple of EP's MPS + // Only add a zero length packet if OUT, flag is set, and transfer length is multiple of EP's MPS bool zero_len_packet = !is_in && (transfer->flags & USB_TRANSFER_FLAG_ZERO_PACK) && (mod_mps == 0); if (is_in) { - assert(mod_mps == 0); //IN transfers MUST be integer multiple of MPS - num_qtds = transfer->num_bytes / mps; //Can just floor divide as it's already multiple of MPS + assert(mod_mps == 0); // IN transfers MUST be integer multiple of MPS + num_qtds = transfer->num_bytes / mps; // Can just floor divide as it's already multiple of MPS } else { - num_qtds = transfer->num_bytes / mps; //Floor division to get the number of MPS sized packets + num_qtds = transfer->num_bytes / mps; // Floor division to get the number of MPS sized packets if (mod_mps > 0) { - num_qtds++; //Add a short packet for the remainder + num_qtds++; // Add a short packet for the remainder } } - assert((zero_len_packet) ? num_qtds + 1 : num_qtds <= XFER_LIST_LEN_INTR); //Check that the number of QTDs doesn't exceed the QTD list's length + assert((zero_len_packet) ? num_qtds + 1 : num_qtds <= XFER_LIST_LEN_INTR); // Check that the number of QTDs doesn't exceed the QTD list's length uint32_t xfer_desc_flags = (is_in) ? USB_DWC_HAL_XFER_DESC_FLAG_IN : 0; int bytes_filled = 0; - //Fill all but last QTD + // Fill all but last QTD for (int i = 0; i < num_qtds - 1; i++) { usb_dwc_hal_xfer_desc_fill(buffer->xfer_desc_list, i, &transfer->data_buffer[bytes_filled], mps, xfer_desc_flags); bytes_filled += mps; } - //Fill last QTD and zero length packet + // Fill last QTD and zero length packet if (zero_len_packet) { - //Fill in last data packet without HOC flag + // Fill in last data packet without HOC flag usb_dwc_hal_xfer_desc_fill(buffer->xfer_desc_list, num_qtds - 1, &transfer->data_buffer[bytes_filled], transfer->num_bytes - bytes_filled, - xfer_desc_flags); - //HOC flag goes to zero length packet instead + xfer_desc_flags); + // HOC flag goes to zero length packet instead usb_dwc_hal_xfer_desc_fill(buffer->xfer_desc_list, num_qtds, NULL, 0, USB_DWC_HAL_XFER_DESC_FLAG_HOC); } else { - //Zero length packet not required. Fill in last QTD with HOC flag + // Zero length packet not required. Fill in last QTD with HOC flag usb_dwc_hal_xfer_desc_fill(buffer->xfer_desc_list, num_qtds - 1, &transfer->data_buffer[bytes_filled], transfer->num_bytes - bytes_filled, - xfer_desc_flags | USB_DWC_HAL_XFER_DESC_FLAG_HOC); + xfer_desc_flags | USB_DWC_HAL_XFER_DESC_FLAG_HOC); } - //Update buffer members and flags + // Update buffer members and flags buffer->flags.intr.num_qtds = num_qtds; buffer->flags.intr.zero_len_packet = zero_len_packet; } @@ -2197,12 +2197,12 @@ static inline void _buffer_fill_isoc(dma_buffer_block_t *buffer, usb_transfer_t assert(total_num_desc <= XFER_LIST_LEN_ISOC); int desc_idx = start_idx; int bytes_filled = 0; - //For each packet, fill in a descriptor and a interval-1 blank descriptor after it + // For each packet, fill in a descriptor and a interval-1 blank descriptor after it for (int pkt_idx = 0; pkt_idx < transfer->num_isoc_packets; pkt_idx++) { int xfer_len = transfer->isoc_packet_desc[pkt_idx].num_bytes; uint32_t flags = (is_in) ? USB_DWC_HAL_XFER_DESC_FLAG_IN : 0; if (pkt_idx == transfer->num_isoc_packets - 1) { - //Last packet, set the the HOC flag + // Last packet, set the the HOC flag flags |= USB_DWC_HAL_XFER_DESC_FLAG_HOC; } usb_dwc_hal_xfer_desc_fill(buffer->xfer_desc_list, desc_idx, &transfer->data_buffer[bytes_filled], xfer_len, flags); @@ -2210,7 +2210,7 @@ static inline void _buffer_fill_isoc(dma_buffer_block_t *buffer, usb_transfer_t if (++desc_idx >= XFER_LIST_LEN_ISOC) { desc_idx = 0; } - //Clear descriptors for unscheduled frames + // Clear descriptors for unscheduled frames for (int i = 0; i < interval - 1; i++) { usb_dwc_hal_xfer_desc_clear(buffer->xfer_desc_list, desc_idx); if (++desc_idx >= XFER_LIST_LEN_ISOC) { @@ -2218,7 +2218,7 @@ static inline void _buffer_fill_isoc(dma_buffer_block_t *buffer, usb_transfer_t } } } - //Update buffer members and flags + // Update buffer members and flags buffer->flags.isoc.num_qtds = total_num_desc; buffer->flags.isoc.interval = interval; buffer->flags.isoc.start_idx = start_idx; @@ -2227,67 +2227,67 @@ static inline void _buffer_fill_isoc(dma_buffer_block_t *buffer, usb_transfer_t static void _buffer_fill(pipe_t *pipe) { - //Get an URB from the pending tailq + // Get an URB from the pending tailq urb_t *urb = TAILQ_FIRST(&pipe->pending_urb_tailq); assert(pipe->num_urb_pending > 0 && urb != NULL); TAILQ_REMOVE(&pipe->pending_urb_tailq, urb, tailq_entry); pipe->num_urb_pending--; - //Select the inactive buffer + // Select the inactive buffer assert(pipe->multi_buffer_control.buffer_num_to_exec <= NUM_BUFFERS); dma_buffer_block_t *buffer_to_fill = pipe->buffers[pipe->multi_buffer_control.wr_idx]; - buffer_to_fill->status_flags.val = 0; //Clear the buffer's status flags + buffer_to_fill->status_flags.val = 0; // Clear the buffer's status flags assert(buffer_to_fill->urb == NULL); bool is_in = pipe->ep_char.bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK; int mps = pipe->ep_char.mps; usb_transfer_t *transfer = &urb->transfer; switch (pipe->ep_char.type) { - case USB_PRIV_XFER_TYPE_CTRL: { - _buffer_fill_ctrl(buffer_to_fill, transfer); - break; - } - case USB_PRIV_XFER_TYPE_ISOCHRONOUS: { - uint32_t start_idx; - if (pipe->multi_buffer_control.buffer_num_to_exec == 0) { - //There are no more previously filled buffers to execute. We need to calculate a new start index based on HFNUM and the pipe's schedule - uint32_t cur_frame_num = usb_dwc_hal_port_get_cur_frame_num(pipe->port->hal); - uint32_t cur_mod_idx_no_offset = (cur_frame_num - pipe->ep_char.periodic.phase_offset_frames) & (XFER_LIST_LEN_ISOC - 1); //Get the modulated index (i.e., the Nth desc in the descriptor list) - //This is the non-offset modulated QTD index of the last scheduled interval - uint32_t last_interval_mod_idx_no_offset = (cur_mod_idx_no_offset / pipe->ep_char.periodic.interval) * pipe->ep_char.periodic.interval; //Floor divide and the multiply again - uint32_t next_interval_idx_no_offset = (last_interval_mod_idx_no_offset + pipe->ep_char.periodic.interval); - //We want at least a half interval or 2 frames of buffer space - if (next_interval_idx_no_offset - cur_mod_idx_no_offset > (pipe->ep_char.periodic.interval / 2) + case USB_PRIV_XFER_TYPE_CTRL: { + _buffer_fill_ctrl(buffer_to_fill, transfer); + break; + } + case USB_PRIV_XFER_TYPE_ISOCHRONOUS: { + uint32_t start_idx; + if (pipe->multi_buffer_control.buffer_num_to_exec == 0) { + // There are no more previously filled buffers to execute. We need to calculate a new start index based on HFNUM and the pipe's schedule + uint32_t cur_frame_num = usb_dwc_hal_port_get_cur_frame_num(pipe->port->hal); + uint32_t cur_mod_idx_no_offset = (cur_frame_num - pipe->ep_char.periodic.phase_offset_frames) & (XFER_LIST_LEN_ISOC - 1); // Get the modulated index (i.e., the Nth desc in the descriptor list) + // This is the non-offset modulated QTD index of the last scheduled interval + uint32_t last_interval_mod_idx_no_offset = (cur_mod_idx_no_offset / pipe->ep_char.periodic.interval) * pipe->ep_char.periodic.interval; // Floor divide and the multiply again + uint32_t next_interval_idx_no_offset = (last_interval_mod_idx_no_offset + pipe->ep_char.periodic.interval); + // We want at least a half interval or 2 frames of buffer space + if (next_interval_idx_no_offset - cur_mod_idx_no_offset > (pipe->ep_char.periodic.interval / 2) && next_interval_idx_no_offset - cur_mod_idx_no_offset >= 2) { - start_idx = (next_interval_idx_no_offset + pipe->ep_char.periodic.phase_offset_frames) & (XFER_LIST_LEN_ISOC - 1); - } else { - //Not enough time until the next schedule, add another interval to it. - start_idx = (next_interval_idx_no_offset + pipe->ep_char.periodic.interval + pipe->ep_char.periodic.phase_offset_frames) & (XFER_LIST_LEN_ISOC - 1); - } + start_idx = (next_interval_idx_no_offset + pipe->ep_char.periodic.phase_offset_frames) & (XFER_LIST_LEN_ISOC - 1); } else { - //Start index is based on previously filled buffer - uint32_t prev_buffer_idx = (pipe->multi_buffer_control.wr_idx - 1) & (NUM_BUFFERS - 1); - dma_buffer_block_t *prev_filled_buffer = pipe->buffers[prev_buffer_idx]; - start_idx = prev_filled_buffer->flags.isoc.next_start_idx; + // Not enough time until the next schedule, add another interval to it. + start_idx = (next_interval_idx_no_offset + pipe->ep_char.periodic.interval + pipe->ep_char.periodic.phase_offset_frames) & (XFER_LIST_LEN_ISOC - 1); } - _buffer_fill_isoc(buffer_to_fill, transfer, is_in, mps, (int)pipe->ep_char.periodic.interval, start_idx); - break; - } - case USB_PRIV_XFER_TYPE_BULK: { - _buffer_fill_bulk(buffer_to_fill, transfer, is_in, mps); - break; - } - case USB_PRIV_XFER_TYPE_INTR: { - _buffer_fill_intr(buffer_to_fill, transfer, is_in, mps); - break; - } - default: { - abort(); - break; + } else { + // Start index is based on previously filled buffer + uint32_t prev_buffer_idx = (pipe->multi_buffer_control.wr_idx - 1) & (NUM_BUFFERS - 1); + dma_buffer_block_t *prev_filled_buffer = pipe->buffers[prev_buffer_idx]; + start_idx = prev_filled_buffer->flags.isoc.next_start_idx; } + _buffer_fill_isoc(buffer_to_fill, transfer, is_in, mps, (int)pipe->ep_char.periodic.interval, start_idx); + break; + } + case USB_PRIV_XFER_TYPE_BULK: { + _buffer_fill_bulk(buffer_to_fill, transfer, is_in, mps); + break; + } + case USB_PRIV_XFER_TYPE_INTR: { + _buffer_fill_intr(buffer_to_fill, transfer, is_in, mps); + break; + } + default: { + abort(); + break; + } } buffer_to_fill->urb = urb; urb->hcd_var = URB_HCD_STATE_INFLIGHT; - //Update multi buffer flags + // Update multi buffer flags pipe->multi_buffer_control.wr_idx++; pipe->multi_buffer_control.buffer_num_to_fill--; pipe->multi_buffer_control.buffer_num_to_exec++; @@ -2302,37 +2302,37 @@ static void _buffer_exec(pipe_t *pipe) uint32_t start_idx; int desc_list_len; switch (pipe->ep_char.type) { - case USB_PRIV_XFER_TYPE_CTRL: { - start_idx = 0; - desc_list_len = XFER_LIST_LEN_CTRL; - //Set the channel's direction to OUT and PID to 0 respectively for the the setup stage - usb_dwc_hal_chan_set_dir(pipe->chan_obj, false); //Setup stage is always OUT - usb_dwc_hal_chan_set_pid(pipe->chan_obj, 0); //Setup stage always has a PID of DATA0 - break; - } - case USB_PRIV_XFER_TYPE_ISOCHRONOUS: { - start_idx = buffer_to_exec->flags.isoc.start_idx; - desc_list_len = XFER_LIST_LEN_ISOC; - break; - } - case USB_PRIV_XFER_TYPE_BULK: { - start_idx = 0; - desc_list_len = (buffer_to_exec->flags.bulk.zero_len_packet) ? XFER_LIST_LEN_BULK : 1; - break; - } - case USB_PRIV_XFER_TYPE_INTR: { - start_idx = 0; - desc_list_len = (buffer_to_exec->flags.intr.zero_len_packet) ? buffer_to_exec->flags.intr.num_qtds + 1 : buffer_to_exec->flags.intr.num_qtds; - break; - } - default: { - start_idx = 0; - desc_list_len = 0; - abort(); - break; - } + case USB_PRIV_XFER_TYPE_CTRL: { + start_idx = 0; + desc_list_len = XFER_LIST_LEN_CTRL; + // Set the channel's direction to OUT and PID to 0 respectively for the the setup stage + usb_dwc_hal_chan_set_dir(pipe->chan_obj, false); // Setup stage is always OUT + usb_dwc_hal_chan_set_pid(pipe->chan_obj, 0); // Setup stage always has a PID of DATA0 + break; } - //Update buffer and multi buffer flags + case USB_PRIV_XFER_TYPE_ISOCHRONOUS: { + start_idx = buffer_to_exec->flags.isoc.start_idx; + desc_list_len = XFER_LIST_LEN_ISOC; + break; + } + case USB_PRIV_XFER_TYPE_BULK: { + start_idx = 0; + desc_list_len = (buffer_to_exec->flags.bulk.zero_len_packet) ? XFER_LIST_LEN_BULK : 1; + break; + } + case USB_PRIV_XFER_TYPE_INTR: { + start_idx = 0; + desc_list_len = (buffer_to_exec->flags.intr.zero_len_packet) ? buffer_to_exec->flags.intr.num_qtds + 1 : buffer_to_exec->flags.intr.num_qtds; + break; + } + default: { + start_idx = 0; + desc_list_len = 0; + abort(); + break; + } + } + // Update buffer and multi buffer flags buffer_to_exec->status_flags.executing = 1; pipe->multi_buffer_control.buffer_is_executing = 1; usb_dwc_hal_chan_activate(pipe->chan_obj, buffer_to_exec->xfer_desc_list, desc_list_len, start_idx); @@ -2340,30 +2340,30 @@ static void _buffer_exec(pipe_t *pipe) static void _buffer_exec_cont(pipe_t *pipe) { - //This should only ever be called on control transfers + // This should only ever be called on control transfers assert(pipe->ep_char.type == USB_PRIV_XFER_TYPE_CTRL); dma_buffer_block_t *buffer_inflight = pipe->buffers[pipe->multi_buffer_control.rd_idx]; bool next_dir_is_in; int next_pid; assert(buffer_inflight->flags.ctrl.cur_stg != 2); - if (buffer_inflight->flags.ctrl.cur_stg == 0) { //Just finished control stage + if (buffer_inflight->flags.ctrl.cur_stg == 0) { // Just finished control stage if (buffer_inflight->flags.ctrl.data_stg_skip) { - //Skipping data stage. Go straight to status stage - next_dir_is_in = true; //With no data stage, status stage must be IN - next_pid = 1; //Status stage always has a PID of DATA1 - buffer_inflight->flags.ctrl.cur_stg = 2; //Skip over the null descriptor representing the skipped data stage + // Skipping data stage. Go straight to status stage + next_dir_is_in = true; // With no data stage, status stage must be IN + next_pid = 1; // Status stage always has a PID of DATA1 + buffer_inflight->flags.ctrl.cur_stg = 2; // Skip over the null descriptor representing the skipped data stage } else { - //Go to data stage + // Go to data stage next_dir_is_in = buffer_inflight->flags.ctrl.data_stg_in; - next_pid = 1; //Data stage always starts with a PID of DATA1 + next_pid = 1; // Data stage always starts with a PID of DATA1 buffer_inflight->flags.ctrl.cur_stg = 1; } - } else { //cur_stg == 1. //Just finished data stage. Go to status stage - next_dir_is_in = !buffer_inflight->flags.ctrl.data_stg_in; //Status stage is always the opposite direction of data stage - next_pid = 1; //Status stage always has a PID of DATA1 + } else { // cur_stg == 1. // Just finished data stage. Go to status stage + next_dir_is_in = !buffer_inflight->flags.ctrl.data_stg_in; // Status stage is always the opposite direction of data stage + next_pid = 1; // Status stage always has a PID of DATA1 buffer_inflight->flags.ctrl.cur_stg = 2; } - //Continue the control transfer + // Continue the control transfer usb_dwc_hal_chan_set_dir(pipe->chan_obj, next_dir_is_in); usb_dwc_hal_chan_set_pid(pipe->chan_obj, next_pid); usb_dwc_hal_chan_activate(pipe->chan_obj, buffer_inflight->xfer_desc_list, XFER_LIST_LEN_CTRL, buffer_inflight->flags.ctrl.cur_stg); @@ -2372,12 +2372,12 @@ static void _buffer_exec_cont(pipe_t *pipe) static inline void _buffer_parse_ctrl(dma_buffer_block_t *buffer) { usb_transfer_t *transfer = &buffer->urb->transfer; - //Update URB's actual number of bytes + // Update URB's actual number of bytes if (buffer->flags.ctrl.data_stg_skip) { - //There was no data stage. Just set the actual length to the size of the setup packet + // There was no data stage. Just set the actual length to the size of the setup packet transfer->actual_num_bytes = sizeof(usb_setup_packet_t); } else { - //Parse the data stage for the remaining length + // Parse the data stage for the remaining length int rem_len; int desc_status; usb_dwc_hal_xfer_desc_parse(buffer->xfer_desc_list, 1, &rem_len, &desc_status); @@ -2385,25 +2385,25 @@ static inline void _buffer_parse_ctrl(dma_buffer_block_t *buffer) assert(rem_len <= (transfer->num_bytes - sizeof(usb_setup_packet_t))); transfer->actual_num_bytes = transfer->num_bytes - rem_len; } - //Update URB status + // Update URB status transfer->status = USB_TRANSFER_STATUS_COMPLETED; - //Clear the descriptor list + // Clear the descriptor list memset(buffer->xfer_desc_list, 0, XFER_LIST_LEN_CTRL * sizeof(usb_dwc_ll_dma_qtd_t)); } static inline void _buffer_parse_bulk(dma_buffer_block_t *buffer) { usb_transfer_t *transfer = &buffer->urb->transfer; - //Update URB's actual number of bytes + // Update URB's actual number of bytes int rem_len; int desc_status; usb_dwc_hal_xfer_desc_parse(buffer->xfer_desc_list, 0, &rem_len, &desc_status); assert(desc_status == USB_DWC_HAL_XFER_DESC_STS_SUCCESS); assert(rem_len <= transfer->num_bytes); transfer->actual_num_bytes = transfer->num_bytes - rem_len; - //Update URB's status + // Update URB's status transfer->status = USB_TRANSFER_STATUS_COMPLETED; - //Clear the descriptor list + // Clear the descriptor list memset(buffer->xfer_desc_list, 0, XFER_LIST_LEN_BULK * sizeof(usb_dwc_ll_dma_qtd_t)); } @@ -2412,37 +2412,37 @@ static inline void _buffer_parse_intr(dma_buffer_block_t *buffer, bool is_in, in usb_transfer_t *transfer = &buffer->urb->transfer; int intr_stop_idx = buffer->status_flags.stop_idx; if (is_in) { - if (intr_stop_idx > 0) { //This is an early stop (short packet) + if (intr_stop_idx > 0) { // This is an early stop (short packet) assert(intr_stop_idx <= buffer->flags.intr.num_qtds); int rem_len; int desc_status; - for (int i = 0; i < intr_stop_idx - 1; i++) { //Check all packets before the short + for (int i = 0; i < intr_stop_idx - 1; i++) { // Check all packets before the short usb_dwc_hal_xfer_desc_parse(buffer->xfer_desc_list, i, &rem_len, &desc_status); assert(rem_len == 0 && desc_status == USB_DWC_HAL_XFER_DESC_STS_SUCCESS); } - //Check the short packet + // Check the short packet usb_dwc_hal_xfer_desc_parse(buffer->xfer_desc_list, intr_stop_idx - 1, &rem_len, &desc_status); assert(rem_len > 0 && desc_status == USB_DWC_HAL_XFER_DESC_STS_SUCCESS); - //Update actual bytes + // Update actual bytes transfer->actual_num_bytes = (mps * intr_stop_idx - 2) + (mps - rem_len); } else { - //Check that all but the last packet transmitted MPS + // Check that all but the last packet transmitted MPS for (int i = 0; i < buffer->flags.intr.num_qtds - 1; i++) { int rem_len; int desc_status; usb_dwc_hal_xfer_desc_parse(buffer->xfer_desc_list, i, &rem_len, &desc_status); assert(rem_len == 0 && desc_status == USB_DWC_HAL_XFER_DESC_STS_SUCCESS); } - //Check the last packet + // Check the last packet int last_packet_rem_len; int last_packet_desc_status; usb_dwc_hal_xfer_desc_parse(buffer->xfer_desc_list, buffer->flags.intr.num_qtds - 1, &last_packet_rem_len, &last_packet_desc_status); assert(last_packet_desc_status == USB_DWC_HAL_XFER_DESC_STS_SUCCESS); - //All packets except last MUST be MPS. So just deduct the remaining length of the last packet to get actual number of bytes + // All packets except last MUST be MPS. So just deduct the remaining length of the last packet to get actual number of bytes transfer->actual_num_bytes = transfer->num_bytes - last_packet_rem_len; } } else { - //OUT INTR transfers can only complete successfully if all packets have been transmitted. Double check + // OUT INTR transfers can only complete successfully if all packets have been transmitted. Double check for (int i = 0 ; i < buffer->flags.intr.num_qtds; i++) { int rem_len; int desc_status; @@ -2451,37 +2451,37 @@ static inline void _buffer_parse_intr(dma_buffer_block_t *buffer, bool is_in, in } transfer->actual_num_bytes = transfer->num_bytes; } - //Update URB's status + // Update URB's status transfer->status = USB_TRANSFER_STATUS_COMPLETED; - //Clear the descriptor list + // Clear the descriptor list memset(buffer->xfer_desc_list, 0, XFER_LIST_LEN_INTR * sizeof(usb_dwc_ll_dma_qtd_t)); } static inline void _buffer_parse_isoc(dma_buffer_block_t *buffer, bool is_in) { usb_transfer_t *transfer = &buffer->urb->transfer; - int desc_idx = buffer->flags.isoc.start_idx; //Descriptor index tracks which descriptor in the QTD list + int desc_idx = buffer->flags.isoc.start_idx; // Descriptor index tracks which descriptor in the QTD list int total_actual_num_bytes = 0; for (int pkt_idx = 0; pkt_idx < transfer->num_isoc_packets; pkt_idx++) { - //Clear the filled descriptor + // Clear the filled descriptor int rem_len; int desc_status; usb_dwc_hal_xfer_desc_parse(buffer->xfer_desc_list, desc_idx, &rem_len, &desc_status); usb_dwc_hal_xfer_desc_clear(buffer->xfer_desc_list, desc_idx); assert(rem_len == 0 || is_in); assert(desc_status == USB_DWC_HAL_XFER_DESC_STS_SUCCESS || desc_status == USB_DWC_HAL_XFER_DESC_STS_NOT_EXECUTED); - assert(rem_len <= transfer->isoc_packet_desc[pkt_idx].num_bytes); //Check for DMA errata - //Update ISO packet actual length and status + assert(rem_len <= transfer->isoc_packet_desc[pkt_idx].num_bytes); // Check for DMA errata + // Update ISO packet actual length and status transfer->isoc_packet_desc[pkt_idx].actual_num_bytes = transfer->isoc_packet_desc[pkt_idx].num_bytes - rem_len; total_actual_num_bytes += transfer->isoc_packet_desc[pkt_idx].actual_num_bytes; transfer->isoc_packet_desc[pkt_idx].status = (desc_status == USB_DWC_HAL_XFER_DESC_STS_NOT_EXECUTED) ? USB_TRANSFER_STATUS_SKIPPED : USB_TRANSFER_STATUS_COMPLETED; - //A descriptor is also allocated for unscheduled frames. We need to skip over them + // A descriptor is also allocated for unscheduled frames. We need to skip over them desc_idx += buffer->flags.isoc.interval; if (desc_idx >= XFER_LIST_LEN_INTR) { desc_idx -= XFER_LIST_LEN_INTR; } } - //Write back the actual_num_bytes and statue of entire transfer + // Write back the actual_num_bytes and statue of entire transfer assert(total_actual_num_bytes <= transfer->num_bytes); transfer->actual_num_bytes = total_actual_num_bytes; transfer->status = USB_TRANSFER_STATUS_COMPLETED; @@ -2489,27 +2489,27 @@ static inline void _buffer_parse_isoc(dma_buffer_block_t *buffer, bool is_in) static inline void _buffer_parse_error(dma_buffer_block_t *buffer) { - //The URB had an error in one of its packet, or a port error), so we the entire URB an error. + // The URB had an error in one of its packet, or a port error), so we the entire URB an error. usb_transfer_t *transfer = &buffer->urb->transfer; transfer->actual_num_bytes = 0; - //Update the overall status of URB. Status will depend on the pipe_event + // Update the overall status of URB. Status will depend on the pipe_event switch (buffer->status_flags.pipe_event) { - case HCD_PIPE_EVENT_NONE: - transfer->status = (buffer->status_flags.was_canceled) ? USB_TRANSFER_STATUS_CANCELED : USB_TRANSFER_STATUS_NO_DEVICE; - break; - case HCD_PIPE_EVENT_ERROR_XFER: - transfer->status = USB_TRANSFER_STATUS_ERROR; - break; - case HCD_PIPE_EVENT_ERROR_OVERFLOW: - transfer->status = USB_TRANSFER_STATUS_OVERFLOW; - break; - case HCD_PIPE_EVENT_ERROR_STALL: - transfer->status = USB_TRANSFER_STATUS_STALL; - break; - default: - //HCD_PIPE_EVENT_URB_DONE and HCD_PIPE_EVENT_ERROR_URB_NOT_AVAIL should not occur here - abort(); - break; + case HCD_PIPE_EVENT_NONE: + transfer->status = (buffer->status_flags.was_canceled) ? USB_TRANSFER_STATUS_CANCELED : USB_TRANSFER_STATUS_NO_DEVICE; + break; + case HCD_PIPE_EVENT_ERROR_XFER: + transfer->status = USB_TRANSFER_STATUS_ERROR; + break; + case HCD_PIPE_EVENT_ERROR_OVERFLOW: + transfer->status = USB_TRANSFER_STATUS_OVERFLOW; + break; + case HCD_PIPE_EVENT_ERROR_STALL: + transfer->status = USB_TRANSFER_STATUS_STALL; + break; + default: + // HCD_PIPE_EVENT_URB_DONE and HCD_PIPE_EVENT_ERROR_URB_NOT_AVAIL should not occur here + abort(); + break; } } @@ -2521,43 +2521,43 @@ static void _buffer_parse(pipe_t *pipe) bool is_in = pipe->ep_char.bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK; int mps = pipe->ep_char.mps; - //Parsing the buffer will update the buffer's corresponding URB + // Parsing the buffer will update the buffer's corresponding URB if (buffer_to_parse->status_flags.pipe_event == HCD_PIPE_EVENT_URB_DONE) { - //URB was successful + // URB was successful switch (pipe->ep_char.type) { - case USB_PRIV_XFER_TYPE_CTRL: { - _buffer_parse_ctrl(buffer_to_parse); - break; - } - case USB_PRIV_XFER_TYPE_ISOCHRONOUS: { - _buffer_parse_isoc(buffer_to_parse, is_in); - break; - } - case USB_PRIV_XFER_TYPE_BULK: { - _buffer_parse_bulk(buffer_to_parse); - break; - } - case USB_PRIV_XFER_TYPE_INTR: { - _buffer_parse_intr(buffer_to_parse, is_in, mps); - break; - } - default: { - abort(); - break; - } + case USB_PRIV_XFER_TYPE_CTRL: { + _buffer_parse_ctrl(buffer_to_parse); + break; + } + case USB_PRIV_XFER_TYPE_ISOCHRONOUS: { + _buffer_parse_isoc(buffer_to_parse, is_in); + break; + } + case USB_PRIV_XFER_TYPE_BULK: { + _buffer_parse_bulk(buffer_to_parse); + break; + } + case USB_PRIV_XFER_TYPE_INTR: { + _buffer_parse_intr(buffer_to_parse, is_in, mps); + break; + } + default: { + abort(); + break; + } } } else { - //URB failed + // URB failed _buffer_parse_error(buffer_to_parse); } urb_t *urb = buffer_to_parse->urb; urb->hcd_var = URB_HCD_STATE_DONE; buffer_to_parse->urb = NULL; - buffer_to_parse->flags.val = 0; //Clear flags - //Move the URB to the done tailq + buffer_to_parse->flags.val = 0; // Clear flags + // Move the URB to the done tailq TAILQ_INSERT_TAIL(&pipe->done_urb_tailq, urb, tailq_entry); pipe->num_urb_done++; - //Update multi buffer flags + // Update multi buffer flags pipe->multi_buffer_control.fr_idx++; pipe->multi_buffer_control.buffer_num_to_parse--; pipe->multi_buffer_control.buffer_num_to_fill++; @@ -2567,14 +2567,14 @@ static bool _buffer_flush_all(pipe_t *pipe, bool canceled) { int cur_num_to_mark_done = pipe->multi_buffer_control.buffer_num_to_exec; for (int i = 0; i < cur_num_to_mark_done; i++) { - //Mark any filled buffers as done + // Mark any filled buffers as done _buffer_done(pipe, 0, HCD_PIPE_EVENT_NONE, canceled); } int cur_num_to_parse = pipe->multi_buffer_control.buffer_num_to_parse; for (int i = 0; i < cur_num_to_parse; i++) { _buffer_parse(pipe); } - //At this point, there should be no more filled buffers. Only URBs in the pending or done tailq + // At this point, there should be no more filled buffers. Only URBs in the pending or done tailq return (cur_num_to_parse > 0); } @@ -2584,24 +2584,24 @@ static bool _buffer_flush_all(pipe_t *pipe, bool canceled) esp_err_t hcd_urb_enqueue(hcd_pipe_handle_t pipe_hdl, urb_t *urb) { - //Check that URB has not already been enqueued + // Check that URB has not already been enqueued HCD_CHECK(urb->hcd_ptr == NULL && urb->hcd_var == URB_HCD_STATE_IDLE, ESP_ERR_INVALID_STATE); pipe_t *pipe = (pipe_t *)pipe_hdl; HCD_ENTER_CRITICAL(); - //Check that pipe and port are in the correct state to receive URBs - HCD_CHECK_FROM_CRIT(pipe->port->state == HCD_PORT_STATE_ENABLED //The pipe's port must be in the correct state - && pipe->state == HCD_PIPE_STATE_ACTIVE //The pipe must be in the correct state - && !pipe->cs_flags.pipe_cmd_processing //Pipe cannot currently be processing a pipe command - && !pipe->cs_flags.reset_lock, //Pipe cannot be persisting through a port reset + // Check that pipe and port are in the correct state to receive URBs + HCD_CHECK_FROM_CRIT(pipe->port->state == HCD_PORT_STATE_ENABLED // The pipe's port must be in the correct state + && pipe->state == HCD_PIPE_STATE_ACTIVE // The pipe must be in the correct state + && !pipe->cs_flags.pipe_cmd_processing // Pipe cannot currently be processing a pipe command + && !pipe->cs_flags.reset_lock, // Pipe cannot be persisting through a port reset ESP_ERR_INVALID_STATE); - //Use the URB's reserved_ptr to store the pipe's + // Use the URB's reserved_ptr to store the pipe's urb->hcd_ptr = (void *)pipe; - //Add the URB to the pipe's pending tailq + // Add the URB to the pipe's pending tailq urb->hcd_var = URB_HCD_STATE_PENDING; TAILQ_INSERT_TAIL(&pipe->pending_urb_tailq, urb, tailq_entry); pipe->num_urb_pending++; - //use the URB's reserved_flags to store the URB's current state + // use the URB's reserved_flags to store the URB's current state if (_buffer_can_fill(pipe)) { _buffer_fill(pipe); } @@ -2609,7 +2609,7 @@ esp_err_t hcd_urb_enqueue(hcd_pipe_handle_t pipe_hdl, urb_t *urb) _buffer_exec(pipe); } if (!pipe->cs_flags.has_urb) { - //This is the first URB to be enqueued into the pipe. Move the pipe to the list of active pipes + // This is the first URB to be enqueued into the pipe. Move the pipe to the list of active pipes TAILQ_REMOVE(&pipe->port->pipes_idle_tailq, pipe, tailq_entry); TAILQ_INSERT_TAIL(&pipe->port->pipes_active_tailq, pipe, tailq_entry); pipe->port->num_pipes_idle--; @@ -2630,14 +2630,14 @@ urb_t *hcd_urb_dequeue(hcd_pipe_handle_t pipe_hdl) urb = TAILQ_FIRST(&pipe->done_urb_tailq); TAILQ_REMOVE(&pipe->done_urb_tailq, urb, tailq_entry); pipe->num_urb_done--; - //Check the URB's reserved fields then reset them - assert(urb->hcd_ptr == (void *)pipe && urb->hcd_var == URB_HCD_STATE_DONE); //The URB's reserved field should have been set to this pipe + // Check the URB's reserved fields then reset them + assert(urb->hcd_ptr == (void *)pipe && urb->hcd_var == URB_HCD_STATE_DONE); // The URB's reserved field should have been set to this pipe urb->hcd_ptr = NULL; urb->hcd_var = URB_HCD_STATE_IDLE; if (pipe->cs_flags.has_urb - && pipe->num_urb_pending == 0 && pipe->num_urb_done == 0 - && pipe->multi_buffer_control.buffer_num_to_exec == 0 && pipe->multi_buffer_control.buffer_num_to_parse == 0) { - //This pipe has no more enqueued URBs. Move the pipe to the list of idle pipes + && pipe->num_urb_pending == 0 && pipe->num_urb_done == 0 + && pipe->multi_buffer_control.buffer_num_to_exec == 0 && pipe->multi_buffer_control.buffer_num_to_parse == 0) { + // This pipe has no more enqueued URBs. Move the pipe to the list of idle pipes TAILQ_REMOVE(&pipe->port->pipes_active_tailq, pipe, tailq_entry); TAILQ_INSERT_TAIL(&pipe->port->pipes_idle_tailq, pipe, tailq_entry); pipe->port->num_pipes_idle++; @@ -2645,7 +2645,7 @@ urb_t *hcd_urb_dequeue(hcd_pipe_handle_t pipe_hdl) pipe->cs_flags.has_urb = 0; } } else { - //No more URBs to dequeue from this pipe + // No more URBs to dequeue from this pipe urb = NULL; } HCD_EXIT_CRITICAL(); @@ -2655,24 +2655,24 @@ urb_t *hcd_urb_dequeue(hcd_pipe_handle_t pipe_hdl) esp_err_t hcd_urb_abort(urb_t *urb) { HCD_ENTER_CRITICAL(); - //Check that the URB was enqueued to begin with + // Check that the URB was enqueued to begin with HCD_CHECK_FROM_CRIT(urb->hcd_ptr != NULL && urb->hcd_var != URB_HCD_STATE_IDLE, ESP_ERR_INVALID_STATE); if (urb->hcd_var == URB_HCD_STATE_PENDING) { - //URB has not been executed so it can be aborted + // URB has not been executed so it can be aborted pipe_t *pipe = (pipe_t *)urb->hcd_ptr; - //Remove it form the pending queue + // Remove it form the pending queue TAILQ_REMOVE(&pipe->pending_urb_tailq, urb, tailq_entry); pipe->num_urb_pending--; - //Add it to the done queue + // Add it to the done queue TAILQ_INSERT_TAIL(&pipe->done_urb_tailq, urb, tailq_entry); pipe->num_urb_done++; - //Update the URB's current state, status, and actual length + // Update the URB's current state, status, and actual length urb->hcd_var = URB_HCD_STATE_DONE; if (urb->transfer.num_isoc_packets == 0) { urb->transfer.actual_num_bytes = 0; urb->transfer.status = USB_TRANSFER_STATUS_CANCELED; } else { - //If this is an ISOC URB, update the ISO packet descriptors instead + // If this is an ISOC URB, update the ISO packet descriptors instead for (int i = 0; i < urb->transfer.num_isoc_packets; i++) { urb->transfer.isoc_packet_desc[i].actual_num_bytes = 0; urb->transfer.isoc_packet_desc[i].status = USB_TRANSFER_STATUS_CANCELED; diff --git a/components/usb/hub.c b/components/usb/hub.c index 5574921283..40e2ae1b04 100644 --- a/components/usb/hub.c +++ b/components/usb/hub.c @@ -23,28 +23,28 @@ Implementation of the HUB driver that only supports the Root Hub with a single p implement the bare minimum to control the root HCD port. */ -#define HUB_ROOT_PORT_NUM 1 //HCD only supports one port +#define HUB_ROOT_PORT_NUM 1 // HCD only supports one port #ifdef CONFIG_USB_HOST_HW_BUFFER_BIAS_IN #define HUB_ROOT_HCD_PORT_FIFO_BIAS HCD_PORT_FIFO_BIAS_RX #elif CONFIG_USB_HOST_HW_BUFFER_BIAS_PERIODIC_OUT #define HUB_ROOT_HCD_PORT_FIFO_BIAS HCD_PORT_FIFO_BIAS_PTX -#else //CONFIG_USB_HOST_HW_BUFFER_BIAS_BALANCED +#else // CONFIG_USB_HOST_HW_BUFFER_BIAS_BALANCED #define HUB_ROOT_HCD_PORT_FIFO_BIAS HCD_PORT_FIFO_BIAS_BALANCED #endif #define SET_ADDR_RECOVERY_INTERVAL_MS CONFIG_USB_HOST_SET_ADDR_RECOVERY_MS #define ENUM_CTRL_TRANSFER_MAX_DATA_LEN CONFIG_USB_HOST_CONTROL_TRANSFER_MAX_SIZE -#define ENUM_DEV_ADDR 1 //Device address used in enumeration -#define ENUM_CONFIG_INDEX 0 //Index used to get the first configuration descriptor of the device -#define ENUM_SHORT_DESC_REQ_LEN 8 //Number of bytes to request when getting a short descriptor (just enough to get bMaxPacketSize0 or wTotalLength) -#define ENUM_WORST_CASE_MPS_LS 8 //The worst case MPS of EP0 for a LS device -#define ENUM_WORST_CASE_MPS_FS 64 //The worst case MPS of EP0 for a FS device -#define ENUM_LOW_SPEED_MPS 8 //Worst case MPS for the default endpoint of a low-speed device -#define ENUM_FULL_SPEED_MPS 64 //Worst case MPS for the default endpoint of a full-speed device -#define ENUM_LANGID 0x409 //Current enumeration only supports English (United States) string descriptors +#define ENUM_DEV_ADDR 1 // Device address used in enumeration +#define ENUM_CONFIG_INDEX 0 // Index used to get the first configuration descriptor of the device +#define ENUM_SHORT_DESC_REQ_LEN 8 // Number of bytes to request when getting a short descriptor (just enough to get bMaxPacketSize0 or wTotalLength) +#define ENUM_WORST_CASE_MPS_LS 8 // The worst case MPS of EP0 for a LS device +#define ENUM_WORST_CASE_MPS_FS 64 // The worst case MPS of EP0 for a FS device +#define ENUM_LOW_SPEED_MPS 8 // Worst case MPS for the default endpoint of a low-speed device +#define ENUM_FULL_SPEED_MPS 64 // Worst case MPS for the default endpoint of a full-speed device +#define ENUM_LANGID 0x409 // Current enumeration only supports English (United States) string descriptors -//Hub driver action flags. LISTED IN THE ORDER THEY SHOULD BE HANDLED IN within hub_process(). Some actions are mutually exclusive +// Hub driver action flags. LISTED IN THE ORDER THEY SHOULD BE HANDLED IN within hub_process(). Some actions are mutually exclusive #define HUB_DRIVER_FLAG_ACTION_ROOT_EVENT 0x01 #define HUB_DRIVER_FLAG_ACTION_PORT_DISABLE 0x02 #define HUB_DRIVER_FLAG_ACTION_PORT_RECOVER 0x04 @@ -75,7 +75,7 @@ typedef enum { typedef enum { ENUM_STAGE_NONE = 0, /**< There is no device awaiting enumeration. Start requires device connection and first reset. */ ENUM_STAGE_START, /**< A device has connected and has already been reset once. Allocate a device object in USBH */ - //Basic device enumeration + // Basic device enumeration ENUM_STAGE_GET_SHORT_DEV_DESC, /**< Getting short dev desc (wLength is ENUM_SHORT_DESC_REQ_LEN) */ ENUM_STAGE_CHECK_SHORT_DEV_DESC, /**< Save bMaxPacketSize0 from the short dev desc. Update the MPS of the enum pipe */ ENUM_STAGE_SECOND_RESET, /**< Reset the device again (Workaround for old USB devices that get confused by the previous short dev desc request). */ @@ -90,7 +90,7 @@ typedef enum { ENUM_STAGE_CHECK_FULL_CONFIG_DESC, /**< Check the full config desc, fill it into the device object in USBH */ ENUM_STAGE_SET_CONFIG, /**< Send SET_CONFIGURATION request */ ENUM_STAGE_CHECK_CONFIG, /**< Check that SET_CONFIGURATION request was successful */ - //Get string descriptors + // Get string descriptors ENUM_STAGE_GET_SHORT_LANGID_TABLE, /**< Get the header of the LANGID table string descriptor */ ENUM_STAGE_CHECK_SHORT_LANGID_TABLE, /**< Save the bLength of the LANGID table string descriptor */ ENUM_STAGE_GET_FULL_LANGID_TABLE, /**< Get the full LANGID table string descriptor */ @@ -107,7 +107,7 @@ typedef enum { ENUM_STAGE_CHECK_SHORT_SER_STR_DESC, /**< Save the bLength of the iSerialNumber string descriptor */ ENUM_STAGE_GET_FULL_SER_STR_DESC, /**< Get the full iSerialNumber string descriptor */ ENUM_STAGE_CHECK_FULL_SER_STR_DESC, /**< Check and fill the full iSerialNumber string descriptor */ - //Cleanup + // Cleanup ENUM_STAGE_CLEANUP, /**< Clean up after successful enumeration. Adds enumerated device to USBH */ ENUM_STAGE_CLEANUP_FAILED, /**< Cleanup failed enumeration. Free device resources */ } enum_stage_t; @@ -150,12 +150,12 @@ const char *const enum_stage_strings[] = { }; typedef struct { - //Constant + // Constant urb_t *urb; /**< URB used for enumeration control transfers. Max data length of ENUM_CTRL_TRANSFER_MAX_DATA_LEN */ - //Initialized at start of a particular enumeration + // Initialized at start of a particular enumeration usb_device_handle_t dev_hdl; /**< Handle of device being enumerated */ hcd_pipe_handle_t pipe; /**< Default pipe handle of the device being enumerated */ - //Updated during enumeration + // Updated during enumeration enum_stage_t stage; /**< Current enumeration stage */ int expect_num_bytes; /**< Expected number of bytes for IN transfers stages. Set to 0 for OUT transfer */ uint8_t bMaxPacketSize0; /**< Max packet size of the device's EP0. Read from bMaxPacketSize0 field of device descriptor */ @@ -168,7 +168,7 @@ typedef struct { } enum_ctrl_t; typedef struct { - //Dynamic members require a critical section + // Dynamic members require a critical section struct { union { struct { @@ -179,12 +179,12 @@ typedef struct { } flags; hub_driver_state_t driver_state; } dynamic; - //Single thread members don't require a critical section so long as they are never accessed from multiple threads + // Single thread members don't require a critical section so long as they are never accessed from multiple threads struct { - usb_device_handle_t root_dev_hdl; //Indicates if an enumerated device is connected to the root port + usb_device_handle_t root_dev_hdl; // Indicates if an enumerated device is connected to the root port enum_ctrl_t enum_ctrl; } single_thread; - //Constant members do no change after installation thus do not require a critical section + // Constant members do no change after installation thus do not require a critical section struct { hcd_port_handle_t root_port_hdl; usb_proc_req_cb_t proc_req_cb; @@ -263,20 +263,20 @@ static void usbh_hub_req_callback(hcd_port_handle_t port_hdl, usbh_hub_req_t hub static bool enum_stage_start(enum_ctrl_t *enum_ctrl) { - //Get the speed of the device, and set the enum MPS to the worst case size for now + // Get the speed of the device, and set the enum MPS to the worst case size for now usb_speed_t speed; if (hcd_port_get_speed(p_hub_driver_obj->constant.root_port_hdl, &speed) != ESP_OK) { return false; } enum_ctrl->bMaxPacketSize0 = (speed == USB_SPEED_LOW) ? ENUM_WORST_CASE_MPS_LS : ENUM_WORST_CASE_MPS_FS; - //Try to add the device to USBH + // Try to add the device to USBH usb_device_handle_t enum_dev_hdl; hcd_pipe_handle_t enum_dflt_pipe_hdl; - //We use NULL as the parent device to indicate the Root Hub port 1. We currently only support a single device + // We use NULL as the parent device to indicate the Root Hub port 1. We currently only support a single device if (usbh_hub_add_dev(p_hub_driver_obj->constant.root_port_hdl, speed, &enum_dev_hdl, &enum_dflt_pipe_hdl) != ESP_OK) { return false; } - //Set our own default pipe callback + // Set our own default pipe callback ESP_ERROR_CHECK(hcd_pipe_update_callback(enum_dflt_pipe_hdl, enum_dflt_pipe_callback, NULL)); enum_ctrl->dev_hdl = enum_dev_hdl; enum_ctrl->pipe = enum_dflt_pipe_hdl; @@ -285,7 +285,7 @@ static bool enum_stage_start(enum_ctrl_t *enum_ctrl) static bool enum_stage_second_reset(enum_ctrl_t *enum_ctrl) { - ESP_ERROR_CHECK(hcd_pipe_set_persist_reset(enum_ctrl->pipe)); //Persist the default pipe through the reset + ESP_ERROR_CHECK(hcd_pipe_set_persist_reset(enum_ctrl->pipe)); // Persist the default pipe through the reset if (hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_RESET) != ESP_OK) { ESP_LOGE(HUB_DRIVER_TAG, "Failed to issue second reset"); return false; @@ -296,30 +296,30 @@ static bool enum_stage_second_reset(enum_ctrl_t *enum_ctrl) static void get_string_desc_index_and_langid(enum_ctrl_t *enum_ctrl, uint8_t *index, uint16_t *langid) { switch (enum_ctrl->stage) { - case ENUM_STAGE_GET_SHORT_LANGID_TABLE: - case ENUM_STAGE_GET_FULL_LANGID_TABLE: - *index = 0; //The LANGID table uses an index of 0 - *langid = 0; //Getting the LANGID table itself should use a LANGID of 0 - break; - case ENUM_STAGE_GET_SHORT_MANU_STR_DESC: - case ENUM_STAGE_GET_FULL_MANU_STR_DESC: - *index = enum_ctrl->iManufacturer; - *langid = ENUM_LANGID; //Use the default LANGID - break; - case ENUM_STAGE_GET_SHORT_PROD_STR_DESC: - case ENUM_STAGE_GET_FULL_PROD_STR_DESC: - *index = enum_ctrl->iProduct; - *langid = ENUM_LANGID; //Use the default LANGID - break; - case ENUM_STAGE_GET_SHORT_SER_STR_DESC: - case ENUM_STAGE_GET_FULL_SER_STR_DESC: - *index = enum_ctrl->iSerialNumber; - *langid = ENUM_LANGID; //Use the default LANGID - break; - default: - //Should not occur - abort(); - break; + case ENUM_STAGE_GET_SHORT_LANGID_TABLE: + case ENUM_STAGE_GET_FULL_LANGID_TABLE: + *index = 0; // The LANGID table uses an index of 0 + *langid = 0; // Getting the LANGID table itself should use a LANGID of 0 + break; + case ENUM_STAGE_GET_SHORT_MANU_STR_DESC: + case ENUM_STAGE_GET_FULL_MANU_STR_DESC: + *index = enum_ctrl->iManufacturer; + *langid = ENUM_LANGID; // Use the default LANGID + break; + case ENUM_STAGE_GET_SHORT_PROD_STR_DESC: + case ENUM_STAGE_GET_FULL_PROD_STR_DESC: + *index = enum_ctrl->iProduct; + *langid = ENUM_LANGID; // Use the default LANGID + break; + case ENUM_STAGE_GET_SHORT_SER_STR_DESC: + case ENUM_STAGE_GET_FULL_SER_STR_DESC: + *index = enum_ctrl->iSerialNumber; + *langid = ENUM_LANGID; // Use the default LANGID + break; + default: + // Should not occur + abort(); + break; } } @@ -327,87 +327,87 @@ static bool enum_stage_transfer(enum_ctrl_t *enum_ctrl) { usb_transfer_t *transfer = &enum_ctrl->urb->transfer; switch (enum_ctrl->stage) { - case ENUM_STAGE_GET_SHORT_DEV_DESC: { - //Initialize a short device descriptor request - USB_SETUP_PACKET_INIT_GET_DEVICE_DESC((usb_setup_packet_t *)transfer->data_buffer); - ((usb_setup_packet_t *)transfer->data_buffer)->wLength = ENUM_SHORT_DESC_REQ_LEN; - transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(ENUM_SHORT_DESC_REQ_LEN, enum_ctrl->bMaxPacketSize0); - //IN data stage should return exactly ENUM_SHORT_DESC_REQ_LEN bytes - enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + ENUM_SHORT_DESC_REQ_LEN; - break; - } - case ENUM_STAGE_SET_ADDR: { - USB_SETUP_PACKET_INIT_SET_ADDR((usb_setup_packet_t *)transfer->data_buffer, ENUM_DEV_ADDR); - transfer->num_bytes = sizeof(usb_setup_packet_t); //No data stage - enum_ctrl->expect_num_bytes = 0; //OUT transfer. No need to check number of bytes returned - break; - } - case ENUM_STAGE_GET_FULL_DEV_DESC: { - USB_SETUP_PACKET_INIT_GET_DEVICE_DESC((usb_setup_packet_t *)transfer->data_buffer); - transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(sizeof(usb_device_desc_t), enum_ctrl->bMaxPacketSize0); - //IN data stage should return exactly sizeof(usb_device_desc_t) bytes - enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + sizeof(usb_device_desc_t); - break; - } - case ENUM_STAGE_GET_SHORT_CONFIG_DESC: { - //Get a short config descriptor at index 0 - USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)transfer->data_buffer, ENUM_CONFIG_INDEX, ENUM_SHORT_DESC_REQ_LEN); - transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(ENUM_SHORT_DESC_REQ_LEN, enum_ctrl->bMaxPacketSize0); - //IN data stage should return exactly ENUM_SHORT_DESC_REQ_LEN bytes - enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + ENUM_SHORT_DESC_REQ_LEN; - break; - } - case ENUM_STAGE_GET_FULL_CONFIG_DESC: { - //Get the full configuration descriptor at index 0, requesting its exact length. - USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)transfer->data_buffer, ENUM_CONFIG_INDEX, enum_ctrl->wTotalLength); - transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(enum_ctrl->wTotalLength, enum_ctrl->bMaxPacketSize0); - //IN data stage should return exactly wTotalLength bytes - enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + enum_ctrl->wTotalLength; - break; - } - case ENUM_STAGE_SET_CONFIG: { - USB_SETUP_PACKET_INIT_SET_CONFIG((usb_setup_packet_t *)transfer->data_buffer, enum_ctrl->bConfigurationValue); - transfer->num_bytes = sizeof(usb_setup_packet_t); //No data stage - enum_ctrl->expect_num_bytes = 0; //OUT transfer. No need to check number of bytes returned - break; - } - case ENUM_STAGE_GET_SHORT_LANGID_TABLE: - case ENUM_STAGE_GET_SHORT_MANU_STR_DESC: - case ENUM_STAGE_GET_SHORT_PROD_STR_DESC: - case ENUM_STAGE_GET_SHORT_SER_STR_DESC: { - uint8_t index; - uint16_t langid; - get_string_desc_index_and_langid(enum_ctrl, &index, &langid); - //Get only the header of the string descriptor - USB_SETUP_PACKET_INIT_GET_STR_DESC((usb_setup_packet_t *)transfer->data_buffer, - index, - langid, - sizeof(usb_str_desc_t)); - transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(sizeof(usb_str_desc_t), enum_ctrl->bMaxPacketSize0); - //IN data stage should return exactly sizeof(usb_str_desc_t) bytes - enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + sizeof(usb_str_desc_t); - break; - } - case ENUM_STAGE_GET_FULL_LANGID_TABLE: - case ENUM_STAGE_GET_FULL_MANU_STR_DESC: - case ENUM_STAGE_GET_FULL_PROD_STR_DESC: - case ENUM_STAGE_GET_FULL_SER_STR_DESC: { - uint8_t index; - uint16_t langid; - get_string_desc_index_and_langid(enum_ctrl, &index, &langid); - //Get the full string descriptor at a particular index, requesting the descriptors exact length - USB_SETUP_PACKET_INIT_GET_STR_DESC((usb_setup_packet_t *)transfer->data_buffer, - index, - langid, - enum_ctrl->str_desc_bLength); - transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(enum_ctrl->str_desc_bLength, enum_ctrl->bMaxPacketSize0); - //IN data stage should return exactly str_desc_bLength bytes - enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + enum_ctrl->str_desc_bLength; - break; - } - default: //Should never occur - abort(); - break; + case ENUM_STAGE_GET_SHORT_DEV_DESC: { + // Initialize a short device descriptor request + USB_SETUP_PACKET_INIT_GET_DEVICE_DESC((usb_setup_packet_t *)transfer->data_buffer); + ((usb_setup_packet_t *)transfer->data_buffer)->wLength = ENUM_SHORT_DESC_REQ_LEN; + transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(ENUM_SHORT_DESC_REQ_LEN, enum_ctrl->bMaxPacketSize0); + // IN data stage should return exactly ENUM_SHORT_DESC_REQ_LEN bytes + enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + ENUM_SHORT_DESC_REQ_LEN; + break; + } + case ENUM_STAGE_SET_ADDR: { + USB_SETUP_PACKET_INIT_SET_ADDR((usb_setup_packet_t *)transfer->data_buffer, ENUM_DEV_ADDR); + transfer->num_bytes = sizeof(usb_setup_packet_t); // No data stage + enum_ctrl->expect_num_bytes = 0; // OUT transfer. No need to check number of bytes returned + break; + } + case ENUM_STAGE_GET_FULL_DEV_DESC: { + USB_SETUP_PACKET_INIT_GET_DEVICE_DESC((usb_setup_packet_t *)transfer->data_buffer); + transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(sizeof(usb_device_desc_t), enum_ctrl->bMaxPacketSize0); + // IN data stage should return exactly sizeof(usb_device_desc_t) bytes + enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + sizeof(usb_device_desc_t); + break; + } + case ENUM_STAGE_GET_SHORT_CONFIG_DESC: { + // Get a short config descriptor at index 0 + USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)transfer->data_buffer, ENUM_CONFIG_INDEX, ENUM_SHORT_DESC_REQ_LEN); + transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(ENUM_SHORT_DESC_REQ_LEN, enum_ctrl->bMaxPacketSize0); + // IN data stage should return exactly ENUM_SHORT_DESC_REQ_LEN bytes + enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + ENUM_SHORT_DESC_REQ_LEN; + break; + } + case ENUM_STAGE_GET_FULL_CONFIG_DESC: { + // Get the full configuration descriptor at index 0, requesting its exact length. + USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)transfer->data_buffer, ENUM_CONFIG_INDEX, enum_ctrl->wTotalLength); + transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(enum_ctrl->wTotalLength, enum_ctrl->bMaxPacketSize0); + // IN data stage should return exactly wTotalLength bytes + enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + enum_ctrl->wTotalLength; + break; + } + case ENUM_STAGE_SET_CONFIG: { + USB_SETUP_PACKET_INIT_SET_CONFIG((usb_setup_packet_t *)transfer->data_buffer, enum_ctrl->bConfigurationValue); + transfer->num_bytes = sizeof(usb_setup_packet_t); // No data stage + enum_ctrl->expect_num_bytes = 0; // OUT transfer. No need to check number of bytes returned + break; + } + case ENUM_STAGE_GET_SHORT_LANGID_TABLE: + case ENUM_STAGE_GET_SHORT_MANU_STR_DESC: + case ENUM_STAGE_GET_SHORT_PROD_STR_DESC: + case ENUM_STAGE_GET_SHORT_SER_STR_DESC: { + uint8_t index; + uint16_t langid; + get_string_desc_index_and_langid(enum_ctrl, &index, &langid); + // Get only the header of the string descriptor + USB_SETUP_PACKET_INIT_GET_STR_DESC((usb_setup_packet_t *)transfer->data_buffer, + index, + langid, + sizeof(usb_str_desc_t)); + transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(sizeof(usb_str_desc_t), enum_ctrl->bMaxPacketSize0); + // IN data stage should return exactly sizeof(usb_str_desc_t) bytes + enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + sizeof(usb_str_desc_t); + break; + } + case ENUM_STAGE_GET_FULL_LANGID_TABLE: + case ENUM_STAGE_GET_FULL_MANU_STR_DESC: + case ENUM_STAGE_GET_FULL_PROD_STR_DESC: + case ENUM_STAGE_GET_FULL_SER_STR_DESC: { + uint8_t index; + uint16_t langid; + get_string_desc_index_and_langid(enum_ctrl, &index, &langid); + // Get the full string descriptor at a particular index, requesting the descriptors exact length + USB_SETUP_PACKET_INIT_GET_STR_DESC((usb_setup_packet_t *)transfer->data_buffer, + index, + langid, + enum_ctrl->str_desc_bLength); + transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(enum_ctrl->str_desc_bLength, enum_ctrl->bMaxPacketSize0); + // IN data stage should return exactly str_desc_bLength bytes + enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + enum_ctrl->str_desc_bLength; + break; + } + default: // Should never occur + abort(); + break; } if (hcd_urb_enqueue(enum_ctrl->pipe, enum_ctrl->urb) != ESP_OK) { ESP_LOGE(HUB_DRIVER_TAG, "Failed to submit: %s", enum_stage_strings[enum_ctrl->stage]); @@ -419,230 +419,230 @@ static bool enum_stage_transfer(enum_ctrl_t *enum_ctrl) static bool enum_stage_wait(enum_ctrl_t *enum_ctrl) { switch (enum_ctrl->stage) { - case ENUM_STAGE_SET_ADDR_RECOVERY: { - vTaskDelay(pdMS_TO_TICKS(SET_ADDR_RECOVERY_INTERVAL_MS)); // Need a short delay before device is ready. Todo: IDF-7007 - return true; - } + case ENUM_STAGE_SET_ADDR_RECOVERY: { + vTaskDelay(pdMS_TO_TICKS(SET_ADDR_RECOVERY_INTERVAL_MS)); // Need a short delay before device is ready. Todo: IDF-7007 + return true; + } - default: //Should never occur - abort(); - break; - } + default: // Should never occur + abort(); + break; + } return false; } static bool enum_stage_transfer_check(enum_ctrl_t *enum_ctrl) { - //Dequeue the URB + // Dequeue the URB urb_t *dequeued_enum_urb = hcd_urb_dequeue(enum_ctrl->pipe); assert(dequeued_enum_urb == enum_ctrl->urb); - //Check transfer status + // Check transfer status usb_transfer_t *transfer = &dequeued_enum_urb->transfer; if (transfer->status != USB_TRANSFER_STATUS_COMPLETED) { ESP_LOGE(HUB_DRIVER_TAG, "Bad transfer status %d: %s", transfer->status, enum_stage_strings[enum_ctrl->stage]); if (transfer->status == USB_TRANSFER_STATUS_STALL) { - //EP stalled, clearing the pipe to execute further stages + // EP stalled, clearing the pipe to execute further stages ESP_ERROR_CHECK(hcd_pipe_command(enum_ctrl->pipe, HCD_PIPE_CMD_CLEAR)); } return false; } - //Check IN transfer returned the expected correct number of bytes + // Check IN transfer returned the expected correct number of bytes if (enum_ctrl->expect_num_bytes != 0 && enum_ctrl->expect_num_bytes != transfer->actual_num_bytes) { ESP_LOGE(HUB_DRIVER_TAG, "Incorrect number of bytes returned %d: %s", transfer->actual_num_bytes, enum_stage_strings[enum_ctrl->stage]); return false; } - //Stage specific checks and updates + // Stage specific checks and updates bool ret; switch (enum_ctrl->stage) { - case ENUM_STAGE_CHECK_SHORT_DEV_DESC: { - const usb_device_desc_t *device_desc = (usb_device_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t)); - //Check if the returned descriptor is corrupted - if (device_desc->bDescriptorType != USB_B_DESCRIPTOR_TYPE_DEVICE) { - ESP_LOGE(HUB_DRIVER_TAG, "Short dev desc corrupt"); - ret = false; - break; - } - //Update and save the MPS of the default pipe - if (hcd_pipe_update_mps(enum_ctrl->pipe, device_desc->bMaxPacketSize0) != ESP_OK) { - ESP_LOGE(HUB_DRIVER_TAG, "Failed to update MPS"); - ret = false; - break; - } - //Save the actual MPS of EP0 - enum_ctrl->bMaxPacketSize0 = device_desc->bMaxPacketSize0; - ret = true; - break; - } - case ENUM_STAGE_CHECK_ADDR: { - //Update the pipe and device's address, and fill the address into the device object - ESP_ERROR_CHECK(hcd_pipe_update_dev_addr(enum_ctrl->pipe, ENUM_DEV_ADDR)); - ESP_ERROR_CHECK(usbh_hub_enum_fill_dev_addr(enum_ctrl->dev_hdl, ENUM_DEV_ADDR)); - ret = true; - break; - } - case ENUM_STAGE_CHECK_FULL_DEV_DESC: { - //Fill device descriptor into the device object - const usb_device_desc_t *device_desc = (const usb_device_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t)); - ESP_ERROR_CHECK(usbh_hub_enum_fill_dev_desc(enum_ctrl->dev_hdl, device_desc)); - enum_ctrl->iManufacturer = device_desc->iManufacturer; - enum_ctrl->iProduct = device_desc->iProduct; - enum_ctrl->iSerialNumber = device_desc->iSerialNumber; - ret = true; - break; - } - case ENUM_STAGE_CHECK_SHORT_CONFIG_DESC: { - const usb_config_desc_t *config_desc = (usb_config_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t)); - //Check if the returned descriptor is corrupted - if (config_desc->bDescriptorType != USB_B_DESCRIPTOR_TYPE_CONFIGURATION) { - ESP_LOGE(HUB_DRIVER_TAG, "Short config desc corrupt"); - ret = false; - break; - } -#if (ENUM_CTRL_TRANSFER_MAX_DATA_LEN < UINT16_MAX) //Suppress -Wtype-limits warning due to uint16_t wTotalLength - //Check if the descriptor is too long to be supported - if (config_desc->wTotalLength > ENUM_CTRL_TRANSFER_MAX_DATA_LEN) { - ESP_LOGE(HUB_DRIVER_TAG, "Configuration descriptor larger than control transfer max length"); - ret = false; - break; - } -#endif - //Save the configuration descriptors full length - enum_ctrl->wTotalLength = config_desc->wTotalLength; - ret = true; - break; - } - case ENUM_STAGE_CHECK_FULL_CONFIG_DESC: { - //Fill configuration descriptor into the device object - const usb_config_desc_t *config_desc = (usb_config_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t)); - enum_ctrl->bConfigurationValue = config_desc->bConfigurationValue; - ESP_ERROR_CHECK(usbh_hub_enum_fill_config_desc(enum_ctrl->dev_hdl, config_desc)); - ret = true; - break; - } - case ENUM_STAGE_CHECK_CONFIG: { - ret = true; - //Nothing to do - break; - } - case ENUM_STAGE_CHECK_SHORT_LANGID_TABLE: - case ENUM_STAGE_CHECK_SHORT_MANU_STR_DESC: - case ENUM_STAGE_CHECK_SHORT_PROD_STR_DESC: - case ENUM_STAGE_CHECK_SHORT_SER_STR_DESC: { - const usb_str_desc_t *str_desc = (usb_str_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t)); - //Check if the returned descriptor is supported or corrupted - if (str_desc->bDescriptorType == 0) { - ESP_LOGW(HUB_DRIVER_TAG, "String desc not supported"); - ret = false; - break; - } else if (str_desc->bDescriptorType != USB_B_DESCRIPTOR_TYPE_STRING) { - ESP_LOGE(HUB_DRIVER_TAG, "Full string desc corrupt"); - ret = false; - break; - } -#if (ENUM_CTRL_TRANSFER_MAX_DATA_LEN < UINT8_MAX) //Suppress -Wtype-limits warning due to uint8_t bLength - //Check if the descriptor is too long to be supported - if (str_desc->bLength > (uint32_t)ENUM_CTRL_TRANSFER_MAX_DATA_LEN) { - ESP_LOGE(HUB_DRIVER_TAG, "String descriptor larger than control transfer max length"); - ret = false; - break; - } -#endif - //Save the descriptors full length - enum_ctrl->str_desc_bLength = str_desc->bLength; - ret = true; - break; - } - case ENUM_STAGE_CHECK_FULL_LANGID_TABLE: - case ENUM_STAGE_CHECK_FULL_MANU_STR_DESC: - case ENUM_STAGE_CHECK_FULL_PROD_STR_DESC: - case ENUM_STAGE_CHECK_FULL_SER_STR_DESC: { - const usb_str_desc_t *str_desc = (usb_str_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t)); - //Check if the returned descriptor is supported or corrupted - if (str_desc->bDescriptorType == 0) { - ESP_LOGW(HUB_DRIVER_TAG, "String desc not supported"); - ret = false; - break; - } else if (str_desc->bDescriptorType != USB_B_DESCRIPTOR_TYPE_STRING) { - ESP_LOGE(HUB_DRIVER_TAG, "Full string desc corrupt"); - ret = false; - break; - } - if (enum_ctrl->stage == ENUM_STAGE_CHECK_FULL_LANGID_TABLE) { - //Scan the LANGID table for our target LANGID - bool target_langid_found = false; - int langid_table_num_entries = (str_desc->bLength - sizeof(usb_str_desc_t))/2; //Each LANGID is 2 bytes - for (int i = 0; i < langid_table_num_entries; i++) { //Each LANGID is 2 bytes - if (str_desc->wData[i] == ENUM_LANGID) { - target_langid_found = true; - break; - } - } - if (!target_langid_found) { - ESP_LOGE(HUB_DRIVER_TAG, "LANGID 0x%x not found", ENUM_LANGID); - } - ret = target_langid_found; - break; - } else { - //Fill the string descriptor into the device object - int select; - if (enum_ctrl->stage == ENUM_STAGE_CHECK_FULL_MANU_STR_DESC) { - select = 0; - } else if (enum_ctrl->stage == ENUM_STAGE_CHECK_FULL_PROD_STR_DESC) { - select = 1; - } else { //ENUM_STAGE_CHECK_FULL_PROD_STR_DESC - select = 2; - } - ESP_ERROR_CHECK(usbh_hub_enum_fill_str_desc(enum_ctrl->dev_hdl, str_desc, select)); - ret = true; - break; - } - } - default: //Should never occur + case ENUM_STAGE_CHECK_SHORT_DEV_DESC: { + const usb_device_desc_t *device_desc = (usb_device_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t)); + // Check if the returned descriptor is corrupted + if (device_desc->bDescriptorType != USB_B_DESCRIPTOR_TYPE_DEVICE) { + ESP_LOGE(HUB_DRIVER_TAG, "Short dev desc corrupt"); ret = false; - abort(); break; + } + // Update and save the MPS of the default pipe + if (hcd_pipe_update_mps(enum_ctrl->pipe, device_desc->bMaxPacketSize0) != ESP_OK) { + ESP_LOGE(HUB_DRIVER_TAG, "Failed to update MPS"); + ret = false; + break; + } + // Save the actual MPS of EP0 + enum_ctrl->bMaxPacketSize0 = device_desc->bMaxPacketSize0; + ret = true; + break; + } + case ENUM_STAGE_CHECK_ADDR: { + // Update the pipe and device's address, and fill the address into the device object + ESP_ERROR_CHECK(hcd_pipe_update_dev_addr(enum_ctrl->pipe, ENUM_DEV_ADDR)); + ESP_ERROR_CHECK(usbh_hub_enum_fill_dev_addr(enum_ctrl->dev_hdl, ENUM_DEV_ADDR)); + ret = true; + break; + } + case ENUM_STAGE_CHECK_FULL_DEV_DESC: { + // Fill device descriptor into the device object + const usb_device_desc_t *device_desc = (const usb_device_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t)); + ESP_ERROR_CHECK(usbh_hub_enum_fill_dev_desc(enum_ctrl->dev_hdl, device_desc)); + enum_ctrl->iManufacturer = device_desc->iManufacturer; + enum_ctrl->iProduct = device_desc->iProduct; + enum_ctrl->iSerialNumber = device_desc->iSerialNumber; + ret = true; + break; + } + case ENUM_STAGE_CHECK_SHORT_CONFIG_DESC: { + const usb_config_desc_t *config_desc = (usb_config_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t)); + // Check if the returned descriptor is corrupted + if (config_desc->bDescriptorType != USB_B_DESCRIPTOR_TYPE_CONFIGURATION) { + ESP_LOGE(HUB_DRIVER_TAG, "Short config desc corrupt"); + ret = false; + break; + } +#if (ENUM_CTRL_TRANSFER_MAX_DATA_LEN < UINT16_MAX) // Suppress -Wtype-limits warning due to uint16_t wTotalLength + // Check if the descriptor is too long to be supported + if (config_desc->wTotalLength > ENUM_CTRL_TRANSFER_MAX_DATA_LEN) { + ESP_LOGE(HUB_DRIVER_TAG, "Configuration descriptor larger than control transfer max length"); + ret = false; + break; + } +#endif + // Save the configuration descriptors full length + enum_ctrl->wTotalLength = config_desc->wTotalLength; + ret = true; + break; + } + case ENUM_STAGE_CHECK_FULL_CONFIG_DESC: { + // Fill configuration descriptor into the device object + const usb_config_desc_t *config_desc = (usb_config_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t)); + enum_ctrl->bConfigurationValue = config_desc->bConfigurationValue; + ESP_ERROR_CHECK(usbh_hub_enum_fill_config_desc(enum_ctrl->dev_hdl, config_desc)); + ret = true; + break; + } + case ENUM_STAGE_CHECK_CONFIG: { + ret = true; + // Nothing to do + break; + } + case ENUM_STAGE_CHECK_SHORT_LANGID_TABLE: + case ENUM_STAGE_CHECK_SHORT_MANU_STR_DESC: + case ENUM_STAGE_CHECK_SHORT_PROD_STR_DESC: + case ENUM_STAGE_CHECK_SHORT_SER_STR_DESC: { + const usb_str_desc_t *str_desc = (usb_str_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t)); + // Check if the returned descriptor is supported or corrupted + if (str_desc->bDescriptorType == 0) { + ESP_LOGW(HUB_DRIVER_TAG, "String desc not supported"); + ret = false; + break; + } else if (str_desc->bDescriptorType != USB_B_DESCRIPTOR_TYPE_STRING) { + ESP_LOGE(HUB_DRIVER_TAG, "Full string desc corrupt"); + ret = false; + break; + } +#if (ENUM_CTRL_TRANSFER_MAX_DATA_LEN < UINT8_MAX) // Suppress -Wtype-limits warning due to uint8_t bLength + // Check if the descriptor is too long to be supported + if (str_desc->bLength > (uint32_t)ENUM_CTRL_TRANSFER_MAX_DATA_LEN) { + ESP_LOGE(HUB_DRIVER_TAG, "String descriptor larger than control transfer max length"); + ret = false; + break; + } +#endif + // Save the descriptors full length + enum_ctrl->str_desc_bLength = str_desc->bLength; + ret = true; + break; + } + case ENUM_STAGE_CHECK_FULL_LANGID_TABLE: + case ENUM_STAGE_CHECK_FULL_MANU_STR_DESC: + case ENUM_STAGE_CHECK_FULL_PROD_STR_DESC: + case ENUM_STAGE_CHECK_FULL_SER_STR_DESC: { + const usb_str_desc_t *str_desc = (usb_str_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t)); + // Check if the returned descriptor is supported or corrupted + if (str_desc->bDescriptorType == 0) { + ESP_LOGW(HUB_DRIVER_TAG, "String desc not supported"); + ret = false; + break; + } else if (str_desc->bDescriptorType != USB_B_DESCRIPTOR_TYPE_STRING) { + ESP_LOGE(HUB_DRIVER_TAG, "Full string desc corrupt"); + ret = false; + break; + } + if (enum_ctrl->stage == ENUM_STAGE_CHECK_FULL_LANGID_TABLE) { + // Scan the LANGID table for our target LANGID + bool target_langid_found = false; + int langid_table_num_entries = (str_desc->bLength - sizeof(usb_str_desc_t)) / 2; // Each LANGID is 2 bytes + for (int i = 0; i < langid_table_num_entries; i++) { // Each LANGID is 2 bytes + if (str_desc->wData[i] == ENUM_LANGID) { + target_langid_found = true; + break; + } + } + if (!target_langid_found) { + ESP_LOGE(HUB_DRIVER_TAG, "LANGID 0x%x not found", ENUM_LANGID); + } + ret = target_langid_found; + break; + } else { + // Fill the string descriptor into the device object + int select; + if (enum_ctrl->stage == ENUM_STAGE_CHECK_FULL_MANU_STR_DESC) { + select = 0; + } else if (enum_ctrl->stage == ENUM_STAGE_CHECK_FULL_PROD_STR_DESC) { + select = 1; + } else { // ENUM_STAGE_CHECK_FULL_PROD_STR_DESC + select = 2; + } + ESP_ERROR_CHECK(usbh_hub_enum_fill_str_desc(enum_ctrl->dev_hdl, str_desc, select)); + ret = true; + break; + } + } + default: // Should never occur + ret = false; + abort(); + break; } return ret; } static void enum_stage_cleanup(enum_ctrl_t *enum_ctrl) { - //We currently only support a single device connected to the root port. Move the device handle from enum to root + // We currently only support a single device connected to the root port. Move the device handle from enum to root HUB_DRIVER_ENTER_CRITICAL(); p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_ACTIVE; HUB_DRIVER_EXIT_CRITICAL(); p_hub_driver_obj->single_thread.root_dev_hdl = enum_ctrl->dev_hdl; usb_device_handle_t dev_hdl = enum_ctrl->dev_hdl; - //Clear values in enum_ctrl + // Clear values in enum_ctrl enum_ctrl->dev_hdl = NULL; enum_ctrl->pipe = NULL; - //Update device object after enumeration is done + // Update device object after enumeration is done ESP_ERROR_CHECK(usbh_hub_enum_done(dev_hdl)); } static void enum_stage_cleanup_failed(enum_ctrl_t *enum_ctrl) { - //Enumeration failed. Clear the enum device handle and pipe + // Enumeration failed. Clear the enum device handle and pipe if (enum_ctrl->dev_hdl) { - //If enumeration failed due to a port event, we need to Halt, flush, and dequeue enum default pipe in case there - //was an in-flight URB. + // If enumeration failed due to a port event, we need to Halt, flush, and dequeue enum default pipe in case there + // was an in-flight URB. ESP_ERROR_CHECK(hcd_pipe_command(enum_ctrl->pipe, HCD_PIPE_CMD_HALT)); ESP_ERROR_CHECK(hcd_pipe_command(enum_ctrl->pipe, HCD_PIPE_CMD_FLUSH)); - hcd_urb_dequeue(enum_ctrl->pipe); //This could return NULL if there - ESP_ERROR_CHECK(usbh_hub_enum_failed(enum_ctrl->dev_hdl)); //Free the underlying device object first before recovering the port + hcd_urb_dequeue(enum_ctrl->pipe); // This could return NULL if there + ESP_ERROR_CHECK(usbh_hub_enum_failed(enum_ctrl->dev_hdl)); // Free the underlying device object first before recovering the port } - //Clear values in enum_ctrl + // Clear values in enum_ctrl enum_ctrl->dev_hdl = NULL; enum_ctrl->pipe = NULL; HUB_DRIVER_ENTER_CRITICAL(); - //Enum could have failed due to a port error. If so, we need to trigger a port recovery + // Enum could have failed due to a port error. If so, we need to trigger a port recovery if (p_hub_driver_obj->dynamic.driver_state == HUB_DRIVER_STATE_ROOT_RECOVERY) { p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_RECOVER; } else { - //Otherwise, we move to the enum failed state and wait for the device to disconnect + // Otherwise, we move to the enum failed state and wait for the device to disconnect p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_ENUM_FAILED; } HUB_DRIVER_EXIT_CRITICAL(); @@ -651,93 +651,93 @@ static void enum_stage_cleanup_failed(enum_ctrl_t *enum_ctrl) static enum_stage_t get_next_stage(enum_stage_t old_stage, enum_ctrl_t *enum_ctrl) { enum_stage_t new_stage = old_stage + 1; - //Skip the GET_DESCRIPTOR string type corresponding stages if a particular index is 0. - while(((new_stage == ENUM_STAGE_GET_SHORT_MANU_STR_DESC || - new_stage == ENUM_STAGE_CHECK_SHORT_MANU_STR_DESC || - new_stage == ENUM_STAGE_GET_FULL_MANU_STR_DESC || - new_stage == ENUM_STAGE_CHECK_FULL_MANU_STR_DESC) && enum_ctrl->iManufacturer == 0) || - ((new_stage == ENUM_STAGE_GET_SHORT_PROD_STR_DESC || - new_stage == ENUM_STAGE_CHECK_SHORT_PROD_STR_DESC || - new_stage == ENUM_STAGE_GET_FULL_PROD_STR_DESC || - new_stage == ENUM_STAGE_CHECK_FULL_PROD_STR_DESC) && enum_ctrl->iProduct == 0) || - ((new_stage == ENUM_STAGE_GET_SHORT_SER_STR_DESC || - new_stage == ENUM_STAGE_CHECK_SHORT_SER_STR_DESC || - new_stage == ENUM_STAGE_GET_FULL_SER_STR_DESC || - new_stage == ENUM_STAGE_CHECK_FULL_SER_STR_DESC) && enum_ctrl->iSerialNumber == 0)) { - new_stage++; - } + // Skip the GET_DESCRIPTOR string type corresponding stages if a particular index is 0. + while (((new_stage == ENUM_STAGE_GET_SHORT_MANU_STR_DESC || + new_stage == ENUM_STAGE_CHECK_SHORT_MANU_STR_DESC || + new_stage == ENUM_STAGE_GET_FULL_MANU_STR_DESC || + new_stage == ENUM_STAGE_CHECK_FULL_MANU_STR_DESC) && enum_ctrl->iManufacturer == 0) || + ((new_stage == ENUM_STAGE_GET_SHORT_PROD_STR_DESC || + new_stage == ENUM_STAGE_CHECK_SHORT_PROD_STR_DESC || + new_stage == ENUM_STAGE_GET_FULL_PROD_STR_DESC || + new_stage == ENUM_STAGE_CHECK_FULL_PROD_STR_DESC) && enum_ctrl->iProduct == 0) || + ((new_stage == ENUM_STAGE_GET_SHORT_SER_STR_DESC || + new_stage == ENUM_STAGE_CHECK_SHORT_SER_STR_DESC || + new_stage == ENUM_STAGE_GET_FULL_SER_STR_DESC || + new_stage == ENUM_STAGE_CHECK_FULL_SER_STR_DESC) && enum_ctrl->iSerialNumber == 0)) { + new_stage++; + } return new_stage; } static void enum_set_next_stage(enum_ctrl_t *enum_ctrl, bool last_stage_pass) { - //Set next stage + // Set next stage if (last_stage_pass) { if (enum_ctrl->stage != ENUM_STAGE_NONE && - enum_ctrl->stage != ENUM_STAGE_CLEANUP && - enum_ctrl->stage != ENUM_STAGE_CLEANUP_FAILED) { - enum_ctrl->stage = get_next_stage(enum_ctrl->stage, enum_ctrl); + enum_ctrl->stage != ENUM_STAGE_CLEANUP && + enum_ctrl->stage != ENUM_STAGE_CLEANUP_FAILED) { + enum_ctrl->stage = get_next_stage(enum_ctrl->stage, enum_ctrl); } else { - enum_ctrl->stage = ENUM_STAGE_NONE; + enum_ctrl->stage = ENUM_STAGE_NONE; } } else { switch (enum_ctrl->stage) { - case ENUM_STAGE_START: - //Stage failed but clean up not required - enum_ctrl->stage = ENUM_STAGE_NONE; - break; - case ENUM_STAGE_GET_SHORT_LANGID_TABLE: - case ENUM_STAGE_CHECK_SHORT_LANGID_TABLE: - case ENUM_STAGE_GET_FULL_LANGID_TABLE: - case ENUM_STAGE_CHECK_FULL_LANGID_TABLE: - case ENUM_STAGE_GET_SHORT_MANU_STR_DESC: - case ENUM_STAGE_CHECK_SHORT_MANU_STR_DESC: - case ENUM_STAGE_GET_FULL_MANU_STR_DESC: - case ENUM_STAGE_CHECK_FULL_MANU_STR_DESC: - case ENUM_STAGE_GET_SHORT_PROD_STR_DESC: - case ENUM_STAGE_CHECK_SHORT_PROD_STR_DESC: - case ENUM_STAGE_GET_FULL_PROD_STR_DESC: - case ENUM_STAGE_CHECK_FULL_PROD_STR_DESC: - case ENUM_STAGE_GET_SHORT_SER_STR_DESC: - case ENUM_STAGE_CHECK_SHORT_SER_STR_DESC: - case ENUM_STAGE_GET_FULL_SER_STR_DESC: - case ENUM_STAGE_CHECK_FULL_SER_STR_DESC: - //String descriptor stages are allow to fail. We just don't fetch them and treat enumeration as successful - enum_ctrl->stage = ENUM_STAGE_CLEANUP; - break; - default: - //Enumeration failed. Go to failure clean up - enum_ctrl->stage = ENUM_STAGE_CLEANUP_FAILED; - break; + case ENUM_STAGE_START: + // Stage failed but clean up not required + enum_ctrl->stage = ENUM_STAGE_NONE; + break; + case ENUM_STAGE_GET_SHORT_LANGID_TABLE: + case ENUM_STAGE_CHECK_SHORT_LANGID_TABLE: + case ENUM_STAGE_GET_FULL_LANGID_TABLE: + case ENUM_STAGE_CHECK_FULL_LANGID_TABLE: + case ENUM_STAGE_GET_SHORT_MANU_STR_DESC: + case ENUM_STAGE_CHECK_SHORT_MANU_STR_DESC: + case ENUM_STAGE_GET_FULL_MANU_STR_DESC: + case ENUM_STAGE_CHECK_FULL_MANU_STR_DESC: + case ENUM_STAGE_GET_SHORT_PROD_STR_DESC: + case ENUM_STAGE_CHECK_SHORT_PROD_STR_DESC: + case ENUM_STAGE_GET_FULL_PROD_STR_DESC: + case ENUM_STAGE_CHECK_FULL_PROD_STR_DESC: + case ENUM_STAGE_GET_SHORT_SER_STR_DESC: + case ENUM_STAGE_CHECK_SHORT_SER_STR_DESC: + case ENUM_STAGE_GET_FULL_SER_STR_DESC: + case ENUM_STAGE_CHECK_FULL_SER_STR_DESC: + // String descriptor stages are allow to fail. We just don't fetch them and treat enumeration as successful + enum_ctrl->stage = ENUM_STAGE_CLEANUP; + break; + default: + // Enumeration failed. Go to failure clean up + enum_ctrl->stage = ENUM_STAGE_CLEANUP_FAILED; + break; } } - //These stages are not waiting for a callback, so we need to re-trigger the enum event + // These stages are not waiting for a callback, so we need to re-trigger the enum event bool re_trigger; switch (enum_ctrl->stage) { - case ENUM_STAGE_GET_SHORT_DEV_DESC: - case ENUM_STAGE_SECOND_RESET: - case ENUM_STAGE_SET_ADDR: - case ENUM_STAGE_SET_ADDR_RECOVERY: - case ENUM_STAGE_GET_FULL_DEV_DESC: - case ENUM_STAGE_GET_SHORT_CONFIG_DESC: - case ENUM_STAGE_GET_FULL_CONFIG_DESC: - case ENUM_STAGE_SET_CONFIG: - case ENUM_STAGE_GET_SHORT_LANGID_TABLE: - case ENUM_STAGE_GET_FULL_LANGID_TABLE: - case ENUM_STAGE_GET_SHORT_MANU_STR_DESC: - case ENUM_STAGE_GET_FULL_MANU_STR_DESC: - case ENUM_STAGE_GET_SHORT_PROD_STR_DESC: - case ENUM_STAGE_GET_FULL_PROD_STR_DESC: - case ENUM_STAGE_GET_SHORT_SER_STR_DESC: - case ENUM_STAGE_GET_FULL_SER_STR_DESC: - case ENUM_STAGE_CLEANUP: - case ENUM_STAGE_CLEANUP_FAILED: - re_trigger = true; - break; - default: - re_trigger = false; - break; + case ENUM_STAGE_GET_SHORT_DEV_DESC: + case ENUM_STAGE_SECOND_RESET: + case ENUM_STAGE_SET_ADDR: + case ENUM_STAGE_SET_ADDR_RECOVERY: + case ENUM_STAGE_GET_FULL_DEV_DESC: + case ENUM_STAGE_GET_SHORT_CONFIG_DESC: + case ENUM_STAGE_GET_FULL_CONFIG_DESC: + case ENUM_STAGE_SET_CONFIG: + case ENUM_STAGE_GET_SHORT_LANGID_TABLE: + case ENUM_STAGE_GET_FULL_LANGID_TABLE: + case ENUM_STAGE_GET_SHORT_MANU_STR_DESC: + case ENUM_STAGE_GET_FULL_MANU_STR_DESC: + case ENUM_STAGE_GET_SHORT_PROD_STR_DESC: + case ENUM_STAGE_GET_FULL_PROD_STR_DESC: + case ENUM_STAGE_GET_SHORT_SER_STR_DESC: + case ENUM_STAGE_GET_FULL_SER_STR_DESC: + case ENUM_STAGE_CLEANUP: + case ENUM_STAGE_CLEANUP_FAILED: + re_trigger = true; + break; + default: + re_trigger = false; + break; } if (re_trigger) { HUB_DRIVER_ENTER_CRITICAL(); @@ -755,13 +755,13 @@ static bool root_port_callback(hcd_port_handle_t port_hdl, hcd_port_event_t port HUB_DRIVER_ENTER_CRITICAL_SAFE(); p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ROOT_EVENT; HUB_DRIVER_EXIT_CRITICAL_SAFE(); - assert(in_isr); //Currently, this callback should only ever be called from an ISR context + assert(in_isr); // Currently, this callback should only ever be called from an ISR context return p_hub_driver_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_HUB, in_isr, p_hub_driver_obj->constant.proc_req_cb_arg);; } static bool enum_dflt_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_event, void *user_arg, bool in_isr) { - //Note: This callback may have triggered when a failed enumeration is already cleaned up (e.g., due to a failed port reset) + // Note: This callback may have triggered when a failed enumeration is already cleaned up (e.g., due to a failed port reset) HUB_DRIVER_ENTER_CRITICAL_SAFE(); p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT; HUB_DRIVER_EXIT_CRITICAL_SAFE(); @@ -770,21 +770,21 @@ static bool enum_dflt_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t static void usbh_hub_req_callback(hcd_port_handle_t port_hdl, usbh_hub_req_t hub_req, void *arg) { - //We currently only support the root port, so the port_hdl should match the root port + // We currently only support the root port, so the port_hdl should match the root port assert(port_hdl == p_hub_driver_obj->constant.root_port_hdl); HUB_DRIVER_ENTER_CRITICAL(); switch (hub_req) { - case USBH_HUB_REQ_PORT_DISABLE: - p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_DISABLE; - break; - case USBH_HUB_REQ_PORT_RECOVER: - p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_RECOVER; - break; - default: - //Should never occur - abort(); - break; + case USBH_HUB_REQ_PORT_DISABLE: + p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_DISABLE; + break; + case USBH_HUB_REQ_PORT_RECOVER: + p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_RECOVER; + break; + default: + // Should never occur + abort(); + break; } HUB_DRIVER_EXIT_CRITICAL(); @@ -797,58 +797,58 @@ static void root_port_handle_events(hcd_port_handle_t root_port_hdl) { hcd_port_event_t port_event = hcd_port_handle_event(root_port_hdl); switch (port_event) { - case HCD_PORT_EVENT_NONE: - //Nothing to do - break; - case HCD_PORT_EVENT_CONNECTION: { - if (hcd_port_command(root_port_hdl, HCD_PORT_CMD_RESET) == ESP_OK) { - ESP_LOGD(HUB_DRIVER_TAG, "Root port reset"); - //Start enumeration - HUB_DRIVER_ENTER_CRITICAL(); - p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT; - p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_ENUM; - HUB_DRIVER_EXIT_CRITICAL(); - p_hub_driver_obj->single_thread.enum_ctrl.stage = ENUM_STAGE_START; - } else { - ESP_LOGE(HUB_DRIVER_TAG, "Root port reset failed"); - } - break; - } - case HCD_PORT_EVENT_DISCONNECTION: - case HCD_PORT_EVENT_ERROR: - case HCD_PORT_EVENT_OVERCURRENT: { - bool pass_event_to_usbh = false; + case HCD_PORT_EVENT_NONE: + // Nothing to do + break; + case HCD_PORT_EVENT_CONNECTION: { + if (hcd_port_command(root_port_hdl, HCD_PORT_CMD_RESET) == ESP_OK) { + ESP_LOGD(HUB_DRIVER_TAG, "Root port reset"); + // Start enumeration HUB_DRIVER_ENTER_CRITICAL(); - switch (p_hub_driver_obj->dynamic.driver_state) { - case HUB_DRIVER_STATE_ROOT_POWERED: //This occurred before enumeration - case HUB_DRIVER_STATE_ROOT_ENUM_FAILED: //This occurred after a failed enumeration. - //Therefore, there's no device and we can go straight to port recovery - p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_RECOVER; - break; - case HUB_DRIVER_STATE_ROOT_ENUM: - //This occurred during enumeration. Therefore, we need to recover the failed enumeration - p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT; - p_hub_driver_obj->single_thread.enum_ctrl.stage = ENUM_STAGE_CLEANUP_FAILED; - break; - case HUB_DRIVER_STATE_ROOT_ACTIVE: - //There was an enumerated device. We need to indicate to USBH that the device is gone - pass_event_to_usbh = true; - break; - default: - abort(); //Should never occur - break; - } - p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_RECOVERY; + p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT; + p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_ENUM; HUB_DRIVER_EXIT_CRITICAL(); - if (pass_event_to_usbh) { - assert(p_hub_driver_obj->single_thread.root_dev_hdl); - ESP_ERROR_CHECK(usbh_hub_pass_event(p_hub_driver_obj->single_thread.root_dev_hdl, USBH_HUB_EVENT_PORT_ERROR)); - } + p_hub_driver_obj->single_thread.enum_ctrl.stage = ENUM_STAGE_START; + } else { + ESP_LOGE(HUB_DRIVER_TAG, "Root port reset failed"); + } + break; + } + case HCD_PORT_EVENT_DISCONNECTION: + case HCD_PORT_EVENT_ERROR: + case HCD_PORT_EVENT_OVERCURRENT: { + bool pass_event_to_usbh = false; + HUB_DRIVER_ENTER_CRITICAL(); + switch (p_hub_driver_obj->dynamic.driver_state) { + case HUB_DRIVER_STATE_ROOT_POWERED: // This occurred before enumeration + case HUB_DRIVER_STATE_ROOT_ENUM_FAILED: // This occurred after a failed enumeration. + // Therefore, there's no device and we can go straight to port recovery + p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_RECOVER; + break; + case HUB_DRIVER_STATE_ROOT_ENUM: + // This occurred during enumeration. Therefore, we need to recover the failed enumeration + p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT; + p_hub_driver_obj->single_thread.enum_ctrl.stage = ENUM_STAGE_CLEANUP_FAILED; + break; + case HUB_DRIVER_STATE_ROOT_ACTIVE: + // There was an enumerated device. We need to indicate to USBH that the device is gone + pass_event_to_usbh = true; + break; + default: + abort(); // Should never occur break; } - default: - abort(); //Should never occur - break; + p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_RECOVERY; + HUB_DRIVER_EXIT_CRITICAL(); + if (pass_event_to_usbh) { + assert(p_hub_driver_obj->single_thread.root_dev_hdl); + ESP_ERROR_CHECK(usbh_hub_pass_event(p_hub_driver_obj->single_thread.root_dev_hdl, USBH_HUB_EVENT_PORT_ERROR)); + } + break; + } + default: + abort(); // Should never occur + break; } } @@ -857,62 +857,62 @@ static void enum_handle_events(void) bool stage_pass; enum_ctrl_t *enum_ctrl = &p_hub_driver_obj->single_thread.enum_ctrl; switch (enum_ctrl->stage) { - case ENUM_STAGE_START: - stage_pass = enum_stage_start(enum_ctrl); - break; - case ENUM_STAGE_SECOND_RESET: - stage_pass = enum_stage_second_reset(enum_ctrl); - break; - //Transfer submission stages - case ENUM_STAGE_GET_SHORT_DEV_DESC: - case ENUM_STAGE_SET_ADDR: - case ENUM_STAGE_GET_FULL_DEV_DESC: - case ENUM_STAGE_GET_SHORT_CONFIG_DESC: - case ENUM_STAGE_GET_FULL_CONFIG_DESC: - case ENUM_STAGE_SET_CONFIG: - case ENUM_STAGE_GET_SHORT_LANGID_TABLE: - case ENUM_STAGE_GET_FULL_LANGID_TABLE: - case ENUM_STAGE_GET_SHORT_MANU_STR_DESC: - case ENUM_STAGE_GET_FULL_MANU_STR_DESC: - case ENUM_STAGE_GET_SHORT_PROD_STR_DESC: - case ENUM_STAGE_GET_FULL_PROD_STR_DESC: - case ENUM_STAGE_GET_SHORT_SER_STR_DESC: - case ENUM_STAGE_GET_FULL_SER_STR_DESC: - stage_pass = enum_stage_transfer(enum_ctrl); - break; - //Recovery interval - case ENUM_STAGE_SET_ADDR_RECOVERY: - stage_pass = enum_stage_wait(enum_ctrl); - break; - //Transfer check stages - case ENUM_STAGE_CHECK_SHORT_DEV_DESC: - case ENUM_STAGE_CHECK_ADDR: - case ENUM_STAGE_CHECK_FULL_DEV_DESC: - case ENUM_STAGE_CHECK_SHORT_CONFIG_DESC: - case ENUM_STAGE_CHECK_FULL_CONFIG_DESC: - case ENUM_STAGE_CHECK_CONFIG: - case ENUM_STAGE_CHECK_SHORT_LANGID_TABLE: - case ENUM_STAGE_CHECK_FULL_LANGID_TABLE: - case ENUM_STAGE_CHECK_SHORT_MANU_STR_DESC: - case ENUM_STAGE_CHECK_FULL_MANU_STR_DESC: - case ENUM_STAGE_CHECK_SHORT_PROD_STR_DESC: - case ENUM_STAGE_CHECK_FULL_PROD_STR_DESC: - case ENUM_STAGE_CHECK_SHORT_SER_STR_DESC: - case ENUM_STAGE_CHECK_FULL_SER_STR_DESC: - stage_pass = enum_stage_transfer_check(enum_ctrl); - break; - case ENUM_STAGE_CLEANUP: - enum_stage_cleanup(enum_ctrl); - stage_pass = true; - break; - case ENUM_STAGE_CLEANUP_FAILED: - enum_stage_cleanup_failed(enum_ctrl); - stage_pass = true; - break; - default: - //Note: Don't abort here. The enum_dflt_pipe_callback() can trigger a HUB_DRIVER_FLAG_ACTION_ENUM_EVENT after a cleanup. - stage_pass = true; - break; + case ENUM_STAGE_START: + stage_pass = enum_stage_start(enum_ctrl); + break; + case ENUM_STAGE_SECOND_RESET: + stage_pass = enum_stage_second_reset(enum_ctrl); + break; + // Transfer submission stages + case ENUM_STAGE_GET_SHORT_DEV_DESC: + case ENUM_STAGE_SET_ADDR: + case ENUM_STAGE_GET_FULL_DEV_DESC: + case ENUM_STAGE_GET_SHORT_CONFIG_DESC: + case ENUM_STAGE_GET_FULL_CONFIG_DESC: + case ENUM_STAGE_SET_CONFIG: + case ENUM_STAGE_GET_SHORT_LANGID_TABLE: + case ENUM_STAGE_GET_FULL_LANGID_TABLE: + case ENUM_STAGE_GET_SHORT_MANU_STR_DESC: + case ENUM_STAGE_GET_FULL_MANU_STR_DESC: + case ENUM_STAGE_GET_SHORT_PROD_STR_DESC: + case ENUM_STAGE_GET_FULL_PROD_STR_DESC: + case ENUM_STAGE_GET_SHORT_SER_STR_DESC: + case ENUM_STAGE_GET_FULL_SER_STR_DESC: + stage_pass = enum_stage_transfer(enum_ctrl); + break; + // Recovery interval + case ENUM_STAGE_SET_ADDR_RECOVERY: + stage_pass = enum_stage_wait(enum_ctrl); + break; + // Transfer check stages + case ENUM_STAGE_CHECK_SHORT_DEV_DESC: + case ENUM_STAGE_CHECK_ADDR: + case ENUM_STAGE_CHECK_FULL_DEV_DESC: + case ENUM_STAGE_CHECK_SHORT_CONFIG_DESC: + case ENUM_STAGE_CHECK_FULL_CONFIG_DESC: + case ENUM_STAGE_CHECK_CONFIG: + case ENUM_STAGE_CHECK_SHORT_LANGID_TABLE: + case ENUM_STAGE_CHECK_FULL_LANGID_TABLE: + case ENUM_STAGE_CHECK_SHORT_MANU_STR_DESC: + case ENUM_STAGE_CHECK_FULL_MANU_STR_DESC: + case ENUM_STAGE_CHECK_SHORT_PROD_STR_DESC: + case ENUM_STAGE_CHECK_FULL_PROD_STR_DESC: + case ENUM_STAGE_CHECK_SHORT_SER_STR_DESC: + case ENUM_STAGE_CHECK_FULL_SER_STR_DESC: + stage_pass = enum_stage_transfer_check(enum_ctrl); + break; + case ENUM_STAGE_CLEANUP: + enum_stage_cleanup(enum_ctrl); + stage_pass = true; + break; + case ENUM_STAGE_CLEANUP_FAILED: + enum_stage_cleanup_failed(enum_ctrl); + stage_pass = true; + break; + default: + // Note: Don't abort here. The enum_dflt_pipe_callback() can trigger a HUB_DRIVER_FLAG_ACTION_ENUM_EVENT after a cleanup. + stage_pass = true; + break; } if (stage_pass) { ESP_LOGD(HUB_DRIVER_TAG, "Stage done: %s", enum_stage_strings[enum_ctrl->stage]); @@ -929,14 +929,14 @@ esp_err_t hub_install(hub_config_t *hub_config) HUB_DRIVER_ENTER_CRITICAL(); HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj == NULL, ESP_ERR_INVALID_STATE); HUB_DRIVER_EXIT_CRITICAL(); - //Allocate Hub driver object + // Allocate Hub driver object hub_driver_t *hub_driver_obj = heap_caps_calloc(1, sizeof(hub_driver_t), MALLOC_CAP_DEFAULT); urb_t *enum_urb = urb_alloc(sizeof(usb_setup_packet_t) + ENUM_CTRL_TRANSFER_MAX_DATA_LEN, 0, 0); if (hub_driver_obj == NULL || enum_urb == NULL) { return ESP_ERR_NO_MEM; } esp_err_t ret; - //Install HCD port + // Install HCD port hcd_port_config_t port_config = { .fifo_bias = HUB_ROOT_HCD_PORT_FIFO_BIAS, .callback = root_port_callback, @@ -948,7 +948,7 @@ esp_err_t hub_install(hub_config_t *hub_config) if (ret != ESP_OK) { goto err; } - //Initialize Hub driver object + // Initialize Hub driver object hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_INSTALLED; hub_driver_obj->single_thread.enum_ctrl.stage = ENUM_STAGE_NONE; hub_driver_obj->single_thread.enum_ctrl.urb = enum_urb; @@ -963,7 +963,7 @@ esp_err_t hub_install(hub_config_t *hub_config) } p_hub_driver_obj = hub_driver_obj; HUB_DRIVER_EXIT_CRITICAL(); - //Indicate to USBH that the hub is installed + // Indicate to USBH that the hub is installed ESP_ERROR_CHECK(usbh_hub_is_installed(usbh_hub_req_callback, NULL)); ret = ESP_OK; return ret; @@ -986,7 +986,7 @@ esp_err_t hub_uninstall(void) HUB_DRIVER_EXIT_CRITICAL(); ESP_ERROR_CHECK(hcd_port_deinit(hub_driver_obj->constant.root_port_hdl)); - //Free Hub driver resources + // Free Hub driver resources urb_free(hub_driver_obj->single_thread.enum_ctrl.urb); heap_caps_free(hub_driver_obj); return ESP_OK; @@ -998,7 +998,7 @@ esp_err_t hub_root_start(void) HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj != NULL, ESP_ERR_INVALID_STATE); HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj->dynamic.driver_state == HUB_DRIVER_STATE_INSTALLED, ESP_ERR_INVALID_STATE); HUB_DRIVER_EXIT_CRITICAL(); - //Power ON the root port + // Power ON the root port esp_err_t ret; ret = hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_POWER_ON); if (ret == ESP_OK) { @@ -1045,7 +1045,7 @@ esp_err_t hub_process(void) ESP_LOGD(HUB_DRIVER_TAG, "Disabling root port"); hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_DISABLE); ESP_ERROR_CHECK(usbh_hub_pass_event(p_hub_driver_obj->single_thread.root_dev_hdl, USBH_HUB_EVENT_PORT_DISABLED)); - //The root port has been disabled, so the root_dev_hdl is no longer valid + // The root port has been disabled, so the root_dev_hdl is no longer valid p_hub_driver_obj->single_thread.root_dev_hdl = NULL; } @@ -1056,7 +1056,7 @@ esp_err_t hub_process(void) HUB_DRIVER_ENTER_CRITICAL(); p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_POWERED; HUB_DRIVER_EXIT_CRITICAL(); - //USBH requesting a port recovery means the device has already been freed. Clear root_dev_hdl + // USBH requesting a port recovery means the device has already been freed. Clear root_dev_hdl p_hub_driver_obj->single_thread.root_dev_hdl = NULL; } diff --git a/components/usb/include/usb/usb_host.h b/components/usb/include/usb/usb_host.h index c9b9ce6f61..89cc88cbc9 100644 --- a/components/usb/include/usb/usb_host.h +++ b/components/usb/include/usb/usb_host.h @@ -14,7 +14,7 @@ Warning: The USB Host Library API is still a beta version and may be subject to #include "freertos/FreeRTOS.h" #include "esp_err.h" #include "esp_intr_alloc.h" -//Include the other USB Host Library headers as well +// Include the other USB Host Library headers as well #include "usb/usb_helpers.h" #include "usb/usb_types_ch9.h" #include "usb/usb_types_stack.h" @@ -34,7 +34,7 @@ extern "C" { * * @note Asynchronous API */ -typedef struct usb_host_client_handle_s * usb_host_client_handle_t; +typedef struct usb_host_client_handle_s *usb_host_client_handle_t; // ----------------------- Events -------------------------- @@ -116,7 +116,7 @@ typedef struct { typedef struct { bool is_synchronous; /**< Whether the client is asynchronous or synchronous or not. Set to false for now. */ int max_num_event_msg; /**< Maximum number of event messages that can be stored (e.g., 3) */ - union { //Note: Made into union or future expansion + union { // Note: Made into union or future expansion struct { usb_host_client_event_cb_t client_event_callback; /**< Client's event callback function */ void *callback_arg; /**< Event callback function argument */ diff --git a/components/usb/include/usb/usb_types_ch9.h b/components/usb/include/usb/usb_types_ch9.h index 69886c7426..36c4391ccb 100644 --- a/components/usb/include/usb/usb_types_ch9.h +++ b/components/usb/include/usb/usb_types_ch9.h @@ -346,10 +346,10 @@ ESP_STATIC_ASSERT(sizeof(usb_config_desc_t) == USB_CONFIG_DESC_SIZE, "Size of us /** * @brief Bit masks belonging to the bmAttributes field of a configuration descriptor */ -#define USB_BM_ATTRIBUTES_ONE (1 << 7) //Must be set -#define USB_BM_ATTRIBUTES_SELFPOWER (1 << 6) //Self powered -#define USB_BM_ATTRIBUTES_WAKEUP (1 << 5) //Can wake-up -#define USB_BM_ATTRIBUTES_BATTERY (1 << 4) //Battery powered +#define USB_BM_ATTRIBUTES_ONE (1 << 7) /**< Must be set */ +#define USB_BM_ATTRIBUTES_SELFPOWER (1 << 6) /**< Self powered */ +#define USB_BM_ATTRIBUTES_WAKEUP (1 << 5) /**< Can wake-up */ +#define USB_BM_ATTRIBUTES_BATTERY (1 << 4) /**< Battery powered */ // ---------- Interface Association Descriptor ------------- diff --git a/components/usb/include/usb/usb_types_stack.h b/components/usb/include/usb/usb_types_stack.h index 4d71753a0a..94ab481ee9 100644 --- a/components/usb/include/usb/usb_types_stack.h +++ b/components/usb/include/usb/usb_types_stack.h @@ -43,7 +43,7 @@ typedef enum { /** * @brief Handle of a USB Device connected to a USB Host */ -typedef struct usb_device_handle_s * usb_device_handle_t; +typedef struct usb_device_handle_s *usb_device_handle_t; /** * @brief Basic information of an enumerated device @@ -126,7 +126,7 @@ typedef void (*usb_transfer_cb_t)(usb_transfer_t *transfer); * @brief USB transfer structure * */ -struct usb_transfer_s{ +struct usb_transfer_s { uint8_t *const data_buffer; /**< Pointer to data buffer */ const size_t data_buffer_size; /**< Size of the data buffer in bytes */ int num_bytes; /**< Number of bytes to transfer. diff --git a/components/usb/private_include/hcd.h b/components/usb/private_include/hcd.h index 77380b8ddc..d2de4aa9f0 100644 --- a/components/usb/private_include/hcd.h +++ b/components/usb/private_include/hcd.h @@ -116,12 +116,12 @@ typedef enum { /** * @brief Port handle type */ -typedef void * hcd_port_handle_t; +typedef void *hcd_port_handle_t; /** * @brief Pipe handle type */ -typedef void * hcd_pipe_handle_t; +typedef void *hcd_pipe_handle_t; /** * @brief Port event callback type diff --git a/components/usb/private_include/usb_private.h b/components/usb/private_include/usb_private.h index 1d177c5159..ccdcd44a23 100644 --- a/components/usb/private_include/usb_private.h +++ b/components/usb/private_include/usb_private.h @@ -36,16 +36,16 @@ typedef struct { } usb_transfer_dummy_t; _Static_assert(sizeof(usb_transfer_dummy_t) == sizeof(usb_transfer_t), "usb_transfer_dummy_t does not match usb_transfer_t"); -struct urb_s{ +struct urb_s { TAILQ_ENTRY(urb_s) tailq_entry; - //HCD Layer: Handler pointer and variables. Must be initialized to NULL and 0 respectively + // HCD Layer: Handler pointer and variables. Must be initialized to NULL and 0 respectively void *hcd_ptr; uint32_t hcd_var; - //Host Lib Layer: - void *usb_host_client; //Currently only used when submitted to shared pipes (i.e., Device default pipes) - size_t usb_host_header_size; //USB Host may need the data buffer to have a transparent header - bool usb_host_inflight; //Debugging variable, used to prevent re-submitting URBs already inflight - //Public transfer structure. Must be last due to variable length array + // Host Lib Layer: + void *usb_host_client; // Currently only used when submitted to shared pipes (i.e., Device default pipes) + size_t usb_host_header_size; // USB Host may need the data buffer to have a transparent header + bool usb_host_inflight; // Debugging variable, used to prevent re-submitting URBs already inflight + // Public transfer structure. Must be last due to variable length array usb_transfer_t transfer; }; typedef struct urb_s urb_t; diff --git a/components/usb/private_include/usbh.h b/components/usb/private_include/usbh.h index 3e01350897..0fafea2974 100644 --- a/components/usb/private_include/usbh.h +++ b/components/usb/private_include/usbh.h @@ -25,7 +25,7 @@ extern "C" { /** * @brief Handle of a allocated endpoint */ -typedef struct usbh_ep_handle_s * usbh_ep_handle_t; +typedef struct usbh_ep_handle_s *usbh_ep_handle_t; // ----------------------- Events -------------------------- diff --git a/components/usb/usb_helpers.c b/components/usb/usb_helpers.c index 3712c1eaab..0c06d57f8a 100644 --- a/components/usb/usb_helpers.c +++ b/components/usb/usb_helpers.c @@ -21,12 +21,12 @@ const usb_standard_desc_t *usb_parse_next_descriptor(const usb_standard_desc_t * { assert(cur_desc != NULL && offset != NULL); if (*offset >= wTotalLength) { - return NULL; //We have traversed the entire configuration descriptor + return NULL; // We have traversed the entire configuration descriptor } if (*offset + cur_desc->bLength >= wTotalLength) { - return NULL; //Next descriptor is out of bounds + return NULL; // Next descriptor is out of bounds } - //Return the next descriptor, update offset + // Return the next descriptor, update offset const usb_standard_desc_t *ret_desc = (const usb_standard_desc_t *)(((uint32_t)cur_desc) + cur_desc->bLength); *offset += cur_desc->bLength; return ret_desc; @@ -35,8 +35,8 @@ const usb_standard_desc_t *usb_parse_next_descriptor(const usb_standard_desc_t * const usb_standard_desc_t *usb_parse_next_descriptor_of_type(const usb_standard_desc_t *cur_desc, uint16_t wTotalLength, uint8_t bDescriptorType, int *offset) { assert(cur_desc != NULL && offset != NULL); - int offset_temp = *offset; //We only want to update offset if we've actually found a descriptor - //Keep stepping over descriptors until we find one of bDescriptorType or until we go out of bounds + int offset_temp = *offset; // We only want to update offset if we've actually found a descriptor + // Keep stepping over descriptors until we find one of bDescriptorType or until we go out of bounds const usb_standard_desc_t *ret_desc = usb_parse_next_descriptor(cur_desc, wTotalLength, &offset_temp); while (ret_desc != NULL) { if (ret_desc->bDescriptorType == bDescriptorType) { @@ -45,7 +45,7 @@ const usb_standard_desc_t *usb_parse_next_descriptor_of_type(const usb_standard_ ret_desc = usb_parse_next_descriptor(ret_desc, wTotalLength, &offset_temp); } if (ret_desc != NULL) { - //We've found a descriptor. Update the offset + // We've found a descriptor. Update the offset *offset = offset_temp; } return ret_desc; @@ -55,10 +55,10 @@ int usb_parse_interface_number_of_alternate(const usb_config_desc_t *config_desc { assert(config_desc != NULL); int offset = 0; - //Find the first interface descriptor of bInterfaceNumber + // Find the first interface descriptor of bInterfaceNumber const usb_intf_desc_t *first_intf_desc = usb_parse_interface_descriptor(config_desc, bInterfaceNumber, 0, &offset); if (first_intf_desc == NULL) { - return -1; //bInterfaceNumber not found + return -1; // bInterfaceNumber not found } int num_alt_setting = 0; @@ -77,31 +77,31 @@ const usb_intf_desc_t *usb_parse_interface_descriptor(const usb_config_desc_t *c { assert(config_desc != NULL); - //Walk to first interface descriptor of bInterfaceNumber + // Walk to first interface descriptor of bInterfaceNumber int offset_temp = 0; const usb_intf_desc_t *next_intf_desc = (const usb_intf_desc_t *)usb_parse_next_descriptor_of_type((const usb_standard_desc_t *)config_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset_temp); while (next_intf_desc != NULL) { if (next_intf_desc->bInterfaceNumber == bInterfaceNumber) { - break; //We found the first interface descriptor with matching bInterfaceNumber + break; // We found the first interface descriptor with matching bInterfaceNumber } next_intf_desc = (const usb_intf_desc_t *)usb_parse_next_descriptor_of_type((const usb_standard_desc_t *)next_intf_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset_temp); } if (next_intf_desc == NULL) { - return NULL; //Couldn't find a interface with bInterfaceNumber + return NULL; // Couldn't find a interface with bInterfaceNumber } - //Keep walking until an interface descriptor matching bInterfaceNumber and bAlternateSetting is found + // Keep walking until an interface descriptor matching bInterfaceNumber and bAlternateSetting is found while (next_intf_desc != NULL) { if (next_intf_desc->bInterfaceNumber == bInterfaceNumber + 1) { - //We've walked past our target bInterfaceNumber + // We've walked past our target bInterfaceNumber next_intf_desc = NULL; break; } if (next_intf_desc->bAlternateSetting == bAlternateSetting) { - //We've found our target interface descriptor + // We've found our target interface descriptor break; } - //Get the next interface descriptor + // Get the next interface descriptor next_intf_desc = (const usb_intf_desc_t *)usb_parse_next_descriptor_of_type((const usb_standard_desc_t *)next_intf_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset_temp); } if (next_intf_desc != NULL && offset != NULL) { @@ -114,9 +114,9 @@ const usb_ep_desc_t *usb_parse_endpoint_descriptor_by_index(const usb_intf_desc_ { assert(intf_desc != NULL && offset != NULL); if (index >= intf_desc->bNumEndpoints) { - return NULL; //Index is out of range + return NULL; // Index is out of range } - //Walk to the Nth endpoint descriptor we find + // Walk to the Nth endpoint descriptor we find int offset_temp = *offset; bool ep_found = true; const usb_standard_desc_t *next_desc = (const usb_standard_desc_t *)intf_desc; @@ -138,14 +138,14 @@ const usb_ep_desc_t *usb_parse_endpoint_descriptor_by_address(const usb_config_d { assert(config_desc != NULL); - //Find the interface descriptor + // Find the interface descriptor int offset_intf; const usb_intf_desc_t *intf_desc = usb_parse_interface_descriptor(config_desc, bInterfaceNumber, bAlternateSetting, &offset_intf); if (intf_desc == NULL) { return NULL; } - //Walk endpoint descriptors until one matching bEndpointAddress is found + // Walk endpoint descriptors until one matching bEndpointAddress is found int offset_ep; bool ep_found = false; const usb_ep_desc_t *ep_desc = NULL; @@ -174,21 +174,21 @@ static void print_ep_desc(const usb_ep_desc_t *ep_desc) int type = ep_desc->bmAttributes & USB_BM_ATTRIBUTES_XFERTYPE_MASK; switch (type) { - case USB_BM_ATTRIBUTES_XFER_CONTROL: - ep_type_str = "CTRL"; - break; - case USB_BM_ATTRIBUTES_XFER_ISOC: - ep_type_str = "ISOC"; - break; - case USB_BM_ATTRIBUTES_XFER_BULK: - ep_type_str = "BULK"; - break; - case USB_BM_ATTRIBUTES_XFER_INT: - ep_type_str = "INT"; - break; - default: - ep_type_str = NULL; - break; + case USB_BM_ATTRIBUTES_XFER_CONTROL: + ep_type_str = "CTRL"; + break; + case USB_BM_ATTRIBUTES_XFER_ISOC: + ep_type_str = "ISOC"; + break; + case USB_BM_ATTRIBUTES_XFER_BULK: + ep_type_str = "BULK"; + break; + case USB_BM_ATTRIBUTES_XFER_INT: + ep_type_str = "INT"; + break; + default: + ep_type_str = NULL; + break; } printf("\t\t*** Endpoint descriptor ***\n"); @@ -277,23 +277,23 @@ void usb_print_config_descriptor(const usb_config_desc_t *cfg_desc, print_class_ do { switch (next_desc->bDescriptorType) { - case USB_B_DESCRIPTOR_TYPE_CONFIGURATION: - usbh_print_cfg_desc((const usb_config_desc_t *)next_desc); - break; - case USB_B_DESCRIPTOR_TYPE_INTERFACE: - usbh_print_intf_desc((const usb_intf_desc_t *)next_desc); - break; - case USB_B_DESCRIPTOR_TYPE_ENDPOINT: - print_ep_desc((const usb_ep_desc_t *)next_desc); - break; - case USB_B_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION: - print_iad_desc((const usb_iad_desc_t*)next_desc); - break; - default: - if(class_specific_cb) { - class_specific_cb(next_desc); - } - break; + case USB_B_DESCRIPTOR_TYPE_CONFIGURATION: + usbh_print_cfg_desc((const usb_config_desc_t *)next_desc); + break; + case USB_B_DESCRIPTOR_TYPE_INTERFACE: + usbh_print_intf_desc((const usb_intf_desc_t *)next_desc); + break; + case USB_B_DESCRIPTOR_TYPE_ENDPOINT: + print_ep_desc((const usb_ep_desc_t *)next_desc); + break; + case USB_B_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION: + print_iad_desc((const usb_iad_desc_t *)next_desc); + break; + default: + if (class_specific_cb) { + class_specific_cb(next_desc); + } + break; } next_desc = usb_parse_next_descriptor(next_desc, wTotalLength, &offset); @@ -307,7 +307,7 @@ void usb_print_string_descriptor(const usb_str_desc_t *str_desc) return; } - for (int i = 0; i < str_desc->bLength/2; i++) { + for (int i = 0; i < str_desc->bLength / 2; i++) { /* USB String descriptors of UTF-16. Right now We just skip any character larger than 0xFF to stay in BMP Basic Latin and Latin-1 Supplement range. diff --git a/components/usb/usb_host.c b/components/usb/usb_host.c index a3ad4d603b..e0182d5660 100644 --- a/components/usb/usb_host.c +++ b/components/usb/usb_host.c @@ -52,19 +52,19 @@ typedef struct interface_s interface_t; typedef struct client_s client_t; struct ep_wrapper_s { - //Dynamic members require a critical section + // Dynamic members require a critical section struct { TAILQ_ENTRY(ep_wrapper_s) tailq_entry; union { struct { uint32_t pending: 1; - uint32_t reserved31:31; + uint32_t reserved31: 31; }; } flags; uint32_t num_urb_inflight; usbh_ep_event_t last_event; } dynamic; - //Constant members do no change after claiming the interface thus do not require a critical section + // Constant members do no change after claiming the interface thus do not require a critical section struct { usbh_ep_handle_t ep_hdl; interface_t *intf_obj; @@ -72,11 +72,11 @@ struct ep_wrapper_s { }; struct interface_s { - //Dynamic members require a critical section + // Dynamic members require a critical section struct { TAILQ_ENTRY(interface_s) tailq_entry; } mux_protected; - //Constant members do no change after claiming the interface thus do not require a critical section + // Constant members do no change after claiming the interface thus do not require a critical section struct { const usb_intf_desc_t *intf_desc; usb_device_handle_t dev_hdl; @@ -86,7 +86,7 @@ struct interface_s { }; struct client_s { - //Dynamic members require a critical section + // Dynamic members require a critical section struct { TAILQ_ENTRY(client_s) tailq_entry; TAILQ_HEAD(tailhead_pending_ep, ep_wrapper_s) pending_ep_tailq; @@ -107,11 +107,11 @@ struct client_s { uint32_t num_done_ctrl_xfer; uint32_t opened_dev_addr_map; } dynamic; - //Mux protected members must be protected by host library the mux_lock when accessed + // Mux protected members must be protected by host library the mux_lock when accessed struct { TAILQ_HEAD(tailhead_interfaces, interface_s) interface_tailq; } mux_protected; - //Constant members do no change after registration thus do not require a critical section + // Constant members do no change after registration thus do not require a critical section struct { SemaphoreHandle_t event_sem; usb_host_client_event_cb_t event_callback; @@ -121,9 +121,9 @@ struct client_s { }; typedef struct { - //Dynamic members require a critical section + // Dynamic members require a critical section struct { - //Access to these should be done in a critical section + // Access to these should be done in a critical section uint32_t process_pending_flags; uint32_t lib_event_flags; union { @@ -138,15 +138,15 @@ typedef struct { uint32_t val; } flags; } dynamic; - //Mux protected members must be protected by host library the mux_lock when accessed + // Mux protected members must be protected by host library the mux_lock when accessed struct { - TAILQ_HEAD(tailhead_clients, client_s) client_tailq; //List of all clients registered + TAILQ_HEAD(tailhead_clients, client_s) client_tailq; // List of all clients registered } mux_protected; - //Constant members do no change after installation thus do not require a critical section + // Constant members do no change after installation thus do not require a critical section 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 + usb_phy_handle_t phy_handle; // Will be NULL if host library is installed with skip_phy_setup } constant; } host_lib_t; @@ -228,13 +228,13 @@ static bool _unblock_lib(bool in_isr) 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 + // Lock client list xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY); - //Send event message to relevant or all clients + // Send event message to relevant or all clients client_t *client_obj; TAILQ_FOREACH(client_obj, &p_host_lib_obj->mux_protected.client_tailq, dynamic.tailq_entry) { if (!send_to_all) { - //Check if client opened the device + // Check if client opened the device HOST_ENTER_CRITICAL(); bool send = _check_client_opened_device(client_obj, opened_dev_addr); HOST_EXIT_CRITICAL(); @@ -242,7 +242,7 @@ static void send_event_msg_to_clients(const usb_host_client_event_msg_t *event_m continue; } } - //Send the event message + // Send the event message if (xQueueSend(client_obj->constant.event_msg_queue, event_msg, 0) == pdTRUE) { HOST_ENTER_CRITICAL(); _unblock_client(client_obj, false); @@ -251,7 +251,7 @@ static void send_event_msg_to_clients(const usb_host_client_event_msg_t *event_m ESP_LOGE(USB_HOST_TAG, "Client event message queue full"); } } - //Unlock client list + // Unlock client list xSemaphoreGive(p_host_lib_obj->constant.mux_lock); } @@ -262,14 +262,14 @@ static void send_event_msg_to_clients(const usb_host_client_event_msg_t *event_m static bool proc_req_callback(usb_proc_req_source_t source, bool in_isr, void *arg) { HOST_ENTER_CRITICAL_SAFE(); - //Store the processing request source + // Store the processing request source switch (source) { - case USB_PROC_REQ_SOURCE_USBH: - p_host_lib_obj->dynamic.process_pending_flags |= PROCESS_REQUEST_PENDING_FLAG_USBH; - break; - 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_USBH: + p_host_lib_obj->dynamic.process_pending_flags |= PROCESS_REQUEST_PENDING_FLAG_USBH; + break; + case USB_PROC_REQ_SOURCE_HUB: + p_host_lib_obj->dynamic.process_pending_flags |= PROCESS_REQUEST_PENDING_FLAG_HUB; + break; } bool yield = _unblock_lib(in_isr); HOST_EXIT_CRITICAL_SAFE(); @@ -280,7 +280,7 @@ static bool proc_req_callback(usb_proc_req_source_t source, bool in_isr, void *a static void ctrl_xfer_callback(usb_device_handle_t dev_hdl, urb_t *urb, void *arg) { assert(urb->usb_host_client != NULL); - //Redistribute done control transfer to the clients that submitted them + // Redistribute done control transfer to the clients that submitted them client_t *client_obj = (client_t *)urb->usb_host_client; HOST_ENTER_CRITICAL(); @@ -292,41 +292,41 @@ static void ctrl_xfer_callback(usb_device_handle_t dev_hdl, urb_t *urb, void *ar static void dev_event_callback(usb_device_handle_t dev_hdl, usbh_event_t usbh_event, void *arg) { - //Check usbh_event. The data type of event_arg depends on the type of event + // Check usbh_event. The data type of event_arg depends on the type of event switch (usbh_event) { - case USBH_EVENT_DEV_NEW: { - //Prepare a NEW_DEV client event message, the send it to all clients - uint8_t dev_addr; - ESP_ERROR_CHECK(usbh_dev_get_addr(dev_hdl, &dev_addr)); - usb_host_client_event_msg_t event_msg = { - .event = USB_HOST_CLIENT_EVENT_NEW_DEV, - .new_dev.address = dev_addr, - }; - send_event_msg_to_clients(&event_msg, true, 0); - break; - } - case USBH_EVENT_DEV_GONE: { - //Prepare event msg, send only to clients that have opened the device - uint8_t dev_addr; - ESP_ERROR_CHECK(usbh_dev_get_addr(dev_hdl, &dev_addr)); - usb_host_client_event_msg_t event_msg = { - .event = USB_HOST_CLIENT_EVENT_DEV_GONE, - .dev_gone.dev_hdl = dev_hdl, - }; - send_event_msg_to_clients(&event_msg, false, dev_addr); - break; - } - case USBH_EVENT_DEV_ALL_FREE: { - //Notify the lib handler that all devices are free - HOST_ENTER_CRITICAL(); - p_host_lib_obj->dynamic.lib_event_flags |= USB_HOST_LIB_EVENT_FLAGS_ALL_FREE; - _unblock_lib(false); - HOST_EXIT_CRITICAL(); - break; - } - default: - abort(); //Should never occur - break; + case USBH_EVENT_DEV_NEW: { + // Prepare a NEW_DEV client event message, the send it to all clients + uint8_t dev_addr; + ESP_ERROR_CHECK(usbh_dev_get_addr(dev_hdl, &dev_addr)); + usb_host_client_event_msg_t event_msg = { + .event = USB_HOST_CLIENT_EVENT_NEW_DEV, + .new_dev.address = dev_addr, + }; + send_event_msg_to_clients(&event_msg, true, 0); + break; + } + case USBH_EVENT_DEV_GONE: { + // Prepare event msg, send only to clients that have opened the device + uint8_t dev_addr; + ESP_ERROR_CHECK(usbh_dev_get_addr(dev_hdl, &dev_addr)); + usb_host_client_event_msg_t event_msg = { + .event = USB_HOST_CLIENT_EVENT_DEV_GONE, + .dev_gone.dev_hdl = dev_hdl, + }; + send_event_msg_to_clients(&event_msg, false, dev_addr); + break; + } + case USBH_EVENT_DEV_ALL_FREE: { + // Notify the lib handler that all devices are free + HOST_ENTER_CRITICAL(); + p_host_lib_obj->dynamic.lib_event_flags |= USB_HOST_LIB_EVENT_FLAGS_ALL_FREE; + _unblock_lib(false); + HOST_EXIT_CRITICAL(); + break; + } + default: + abort(); // Should never occur + break; } } @@ -338,9 +338,9 @@ static bool endpoint_callback(usbh_ep_handle_t ep_hdl, usbh_ep_event_t ep_event, client_t *client_obj = (client_t *)ep_wrap->constant.intf_obj->constant.client_obj; HOST_ENTER_CRITICAL_SAFE(); - //Store the event to be handled later. Note that we allow overwriting of events because more severe will halt the pipe prevent any further events. + // Store the event to be handled later. Note that we allow overwriting of events because more severe will halt the pipe prevent any further events. ep_wrap->dynamic.last_event = ep_event; - //Add the EP to the client's pending list if it's not in the list already + // Add the EP to the client's pending list if it's not in the list already if (!ep_wrap->dynamic.flags.pending) { ep_wrap->dynamic.flags.pending = 1; TAILQ_REMOVE(&client_obj->dynamic.idle_ep_tailq, ep_wrap, dynamic.tailq_entry); @@ -371,7 +371,7 @@ esp_err_t usb_host_install(const usb_host_config_t *config) ret = ESP_ERR_NO_MEM; goto alloc_err; } - //Initialize host library object + // Initialize host library object TAILQ_INIT(&host_lib_obj->mux_protected.client_tailq); host_lib_obj->constant.event_sem = event_sem; host_lib_obj->constant.mux_lock = mux_lock; @@ -384,24 +384,24 @@ esp_err_t usb_host_install(const usb_host_config_t *config) - Hub */ - //Install USB PHY (if necessary). USB PHY driver will also enable the underlying Host Controller + // Install USB PHY (if necessary). USB PHY driver will also enable the underlying Host Controller if (!config->skip_phy_setup) { - //Host Library defaults to internal PHY + // Host Library defaults to internal PHY usb_phy_config_t phy_config = { .controller = USB_PHY_CTRL_OTG, .target = USB_PHY_TARGET_INT, .otg_mode = USB_OTG_MODE_HOST, - .otg_speed = USB_PHY_SPEED_UNDEFINED, //In Host mode, the speed is determined by the connected device + .otg_speed = USB_PHY_SPEED_UNDEFINED, // In Host mode, the speed is determined by the connected device .ext_io_conf = NULL, .otg_io_conf = NULL, }; ret = usb_new_phy(&phy_config, &host_lib_obj->constant.phy_handle); - if (ret != ESP_OK) { - goto phy_err; - } + if (ret != ESP_OK) { + goto phy_err; + } } - //Install HCD + // Install HCD hcd_config_t hcd_config = { .intr_flags = config->intr_flags }; @@ -410,7 +410,7 @@ esp_err_t usb_host_install(const usb_host_config_t *config) goto hcd_err; } - //Install USBH + // Install USBH usbh_config_t usbh_config = { .proc_req_cb = proc_req_callback, .proc_req_cb_arg = NULL, @@ -424,7 +424,7 @@ esp_err_t usb_host_install(const usb_host_config_t *config) goto usbh_err; } - //Install Hub + // Install Hub hub_config_t hub_config = { .proc_req_cb = proc_req_callback, .proc_req_cb_arg = NULL, @@ -434,7 +434,7 @@ esp_err_t usb_host_install(const usb_host_config_t *config) goto hub_err; } - //Assign host library object + // Assign host library object HOST_ENTER_CRITICAL(); if (p_host_lib_obj != NULL) { HOST_EXIT_CRITICAL(); @@ -444,7 +444,7 @@ esp_err_t usb_host_install(const usb_host_config_t *config) p_host_lib_obj = host_lib_obj; HOST_EXIT_CRITICAL(); - //Start the root hub + // Start the root hub ESP_ERROR_CHECK(hub_root_start()); ret = ESP_OK; return ret; @@ -473,7 +473,7 @@ alloc_err: esp_err_t usb_host_uninstall(void) { - //All devices must have been freed at this point + // All devices must have been freed at this point HOST_ENTER_CRITICAL(); HOST_CHECK_FROM_CRIT(p_host_lib_obj != NULL, ESP_ERR_INVALID_STATE); HOST_CHECK_FROM_CRIT(p_host_lib_obj->dynamic.process_pending_flags == 0 && @@ -482,10 +482,10 @@ esp_err_t usb_host_uninstall(void) ESP_ERR_INVALID_STATE); HOST_EXIT_CRITICAL(); - //Stop the root hub + // Stop the root hub ESP_ERROR_CHECK(hub_root_stop()); - //Unassign the host library object + // Unassign the host library object HOST_ENTER_CRITICAL(); host_lib_t *host_lib_obj = p_host_lib_obj; p_host_lib_obj = NULL; @@ -501,12 +501,12 @@ esp_err_t usb_host_uninstall(void) ESP_ERROR_CHECK(hub_uninstall()); ESP_ERROR_CHECK(usbh_uninstall()); ESP_ERROR_CHECK(hcd_uninstall()); - //If the USB PHY was setup, then delete it + // If the USB PHY was setup, then delete it if (host_lib_obj->constant.phy_handle) { ESP_ERROR_CHECK(usb_del_phy(host_lib_obj->constant.phy_handle)); } - //Free memory objects + // Free memory objects vSemaphoreDelete(host_lib_obj->constant.mux_lock); vSemaphoreDelete(host_lib_obj->constant.event_sem); heap_caps_free(host_lib_obj); @@ -520,7 +520,7 @@ esp_err_t usb_host_lib_handle_events(TickType_t timeout_ticks, uint32_t *event_f HOST_ENTER_CRITICAL(); if (!p_host_lib_obj->dynamic.flags.process_pending) { - //There is currently processing that needs to be done. Wait for some processing + // There is currently processing that needs to be done. Wait for some processing HOST_EXIT_CRITICAL(); BaseType_t sem_ret = xSemaphoreTake(p_host_lib_obj->constant.event_sem, timeout_ticks); if (sem_ret == pdFALSE) { @@ -529,7 +529,7 @@ esp_err_t usb_host_lib_handle_events(TickType_t timeout_ticks, uint32_t *event_f } HOST_ENTER_CRITICAL(); } - //Read and clear process pending flags + // Read and clear process pending flags uint32_t process_pending_flags = p_host_lib_obj->dynamic.process_pending_flags; p_host_lib_obj->dynamic.process_pending_flags = 0; p_host_lib_obj->dynamic.flags.handling_events = 1; @@ -542,7 +542,7 @@ esp_err_t usb_host_lib_handle_events(TickType_t timeout_ticks, uint32_t *event_f ESP_ERROR_CHECK(hub_process()); } HOST_ENTER_CRITICAL(); - //Read and clear process pending flags again, and loop back if there is more to process + // Read and clear process pending flags again, and loop back if there is more to process process_pending_flags = p_host_lib_obj->dynamic.process_pending_flags; p_host_lib_obj->dynamic.process_pending_flags = 0; } @@ -562,7 +562,7 @@ exit: esp_err_t usb_host_lib_unblock(void) { - //All devices must have been freed at this point + // All devices must have been freed at this point HOST_ENTER_CRITICAL(); HOST_CHECK_FROM_CRIT(p_host_lib_obj != NULL, ESP_ERR_INVALID_STATE); _unblock_lib(false); @@ -581,7 +581,7 @@ esp_err_t usb_host_lib_info(usb_host_lib_info_t *info_ret) HOST_EXIT_CRITICAL(); usbh_num_devs(&num_devs_temp); - //Write back return values + // Write back return values info_ret->num_devices = num_devs_temp; info_ret->num_clients = num_clients_temp; return ESP_OK; @@ -593,9 +593,9 @@ esp_err_t usb_host_lib_info(usb_host_lib_info_t *info_ret) static void _handle_pending_ep(client_t *client_obj) { - //Handle each EP on the pending list + // Handle each EP on the pending list while (!TAILQ_EMPTY(&client_obj->dynamic.pending_ep_tailq)) { - //Get the next pending EP. + // Get the next pending EP. ep_wrapper_t *ep_wrap = TAILQ_FIRST(&client_obj->dynamic.pending_ep_tailq); TAILQ_REMOVE(&client_obj->dynamic.pending_ep_tailq, ep_wrap, dynamic.tailq_entry); TAILQ_INSERT_TAIL(&client_obj->dynamic.idle_ep_tailq, ep_wrap, dynamic.tailq_entry); @@ -604,36 +604,36 @@ static void _handle_pending_ep(client_t *client_obj) uint32_t num_urb_dequeued = 0; HOST_EXIT_CRITICAL(); - //Handle pipe event + // Handle pipe event switch (last_event) { - case USBH_EP_EVENT_ERROR_XFER: - case USBH_EP_EVENT_ERROR_URB_NOT_AVAIL: - case USBH_EP_EVENT_ERROR_OVERFLOW: - case USBH_EP_EVENT_ERROR_STALL: - //The endpoint is now stalled. Flush all pending URBs - ESP_ERROR_CHECK(usbh_ep_command(ep_wrap->constant.ep_hdl, USBH_EP_CMD_FLUSH)); - //All URBs in this pipe are now retired waiting to be dequeued. Fall through to dequeue them - __attribute__((fallthrough)); - case USBH_EP_EVENT_URB_DONE: { - //Dequeue all URBs and run their transfer callback - urb_t *urb; + case USBH_EP_EVENT_ERROR_XFER: + case USBH_EP_EVENT_ERROR_URB_NOT_AVAIL: + case USBH_EP_EVENT_ERROR_OVERFLOW: + case USBH_EP_EVENT_ERROR_STALL: + // The endpoint is now stalled. Flush all pending URBs + ESP_ERROR_CHECK(usbh_ep_command(ep_wrap->constant.ep_hdl, USBH_EP_CMD_FLUSH)); + // All URBs in this pipe are now retired waiting to be dequeued. Fall through to dequeue them + __attribute__((fallthrough)); + case USBH_EP_EVENT_URB_DONE: { + // Dequeue all URBs and run their transfer callback + urb_t *urb; + usbh_ep_dequeue_urb(ep_wrap->constant.ep_hdl, &urb); + while (urb != NULL) { + // Clear the transfer's in-flight flag to indicate the transfer is no longer in-flight + urb->usb_host_inflight = false; + urb->transfer.callback(&urb->transfer); + num_urb_dequeued++; usbh_ep_dequeue_urb(ep_wrap->constant.ep_hdl, &urb); - while (urb != NULL) { - //Clear the transfer's in-flight flag to indicate the transfer is no longer in-flight - urb->usb_host_inflight = false; - urb->transfer.callback(&urb->transfer); - num_urb_dequeued++; - usbh_ep_dequeue_urb(ep_wrap->constant.ep_hdl, &urb); - } - break; } - default: - abort(); //Should never occur - break; + break; + } + default: + abort(); // Should never occur + break; } HOST_ENTER_CRITICAL(); - //Update the endpoint's number of URB's in-flight + // Update the endpoint's number of URB's in-flight assert(num_urb_dequeued <= ep_wrap->dynamic.num_urb_inflight); ep_wrap->dynamic.num_urb_inflight -= num_urb_dequeued; } @@ -647,12 +647,12 @@ esp_err_t usb_host_client_register(const usb_host_client_config_t *client_config HOST_CHECK(client_config != NULL && client_hdl_ret != NULL, ESP_ERR_INVALID_ARG); HOST_CHECK(client_config->max_num_event_msg > 0, ESP_ERR_INVALID_ARG); if (!client_config->is_synchronous) { - //Asynchronous clients must provide a + // Asynchronous clients must provide a HOST_CHECK(client_config->async.client_event_callback != NULL, ESP_ERR_INVALID_ARG); } esp_err_t ret; - //Create client object + // Create client object client_t *client_obj = heap_caps_calloc(1, sizeof(client_t), MALLOC_CAP_DEFAULT); SemaphoreHandle_t event_sem = xSemaphoreCreateBinary(); QueueHandle_t event_msg_queue = xQueueCreate(client_config->max_num_event_msg, sizeof(usb_host_client_event_msg_t)); @@ -660,7 +660,7 @@ esp_err_t usb_host_client_register(const usb_host_client_config_t *client_config ret = ESP_ERR_NO_MEM; goto alloc_err; } - //Initialize client object + // Initialize client object TAILQ_INIT(&client_obj->dynamic.pending_ep_tailq); TAILQ_INIT(&client_obj->dynamic.idle_ep_tailq); TAILQ_INIT(&client_obj->mux_protected.interface_tailq); @@ -670,7 +670,7 @@ esp_err_t usb_host_client_register(const usb_host_client_config_t *client_config client_obj->constant.callback_arg = client_config->async.callback_arg; client_obj->constant.event_msg_queue = event_msg_queue; - //Add client to the host library's list of clients + // Add client to the host library's list of clients xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY); HOST_ENTER_CRITICAL(); p_host_lib_obj->dynamic.flags.num_clients++; @@ -678,7 +678,7 @@ esp_err_t usb_host_client_register(const usb_host_client_config_t *client_config TAILQ_INSERT_TAIL(&p_host_lib_obj->mux_protected.client_tailq, client_obj, dynamic.tailq_entry); xSemaphoreGive(p_host_lib_obj->constant.mux_lock); - //Write back client handle + // Write back client handle *client_hdl_ret = (usb_host_client_handle_t)client_obj; ret = ESP_OK; return ret; @@ -700,41 +700,41 @@ esp_err_t usb_host_client_deregister(usb_host_client_handle_t client_hdl) client_t *client_obj = (client_t *)client_hdl; esp_err_t ret; - //We take the mux_lock because we need to access the host library's client_tailq + // We take the mux_lock because we need to access the host library's client_tailq xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY); HOST_ENTER_CRITICAL(); - //Check that client can currently deregistered + // Check that client can currently deregistered bool can_deregister; if (!TAILQ_EMPTY(&client_obj->dynamic.pending_ep_tailq) || - !TAILQ_EMPTY(&client_obj->dynamic.idle_ep_tailq) || - !TAILQ_EMPTY(&client_obj->dynamic.done_ctrl_xfer_tailq) || - client_obj->dynamic.flags.handling_events || - client_obj->dynamic.flags.blocked || - client_obj->dynamic.flags.taking_mux || - client_obj->dynamic.flags.num_intf_claimed != 0 || - client_obj->dynamic.num_done_ctrl_xfer != 0 || - client_obj->dynamic.opened_dev_addr_map != 0) { - can_deregister = false; - } else { - can_deregister = true; - } + !TAILQ_EMPTY(&client_obj->dynamic.idle_ep_tailq) || + !TAILQ_EMPTY(&client_obj->dynamic.done_ctrl_xfer_tailq) || + client_obj->dynamic.flags.handling_events || + client_obj->dynamic.flags.blocked || + client_obj->dynamic.flags.taking_mux || + client_obj->dynamic.flags.num_intf_claimed != 0 || + client_obj->dynamic.num_done_ctrl_xfer != 0 || + client_obj->dynamic.opened_dev_addr_map != 0) { + can_deregister = false; + } else { + can_deregister = true; + } HOST_EXIT_CRITICAL(); if (!can_deregister) { ret = ESP_ERR_INVALID_STATE; goto exit; } - //Remove client object from the library's list of clients + // Remove client object from the library's list of clients TAILQ_REMOVE(&p_host_lib_obj->mux_protected.client_tailq, client_obj, dynamic.tailq_entry); HOST_ENTER_CRITICAL(); p_host_lib_obj->dynamic.flags.num_clients--; if (p_host_lib_obj->dynamic.flags.num_clients == 0) { - //This is the last client being deregistered. Notify the lib handler + // This is the last client being deregistered. Notify the lib handler p_host_lib_obj->dynamic.lib_event_flags |= USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS; _unblock_lib(false); } HOST_EXIT_CRITICAL(); - //Free client object + // Free client object vQueueDelete(client_obj->constant.event_msg_queue); vSemaphoreDelete(client_obj->constant.event_sem); heap_caps_free(client_obj); @@ -752,7 +752,7 @@ esp_err_t usb_host_client_handle_events(usb_host_client_handle_t client_hdl, Tic HOST_ENTER_CRITICAL(); if (!client_obj->dynamic.flags.events_pending) { - //There are currently no events, wait for one to occur + // There are currently no events, wait for one to occur client_obj->dynamic.flags.blocked = 1; HOST_EXIT_CRITICAL(); BaseType_t sem_ret = xSemaphoreTake(client_obj->constant.event_sem, timeout_ticks); @@ -760,45 +760,45 @@ esp_err_t usb_host_client_handle_events(usb_host_client_handle_t client_hdl, Tic client_obj->dynamic.flags.blocked = 0; if (sem_ret == pdFALSE) { HOST_EXIT_CRITICAL(); - //Timed out waiting for semaphore + // Timed out waiting for semaphore ret = ESP_ERR_TIMEOUT; goto exit; } } - //Mark that we're processing events + // Mark that we're processing events client_obj->dynamic.flags.handling_events = 1; while (client_obj->dynamic.flags.handling_events) { - //Handle pending endpoints + // Handle pending endpoints if (!TAILQ_EMPTY(&client_obj->dynamic.pending_ep_tailq)) { _handle_pending_ep(client_obj); } - //Handle any done control transfers + // Handle any done control transfers while (client_obj->dynamic.num_done_ctrl_xfer > 0) { urb_t *urb = TAILQ_FIRST(&client_obj->dynamic.done_ctrl_xfer_tailq); TAILQ_REMOVE(&client_obj->dynamic.done_ctrl_xfer_tailq, urb, tailq_entry); client_obj->dynamic.num_done_ctrl_xfer--; HOST_EXIT_CRITICAL(); - //Clear the transfer's in-flight flag to indicate the transfer is no longer in-flight + // Clear the transfer's in-flight flag to indicate the transfer is no longer in-flight urb->usb_host_inflight = false; - //Call the transfer's callback + // Call the transfer's callback urb->transfer.callback(&urb->transfer); HOST_ENTER_CRITICAL(); } - //Handle event messages + // Handle event messages while (uxQueueMessagesWaiting(client_obj->constant.event_msg_queue) > 0) { HOST_EXIT_CRITICAL(); - //Dequeue the event message and call the client event callback + // Dequeue the event message and call the client event callback usb_host_client_event_msg_t event_msg; BaseType_t queue_ret = xQueueReceive(client_obj->constant.event_msg_queue, &event_msg, 0); assert(queue_ret == pdTRUE); client_obj->constant.event_callback(&event_msg, client_obj->constant.callback_arg); HOST_ENTER_CRITICAL(); } - //Check each event again to see any new events occurred + // Check each event again to see any new events occurred if (TAILQ_EMPTY(&client_obj->dynamic.pending_ep_tailq) && - client_obj->dynamic.num_done_ctrl_xfer == 0 && - uxQueueMessagesWaiting(client_obj->constant.event_msg_queue) == 0) { - //All pending endpoints and event messages handled + client_obj->dynamic.num_done_ctrl_xfer == 0 && + uxQueueMessagesWaiting(client_obj->constant.event_msg_queue) == 0) { + // All pending endpoints and event messages handled client_obj->dynamic.flags.events_pending = 0; client_obj->dynamic.flags.handling_events = 0; } @@ -838,12 +838,12 @@ esp_err_t usb_host_device_open(usb_host_client_handle_t client_hdl, uint8_t dev_ HOST_ENTER_CRITICAL(); if (_check_client_opened_device(client_obj, dev_addr)) { - //Client has already opened the device. Close it and return an error + // Client has already opened the device. Close it and return an error ret = ESP_ERR_INVALID_STATE; HOST_EXIT_CRITICAL(); goto already_opened; } - //Record in client object that we have opened the device of this address + // Record in client object that we have opened the device of this address _record_client_opened_device(client_obj, dev_addr); HOST_EXIT_CRITICAL(); @@ -862,10 +862,10 @@ esp_err_t usb_host_device_close(usb_host_client_handle_t client_hdl, usb_device_ HOST_CHECK(dev_hdl != NULL && client_hdl != NULL, ESP_ERR_INVALID_ARG); client_t *client_obj = (client_t *)client_hdl; - //We take the lock because we need to walk the interface list + // We take the lock because we need to walk the interface list xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY); esp_err_t ret; - //Check that all interfaces claimed by this client do not belong to this device + // Check that all interfaces claimed by this client do not belong to this device bool all_released = true; interface_t *intf_obj; TAILQ_FOREACH(intf_obj, &client_obj->mux_protected.interface_tailq, mux_protected.tailq_entry) { @@ -879,18 +879,18 @@ esp_err_t usb_host_device_close(usb_host_client_handle_t client_hdl, usb_device_ goto exit; } - //Check that client actually opened the device in the first place + // Check that client actually opened the device in the first place HOST_ENTER_CRITICAL(); uint8_t dev_addr; ESP_ERROR_CHECK(usbh_dev_get_addr(dev_hdl, &dev_addr)); HOST_CHECK_FROM_CRIT(_check_client_opened_device(client_obj, dev_addr), ESP_ERR_NOT_FOUND); if (!_check_client_opened_device(client_obj, dev_addr)) { - //Client never opened this device + // Client never opened this device ret = ESP_ERR_INVALID_STATE; HOST_EXIT_CRITICAL(); goto exit; } - //Proceed to clear the record of the device form the client + // Proceed to clear the record of the device form the client _clear_client_opened_device(client_obj, dev_addr); HOST_EXIT_CRITICAL(); @@ -904,11 +904,11 @@ exit: esp_err_t usb_host_device_free_all(void) { HOST_ENTER_CRITICAL(); - HOST_CHECK_FROM_CRIT(p_host_lib_obj->dynamic.flags.num_clients == 0, ESP_ERR_INVALID_STATE); //All clients must have been deregistered + HOST_CHECK_FROM_CRIT(p_host_lib_obj->dynamic.flags.num_clients == 0, ESP_ERR_INVALID_STATE); // All clients must have been deregistered HOST_EXIT_CRITICAL(); esp_err_t ret; ret = usbh_dev_mark_all_free(); - //If ESP_ERR_NOT_FINISHED is returned, caller must wait for USB_HOST_LIB_EVENT_FLAGS_ALL_FREE to confirm all devices are free + // If ESP_ERR_NOT_FINISHED is returned, caller must wait for USB_HOST_LIB_EVENT_FLAGS_ALL_FREE to confirm all devices are free return ret; } @@ -968,10 +968,10 @@ static esp_err_t ep_wrapper_alloc(usb_device_handle_t dev_hdl, const usb_ep_desc if (ret != ESP_OK) { goto alloc_err; } - //Initialize endpoint wrapper item + // Initialize endpoint wrapper item ep_wrap->constant.ep_hdl = ep_hdl; ep_wrap->constant.intf_obj = intf_obj; - //Write back result + // Write back result *ep_wrap_ret = ep_wrap; ret = ESP_OK; return ret; @@ -986,9 +986,9 @@ static void ep_wrapper_free(usb_device_handle_t dev_hdl, ep_wrapper_t *ep_wrap) if (ep_wrap == NULL) { return; } - //Free the underlying endpoint + // Free the underlying endpoint ESP_ERROR_CHECK(usbh_ep_free(ep_wrap->constant.ep_hdl)); - //Free the endpoint wrapper item + // Free the endpoint wrapper item heap_caps_free(ep_wrap); } @@ -1018,21 +1018,21 @@ static void interface_free(interface_t *intf_obj) static esp_err_t interface_claim(client_t *client_obj, usb_device_handle_t dev_hdl, const usb_config_desc_t *config_desc, uint8_t bInterfaceNumber, uint8_t bAlternateSetting, interface_t **intf_obj_ret) { esp_err_t ret; - //We need to walk to configuration descriptor to find the correct interface descriptor, and each of its constituent endpoint descriptors - //Find the interface descriptor and allocate the interface object + // We need to walk to configuration descriptor to find the correct interface descriptor, and each of its constituent endpoint descriptors + // Find the interface descriptor and allocate the interface object int offset_intf; const usb_intf_desc_t *intf_desc = usb_parse_interface_descriptor(config_desc, bInterfaceNumber, bAlternateSetting, &offset_intf); if (intf_desc == NULL) { ret = ESP_ERR_NOT_FOUND; goto exit; } - //Allocate interface object + // Allocate interface object interface_t *intf_obj = interface_alloc(client_obj, dev_hdl, intf_desc); if (intf_obj == NULL) { ret = ESP_ERR_NO_MEM; goto exit; } - //Find each endpoint descriptor in the interface by index, and allocate those endpoints + // Find each endpoint descriptor in the interface by index, and allocate those endpoints for (int i = 0; i < intf_desc->bNumEndpoints; i++) { int offset_ep = offset_intf; const usb_ep_desc_t *ep_desc = usb_parse_endpoint_descriptor_by_index(intf_desc, i, config_desc->wTotalLength, &offset_ep); @@ -1040,24 +1040,24 @@ static esp_err_t interface_claim(client_t *client_obj, usb_device_handle_t dev_h ret = ESP_ERR_NOT_FOUND; goto ep_alloc_err; } - //Allocate the endpoint wrapper item + // Allocate the endpoint wrapper item ep_wrapper_t *ep_wrap; ret = ep_wrapper_alloc(dev_hdl, ep_desc, intf_obj, &ep_wrap); if (ret != ESP_OK) { goto ep_alloc_err; } - //Fill the interface object with the allocated endpoints + // Fill the interface object with the allocated endpoints intf_obj->constant.endpoints[i] = ep_wrap; } - //Add interface object to client (safe because we have already taken the mutex) + // Add interface object to client (safe because we have already taken the mutex) TAILQ_INSERT_TAIL(&client_obj->mux_protected.interface_tailq, intf_obj, mux_protected.tailq_entry); - //Add each endpoint wrapper item to the client's endpoint list + // Add each endpoint wrapper item to the client's endpoint list HOST_ENTER_CRITICAL(); for (int i = 0; i < intf_desc->bNumEndpoints; i++) { TAILQ_INSERT_TAIL(&client_obj->dynamic.idle_ep_tailq, intf_obj->constant.endpoints[i], dynamic.tailq_entry); } HOST_EXIT_CRITICAL(); - //Write back result + // Write back result *intf_obj_ret = intf_obj; ret = ESP_OK; return ret; @@ -1075,7 +1075,7 @@ exit: static esp_err_t interface_release(client_t *client_obj, usb_device_handle_t dev_hdl, uint8_t bInterfaceNumber) { esp_err_t ret; - //Find the interface object + // Find the interface object interface_t *intf_obj_iter; interface_t *intf_obj = NULL; TAILQ_FOREACH(intf_obj_iter, &client_obj->mux_protected.interface_tailq, mux_protected.tailq_entry) { @@ -1089,13 +1089,13 @@ static esp_err_t interface_release(client_t *client_obj, usb_device_handle_t dev goto exit; } - //Check that all endpoints in the interface are in a state to be freed - //Todo: Check that each EP is halted before allowing them to be freed (IDF-7273) + // Check that all endpoints in the interface are in a state to be freed + // Todo: Check that each EP is halted before allowing them to be freed (IDF-7273) HOST_ENTER_CRITICAL(); bool can_free = true; for (int i = 0; i < intf_obj->constant.intf_desc->bNumEndpoints; i++) { ep_wrapper_t *ep_wrap = intf_obj->constant.endpoints[i]; - //Endpoint must not be on the pending list and must not have in-flight URBs + // Endpoint must not be on the pending list and must not have in-flight URBs if (ep_wrap->dynamic.num_urb_inflight != 0 || ep_wrap->dynamic.flags.pending) { can_free = false; break; @@ -1106,21 +1106,21 @@ static esp_err_t interface_release(client_t *client_obj, usb_device_handle_t dev ret = ESP_ERR_INVALID_STATE; goto exit; } - //Proceed to remove all endpoint wrapper items from the list + // Proceed to remove all endpoint wrapper items from the list for (int i = 0; i < intf_obj->constant.intf_desc->bNumEndpoints; i++) { TAILQ_REMOVE(&client_obj->dynamic.idle_ep_tailq, intf_obj->constant.endpoints[i], dynamic.tailq_entry); } HOST_EXIT_CRITICAL(); - //Remove the interface object from the list (safe because we have already taken the mutex) + // Remove the interface object from the list (safe because we have already taken the mutex) TAILQ_REMOVE(&client_obj->mux_protected.interface_tailq, intf_obj, mux_protected.tailq_entry); - //Free each endpoint in the interface - for (int i = 0; i < intf_obj->constant.intf_desc->bNumEndpoints; i++) { + // Free each endpoint in the interface + for (int i = 0; i < intf_obj->constant.intf_desc->bNumEndpoints; i++) { ep_wrapper_free(dev_hdl, intf_obj->constant.endpoints[i]); intf_obj->constant.endpoints[i] = NULL; } - //Free the interface object itself + // Free the interface object itself interface_free(intf_obj); ret = ESP_OK; exit: @@ -1137,18 +1137,18 @@ esp_err_t usb_host_interface_claim(usb_host_client_handle_t client_hdl, usb_devi HOST_ENTER_CRITICAL(); uint8_t dev_addr; ESP_ERROR_CHECK(usbh_dev_get_addr(dev_hdl, &dev_addr)); - //Check if client actually opened device + // Check if client actually opened device HOST_CHECK_FROM_CRIT(_check_client_opened_device(client_obj, dev_addr), ESP_ERR_INVALID_STATE); client_obj->dynamic.flags.taking_mux = 1; HOST_EXIT_CRITICAL(); - //Take mux lock. This protects the client being released or other clients from claiming interfaces + // Take mux lock. This protects the client being released or other clients from claiming interfaces xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY); esp_err_t ret; const usb_config_desc_t *config_desc; ESP_ERROR_CHECK(usbh_dev_get_config_desc(dev_hdl, &config_desc)); interface_t *intf_obj; - //Claim interface + // Claim interface ret = interface_claim(client_obj, dev_hdl, config_desc, bInterfaceNumber, bAlternateSetting, &intf_obj); if (ret != ESP_OK) { goto exit; @@ -1174,12 +1174,12 @@ esp_err_t usb_host_interface_release(usb_host_client_handle_t client_hdl, usb_de HOST_ENTER_CRITICAL(); uint8_t dev_addr; ESP_ERROR_CHECK(usbh_dev_get_addr(dev_hdl, &dev_addr)); - //Check if client actually opened device + // Check if client actually opened device HOST_CHECK_FROM_CRIT(_check_client_opened_device(client_obj, dev_addr), ESP_ERR_INVALID_STATE); client_obj->dynamic.flags.taking_mux = 1; HOST_EXIT_CRITICAL(); - //Take mux lock. This protects the client being released or other clients from claiming interfaces + // Take mux lock. This protects the client being released or other clients from claiming interfaces xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY); esp_err_t ret = interface_release(client_obj, dev_hdl, bInterfaceNumber); xSemaphoreGive(p_host_lib_obj->constant.mux_lock); @@ -1266,8 +1266,8 @@ esp_err_t usb_host_transfer_free(usb_transfer_t *transfer) esp_err_t usb_host_transfer_submit(usb_transfer_t *transfer) { HOST_CHECK(transfer != NULL, ESP_ERR_INVALID_ARG); - //Check that transfer and target endpoint are valid - HOST_CHECK(transfer->device_handle != NULL, ESP_ERR_INVALID_ARG); //Target device must be set + // Check that transfer and target endpoint are valid + HOST_CHECK(transfer->device_handle != NULL, ESP_ERR_INVALID_ARG); // Target device must be set HOST_CHECK((transfer->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK) != 0, ESP_ERR_INVALID_ARG); usbh_ep_handle_t ep_hdl; @@ -1281,7 +1281,7 @@ esp_err_t usb_host_transfer_submit(usb_transfer_t *transfer) } ep_wrap = usbh_ep_get_context(ep_hdl); assert(ep_wrap != NULL); - //Check that we are not submitting a transfer already in-flight + // Check that we are not submitting a transfer already in-flight HOST_CHECK(!urb_obj->usb_host_inflight, ESP_ERR_NOT_FINISHED); urb_obj->usb_host_inflight = true; HOST_ENTER_CRITICAL(); @@ -1306,17 +1306,17 @@ err: esp_err_t usb_host_transfer_submit_control(usb_host_client_handle_t client_hdl, usb_transfer_t *transfer) { HOST_CHECK(client_hdl != NULL && transfer != NULL, ESP_ERR_INVALID_ARG); - //Check that control transfer is valid - HOST_CHECK(transfer->device_handle != NULL, ESP_ERR_INVALID_ARG); //Target device must be set - //Control transfers must be targeted at EP 0 + // Check that control transfer is valid + HOST_CHECK(transfer->device_handle != NULL, ESP_ERR_INVALID_ARG); // Target device must be set + // Control transfers must be targeted at EP 0 HOST_CHECK((transfer->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK) == 0, ESP_ERR_INVALID_ARG); usb_device_handle_t dev_hdl = transfer->device_handle; urb_t *urb_obj = __containerof(transfer, urb_t, transfer); - //Check that we are not submitting a transfer already in-flight + // Check that we are not submitting a transfer already in-flight HOST_CHECK(!urb_obj->usb_host_inflight, ESP_ERR_NOT_FINISHED); urb_obj->usb_host_inflight = true; - //Save client handle into URB + // Save client handle into URB urb_obj->usb_host_client = (void *)client_hdl; esp_err_t ret; diff --git a/components/usb/usb_phy.c b/components/usb/usb_phy.c index a16a7dde9c..2ba62112bf 100644 --- a/components/usb/usb_phy.c +++ b/components/usb/usb_phy.c @@ -85,7 +85,7 @@ static esp_err_t phy_external_iopins_configure(const usb_phy_ext_io_conf_t *ext_ {ext_io_conf->vmo_io_num, usb_otg_periph_signal.extphy_vmo_out, true}, }; - return phy_iopins_configure(usb_periph_iopins, sizeof(usb_periph_iopins)/sizeof(usb_iopin_dsc_t)); + return phy_iopins_configure(usb_periph_iopins, sizeof(usb_periph_iopins) / sizeof(usb_iopin_dsc_t)); } static esp_err_t phy_otg_iopins_configure(const usb_phy_otg_io_conf_t *otg_io_conf) @@ -103,7 +103,7 @@ static esp_err_t phy_otg_iopins_configure(const usb_phy_otg_io_conf_t *otg_io_co {otg_io_conf->chrgvbus_io_num, usb_otg_periph_signal.srp_chrgvbus_out, true}, {otg_io_conf->dischrgvbus_io_num, usb_otg_periph_signal.srp_dischrgvbus_out, true}, }; - return phy_iopins_configure(usb_periph_iopins, sizeof(usb_periph_iopins)/sizeof(usb_iopin_dsc_t)); + return phy_iopins_configure(usb_periph_iopins, sizeof(usb_periph_iopins) / sizeof(usb_iopin_dsc_t)); } esp_err_t usb_phy_otg_set_mode(usb_phy_handle_t handle, usb_otg_mode_t mode) @@ -114,17 +114,17 @@ esp_err_t usb_phy_otg_set_mode(usb_phy_handle_t handle, usb_otg_mode_t mode) handle->otg_mode = mode; if (mode == USB_OTG_MODE_HOST) { - esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_OTG_IDDIG_IN_IDX, false); //connected connector is A side + esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_OTG_IDDIG_IN_IDX, false); // connected connector is A side esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_SRP_BVALID_IN_IDX, false); - esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_VBUSVALID_IN_IDX, false); //receiving a valid Vbus from host - esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_AVALID_IN_IDX, false); //HIGH to force USB host mode + esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_VBUSVALID_IN_IDX, false); // receiving a valid Vbus from host + esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_AVALID_IN_IDX, false); // HIGH to force USB host mode if (handle->target == USB_PHY_TARGET_INT) { usb_phy_hal_int_load_conf_host(&(handle->hal_context)); } } else if (mode == USB_OTG_MODE_DEVICE) { - esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_IDDIG_IN_IDX, false); //connected connector is mini-B side - esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_SRP_BVALID_IN_IDX, false); //HIGH to force USB device mode - esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_VBUSVALID_IN_IDX, false); //receiving a valid Vbus from device + esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_IDDIG_IN_IDX, false); // connected connector is mini-B side + esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_SRP_BVALID_IN_IDX, false); // HIGH to force USB device mode + esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_VBUSVALID_IN_IDX, false); // receiving a valid Vbus from device esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_OTG_AVALID_IN_IDX, false); } @@ -160,37 +160,37 @@ esp_err_t usb_phy_action(usb_phy_handle_t handle, usb_phy_action_t action) esp_err_t ret = ESP_OK; switch (action) { - case USB_PHY_ACTION_HOST_ALLOW_CONN: - if (handle->target == USB_PHY_TARGET_INT) { - usb_phy_hal_int_mimick_disconn(&(handle->hal_context), false); - } else { - if (!handle->iopins) { - ret = ESP_FAIL; - ESP_LOGE(USBPHY_TAG, "no I/O pins provided for connection"); - break; - } - /* - Allow for connections on the external PHY by connecting the VP and VM signals to the external PHY. - */ - esp_rom_gpio_connect_in_signal(handle->iopins->vp_io_num, USB_EXTPHY_VP_IDX, false); - esp_rom_gpio_connect_in_signal(handle->iopins->vm_io_num, USB_EXTPHY_VM_IDX, false); + case USB_PHY_ACTION_HOST_ALLOW_CONN: + if (handle->target == USB_PHY_TARGET_INT) { + usb_phy_hal_int_mimick_disconn(&(handle->hal_context), false); + } else { + if (!handle->iopins) { + ret = ESP_FAIL; + ESP_LOGE(USBPHY_TAG, "no I/O pins provided for connection"); + break; } - break; + /* + Allow for connections on the external PHY by connecting the VP and VM signals to the external PHY. + */ + esp_rom_gpio_connect_in_signal(handle->iopins->vp_io_num, USB_EXTPHY_VP_IDX, false); + esp_rom_gpio_connect_in_signal(handle->iopins->vm_io_num, USB_EXTPHY_VM_IDX, false); + } + break; - case USB_PHY_ACTION_HOST_FORCE_DISCONN: - if (handle->target == USB_PHY_TARGET_INT) { - usb_phy_hal_int_mimick_disconn(&(handle->hal_context), true); - } else { - /* - Disable connections on the external PHY by connecting the VP and VM signals to the constant LOW signal. - */ - esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_EXTPHY_VP_IDX, false); - esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_EXTPHY_VM_IDX, false); - } - break; + case USB_PHY_ACTION_HOST_FORCE_DISCONN: + if (handle->target == USB_PHY_TARGET_INT) { + usb_phy_hal_int_mimick_disconn(&(handle->hal_context), true); + } else { + /* + Disable connections on the external PHY by connecting the VP and VM signals to the constant LOW signal. + */ + esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_EXTPHY_VP_IDX, false); + esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_EXTPHY_VM_IDX, false); + } + break; - default: - break; + default: + break; } return ret; diff --git a/components/usb/usb_private.c b/components/usb/usb_private.c index 1ab0448a6f..9508597641 100644 --- a/components/usb/usb_private.c +++ b/components/usb/usb_private.c @@ -15,8 +15,8 @@ urb_t *urb_alloc(size_t data_buffer_size, size_t header_size, int num_isoc_packe if (urb == NULL || data_buffer == NULL) { goto err; } - urb->usb_host_header_size = header_size; //Indicate that this URB's data_buffer has a header in front of it. - //Case as dummy transfer to write to initialize const fields + urb->usb_host_header_size = header_size; // Indicate that this URB's data_buffer has a header in front of it. + // Case as dummy transfer to write to initialize const fields usb_transfer_dummy_t *dummy_transfer = (usb_transfer_dummy_t *)&urb->transfer; dummy_transfer->data_buffer = (uint8_t *)(data_buffer + header_size); dummy_transfer->data_buffer_size = data_buffer_size; diff --git a/components/usb/usbh.c b/components/usb/usbh.c index 799ff2a5d4..3fb68e70c1 100644 --- a/components/usb/usbh.c +++ b/components/usb/usbh.c @@ -25,17 +25,17 @@ #define EP_NUM_MAX 16 // The largest possible non-default endpoint number #define NUM_NON_DEFAULT_EP ((EP_NUM_MAX - 1) * 2) // The total number of non-default endpoints a device can have. -//Device action flags. LISTED IN THE ORDER THEY SHOULD BE HANDLED IN within usbh_process(). Some actions are mutually exclusive +// Device action flags. LISTED IN THE ORDER THEY SHOULD BE HANDLED IN within usbh_process(). Some actions are mutually exclusive typedef enum { - DEV_ACTION_EPn_HALT_FLUSH = (1 << 0), //Halt all non-default endpoints then flush them (called after a device gone is gone) - DEV_ACTION_EP0_FLUSH = (1 << 1), //Retire all URBS submitted to EP0 - DEV_ACTION_EP0_DEQUEUE = (1 << 2), //Dequeue all URBs from EP0 - DEV_ACTION_EP0_CLEAR = (1 << 3), //Move EP0 to the the active state - DEV_ACTION_PROP_GONE_EVT = (1 << 4), //Propagate a USBH_EVENT_DEV_GONE event - DEV_ACTION_FREE_AND_RECOVER = (1 << 5), //Free the device object, but send a USBH_HUB_REQ_PORT_RECOVER request afterwards. - DEV_ACTION_FREE = (1 << 6), //Free the device object - DEV_ACTION_PORT_DISABLE = (1 << 7), //Request the hub driver to disable the port of the device - DEV_ACTION_PROP_NEW = (1 << 8), //Propagate a USBH_EVENT_DEV_NEW event + DEV_ACTION_EPn_HALT_FLUSH = (1 << 0), // Halt all non-default endpoints then flush them (called after a device gone is gone) + DEV_ACTION_EP0_FLUSH = (1 << 1), // Retire all URBS submitted to EP0 + DEV_ACTION_EP0_DEQUEUE = (1 << 2), // Dequeue all URBs from EP0 + DEV_ACTION_EP0_CLEAR = (1 << 3), // Move EP0 to the the active state + DEV_ACTION_PROP_GONE_EVT = (1 << 4), // Propagate a USBH_EVENT_DEV_GONE event + DEV_ACTION_FREE_AND_RECOVER = (1 << 5), // Free the device object, but send a USBH_HUB_REQ_PORT_RECOVER request afterwards. + DEV_ACTION_FREE = (1 << 6), // Free the device object + DEV_ACTION_PORT_DISABLE = (1 << 7), // Request the hub driver to disable the port of the device + DEV_ACTION_PROP_NEW = (1 << 8), // Propagate a USBH_EVENT_DEV_NEW event } dev_action_t; typedef struct device_s device_t; @@ -45,13 +45,13 @@ typedef 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" + 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; } endpoint_t; struct device_s { - //Dynamic members require a critical section + // Dynamic members require a critical section struct { TAILQ_ENTRY(device_s) tailq_entry; union { @@ -70,7 +70,7 @@ struct device_s { usb_device_state_t state; uint32_t ref_count; } dynamic; - //Mux protected members must be protected by the USBH mux_lock when accessed + // Mux protected members must be protected by the USBH mux_lock when accessed struct { /* - Endpoint object pointers for each possible non-default endpoint @@ -78,7 +78,7 @@ struct device_s { */ endpoint_t *endpoints[NUM_NON_DEFAULT_EP]; } mux_protected; - //Constant members do not change after device allocation and enumeration thus do not require a critical section + // Constant members do not change after device allocation and enumeration thus do not require a critical section struct { hcd_pipe_handle_t default_pipe; hcd_port_handle_t port_hdl; @@ -93,16 +93,16 @@ struct device_s { }; typedef struct { - //Dynamic members require a critical section + // 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 + 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 + // Mux protected members must be protected by the USBH mux_lock when accessed struct { - uint8_t num_device; //Number of enumerated devices + uint8_t num_device; // Number of enumerated devices } mux_protected; - //Constant members do no change after installation thus do not require a critical section + // Constant members do no change after installation thus do not require a critical section struct { usb_proc_req_cb_t proc_req_cb; void *proc_req_cb_arg; @@ -169,13 +169,13 @@ static endpoint_t *get_ep_from_addr(device_t *dev_obj, uint8_t bEndpointAddress) CALLER IS RESPONSIBLE FOR TAKING THE mux_lock */ - //Calculate index to the device's endpoint object list + // Calculate index to the device's endpoint object list int index; // EP_NUM_MIN should map to an index of 0 index = (bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK) - EP_NUM_MIN; assert(index >= 0); // Endpoint address is not supported if (bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK) { - //OUT EPs are listed before IN EPs, so add an offset + // OUT EPs are listed before IN EPs, so add an offset index += (EP_NUM_MAX - EP_NUM_MIN); } return dev_obj->mux_protected.endpoints[index]; @@ -187,13 +187,13 @@ static inline void set_ep_from_addr(device_t *dev_obj, uint8_t bEndpointAddress, CALLER IS RESPONSIBLE FOR TAKING THE mux_lock */ - //Calculate index to the device's endpoint object list + // Calculate index to the device's endpoint object list int index; - // EP_NUM_MIN should map to an index of 0 + // EP_NUM_MIN should map to an index of 0 index = (bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK) - EP_NUM_MIN; assert(index >= 0); // Endpoint address is not supported if (bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK) { - //OUT EPs are listed before IN EPs, so add an offset + // OUT EPs are listed before IN EPs, so add an offset index += (EP_NUM_MAX - EP_NUM_MIN); } dev_obj->mux_protected.endpoints[index] = ep_obj; @@ -215,20 +215,20 @@ static bool urb_check_args(urb_t *urb) static bool transfer_check_usb_compliance(usb_transfer_t *transfer, usb_transfer_type_t type, int mps, bool is_in) { if (type == USB_TRANSFER_TYPE_CTRL) { - //Check that num_bytes and wLength are set correctly + // Check that num_bytes and wLength are set correctly usb_setup_packet_t *setup_pkt = (usb_setup_packet_t *)transfer->data_buffer; if (transfer->num_bytes != sizeof(usb_setup_packet_t) + setup_pkt->wLength) { ESP_LOGE(USBH_TAG, "usb_transfer_t num_bytes and usb_setup_packet_t wLength mismatch"); return false; } } else if (type == USB_TRANSFER_TYPE_ISOCHRONOUS) { - //Check that there is at least one isochronous packet descriptor + // Check that there is at least one isochronous packet descriptor if (transfer->num_isoc_packets <= 0) { ESP_LOGE(USBH_TAG, "usb_transfer_t num_isoc_packets is 0"); return false; } - //Check that sum of all packet lengths add up to transfer length - //If IN, check that each packet length is integer multiple of MPS + // Check that sum of all packet lengths add up to transfer length + // If IN, check that each packet length is integer multiple of MPS int total_num_bytes = 0; bool mod_mps_all_zero = true; for (int i = 0; i < transfer->num_isoc_packets; i++) { @@ -246,7 +246,7 @@ static bool transfer_check_usb_compliance(usb_transfer_t *transfer, usb_transfer return false; } } else { - //Check that IN transfers are integer multiple of MPS + // Check that IN transfers are integer multiple of MPS if (is_in && (transfer->num_bytes % mps != 0)) { ESP_LOGE(USBH_TAG, "IN transfer num_bytes not integer multiple of MPS"); return false; @@ -267,7 +267,7 @@ static esp_err_t endpoint_alloc(device_t *dev_obj, const usb_ep_desc_t *ep_desc, if (ep_obj == NULL) { return ESP_ERR_NO_MEM; } - //Allocate the EP's underlying pipe + // Allocate the EP's underlying pipe hcd_pipe_config_t pipe_config = { .callback = epN_pipe_callback, .callback_arg = (void *)ep_obj, @@ -280,13 +280,13 @@ static esp_err_t endpoint_alloc(device_t *dev_obj, const usb_ep_desc_t *ep_desc, if (ret != ESP_OK) { goto pipe_err; } - //Initialize the endpoint object + // Initialize the endpoint object ep_obj->constant.pipe_hdl = pipe_hdl; ep_obj->constant.ep_cb = ep_config->ep_cb; ep_obj->constant.ep_cb_arg = ep_config->ep_cb_arg; ep_obj->constant.dev = dev_obj; ep_obj->constant.ep_desc = ep_desc; - //Return the endpoint object + // Return the endpoint object *ep_obj_ret = ep_obj; ret = ESP_OK; @@ -302,9 +302,9 @@ static void endpoint_free(endpoint_t *ep_obj) if (ep_obj == NULL) { return; } - //Deallocate the EP's underlying pipe + // Deallocate the EP's underlying pipe ESP_ERROR_CHECK(hcd_pipe_free(ep_obj->constant.pipe_hdl)); - //Free the heap object + // Free the heap object heap_caps_free(ep_obj); } @@ -317,12 +317,12 @@ static esp_err_t device_alloc(hcd_port_handle_t port_hdl, usb_speed_t speed, dev ret = ESP_ERR_NO_MEM; goto err; } - //Allocate a pipe for EP0. We set the pipe callback to NULL for now + // Allocate a pipe for EP0. We set the pipe callback to NULL for now hcd_pipe_config_t pipe_config = { .callback = NULL, .callback_arg = NULL, .context = (void *)dev_obj, - .ep_desc = NULL, //No endpoint descriptor means we're allocating a pipe for EP0 + .ep_desc = NULL, // No endpoint descriptor means we're allocating a pipe for EP0 .dev_speed = speed, .dev_addr = 0, }; @@ -331,11 +331,11 @@ static esp_err_t device_alloc(hcd_port_handle_t port_hdl, usb_speed_t speed, dev if (ret != ESP_OK) { goto err; } - //Initialize device object + // 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; - //Note: dev_obj->constant.address is assigned later during enumeration + // Note: dev_obj->constant.address is assigned later during enumeration dev_obj->constant.speed = speed; dev_obj->constant.desc = dev_desc; *dev_obj_ret = dev_obj; @@ -353,11 +353,11 @@ static void device_free(device_t *dev_obj) if (dev_obj == NULL) { return; } - //Configuration might not have been allocated (in case of early enumeration failure) + // Configuration might not have been allocated (in case of early enumeration failure) if (dev_obj->constant.config_desc) { heap_caps_free((usb_config_desc_t *)dev_obj->constant.config_desc); } - //String descriptors might not have been allocated (in case of early enumeration failure) + // String descriptors might not have been allocated (in case of early enumeration failure) if (dev_obj->constant.str_desc_manu) { heap_caps_free((usb_str_desc_t *)dev_obj->constant.str_desc_manu); } @@ -379,35 +379,35 @@ static bool ep0_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_ uint32_t action_flags; device_t *dev_obj = (device_t *)user_arg; switch (pipe_event) { - case HCD_PIPE_EVENT_URB_DONE: - //A control transfer completed on EP0's pipe . We need to dequeue it - action_flags = DEV_ACTION_EP0_DEQUEUE; - break; - case HCD_PIPE_EVENT_ERROR_XFER: - case HCD_PIPE_EVENT_ERROR_URB_NOT_AVAIL: - case HCD_PIPE_EVENT_ERROR_OVERFLOW: - //EP0's pipe has encountered an error. We need to retire all URBs, dequeue them, then make the pipe active again - action_flags = DEV_ACTION_EP0_FLUSH | - DEV_ACTION_EP0_DEQUEUE | - DEV_ACTION_EP0_CLEAR; - if (in_isr) { - ESP_EARLY_LOGE(USBH_TAG, "Dev %d EP 0 Error", dev_obj->constant.address); - } else { - ESP_LOGE(USBH_TAG, "Dev %d EP 0 Error", dev_obj->constant.address); - } - break; - case HCD_PIPE_EVENT_ERROR_STALL: - //EP0's pipe encountered a "protocol stall". We just need to dequeue URBs then make the pipe active again - action_flags = DEV_ACTION_EP0_DEQUEUE | DEV_ACTION_EP0_CLEAR; - if (in_isr) { - ESP_EARLY_LOGE(USBH_TAG, "Dev %d EP 0 STALL", dev_obj->constant.address); - } else { - ESP_LOGE(USBH_TAG, "Dev %d EP 0 STALL", dev_obj->constant.address); - } - break; - default: - action_flags = 0; - break; + case HCD_PIPE_EVENT_URB_DONE: + // A control transfer completed on EP0's pipe . We need to dequeue it + action_flags = DEV_ACTION_EP0_DEQUEUE; + break; + case HCD_PIPE_EVENT_ERROR_XFER: + case HCD_PIPE_EVENT_ERROR_URB_NOT_AVAIL: + case HCD_PIPE_EVENT_ERROR_OVERFLOW: + // EP0's pipe has encountered an error. We need to retire all URBs, dequeue them, then make the pipe active again + action_flags = DEV_ACTION_EP0_FLUSH | + DEV_ACTION_EP0_DEQUEUE | + DEV_ACTION_EP0_CLEAR; + if (in_isr) { + ESP_EARLY_LOGE(USBH_TAG, "Dev %d EP 0 Error", dev_obj->constant.address); + } else { + ESP_LOGE(USBH_TAG, "Dev %d EP 0 Error", dev_obj->constant.address); + } + break; + case HCD_PIPE_EVENT_ERROR_STALL: + // EP0's pipe encountered a "protocol stall". We just need to dequeue URBs then make the pipe active again + action_flags = DEV_ACTION_EP0_DEQUEUE | DEV_ACTION_EP0_CLEAR; + if (in_isr) { + ESP_EARLY_LOGE(USBH_TAG, "Dev %d EP 0 STALL", dev_obj->constant.address); + } else { + ESP_LOGE(USBH_TAG, "Dev %d EP 0 STALL", dev_obj->constant.address); + } + break; + default: + action_flags = 0; + break; } USBH_ENTER_CRITICAL_SAFE(); @@ -438,9 +438,9 @@ static bool _dev_set_actions(device_t *dev_obj, uint32_t action_flags) return false; } bool call_proc_req_cb; - //Check if device is already on the callback list + // Check if device is already on the callback list if (!dev_obj->dynamic.flags.in_pending_list) { - //Move device form idle device list to callback device list + // Move device form idle device list to callback device list TAILQ_REMOVE(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry); TAILQ_INSERT_TAIL(&p_usbh_obj->dynamic.devs_pending_tailq, dev_obj, dynamic.tailq_entry); dev_obj->dynamic.action_flags |= action_flags; @@ -454,9 +454,9 @@ static bool _dev_set_actions(device_t *dev_obj, uint32_t action_flags) static inline void handle_epn_halt_flush(device_t *dev_obj) { - //We need to take the mux_lock to access mux_protected members + // We need to take the mux_lock to access mux_protected members xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); - //Halt then flush all non-default EPs + // Halt then flush all non-default EPs for (int i = 0; i < NUM_NON_DEFAULT_EP; i++) { if (dev_obj->mux_protected.endpoints[i] != NULL) { ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->mux_protected.endpoints[i]->constant.pipe_hdl, HCD_PIPE_CMD_HALT)); @@ -474,7 +474,7 @@ static inline void handle_ep0_flush(device_t *dev_obj) static inline void handle_ep0_dequeue(device_t *dev_obj) { - //Empty URBs from EP0's pipe and call the control transfer callback + // Empty URBs from EP0's pipe and call the control transfer callback ESP_LOGD(USBH_TAG, "Default pipe device %d", dev_obj->constant.address); int num_urbs = 0; urb_t *urb = hcd_urb_dequeue(dev_obj->constant.default_pipe); @@ -490,28 +490,28 @@ static inline void handle_ep0_dequeue(device_t *dev_obj) static inline void handle_ep0_clear(device_t *dev_obj) { - //We allow the pipe command to fail just in case the pipe becomes invalid mid command + // We allow the pipe command to fail just in case the pipe becomes invalid mid command hcd_pipe_command(dev_obj->constant.default_pipe, HCD_PIPE_CMD_CLEAR); } static inline void handle_prop_gone_evt(device_t *dev_obj) { - //Flush EP0's pipe. Then propagate a USBH_EVENT_DEV_GONE event + // Flush EP0's pipe. Then propagate a USBH_EVENT_DEV_GONE event ESP_LOGE(USBH_TAG, "Device %d gone", dev_obj->constant.address); p_usbh_obj->constant.event_cb((usb_device_handle_t)dev_obj, USBH_EVENT_DEV_GONE, p_usbh_obj->constant.event_cb_arg); } static void handle_free_and_recover(device_t *dev_obj, bool recover_port) { - //Cache a copy of the port handle as we are about to free the device object + // Cache a copy of the port handle as we are about to free the device object bool all_free; hcd_port_handle_t port_hdl = dev_obj->constant.port_hdl; ESP_LOGD(USBH_TAG, "Freeing device %d", dev_obj->constant.address); - //We need to take the mux_lock to access mux_protected members + // We need to take the mux_lock to access mux_protected members xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); USBH_ENTER_CRITICAL(); - //Remove the device object for it's containing list + // Remove the device object for it's containing list if (dev_obj->dynamic.flags.in_pending_list) { dev_obj->dynamic.flags.in_pending_list = 0; TAILQ_REMOVE(&p_usbh_obj->dynamic.devs_pending_tailq, dev_obj, dynamic.tailq_entry); @@ -524,12 +524,12 @@ static void handle_free_and_recover(device_t *dev_obj, bool recover_port) xSemaphoreGive(p_usbh_obj->constant.mux_lock); device_free(dev_obj); - //If all devices have been freed, propagate a USBH_EVENT_DEV_ALL_FREE event + // If all devices have been freed, propagate a USBH_EVENT_DEV_ALL_FREE event if (all_free) { ESP_LOGD(USBH_TAG, "Device all free"); p_usbh_obj->constant.event_cb((usb_device_handle_t)NULL, USBH_EVENT_DEV_ALL_FREE, p_usbh_obj->constant.event_cb_arg); } - //Check if we need to recover the device's port + // Check if we need to recover the device's port if (recover_port) { p_usbh_obj->constant.hub_req_cb(port_hdl, USBH_HUB_REQ_PORT_RECOVER, p_usbh_obj->constant.hub_req_cb_arg); } @@ -537,7 +537,7 @@ static void handle_free_and_recover(device_t *dev_obj, bool recover_port) static inline void handle_port_disable(device_t *dev_obj) { - //Request that the HUB disables this device's port + // Request that the HUB disables this device's port ESP_LOGD(USBH_TAG, "Disable device port %d", dev_obj->constant.address); p_usbh_obj->constant.hub_req_cb(dev_obj->constant.port_hdl, USBH_HUB_REQ_PORT_DISABLE, p_usbh_obj->constant.hub_req_cb_arg); } @@ -564,7 +564,7 @@ esp_err_t usbh_install(const usbh_config_t *usbh_config) ret = ESP_ERR_NO_MEM; goto err; } - //Initialize USBH object + // Initialize USBH object TAILQ_INIT(&usbh_obj->dynamic.devs_idle_tailq); TAILQ_INIT(&usbh_obj->dynamic.devs_pending_tailq); usbh_obj->constant.proc_req_cb = usbh_config->proc_req_cb; @@ -575,7 +575,7 @@ esp_err_t usbh_install(const usbh_config_t *usbh_config) usbh_obj->constant.ctrl_xfer_cb_arg = usbh_config->ctrl_xfer_cb_arg; usbh_obj->constant.mux_lock = mux_lock; - //Assign USBH object pointer + // Assign USBH object pointer USBH_ENTER_CRITICAL(); if (p_usbh_obj != NULL) { USBH_EXIT_CRITICAL(); @@ -598,28 +598,28 @@ err: esp_err_t usbh_uninstall(void) { - //Check that USBH is in a state to be uninstalled + // Check that USBH is in a state to be uninstalled USBH_ENTER_CRITICAL(); USBH_CHECK_FROM_CRIT(p_usbh_obj != NULL, ESP_ERR_INVALID_STATE); usbh_t *usbh_obj = p_usbh_obj; USBH_EXIT_CRITICAL(); esp_err_t ret; - //We need to take the mux_lock to access mux_protected members + // We need to take the mux_lock to access mux_protected members xSemaphoreTake(usbh_obj->constant.mux_lock, portMAX_DELAY); if (p_usbh_obj->mux_protected.num_device > 0) { - //There are still devices allocated. Can't uninstall right now. + // There are still devices allocated. Can't uninstall right now. ret = ESP_ERR_INVALID_STATE; goto exit; } - //Check again if we can uninstall + // Check again if we can uninstall USBH_ENTER_CRITICAL(); assert(p_usbh_obj == usbh_obj); p_usbh_obj = NULL; USBH_EXIT_CRITICAL(); xSemaphoreGive(usbh_obj->constant.mux_lock); - //Free resources + // Free resources vSemaphoreDelete(usbh_obj->constant.mux_lock); heap_caps_free(usbh_obj); ret = ESP_OK; @@ -634,13 +634,13 @@ esp_err_t usbh_process(void) { USBH_ENTER_CRITICAL(); USBH_CHECK_FROM_CRIT(p_usbh_obj != NULL, ESP_ERR_INVALID_STATE); - //Keep processing until all device's with pending events have been handled - while (!TAILQ_EMPTY(&p_usbh_obj->dynamic.devs_pending_tailq)){ - //Move the device back into the idle device list, + // Keep processing until all device's with pending events have been handled + while (!TAILQ_EMPTY(&p_usbh_obj->dynamic.devs_pending_tailq)) { + // Move the device back into the idle device list, device_t *dev_obj = TAILQ_FIRST(&p_usbh_obj->dynamic.devs_pending_tailq); TAILQ_REMOVE(&p_usbh_obj->dynamic.devs_pending_tailq, dev_obj, dynamic.tailq_entry); TAILQ_INSERT_TAIL(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry); - //Clear the device's flags + // Clear the device's flags uint32_t action_flags = dev_obj->dynamic.action_flags; dev_obj->dynamic.action_flags = 0; dev_obj->dynamic.flags.in_pending_list = 0; @@ -650,7 +650,7 @@ esp_err_t usbh_process(void) --------------------------------------------------------------------- */ USBH_EXIT_CRITICAL(); ESP_LOGD(USBH_TAG, "Processing actions 0x%"PRIx32"", action_flags); - //Sanity check. If the device is being freed, there must not be any other action flags set + // Sanity check. If the device is being freed, there must not be any other action flags set assert(!(action_flags & DEV_ACTION_FREE) || action_flags == DEV_ACTION_FREE); if (action_flags & DEV_ACTION_EPn_HALT_FLUSH) { @@ -713,7 +713,7 @@ esp_err_t usbh_dev_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *num USBH_ENTER_CRITICAL(); int num_filled = 0; device_t *dev_obj; - //Fill list with devices from idle tailq + // Fill list with devices from idle tailq TAILQ_FOREACH(dev_obj, &p_usbh_obj->dynamic.devs_idle_tailq, dynamic.tailq_entry) { if (num_filled < list_len) { dev_addr_list[num_filled] = dev_obj->constant.address; @@ -722,7 +722,7 @@ esp_err_t usbh_dev_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *num break; } } - //Fill list with devices from pending tailq + // Fill list with devices from pending tailq TAILQ_FOREACH(dev_obj, &p_usbh_obj->dynamic.devs_pending_tailq, dynamic.tailq_entry) { if (num_filled < list_len) { dev_addr_list[num_filled] = dev_obj->constant.address; @@ -732,7 +732,7 @@ esp_err_t usbh_dev_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *num } } USBH_EXIT_CRITICAL(); - //Write back number of devices filled + // Write back number of devices filled *num_dev_ret = num_filled; return ESP_OK; } @@ -743,7 +743,7 @@ esp_err_t usbh_dev_open(uint8_t dev_addr, usb_device_handle_t *dev_hdl) esp_err_t ret; USBH_ENTER_CRITICAL(); - //Go through the device lists to find the device with the specified address + // Go through the device lists to find the device with the specified address device_t *found_dev_obj = NULL; device_t *dev_obj; TAILQ_FOREACH(dev_obj, &p_usbh_obj->dynamic.devs_idle_tailq, dynamic.tailq_entry) { @@ -760,7 +760,7 @@ esp_err_t usbh_dev_open(uint8_t dev_addr, usb_device_handle_t *dev_hdl) } exit: if (found_dev_obj != NULL) { - //The device is not in a state to be referenced + // The device is not in a state to be referenced if (dev_obj->dynamic.flags.is_gone || dev_obj->dynamic.flags.waiting_port_disable || dev_obj->dynamic.flags.waiting_free) { ret = ESP_ERR_INVALID_STATE; } else { @@ -785,19 +785,19 @@ esp_err_t usbh_dev_close(usb_device_handle_t dev_hdl) dev_obj->dynamic.ref_count--; bool call_proc_req_cb = false; if (dev_obj->dynamic.ref_count == 0) { - //Sanity check. - assert(dev_obj->dynamic.num_ctrl_xfers_inflight == 0); //There cannot be any control transfer in-flight - assert(!dev_obj->dynamic.flags.waiting_free); //This can only be set when ref count reaches 0 + // Sanity check. + assert(dev_obj->dynamic.num_ctrl_xfers_inflight == 0); // There cannot be any control transfer in-flight + assert(!dev_obj->dynamic.flags.waiting_free); // This can only be set when ref count reaches 0 if (dev_obj->dynamic.flags.is_gone) { - //Device is already gone so it's port is already disabled. Trigger the USBH process to free the device + // Device is already gone so it's port is already disabled. Trigger the USBH process to free the device dev_obj->dynamic.flags.waiting_free = 1; - call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_FREE_AND_RECOVER); //Port error occurred so we need to recover it + call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_FREE_AND_RECOVER); // Port error occurred so we need to recover it } else if (dev_obj->dynamic.flags.waiting_close) { - //Device is still connected but is no longer needed. Trigger the USBH process to request device's port be disabled + // Device is still connected but is no longer needed. Trigger the USBH process to request device's port be disabled dev_obj->dynamic.flags.waiting_port_disable = 1; call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_PORT_DISABLE); } - //Else, there's nothing to do. Leave the device allocated + // Else, there's nothing to do. Leave the device allocated } USBH_EXIT_CRITICAL(); @@ -820,25 +820,25 @@ esp_err_t usbh_dev_mark_all_free(void) for (int i = 0; i < 2; i++) { device_t *dev_obj_cur; device_t *dev_obj_next; - //Go through pending list first as it's more efficient + // Go through pending list first as it's more efficient if (i == 0) { dev_obj_cur = TAILQ_FIRST(&p_usbh_obj->dynamic.devs_pending_tailq); } else { dev_obj_cur = TAILQ_FIRST(&p_usbh_obj->dynamic.devs_idle_tailq); } while (dev_obj_cur != NULL) { - assert(!dev_obj_cur->dynamic.flags.waiting_close); //Sanity check - //Keep a copy of the next item first in case we remove the current item + assert(!dev_obj_cur->dynamic.flags.waiting_close); // Sanity check + // Keep a copy of the next item first in case we remove the current item dev_obj_next = TAILQ_NEXT(dev_obj_cur, dynamic.tailq_entry); if (dev_obj_cur->dynamic.ref_count == 0 && !dev_obj_cur->dynamic.flags.is_gone) { - //Device is not opened as is not gone, so we can disable it now + // Device is not opened as is not gone, so we can disable it now dev_obj_cur->dynamic.flags.waiting_port_disable = 1; call_proc_req_cb |= _dev_set_actions(dev_obj_cur, DEV_ACTION_PORT_DISABLE); } else { - //Device is still opened. Just mark it as waiting to be closed + // Device is still opened. Just mark it as waiting to be closed dev_obj_cur->dynamic.flags.waiting_close = 1; } - wait_for_free = true; //As long as there is still a device, we need to wait for an event indicating it is freed + wait_for_free = true; // As long as there is still a device, we need to wait for an event indicating it is freed dev_obj_cur = dev_obj_next; } } @@ -871,21 +871,21 @@ esp_err_t usbh_dev_get_info(usb_device_handle_t dev_hdl, usb_device_info_t *dev_ device_t *dev_obj = (device_t *)dev_hdl; esp_err_t ret; - //Device must be configured, or not attached (if it suddenly disconnected) + // Device must be configured, or not attached (if it suddenly disconnected) USBH_ENTER_CRITICAL(); if (!(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED || dev_obj->dynamic.state == USB_DEVICE_STATE_NOT_ATTACHED)) { USBH_EXIT_CRITICAL(); ret = ESP_ERR_INVALID_STATE; goto exit; } - //Critical section for the dynamic members + // Critical section for the dynamic members dev_info->speed = dev_obj->constant.speed; dev_info->dev_addr = dev_obj->constant.address; dev_info->bMaxPacketSize0 = dev_obj->constant.desc->bMaxPacketSize0; USBH_EXIT_CRITICAL(); assert(dev_obj->constant.config_desc); dev_info->bConfigurationValue = dev_obj->constant.config_desc->bConfigurationValue; - //String descriptors are allowed to be NULL as not all devices support them + // String descriptors are allowed to be NULL as not all devices support them dev_info->str_desc_manufacturer = dev_obj->constant.str_desc_manu; dev_info->str_desc_product = dev_obj->constant.str_desc_product; dev_info->str_desc_serial_num = dev_obj->constant.str_desc_ser_num; @@ -913,7 +913,7 @@ esp_err_t usbh_dev_get_config_desc(usb_device_handle_t dev_hdl, const usb_config device_t *dev_obj = (device_t *)dev_hdl; esp_err_t ret; - //Device must be in the configured state + // Device must be in the configured state USBH_ENTER_CRITICAL(); if (dev_obj->dynamic.state != USB_DEVICE_STATE_CONFIGURED) { USBH_EXIT_CRITICAL(); @@ -938,7 +938,7 @@ esp_err_t usbh_dev_submit_ctrl_urb(usb_device_handle_t dev_hdl, urb_t *urb) USBH_ENTER_CRITICAL(); USBH_CHECK_FROM_CRIT(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED, ESP_ERR_INVALID_STATE); - //Increment the control transfer count first + // Increment the control transfer count first dev_obj->dynamic.num_ctrl_xfers_inflight++; USBH_EXIT_CRITICAL(); @@ -973,41 +973,41 @@ esp_err_t usbh_ep_alloc(usb_device_handle_t dev_hdl, usbh_ep_config_t *ep_config device_t *dev_obj = (device_t *)dev_hdl; endpoint_t *ep_obj; - //Find the endpoint descriptor from the device's current configuration descriptor + // Find the endpoint descriptor from the device's current configuration descriptor const usb_ep_desc_t *ep_desc = usb_parse_endpoint_descriptor_by_address(dev_obj->constant.config_desc, ep_config->bInterfaceNumber, ep_config->bAlternateSetting, ep_config->bEndpointAddress, NULL); if (ep_desc == NULL) { return ESP_ERR_NOT_FOUND; } - //Allocate the endpoint object + // Allocate the endpoint object ret = endpoint_alloc(dev_obj, ep_desc, ep_config, &ep_obj); if (ret != ESP_OK) { goto alloc_err; } - //We need to take the mux_lock to access mux_protected members + // We need to take the mux_lock to access mux_protected members xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); USBH_ENTER_CRITICAL(); - //Check the device's state before we assign the a pipe to the allocated endpoint + // Check the device's state before we assign the a pipe to the allocated endpoint if (dev_obj->dynamic.state != USB_DEVICE_STATE_CONFIGURED) { USBH_EXIT_CRITICAL(); ret = ESP_ERR_INVALID_STATE; goto dev_state_err; } USBH_EXIT_CRITICAL(); - //Check if the endpoint has already been allocated + // Check if the endpoint has already been allocated if (get_ep_from_addr(dev_obj, bEndpointAddress) == NULL) { set_ep_from_addr(dev_obj, bEndpointAddress, ep_obj); - //Write back the endpoint handle + // Write back the endpoint handle *ep_hdl_ret = (usbh_ep_handle_t)ep_obj; ret = ESP_OK; } else { - //Endpoint is already allocated + // Endpoint is already allocated ret = ESP_ERR_INVALID_STATE; } dev_state_err: xSemaphoreGive(p_usbh_obj->constant.mux_lock); - //If the endpoint was not assigned, free it + // If the endpoint was not assigned, free it if (ret != ESP_OK) { endpoint_free(ep_obj); } @@ -1024,18 +1024,18 @@ esp_err_t usbh_ep_free(usbh_ep_handle_t ep_hdl) device_t *dev_obj = (device_t *)ep_obj->constant.dev; uint8_t bEndpointAddress = ep_obj->constant.ep_desc->bEndpointAddress; - //Todo: Check that the EP's underlying pipe is halted before allowing the EP to be freed (IDF-7273) - //Check that the the EP's underlying pipe has no more in-flight URBs + // Todo: Check that the EP's underlying pipe is halted before allowing the EP to be freed (IDF-7273) + // Check that the the EP's underlying pipe has no more in-flight URBs if (hcd_pipe_get_num_urbs(ep_obj->constant.pipe_hdl) != 0) { ret = ESP_ERR_INVALID_STATE; goto exit; } - //We need to take the mux_lock to access mux_protected members + // We need to take the mux_lock to access mux_protected members xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); - //Check if the endpoint was allocated on this device + // Check if the endpoint was allocated on this device if (ep_obj == get_ep_from_addr(dev_obj, bEndpointAddress)) { - //Clear the endpoint from the device's endpoint object list + // Clear the endpoint from the device's endpoint object list set_ep_from_addr(dev_obj, bEndpointAddress, NULL); ret = ESP_OK; } else { @@ -1043,7 +1043,7 @@ esp_err_t usbh_ep_free(usbh_ep_handle_t ep_hdl) } xSemaphoreGive(p_usbh_obj->constant.mux_lock); - //Finally, we free the endpoint object + // Finally, we free the endpoint object if (ret == ESP_OK) { endpoint_free(ep_obj); } @@ -1060,7 +1060,7 @@ esp_err_t usbh_ep_get_handle(usb_device_handle_t dev_hdl, uint8_t bEndpointAddre device_t *dev_obj = (device_t *)dev_hdl; endpoint_t *ep_obj; - //We need to take the mux_lock to access mux_protected members + // We need to take the mux_lock to access mux_protected members xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); ep_obj = get_ep_from_addr(dev_obj, bEndpointAddress); xSemaphoreGive(p_usbh_obj->constant.mux_lock); @@ -1083,11 +1083,11 @@ esp_err_t usbh_ep_enqueue_urb(usbh_ep_handle_t ep_hdl, urb_t *urb) */ endpoint_t *ep_obj = (endpoint_t *)ep_hdl; - //Check that the EP's underlying pipe is in the active state before submitting the URB + // Check that the EP's underlying pipe is in the active state before submitting the URB if (hcd_pipe_get_state(ep_obj->constant.pipe_hdl) != HCD_PIPE_STATE_ACTIVE) { return ESP_ERR_INVALID_STATE; } - //Enqueue the URB to the EP's underlying pipe + // Enqueue the URB to the EP's underlying pipe return hcd_urb_enqueue(ep_obj->constant.pipe_hdl, urb); } @@ -1096,7 +1096,7 @@ esp_err_t usbh_ep_dequeue_urb(usbh_ep_handle_t ep_hdl, urb_t **urb_ret) USBH_CHECK(ep_hdl != NULL && urb_ret != NULL, ESP_ERR_INVALID_ARG); endpoint_t *ep_obj = (endpoint_t *)ep_hdl; - //Enqueue the URB to the EP's underlying pipe + // Enqueue the URB to the EP's underlying pipe *urb_ret = hcd_urb_dequeue(ep_obj->constant.pipe_hdl); return ESP_OK; } @@ -1106,7 +1106,7 @@ esp_err_t usbh_ep_command(usbh_ep_handle_t ep_hdl, usbh_ep_cmd_t command) USBH_CHECK(ep_hdl != NULL, ESP_ERR_INVALID_ARG); endpoint_t *ep_obj = (endpoint_t *)ep_hdl; - //Send the command to the EP's underlying pipe + // Send the command to the EP's underlying pipe return hcd_pipe_command(ep_obj->constant.pipe_hdl, (hcd_pipe_cmd_t)command); } @@ -1126,9 +1126,9 @@ esp_err_t usbh_hub_is_installed(usbh_hub_req_cb_t hub_req_callback, void *callba USBH_CHECK(hub_req_callback != NULL, ESP_ERR_INVALID_ARG); USBH_ENTER_CRITICAL(); - //Check that USBH is already installed + // Check that USBH is already installed USBH_CHECK_FROM_CRIT(p_usbh_obj != NULL, ESP_ERR_INVALID_STATE); - //Check that Hub has not be installed yet + // Check that Hub has not be installed yet USBH_CHECK_FROM_CRIT(p_usbh_obj->constant.hub_req_cb == NULL, ESP_ERR_INVALID_STATE); p_usbh_obj->constant.hub_req_cb = hub_req_callback; p_usbh_obj->constant.hub_req_cb_arg = callback_arg; @@ -1139,7 +1139,7 @@ esp_err_t usbh_hub_is_installed(usbh_hub_req_cb_t hub_req_callback, void *callba esp_err_t usbh_hub_add_dev(hcd_port_handle_t port_hdl, usb_speed_t dev_speed, usb_device_handle_t *new_dev_hdl, hcd_pipe_handle_t *default_pipe_hdl) { - //Note: Parent device handle can be NULL if it's connected to the root hub + // Note: Parent device handle can be NULL if it's connected to the root hub USBH_CHECK(new_dev_hdl != NULL, ESP_ERR_INVALID_ARG); esp_err_t ret; device_t *dev_obj; @@ -1147,7 +1147,7 @@ esp_err_t usbh_hub_add_dev(hcd_port_handle_t port_hdl, usb_speed_t dev_speed, us if (ret != ESP_OK) { return ret; } - //Write-back device handle + // Write-back device handle *new_dev_hdl = (usb_device_handle_t)dev_obj; *default_pipe_hdl = dev_obj->constant.default_pipe; ret = ESP_OK; @@ -1161,34 +1161,34 @@ esp_err_t usbh_hub_pass_event(usb_device_handle_t dev_hdl, usbh_hub_event_t hub_ bool call_proc_req_cb; switch (hub_event) { - case USBH_HUB_EVENT_PORT_ERROR: { - USBH_ENTER_CRITICAL(); - dev_obj->dynamic.flags.is_gone = 1; - //Check if the device can be freed now - if (dev_obj->dynamic.ref_count == 0) { - dev_obj->dynamic.flags.waiting_free = 1; - //Device is already waiting free so none of it's EP's will be in use. Can free immediately. - call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_FREE_AND_RECOVER); //Port error occurred so we need to recover it - } else { - call_proc_req_cb = _dev_set_actions(dev_obj, - DEV_ACTION_EPn_HALT_FLUSH | - DEV_ACTION_EP0_FLUSH | - DEV_ACTION_EP0_DEQUEUE | - DEV_ACTION_PROP_GONE_EVT); - } - USBH_EXIT_CRITICAL(); - break; - } - case USBH_HUB_EVENT_PORT_DISABLED: { - USBH_ENTER_CRITICAL(); - assert(dev_obj->dynamic.ref_count == 0); //At this stage, the device should have been closed by all users + case USBH_HUB_EVENT_PORT_ERROR: { + USBH_ENTER_CRITICAL(); + dev_obj->dynamic.flags.is_gone = 1; + // Check if the device can be freed now + if (dev_obj->dynamic.ref_count == 0) { dev_obj->dynamic.flags.waiting_free = 1; - call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_FREE); - USBH_EXIT_CRITICAL(); - break; + // Device is already waiting free so none of it's EP's will be in use. Can free immediately. + call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_FREE_AND_RECOVER); // Port error occurred so we need to recover it + } else { + call_proc_req_cb = _dev_set_actions(dev_obj, + DEV_ACTION_EPn_HALT_FLUSH | + DEV_ACTION_EP0_FLUSH | + DEV_ACTION_EP0_DEQUEUE | + DEV_ACTION_PROP_GONE_EVT); } - default: - return ESP_ERR_INVALID_ARG; + USBH_EXIT_CRITICAL(); + break; + } + case USBH_HUB_EVENT_PORT_DISABLED: { + USBH_ENTER_CRITICAL(); + assert(dev_obj->dynamic.ref_count == 0); // At this stage, the device should have been closed by all users + dev_obj->dynamic.flags.waiting_free = 1; + call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_FREE); + USBH_EXIT_CRITICAL(); + break; + } + default: + return ESP_ERR_INVALID_ARG; } if (call_proc_req_cb) { @@ -1208,7 +1208,7 @@ esp_err_t usbh_hub_enum_fill_dev_addr(usb_device_handle_t dev_hdl, uint8_t dev_a dev_obj->dynamic.state = USB_DEVICE_STATE_ADDRESS; USBH_EXIT_CRITICAL(); - //We can modify the info members outside the critical section + // We can modify the info members outside the critical section dev_obj->constant.address = dev_addr; return ESP_OK; } @@ -1217,7 +1217,7 @@ esp_err_t usbh_hub_enum_fill_dev_desc(usb_device_handle_t dev_hdl, const usb_dev { USBH_CHECK(dev_hdl != NULL && device_desc != NULL, ESP_ERR_INVALID_ARG); device_t *dev_obj = (device_t *)dev_hdl; - //We can modify the info members outside the critical section + // We can modify the info members outside the critical section memcpy((usb_device_desc_t *)dev_obj->constant.desc, device_desc, sizeof(usb_device_desc_t)); return ESP_OK; } @@ -1226,14 +1226,14 @@ esp_err_t usbh_hub_enum_fill_config_desc(usb_device_handle_t dev_hdl, const usb_ { USBH_CHECK(dev_hdl != NULL && config_desc_full != NULL, ESP_ERR_INVALID_ARG); device_t *dev_obj = (device_t *)dev_hdl; - //Allocate memory to store the configuration descriptor - usb_config_desc_t *config_desc = heap_caps_malloc(config_desc_full->wTotalLength, MALLOC_CAP_DEFAULT); //Buffer to copy over full configuration descriptor (wTotalLength) + // Allocate memory to store the configuration descriptor + usb_config_desc_t *config_desc = heap_caps_malloc(config_desc_full->wTotalLength, MALLOC_CAP_DEFAULT); // Buffer to copy over full configuration descriptor (wTotalLength) if (config_desc == NULL) { return ESP_ERR_NO_MEM; } - //Copy the configuration descriptor + // Copy the configuration descriptor memcpy(config_desc, config_desc_full, config_desc_full->wTotalLength); - //Assign the config desc to the device object + // Assign the config desc to the device object assert(dev_obj->constant.config_desc == NULL); dev_obj->constant.config_desc = config_desc; return ESP_OK; @@ -1243,27 +1243,27 @@ esp_err_t usbh_hub_enum_fill_str_desc(usb_device_handle_t dev_hdl, const usb_str { USBH_CHECK(dev_hdl != NULL && str_desc != NULL && (select >= 0 && select < 3), ESP_ERR_INVALID_ARG); device_t *dev_obj = (device_t *)dev_hdl; - //Allocate memory to store the manufacturer string descriptor + // Allocate memory to store the manufacturer string descriptor usb_str_desc_t *str_desc_fill = heap_caps_malloc(str_desc->bLength, MALLOC_CAP_DEFAULT); if (str_desc_fill == NULL) { return ESP_ERR_NO_MEM; } - //Copy the string descriptor + // Copy the string descriptor memcpy(str_desc_fill, str_desc, str_desc->bLength); - //Assign filled string descriptor to the device object + // Assign filled string descriptor to the device object switch (select) { - case 0: - assert(dev_obj->constant.str_desc_manu == NULL); - dev_obj->constant.str_desc_manu = str_desc_fill; - break; - case 1: - assert(dev_obj->constant.str_desc_product == NULL); - dev_obj->constant.str_desc_product = str_desc_fill; - break; - default: //2 - assert(dev_obj->constant.str_desc_ser_num == NULL); - dev_obj->constant.str_desc_ser_num = str_desc_fill; - break; + case 0: + assert(dev_obj->constant.str_desc_manu == NULL); + dev_obj->constant.str_desc_manu = str_desc_fill; + break; + case 1: + assert(dev_obj->constant.str_desc_product == NULL); + dev_obj->constant.str_desc_product = str_desc_fill; + break; + default: // 2 + assert(dev_obj->constant.str_desc_ser_num == NULL); + dev_obj->constant.str_desc_ser_num = str_desc_fill; + break; } return ESP_OK; } @@ -1273,20 +1273,20 @@ esp_err_t usbh_hub_enum_done(usb_device_handle_t dev_hdl) USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG); device_t *dev_obj = (device_t *)dev_hdl; - //We need to take the mux_lock to access mux_protected members + // We need to take the mux_lock to access mux_protected members xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); USBH_ENTER_CRITICAL(); dev_obj->dynamic.state = USB_DEVICE_STATE_CONFIGURED; - //Add the device to list of devices, then trigger a device event - TAILQ_INSERT_TAIL(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry); //Add it to the idle device list first + // Add the device to list of devices, then trigger a device event + TAILQ_INSERT_TAIL(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry); // Add it to the idle device list first bool call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_PROP_NEW); USBH_EXIT_CRITICAL(); p_usbh_obj->mux_protected.num_device++; xSemaphoreGive(p_usbh_obj->constant.mux_lock); - //Update the EP0's underlying pipe's callback + // Update the EP0's underlying pipe's callback ESP_ERROR_CHECK(hcd_pipe_update_callback(dev_obj->constant.default_pipe, ep0_pipe_callback, (void *)dev_obj)); - //Call the processing request callback + // 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); }