usbh.c 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052
  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 <stdint.h>
  8. #include <string.h>
  9. #include <assert.h>
  10. #include <sys/queue.h>
  11. #include "freertos/FreeRTOS.h"
  12. #include "freertos/portmacro.h"
  13. #include "freertos/task.h"
  14. #include "freertos/semphr.h"
  15. #include "esp_err.h"
  16. #include "esp_log.h"
  17. #include "esp_heap_caps.h"
  18. #include "hcd.h"
  19. #include "usbh.h"
  20. #include "usb/usb_helpers.h"
  21. #include "usb/usb_types_ch9.h"
  22. //Device action flags. LISTED IN THE ORDER THEY SHOULD BE HANDLED IN within usbh_process(). Some actions are mutually exclusive
  23. #define DEV_FLAG_ACTION_PIPE_HALT_AND_FLUSH 0x01 //Halt all non-default pipes then flush them (called after a device gone is gone)
  24. #define DEV_FLAG_ACTION_DEFAULT_PIPE_FLUSH 0x02 //Retire all URBS in the default pipe
  25. #define DEV_FLAG_ACTION_DEFAULT_PIPE_DEQUEUE 0x04 //Dequeue all URBs from default pipe
  26. #define DEV_FLAG_ACTION_DEFAULT_PIPE_CLEAR 0x08 //Move the default pipe to the active state
  27. #define DEV_FLAG_ACTION_SEND_GONE_EVENT 0x10 //Send a USB_HOST_CLIENT_EVENT_DEV_GONE event
  28. #define DEV_FLAG_ACTION_FREE 0x20 //Free the device object
  29. #define DEV_FLAG_ACTION_PORT_DISABLE 0x40 //Request the hub driver to disable the port of the device
  30. #define DEV_FLAG_ACTION_SEND_NEW 0x80 //Send a new device event
  31. #define DEV_ENUM_TODO_FLAG_DEV_ADDR 0x01
  32. #define DEV_ENUM_TODO_FLAG_DEV_DESC 0x02
  33. #define DEV_ENUM_TODO_FLAG_CONFIG_DESC 0x04
  34. #define EP_NUM_MIN 1
  35. #define EP_NUM_MAX 16
  36. typedef struct device_s device_t;
  37. struct device_s {
  38. //Dynamic members require a critical section
  39. struct {
  40. TAILQ_ENTRY(device_s) tailq_entry;
  41. union {
  42. struct {
  43. uint32_t actions: 8;
  44. uint32_t in_pending_list: 1;
  45. uint32_t is_gone: 1;
  46. uint32_t waiting_close: 1;
  47. uint32_t waiting_port_disable: 1;
  48. uint32_t waiting_free: 1;
  49. uint32_t reserved19: 19;
  50. };
  51. uint32_t val;
  52. } flags;
  53. int num_ctrl_xfers_inflight;
  54. usb_device_state_t state;
  55. uint32_t ref_count;
  56. } dynamic;
  57. //Mux protected members must be protected by the USBH mux_lock when accessed
  58. struct {
  59. usb_config_desc_t *config_desc;
  60. hcd_pipe_handle_t ep_in[EP_NUM_MAX - 1]; //IN EP owner contexts. -1 to exclude the default endpoint
  61. hcd_pipe_handle_t ep_out[EP_NUM_MAX - 1]; //OUT EP owner contexts. -1 to exclude the default endpoint
  62. } mux_protected;
  63. //Constant members do no change after device allocation and enumeration thus do not require a critical section
  64. struct {
  65. hcd_pipe_handle_t default_pipe;
  66. hcd_port_handle_t port_hdl;
  67. uint8_t address;
  68. usb_speed_t speed;
  69. const usb_device_desc_t *desc;
  70. uint32_t enum_todo_flags;
  71. } constant;
  72. };
  73. typedef struct {
  74. //Dynamic members require a critical section
  75. struct {
  76. TAILQ_HEAD(tailhead_devs, device_s) devs_idle_tailq; //Tailq of all enum and configured devices
  77. TAILQ_HEAD(tailhead_devs_cb, device_s) devs_pending_tailq; //Tailq of devices that need to have their cb called
  78. } dynamic;
  79. //Mux protected members must be protected by the USBH mux_lock when accessed
  80. struct {
  81. uint8_t num_device; //Number of enumerated devices
  82. } mux_protected;
  83. //Constant members do no change after installation thus do not require a critical section
  84. struct {
  85. usb_notif_cb_t notif_cb;
  86. void *notif_cb_arg;
  87. usbh_hub_cb_t hub_cb;
  88. void *hub_cb_arg;
  89. usbh_event_cb_t event_cb;
  90. void *event_cb_arg;
  91. usbh_ctrl_xfer_cb_t ctrl_xfer_cb;
  92. void *ctrl_xfer_cb_arg;
  93. SemaphoreHandle_t mux_lock;
  94. } constant;
  95. } usbh_t;
  96. static usbh_t *p_usbh_obj = NULL;
  97. static portMUX_TYPE usbh_lock = portMUX_INITIALIZER_UNLOCKED;
  98. const char *USBH_TAG = "USBH";
  99. #define USBH_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&usbh_lock)
  100. #define USBH_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&usbh_lock)
  101. #define USBH_ENTER_CRITICAL() portENTER_CRITICAL(&usbh_lock)
  102. #define USBH_EXIT_CRITICAL() portEXIT_CRITICAL(&usbh_lock)
  103. #define USBH_ENTER_CRITICAL_SAFE() portENTER_CRITICAL_SAFE(&usbh_lock)
  104. #define USBH_EXIT_CRITICAL_SAFE() portEXIT_CRITICAL_SAFE(&usbh_lock)
  105. #define USBH_CHECK(cond, ret_val) ({ \
  106. if (!(cond)) { \
  107. return (ret_val); \
  108. } \
  109. })
  110. #define USBH_CHECK_FROM_CRIT(cond, ret_val) ({ \
  111. if (!(cond)) { \
  112. USBH_EXIT_CRITICAL(); \
  113. return ret_val; \
  114. } \
  115. })
  116. // --------------------------------------------------- Allocation ------------------------------------------------------
  117. static esp_err_t device_alloc(hcd_port_handle_t port_hdl, usb_speed_t speed, device_t **dev_obj_ret)
  118. {
  119. esp_err_t ret;
  120. device_t *dev_obj = heap_caps_calloc(1, sizeof(device_t), MALLOC_CAP_DEFAULT);
  121. usb_device_desc_t *dev_desc = heap_caps_calloc(1, sizeof(usb_device_desc_t), MALLOC_CAP_DEFAULT);
  122. if (dev_obj == NULL || dev_desc == NULL) {
  123. ret = ESP_ERR_NO_MEM;
  124. goto err;
  125. }
  126. //Allocate default pipe. We set the pipe callback to NULL for now
  127. hcd_pipe_config_t pipe_config = {
  128. .callback = NULL,
  129. .callback_arg = NULL,
  130. .context = (void *)dev_obj,
  131. .ep_desc = NULL, //No endpoint descriptor means we're allocating a default pipe
  132. .dev_speed = speed,
  133. .dev_addr = 0,
  134. };
  135. hcd_pipe_handle_t default_pipe_hdl;
  136. ret = hcd_pipe_alloc(port_hdl, &pipe_config, &default_pipe_hdl);
  137. if (ret != ESP_OK) {
  138. goto err;
  139. }
  140. //Initialize device object
  141. dev_obj->dynamic.state = USB_DEVICE_STATE_DEFAULT;
  142. dev_obj->constant.default_pipe = default_pipe_hdl;
  143. dev_obj->constant.port_hdl = port_hdl;
  144. //Note: dev_obj->constant.address is assigned later during enumeration
  145. dev_obj->constant.speed = speed;
  146. dev_obj->constant.desc = dev_desc;
  147. dev_obj->constant.enum_todo_flags = (DEV_ENUM_TODO_FLAG_DEV_ADDR | DEV_ENUM_TODO_FLAG_DEV_DESC | DEV_ENUM_TODO_FLAG_CONFIG_DESC);
  148. *dev_obj_ret = dev_obj;
  149. ret = ESP_OK;
  150. return ret;
  151. err:
  152. heap_caps_free(dev_desc);
  153. heap_caps_free(dev_obj);
  154. return ret;
  155. }
  156. static void device_free(device_t *dev_obj)
  157. {
  158. if (dev_obj == NULL) {
  159. return;
  160. }
  161. //Configuration must be freed
  162. assert(dev_obj->mux_protected.config_desc == NULL); //Sanity check. No need for mux
  163. ESP_ERROR_CHECK(hcd_pipe_free(dev_obj->constant.default_pipe));
  164. heap_caps_free((usb_device_desc_t *)dev_obj->constant.desc);
  165. heap_caps_free(dev_obj);
  166. }
  167. // -------------------------------------------------- Event Related ----------------------------------------------------
  168. static bool _dev_set_actions(device_t *dev_obj, uint32_t action_flags)
  169. {
  170. if (action_flags == 0) {
  171. return false;
  172. }
  173. bool call_notif_cb;
  174. //Check if device is already on the callback list
  175. if (!dev_obj->dynamic.flags.in_pending_list) {
  176. //Move device form idle device list to callback device list
  177. TAILQ_REMOVE(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry);
  178. TAILQ_INSERT_TAIL(&p_usbh_obj->dynamic.devs_pending_tailq, dev_obj, dynamic.tailq_entry);
  179. dev_obj->dynamic.flags.actions |= action_flags;
  180. dev_obj->dynamic.flags.in_pending_list = 1;
  181. call_notif_cb = true;
  182. } else {
  183. call_notif_cb = false;
  184. }
  185. return call_notif_cb;
  186. }
  187. static bool default_pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_event, void *user_arg, bool in_isr)
  188. {
  189. uint32_t action_flags;
  190. device_t *dev_obj = (device_t *)user_arg;
  191. switch (pipe_event) {
  192. case HCD_PIPE_EVENT_URB_DONE:
  193. //A control transfer completed on the default pipe. We need to dequeue it
  194. action_flags = DEV_FLAG_ACTION_DEFAULT_PIPE_DEQUEUE;
  195. break;
  196. case HCD_PIPE_EVENT_ERROR_XFER:
  197. case HCD_PIPE_EVENT_ERROR_URB_NOT_AVAIL:
  198. case HCD_PIPE_EVENT_ERROR_OVERFLOW:
  199. //The default pipe has encountered an error. We need to retire all URBs, dequeue them, then make the pipe active again
  200. action_flags = DEV_FLAG_ACTION_DEFAULT_PIPE_FLUSH |
  201. DEV_FLAG_ACTION_DEFAULT_PIPE_DEQUEUE |
  202. DEV_FLAG_ACTION_DEFAULT_PIPE_CLEAR;
  203. if (in_isr) {
  204. ESP_EARLY_LOGE(USBH_TAG, "Dev %d EP 0 Error", dev_obj->constant.address);
  205. } else {
  206. ESP_LOGE(USBH_TAG, "Dev %d EP 0 Error", dev_obj->constant.address);
  207. }
  208. break;
  209. case HCD_PIPE_EVENT_ERROR_STALL:
  210. //The default pipe encountered a "protocol stall". We just need to dequeue URBs then make the pipe active again
  211. action_flags = DEV_FLAG_ACTION_DEFAULT_PIPE_DEQUEUE | DEV_FLAG_ACTION_DEFAULT_PIPE_CLEAR;
  212. if (in_isr) {
  213. ESP_EARLY_LOGE(USBH_TAG, "Dev %d EP 0 STALL", dev_obj->constant.address);
  214. } else {
  215. ESP_LOGE(USBH_TAG, "Dev %d EP 0 STALL", dev_obj->constant.address);
  216. }
  217. break;
  218. default:
  219. action_flags = 0;
  220. break;
  221. }
  222. USBH_ENTER_CRITICAL_SAFE();
  223. bool call_notif_cb = _dev_set_actions(dev_obj, action_flags);
  224. USBH_EXIT_CRITICAL_SAFE();
  225. bool yield = false;
  226. if (call_notif_cb) {
  227. yield = p_usbh_obj->constant.notif_cb(USB_NOTIF_SOURCE_USBH, in_isr, p_usbh_obj->constant.notif_cb_arg);
  228. }
  229. return yield;
  230. }
  231. static void handle_pipe_halt_and_flush(device_t *dev_obj)
  232. {
  233. //We need to take the mux_lock to access mux_protected members
  234. xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
  235. //Halt then flush all non-default IN pipes
  236. for (int i = 0; i < (EP_NUM_MAX - 1); i++) {
  237. if (dev_obj->mux_protected.ep_in[i] != NULL) {
  238. ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->mux_protected.ep_in[i], HCD_PIPE_CMD_HALT));
  239. ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->mux_protected.ep_in[i], HCD_PIPE_CMD_FLUSH));
  240. }
  241. if (dev_obj->mux_protected.ep_out[i] != NULL) {
  242. ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->mux_protected.ep_out[i], HCD_PIPE_CMD_HALT));
  243. ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->mux_protected.ep_out[i], HCD_PIPE_CMD_FLUSH));
  244. }
  245. }
  246. xSemaphoreGive(p_usbh_obj->constant.mux_lock);
  247. }
  248. static bool handle_dev_free(device_t *dev_obj)
  249. {
  250. //We need to take the mux_lock to access mux_protected members
  251. xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
  252. USBH_ENTER_CRITICAL();
  253. //Remove the device object for it's containing list
  254. if (dev_obj->dynamic.flags.in_pending_list) {
  255. dev_obj->dynamic.flags.in_pending_list = 0;
  256. TAILQ_REMOVE(&p_usbh_obj->dynamic.devs_pending_tailq, dev_obj, dynamic.tailq_entry);
  257. } else {
  258. TAILQ_REMOVE(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry);
  259. }
  260. USBH_EXIT_CRITICAL();
  261. p_usbh_obj->mux_protected.num_device--;
  262. bool all_free = (p_usbh_obj->mux_protected.num_device == 0);
  263. heap_caps_free(dev_obj->mux_protected.config_desc);
  264. dev_obj->mux_protected.config_desc = NULL;
  265. device_free(dev_obj);
  266. xSemaphoreGive(p_usbh_obj->constant.mux_lock);
  267. return all_free;
  268. }
  269. // ------------------------------------------------- USBH Functions ----------------------------------------------------
  270. esp_err_t usbh_install(const usbh_config_t *usbh_config)
  271. {
  272. USBH_CHECK(usbh_config != NULL, ESP_ERR_INVALID_ARG);
  273. USBH_ENTER_CRITICAL();
  274. USBH_CHECK_FROM_CRIT(p_usbh_obj == NULL, ESP_ERR_INVALID_STATE);
  275. USBH_EXIT_CRITICAL();
  276. esp_err_t ret;
  277. usbh_t *usbh_obj = heap_caps_calloc(1, sizeof(usbh_t), MALLOC_CAP_DEFAULT);
  278. SemaphoreHandle_t mux_lock = xSemaphoreCreateMutex();
  279. if (usbh_obj == NULL || mux_lock == NULL) {
  280. ret = ESP_ERR_NO_MEM;
  281. goto alloc_err;
  282. }
  283. //Install HCD
  284. ret = hcd_install(&usbh_config->hcd_config);
  285. if (ret != ESP_OK) {
  286. goto hcd_install_err;
  287. }
  288. //Initialize usbh object
  289. TAILQ_INIT(&usbh_obj->dynamic.devs_idle_tailq);
  290. TAILQ_INIT(&usbh_obj->dynamic.devs_pending_tailq);
  291. usbh_obj->constant.notif_cb = usbh_config->notif_cb;
  292. usbh_obj->constant.notif_cb_arg = usbh_config->notif_cb_arg;
  293. usbh_obj->constant.event_cb = usbh_config->event_cb;
  294. usbh_obj->constant.event_cb_arg = usbh_config->event_cb_arg;
  295. usbh_obj->constant.ctrl_xfer_cb = usbh_config->ctrl_xfer_cb;
  296. usbh_obj->constant.ctrl_xfer_cb_arg = usbh_config->ctrl_xfer_cb_arg;
  297. usbh_obj->constant.mux_lock = mux_lock;
  298. //Assign usbh object pointer
  299. USBH_ENTER_CRITICAL();
  300. if (p_usbh_obj != NULL) {
  301. USBH_EXIT_CRITICAL();
  302. ret = ESP_ERR_INVALID_STATE;
  303. goto assign_err;
  304. }
  305. p_usbh_obj = usbh_obj;
  306. USBH_EXIT_CRITICAL();
  307. ret = ESP_OK;
  308. return ret;
  309. assign_err:
  310. ESP_ERROR_CHECK(hcd_uninstall());
  311. hcd_install_err:
  312. alloc_err:
  313. if (mux_lock != NULL) {
  314. vSemaphoreDelete(mux_lock);
  315. }
  316. heap_caps_free(usbh_obj);
  317. return ret;
  318. }
  319. esp_err_t usbh_uninstall(void)
  320. {
  321. //Check that USBH is in a state to be uninstalled
  322. USBH_ENTER_CRITICAL();
  323. USBH_CHECK_FROM_CRIT(p_usbh_obj != NULL, ESP_ERR_INVALID_STATE);
  324. usbh_t *usbh_obj = p_usbh_obj;
  325. USBH_EXIT_CRITICAL();
  326. esp_err_t ret;
  327. //We need to take the mux_lock to access mux_protected members
  328. xSemaphoreTake(usbh_obj->constant.mux_lock, portMAX_DELAY);
  329. if (p_usbh_obj->mux_protected.num_device > 0) {
  330. //There are still devices allocated. Can't uninstall right now.
  331. ret = ESP_ERR_INVALID_STATE;
  332. goto exit;
  333. }
  334. //Check again if we can uninstall
  335. USBH_ENTER_CRITICAL();
  336. assert(p_usbh_obj == usbh_obj);
  337. p_usbh_obj = NULL;
  338. USBH_EXIT_CRITICAL();
  339. xSemaphoreGive(usbh_obj->constant.mux_lock);
  340. //Uninstall HCD, free resources
  341. ESP_ERROR_CHECK(hcd_uninstall());
  342. vSemaphoreDelete(usbh_obj->constant.mux_lock);
  343. heap_caps_free(usbh_obj);
  344. ret = ESP_OK;
  345. return ret;
  346. exit:
  347. xSemaphoreGive(p_usbh_obj->constant.mux_lock);
  348. return ret;
  349. }
  350. esp_err_t usbh_process(void)
  351. {
  352. USBH_ENTER_CRITICAL();
  353. USBH_CHECK_FROM_CRIT(p_usbh_obj != NULL, ESP_ERR_INVALID_STATE);
  354. //Keep clearing devices with events
  355. while (!TAILQ_EMPTY(&p_usbh_obj->dynamic.devs_pending_tailq)){
  356. //Move the device back into the idle device list,
  357. device_t *dev_obj = TAILQ_FIRST(&p_usbh_obj->dynamic.devs_pending_tailq);
  358. TAILQ_REMOVE(&p_usbh_obj->dynamic.devs_pending_tailq, dev_obj, dynamic.tailq_entry);
  359. TAILQ_INSERT_TAIL(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry);
  360. //Clear the device's flags
  361. uint32_t action_flags = dev_obj->dynamic.flags.actions;
  362. dev_obj->dynamic.flags.actions = 0;
  363. dev_obj->dynamic.flags.in_pending_list = 0;
  364. /* ---------------------------------------------------------------------
  365. Exit critical section to handle device action flags in their listed order
  366. --------------------------------------------------------------------- */
  367. USBH_EXIT_CRITICAL();
  368. ESP_LOGD(USBH_TAG, "Processing actions 0x%x", action_flags);
  369. //Sanity check. If the device is being freed, there must not be any other action flags set
  370. assert(!(action_flags & DEV_FLAG_ACTION_FREE) || action_flags == DEV_FLAG_ACTION_FREE);
  371. if (action_flags & DEV_FLAG_ACTION_PIPE_HALT_AND_FLUSH) {
  372. handle_pipe_halt_and_flush(dev_obj);
  373. }
  374. if (action_flags & DEV_FLAG_ACTION_DEFAULT_PIPE_FLUSH) {
  375. ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->constant.default_pipe, HCD_PIPE_CMD_HALT));
  376. ESP_ERROR_CHECK(hcd_pipe_command(dev_obj->constant.default_pipe, HCD_PIPE_CMD_FLUSH));
  377. }
  378. if (action_flags & DEV_FLAG_ACTION_DEFAULT_PIPE_DEQUEUE) {
  379. //Empty URBs from default pipe and trigger a control transfer callback
  380. ESP_LOGD(USBH_TAG, "Default pipe device %d", dev_obj->constant.address);
  381. int num_urbs = 0;
  382. urb_t *urb = hcd_urb_dequeue(dev_obj->constant.default_pipe);
  383. while (urb != NULL) {
  384. num_urbs++;
  385. p_usbh_obj->constant.ctrl_xfer_cb((usb_device_handle_t)dev_obj, urb, p_usbh_obj->constant.ctrl_xfer_cb_arg);
  386. urb = hcd_urb_dequeue(dev_obj->constant.default_pipe);
  387. }
  388. USBH_ENTER_CRITICAL();
  389. dev_obj->dynamic.num_ctrl_xfers_inflight -= num_urbs;
  390. USBH_EXIT_CRITICAL();
  391. }
  392. if (action_flags & DEV_FLAG_ACTION_DEFAULT_PIPE_CLEAR) {
  393. //We allow the pipe command to fail just in case the pipe becomes invalid mid command
  394. hcd_pipe_command(dev_obj->constant.default_pipe, HCD_PIPE_CMD_CLEAR);
  395. }
  396. if (action_flags & DEV_FLAG_ACTION_SEND_GONE_EVENT) {
  397. //Flush the default pipe. Then do an event gone
  398. ESP_LOGE(USBH_TAG, "Device %d gone", dev_obj->constant.address);
  399. p_usbh_obj->constant.event_cb((usb_device_handle_t)dev_obj, USBH_EVENT_DEV_GONE, p_usbh_obj->constant.event_cb_arg);
  400. }
  401. /*
  402. Note: We make these action flags mutually exclusive in case they happen in rapid succession. They are handled
  403. in the order of precedence
  404. For example
  405. - New device event is requested followed immediately by a disconnection
  406. - Port disable requested followed immediately by a disconnection
  407. */
  408. if (action_flags & DEV_FLAG_ACTION_FREE) {
  409. ESP_LOGD(USBH_TAG, "Freeing device %d", dev_obj->constant.address);
  410. if (handle_dev_free(dev_obj)) {
  411. ESP_LOGD(USBH_TAG, "Device all free");
  412. p_usbh_obj->constant.event_cb((usb_device_handle_t)NULL, USBH_EVENT_DEV_ALL_FREE, p_usbh_obj->constant.event_cb_arg);
  413. }
  414. } else if (action_flags & DEV_FLAG_ACTION_PORT_DISABLE) {
  415. //Request that the HUB disables this device's port
  416. ESP_LOGD(USBH_TAG, "Disable device port %d", dev_obj->constant.address);
  417. p_usbh_obj->constant.hub_cb(dev_obj->constant.port_hdl, USBH_HUB_EVENT_DISABLE_PORT, p_usbh_obj->constant.hub_cb_arg);
  418. } else if (action_flags & DEV_FLAG_ACTION_SEND_NEW) {
  419. ESP_LOGD(USBH_TAG, "New device %d", dev_obj->constant.address);
  420. p_usbh_obj->constant.event_cb((usb_device_handle_t)dev_obj, USBH_EVENT_DEV_NEW, p_usbh_obj->constant.event_cb_arg);
  421. }
  422. USBH_ENTER_CRITICAL();
  423. /* ---------------------------------------------------------------------
  424. Re-enter critical sections. All device action flags should have been handled.
  425. --------------------------------------------------------------------- */
  426. }
  427. USBH_EXIT_CRITICAL();
  428. return ESP_OK;
  429. }
  430. // ------------------------------------------------ Device Functions ---------------------------------------------------
  431. // --------------------- Device Pool -----------------------
  432. esp_err_t usbh_dev_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *num_dev_ret)
  433. {
  434. USBH_CHECK(dev_addr_list != NULL && num_dev_ret != NULL, ESP_ERR_INVALID_ARG);
  435. USBH_ENTER_CRITICAL();
  436. int num_filled = 0;
  437. device_t *dev_obj;
  438. //Fill list with devices from idle tailq
  439. TAILQ_FOREACH(dev_obj, &p_usbh_obj->dynamic.devs_idle_tailq, dynamic.tailq_entry) {
  440. if (num_filled < list_len) {
  441. dev_addr_list[num_filled] = dev_obj->constant.address;
  442. num_filled++;
  443. } else {
  444. break;
  445. }
  446. }
  447. //Fill list with devices from pending tailq
  448. TAILQ_FOREACH(dev_obj, &p_usbh_obj->dynamic.devs_pending_tailq, dynamic.tailq_entry) {
  449. if (num_filled < list_len) {
  450. dev_addr_list[num_filled] = dev_obj->constant.address;
  451. num_filled++;
  452. } else {
  453. break;
  454. }
  455. }
  456. USBH_EXIT_CRITICAL();
  457. //Write back number of devices filled
  458. *num_dev_ret = num_filled;
  459. return ESP_OK;
  460. }
  461. esp_err_t usbh_dev_open(uint8_t dev_addr, usb_device_handle_t *dev_hdl)
  462. {
  463. USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG);
  464. esp_err_t ret;
  465. USBH_ENTER_CRITICAL();
  466. //Go through the device lists to find the device with the specified address
  467. device_t *found_dev_obj = NULL;
  468. device_t *dev_obj;
  469. TAILQ_FOREACH(dev_obj, &p_usbh_obj->dynamic.devs_idle_tailq, dynamic.tailq_entry) {
  470. if (dev_obj->constant.address == dev_addr) {
  471. found_dev_obj = dev_obj;
  472. goto exit;
  473. }
  474. }
  475. TAILQ_FOREACH(dev_obj, &p_usbh_obj->dynamic.devs_idle_tailq, dynamic.tailq_entry) {
  476. if (dev_obj->constant.address == dev_addr) {
  477. found_dev_obj = dev_obj;
  478. goto exit;
  479. }
  480. }
  481. exit:
  482. if (found_dev_obj != NULL) {
  483. //The device is not in a state to be referenced
  484. if (dev_obj->dynamic.flags.is_gone || dev_obj->dynamic.flags.waiting_port_disable || dev_obj->dynamic.flags.waiting_free) {
  485. ret = ESP_ERR_INVALID_STATE;
  486. } else {
  487. dev_obj->dynamic.ref_count++;
  488. *dev_hdl = (usb_device_handle_t)found_dev_obj;
  489. ret = ESP_OK;
  490. }
  491. } else {
  492. ret = ESP_ERR_NOT_FOUND;
  493. }
  494. USBH_EXIT_CRITICAL();
  495. return ret;
  496. }
  497. esp_err_t usbh_dev_close(usb_device_handle_t dev_hdl)
  498. {
  499. USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG);
  500. device_t *dev_obj = (device_t *)dev_hdl;
  501. USBH_ENTER_CRITICAL();
  502. USBH_CHECK_FROM_CRIT(dev_obj->dynamic.num_ctrl_xfers_inflight == 0, ESP_ERR_INVALID_STATE);
  503. dev_obj->dynamic.ref_count--;
  504. bool call_notif_cb = false;
  505. if (dev_obj->dynamic.ref_count == 0) {
  506. //Sanity check. This can only be set when ref count reaches 0
  507. assert(!dev_obj->dynamic.flags.waiting_free);
  508. if (dev_obj->dynamic.flags.is_gone) {
  509. //Device is already gone so it's port is already disabled. Trigger the USBH process to free the device
  510. dev_obj->dynamic.flags.waiting_free = 1;
  511. call_notif_cb = _dev_set_actions(dev_obj, DEV_FLAG_ACTION_FREE);
  512. } else if (dev_obj->dynamic.flags.waiting_close) {
  513. //Device is still connected but is no longer needed. Trigger the USBH process to request device's port be disabled
  514. dev_obj->dynamic.flags.waiting_port_disable = 1;
  515. call_notif_cb = _dev_set_actions(dev_obj, DEV_FLAG_ACTION_PORT_DISABLE);
  516. }
  517. //Else, there's nothing to do. Leave the device allocated
  518. }
  519. USBH_EXIT_CRITICAL();
  520. if (call_notif_cb) {
  521. p_usbh_obj->constant.notif_cb(USB_NOTIF_SOURCE_USBH, false, p_usbh_obj->constant.notif_cb_arg);
  522. }
  523. return ESP_OK;
  524. }
  525. esp_err_t usbh_dev_mark_all_free(void)
  526. {
  527. USBH_ENTER_CRITICAL();
  528. /*
  529. Go through the device list and mark each device as waiting to be closed. If the device is not opened at all, we can
  530. disable it immediately.
  531. Note: We manually traverse the list because we need to add/remove items while traversing
  532. */
  533. bool call_notif_cb = false;
  534. bool wait_for_free = false;
  535. for (int i = 0; i < 2; i++) {
  536. device_t *dev_obj_cur;
  537. device_t *dev_obj_next;
  538. //Go through pending list first as it's more efficient
  539. if (i == 0) {
  540. dev_obj_cur = TAILQ_FIRST(&p_usbh_obj->dynamic.devs_pending_tailq);
  541. } else {
  542. dev_obj_cur = TAILQ_FIRST(&p_usbh_obj->dynamic.devs_idle_tailq);
  543. }
  544. while (dev_obj_cur != NULL) {
  545. assert(!dev_obj_cur->dynamic.flags.waiting_close); //Sanity check
  546. //Keep a copy of the next item first in case we remove the current item
  547. dev_obj_next = TAILQ_NEXT(dev_obj_cur, dynamic.tailq_entry);
  548. if (dev_obj_cur->dynamic.ref_count == 0 && !dev_obj_cur->dynamic.flags.is_gone) {
  549. //Device is not opened as is not gone, so we can disable it now
  550. dev_obj_cur->dynamic.flags.waiting_port_disable = 1;
  551. call_notif_cb |= _dev_set_actions(dev_obj_cur, DEV_FLAG_ACTION_PORT_DISABLE);
  552. } else {
  553. //Device is still opened. Just mark it as waiting to be closed
  554. dev_obj_cur->dynamic.flags.waiting_close = 1;
  555. }
  556. wait_for_free = true; //As long as there is still a device, we need to wait for an event indicating it is freed
  557. dev_obj_cur = dev_obj_next;
  558. }
  559. }
  560. USBH_EXIT_CRITICAL();
  561. if (call_notif_cb) {
  562. p_usbh_obj->constant.notif_cb(USB_NOTIF_SOURCE_USBH, false, p_usbh_obj->constant.notif_cb_arg);
  563. }
  564. return (wait_for_free) ? ESP_ERR_NOT_FINISHED : ESP_OK;
  565. }
  566. // ------------------- Single Device ----------------------
  567. esp_err_t usbh_dev_get_addr(usb_device_handle_t dev_hdl, uint8_t *dev_addr)
  568. {
  569. USBH_CHECK(dev_hdl != NULL && dev_addr != NULL, ESP_ERR_INVALID_ARG);
  570. device_t *dev_obj = (device_t *)dev_hdl;
  571. USBH_ENTER_CRITICAL();
  572. USBH_CHECK_FROM_CRIT(dev_obj->constant.address > 0, ESP_ERR_INVALID_STATE);
  573. *dev_addr = dev_obj->constant.address;
  574. USBH_EXIT_CRITICAL();
  575. return ESP_OK;
  576. }
  577. esp_err_t usbh_dev_get_info(usb_device_handle_t dev_hdl, usb_device_info_t *dev_info)
  578. {
  579. USBH_CHECK(dev_hdl != NULL && dev_info != NULL, ESP_ERR_INVALID_ARG);
  580. device_t *dev_obj = (device_t *)dev_hdl;
  581. esp_err_t ret;
  582. //We need to take the mux_lock to access mux_protected members
  583. xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
  584. //Device must be configured, or not attached (if it suddenly disconnected)
  585. USBH_ENTER_CRITICAL();
  586. if (!(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED || dev_obj->dynamic.state == USB_DEVICE_STATE_NOT_ATTACHED)) {
  587. USBH_EXIT_CRITICAL();
  588. ret = ESP_ERR_INVALID_STATE;
  589. goto exit;
  590. }
  591. //Critical section for the dynamic members
  592. dev_info->speed = dev_obj->constant.speed;
  593. dev_info->dev_addr = dev_obj->constant.address;
  594. dev_info->bMaxPacketSize0 = dev_obj->constant.desc->bMaxPacketSize0;
  595. USBH_EXIT_CRITICAL();
  596. if (dev_obj->mux_protected.config_desc == NULL) {
  597. dev_info->bConfigurationValue = 0;
  598. } else {
  599. dev_info->bConfigurationValue = dev_obj->mux_protected.config_desc->bConfigurationValue;
  600. }
  601. ret = ESP_OK;
  602. exit:
  603. xSemaphoreGive(p_usbh_obj->constant.mux_lock);
  604. return ret;
  605. }
  606. esp_err_t usbh_dev_get_desc(usb_device_handle_t dev_hdl, const usb_device_desc_t **dev_desc_ret)
  607. {
  608. USBH_CHECK(dev_hdl != NULL && dev_desc_ret != NULL, ESP_ERR_INVALID_ARG);
  609. device_t *dev_obj = (device_t *)dev_hdl;
  610. USBH_ENTER_CRITICAL();
  611. USBH_CHECK_FROM_CRIT(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED, ESP_ERR_INVALID_STATE);
  612. USBH_EXIT_CRITICAL();
  613. *dev_desc_ret = dev_obj->constant.desc;
  614. return ESP_OK;
  615. }
  616. esp_err_t usbh_dev_get_config_desc(usb_device_handle_t dev_hdl, const usb_config_desc_t **config_desc_ret)
  617. {
  618. USBH_CHECK(dev_hdl != NULL && config_desc_ret != NULL, ESP_ERR_INVALID_ARG);
  619. device_t *dev_obj = (device_t *)dev_hdl;
  620. esp_err_t ret;
  621. //We need to take the mux_lock to access mux_protected members
  622. xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
  623. //Device must be in the configured state
  624. USBH_ENTER_CRITICAL();
  625. if (dev_obj->dynamic.state != USB_DEVICE_STATE_CONFIGURED) {
  626. USBH_EXIT_CRITICAL();
  627. ret = ESP_ERR_INVALID_STATE;
  628. goto exit;
  629. }
  630. USBH_EXIT_CRITICAL();
  631. *config_desc_ret = dev_obj->mux_protected.config_desc;
  632. ret = ESP_OK;
  633. exit:
  634. xSemaphoreGive(p_usbh_obj->constant.mux_lock);
  635. return ret;
  636. }
  637. esp_err_t usbh_dev_submit_ctrl_urb(usb_device_handle_t dev_hdl, urb_t *urb)
  638. {
  639. USBH_CHECK(dev_hdl != NULL && urb != NULL, ESP_ERR_INVALID_ARG);
  640. device_t *dev_obj = (device_t *)dev_hdl;
  641. USBH_ENTER_CRITICAL();
  642. USBH_CHECK_FROM_CRIT(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED, ESP_ERR_INVALID_STATE);
  643. //Increment the control transfer count first
  644. dev_obj->dynamic.num_ctrl_xfers_inflight++;
  645. USBH_EXIT_CRITICAL();
  646. esp_err_t ret;
  647. if (hcd_pipe_get_state(dev_obj->constant.default_pipe) != HCD_PIPE_STATE_ACTIVE) {
  648. ret = ESP_ERR_INVALID_STATE;
  649. goto hcd_err;
  650. }
  651. ret = hcd_urb_enqueue(dev_obj->constant.default_pipe, urb);
  652. if (ret != ESP_OK) {
  653. goto hcd_err;
  654. }
  655. ret = ESP_OK;
  656. return ret;
  657. hcd_err:
  658. USBH_ENTER_CRITICAL();
  659. dev_obj->dynamic.num_ctrl_xfers_inflight--;
  660. USBH_EXIT_CRITICAL();
  661. return ret;
  662. }
  663. // ----------------------------------------------- Interface Functions -------------------------------------------------
  664. esp_err_t usbh_ep_alloc(usb_device_handle_t dev_hdl, usbh_ep_config_t *ep_config, hcd_pipe_handle_t *pipe_hdl_ret)
  665. {
  666. USBH_CHECK(dev_hdl != NULL && ep_config != NULL && pipe_hdl_ret != NULL, ESP_ERR_INVALID_ARG);
  667. device_t *dev_obj = (device_t *)dev_hdl;
  668. USBH_ENTER_CRITICAL();
  669. USBH_CHECK_FROM_CRIT(dev_obj->dynamic.state == USB_DEVICE_STATE_CONFIGURED, ESP_ERR_INVALID_STATE);
  670. dev_obj->dynamic.ref_count++; //Increase the ref_count to keep the device alive while allocating the endpoint
  671. USBH_EXIT_CRITICAL();
  672. esp_err_t ret;
  673. //Allocate HCD pipe
  674. hcd_pipe_config_t pipe_config = {
  675. .callback = ep_config->pipe_cb,
  676. .callback_arg = ep_config->pipe_cb_arg,
  677. .context = ep_config->context,
  678. .ep_desc = ep_config->ep_desc,
  679. .dev_speed = dev_obj->constant.speed,
  680. .dev_addr = dev_obj->constant.address,
  681. };
  682. hcd_pipe_handle_t pipe_hdl;
  683. ret = hcd_pipe_alloc(dev_obj->constant.port_hdl, &pipe_config, &pipe_hdl);
  684. if (ret != ESP_OK) {
  685. goto pipe_alloc_err;
  686. }
  687. bool is_in = ep_config->ep_desc->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK;
  688. uint8_t addr = ep_config->ep_desc->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK;
  689. bool assigned = false;
  690. //We need to take the mux_lock to access mux_protected members
  691. xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
  692. if (is_in && dev_obj->mux_protected.ep_in[addr - 1] == NULL) { //Is an IN EP
  693. dev_obj->mux_protected.ep_in[addr - 1] = pipe_hdl;
  694. assigned = true;
  695. } else {
  696. dev_obj->mux_protected.ep_out[addr - 1] = pipe_hdl;
  697. assigned = true;
  698. }
  699. //Restore ref_count
  700. USBH_ENTER_CRITICAL();
  701. dev_obj->dynamic.ref_count--;
  702. USBH_EXIT_CRITICAL();
  703. xSemaphoreGive(p_usbh_obj->constant.mux_lock);
  704. if (!assigned) {
  705. ret = ESP_ERR_INVALID_STATE;
  706. goto assign_err;
  707. }
  708. //Write back output
  709. *pipe_hdl_ret = pipe_hdl;
  710. ret = ESP_OK;
  711. return ret;
  712. assign_err:
  713. ESP_ERROR_CHECK(hcd_pipe_free(pipe_hdl));
  714. pipe_alloc_err:
  715. return ret;
  716. }
  717. esp_err_t usbh_ep_free(usb_device_handle_t dev_hdl, uint8_t bEndpointAddress)
  718. {
  719. USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG);
  720. device_t *dev_obj = (device_t *)dev_hdl;
  721. esp_err_t ret;
  722. bool is_in = bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK;
  723. uint8_t addr = bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK;
  724. hcd_pipe_handle_t pipe_hdl;
  725. //We need to take the mux_lock to access mux_protected members
  726. xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
  727. //Check if the EP was previously allocated. If so, set it to NULL
  728. if (is_in) {
  729. if (dev_obj->mux_protected.ep_in[addr - 1] != NULL) {
  730. pipe_hdl = dev_obj->mux_protected.ep_in[addr - 1];
  731. dev_obj->mux_protected.ep_in[addr - 1] = NULL;
  732. ret = ESP_OK;
  733. } else {
  734. ret = ESP_ERR_INVALID_STATE;
  735. }
  736. } else {
  737. //EP must have been previously allocated
  738. if (dev_obj->mux_protected.ep_out[addr - 1] != NULL) {
  739. pipe_hdl = dev_obj->mux_protected.ep_out[addr - 1];
  740. dev_obj->mux_protected.ep_out[addr - 1] = NULL;
  741. ret = ESP_OK;
  742. } else {
  743. ret = ESP_ERR_INVALID_STATE;
  744. }
  745. }
  746. xSemaphoreGive(p_usbh_obj->constant.mux_lock);
  747. if (ret == ESP_OK) {
  748. ESP_ERROR_CHECK(hcd_pipe_free(pipe_hdl));
  749. }
  750. return ret;
  751. }
  752. esp_err_t usbh_ep_get_context(usb_device_handle_t dev_hdl, uint8_t bEndpointAddress, void **context_ret)
  753. {
  754. bool is_in = bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK;
  755. uint8_t addr = bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK;
  756. USBH_CHECK(dev_hdl != NULL &&
  757. addr >= EP_NUM_MIN && //Control endpoints are owned by the USBH
  758. addr <= EP_NUM_MAX &&
  759. context_ret != NULL,
  760. ESP_ERR_INVALID_ARG);
  761. esp_err_t ret;
  762. device_t *dev_obj = (device_t *)dev_hdl;
  763. hcd_pipe_handle_t pipe_hdl;
  764. //We need to take the mux_lock to access mux_protected members
  765. xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
  766. //Get the endpoint's corresponding pipe
  767. if (is_in) {
  768. pipe_hdl = dev_obj->mux_protected.ep_in[addr - 1];
  769. } else {
  770. pipe_hdl = dev_obj->mux_protected.ep_out[addr - 1];
  771. }
  772. //Check if the EP was allocated to begin with
  773. if (pipe_hdl == NULL) {
  774. ret = ESP_ERR_NOT_FOUND;
  775. goto exit;
  776. }
  777. //Return the context of the pipe
  778. void *context = hcd_pipe_get_context(pipe_hdl);
  779. *context_ret = context;
  780. ret = ESP_OK;
  781. exit:
  782. xSemaphoreGive(p_usbh_obj->constant.mux_lock);
  783. return ret;
  784. }
  785. // -------------------------------------------------- Hub Functions ----------------------------------------------------
  786. // ------------------- Device Related ----------------------
  787. esp_err_t usbh_hub_is_installed(usbh_hub_cb_t hub_callback, void *callback_arg)
  788. {
  789. USBH_CHECK(hub_callback != NULL, ESP_ERR_INVALID_ARG);
  790. USBH_ENTER_CRITICAL();
  791. //Check that USBH is already installed
  792. USBH_CHECK_FROM_CRIT(p_usbh_obj != NULL, ESP_ERR_INVALID_STATE);
  793. //Check that Hub has not be installed yet
  794. USBH_CHECK_FROM_CRIT(p_usbh_obj->constant.hub_cb == NULL, ESP_ERR_INVALID_STATE);
  795. p_usbh_obj->constant.hub_cb = hub_callback;
  796. p_usbh_obj->constant.hub_cb_arg = callback_arg;
  797. USBH_EXIT_CRITICAL();
  798. return ESP_OK;
  799. }
  800. esp_err_t usbh_hub_add_dev(hcd_port_handle_t port_hdl, usb_speed_t dev_speed, usb_device_handle_t *new_dev_hdl, hcd_pipe_handle_t *default_pipe_hdl)
  801. {
  802. //Note: Parent device handle can be NULL if it's connected to the root hub
  803. USBH_CHECK(new_dev_hdl != NULL, ESP_ERR_INVALID_ARG);
  804. esp_err_t ret;
  805. device_t *dev_obj;
  806. ret = device_alloc(port_hdl, dev_speed, &dev_obj);
  807. if (ret != ESP_OK) {
  808. return ret;
  809. }
  810. //Write-back device handle
  811. *new_dev_hdl = (usb_device_handle_t)dev_obj;
  812. *default_pipe_hdl = dev_obj->constant.default_pipe;
  813. ret = ESP_OK;
  814. return ret;
  815. }
  816. esp_err_t usbh_hub_mark_dev_gone(usb_device_handle_t dev_hdl)
  817. {
  818. USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG);
  819. device_t *dev_obj = (device_t *)dev_hdl;
  820. USBH_ENTER_CRITICAL();
  821. dev_obj->dynamic.flags.is_gone = 1;
  822. bool call_notif_cb;
  823. //Check if the device can be freed now
  824. if (dev_obj->dynamic.ref_count == 0) {
  825. dev_obj->dynamic.flags.waiting_free = 1;
  826. //Device is already waiting free so none of it's pipes will be in use. Can free immediately.
  827. call_notif_cb = _dev_set_actions(dev_obj, DEV_FLAG_ACTION_FREE);
  828. } else {
  829. call_notif_cb = _dev_set_actions(dev_obj, DEV_FLAG_ACTION_PIPE_HALT_AND_FLUSH |
  830. DEV_FLAG_ACTION_DEFAULT_PIPE_FLUSH |
  831. DEV_FLAG_ACTION_DEFAULT_PIPE_DEQUEUE |
  832. DEV_FLAG_ACTION_SEND_GONE_EVENT);
  833. }
  834. USBH_EXIT_CRITICAL();
  835. if (call_notif_cb) {
  836. p_usbh_obj->constant.notif_cb(USB_NOTIF_SOURCE_USBH, false, p_usbh_obj->constant.notif_cb_arg);
  837. }
  838. return ESP_OK;
  839. }
  840. esp_err_t usbh_hub_dev_port_disabled(usb_device_handle_t dev_hdl)
  841. {
  842. USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG);
  843. device_t *dev_obj = (device_t *)dev_hdl;
  844. USBH_ENTER_CRITICAL();
  845. assert(dev_obj->dynamic.ref_count == 0); //At this stage, the device should have been closed by all users
  846. dev_obj->dynamic.flags.waiting_free = 1;
  847. bool call_notif_cb = _dev_set_actions(dev_obj, DEV_FLAG_ACTION_FREE);
  848. USBH_EXIT_CRITICAL();
  849. if (call_notif_cb) {
  850. ESP_LOGD(USBH_TAG, "Notif free");
  851. p_usbh_obj->constant.notif_cb(USB_NOTIF_SOURCE_USBH, false, p_usbh_obj->constant.notif_cb_arg);
  852. }
  853. return ESP_OK;
  854. }
  855. // ----------------- Enumeration Related -------------------
  856. esp_err_t usbh_hub_enum_fill_dev_addr(usb_device_handle_t dev_hdl, uint8_t dev_addr)
  857. {
  858. USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG);
  859. device_t *dev_obj = (device_t *)dev_hdl;
  860. USBH_ENTER_CRITICAL();
  861. USBH_CHECK_FROM_CRIT(dev_obj->constant.enum_todo_flags & DEV_ENUM_TODO_FLAG_DEV_ADDR, ESP_ERR_INVALID_STATE);
  862. dev_obj->dynamic.state = USB_DEVICE_STATE_ADDRESS;
  863. USBH_EXIT_CRITICAL();
  864. //We can modify the info members outside the critical section
  865. dev_obj->constant.enum_todo_flags &= ~DEV_ENUM_TODO_FLAG_DEV_ADDR;
  866. dev_obj->constant.address = dev_addr;
  867. return ESP_OK;
  868. }
  869. esp_err_t usbh_hub_enum_fill_dev_desc(usb_device_handle_t dev_hdl, const usb_device_desc_t *device_desc)
  870. {
  871. USBH_CHECK(dev_hdl != NULL && device_desc != NULL, ESP_ERR_INVALID_ARG);
  872. device_t *dev_obj = (device_t *)dev_hdl;
  873. //We can modify the info members outside the critical section
  874. USBH_CHECK(dev_obj->constant.enum_todo_flags & DEV_ENUM_TODO_FLAG_DEV_DESC, ESP_ERR_INVALID_STATE);
  875. dev_obj->constant.enum_todo_flags &= ~DEV_ENUM_TODO_FLAG_DEV_DESC;
  876. memcpy((usb_device_desc_t *)dev_obj->constant.desc, device_desc, sizeof(usb_device_desc_t));
  877. return ESP_OK;
  878. }
  879. esp_err_t usbh_hub_enum_fill_config_desc(usb_device_handle_t dev_hdl, const usb_config_desc_t *config_desc_full)
  880. {
  881. USBH_CHECK(dev_hdl != NULL && config_desc_full != NULL, ESP_ERR_INVALID_ARG);
  882. device_t *dev_obj = (device_t *)dev_hdl;
  883. esp_err_t ret;
  884. //Allocate memory to store the configuration descriptor
  885. usb_config_desc_t *config_desc = heap_caps_malloc(config_desc_full->wTotalLength, MALLOC_CAP_DEFAULT); //Buffer to copy over full configuration descriptor (wTotalLength)
  886. if (config_desc == NULL) {
  887. ret = ESP_ERR_NO_MEM;
  888. goto err;
  889. }
  890. //Copy the configuration descriptor
  891. memcpy(config_desc, config_desc_full, config_desc_full->wTotalLength);
  892. //Assign the config object to the device object
  893. if (!(dev_obj->constant.enum_todo_flags & DEV_ENUM_TODO_FLAG_CONFIG_DESC)) {
  894. ret = ESP_ERR_INVALID_STATE;
  895. goto assign_err;
  896. }
  897. //We need to take the mux_lock to access mux_protected members
  898. xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
  899. assert(dev_obj->mux_protected.config_desc == NULL);
  900. dev_obj->mux_protected.config_desc = config_desc;
  901. xSemaphoreGive(p_usbh_obj->constant.mux_lock);
  902. //We can modify the info members outside the critical section
  903. dev_obj->constant.enum_todo_flags &= ~DEV_ENUM_TODO_FLAG_CONFIG_DESC;
  904. ret = ESP_OK;
  905. return ret;
  906. assign_err:
  907. heap_caps_free(config_desc);
  908. err:
  909. return ret;
  910. }
  911. esp_err_t usbh_hub_enum_done(usb_device_handle_t dev_hdl)
  912. {
  913. USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG);
  914. device_t *dev_obj = (device_t *)dev_hdl;
  915. USBH_CHECK(dev_obj->constant.enum_todo_flags == 0, ESP_ERR_INVALID_STATE); //All enumeration stages to be done
  916. //We need to take the mux_lock to access mux_protected members
  917. xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
  918. USBH_ENTER_CRITICAL();
  919. dev_obj->dynamic.state = USB_DEVICE_STATE_CONFIGURED;
  920. //Add the device to list of devices, then trigger a device event
  921. TAILQ_INSERT_TAIL(&p_usbh_obj->dynamic.devs_idle_tailq, dev_obj, dynamic.tailq_entry); //Add it to the idle device list first
  922. bool call_notif_cb = _dev_set_actions(dev_obj, DEV_FLAG_ACTION_SEND_NEW);
  923. USBH_EXIT_CRITICAL();
  924. p_usbh_obj->mux_protected.num_device++;
  925. xSemaphoreGive(p_usbh_obj->constant.mux_lock);
  926. //Update the default pipe callback
  927. ESP_ERROR_CHECK(hcd_pipe_update_callback(dev_obj->constant.default_pipe, default_pipe_callback, (void *)dev_obj));
  928. //Call the notification callback
  929. if (call_notif_cb) {
  930. p_usbh_obj->constant.notif_cb(USB_NOTIF_SOURCE_USBH, false, p_usbh_obj->constant.notif_cb_arg);
  931. }
  932. return ESP_OK;
  933. }
  934. esp_err_t usbh_hub_enum_failed(usb_device_handle_t dev_hdl)
  935. {
  936. USBH_CHECK(dev_hdl != NULL, ESP_ERR_INVALID_ARG);
  937. device_t *dev_obj = (device_t *)dev_hdl;
  938. //We need to take the mux_lock to access mux_protected members
  939. xSemaphoreTake(p_usbh_obj->constant.mux_lock, portMAX_DELAY);
  940. usb_config_desc_t *config_desc = dev_obj->mux_protected.config_desc;
  941. dev_obj->mux_protected.config_desc = NULL;
  942. xSemaphoreGive(p_usbh_obj->constant.mux_lock);
  943. if (config_desc) {
  944. heap_caps_free(config_desc);
  945. }
  946. device_free(dev_obj);
  947. return ESP_OK;
  948. }