hub.c 47 KB

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