hub.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. /*
  2. * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include "sdkconfig.h"
  7. #include <stdlib.h>
  8. #include "freertos/FreeRTOS.h"
  9. #include "freertos/portmacro.h"
  10. #include "esp_err.h"
  11. #include "esp_heap_caps.h"
  12. #include "esp_log.h"
  13. #include "usb_private.h"
  14. #include "hcd.h"
  15. #include "hub.h"
  16. /*
  17. Implementation of the HUB driver that only supports the root hub with a single port. Therefore, we currently don't
  18. implement the bare minimum to control the root HCD port.
  19. */
  20. #define HUB_ROOT_PORT_NUM 1 //HCD only supports one port
  21. #ifdef CONFIG_USB_HOST_HW_BUFFER_BIAS_IN
  22. #define HUB_ROOT_HCD_PORT_FIFO_BIAS HCD_PORT_FIFO_BIAS_RX
  23. #elif CONFIG_USB_HOST_HW_BUFFER_BIAS_PERIODIC_OUT
  24. #define HUB_ROOT_HCD_PORT_FIFO_BIAS HCD_PORT_FIFO_BIAS_PTX
  25. #else //CONFIG_USB_HOST_HW_BUFFER_BIAS_BALANCED
  26. #define HUB_ROOT_HCD_PORT_FIFO_BIAS HCD_PORT_FIFO_BIAS_BALANCED
  27. #endif
  28. #define ENUM_CTRL_TRANSFER_MAX_LEN CONFIG_USB_HOST_CONTROL_TRANSFER_MAX_SIZE
  29. #define ENUM_DEV_ADDR 1 //Device address used in enumeration
  30. #define ENUM_CONFIG_INDEX 0 //Index of the first configuration of the device
  31. #define ENUM_DEV_DESC_REQ_SIZE 64 //Worst case size for device descriptor request
  32. #define ENUM_LOW_SPEED_MPS 8 //Worst case MPS for the default endpoint of a low-speed device
  33. #define ENUM_FULL_SPEED_MPS 64 //Worst case MPS for the default endpoint of a full-speed device
  34. #define HUB_DRIVER_FLAG_ACTION_ROOT_EVENT 0x01
  35. #define HUB_DRIVER_FLAG_ACTION_ENUM_EVENT 0x02
  36. #define HUB_DRIVER_FLAG_ACTION_PORT_RECOVER 0x04
  37. typedef enum {
  38. HUB_DRIVER_STATE_INSTALLED,
  39. HUB_DRIVER_STATE_ROOT_POWERD,
  40. HUB_DRIVER_STATE_ROOT_ENUMERATING,
  41. HUB_DRIVER_STATE_ROOT_ACTIVE,
  42. HUB_DRIVER_STATE_ROOT_RECOVERY,
  43. } hub_driver_state_t;
  44. typedef enum {
  45. ENUM_STAGE_NONE, /**< There is no device awaiting enumeration */
  46. ENUM_STAGE_START, /**< Start of enumeration. Allocates device object */
  47. ENUM_STAGE_GET_SHORT_DEV_DESC, /**< Getting short device descriptor */
  48. ENUM_STAGE_GET_SHORT_DEV_DESC_CHECK, /**< Check that short device descriptor was obtained */
  49. ENUM_STAGE_SECOND_RESET, /**< Doing second reset */
  50. ENUM_STAGE_SET_ADDR, /**< Setting address */
  51. ENUM_STAGE_SET_ADDR_CHECK, /**< Check that address was set successful */
  52. ENUM_STAGE_GET_FULL_DEV_DESC, /**< Getting full device descriptor */
  53. ENUM_STAGE_GET_FULL_DEV_DESC_CHECK, /**< Check that full device descriptor was obtained */
  54. ENUM_STAGE_GET_CONFIG_DESC, /**< Getting full configuration descriptor */
  55. ENUM_STAGE_GET_CONFIG_DESC_CHECK, /**< Check that full configuration descriptor was obtained */
  56. ENUM_STAGE_SET_CONFIG, /**< Set configuration number */
  57. ENUM_STAGE_SET_CONFIG_CHECK, /**< Check that configuration number was set */
  58. ENUM_STAGE_CLEANUP, /**< Clean up successful enumeration. Adds enumerated device to USBH */
  59. ENUM_STAGE_CLEANUP_FAILED, /**< Cleanup failed enumeration. Free device resources */
  60. } enum_stage_t;
  61. typedef struct {
  62. //Dynamic members require a critical section
  63. struct {
  64. union {
  65. struct {
  66. uint32_t actions: 8;
  67. uint32_t reserved24: 24;
  68. };
  69. uint32_t val;
  70. } flags;
  71. hub_driver_state_t driver_state;
  72. usb_device_handle_t root_dev_hdl; //Indicates if an enumerated device is connected to the root port
  73. } dynamic;
  74. //Single thread members don't require a critical section so long as they are never accessed from multiple threads
  75. struct {
  76. enum_stage_t enum_stage;
  77. urb_t *enum_urb;
  78. usb_device_handle_t enum_dev_hdl; //Handle of the device being enumerated. Moves to root_dev_hdl on enumeration completion
  79. hcd_pipe_handle_t enum_dflt_pipe_hdl;
  80. } single_thread;
  81. //Constant members do no change after installation thus do not require a critical section
  82. struct {
  83. hcd_port_handle_t root_port_hdl;
  84. usb_notif_cb_t notif_cb;
  85. void *notif_cb_arg;
  86. } constant;
  87. } hub_driver_t;
  88. static hub_driver_t *p_hub_driver_obj = NULL;
  89. static portMUX_TYPE hub_driver_lock = portMUX_INITIALIZER_UNLOCKED;
  90. const char *HUB_DRIVER_TAG = "HUB";
  91. #define HUB_DRIVER_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&hub_driver_lock)
  92. #define HUB_DRIVER_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&hub_driver_lock)
  93. #define HUB_DRIVER_ENTER_CRITICAL() portENTER_CRITICAL(&hub_driver_lock)
  94. #define HUB_DRIVER_EXIT_CRITICAL() portEXIT_CRITICAL(&hub_driver_lock)
  95. #define HUB_DRIVER_ENTER_CRITICAL_SAFE() portENTER_CRITICAL_SAFE(&hub_driver_lock)
  96. #define HUB_DRIVER_EXIT_CRITICAL_SAFE() portEXIT_CRITICAL_SAFE(&hub_driver_lock)
  97. #define HUB_DRIVER_CHECK(cond, ret_val) ({ \
  98. if (!(cond)) { \
  99. return (ret_val); \
  100. } \
  101. })
  102. #define HUB_DRIVER_CHECK_FROM_CRIT(cond, ret_val) ({ \
  103. if (!(cond)) { \
  104. HUB_DRIVER_EXIT_CRITICAL(); \
  105. return ret_val; \
  106. } \
  107. })
  108. // ------------------------------------------------- Event Handling ----------------------------------------------------
  109. // ---------------------- Callbacks ------------------------
  110. static bool root_port_callback(hcd_port_handle_t port_hdl, hcd_port_event_t port_event, void *user_arg, bool in_isr)
  111. {
  112. HUB_DRIVER_ENTER_CRITICAL_SAFE();
  113. p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ROOT_EVENT;
  114. HUB_DRIVER_EXIT_CRITICAL_SAFE();
  115. bool yield;
  116. if (in_isr) {
  117. p_hub_driver_obj->constant.notif_cb(USB_NOTIF_SOURCE_HUB, in_isr, p_hub_driver_obj->constant.notif_cb_arg);
  118. } else {
  119. yield = false;
  120. }
  121. return yield;
  122. }
  123. static bool enum_dflt_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_event, void *user_arg, bool in_isr)
  124. {
  125. //Note: This callback may have triggered when a failed enumeration is already cleaned up (e.g., due to a failed port reset)
  126. HUB_DRIVER_ENTER_CRITICAL_SAFE();
  127. p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT;
  128. HUB_DRIVER_EXIT_CRITICAL_SAFE();
  129. return p_hub_driver_obj->constant.notif_cb(USB_NOTIF_SOURCE_HUB, in_isr, p_hub_driver_obj->constant.notif_cb_arg);
  130. }
  131. static void usbh_hub_callback(hcd_port_handle_t port_hdl, usbh_hub_event_t hub_event, void *arg)
  132. {
  133. //We currently only support the root port
  134. assert(port_hdl == p_hub_driver_obj->constant.root_port_hdl);
  135. HUB_DRIVER_ENTER_CRITICAL();
  136. //Any hub_event results in whatever device connected to the root port to no longer be valid. We clear root_dev_hdl here.
  137. usb_device_handle_t dev_hdl = p_hub_driver_obj->dynamic.root_dev_hdl;
  138. p_hub_driver_obj->dynamic.root_dev_hdl = NULL;
  139. assert(dev_hdl);
  140. bool call_port_disable = false;
  141. switch (hub_event) {
  142. case USBH_HUB_EVENT_CLEANUP_PORT:
  143. //After USBH has cleaned up gone device. The port can be recovered.
  144. p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_RECOVER;
  145. break;
  146. case USBH_HUB_EVENT_DISABLE_PORT:
  147. p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_POWERD;
  148. call_port_disable = true;
  149. break;
  150. default:
  151. abort(); //Should never occur
  152. break;
  153. }
  154. HUB_DRIVER_EXIT_CRITICAL();
  155. if (call_port_disable) {
  156. ESP_LOGD(HUB_DRIVER_TAG, "Disabling root port");
  157. hcd_port_command(port_hdl, HCD_PORT_CMD_DISABLE);
  158. ESP_ERROR_CHECK(usbh_hub_dev_port_disabled(dev_hdl));
  159. }
  160. }
  161. // ---------------------- Handlers -------------------------
  162. static void root_port_handle_events(hcd_port_handle_t root_port_hdl)
  163. {
  164. hcd_port_event_t port_event = hcd_port_handle_event(root_port_hdl);
  165. switch (port_event) {
  166. case HCD_PORT_EVENT_NONE:
  167. //Nothing to do
  168. break;
  169. case HCD_PORT_EVENT_CONNECTION: {
  170. if (hcd_port_command(root_port_hdl, HCD_PORT_CMD_RESET) == ESP_OK) {
  171. ESP_LOGD(HUB_DRIVER_TAG, "Root port reset");
  172. //Start enumeration
  173. HUB_DRIVER_ENTER_CRITICAL();
  174. p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT;
  175. p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_ENUMERATING;
  176. HUB_DRIVER_EXIT_CRITICAL();
  177. p_hub_driver_obj->single_thread.enum_stage = ENUM_STAGE_START;
  178. } else {
  179. ESP_LOGE(HUB_DRIVER_TAG, "Root port reset failed");
  180. }
  181. break;
  182. }
  183. case HCD_PORT_EVENT_DISCONNECTION:
  184. case HCD_PORT_EVENT_ERROR:
  185. case HCD_PORT_EVENT_OVERCURRENT: {
  186. usb_device_handle_t dev_hdl = NULL;
  187. HUB_DRIVER_ENTER_CRITICAL();
  188. switch (p_hub_driver_obj->dynamic.driver_state) {
  189. case HUB_DRIVER_STATE_ROOT_POWERD:
  190. //This occurred before enumeration. Therefore, there's no device and we can go straight to port recovery
  191. p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT;
  192. break;
  193. case HUB_DRIVER_STATE_ROOT_ENUMERATING:
  194. //This occurred during enumeration. Therefore, we need to recover the failed enumeration
  195. p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT;
  196. p_hub_driver_obj->single_thread.enum_stage = ENUM_STAGE_CLEANUP_FAILED;
  197. break;
  198. case HUB_DRIVER_STATE_ROOT_ACTIVE:
  199. //There was an enumerated device. We need to indicate to USBH that the device is gone
  200. dev_hdl = p_hub_driver_obj->dynamic.root_dev_hdl;
  201. break;
  202. default:
  203. abort(); //Should never occur
  204. break;
  205. }
  206. p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_RECOVERY;
  207. HUB_DRIVER_EXIT_CRITICAL();
  208. if (dev_hdl) {
  209. ESP_ERROR_CHECK(usbh_hub_mark_dev_gone(dev_hdl));
  210. }
  211. break;
  212. }
  213. default:
  214. abort(); //Should never occur
  215. break;
  216. }
  217. }
  218. // ------------------------------------------------- Enum Functions ----------------------------------------------------
  219. static enum_stage_t enum_stage_start(void)
  220. {
  221. usb_speed_t speed;
  222. if (hcd_port_get_speed(p_hub_driver_obj->constant.root_port_hdl, &speed) != ESP_OK) {
  223. return ENUM_STAGE_NONE;
  224. }
  225. usb_device_handle_t enum_dev_hdl;
  226. hcd_pipe_handle_t enum_dflt_pipe_hdl;
  227. //We use NULL as the parent device to indicate the root hub port 1. We currently only support a single device
  228. if (usbh_hub_add_dev(p_hub_driver_obj->constant.root_port_hdl, speed, &enum_dev_hdl, &enum_dflt_pipe_hdl) != ESP_OK) {
  229. return ENUM_STAGE_NONE;
  230. }
  231. //Set our own default pipe callback
  232. ESP_ERROR_CHECK(hcd_pipe_update_callback(enum_dflt_pipe_hdl, enum_dflt_pipe_callback, NULL));
  233. HUB_DRIVER_ENTER_CRITICAL();
  234. p_hub_driver_obj->single_thread.enum_dev_hdl = enum_dev_hdl;
  235. p_hub_driver_obj->single_thread.enum_dflt_pipe_hdl = enum_dflt_pipe_hdl;
  236. HUB_DRIVER_EXIT_CRITICAL();
  237. ESP_LOGD(HUB_DRIVER_TAG, "Enumeration starting");
  238. return ENUM_STAGE_GET_SHORT_DEV_DESC;
  239. }
  240. static enum_stage_t enum_stage_get_short_dev_desc(hcd_pipe_handle_t pipe_hdl, urb_t *enum_urb)
  241. {
  242. USB_SETUP_PACKET_INIT_GET_DEVICE_DESC((usb_setup_packet_t *)enum_urb->transfer.data_buffer);
  243. enum_urb->transfer.num_bytes = sizeof(usb_setup_packet_t) + ENUM_DEV_DESC_REQ_SIZE;
  244. if (hcd_urb_enqueue(pipe_hdl, enum_urb) != ESP_OK) {
  245. ESP_LOGE(HUB_DRIVER_TAG, "Failed to get short device descriptor");
  246. return ENUM_STAGE_CLEANUP_FAILED;
  247. }
  248. ESP_LOGD(HUB_DRIVER_TAG, "Getting short device descriptor");
  249. return ENUM_STAGE_GET_SHORT_DEV_DESC_CHECK;
  250. }
  251. static enum_stage_t enum_stage_check_short_dev_desc(hcd_pipe_handle_t pipe_hdl, urb_t *enum_urb)
  252. {
  253. //Dequeue the URB
  254. urb_t *dequeued_enum_urb = hcd_urb_dequeue(pipe_hdl);
  255. assert(dequeued_enum_urb == enum_urb);
  256. if (enum_urb->transfer.status != USB_TRANSFER_STATUS_COMPLETED) {
  257. ESP_LOGE(HUB_DRIVER_TAG, "Short device descriptor transfer failed");
  258. return ENUM_STAGE_CLEANUP_FAILED;
  259. }
  260. usb_device_desc_t *device_desc = (usb_device_desc_t *)(enum_urb->transfer.data_buffer + sizeof(usb_setup_packet_t));
  261. if (enum_urb->transfer.actual_num_bytes < sizeof(usb_setup_packet_t) + 8) { //Device must return at least 8 bytes in its data stage
  262. ESP_LOGE(HUB_DRIVER_TAG, "Short device descriptor too short");
  263. return ENUM_STAGE_CLEANUP_FAILED;
  264. }
  265. //Update the MPS of the default pipe
  266. if (hcd_pipe_update_mps(pipe_hdl, device_desc->bMaxPacketSize0) != ESP_OK) {
  267. ESP_LOGE(HUB_DRIVER_TAG, "Failed to update default pipe MPS");
  268. return ENUM_STAGE_CLEANUP_FAILED;
  269. }
  270. ESP_LOGD(HUB_DRIVER_TAG, "Short device descriptor obtained");
  271. return ENUM_STAGE_SECOND_RESET;
  272. }
  273. static enum_stage_t enum_stage_second_reset(hcd_pipe_handle_t pipe_hdl, urb_t *enum_urb)
  274. {
  275. ESP_ERROR_CHECK(hcd_pipe_set_persist_reset(pipe_hdl)); //Persist the default pipe through the reset
  276. if (hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_RESET) != ESP_OK) {
  277. ESP_LOGE(HUB_DRIVER_TAG, "Failed to issue second reset");
  278. return ENUM_STAGE_CLEANUP_FAILED;
  279. }
  280. ESP_LOGD(HUB_DRIVER_TAG, "Second reset done");
  281. return ENUM_STAGE_SET_ADDR;
  282. }
  283. static enum_stage_t enum_stage_set_addr(hcd_pipe_handle_t pipe_hdl, urb_t *enum_urb)
  284. {
  285. USB_SETUP_PACKET_INIT_SET_ADDR((usb_setup_packet_t *)enum_urb->transfer.data_buffer, ENUM_DEV_ADDR);
  286. enum_urb->transfer.num_bytes = sizeof(usb_setup_packet_t); //No data stage
  287. if (hcd_urb_enqueue(pipe_hdl, enum_urb) != ESP_OK) {
  288. ESP_LOGE(HUB_DRIVER_TAG, "Failed to set address");
  289. return ENUM_STAGE_CLEANUP_FAILED;
  290. }
  291. ESP_LOGD(HUB_DRIVER_TAG, "Setting address %d", ENUM_DEV_ADDR);
  292. return ENUM_STAGE_SET_ADDR_CHECK;
  293. }
  294. static enum_stage_t enum_stage_check_set_addr(hcd_pipe_handle_t pipe_hdl, urb_t *enum_urb, usb_device_handle_t dev_hdl)
  295. {
  296. //Dequeue the URB
  297. urb_t *dequeued_enum_urb = hcd_urb_dequeue(pipe_hdl);
  298. assert(dequeued_enum_urb == enum_urb);
  299. if (enum_urb->transfer.status != USB_TRANSFER_STATUS_COMPLETED) {
  300. ESP_LOGE(HUB_DRIVER_TAG, "Set address transfer failed");
  301. return ENUM_STAGE_CLEANUP_FAILED;
  302. }
  303. //Update the pipe and device's address, and fill the address into the device object
  304. ESP_ERROR_CHECK(hcd_pipe_update_dev_addr(pipe_hdl, ENUM_DEV_ADDR));
  305. ESP_ERROR_CHECK(usbh_hub_enum_fill_dev_addr(dev_hdl, ENUM_DEV_ADDR));
  306. ESP_LOGD(HUB_DRIVER_TAG, "Address set successfully");
  307. return ENUM_STAGE_GET_FULL_DEV_DESC;
  308. }
  309. static enum_stage_t enum_stage_get_full_dev_desc(hcd_pipe_handle_t pipe_hdl, urb_t *enum_urb)
  310. {
  311. USB_SETUP_PACKET_INIT_GET_DEVICE_DESC((usb_setup_packet_t *)enum_urb->transfer.data_buffer);
  312. enum_urb->transfer.num_bytes = sizeof(usb_setup_packet_t) + ENUM_DEV_DESC_REQ_SIZE;
  313. if (hcd_urb_enqueue(pipe_hdl, enum_urb) != ESP_OK) {
  314. ESP_LOGE(HUB_DRIVER_TAG, "Failed to get full device descriptor");
  315. return ENUM_STAGE_CLEANUP_FAILED;
  316. }
  317. ESP_LOGD(HUB_DRIVER_TAG, "Getting full device descriptor");
  318. return ENUM_STAGE_GET_FULL_DEV_DESC_CHECK;
  319. }
  320. static enum_stage_t enum_stage_check_full_dev_desc(hcd_pipe_handle_t pipe_hdl, urb_t *enum_urb, usb_device_handle_t dev_hdl)
  321. {
  322. //Dequeue the URB
  323. urb_t *dequeued_enum_urb = hcd_urb_dequeue(pipe_hdl);
  324. assert(dequeued_enum_urb == enum_urb);
  325. if (enum_urb->transfer.status != USB_TRANSFER_STATUS_COMPLETED) {
  326. ESP_LOGE(HUB_DRIVER_TAG, "Full device descriptor transfer failed");
  327. return ENUM_STAGE_CLEANUP_FAILED;
  328. }
  329. if (enum_urb->transfer.actual_num_bytes < sizeof(usb_setup_packet_t) + sizeof(usb_device_desc_t)) {
  330. ESP_LOGE(HUB_DRIVER_TAG, "Full device descriptor too short");
  331. return ENUM_STAGE_CLEANUP_FAILED;
  332. }
  333. //Fill device descriptor into device
  334. const usb_device_desc_t *device_desc = (const usb_device_desc_t *)(enum_urb->transfer.data_buffer + sizeof(usb_setup_packet_t));
  335. ESP_ERROR_CHECK(usbh_hub_enum_fill_dev_desc(dev_hdl, device_desc));
  336. ESP_LOGD(HUB_DRIVER_TAG, "Full device descriptor obtained");
  337. return ENUM_STAGE_GET_CONFIG_DESC;
  338. }
  339. static enum_stage_t enum_stage_get_config_desc(hcd_pipe_handle_t pipe_hdl, urb_t *enum_urb)
  340. {
  341. //Get the configuration descriptor at index 0
  342. USB_SETUP_PACKET_INIT_GET_CONFIG_DESC((usb_setup_packet_t *)enum_urb->transfer.data_buffer, ENUM_CONFIG_INDEX, ENUM_CTRL_TRANSFER_MAX_LEN);
  343. enum_urb->transfer.num_bytes = sizeof(usb_setup_packet_t) + ENUM_CTRL_TRANSFER_MAX_LEN;
  344. if (hcd_urb_enqueue(pipe_hdl, enum_urb) != ESP_OK) {
  345. ESP_LOGE(HUB_DRIVER_TAG, "Failed to get configuration descriptor");
  346. return ENUM_STAGE_CLEANUP_FAILED;
  347. }
  348. ESP_LOGD(HUB_DRIVER_TAG, "Getting configuration descriptor");
  349. return ENUM_STAGE_GET_CONFIG_DESC_CHECK;
  350. }
  351. static enum_stage_t enum_stage_check_config_desc(hcd_pipe_handle_t pipe_hdl, urb_t *enum_urb, usb_device_handle_t dev_hdl)
  352. {
  353. //Dequeue the URB
  354. urb_t *dequeued_enum_urb = hcd_urb_dequeue(pipe_hdl);
  355. assert(dequeued_enum_urb == enum_urb);
  356. if (enum_urb->transfer.status != USB_TRANSFER_STATUS_COMPLETED) {
  357. ESP_LOGE(HUB_DRIVER_TAG, "Configuration descriptor transfer failed");
  358. return ENUM_STAGE_CLEANUP_FAILED;
  359. }
  360. usb_config_desc_t *config_desc = (usb_config_desc_t *)(enum_urb->transfer.data_buffer + sizeof(usb_setup_packet_t));
  361. if (enum_urb->transfer.actual_num_bytes < sizeof(usb_setup_packet_t) + sizeof(usb_config_desc_t)) {
  362. ESP_LOGE(HUB_DRIVER_TAG, "Configuration descriptor too small");
  363. return ENUM_STAGE_CLEANUP_FAILED;
  364. }
  365. if (config_desc->wTotalLength > ENUM_CTRL_TRANSFER_MAX_LEN) {
  366. ESP_LOGE(HUB_DRIVER_TAG, "Configuration descriptor larger than control transfer max length");
  367. return ENUM_STAGE_CLEANUP_FAILED;
  368. }
  369. //Fill configuration descriptor into device
  370. ESP_ERROR_CHECK(usbh_hub_enum_fill_config_desc(dev_hdl, config_desc));
  371. return ENUM_STAGE_SET_CONFIG;
  372. }
  373. static enum_stage_t enum_stage_set_config(hcd_pipe_handle_t pipe_hdl, urb_t *enum_urb)
  374. {
  375. USB_SETUP_PACKET_INIT_SET_CONFIG((usb_setup_packet_t *)enum_urb->transfer.data_buffer, ENUM_CONFIG_INDEX + 1);
  376. enum_urb->transfer.num_bytes = sizeof(usb_setup_packet_t); //No data stage
  377. if (hcd_urb_enqueue(pipe_hdl, enum_urb) != ESP_OK) {
  378. ESP_LOGE(HUB_DRIVER_TAG, "Failed to set configuration");
  379. return ENUM_STAGE_CLEANUP_FAILED;
  380. }
  381. ESP_LOGD(HUB_DRIVER_TAG, "Setting configuration");
  382. return ENUM_STAGE_SET_CONFIG_CHECK;
  383. }
  384. static enum_stage_t enum_stage_check_config(hcd_pipe_handle_t pipe_hdl, urb_t *enum_urb)
  385. {
  386. //Dequeue the URB
  387. urb_t *dequeued_enum_urb = hcd_urb_dequeue(pipe_hdl);
  388. assert(dequeued_enum_urb == enum_urb);
  389. if (enum_urb->transfer.status != USB_TRANSFER_STATUS_COMPLETED) {
  390. ESP_LOGE(HUB_DRIVER_TAG, "Set configuration transfer failed");
  391. return ENUM_STAGE_CLEANUP_FAILED;
  392. }
  393. ESP_LOGD(HUB_DRIVER_TAG, "Configuration set successfully");
  394. return ENUM_STAGE_CLEANUP;
  395. }
  396. static enum_stage_t enum_stage_cleanup(void)
  397. {
  398. //We currently only support a single device connected to the root port. Move the device handle from enum to root
  399. HUB_DRIVER_ENTER_CRITICAL();
  400. p_hub_driver_obj->dynamic.root_dev_hdl = p_hub_driver_obj->single_thread.enum_dev_hdl;
  401. p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_ACTIVE;
  402. HUB_DRIVER_EXIT_CRITICAL();
  403. usb_device_handle_t dev_hdl = p_hub_driver_obj->single_thread.enum_dev_hdl;
  404. p_hub_driver_obj->single_thread.enum_dev_hdl = NULL;
  405. p_hub_driver_obj->single_thread.enum_dflt_pipe_hdl = NULL;
  406. //Update device object after enumeration is done
  407. ESP_ERROR_CHECK(usbh_hub_enum_done(dev_hdl));
  408. return ENUM_STAGE_NONE;
  409. }
  410. static enum_stage_t enum_stage_cleanup_failed(void)
  411. {
  412. //Enumeration failed. Clear the enum device handle and pipe
  413. usb_device_handle_t dev_hdl = p_hub_driver_obj->single_thread.enum_dev_hdl;
  414. if (p_hub_driver_obj->single_thread.enum_dev_hdl) {
  415. //Halt, flush, and dequeue enum default pipe
  416. ESP_ERROR_CHECK(hcd_pipe_command(p_hub_driver_obj->single_thread.enum_dflt_pipe_hdl, HCD_PIPE_CMD_HALT));
  417. ESP_ERROR_CHECK(hcd_pipe_command(p_hub_driver_obj->single_thread.enum_dflt_pipe_hdl, HCD_PIPE_CMD_FLUSH));
  418. urb_t *dequeued_enum_urb = hcd_urb_dequeue(p_hub_driver_obj->single_thread.enum_dflt_pipe_hdl);
  419. assert(dequeued_enum_urb == p_hub_driver_obj->single_thread.enum_urb);
  420. ESP_ERROR_CHECK(usbh_hub_enum_failed(dev_hdl)); //Free the underlying device object first before recovering the port
  421. }
  422. p_hub_driver_obj->single_thread.enum_dev_hdl = NULL;
  423. p_hub_driver_obj->single_thread.enum_dflt_pipe_hdl = NULL;
  424. HUB_DRIVER_ENTER_CRITICAL();
  425. //Enum could have failed due to a port error. If so, we need to trigger a port recovery
  426. if (p_hub_driver_obj->dynamic.driver_state == HUB_DRIVER_STATE_ROOT_RECOVERY) {
  427. p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_PORT_RECOVER;
  428. }
  429. HUB_DRIVER_EXIT_CRITICAL();
  430. return ENUM_STAGE_NONE;
  431. }
  432. static void enum_handle_events(void)
  433. {
  434. enum_stage_t cur_stage = p_hub_driver_obj->single_thread.enum_stage;
  435. hcd_pipe_handle_t enum_dflt_pipe_hdl = p_hub_driver_obj->single_thread.enum_dflt_pipe_hdl;
  436. urb_t *enum_urb = p_hub_driver_obj->single_thread.enum_urb;
  437. usb_device_handle_t dev_hdl = p_hub_driver_obj->single_thread.enum_dev_hdl;
  438. enum_stage_t next_stage;
  439. switch (cur_stage) {
  440. case ENUM_STAGE_START:
  441. next_stage = enum_stage_start();
  442. break;
  443. case ENUM_STAGE_GET_SHORT_DEV_DESC:
  444. next_stage = enum_stage_get_short_dev_desc(enum_dflt_pipe_hdl, enum_urb);
  445. break;
  446. case ENUM_STAGE_GET_SHORT_DEV_DESC_CHECK:
  447. next_stage = enum_stage_check_short_dev_desc(enum_dflt_pipe_hdl, enum_urb);
  448. break;
  449. case ENUM_STAGE_SECOND_RESET:
  450. next_stage = enum_stage_second_reset(enum_dflt_pipe_hdl, enum_urb);
  451. break;
  452. case ENUM_STAGE_SET_ADDR:
  453. next_stage = enum_stage_set_addr(enum_dflt_pipe_hdl, enum_urb);
  454. break;
  455. case ENUM_STAGE_SET_ADDR_CHECK:
  456. next_stage = enum_stage_check_set_addr(enum_dflt_pipe_hdl, enum_urb, dev_hdl);
  457. break;
  458. case ENUM_STAGE_GET_FULL_DEV_DESC:
  459. next_stage = enum_stage_get_full_dev_desc(enum_dflt_pipe_hdl, enum_urb);
  460. break;
  461. case ENUM_STAGE_GET_FULL_DEV_DESC_CHECK:
  462. next_stage = enum_stage_check_full_dev_desc(enum_dflt_pipe_hdl, enum_urb, dev_hdl);
  463. break;
  464. case ENUM_STAGE_GET_CONFIG_DESC:
  465. next_stage = enum_stage_get_config_desc(enum_dflt_pipe_hdl, enum_urb);
  466. break;
  467. case ENUM_STAGE_GET_CONFIG_DESC_CHECK:
  468. next_stage = enum_stage_check_config_desc(enum_dflt_pipe_hdl, enum_urb, dev_hdl);
  469. break;
  470. case ENUM_STAGE_SET_CONFIG:
  471. next_stage = enum_stage_set_config(enum_dflt_pipe_hdl, enum_urb);
  472. break;
  473. case ENUM_STAGE_SET_CONFIG_CHECK:
  474. next_stage = enum_stage_check_config(enum_dflt_pipe_hdl, enum_urb);
  475. break;
  476. case ENUM_STAGE_CLEANUP:
  477. next_stage = enum_stage_cleanup();
  478. break;
  479. case ENUM_STAGE_CLEANUP_FAILED:
  480. next_stage = enum_stage_cleanup_failed();
  481. break;
  482. default:
  483. //Note: Don't abort here. The enum_dflt_pipe_callback() can trigger a HUB_DRIVER_FLAG_ACTION_ENUM_EVENT after a cleanup
  484. next_stage = ENUM_STAGE_NONE;
  485. break;
  486. }
  487. p_hub_driver_obj->single_thread.enum_stage = next_stage;
  488. HUB_DRIVER_ENTER_CRITICAL();
  489. if (next_stage == ENUM_STAGE_GET_SHORT_DEV_DESC ||
  490. next_stage == ENUM_STAGE_SECOND_RESET ||
  491. next_stage == ENUM_STAGE_SET_ADDR ||
  492. next_stage == ENUM_STAGE_GET_FULL_DEV_DESC ||
  493. next_stage == ENUM_STAGE_GET_CONFIG_DESC ||
  494. next_stage == ENUM_STAGE_SET_CONFIG ||
  495. next_stage == ENUM_STAGE_CLEANUP ||
  496. next_stage == ENUM_STAGE_CLEANUP_FAILED) {
  497. p_hub_driver_obj->dynamic.flags.actions |= HUB_DRIVER_FLAG_ACTION_ENUM_EVENT;
  498. }
  499. HUB_DRIVER_EXIT_CRITICAL();
  500. }
  501. // ---------------------------------------------- Hub Driver Functions -------------------------------------------------
  502. esp_err_t hub_install(hub_config_t *hub_config)
  503. {
  504. HUB_DRIVER_ENTER_CRITICAL();
  505. HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj == NULL, ESP_ERR_INVALID_STATE);
  506. HUB_DRIVER_EXIT_CRITICAL();
  507. //Allocate Hub driver object
  508. hub_driver_t *hub_driver_obj = heap_caps_calloc(1, sizeof(hub_driver_t), MALLOC_CAP_DEFAULT);
  509. urb_t *enum_urb = urb_alloc(sizeof(usb_setup_packet_t) + ENUM_CTRL_TRANSFER_MAX_LEN, 0, 0);
  510. if (hub_driver_obj == NULL || enum_urb == NULL) {
  511. return ESP_ERR_NO_MEM;
  512. }
  513. esp_err_t ret;
  514. //Install HCD port
  515. hcd_port_config_t port_config = {
  516. .fifo_bias = HUB_ROOT_HCD_PORT_FIFO_BIAS,
  517. .callback = root_port_callback,
  518. .callback_arg = NULL,
  519. .context = NULL,
  520. };
  521. hcd_port_handle_t port_hdl;
  522. ret = hcd_port_init(HUB_ROOT_PORT_NUM, &port_config, &port_hdl);
  523. if (ret != ESP_OK) {
  524. goto err;
  525. }
  526. //Initialize hub driver object
  527. hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_INSTALLED;
  528. hub_driver_obj->single_thread.enum_stage = ENUM_STAGE_NONE;
  529. hub_driver_obj->single_thread.enum_urb = enum_urb;
  530. hub_driver_obj->constant.root_port_hdl = port_hdl;
  531. hub_driver_obj->constant.notif_cb = hub_config->notif_cb;
  532. hub_driver_obj->constant.notif_cb_arg = hub_config->notif_cb_arg;
  533. HUB_DRIVER_ENTER_CRITICAL();
  534. if (p_hub_driver_obj != NULL) {
  535. HUB_DRIVER_EXIT_CRITICAL();
  536. ret = ESP_ERR_INVALID_STATE;
  537. goto assign_err;
  538. }
  539. p_hub_driver_obj = hub_driver_obj;
  540. HUB_DRIVER_EXIT_CRITICAL();
  541. //Indicate to USBH that the hub is installed
  542. ESP_ERROR_CHECK(usbh_hub_is_installed(usbh_hub_callback, NULL));
  543. ret = ESP_OK;
  544. return ret;
  545. assign_err:
  546. ESP_ERROR_CHECK(hcd_port_deinit(port_hdl));
  547. err:
  548. urb_free(enum_urb);
  549. heap_caps_free(hub_driver_obj);
  550. return ret;
  551. }
  552. esp_err_t hub_uninstall(void)
  553. {
  554. HUB_DRIVER_ENTER_CRITICAL();
  555. HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj != NULL, ESP_ERR_INVALID_STATE);
  556. HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj->dynamic.driver_state == HUB_DRIVER_STATE_INSTALLED, ESP_ERR_INVALID_STATE);
  557. hub_driver_t *hub_driver_obj = p_hub_driver_obj;
  558. p_hub_driver_obj = NULL;
  559. HUB_DRIVER_EXIT_CRITICAL();
  560. ESP_ERROR_CHECK(hcd_port_deinit(hub_driver_obj->constant.root_port_hdl));
  561. //Free Hub driver resources
  562. urb_free(hub_driver_obj->single_thread.enum_urb);
  563. heap_caps_free(hub_driver_obj);
  564. return ESP_OK;
  565. }
  566. esp_err_t hub_root_start(void)
  567. {
  568. HUB_DRIVER_ENTER_CRITICAL();
  569. HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj != NULL, ESP_ERR_INVALID_STATE);
  570. HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj->dynamic.driver_state == HUB_DRIVER_STATE_INSTALLED, ESP_ERR_INVALID_STATE);
  571. HUB_DRIVER_EXIT_CRITICAL();
  572. //Power ON the root port
  573. esp_err_t ret;
  574. ret = hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_POWER_ON);
  575. if (ret == ESP_OK) {
  576. HUB_DRIVER_ENTER_CRITICAL();
  577. p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_POWERD;
  578. HUB_DRIVER_EXIT_CRITICAL();
  579. }
  580. return ret;
  581. }
  582. esp_err_t hub_root_stop(void)
  583. {
  584. HUB_DRIVER_ENTER_CRITICAL();
  585. HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj != NULL, ESP_ERR_INVALID_STATE);
  586. HUB_DRIVER_CHECK_FROM_CRIT(p_hub_driver_obj->dynamic.driver_state != HUB_DRIVER_STATE_INSTALLED, ESP_ERR_INVALID_STATE);
  587. HUB_DRIVER_EXIT_CRITICAL();
  588. esp_err_t ret;
  589. ret = hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_POWER_OFF);
  590. if (ret == ESP_OK) {
  591. HUB_DRIVER_ENTER_CRITICAL();
  592. p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_INSTALLED;
  593. HUB_DRIVER_EXIT_CRITICAL();
  594. }
  595. return ret;
  596. }
  597. esp_err_t hub_process(void)
  598. {
  599. HUB_DRIVER_ENTER_CRITICAL();
  600. uint32_t action_flags = p_hub_driver_obj->dynamic.flags.actions;
  601. p_hub_driver_obj->dynamic.flags.actions = 0;
  602. HUB_DRIVER_EXIT_CRITICAL();
  603. while (action_flags) {
  604. if (action_flags & HUB_DRIVER_FLAG_ACTION_ROOT_EVENT) {
  605. root_port_handle_events(p_hub_driver_obj->constant.root_port_hdl);
  606. }
  607. if (action_flags & HUB_DRIVER_FLAG_ACTION_ENUM_EVENT) {
  608. enum_handle_events();
  609. }
  610. if (action_flags & HUB_DRIVER_FLAG_ACTION_PORT_RECOVER) {
  611. ESP_LOGD(HUB_DRIVER_TAG, "Recovering root port");
  612. ESP_ERROR_CHECK(hcd_port_recover(p_hub_driver_obj->constant.root_port_hdl));
  613. ESP_ERROR_CHECK(hcd_port_command(p_hub_driver_obj->constant.root_port_hdl, HCD_PORT_CMD_POWER_ON));
  614. HUB_DRIVER_ENTER_CRITICAL();
  615. p_hub_driver_obj->dynamic.driver_state = HUB_DRIVER_STATE_ROOT_POWERD;
  616. HUB_DRIVER_EXIT_CRITICAL();
  617. }
  618. HUB_DRIVER_ENTER_CRITICAL();
  619. action_flags = p_hub_driver_obj->dynamic.flags.actions;
  620. p_hub_driver_obj->dynamic.flags.actions = 0;
  621. HUB_DRIVER_EXIT_CRITICAL();
  622. }
  623. return ESP_OK;
  624. }