1 /*
2  * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "sdkconfig.h"
8 #include <stdlib.h>
9 #include <stdbool.h>
10 #include <string.h>
11 #include "freertos/FreeRTOS.h"
12 #include "freertos/portmacro.h"
13 #include "esp_err.h"
14 #include "esp_heap_caps.h"
15 #include "esp_log.h"
16 #include "usb_private.h"
17 #include "hcd.h"
18 #include "hub.h"
19 #include "usb/usb_helpers.h"
20 
21 /*
22 Implementation of the HUB driver that only supports the Root Hub with a single port. Therefore, we currently don't
23 implement the bare minimum to control the root HCD port.
24 */
25 
26 #define HUB_ROOT_PORT_NUM                           1   //HCD only supports one port
27 #ifdef CONFIG_USB_HOST_HW_BUFFER_BIAS_IN
28 #define HUB_ROOT_HCD_PORT_FIFO_BIAS                 HCD_PORT_FIFO_BIAS_RX
29 #elif CONFIG_USB_HOST_HW_BUFFER_BIAS_PERIODIC_OUT
30 #define HUB_ROOT_HCD_PORT_FIFO_BIAS                 HCD_PORT_FIFO_BIAS_PTX
31 #else   //CONFIG_USB_HOST_HW_BUFFER_BIAS_BALANCED
32 #define HUB_ROOT_HCD_PORT_FIFO_BIAS                 HCD_PORT_FIFO_BIAS_BALANCED
33 #endif
34 
35 #define ENUM_CTRL_TRANSFER_MAX_DATA_LEN             CONFIG_USB_HOST_CONTROL_TRANSFER_MAX_SIZE
36 #define ENUM_DEV_ADDR                               1       //Device address used in enumeration
37 #define ENUM_CONFIG_INDEX                           0       //Index of the first configuration of the device
38 #define ENUM_SHORT_DESC_REQ_LEN                     8       //Number of bytes to request when getting a short descriptor (just enough to get bMaxPacketSize0 or wTotalLength)
39 #define ENUM_WORST_CASE_MPS_LS                      8       //The worst case MPS of EP0 for a LS device
40 #define ENUM_WORST_CASE_MPS_FS                      64      //The worst case MPS of EP0 for a FS device
41 #define ENUM_LOW_SPEED_MPS                          8       //Worst case MPS for the default endpoint of a low-speed device
42 #define ENUM_FULL_SPEED_MPS                         64      //Worst case MPS for the default endpoint of a full-speed device
43 #define ENUM_LANGID                                 0x409   //Current enumeration only supports English (United States) string descriptors
44 
45 //Hub driver action flags. LISTED IN THE ORDER THEY SHOULD BE HANDLED IN within hub_process(). Some actions are mutually exclusive
46 #define HUB_DRIVER_FLAG_ACTION_ROOT_EVENT           0x01
47 #define HUB_DRIVER_FLAG_ACTION_PORT_DISABLE         0x02
48 #define HUB_DRIVER_FLAG_ACTION_PORT_RECOVER         0x04
49 #define HUB_DRIVER_FLAG_ACTION_ENUM_EVENT           0x08
50 
51 /**
52  * @brief Hub driver states
53  *
54  * These states represent a Hub driver that only has a single port (the root port)
55  */
56 typedef enum {
57     HUB_DRIVER_STATE_INSTALLED,             /**< Hub driver is installed. Root port is not powered */
58     HUB_DRIVER_STATE_ROOT_POWERED,          /**< Root port is powered, is not connected */
59     HUB_DRIVER_STATE_ROOT_ENUM,             /**< A device has connected to the root port and is undergoing enumeration */
60     HUB_DRIVER_STATE_ROOT_ENUM_FAILED,      /**< Enumeration of a connect device has failed. Waiting for that device to disconnect */
61     HUB_DRIVER_STATE_ROOT_ACTIVE,           /**< The connected device is enumerated */
62     HUB_DRIVER_STATE_ROOT_RECOVERY,         /**< Root port encountered an error and needs to be recovered */
63 } hub_driver_state_t;
64 
65 /**
66  * @brief Stages of device enumeration listed in their order of execution
67  *
68  * - These stages MUST BE LISTED IN THE ORDER OF THEIR EXECUTION as the enumeration will simply increment the current stage
69  * - If an error occurs at any stage, ENUM_STAGE_CLEANUP_FAILED acts as a common exit stage on failure
70  * - Must start with 0 as enum is also used as an index
71  * - The short descriptor stages are used to fetch the start particular descriptors that don't have a fixed length in order to determine the full descriptors length
72  */
73 typedef enum {
74     ENUM_STAGE_NONE = 0,                    /**< There is no device awaiting enumeration. Start requires device connection and first reset. */
75     ENUM_STAGE_START,                       /**< A device has connected and has already been reset once. Allocate a device object in USBH */
76     //Basic device enumeration
77     ENUM_STAGE_GET_SHORT_DEV_DESC,          /**< Getting short dev desc (wLength is ENUM_SHORT_DESC_REQ_LEN) */
78     ENUM_STAGE_CHECK_SHORT_DEV_DESC,        /**< Save bMaxPacketSize0 from the short dev desc. Update the MPS of the enum pipe */
79     ENUM_STAGE_SECOND_RESET,                /**< Reset the device again (Workaround for old USB devices that get confused by the previous short dev desc request). */
80     ENUM_STAGE_SET_ADDR,                    /**< Send SET_ADDRESS request */
81     ENUM_STAGE_CHECK_ADDR,                  /**< Update the enum pipe's target address */
82     ENUM_STAGE_GET_FULL_DEV_DESC,           /**< Get the full dev desc */
83     ENUM_STAGE_CHECK_FULL_DEV_DESC,         /**< Check the full dev desc, fill it into the device object in USBH. Save the string descriptor indexes*/
84     ENUM_STAGE_GET_SHORT_CONFIG_DESC,       /**< Getting a short config desc (wLength is ENUM_SHORT_DESC_REQ_LEN) */
85     ENUM_STAGE_CHECK_SHORT_CONFIG_DESC,     /**< Save wTotalLength of the short config desc */
86     ENUM_STAGE_GET_FULL_CONFIG_DESC,        /**< Get the full config desc (wLength is the saved wTotalLength) */
87     ENUM_STAGE_CHECK_FULL_CONFIG_DESC,      /**< Check the full config desc, fill it into the device object in USBH */
88     ENUM_STAGE_SET_CONFIG,                  /**< Send SET_CONFIGURATION request */
89     ENUM_STAGE_CHECK_CONFIG,                /**< Check that SET_CONFIGURATION request was successful */
90     //Get string descriptors
91     ENUM_STAGE_GET_SHORT_LANGID_TABLE,      /**< Get the header of the LANGID table string descriptor */
92     ENUM_STAGE_CHECK_SHORT_LANGID_TABLE,    /**< Save the bLength of the LANGID table string descriptor */
93     ENUM_STAGE_GET_FULL_LANGID_TABLE,       /**< Get the full LANGID table string descriptor */
94     ENUM_STAGE_CHECK_FULL_LANGID_TABLE,     /**< Check whether ENUM_LANGID is in the LANGID table */
95     ENUM_STAGE_GET_SHORT_MANU_STR_DESC,     /**< Get the header of the iManufacturer string descriptor */
96     ENUM_STAGE_CHECK_SHORT_MANU_STR_DESC,   /**< Save the bLength of the iManufacturer string descriptor */
97     ENUM_STAGE_GET_FULL_MANU_STR_DESC,      /**< Get the full iManufacturer string descriptor */
98     ENUM_STAGE_CHECK_FULL_MANU_STR_DESC,    /**< Check and fill the full iManufacturer string descriptor */
99     ENUM_STAGE_GET_SHORT_PROD_STR_DESC,     /**< Get the header of the string descriptor at index iProduct */
100     ENUM_STAGE_CHECK_SHORT_PROD_STR_DESC,   /**< Save the bLength of the iProduct string descriptor */
101     ENUM_STAGE_GET_FULL_PROD_STR_DESC,      /**< Get the full iProduct string descriptor */
102     ENUM_STAGE_CHECK_FULL_PROD_STR_DESC,    /**< Check and fill the full iProduct string descriptor */
103     ENUM_STAGE_GET_SHORT_SER_STR_DESC,      /**< Get the header of the string descriptor at index iSerialNumber */
104     ENUM_STAGE_CHECK_SHORT_SER_STR_DESC,    /**< Save the bLength of the iSerialNumber string descriptor */
105     ENUM_STAGE_GET_FULL_SER_STR_DESC,       /**< Get the full iSerialNumber string descriptor */
106     ENUM_STAGE_CHECK_FULL_SER_STR_DESC,     /**< Check and fill the full iSerialNumber string descriptor */
107     //Cleanup
108     ENUM_STAGE_CLEANUP,                     /**< Clean up after successful enumeration. Adds enumerated device to USBH */
109     ENUM_STAGE_CLEANUP_FAILED,              /**< Cleanup failed enumeration. Free device resources */
110 } enum_stage_t;
111 
112 const char *const enum_stage_strings[] = {
113     "NONE",
114     "START",
115     "GET_SHORT_DEV_DESC",
116     "CHECK_SHORT_DEV_DESC",
117     "SECOND_RESET",
118     "SET_ADDR",
119     "CHECK_ADDR",
120     "GET_FULL_DEV_DESC",
121     "CHECK_FULL_DEV_DESC",
122     "GET_SHORT_CONFIG_DESC",
123     "CHECK_SHORT_CONFIG_DESC",
124     "GET_FULL_CONFIG_DESC",
125     "CHECK_FULL_CONFIG_DESC",
126     "SET_CONFIG",
127     "CHECK_CONFIG",
128     "GET_SHORT_LANGID_TABLE",
129     "CHECK_SHORT_LANGID_TABLE",
130     "GET_FULL_LANGID_TABLE",
131     "CHECK_FULL_LANGID_TABLE",
132     "GET_SHORT_MANU_STR_DESC",
133     "CHECK_SHORT_MANU_STR_DESC",
134     "GET_FULL_MANU_STR_DESC",
135     "CHECK_FULL_MANU_STR_DESC",
136     "GET_SHORT_PROD_STR_DESC",
137     "CHECK_SHORT_PROD_STR_DESC",
138     "GET_FULL_PROD_STR_DESC",
139     "CHECK_FULL_PROD_STR_DESC",
140     "GET_SHORT_SER_STR_DESC",
141     "CHECK_SHORT_SER_STR_DESC",
142     "GET_FULL_SER_STR_DESC",
143     "CHECK_FULL_SER_STR_DESC",
144     "CLEANUP",
145     "CLEANUP_FAILED",
146 };
147 
148 typedef struct {
149     //Constant
150     urb_t *urb;                     /**< URB used for enumeration control transfers. Max data length of ENUM_CTRL_TRANSFER_MAX_DATA_LEN */
151     //Initialized at start of a particular enumeration
152     usb_device_handle_t dev_hdl;    /**< Handle of device being enumerated */
153     hcd_pipe_handle_t pipe;         /**< Default pipe handle of the device being enumerated */
154     //Updated during enumeration
155     enum_stage_t stage;             /**< Current enumeration stage */
156     int expect_num_bytes;           /**< Expected number of bytes for IN transfers stages. Set to 0 for OUT transfer */
157     uint8_t bMaxPacketSize0;        /**< Max packet size of the device's EP0. Read from bMaxPacketSize0 field of device descriptor */
158     uint16_t wTotalLength;          /**< Total length of device's configuration descriptor. Read from wTotalLength field of config descriptor */
159     uint8_t iManufacturer;          /**< Index of the Manufacturer string descriptor */
160     uint8_t iProduct;               /**< Index of the Product string descriptor */
161     uint8_t iSerialNumber;          /**< Index of the Serial Number string descriptor */
162     uint8_t str_desc_bLength;       /**< Saved bLength from getting a short string descriptor */
163 } enum_ctrl_t;
164 
165 typedef struct {
166     //Dynamic members require a critical section
167     struct {
168         union {
169             struct {
170                 uint32_t actions: 8;
171                 uint32_t reserved24: 24;
172             };
173             uint32_t val;
174         } flags;
175         hub_driver_state_t driver_state;
176     } dynamic;
177     //Single thread members don't require a critical section so long as they are never accessed from multiple threads
178     struct {
179         usb_device_handle_t root_dev_hdl;   //Indicates if an enumerated device is connected to the root port
180         enum_ctrl_t enum_ctrl;
181     } single_thread;
182     //Constant members do no change after installation thus do not require a critical section
183     struct {
184         hcd_port_handle_t root_port_hdl;
185         usb_notif_cb_t notif_cb;
186         void *notif_cb_arg;
187     } constant;
188 } hub_driver_t;
189 
190 static hub_driver_t *p_hub_driver_obj = NULL;
191 static portMUX_TYPE hub_driver_lock = portMUX_INITIALIZER_UNLOCKED;
192 
193 const char *HUB_DRIVER_TAG = "HUB";
194 
195 #define HUB_DRIVER_ENTER_CRITICAL_ISR()                 portENTER_CRITICAL_ISR(&hub_driver_lock)
196 #define HUB_DRIVER_EXIT_CRITICAL_ISR()                  portEXIT_CRITICAL_ISR(&hub_driver_lock)
197 #define HUB_DRIVER_ENTER_CRITICAL()                     portENTER_CRITICAL(&hub_driver_lock)
198 #define HUB_DRIVER_EXIT_CRITICAL()                      portEXIT_CRITICAL(&hub_driver_lock)
199 #define HUB_DRIVER_ENTER_CRITICAL_SAFE()                portENTER_CRITICAL_SAFE(&hub_driver_lock)
200 #define HUB_DRIVER_EXIT_CRITICAL_SAFE()                 portEXIT_CRITICAL_SAFE(&hub_driver_lock)
201 
202 #define HUB_DRIVER_CHECK(cond, ret_val) ({              \
203             if (!(cond)) {                              \
204                 return (ret_val);                       \
205             }                                           \
206 })
207 #define HUB_DRIVER_CHECK_FROM_CRIT(cond, ret_val) ({    \
208             if (!(cond)) {                              \
209                 HUB_DRIVER_EXIT_CRITICAL();             \
210                 return ret_val;                         \
211             }                                           \
212 })
213 
214 // ------------------------------------------------- Forward Declare ---------------------------------------------------
215 
216 /**
217  * @brief HCD port callback for the root port
218  *
219  * - This callback is called from the context of the HCD, so any event handling should be deferred to hub_process()
220  * - Under the current HCD implementation, this callback should only be ever be called in an ISR
221  * - This callback needs to call the notification to ensure hub_process() gets a chance to run
222  *
223  * @param port_hdl HCD port handle
224  * @param port_event HCD port event
225  * @param user_arg Callback argument
226  * @param in_isr Whether callback is in an ISR context
227  * @return Whether a yield is required
228  */
229 static bool root_port_callback(hcd_port_handle_t port_hdl, hcd_port_event_t port_event, void *user_arg, bool in_isr);
230 
231 /**
232  * @brief HCD pipe callback for the default pipe of the device under enumeration
233  *
234  * - This callback is called from the context of the HCD, so any event handling should be deferred to hub_process()
235  * - This callback needs to call the notification to ensure hub_process() gets a chance to run
236  *
237  * @param pipe_hdl HCD pipe handle
238  * @param pipe_event Pipe event
239  * @param user_arg Callback argument
240  * @param in_isr Whether callback is in an ISR context
241  * @return Whether a yield is required
242  */
243 static bool enum_dflt_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_event, void *user_arg, bool in_isr);
244 
245 /**
246  * @brief USBH Hub driver request callback
247  *
248  * - This callback is called from the context of the USBH, so so any event handling should be deferred to hub_process()
249  * - This callback needs to call the notification to ensure hub_process() gets a chance to run
250  *
251  * @param port_hdl HCD port handle
252  * @param hub_req Hub driver request
253  * @param arg Callback argument
254  */
255 static void usbh_hub_req_callback(hcd_port_handle_t port_hdl, usbh_hub_req_t hub_req, void *arg);
256 
257 // ------------------------------------------------- Enum Functions ----------------------------------------------------
258 
enum_stage_start(enum_ctrl_t * enum_ctrl)259 static bool enum_stage_start(enum_ctrl_t *enum_ctrl)
260 {
261     //Get the speed of the device, and set the enum MPS to the worst case size for now
262     usb_speed_t speed;
263     if (hcd_port_get_speed(p_hub_driver_obj->constant.root_port_hdl, &speed) != ESP_OK) {
264         return false;
265     }
266     enum_ctrl->bMaxPacketSize0 = (speed == USB_SPEED_LOW) ? ENUM_WORST_CASE_MPS_LS : ENUM_WORST_CASE_MPS_FS;
267     //Try to add the device to USBH
268     usb_device_handle_t enum_dev_hdl;
269     hcd_pipe_handle_t enum_dflt_pipe_hdl;
270     //We use NULL as the parent device to indicate the Root Hub port 1. We currently only support a single device
271     if (usbh_hub_add_dev(p_hub_driver_obj->constant.root_port_hdl, speed, &enum_dev_hdl, &enum_dflt_pipe_hdl) != ESP_OK) {
272         return false;
273     }
274     //Set our own default pipe callback
275     ESP_ERROR_CHECK(hcd_pipe_update_callback(enum_dflt_pipe_hdl, enum_dflt_pipe_callback, NULL));
276     enum_ctrl->dev_hdl = enum_dev_hdl;
277     enum_ctrl->pipe = enum_dflt_pipe_hdl;
278     return true;
279 }
280 
enum_stage_second_reset(enum_ctrl_t * enum_ctrl)281 static bool enum_stage_second_reset(enum_ctrl_t *enum_ctrl)
282 {
283     ESP_ERROR_CHECK(hcd_pipe_set_persist_reset(enum_ctrl->pipe));  //Persist the default pipe through the reset
284     if (hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_RESET) != ESP_OK) {
285         ESP_LOGE(HUB_DRIVER_TAG, "Failed to issue second reset");
286         return false;
287     }
288     return true;
289 }
290 
get_string_desc_index(enum_ctrl_t * enum_ctrl)291 static uint8_t get_string_desc_index(enum_ctrl_t *enum_ctrl)
292 {
293     uint8_t index;
294     switch (enum_ctrl->stage) {
295         case ENUM_STAGE_GET_SHORT_LANGID_TABLE:
296         case ENUM_STAGE_GET_FULL_LANGID_TABLE:
297             index = 0;  //The LANGID table uses an index of 0
298             break;
299         case ENUM_STAGE_GET_SHORT_MANU_STR_DESC:
300         case ENUM_STAGE_GET_FULL_MANU_STR_DESC:
301             index = enum_ctrl->iManufacturer;
302             break;
303         case ENUM_STAGE_GET_SHORT_PROD_STR_DESC:
304         case ENUM_STAGE_GET_FULL_PROD_STR_DESC:
305             index = enum_ctrl->iProduct;
306             break;
307         case ENUM_STAGE_GET_SHORT_SER_STR_DESC:
308         case ENUM_STAGE_GET_FULL_SER_STR_DESC:
309             index = enum_ctrl->iSerialNumber;
310             break;
311         default:
312             //Should not occur
313             index = 0;
314             abort();
315             break;
316     }
317     return index;
318 }
319 
enum_stage_transfer(enum_ctrl_t * enum_ctrl)320 static bool enum_stage_transfer(enum_ctrl_t *enum_ctrl)
321 {
322     usb_transfer_t *transfer = &enum_ctrl->urb->transfer;
323     switch (enum_ctrl->stage) {
324         case ENUM_STAGE_GET_SHORT_DEV_DESC: {
325             //Initialize a short device descriptor request
326             USB_SETUP_PACKET_INIT_GET_DEVICE_DESC((usb_setup_packet_t *)transfer->data_buffer);
327             ((usb_setup_packet_t *)transfer->data_buffer)->wLength = ENUM_SHORT_DESC_REQ_LEN;
328             transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(ENUM_SHORT_DESC_REQ_LEN, enum_ctrl->bMaxPacketSize0);
329             //IN data stage should return exactly ENUM_SHORT_DESC_REQ_LEN bytes
330             enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + ENUM_SHORT_DESC_REQ_LEN;
331             break;
332         }
333         case ENUM_STAGE_SET_ADDR: {
334             USB_SETUP_PACKET_INIT_SET_ADDR((usb_setup_packet_t *)transfer->data_buffer, ENUM_DEV_ADDR);
335             transfer->num_bytes = sizeof(usb_setup_packet_t);   //No data stage
336             enum_ctrl->expect_num_bytes = 0;    //OUT transfer. No need to check number of bytes returned
337             break;
338         }
339         case ENUM_STAGE_GET_FULL_DEV_DESC: {
340             USB_SETUP_PACKET_INIT_GET_DEVICE_DESC((usb_setup_packet_t *)transfer->data_buffer);
341             transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(sizeof(usb_device_desc_t), enum_ctrl->bMaxPacketSize0);
342             //IN data stage should return exactly sizeof(usb_device_desc_t) bytes
343             enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + sizeof(usb_device_desc_t);
344             break;
345         }
346         case ENUM_STAGE_GET_SHORT_CONFIG_DESC: {
347             //Get a short config descriptor at index 0
348             USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)transfer->data_buffer, ENUM_CONFIG_INDEX, ENUM_SHORT_DESC_REQ_LEN);
349             transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(ENUM_SHORT_DESC_REQ_LEN, enum_ctrl->bMaxPacketSize0);
350             //IN data stage should return exactly ENUM_SHORT_DESC_REQ_LEN bytes
351             enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + ENUM_SHORT_DESC_REQ_LEN;
352             break;
353         }
354         case ENUM_STAGE_GET_FULL_CONFIG_DESC: {
355             //Get the full configuration descriptor at index 0, requesting its exact length.
356             USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)transfer->data_buffer, ENUM_CONFIG_INDEX, enum_ctrl->wTotalLength);
357             transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(enum_ctrl->wTotalLength, enum_ctrl->bMaxPacketSize0);
358             //IN data stage should return exactly wTotalLength bytes
359             enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + enum_ctrl->wTotalLength;
360             break;
361         }
362         case ENUM_STAGE_SET_CONFIG: {
363             USB_SETUP_PACKET_INIT_SET_CONFIG((usb_setup_packet_t *)transfer->data_buffer, ENUM_CONFIG_INDEX + 1);
364             transfer->num_bytes = sizeof(usb_setup_packet_t);   //No data stage
365             enum_ctrl->expect_num_bytes = 0;    //OUT transfer. No need to check number of bytes returned
366             break;
367         }
368         case ENUM_STAGE_GET_SHORT_LANGID_TABLE:
369         case ENUM_STAGE_GET_SHORT_MANU_STR_DESC:
370         case ENUM_STAGE_GET_SHORT_PROD_STR_DESC:
371         case ENUM_STAGE_GET_SHORT_SER_STR_DESC: {
372             uint8_t index = get_string_desc_index(enum_ctrl);
373             //Get only the header of the string descriptor
374             USB_SETUP_PACKET_INIT_GET_STR_DESC((usb_setup_packet_t *)transfer->data_buffer,
375                                                index,
376                                                ENUM_LANGID,
377                                                sizeof(usb_str_desc_t));
378             transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(sizeof(usb_str_desc_t), enum_ctrl->bMaxPacketSize0);
379             //IN data stage should return exactly sizeof(usb_str_desc_t) bytes
380             enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + sizeof(usb_str_desc_t);
381             break;
382         }
383         case ENUM_STAGE_GET_FULL_LANGID_TABLE:
384         case ENUM_STAGE_GET_FULL_MANU_STR_DESC:
385         case ENUM_STAGE_GET_FULL_PROD_STR_DESC:
386         case ENUM_STAGE_GET_FULL_SER_STR_DESC: {
387             uint8_t index = get_string_desc_index(enum_ctrl);
388             //Get the full string descriptor at a particular index, requesting the descriptors exact length
389             USB_SETUP_PACKET_INIT_GET_STR_DESC((usb_setup_packet_t *)transfer->data_buffer,
390                                                index,
391                                                ENUM_LANGID,
392                                                enum_ctrl->str_desc_bLength);
393             transfer->num_bytes = sizeof(usb_setup_packet_t) + usb_round_up_to_mps(enum_ctrl->str_desc_bLength, enum_ctrl->bMaxPacketSize0);
394             //IN data stage should return exactly str_desc_bLength bytes
395             enum_ctrl->expect_num_bytes = sizeof(usb_setup_packet_t) + enum_ctrl->str_desc_bLength;
396             break;
397         }
398         default:    //Should never occur
399             abort();
400             break;
401     }
402     if (hcd_urb_enqueue(enum_ctrl->pipe, enum_ctrl->urb) != ESP_OK) {
403         ESP_LOGE(HUB_DRIVER_TAG, "Failed to submit: %s", enum_stage_strings[enum_ctrl->stage]);
404         return false;
405     }
406     return true;
407 }
408 
enum_stage_transfer_check(enum_ctrl_t * enum_ctrl)409 static bool enum_stage_transfer_check(enum_ctrl_t *enum_ctrl)
410 {
411     //Dequeue the URB
412     urb_t *dequeued_enum_urb = hcd_urb_dequeue(enum_ctrl->pipe);
413     assert(dequeued_enum_urb == enum_ctrl->urb);
414 
415     //Check transfer status
416     usb_transfer_t *transfer = &dequeued_enum_urb->transfer;
417     if (transfer->status != USB_TRANSFER_STATUS_COMPLETED) {
418         ESP_LOGE(HUB_DRIVER_TAG, "Bad transfer status: %s", enum_stage_strings[enum_ctrl->stage]);
419         return false;
420     }
421     //Check IN transfer returned the expected correct number of bytes
422     if (enum_ctrl->expect_num_bytes != 0 && enum_ctrl->expect_num_bytes != transfer->actual_num_bytes) {
423         ESP_LOGE(HUB_DRIVER_TAG, "Incorrect number of bytes returned: %s", enum_stage_strings[enum_ctrl->stage]);
424         return false;
425     }
426 
427     //Stage specific checks and updates
428     bool ret;
429     switch (enum_ctrl->stage) {
430         case ENUM_STAGE_CHECK_SHORT_DEV_DESC: {
431             const usb_device_desc_t *device_desc = (usb_device_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t));
432             //Check if the returned descriptor is corrupted
433             if (device_desc->bDescriptorType != USB_B_DESCRIPTOR_TYPE_DEVICE) {
434                 ESP_LOGE(HUB_DRIVER_TAG, "Short dev desc corrupt");
435                 ret = false;
436                 break;
437             }
438             //Update and save the MPS of the default pipe
439             if (hcd_pipe_update_mps(enum_ctrl->pipe, device_desc->bMaxPacketSize0) != ESP_OK) {
440                 ESP_LOGE(HUB_DRIVER_TAG, "Failed to update MPS");
441                 ret = false;
442                 break;
443             }
444             //Save the actual MPS of EP0
445             enum_ctrl->bMaxPacketSize0 = device_desc->bMaxPacketSize0;
446             ret = true;
447             break;
448         }
449         case ENUM_STAGE_CHECK_ADDR: {
450             //Update the pipe and device's address, and fill the address into the device object
451             ESP_ERROR_CHECK(hcd_pipe_update_dev_addr(enum_ctrl->pipe, ENUM_DEV_ADDR));
452             ESP_ERROR_CHECK(usbh_hub_enum_fill_dev_addr(enum_ctrl->dev_hdl, ENUM_DEV_ADDR));
453             ret = true;
454             break;
455         }
456         case ENUM_STAGE_CHECK_FULL_DEV_DESC: {
457             //Fill device descriptor into the device object
458             const usb_device_desc_t *device_desc = (const usb_device_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t));
459             ESP_ERROR_CHECK(usbh_hub_enum_fill_dev_desc(enum_ctrl->dev_hdl, device_desc));
460             enum_ctrl->iManufacturer = device_desc->iManufacturer;
461             enum_ctrl->iProduct = device_desc->iProduct;
462             enum_ctrl->iSerialNumber = device_desc->iSerialNumber;
463             ret = true;
464             break;
465         }
466         case ENUM_STAGE_CHECK_SHORT_CONFIG_DESC: {
467             const usb_config_desc_t *config_desc = (usb_config_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t));
468             //Check if the returned descriptor is corrupted
469             if (config_desc->bDescriptorType != USB_B_DESCRIPTOR_TYPE_CONFIGURATION) {
470                 ESP_LOGE(HUB_DRIVER_TAG, "Short config desc corrupt");
471                 ret = false;
472                 break;
473             }
474 #if (ENUM_CTRL_TRANSFER_MAX_DATA_LEN < UINT16_MAX)  //Suppress -Wtype-limits warning due to uint16_t wTotalLength
475             //Check if the descriptor is too long to be supported
476             if (config_desc->wTotalLength > ENUM_CTRL_TRANSFER_MAX_DATA_LEN) {
477                 ESP_LOGE(HUB_DRIVER_TAG, "Configuration descriptor larger than control transfer max length");
478                 ret = false;
479                 break;
480             }
481 #endif
482             //Save the configuration descriptors full length
483             enum_ctrl->wTotalLength = config_desc->wTotalLength;
484             ret = true;
485             break;
486         }
487         case ENUM_STAGE_CHECK_FULL_CONFIG_DESC: {
488             //Fill configuration descriptor into the device object
489             const usb_config_desc_t *config_desc = (usb_config_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t));
490             ESP_ERROR_CHECK(usbh_hub_enum_fill_config_desc(enum_ctrl->dev_hdl, config_desc));
491             ret = true;
492             break;
493         }
494         case ENUM_STAGE_CHECK_CONFIG: {
495             ret = true;
496             //Nothing to do
497             break;
498         }
499         case ENUM_STAGE_CHECK_SHORT_LANGID_TABLE:
500         case ENUM_STAGE_CHECK_SHORT_MANU_STR_DESC:
501         case ENUM_STAGE_CHECK_SHORT_PROD_STR_DESC:
502         case ENUM_STAGE_CHECK_SHORT_SER_STR_DESC: {
503             const usb_str_desc_t *str_desc = (usb_str_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t));
504             //Check if the returned descriptor is supported or corrupted
505             if (str_desc->bDescriptorType == 0) {
506                 ESP_LOGW(HUB_DRIVER_TAG, "String desc not supported");
507                 ret = false;
508                 break;
509             } else if (str_desc->bDescriptorType != USB_B_DESCRIPTOR_TYPE_STRING) {
510                 ESP_LOGE(HUB_DRIVER_TAG, "Full string desc corrupt");
511                 ret = false;
512                 break;
513             }
514 #if (ENUM_CTRL_TRANSFER_MAX_DATA_LEN < UINT8_MAX)   //Suppress -Wtype-limits warning due to uint8_t bLength
515             //Check if the descriptor is too long to be supported
516             if (str_desc->bLength > (uint32_t)ENUM_CTRL_TRANSFER_MAX_DATA_LEN) {
517                 ESP_LOGE(HUB_DRIVER_TAG, "String descriptor larger than control transfer max length");
518                 ret = false;
519                 break;
520             }
521 #endif
522             //Save the descriptors full length
523             enum_ctrl->str_desc_bLength = str_desc->bLength;
524             ret = true;
525             break;
526         }
527         case ENUM_STAGE_CHECK_FULL_LANGID_TABLE:
528         case ENUM_STAGE_CHECK_FULL_MANU_STR_DESC:
529         case ENUM_STAGE_CHECK_FULL_PROD_STR_DESC:
530         case ENUM_STAGE_CHECK_FULL_SER_STR_DESC: {
531             const usb_str_desc_t *str_desc = (usb_str_desc_t *)(transfer->data_buffer + sizeof(usb_setup_packet_t));
532             //Check if the returned descriptor is supported or corrupted
533             if (str_desc->bDescriptorType == 0) {
534                 ESP_LOGW(HUB_DRIVER_TAG, "String desc not supported");
535                 ret = false;
536                 break;
537             } else if (str_desc->bDescriptorType != USB_B_DESCRIPTOR_TYPE_STRING) {
538                 ESP_LOGE(HUB_DRIVER_TAG, "Full string desc corrupt");
539                 ret = false;
540                 break;
541             }
542             if (enum_ctrl->stage == ENUM_STAGE_CHECK_FULL_LANGID_TABLE) {
543                 //Scan the LANGID table for our target LANGID
544                 bool target_langid_found = false;
545                 int langid_table_num_entries = (str_desc->bLength - sizeof(usb_str_desc_t))/2;    //Each LANGID is 2 bytes
546                 for (int i = 0; i < langid_table_num_entries; i++) {  //Each LANGID is 2 bytes
547                     if (str_desc->wData[i] == ENUM_LANGID) {
548                         target_langid_found = true;
549                         break;
550                     }
551                 }
552                 if (!target_langid_found) {
553                     ESP_LOGE(HUB_DRIVER_TAG, "LANGID 0x%x not found", ENUM_LANGID);
554                 }
555                 ret = target_langid_found;
556                 break;
557             } else {
558                 //Fill the string descriptor into the device object
559                 int select;
560                 if (enum_ctrl->stage == ENUM_STAGE_CHECK_FULL_MANU_STR_DESC) {
561                     select = 0;
562                 } else if (enum_ctrl->stage == ENUM_STAGE_CHECK_FULL_PROD_STR_DESC) {
563                     select = 1;
564                 } else {    //ENUM_STAGE_CHECK_FULL_PROD_STR_DESC
565                     select = 2;
566                 }
567                 ESP_ERROR_CHECK(usbh_hub_enum_fill_str_desc(enum_ctrl->dev_hdl, str_desc, select));
568                 ret = true;
569                 break;
570             }
571         }
572         default:    //Should never occur
573             ret = false;
574             abort();
575             break;
576     }
577     return ret;
578 }
579 
enum_stage_cleanup(enum_ctrl_t * enum_ctrl)580 static void enum_stage_cleanup(enum_ctrl_t *enum_ctrl)
581 {
582     //We currently only support a single device connected to the root port. Move the device handle from enum to root
583     HUB_DRIVER_ENTER_CRITICAL();
584     p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_ACTIVE;
585     HUB_DRIVER_EXIT_CRITICAL();
586     p_hub_driver_obj->single_thread.root_dev_hdl = enum_ctrl->dev_hdl;
587     usb_device_handle_t dev_hdl = enum_ctrl->dev_hdl;
588     //Clear values in enum_ctrl
589     enum_ctrl->dev_hdl = NULL;
590     enum_ctrl->pipe = NULL;
591     //Update device object after enumeration is done
592     ESP_ERROR_CHECK(usbh_hub_enum_done(dev_hdl));
593 }
594 
enum_stage_cleanup_failed(enum_ctrl_t * enum_ctrl)595 static void enum_stage_cleanup_failed(enum_ctrl_t *enum_ctrl)
596 {
597     //Enumeration failed. Clear the enum device handle and pipe
598     if (enum_ctrl->dev_hdl) {
599         //If enumeration failed due to a port event, we need to Halt, flush, and dequeue enum default pipe in case there
600         //was an in-flight URB.
601         ESP_ERROR_CHECK(hcd_pipe_command(enum_ctrl->pipe, HCD_PIPE_CMD_HALT));
602         ESP_ERROR_CHECK(hcd_pipe_command(enum_ctrl->pipe, HCD_PIPE_CMD_FLUSH));
603         hcd_urb_dequeue(enum_ctrl->pipe);   //This could return NULL if there
604         ESP_ERROR_CHECK(usbh_hub_enum_failed(enum_ctrl->dev_hdl)); //Free the underlying device object first before recovering the port
605     }
606     //Clear values in enum_ctrl
607     enum_ctrl->dev_hdl = NULL;
608     enum_ctrl->pipe = NULL;
609     HUB_DRIVER_ENTER_CRITICAL();
610     //Enum could have failed due to a port error. If so, we need to trigger a port recovery
611     if (p_hub_driver_obj->dynamic.driver_state == HUB_DRIVER_STATE_ROOT_RECOVERY) {
612         p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_RECOVER;
613     } else {
614         //Otherwise, we move to the enum failed state and wait for the device to disconnect
615         p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_ENUM_FAILED;
616     }
617     HUB_DRIVER_EXIT_CRITICAL();
618 }
619 
enum_set_next_stage(enum_ctrl_t * enum_ctrl,bool last_stage_pass)620 static void enum_set_next_stage(enum_ctrl_t *enum_ctrl, bool last_stage_pass)
621 {
622     //Set next stage
623     if (last_stage_pass) {
624         if (enum_ctrl->stage != ENUM_STAGE_NONE &&
625             enum_ctrl->stage != ENUM_STAGE_CLEANUP &&
626             enum_ctrl->stage != ENUM_STAGE_CLEANUP_FAILED) {
627                 enum_ctrl->stage++; //Go to next stage
628         } else {
629                 enum_ctrl->stage = ENUM_STAGE_NONE;
630         }
631     } else {
632         switch (enum_ctrl->stage) {
633             case ENUM_STAGE_START:
634                 //Stage failed but clean up not required
635                 enum_ctrl->stage = ENUM_STAGE_NONE;
636                 break;
637             case ENUM_STAGE_GET_SHORT_LANGID_TABLE:
638             case ENUM_STAGE_CHECK_SHORT_LANGID_TABLE:
639             case ENUM_STAGE_GET_FULL_LANGID_TABLE:
640             case ENUM_STAGE_CHECK_FULL_LANGID_TABLE:
641             case ENUM_STAGE_GET_SHORT_MANU_STR_DESC:
642             case ENUM_STAGE_CHECK_SHORT_MANU_STR_DESC:
643             case ENUM_STAGE_GET_FULL_MANU_STR_DESC:
644             case ENUM_STAGE_CHECK_FULL_MANU_STR_DESC:
645             case ENUM_STAGE_GET_SHORT_PROD_STR_DESC:
646             case ENUM_STAGE_CHECK_SHORT_PROD_STR_DESC:
647             case ENUM_STAGE_GET_FULL_PROD_STR_DESC:
648             case ENUM_STAGE_CHECK_FULL_PROD_STR_DESC:
649             case ENUM_STAGE_GET_SHORT_SER_STR_DESC:
650             case ENUM_STAGE_CHECK_SHORT_SER_STR_DESC:
651             case ENUM_STAGE_GET_FULL_SER_STR_DESC:
652             case ENUM_STAGE_CHECK_FULL_SER_STR_DESC:
653                 //String descriptor stages are allow to fail. We just don't fetch them and treat enumeration as successful
654                 enum_ctrl->stage = ENUM_STAGE_CLEANUP;
655                 break;
656             default:
657                 //Enumeration failed. Go to failure clean up
658                 enum_ctrl->stage = ENUM_STAGE_CLEANUP_FAILED;
659                 break;
660         }
661     }
662 
663     //These stages are not waiting for a callback, so we need to re-trigger the enum event
664     bool re_trigger;
665     switch (enum_ctrl->stage) {
666         case ENUM_STAGE_GET_SHORT_DEV_DESC:
667         case ENUM_STAGE_SECOND_RESET:
668         case ENUM_STAGE_SET_ADDR:
669         case ENUM_STAGE_GET_FULL_DEV_DESC:
670         case ENUM_STAGE_GET_SHORT_CONFIG_DESC:
671         case ENUM_STAGE_GET_FULL_CONFIG_DESC:
672         case ENUM_STAGE_SET_CONFIG:
673         case ENUM_STAGE_GET_SHORT_LANGID_TABLE:
674         case ENUM_STAGE_GET_FULL_LANGID_TABLE:
675         case ENUM_STAGE_GET_SHORT_MANU_STR_DESC:
676         case ENUM_STAGE_GET_FULL_MANU_STR_DESC:
677         case ENUM_STAGE_GET_SHORT_PROD_STR_DESC:
678         case ENUM_STAGE_GET_FULL_PROD_STR_DESC:
679         case ENUM_STAGE_GET_SHORT_SER_STR_DESC:
680         case ENUM_STAGE_GET_FULL_SER_STR_DESC:
681         case ENUM_STAGE_CLEANUP:
682         case ENUM_STAGE_CLEANUP_FAILED:
683             re_trigger = true;
684             break;
685         default:
686             re_trigger = false;
687             break;
688     }
689     if (re_trigger) {
690         HUB_DRIVER_ENTER_CRITICAL();
691         p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT;
692         HUB_DRIVER_EXIT_CRITICAL();
693     }
694 }
695 
696 // ------------------------------------------------- Event Handling ----------------------------------------------------
697 
698 // ---------------------- Callbacks ------------------------
699 
root_port_callback(hcd_port_handle_t port_hdl,hcd_port_event_t port_event,void * user_arg,bool in_isr)700 static bool root_port_callback(hcd_port_handle_t port_hdl, hcd_port_event_t port_event, void *user_arg, bool in_isr)
701 {
702     HUB_DRIVER_ENTER_CRITICAL_SAFE();
703     p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ROOT_EVENT;
704     HUB_DRIVER_EXIT_CRITICAL_SAFE();
705     assert(in_isr); //Currently, this callback should only ever be called from an ISR context
706     return p_hub_driver_obj->constant.notif_cb(USB_NOTIF_SOURCE_HUB, in_isr, p_hub_driver_obj->constant.notif_cb_arg);;
707 }
708 
enum_dflt_pipe_callback(hcd_pipe_handle_t pipe_hdl,hcd_pipe_event_t pipe_event,void * user_arg,bool in_isr)709 static bool enum_dflt_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_event, void *user_arg, bool in_isr)
710 {
711     //Note: This callback may have triggered when a failed enumeration is already cleaned up (e.g., due to a failed port reset)
712     HUB_DRIVER_ENTER_CRITICAL_SAFE();
713     p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT;
714     HUB_DRIVER_EXIT_CRITICAL_SAFE();
715     return p_hub_driver_obj->constant.notif_cb(USB_NOTIF_SOURCE_HUB, in_isr, p_hub_driver_obj->constant.notif_cb_arg);
716 }
717 
usbh_hub_req_callback(hcd_port_handle_t port_hdl,usbh_hub_req_t hub_req,void * arg)718 static void usbh_hub_req_callback(hcd_port_handle_t port_hdl, usbh_hub_req_t hub_req, void *arg)
719 {
720     //We currently only support the root port, so the port_hdl should match the root port
721     assert(port_hdl == p_hub_driver_obj->constant.root_port_hdl);
722 
723     HUB_DRIVER_ENTER_CRITICAL();
724     switch (hub_req) {
725         case USBH_HUB_REQ_PORT_DISABLE:
726             p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_DISABLE;
727             break;
728         case USBH_HUB_REQ_PORT_RECOVER:
729             p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_RECOVER;
730             break;
731         default:
732             //Should never occur
733             abort();
734             break;
735     }
736     HUB_DRIVER_EXIT_CRITICAL();
737 
738     p_hub_driver_obj->constant.notif_cb(USB_NOTIF_SOURCE_HUB, false, p_hub_driver_obj->constant.notif_cb_arg);
739 }
740 
741 // ---------------------- Handlers -------------------------
742 
root_port_handle_events(hcd_port_handle_t root_port_hdl)743 static void root_port_handle_events(hcd_port_handle_t root_port_hdl)
744 {
745     hcd_port_event_t port_event = hcd_port_handle_event(root_port_hdl);
746     switch (port_event) {
747         case HCD_PORT_EVENT_NONE:
748             //Nothing to do
749             break;
750         case HCD_PORT_EVENT_CONNECTION: {
751             if (hcd_port_command(root_port_hdl, HCD_PORT_CMD_RESET) == ESP_OK) {
752                 ESP_LOGD(HUB_DRIVER_TAG, "Root port reset");
753                 //Start enumeration
754                 HUB_DRIVER_ENTER_CRITICAL();
755                 p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT;
756                 p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_ENUM;
757                 HUB_DRIVER_EXIT_CRITICAL();
758                 p_hub_driver_obj->single_thread.enum_ctrl.stage = ENUM_STAGE_START;
759             } else {
760                 ESP_LOGE(HUB_DRIVER_TAG, "Root port reset failed");
761             }
762             break;
763         }
764         case HCD_PORT_EVENT_DISCONNECTION:
765         case HCD_PORT_EVENT_ERROR:
766         case HCD_PORT_EVENT_OVERCURRENT: {
767             bool pass_event_to_usbh = false;
768             HUB_DRIVER_ENTER_CRITICAL();
769             switch (p_hub_driver_obj->dynamic.driver_state) {
770                 case HUB_DRIVER_STATE_ROOT_POWERED: //This occurred before enumeration
771                 case HUB_DRIVER_STATE_ROOT_ENUM_FAILED: //This occurred after a failed enumeration.
772                     //Therefore, there's no device and we can go straight to port recovery
773                     p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_RECOVER;
774                     break;
775                 case HUB_DRIVER_STATE_ROOT_ENUM:
776                     //This occurred during enumeration. Therefore, we need to recover the failed enumeration
777                     p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT;
778                     p_hub_driver_obj->single_thread.enum_ctrl.stage = ENUM_STAGE_CLEANUP_FAILED;
779                     break;
780                 case HUB_DRIVER_STATE_ROOT_ACTIVE:
781                     //There was an enumerated device. We need to indicate to USBH that the device is gone
782                     pass_event_to_usbh = true;
783                     break;
784                 default:
785                     abort();    //Should never occur
786                     break;
787             }
788             p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_RECOVERY;
789             HUB_DRIVER_EXIT_CRITICAL();
790             if (pass_event_to_usbh) {
791                 assert(p_hub_driver_obj->single_thread.root_dev_hdl);
792                 ESP_ERROR_CHECK(usbh_hub_pass_event(p_hub_driver_obj->single_thread.root_dev_hdl, USBH_HUB_EVENT_PORT_ERROR));
793             }
794             break;
795         }
796         default:
797             abort();    //Should never occur
798             break;
799     }
800 }
801 
enum_handle_events(void)802 static void enum_handle_events(void)
803 {
804     bool stage_pass;
805     enum_ctrl_t *enum_ctrl = &p_hub_driver_obj->single_thread.enum_ctrl;
806     switch (enum_ctrl->stage) {
807         case ENUM_STAGE_START:
808             stage_pass = enum_stage_start(enum_ctrl);
809             break;
810         case ENUM_STAGE_SECOND_RESET:
811             stage_pass = enum_stage_second_reset(enum_ctrl);
812             break;
813         //Transfer submission stages
814         case ENUM_STAGE_GET_SHORT_DEV_DESC:
815         case ENUM_STAGE_SET_ADDR:
816         case ENUM_STAGE_GET_FULL_DEV_DESC:
817         case ENUM_STAGE_GET_SHORT_CONFIG_DESC:
818         case ENUM_STAGE_GET_FULL_CONFIG_DESC:
819         case ENUM_STAGE_SET_CONFIG:
820         case ENUM_STAGE_GET_SHORT_LANGID_TABLE:
821         case ENUM_STAGE_GET_FULL_LANGID_TABLE:
822         case ENUM_STAGE_GET_SHORT_MANU_STR_DESC:
823         case ENUM_STAGE_GET_FULL_MANU_STR_DESC:
824         case ENUM_STAGE_GET_SHORT_PROD_STR_DESC:
825         case ENUM_STAGE_GET_FULL_PROD_STR_DESC:
826         case ENUM_STAGE_GET_SHORT_SER_STR_DESC:
827         case ENUM_STAGE_GET_FULL_SER_STR_DESC:
828             stage_pass = enum_stage_transfer(enum_ctrl);
829             break;
830         //Transfer check stages
831         case ENUM_STAGE_CHECK_SHORT_DEV_DESC:
832         case ENUM_STAGE_CHECK_ADDR:
833         case ENUM_STAGE_CHECK_FULL_DEV_DESC:
834         case ENUM_STAGE_CHECK_SHORT_CONFIG_DESC:
835         case ENUM_STAGE_CHECK_FULL_CONFIG_DESC:
836         case ENUM_STAGE_CHECK_CONFIG:
837         case ENUM_STAGE_CHECK_SHORT_LANGID_TABLE:
838         case ENUM_STAGE_CHECK_FULL_LANGID_TABLE:
839         case ENUM_STAGE_CHECK_SHORT_MANU_STR_DESC:
840         case ENUM_STAGE_CHECK_FULL_MANU_STR_DESC:
841         case ENUM_STAGE_CHECK_SHORT_PROD_STR_DESC:
842         case ENUM_STAGE_CHECK_FULL_PROD_STR_DESC:
843         case ENUM_STAGE_CHECK_SHORT_SER_STR_DESC:
844         case ENUM_STAGE_CHECK_FULL_SER_STR_DESC:
845             stage_pass = enum_stage_transfer_check(enum_ctrl);
846             break;
847         case ENUM_STAGE_CLEANUP:
848             enum_stage_cleanup(enum_ctrl);
849             stage_pass = true;
850             break;
851         case ENUM_STAGE_CLEANUP_FAILED:
852             enum_stage_cleanup_failed(enum_ctrl);
853             stage_pass = true;
854             break;
855         default:
856             //Note: Don't abort here. The enum_dflt_pipe_callback() can trigger a HUB_DRIVER_FLAG_ACTION_ENUM_EVENT after a cleanup.
857             stage_pass = true;
858             break;
859     }
860     if (stage_pass) {
861         ESP_LOGD(HUB_DRIVER_TAG, "Stage done: %s", enum_stage_strings[enum_ctrl->stage]);
862     } else {
863         ESP_LOGE(HUB_DRIVER_TAG, "Stage failed: %s", enum_stage_strings[enum_ctrl->stage]);
864     }
865     enum_set_next_stage(enum_ctrl, stage_pass);
866 }
867 
868 // ---------------------------------------------- Hub Driver Functions -------------------------------------------------
869 
hub_install(hub_config_t * hub_config)870 esp_err_t hub_install(hub_config_t *hub_config)
871 {
872     HUB_DRIVER_ENTER_CRITICAL();
873     HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj == NULL, ESP_ERR_INVALID_STATE);
874     HUB_DRIVER_EXIT_CRITICAL();
875     //Allocate Hub driver object
876     hub_driver_t *hub_driver_obj = heap_caps_calloc(1, sizeof(hub_driver_t), MALLOC_CAP_DEFAULT);
877     urb_t *enum_urb = urb_alloc(sizeof(usb_setup_packet_t) + ENUM_CTRL_TRANSFER_MAX_DATA_LEN, 0, 0);
878     if (hub_driver_obj == NULL || enum_urb == NULL) {
879         return ESP_ERR_NO_MEM;
880     }
881     esp_err_t ret;
882     //Install HCD port
883     hcd_port_config_t port_config = {
884         .fifo_bias = HUB_ROOT_HCD_PORT_FIFO_BIAS,
885         .callback = root_port_callback,
886         .callback_arg = NULL,
887         .context = NULL,
888     };
889     hcd_port_handle_t port_hdl;
890     ret = hcd_port_init(HUB_ROOT_PORT_NUM, &port_config, &port_hdl);
891     if (ret != ESP_OK) {
892         goto err;
893     }
894     //Initialize Hub driver object
895     hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_INSTALLED;
896     hub_driver_obj->single_thread.enum_ctrl.stage = ENUM_STAGE_NONE;
897     hub_driver_obj->single_thread.enum_ctrl.urb = enum_urb;
898     hub_driver_obj->constant.root_port_hdl = port_hdl;
899     hub_driver_obj->constant.notif_cb = hub_config->notif_cb;
900     hub_driver_obj->constant.notif_cb_arg = hub_config->notif_cb_arg;
901     HUB_DRIVER_ENTER_CRITICAL();
902     if (p_hub_driver_obj != NULL) {
903         HUB_DRIVER_EXIT_CRITICAL();
904         ret = ESP_ERR_INVALID_STATE;
905         goto assign_err;
906     }
907     p_hub_driver_obj = hub_driver_obj;
908     HUB_DRIVER_EXIT_CRITICAL();
909     //Indicate to USBH that the hub is installed
910     ESP_ERROR_CHECK(usbh_hub_is_installed(usbh_hub_req_callback, NULL));
911     ret = ESP_OK;
912     return ret;
913 
914 assign_err:
915     ESP_ERROR_CHECK(hcd_port_deinit(port_hdl));
916 err:
917     urb_free(enum_urb);
918     heap_caps_free(hub_driver_obj);
919     return ret;
920 }
921 
hub_uninstall(void)922 esp_err_t hub_uninstall(void)
923 {
924     HUB_DRIVER_ENTER_CRITICAL();
925     HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj != NULL, ESP_ERR_INVALID_STATE);
926     HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj->dynamic.driver_state == HUB_DRIVER_STATE_INSTALLED, ESP_ERR_INVALID_STATE);
927     hub_driver_t *hub_driver_obj = p_hub_driver_obj;
928     p_hub_driver_obj = NULL;
929     HUB_DRIVER_EXIT_CRITICAL();
930 
931     ESP_ERROR_CHECK(hcd_port_deinit(hub_driver_obj->constant.root_port_hdl));
932     //Free Hub driver resources
933     urb_free(hub_driver_obj->single_thread.enum_ctrl.urb);
934     heap_caps_free(hub_driver_obj);
935     return ESP_OK;
936 }
937 
hub_root_start(void)938 esp_err_t hub_root_start(void)
939 {
940     HUB_DRIVER_ENTER_CRITICAL();
941     HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj != NULL, ESP_ERR_INVALID_STATE);
942     HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj->dynamic.driver_state == HUB_DRIVER_STATE_INSTALLED, ESP_ERR_INVALID_STATE);
943     HUB_DRIVER_EXIT_CRITICAL();
944     //Power ON the root port
945     esp_err_t ret;
946     ret = hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_POWER_ON);
947     if (ret == ESP_OK) {
948         HUB_DRIVER_ENTER_CRITICAL();
949         p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_POWERED;
950         HUB_DRIVER_EXIT_CRITICAL();
951     }
952     return ret;
953 }
954 
hub_root_stop(void)955 esp_err_t hub_root_stop(void)
956 {
957     HUB_DRIVER_ENTER_CRITICAL();
958     HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj != NULL, ESP_ERR_INVALID_STATE);
959     HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj->dynamic.driver_state != HUB_DRIVER_STATE_INSTALLED, ESP_ERR_INVALID_STATE);
960     HUB_DRIVER_EXIT_CRITICAL();
961     esp_err_t ret;
962     ret = hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_POWER_OFF);
963     if (ret == ESP_OK) {
964         HUB_DRIVER_ENTER_CRITICAL();
965         p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_INSTALLED;
966         HUB_DRIVER_EXIT_CRITICAL();
967     }
968     return ret;
969 }
970 
hub_process(void)971 esp_err_t hub_process(void)
972 {
973     HUB_DRIVER_ENTER_CRITICAL();
974     uint32_t action_flags = p_hub_driver_obj->dynamic.flags.actions;
975     p_hub_driver_obj->dynamic.flags.actions = 0;
976     HUB_DRIVER_EXIT_CRITICAL();
977 
978     while (action_flags) {
979         /*
980         Mutually exclude Root event and Port disable:
981         If a device was waiting for its port to be disabled, and a port error occurs in that time, the root event
982         handler will send a USBH_HUB_EVENT_PORT_ERROR to the USBH already, thus freeing the device and canceling the
983         waiting of port disable.
984         */
985         if (action_flags & HUB_DRIVER_FLAG_ACTION_ROOT_EVENT) {
986             root_port_handle_events(p_hub_driver_obj->constant.root_port_hdl);
987         } else if (action_flags & HUB_DRIVER_FLAG_ACTION_PORT_DISABLE) {
988             ESP_LOGD(HUB_DRIVER_TAG, "Disabling root port");
989             hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_DISABLE);
990             ESP_ERROR_CHECK(usbh_hub_pass_event(p_hub_driver_obj->single_thread.root_dev_hdl, USBH_HUB_EVENT_PORT_DISABLED));
991             //The root port has been disabled, so the root_dev_hdl is no longer valid
992             p_hub_driver_obj->single_thread.root_dev_hdl = NULL;
993         }
994 
995         if (action_flags & HUB_DRIVER_FLAG_ACTION_PORT_RECOVER) {
996             ESP_LOGD(HUB_DRIVER_TAG, "Recovering root port");
997             ESP_ERROR_CHECK(hcd_port_recover(p_hub_driver_obj->constant.root_port_hdl));
998             ESP_ERROR_CHECK(hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_POWER_ON));
999             HUB_DRIVER_ENTER_CRITICAL();
1000             p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_POWERED;
1001             HUB_DRIVER_EXIT_CRITICAL();
1002             //USBH requesting a port recovery means the device has already been freed. Clear root_dev_hdl
1003             p_hub_driver_obj->single_thread.root_dev_hdl = NULL;
1004         }
1005 
1006         if (action_flags & HUB_DRIVER_FLAG_ACTION_ENUM_EVENT) {
1007             enum_handle_events();
1008         }
1009 
1010         HUB_DRIVER_ENTER_CRITICAL();
1011         action_flags = p_hub_driver_obj->dynamic.flags.actions;
1012         p_hub_driver_obj->dynamic.flags.actions = 0;
1013         HUB_DRIVER_EXIT_CRITICAL();
1014     }
1015     return ESP_OK;
1016 }
1017