diff --git a/components/usb/hcd.c b/components/usb/hcd.c index 8e2f17c5f7..d4c26d8a92 100644 --- a/components/usb/hcd.c +++ b/components/usb/hcd.c @@ -28,8 +28,9 @@ #include "soc/gpio_pins.h" #include "soc/gpio_sig_map.h" #include "driver/periph_ctrl.h" -#include "usb.h" #include "hcd.h" +#include "usb_private.h" +#include "usb.h" // ----------------------------------------------------- Macros -------------------------------------------------------- @@ -150,18 +151,18 @@ const fifo_mps_limits_t mps_limits_bias_ptx = { // ------------------------ Flags -------------------------- /** - * @brief Bit masks for the HCD to use in the IRPs reserved_flags field + * @brief Bit masks for the HCD to use in the URBs reserved_flags field * - * The IRP 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 IRP within the HCD. + * 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 IRP_STATE_IDLE 0x0 //The IRP is not enqueued in an HCD pipe -#define IRP_STATE_PENDING 0x1 //The IRP is enqueued and pending execution -#define IRP_STATE_INFLIGHT 0x2 //The IRP is currently in flight -#define IRP_STATE_DONE 0x3 //The IRP has completed execution or is retired, and is waiting to be dequeued -#define IRP_STATE_MASK 0x3 //Bit mask of all the IRP state flags -#define IRP_STATE_SET(reserved_flags, state) (reserved_flags = (reserved_flags & ~IRP_STATE_MASK) | state) -#define IRP_STATE_GET(reserved_flags) (reserved_flags & IRP_STATE_MASK) +#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) // -------------------- Convenience ------------------------ @@ -192,7 +193,7 @@ typedef struct port_obj port_t; */ typedef struct { void *xfer_desc_list; - usb_irp_t *irp; + urb_t *urb; union { struct { uint32_t data_stg_in: 1; //Data stage of the control transfer is IN @@ -211,8 +212,8 @@ typedef struct { 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 irp_start_idx: 8; //Index of the first transfer descriptor in the list - uint32_t next_irp_start_idx: 8; //Index for the first descriptor of the next buffer + 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; @@ -234,11 +235,11 @@ typedef struct { * @brief Object representing a pipe in the HCD layer */ struct pipe_obj { - //IRP queueing related - TAILQ_HEAD(tailhead_irp_pending, usb_irp_obj) pending_irp_tailq; - TAILQ_HEAD(tailhead_irp_done, usb_irp_obj) done_irp_tailq; - int num_irp_pending; - int num_irp_done; + //URB queueing related + TAILQ_HEAD(tailhead_urb_pending, urb_obj) pending_urb_tailq; + TAILQ_HEAD(tailhead_urb_done, urb_obj) done_urb_tailq; + int num_urb_pending; + int num_urb_done; //Multi-buffer control dma_buffer_block_t *buffers[NUM_BUFFERS]; //Double buffering scheme union { @@ -276,7 +277,7 @@ struct pipe_obj { uint32_t val; } cs_flags; //Pipe callback and context - hcd_pipe_isr_callback_t callback; + hcd_pipe_callback_t callback; void *callback_arg; void *context; }; @@ -304,9 +305,9 @@ struct port_obj { uint32_t cmd_processing: 1; //Used to indicate command handling is ongoing uint32_t waiting_all_pipes_pause: 1; //Waiting for all pipes routed through this port to be paused uint32_t disable_requested: 1; - uint32_t conn_devc_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 reserved9: 9; + uint32_t reserved9:9; uint32_t num_pipes_waiting_pause: 16; }; uint32_t val; @@ -314,7 +315,7 @@ struct port_obj { bool initialized; hcd_port_fifo_bias_t fifo_bias; //Port callback and context - hcd_port_isr_callback_t callback; + hcd_port_callback_t callback; void *callback_arg; SemaphoreHandle_t port_mux; void *context; @@ -337,16 +338,16 @@ static hcd_obj_t *s_hcd_obj = NULL; //Note: "s_" is for the static pointer // ------------------- Buffer Control ---------------------- /** - * @brief Check if an inactive buffer can be filled with a pending IRP + * @brief Check if an inactive buffer can be filled with a pending URB * * @param pipe Pipe object - * @return true There are one or more pending IRPs, and the inactive buffer is yet to be filled + * @return true There are one or more pending URBs, and the inactive buffer is yet to be filled * @return false Otherwise */ static inline bool _buffer_can_fill(pipe_t *pipe) { - //We can only fill if there are pending IRPs and at least one unfilled buffer - if (pipe->num_irp_pending > 0 && pipe->multi_buffer_control.buffer_num_to_fill > 0) { + //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 { return false; @@ -357,8 +358,8 @@ static inline bool _buffer_can_fill(pipe_t *pipe) * @brief Fill an empty buffer with * * This function will: - * - Remove an IRP from the pending tailq - * - Fill that IRP into the inactive buffer + * - Remove an URB from the pending tailq + * - Fill that URB into the inactive buffer * * @note _buffer_can_fill() must return true before calling this function * @@ -473,13 +474,13 @@ static inline bool _buffer_can_parse(pipe_t *pipe) * @brief Parse a completed buffer * * This function will: - * - Parse the results of an IRP from a completed buffer - * - Put the IRP into the done tailq + * - Parse the results of an URB from a completed buffer + * - Put the URB into the done tailq * * @note This function should only be called on the completion of a buffer * * @param pipe Pipe object - * @param stop_idx (For INTR pipes only) The index of the descriptor that follows the last descriptor of the IRP. Set to 0 otherwise + * @param stop_idx (For INTR pipes only) The index of the descriptor that follows the last descriptor of the URB. Set to 0 otherwise */ static void _buffer_parse(pipe_t *pipe); @@ -496,10 +497,10 @@ static void _buffer_flush_all(pipe_t *pipe, bool cancelled); // ------------------------ Pipe --------------------------- /** - * @brief Wait until a pipe's in-flight IRP is done + * @brief Wait until a pipe's in-flight URB is done * - * If the pipe has an in-flight IRP, this function will block until it is done (via a internal pipe event). - * If the pipe has no in-flight IRP, this function do nothing and return immediately. + * If the pipe has an in-flight URB, this function will block until it is done (via a internal pipe event). + * If the pipe has no in-flight URB, this function do nothing and return immediately. * If the pipe's state changes unexpectedly, this function will return false. * * Also parses all buffers on exit @@ -507,29 +508,29 @@ static void _buffer_flush_all(pipe_t *pipe, bool cancelled); * @note This function is blocking (will exit and re-enter the critical section to do so) * * @param pipe Pipe object - * @return true Pipes in-flight IRP is done + * @return true Pipes in-flight URB is done * @return false Pipes state unexpectedly changed */ static bool _pipe_wait_done(pipe_t *pipe); /** - * @brief Retires all IRPs (those that were previously in-flight or pending) + * @brief Retires all URBs (those that were previously in-flight or pending) * - * Retiring all IRPs will result in any pending IRP being moved to the done tailq. This function will update the IPR - * status of each IRP. - * - If the retiring is self-initiated (i.e., due to a pipe command), the IRP status will be set to USB_TRANSFER_STATUS_CANCELED. - * - If the retiring is NOT self-initiated (i.e., the pipe is no longer valid), the IRP status will be set to USB_TRANSFER_STATUS_NO_DEVICE + * Retiring all URBs will result in any pending URB being moved to the done tailq. This function will update the IPR + * status of each URB. + * - If the retiring is self-initiated (i.e., due to a pipe command), the URB status will be set to USB_TRANSFER_STATUS_CANCELED. + * - If the retiring is NOT self-initiated (i.e., the pipe is no longer valid), the URB status will be set to USB_TRANSFER_STATUS_NO_DEVICE * * Entry: - * - There can be no in-flight IRP (must already be parsed and returned to done queue) + * - There can be no in-flight URB (must already be parsed and returned to done queue) * - All buffers must be parsed * Exit: - * - If there was an in-flight IRP, it is parsed and returned to the done queue - * - If there are any pending IRPs: + * - If there was an in-flight URB, it is parsed and returned to the done queue + * - If there are any pending URBs: * - They are moved to the done tailq * * @param pipe Pipe object - * @param cancelled Are we actively Pipe retire is initialized by the user due to a command, thus IRP are + * @param cancelled Are we actively Pipe retire is initialized by the user due to a command, thus URB are * actively cancelled. */ static void _pipe_retire(pipe_t *pipe, bool self_initiated); @@ -555,7 +556,7 @@ static inline hcd_pipe_event_t pipe_decode_error_event(usbh_hal_chan_error_t cha * Entry: * - The port or its connected device is no longer valid. This guarantees that none of the pipes will be transferring * Exit: - * - Each pipe will have any pending IRPs moved to their respective done tailq + * - Each pipe will have any pending URBs moved to their respective done tailq * - Each pipe will be put into the invalid state * - Generate a HCD_PIPE_EVENT_INVALID event on each pipe and run their respective callbacks * @@ -571,7 +572,7 @@ static void _port_invalidate_all_pipes(port_t *port); * Entry: * - The port is in the HCD_PORT_STATE_ENABLED state (i.e., there is a connected device which has been reset) * Exit: - * - All pipes routed through the port have either paused, or are waiting to complete their in-flight IRPs before pausing + * - All pipes routed through the port have either paused, or are waiting to complete their in-flight URBs before pausing * - If waiting for one or more pipes to pause, _internal_port_event_wait() must be called after this function returns * * @param port Port object @@ -589,7 +590,7 @@ static bool _port_pause_all_pipes(port_t *port); * - The port is in the HCD_PORT_STATE_ENABLED state * - All pipes are paused * Exit: - * - All pipes un-paused. If those pipes have pending IRPs, they will be started. + * - All pipes un-paused. If those pipes have pending URBs, they will be started. * * @param port Port object */ @@ -797,7 +798,7 @@ static hcd_port_event_t _intr_hdlr_hprt(port_t *port, usbh_hal_port_event_t hal_ break; } case USBH_HAL_PORT_EVENT_DISCONN: { - if (port->flags.conn_devc_ena) { + if (port->flags.conn_dev_ena) { //The port was previously enabled, so this is a sudden disconnection port->state = HCD_PORT_STATE_RECOVERY; port_event = HCD_PORT_EVENT_SUDDEN_DISCONN; @@ -805,19 +806,19 @@ static hcd_port_event_t _intr_hdlr_hprt(port_t *port, usbh_hal_port_event_t hal_ //For normal disconnections, don't update state immediately as we still need to debounce. port_event = HCD_PORT_EVENT_DISCONNECTION; } - port->flags.conn_devc_ena = 0; + port->flags.conn_dev_ena = 0; break; } case USBH_HAL_PORT_EVENT_ENABLED: { usbh_hal_port_enable(port->hal); //Initialize remaining host port registers port->speed = (usbh_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_devc_ena = 1; + port->flags.conn_dev_ena = 1; //This was triggered by a command, so no event needs to be propagated. break; } case USBH_HAL_PORT_EVENT_DISABLED: { - port->flags.conn_devc_ena = 0; + 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 port->state = HCD_PORT_STATE_DISABLED; @@ -840,7 +841,7 @@ static hcd_port_event_t _intr_hdlr_hprt(port_t *port, usbh_hal_port_event_t hal_ port->state = HCD_PORT_STATE_NOT_POWERED; port_event = HCD_PORT_EVENT_OVERCURRENT; } - port->flags.conn_devc_ena = 0; + port->flags.conn_dev_ena = 0; break; } default: { @@ -867,7 +868,7 @@ static hcd_pipe_event_t _intr_hdlr_chan(pipe_t *pipe, usbh_hal_chan_t *chan_obj, usbh_hal_chan_event_t chan_event = usbh_hal_chan_decode_intr(chan_obj); hcd_pipe_event_t event = HCD_PIPE_EVENT_NONE; //Check the the pipe's port still has a connected and enabled device before processing the interrupt - if (!pipe->port->flags.conn_devc_ena) { + if (!pipe->port->flags.conn_dev_ena) { return event; //Treat as a no event. } bool handle_waiting_xfer_done = false; @@ -876,7 +877,7 @@ static hcd_pipe_event_t _intr_hdlr_chan(pipe_t *pipe, usbh_hal_chan_t *chan_obj, if (!_buffer_check_done(pipe)) { break; } - pipe->last_event = HCD_PIPE_EVENT_IRP_DONE; + pipe->last_event = HCD_PIPE_EVENT_URB_DONE; event = pipe->last_event; //Mark the buffer as done int stop_idx = usbh_hal_chan_get_qtd_idx(chan_obj); @@ -891,7 +892,7 @@ static hcd_pipe_event_t _intr_hdlr_chan(pipe_t *pipe, usbh_hal_chan_t *chan_obj, if (pipe->cs_flags.waiting_xfer_done) { handle_waiting_xfer_done = true; } else if (_buffer_can_fill(pipe)) { - //Now that we've parsed a buffer, see if another IRP can be filled in its place + //Now that we've parsed a buffer, see if another URB can be filled in its place _buffer_fill(pipe); } break; @@ -1117,16 +1118,16 @@ esp_err_t hcd_uninstall(void) static void _port_invalidate_all_pipes(port_t *port) { //This function should only be called when the port is invalid - assert(!port->flags.conn_devc_ena); + assert(!port->flags.conn_dev_ena); pipe_t *pipe; - //Process all pipes that have queued IRPs + //Process all pipes that have queued URBs TAILQ_FOREACH(pipe, &port->pipes_active_tailq, tailq_entry) { //Mark the pipe as invalid and set an invalid event pipe->state = HCD_PIPE_STATE_INVALID; pipe->last_event = HCD_PIPE_EVENT_INVALID; //Flush all buffers that are still awaiting exec _buffer_flush_all(pipe, false); - //Retire any remaining IRPs in the pending tailq + //Retire any remaining URBs in the pending tailq _pipe_retire(pipe, false); if (pipe->task_waiting_pipe_notif != NULL) { //Unblock the thread/task waiting for a notification from the pipe as the pipe is no longer valid. @@ -1156,7 +1157,7 @@ static bool _port_pause_all_pipes(port_t *port) assert(port->state == HCD_PORT_STATE_ENABLED); pipe_t *pipe; int num_pipes_waiting_done = 0; - //Process all pipes that have queued IRPs + //Process all pipes that have queued URBs TAILQ_FOREACH(pipe, &port->pipes_active_tailq, tailq_entry) { //Check if pipe is currently executing if (pipe->multi_buffer_control.buffer_is_executing) { @@ -1189,7 +1190,7 @@ static void _port_unpause_all_pipes(port_t *port) TAILQ_FOREACH(pipe, &port->pipes_idle_tailq, tailq_entry) { pipe->cs_flags.paused = 0; } - //Process all pipes that have queued IRPs + //Process all pipes that have queued URBs TAILQ_FOREACH(pipe, &port->pipes_active_tailq, tailq_entry) { pipe->cs_flags.paused = 0; if (_buffer_can_fill(pipe)) { @@ -1219,7 +1220,7 @@ static bool _port_bus_reset(port_t *port) HCD_EXIT_CRITICAL(); vTaskDelay(pdMS_TO_TICKS(RESET_RECOVERY_MS)); HCD_ENTER_CRITICAL(); - if (port->state != HCD_PORT_STATE_ENABLED || !port->flags.conn_devc_ena) { + if (port->state != HCD_PORT_STATE_ENABLED || !port->flags.conn_dev_ena) { //The port state has unexpectedly changed goto bailout; } @@ -1235,7 +1236,7 @@ static bool _port_bus_suspend(port_t *port) if (!_port_pause_all_pipes(port)) { //Need to wait for some pipes to pause. Wait for notification from ISR _internal_port_event_wait(port); - if (port->state != HCD_PORT_STATE_ENABLED || !port->flags.conn_devc_ena) { + if (port->state != HCD_PORT_STATE_ENABLED || !port->flags.conn_dev_ena) { //Port state unexpectedly changed goto bailout; } @@ -1259,14 +1260,14 @@ static bool _port_bus_resume(port_t *port) HCD_ENTER_CRITICAL(); //Return and hold the bus to the J state (as port of the LS EOP) usbh_hal_port_toggle_resume(port->hal, false); - if (port->state != HCD_PORT_STATE_RESUMING || !port->flags.conn_devc_ena) { + if (port->state != HCD_PORT_STATE_RESUMING || !port->flags.conn_dev_ena) { //Port state unexpectedly changed goto bailout; } HCD_EXIT_CRITICAL(); vTaskDelay(pdMS_TO_TICKS(RESUME_RECOVERY_MS)); HCD_ENTER_CRITICAL(); - if (port->state != HCD_PORT_STATE_RESUMING || !port->flags.conn_devc_ena) { + if (port->state != HCD_PORT_STATE_RESUMING || !port->flags.conn_dev_ena) { //Port state unexpectedly changed goto bailout; } @@ -1285,7 +1286,7 @@ static bool _port_disable(port_t *port) if (!_port_pause_all_pipes(port)) { //Need to wait for some pipes to pause. Wait for notification from ISR _internal_port_event_wait(port); - if (port->state != HCD_PORT_STATE_ENABLED || !port->flags.conn_devc_ena) { + if (port->state != HCD_PORT_STATE_ENABLED || !port->flags.conn_dev_ena) { //Port state unexpectedly changed goto bailout; } @@ -1328,7 +1329,7 @@ static bool _port_debounce(port_t *port) // ----------------------- Public -------------------------- -esp_err_t hcd_port_init(int port_number, hcd_port_config_t *port_config, hcd_port_handle_t *port_hdl) +esp_err_t hcd_port_init(int port_number, const hcd_port_config_t *port_config, hcd_port_handle_t *port_hdl) { 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); @@ -1465,7 +1466,7 @@ esp_err_t hcd_port_get_speed(hcd_port_handle_t port_hdl, usb_speed_t *speed) 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 - HCD_CHECK_FROM_CRIT(port->flags.conn_devc_ena, ESP_ERR_INVALID_STATE); + HCD_CHECK_FROM_CRIT(port->flags.conn_dev_ena, ESP_ERR_INVALID_STATE); usb_priv_speed_t hal_speed = usbh_hal_port_get_conn_speed(port->hal); if (hal_speed == USB_PRIV_SPEED_FULL) { *speed = USB_SPEED_FULL; @@ -1613,19 +1614,19 @@ static void _pipe_retire(pipe_t *pipe, bool self_initiated) { //Cannot have a currently executing buffer assert(!pipe->multi_buffer_control.buffer_is_executing); - if (pipe->num_irp_pending > 0) { - //Process all remaining pending IRPs - usb_irp_t *irp; - TAILQ_FOREACH(irp, &pipe->pending_irp_tailq, tailq_entry) { - //Update the IRP's current state - IRP_STATE_SET(irp->reserved_flags, IRP_STATE_DONE); - //If we are initiating the retire, mark the IRP as canceled - irp->status = (self_initiated) ? USB_TRANSFER_STATUS_CANCELED : USB_TRANSFER_STATUS_NO_DEVICE; + if (pipe->num_urb_pending > 0) { + //Process all remaining pending URBs + urb_t *urb; + TAILQ_FOREACH(urb, &pipe->pending_urb_tailq, tailq_entry) { + //Update the URB's current state + urb->hcd_var = URB_HCD_STATE_DONE; + //If we are initiating the retire, mark the URB as canceled + urb->transfer.status = (self_initiated) ? USB_TRANSFER_STATUS_CANCELED : USB_TRANSFER_STATUS_NO_DEVICE; } //Concatenated pending tailq to the done tailq - TAILQ_CONCAT(&pipe->done_irp_tailq, &pipe->pending_irp_tailq, tailq_entry); - pipe->num_irp_done += pipe->num_irp_pending; - pipe->num_irp_pending = 0; + 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; } } @@ -1637,7 +1638,7 @@ static inline hcd_pipe_event_t pipe_decode_error_event(usbh_hal_chan_error_t cha event = HCD_PIPE_EVENT_ERROR_XFER; break; case USBH_HAL_CHAN_ERROR_BNA: - event = HCD_PIPE_EVENT_ERROR_IRP_NOT_AVAIL; + event = HCD_PIPE_EVENT_ERROR_URB_NOT_AVAIL; break; case USBH_HAL_CHAN_ERROR_PKT_BBL: event = HCD_PIPE_EVENT_ERROR_OVERFLOW; @@ -1806,7 +1807,7 @@ esp_err_t hcd_pipe_alloc(hcd_port_handle_t port_hdl, const hcd_pipe_config_t *pi 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 - HCD_CHECK_FROM_CRIT(port->initialized && port->flags.conn_devc_ena, ESP_ERR_INVALID_STATE); + HCD_CHECK_FROM_CRIT(port->initialized && port->flags.conn_dev_ena, ESP_ERR_INVALID_STATE); usb_speed_t port_speed = port->speed; hcd_port_fifo_bias_t port_fifo_bias = port->fifo_bias; int pipe_idx = port->num_pipes_idle + port->num_pipes_queued; @@ -1844,8 +1845,8 @@ esp_err_t hcd_pipe_alloc(hcd_port_handle_t port_hdl, const hcd_pipe_config_t *pi } //Initialize pipe object - TAILQ_INIT(&pipe->pending_irp_tailq); - TAILQ_INIT(&pipe->done_irp_tailq); + TAILQ_INIT(&pipe->pending_urb_tailq); + TAILQ_INIT(&pipe->done_urb_tailq); for (int i = 0; i < NUM_BUFFERS; i++) { pipe->buffers[i] = buffers[i]; } @@ -1862,7 +1863,7 @@ esp_err_t hcd_pipe_alloc(hcd_port_handle_t port_hdl, const hcd_pipe_config_t *pi //Allocate channel HCD_ENTER_CRITICAL(); - if (!port->initialized || !port->flags.conn_devc_ena) { + if (!port->initialized || !port->flags.conn_dev_ena) { HCD_EXIT_CRITICAL(); ret = ESP_ERR_INVALID_STATE; goto err; @@ -1895,14 +1896,14 @@ 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 IRPs 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->multi_buffer_control.buffer_num_to_parse == 0 && pipe->multi_buffer_control.buffer_num_to_exec == 0 - && pipe->num_irp_pending == 0 - && pipe->num_irp_done == 0, + && pipe->num_urb_pending == 0 + && pipe->num_urb_done == 0, 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 IRPs) + //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--; usbh_hal_chan_free(pipe->port->hal, pipe->chan_obj); @@ -1924,8 +1925,8 @@ esp_err_t hcd_pipe_update_mps(hcd_pipe_handle_t pipe_hdl, int mps) //Check if pipe is in the correct state to be updated HCD_CHECK_FROM_CRIT(pipe->state != HCD_PIPE_STATE_INVALID && !pipe->cs_flags.pipe_cmd_processing - && pipe->num_irp_pending == 0 - && pipe->num_irp_done == 0, + && pipe->num_urb_pending == 0 + && pipe->num_urb_done == 0, ESP_ERR_INVALID_STATE); pipe->ep_char.mps = mps; //Update the underlying channel's registers @@ -1941,8 +1942,8 @@ esp_err_t hcd_pipe_update_dev_addr(hcd_pipe_handle_t pipe_hdl, uint8_t dev_addr) //Check if pipe is in the correct state to be updated HCD_CHECK_FROM_CRIT(pipe->state != HCD_PIPE_STATE_INVALID && !pipe->cs_flags.pipe_cmd_processing - && pipe->num_irp_pending == 0 - && pipe->num_irp_done == 0, + && pipe->num_urb_pending == 0 + && pipe->num_urb_done == 0, ESP_ERR_INVALID_STATE); pipe->ep_char.dev_addr = dev_addr; //Update the underlying channel's registers @@ -1985,13 +1986,13 @@ esp_err_t hcd_pipe_command(hcd_pipe_handle_t pipe_hdl, hcd_pipe_cmd_t command) 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 - if (pipe->cs_flags.pipe_cmd_processing || !pipe->port->flags.conn_devc_ena || pipe->state == HCD_PIPE_STATE_INVALID) { + if (pipe->cs_flags.pipe_cmd_processing || !pipe->port->flags.conn_dev_ena || pipe->state == HCD_PIPE_STATE_INVALID) { ret = ESP_ERR_INVALID_STATE; } else { pipe->cs_flags.pipe_cmd_processing = 1; switch (command) { case HCD_PIPE_CMD_ABORT: { - //Retire all scheduled IRPs. Pipe's state remains unchanged + //Retire all scheduled URBs. Pipe's state remains unchanged if (!_pipe_wait_done(pipe)) { //Stop any on going transfers ret = ESP_ERR_INVALID_RESPONSE; } @@ -2000,7 +2001,7 @@ esp_err_t hcd_pipe_command(hcd_pipe_handle_t pipe_hdl, hcd_pipe_cmd_t command) break; } case HCD_PIPE_CMD_RESET: { - //Retire all scheduled IRPs. Pipe's state moves to active + //Retire all scheduled URBs. Pipe's state moves to active if (!_pipe_wait_done(pipe)) { //Stop any on going transfers ret = ESP_ERR_INVALID_RESPONSE; break; @@ -2053,14 +2054,14 @@ hcd_pipe_event_t hcd_pipe_get_event(hcd_pipe_handle_t pipe_hdl) // ------------------------------------------------- Buffer Control ---------------------------------------------------- -static inline void _buffer_fill_ctrl(dma_buffer_block_t *buffer, usb_irp_t *irp) +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 IRP's data) - usb_ctrl_req_t *ctrl_req = (usb_ctrl_req_t *)irp->data_buffer; + //Get information about the control transfer by analyzing the setup packet (the first 8 bytes of the URB's data) + usb_ctrl_req_t *ctrl_req = (usb_ctrl_req_t *)transfer->data_buffer; bool data_stg_in = (ctrl_req->bRequestType & USB_B_REQUEST_TYPE_DIR_IN); - bool data_stg_skip = (irp->num_bytes == 0); + bool data_stg_skip = (transfer->num_bytes == 0); //Fill setup stage - usbh_hal_xfer_desc_fill(buffer->xfer_desc_list, 0, irp->data_buffer, sizeof(usb_ctrl_req_t), + usbh_hal_xfer_desc_fill(buffer->xfer_desc_list, 0, transfer->data_buffer, sizeof(usb_ctrl_req_t), USBH_HAL_XFER_DESC_FLAG_SETUP | USBH_HAL_XFER_DESC_FLAG_HOC); //Fill data stage if (data_stg_skip) { @@ -2068,7 +2069,7 @@ static inline void _buffer_fill_ctrl(dma_buffer_block_t *buffer, usb_irp_t *irp) usbh_hal_xfer_desc_clear(buffer->xfer_desc_list, 1); } else { //Fill data stage - usbh_hal_xfer_desc_fill(buffer->xfer_desc_list, 1, irp->data_buffer + sizeof(usb_ctrl_req_t), irp->num_bytes, + usbh_hal_xfer_desc_fill(buffer->xfer_desc_list, 1, transfer->data_buffer + sizeof(usb_ctrl_req_t), transfer->num_bytes, ((data_stg_in) ? USBH_HAL_XFER_DESC_FLAG_IN : 0) | USBH_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. @@ -2080,31 +2081,31 @@ static inline void _buffer_fill_ctrl(dma_buffer_block_t *buffer, usb_irp_t *irp) buffer->flags.ctrl.cur_stg = 0; } -static inline void _buffer_fill_bulk(dma_buffer_block_t *buffer, usb_irp_t *irp, bool is_in) +static inline void _buffer_fill_bulk(dma_buffer_block_t *buffer, usb_transfer_t *transfer, bool is_in) { if (is_in) { - usbh_hal_xfer_desc_fill(buffer->xfer_desc_list, 0, irp->data_buffer, irp->num_bytes, + usbh_hal_xfer_desc_fill(buffer->xfer_desc_list, 0, transfer->data_buffer, transfer->num_bytes, USBH_HAL_XFER_DESC_FLAG_IN | USBH_HAL_XFER_DESC_FLAG_HOC); - } else if (irp->flags & USB_IRP_FLAG_ZERO_PACK) { + } else if (transfer->flags & USB_TRANSFER_FLAG_ZERO_PACK) { //We need to add an extra zero length packet, so two descriptors are used - usbh_hal_xfer_desc_fill(buffer->xfer_desc_list, 0, irp->data_buffer, irp->num_bytes, 0); + usbh_hal_xfer_desc_fill(buffer->xfer_desc_list, 0, transfer->data_buffer, transfer->num_bytes, 0); usbh_hal_xfer_desc_fill(buffer->xfer_desc_list, 1, NULL, 0, USBH_HAL_XFER_DESC_FLAG_HOC); } else { - usbh_hal_xfer_desc_fill(buffer->xfer_desc_list, 0, irp->data_buffer, irp->num_bytes, USBH_HAL_XFER_DESC_FLAG_HOC); + usbh_hal_xfer_desc_fill(buffer->xfer_desc_list, 0, transfer->data_buffer, transfer->num_bytes, USBH_HAL_XFER_DESC_FLAG_HOC); } //Update buffer flags - buffer->flags.bulk.zero_len_packet = (is_in && (irp->flags & USB_IRP_FLAG_ZERO_PACK)) ? 1 : 0; + buffer->flags.bulk.zero_len_packet = (is_in && (transfer->flags & USB_TRANSFER_FLAG_ZERO_PACK)) ? 1 : 0; } -static inline void _buffer_fill_intr(dma_buffer_block_t *buffer, usb_irp_t *irp, bool is_in, int mps) +static inline void _buffer_fill_intr(dma_buffer_block_t *buffer, usb_transfer_t *transfer, bool is_in, int mps) { int num_qtds; if (is_in) { - assert(irp->num_bytes % mps == 0); //IN transfers MUST be integer multiple of MPS - num_qtds = irp->num_bytes / mps; + assert(transfer->num_bytes % mps == 0); //IN transfers MUST be integer multiple of MPS + num_qtds = transfer->num_bytes / mps; } else { - num_qtds = irp->num_bytes / mps; //Floor division for number of MPS packets - if (irp->num_bytes % irp->num_bytes > 0) { + num_qtds = transfer->num_bytes / mps; //Floor division for number of MPS packets + if (transfer->num_bytes % transfer->num_bytes > 0) { num_qtds++; //For the last shot packet } } @@ -2112,32 +2113,32 @@ static inline void _buffer_fill_intr(dma_buffer_block_t *buffer, usb_irp_t *irp, //Fill all but last descriptor int bytes_filled = 0; for (int i = 0; i < num_qtds - 1; i++) { - usbh_hal_xfer_desc_fill(buffer->xfer_desc_list, i, &irp->data_buffer[bytes_filled], mps, (is_in) ? USBH_HAL_XFER_DESC_FLAG_IN : 0); + usbh_hal_xfer_desc_fill(buffer->xfer_desc_list, i, &transfer->data_buffer[bytes_filled], mps, (is_in) ? USBH_HAL_XFER_DESC_FLAG_IN : 0); bytes_filled += mps; } //Fill in the last descriptor with HOC flag - usbh_hal_xfer_desc_fill(buffer->xfer_desc_list, num_qtds - 1, &irp->data_buffer[bytes_filled], irp->num_bytes - bytes_filled, + usbh_hal_xfer_desc_fill(buffer->xfer_desc_list, num_qtds - 1, &transfer->data_buffer[bytes_filled], transfer->num_bytes - bytes_filled, ((is_in) ? USBH_HAL_XFER_DESC_FLAG_IN : 0) | USBH_HAL_XFER_DESC_FLAG_HOC); //Update buffer members and flags buffer->flags.intr.num_qtds = num_qtds; } -static inline void _buffer_fill_isoc(dma_buffer_block_t *buffer, usb_irp_t *irp, bool is_in, int mps, int interval, int start_idx) +static inline void _buffer_fill_isoc(dma_buffer_block_t *buffer, usb_transfer_t *transfer, bool is_in, int mps, int interval, int start_idx) { assert(interval > 0); - int total_num_desc = irp->num_iso_packets * interval; + int total_num_desc = transfer->num_isoc_packets * interval; 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 (int pkt_idx = 0; pkt_idx < irp->num_iso_packets; pkt_idx++) { - int xfer_len = irp->iso_packet_desc[pkt_idx].length; + 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) ? USBH_HAL_XFER_DESC_FLAG_IN : 0; - if (pkt_idx == irp->num_iso_packets - 1) { + if (pkt_idx == transfer->num_isoc_packets - 1) { //Last packet, set the the HOC flag flags |= USBH_HAL_XFER_DESC_FLAG_HOC; } - usbh_hal_xfer_desc_fill(buffer->xfer_desc_list, desc_idx, &irp->data_buffer[bytes_filled], xfer_len, flags); + usbh_hal_xfer_desc_fill(buffer->xfer_desc_list, desc_idx, &transfer->data_buffer[bytes_filled], xfer_len, flags); bytes_filled += xfer_len; if (++desc_idx >= XFER_LIST_LEN_ISOC) { desc_idx = 0; @@ -2153,27 +2154,28 @@ static inline void _buffer_fill_isoc(dma_buffer_block_t *buffer, usb_irp_t *irp, //Update buffer members and flags buffer->flags.isoc.num_qtds = total_num_desc; buffer->flags.isoc.interval = interval; - buffer->flags.isoc.irp_start_idx = start_idx; - buffer->flags.isoc.next_irp_start_idx = desc_idx; + buffer->flags.isoc.start_idx = start_idx; + buffer->flags.isoc.next_start_idx = desc_idx; } static void _buffer_fill(pipe_t *pipe) { - //Get an IRP from the pending tailq - usb_irp_t *irp = TAILQ_FIRST(&pipe->pending_irp_tailq); - assert(pipe->num_irp_pending > 0 && irp != NULL); - TAILQ_REMOVE(&pipe->pending_irp_tailq, irp, tailq_entry); - pipe->num_irp_pending--; + //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 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]; - assert(buffer_to_fill->irp == NULL); + 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, irp); + _buffer_fill_ctrl(buffer_to_fill, transfer); break; } case USB_PRIV_XFER_TYPE_ISOCHRONOUS: { @@ -2197,17 +2199,17 @@ static void _buffer_fill(pipe_t *pipe) //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_irp_start_idx; + start_idx = prev_filled_buffer->flags.isoc.next_start_idx; } - _buffer_fill_isoc(buffer_to_fill, irp, is_in, mps, (int)pipe->ep_char.periodic.interval, 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, irp, is_in); + _buffer_fill_bulk(buffer_to_fill, transfer, is_in); break; } case USB_PRIV_XFER_TYPE_INTR: { - _buffer_fill_intr(buffer_to_fill, irp, is_in, mps); + _buffer_fill_intr(buffer_to_fill, transfer, is_in, mps); break; } default: { @@ -2215,8 +2217,8 @@ static void _buffer_fill(pipe_t *pipe) break; } } - buffer_to_fill->irp = irp; - IRP_STATE_SET(irp->reserved_flags, IRP_STATE_INFLIGHT); + buffer_to_fill->urb = urb; + urb->hcd_var = URB_HCD_STATE_INFLIGHT; //Update multi buffer flags pipe->multi_buffer_control.wr_idx++; pipe->multi_buffer_control.buffer_num_to_fill--; @@ -2227,7 +2229,7 @@ static void _buffer_exec(pipe_t *pipe) { assert(pipe->multi_buffer_control.rd_idx != pipe->multi_buffer_control.wr_idx || pipe->multi_buffer_control.buffer_num_to_exec > 0); dma_buffer_block_t *buffer_to_exec = pipe->buffers[pipe->multi_buffer_control.rd_idx]; - assert(buffer_to_exec->irp != NULL); + assert(buffer_to_exec->urb != NULL); uint32_t start_idx; int desc_list_len; @@ -2241,7 +2243,7 @@ static void _buffer_exec(pipe_t *pipe) break; } case USB_PRIV_XFER_TYPE_ISOCHRONOUS: { - start_idx = buffer_to_exec->flags.isoc.irp_start_idx; + start_idx = buffer_to_exec->flags.isoc.start_idx; desc_list_len = XFER_LIST_LEN_ISOC; break; } @@ -2305,45 +2307,45 @@ static bool _buffer_check_done(pipe_t *pipe) static inline void _buffer_parse_ctrl(dma_buffer_block_t *buffer) { - usb_irp_t *irp = buffer->irp; - //Update IRP's actual number of bytes + usb_transfer_t *transfer = &buffer->urb->transfer; + //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 zero - irp->actual_num_bytes = 0; + transfer->actual_num_bytes = 0; } else { //Parse the data stage for the remaining length int rem_len; int desc_status; usbh_hal_xfer_desc_parse(buffer->xfer_desc_list, 1, &rem_len, &desc_status); assert(desc_status == USBH_HAL_XFER_DESC_STS_SUCCESS); - assert(rem_len <= irp->num_bytes); - irp->actual_num_bytes = irp->num_bytes - rem_len; + assert(rem_len <= transfer->num_bytes); + transfer->actual_num_bytes = transfer->num_bytes - rem_len; } - //Update IRP status - irp->status = USB_TRANSFER_STATUS_COMPLETED; + //Update URB status + transfer->status = USB_TRANSFER_STATUS_COMPLETED; //Clear the descriptor list memset(buffer->xfer_desc_list, XFER_LIST_LEN_CTRL, sizeof(usbh_ll_dma_qtd_t)); } static inline void _buffer_parse_bulk(dma_buffer_block_t *buffer) { - usb_irp_t *irp = buffer->irp; - //Update IRP's actual number of bytes + usb_transfer_t *transfer = &buffer->urb->transfer; + //Update URB's actual number of bytes int rem_len; int desc_status; usbh_hal_xfer_desc_parse(buffer->xfer_desc_list, 0, &rem_len, &desc_status); assert(desc_status == USBH_HAL_XFER_DESC_STS_SUCCESS); - assert(rem_len <= irp->num_bytes); - irp->actual_num_bytes = irp->num_bytes - rem_len; - //Update IRP's status - irp->status = USB_TRANSFER_STATUS_COMPLETED; + assert(rem_len <= transfer->num_bytes); + transfer->actual_num_bytes = transfer->num_bytes - rem_len; + //Update URB's status + transfer->status = USB_TRANSFER_STATUS_COMPLETED; //Clear the descriptor list memset(buffer->xfer_desc_list, XFER_LIST_LEN_BULK, sizeof(usbh_ll_dma_qtd_t)); } static inline void _buffer_parse_intr(dma_buffer_block_t *buffer, bool is_in, int mps) { - usb_irp_t *irp = buffer->irp; + 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) @@ -2358,7 +2360,7 @@ static inline void _buffer_parse_intr(dma_buffer_block_t *buffer, bool is_in, in usbh_hal_xfer_desc_parse(buffer->xfer_desc_list, intr_stop_idx - 1, &rem_len, &desc_status); assert(rem_len > 0 && desc_status == USBH_HAL_XFER_DESC_STS_SUCCESS); //Update actual bytes - irp->actual_num_bytes = (mps * intr_stop_idx - 2) + (mps - rem_len); + transfer->actual_num_bytes = (mps * intr_stop_idx - 2) + (mps - rem_len); } else { //Check that all but the last packet transmitted MPS for (int i = 0; i < buffer->flags.intr.num_qtds - 1; i++) { @@ -2373,7 +2375,7 @@ static inline void _buffer_parse_intr(dma_buffer_block_t *buffer, bool is_in, in usbh_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 == USBH_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 - irp->actual_num_bytes = irp->num_bytes - last_packet_rem_len; + transfer->actual_num_bytes = transfer->num_bytes - last_packet_rem_len; } } else { //OUT INTR transfers can only complete successfully if all MPS packets have been transmitted. Double check @@ -2383,19 +2385,19 @@ static inline void _buffer_parse_intr(dma_buffer_block_t *buffer, bool is_in, in usbh_hal_xfer_desc_parse(buffer->xfer_desc_list, i, &rem_len, &desc_status); assert(rem_len == 0 && desc_status == USBH_HAL_XFER_DESC_STS_SUCCESS); } - irp->actual_num_bytes = irp->num_bytes; + transfer->actual_num_bytes = transfer->num_bytes; } - //Update IRP's status - irp->status = USB_TRANSFER_STATUS_COMPLETED; + //Update URB's status + transfer->status = USB_TRANSFER_STATUS_COMPLETED; //Clear the descriptor list memset(buffer->xfer_desc_list, XFER_LIST_LEN_INTR, sizeof(usbh_ll_dma_qtd_t)); } static inline void _buffer_parse_isoc(dma_buffer_block_t *buffer, bool is_in) { - usb_irp_t *irp = buffer->irp; - int desc_idx = buffer->flags.isoc.irp_start_idx; //Descriptor index tracks which descriptor in the QTD list - for (int pkt_idx = 0; pkt_idx < irp->num_iso_packets; pkt_idx++) { + usb_transfer_t *transfer = &buffer->urb->transfer; + int desc_idx = buffer->flags.isoc.start_idx; //Descriptor index tracks which descriptor in the QTD list + for (int pkt_idx = 0; pkt_idx < transfer->num_isoc_packets; pkt_idx++) { //Clear the filled descriptor int rem_len; int desc_status; @@ -2403,10 +2405,10 @@ static inline void _buffer_parse_isoc(dma_buffer_block_t *buffer, bool is_in) usbh_hal_xfer_desc_clear(buffer->xfer_desc_list, desc_idx); assert(rem_len == 0 || is_in); assert(desc_status == USBH_HAL_XFER_DESC_STS_SUCCESS || USBH_HAL_XFER_DESC_STS_NOT_EXECUTED); - assert(rem_len <= irp->iso_packet_desc[pkt_idx].length); //Check for DMA errata + assert(rem_len <= transfer->isoc_packet_desc[pkt_idx].num_bytes); //Check for DMA errata //Update ISO packet actual length and status - irp->iso_packet_desc[pkt_idx].actual_length = irp->iso_packet_desc[pkt_idx].length - rem_len; - irp->iso_packet_desc[pkt_idx].status = (desc_status == USBH_HAL_XFER_DESC_STS_NOT_EXECUTED) ? USB_TRANSFER_STATUS_SKIPPED : USB_TRANSFER_STATUS_COMPLETED; + transfer->isoc_packet_desc[pkt_idx].actual_num_bytes = transfer->isoc_packet_desc[pkt_idx].num_bytes - rem_len; + transfer->isoc_packet_desc[pkt_idx].status = (desc_status == USBH_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 desc_idx += buffer->flags.isoc.interval; if (desc_idx >= XFER_LIST_LEN_INTR) { @@ -2417,33 +2419,33 @@ 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 IRP had an error, so we consider that NO bytes were transferred - usb_irp_t *irp = buffer->irp; - irp->actual_num_bytes = 0; - for (int i = 0; i < irp->num_iso_packets; i++) { - irp->iso_packet_desc[i].actual_length = 0; + //The URB had an error, so we consider that NO bytes were transferred + usb_transfer_t *transfer = &buffer->urb->transfer; + transfer->actual_num_bytes = 0; + for (int i = 0; i < transfer->num_isoc_packets; i++) { + transfer->isoc_packet_desc[i].actual_num_bytes = 0; } - //Update status of IRP + //Update status of URB if (buffer->status_flags.cancelled) { - irp->status = USB_TRANSFER_STATUS_CANCELED; + transfer->status = USB_TRANSFER_STATUS_CANCELED; } else if (buffer->status_flags.pipe_state == HCD_PIPE_STATE_INVALID) { - irp->status = USB_TRANSFER_STATUS_NO_DEVICE; + transfer->status = USB_TRANSFER_STATUS_NO_DEVICE; } else { switch (buffer->status_flags.pipe_event) { case HCD_PIPE_EVENT_ERROR_XFER: //Excessive transaction error - irp->status = USB_TRANSFER_STATUS_ERROR; + transfer->status = USB_TRANSFER_STATUS_ERROR; break; case HCD_PIPE_EVENT_ERROR_OVERFLOW: - irp->status = USB_TRANSFER_STATUS_OVERFLOW; + transfer->status = USB_TRANSFER_STATUS_OVERFLOW; break; case HCD_PIPE_EVENT_ERROR_STALL: - irp->status = USB_TRANSFER_STATUS_STALL; + transfer->status = USB_TRANSFER_STATUS_STALL; break; - case HCD_PIPE_EVENT_IRP_DONE: //Special case where we are cancelling an IRP due to pipe_retire - irp->status = USB_TRANSFER_STATUS_CANCELED; + case HCD_PIPE_EVENT_URB_DONE: //Special case where we are cancelling an URB due to pipe_retire + transfer->status = USB_TRANSFER_STATUS_CANCELED; break; default: - //HCD_PIPE_EVENT_ERROR_IRP_NOT_AVAIL should never occur + //HCD_PIPE_EVENT_ERROR_URB_NOT_AVAIL should never occur abort(); break; } @@ -2456,11 +2458,11 @@ static void _buffer_parse(pipe_t *pipe) { assert(pipe->multi_buffer_control.buffer_num_to_parse > 0); dma_buffer_block_t *buffer_to_parse = pipe->buffers[pipe->multi_buffer_control.fr_idx]; - assert(buffer_to_parse->irp != NULL); + assert(buffer_to_parse->urb != NULL); 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 IRP + //Parsing the buffer will update the buffer's corresponding URB if (buffer_to_parse->status_flags.error_occurred) { _buffer_parse_error(buffer_to_parse); } else { @@ -2487,13 +2489,13 @@ static void _buffer_parse(pipe_t *pipe) } } } - usb_irp_t *irp = buffer_to_parse->irp; - IRP_STATE_SET(irp->reserved_flags, IRP_STATE_DONE); - buffer_to_parse->irp = NULL; + 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 IRP to the done tailq - TAILQ_INSERT_TAIL(&pipe->done_irp_tailq, irp, tailq_entry); - pipe->num_irp_done++; + //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 pipe->multi_buffer_control.fr_idx++; pipe->multi_buffer_control.buffer_num_to_parse--; @@ -2511,34 +2513,32 @@ static void _buffer_flush_all(pipe_t *pipe, bool cancelled) for (int i = 0; i < cur_num_to_parse; i++) { _buffer_parse(pipe); } - //At this point, there should be no more filled buffers. Only IRPs in the pending or done tailq + //At this point, there should be no more filled buffers. Only URBs in the pending or done tailq } // ---------------------------------------------- HCD Transfer Descriptors --------------------------------------------- // ----------------------- Public -------------------------- -esp_err_t hcd_irp_enqueue(hcd_pipe_handle_t pipe_hdl, usb_irp_t *irp) +esp_err_t hcd_urb_enqueue(hcd_pipe_handle_t pipe_hdl, urb_t *urb) { - //Check that IRP has not already been enqueued - HCD_CHECK(irp->reserved_ptr == NULL - && IRP_STATE_GET(irp->reserved_flags) == IRP_STATE_IDLE, - ESP_ERR_INVALID_STATE); + //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 IRPs + //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.pipe_cmd_processing, //Pipe cannot currently be processing a pipe command ESP_ERR_INVALID_STATE); - //Use the IRP's reserved_ptr to store the pipe's - irp->reserved_ptr = (void *)pipe; - //Add the IRP to the pipe's pending tailq - IRP_STATE_SET(irp->reserved_flags, IRP_STATE_PENDING); - TAILQ_INSERT_TAIL(&pipe->pending_irp_tailq, irp, tailq_entry); - pipe->num_irp_pending++; - //use the IRP's reserved_flags to store the IRP's current state + //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 + 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 if (_buffer_can_fill(pipe)) { _buffer_fill(pipe); } @@ -2546,7 +2546,7 @@ esp_err_t hcd_irp_enqueue(hcd_pipe_handle_t pipe_hdl, usb_irp_t *irp) _buffer_exec(pipe); } if (!pipe->cs_flags.is_active) { - //This is the first IRP 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--; @@ -2557,24 +2557,24 @@ esp_err_t hcd_irp_enqueue(hcd_pipe_handle_t pipe_hdl, usb_irp_t *irp) return ESP_OK; } -usb_irp_t *hcd_irp_dequeue(hcd_pipe_handle_t pipe_hdl) +urb_t *hcd_urb_dequeue(hcd_pipe_handle_t pipe_hdl) { pipe_t *pipe = (pipe_t *)pipe_hdl; - usb_irp_t *irp; + urb_t *urb; HCD_ENTER_CRITICAL(); - if (pipe->num_irp_done > 0) { - irp = TAILQ_FIRST(&pipe->done_irp_tailq); - TAILQ_REMOVE(&pipe->done_irp_tailq, irp, tailq_entry); - pipe->num_irp_done--; - //Check the IRP's reserved fields then reset them - assert(irp->reserved_ptr == (void *)pipe && IRP_STATE_GET(irp->reserved_flags) == IRP_STATE_DONE); //The IRP's reserved field should have been set to this pipe - irp->reserved_ptr = NULL; - IRP_STATE_SET(irp->reserved_flags, IRP_STATE_IDLE); + if (pipe->num_urb_done > 0) { + 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 + urb->hcd_ptr = NULL; + urb->hcd_var = URB_HCD_STATE_IDLE; if (pipe->cs_flags.is_active - && pipe->num_irp_pending == 0 && pipe->num_irp_done == 0 + && 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 IRPs. Move the pipe to the list of idle pipes + //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++; @@ -2582,39 +2582,40 @@ usb_irp_t *hcd_irp_dequeue(hcd_pipe_handle_t pipe_hdl) pipe->cs_flags.is_active = 0; } } else { - //No more IRPs to dequeue from this pipe - irp = NULL; + //No more URBs to dequeue from this pipe + urb = NULL; } HCD_EXIT_CRITICAL(); - return irp; + return urb; } -esp_err_t hcd_irp_abort(usb_irp_t *irp) +esp_err_t hcd_urb_abort(urb_t *urb) { HCD_ENTER_CRITICAL(); - //Check that the IRP was enqueued to begin with - HCD_CHECK_FROM_CRIT(irp->reserved_ptr != NULL - && IRP_STATE_GET(irp->reserved_flags) != IRP_STATE_IDLE, - ESP_ERR_INVALID_STATE); - if (IRP_STATE_GET(irp->reserved_flags) == IRP_STATE_PENDING) { - //IRP has not been executed so it can be aborted - pipe_t *pipe = (pipe_t *)irp->reserved_ptr; + //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 + pipe_t *pipe = (pipe_t *)urb->hcd_ptr; //Remove it form the pending queue - TAILQ_REMOVE(&pipe->pending_irp_tailq, irp, tailq_entry); - pipe->num_irp_pending--; + TAILQ_REMOVE(&pipe->pending_urb_tailq, urb, tailq_entry); + pipe->num_urb_pending--; //Add it to the done queue - TAILQ_INSERT_TAIL(&pipe->done_irp_tailq, irp, tailq_entry); - pipe->num_irp_done++; - //Update the IRP's current state, status, and actual length - IRP_STATE_SET(irp->reserved_flags, IRP_STATE_DONE); - irp->actual_num_bytes = 0; - irp->status = USB_TRANSFER_STATUS_CANCELED; - //If this is an ISOC IRP, update the ISO packet descriptors as well - for (int i = 0; i < irp->num_iso_packets; i++) { - irp->iso_packet_desc[i].actual_length = 0; - irp->iso_packet_desc[i].status = USB_TRANSFER_STATUS_CANCELED; + TAILQ_INSERT_TAIL(&pipe->done_urb_tailq, urb, tailq_entry); + pipe->num_urb_done++; + //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 + 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; + } } - }// Otherwise, the IRP is in-flight or already done thus cannot be aborted + } // Otherwise, the URB is in-flight or already done thus cannot be aborted HCD_EXIT_CRITICAL(); return ESP_OK; } diff --git a/components/usb/maintainers.md b/components/usb/maintainers.md index ab243489b4..d31fb84d25 100644 --- a/components/usb/maintainers.md +++ b/components/usb/maintainers.md @@ -50,7 +50,7 @@ The HAL layer abstracts the DWC_OTG operating in Host Mode using Internal Scatte The HCD (Host Controller Driver) abstracts the DWC_OTG as N number of ports and an arbitrary number of pipes that can be routed through one of the ports to a device. However note that **the underlying hardware controller only has a single port, so technically only one port can ever be enabled**. - In other words, the HCD essentially implements a root hub (not fully behavioral compliant) that contains a single port. -- Pipes are "an association between an endpoint on a device and software on the host". IRPs (I/O Request Packets) that each represent a USB transfer can be enqueued into a pipe for transmission, and dequeued from a pipe when completed. +- Pipes are "an association between an endpoint on a device and software on the host". URBs (USB Request Block) represent a USB transfer that can be enqueued into a pipe for transmission, and dequeued from a pipe when completed. The HCD currently has the following limitations: @@ -72,12 +72,11 @@ The HCD currently has the following limitations: ## HCD Pipes -- Pipes can be opened to a particular endpoint based on a descriptor provided on allocation. If opening a default pipe, a `NULL` descriptor can be provided. -- IRPs can be enqueued into a pipe. Pipes use a linked list internally, so there is in-theory no limit to the number of IRPs that can be enqueued. -- IRPs need to be dequeued once they are completed. -- IRPs need to have the transfer information (such as data buffer, transfer length in bytes) filled before they should be enqueued. -- IRPs will be owned by the HCD until they are dequeued. Thus, users should not attempt to modify an IRP object (and the IRP's data buffer) until the IRP is dequeued. -- The IRP is defined in `usb.h` instead of `hcd.h` so that it can be used throughout the entire Host stack. Each layer simply needs to pass the pointer of the IRP to the next layer thus minimizing the amount of copying required. +- URBs can be enqueued into a pipe. Pipes use a linked list internally, so there is in-theory no limit to the number of URBs that can be enqueued. +- URBs need to be dequeued once they are completed. +- URBs need to have the transfer information (such as data buffer, transfer length in bytes) filled before they should be enqueued. +- URBs will be owned by the HCD until they are dequeued. Thus, users should not attempt to modify an URB object (and the URB's data buffer) until the URB is dequeued. +- The URB is defined in `usb_private.h` instead of `hcd.h` so that the same structure can shared throughout the entire Host stack. Each layer simply needs to pass the pointer of the URB to the next layer thus minimizing the amount of copying required. ## HCD SW Arch diff --git a/components/usb/private_include/hcd.h b/components/usb/private_include/hcd.h index 9e692f1d9d..d5fc5b61eb 100644 --- a/components/usb/private_include/hcd.h +++ b/components/usb/private_include/hcd.h @@ -22,6 +22,7 @@ extern "C" { #include #include #include "esp_err.h" +#include "usb_private.h" #include "usb.h" // ------------------------------------------------- Macros & Types ---------------------------------------------------- @@ -51,14 +52,14 @@ typedef enum { * @brief States of an HCD pipe * * Active: - * - Pipe is able to transmit data. IRPs can be enqueued. - * - Event if pipe has no IRPs enqueued, it can still be in the active state. + * - Pipe is able to transmit data. URBs can be enqueued. + * - Event if pipe has no URBs enqueued, it can still be in the active state. * Halted: - * - An error has occurred on the pipe. IRPs will no longer be executed. + * - An error has occurred on the pipe. URBs will no longer be executed. * - Halt should be cleared using the clear command * Invalid: * - The underlying device that the pipe connects is not longer valid, thus making the pipe invalid. - * - Pending IRPs should be dequeued and the pipe should be freed. + * - Pending URBs should be dequeued and the pipe should be freed. */ typedef enum { HCD_PIPE_STATE_ACTIVE, /**< The pipe is active */ @@ -91,10 +92,10 @@ typedef enum { */ typedef enum { HCD_PIPE_EVENT_NONE, /**< The pipe has no events (used to indicate no events when polling) */ - HCD_PIPE_EVENT_IRP_DONE, /**< The pipe has completed an IRP. The IRP can be dequeued */ - HCD_PIPE_EVENT_INVALID, /**< The pipe is invalid because */ + HCD_PIPE_EVENT_URB_DONE, /**< The pipe has completed an URB. The URB can be dequeued */ + HCD_PIPE_EVENT_INVALID, /**< The pipe is invalid because the underlying device is no longer valid */ HCD_PIPE_EVENT_ERROR_XFER, /**< Excessive (three consecutive) transaction errors (e.g., no ACK, bad CRC etc) */ - HCD_PIPE_EVENT_ERROR_IRP_NOT_AVAIL, /**< IRP was not available */ + HCD_PIPE_EVENT_ERROR_URB_NOT_AVAIL, /**< URB was not available */ HCD_PIPE_EVENT_ERROR_OVERFLOW, /**< Received more data than requested. Usually a Packet babble error (i.e., an IN packet has exceeded the endpoint's MPS) */ HCD_PIPE_EVENT_ERROR_STALL, /**< Pipe received a STALL response received */ @@ -107,11 +108,12 @@ typedef enum { */ typedef enum { HCD_PORT_CMD_POWER_ON, /**< Power ON the port */ - HCD_PORT_CMD_POWER_OFF, /**< Power OFF the port */ + HCD_PORT_CMD_POWER_OFF, /**< Power OFF the port. If the port is enabled, this will cause a HCD_PORT_EVENT_SUDDEN_DISCONN event. + If the port is disabled, this will cause a HCD_PORT_EVENT_DISCONNECTION event. */ HCD_PORT_CMD_RESET, /**< Issue a reset on the port */ HCD_PORT_CMD_SUSPEND, /**< Suspend the port */ HCD_PORT_CMD_RESUME, /**< Resume the port */ - HCD_PORT_CMD_DISABLE, /**< Disable the port (stops the SOFs or keep alive) */ + HCD_PORT_CMD_DISABLE, /**< Disable the port (stops the SOFs or keep alive). Any created pipes will receive a HCD_PIPE_EVENT_INVALID event */ } hcd_port_cmd_t; /** @@ -120,8 +122,8 @@ typedef enum { * The pipe commands represent the list of pipe manipulations outlined in 10.5.2.2. of USB2.0 specification. */ typedef enum { - HCD_PIPE_CMD_ABORT, /**< Retire all scheduled IRPs. Pipe's state remains unchanged */ - HCD_PIPE_CMD_RESET, /**< Retire all scheduled IRPs. Pipe's state moves to active */ + HCD_PIPE_CMD_ABORT, /**< Retire all scheduled URBs. Pipe's state remains unchanged */ + HCD_PIPE_CMD_RESET, /**< Retire all scheduled URBs. Pipe's state moves to active */ HCD_PIPE_CMD_CLEAR, /**< Pipe's state moves from halted to active */ HCD_PIPE_CMD_HALT /**< Pipe's state moves to halted */ } hcd_pipe_cmd_t; @@ -143,14 +145,14 @@ typedef void * hcd_pipe_handle_t; * * This callback is run when a port event occurs */ -typedef bool (*hcd_port_isr_callback_t)(hcd_port_handle_t port_hdl, hcd_port_event_t port_event, void *user_arg, bool in_isr); +typedef bool (*hcd_port_callback_t)(hcd_port_handle_t port_hdl, hcd_port_event_t port_event, void *user_arg, bool in_isr); /** * @brief Pipe event callback * * This callback is run when a pipe event occurs */ -typedef bool (*hcd_pipe_isr_callback_t)(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_event, void *user_arg, bool in_isr); +typedef bool (*hcd_pipe_callback_t)(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_event, void *user_arg, bool in_isr); typedef enum { HCD_PORT_FIFO_BIAS_BALANCED, /**< Balanced FIFO sizing for RX, Non-periodic TX, and periodic TX */ @@ -169,7 +171,7 @@ typedef struct { * @brief Port configuration structure */ typedef struct { - hcd_port_isr_callback_t callback; /**< HCD port event callback */ + hcd_port_callback_t callback; /**< HCD port event callback */ void *callback_arg; /**< User argument for HCD port callback */ void *context; /**< Context variable used to associate the port with upper layer object */ } hcd_port_config_t; @@ -180,10 +182,10 @@ typedef struct { * @note The callback can be set to NULL if no callback is required (e.g., using HCD in a polling manner). */ typedef struct { - hcd_pipe_isr_callback_t callback; /**< HCD pipe event ISR callback */ + hcd_pipe_callback_t callback; /**< HCD pipe event ISR callback */ void *callback_arg; /**< User argument for HCD pipe callback */ void *context; /**< Context variable used to associate the pipe with upper layer object */ - const usb_desc_ep_t *ep_desc; /**< Pointer to endpoint descriptor of the pipe */ + const usb_desc_ep_t *ep_desc; /**< Pointer to endpoint descriptor of the pipe */ usb_speed_t dev_speed; /**< Speed of the device */ uint8_t dev_addr; /**< Device address of the pipe */ } hcd_pipe_config_t; @@ -236,7 +238,7 @@ esp_err_t hcd_uninstall(void); * @retval ESP_ERR_NOT_FOUND: Port number not found * @retval ESP_ERR_INVALID_ARG: Arguments are invalid */ -esp_err_t hcd_port_init(int port_number, hcd_port_config_t *port_config, hcd_port_handle_t *port_hdl); +esp_err_t hcd_port_init(int port_number, const hcd_port_config_t *port_config, hcd_port_handle_t *port_hdl); /** * @brief Deinitialize a particular port @@ -376,7 +378,7 @@ esp_err_t hcd_pipe_alloc(hcd_port_handle_t port_hdl, const hcd_pipe_config_t *pi * * Frees the resources used by an HCD pipe. The pipe's handle should be discarded after calling this function. The pipe * must be in following condition before it can be freed: - * - All IRPs have been dequeued + * - All URBs have been dequeued * * @param pipe_hdl Pipe handle * @@ -392,7 +394,7 @@ esp_err_t hcd_pipe_free(hcd_pipe_handle_t pipe_hdl); * packet size. This function can only be called on a pipe that has met the following conditions: * - Pipe is still valid (i.e., not in the HCD_PIPE_STATE_INVALID state) * - Pipe is not currently processing a command - * - All IRPs have been dequeued from the pipe + * - All URBs have been dequeued from the pipe * * @param pipe_hdl Pipe handle * @param mps New Maximum Packet Size @@ -409,7 +411,7 @@ esp_err_t hcd_pipe_update_mps(hcd_pipe_handle_t pipe_hdl, int mps); * address. This function can only be called on a pipe that has met the following conditions: * - Pipe is still valid (i.e., not in the HCD_PIPE_STATE_INVALID state) * - Pipe is not currently processing a command - * - All IRPs have been dequeued from the pipe + * - All URBs have been dequeued from the pipe * * @param pipe_hdl Pipe handle * @param dev_addr New device address @@ -438,19 +440,19 @@ hcd_pipe_state_t hcd_pipe_get_state(hcd_pipe_handle_t pipe_hdl); /** * @brief Execute a command on a particular pipe * - * Pipe commands allow a pipe to be manipulated (such as clearing a halt, retiring all IRPs etc). The following + * Pipe commands allow a pipe to be manipulated (such as clearing a halt, retiring all URBs etc). The following * conditions must for a pipe command to be issued: * - Pipe is still valid (i.e., not in the HCD_PIPE_STATE_INVALID) * - No other thread/task processing a command on the pipe concurrently (will return) * - * @note Some pipe commands will block until the pipe's current in-flight IRP is complete. If the pipe's state + * @note Some pipe commands will block until the pipe's current in-flight URB is complete. If the pipe's state * changes unexpectedly, this function will return ESP_ERR_INVALID_RESPONSE * * @param pipe_hdl Pipe handle * @param command Pipe command * @retval ESP_OK: Command executed successfully * @retval ESP_ERR_INVALID_STATE: The pipe is not in the correct state/condition too execute the command - * @retval ESP_ERR_INVALID_RESPONSE: The pipe's state changed unexpectedley + * @retval ESP_ERR_INVALID_RESPONSE: The pipe's state changed unexpectedly */ esp_err_t hcd_pipe_command(hcd_pipe_handle_t pipe_hdl, hcd_pipe_cmd_t command); @@ -465,47 +467,47 @@ esp_err_t hcd_pipe_command(hcd_pipe_handle_t pipe_hdl, hcd_pipe_cmd_t command); */ hcd_pipe_event_t hcd_pipe_get_event(hcd_pipe_handle_t pipe_hdl); -// ---------------------------------------------------- HCD IRPs ------------------------------------------------------- +// ---------------------------------------------------- HCD URBs ------------------------------------------------------- /** - * @brief Enqueue an IRP to a particular pipe + * @brief Enqueue an URB to a particular pipe * - * The following conditions must be met before an IRP can be enqueued: - * - The IRP is properly initialized (data buffer and transfer length are set) - * - The IRP must not already be enqueued + * The following conditions must be met before an URB can be enqueued: + * - The URB is properly initialized (data buffer and transfer length are set) + * - The URB must not already be enqueued * - The pipe must be in the HCD_PIPE_STATE_ACTIVE state * * @param pipe_hdl Pipe handle - * @param irp I/O Request Packet to enqueue - * @retval ESP_OK: IRP enqueued successfully - * @retval ESP_ERR_INVALID_STATE: Conditions not met to enqueue IRP + * @param urb URB to enqueue + * @retval ESP_OK: URB enqueued successfully + * @retval ESP_ERR_INVALID_STATE: Conditions not met to enqueue URB */ -esp_err_t hcd_irp_enqueue(hcd_pipe_handle_t pipe_hdl, usb_irp_t *irp); +esp_err_t hcd_urb_enqueue(hcd_pipe_handle_t pipe_hdl, urb_t *urb); /** - * @brief Dequeue an IRP from a particular pipe + * @brief Dequeue an URB from a particular pipe * - * This function should be called on a pipe after a pipe receives a HCD_PIPE_EVENT_IRP_DONE event. If a pipe has - * multiple IRPs that can be dequeued, this function should be called repeatedly until all IRPs are dequeued. If a pipe - * has no more IRPs to dequeue, this function will return NULL. + * This function should be called on a pipe after a pipe receives a HCD_PIPE_EVENT_URB_DONE event. If a pipe has + * multiple URBs that can be dequeued, this function should be called repeatedly until all URBs are dequeued. If a pipe + * has no more URBs to dequeue, this function will return NULL. * * @param pipe_hdl Pipe handle - * @return usb_irp_t* Dequeued I/O Request Packet, or NULL if no more IRPs to dequeue + * @return urb_t* Dequeued URB, or NULL if no more URBs to dequeue */ -usb_irp_t *hcd_irp_dequeue(hcd_pipe_handle_t pipe_hdl); +urb_t *hcd_urb_dequeue(hcd_pipe_handle_t pipe_hdl); /** - * @brief Abort an enqueued IRP + * @brief Abort an enqueued URB * - * This function will attempt to abort an IRP that is already enqueued. If the IRP has yet to be executed, it will be - * "cancelled" and can then be dequeued. If the IRP is currenty in-flight or has already completed, the IRP will not be + * This function will attempt to abort an URB that is already enqueued. If the URB has yet to be executed, it will be + * "cancelled" and can then be dequeued. If the URB is currenty in-flight or has already completed, the URB will not be * affected by this function. * - * @param irp I/O Request Packet to abort - * @retval ESP_OK: IRP successfully aborted, or was not affected by this function - * @retval ESP_ERR_INVALID_STATE: IRP was never enqueued + * @param urb URB to abort + * @retval ESP_OK: URB successfully aborted, or was not affected by this function + * @retval ESP_ERR_INVALID_STATE: URB was never enqueued */ -esp_err_t hcd_irp_abort(usb_irp_t *irp); +esp_err_t hcd_urb_abort(urb_t *urb); #ifdef __cplusplus } diff --git a/components/usb/private_include/usb.h b/components/usb/private_include/usb.h index 3abe2801f6..7c4287ec6e 100644 --- a/components/usb/private_include/usb.h +++ b/components/usb/private_include/usb.h @@ -15,8 +15,8 @@ /* Note: This header file contains the types and macros belong/relate to the USB2.0 protocol and are HW implementation agnostic. In other words, this header is only meant to be used in the HCD layer and above of the USB Host stack. For -types and macros that are HW implementation specific (i.e., HAL layer and below), add them to the "usb_types.h" header -instead. +types and macros that are HW implementation specific (i.e., HAL layer and below), add them to the +"hal/usb_types_private.h" header instead. */ #pragma once @@ -28,9 +28,6 @@ extern "C" { #endif -#include -#include - #define USB_CTRL_REQ_ATTR __attribute__((packed)) #define USB_DESC_ATTR __attribute__((packed)) @@ -67,76 +64,114 @@ typedef enum { USB_TRANSFER_STATUS_COMPLETED, /**< The transfer was successful (but may be short) */ USB_TRANSFER_STATUS_ERROR, /**< The transfer failed because due to excessive errors (e.g. no response or CRC error) */ USB_TRANSFER_STATUS_TIMED_OUT, /**< The transfer failed due to a time out */ - USB_TRANSFER_STATUS_CANCELED, /**< The transfer was canceled */ + USB_TRANSFER_STATUS_CANCELED, /**< The transfer was canceled */ USB_TRANSFER_STATUS_STALL, /**< The transfer was stalled */ USB_TRANSFER_STATUS_NO_DEVICE, /**< The transfer failed because the device is no longer valid (e.g., disconnected */ USB_TRANSFER_STATUS_OVERFLOW, /**< The transfer as more data was sent than was requested */ - USB_TRANSFER_STATUS_SKIPPED, /**< ISOC only. The packet was skipped due to system latency */ + USB_TRANSFER_STATUS_SKIPPED, /**< ISOC packets only. The packet was skipped due to system latency or bus overload */ } usb_transfer_status_t; + +#define USB_TRANSFER_FLAG_ZERO_PACK 0x01 /**< (For bulk OUT only). Indicates that a bulk OUT transfers should always terminate with a short packet, even if it means adding an extra zero length packet */ + /** * @brief Isochronous packet descriptor * - * If the number of bytes in an IRP (I/O Request Packet, see USB2.0 Spec) is - * larger than the MPS of the endpoint, the IRP is split over multiple packets - * (one packet per bInterval of the endpoint). An array of Isochronous packet - * descriptors describes how an IRP should be split over multiple packets. + * If the number of bytes in an Isochronous transfer is larger than the MPS of the endpoint, the transfer is split + * into multiple packets transmitted at the endpoint's specified interval. An array of Isochronous packet descriptors + * describes how an Isochronous transfer should be split into multiple packets. */ typedef struct { - int length; /**< Number of bytes to transmit/receive in the packet */ - int actual_length; /**< Actual number of bytes transmitted/received in the packet */ - usb_transfer_status_t status; /**< Status of the packet */ -} usb_iso_packet_desc_t; - -#define USB_IRP_FLAG_ZERO_PACK 0x01 /**< (For bulk OUT only). Indicates that a bulk OUT transfers should always terminate with a short packet, even if it means adding an extra zero length packet */ + int num_bytes; /**< Number of bytes to transmit/receive in the packet */ + int actual_num_bytes; /**< Actual number of bytes transmitted/received in the packet */ + usb_transfer_status_t status; /**< Status of the packet */ +} usb_isoc_packet_desc_t; /** - * @brief USB IRP (I/O Request Packet). See USB2.0 Spec + * @brief USB transfer structure * - * An IRP is used to represent data transfer request form a software client to and endpoint over the USB bus. The same - * IRP object type is used at each layer of the USB stack. This minimizes copying/conversion across the different layers - * of the stack as each layer will pass a pointer to this type of object. + * This structure is used to represent a transfer from a software client to an endopint over the USB bus. Some of the + * fields are made const on purpose as they are fixed on allocation. Users should call the appropriate USB Host Driver + * function to allocate a USB transfer structure instead of allocating this structure themselves. * - * See 10.5.3.1 os USB2.0 specification - * Bulk: Represents a single bulk transfer which a pipe will transparently split into multiple MPS transactions (until - * the last) - * Control: Represents a single control transfer with the setup packet at the first 8 bytes of the buffer. - * Interrupt: Represents a single interrupt transaction - * Isochronous: Represents a buffer of a stream of bytes which the pipe will transparently transfer the stream of bytes - * one or more service periods + * The transfer type is inferred from the endpoint this transfer is sent to. Depending on the transfer type, users + * should note the following: * - * @note The tailq_entry and reserved variables are used by the USB Host stack internally. Users should not modify those fields. - * @note Once an IRP is submitted, users should not modify the IRP as the Host stack takes ownership of the IRP. + * - Bulk: This structure represents a single bulk transfer. If the number of bytes exceeds the endpoint's MPS, the + * transfer will be split into multiple MPS sized packets followed by a short packet. + * - Control: This structure represents a single control transfer. This first 8 bytes of the data_buffer must be filled + * with the setup packet. The num_bytes field should exclude the size of the setup packet (i.e., set to 0 if + * the control transfer has no data stage). + * - Interrupt: Represents an interrupt transfer. If num_bytes exceeds the MPS of the endpoint, the transfer will be + * split into multiple packets, and each packet is transferred at the endpoint's specified interval. + * - Isochronous: Represents a stream of bytes that should be transferred to an endpoint at a fixed rate. The transfer + * is split into packets according to the each isoc_packet_desc. A packet is transferred at each interval + * of the endpoint. + * + * @note For Bulk/Control/Interrupt IN transfers, the num_bytes must be a integer multiple of the endpoint's MPS + * @note This structure should be allocated via __insert_func_name__() + * @note Once the transfer has be submitted, users should not modify the structure until the transfer has completed */ -struct usb_irp_obj { - //Internal members - TAILQ_ENTRY(usb_irp_obj) tailq_entry; /**< TAILQ entry that allows this object to be added to linked lists. Users should NOT modify this field */ - void *reserved_ptr; /**< Reserved pointer variable for internal use in the stack. Users should set this to NULL on allocation and NOT modify this afterwards */ - uint32_t reserved_flags; /**< Reserved variable for flags used internally in the stack. Users should set this to 0 on allocation and NOT modify this afterwards */ - //Public members - uint8_t *data_buffer; /**< Pointer to data buffer. Must be DMA capable memory */ - int num_bytes; /**< Number of bytes in IRP. Control should exclude size of setup. IN should be integer multiple of MPS */ - int actual_num_bytes; /**< Actual number of bytes transmitted/receives in the IRP */ - uint32_t flags; /**< IRP flags */ - usb_transfer_status_t status; /**< Status of the transfer */ - uint32_t timeout; /**< Timeout (in milliseconds) of the packet (currently not supported yet) */ - void *context; /**< Context variable used to associate the IRP object with another object */ - int num_iso_packets; /**< Only relevant to Isochronous. Number of service periods to transfer data buffer over. Set to 0 for non-iso transfers */ - usb_iso_packet_desc_t iso_packet_desc[0]; /**< Descriptors for each ISO packet */ +typedef struct usb_transfer_obj usb_transfer_t; + +/** + * @brief USB transfer completion callback + */ +typedef void (*usb_transfer_cb_t)(usb_transfer_t *transfer); + +struct usb_transfer_obj{ + 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. Control transfers should exclude size of setup packet. IN transfers should be integer multiple of MPS */ + int actual_num_bytes; /**< Actual number of bytes transferred */ + uint32_t flags; /**< Transfer flags */ + usb_transfer_status_t status; /**< Status of the transfer */ + uint32_t timeout; /**< Timeout (in milliseconds) of the packet (currently not supported yet) */ + usb_transfer_cb_t callback; /**< Transfer callback */ + void *context; /**< Context variable for transfer to associate transfer with something */ + const int num_isoc_packets; /**< Only relevant to Isochronous. Number of service periods (i.e., intervals) to transfer data buffer over. */ + usb_isoc_packet_desc_t isoc_packet_desc[0]; /**< Descriptors for each Isochronous packet */ }; -typedef struct usb_irp_obj usb_irp_t; // ---------------------------------------------------- Chapter 9 ------------------------------------------------------ -#define USB_B_DESCRIPTOR_TYPE_DEVICE 1 -#define USB_B_DESCRIPTOR_TYPE_CONFIGURATION 2 -#define USB_B_DESCRIPTOR_TYPE_STRING 3 -#define USB_B_DESCRIPTOR_TYPE_INTERFACE 4 -#define USB_B_DESCRIPTOR_TYPE_ENDPOINT 5 -#define USB_B_DESCRIPTOR_TYPE_DEVICE_QUALIFIER 6 -#define USB_B_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION 7 -#define USB_B_DESCRIPTOR_TYPE_INTERFACE_POWER 8 +/** + * @brief Descriptor types from USB2.0 specification table 9.5 + */ +#define USB_B_DESCRIPTOR_TYPE_DEVICE 0x01 +#define USB_B_DESCRIPTOR_TYPE_CONFIGURATION 0x02 +#define USB_B_DESCRIPTOR_TYPE_STRING 0x03 +#define USB_B_DESCRIPTOR_TYPE_INTERFACE 0x04 +#define USB_B_DESCRIPTOR_TYPE_ENDPOINT 0x05 +#define USB_B_DESCRIPTOR_TYPE_DEVICE_QUALIFIER 0x06 +#define USB_B_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION 0x07 +#define USB_B_DESCRIPTOR_TYPE_INTERFACE_POWER 0x08 + +/** + * @brief Descriptor types from USB 2.0 ECN + */ +#define USB_B_DESCRIPTOR_TYPE_OTG 0x09 +#define USB_B_DESCRIPTOR_TYPE_DEBUG 0x0a +#define USB_B_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION 0x0b + +/** + * @brief Descriptor types from Wireless USB spec + */ +#define USB_B_DESCRIPTOR_TYPE_SECURITY 0x0c +#define USB_B_DESCRIPTOR_TYPE_KEY 0x0d +#define USB_B_DESCRIPTOR_TYPE_ENCRYPTION_TYPE 0x0e +#define USB_B_DESCRIPTOR_TYPE_BOS 0x0f +#define USB_B_DESCRIPTOR_TYPE_DEVICE_CAPABILITY 0x10 +#define USB_B_DESCRIPTOR_TYPE_WIRELESS_ENDPOINT_COMP 0x11 +#define USB_B_DESCRIPTOR_TYPE_WIRE_ADAPTER 0x21 +#define USB_B_DESCRIPTOR_TYPE_RPIPE 0x22 +#define USB_B_DESCRIPTOR_TYPE_CS_RADIO_CONTROL 0x23 + +/** + * @brief Descriptor types from UAS specification + */ +#define USB_B_DESCRIPTOR_TYPE_PIPE_USAGE 0x24 // ------------------- Control Request --------------------- @@ -219,7 +254,7 @@ _Static_assert(sizeof(usb_ctrl_req_t) == USB_CTRL_REQ_SIZE, "Size of usb_ctrl_re /** * @brief Initializer for a request to get a device's device descriptor */ -#define USB_CTRL_REQ_INIT_GET_DEVC_DESC(ctrl_req_ptr) ({ \ +#define USB_CTRL_REQ_INIT_GET_DEVICE_DESC(ctrl_req_ptr) ({ \ (ctrl_req_ptr)->bRequestType = USB_B_REQUEST_TYPE_DIR_IN | USB_B_REQUEST_TYPE_TYPE_STANDARD | USB_B_REQUEST_TYPE_RECIP_DEVICE; \ (ctrl_req_ptr)->bRequest = USB_B_REQUEST_GET_DESCRIPTOR; \ (ctrl_req_ptr)->wValue = (USB_W_VALUE_DT_DEVICE << 8); \ @@ -244,7 +279,7 @@ _Static_assert(sizeof(usb_ctrl_req_t) == USB_CTRL_REQ_SIZE, "Size of usb_ctrl_re * - desc_index indicates the configuration's index number * - Number of bytes of the configuration descriptor to get */ -#define USB_CTRL_REQ_INIT_GET_CFG_DESC(ctrl_req_ptr, desc_index, desc_len) ({ \ +#define USB_CTRL_REQ_INIT_GET_CONFIG_DESC(ctrl_req_ptr, desc_index, desc_len) ({ \ (ctrl_req_ptr)->bRequestType = USB_B_REQUEST_TYPE_DIR_IN | USB_B_REQUEST_TYPE_TYPE_STANDARD | USB_B_REQUEST_TYPE_RECIP_DEVICE; \ (ctrl_req_ptr)->bRequest = USB_B_REQUEST_GET_DESCRIPTOR; \ (ctrl_req_ptr)->wValue = (USB_W_VALUE_DT_CONFIG << 8) | ((desc_index) & 0xFF); \ @@ -274,12 +309,33 @@ _Static_assert(sizeof(usb_ctrl_req_t) == USB_CTRL_REQ_SIZE, "Size of usb_ctrl_re (ctrl_req_ptr)->wLength = 0; \ }) +// ---------------- Standard Descriptor -------------------- + +/** + * @brief Size of dummy USB standard descriptor + */ +#define USB_DESC_STANDARD_SIZE 2 + +/** + * @brief Dummy USB standard descriptor + * + * All USB standard descriptors start with these two bytes. Use this type traversing over descriptors + */ +typedef union { + struct { + uint8_t bLength; + uint8_t bDescriptorType; + } USB_DESC_ATTR; + uint8_t val[USB_DESC_STANDARD_SIZE]; +} usb_desc_standard_t; +_Static_assert(sizeof(usb_desc_standard_t) == USB_DESC_STANDARD_SIZE, "Size of usb_desc_standard_t incorrect"); + // ------------------ Device Descriptor -------------------- /** * @brief Size of a USB device descriptor in bytes */ -#define USB_DESC_DEVC_SIZE 18 +#define USB_DESC_DEVICE_SIZE 18 /** * @brief Structure representing a USB device descriptor @@ -301,9 +357,9 @@ typedef union { uint8_t iSerialNumber; uint8_t bNumConfigurations; } USB_DESC_ATTR; - uint8_t val[USB_DESC_DEVC_SIZE]; -} usb_desc_devc_t; -_Static_assert(sizeof(usb_desc_devc_t) == USB_DESC_DEVC_SIZE, "Size of usb_desc_devc_t incorrect"); + uint8_t val[USB_DESC_DEVICE_SIZE]; +} usb_desc_device_t; +_Static_assert(sizeof(usb_desc_device_t) == USB_DESC_DEVICE_SIZE, "Size of usb_desc_device_t incorrect"); /** * @brief Possible base class values of the bDeviceClass field of a USB device descriptor @@ -343,7 +399,7 @@ _Static_assert(sizeof(usb_desc_devc_t) == USB_DESC_DEVC_SIZE, "Size of usb_desc_ * @note The size of a full USB configuration includes all the interface and endpoint * descriptors of that configuration. */ -#define USB_DESC_CFG_SIZE 9 +#define USB_DESC_CONFIG_SIZE 9 /** * @brief Structure representing a short USB configuration descriptor @@ -362,9 +418,9 @@ typedef union { uint8_t bmAttributes; uint8_t bMaxPower; } USB_DESC_ATTR; - uint8_t val[USB_DESC_CFG_SIZE]; -} usb_desc_cfg_t; -_Static_assert(sizeof(usb_desc_cfg_t) == USB_DESC_CFG_SIZE, "Size of usb_desc_cfg_t incorrect"); + uint8_t val[USB_DESC_CONFIG_SIZE]; +} usb_desc_config_t; +_Static_assert(sizeof(usb_desc_config_t) == USB_DESC_CONFIG_SIZE, "Size of usb_desc_config_t incorrect"); /** * @brief Bit masks belonging to the bmAttributes field of a configuration descriptor @@ -374,6 +430,31 @@ _Static_assert(sizeof(usb_desc_cfg_t) == USB_DESC_CFG_SIZE, "Size of usb_desc_cf #define USB_BM_ATTRIBUTES_WAKEUP (1 << 5) //Can wake-up #define USB_BM_ATTRIBUTES_BATTERY (1 << 4) //Battery powered +// ---------- Interface Association Descriptor ------------- + +/** + * @brief Size of a USB interface association descriptor in bytes + */ +#define USB_DESC_INTF_ASSOC_SIZE 9 + +/** + * @brief Structure representing a USB interface association descriptor + */ +typedef union { + struct { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bFirstInterface; + uint8_t bInterfaceCount; + uint8_t bFunctionClass; + uint8_t bFunctionSubClass; + uint8_t bFunctionProtocol; + uint8_t iFunction; + } USB_DESC_ATTR; + uint8_t val[USB_DESC_INTF_ASSOC_SIZE]; +} usb_desc_iad_t; +_Static_assert(sizeof(usb_desc_iad_t) == USB_DESC_INTF_ASSOC_SIZE, "Size of usb_desc_iad_t incorrect"); + // ---------------- Interface Descriptor ------------------- /** diff --git a/components/usb/private_include/usb_private.h b/components/usb/private_include/usb_private.h new file mode 100644 index 0000000000..f3b0eaac38 --- /dev/null +++ b/components/usb/private_include/usb_private.h @@ -0,0 +1,55 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include "usb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + uint8_t *data_buffer; + size_t data_buffer_size; + int num_bytes; + int actual_num_bytes; + uint32_t flags; + usb_transfer_status_t status; + uint32_t timeout; + usb_transfer_cb_t callback; + void *context; + int num_isoc_packets; + usb_isoc_packet_desc_t isoc_packet_desc[0]; +} 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_obj{ + TAILQ_ENTRY(urb_obj) tailq_entry; + //HCD context pointer and variables. Must be initialized to NULL and 0 respectively + void *hcd_ptr; + uint32_t hcd_var; + //Host Driver layer will add its fields here. + //Public transfer structure. Must be last due to variable length array + usb_transfer_t transfer; +}; + +typedef struct urb_obj urb_t; + +#ifdef __cplusplus +} +#endif diff --git a/components/usb/test/hcd/test_hcd_bulk.c b/components/usb/test/hcd/test_hcd_bulk.c index f3cbda5df7..e763b698fe 100644 --- a/components/usb/test/hcd/test_hcd_bulk.c +++ b/components/usb/test/hcd/test_hcd_bulk.c @@ -72,7 +72,7 @@ static const usb_desc_ep_t bulk_in_ep_desc = { #define MOCK_MSC_SCSI_SECTOR_SIZE 512 #define MOCK_MSC_SCSI_LUN 0 -#define MSC_SCSI_INTR_NUMBER 0 +#define MOCK_MSC_SCSI_INTF_NUMBER 0 #define MOCK_MSC_SCSI_REQ_INIT_RESET(ctrl_req_ptr, intf_num) ({ \ (ctrl_req_ptr)->bRequestType = USB_B_REQUEST_TYPE_DIR_OUT | USB_B_REQUEST_TYPE_TYPE_CLASS | USB_B_REQUEST_TYPE_RECIP_INTERFACE; \ @@ -116,22 +116,18 @@ typedef struct __attribute__((packed)) { static void mock_msc_reset_req(hcd_pipe_handle_t default_pipe) { - //Create IRP - usb_irp_t *irp = heap_caps_calloc(1, sizeof(usb_irp_t), MALLOC_CAP_DEFAULT); - TEST_ASSERT_NOT_EQUAL(NULL, irp); - irp->data_buffer = heap_caps_malloc(sizeof(usb_ctrl_req_t), MALLOC_CAP_DMA); - TEST_ASSERT_NOT_EQUAL(NULL, irp->data_buffer); - usb_ctrl_req_t *ctrl_req = (usb_ctrl_req_t *)irp->data_buffer; - MOCK_MSC_SCSI_REQ_INIT_RESET(ctrl_req, MSC_SCSI_INTR_NUMBER); - irp->num_bytes = 0; - //Enqueue, wait, dequeue, and check IRP - TEST_ASSERT_EQUAL(ESP_OK, hcd_irp_enqueue(default_pipe, irp)); - test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_IRP_DONE); - TEST_ASSERT_EQUAL(irp, hcd_irp_dequeue(default_pipe)); - TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, irp->status); - //Free IRP - heap_caps_free(irp->data_buffer); - heap_caps_free(irp); + //Create URB + urb_t *urb = test_hcd_alloc_urb(0, sizeof(usb_ctrl_req_t)); + usb_ctrl_req_t *ctrl_req = (usb_ctrl_req_t *)urb->transfer.data_buffer; + MOCK_MSC_SCSI_REQ_INIT_RESET(ctrl_req, MOCK_MSC_SCSI_INTF_NUMBER); + urb->transfer.num_bytes = 0; + //Enqueue, wait, dequeue, and check URB + TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb)); + test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_URB_DONE); + TEST_ASSERT_EQUAL(urb, hcd_urb_dequeue(default_pipe)); + TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status); + //Free URB + test_hcd_free_urb(urb); } static void mock_msc_scsi_init_cbw(mock_msc_bulk_cbw_t *cbw, bool is_read, int offset, int num_sectors, uint32_t tag) @@ -180,28 +176,28 @@ static bool mock_msc_scsi_check_csw(mock_msc_bulk_csw_t *csw, uint32_t tag_expec // --------------------------------------------------- Test Cases ------------------------------------------------------ /* -Test HCD bulk pipe IRPs +Test HCD bulk pipe URBs Purpose: - Test that a bulk pipe can be created - - IRPs can be created and enqueued to the bulk pipe pipe - - Bulk pipe returns HCD_PIPE_EVENT_IRP_DONE for completed IRPs + - URBs can be created and enqueued to the bulk pipe pipe + - Bulk pipe returns HCD_PIPE_EVENT_URB_DONE for completed URBs - Test utilizes a bare bones (i.e., mock) MSC class using SCSI commands Procedure: - Setup HCD and wait for connection - Allocate default pipe and enumerate the device - - Allocate separate IRPS for CBW, Data, and CSW transfers of the MSC class - - Read TEST_NUM_SECTORS number of sectors for the mass storage device - - Expect HCD_PIPE_EVENT_IRP_DONE for each IRP - - Deallocate IRPs + - Allocate separate URBS for CBW, Data, and CSW transfers of the MSC class + - Read TEST_NUM_SECTORS_TOTAL number of sectors for the mass storage device + - Expect HCD_PIPE_EVENT_URB_DONE for each URB + - Deallocate URBs - Teardown */ -#define TEST_NUM_SECTORS 10 -#define TEST_NUM_SECTORS_PER_ITER 2 +#define TEST_NUM_SECTORS_TOTAL 10 +#define TEST_NUM_SECTORS_PER_XFER 2 -TEST_CASE("Test HCD bulk pipe IRPs", "[hcd][ignore]") +TEST_CASE("Test HCD bulk pipe URBs", "[hcd][ignore]") { hcd_port_handle_t port_hdl = test_hcd_setup(); //Setup the HCD and port usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); //Trigger a connection @@ -209,50 +205,50 @@ TEST_CASE("Test HCD bulk pipe IRPs", "[hcd][ignore]") //Enumerate and reset MSC SCSI device hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, 0, port_speed); //Create a default pipe (using a NULL EP descriptor) - uint8_t dev_addr = test_hcd_enum_devc(default_pipe); + uint8_t dev_addr = test_hcd_enum_device(default_pipe); mock_msc_reset_req(default_pipe); //Create BULK IN and BULK OUT pipes for SCSI hcd_pipe_handle_t bulk_out_pipe = test_hcd_pipe_alloc(port_hdl, &bulk_out_ep_desc, dev_addr, port_speed); hcd_pipe_handle_t bulk_in_pipe = test_hcd_pipe_alloc(port_hdl, &bulk_in_ep_desc, dev_addr, port_speed); - //Create IRPs for CBW, Data, and CSW transport. IN Buffer sizes are rounded up to nearest MPS - usb_irp_t *irp_cbw = test_hcd_alloc_irp(0, sizeof(mock_msc_bulk_cbw_t)); - usb_irp_t *irp_data = test_hcd_alloc_irp(0, TEST_NUM_SECTORS_PER_ITER * MOCK_MSC_SCSI_SECTOR_SIZE); - usb_irp_t *irp_csw = test_hcd_alloc_irp(0, sizeof(mock_msc_bulk_csw_t) + (bulk_in_ep_desc.wMaxPacketSize - (sizeof(mock_msc_bulk_csw_t) % bulk_in_ep_desc.wMaxPacketSize))); - irp_cbw->num_bytes = sizeof(mock_msc_bulk_cbw_t); - irp_data->num_bytes = TEST_NUM_SECTORS_PER_ITER * MOCK_MSC_SCSI_SECTOR_SIZE; - irp_csw->num_bytes = sizeof(mock_msc_bulk_csw_t) + (bulk_in_ep_desc.wMaxPacketSize - (sizeof(mock_msc_bulk_csw_t) % bulk_in_ep_desc.wMaxPacketSize)); + //Create URBs for CBW, Data, and CSW transport. IN Buffer sizes are rounded up to nearest MPS + urb_t *urb_cbw = test_hcd_alloc_urb(0, sizeof(mock_msc_bulk_cbw_t)); + urb_t *urb_data = test_hcd_alloc_urb(0, TEST_NUM_SECTORS_PER_XFER * MOCK_MSC_SCSI_SECTOR_SIZE); + urb_t *urb_csw = test_hcd_alloc_urb(0, sizeof(mock_msc_bulk_csw_t) + (bulk_in_ep_desc.wMaxPacketSize - (sizeof(mock_msc_bulk_csw_t) % bulk_in_ep_desc.wMaxPacketSize))); + urb_cbw->transfer.num_bytes = sizeof(mock_msc_bulk_cbw_t); + urb_data->transfer.num_bytes = TEST_NUM_SECTORS_PER_XFER * MOCK_MSC_SCSI_SECTOR_SIZE; + urb_csw->transfer.num_bytes = sizeof(mock_msc_bulk_csw_t) + (bulk_in_ep_desc.wMaxPacketSize - (sizeof(mock_msc_bulk_csw_t) % bulk_in_ep_desc.wMaxPacketSize)); - for (int block_num = 0; block_num < TEST_NUM_SECTORS; block_num += TEST_NUM_SECTORS_PER_ITER) { - //Initialize CBW IRP, then send it on the BULK OUT pipe - mock_msc_scsi_init_cbw((mock_msc_bulk_cbw_t *)irp_cbw->data_buffer, true, block_num, TEST_NUM_SECTORS_PER_ITER, 0xAAAAAAAA); - TEST_ASSERT_EQUAL(ESP_OK, hcd_irp_enqueue(bulk_out_pipe, irp_cbw)); - test_hcd_expect_pipe_event(bulk_out_pipe, HCD_PIPE_EVENT_IRP_DONE); - TEST_ASSERT_EQUAL(irp_cbw, hcd_irp_dequeue(bulk_out_pipe)); - TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, irp_cbw->status); + for (int block_num = 0; block_num < TEST_NUM_SECTORS_TOTAL; block_num += TEST_NUM_SECTORS_PER_XFER) { + //Initialize CBW URB, then send it on the BULK OUT pipe + mock_msc_scsi_init_cbw((mock_msc_bulk_cbw_t *)urb_cbw->transfer.data_buffer, true, block_num, TEST_NUM_SECTORS_PER_XFER, 0xAAAAAAAA); + TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(bulk_out_pipe, urb_cbw)); + test_hcd_expect_pipe_event(bulk_out_pipe, HCD_PIPE_EVENT_URB_DONE); + TEST_ASSERT_EQUAL(urb_cbw, hcd_urb_dequeue(bulk_out_pipe)); + TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, urb_cbw->transfer.status); //Read data through BULK IN pipe - TEST_ASSERT_EQUAL(ESP_OK, hcd_irp_enqueue(bulk_in_pipe, irp_data)); - test_hcd_expect_pipe_event(bulk_in_pipe, HCD_PIPE_EVENT_IRP_DONE); - TEST_ASSERT_EQUAL(irp_data, hcd_irp_dequeue(bulk_in_pipe)); - TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, irp_data->status); + TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(bulk_in_pipe, urb_data)); + test_hcd_expect_pipe_event(bulk_in_pipe, HCD_PIPE_EVENT_URB_DONE); + TEST_ASSERT_EQUAL(urb_data, hcd_urb_dequeue(bulk_in_pipe)); + TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, urb_data->transfer.status); //Read the CSW through BULK IN pipe - TEST_ASSERT_EQUAL(ESP_OK, hcd_irp_enqueue(bulk_in_pipe, irp_csw)); - test_hcd_expect_pipe_event(bulk_in_pipe, HCD_PIPE_EVENT_IRP_DONE); - TEST_ASSERT_EQUAL(irp_csw, hcd_irp_dequeue(bulk_in_pipe)); - TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, irp_data->status); - TEST_ASSERT_EQUAL(sizeof(mock_msc_bulk_csw_t), irp_csw->actual_num_bytes); - TEST_ASSERT_EQUAL(true, mock_msc_scsi_check_csw((mock_msc_bulk_csw_t *)irp_csw->data_buffer, 0xAAAAAAAA)); + TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(bulk_in_pipe, urb_csw)); + test_hcd_expect_pipe_event(bulk_in_pipe, HCD_PIPE_EVENT_URB_DONE); + TEST_ASSERT_EQUAL(urb_csw, hcd_urb_dequeue(bulk_in_pipe)); + TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, urb_data->transfer.status); + TEST_ASSERT_EQUAL(sizeof(mock_msc_bulk_csw_t), urb_csw->transfer.actual_num_bytes); + TEST_ASSERT_EQUAL(true, mock_msc_scsi_check_csw((mock_msc_bulk_csw_t *)urb_csw->transfer.data_buffer, 0xAAAAAAAA)); //Print the read data - printf("Block %d to %d:\n", block_num, block_num + TEST_NUM_SECTORS_PER_ITER); - for (int i = 0; i < irp_data->actual_num_bytes; i++) { - printf("0x%02x,", ((char *)irp_data->data_buffer)[i]); + printf("Block %d to %d:\n", block_num, block_num + TEST_NUM_SECTORS_PER_XFER); + for (int i = 0; i < urb_data->transfer.actual_num_bytes; i++) { + printf("0x%02x,", ((char *)urb_data->transfer.data_buffer)[i]); } printf("\n\n"); } - test_hcd_free_irp(irp_cbw); - test_hcd_free_irp(irp_data); - test_hcd_free_irp(irp_csw); + test_hcd_free_urb(urb_cbw); + test_hcd_free_urb(urb_data); + test_hcd_free_urb(urb_csw); test_hcd_pipe_free(bulk_out_pipe); test_hcd_pipe_free(bulk_in_pipe); test_hcd_pipe_free(default_pipe); diff --git a/components/usb/test/hcd/test_hcd_common.c b/components/usb/test/hcd/test_hcd_common.c index 3f1a8464ca..b6f1281fae 100644 --- a/components/usb/test/hcd/test_hcd_common.c +++ b/components/usb/test/hcd/test_hcd_common.c @@ -31,9 +31,11 @@ #include "esp_err.h" #include "esp_attr.h" #include "esp_rom_gpio.h" -#include "hal/usbh_ll.h" -#include "usb.h" +#include "soc/usb_wrap_struct.h" #include "hcd.h" +#include "usb_private.h" +#include "usb.h" +#include "test_hcd_common.h" #define PORT_NUM 1 #define EVENT_QUEUE_LEN 5 @@ -281,70 +283,66 @@ void test_hcd_pipe_free(hcd_pipe_handle_t pipe_hdl) vQueueDelete(pipe_evt_queue); } -usb_irp_t *test_hcd_alloc_irp(int num_iso_packets, size_t data_buffer_size) +urb_t *test_hcd_alloc_urb(int num_isoc_packets, size_t data_buffer_size) { - //Allocate list of IRPs - usb_irp_t *irp = heap_caps_calloc(1, sizeof(usb_irp_t) + (num_iso_packets * sizeof(usb_iso_packet_desc_t)), MALLOC_CAP_DEFAULT); - TEST_ASSERT_NOT_EQUAL(NULL, irp); - //Allocate data buffer for each IRP and assign them + //Allocate a URB and data buffer + urb_t *urb = heap_caps_calloc(1, sizeof(urb_t) + (num_isoc_packets * sizeof(usb_isoc_packet_desc_t)), MALLOC_CAP_DEFAULT); uint8_t *data_buffer = heap_caps_malloc(data_buffer_size, MALLOC_CAP_DMA); + TEST_ASSERT_NOT_EQUAL(NULL, urb); TEST_ASSERT_NOT_EQUAL(NULL, data_buffer); - irp->data_buffer = data_buffer; - irp->num_iso_packets = num_iso_packets; - return irp; + //Initialize URB and underlying transfer structure. Need to cast to dummy due to const fields + usb_transfer_dummy_t *transfer_dummy = (usb_transfer_dummy_t *)&urb->transfer; + transfer_dummy->data_buffer = data_buffer; + transfer_dummy->num_isoc_packets = num_isoc_packets; + return urb; } -void test_hcd_free_irp(usb_irp_t *irp) +void test_hcd_free_urb(urb_t *urb) { - //Free data buffers of each IRP - heap_caps_free(irp->data_buffer); - //Free the IRP list - heap_caps_free(irp); + //Free data buffer of the transfer + heap_caps_free(urb->transfer.data_buffer); + //Free the URB + heap_caps_free(urb); } -uint8_t test_hcd_enum_devc(hcd_pipe_handle_t default_pipe) +uint8_t test_hcd_enum_device(hcd_pipe_handle_t default_pipe) { - //We need to create an IRP for the enumeration control transfers - usb_irp_t *irp = heap_caps_calloc(1, sizeof(usb_irp_t), MALLOC_CAP_DEFAULT); - TEST_ASSERT_NOT_EQUAL(NULL, irp); - //We use a single data buffer for all control transfers during enumerations. 256 bytes should be large enough for most descriptors - irp->data_buffer = heap_caps_malloc(sizeof(usb_ctrl_req_t) + 256, MALLOC_CAP_DMA); - TEST_ASSERT_NOT_EQUAL(NULL, irp->data_buffer); - usb_ctrl_req_t *ctrl_req = (usb_ctrl_req_t *)irp->data_buffer; + //We need to create a URB for the enumeration control transfers + urb_t *urb = test_hcd_alloc_urb(0, sizeof(usb_ctrl_req_t) + 256); + usb_ctrl_req_t *ctrl_req = (usb_ctrl_req_t *)urb->transfer.data_buffer; //Get the device descriptor (note that device might only return 8 bytes) - USB_CTRL_REQ_INIT_GET_DEVC_DESC(ctrl_req); - irp->num_bytes = sizeof(usb_desc_devc_t); - TEST_ASSERT_EQUAL(ESP_OK, hcd_irp_enqueue(default_pipe, irp)); - test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_IRP_DONE); - TEST_ASSERT_EQUAL(irp, hcd_irp_dequeue(default_pipe)); - TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, irp->status); + USB_CTRL_REQ_INIT_GET_DEVICE_DESC(ctrl_req); + urb->transfer.num_bytes = sizeof(usb_desc_device_t); + TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb)); + test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_URB_DONE); + TEST_ASSERT_EQUAL(urb, hcd_urb_dequeue(default_pipe)); + TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status); //Update the MPS of the default pipe - usb_desc_devc_t *devc_desc = (usb_desc_devc_t *)(irp->data_buffer + sizeof(usb_ctrl_req_t)); - TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_update_mps(default_pipe, devc_desc->bMaxPacketSize0)); + usb_desc_device_t *device_desc = (usb_desc_device_t *)(urb->transfer.data_buffer + sizeof(usb_ctrl_req_t)); + TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_update_mps(default_pipe, device_desc->bMaxPacketSize0)); //Send a set address request USB_CTRL_REQ_INIT_SET_ADDR(ctrl_req, ENUM_ADDR); //We only support one device for now so use address 1 - irp->num_bytes = 0; - TEST_ASSERT_EQUAL(ESP_OK, hcd_irp_enqueue(default_pipe, irp)); - test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_IRP_DONE); - TEST_ASSERT_EQUAL(irp, hcd_irp_dequeue(default_pipe)); - TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, irp->status); + urb->transfer.num_bytes = 0; + TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb)); + test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_URB_DONE); + TEST_ASSERT_EQUAL(urb, hcd_urb_dequeue(default_pipe)); + TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status); //Update address of default pipe TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_update_dev_addr(default_pipe, ENUM_ADDR)); //Send a set configuration request USB_CTRL_REQ_INIT_SET_CONFIG(ctrl_req, ENUM_CONFIG); - irp->num_bytes = 0; - TEST_ASSERT_EQUAL(ESP_OK, hcd_irp_enqueue(default_pipe, irp)); - test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_IRP_DONE); - TEST_ASSERT_EQUAL(irp, hcd_irp_dequeue(default_pipe)); - TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, irp->status); + urb->transfer.num_bytes = 0; + TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb)); + test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_URB_DONE); + TEST_ASSERT_EQUAL(urb, hcd_urb_dequeue(default_pipe)); + TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status); - //Free IRP - heap_caps_free(irp->data_buffer); - heap_caps_free(irp); + //Free URB + test_hcd_free_urb(urb); return ENUM_ADDR; } diff --git a/components/usb/test/hcd/test_hcd_common.h b/components/usb/test/hcd/test_hcd_common.h index 71a06ce057..1d9dac14a2 100644 --- a/components/usb/test/hcd/test_hcd_common.h +++ b/components/usb/test/hcd/test_hcd_common.h @@ -14,10 +14,11 @@ #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" -#include "usb.h" #include "hcd.h" +#include "usb_private.h" +#include "usb.h" -#define IRP_CONTEXT_VAL ((void *)0xDEADBEEF) +#define URB_CONTEXT_VAL ((void *)0xDEADBEEF) // ------------------------------------------------- HCD Event Test ---------------------------------------------------- @@ -118,20 +119,20 @@ hcd_pipe_handle_t test_hcd_pipe_alloc(hcd_port_handle_t port_hdl, const usb_desc void test_hcd_pipe_free(hcd_pipe_handle_t pipe_hdl); /** - * @brief Allocate an IRP + * @brief Allocate a URB * - * @param num_iso_packets Number of isochronous packets - * @param data_buffer_size Size of the data buffer of the IRP - * @return usb_irp_t* IRP + * @param num_isoc_packets Number of isochronous packets + * @param data_buffer_size Size of the data buffer of the URB + * @return urb_t* URB */ -usb_irp_t *test_hcd_alloc_irp(int num_iso_packets, size_t data_buffer_size); +urb_t *test_hcd_alloc_urb(int num_isoc_packets, size_t data_buffer_size); /** - * @brief Free an IRP + * @brief Free a URB * - * @param irp IRP + * @param urb URB */ -void test_hcd_free_irp(usb_irp_t *irp); +void test_hcd_free_urb(urb_t *urb); // --------------------------------------------------- Enumeration ----------------------------------------------------- @@ -148,4 +149,4 @@ void test_hcd_free_irp(usb_irp_t *irp); * @param default_pipe The connected device's default pipe * @return uint8_t The address of the device after enumeration */ -uint8_t test_hcd_enum_devc(hcd_pipe_handle_t default_pipe); +uint8_t test_hcd_enum_device(hcd_pipe_handle_t default_pipe); diff --git a/components/usb/test/hcd/test_hcd_ctrl.c b/components/usb/test/hcd/test_hcd_ctrl.c index 6e8f7a1915..fe29db4374 100644 --- a/components/usb/test/hcd/test_hcd_ctrl.c +++ b/components/usb/test/hcd/test_hcd_ctrl.c @@ -20,88 +20,94 @@ #include "test_hcd_common.h" #define TEST_DEV_ADDR 0 -#define NUM_IRPS 3 +#define NUM_URBS 3 #define TRANSFER_MAX_BYTES 256 -#define IRP_DATA_BUFF_SIZE (sizeof(usb_ctrl_req_t) + TRANSFER_MAX_BYTES) //256 is worst case size for configuration descriptors +#define URB_DATA_BUFF_SIZE (sizeof(usb_ctrl_req_t) + TRANSFER_MAX_BYTES) //256 is worst case size for configuration descriptors /* -Test HCD control pipe IRPs (normal completion and early abort) +Test HCD control pipe URBs (normal completion and early abort) Purpose: - Test that a control pipe can be created - - IRPs can be created and enqueued to the control pipe - - Control pipe returns HCD_PIPE_EVENT_IRP_DONE - - Test that IRPs can be aborted when enqueued + - URBs can be created and enqueued to the control pipe + - Control pipe returns HCD_PIPE_EVENT_URB_DONE + - Test that URBs can be aborted when enqueued Procedure: - Setup HCD and wait for connection - - Setup default pipe and allocate IRPs - - Enqueue IRPs - - Expect HCD_PIPE_EVENT_IRP_DONE - - Requeue IRPs, but abort them immediately - - Expect IRP to be USB_TRANSFER_STATUS_CANCELED or USB_TRANSFER_STATUS_COMPLETED + - Setup default pipe and allocate URBs + - Enqueue URBs + - Expect HCD_PIPE_EVENT_URB_DONE + - Requeue URBs, but abort them immediately + - Expect URB to be USB_TRANSFER_STATUS_CANCELED or USB_TRANSFER_STATUS_COMPLETED - Teardown */ -TEST_CASE("Test HCD control pipe IRPs", "[hcd][ignore]") +TEST_CASE("Test HCD control pipe URBs", "[hcd][ignore]") { hcd_port_handle_t port_hdl = test_hcd_setup(); //Setup the HCD and port usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); //Trigger a connection vTaskDelay(pdMS_TO_TICKS(100)); //Short delay send of SOF (for FS) or EOPs (for LS) - //Allocate some IRPs and initialize their data buffers with control transfers + //Allocate some URBs and initialize their data buffers with control transfers hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, TEST_DEV_ADDR, port_speed); //Create a default pipe (using a NULL EP descriptor) - usb_irp_t *irp_list[NUM_IRPS]; - for (int i = 0; i < NUM_IRPS; i++) { - irp_list[i] = test_hcd_alloc_irp(0, IRP_DATA_BUFF_SIZE); + urb_t *urb_list[NUM_URBS]; + for (int i = 0; i < NUM_URBS; i++) { + urb_list[i] = test_hcd_alloc_urb(0, URB_DATA_BUFF_SIZE); //Initialize with a "Get Config Descriptor request" - irp_list[i]->num_bytes = TRANSFER_MAX_BYTES; - USB_CTRL_REQ_INIT_GET_CFG_DESC((usb_ctrl_req_t *)irp_list[i]->data_buffer, 0, TRANSFER_MAX_BYTES); - irp_list[i]->context = IRP_CONTEXT_VAL; + urb_list[i]->transfer.num_bytes = TRANSFER_MAX_BYTES; + USB_CTRL_REQ_INIT_GET_CONFIG_DESC((usb_ctrl_req_t *)urb_list[i]->transfer.data_buffer, 0, TRANSFER_MAX_BYTES); + urb_list[i]->transfer.context = URB_CONTEXT_VAL; } - //Enqueue IRPs but immediately suspend the port - printf("Enqueuing IRPs\n"); - for (int i = 0; i < NUM_IRPS; i++) { - TEST_ASSERT_EQUAL(ESP_OK, hcd_irp_enqueue(default_pipe, irp_list[i])); + //Enqueue URBs but immediately suspend the port + printf("Enqueuing URBs\n"); + for (int i = 0; i < NUM_URBS; i++) { + TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb_list[i])); } - //Wait for each done event of each IRP - for (int i = 0; i < NUM_IRPS; i++) { - test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_IRP_DONE); + //Wait for each done event of each URB + for (int i = 0; i < NUM_URBS; i++) { + test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_URB_DONE); } - //Dequeue IRPs - for (int i = 0; i < NUM_IRPS; i++) { - usb_irp_t *irp = hcd_irp_dequeue(default_pipe); - TEST_ASSERT_EQUAL(irp_list[i], irp); - TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, irp->status); - TEST_ASSERT_EQUAL(IRP_CONTEXT_VAL, irp->context); + //Dequeue URBs + for (int i = 0; i < NUM_URBS; i++) { + urb_t *urb = hcd_urb_dequeue(default_pipe); + TEST_ASSERT_EQUAL(urb_list[i], urb); + TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status); + TEST_ASSERT_EQUAL(URB_CONTEXT_VAL, urb->transfer.context); } - //Enqueue IRPs again but abort them short after - for (int i = 0; i < NUM_IRPS; i++) { - TEST_ASSERT_EQUAL(ESP_OK, hcd_irp_enqueue(default_pipe, irp_list[i])); + //Print config desc + for (int i = 0; i < urb_list[0]->transfer.actual_num_bytes; i++) { + printf("%d\t0x%x\n", i, urb_list[0]->transfer.data_buffer[sizeof(usb_ctrl_req_t) + i]); } - for (int i = 0; i < NUM_IRPS; i++) { - TEST_ASSERT_EQUAL(ESP_OK, hcd_irp_abort(irp_list[i])); + + + //Enqueue URBs again but abort them short after + for (int i = 0; i < NUM_URBS; i++) { + TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb_list[i])); + } + for (int i = 0; i < NUM_URBS; i++) { + TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_abort(urb_list[i])); } vTaskDelay(pdMS_TO_TICKS(100)); //Give some time for any inflight transfers to complete - //Wait for the IRPs to complete and dequeue them, then check results - //Dequeue IRPs - for (int i = 0; i < NUM_IRPS; i++) { - usb_irp_t *irp = hcd_irp_dequeue(default_pipe); - //No need to check for IRP pointer address as they may be out of order - TEST_ASSERT(irp->status == USB_TRANSFER_STATUS_COMPLETED || irp->status == USB_TRANSFER_STATUS_CANCELED); - if (irp->status == USB_TRANSFER_STATUS_COMPLETED) { - TEST_ASSERT_GREATER_THAN(0, irp->actual_num_bytes); + //Wait for the URBs to complete and dequeue them, then check results + //Dequeue URBs + for (int i = 0; i < NUM_URBS; i++) { + urb_t *urb = hcd_urb_dequeue(default_pipe); + //No need to check for URB pointer address as they may be out of order + TEST_ASSERT(urb->transfer.status == USB_TRANSFER_STATUS_COMPLETED || urb->transfer.status == USB_TRANSFER_STATUS_CANCELED); + if (urb->transfer.status == USB_TRANSFER_STATUS_COMPLETED) { + TEST_ASSERT_GREATER_THAN(0, urb->transfer.actual_num_bytes); } else { - TEST_ASSERT_EQUAL(0, irp->actual_num_bytes); + TEST_ASSERT_EQUAL(0, urb->transfer.actual_num_bytes); } - TEST_ASSERT_EQUAL(irp->context, IRP_CONTEXT_VAL); + TEST_ASSERT_EQUAL(urb->transfer.context, URB_CONTEXT_VAL); } - //Free IRP list and pipe - for (int i = 0; i < NUM_IRPS; i++) { - test_hcd_free_irp(irp_list[i]); + //Free URB list and pipe + for (int i = 0; i < NUM_URBS; i++) { + test_hcd_free_urb(urb_list[i]); } test_hcd_pipe_free(default_pipe); //Cleanup @@ -114,18 +120,18 @@ Test HCD control pipe STALL condition, abort, and clear Purpose: - Test that a control pipe can react to a STALL (i.e., a HCD_PIPE_EVENT_HALTED event) - - The HCD_PIPE_CMD_ABORT can retire all IRPs + - The HCD_PIPE_CMD_ABORT can retire all URBs - Pipe clear command can return the pipe to being active Procedure: - Setup HCD and wait for connection - - Setup default pipe and allocate IRPs - - Corrupt the first IRP so that it will trigger a STALL, then enqueue all the IRPs + - Setup default pipe and allocate URBs + - Corrupt the first URB so that it will trigger a STALL, then enqueue all the URBs - Check that a HCD_PIPE_EVENT_ERROR_STALL event is triggered - - Check that all IRPs can be retired using HCD_PIPE_CMD_ABORT + - Check that all URBs can be retired using HCD_PIPE_CMD_ABORT - Check that the STALL can be cleared by using HCD_PIPE_CMD_CLEAR - - Fix the corrupt first IRP and retry the IRPs - - Dequeue IRPs + - Fix the corrupt first URB and retry the URBs + - Dequeue URBs - Teardown */ TEST_CASE("Test HCD control pipe STALL", "[hcd][ignore]") @@ -134,39 +140,45 @@ TEST_CASE("Test HCD control pipe STALL", "[hcd][ignore]") usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); //Trigger a connection vTaskDelay(pdMS_TO_TICKS(100)); //Short delay send of SOF (for FS) or EOPs (for LS) - //Allocate some IRPs and initialize their data buffers with control transfers + //Allocate some URBs and initialize their data buffers with control transfers hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, TEST_DEV_ADDR, port_speed); //Create a default pipe (using a NULL EP descriptor) - usb_irp_t *irp_list[NUM_IRPS]; - for (int i = 0; i < NUM_IRPS; i++) { - irp_list[i] = test_hcd_alloc_irp(0, IRP_DATA_BUFF_SIZE); + urb_t *urb_list[NUM_URBS]; + for (int i = 0; i < NUM_URBS; i++) { + urb_list[i] = test_hcd_alloc_urb(0, URB_DATA_BUFF_SIZE); //Initialize with a "Get Config Descriptor request" - irp_list[i]->num_bytes = TRANSFER_MAX_BYTES; - USB_CTRL_REQ_INIT_GET_CFG_DESC((usb_ctrl_req_t *)irp_list[i]->data_buffer, 0, TRANSFER_MAX_BYTES); - irp_list[i]->context = IRP_CONTEXT_VAL; + urb_list[i]->transfer.num_bytes = TRANSFER_MAX_BYTES; + USB_CTRL_REQ_INIT_GET_CONFIG_DESC((usb_ctrl_req_t *)urb_list[i]->transfer.data_buffer, 0, TRANSFER_MAX_BYTES); + urb_list[i]->transfer.context = URB_CONTEXT_VAL; } - //Corrupt the first IRP so that it triggers a STALL - ((usb_ctrl_req_t *)irp_list[0]->data_buffer)->bRequest = 0xAA; + //Corrupt the first URB so that it triggers a STALL + ((usb_ctrl_req_t *)urb_list[0]->transfer.data_buffer)->bRequest = 0xAA; - //Enqueue IRPs. A STALL should occur - for (int i = 0; i < NUM_IRPS; i++) { - TEST_ASSERT_EQUAL(ESP_OK, hcd_irp_enqueue(default_pipe, irp_list[i])); + //Enqueue URBs. A STALL should occur + int num_enqueued = 0; + for (int i = 0; i < NUM_URBS; i++) { + if (hcd_urb_enqueue(default_pipe, urb_list[i]) != ESP_OK) { + //STALL may occur before we are done enqueing + break; + } + num_enqueued++; } + TEST_ASSERT_GREATER_THAN(0, num_enqueued); printf("Expecting STALL\n"); test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_ERROR_STALL); TEST_ASSERT_EQUAL(HCD_PIPE_STATE_HALTED, hcd_pipe_get_state(default_pipe)); - //Call the pipe abort command to retire all IRPs then dequeue them all + //Call the pipe abort command to retire all URBs then dequeue them all TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_command(default_pipe, HCD_PIPE_CMD_ABORT)); - for (int i = 0; i < NUM_IRPS; i++) { - usb_irp_t *irp = hcd_irp_dequeue(default_pipe); - TEST_ASSERT_EQUAL(irp_list[i], irp); - TEST_ASSERT(irp->status == USB_TRANSFER_STATUS_STALL || irp->status == USB_TRANSFER_STATUS_CANCELED); - if (irp->status == USB_TRANSFER_STATUS_COMPLETED) { - TEST_ASSERT_GREATER_THAN(0, irp->actual_num_bytes); + for (int i = 0; i < num_enqueued; i++) { + urb_t *urb = hcd_urb_dequeue(default_pipe); + TEST_ASSERT_EQUAL(urb_list[i], urb); + TEST_ASSERT(urb->transfer.status == USB_TRANSFER_STATUS_STALL || urb->transfer.status == USB_TRANSFER_STATUS_CANCELED); + if (urb->transfer.status == USB_TRANSFER_STATUS_COMPLETED) { + TEST_ASSERT_GREATER_THAN(0, urb->transfer.actual_num_bytes); } else { - TEST_ASSERT_EQUAL(0, irp->actual_num_bytes); + TEST_ASSERT_EQUAL(0, urb->transfer.actual_num_bytes); } - TEST_ASSERT_EQUAL(IRP_CONTEXT_VAL, irp->context); + TEST_ASSERT_EQUAL(URB_CONTEXT_VAL, urb->transfer.context); } //Call the clear command to un-stall the pipe @@ -174,26 +186,26 @@ TEST_CASE("Test HCD control pipe STALL", "[hcd][ignore]") TEST_ASSERT_EQUAL(HCD_PIPE_STATE_ACTIVE, hcd_pipe_get_state(default_pipe)); printf("Retrying\n"); - //Correct first IRP then requeue - USB_CTRL_REQ_INIT_GET_CFG_DESC((usb_ctrl_req_t *)irp_list[0]->data_buffer, 0, TRANSFER_MAX_BYTES); - for (int i = 0; i < NUM_IRPS; i++) { - TEST_ASSERT_EQUAL(ESP_OK, hcd_irp_enqueue(default_pipe, irp_list[i])); + //Correct first URB then requeue + USB_CTRL_REQ_INIT_GET_CONFIG_DESC((usb_ctrl_req_t *)urb_list[0]->transfer.data_buffer, 0, TRANSFER_MAX_BYTES); + for (int i = 0; i < NUM_URBS; i++) { + TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb_list[i])); } - //Wait for each IRP to be done, deequeue, and check results - for (int i = 0; i < NUM_IRPS; i++) { - test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_IRP_DONE); - //expect_pipe_event(pipe_evt_queue, default_pipe, HCD_PIPE_EVENT_IRP_DONE); - usb_irp_t *irp = hcd_irp_dequeue(default_pipe); - TEST_ASSERT_EQUAL(irp_list[i], irp); - TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, irp->status); - TEST_ASSERT_GREATER_THAN(0, irp->actual_num_bytes); - TEST_ASSERT_EQUAL(IRP_CONTEXT_VAL, irp->context); + //Wait for each URB to be done, deequeue, and check results + for (int i = 0; i < NUM_URBS; i++) { + test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_URB_DONE); + //expect_pipe_event(pipe_evt_queue, default_pipe, HCD_PIPE_EVENT_URB_DONE); + urb_t *urb = hcd_urb_dequeue(default_pipe); + TEST_ASSERT_EQUAL(urb_list[i], urb); + TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status); + TEST_ASSERT_GREATER_THAN(0, urb->transfer.actual_num_bytes); + TEST_ASSERT_EQUAL(URB_CONTEXT_VAL, urb->transfer.context); } - //Free IRP list and pipe - for (int i = 0; i < NUM_IRPS; i++) { - test_hcd_free_irp(irp_list[i]); + //Free URB list and pipe + for (int i = 0; i < NUM_URBS; i++) { + test_hcd_free_urb(urb_list[i]); } test_hcd_pipe_free(default_pipe); //Cleanup @@ -205,18 +217,18 @@ TEST_CASE("Test HCD control pipe STALL", "[hcd][ignore]") Test control pipe run-time halt and clear Purpose: - - Test that a control pipe can be halted with HCD_PIPE_CMD_HALT whilst there are ongoing IRPs + - Test that a control pipe can be halted with HCD_PIPE_CMD_HALT whilst there are ongoing URBs - Test that a control pipe can be un-halted with a HCD_PIPE_CMD_CLEAR - - Test that enqueued IRPs are resumed when pipe is un-halted + - Test that enqueued URBs are resumed when pipe is un-halted Procedure: - Setup HCD and wait for connection - - Setup default pipe and allocate IRPs - - Enqqueue IRPs but execute a HCD_PIPE_CMD_HALT command immediately after. Halt command should let on - the current going IRP finish before actually halting the pipe. - - Un-halt the pipe a HCD_PIPE_CMD_HALT command. Enqueued IRPs will be resumed - - Check that all IRPs have completed successfully - - Dequeue IRPs and teardown + - Setup default pipe and allocate URBs + - Enqqueue URBs but execute a HCD_PIPE_CMD_HALT command immediately after. Halt command should let on + the current going URB finish before actually halting the pipe. + - Un-halt the pipe a HCD_PIPE_CMD_HALT command. Enqueued URBs will be resumed + - Check that all URBs have completed successfully + - Dequeue URBs and teardown */ TEST_CASE("Test HCD control pipe runtime halt and clear", "[hcd][ignore]") { @@ -224,21 +236,21 @@ TEST_CASE("Test HCD control pipe runtime halt and clear", "[hcd][ignore]") usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); //Trigger a connection vTaskDelay(pdMS_TO_TICKS(100)); //Short delay send of SOF (for FS) or EOPs (for LS) - //Allocate some IRPs and initialize their data buffers with control transfers + //Allocate some URBs and initialize their data buffers with control transfers hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, TEST_DEV_ADDR, port_speed); //Create a default pipe (using a NULL EP descriptor) - usb_irp_t *irp_list[NUM_IRPS]; - for (int i = 0; i < NUM_IRPS; i++) { - irp_list[i] = test_hcd_alloc_irp(0, IRP_DATA_BUFF_SIZE); + urb_t *urb_list[NUM_URBS]; + for (int i = 0; i < NUM_URBS; i++) { + urb_list[i] = test_hcd_alloc_urb(0, URB_DATA_BUFF_SIZE); //Initialize with a "Get Config Descriptor request" - irp_list[i]->num_bytes = TRANSFER_MAX_BYTES; - USB_CTRL_REQ_INIT_GET_CFG_DESC((usb_ctrl_req_t *)irp_list[i]->data_buffer, 0, TRANSFER_MAX_BYTES); - irp_list[i]->context = IRP_CONTEXT_VAL; + urb_list[i]->transfer.num_bytes = TRANSFER_MAX_BYTES; + USB_CTRL_REQ_INIT_GET_CONFIG_DESC((usb_ctrl_req_t *)urb_list[i]->transfer.data_buffer, 0, TRANSFER_MAX_BYTES); + urb_list[i]->transfer.context = URB_CONTEXT_VAL; } - //Enqueue IRPs but immediately halt the pipe - printf("Enqueuing IRPs\n"); - for (int i = 0; i < NUM_IRPS; i++) { - TEST_ASSERT_EQUAL(ESP_OK, hcd_irp_enqueue(default_pipe, irp_list[i])); + //Enqueue URBs but immediately halt the pipe + printf("Enqueuing URBs\n"); + for (int i = 0; i < NUM_URBS; i++) { + TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb_list[i])); } TEST_ASSERT_EQUAL(ESP_OK, hcd_pipe_command(default_pipe, HCD_PIPE_CMD_HALT)); TEST_ASSERT_EQUAL(HCD_PIPE_STATE_HALTED, hcd_pipe_get_state(default_pipe)); @@ -250,19 +262,19 @@ TEST_CASE("Test HCD control pipe runtime halt and clear", "[hcd][ignore]") printf("Pipe cleared\n"); vTaskDelay(pdMS_TO_TICKS(100)); //Give some time pending for transfers to restart and complete - //Wait for each IRP to be done, dequeue, and check results - for (int i = 0; i < NUM_IRPS; i++) { - test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_IRP_DONE); - usb_irp_t *irp = hcd_irp_dequeue(default_pipe); - TEST_ASSERT_EQUAL(irp_list[i], irp); - TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, irp->status); - TEST_ASSERT_GREATER_THAN(0, irp->actual_num_bytes); - TEST_ASSERT_EQUAL(IRP_CONTEXT_VAL, irp->context); + //Wait for each URB to be done, dequeue, and check results + for (int i = 0; i < NUM_URBS; i++) { + test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_URB_DONE); + urb_t *urb = hcd_urb_dequeue(default_pipe); + TEST_ASSERT_EQUAL(urb_list[i], urb); + TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status); + TEST_ASSERT_GREATER_THAN(0, urb->transfer.actual_num_bytes); + TEST_ASSERT_EQUAL(URB_CONTEXT_VAL, urb->transfer.context); } - //Free IRP list and pipe - for (int i = 0; i < NUM_IRPS; i++) { - test_hcd_free_irp(irp_list[i]); + //Free URB list and pipe + for (int i = 0; i < NUM_URBS; i++) { + test_hcd_free_urb(urb_list[i]); } test_hcd_pipe_free(default_pipe); //Cleanup diff --git a/components/usb/test/hcd/test_hcd_intr.c b/components/usb/test/hcd/test_hcd_intr.c index 8495fd72eb..bf733932b7 100644 --- a/components/usb/test/hcd/test_hcd_intr.c +++ b/components/usb/test/hcd/test_hcd_intr.c @@ -84,32 +84,31 @@ static void mock_hid_process_report(mock_hid_mouse_report_t *report, int iter) // --------------------------------------------------- Test Cases ------------------------------------------------------ /* -Test HCD interrupt pipe IRPs +Test HCD interrupt pipe URBs Purpose: - Test that an interrupt pipe can be created - - IRPs can be created and enqueued to the interrupt pipe - - Interrupt pipe returns HCD_PIPE_EVENT_IRP_DONE - - Test that IRPs can be aborted when enqueued + - URBs can be created and enqueued to the interrupt pipe + - Interrupt pipe returns HCD_PIPE_EVENT_URB_DONE + - Test that URBs can be aborted when enqueued Procedure: - Setup HCD and wait for connection - Allocate default pipe and enumerate the device - - Setup interrupt pipe and allocate IRPs - - Enqueue IRPs, expect HCD_PIPE_EVENT_IRP_DONE, and requeue + - Setup interrupt pipe and allocate URBs + - Enqueue URBs, expect HCD_PIPE_EVENT_URB_DONE, and requeue - Stop after fixed number of iterations - - Deallocate IRPs + - Deallocate URBs - Teardown Note: Some mice will NAK until it is moved, so try moving the mouse around if this test case gets stuck. */ #define TEST_HID_DEV_SPEED USB_SPEED_LOW -#define NUM_IRPS 3 -#define IRP_DATA_BUFF_SIZE 4 //MPS is 4 -#define MOCK_HID_NUM_REPORT_PER_IRP 2 -#define NUM_IRP_ITERS (NUM_IRPS * 100) +#define NUM_URBS 3 +#define URB_DATA_BUFF_SIZE 4 //MPS is 4 +#define NUM_URB_ITERS (NUM_URBS * 100) -TEST_CASE("Test HCD interrupt pipe IRPs", "[hcd][ignore]") +TEST_CASE("Test HCD interrupt pipe URBs", "[hcd][ignore]") { hcd_port_handle_t port_hdl = test_hcd_setup(); //Setup the HCD and port usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); //Trigger a connection @@ -117,39 +116,39 @@ TEST_CASE("Test HCD interrupt pipe IRPs", "[hcd][ignore]") vTaskDelay(pdMS_TO_TICKS(100)); //Short delay send of SOF (for FS) or EOPs (for LS) hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, 0, port_speed); //Create a default pipe (using a NULL EP descriptor) - uint8_t dev_addr = test_hcd_enum_devc(default_pipe); + uint8_t dev_addr = test_hcd_enum_device(default_pipe); - //Allocate interrupt pipe and IRPS + //Allocate interrupt pipe and URBS hcd_pipe_handle_t intr_pipe = test_hcd_pipe_alloc(port_hdl, &in_ep_desc, dev_addr, port_speed); - usb_irp_t *irp_list[NUM_IRPS]; - for (int i = 0; i < NUM_IRPS; i++) { - irp_list[i] = test_hcd_alloc_irp(0, IRP_DATA_BUFF_SIZE); - irp_list[i]->num_bytes = IRP_DATA_BUFF_SIZE; - irp_list[i]->context = IRP_CONTEXT_VAL; + urb_t *urb_list[NUM_URBS]; + for (int i = 0; i < NUM_URBS; i++) { + urb_list[i] = test_hcd_alloc_urb(0, URB_DATA_BUFF_SIZE); + urb_list[i]->transfer.num_bytes = URB_DATA_BUFF_SIZE; + urb_list[i]->transfer.context = URB_CONTEXT_VAL; } - //Enqueue IRPs - for (int i = 0; i < NUM_IRPS; i++) { - TEST_ASSERT_EQUAL(ESP_OK, hcd_irp_enqueue(intr_pipe, irp_list[i])); + //Enqueue URBs + for (int i = 0; i < NUM_URBS; i++) { + TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(intr_pipe, urb_list[i])); } - int iter_count = NUM_IRP_ITERS; - for (iter_count = NUM_IRP_ITERS; iter_count > 0; iter_count--) { - //Wait for an IRP to be done - test_hcd_expect_pipe_event(intr_pipe, HCD_PIPE_EVENT_IRP_DONE); - //Dequeue the IRP and check results - usb_irp_t *irp = hcd_irp_dequeue(intr_pipe); - TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, irp->status); - TEST_ASSERT_EQUAL(IRP_CONTEXT_VAL, irp->context); - mock_hid_process_report((mock_hid_mouse_report_t *)irp->data_buffer, iter_count); - //Requeue IRP - if (iter_count > NUM_IRPS) { - TEST_ASSERT_EQUAL(ESP_OK, hcd_irp_enqueue(intr_pipe, irp)); + int iter_count = NUM_URB_ITERS; + for (iter_count = NUM_URB_ITERS; iter_count > 0; iter_count--) { + //Wait for an URB to be done + test_hcd_expect_pipe_event(intr_pipe, HCD_PIPE_EVENT_URB_DONE); + //Dequeue the URB and check results + urb_t *urb = hcd_urb_dequeue(intr_pipe); + TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.status); + TEST_ASSERT_EQUAL(URB_CONTEXT_VAL, urb->transfer.context); + mock_hid_process_report((mock_hid_mouse_report_t *)urb->transfer.data_buffer, iter_count); + //Requeue URB + if (iter_count > NUM_URBS) { + TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(intr_pipe, urb)); } } - //Free IRP list and pipe - for (int i = 0; i < NUM_IRPS; i++) { - test_hcd_free_irp(irp_list[i]); + //Free URB list and pipe + for (int i = 0; i < NUM_URBS; i++) { + test_hcd_free_urb(urb_list[i]); } test_hcd_pipe_free(intr_pipe); test_hcd_pipe_free(default_pipe); diff --git a/components/usb/test/hcd/test_hcd_isoc.c b/components/usb/test/hcd/test_hcd_isoc.c index 4379a7b0d2..f2c6e59220 100644 --- a/components/usb/test/hcd/test_hcd_isoc.c +++ b/components/usb/test/hcd/test_hcd_isoc.c @@ -24,10 +24,10 @@ #define MOCK_ISOC_EP_NUM 2 #define MOCK_ISOC_EP_MPS 512 -#define NUM_IRPS 3 -#define NUM_PACKETS_PER_IRP 3 +#define NUM_URBS 3 +#define NUM_PACKETS_PER_URB 3 #define ISOC_PACKET_SIZE MOCK_ISOC_EP_MPS -#define IRP_DATA_BUFF_SIZE (NUM_PACKETS_PER_IRP * ISOC_PACKET_SIZE) +#define URB_DATA_BUFF_SIZE (NUM_PACKETS_PER_URB * ISOC_PACKET_SIZE) static const usb_desc_ep_t isoc_out_ep_desc = { .bLength = sizeof(usb_desc_ep_t), @@ -39,26 +39,26 @@ static const usb_desc_ep_t isoc_out_ep_desc = { }; /* -Test HCD ISOC pipe IRPs +Test HCD ISOC pipe URBs Purpose: - Test that an isochronous pipe can be created - - IRPs can be created and enqueued to the isoc pipe pipe - - isoc pipe returns HCD_PIPE_EVENT_IRP_DONE for completed IRPs + - URBs can be created and enqueued to the isoc pipe pipe + - isoc pipe returns HCD_PIPE_EVENT_URB_DONE for completed URBs - Test utilizes ISOC OUT transfers and do not require ACKs. So the isoc pipe will target a non existing endpoint Procedure: - Setup HCD and wait for connection - Allocate default pipe and enumerate the device - - Allocate an isochronous pipe and multiple IRPs. Each IRP should contain multiple packets to test HCD's ability to - schedule an IRP across multiple intervals. - - Enqueue those IRPs - - Expect HCD_PIPE_EVENT_IRP_DONE for each IRP. Verify that data is correct using logic analyzer - - Deallocate IRPs + - Allocate an isochronous pipe and multiple URBs. Each URB should contain multiple packets to test HCD's ability to + schedule an URB across multiple intervals. + - Enqueue those URBs + - Expect HCD_PIPE_EVENT_URB_DONE for each URB. Verify that data is correct using logic analyzer + - Deallocate URBs - Teardown */ -TEST_CASE("Test HCD isochronous pipe IRPs", "[hcd][ignore]") +TEST_CASE("Test HCD isochronous pipe URBs", "[hcd][ignore]") { hcd_port_handle_t port_hdl = test_hcd_setup(); //Setup the HCD and port usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); //Trigger a connection @@ -68,43 +68,43 @@ TEST_CASE("Test HCD isochronous pipe IRPs", "[hcd][ignore]") //Enumerate and reset device hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, 0, port_speed); //Create a default pipe (using a NULL EP descriptor) - uint8_t dev_addr = test_hcd_enum_devc(default_pipe); + uint8_t dev_addr = test_hcd_enum_device(default_pipe); //Create ISOC OUT pipe to non-existent device hcd_pipe_handle_t isoc_out_pipe = test_hcd_pipe_alloc(port_hdl, &isoc_out_ep_desc, dev_addr + 1, port_speed); - //Create IRPs - usb_irp_t *irp_list[NUM_IRPS]; - //Initialize IRPs - for (int irp_idx = 0; irp_idx < NUM_IRPS; irp_idx++) { - irp_list[irp_idx] = test_hcd_alloc_irp(NUM_PACKETS_PER_IRP, IRP_DATA_BUFF_SIZE); - irp_list[irp_idx]->num_bytes = 0; //num_bytes is not used for ISOC - irp_list[irp_idx]->context = IRP_CONTEXT_VAL; - for (int pkt_idx = 0; pkt_idx < NUM_PACKETS_PER_IRP; pkt_idx++) { - irp_list[irp_idx]->iso_packet_desc[pkt_idx].length = ISOC_PACKET_SIZE; + //Create URBs + urb_t *urb_list[NUM_URBS]; + //Initialize URBs + for (int urb_idx = 0; urb_idx < NUM_URBS; urb_idx++) { + urb_list[urb_idx] = test_hcd_alloc_urb(NUM_PACKETS_PER_URB, URB_DATA_BUFF_SIZE); + urb_list[urb_idx]->transfer.num_bytes = 0; //num_bytes is not used for ISOC + urb_list[urb_idx]->transfer.context = URB_CONTEXT_VAL; + for (int pkt_idx = 0; pkt_idx < NUM_PACKETS_PER_URB; pkt_idx++) { + urb_list[urb_idx]->transfer.isoc_packet_desc[pkt_idx].num_bytes = ISOC_PACKET_SIZE; //Each packet will consist of the same byte, but each subsequent packet's byte will increment (i.e., packet 0 transmits all 0x0, packet 1 transmits all 0x1) - memset(&irp_list[irp_idx]->data_buffer[pkt_idx * ISOC_PACKET_SIZE], (irp_idx * NUM_IRPS) + pkt_idx, ISOC_PACKET_SIZE); + memset(&urb_list[urb_idx]->transfer.data_buffer[pkt_idx * ISOC_PACKET_SIZE], (urb_idx * NUM_URBS) + pkt_idx, ISOC_PACKET_SIZE); } } - //Enqueue IRPs - for (int i = 0; i < NUM_IRPS; i++) { - TEST_ASSERT_EQUAL(ESP_OK, hcd_irp_enqueue(isoc_out_pipe, irp_list[i])); + //Enqueue URBs + for (int i = 0; i < NUM_URBS; i++) { + TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(isoc_out_pipe, urb_list[i])); } - //Wait for each done event from each IRP - for (int i = 0; i < NUM_IRPS; i++) { - test_hcd_expect_pipe_event(isoc_out_pipe, HCD_PIPE_EVENT_IRP_DONE); + //Wait for each done event from each URB + for (int i = 0; i < NUM_URBS; i++) { + test_hcd_expect_pipe_event(isoc_out_pipe, HCD_PIPE_EVENT_URB_DONE); } - //Dequeue IRPs - for (int irp_idx = 0; irp_idx < NUM_IRPS; irp_idx++) { - usb_irp_t *irp = hcd_irp_dequeue(isoc_out_pipe); - TEST_ASSERT_EQUAL(irp_list[irp_idx], irp); - TEST_ASSERT_EQUAL(IRP_CONTEXT_VAL, irp->context); - for (int pkt_idx = 0; pkt_idx < NUM_PACKETS_PER_IRP; pkt_idx++) { - TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, irp->iso_packet_desc[pkt_idx].status); + //Dequeue URBs + for (int urb_idx = 0; urb_idx < NUM_URBS; urb_idx++) { + urb_t *urb = hcd_urb_dequeue(isoc_out_pipe); + TEST_ASSERT_EQUAL(urb_list[urb_idx], urb); + TEST_ASSERT_EQUAL(URB_CONTEXT_VAL, urb->transfer.context); + for (int pkt_idx = 0; pkt_idx < NUM_PACKETS_PER_URB; pkt_idx++) { + TEST_ASSERT_EQUAL(USB_TRANSFER_STATUS_COMPLETED, urb->transfer.isoc_packet_desc[pkt_idx].status); } } - //Free IRP list and pipe - for (int i = 0; i < NUM_IRPS; i++) { - test_hcd_free_irp(irp_list[i]); + //Free URB list and pipe + for (int i = 0; i < NUM_URBS; i++) { + test_hcd_free_urb(urb_list[i]); } test_hcd_pipe_free(isoc_out_pipe); test_hcd_pipe_free(default_pipe); diff --git a/components/usb/test/hcd/test_hcd_port.c b/components/usb/test/hcd/test_hcd_port.c index e3f5bab9be..5d2c56f8ab 100644 --- a/components/usb/test/hcd/test_hcd_port.c +++ b/components/usb/test/hcd/test_hcd_port.c @@ -20,16 +20,16 @@ #include "test_hcd_common.h" #define TEST_DEV_ADDR 0 -#define NUM_IRPS 3 +#define NUM_URBS 3 #define TRANSFER_MAX_BYTES 256 -#define IRP_DATA_BUFF_SIZE (sizeof(usb_ctrl_req_t) + TRANSFER_MAX_BYTES) //256 is worst case size for configuration descriptors +#define URB_DATA_BUFF_SIZE (sizeof(usb_ctrl_req_t) + TRANSFER_MAX_BYTES) //256 is worst case size for configuration descriptors /* Test a port sudden disconnect and port recovery Purpose: Test that when sudden disconnection happens on an HCD port, the port will - Generate the HCD_PORT_EVENT_SUDDEN_DISCONN and be put into the HCD_PORT_STATE_RECOVERY state - - Ongoing IRPs and pipes are handled correctly + - Ongoing URBs and pipes are handled correctly Procedure: - Setup the HCD and a port @@ -37,7 +37,7 @@ Procedure: - Create a default pipe - Start transfers but immediately trigger a disconnect - Check that HCD_PORT_EVENT_SUDDEN_DISCONN event is generated. Handle the event. - - Check that default pipe received a HCD_PIPE_EVENT_INVALID event. Pipe state should be invalid. Dequeue IRPs + - Check that default pipe received a HCD_PIPE_EVENT_INVALID event. Pipe state should be invalid. Dequeue URBs - Free default pipe - Recover the port - Trigger connection and disconnection again (to make sure the port works post recovery) @@ -50,21 +50,21 @@ TEST_CASE("Test HCD port sudden disconnect", "[hcd][ignore]") usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); //Trigger a connection vTaskDelay(pdMS_TO_TICKS(100)); //Short delay send of SOF (for FS) or EOPs (for LS) - //Allocate some IRPs and initialize their data buffers with control transfers + //Allocate some URBs and initialize their data buffers with control transfers hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, TEST_DEV_ADDR, port_speed); //Create a default pipe (using a NULL EP descriptor) - usb_irp_t *irp_list[NUM_IRPS]; - for (int i = 0; i < NUM_IRPS; i++) { - irp_list[i] = test_hcd_alloc_irp(0, IRP_DATA_BUFF_SIZE); + urb_t *urb_list[NUM_URBS]; + for (int i = 0; i < NUM_URBS; i++) { + urb_list[i] = test_hcd_alloc_urb(0, URB_DATA_BUFF_SIZE); //Initialize with a "Get Config Descriptor request" - irp_list[i]->num_bytes = TRANSFER_MAX_BYTES; - USB_CTRL_REQ_INIT_GET_CFG_DESC((usb_ctrl_req_t *)irp_list[i]->data_buffer, 0, TRANSFER_MAX_BYTES); - irp_list[i]->context = (void *)0xDEADBEEF; + urb_list[i]->transfer.num_bytes = TRANSFER_MAX_BYTES; + USB_CTRL_REQ_INIT_GET_CONFIG_DESC((usb_ctrl_req_t *)urb_list[i]->transfer.data_buffer, 0, TRANSFER_MAX_BYTES); + urb_list[i]->transfer.context = (void *)0xDEADBEEF; } - //Enqueue IRPs but immediately trigger a disconnect - printf("Enqueuing IRPs\n"); - for (int i = 0; i < NUM_IRPS; i++) { - TEST_ASSERT_EQUAL(ESP_OK, hcd_irp_enqueue(default_pipe, irp_list[i])); + //Enqueue URBs but immediately trigger a disconnect + printf("Enqueuing URBs\n"); + for (int i = 0; i < NUM_URBS; i++) { + TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb_list[i])); } test_hcd_force_conn_state(false, 0); //Disconnect event should have occurred. Handle the event @@ -73,29 +73,29 @@ TEST_CASE("Test HCD port sudden disconnect", "[hcd][ignore]") TEST_ASSERT_EQUAL(HCD_PORT_STATE_RECOVERY, hcd_port_get_state(port_hdl)); printf("Sudden disconnect\n"); - //Pipe should have received (zero or more HCD_PIPE_EVENT_IRP_DONE) followed by a HCD_PIPE_EVENT_INVALID (MUST OCCUR) + //Pipe should have received (zero or more HCD_PIPE_EVENT_URB_DONE) followed by a HCD_PIPE_EVENT_INVALID (MUST OCCUR) int num_pipe_events = test_hcd_get_num_pipe_events(default_pipe); for (int i = 0; i < num_pipe_events - 1; i++) { - test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_IRP_DONE); + test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_URB_DONE); } test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_INVALID); TEST_ASSERT_EQUAL(hcd_pipe_get_state(default_pipe), HCD_PIPE_STATE_INVALID); - //Dequeue IRPs - for (int i = 0; i < NUM_IRPS; i++) { - usb_irp_t *irp = hcd_irp_dequeue(default_pipe); - TEST_ASSERT_EQUAL(irp_list[i], irp); - TEST_ASSERT(irp->status == USB_TRANSFER_STATUS_COMPLETED || irp->status == USB_TRANSFER_STATUS_NO_DEVICE); - if (irp->status == USB_TRANSFER_STATUS_COMPLETED) { - TEST_ASSERT_GREATER_THAN(0, irp->actual_num_bytes); + //Dequeue URBs + for (int i = 0; i < NUM_URBS; i++) { + urb_t *urb = hcd_urb_dequeue(default_pipe); + TEST_ASSERT_EQUAL(urb_list[i], urb); + TEST_ASSERT(urb->transfer.status == USB_TRANSFER_STATUS_COMPLETED || urb->transfer.status == USB_TRANSFER_STATUS_NO_DEVICE); + if (urb->transfer.status == USB_TRANSFER_STATUS_COMPLETED) { + TEST_ASSERT_GREATER_THAN(0, urb->transfer.actual_num_bytes); } else { - TEST_ASSERT_EQUAL(0, irp->actual_num_bytes); + TEST_ASSERT_EQUAL(0, urb->transfer.actual_num_bytes); } - TEST_ASSERT_EQUAL(0xDEADBEEF, irp->context); + TEST_ASSERT_EQUAL(0xDEADBEEF, urb->transfer.context); } - //Free IRP list and pipe - for (int i = 0; i < NUM_IRPS; i++) { - test_hcd_free_irp(irp_list[i]); + //Free URB list and pipe + for (int i = 0; i < NUM_URBS; i++) { + test_hcd_free_urb(urb_list[i]); } test_hcd_pipe_free(default_pipe); @@ -123,8 +123,8 @@ Procedure: - Create a default pipe - Start transfers but suspend the port immediately - Resume the port - - Check that all the IRPs have completed successfully - - Cleanup IRPs and default pipe + - Check that all the URBs have completed successfully + - Cleanup URBs and default pipe - Trigger disconnection and teardown */ TEST_CASE("Test HCD port suspend and resume", "[hcd][ignore]") @@ -133,21 +133,21 @@ TEST_CASE("Test HCD port suspend and resume", "[hcd][ignore]") usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); //Trigger a connection vTaskDelay(pdMS_TO_TICKS(100)); //Short delay send of SOF (for FS) or EOPs (for LS) - //Allocate some IRPs and initialize their data buffers with control transfers + //Allocate some URBs and initialize their data buffers with control transfers hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, TEST_DEV_ADDR, port_speed); //Create a default pipe (using a NULL EP descriptor) - usb_irp_t *irp_list[NUM_IRPS]; - for (int i = 0; i < NUM_IRPS; i++) { - irp_list[i] = test_hcd_alloc_irp(0, IRP_DATA_BUFF_SIZE); + urb_t *urb_list[NUM_URBS]; + for (int i = 0; i < NUM_URBS; i++) { + urb_list[i] = test_hcd_alloc_urb(0, URB_DATA_BUFF_SIZE); //Initialize with a "Get Config Descriptor request" - irp_list[i]->num_bytes = TRANSFER_MAX_BYTES; - USB_CTRL_REQ_INIT_GET_CFG_DESC((usb_ctrl_req_t *)irp_list[i]->data_buffer, 0, TRANSFER_MAX_BYTES); - irp_list[i]->context = (void *)0xDEADBEEF; + urb_list[i]->transfer.num_bytes = TRANSFER_MAX_BYTES; + USB_CTRL_REQ_INIT_GET_CONFIG_DESC((usb_ctrl_req_t *)urb_list[i]->transfer.data_buffer, 0, TRANSFER_MAX_BYTES); + urb_list[i]->transfer.context = (void *)0xDEADBEEF; } - //Enqueue IRPs but immediately suspend the port - printf("Enqueuing IRPs\n"); - for (int i = 0; i < NUM_IRPS; i++) { - TEST_ASSERT_EQUAL(ESP_OK, hcd_irp_enqueue(default_pipe, irp_list[i])); + //Enqueue URBs but immediately suspend the port + printf("Enqueuing URBs\n"); + for (int i = 0; i < NUM_URBS; i++) { + TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb_list[i])); } TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_SUSPEND)); TEST_ASSERT_EQUAL(HCD_PORT_STATE_SUSPENDED, hcd_port_get_state(port_hdl)); @@ -158,19 +158,19 @@ TEST_CASE("Test HCD port suspend and resume", "[hcd][ignore]") TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_RESUME)); TEST_ASSERT_EQUAL(HCD_PORT_STATE_ENABLED, hcd_port_get_state(port_hdl)); printf("Resumed\n"); - vTaskDelay(pdMS_TO_TICKS(100)); //Give some time for resumed IRPs to complete - //Dequeue IRPs - for (int i = 0; i < NUM_IRPS; i++) { - usb_irp_t *irp = hcd_irp_dequeue(default_pipe); - TEST_ASSERT_EQUAL(irp_list[i], irp); - TEST_ASSERT_EQUAL(irp->status, USB_TRANSFER_STATUS_COMPLETED); - TEST_ASSERT_GREATER_THAN(0, irp->actual_num_bytes); - TEST_ASSERT_EQUAL(0xDEADBEEF, irp->context); + vTaskDelay(pdMS_TO_TICKS(100)); //Give some time for resumed URBs to complete + //Dequeue URBs + for (int i = 0; i < NUM_URBS; i++) { + urb_t *urb = hcd_urb_dequeue(default_pipe); + TEST_ASSERT_EQUAL(urb_list[i], urb); + TEST_ASSERT_EQUAL(urb->transfer.status, USB_TRANSFER_STATUS_COMPLETED); + TEST_ASSERT_GREATER_THAN(0, urb->transfer.actual_num_bytes); + TEST_ASSERT_EQUAL(0xDEADBEEF, urb->transfer.context); } - //Free IRP list and pipe - for (int i = 0; i < NUM_IRPS; i++) { - test_hcd_free_irp(irp_list[i]); + //Free URB list and pipe + for (int i = 0; i < NUM_URBS; i++) { + test_hcd_free_urb(urb_list[i]); } test_hcd_pipe_free(default_pipe); //Cleanup @@ -187,7 +187,7 @@ Purpose: - After disabling the port, all pipes should become invalid. Procedure: - - Setup HCD, a default pipe, and multiple IRPs + - Setup HCD, a default pipe, and multiple URBs - Start transfers but immediately disable the port - Check pipe received invalid event - Check that transfer are either done or not executed @@ -199,49 +199,49 @@ TEST_CASE("Test HCD port disable", "[hcd][ignore]") usb_speed_t port_speed = test_hcd_wait_for_conn(port_hdl); //Trigger a connection vTaskDelay(pdMS_TO_TICKS(100)); //Short delay send of SOF (for FS) or EOPs (for LS) - //Allocate some IRPs and initialize their data buffers with control transfers + //Allocate some URBs and initialize their data buffers with control transfers hcd_pipe_handle_t default_pipe = test_hcd_pipe_alloc(port_hdl, NULL, TEST_DEV_ADDR, port_speed); //Create a default pipe (using a NULL EP descriptor) - usb_irp_t *irp_list[NUM_IRPS]; - for (int i = 0; i < NUM_IRPS; i++) { - irp_list[i] = test_hcd_alloc_irp(0, IRP_DATA_BUFF_SIZE); + urb_t *urb_list[NUM_URBS]; + for (int i = 0; i < NUM_URBS; i++) { + urb_list[i] = test_hcd_alloc_urb(0, URB_DATA_BUFF_SIZE); //Initialize with a "Get Config Descriptor request" - irp_list[i]->num_bytes = TRANSFER_MAX_BYTES; - USB_CTRL_REQ_INIT_GET_CFG_DESC((usb_ctrl_req_t *)irp_list[i]->data_buffer, 0, TRANSFER_MAX_BYTES); - irp_list[i]->context = (void *)0xDEADBEEF; + urb_list[i]->transfer.num_bytes = TRANSFER_MAX_BYTES; + USB_CTRL_REQ_INIT_GET_CONFIG_DESC((usb_ctrl_req_t *)urb_list[i]->transfer.data_buffer, 0, TRANSFER_MAX_BYTES); + urb_list[i]->transfer.context = (void *)0xDEADBEEF; } - //Enqueue IRPs but immediately disable the port - printf("Enqueuing IRPs\n"); - for (int i = 0; i < NUM_IRPS; i++) { - TEST_ASSERT_EQUAL(ESP_OK, hcd_irp_enqueue(default_pipe, irp_list[i])); + //Enqueue URBs but immediately disable the port + printf("Enqueuing URBs\n"); + for (int i = 0; i < NUM_URBS; i++) { + TEST_ASSERT_EQUAL(ESP_OK, hcd_urb_enqueue(default_pipe, urb_list[i])); } TEST_ASSERT_EQUAL(ESP_OK, hcd_port_command(port_hdl, HCD_PORT_CMD_DISABLE)); TEST_ASSERT_EQUAL(HCD_PORT_STATE_DISABLED, hcd_port_get_state(port_hdl)); printf("Disabled\n"); - //Pipe should have received (zero or more HCD_PIPE_EVENT_IRP_DONE) followed by a HCD_PIPE_EVENT_INVALID (MUST OCCUR) + //Pipe should have received (zero or more HCD_PIPE_EVENT_URB_DONE) followed by a HCD_PIPE_EVENT_INVALID (MUST OCCUR) int num_pipe_events = test_hcd_get_num_pipe_events(default_pipe); for (int i = 0; i < num_pipe_events - 1; i++) { - test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_IRP_DONE); + test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_URB_DONE); } test_hcd_expect_pipe_event(default_pipe, HCD_PIPE_EVENT_INVALID); - //Dequeue IRPs - for (int i = 0; i < NUM_IRPS; i++) { - usb_irp_t *irp = hcd_irp_dequeue(default_pipe); - TEST_ASSERT_EQUAL(irp_list[i], irp); - TEST_ASSERT(irp->status == USB_TRANSFER_STATUS_COMPLETED || irp->status == USB_TRANSFER_STATUS_NO_DEVICE); - if (irp->status == USB_TRANSFER_STATUS_COMPLETED) { - TEST_ASSERT_GREATER_THAN(0, irp->actual_num_bytes); + //Dequeue URBs + for (int i = 0; i < NUM_URBS; i++) { + urb_t *urb = hcd_urb_dequeue(default_pipe); + TEST_ASSERT_EQUAL(urb_list[i], urb); + TEST_ASSERT(urb->transfer.status == USB_TRANSFER_STATUS_COMPLETED || urb->transfer.status == USB_TRANSFER_STATUS_NO_DEVICE); + if (urb->transfer.status == USB_TRANSFER_STATUS_COMPLETED) { + TEST_ASSERT_GREATER_THAN(0, urb->transfer.actual_num_bytes); } else { - TEST_ASSERT_EQUAL(0, irp->actual_num_bytes); + TEST_ASSERT_EQUAL(0, urb->transfer.actual_num_bytes); } - TEST_ASSERT_EQUAL(0xDEADBEEF, irp->context); + TEST_ASSERT_EQUAL(0xDEADBEEF, urb->transfer.context); } - //Free IRP list and pipe - for (int i = 0; i < NUM_IRPS; i++) { - test_hcd_free_irp(irp_list[i]); + //Free URB list and pipe + for (int i = 0; i < NUM_URBS; i++) { + test_hcd_free_urb(urb_list[i]); } test_hcd_pipe_free(default_pipe); //Cleanup