usb_host: Run formatting script

This commit is contained in:
Darian Leung
2023-05-09 00:53:27 +08:00
parent 3c7776cd58
commit aeef81cde7
13 changed files with 1604 additions and 1604 deletions

File diff suppressed because it is too large Load Diff

View File

@ -23,28 +23,28 @@ Implementation of the HUB driver that only supports the Root Hub with a single p
implement the bare minimum to control the root HCD port. implement the bare minimum to control the root HCD port.
*/ */
#define HUB_ROOT_PORT_NUM 1 //HCD only supports one port #define HUB_ROOT_PORT_NUM 1 // HCD only supports one port
#ifdef CONFIG_USB_HOST_HW_BUFFER_BIAS_IN #ifdef CONFIG_USB_HOST_HW_BUFFER_BIAS_IN
#define HUB_ROOT_HCD_PORT_FIFO_BIAS HCD_PORT_FIFO_BIAS_RX #define HUB_ROOT_HCD_PORT_FIFO_BIAS HCD_PORT_FIFO_BIAS_RX
#elif CONFIG_USB_HOST_HW_BUFFER_BIAS_PERIODIC_OUT #elif CONFIG_USB_HOST_HW_BUFFER_BIAS_PERIODIC_OUT
#define HUB_ROOT_HCD_PORT_FIFO_BIAS HCD_PORT_FIFO_BIAS_PTX #define HUB_ROOT_HCD_PORT_FIFO_BIAS HCD_PORT_FIFO_BIAS_PTX
#else //CONFIG_USB_HOST_HW_BUFFER_BIAS_BALANCED #else // CONFIG_USB_HOST_HW_BUFFER_BIAS_BALANCED
#define HUB_ROOT_HCD_PORT_FIFO_BIAS HCD_PORT_FIFO_BIAS_BALANCED #define HUB_ROOT_HCD_PORT_FIFO_BIAS HCD_PORT_FIFO_BIAS_BALANCED
#endif #endif
#define SET_ADDR_RECOVERY_INTERVAL_MS CONFIG_USB_HOST_SET_ADDR_RECOVERY_MS #define SET_ADDR_RECOVERY_INTERVAL_MS CONFIG_USB_HOST_SET_ADDR_RECOVERY_MS
#define ENUM_CTRL_TRANSFER_MAX_DATA_LEN CONFIG_USB_HOST_CONTROL_TRANSFER_MAX_SIZE #define ENUM_CTRL_TRANSFER_MAX_DATA_LEN CONFIG_USB_HOST_CONTROL_TRANSFER_MAX_SIZE
#define ENUM_DEV_ADDR 1 //Device address used in enumeration #define ENUM_DEV_ADDR 1 // Device address used in enumeration
#define ENUM_CONFIG_INDEX 0 //Index used to get the first configuration descriptor of the device #define ENUM_CONFIG_INDEX 0 // Index used to get the first configuration descriptor of the device
#define ENUM_SHORT_DESC_REQ_LEN 8 //Number of bytes to request when getting a short descriptor (just enough to get bMaxPacketSize0 or wTotalLength) #define ENUM_SHORT_DESC_REQ_LEN 8 // Number of bytes to request when getting a short descriptor (just enough to get bMaxPacketSize0 or wTotalLength)
#define ENUM_WORST_CASE_MPS_LS 8 //The worst case MPS of EP0 for a LS device #define ENUM_WORST_CASE_MPS_LS 8 // The worst case MPS of EP0 for a LS device
#define ENUM_WORST_CASE_MPS_FS 64 //The worst case MPS of EP0 for a FS device #define ENUM_WORST_CASE_MPS_FS 64 // The worst case MPS of EP0 for a FS device
#define ENUM_LOW_SPEED_MPS 8 //Worst case MPS for the default endpoint of a low-speed device #define ENUM_LOW_SPEED_MPS 8 // Worst case MPS for the default endpoint of a low-speed device
#define ENUM_FULL_SPEED_MPS 64 //Worst case MPS for the default endpoint of a full-speed device #define ENUM_FULL_SPEED_MPS 64 // Worst case MPS for the default endpoint of a full-speed device
#define ENUM_LANGID 0x409 //Current enumeration only supports English (United States) string descriptors #define ENUM_LANGID 0x409 // Current enumeration only supports English (United States) string descriptors
//Hub driver action flags. LISTED IN THE ORDER THEY SHOULD BE HANDLED IN within hub_process(). Some actions are mutually exclusive // Hub driver action flags. LISTED IN THE ORDER THEY SHOULD BE HANDLED IN within hub_process(). Some actions are mutually exclusive
#define HUB_DRIVER_FLAG_ACTION_ROOT_EVENT 0x01 #define HUB_DRIVER_FLAG_ACTION_ROOT_EVENT 0x01
#define HUB_DRIVER_FLAG_ACTION_PORT_DISABLE 0x02 #define HUB_DRIVER_FLAG_ACTION_PORT_DISABLE 0x02
#define HUB_DRIVER_FLAG_ACTION_PORT_RECOVER 0x04 #define HUB_DRIVER_FLAG_ACTION_PORT_RECOVER 0x04
@ -75,7 +75,7 @@ typedef enum {
typedef enum { typedef enum {
ENUM_STAGE_NONE = 0, /**< There is no device awaiting enumeration. Start requires device connection and first reset. */ ENUM_STAGE_NONE = 0, /**< There is no device awaiting enumeration. Start requires device connection and first reset. */
ENUM_STAGE_START, /**< A device has connected and has already been reset once. Allocate a device object in USBH */ ENUM_STAGE_START, /**< A device has connected and has already been reset once. Allocate a device object in USBH */
//Basic device enumeration // Basic device enumeration
ENUM_STAGE_GET_SHORT_DEV_DESC, /**< Getting short dev desc (wLength is ENUM_SHORT_DESC_REQ_LEN) */ ENUM_STAGE_GET_SHORT_DEV_DESC, /**< Getting short dev desc (wLength is ENUM_SHORT_DESC_REQ_LEN) */
ENUM_STAGE_CHECK_SHORT_DEV_DESC, /**< Save bMaxPacketSize0 from the short dev desc. Update the MPS of the enum pipe */ ENUM_STAGE_CHECK_SHORT_DEV_DESC, /**< Save bMaxPacketSize0 from the short dev desc. Update the MPS of the enum pipe */
ENUM_STAGE_SECOND_RESET, /**< Reset the device again (Workaround for old USB devices that get confused by the previous short dev desc request). */ ENUM_STAGE_SECOND_RESET, /**< Reset the device again (Workaround for old USB devices that get confused by the previous short dev desc request). */
@ -90,7 +90,7 @@ typedef enum {
ENUM_STAGE_CHECK_FULL_CONFIG_DESC, /**< Check the full config desc, fill it into the device object in USBH */ ENUM_STAGE_CHECK_FULL_CONFIG_DESC, /**< Check the full config desc, fill it into the device object in USBH */
ENUM_STAGE_SET_CONFIG, /**< Send SET_CONFIGURATION request */ ENUM_STAGE_SET_CONFIG, /**< Send SET_CONFIGURATION request */
ENUM_STAGE_CHECK_CONFIG, /**< Check that SET_CONFIGURATION request was successful */ ENUM_STAGE_CHECK_CONFIG, /**< Check that SET_CONFIGURATION request was successful */
//Get string descriptors // Get string descriptors
ENUM_STAGE_GET_SHORT_LANGID_TABLE, /**< Get the header of the LANGID table string descriptor */ ENUM_STAGE_GET_SHORT_LANGID_TABLE, /**< Get the header of the LANGID table string descriptor */
ENUM_STAGE_CHECK_SHORT_LANGID_TABLE, /**< Save the bLength of the LANGID table string descriptor */ ENUM_STAGE_CHECK_SHORT_LANGID_TABLE, /**< Save the bLength of the LANGID table string descriptor */
ENUM_STAGE_GET_FULL_LANGID_TABLE, /**< Get the full LANGID table string descriptor */ ENUM_STAGE_GET_FULL_LANGID_TABLE, /**< Get the full LANGID table string descriptor */
@ -107,7 +107,7 @@ typedef enum {
ENUM_STAGE_CHECK_SHORT_SER_STR_DESC, /**< Save the bLength of the iSerialNumber string descriptor */ ENUM_STAGE_CHECK_SHORT_SER_STR_DESC, /**< Save the bLength of the iSerialNumber string descriptor */
ENUM_STAGE_GET_FULL_SER_STR_DESC, /**< Get the full iSerialNumber string descriptor */ ENUM_STAGE_GET_FULL_SER_STR_DESC, /**< Get the full iSerialNumber string descriptor */
ENUM_STAGE_CHECK_FULL_SER_STR_DESC, /**< Check and fill the full iSerialNumber string descriptor */ ENUM_STAGE_CHECK_FULL_SER_STR_DESC, /**< Check and fill the full iSerialNumber string descriptor */
//Cleanup // Cleanup
ENUM_STAGE_CLEANUP, /**< Clean up after successful enumeration. Adds enumerated device to USBH */ ENUM_STAGE_CLEANUP, /**< Clean up after successful enumeration. Adds enumerated device to USBH */
ENUM_STAGE_CLEANUP_FAILED, /**< Cleanup failed enumeration. Free device resources */ ENUM_STAGE_CLEANUP_FAILED, /**< Cleanup failed enumeration. Free device resources */
} enum_stage_t; } enum_stage_t;
@ -150,12 +150,12 @@ const char *const enum_stage_strings[] = {
}; };
typedef struct { typedef struct {
//Constant // Constant
urb_t *urb; /**< URB used for enumeration control transfers. Max data length of ENUM_CTRL_TRANSFER_MAX_DATA_LEN */ urb_t *urb; /**< URB used for enumeration control transfers. Max data length of ENUM_CTRL_TRANSFER_MAX_DATA_LEN */
//Initialized at start of a particular enumeration // Initialized at start of a particular enumeration
usb_device_handle_t dev_hdl; /**< Handle of device being enumerated */ usb_device_handle_t dev_hdl; /**< Handle of device being enumerated */
hcd_pipe_handle_t pipe; /**< Default pipe handle of the device being enumerated */ hcd_pipe_handle_t pipe; /**< Default pipe handle of the device being enumerated */
//Updated during enumeration // Updated during enumeration
enum_stage_t stage; /**< Current enumeration stage */ enum_stage_t stage; /**< Current enumeration stage */
int expect_num_bytes; /**< Expected number of bytes for IN transfers stages. Set to 0 for OUT transfer */ int expect_num_bytes; /**< Expected number of bytes for IN transfers stages. Set to 0 for OUT transfer */
uint8_t bMaxPacketSize0; /**< Max packet size of the device's EP0. Read from bMaxPacketSize0 field of device descriptor */ uint8_t bMaxPacketSize0; /**< Max packet size of the device's EP0. Read from bMaxPacketSize0 field of device descriptor */
@ -168,7 +168,7 @@ typedef struct {
} enum_ctrl_t; } enum_ctrl_t;
typedef struct { typedef struct {
//Dynamic members require a critical section // Dynamic members require a critical section
struct { struct {
union { union {
struct { struct {
@ -179,12 +179,12 @@ typedef struct {
} flags; } flags;
hub_driver_state_t driver_state; hub_driver_state_t driver_state;
} dynamic; } dynamic;
//Single thread members don't require a critical section so long as they are never accessed from multiple threads // Single thread members don't require a critical section so long as they are never accessed from multiple threads
struct { struct {
usb_device_handle_t root_dev_hdl; //Indicates if an enumerated device is connected to the root port usb_device_handle_t root_dev_hdl; // Indicates if an enumerated device is connected to the root port
enum_ctrl_t enum_ctrl; enum_ctrl_t enum_ctrl;
} single_thread; } single_thread;
//Constant members do no change after installation thus do not require a critical section // Constant members do no change after installation thus do not require a critical section
struct { struct {
hcd_port_handle_t root_port_hdl; hcd_port_handle_t root_port_hdl;
usb_proc_req_cb_t proc_req_cb; usb_proc_req_cb_t proc_req_cb;
@ -263,20 +263,20 @@ static void usbh_hub_req_callback(hcd_port_handle_t port_hdl, usbh_hub_req_t hub
static bool enum_stage_start(enum_ctrl_t *enum_ctrl) static bool enum_stage_start(enum_ctrl_t *enum_ctrl)
{ {
//Get the speed of the device, and set the enum MPS to the worst case size for now // Get the speed of the device, and set the enum MPS to the worst case size for now
usb_speed_t speed; usb_speed_t speed;
if (hcd_port_get_speed(p_hub_driver_obj->constant.root_port_hdl, &speed) != ESP_OK) { if (hcd_port_get_speed(p_hub_driver_obj->constant.root_port_hdl, &speed) != ESP_OK) {
return false; return false;
} }
enum_ctrl->bMaxPacketSize0 = (speed == USB_SPEED_LOW) ? ENUM_WORST_CASE_MPS_LS : ENUM_WORST_CASE_MPS_FS; enum_ctrl->bMaxPacketSize0 = (speed == USB_SPEED_LOW) ? ENUM_WORST_CASE_MPS_LS : ENUM_WORST_CASE_MPS_FS;
//Try to add the device to USBH // Try to add the device to USBH
usb_device_handle_t enum_dev_hdl; usb_device_handle_t enum_dev_hdl;
hcd_pipe_handle_t enum_dflt_pipe_hdl; hcd_pipe_handle_t enum_dflt_pipe_hdl;
//We use NULL as the parent device to indicate the Root Hub port 1. We currently only support a single device // We use NULL as the parent device to indicate the Root Hub port 1. We currently only support a single device
if (usbh_hub_add_dev(p_hub_driver_obj->constant.root_port_hdl, speed, &enum_dev_hdl, &enum_dflt_pipe_hdl) != ESP_OK) { if (usbh_hub_add_dev(p_hub_driver_obj->constant.root_port_hdl, speed, &enum_dev_hdl, &enum_dflt_pipe_hdl) != ESP_OK) {
return false; return false;
} }
//Set our own default pipe callback // Set our own default pipe callback
ESP_ERROR_CHECK(hcd_pipe_update_callback(enum_dflt_pipe_hdl, enum_dflt_pipe_callback, NULL)); ESP_ERROR_CHECK(hcd_pipe_update_callback(enum_dflt_pipe_hdl, enum_dflt_pipe_callback, NULL));
enum_ctrl->dev_hdl = enum_dev_hdl; enum_ctrl->dev_hdl = enum_dev_hdl;
enum_ctrl->pipe = enum_dflt_pipe_hdl; enum_ctrl->pipe = enum_dflt_pipe_hdl;
@ -285,7 +285,7 @@ static bool enum_stage_start(enum_ctrl_t *enum_ctrl)
static bool enum_stage_second_reset(enum_ctrl_t *enum_ctrl) static bool enum_stage_second_reset(enum_ctrl_t *enum_ctrl)
{ {
ESP_ERROR_CHECK(hcd_pipe_set_persist_reset(enum_ctrl->pipe)); //Persist the default pipe through the reset ESP_ERROR_CHECK(hcd_pipe_set_persist_reset(enum_ctrl->pipe)); // Persist the default pipe through the reset
if (hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_RESET) != ESP_OK) { if (hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_RESET) != ESP_OK) {
ESP_LOGE(HUB_DRIVER_TAG, "Failed to issue second reset"); ESP_LOGE(HUB_DRIVER_TAG, "Failed to issue second reset");
return false; return false;
@ -298,26 +298,26 @@ static void get_string_desc_index_and_langid(enum_ctrl_t *enum_ctrl, uint8_t *in
switch (enum_ctrl->stage) { switch (enum_ctrl->stage) {
case ENUM_STAGE_GET_SHORT_LANGID_TABLE: case ENUM_STAGE_GET_SHORT_LANGID_TABLE:
case ENUM_STAGE_GET_FULL_LANGID_TABLE: case ENUM_STAGE_GET_FULL_LANGID_TABLE:
*index = 0; //The LANGID table uses an index of 0 *index = 0; // The LANGID table uses an index of 0
*langid = 0; //Getting the LANGID table itself should use a LANGID of 0 *langid = 0; // Getting the LANGID table itself should use a LANGID of 0
break; break;
case ENUM_STAGE_GET_SHORT_MANU_STR_DESC: case ENUM_STAGE_GET_SHORT_MANU_STR_DESC:
case ENUM_STAGE_GET_FULL_MANU_STR_DESC: case ENUM_STAGE_GET_FULL_MANU_STR_DESC:
*index = enum_ctrl->iManufacturer; *index = enum_ctrl->iManufacturer;
*langid = ENUM_LANGID; //Use the default LANGID *langid = ENUM_LANGID; // Use the default LANGID
break; break;
case ENUM_STAGE_GET_SHORT_PROD_STR_DESC: case ENUM_STAGE_GET_SHORT_PROD_STR_DESC:
case ENUM_STAGE_GET_FULL_PROD_STR_DESC: case ENUM_STAGE_GET_FULL_PROD_STR_DESC:
*index = enum_ctrl->iProduct; *index = enum_ctrl->iProduct;
*langid = ENUM_LANGID; //Use the default LANGID *langid = ENUM_LANGID; // Use the default LANGID
break; break;
case ENUM_STAGE_GET_SHORT_SER_STR_DESC: case ENUM_STAGE_GET_SHORT_SER_STR_DESC:
case ENUM_STAGE_GET_FULL_SER_STR_DESC: case ENUM_STAGE_GET_FULL_SER_STR_DESC:
*index = enum_ctrl->iSerialNumber; *index = enum_ctrl->iSerialNumber;
*langid = ENUM_LANGID; //Use the default LANGID *langid = ENUM_LANGID; // Use the default LANGID
break; break;
default: default:
//Should not occur // Should not occur
abort(); abort();
break; break;
} }
@ -328,47 +328,47 @@ static bool enum_stage_transfer(enum_ctrl_t *enum_ctrl)
usb_transfer_t *transfer = &enum_ctrl->urb->transfer; usb_transfer_t *transfer = &enum_ctrl->urb->transfer;
switch (enum_ctrl->stage) { switch (enum_ctrl->stage) {
case ENUM_STAGE_GET_SHORT_DEV_DESC: { case ENUM_STAGE_GET_SHORT_DEV_DESC: {
//Initialize a short device descriptor request // Initialize a short device descriptor request
USB_SETUP_PACKET_INIT_GET_DEVICE_DESC((usb_setup_packet_t *)transfer->data_buffer); USB_SETUP_PACKET_INIT_GET_DEVICE_DESC((usb_setup_packet_t *)transfer->data_buffer);
((usb_setup_packet_t *)transfer->data_buffer)->wLength = ENUM_SHORT_DESC_REQ_LEN; ((usb_setup_packet_t *)transfer->data_buffer)->wLength = ENUM_SHORT_DESC_REQ_LEN;
transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(ENUM_SHORT_DESC_REQ_LEN, enum_ctrl->bMaxPacketSize0); transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(ENUM_SHORT_DESC_REQ_LEN, enum_ctrl->bMaxPacketSize0);
//IN data stage should return exactly ENUM_SHORT_DESC_REQ_LEN bytes // IN data stage should return exactly ENUM_SHORT_DESC_REQ_LEN bytes
enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + ENUM_SHORT_DESC_REQ_LEN; enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + ENUM_SHORT_DESC_REQ_LEN;
break; break;
} }
case ENUM_STAGE_SET_ADDR: { case ENUM_STAGE_SET_ADDR: {
USB_SETUP_PACKET_INIT_SET_ADDR((usb_setup_packet_t *)transfer->data_buffer, ENUM_DEV_ADDR); USB_SETUP_PACKET_INIT_SET_ADDR((usb_setup_packet_t *)transfer->data_buffer, ENUM_DEV_ADDR);
transfer->num_bytes = sizeof(usb_setup_packet_t); //No data stage transfer->num_bytes = sizeof(usb_setup_packet_t); // No data stage
enum_ctrl->expect_num_bytes = 0; //OUT transfer. No need to check number of bytes returned enum_ctrl->expect_num_bytes = 0; // OUT transfer. No need to check number of bytes returned
break; break;
} }
case ENUM_STAGE_GET_FULL_DEV_DESC: { case ENUM_STAGE_GET_FULL_DEV_DESC: {
USB_SETUP_PACKET_INIT_GET_DEVICE_DESC((usb_setup_packet_t *)transfer->data_buffer); USB_SETUP_PACKET_INIT_GET_DEVICE_DESC((usb_setup_packet_t *)transfer->data_buffer);
transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(sizeof(usb_device_desc_t), enum_ctrl->bMaxPacketSize0); transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(sizeof(usb_device_desc_t), enum_ctrl->bMaxPacketSize0);
//IN data stage should return exactly sizeof(usb_device_desc_t) bytes // IN data stage should return exactly sizeof(usb_device_desc_t) bytes
enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + sizeof(usb_device_desc_t); enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + sizeof(usb_device_desc_t);
break; break;
} }
case ENUM_STAGE_GET_SHORT_CONFIG_DESC: { case ENUM_STAGE_GET_SHORT_CONFIG_DESC: {
//Get a short config descriptor at index 0 // Get a short config descriptor at index 0
USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)transfer->data_buffer, ENUM_CONFIG_INDEX, ENUM_SHORT_DESC_REQ_LEN); USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)transfer->data_buffer, ENUM_CONFIG_INDEX, ENUM_SHORT_DESC_REQ_LEN);
transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(ENUM_SHORT_DESC_REQ_LEN, enum_ctrl->bMaxPacketSize0); transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(ENUM_SHORT_DESC_REQ_LEN, enum_ctrl->bMaxPacketSize0);
//IN data stage should return exactly ENUM_SHORT_DESC_REQ_LEN bytes // IN data stage should return exactly ENUM_SHORT_DESC_REQ_LEN bytes
enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + ENUM_SHORT_DESC_REQ_LEN; enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + ENUM_SHORT_DESC_REQ_LEN;
break; break;
} }
case ENUM_STAGE_GET_FULL_CONFIG_DESC: { case ENUM_STAGE_GET_FULL_CONFIG_DESC: {
//Get the full configuration descriptor at index 0, requesting its exact length. // Get the full configuration descriptor at index 0, requesting its exact length.
USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)transfer->data_buffer, ENUM_CONFIG_INDEX, enum_ctrl->wTotalLength); USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)transfer->data_buffer, ENUM_CONFIG_INDEX, enum_ctrl->wTotalLength);
transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(enum_ctrl->wTotalLength, enum_ctrl->bMaxPacketSize0); transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(enum_ctrl->wTotalLength, enum_ctrl->bMaxPacketSize0);
//IN data stage should return exactly wTotalLength bytes // IN data stage should return exactly wTotalLength bytes
enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + enum_ctrl->wTotalLength; enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + enum_ctrl->wTotalLength;
break; break;
} }
case ENUM_STAGE_SET_CONFIG: { case ENUM_STAGE_SET_CONFIG: {
USB_SETUP_PACKET_INIT_SET_CONFIG((usb_setup_packet_t *)transfer->data_buffer, enum_ctrl->bConfigurationValue); USB_SETUP_PACKET_INIT_SET_CONFIG((usb_setup_packet_t *)transfer->data_buffer, enum_ctrl->bConfigurationValue);
transfer->num_bytes = sizeof(usb_setup_packet_t); //No data stage transfer->num_bytes = sizeof(usb_setup_packet_t); // No data stage
enum_ctrl->expect_num_bytes = 0; //OUT transfer. No need to check number of bytes returned enum_ctrl->expect_num_bytes = 0; // OUT transfer. No need to check number of bytes returned
break; break;
} }
case ENUM_STAGE_GET_SHORT_LANGID_TABLE: case ENUM_STAGE_GET_SHORT_LANGID_TABLE:
@ -378,13 +378,13 @@ static bool enum_stage_transfer(enum_ctrl_t *enum_ctrl)
uint8_t index; uint8_t index;
uint16_t langid; uint16_t langid;
get_string_desc_index_and_langid(enum_ctrl, &index, &langid); get_string_desc_index_and_langid(enum_ctrl, &index, &langid);
//Get only the header of the string descriptor // Get only the header of the string descriptor
USB_SETUP_PACKET_INIT_GET_STR_DESC((usb_setup_packet_t *)transfer->data_buffer, USB_SETUP_PACKET_INIT_GET_STR_DESC((usb_setup_packet_t *)transfer->data_buffer,
index, index,
langid, langid,
sizeof(usb_str_desc_t)); sizeof(usb_str_desc_t));
transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(sizeof(usb_str_desc_t), enum_ctrl->bMaxPacketSize0); transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(sizeof(usb_str_desc_t), enum_ctrl->bMaxPacketSize0);
//IN data stage should return exactly sizeof(usb_str_desc_t) bytes // IN data stage should return exactly sizeof(usb_str_desc_t) bytes
enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + sizeof(usb_str_desc_t); enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + sizeof(usb_str_desc_t);
break; break;
} }
@ -395,17 +395,17 @@ static bool enum_stage_transfer(enum_ctrl_t *enum_ctrl)
uint8_t index; uint8_t index;
uint16_t langid; uint16_t langid;
get_string_desc_index_and_langid(enum_ctrl, &index, &langid); get_string_desc_index_and_langid(enum_ctrl, &index, &langid);
//Get the full string descriptor at a particular index, requesting the descriptors exact length // Get the full string descriptor at a particular index, requesting the descriptors exact length
USB_SETUP_PACKET_INIT_GET_STR_DESC((usb_setup_packet_t *)transfer->data_buffer, USB_SETUP_PACKET_INIT_GET_STR_DESC((usb_setup_packet_t *)transfer->data_buffer,
index, index,
langid, langid,
enum_ctrl->str_desc_bLength); enum_ctrl->str_desc_bLength);
transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(enum_ctrl->str_desc_bLength, enum_ctrl->bMaxPacketSize0); transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(enum_ctrl->str_desc_bLength, enum_ctrl->bMaxPacketSize0);
//IN data stage should return exactly str_desc_bLength bytes // IN data stage should return exactly str_desc_bLength bytes
enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + enum_ctrl->str_desc_bLength; enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + enum_ctrl->str_desc_bLength;
break; break;
} }
default: //Should never occur default: // Should never occur
abort(); abort();
break; break;
} }
@ -424,7 +424,7 @@ static bool enum_stage_wait(enum_ctrl_t *enum_ctrl)
return true; return true;
} }
default: //Should never occur default: // Should never occur
abort(); abort();
break; break;
} }
@ -434,57 +434,57 @@ static bool enum_stage_wait(enum_ctrl_t *enum_ctrl)
static bool enum_stage_transfer_check(enum_ctrl_t *enum_ctrl) static bool enum_stage_transfer_check(enum_ctrl_t *enum_ctrl)
{ {
//Dequeue the URB // Dequeue the URB
urb_t *dequeued_enum_urb = hcd_urb_dequeue(enum_ctrl->pipe); urb_t *dequeued_enum_urb = hcd_urb_dequeue(enum_ctrl->pipe);
assert(dequeued_enum_urb == enum_ctrl->urb); assert(dequeued_enum_urb == enum_ctrl->urb);
//Check transfer status // Check transfer status
usb_transfer_t *transfer = &dequeued_enum_urb->transfer; usb_transfer_t *transfer = &dequeued_enum_urb->transfer;
if (transfer->status != USB_TRANSFER_STATUS_COMPLETED) { if (transfer->status != USB_TRANSFER_STATUS_COMPLETED) {
ESP_LOGE(HUB_DRIVER_TAG, "Bad transfer status %d: %s", transfer->status, enum_stage_strings[enum_ctrl->stage]); ESP_LOGE(HUB_DRIVER_TAG, "Bad transfer status %d: %s", transfer->status, enum_stage_strings[enum_ctrl->stage]);
if (transfer->status == USB_TRANSFER_STATUS_STALL) { if (transfer->status == USB_TRANSFER_STATUS_STALL) {
//EP stalled, clearing the pipe to execute further stages // EP stalled, clearing the pipe to execute further stages
ESP_ERROR_CHECK(hcd_pipe_command(enum_ctrl->pipe, HCD_PIPE_CMD_CLEAR)); ESP_ERROR_CHECK(hcd_pipe_command(enum_ctrl->pipe, HCD_PIPE_CMD_CLEAR));
} }
return false; return false;
} }
//Check IN transfer returned the expected correct number of bytes // Check IN transfer returned the expected correct number of bytes
if (enum_ctrl->expect_num_bytes != 0 && enum_ctrl->expect_num_bytes != transfer->actual_num_bytes) { if (enum_ctrl->expect_num_bytes != 0 && enum_ctrl->expect_num_bytes != transfer->actual_num_bytes) {
ESP_LOGE(HUB_DRIVER_TAG, "Incorrect number of bytes returned %d: %s", transfer->actual_num_bytes, enum_stage_strings[enum_ctrl->stage]); ESP_LOGE(HUB_DRIVER_TAG, "Incorrect number of bytes returned %d: %s", transfer->actual_num_bytes, enum_stage_strings[enum_ctrl->stage]);
return false; return false;
} }
//Stage specific checks and updates // Stage specific checks and updates
bool ret; bool ret;
switch (enum_ctrl->stage) { switch (enum_ctrl->stage) {
case ENUM_STAGE_CHECK_SHORT_DEV_DESC: { case ENUM_STAGE_CHECK_SHORT_DEV_DESC: {
const usb_device_desc_t *device_desc = (usb_device_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t)); const usb_device_desc_t *device_desc = (usb_device_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t));
//Check if the returned descriptor is corrupted // Check if the returned descriptor is corrupted
if (device_desc->bDescriptorType != USB_B_DESCRIPTOR_TYPE_DEVICE) { if (device_desc->bDescriptorType != USB_B_DESCRIPTOR_TYPE_DEVICE) {
ESP_LOGE(HUB_DRIVER_TAG, "Short dev desc corrupt"); ESP_LOGE(HUB_DRIVER_TAG, "Short dev desc corrupt");
ret = false; ret = false;
break; break;
} }
//Update and save the MPS of the default pipe // Update and save the MPS of the default pipe
if (hcd_pipe_update_mps(enum_ctrl->pipe, device_desc->bMaxPacketSize0) != ESP_OK) { if (hcd_pipe_update_mps(enum_ctrl->pipe, device_desc->bMaxPacketSize0) != ESP_OK) {
ESP_LOGE(HUB_DRIVER_TAG, "Failed to update MPS"); ESP_LOGE(HUB_DRIVER_TAG, "Failed to update MPS");
ret = false; ret = false;
break; break;
} }
//Save the actual MPS of EP0 // Save the actual MPS of EP0
enum_ctrl->bMaxPacketSize0 = device_desc->bMaxPacketSize0; enum_ctrl->bMaxPacketSize0 = device_desc->bMaxPacketSize0;
ret = true; ret = true;
break; break;
} }
case ENUM_STAGE_CHECK_ADDR: { case ENUM_STAGE_CHECK_ADDR: {
//Update the pipe and device's address, and fill the address into the device object // Update the pipe and device's address, and fill the address into the device object
ESP_ERROR_CHECK(hcd_pipe_update_dev_addr(enum_ctrl->pipe, ENUM_DEV_ADDR)); ESP_ERROR_CHECK(hcd_pipe_update_dev_addr(enum_ctrl->pipe, ENUM_DEV_ADDR));
ESP_ERROR_CHECK(usbh_hub_enum_fill_dev_addr(enum_ctrl->dev_hdl, ENUM_DEV_ADDR)); ESP_ERROR_CHECK(usbh_hub_enum_fill_dev_addr(enum_ctrl->dev_hdl, ENUM_DEV_ADDR));
ret = true; ret = true;
break; break;
} }
case ENUM_STAGE_CHECK_FULL_DEV_DESC: { case ENUM_STAGE_CHECK_FULL_DEV_DESC: {
//Fill device descriptor into the device object // Fill device descriptor into the device object
const usb_device_desc_t *device_desc = (const usb_device_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t)); const usb_device_desc_t *device_desc = (const usb_device_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t));
ESP_ERROR_CHECK(usbh_hub_enum_fill_dev_desc(enum_ctrl->dev_hdl, device_desc)); ESP_ERROR_CHECK(usbh_hub_enum_fill_dev_desc(enum_ctrl->dev_hdl, device_desc));
enum_ctrl->iManufacturer = device_desc->iManufacturer; enum_ctrl->iManufacturer = device_desc->iManufacturer;
@ -495,27 +495,27 @@ static bool enum_stage_transfer_check(enum_ctrl_t *enum_ctrl)
} }
case ENUM_STAGE_CHECK_SHORT_CONFIG_DESC: { case ENUM_STAGE_CHECK_SHORT_CONFIG_DESC: {
const usb_config_desc_t *config_desc = (usb_config_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t)); const usb_config_desc_t *config_desc = (usb_config_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t));
//Check if the returned descriptor is corrupted // Check if the returned descriptor is corrupted
if (config_desc->bDescriptorType != USB_B_DESCRIPTOR_TYPE_CONFIGURATION) { if (config_desc->bDescriptorType != USB_B_DESCRIPTOR_TYPE_CONFIGURATION) {
ESP_LOGE(HUB_DRIVER_TAG, "Short config desc corrupt"); ESP_LOGE(HUB_DRIVER_TAG, "Short config desc corrupt");
ret = false; ret = false;
break; break;
} }
#if (ENUM_CTRL_TRANSFER_MAX_DATA_LEN < UINT16_MAX) //Suppress -Wtype-limits warning due to uint16_t wTotalLength #if (ENUM_CTRL_TRANSFER_MAX_DATA_LEN < UINT16_MAX) // Suppress -Wtype-limits warning due to uint16_t wTotalLength
//Check if the descriptor is too long to be supported // Check if the descriptor is too long to be supported
if (config_desc->wTotalLength > ENUM_CTRL_TRANSFER_MAX_DATA_LEN) { if (config_desc->wTotalLength > ENUM_CTRL_TRANSFER_MAX_DATA_LEN) {
ESP_LOGE(HUB_DRIVER_TAG, "Configuration descriptor larger than control transfer max length"); ESP_LOGE(HUB_DRIVER_TAG, "Configuration descriptor larger than control transfer max length");
ret = false; ret = false;
break; break;
} }
#endif #endif
//Save the configuration descriptors full length // Save the configuration descriptors full length
enum_ctrl->wTotalLength = config_desc->wTotalLength; enum_ctrl->wTotalLength = config_desc->wTotalLength;
ret = true; ret = true;
break; break;
} }
case ENUM_STAGE_CHECK_FULL_CONFIG_DESC: { case ENUM_STAGE_CHECK_FULL_CONFIG_DESC: {
//Fill configuration descriptor into the device object // Fill configuration descriptor into the device object
const usb_config_desc_t *config_desc = (usb_config_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t)); const usb_config_desc_t *config_desc = (usb_config_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t));
enum_ctrl->bConfigurationValue = config_desc->bConfigurationValue; enum_ctrl->bConfigurationValue = config_desc->bConfigurationValue;
ESP_ERROR_CHECK(usbh_hub_enum_fill_config_desc(enum_ctrl->dev_hdl, config_desc)); ESP_ERROR_CHECK(usbh_hub_enum_fill_config_desc(enum_ctrl->dev_hdl, config_desc));
@ -524,7 +524,7 @@ static bool enum_stage_transfer_check(enum_ctrl_t *enum_ctrl)
} }
case ENUM_STAGE_CHECK_CONFIG: { case ENUM_STAGE_CHECK_CONFIG: {
ret = true; ret = true;
//Nothing to do // Nothing to do
break; break;
} }
case ENUM_STAGE_CHECK_SHORT_LANGID_TABLE: case ENUM_STAGE_CHECK_SHORT_LANGID_TABLE:
@ -532,7 +532,7 @@ static bool enum_stage_transfer_check(enum_ctrl_t *enum_ctrl)
case ENUM_STAGE_CHECK_SHORT_PROD_STR_DESC: case ENUM_STAGE_CHECK_SHORT_PROD_STR_DESC:
case ENUM_STAGE_CHECK_SHORT_SER_STR_DESC: { case ENUM_STAGE_CHECK_SHORT_SER_STR_DESC: {
const usb_str_desc_t *str_desc = (usb_str_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t)); const usb_str_desc_t *str_desc = (usb_str_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t));
//Check if the returned descriptor is supported or corrupted // Check if the returned descriptor is supported or corrupted
if (str_desc->bDescriptorType == 0) { if (str_desc->bDescriptorType == 0) {
ESP_LOGW(HUB_DRIVER_TAG, "String desc not supported"); ESP_LOGW(HUB_DRIVER_TAG, "String desc not supported");
ret = false; ret = false;
@ -542,15 +542,15 @@ static bool enum_stage_transfer_check(enum_ctrl_t *enum_ctrl)
ret = false; ret = false;
break; break;
} }
#if (ENUM_CTRL_TRANSFER_MAX_DATA_LEN < UINT8_MAX) //Suppress -Wtype-limits warning due to uint8_t bLength #if (ENUM_CTRL_TRANSFER_MAX_DATA_LEN < UINT8_MAX) // Suppress -Wtype-limits warning due to uint8_t bLength
//Check if the descriptor is too long to be supported // Check if the descriptor is too long to be supported
if (str_desc->bLength > (uint32_t)ENUM_CTRL_TRANSFER_MAX_DATA_LEN) { if (str_desc->bLength > (uint32_t)ENUM_CTRL_TRANSFER_MAX_DATA_LEN) {
ESP_LOGE(HUB_DRIVER_TAG, "String descriptor larger than control transfer max length"); ESP_LOGE(HUB_DRIVER_TAG, "String descriptor larger than control transfer max length");
ret = false; ret = false;
break; break;
} }
#endif #endif
//Save the descriptors full length // Save the descriptors full length
enum_ctrl->str_desc_bLength = str_desc->bLength; enum_ctrl->str_desc_bLength = str_desc->bLength;
ret = true; ret = true;
break; break;
@ -560,7 +560,7 @@ static bool enum_stage_transfer_check(enum_ctrl_t *enum_ctrl)
case ENUM_STAGE_CHECK_FULL_PROD_STR_DESC: case ENUM_STAGE_CHECK_FULL_PROD_STR_DESC:
case ENUM_STAGE_CHECK_FULL_SER_STR_DESC: { case ENUM_STAGE_CHECK_FULL_SER_STR_DESC: {
const usb_str_desc_t *str_desc = (usb_str_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t)); const usb_str_desc_t *str_desc = (usb_str_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t));
//Check if the returned descriptor is supported or corrupted // Check if the returned descriptor is supported or corrupted
if (str_desc->bDescriptorType == 0) { if (str_desc->bDescriptorType == 0) {
ESP_LOGW(HUB_DRIVER_TAG, "String desc not supported"); ESP_LOGW(HUB_DRIVER_TAG, "String desc not supported");
ret = false; ret = false;
@ -571,10 +571,10 @@ static bool enum_stage_transfer_check(enum_ctrl_t *enum_ctrl)
break; break;
} }
if (enum_ctrl->stage == ENUM_STAGE_CHECK_FULL_LANGID_TABLE) { if (enum_ctrl->stage == ENUM_STAGE_CHECK_FULL_LANGID_TABLE) {
//Scan the LANGID table for our target LANGID // Scan the LANGID table for our target LANGID
bool target_langid_found = false; bool target_langid_found = false;
int langid_table_num_entries = (str_desc->bLength - sizeof(usb_str_desc_t))/2; //Each LANGID is 2 bytes int langid_table_num_entries = (str_desc->bLength - sizeof(usb_str_desc_t)) / 2; // Each LANGID is 2 bytes
for (int i = 0; i < langid_table_num_entries; i++) { //Each LANGID is 2 bytes for (int i = 0; i < langid_table_num_entries; i++) { // Each LANGID is 2 bytes
if (str_desc->wData[i] == ENUM_LANGID) { if (str_desc->wData[i] == ENUM_LANGID) {
target_langid_found = true; target_langid_found = true;
break; break;
@ -586,13 +586,13 @@ static bool enum_stage_transfer_check(enum_ctrl_t *enum_ctrl)
ret = target_langid_found; ret = target_langid_found;
break; break;
} else { } else {
//Fill the string descriptor into the device object // Fill the string descriptor into the device object
int select; int select;
if (enum_ctrl->stage == ENUM_STAGE_CHECK_FULL_MANU_STR_DESC) { if (enum_ctrl->stage == ENUM_STAGE_CHECK_FULL_MANU_STR_DESC) {
select = 0; select = 0;
} else if (enum_ctrl->stage == ENUM_STAGE_CHECK_FULL_PROD_STR_DESC) { } else if (enum_ctrl->stage == ENUM_STAGE_CHECK_FULL_PROD_STR_DESC) {
select = 1; select = 1;
} else { //ENUM_STAGE_CHECK_FULL_PROD_STR_DESC } else { // ENUM_STAGE_CHECK_FULL_PROD_STR_DESC
select = 2; select = 2;
} }
ESP_ERROR_CHECK(usbh_hub_enum_fill_str_desc(enum_ctrl->dev_hdl, str_desc, select)); ESP_ERROR_CHECK(usbh_hub_enum_fill_str_desc(enum_ctrl->dev_hdl, str_desc, select));
@ -600,7 +600,7 @@ static bool enum_stage_transfer_check(enum_ctrl_t *enum_ctrl)
break; break;
} }
} }
default: //Should never occur default: // Should never occur
ret = false; ret = false;
abort(); abort();
break; break;
@ -610,39 +610,39 @@ static bool enum_stage_transfer_check(enum_ctrl_t *enum_ctrl)
static void enum_stage_cleanup(enum_ctrl_t *enum_ctrl) static void enum_stage_cleanup(enum_ctrl_t *enum_ctrl)
{ {
//We currently only support a single device connected to the root port. Move the device handle from enum to root // We currently only support a single device connected to the root port. Move the device handle from enum to root
HUB_DRIVER_ENTER_CRITICAL(); HUB_DRIVER_ENTER_CRITICAL();
p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_ACTIVE; p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_ACTIVE;
HUB_DRIVER_EXIT_CRITICAL(); HUB_DRIVER_EXIT_CRITICAL();
p_hub_driver_obj->single_thread.root_dev_hdl = enum_ctrl->dev_hdl; p_hub_driver_obj->single_thread.root_dev_hdl = enum_ctrl->dev_hdl;
usb_device_handle_t dev_hdl = enum_ctrl->dev_hdl; usb_device_handle_t dev_hdl = enum_ctrl->dev_hdl;
//Clear values in enum_ctrl // Clear values in enum_ctrl
enum_ctrl->dev_hdl = NULL; enum_ctrl->dev_hdl = NULL;
enum_ctrl->pipe = NULL; enum_ctrl->pipe = NULL;
//Update device object after enumeration is done // Update device object after enumeration is done
ESP_ERROR_CHECK(usbh_hub_enum_done(dev_hdl)); ESP_ERROR_CHECK(usbh_hub_enum_done(dev_hdl));
} }
static void enum_stage_cleanup_failed(enum_ctrl_t *enum_ctrl) static void enum_stage_cleanup_failed(enum_ctrl_t *enum_ctrl)
{ {
//Enumeration failed. Clear the enum device handle and pipe // Enumeration failed. Clear the enum device handle and pipe
if (enum_ctrl->dev_hdl) { if (enum_ctrl->dev_hdl) {
//If enumeration failed due to a port event, we need to Halt, flush, and dequeue enum default pipe in case there // If enumeration failed due to a port event, we need to Halt, flush, and dequeue enum default pipe in case there
//was an in-flight URB. // was an in-flight URB.
ESP_ERROR_CHECK(hcd_pipe_command(enum_ctrl->pipe, HCD_PIPE_CMD_HALT)); ESP_ERROR_CHECK(hcd_pipe_command(enum_ctrl->pipe, HCD_PIPE_CMD_HALT));
ESP_ERROR_CHECK(hcd_pipe_command(enum_ctrl->pipe, HCD_PIPE_CMD_FLUSH)); ESP_ERROR_CHECK(hcd_pipe_command(enum_ctrl->pipe, HCD_PIPE_CMD_FLUSH));
hcd_urb_dequeue(enum_ctrl->pipe); //This could return NULL if there hcd_urb_dequeue(enum_ctrl->pipe); // This could return NULL if there
ESP_ERROR_CHECK(usbh_hub_enum_failed(enum_ctrl->dev_hdl)); //Free the underlying device object first before recovering the port ESP_ERROR_CHECK(usbh_hub_enum_failed(enum_ctrl->dev_hdl)); // Free the underlying device object first before recovering the port
} }
//Clear values in enum_ctrl // Clear values in enum_ctrl
enum_ctrl->dev_hdl = NULL; enum_ctrl->dev_hdl = NULL;
enum_ctrl->pipe = NULL; enum_ctrl->pipe = NULL;
HUB_DRIVER_ENTER_CRITICAL(); HUB_DRIVER_ENTER_CRITICAL();
//Enum could have failed due to a port error. If so, we need to trigger a port recovery // Enum could have failed due to a port error. If so, we need to trigger a port recovery
if (p_hub_driver_obj->dynamic.driver_state == HUB_DRIVER_STATE_ROOT_RECOVERY) { if (p_hub_driver_obj->dynamic.driver_state == HUB_DRIVER_STATE_ROOT_RECOVERY) {
p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_RECOVER; p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_RECOVER;
} else { } else {
//Otherwise, we move to the enum failed state and wait for the device to disconnect // Otherwise, we move to the enum failed state and wait for the device to disconnect
p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_ENUM_FAILED; p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_ENUM_FAILED;
} }
HUB_DRIVER_EXIT_CRITICAL(); HUB_DRIVER_EXIT_CRITICAL();
@ -651,8 +651,8 @@ static void enum_stage_cleanup_failed(enum_ctrl_t *enum_ctrl)
static enum_stage_t get_next_stage(enum_stage_t old_stage, enum_ctrl_t *enum_ctrl) static enum_stage_t get_next_stage(enum_stage_t old_stage, enum_ctrl_t *enum_ctrl)
{ {
enum_stage_t new_stage = old_stage + 1; enum_stage_t new_stage = old_stage + 1;
//Skip the GET_DESCRIPTOR string type corresponding stages if a particular index is 0. // Skip the GET_DESCRIPTOR string type corresponding stages if a particular index is 0.
while(((new_stage == ENUM_STAGE_GET_SHORT_MANU_STR_DESC || while (((new_stage == ENUM_STAGE_GET_SHORT_MANU_STR_DESC ||
new_stage == ENUM_STAGE_CHECK_SHORT_MANU_STR_DESC || new_stage == ENUM_STAGE_CHECK_SHORT_MANU_STR_DESC ||
new_stage == ENUM_STAGE_GET_FULL_MANU_STR_DESC || new_stage == ENUM_STAGE_GET_FULL_MANU_STR_DESC ||
new_stage == ENUM_STAGE_CHECK_FULL_MANU_STR_DESC) && enum_ctrl->iManufacturer == 0) || new_stage == ENUM_STAGE_CHECK_FULL_MANU_STR_DESC) && enum_ctrl->iManufacturer == 0) ||
@ -671,7 +671,7 @@ static enum_stage_t get_next_stage(enum_stage_t old_stage, enum_ctrl_t *enum_ctr
static void enum_set_next_stage(enum_ctrl_t *enum_ctrl, bool last_stage_pass) static void enum_set_next_stage(enum_ctrl_t *enum_ctrl, bool last_stage_pass)
{ {
//Set next stage // Set next stage
if (last_stage_pass) { if (last_stage_pass) {
if (enum_ctrl->stage != ENUM_STAGE_NONE && if (enum_ctrl->stage != ENUM_STAGE_NONE &&
enum_ctrl->stage != ENUM_STAGE_CLEANUP && enum_ctrl->stage != ENUM_STAGE_CLEANUP &&
@ -683,7 +683,7 @@ static void enum_set_next_stage(enum_ctrl_t *enum_ctrl, bool last_stage_pass)
} else { } else {
switch (enum_ctrl->stage) { switch (enum_ctrl->stage) {
case ENUM_STAGE_START: case ENUM_STAGE_START:
//Stage failed but clean up not required // Stage failed but clean up not required
enum_ctrl->stage = ENUM_STAGE_NONE; enum_ctrl->stage = ENUM_STAGE_NONE;
break; break;
case ENUM_STAGE_GET_SHORT_LANGID_TABLE: case ENUM_STAGE_GET_SHORT_LANGID_TABLE:
@ -702,17 +702,17 @@ static void enum_set_next_stage(enum_ctrl_t *enum_ctrl, bool last_stage_pass)
case ENUM_STAGE_CHECK_SHORT_SER_STR_DESC: case ENUM_STAGE_CHECK_SHORT_SER_STR_DESC:
case ENUM_STAGE_GET_FULL_SER_STR_DESC: case ENUM_STAGE_GET_FULL_SER_STR_DESC:
case ENUM_STAGE_CHECK_FULL_SER_STR_DESC: case ENUM_STAGE_CHECK_FULL_SER_STR_DESC:
//String descriptor stages are allow to fail. We just don't fetch them and treat enumeration as successful // String descriptor stages are allow to fail. We just don't fetch them and treat enumeration as successful
enum_ctrl->stage = ENUM_STAGE_CLEANUP; enum_ctrl->stage = ENUM_STAGE_CLEANUP;
break; break;
default: default:
//Enumeration failed. Go to failure clean up // Enumeration failed. Go to failure clean up
enum_ctrl->stage = ENUM_STAGE_CLEANUP_FAILED; enum_ctrl->stage = ENUM_STAGE_CLEANUP_FAILED;
break; break;
} }
} }
//These stages are not waiting for a callback, so we need to re-trigger the enum event // These stages are not waiting for a callback, so we need to re-trigger the enum event
bool re_trigger; bool re_trigger;
switch (enum_ctrl->stage) { switch (enum_ctrl->stage) {
case ENUM_STAGE_GET_SHORT_DEV_DESC: case ENUM_STAGE_GET_SHORT_DEV_DESC:
@ -755,13 +755,13 @@ static bool root_port_callback(hcd_port_handle_t port_hdl, hcd_port_event_t port
HUB_DRIVER_ENTER_CRITICAL_SAFE(); HUB_DRIVER_ENTER_CRITICAL_SAFE();
p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ROOT_EVENT; p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ROOT_EVENT;
HUB_DRIVER_EXIT_CRITICAL_SAFE(); HUB_DRIVER_EXIT_CRITICAL_SAFE();
assert(in_isr); //Currently, this callback should only ever be called from an ISR context assert(in_isr); // Currently, this callback should only ever be called from an ISR context
return p_hub_driver_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_HUB, in_isr, p_hub_driver_obj->constant.proc_req_cb_arg);; return p_hub_driver_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_HUB, in_isr, p_hub_driver_obj->constant.proc_req_cb_arg);;
} }
static bool enum_dflt_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_event, void *user_arg, bool in_isr) static bool enum_dflt_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_event, void *user_arg, bool in_isr)
{ {
//Note: This callback may have triggered when a failed enumeration is already cleaned up (e.g., due to a failed port reset) // Note: This callback may have triggered when a failed enumeration is already cleaned up (e.g., due to a failed port reset)
HUB_DRIVER_ENTER_CRITICAL_SAFE(); HUB_DRIVER_ENTER_CRITICAL_SAFE();
p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT; p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT;
HUB_DRIVER_EXIT_CRITICAL_SAFE(); HUB_DRIVER_EXIT_CRITICAL_SAFE();
@ -770,7 +770,7 @@ static bool enum_dflt_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t
static void usbh_hub_req_callback(hcd_port_handle_t port_hdl, usbh_hub_req_t hub_req, void *arg) static void usbh_hub_req_callback(hcd_port_handle_t port_hdl, usbh_hub_req_t hub_req, void *arg)
{ {
//We currently only support the root port, so the port_hdl should match the root port // We currently only support the root port, so the port_hdl should match the root port
assert(port_hdl == p_hub_driver_obj->constant.root_port_hdl); assert(port_hdl == p_hub_driver_obj->constant.root_port_hdl);
HUB_DRIVER_ENTER_CRITICAL(); HUB_DRIVER_ENTER_CRITICAL();
@ -782,7 +782,7 @@ static void usbh_hub_req_callback(hcd_port_handle_t port_hdl, usbh_hub_req_t hub
p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_RECOVER; p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_RECOVER;
break; break;
default: default:
//Should never occur // Should never occur
abort(); abort();
break; break;
} }
@ -798,12 +798,12 @@ static void root_port_handle_events(hcd_port_handle_t root_port_hdl)
hcd_port_event_t port_event = hcd_port_handle_event(root_port_hdl); hcd_port_event_t port_event = hcd_port_handle_event(root_port_hdl);
switch (port_event) { switch (port_event) {
case HCD_PORT_EVENT_NONE: case HCD_PORT_EVENT_NONE:
//Nothing to do // Nothing to do
break; break;
case HCD_PORT_EVENT_CONNECTION: { case HCD_PORT_EVENT_CONNECTION: {
if (hcd_port_command(root_port_hdl, HCD_PORT_CMD_RESET) == ESP_OK) { if (hcd_port_command(root_port_hdl, HCD_PORT_CMD_RESET) == ESP_OK) {
ESP_LOGD(HUB_DRIVER_TAG, "Root port reset"); ESP_LOGD(HUB_DRIVER_TAG, "Root port reset");
//Start enumeration // Start enumeration
HUB_DRIVER_ENTER_CRITICAL(); HUB_DRIVER_ENTER_CRITICAL();
p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT; p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT;
p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_ENUM; p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_ENUM;
@ -820,22 +820,22 @@ static void root_port_handle_events(hcd_port_handle_t root_port_hdl)
bool pass_event_to_usbh = false; bool pass_event_to_usbh = false;
HUB_DRIVER_ENTER_CRITICAL(); HUB_DRIVER_ENTER_CRITICAL();
switch (p_hub_driver_obj->dynamic.driver_state) { switch (p_hub_driver_obj->dynamic.driver_state) {
case HUB_DRIVER_STATE_ROOT_POWERED: //This occurred before enumeration case HUB_DRIVER_STATE_ROOT_POWERED: // This occurred before enumeration
case HUB_DRIVER_STATE_ROOT_ENUM_FAILED: //This occurred after a failed enumeration. case HUB_DRIVER_STATE_ROOT_ENUM_FAILED: // This occurred after a failed enumeration.
//Therefore, there's no device and we can go straight to port recovery // Therefore, there's no device and we can go straight to port recovery
p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_RECOVER; p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_RECOVER;
break; break;
case HUB_DRIVER_STATE_ROOT_ENUM: case HUB_DRIVER_STATE_ROOT_ENUM:
//This occurred during enumeration. Therefore, we need to recover the failed enumeration // This occurred during enumeration. Therefore, we need to recover the failed enumeration
p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT; p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT;
p_hub_driver_obj->single_thread.enum_ctrl.stage = ENUM_STAGE_CLEANUP_FAILED; p_hub_driver_obj->single_thread.enum_ctrl.stage = ENUM_STAGE_CLEANUP_FAILED;
break; break;
case HUB_DRIVER_STATE_ROOT_ACTIVE: case HUB_DRIVER_STATE_ROOT_ACTIVE:
//There was an enumerated device. We need to indicate to USBH that the device is gone // There was an enumerated device. We need to indicate to USBH that the device is gone
pass_event_to_usbh = true; pass_event_to_usbh = true;
break; break;
default: default:
abort(); //Should never occur abort(); // Should never occur
break; break;
} }
p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_RECOVERY; p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_RECOVERY;
@ -847,7 +847,7 @@ static void root_port_handle_events(hcd_port_handle_t root_port_hdl)
break; break;
} }
default: default:
abort(); //Should never occur abort(); // Should never occur
break; break;
} }
} }
@ -863,7 +863,7 @@ static void enum_handle_events(void)
case ENUM_STAGE_SECOND_RESET: case ENUM_STAGE_SECOND_RESET:
stage_pass = enum_stage_second_reset(enum_ctrl); stage_pass = enum_stage_second_reset(enum_ctrl);
break; break;
//Transfer submission stages // Transfer submission stages
case ENUM_STAGE_GET_SHORT_DEV_DESC: case ENUM_STAGE_GET_SHORT_DEV_DESC:
case ENUM_STAGE_SET_ADDR: case ENUM_STAGE_SET_ADDR:
case ENUM_STAGE_GET_FULL_DEV_DESC: case ENUM_STAGE_GET_FULL_DEV_DESC:
@ -880,11 +880,11 @@ static void enum_handle_events(void)
case ENUM_STAGE_GET_FULL_SER_STR_DESC: case ENUM_STAGE_GET_FULL_SER_STR_DESC:
stage_pass = enum_stage_transfer(enum_ctrl); stage_pass = enum_stage_transfer(enum_ctrl);
break; break;
//Recovery interval // Recovery interval
case ENUM_STAGE_SET_ADDR_RECOVERY: case ENUM_STAGE_SET_ADDR_RECOVERY:
stage_pass = enum_stage_wait(enum_ctrl); stage_pass = enum_stage_wait(enum_ctrl);
break; break;
//Transfer check stages // Transfer check stages
case ENUM_STAGE_CHECK_SHORT_DEV_DESC: case ENUM_STAGE_CHECK_SHORT_DEV_DESC:
case ENUM_STAGE_CHECK_ADDR: case ENUM_STAGE_CHECK_ADDR:
case ENUM_STAGE_CHECK_FULL_DEV_DESC: case ENUM_STAGE_CHECK_FULL_DEV_DESC:
@ -910,7 +910,7 @@ static void enum_handle_events(void)
stage_pass = true; stage_pass = true;
break; break;
default: default:
//Note: Don't abort here. The enum_dflt_pipe_callback() can trigger a HUB_DRIVER_FLAG_ACTION_ENUM_EVENT after a cleanup. // Note: Don't abort here. The enum_dflt_pipe_callback() can trigger a HUB_DRIVER_FLAG_ACTION_ENUM_EVENT after a cleanup.
stage_pass = true; stage_pass = true;
break; break;
} }
@ -929,14 +929,14 @@ esp_err_t hub_install(hub_config_t *hub_config)
HUB_DRIVER_ENTER_CRITICAL(); HUB_DRIVER_ENTER_CRITICAL();
HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj == NULL, ESP_ERR_INVALID_STATE); HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj == NULL, ESP_ERR_INVALID_STATE);
HUB_DRIVER_EXIT_CRITICAL(); HUB_DRIVER_EXIT_CRITICAL();
//Allocate Hub driver object // Allocate Hub driver object
hub_driver_t *hub_driver_obj = heap_caps_calloc(1, sizeof(hub_driver_t), MALLOC_CAP_DEFAULT); hub_driver_t *hub_driver_obj = heap_caps_calloc(1, sizeof(hub_driver_t), MALLOC_CAP_DEFAULT);
urb_t *enum_urb = urb_alloc(sizeof(usb_setup_packet_t) + ENUM_CTRL_TRANSFER_MAX_DATA_LEN, 0, 0); urb_t *enum_urb = urb_alloc(sizeof(usb_setup_packet_t) + ENUM_CTRL_TRANSFER_MAX_DATA_LEN, 0, 0);
if (hub_driver_obj == NULL || enum_urb == NULL) { if (hub_driver_obj == NULL || enum_urb == NULL) {
return ESP_ERR_NO_MEM; return ESP_ERR_NO_MEM;
} }
esp_err_t ret; esp_err_t ret;
//Install HCD port // Install HCD port
hcd_port_config_t port_config = { hcd_port_config_t port_config = {
.fifo_bias = HUB_ROOT_HCD_PORT_FIFO_BIAS, .fifo_bias = HUB_ROOT_HCD_PORT_FIFO_BIAS,
.callback = root_port_callback, .callback = root_port_callback,
@ -948,7 +948,7 @@ esp_err_t hub_install(hub_config_t *hub_config)
if (ret != ESP_OK) { if (ret != ESP_OK) {
goto err; goto err;
} }
//Initialize Hub driver object // Initialize Hub driver object
hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_INSTALLED; hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_INSTALLED;
hub_driver_obj->single_thread.enum_ctrl.stage = ENUM_STAGE_NONE; hub_driver_obj->single_thread.enum_ctrl.stage = ENUM_STAGE_NONE;
hub_driver_obj->single_thread.enum_ctrl.urb = enum_urb; hub_driver_obj->single_thread.enum_ctrl.urb = enum_urb;
@ -963,7 +963,7 @@ esp_err_t hub_install(hub_config_t *hub_config)
} }
p_hub_driver_obj = hub_driver_obj; p_hub_driver_obj = hub_driver_obj;
HUB_DRIVER_EXIT_CRITICAL(); HUB_DRIVER_EXIT_CRITICAL();
//Indicate to USBH that the hub is installed // Indicate to USBH that the hub is installed
ESP_ERROR_CHECK(usbh_hub_is_installed(usbh_hub_req_callback, NULL)); ESP_ERROR_CHECK(usbh_hub_is_installed(usbh_hub_req_callback, NULL));
ret = ESP_OK; ret = ESP_OK;
return ret; return ret;
@ -986,7 +986,7 @@ esp_err_t hub_uninstall(void)
HUB_DRIVER_EXIT_CRITICAL(); HUB_DRIVER_EXIT_CRITICAL();
ESP_ERROR_CHECK(hcd_port_deinit(hub_driver_obj->constant.root_port_hdl)); ESP_ERROR_CHECK(hcd_port_deinit(hub_driver_obj->constant.root_port_hdl));
//Free Hub driver resources // Free Hub driver resources
urb_free(hub_driver_obj->single_thread.enum_ctrl.urb); urb_free(hub_driver_obj->single_thread.enum_ctrl.urb);
heap_caps_free(hub_driver_obj); heap_caps_free(hub_driver_obj);
return ESP_OK; return ESP_OK;
@ -998,7 +998,7 @@ esp_err_t hub_root_start(void)
HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj != NULL, ESP_ERR_INVALID_STATE); HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj != NULL, ESP_ERR_INVALID_STATE);
HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj->dynamic.driver_state == HUB_DRIVER_STATE_INSTALLED, ESP_ERR_INVALID_STATE); HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj->dynamic.driver_state == HUB_DRIVER_STATE_INSTALLED, ESP_ERR_INVALID_STATE);
HUB_DRIVER_EXIT_CRITICAL(); HUB_DRIVER_EXIT_CRITICAL();
//Power ON the root port // Power ON the root port
esp_err_t ret; esp_err_t ret;
ret = hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_POWER_ON); ret = hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_POWER_ON);
if (ret == ESP_OK) { if (ret == ESP_OK) {
@ -1045,7 +1045,7 @@ esp_err_t hub_process(void)
ESP_LOGD(HUB_DRIVER_TAG, "Disabling root port"); ESP_LOGD(HUB_DRIVER_TAG, "Disabling root port");
hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_DISABLE); hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_DISABLE);
ESP_ERROR_CHECK(usbh_hub_pass_event(p_hub_driver_obj->single_thread.root_dev_hdl, USBH_HUB_EVENT_PORT_DISABLED)); ESP_ERROR_CHECK(usbh_hub_pass_event(p_hub_driver_obj->single_thread.root_dev_hdl, USBH_HUB_EVENT_PORT_DISABLED));
//The root port has been disabled, so the root_dev_hdl is no longer valid // The root port has been disabled, so the root_dev_hdl is no longer valid
p_hub_driver_obj->single_thread.root_dev_hdl = NULL; p_hub_driver_obj->single_thread.root_dev_hdl = NULL;
} }
@ -1056,7 +1056,7 @@ esp_err_t hub_process(void)
HUB_DRIVER_ENTER_CRITICAL(); HUB_DRIVER_ENTER_CRITICAL();
p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_POWERED; p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_POWERED;
HUB_DRIVER_EXIT_CRITICAL(); HUB_DRIVER_EXIT_CRITICAL();
//USBH requesting a port recovery means the device has already been freed. Clear root_dev_hdl // USBH requesting a port recovery means the device has already been freed. Clear root_dev_hdl
p_hub_driver_obj->single_thread.root_dev_hdl = NULL; p_hub_driver_obj->single_thread.root_dev_hdl = NULL;
} }

View File

@ -14,7 +14,7 @@ Warning: The USB Host Library API is still a beta version and may be subject to
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "esp_err.h" #include "esp_err.h"
#include "esp_intr_alloc.h" #include "esp_intr_alloc.h"
//Include the other USB Host Library headers as well // Include the other USB Host Library headers as well
#include "usb/usb_helpers.h" #include "usb/usb_helpers.h"
#include "usb/usb_types_ch9.h" #include "usb/usb_types_ch9.h"
#include "usb/usb_types_stack.h" #include "usb/usb_types_stack.h"
@ -34,7 +34,7 @@ extern "C" {
* *
* @note Asynchronous API * @note Asynchronous API
*/ */
typedef struct usb_host_client_handle_s * usb_host_client_handle_t; typedef struct usb_host_client_handle_s *usb_host_client_handle_t;
// ----------------------- Events -------------------------- // ----------------------- Events --------------------------
@ -116,7 +116,7 @@ typedef struct {
typedef struct { typedef struct {
bool is_synchronous; /**< Whether the client is asynchronous or synchronous or not. Set to false for now. */ bool is_synchronous; /**< Whether the client is asynchronous or synchronous or not. Set to false for now. */
int max_num_event_msg; /**< Maximum number of event messages that can be stored (e.g., 3) */ int max_num_event_msg; /**< Maximum number of event messages that can be stored (e.g., 3) */
union { //Note: Made into union or future expansion union { // Note: Made into union or future expansion
struct { struct {
usb_host_client_event_cb_t client_event_callback; /**< Client's event callback function */ usb_host_client_event_cb_t client_event_callback; /**< Client's event callback function */
void *callback_arg; /**< Event callback function argument */ void *callback_arg; /**< Event callback function argument */

View File

@ -346,10 +346,10 @@ ESP_STATIC_ASSERT(sizeof(usb_config_desc_t) == USB_CONFIG_DESC_SIZE, "Size of us
/** /**
* @brief Bit masks belonging to the bmAttributes field of a configuration descriptor * @brief Bit masks belonging to the bmAttributes field of a configuration descriptor
*/ */
#define USB_BM_ATTRIBUTES_ONE (1 << 7) //Must be set #define USB_BM_ATTRIBUTES_ONE (1 << 7) /**< Must be set */
#define USB_BM_ATTRIBUTES_SELFPOWER (1 << 6) //Self powered #define USB_BM_ATTRIBUTES_SELFPOWER (1 << 6) /**< Self powered */
#define USB_BM_ATTRIBUTES_WAKEUP (1 << 5) //Can wake-up #define USB_BM_ATTRIBUTES_WAKEUP (1 << 5) /**< Can wake-up */
#define USB_BM_ATTRIBUTES_BATTERY (1 << 4) //Battery powered #define USB_BM_ATTRIBUTES_BATTERY (1 << 4) /**< Battery powered */
// ---------- Interface Association Descriptor ------------- // ---------- Interface Association Descriptor -------------

View File

@ -43,7 +43,7 @@ typedef enum {
/** /**
* @brief Handle of a USB Device connected to a USB Host * @brief Handle of a USB Device connected to a USB Host
*/ */
typedef struct usb_device_handle_s * usb_device_handle_t; typedef struct usb_device_handle_s *usb_device_handle_t;
/** /**
* @brief Basic information of an enumerated device * @brief Basic information of an enumerated device
@ -126,7 +126,7 @@ typedef void (*usb_transfer_cb_t)(usb_transfer_t *transfer);
* @brief USB transfer structure * @brief USB transfer structure
* *
*/ */
struct usb_transfer_s{ struct usb_transfer_s {
uint8_t *const data_buffer; /**< Pointer to data buffer */ uint8_t *const data_buffer; /**< Pointer to data buffer */
const size_t data_buffer_size; /**< Size of the data buffer in bytes */ const size_t data_buffer_size; /**< Size of the data buffer in bytes */
int num_bytes; /**< Number of bytes to transfer. int num_bytes; /**< Number of bytes to transfer.

View File

@ -116,12 +116,12 @@ typedef enum {
/** /**
* @brief Port handle type * @brief Port handle type
*/ */
typedef void * hcd_port_handle_t; typedef void *hcd_port_handle_t;
/** /**
* @brief Pipe handle type * @brief Pipe handle type
*/ */
typedef void * hcd_pipe_handle_t; typedef void *hcd_pipe_handle_t;
/** /**
* @brief Port event callback type * @brief Port event callback type

View File

@ -36,16 +36,16 @@ typedef struct {
} usb_transfer_dummy_t; } 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"); _Static_assert(sizeof(usb_transfer_dummy_t) == sizeof(usb_transfer_t), "usb_transfer_dummy_t does not match usb_transfer_t");
struct urb_s{ struct urb_s {
TAILQ_ENTRY(urb_s) tailq_entry; TAILQ_ENTRY(urb_s) tailq_entry;
//HCD Layer: Handler pointer and variables. Must be initialized to NULL and 0 respectively // HCD Layer: Handler pointer and variables. Must be initialized to NULL and 0 respectively
void *hcd_ptr; void *hcd_ptr;
uint32_t hcd_var; uint32_t hcd_var;
//Host Lib Layer: // Host Lib Layer:
void *usb_host_client; //Currently only used when submitted to shared pipes (i.e., Device default pipes) void *usb_host_client; // Currently only used when submitted to shared pipes (i.e., Device default pipes)
size_t usb_host_header_size; //USB Host may need the data buffer to have a transparent header size_t usb_host_header_size; // USB Host may need the data buffer to have a transparent header
bool usb_host_inflight; //Debugging variable, used to prevent re-submitting URBs already inflight bool usb_host_inflight; // Debugging variable, used to prevent re-submitting URBs already inflight
//Public transfer structure. Must be last due to variable length array // Public transfer structure. Must be last due to variable length array
usb_transfer_t transfer; usb_transfer_t transfer;
}; };
typedef struct urb_s urb_t; typedef struct urb_s urb_t;

View File

@ -25,7 +25,7 @@ extern "C" {
/** /**
* @brief Handle of a allocated endpoint * @brief Handle of a allocated endpoint
*/ */
typedef struct usbh_ep_handle_s * usbh_ep_handle_t; typedef struct usbh_ep_handle_s *usbh_ep_handle_t;
// ----------------------- Events -------------------------- // ----------------------- Events --------------------------

View File

@ -21,12 +21,12 @@ const usb_standard_desc_t *usb_parse_next_descriptor(const usb_standard_desc_t *
{ {
assert(cur_desc != NULL && offset != NULL); assert(cur_desc != NULL && offset != NULL);
if (*offset >= wTotalLength) { if (*offset >= wTotalLength) {
return NULL; //We have traversed the entire configuration descriptor return NULL; // We have traversed the entire configuration descriptor
} }
if (*offset + cur_desc->bLength >= wTotalLength) { if (*offset + cur_desc->bLength >= wTotalLength) {
return NULL; //Next descriptor is out of bounds return NULL; // Next descriptor is out of bounds
} }
//Return the next descriptor, update offset // Return the next descriptor, update offset
const usb_standard_desc_t *ret_desc = (const usb_standard_desc_t *)(((uint32_t)cur_desc) + cur_desc->bLength); const usb_standard_desc_t *ret_desc = (const usb_standard_desc_t *)(((uint32_t)cur_desc) + cur_desc->bLength);
*offset += cur_desc->bLength; *offset += cur_desc->bLength;
return ret_desc; return ret_desc;
@ -35,8 +35,8 @@ const usb_standard_desc_t *usb_parse_next_descriptor(const usb_standard_desc_t *
const usb_standard_desc_t *usb_parse_next_descriptor_of_type(const usb_standard_desc_t *cur_desc, uint16_t wTotalLength, uint8_t bDescriptorType, int *offset) const usb_standard_desc_t *usb_parse_next_descriptor_of_type(const usb_standard_desc_t *cur_desc, uint16_t wTotalLength, uint8_t bDescriptorType, int *offset)
{ {
assert(cur_desc != NULL && offset != NULL); assert(cur_desc != NULL && offset != NULL);
int offset_temp = *offset; //We only want to update offset if we've actually found a descriptor int offset_temp = *offset; // We only want to update offset if we've actually found a descriptor
//Keep stepping over descriptors until we find one of bDescriptorType or until we go out of bounds // Keep stepping over descriptors until we find one of bDescriptorType or until we go out of bounds
const usb_standard_desc_t *ret_desc = usb_parse_next_descriptor(cur_desc, wTotalLength, &offset_temp); const usb_standard_desc_t *ret_desc = usb_parse_next_descriptor(cur_desc, wTotalLength, &offset_temp);
while (ret_desc != NULL) { while (ret_desc != NULL) {
if (ret_desc->bDescriptorType == bDescriptorType) { if (ret_desc->bDescriptorType == bDescriptorType) {
@ -45,7 +45,7 @@ const usb_standard_desc_t *usb_parse_next_descriptor_of_type(const usb_standard_
ret_desc = usb_parse_next_descriptor(ret_desc, wTotalLength, &offset_temp); ret_desc = usb_parse_next_descriptor(ret_desc, wTotalLength, &offset_temp);
} }
if (ret_desc != NULL) { if (ret_desc != NULL) {
//We've found a descriptor. Update the offset // We've found a descriptor. Update the offset
*offset = offset_temp; *offset = offset_temp;
} }
return ret_desc; return ret_desc;
@ -55,10 +55,10 @@ int usb_parse_interface_number_of_alternate(const usb_config_desc_t *config_desc
{ {
assert(config_desc != NULL); assert(config_desc != NULL);
int offset = 0; int offset = 0;
//Find the first interface descriptor of bInterfaceNumber // Find the first interface descriptor of bInterfaceNumber
const usb_intf_desc_t *first_intf_desc = usb_parse_interface_descriptor(config_desc, bInterfaceNumber, 0, &offset); const usb_intf_desc_t *first_intf_desc = usb_parse_interface_descriptor(config_desc, bInterfaceNumber, 0, &offset);
if (first_intf_desc == NULL) { if (first_intf_desc == NULL) {
return -1; //bInterfaceNumber not found return -1; // bInterfaceNumber not found
} }
int num_alt_setting = 0; int num_alt_setting = 0;
@ -77,31 +77,31 @@ const usb_intf_desc_t *usb_parse_interface_descriptor(const usb_config_desc_t *c
{ {
assert(config_desc != NULL); assert(config_desc != NULL);
//Walk to first interface descriptor of bInterfaceNumber // Walk to first interface descriptor of bInterfaceNumber
int offset_temp = 0; int offset_temp = 0;
const usb_intf_desc_t *next_intf_desc = (const usb_intf_desc_t *)usb_parse_next_descriptor_of_type((const usb_standard_desc_t *)config_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset_temp); const usb_intf_desc_t *next_intf_desc = (const usb_intf_desc_t *)usb_parse_next_descriptor_of_type((const usb_standard_desc_t *)config_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset_temp);
while (next_intf_desc != NULL) { while (next_intf_desc != NULL) {
if (next_intf_desc->bInterfaceNumber == bInterfaceNumber) { if (next_intf_desc->bInterfaceNumber == bInterfaceNumber) {
break; //We found the first interface descriptor with matching bInterfaceNumber break; // We found the first interface descriptor with matching bInterfaceNumber
} }
next_intf_desc = (const usb_intf_desc_t *)usb_parse_next_descriptor_of_type((const usb_standard_desc_t *)next_intf_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset_temp); next_intf_desc = (const usb_intf_desc_t *)usb_parse_next_descriptor_of_type((const usb_standard_desc_t *)next_intf_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset_temp);
} }
if (next_intf_desc == NULL) { if (next_intf_desc == NULL) {
return NULL; //Couldn't find a interface with bInterfaceNumber return NULL; // Couldn't find a interface with bInterfaceNumber
} }
//Keep walking until an interface descriptor matching bInterfaceNumber and bAlternateSetting is found // Keep walking until an interface descriptor matching bInterfaceNumber and bAlternateSetting is found
while (next_intf_desc != NULL) { while (next_intf_desc != NULL) {
if (next_intf_desc->bInterfaceNumber == bInterfaceNumber + 1) { if (next_intf_desc->bInterfaceNumber == bInterfaceNumber + 1) {
//We've walked past our target bInterfaceNumber // We've walked past our target bInterfaceNumber
next_intf_desc = NULL; next_intf_desc = NULL;
break; break;
} }
if (next_intf_desc->bAlternateSetting == bAlternateSetting) { if (next_intf_desc->bAlternateSetting == bAlternateSetting) {
//We've found our target interface descriptor // We've found our target interface descriptor
break; break;
} }
//Get the next interface descriptor // Get the next interface descriptor
next_intf_desc = (const usb_intf_desc_t *)usb_parse_next_descriptor_of_type((const usb_standard_desc_t *)next_intf_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset_temp); next_intf_desc = (const usb_intf_desc_t *)usb_parse_next_descriptor_of_type((const usb_standard_desc_t *)next_intf_desc, config_desc->wTotalLength, USB_B_DESCRIPTOR_TYPE_INTERFACE, &offset_temp);
} }
if (next_intf_desc != NULL && offset != NULL) { if (next_intf_desc != NULL && offset != NULL) {
@ -114,9 +114,9 @@ const usb_ep_desc_t *usb_parse_endpoint_descriptor_by_index(const usb_intf_desc_
{ {
assert(intf_desc != NULL && offset != NULL); assert(intf_desc != NULL && offset != NULL);
if (index >= intf_desc->bNumEndpoints) { if (index >= intf_desc->bNumEndpoints) {
return NULL; //Index is out of range return NULL; // Index is out of range
} }
//Walk to the Nth endpoint descriptor we find // Walk to the Nth endpoint descriptor we find
int offset_temp = *offset; int offset_temp = *offset;
bool ep_found = true; bool ep_found = true;
const usb_standard_desc_t *next_desc = (const usb_standard_desc_t *)intf_desc; const usb_standard_desc_t *next_desc = (const usb_standard_desc_t *)intf_desc;
@ -138,14 +138,14 @@ const usb_ep_desc_t *usb_parse_endpoint_descriptor_by_address(const usb_config_d
{ {
assert(config_desc != NULL); assert(config_desc != NULL);
//Find the interface descriptor // Find the interface descriptor
int offset_intf; int offset_intf;
const usb_intf_desc_t *intf_desc = usb_parse_interface_descriptor(config_desc, bInterfaceNumber, bAlternateSetting, &offset_intf); const usb_intf_desc_t *intf_desc = usb_parse_interface_descriptor(config_desc, bInterfaceNumber, bAlternateSetting, &offset_intf);
if (intf_desc == NULL) { if (intf_desc == NULL) {
return NULL; return NULL;
} }
//Walk endpoint descriptors until one matching bEndpointAddress is found // Walk endpoint descriptors until one matching bEndpointAddress is found
int offset_ep; int offset_ep;
bool ep_found = false; bool ep_found = false;
const usb_ep_desc_t *ep_desc = NULL; const usb_ep_desc_t *ep_desc = NULL;
@ -287,10 +287,10 @@ void usb_print_config_descriptor(const usb_config_desc_t *cfg_desc, print_class_
print_ep_desc((const usb_ep_desc_t *)next_desc); print_ep_desc((const usb_ep_desc_t *)next_desc);
break; break;
case USB_B_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION: case USB_B_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION:
print_iad_desc((const usb_iad_desc_t*)next_desc); print_iad_desc((const usb_iad_desc_t *)next_desc);
break; break;
default: default:
if(class_specific_cb) { if (class_specific_cb) {
class_specific_cb(next_desc); class_specific_cb(next_desc);
} }
break; break;
@ -307,7 +307,7 @@ void usb_print_string_descriptor(const usb_str_desc_t *str_desc)
return; return;
} }
for (int i = 0; i < str_desc->bLength/2; i++) { for (int i = 0; i < str_desc->bLength / 2; i++) {
/* /*
USB String descriptors of UTF-16. USB String descriptors of UTF-16.
Right now We just skip any character larger than 0xFF to stay in BMP Basic Latin and Latin-1 Supplement range. Right now We just skip any character larger than 0xFF to stay in BMP Basic Latin and Latin-1 Supplement range.

View File

@ -52,19 +52,19 @@ typedef struct interface_s interface_t;
typedef struct client_s client_t; typedef struct client_s client_t;
struct ep_wrapper_s { struct ep_wrapper_s {
//Dynamic members require a critical section // Dynamic members require a critical section
struct { struct {
TAILQ_ENTRY(ep_wrapper_s) tailq_entry; TAILQ_ENTRY(ep_wrapper_s) tailq_entry;
union { union {
struct { struct {
uint32_t pending: 1; uint32_t pending: 1;
uint32_t reserved31:31; uint32_t reserved31: 31;
}; };
} flags; } flags;
uint32_t num_urb_inflight; uint32_t num_urb_inflight;
usbh_ep_event_t last_event; usbh_ep_event_t last_event;
} dynamic; } dynamic;
//Constant members do no change after claiming the interface thus do not require a critical section // Constant members do no change after claiming the interface thus do not require a critical section
struct { struct {
usbh_ep_handle_t ep_hdl; usbh_ep_handle_t ep_hdl;
interface_t *intf_obj; interface_t *intf_obj;
@ -72,11 +72,11 @@ struct ep_wrapper_s {
}; };
struct interface_s { struct interface_s {
//Dynamic members require a critical section // Dynamic members require a critical section
struct { struct {
TAILQ_ENTRY(interface_s) tailq_entry; TAILQ_ENTRY(interface_s) tailq_entry;
} mux_protected; } mux_protected;
//Constant members do no change after claiming the interface thus do not require a critical section // Constant members do no change after claiming the interface thus do not require a critical section
struct { struct {
const usb_intf_desc_t *intf_desc; const usb_intf_desc_t *intf_desc;
usb_device_handle_t dev_hdl; usb_device_handle_t dev_hdl;
@ -86,7 +86,7 @@ struct interface_s {
}; };
struct client_s { struct client_s {
//Dynamic members require a critical section // Dynamic members require a critical section
struct { struct {
TAILQ_ENTRY(client_s) tailq_entry; TAILQ_ENTRY(client_s) tailq_entry;
TAILQ_HEAD(tailhead_pending_ep, ep_wrapper_s) pending_ep_tailq; TAILQ_HEAD(tailhead_pending_ep, ep_wrapper_s) pending_ep_tailq;
@ -107,11 +107,11 @@ struct client_s {
uint32_t num_done_ctrl_xfer; uint32_t num_done_ctrl_xfer;
uint32_t opened_dev_addr_map; uint32_t opened_dev_addr_map;
} dynamic; } dynamic;
//Mux protected members must be protected by host library the mux_lock when accessed // Mux protected members must be protected by host library the mux_lock when accessed
struct { struct {
TAILQ_HEAD(tailhead_interfaces, interface_s) interface_tailq; TAILQ_HEAD(tailhead_interfaces, interface_s) interface_tailq;
} mux_protected; } mux_protected;
//Constant members do no change after registration thus do not require a critical section // Constant members do no change after registration thus do not require a critical section
struct { struct {
SemaphoreHandle_t event_sem; SemaphoreHandle_t event_sem;
usb_host_client_event_cb_t event_callback; usb_host_client_event_cb_t event_callback;
@ -121,9 +121,9 @@ struct client_s {
}; };
typedef struct { typedef struct {
//Dynamic members require a critical section // Dynamic members require a critical section
struct { struct {
//Access to these should be done in a critical section // Access to these should be done in a critical section
uint32_t process_pending_flags; uint32_t process_pending_flags;
uint32_t lib_event_flags; uint32_t lib_event_flags;
union { union {
@ -138,15 +138,15 @@ typedef struct {
uint32_t val; uint32_t val;
} flags; } flags;
} dynamic; } dynamic;
//Mux protected members must be protected by host library the mux_lock when accessed // Mux protected members must be protected by host library the mux_lock when accessed
struct { struct {
TAILQ_HEAD(tailhead_clients, client_s) client_tailq; //List of all clients registered TAILQ_HEAD(tailhead_clients, client_s) client_tailq; // List of all clients registered
} mux_protected; } mux_protected;
//Constant members do no change after installation thus do not require a critical section // Constant members do no change after installation thus do not require a critical section
struct { struct {
SemaphoreHandle_t event_sem; SemaphoreHandle_t event_sem;
SemaphoreHandle_t mux_lock; SemaphoreHandle_t mux_lock;
usb_phy_handle_t phy_handle; //Will be NULL if host library is installed with skip_phy_setup usb_phy_handle_t phy_handle; // Will be NULL if host library is installed with skip_phy_setup
} constant; } constant;
} host_lib_t; } host_lib_t;
@ -228,13 +228,13 @@ static bool _unblock_lib(bool in_isr)
static void send_event_msg_to_clients(const usb_host_client_event_msg_t *event_msg, bool send_to_all, uint8_t opened_dev_addr) static void send_event_msg_to_clients(const usb_host_client_event_msg_t *event_msg, bool send_to_all, uint8_t opened_dev_addr)
{ {
//Lock client list // Lock client list
xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY); xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY);
//Send event message to relevant or all clients // Send event message to relevant or all clients
client_t *client_obj; client_t *client_obj;
TAILQ_FOREACH(client_obj, &p_host_lib_obj->mux_protected.client_tailq, dynamic.tailq_entry) { TAILQ_FOREACH(client_obj, &p_host_lib_obj->mux_protected.client_tailq, dynamic.tailq_entry) {
if (!send_to_all) { if (!send_to_all) {
//Check if client opened the device // Check if client opened the device
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
bool send = _check_client_opened_device(client_obj, opened_dev_addr); bool send = _check_client_opened_device(client_obj, opened_dev_addr);
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
@ -242,7 +242,7 @@ static void send_event_msg_to_clients(const usb_host_client_event_msg_t *event_m
continue; continue;
} }
} }
//Send the event message // Send the event message
if (xQueueSend(client_obj->constant.event_msg_queue, event_msg, 0) == pdTRUE) { if (xQueueSend(client_obj->constant.event_msg_queue, event_msg, 0) == pdTRUE) {
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
_unblock_client(client_obj, false); _unblock_client(client_obj, false);
@ -251,7 +251,7 @@ static void send_event_msg_to_clients(const usb_host_client_event_msg_t *event_m
ESP_LOGE(USB_HOST_TAG, "Client event message queue full"); ESP_LOGE(USB_HOST_TAG, "Client event message queue full");
} }
} }
//Unlock client list // Unlock client list
xSemaphoreGive(p_host_lib_obj->constant.mux_lock); xSemaphoreGive(p_host_lib_obj->constant.mux_lock);
} }
@ -262,7 +262,7 @@ static void send_event_msg_to_clients(const usb_host_client_event_msg_t *event_m
static bool proc_req_callback(usb_proc_req_source_t source, bool in_isr, void *arg) static bool proc_req_callback(usb_proc_req_source_t source, bool in_isr, void *arg)
{ {
HOST_ENTER_CRITICAL_SAFE(); HOST_ENTER_CRITICAL_SAFE();
//Store the processing request source // Store the processing request source
switch (source) { switch (source) {
case USB_PROC_REQ_SOURCE_USBH: case USB_PROC_REQ_SOURCE_USBH:
p_host_lib_obj->dynamic.process_pending_flags |= PROCESS_REQUEST_PENDING_FLAG_USBH; p_host_lib_obj->dynamic.process_pending_flags |= PROCESS_REQUEST_PENDING_FLAG_USBH;
@ -280,7 +280,7 @@ static bool proc_req_callback(usb_proc_req_source_t source, bool in_isr, void *a
static void ctrl_xfer_callback(usb_device_handle_t dev_hdl, urb_t *urb, void *arg) static void ctrl_xfer_callback(usb_device_handle_t dev_hdl, urb_t *urb, void *arg)
{ {
assert(urb->usb_host_client != NULL); assert(urb->usb_host_client != NULL);
//Redistribute done control transfer to the clients that submitted them // Redistribute done control transfer to the clients that submitted them
client_t *client_obj = (client_t *)urb->usb_host_client; client_t *client_obj = (client_t *)urb->usb_host_client;
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
@ -292,10 +292,10 @@ static void ctrl_xfer_callback(usb_device_handle_t dev_hdl, urb_t *urb, void *ar
static void dev_event_callback(usb_device_handle_t dev_hdl, usbh_event_t usbh_event, void *arg) static void dev_event_callback(usb_device_handle_t dev_hdl, usbh_event_t usbh_event, void *arg)
{ {
//Check usbh_event. The data type of event_arg depends on the type of event // Check usbh_event. The data type of event_arg depends on the type of event
switch (usbh_event) { switch (usbh_event) {
case USBH_EVENT_DEV_NEW: { case USBH_EVENT_DEV_NEW: {
//Prepare a NEW_DEV client event message, the send it to all clients // Prepare a NEW_DEV client event message, the send it to all clients
uint8_t dev_addr; uint8_t dev_addr;
ESP_ERROR_CHECK(usbh_dev_get_addr(dev_hdl, &dev_addr)); ESP_ERROR_CHECK(usbh_dev_get_addr(dev_hdl, &dev_addr));
usb_host_client_event_msg_t event_msg = { usb_host_client_event_msg_t event_msg = {
@ -306,7 +306,7 @@ static void dev_event_callback(usb_device_handle_t dev_hdl, usbh_event_t usbh_ev
break; break;
} }
case USBH_EVENT_DEV_GONE: { case USBH_EVENT_DEV_GONE: {
//Prepare event msg, send only to clients that have opened the device // Prepare event msg, send only to clients that have opened the device
uint8_t dev_addr; uint8_t dev_addr;
ESP_ERROR_CHECK(usbh_dev_get_addr(dev_hdl, &dev_addr)); ESP_ERROR_CHECK(usbh_dev_get_addr(dev_hdl, &dev_addr));
usb_host_client_event_msg_t event_msg = { usb_host_client_event_msg_t event_msg = {
@ -317,7 +317,7 @@ static void dev_event_callback(usb_device_handle_t dev_hdl, usbh_event_t usbh_ev
break; break;
} }
case USBH_EVENT_DEV_ALL_FREE: { case USBH_EVENT_DEV_ALL_FREE: {
//Notify the lib handler that all devices are free // Notify the lib handler that all devices are free
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
p_host_lib_obj->dynamic.lib_event_flags |= USB_HOST_LIB_EVENT_FLAGS_ALL_FREE; p_host_lib_obj->dynamic.lib_event_flags |= USB_HOST_LIB_EVENT_FLAGS_ALL_FREE;
_unblock_lib(false); _unblock_lib(false);
@ -325,7 +325,7 @@ static void dev_event_callback(usb_device_handle_t dev_hdl, usbh_event_t usbh_ev
break; break;
} }
default: default:
abort(); //Should never occur abort(); // Should never occur
break; break;
} }
} }
@ -338,9 +338,9 @@ static bool endpoint_callback(usbh_ep_handle_t ep_hdl, usbh_ep_event_t ep_event,
client_t *client_obj = (client_t *)ep_wrap->constant.intf_obj->constant.client_obj; client_t *client_obj = (client_t *)ep_wrap->constant.intf_obj->constant.client_obj;
HOST_ENTER_CRITICAL_SAFE(); HOST_ENTER_CRITICAL_SAFE();
//Store the event to be handled later. Note that we allow overwriting of events because more severe will halt the pipe prevent any further events. // Store the event to be handled later. Note that we allow overwriting of events because more severe will halt the pipe prevent any further events.
ep_wrap->dynamic.last_event = ep_event; ep_wrap->dynamic.last_event = ep_event;
//Add the EP to the client's pending list if it's not in the list already // Add the EP to the client's pending list if it's not in the list already
if (!ep_wrap->dynamic.flags.pending) { if (!ep_wrap->dynamic.flags.pending) {
ep_wrap->dynamic.flags.pending = 1; ep_wrap->dynamic.flags.pending = 1;
TAILQ_REMOVE(&client_obj->dynamic.idle_ep_tailq, ep_wrap, dynamic.tailq_entry); TAILQ_REMOVE(&client_obj->dynamic.idle_ep_tailq, ep_wrap, dynamic.tailq_entry);
@ -371,7 +371,7 @@ esp_err_t usb_host_install(const usb_host_config_t *config)
ret = ESP_ERR_NO_MEM; ret = ESP_ERR_NO_MEM;
goto alloc_err; goto alloc_err;
} }
//Initialize host library object // Initialize host library object
TAILQ_INIT(&host_lib_obj->mux_protected.client_tailq); TAILQ_INIT(&host_lib_obj->mux_protected.client_tailq);
host_lib_obj->constant.event_sem = event_sem; host_lib_obj->constant.event_sem = event_sem;
host_lib_obj->constant.mux_lock = mux_lock; host_lib_obj->constant.mux_lock = mux_lock;
@ -384,14 +384,14 @@ esp_err_t usb_host_install(const usb_host_config_t *config)
- Hub - Hub
*/ */
//Install USB PHY (if necessary). USB PHY driver will also enable the underlying Host Controller // Install USB PHY (if necessary). USB PHY driver will also enable the underlying Host Controller
if (!config->skip_phy_setup) { if (!config->skip_phy_setup) {
//Host Library defaults to internal PHY // Host Library defaults to internal PHY
usb_phy_config_t phy_config = { usb_phy_config_t phy_config = {
.controller = USB_PHY_CTRL_OTG, .controller = USB_PHY_CTRL_OTG,
.target = USB_PHY_TARGET_INT, .target = USB_PHY_TARGET_INT,
.otg_mode = USB_OTG_MODE_HOST, .otg_mode = USB_OTG_MODE_HOST,
.otg_speed = USB_PHY_SPEED_UNDEFINED, //In Host mode, the speed is determined by the connected device .otg_speed = USB_PHY_SPEED_UNDEFINED, // In Host mode, the speed is determined by the connected device
.ext_io_conf = NULL, .ext_io_conf = NULL,
.otg_io_conf = NULL, .otg_io_conf = NULL,
}; };
@ -401,7 +401,7 @@ esp_err_t usb_host_install(const usb_host_config_t *config)
} }
} }
//Install HCD // Install HCD
hcd_config_t hcd_config = { hcd_config_t hcd_config = {
.intr_flags = config->intr_flags .intr_flags = config->intr_flags
}; };
@ -410,7 +410,7 @@ esp_err_t usb_host_install(const usb_host_config_t *config)
goto hcd_err; goto hcd_err;
} }
//Install USBH // Install USBH
usbh_config_t usbh_config = { usbh_config_t usbh_config = {
.proc_req_cb = proc_req_callback, .proc_req_cb = proc_req_callback,
.proc_req_cb_arg = NULL, .proc_req_cb_arg = NULL,
@ -424,7 +424,7 @@ esp_err_t usb_host_install(const usb_host_config_t *config)
goto usbh_err; goto usbh_err;
} }
//Install Hub // Install Hub
hub_config_t hub_config = { hub_config_t hub_config = {
.proc_req_cb = proc_req_callback, .proc_req_cb = proc_req_callback,
.proc_req_cb_arg = NULL, .proc_req_cb_arg = NULL,
@ -434,7 +434,7 @@ esp_err_t usb_host_install(const usb_host_config_t *config)
goto hub_err; goto hub_err;
} }
//Assign host library object // Assign host library object
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
if (p_host_lib_obj != NULL) { if (p_host_lib_obj != NULL) {
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
@ -444,7 +444,7 @@ esp_err_t usb_host_install(const usb_host_config_t *config)
p_host_lib_obj = host_lib_obj; p_host_lib_obj = host_lib_obj;
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
//Start the root hub // Start the root hub
ESP_ERROR_CHECK(hub_root_start()); ESP_ERROR_CHECK(hub_root_start());
ret = ESP_OK; ret = ESP_OK;
return ret; return ret;
@ -473,7 +473,7 @@ alloc_err:
esp_err_t usb_host_uninstall(void) esp_err_t usb_host_uninstall(void)
{ {
//All devices must have been freed at this point // All devices must have been freed at this point
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
HOST_CHECK_FROM_CRIT(p_host_lib_obj != NULL, ESP_ERR_INVALID_STATE); HOST_CHECK_FROM_CRIT(p_host_lib_obj != NULL, ESP_ERR_INVALID_STATE);
HOST_CHECK_FROM_CRIT(p_host_lib_obj->dynamic.process_pending_flags == 0 && HOST_CHECK_FROM_CRIT(p_host_lib_obj->dynamic.process_pending_flags == 0 &&
@ -482,10 +482,10 @@ esp_err_t usb_host_uninstall(void)
ESP_ERR_INVALID_STATE); ESP_ERR_INVALID_STATE);
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
//Stop the root hub // Stop the root hub
ESP_ERROR_CHECK(hub_root_stop()); ESP_ERROR_CHECK(hub_root_stop());
//Unassign the host library object // Unassign the host library object
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
host_lib_t *host_lib_obj = p_host_lib_obj; host_lib_t *host_lib_obj = p_host_lib_obj;
p_host_lib_obj = NULL; p_host_lib_obj = NULL;
@ -501,12 +501,12 @@ esp_err_t usb_host_uninstall(void)
ESP_ERROR_CHECK(hub_uninstall()); ESP_ERROR_CHECK(hub_uninstall());
ESP_ERROR_CHECK(usbh_uninstall()); ESP_ERROR_CHECK(usbh_uninstall());
ESP_ERROR_CHECK(hcd_uninstall()); ESP_ERROR_CHECK(hcd_uninstall());
//If the USB PHY was setup, then delete it // If the USB PHY was setup, then delete it
if (host_lib_obj->constant.phy_handle) { if (host_lib_obj->constant.phy_handle) {
ESP_ERROR_CHECK(usb_del_phy(host_lib_obj->constant.phy_handle)); ESP_ERROR_CHECK(usb_del_phy(host_lib_obj->constant.phy_handle));
} }
//Free memory objects // Free memory objects
vSemaphoreDelete(host_lib_obj->constant.mux_lock); vSemaphoreDelete(host_lib_obj->constant.mux_lock);
vSemaphoreDelete(host_lib_obj->constant.event_sem); vSemaphoreDelete(host_lib_obj->constant.event_sem);
heap_caps_free(host_lib_obj); heap_caps_free(host_lib_obj);
@ -520,7 +520,7 @@ esp_err_t usb_host_lib_handle_events(TickType_t timeout_ticks, uint32_t *event_f
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
if (!p_host_lib_obj->dynamic.flags.process_pending) { if (!p_host_lib_obj->dynamic.flags.process_pending) {
//There is currently processing that needs to be done. Wait for some processing // There is currently processing that needs to be done. Wait for some processing
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
BaseType_t sem_ret = xSemaphoreTake(p_host_lib_obj->constant.event_sem, timeout_ticks); BaseType_t sem_ret = xSemaphoreTake(p_host_lib_obj->constant.event_sem, timeout_ticks);
if (sem_ret == pdFALSE) { if (sem_ret == pdFALSE) {
@ -529,7 +529,7 @@ esp_err_t usb_host_lib_handle_events(TickType_t timeout_ticks, uint32_t *event_f
} }
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
} }
//Read and clear process pending flags // Read and clear process pending flags
uint32_t process_pending_flags = p_host_lib_obj->dynamic.process_pending_flags; uint32_t process_pending_flags = p_host_lib_obj->dynamic.process_pending_flags;
p_host_lib_obj->dynamic.process_pending_flags = 0; p_host_lib_obj->dynamic.process_pending_flags = 0;
p_host_lib_obj->dynamic.flags.handling_events = 1; p_host_lib_obj->dynamic.flags.handling_events = 1;
@ -542,7 +542,7 @@ esp_err_t usb_host_lib_handle_events(TickType_t timeout_ticks, uint32_t *event_f
ESP_ERROR_CHECK(hub_process()); ESP_ERROR_CHECK(hub_process());
} }
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
//Read and clear process pending flags again, and loop back if there is more to process // Read and clear process pending flags again, and loop back if there is more to process
process_pending_flags = p_host_lib_obj->dynamic.process_pending_flags; process_pending_flags = p_host_lib_obj->dynamic.process_pending_flags;
p_host_lib_obj->dynamic.process_pending_flags = 0; p_host_lib_obj->dynamic.process_pending_flags = 0;
} }
@ -562,7 +562,7 @@ exit:
esp_err_t usb_host_lib_unblock(void) esp_err_t usb_host_lib_unblock(void)
{ {
//All devices must have been freed at this point // All devices must have been freed at this point
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
HOST_CHECK_FROM_CRIT(p_host_lib_obj != NULL, ESP_ERR_INVALID_STATE); HOST_CHECK_FROM_CRIT(p_host_lib_obj != NULL, ESP_ERR_INVALID_STATE);
_unblock_lib(false); _unblock_lib(false);
@ -581,7 +581,7 @@ esp_err_t usb_host_lib_info(usb_host_lib_info_t *info_ret)
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
usbh_num_devs(&num_devs_temp); usbh_num_devs(&num_devs_temp);
//Write back return values // Write back return values
info_ret->num_devices = num_devs_temp; info_ret->num_devices = num_devs_temp;
info_ret->num_clients = num_clients_temp; info_ret->num_clients = num_clients_temp;
return ESP_OK; return ESP_OK;
@ -593,9 +593,9 @@ esp_err_t usb_host_lib_info(usb_host_lib_info_t *info_ret)
static void _handle_pending_ep(client_t *client_obj) static void _handle_pending_ep(client_t *client_obj)
{ {
//Handle each EP on the pending list // Handle each EP on the pending list
while (!TAILQ_EMPTY(&client_obj->dynamic.pending_ep_tailq)) { while (!TAILQ_EMPTY(&client_obj->dynamic.pending_ep_tailq)) {
//Get the next pending EP. // Get the next pending EP.
ep_wrapper_t *ep_wrap = TAILQ_FIRST(&client_obj->dynamic.pending_ep_tailq); ep_wrapper_t *ep_wrap = TAILQ_FIRST(&client_obj->dynamic.pending_ep_tailq);
TAILQ_REMOVE(&client_obj->dynamic.pending_ep_tailq, ep_wrap, dynamic.tailq_entry); TAILQ_REMOVE(&client_obj->dynamic.pending_ep_tailq, ep_wrap, dynamic.tailq_entry);
TAILQ_INSERT_TAIL(&client_obj->dynamic.idle_ep_tailq, ep_wrap, dynamic.tailq_entry); TAILQ_INSERT_TAIL(&client_obj->dynamic.idle_ep_tailq, ep_wrap, dynamic.tailq_entry);
@ -604,22 +604,22 @@ static void _handle_pending_ep(client_t *client_obj)
uint32_t num_urb_dequeued = 0; uint32_t num_urb_dequeued = 0;
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
//Handle pipe event // Handle pipe event
switch (last_event) { switch (last_event) {
case USBH_EP_EVENT_ERROR_XFER: case USBH_EP_EVENT_ERROR_XFER:
case USBH_EP_EVENT_ERROR_URB_NOT_AVAIL: case USBH_EP_EVENT_ERROR_URB_NOT_AVAIL:
case USBH_EP_EVENT_ERROR_OVERFLOW: case USBH_EP_EVENT_ERROR_OVERFLOW:
case USBH_EP_EVENT_ERROR_STALL: case USBH_EP_EVENT_ERROR_STALL:
//The endpoint is now stalled. Flush all pending URBs // The endpoint is now stalled. Flush all pending URBs
ESP_ERROR_CHECK(usbh_ep_command(ep_wrap->constant.ep_hdl, USBH_EP_CMD_FLUSH)); ESP_ERROR_CHECK(usbh_ep_command(ep_wrap->constant.ep_hdl, USBH_EP_CMD_FLUSH));
//All URBs in this pipe are now retired waiting to be dequeued. Fall through to dequeue them // All URBs in this pipe are now retired waiting to be dequeued. Fall through to dequeue them
__attribute__((fallthrough)); __attribute__((fallthrough));
case USBH_EP_EVENT_URB_DONE: { case USBH_EP_EVENT_URB_DONE: {
//Dequeue all URBs and run their transfer callback // Dequeue all URBs and run their transfer callback
urb_t *urb; urb_t *urb;
usbh_ep_dequeue_urb(ep_wrap->constant.ep_hdl, &urb); usbh_ep_dequeue_urb(ep_wrap->constant.ep_hdl, &urb);
while (urb != NULL) { while (urb != NULL) {
//Clear the transfer's in-flight flag to indicate the transfer is no longer in-flight // Clear the transfer's in-flight flag to indicate the transfer is no longer in-flight
urb->usb_host_inflight = false; urb->usb_host_inflight = false;
urb->transfer.callback(&urb->transfer); urb->transfer.callback(&urb->transfer);
num_urb_dequeued++; num_urb_dequeued++;
@ -628,12 +628,12 @@ static void _handle_pending_ep(client_t *client_obj)
break; break;
} }
default: default:
abort(); //Should never occur abort(); // Should never occur
break; break;
} }
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
//Update the endpoint's number of URB's in-flight // Update the endpoint's number of URB's in-flight
assert(num_urb_dequeued <= ep_wrap->dynamic.num_urb_inflight); assert(num_urb_dequeued <= ep_wrap->dynamic.num_urb_inflight);
ep_wrap->dynamic.num_urb_inflight -= num_urb_dequeued; ep_wrap->dynamic.num_urb_inflight -= num_urb_dequeued;
} }
@ -647,12 +647,12 @@ esp_err_t usb_host_client_register(const usb_host_client_config_t *client_config
HOST_CHECK(client_config != NULL && client_hdl_ret != NULL, ESP_ERR_INVALID_ARG); HOST_CHECK(client_config != NULL && client_hdl_ret != NULL, ESP_ERR_INVALID_ARG);
HOST_CHECK(client_config->max_num_event_msg > 0, ESP_ERR_INVALID_ARG); HOST_CHECK(client_config->max_num_event_msg > 0, ESP_ERR_INVALID_ARG);
if (!client_config->is_synchronous) { if (!client_config->is_synchronous) {
//Asynchronous clients must provide a // Asynchronous clients must provide a
HOST_CHECK(client_config->async.client_event_callback != NULL, ESP_ERR_INVALID_ARG); HOST_CHECK(client_config->async.client_event_callback != NULL, ESP_ERR_INVALID_ARG);
} }
esp_err_t ret; esp_err_t ret;
//Create client object // Create client object
client_t *client_obj = heap_caps_calloc(1, sizeof(client_t), MALLOC_CAP_DEFAULT); client_t *client_obj = heap_caps_calloc(1, sizeof(client_t), MALLOC_CAP_DEFAULT);
SemaphoreHandle_t event_sem = xSemaphoreCreateBinary(); SemaphoreHandle_t event_sem = xSemaphoreCreateBinary();
QueueHandle_t event_msg_queue = xQueueCreate(client_config->max_num_event_msg, sizeof(usb_host_client_event_msg_t)); QueueHandle_t event_msg_queue = xQueueCreate(client_config->max_num_event_msg, sizeof(usb_host_client_event_msg_t));
@ -660,7 +660,7 @@ esp_err_t usb_host_client_register(const usb_host_client_config_t *client_config
ret = ESP_ERR_NO_MEM; ret = ESP_ERR_NO_MEM;
goto alloc_err; goto alloc_err;
} }
//Initialize client object // Initialize client object
TAILQ_INIT(&client_obj->dynamic.pending_ep_tailq); TAILQ_INIT(&client_obj->dynamic.pending_ep_tailq);
TAILQ_INIT(&client_obj->dynamic.idle_ep_tailq); TAILQ_INIT(&client_obj->dynamic.idle_ep_tailq);
TAILQ_INIT(&client_obj->mux_protected.interface_tailq); TAILQ_INIT(&client_obj->mux_protected.interface_tailq);
@ -670,7 +670,7 @@ esp_err_t usb_host_client_register(const usb_host_client_config_t *client_config
client_obj->constant.callback_arg = client_config->async.callback_arg; client_obj->constant.callback_arg = client_config->async.callback_arg;
client_obj->constant.event_msg_queue = event_msg_queue; client_obj->constant.event_msg_queue = event_msg_queue;
//Add client to the host library's list of clients // Add client to the host library's list of clients
xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY); xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY);
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
p_host_lib_obj->dynamic.flags.num_clients++; p_host_lib_obj->dynamic.flags.num_clients++;
@ -678,7 +678,7 @@ esp_err_t usb_host_client_register(const usb_host_client_config_t *client_config
TAILQ_INSERT_TAIL(&p_host_lib_obj->mux_protected.client_tailq, client_obj, dynamic.tailq_entry); TAILQ_INSERT_TAIL(&p_host_lib_obj->mux_protected.client_tailq, client_obj, dynamic.tailq_entry);
xSemaphoreGive(p_host_lib_obj->constant.mux_lock); xSemaphoreGive(p_host_lib_obj->constant.mux_lock);
//Write back client handle // Write back client handle
*client_hdl_ret = (usb_host_client_handle_t)client_obj; *client_hdl_ret = (usb_host_client_handle_t)client_obj;
ret = ESP_OK; ret = ESP_OK;
return ret; return ret;
@ -700,10 +700,10 @@ esp_err_t usb_host_client_deregister(usb_host_client_handle_t client_hdl)
client_t *client_obj = (client_t *)client_hdl; client_t *client_obj = (client_t *)client_hdl;
esp_err_t ret; esp_err_t ret;
//We take the mux_lock because we need to access the host library's client_tailq // We take the mux_lock because we need to access the host library's client_tailq
xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY); xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY);
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
//Check that client can currently deregistered // Check that client can currently deregistered
bool can_deregister; bool can_deregister;
if (!TAILQ_EMPTY(&client_obj->dynamic.pending_ep_tailq) || if (!TAILQ_EMPTY(&client_obj->dynamic.pending_ep_tailq) ||
!TAILQ_EMPTY(&client_obj->dynamic.idle_ep_tailq) || !TAILQ_EMPTY(&client_obj->dynamic.idle_ep_tailq) ||
@ -724,17 +724,17 @@ esp_err_t usb_host_client_deregister(usb_host_client_handle_t client_hdl)
goto exit; goto exit;
} }
//Remove client object from the library's list of clients // Remove client object from the library's list of clients
TAILQ_REMOVE(&p_host_lib_obj->mux_protected.client_tailq, client_obj, dynamic.tailq_entry); TAILQ_REMOVE(&p_host_lib_obj->mux_protected.client_tailq, client_obj, dynamic.tailq_entry);
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
p_host_lib_obj->dynamic.flags.num_clients--; p_host_lib_obj->dynamic.flags.num_clients--;
if (p_host_lib_obj->dynamic.flags.num_clients == 0) { if (p_host_lib_obj->dynamic.flags.num_clients == 0) {
//This is the last client being deregistered. Notify the lib handler // This is the last client being deregistered. Notify the lib handler
p_host_lib_obj->dynamic.lib_event_flags |= USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS; p_host_lib_obj->dynamic.lib_event_flags |= USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS;
_unblock_lib(false); _unblock_lib(false);
} }
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
//Free client object // Free client object
vQueueDelete(client_obj->constant.event_msg_queue); vQueueDelete(client_obj->constant.event_msg_queue);
vSemaphoreDelete(client_obj->constant.event_sem); vSemaphoreDelete(client_obj->constant.event_sem);
heap_caps_free(client_obj); heap_caps_free(client_obj);
@ -752,7 +752,7 @@ esp_err_t usb_host_client_handle_events(usb_host_client_handle_t client_hdl, Tic
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
if (!client_obj->dynamic.flags.events_pending) { if (!client_obj->dynamic.flags.events_pending) {
//There are currently no events, wait for one to occur // There are currently no events, wait for one to occur
client_obj->dynamic.flags.blocked = 1; client_obj->dynamic.flags.blocked = 1;
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
BaseType_t sem_ret = xSemaphoreTake(client_obj->constant.event_sem, timeout_ticks); BaseType_t sem_ret = xSemaphoreTake(client_obj->constant.event_sem, timeout_ticks);
@ -760,45 +760,45 @@ esp_err_t usb_host_client_handle_events(usb_host_client_handle_t client_hdl, Tic
client_obj->dynamic.flags.blocked = 0; client_obj->dynamic.flags.blocked = 0;
if (sem_ret == pdFALSE) { if (sem_ret == pdFALSE) {
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
//Timed out waiting for semaphore // Timed out waiting for semaphore
ret = ESP_ERR_TIMEOUT; ret = ESP_ERR_TIMEOUT;
goto exit; goto exit;
} }
} }
//Mark that we're processing events // Mark that we're processing events
client_obj->dynamic.flags.handling_events = 1; client_obj->dynamic.flags.handling_events = 1;
while (client_obj->dynamic.flags.handling_events) { while (client_obj->dynamic.flags.handling_events) {
//Handle pending endpoints // Handle pending endpoints
if (!TAILQ_EMPTY(&client_obj->dynamic.pending_ep_tailq)) { if (!TAILQ_EMPTY(&client_obj->dynamic.pending_ep_tailq)) {
_handle_pending_ep(client_obj); _handle_pending_ep(client_obj);
} }
//Handle any done control transfers // Handle any done control transfers
while (client_obj->dynamic.num_done_ctrl_xfer > 0) { while (client_obj->dynamic.num_done_ctrl_xfer > 0) {
urb_t *urb = TAILQ_FIRST(&client_obj->dynamic.done_ctrl_xfer_tailq); urb_t *urb = TAILQ_FIRST(&client_obj->dynamic.done_ctrl_xfer_tailq);
TAILQ_REMOVE(&client_obj->dynamic.done_ctrl_xfer_tailq, urb, tailq_entry); TAILQ_REMOVE(&client_obj->dynamic.done_ctrl_xfer_tailq, urb, tailq_entry);
client_obj->dynamic.num_done_ctrl_xfer--; client_obj->dynamic.num_done_ctrl_xfer--;
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
//Clear the transfer's in-flight flag to indicate the transfer is no longer in-flight // Clear the transfer's in-flight flag to indicate the transfer is no longer in-flight
urb->usb_host_inflight = false; urb->usb_host_inflight = false;
//Call the transfer's callback // Call the transfer's callback
urb->transfer.callback(&urb->transfer); urb->transfer.callback(&urb->transfer);
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
} }
//Handle event messages // Handle event messages
while (uxQueueMessagesWaiting(client_obj->constant.event_msg_queue) > 0) { while (uxQueueMessagesWaiting(client_obj->constant.event_msg_queue) > 0) {
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
//Dequeue the event message and call the client event callback // Dequeue the event message and call the client event callback
usb_host_client_event_msg_t event_msg; usb_host_client_event_msg_t event_msg;
BaseType_t queue_ret = xQueueReceive(client_obj->constant.event_msg_queue, &event_msg, 0); BaseType_t queue_ret = xQueueReceive(client_obj->constant.event_msg_queue, &event_msg, 0);
assert(queue_ret == pdTRUE); assert(queue_ret == pdTRUE);
client_obj->constant.event_callback(&event_msg, client_obj->constant.callback_arg); client_obj->constant.event_callback(&event_msg, client_obj->constant.callback_arg);
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
} }
//Check each event again to see any new events occurred // Check each event again to see any new events occurred
if (TAILQ_EMPTY(&client_obj->dynamic.pending_ep_tailq) && if (TAILQ_EMPTY(&client_obj->dynamic.pending_ep_tailq) &&
client_obj->dynamic.num_done_ctrl_xfer == 0 && client_obj->dynamic.num_done_ctrl_xfer == 0 &&
uxQueueMessagesWaiting(client_obj->constant.event_msg_queue) == 0) { uxQueueMessagesWaiting(client_obj->constant.event_msg_queue) == 0) {
//All pending endpoints and event messages handled // All pending endpoints and event messages handled
client_obj->dynamic.flags.events_pending = 0; client_obj->dynamic.flags.events_pending = 0;
client_obj->dynamic.flags.handling_events = 0; client_obj->dynamic.flags.handling_events = 0;
} }
@ -838,12 +838,12 @@ esp_err_t usb_host_device_open(usb_host_client_handle_t client_hdl, uint8_t dev_
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
if (_check_client_opened_device(client_obj, dev_addr)) { if (_check_client_opened_device(client_obj, dev_addr)) {
//Client has already opened the device. Close it and return an error // Client has already opened the device. Close it and return an error
ret = ESP_ERR_INVALID_STATE; ret = ESP_ERR_INVALID_STATE;
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
goto already_opened; goto already_opened;
} }
//Record in client object that we have opened the device of this address // Record in client object that we have opened the device of this address
_record_client_opened_device(client_obj, dev_addr); _record_client_opened_device(client_obj, dev_addr);
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
@ -862,10 +862,10 @@ esp_err_t usb_host_device_close(usb_host_client_handle_t client_hdl, usb_device_
HOST_CHECK(dev_hdl != NULL && client_hdl != NULL, ESP_ERR_INVALID_ARG); HOST_CHECK(dev_hdl != NULL && client_hdl != NULL, ESP_ERR_INVALID_ARG);
client_t *client_obj = (client_t *)client_hdl; client_t *client_obj = (client_t *)client_hdl;
//We take the lock because we need to walk the interface list // We take the lock because we need to walk the interface list
xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY); xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY);
esp_err_t ret; esp_err_t ret;
//Check that all interfaces claimed by this client do not belong to this device // Check that all interfaces claimed by this client do not belong to this device
bool all_released = true; bool all_released = true;
interface_t *intf_obj; interface_t *intf_obj;
TAILQ_FOREACH(intf_obj, &client_obj->mux_protected.interface_tailq, mux_protected.tailq_entry) { TAILQ_FOREACH(intf_obj, &client_obj->mux_protected.interface_tailq, mux_protected.tailq_entry) {
@ -879,18 +879,18 @@ esp_err_t usb_host_device_close(usb_host_client_handle_t client_hdl, usb_device_
goto exit; goto exit;
} }
//Check that client actually opened the device in the first place // Check that client actually opened the device in the first place
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
uint8_t dev_addr; uint8_t dev_addr;
ESP_ERROR_CHECK(usbh_dev_get_addr(dev_hdl, &dev_addr)); ESP_ERROR_CHECK(usbh_dev_get_addr(dev_hdl, &dev_addr));
HOST_CHECK_FROM_CRIT(_check_client_opened_device(client_obj, dev_addr), ESP_ERR_NOT_FOUND); HOST_CHECK_FROM_CRIT(_check_client_opened_device(client_obj, dev_addr), ESP_ERR_NOT_FOUND);
if (!_check_client_opened_device(client_obj, dev_addr)) { if (!_check_client_opened_device(client_obj, dev_addr)) {
//Client never opened this device // Client never opened this device
ret = ESP_ERR_INVALID_STATE; ret = ESP_ERR_INVALID_STATE;
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
goto exit; goto exit;
} }
//Proceed to clear the record of the device form the client // Proceed to clear the record of the device form the client
_clear_client_opened_device(client_obj, dev_addr); _clear_client_opened_device(client_obj, dev_addr);
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
@ -904,11 +904,11 @@ exit:
esp_err_t usb_host_device_free_all(void) esp_err_t usb_host_device_free_all(void)
{ {
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
HOST_CHECK_FROM_CRIT(p_host_lib_obj->dynamic.flags.num_clients == 0, ESP_ERR_INVALID_STATE); //All clients must have been deregistered HOST_CHECK_FROM_CRIT(p_host_lib_obj->dynamic.flags.num_clients == 0, ESP_ERR_INVALID_STATE); // All clients must have been deregistered
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
esp_err_t ret; esp_err_t ret;
ret = usbh_dev_mark_all_free(); ret = usbh_dev_mark_all_free();
//If ESP_ERR_NOT_FINISHED is returned, caller must wait for USB_HOST_LIB_EVENT_FLAGS_ALL_FREE to confirm all devices are free // If ESP_ERR_NOT_FINISHED is returned, caller must wait for USB_HOST_LIB_EVENT_FLAGS_ALL_FREE to confirm all devices are free
return ret; return ret;
} }
@ -968,10 +968,10 @@ static esp_err_t ep_wrapper_alloc(usb_device_handle_t dev_hdl, const usb_ep_desc
if (ret != ESP_OK) { if (ret != ESP_OK) {
goto alloc_err; goto alloc_err;
} }
//Initialize endpoint wrapper item // Initialize endpoint wrapper item
ep_wrap->constant.ep_hdl = ep_hdl; ep_wrap->constant.ep_hdl = ep_hdl;
ep_wrap->constant.intf_obj = intf_obj; ep_wrap->constant.intf_obj = intf_obj;
//Write back result // Write back result
*ep_wrap_ret = ep_wrap; *ep_wrap_ret = ep_wrap;
ret = ESP_OK; ret = ESP_OK;
return ret; return ret;
@ -986,9 +986,9 @@ static void ep_wrapper_free(usb_device_handle_t dev_hdl, ep_wrapper_t *ep_wrap)
if (ep_wrap == NULL) { if (ep_wrap == NULL) {
return; return;
} }
//Free the underlying endpoint // Free the underlying endpoint
ESP_ERROR_CHECK(usbh_ep_free(ep_wrap->constant.ep_hdl)); ESP_ERROR_CHECK(usbh_ep_free(ep_wrap->constant.ep_hdl));
//Free the endpoint wrapper item // Free the endpoint wrapper item
heap_caps_free(ep_wrap); heap_caps_free(ep_wrap);
} }
@ -1018,21 +1018,21 @@ static void interface_free(interface_t *intf_obj)
static esp_err_t interface_claim(client_t *client_obj, usb_device_handle_t dev_hdl, const usb_config_desc_t *config_desc, uint8_t bInterfaceNumber, uint8_t bAlternateSetting, interface_t **intf_obj_ret) static esp_err_t interface_claim(client_t *client_obj, usb_device_handle_t dev_hdl, const usb_config_desc_t *config_desc, uint8_t bInterfaceNumber, uint8_t bAlternateSetting, interface_t **intf_obj_ret)
{ {
esp_err_t ret; esp_err_t ret;
//We need to walk to configuration descriptor to find the correct interface descriptor, and each of its constituent endpoint descriptors // We need to walk to configuration descriptor to find the correct interface descriptor, and each of its constituent endpoint descriptors
//Find the interface descriptor and allocate the interface object // Find the interface descriptor and allocate the interface object
int offset_intf; int offset_intf;
const usb_intf_desc_t *intf_desc = usb_parse_interface_descriptor(config_desc, bInterfaceNumber, bAlternateSetting, &offset_intf); const usb_intf_desc_t *intf_desc = usb_parse_interface_descriptor(config_desc, bInterfaceNumber, bAlternateSetting, &offset_intf);
if (intf_desc == NULL) { if (intf_desc == NULL) {
ret = ESP_ERR_NOT_FOUND; ret = ESP_ERR_NOT_FOUND;
goto exit; goto exit;
} }
//Allocate interface object // Allocate interface object
interface_t *intf_obj = interface_alloc(client_obj, dev_hdl, intf_desc); interface_t *intf_obj = interface_alloc(client_obj, dev_hdl, intf_desc);
if (intf_obj == NULL) { if (intf_obj == NULL) {
ret = ESP_ERR_NO_MEM; ret = ESP_ERR_NO_MEM;
goto exit; goto exit;
} }
//Find each endpoint descriptor in the interface by index, and allocate those endpoints // Find each endpoint descriptor in the interface by index, and allocate those endpoints
for (int i = 0; i < intf_desc->bNumEndpoints; i++) { for (int i = 0; i < intf_desc->bNumEndpoints; i++) {
int offset_ep = offset_intf; int offset_ep = offset_intf;
const usb_ep_desc_t *ep_desc = usb_parse_endpoint_descriptor_by_index(intf_desc, i, config_desc->wTotalLength, &offset_ep); const usb_ep_desc_t *ep_desc = usb_parse_endpoint_descriptor_by_index(intf_desc, i, config_desc->wTotalLength, &offset_ep);
@ -1040,24 +1040,24 @@ static esp_err_t interface_claim(client_t *client_obj, usb_device_handle_t dev_h
ret = ESP_ERR_NOT_FOUND; ret = ESP_ERR_NOT_FOUND;
goto ep_alloc_err; goto ep_alloc_err;
} }
//Allocate the endpoint wrapper item // Allocate the endpoint wrapper item
ep_wrapper_t *ep_wrap; ep_wrapper_t *ep_wrap;
ret = ep_wrapper_alloc(dev_hdl, ep_desc, intf_obj, &ep_wrap); ret = ep_wrapper_alloc(dev_hdl, ep_desc, intf_obj, &ep_wrap);
if (ret != ESP_OK) { if (ret != ESP_OK) {
goto ep_alloc_err; goto ep_alloc_err;
} }
//Fill the interface object with the allocated endpoints // Fill the interface object with the allocated endpoints
intf_obj->constant.endpoints[i] = ep_wrap; intf_obj->constant.endpoints[i] = ep_wrap;
} }
//Add interface object to client (safe because we have already taken the mutex) // Add interface object to client (safe because we have already taken the mutex)
TAILQ_INSERT_TAIL(&client_obj->mux_protected.interface_tailq, intf_obj, mux_protected.tailq_entry); TAILQ_INSERT_TAIL(&client_obj->mux_protected.interface_tailq, intf_obj, mux_protected.tailq_entry);
//Add each endpoint wrapper item to the client's endpoint list // Add each endpoint wrapper item to the client's endpoint list
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
for (int i = 0; i < intf_desc->bNumEndpoints; i++) { for (int i = 0; i < intf_desc->bNumEndpoints; i++) {
TAILQ_INSERT_TAIL(&client_obj->dynamic.idle_ep_tailq, intf_obj->constant.endpoints[i], dynamic.tailq_entry); TAILQ_INSERT_TAIL(&client_obj->dynamic.idle_ep_tailq, intf_obj->constant.endpoints[i], dynamic.tailq_entry);
} }
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
//Write back result // Write back result
*intf_obj_ret = intf_obj; *intf_obj_ret = intf_obj;
ret = ESP_OK; ret = ESP_OK;
return ret; return ret;
@ -1075,7 +1075,7 @@ exit:
static esp_err_t interface_release(client_t *client_obj, usb_device_handle_t dev_hdl, uint8_t bInterfaceNumber) static esp_err_t interface_release(client_t *client_obj, usb_device_handle_t dev_hdl, uint8_t bInterfaceNumber)
{ {
esp_err_t ret; esp_err_t ret;
//Find the interface object // Find the interface object
interface_t *intf_obj_iter; interface_t *intf_obj_iter;
interface_t *intf_obj = NULL; interface_t *intf_obj = NULL;
TAILQ_FOREACH(intf_obj_iter, &client_obj->mux_protected.interface_tailq, mux_protected.tailq_entry) { TAILQ_FOREACH(intf_obj_iter, &client_obj->mux_protected.interface_tailq, mux_protected.tailq_entry) {
@ -1089,13 +1089,13 @@ static esp_err_t interface_release(client_t *client_obj, usb_device_handle_t dev
goto exit; goto exit;
} }
//Check that all endpoints in the interface are in a state to be freed // Check that all endpoints in the interface are in a state to be freed
//Todo: Check that each EP is halted before allowing them to be freed (IDF-7273) // Todo: Check that each EP is halted before allowing them to be freed (IDF-7273)
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
bool can_free = true; bool can_free = true;
for (int i = 0; i < intf_obj->constant.intf_desc->bNumEndpoints; i++) { for (int i = 0; i < intf_obj->constant.intf_desc->bNumEndpoints; i++) {
ep_wrapper_t *ep_wrap = intf_obj->constant.endpoints[i]; ep_wrapper_t *ep_wrap = intf_obj->constant.endpoints[i];
//Endpoint must not be on the pending list and must not have in-flight URBs // Endpoint must not be on the pending list and must not have in-flight URBs
if (ep_wrap->dynamic.num_urb_inflight != 0 || ep_wrap->dynamic.flags.pending) { if (ep_wrap->dynamic.num_urb_inflight != 0 || ep_wrap->dynamic.flags.pending) {
can_free = false; can_free = false;
break; break;
@ -1106,21 +1106,21 @@ static esp_err_t interface_release(client_t *client_obj, usb_device_handle_t dev
ret = ESP_ERR_INVALID_STATE; ret = ESP_ERR_INVALID_STATE;
goto exit; goto exit;
} }
//Proceed to remove all endpoint wrapper items from the list // Proceed to remove all endpoint wrapper items from the list
for (int i = 0; i < intf_obj->constant.intf_desc->bNumEndpoints; i++) { for (int i = 0; i < intf_obj->constant.intf_desc->bNumEndpoints; i++) {
TAILQ_REMOVE(&client_obj->dynamic.idle_ep_tailq, intf_obj->constant.endpoints[i], dynamic.tailq_entry); TAILQ_REMOVE(&client_obj->dynamic.idle_ep_tailq, intf_obj->constant.endpoints[i], dynamic.tailq_entry);
} }
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
//Remove the interface object from the list (safe because we have already taken the mutex) // Remove the interface object from the list (safe because we have already taken the mutex)
TAILQ_REMOVE(&client_obj->mux_protected.interface_tailq, intf_obj, mux_protected.tailq_entry); TAILQ_REMOVE(&client_obj->mux_protected.interface_tailq, intf_obj, mux_protected.tailq_entry);
//Free each endpoint in the interface // Free each endpoint in the interface
for (int i = 0; i < intf_obj->constant.intf_desc->bNumEndpoints; i++) { for (int i = 0; i < intf_obj->constant.intf_desc->bNumEndpoints; i++) {
ep_wrapper_free(dev_hdl, intf_obj->constant.endpoints[i]); ep_wrapper_free(dev_hdl, intf_obj->constant.endpoints[i]);
intf_obj->constant.endpoints[i] = NULL; intf_obj->constant.endpoints[i] = NULL;
} }
//Free the interface object itself // Free the interface object itself
interface_free(intf_obj); interface_free(intf_obj);
ret = ESP_OK; ret = ESP_OK;
exit: exit:
@ -1137,18 +1137,18 @@ esp_err_t usb_host_interface_claim(usb_host_client_handle_t client_hdl, usb_devi
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
uint8_t dev_addr; uint8_t dev_addr;
ESP_ERROR_CHECK(usbh_dev_get_addr(dev_hdl, &dev_addr)); ESP_ERROR_CHECK(usbh_dev_get_addr(dev_hdl, &dev_addr));
//Check if client actually opened device // Check if client actually opened device
HOST_CHECK_FROM_CRIT(_check_client_opened_device(client_obj, dev_addr), ESP_ERR_INVALID_STATE); HOST_CHECK_FROM_CRIT(_check_client_opened_device(client_obj, dev_addr), ESP_ERR_INVALID_STATE);
client_obj->dynamic.flags.taking_mux = 1; client_obj->dynamic.flags.taking_mux = 1;
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
//Take mux lock. This protects the client being released or other clients from claiming interfaces // Take mux lock. This protects the client being released or other clients from claiming interfaces
xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY); xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY);
esp_err_t ret; esp_err_t ret;
const usb_config_desc_t *config_desc; const usb_config_desc_t *config_desc;
ESP_ERROR_CHECK(usbh_dev_get_config_desc(dev_hdl, &config_desc)); ESP_ERROR_CHECK(usbh_dev_get_config_desc(dev_hdl, &config_desc));
interface_t *intf_obj; interface_t *intf_obj;
//Claim interface // Claim interface
ret = interface_claim(client_obj, dev_hdl, config_desc, bInterfaceNumber, bAlternateSetting, &intf_obj); ret = interface_claim(client_obj, dev_hdl, config_desc, bInterfaceNumber, bAlternateSetting, &intf_obj);
if (ret != ESP_OK) { if (ret != ESP_OK) {
goto exit; goto exit;
@ -1174,12 +1174,12 @@ esp_err_t usb_host_interface_release(usb_host_client_handle_t client_hdl, usb_de
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
uint8_t dev_addr; uint8_t dev_addr;
ESP_ERROR_CHECK(usbh_dev_get_addr(dev_hdl, &dev_addr)); ESP_ERROR_CHECK(usbh_dev_get_addr(dev_hdl, &dev_addr));
//Check if client actually opened device // Check if client actually opened device
HOST_CHECK_FROM_CRIT(_check_client_opened_device(client_obj, dev_addr), ESP_ERR_INVALID_STATE); HOST_CHECK_FROM_CRIT(_check_client_opened_device(client_obj, dev_addr), ESP_ERR_INVALID_STATE);
client_obj->dynamic.flags.taking_mux = 1; client_obj->dynamic.flags.taking_mux = 1;
HOST_EXIT_CRITICAL(); HOST_EXIT_CRITICAL();
//Take mux lock. This protects the client being released or other clients from claiming interfaces // Take mux lock. This protects the client being released or other clients from claiming interfaces
xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY); xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY);
esp_err_t ret = interface_release(client_obj, dev_hdl, bInterfaceNumber); esp_err_t ret = interface_release(client_obj, dev_hdl, bInterfaceNumber);
xSemaphoreGive(p_host_lib_obj->constant.mux_lock); xSemaphoreGive(p_host_lib_obj->constant.mux_lock);
@ -1266,8 +1266,8 @@ esp_err_t usb_host_transfer_free(usb_transfer_t *transfer)
esp_err_t usb_host_transfer_submit(usb_transfer_t *transfer) esp_err_t usb_host_transfer_submit(usb_transfer_t *transfer)
{ {
HOST_CHECK(transfer != NULL, ESP_ERR_INVALID_ARG); HOST_CHECK(transfer != NULL, ESP_ERR_INVALID_ARG);
//Check that transfer and target endpoint are valid // Check that transfer and target endpoint are valid
HOST_CHECK(transfer->device_handle != NULL, ESP_ERR_INVALID_ARG); //Target device must be set HOST_CHECK(transfer->device_handle != NULL, ESP_ERR_INVALID_ARG); // Target device must be set
HOST_CHECK((transfer->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK) != 0, ESP_ERR_INVALID_ARG); HOST_CHECK((transfer->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK) != 0, ESP_ERR_INVALID_ARG);
usbh_ep_handle_t ep_hdl; usbh_ep_handle_t ep_hdl;
@ -1281,7 +1281,7 @@ esp_err_t usb_host_transfer_submit(usb_transfer_t *transfer)
} }
ep_wrap = usbh_ep_get_context(ep_hdl); ep_wrap = usbh_ep_get_context(ep_hdl);
assert(ep_wrap != NULL); assert(ep_wrap != NULL);
//Check that we are not submitting a transfer already in-flight // Check that we are not submitting a transfer already in-flight
HOST_CHECK(!urb_obj->usb_host_inflight, ESP_ERR_NOT_FINISHED); HOST_CHECK(!urb_obj->usb_host_inflight, ESP_ERR_NOT_FINISHED);
urb_obj->usb_host_inflight = true; urb_obj->usb_host_inflight = true;
HOST_ENTER_CRITICAL(); HOST_ENTER_CRITICAL();
@ -1306,17 +1306,17 @@ err:
esp_err_t usb_host_transfer_submit_control(usb_host_client_handle_t client_hdl, usb_transfer_t *transfer) esp_err_t usb_host_transfer_submit_control(usb_host_client_handle_t client_hdl, usb_transfer_t *transfer)
{ {
HOST_CHECK(client_hdl != NULL && transfer != NULL, ESP_ERR_INVALID_ARG); HOST_CHECK(client_hdl != NULL && transfer != NULL, ESP_ERR_INVALID_ARG);
//Check that control transfer is valid // Check that control transfer is valid
HOST_CHECK(transfer->device_handle != NULL, ESP_ERR_INVALID_ARG); //Target device must be set HOST_CHECK(transfer->device_handle != NULL, ESP_ERR_INVALID_ARG); // Target device must be set
//Control transfers must be targeted at EP 0 // Control transfers must be targeted at EP 0
HOST_CHECK((transfer->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK) == 0, ESP_ERR_INVALID_ARG); HOST_CHECK((transfer->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK) == 0, ESP_ERR_INVALID_ARG);
usb_device_handle_t dev_hdl = transfer->device_handle; usb_device_handle_t dev_hdl = transfer->device_handle;
urb_t *urb_obj = __containerof(transfer, urb_t, transfer); urb_t *urb_obj = __containerof(transfer, urb_t, transfer);
//Check that we are not submitting a transfer already in-flight // Check that we are not submitting a transfer already in-flight
HOST_CHECK(!urb_obj->usb_host_inflight, ESP_ERR_NOT_FINISHED); HOST_CHECK(!urb_obj->usb_host_inflight, ESP_ERR_NOT_FINISHED);
urb_obj->usb_host_inflight = true; urb_obj->usb_host_inflight = true;
//Save client handle into URB // Save client handle into URB
urb_obj->usb_host_client = (void *)client_hdl; urb_obj->usb_host_client = (void *)client_hdl;
esp_err_t ret; esp_err_t ret;

View File

@ -85,7 +85,7 @@ static esp_err_t phy_external_iopins_configure(const usb_phy_ext_io_conf_t *ext_
{ext_io_conf->vmo_io_num, usb_otg_periph_signal.extphy_vmo_out, true}, {ext_io_conf->vmo_io_num, usb_otg_periph_signal.extphy_vmo_out, true},
}; };
return phy_iopins_configure(usb_periph_iopins, sizeof(usb_periph_iopins)/sizeof(usb_iopin_dsc_t)); return phy_iopins_configure(usb_periph_iopins, sizeof(usb_periph_iopins) / sizeof(usb_iopin_dsc_t));
} }
static esp_err_t phy_otg_iopins_configure(const usb_phy_otg_io_conf_t *otg_io_conf) static esp_err_t phy_otg_iopins_configure(const usb_phy_otg_io_conf_t *otg_io_conf)
@ -103,7 +103,7 @@ static esp_err_t phy_otg_iopins_configure(const usb_phy_otg_io_conf_t *otg_io_co
{otg_io_conf->chrgvbus_io_num, usb_otg_periph_signal.srp_chrgvbus_out, true}, {otg_io_conf->chrgvbus_io_num, usb_otg_periph_signal.srp_chrgvbus_out, true},
{otg_io_conf->dischrgvbus_io_num, usb_otg_periph_signal.srp_dischrgvbus_out, true}, {otg_io_conf->dischrgvbus_io_num, usb_otg_periph_signal.srp_dischrgvbus_out, true},
}; };
return phy_iopins_configure(usb_periph_iopins, sizeof(usb_periph_iopins)/sizeof(usb_iopin_dsc_t)); return phy_iopins_configure(usb_periph_iopins, sizeof(usb_periph_iopins) / sizeof(usb_iopin_dsc_t));
} }
esp_err_t usb_phy_otg_set_mode(usb_phy_handle_t handle, usb_otg_mode_t mode) esp_err_t usb_phy_otg_set_mode(usb_phy_handle_t handle, usb_otg_mode_t mode)
@ -114,17 +114,17 @@ esp_err_t usb_phy_otg_set_mode(usb_phy_handle_t handle, usb_otg_mode_t mode)
handle->otg_mode = mode; handle->otg_mode = mode;
if (mode == USB_OTG_MODE_HOST) { if (mode == USB_OTG_MODE_HOST) {
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_OTG_IDDIG_IN_IDX, false); //connected connector is A side esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_OTG_IDDIG_IN_IDX, false); // connected connector is A side
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_SRP_BVALID_IN_IDX, false); esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_SRP_BVALID_IN_IDX, false);
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_VBUSVALID_IN_IDX, false); //receiving a valid Vbus from host esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_VBUSVALID_IN_IDX, false); // receiving a valid Vbus from host
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_AVALID_IN_IDX, false); //HIGH to force USB host mode esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_AVALID_IN_IDX, false); // HIGH to force USB host mode
if (handle->target == USB_PHY_TARGET_INT) { if (handle->target == USB_PHY_TARGET_INT) {
usb_phy_hal_int_load_conf_host(&(handle->hal_context)); usb_phy_hal_int_load_conf_host(&(handle->hal_context));
} }
} else if (mode == USB_OTG_MODE_DEVICE) { } else if (mode == USB_OTG_MODE_DEVICE) {
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_IDDIG_IN_IDX, false); //connected connector is mini-B side esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_IDDIG_IN_IDX, false); // connected connector is mini-B side
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_SRP_BVALID_IN_IDX, false); //HIGH to force USB device mode esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_SRP_BVALID_IN_IDX, false); // HIGH to force USB device mode
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_VBUSVALID_IN_IDX, false); //receiving a valid Vbus from device esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_VBUSVALID_IN_IDX, false); // receiving a valid Vbus from device
esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_OTG_AVALID_IN_IDX, false); esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_OTG_AVALID_IN_IDX, false);
} }

View File

@ -15,8 +15,8 @@ urb_t *urb_alloc(size_t data_buffer_size, size_t header_size, int num_isoc_packe
if (urb == NULL || data_buffer == NULL) { if (urb == NULL || data_buffer == NULL) {
goto err; goto err;
} }
urb->usb_host_header_size = header_size; //Indicate that this URB's data_buffer has a header in front of it. urb->usb_host_header_size = header_size; // Indicate that this URB's data_buffer has a header in front of it.
//Case as dummy transfer to write to initialize const fields // Case as dummy transfer to write to initialize const fields
usb_transfer_dummy_t *dummy_transfer = (usb_transfer_dummy_t *)&urb->transfer; usb_transfer_dummy_t *dummy_transfer = (usb_transfer_dummy_t *)&urb->transfer;
dummy_transfer->data_buffer = (uint8_t *)(data_buffer + header_size); dummy_transfer->data_buffer = (uint8_t *)(data_buffer + header_size);
dummy_transfer->data_buffer_size = data_buffer_size; dummy_transfer->data_buffer_size = data_buffer_size;

View File

@ -25,17 +25,17 @@
#define EP_NUM_MAX 16 // The largest possible non-default endpoint number #define EP_NUM_MAX 16 // The largest possible non-default endpoint number
#define NUM_NON_DEFAULT_EP ((EP_NUM_MAX - 1) * 2) // The total number of non-default endpoints a device can have. #define NUM_NON_DEFAULT_EP ((EP_NUM_MAX - 1) * 2) // The total number of non-default endpoints a device can have.
//Device action flags. LISTED IN THE ORDER THEY SHOULD BE HANDLED IN within usbh_process(). Some actions are mutually exclusive // Device action flags. LISTED IN THE ORDER THEY SHOULD BE HANDLED IN within usbh_process(). Some actions are mutually exclusive
typedef enum { typedef enum {
DEV_ACTION_EPn_HALT_FLUSH = (1 << 0), //Halt all non-default endpoints then flush them (called after a device gone is gone) DEV_ACTION_EPn_HALT_FLUSH = (1 << 0), // Halt all non-default endpoints then flush them (called after a device gone is gone)
DEV_ACTION_EP0_FLUSH = (1 << 1), //Retire all URBS submitted to EP0 DEV_ACTION_EP0_FLUSH = (1 << 1), // Retire all URBS submitted to EP0
DEV_ACTION_EP0_DEQUEUE = (1 << 2), //Dequeue all URBs from EP0 DEV_ACTION_EP0_DEQUEUE = (1 << 2), // Dequeue all URBs from EP0
DEV_ACTION_EP0_CLEAR = (1 << 3), //Move EP0 to the the active state DEV_ACTION_EP0_CLEAR = (1 << 3), // Move EP0 to the the active state
DEV_ACTION_PROP_GONE_EVT = (1 << 4), //Propagate a USBH_EVENT_DEV_GONE event DEV_ACTION_PROP_GONE_EVT = (1 << 4), // Propagate a USBH_EVENT_DEV_GONE event
DEV_ACTION_FREE_AND_RECOVER = (1 << 5), //Free the device object, but send a USBH_HUB_REQ_PORT_RECOVER request afterwards. DEV_ACTION_FREE_AND_RECOVER = (1 << 5), // Free the device object, but send a USBH_HUB_REQ_PORT_RECOVER request afterwards.
DEV_ACTION_FREE = (1 << 6), //Free the device object DEV_ACTION_FREE = (1 << 6), // Free the device object
DEV_ACTION_PORT_DISABLE = (1 << 7), //Request the hub driver to disable the port of the device DEV_ACTION_PORT_DISABLE = (1 << 7), // Request the hub driver to disable the port of the device
DEV_ACTION_PROP_NEW = (1 << 8), //Propagate a USBH_EVENT_DEV_NEW event DEV_ACTION_PROP_NEW = (1 << 8), // Propagate a USBH_EVENT_DEV_NEW event
} dev_action_t; } dev_action_t;
typedef struct device_s device_t; typedef struct device_s device_t;
@ -45,13 +45,13 @@ typedef struct {
usbh_ep_cb_t ep_cb; usbh_ep_cb_t ep_cb;
void *ep_cb_arg; void *ep_cb_arg;
hcd_pipe_handle_t pipe_hdl; hcd_pipe_handle_t pipe_hdl;
device_t *dev; //Pointer to the device object that this endpoint is contained in device_t *dev; // Pointer to the device object that this endpoint is contained in
const usb_ep_desc_t *ep_desc; //This just stores a pointer endpoint descriptor inside the device's "config_desc" const usb_ep_desc_t *ep_desc; // This just stores a pointer endpoint descriptor inside the device's "config_desc"
} constant; } constant;
} endpoint_t; } endpoint_t;
struct device_s { struct device_s {
//Dynamic members require a critical section // Dynamic members require a critical section
struct { struct {
TAILQ_ENTRY(device_s) tailq_entry; TAILQ_ENTRY(device_s) tailq_entry;
union { union {
@ -70,7 +70,7 @@ struct device_s {
usb_device_state_t state; usb_device_state_t state;
uint32_t ref_count; uint32_t ref_count;
} dynamic; } dynamic;
//Mux protected members must be protected by the USBH mux_lock when accessed // Mux protected members must be protected by the USBH mux_lock when accessed
struct { struct {
/* /*
- Endpoint object pointers for each possible non-default endpoint - Endpoint object pointers for each possible non-default endpoint
@ -78,7 +78,7 @@ struct device_s {
*/ */
endpoint_t *endpoints[NUM_NON_DEFAULT_EP]; endpoint_t *endpoints[NUM_NON_DEFAULT_EP];
} mux_protected; } mux_protected;
//Constant members do not change after device allocation and enumeration thus do not require a critical section // Constant members do not change after device allocation and enumeration thus do not require a critical section
struct { struct {
hcd_pipe_handle_t default_pipe; hcd_pipe_handle_t default_pipe;
hcd_port_handle_t port_hdl; hcd_port_handle_t port_hdl;
@ -93,16 +93,16 @@ struct device_s {
}; };
typedef struct { typedef struct {
//Dynamic members require a critical section // Dynamic members require a critical section
struct { struct {
TAILQ_HEAD(tailhead_devs, device_s) devs_idle_tailq; //Tailq of all enum and configured devices TAILQ_HEAD(tailhead_devs, device_s) devs_idle_tailq; // Tailq of all enum and configured devices
TAILQ_HEAD(tailhead_devs_cb, device_s) devs_pending_tailq; //Tailq of devices that need to have their cb called TAILQ_HEAD(tailhead_devs_cb, device_s) devs_pending_tailq; // Tailq of devices that need to have their cb called
} dynamic; } dynamic;
//Mux protected members must be protected by the USBH mux_lock when accessed // Mux protected members must be protected by the USBH mux_lock when accessed
struct { struct {
uint8_t num_device; //Number of enumerated devices uint8_t num_device; // Number of enumerated devices
} mux_protected; } mux_protected;
//Constant members do no change after installation thus do not require a critical section // Constant members do no change after installation thus do not require a critical section
struct { struct {
usb_proc_req_cb_t proc_req_cb; usb_proc_req_cb_t proc_req_cb;
void *proc_req_cb_arg; void *proc_req_cb_arg;
@ -169,13 +169,13 @@ static endpoint_t *get_ep_from_addr(device_t *dev_obj, uint8_t bEndpointAddress)
CALLER IS RESPONSIBLE FOR TAKING THE mux_lock CALLER IS RESPONSIBLE FOR TAKING THE mux_lock
*/ */
//Calculate index to the device's endpoint object list // Calculate index to the device's endpoint object list
int index; int index;
// EP_NUM_MIN should map to an index of 0 // EP_NUM_MIN should map to an index of 0
index = (bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK) - EP_NUM_MIN; index = (bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK) - EP_NUM_MIN;
assert(index >= 0); // Endpoint address is not supported assert(index >= 0); // Endpoint address is not supported
if (bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK) { if (bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK) {
//OUT EPs are listed before IN EPs, so add an offset // OUT EPs are listed before IN EPs, so add an offset
index += (EP_NUM_MAX - EP_NUM_MIN); index += (EP_NUM_MAX - EP_NUM_MIN);
} }
return dev_obj->mux_protected.endpoints[index]; return dev_obj->mux_protected.endpoints[index];
@ -187,13 +187,13 @@ static inline void set_ep_from_addr(device_t *dev_obj, uint8_t bEndpointAddress,
CALLER IS RESPONSIBLE FOR TAKING THE mux_lock CALLER IS RESPONSIBLE FOR TAKING THE mux_lock
*/ */
//Calculate index to the device's endpoint object list // Calculate index to the device's endpoint object list
int index; int index;
// EP_NUM_MIN should map to an index of 0 // EP_NUM_MIN should map to an index of 0
index = (bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK) - EP_NUM_MIN; index = (bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK) - EP_NUM_MIN;
assert(index >= 0); // Endpoint address is not supported assert(index >= 0); // Endpoint address is not supported
if (bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK) { if (bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK) {
//OUT EPs are listed before IN EPs, so add an offset // OUT EPs are listed before IN EPs, so add an offset
index += (EP_NUM_MAX - EP_NUM_MIN); index += (EP_NUM_MAX - EP_NUM_MIN);
} }
dev_obj->mux_protected.endpoints[index] = ep_obj; dev_obj->mux_protected.endpoints[index] = ep_obj;
@ -215,20 +215,20 @@ static bool urb_check_args(urb_t *urb)
static bool transfer_check_usb_compliance(usb_transfer_t *transfer, usb_transfer_type_t type, int mps, bool is_in) static bool transfer_check_usb_compliance(usb_transfer_t *transfer, usb_transfer_type_t type, int mps, bool is_in)
{ {
if (type == USB_TRANSFER_TYPE_CTRL) { if (type == USB_TRANSFER_TYPE_CTRL) {
//Check that num_bytes and wLength are set correctly // Check that num_bytes and wLength are set correctly
usb_setup_packet_t *setup_pkt = (usb_setup_packet_t *)transfer->data_buffer; usb_setup_packet_t *setup_pkt = (usb_setup_packet_t *)transfer->data_buffer;
if (transfer->num_bytes != sizeof(usb_setup_packet_t) + setup_pkt->wLength) { if (transfer->num_bytes != sizeof(usb_setup_packet_t) + setup_pkt->wLength) {
ESP_LOGE(USBH_TAG, "usb_transfer_t num_bytes and usb_setup_packet_t wLength mismatch"); ESP_LOGE(USBH_TAG, "usb_transfer_t num_bytes and usb_setup_packet_t wLength mismatch");
return false; return false;
} }
} else if (type == USB_TRANSFER_TYPE_ISOCHRONOUS) { } else if (type == USB_TRANSFER_TYPE_ISOCHRONOUS) {
//Check that there is at least one isochronous packet descriptor // Check that there is at least one isochronous packet descriptor
if (transfer->num_isoc_packets <= 0) { if (transfer->num_isoc_packets <= 0) {
ESP_LOGE(USBH_TAG, "usb_transfer_t num_isoc_packets is 0"); ESP_LOGE(USBH_TAG, "usb_transfer_t num_isoc_packets is 0");
return false; return false;
} }
//Check that sum of all packet lengths add up to transfer length // Check that sum of all packet lengths add up to transfer length
//If IN, check that each packet length is integer multiple of MPS // If IN, check that each packet length is integer multiple of MPS
int total_num_bytes = 0; int total_num_bytes = 0;
bool mod_mps_all_zero = true; bool mod_mps_all_zero = true;
for (int i = 0; i < transfer->num_isoc_packets; i++) { for (int i = 0; i < transfer->num_isoc_packets; i++) {
@ -246,7 +246,7 @@ static bool transfer_check_usb_compliance(usb_transfer_t *transfer, usb_transfer
return false; return false;
} }
} else { } else {
//Check that IN transfers are integer multiple of MPS // Check that IN transfers are integer multiple of MPS
if (is_in && (transfer->num_bytes % mps != 0)) { if (is_in && (transfer->num_bytes % mps != 0)) {
ESP_LOGE(USBH_TAG, "IN transfer num_bytes not integer multiple of MPS"); ESP_LOGE(USBH_TAG, "IN transfer num_bytes not integer multiple of MPS");
return false; return false;
@ -267,7 +267,7 @@ static esp_err_t endpoint_alloc(device_t *dev_obj, const usb_ep_desc_t *ep_desc,
if (ep_obj == NULL) { if (ep_obj == NULL) {
return ESP_ERR_NO_MEM; return ESP_ERR_NO_MEM;
} }
//Allocate the EP's underlying pipe // Allocate the EP's underlying pipe
hcd_pipe_config_t pipe_config = { hcd_pipe_config_t pipe_config = {
.callback = epN_pipe_callback, .callback = epN_pipe_callback,
.callback_arg = (void *)ep_obj, .callback_arg = (void *)ep_obj,
@ -280,13 +280,13 @@ static esp_err_t endpoint_alloc(device_t *dev_obj, const usb_ep_desc_t *ep_desc,
if (ret != ESP_OK) { if (ret != ESP_OK) {
goto pipe_err; goto pipe_err;
} }
//Initialize the endpoint object // Initialize the endpoint object
ep_obj->constant.pipe_hdl = pipe_hdl; ep_obj->constant.pipe_hdl = pipe_hdl;
ep_obj->constant.ep_cb = ep_config->ep_cb; ep_obj->constant.ep_cb = ep_config->ep_cb;
ep_obj->constant.ep_cb_arg = ep_config->ep_cb_arg; ep_obj->constant.ep_cb_arg = ep_config->ep_cb_arg;
ep_obj->constant.dev = dev_obj; ep_obj->constant.dev = dev_obj;
ep_obj->constant.ep_desc = ep_desc; ep_obj->constant.ep_desc = ep_desc;
//Return the endpoint object // Return the endpoint object
*ep_obj_ret = ep_obj; *ep_obj_ret = ep_obj;
ret = ESP_OK; ret = ESP_OK;
@ -302,9 +302,9 @@ static void endpoint_free(endpoint_t *ep_obj)
if (ep_obj == NULL) { if (ep_obj == NULL) {
return; return;
} }
//Deallocate the EP's underlying pipe // Deallocate the EP's underlying pipe
ESP_ERROR_CHECK(hcd_pipe_free(ep_obj->constant.pipe_hdl)); ESP_ERROR_CHECK(hcd_pipe_free(ep_obj->constant.pipe_hdl));
//Free the heap object // Free the heap object
heap_caps_free(ep_obj); heap_caps_free(ep_obj);
} }
@ -317,12 +317,12 @@ static esp_err_t device_alloc(hcd_port_handle_t port_hdl, usb_speed_t speed, dev
ret = ESP_ERR_NO_MEM; ret = ESP_ERR_NO_MEM;
goto err; goto err;
} }
//Allocate a pipe for EP0. We set the pipe callback to NULL for now // Allocate a pipe for EP0. We set the pipe callback to NULL for now
hcd_pipe_config_t pipe_config = { hcd_pipe_config_t pipe_config = {
.callback = NULL, .callback = NULL,
.callback_arg = NULL, .callback_arg = NULL,
.context = (void *)dev_obj, .context = (void *)dev_obj,
.ep_desc = NULL, //No endpoint descriptor means we're allocating a pipe for EP0 .ep_desc = NULL, // No endpoint descriptor means we're allocating a pipe for EP0
.dev_speed = speed, .dev_speed = speed,
.dev_addr = 0, .dev_addr = 0,
}; };
@ -331,11 +331,11 @@ static esp_err_t device_alloc(hcd_port_handle_t port_hdl, usb_speed_t speed, dev
if (ret != ESP_OK) { if (ret != ESP_OK) {
goto err; goto err;
} }
//Initialize device object // Initialize device object
dev_obj->dynamic.state = USB_DEVICE_STATE_DEFAULT; dev_obj->dynamic.state = USB_DEVICE_STATE_DEFAULT;
dev_obj->constant.default_pipe = default_pipe_hdl; dev_obj->constant.default_pipe = default_pipe_hdl;
dev_obj->constant.port_hdl = port_hdl; dev_obj->constant.port_hdl = port_hdl;
//Note: dev_obj->constant.address is assigned later during enumeration // Note: dev_obj->constant.address is assigned later during enumeration
dev_obj->constant.speed = speed; dev_obj->constant.speed = speed;
dev_obj->constant.desc = dev_desc; dev_obj->constant.desc = dev_desc;
*dev_obj_ret = dev_obj; *dev_obj_ret = dev_obj;
@ -353,11 +353,11 @@ static void device_free(device_t *dev_obj)
if (dev_obj == NULL) { if (dev_obj == NULL) {
return; return;
} }
//Configuration might not have been allocated (in case of early enumeration failure) // Configuration might not have been allocated (in case of early enumeration failure)
if (dev_obj->constant.config_desc) { if (dev_obj->constant.config_desc) {
heap_caps_free((usb_config_desc_t *)dev_obj->constant.config_desc); heap_caps_free((usb_config_desc_t *)dev_obj->constant.config_desc);
} }
//String descriptors might not have been allocated (in case of early enumeration failure) // String descriptors might not have been allocated (in case of early enumeration failure)
if (dev_obj->constant.str_desc_manu) { if (dev_obj->constant.str_desc_manu) {
heap_caps_free((usb_str_desc_t *)dev_obj->constant.str_desc_manu); heap_caps_free((usb_str_desc_t *)dev_obj->constant.str_desc_manu);
} }
@ -380,13 +380,13 @@ static bool ep0_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_
device_t *dev_obj = (device_t *)user_arg; device_t *dev_obj = (device_t *)user_arg;
switch (pipe_event) { switch (pipe_event) {
case HCD_PIPE_EVENT_URB_DONE: case HCD_PIPE_EVENT_URB_DONE:
//A control transfer completed on EP0's pipe . We need to dequeue it // A control transfer completed on EP0's pipe . We need to dequeue it
action_flags = DEV_ACTION_EP0_DEQUEUE; action_flags = DEV_ACTION_EP0_DEQUEUE;
break; break;
case HCD_PIPE_EVENT_ERROR_XFER: case HCD_PIPE_EVENT_ERROR_XFER:
case HCD_PIPE_EVENT_ERROR_URB_NOT_AVAIL: case HCD_PIPE_EVENT_ERROR_URB_NOT_AVAIL:
case HCD_PIPE_EVENT_ERROR_OVERFLOW: case HCD_PIPE_EVENT_ERROR_OVERFLOW:
//EP0's pipe has encountered an error. We need to retire all URBs, dequeue them, then make the pipe active again // EP0's pipe has encountered an error. We need to retire all URBs, dequeue them, then make the pipe active again
action_flags = DEV_ACTION_EP0_FLUSH | action_flags = DEV_ACTION_EP0_FLUSH |
DEV_ACTION_EP0_DEQUEUE | DEV_ACTION_EP0_DEQUEUE |
DEV_ACTION_EP0_CLEAR; DEV_ACTION_EP0_CLEAR;
@ -397,7 +397,7 @@ static bool ep0_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_
} }
break; break;
case HCD_PIPE_EVENT_ERROR_STALL: case HCD_PIPE_EVENT_ERROR_STALL:
//EP0's pipe encountered a "protocol stall". We just need to dequeue URBs then make the pipe active again // EP0's pipe encountered a "protocol stall". We just need to dequeue URBs then make the pipe active again
action_flags = DEV_ACTION_EP0_DEQUEUE | DEV_ACTION_EP0_CLEAR; action_flags = DEV_ACTION_EP0_DEQUEUE | DEV_ACTION_EP0_CLEAR;
if (in_isr) { if (in_isr) {
ESP_EARLY_LOGE(USBH_TAG, "Dev %d EP 0 STALL", dev_obj->constant.address); ESP_EARLY_LOGE(USBH_TAG, "Dev %d EP 0 STALL", dev_obj->constant.address);
@ -438,9 +438,9 @@ static bool _dev_set_actions(device_t *dev_obj, uint32_t action_flags)
return false; return false;
} }
bool call_proc_req_cb; bool call_proc_req_cb;
//Check if device is already on the callback list // Check if device is already on the callback list
if (!dev_obj->dynamic.flags.in_pending_list) { if (!dev_obj->dynamic.flags.in_pending_list) {
//Move device form idle device list to callback device list // Move device form idle device list to callback device list
TAILQ_REMOVE(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry); TAILQ_REMOVE(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry);
TAILQ_INSERT_TAIL(&p_usbh_obj->dynamic.devs_pending_tailq, dev_obj, dynamic.tailq_entry); TAILQ_INSERT_TAIL(&p_usbh_obj->dynamic.devs_pending_tailq, dev_obj, dynamic.tailq_entry);
dev_obj->dynamic.action_flags |= action_flags; dev_obj->dynamic.action_flags |= action_flags;
@ -454,9 +454,9 @@ static bool _dev_set_actions(device_t *dev_obj, uint32_t action_flags)
static inline void handle_epn_halt_flush(device_t *dev_obj) static inline void handle_epn_halt_flush(device_t *dev_obj)
{ {
//We need to take the mux_lock to access mux_protected members // We need to take the mux_lock to access mux_protected members
xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
//Halt then flush all non-default EPs // Halt then flush all non-default EPs
for (int i = 0; i < NUM_NON_DEFAULT_EP; i++) { for (int i = 0; i < NUM_NON_DEFAULT_EP; i++) {
if (dev_obj->mux_protected.endpoints[i] != NULL) { if (dev_obj->mux_protected.endpoints[i] != NULL) {
ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->mux_protected.endpoints[i]->constant.pipe_hdl, HCD_PIPE_CMD_HALT)); ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->mux_protected.endpoints[i]->constant.pipe_hdl, HCD_PIPE_CMD_HALT));
@ -474,7 +474,7 @@ static inline void handle_ep0_flush(device_t *dev_obj)
static inline void handle_ep0_dequeue(device_t *dev_obj) static inline void handle_ep0_dequeue(device_t *dev_obj)
{ {
//Empty URBs from EP0's pipe and call the control transfer callback // Empty URBs from EP0's pipe and call the control transfer callback
ESP_LOGD(USBH_TAG, "Default pipe device %d", dev_obj->constant.address); ESP_LOGD(USBH_TAG, "Default pipe device %d", dev_obj->constant.address);
int num_urbs = 0; int num_urbs = 0;
urb_t *urb = hcd_urb_dequeue(dev_obj->constant.default_pipe); urb_t *urb = hcd_urb_dequeue(dev_obj->constant.default_pipe);
@ -490,28 +490,28 @@ static inline void handle_ep0_dequeue(device_t *dev_obj)
static inline void handle_ep0_clear(device_t *dev_obj) static inline void handle_ep0_clear(device_t *dev_obj)
{ {
//We allow the pipe command to fail just in case the pipe becomes invalid mid command // We allow the pipe command to fail just in case the pipe becomes invalid mid command
hcd_pipe_command(dev_obj->constant.default_pipe, HCD_PIPE_CMD_CLEAR); hcd_pipe_command(dev_obj->constant.default_pipe, HCD_PIPE_CMD_CLEAR);
} }
static inline void handle_prop_gone_evt(device_t *dev_obj) static inline void handle_prop_gone_evt(device_t *dev_obj)
{ {
//Flush EP0's pipe. Then propagate a USBH_EVENT_DEV_GONE event // Flush EP0's pipe. Then propagate a USBH_EVENT_DEV_GONE event
ESP_LOGE(USBH_TAG, "Device %d gone", dev_obj->constant.address); ESP_LOGE(USBH_TAG, "Device %d gone", dev_obj->constant.address);
p_usbh_obj->constant.event_cb((usb_device_handle_t)dev_obj, USBH_EVENT_DEV_GONE, p_usbh_obj->constant.event_cb_arg); p_usbh_obj->constant.event_cb((usb_device_handle_t)dev_obj, USBH_EVENT_DEV_GONE, p_usbh_obj->constant.event_cb_arg);
} }
static void handle_free_and_recover(device_t *dev_obj, bool recover_port) static void handle_free_and_recover(device_t *dev_obj, bool recover_port)
{ {
//Cache a copy of the port handle as we are about to free the device object // Cache a copy of the port handle as we are about to free the device object
bool all_free; bool all_free;
hcd_port_handle_t port_hdl = dev_obj->constant.port_hdl; hcd_port_handle_t port_hdl = dev_obj->constant.port_hdl;
ESP_LOGD(USBH_TAG, "Freeing device %d", dev_obj->constant.address); ESP_LOGD(USBH_TAG, "Freeing device %d", dev_obj->constant.address);
//We need to take the mux_lock to access mux_protected members // We need to take the mux_lock to access mux_protected members
xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
USBH_ENTER_CRITICAL(); USBH_ENTER_CRITICAL();
//Remove the device object for it's containing list // Remove the device object for it's containing list
if (dev_obj->dynamic.flags.in_pending_list) { if (dev_obj->dynamic.flags.in_pending_list) {
dev_obj->dynamic.flags.in_pending_list = 0; dev_obj->dynamic.flags.in_pending_list = 0;
TAILQ_REMOVE(&p_usbh_obj->dynamic.devs_pending_tailq, dev_obj, dynamic.tailq_entry); TAILQ_REMOVE(&p_usbh_obj->dynamic.devs_pending_tailq, dev_obj, dynamic.tailq_entry);
@ -524,12 +524,12 @@ static void handle_free_and_recover(device_t *dev_obj, bool recover_port)
xSemaphoreGive(p_usbh_obj->constant.mux_lock); xSemaphoreGive(p_usbh_obj->constant.mux_lock);
device_free(dev_obj); device_free(dev_obj);
//If all devices have been freed, propagate a USBH_EVENT_DEV_ALL_FREE event // If all devices have been freed, propagate a USBH_EVENT_DEV_ALL_FREE event
if (all_free) { if (all_free) {
ESP_LOGD(USBH_TAG, "Device all free"); ESP_LOGD(USBH_TAG, "Device all free");
p_usbh_obj->constant.event_cb((usb_device_handle_t)NULL, USBH_EVENT_DEV_ALL_FREE, p_usbh_obj->constant.event_cb_arg); p_usbh_obj->constant.event_cb((usb_device_handle_t)NULL, USBH_EVENT_DEV_ALL_FREE, p_usbh_obj->constant.event_cb_arg);
} }
//Check if we need to recover the device's port // Check if we need to recover the device's port
if (recover_port) { if (recover_port) {
p_usbh_obj->constant.hub_req_cb(port_hdl, USBH_HUB_REQ_PORT_RECOVER, p_usbh_obj->constant.hub_req_cb_arg); p_usbh_obj->constant.hub_req_cb(port_hdl, USBH_HUB_REQ_PORT_RECOVER, p_usbh_obj->constant.hub_req_cb_arg);
} }
@ -537,7 +537,7 @@ static void handle_free_and_recover(device_t *dev_obj, bool recover_port)
static inline void handle_port_disable(device_t *dev_obj) static inline void handle_port_disable(device_t *dev_obj)
{ {
//Request that the HUB disables this device's port // Request that the HUB disables this device's port
ESP_LOGD(USBH_TAG, "Disable device port %d", dev_obj->constant.address); ESP_LOGD(USBH_TAG, "Disable device port %d", dev_obj->constant.address);
p_usbh_obj->constant.hub_req_cb(dev_obj->constant.port_hdl, USBH_HUB_REQ_PORT_DISABLE, p_usbh_obj->constant.hub_req_cb_arg); p_usbh_obj->constant.hub_req_cb(dev_obj->constant.port_hdl, USBH_HUB_REQ_PORT_DISABLE, p_usbh_obj->constant.hub_req_cb_arg);
} }
@ -564,7 +564,7 @@ esp_err_t usbh_install(const usbh_config_t *usbh_config)
ret = ESP_ERR_NO_MEM; ret = ESP_ERR_NO_MEM;
goto err; goto err;
} }
//Initialize USBH object // Initialize USBH object
TAILQ_INIT(&usbh_obj->dynamic.devs_idle_tailq); TAILQ_INIT(&usbh_obj->dynamic.devs_idle_tailq);
TAILQ_INIT(&usbh_obj->dynamic.devs_pending_tailq); TAILQ_INIT(&usbh_obj->dynamic.devs_pending_tailq);
usbh_obj->constant.proc_req_cb = usbh_config->proc_req_cb; usbh_obj->constant.proc_req_cb = usbh_config->proc_req_cb;
@ -575,7 +575,7 @@ esp_err_t usbh_install(const usbh_config_t *usbh_config)
usbh_obj->constant.ctrl_xfer_cb_arg = usbh_config->ctrl_xfer_cb_arg; usbh_obj->constant.ctrl_xfer_cb_arg = usbh_config->ctrl_xfer_cb_arg;
usbh_obj->constant.mux_lock = mux_lock; usbh_obj->constant.mux_lock = mux_lock;
//Assign USBH object pointer // Assign USBH object pointer
USBH_ENTER_CRITICAL(); USBH_ENTER_CRITICAL();
if (p_usbh_obj != NULL) { if (p_usbh_obj != NULL) {
USBH_EXIT_CRITICAL(); USBH_EXIT_CRITICAL();
@ -598,28 +598,28 @@ err:
esp_err_t usbh_uninstall(void) esp_err_t usbh_uninstall(void)
{ {
//Check that USBH is in a state to be uninstalled // Check that USBH is in a state to be uninstalled
USBH_ENTER_CRITICAL(); USBH_ENTER_CRITICAL();
USBH_CHECK_FROM_CRIT(p_usbh_obj != NULL, ESP_ERR_INVALID_STATE); USBH_CHECK_FROM_CRIT(p_usbh_obj != NULL, ESP_ERR_INVALID_STATE);
usbh_t *usbh_obj = p_usbh_obj; usbh_t *usbh_obj = p_usbh_obj;
USBH_EXIT_CRITICAL(); USBH_EXIT_CRITICAL();
esp_err_t ret; esp_err_t ret;
//We need to take the mux_lock to access mux_protected members // We need to take the mux_lock to access mux_protected members
xSemaphoreTake(usbh_obj->constant.mux_lock, portMAX_DELAY); xSemaphoreTake(usbh_obj->constant.mux_lock, portMAX_DELAY);
if (p_usbh_obj->mux_protected.num_device > 0) { if (p_usbh_obj->mux_protected.num_device > 0) {
//There are still devices allocated. Can't uninstall right now. // There are still devices allocated. Can't uninstall right now.
ret = ESP_ERR_INVALID_STATE; ret = ESP_ERR_INVALID_STATE;
goto exit; goto exit;
} }
//Check again if we can uninstall // Check again if we can uninstall
USBH_ENTER_CRITICAL(); USBH_ENTER_CRITICAL();
assert(p_usbh_obj == usbh_obj); assert(p_usbh_obj == usbh_obj);
p_usbh_obj = NULL; p_usbh_obj = NULL;
USBH_EXIT_CRITICAL(); USBH_EXIT_CRITICAL();
xSemaphoreGive(usbh_obj->constant.mux_lock); xSemaphoreGive(usbh_obj->constant.mux_lock);
//Free resources // Free resources
vSemaphoreDelete(usbh_obj->constant.mux_lock); vSemaphoreDelete(usbh_obj->constant.mux_lock);
heap_caps_free(usbh_obj); heap_caps_free(usbh_obj);
ret = ESP_OK; ret = ESP_OK;
@ -634,13 +634,13 @@ esp_err_t usbh_process(void)
{ {
USBH_ENTER_CRITICAL(); USBH_ENTER_CRITICAL();
USBH_CHECK_FROM_CRIT(p_usbh_obj != NULL, ESP_ERR_INVALID_STATE); USBH_CHECK_FROM_CRIT(p_usbh_obj != NULL, ESP_ERR_INVALID_STATE);
//Keep processing until all device's with pending events have been handled // Keep processing until all device's with pending events have been handled
while (!TAILQ_EMPTY(&p_usbh_obj->dynamic.devs_pending_tailq)){ while (!TAILQ_EMPTY(&p_usbh_obj->dynamic.devs_pending_tailq)) {
//Move the device back into the idle device list, // Move the device back into the idle device list,
device_t *dev_obj = TAILQ_FIRST(&p_usbh_obj->dynamic.devs_pending_tailq); device_t *dev_obj = TAILQ_FIRST(&p_usbh_obj->dynamic.devs_pending_tailq);
TAILQ_REMOVE(&p_usbh_obj->dynamic.devs_pending_tailq, dev_obj, dynamic.tailq_entry); TAILQ_REMOVE(&p_usbh_obj->dynamic.devs_pending_tailq, dev_obj, dynamic.tailq_entry);
TAILQ_INSERT_TAIL(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry); TAILQ_INSERT_TAIL(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry);
//Clear the device's flags // Clear the device's flags
uint32_t action_flags = dev_obj->dynamic.action_flags; uint32_t action_flags = dev_obj->dynamic.action_flags;
dev_obj->dynamic.action_flags = 0; dev_obj->dynamic.action_flags = 0;
dev_obj->dynamic.flags.in_pending_list = 0; dev_obj->dynamic.flags.in_pending_list = 0;
@ -650,7 +650,7 @@ esp_err_t usbh_process(void)
--------------------------------------------------------------------- */ --------------------------------------------------------------------- */
USBH_EXIT_CRITICAL(); USBH_EXIT_CRITICAL();
ESP_LOGD(USBH_TAG, "Processing actions 0x%"PRIx32"", action_flags); ESP_LOGD(USBH_TAG, "Processing actions 0x%"PRIx32"", action_flags);
//Sanity check. If the device is being freed, there must not be any other action flags set // Sanity check. If the device is being freed, there must not be any other action flags set
assert(!(action_flags & DEV_ACTION_FREE) || action_flags == DEV_ACTION_FREE); assert(!(action_flags & DEV_ACTION_FREE) || action_flags == DEV_ACTION_FREE);
if (action_flags & DEV_ACTION_EPn_HALT_FLUSH) { if (action_flags & DEV_ACTION_EPn_HALT_FLUSH) {
@ -713,7 +713,7 @@ esp_err_t usbh_dev_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *num
USBH_ENTER_CRITICAL(); USBH_ENTER_CRITICAL();
int num_filled = 0; int num_filled = 0;
device_t *dev_obj; device_t *dev_obj;
//Fill list with devices from idle tailq // Fill list with devices from idle tailq
TAILQ_FOREACH(dev_obj, &p_usbh_obj->dynamic.devs_idle_tailq, dynamic.tailq_entry) { TAILQ_FOREACH(dev_obj, &p_usbh_obj->dynamic.devs_idle_tailq, dynamic.tailq_entry) {
if (num_filled < list_len) { if (num_filled < list_len) {
dev_addr_list[num_filled] = dev_obj->constant.address; dev_addr_list[num_filled] = dev_obj->constant.address;
@ -722,7 +722,7 @@ esp_err_t usbh_dev_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *num
break; break;
} }
} }
//Fill list with devices from pending tailq // Fill list with devices from pending tailq
TAILQ_FOREACH(dev_obj, &p_usbh_obj->dynamic.devs_pending_tailq, dynamic.tailq_entry) { TAILQ_FOREACH(dev_obj, &p_usbh_obj->dynamic.devs_pending_tailq, dynamic.tailq_entry) {
if (num_filled < list_len) { if (num_filled < list_len) {
dev_addr_list[num_filled] = dev_obj->constant.address; dev_addr_list[num_filled] = dev_obj->constant.address;
@ -732,7 +732,7 @@ esp_err_t usbh_dev_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *num
} }
} }
USBH_EXIT_CRITICAL(); USBH_EXIT_CRITICAL();
//Write back number of devices filled // Write back number of devices filled
*num_dev_ret = num_filled; *num_dev_ret = num_filled;
return ESP_OK; return ESP_OK;
} }
@ -743,7 +743,7 @@ esp_err_t usbh_dev_open(uint8_t dev_addr, usb_device_handle_t *dev_hdl)
esp_err_t ret; esp_err_t ret;
USBH_ENTER_CRITICAL(); USBH_ENTER_CRITICAL();
//Go through the device lists to find the device with the specified address // Go through the device lists to find the device with the specified address
device_t *found_dev_obj = NULL; device_t *found_dev_obj = NULL;
device_t *dev_obj; device_t *dev_obj;
TAILQ_FOREACH(dev_obj, &p_usbh_obj->dynamic.devs_idle_tailq, dynamic.tailq_entry) { TAILQ_FOREACH(dev_obj, &p_usbh_obj->dynamic.devs_idle_tailq, dynamic.tailq_entry) {
@ -760,7 +760,7 @@ esp_err_t usbh_dev_open(uint8_t dev_addr, usb_device_handle_t *dev_hdl)
} }
exit: exit:
if (found_dev_obj != NULL) { if (found_dev_obj != NULL) {
//The device is not in a state to be referenced // The device is not in a state to be referenced
if (dev_obj->dynamic.flags.is_gone || dev_obj->dynamic.flags.waiting_port_disable || dev_obj->dynamic.flags.waiting_free) { if (dev_obj->dynamic.flags.is_gone || dev_obj->dynamic.flags.waiting_port_disable || dev_obj->dynamic.flags.waiting_free) {
ret = ESP_ERR_INVALID_STATE; ret = ESP_ERR_INVALID_STATE;
} else { } else {
@ -785,19 +785,19 @@ esp_err_t usbh_dev_close(usb_device_handle_t dev_hdl)
dev_obj->dynamic.ref_count--; dev_obj->dynamic.ref_count--;
bool call_proc_req_cb = false; bool call_proc_req_cb = false;
if (dev_obj->dynamic.ref_count == 0) { if (dev_obj->dynamic.ref_count == 0) {
//Sanity check. // Sanity check.
assert(dev_obj->dynamic.num_ctrl_xfers_inflight == 0); //There cannot be any control transfer in-flight assert(dev_obj->dynamic.num_ctrl_xfers_inflight == 0); // There cannot be any control transfer in-flight
assert(!dev_obj->dynamic.flags.waiting_free); //This can only be set when ref count reaches 0 assert(!dev_obj->dynamic.flags.waiting_free); // This can only be set when ref count reaches 0
if (dev_obj->dynamic.flags.is_gone) { if (dev_obj->dynamic.flags.is_gone) {
//Device is already gone so it's port is already disabled. Trigger the USBH process to free the device // Device is already gone so it's port is already disabled. Trigger the USBH process to free the device
dev_obj->dynamic.flags.waiting_free = 1; dev_obj->dynamic.flags.waiting_free = 1;
call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_FREE_AND_RECOVER); //Port error occurred so we need to recover it call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_FREE_AND_RECOVER); // Port error occurred so we need to recover it
} else if (dev_obj->dynamic.flags.waiting_close) { } else if (dev_obj->dynamic.flags.waiting_close) {
//Device is still connected but is no longer needed. Trigger the USBH process to request device's port be disabled // Device is still connected but is no longer needed. Trigger the USBH process to request device's port be disabled
dev_obj->dynamic.flags.waiting_port_disable = 1; dev_obj->dynamic.flags.waiting_port_disable = 1;
call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_PORT_DISABLE); call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_PORT_DISABLE);
} }
//Else, there's nothing to do. Leave the device allocated // Else, there's nothing to do. Leave the device allocated
} }
USBH_EXIT_CRITICAL(); USBH_EXIT_CRITICAL();
@ -820,25 +820,25 @@ esp_err_t usbh_dev_mark_all_free(void)
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
device_t *dev_obj_cur; device_t *dev_obj_cur;
device_t *dev_obj_next; device_t *dev_obj_next;
//Go through pending list first as it's more efficient // Go through pending list first as it's more efficient
if (i == 0) { if (i == 0) {
dev_obj_cur = TAILQ_FIRST(&p_usbh_obj->dynamic.devs_pending_tailq); dev_obj_cur = TAILQ_FIRST(&p_usbh_obj->dynamic.devs_pending_tailq);
} else { } else {
dev_obj_cur = TAILQ_FIRST(&p_usbh_obj->dynamic.devs_idle_tailq); dev_obj_cur = TAILQ_FIRST(&p_usbh_obj->dynamic.devs_idle_tailq);
} }
while (dev_obj_cur != NULL) { while (dev_obj_cur != NULL) {
assert(!dev_obj_cur->dynamic.flags.waiting_close); //Sanity check assert(!dev_obj_cur->dynamic.flags.waiting_close); // Sanity check
//Keep a copy of the next item first in case we remove the current item // Keep a copy of the next item first in case we remove the current item
dev_obj_next = TAILQ_NEXT(dev_obj_cur, dynamic.tailq_entry); dev_obj_next = TAILQ_NEXT(dev_obj_cur, dynamic.tailq_entry);
if (dev_obj_cur->dynamic.ref_count == 0 && !dev_obj_cur->dynamic.flags.is_gone) { if (dev_obj_cur->dynamic.ref_count == 0 && !dev_obj_cur->dynamic.flags.is_gone) {
//Device is not opened as is not gone, so we can disable it now // Device is not opened as is not gone, so we can disable it now
dev_obj_cur->dynamic.flags.waiting_port_disable = 1; dev_obj_cur->dynamic.flags.waiting_port_disable = 1;
call_proc_req_cb |= _dev_set_actions(dev_obj_cur, DEV_ACTION_PORT_DISABLE); call_proc_req_cb |= _dev_set_actions(dev_obj_cur, DEV_ACTION_PORT_DISABLE);
} else { } else {
//Device is still opened. Just mark it as waiting to be closed // Device is still opened. Just mark it as waiting to be closed
dev_obj_cur->dynamic.flags.waiting_close = 1; dev_obj_cur->dynamic.flags.waiting_close = 1;
} }
wait_for_free = true; //As long as there is still a device, we need to wait for an event indicating it is freed wait_for_free = true; // As long as there is still a device, we need to wait for an event indicating it is freed
dev_obj_cur = dev_obj_next; dev_obj_cur = dev_obj_next;
} }
} }
@ -871,21 +871,21 @@ esp_err_t usbh_dev_get_info(usb_device_handle_t dev_hdl, usb_device_info_t *dev_
device_t *dev_obj = (device_t *)dev_hdl; device_t *dev_obj = (device_t *)dev_hdl;
esp_err_t ret; esp_err_t ret;
//Device must be configured, or not attached (if it suddenly disconnected) // Device must be configured, or not attached (if it suddenly disconnected)
USBH_ENTER_CRITICAL(); USBH_ENTER_CRITICAL();
if (!(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED || dev_obj->dynamic.state == USB_DEVICE_STATE_NOT_ATTACHED)) { if (!(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED || dev_obj->dynamic.state == USB_DEVICE_STATE_NOT_ATTACHED)) {
USBH_EXIT_CRITICAL(); USBH_EXIT_CRITICAL();
ret = ESP_ERR_INVALID_STATE; ret = ESP_ERR_INVALID_STATE;
goto exit; goto exit;
} }
//Critical section for the dynamic members // Critical section for the dynamic members
dev_info->speed = dev_obj->constant.speed; dev_info->speed = dev_obj->constant.speed;
dev_info->dev_addr = dev_obj->constant.address; dev_info->dev_addr = dev_obj->constant.address;
dev_info->bMaxPacketSize0 = dev_obj->constant.desc->bMaxPacketSize0; dev_info->bMaxPacketSize0 = dev_obj->constant.desc->bMaxPacketSize0;
USBH_EXIT_CRITICAL(); USBH_EXIT_CRITICAL();
assert(dev_obj->constant.config_desc); assert(dev_obj->constant.config_desc);
dev_info->bConfigurationValue = dev_obj->constant.config_desc->bConfigurationValue; dev_info->bConfigurationValue = dev_obj->constant.config_desc->bConfigurationValue;
//String descriptors are allowed to be NULL as not all devices support them // String descriptors are allowed to be NULL as not all devices support them
dev_info->str_desc_manufacturer = dev_obj->constant.str_desc_manu; dev_info->str_desc_manufacturer = dev_obj->constant.str_desc_manu;
dev_info->str_desc_product = dev_obj->constant.str_desc_product; dev_info->str_desc_product = dev_obj->constant.str_desc_product;
dev_info->str_desc_serial_num = dev_obj->constant.str_desc_ser_num; dev_info->str_desc_serial_num = dev_obj->constant.str_desc_ser_num;
@ -913,7 +913,7 @@ esp_err_t usbh_dev_get_config_desc(usb_device_handle_t dev_hdl, const usb_config
device_t *dev_obj = (device_t *)dev_hdl; device_t *dev_obj = (device_t *)dev_hdl;
esp_err_t ret; esp_err_t ret;
//Device must be in the configured state // Device must be in the configured state
USBH_ENTER_CRITICAL(); USBH_ENTER_CRITICAL();
if (dev_obj->dynamic.state != USB_DEVICE_STATE_CONFIGURED) { if (dev_obj->dynamic.state != USB_DEVICE_STATE_CONFIGURED) {
USBH_EXIT_CRITICAL(); USBH_EXIT_CRITICAL();
@ -938,7 +938,7 @@ esp_err_t usbh_dev_submit_ctrl_urb(usb_device_handle_t dev_hdl, urb_t *urb)
USBH_ENTER_CRITICAL(); USBH_ENTER_CRITICAL();
USBH_CHECK_FROM_CRIT(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED, ESP_ERR_INVALID_STATE); USBH_CHECK_FROM_CRIT(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED, ESP_ERR_INVALID_STATE);
//Increment the control transfer count first // Increment the control transfer count first
dev_obj->dynamic.num_ctrl_xfers_inflight++; dev_obj->dynamic.num_ctrl_xfers_inflight++;
USBH_EXIT_CRITICAL(); USBH_EXIT_CRITICAL();
@ -973,41 +973,41 @@ esp_err_t usbh_ep_alloc(usb_device_handle_t dev_hdl, usbh_ep_config_t *ep_config
device_t *dev_obj = (device_t *)dev_hdl; device_t *dev_obj = (device_t *)dev_hdl;
endpoint_t *ep_obj; endpoint_t *ep_obj;
//Find the endpoint descriptor from the device's current configuration descriptor // Find the endpoint descriptor from the device's current configuration descriptor
const usb_ep_desc_t *ep_desc = usb_parse_endpoint_descriptor_by_address(dev_obj->constant.config_desc, ep_config->bInterfaceNumber, ep_config->bAlternateSetting, ep_config->bEndpointAddress, NULL); const usb_ep_desc_t *ep_desc = usb_parse_endpoint_descriptor_by_address(dev_obj->constant.config_desc, ep_config->bInterfaceNumber, ep_config->bAlternateSetting, ep_config->bEndpointAddress, NULL);
if (ep_desc == NULL) { if (ep_desc == NULL) {
return ESP_ERR_NOT_FOUND; return ESP_ERR_NOT_FOUND;
} }
//Allocate the endpoint object // Allocate the endpoint object
ret = endpoint_alloc(dev_obj, ep_desc, ep_config, &ep_obj); ret = endpoint_alloc(dev_obj, ep_desc, ep_config, &ep_obj);
if (ret != ESP_OK) { if (ret != ESP_OK) {
goto alloc_err; goto alloc_err;
} }
//We need to take the mux_lock to access mux_protected members // We need to take the mux_lock to access mux_protected members
xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
USBH_ENTER_CRITICAL(); USBH_ENTER_CRITICAL();
//Check the device's state before we assign the a pipe to the allocated endpoint // Check the device's state before we assign the a pipe to the allocated endpoint
if (dev_obj->dynamic.state != USB_DEVICE_STATE_CONFIGURED) { if (dev_obj->dynamic.state != USB_DEVICE_STATE_CONFIGURED) {
USBH_EXIT_CRITICAL(); USBH_EXIT_CRITICAL();
ret = ESP_ERR_INVALID_STATE; ret = ESP_ERR_INVALID_STATE;
goto dev_state_err; goto dev_state_err;
} }
USBH_EXIT_CRITICAL(); USBH_EXIT_CRITICAL();
//Check if the endpoint has already been allocated // Check if the endpoint has already been allocated
if (get_ep_from_addr(dev_obj, bEndpointAddress) == NULL) { if (get_ep_from_addr(dev_obj, bEndpointAddress) == NULL) {
set_ep_from_addr(dev_obj, bEndpointAddress, ep_obj); set_ep_from_addr(dev_obj, bEndpointAddress, ep_obj);
//Write back the endpoint handle // Write back the endpoint handle
*ep_hdl_ret = (usbh_ep_handle_t)ep_obj; *ep_hdl_ret = (usbh_ep_handle_t)ep_obj;
ret = ESP_OK; ret = ESP_OK;
} else { } else {
//Endpoint is already allocated // Endpoint is already allocated
ret = ESP_ERR_INVALID_STATE; ret = ESP_ERR_INVALID_STATE;
} }
dev_state_err: dev_state_err:
xSemaphoreGive(p_usbh_obj->constant.mux_lock); xSemaphoreGive(p_usbh_obj->constant.mux_lock);
//If the endpoint was not assigned, free it // If the endpoint was not assigned, free it
if (ret != ESP_OK) { if (ret != ESP_OK) {
endpoint_free(ep_obj); endpoint_free(ep_obj);
} }
@ -1024,18 +1024,18 @@ esp_err_t usbh_ep_free(usbh_ep_handle_t ep_hdl)
device_t *dev_obj = (device_t *)ep_obj->constant.dev; device_t *dev_obj = (device_t *)ep_obj->constant.dev;
uint8_t bEndpointAddress = ep_obj->constant.ep_desc->bEndpointAddress; uint8_t bEndpointAddress = ep_obj->constant.ep_desc->bEndpointAddress;
//Todo: Check that the EP's underlying pipe is halted before allowing the EP to be freed (IDF-7273) // Todo: Check that the EP's underlying pipe is halted before allowing the EP to be freed (IDF-7273)
//Check that the the EP's underlying pipe has no more in-flight URBs // Check that the the EP's underlying pipe has no more in-flight URBs
if (hcd_pipe_get_num_urbs(ep_obj->constant.pipe_hdl) != 0) { if (hcd_pipe_get_num_urbs(ep_obj->constant.pipe_hdl) != 0) {
ret = ESP_ERR_INVALID_STATE; ret = ESP_ERR_INVALID_STATE;
goto exit; goto exit;
} }
//We need to take the mux_lock to access mux_protected members // We need to take the mux_lock to access mux_protected members
xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
//Check if the endpoint was allocated on this device // Check if the endpoint was allocated on this device
if (ep_obj == get_ep_from_addr(dev_obj, bEndpointAddress)) { if (ep_obj == get_ep_from_addr(dev_obj, bEndpointAddress)) {
//Clear the endpoint from the device's endpoint object list // Clear the endpoint from the device's endpoint object list
set_ep_from_addr(dev_obj, bEndpointAddress, NULL); set_ep_from_addr(dev_obj, bEndpointAddress, NULL);
ret = ESP_OK; ret = ESP_OK;
} else { } else {
@ -1043,7 +1043,7 @@ esp_err_t usbh_ep_free(usbh_ep_handle_t ep_hdl)
} }
xSemaphoreGive(p_usbh_obj->constant.mux_lock); xSemaphoreGive(p_usbh_obj->constant.mux_lock);
//Finally, we free the endpoint object // Finally, we free the endpoint object
if (ret == ESP_OK) { if (ret == ESP_OK) {
endpoint_free(ep_obj); endpoint_free(ep_obj);
} }
@ -1060,7 +1060,7 @@ esp_err_t usbh_ep_get_handle(usb_device_handle_t dev_hdl, uint8_t bEndpointAddre
device_t *dev_obj = (device_t *)dev_hdl; device_t *dev_obj = (device_t *)dev_hdl;
endpoint_t *ep_obj; endpoint_t *ep_obj;
//We need to take the mux_lock to access mux_protected members // We need to take the mux_lock to access mux_protected members
xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
ep_obj = get_ep_from_addr(dev_obj, bEndpointAddress); ep_obj = get_ep_from_addr(dev_obj, bEndpointAddress);
xSemaphoreGive(p_usbh_obj->constant.mux_lock); xSemaphoreGive(p_usbh_obj->constant.mux_lock);
@ -1083,11 +1083,11 @@ esp_err_t usbh_ep_enqueue_urb(usbh_ep_handle_t ep_hdl, urb_t *urb)
*/ */
endpoint_t *ep_obj = (endpoint_t *)ep_hdl; endpoint_t *ep_obj = (endpoint_t *)ep_hdl;
//Check that the EP's underlying pipe is in the active state before submitting the URB // Check that the EP's underlying pipe is in the active state before submitting the URB
if (hcd_pipe_get_state(ep_obj->constant.pipe_hdl) != HCD_PIPE_STATE_ACTIVE) { if (hcd_pipe_get_state(ep_obj->constant.pipe_hdl) != HCD_PIPE_STATE_ACTIVE) {
return ESP_ERR_INVALID_STATE; return ESP_ERR_INVALID_STATE;
} }
//Enqueue the URB to the EP's underlying pipe // Enqueue the URB to the EP's underlying pipe
return hcd_urb_enqueue(ep_obj->constant.pipe_hdl, urb); return hcd_urb_enqueue(ep_obj->constant.pipe_hdl, urb);
} }
@ -1096,7 +1096,7 @@ esp_err_t usbh_ep_dequeue_urb(usbh_ep_handle_t ep_hdl, urb_t **urb_ret)
USBH_CHECK(ep_hdl != NULL && urb_ret != NULL, ESP_ERR_INVALID_ARG); USBH_CHECK(ep_hdl != NULL && urb_ret != NULL, ESP_ERR_INVALID_ARG);
endpoint_t *ep_obj = (endpoint_t *)ep_hdl; endpoint_t *ep_obj = (endpoint_t *)ep_hdl;
//Enqueue the URB to the EP's underlying pipe // Enqueue the URB to the EP's underlying pipe
*urb_ret = hcd_urb_dequeue(ep_obj->constant.pipe_hdl); *urb_ret = hcd_urb_dequeue(ep_obj->constant.pipe_hdl);
return ESP_OK; return ESP_OK;
} }
@ -1106,7 +1106,7 @@ esp_err_t usbh_ep_command(usbh_ep_handle_t ep_hdl, usbh_ep_cmd_t command)
USBH_CHECK(ep_hdl != NULL, ESP_ERR_INVALID_ARG); USBH_CHECK(ep_hdl != NULL, ESP_ERR_INVALID_ARG);
endpoint_t *ep_obj = (endpoint_t *)ep_hdl; endpoint_t *ep_obj = (endpoint_t *)ep_hdl;
//Send the command to the EP's underlying pipe // Send the command to the EP's underlying pipe
return hcd_pipe_command(ep_obj->constant.pipe_hdl, (hcd_pipe_cmd_t)command); return hcd_pipe_command(ep_obj->constant.pipe_hdl, (hcd_pipe_cmd_t)command);
} }
@ -1126,9 +1126,9 @@ esp_err_t usbh_hub_is_installed(usbh_hub_req_cb_t hub_req_callback, void *callba
USBH_CHECK(hub_req_callback != NULL, ESP_ERR_INVALID_ARG); USBH_CHECK(hub_req_callback != NULL, ESP_ERR_INVALID_ARG);
USBH_ENTER_CRITICAL(); USBH_ENTER_CRITICAL();
//Check that USBH is already installed // Check that USBH is already installed
USBH_CHECK_FROM_CRIT(p_usbh_obj != NULL, ESP_ERR_INVALID_STATE); USBH_CHECK_FROM_CRIT(p_usbh_obj != NULL, ESP_ERR_INVALID_STATE);
//Check that Hub has not be installed yet // Check that Hub has not be installed yet
USBH_CHECK_FROM_CRIT(p_usbh_obj->constant.hub_req_cb == NULL, ESP_ERR_INVALID_STATE); USBH_CHECK_FROM_CRIT(p_usbh_obj->constant.hub_req_cb == NULL, ESP_ERR_INVALID_STATE);
p_usbh_obj->constant.hub_req_cb = hub_req_callback; p_usbh_obj->constant.hub_req_cb = hub_req_callback;
p_usbh_obj->constant.hub_req_cb_arg = callback_arg; p_usbh_obj->constant.hub_req_cb_arg = callback_arg;
@ -1139,7 +1139,7 @@ esp_err_t usbh_hub_is_installed(usbh_hub_req_cb_t hub_req_callback, void *callba
esp_err_t usbh_hub_add_dev(hcd_port_handle_t port_hdl, usb_speed_t dev_speed, usb_device_handle_t *new_dev_hdl, hcd_pipe_handle_t *default_pipe_hdl) esp_err_t usbh_hub_add_dev(hcd_port_handle_t port_hdl, usb_speed_t dev_speed, usb_device_handle_t *new_dev_hdl, hcd_pipe_handle_t *default_pipe_hdl)
{ {
//Note: Parent device handle can be NULL if it's connected to the root hub // Note: Parent device handle can be NULL if it's connected to the root hub
USBH_CHECK(new_dev_hdl != NULL, ESP_ERR_INVALID_ARG); USBH_CHECK(new_dev_hdl != NULL, ESP_ERR_INVALID_ARG);
esp_err_t ret; esp_err_t ret;
device_t *dev_obj; device_t *dev_obj;
@ -1147,7 +1147,7 @@ esp_err_t usbh_hub_add_dev(hcd_port_handle_t port_hdl, usb_speed_t dev_speed, us
if (ret != ESP_OK) { if (ret != ESP_OK) {
return ret; return ret;
} }
//Write-back device handle // Write-back device handle
*new_dev_hdl = (usb_device_handle_t)dev_obj; *new_dev_hdl = (usb_device_handle_t)dev_obj;
*default_pipe_hdl = dev_obj->constant.default_pipe; *default_pipe_hdl = dev_obj->constant.default_pipe;
ret = ESP_OK; ret = ESP_OK;
@ -1164,11 +1164,11 @@ esp_err_t usbh_hub_pass_event(usb_device_handle_t dev_hdl, usbh_hub_event_t hub_
case USBH_HUB_EVENT_PORT_ERROR: { case USBH_HUB_EVENT_PORT_ERROR: {
USBH_ENTER_CRITICAL(); USBH_ENTER_CRITICAL();
dev_obj->dynamic.flags.is_gone = 1; dev_obj->dynamic.flags.is_gone = 1;
//Check if the device can be freed now // Check if the device can be freed now
if (dev_obj->dynamic.ref_count == 0) { if (dev_obj->dynamic.ref_count == 0) {
dev_obj->dynamic.flags.waiting_free = 1; dev_obj->dynamic.flags.waiting_free = 1;
//Device is already waiting free so none of it's EP's will be in use. Can free immediately. // Device is already waiting free so none of it's EP's will be in use. Can free immediately.
call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_FREE_AND_RECOVER); //Port error occurred so we need to recover it call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_FREE_AND_RECOVER); // Port error occurred so we need to recover it
} else { } else {
call_proc_req_cb = _dev_set_actions(dev_obj, call_proc_req_cb = _dev_set_actions(dev_obj,
DEV_ACTION_EPn_HALT_FLUSH | DEV_ACTION_EPn_HALT_FLUSH |
@ -1181,7 +1181,7 @@ esp_err_t usbh_hub_pass_event(usb_device_handle_t dev_hdl, usbh_hub_event_t hub_
} }
case USBH_HUB_EVENT_PORT_DISABLED: { case USBH_HUB_EVENT_PORT_DISABLED: {
USBH_ENTER_CRITICAL(); USBH_ENTER_CRITICAL();
assert(dev_obj->dynamic.ref_count == 0); //At this stage, the device should have been closed by all users assert(dev_obj->dynamic.ref_count == 0); // At this stage, the device should have been closed by all users
dev_obj->dynamic.flags.waiting_free = 1; dev_obj->dynamic.flags.waiting_free = 1;
call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_FREE); call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_FREE);
USBH_EXIT_CRITICAL(); USBH_EXIT_CRITICAL();
@ -1208,7 +1208,7 @@ esp_err_t usbh_hub_enum_fill_dev_addr(usb_device_handle_t dev_hdl, uint8_t dev_a
dev_obj->dynamic.state = USB_DEVICE_STATE_ADDRESS; dev_obj->dynamic.state = USB_DEVICE_STATE_ADDRESS;
USBH_EXIT_CRITICAL(); USBH_EXIT_CRITICAL();
//We can modify the info members outside the critical section // We can modify the info members outside the critical section
dev_obj->constant.address = dev_addr; dev_obj->constant.address = dev_addr;
return ESP_OK; return ESP_OK;
} }
@ -1217,7 +1217,7 @@ esp_err_t usbh_hub_enum_fill_dev_desc(usb_device_handle_t dev_hdl, const usb_dev
{ {
USBH_CHECK(dev_hdl != NULL && device_desc != NULL, ESP_ERR_INVALID_ARG); USBH_CHECK(dev_hdl != NULL && device_desc != NULL, ESP_ERR_INVALID_ARG);
device_t *dev_obj = (device_t *)dev_hdl; device_t *dev_obj = (device_t *)dev_hdl;
//We can modify the info members outside the critical section // We can modify the info members outside the critical section
memcpy((usb_device_desc_t *)dev_obj->constant.desc, device_desc, sizeof(usb_device_desc_t)); memcpy((usb_device_desc_t *)dev_obj->constant.desc, device_desc, sizeof(usb_device_desc_t));
return ESP_OK; return ESP_OK;
} }
@ -1226,14 +1226,14 @@ esp_err_t usbh_hub_enum_fill_config_desc(usb_device_handle_t dev_hdl, const usb_
{ {
USBH_CHECK(dev_hdl != NULL && config_desc_full != NULL, ESP_ERR_INVALID_ARG); USBH_CHECK(dev_hdl != NULL && config_desc_full != NULL, ESP_ERR_INVALID_ARG);
device_t *dev_obj = (device_t *)dev_hdl; device_t *dev_obj = (device_t *)dev_hdl;
//Allocate memory to store the configuration descriptor // Allocate memory to store the configuration descriptor
usb_config_desc_t *config_desc = heap_caps_malloc(config_desc_full->wTotalLength, MALLOC_CAP_DEFAULT); //Buffer to copy over full configuration descriptor (wTotalLength) usb_config_desc_t *config_desc = heap_caps_malloc(config_desc_full->wTotalLength, MALLOC_CAP_DEFAULT); // Buffer to copy over full configuration descriptor (wTotalLength)
if (config_desc == NULL) { if (config_desc == NULL) {
return ESP_ERR_NO_MEM; return ESP_ERR_NO_MEM;
} }
//Copy the configuration descriptor // Copy the configuration descriptor
memcpy(config_desc, config_desc_full, config_desc_full->wTotalLength); memcpy(config_desc, config_desc_full, config_desc_full->wTotalLength);
//Assign the config desc to the device object // Assign the config desc to the device object
assert(dev_obj->constant.config_desc == NULL); assert(dev_obj->constant.config_desc == NULL);
dev_obj->constant.config_desc = config_desc; dev_obj->constant.config_desc = config_desc;
return ESP_OK; return ESP_OK;
@ -1243,14 +1243,14 @@ esp_err_t usbh_hub_enum_fill_str_desc(usb_device_handle_t dev_hdl, const usb_str
{ {
USBH_CHECK(dev_hdl != NULL && str_desc != NULL && (select >= 0 && select < 3), ESP_ERR_INVALID_ARG); USBH_CHECK(dev_hdl != NULL && str_desc != NULL && (select >= 0 && select < 3), ESP_ERR_INVALID_ARG);
device_t *dev_obj = (device_t *)dev_hdl; device_t *dev_obj = (device_t *)dev_hdl;
//Allocate memory to store the manufacturer string descriptor // Allocate memory to store the manufacturer string descriptor
usb_str_desc_t *str_desc_fill = heap_caps_malloc(str_desc->bLength, MALLOC_CAP_DEFAULT); usb_str_desc_t *str_desc_fill = heap_caps_malloc(str_desc->bLength, MALLOC_CAP_DEFAULT);
if (str_desc_fill == NULL) { if (str_desc_fill == NULL) {
return ESP_ERR_NO_MEM; return ESP_ERR_NO_MEM;
} }
//Copy the string descriptor // Copy the string descriptor
memcpy(str_desc_fill, str_desc, str_desc->bLength); memcpy(str_desc_fill, str_desc, str_desc->bLength);
//Assign filled string descriptor to the device object // Assign filled string descriptor to the device object
switch (select) { switch (select) {
case 0: case 0:
assert(dev_obj->constant.str_desc_manu == NULL); assert(dev_obj->constant.str_desc_manu == NULL);
@ -1260,7 +1260,7 @@ esp_err_t usbh_hub_enum_fill_str_desc(usb_device_handle_t dev_hdl, const usb_str
assert(dev_obj->constant.str_desc_product == NULL); assert(dev_obj->constant.str_desc_product == NULL);
dev_obj->constant.str_desc_product = str_desc_fill; dev_obj->constant.str_desc_product = str_desc_fill;
break; break;
default: //2 default: // 2
assert(dev_obj->constant.str_desc_ser_num == NULL); assert(dev_obj->constant.str_desc_ser_num == NULL);
dev_obj->constant.str_desc_ser_num = str_desc_fill; dev_obj->constant.str_desc_ser_num = str_desc_fill;
break; break;
@ -1273,20 +1273,20 @@ esp_err_t usbh_hub_enum_done(usb_device_handle_t dev_hdl)
USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG); USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG);
device_t *dev_obj = (device_t *)dev_hdl; device_t *dev_obj = (device_t *)dev_hdl;
//We need to take the mux_lock to access mux_protected members // We need to take the mux_lock to access mux_protected members
xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY); xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
USBH_ENTER_CRITICAL(); USBH_ENTER_CRITICAL();
dev_obj->dynamic.state = USB_DEVICE_STATE_CONFIGURED; dev_obj->dynamic.state = USB_DEVICE_STATE_CONFIGURED;
//Add the device to list of devices, then trigger a device event // Add the device to list of devices, then trigger a device event
TAILQ_INSERT_TAIL(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry); //Add it to the idle device list first TAILQ_INSERT_TAIL(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry); // Add it to the idle device list first
bool call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_PROP_NEW); bool call_proc_req_cb = _dev_set_actions(dev_obj, DEV_ACTION_PROP_NEW);
USBH_EXIT_CRITICAL(); USBH_EXIT_CRITICAL();
p_usbh_obj->mux_protected.num_device++; p_usbh_obj->mux_protected.num_device++;
xSemaphoreGive(p_usbh_obj->constant.mux_lock); xSemaphoreGive(p_usbh_obj->constant.mux_lock);
//Update the EP0's underlying pipe's callback // Update the EP0's underlying pipe's callback
ESP_ERROR_CHECK(hcd_pipe_update_callback(dev_obj->constant.default_pipe, ep0_pipe_callback, (void *)dev_obj)); ESP_ERROR_CHECK(hcd_pipe_update_callback(dev_obj->constant.default_pipe, ep0_pipe_callback, (void *)dev_obj));
//Call the processing request callback // Call the processing request callback
if (call_proc_req_cb) { if (call_proc_req_cb) {
p_usbh_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_USBH, false, p_usbh_obj->constant.proc_req_cb_arg); p_usbh_obj->constant.proc_req_cb(USB_PROC_REQ_SOURCE_USBH, false, p_usbh_obj->constant.proc_req_cb_arg);
} }