1 /*
2 * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 Warning: The USB Host Library API is still a beta version and may be subject to change
9 */
10
11 #include <stdlib.h>
12 #include <stdint.h>
13 #include "freertos/FreeRTOS.h"
14 #include "freertos/task.h"
15 #include "freertos/queue.h"
16 #include "freertos/semphr.h"
17 #include "esp_err.h"
18 #include "esp_log.h"
19 #include "esp_heap_caps.h"
20 #include "hub.h"
21 #include "usbh.h"
22 #include "esp_private/usb_phy.h"
23 #include "usb/usb_host.h"
24
25 static portMUX_TYPE host_lock = portMUX_INITIALIZER_UNLOCKED;
26
27 #define HOST_ENTER_CRITICAL_ISR() portENTER_CRITICAL_ISR(&host_lock)
28 #define HOST_EXIT_CRITICAL_ISR() portEXIT_CRITICAL_ISR(&host_lock)
29 #define HOST_ENTER_CRITICAL() portENTER_CRITICAL(&host_lock)
30 #define HOST_EXIT_CRITICAL() portEXIT_CRITICAL(&host_lock)
31 #define HOST_ENTER_CRITICAL_SAFE() portENTER_CRITICAL_SAFE(&host_lock)
32 #define HOST_EXIT_CRITICAL_SAFE() portEXIT_CRITICAL_SAFE(&host_lock)
33
34 #define HOST_CHECK(cond, ret_val) ({ \
35 if (!(cond)) { \
36 return (ret_val); \
37 } \
38 })
39 #define HOST_CHECK_FROM_CRIT(cond, ret_val) ({ \
40 if (!(cond)) { \
41 HOST_EXIT_CRITICAL(); \
42 return ret_val; \
43 } \
44 })
45
46 #define PROCESS_PENDING_FLAG_USBH 0x01
47 #define PROCESS_PENDING_FLAG_HUB 0x02
48 #define PROCESS_PENDING_FLAG_EVENT 0x04
49
50 typedef struct endpoint_s endpoint_t;
51 typedef struct interface_s interface_t;
52 typedef struct client_s client_t;
53
54 struct endpoint_s {
55 //Dynamic members require a critical section
56 struct {
57 TAILQ_ENTRY(endpoint_s) tailq_entry;
58 union {
59 struct {
60 uint32_t pending: 1;
61 uint32_t reserved31:31;
62 };
63 } flags;
64 uint32_t num_urb_inflight;
65 hcd_pipe_event_t last_event;
66 } dynamic;
67 //Constant members do no change after claiming the interface thus do not require a critical section
68 struct {
69 hcd_pipe_handle_t pipe_hdl;
70 const usb_ep_desc_t *ep_desc;
71 interface_t *intf_obj;
72 } constant;
73 };
74
75 struct interface_s {
76 //Dynamic members require a critical section
77 struct {
78 TAILQ_ENTRY(interface_s) tailq_entry;
79 } mux_protected;
80 //Constant members do no change after claiming the interface thus do not require a critical section
81 struct {
82 const usb_intf_desc_t *intf_desc;
83 usb_device_handle_t dev_hdl;
84 client_t *client_obj;
85 endpoint_t *endpoints[0];
86 } constant;
87 };
88
89 struct client_s {
90 //Dynamic members require a critical section
91 struct {
92 TAILQ_ENTRY(client_s) tailq_entry;
93 TAILQ_HEAD(tailhead_pending_ep, endpoint_s) pending_ep_tailq;
94 TAILQ_HEAD(tailhead_idle_ep, endpoint_s) idle_ep_tailq;
95 TAILQ_HEAD(tailhead_done_ctrl_xfers, urb_s) done_ctrl_xfer_tailq;
96 union {
97 struct {
98 uint32_t events_pending: 1;
99 uint32_t handling_events: 1;
100 uint32_t blocked: 1;
101 uint32_t taking_mux: 1;
102 uint32_t reserved4: 4;
103 uint32_t num_intf_claimed: 8;
104 uint32_t reserved16: 16;
105 };
106 uint32_t val;
107 } flags;
108 uint32_t num_done_ctrl_xfer;
109 uint32_t opened_dev_addr_map;
110 } dynamic;
111 //Mux protected members must be protected by host library the mux_lock when accessed
112 struct {
113 TAILQ_HEAD(tailhead_interfaces, interface_s) interface_tailq;
114 } mux_protected;
115 //Constant members do no change after registration thus do not require a critical section
116 struct {
117 SemaphoreHandle_t event_sem;
118 usb_host_client_event_cb_t event_callback;
119 void *callback_arg;
120 QueueHandle_t event_msg_queue;
121 } constant;
122 };
123
124 typedef struct {
125 //Dynamic members require a critical section
126 struct {
127 //Access to these should be done in a critical section
128 uint32_t process_pending_flags;
129 uint32_t lib_event_flags;
130 union {
131 struct {
132 uint32_t process_pending: 1;
133 uint32_t handling_events: 1;
134 uint32_t blocked: 1;
135 uint32_t reserved5: 5;
136 uint32_t num_clients: 8;
137 uint32_t reserved16: 16;
138 };
139 uint32_t val;
140 } flags;
141 } dynamic;
142 //Mux protected members must be protected by host library the mux_lock when accessed
143 struct {
144 TAILQ_HEAD(tailhead_clients, client_s) client_tailq; //List of all clients registered
145 } mux_protected;
146 //Constant members do no change after installation thus do not require a critical section
147 struct {
148 SemaphoreHandle_t event_sem;
149 SemaphoreHandle_t mux_lock;
150 usb_phy_handle_t phy_handle; //Will be NULL if host library is installed with skip_phy_setup
151 } constant;
152 } host_lib_t;
153
154 static host_lib_t *p_host_lib_obj = NULL;
155
156 const char *USB_HOST_TAG = "USB HOST";
157
158 // ----------------------------------------------------- Helpers -------------------------------------------------------
159
_record_client_opened_device(client_t * client_obj,uint8_t dev_addr)160 static inline void _record_client_opened_device(client_t *client_obj, uint8_t dev_addr)
161 {
162 assert(dev_addr != 0);
163 client_obj->dynamic.opened_dev_addr_map |= (1 << (dev_addr - 1));
164 }
165
_clear_client_opened_device(client_t * client_obj,uint8_t dev_addr)166 static inline void _clear_client_opened_device(client_t *client_obj, uint8_t dev_addr)
167 {
168 assert(dev_addr != 0);
169 client_obj->dynamic.opened_dev_addr_map &= ~(1 << (dev_addr - 1));
170 }
171
_check_client_opened_device(client_t * client_obj,uint8_t dev_addr)172 static inline bool _check_client_opened_device(client_t *client_obj, uint8_t dev_addr)
173 {
174 assert(dev_addr != 0);
175 return (client_obj->dynamic.opened_dev_addr_map & (1 << (dev_addr - 1)));
176 }
177
_unblock_client(client_t * client_obj,bool in_isr)178 static bool _unblock_client(client_t *client_obj, bool in_isr)
179 {
180 bool send_sem;
181 if (!client_obj->dynamic.flags.events_pending && !client_obj->dynamic.flags.handling_events) {
182 client_obj->dynamic.flags.events_pending = 1;
183 send_sem = true;
184 } else {
185 send_sem = false;
186 }
187
188 HOST_EXIT_CRITICAL_SAFE();
189 bool yield = false;
190 if (send_sem) {
191 if (in_isr) {
192 BaseType_t xTaskWoken = pdFALSE;
193 xSemaphoreGiveFromISR(client_obj->constant.event_sem, &xTaskWoken);
194 yield = (xTaskWoken == pdTRUE);
195 } else {
196 xSemaphoreGive(client_obj->constant.event_sem);
197 }
198 }
199 HOST_ENTER_CRITICAL_SAFE();
200
201 return yield;
202 }
203
_unblock_lib(bool in_isr)204 static bool _unblock_lib(bool in_isr)
205 {
206 bool send_sem;
207 if (!p_host_lib_obj->dynamic.flags.process_pending && !p_host_lib_obj->dynamic.flags.handling_events) {
208 p_host_lib_obj->dynamic.flags.process_pending = 1;
209 send_sem = true;
210 } else {
211 send_sem = false;
212 }
213
214 HOST_EXIT_CRITICAL_SAFE();
215 bool yield = false;
216 if (send_sem) {
217 if (in_isr) {
218 BaseType_t xTaskWoken = pdFALSE;
219 xSemaphoreGiveFromISR(p_host_lib_obj->constant.event_sem, &xTaskWoken);
220 yield = (xTaskWoken == pdTRUE);
221 } else {
222 xSemaphoreGive(p_host_lib_obj->constant.event_sem);
223 }
224 }
225 HOST_ENTER_CRITICAL_SAFE();
226
227 return yield;
228 }
229
send_event_msg_to_clients(const usb_host_client_event_msg_t * event_msg,bool send_to_all,uint8_t opened_dev_addr)230 static void send_event_msg_to_clients(const usb_host_client_event_msg_t *event_msg, bool send_to_all, uint8_t opened_dev_addr)
231 {
232 //Lock client list
233 xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY);
234 //Send event message to relevant or all clients
235 client_t *client_obj;
236 TAILQ_FOREACH(client_obj, &p_host_lib_obj->mux_protected.client_tailq, dynamic.tailq_entry) {
237 if (!send_to_all) {
238 //Check if client opened the device
239 HOST_ENTER_CRITICAL();
240 bool send = _check_client_opened_device(client_obj, opened_dev_addr);
241 HOST_EXIT_CRITICAL();
242 if (!send) {
243 continue;
244 }
245 }
246 //Send the event message
247 if (xQueueSend(client_obj->constant.event_msg_queue, event_msg, 0) == pdTRUE) {
248 HOST_ENTER_CRITICAL();
249 _unblock_client(client_obj, false);
250 HOST_EXIT_CRITICAL();
251 } else {
252 ESP_LOGE(USB_HOST_TAG, "Client event message queue full");
253 }
254 }
255 //Unlock client list
256 xSemaphoreGive(p_host_lib_obj->constant.mux_lock);
257 }
258
259 // ---------------------------------------------------- Callbacks ------------------------------------------------------
260
261 // ------------------- Library Related ---------------------
262
notif_callback(usb_notif_source_t source,bool in_isr,void * arg)263 static bool notif_callback(usb_notif_source_t source, bool in_isr, void *arg)
264 {
265 HOST_ENTER_CRITICAL_SAFE();
266 //Store notification source
267 switch (source) {
268 case USB_NOTIF_SOURCE_USBH:
269 p_host_lib_obj->dynamic.process_pending_flags |= PROCESS_PENDING_FLAG_USBH;
270 break;
271 case USB_NOTIF_SOURCE_HUB:
272 p_host_lib_obj->dynamic.process_pending_flags |= PROCESS_PENDING_FLAG_HUB;
273 break;
274 }
275 bool yield = _unblock_lib(in_isr);
276 HOST_EXIT_CRITICAL_SAFE();
277
278 return yield;
279 }
280
ctrl_xfer_callback(usb_device_handle_t dev_hdl,urb_t * urb,void * arg)281 static void ctrl_xfer_callback(usb_device_handle_t dev_hdl, urb_t *urb, void *arg)
282 {
283 assert(urb->usb_host_client != NULL);
284 //Redistribute done control transfer to the clients that submitted them
285 client_t *client_obj = (client_t *)urb->usb_host_client;
286
287 HOST_ENTER_CRITICAL();
288 TAILQ_INSERT_TAIL(&client_obj->dynamic.done_ctrl_xfer_tailq, urb, tailq_entry);
289 client_obj->dynamic.num_done_ctrl_xfer++;
290 _unblock_client(client_obj, false);
291 HOST_EXIT_CRITICAL();
292 }
293
dev_event_callback(usb_device_handle_t dev_hdl,usbh_event_t usbh_event,void * arg)294 static void dev_event_callback(usb_device_handle_t dev_hdl, usbh_event_t usbh_event, void *arg)
295 {
296 //Check usbh_event. The data type of event_arg depends on the type of event
297 switch (usbh_event) {
298 case USBH_EVENT_DEV_NEW: {
299 //Prepare a NEW_DEV client event message, the send it to all clients
300 uint8_t dev_addr;
301 ESP_ERROR_CHECK(usbh_dev_get_addr(dev_hdl, &dev_addr));
302 usb_host_client_event_msg_t event_msg = {
303 .event = USB_HOST_CLIENT_EVENT_NEW_DEV,
304 .new_dev.address = dev_addr,
305 };
306 send_event_msg_to_clients(&event_msg, true, 0);
307 break;
308 }
309 case USBH_EVENT_DEV_GONE: {
310 //Prepare event msg, send only to clients that have opened the device
311 uint8_t dev_addr;
312 ESP_ERROR_CHECK(usbh_dev_get_addr(dev_hdl, &dev_addr));
313 usb_host_client_event_msg_t event_msg = {
314 .event = USB_HOST_CLIENT_EVENT_DEV_GONE,
315 .dev_gone.dev_hdl = dev_hdl,
316 };
317 send_event_msg_to_clients(&event_msg, false, dev_addr);
318 break;
319 }
320 case USBH_EVENT_DEV_ALL_FREE: {
321 //Notify the lib handler that all devices are free
322 HOST_ENTER_CRITICAL();
323 p_host_lib_obj->dynamic.lib_event_flags |= USB_HOST_LIB_EVENT_FLAGS_ALL_FREE;
324 _unblock_lib(false);
325 HOST_EXIT_CRITICAL();
326 break;
327 }
328 default:
329 abort(); //Should never occur
330 break;
331 }
332 }
333
334 // ------------------- Client Related ----------------------
335
pipe_callback(hcd_pipe_handle_t pipe_hdl,hcd_pipe_event_t pipe_event,void * user_arg,bool in_isr)336 static bool pipe_callback(hcd_pipe_handle_t pipe_hdl, hcd_pipe_event_t pipe_event, void *user_arg, bool in_isr)
337 {
338 endpoint_t *ep_obj = (endpoint_t *)user_arg;
339 client_t *client_obj = (client_t *)ep_obj->constant.intf_obj->constant.client_obj;
340
341 HOST_ENTER_CRITICAL_SAFE();
342 //Store the event to be handled later. Note that we allow overwriting of events because more severe will halt the pipe prevent any further events.
343 ep_obj->dynamic.last_event = pipe_event;
344 //Add the EP to the client's pending list if it's not in the list already
345 if (!ep_obj->dynamic.flags.pending) {
346 ep_obj->dynamic.flags.pending = 1;
347 TAILQ_REMOVE(&client_obj->dynamic.idle_ep_tailq, ep_obj, dynamic.tailq_entry);
348 TAILQ_INSERT_TAIL(&client_obj->dynamic.pending_ep_tailq, ep_obj, dynamic.tailq_entry);
349 }
350 bool yield = _unblock_client(client_obj, in_isr);
351 HOST_EXIT_CRITICAL_SAFE();
352
353 return yield;
354 }
355
356 // ------------------------------------------------ Library Functions --------------------------------------------------
357
358 // ----------------------- Public --------------------------
359
usb_host_install(const usb_host_config_t * config)360 esp_err_t usb_host_install(const usb_host_config_t *config)
361 {
362 HOST_CHECK(config != NULL, ESP_ERR_INVALID_ARG);
363 HOST_ENTER_CRITICAL();
364 HOST_CHECK_FROM_CRIT(p_host_lib_obj == NULL, ESP_ERR_INVALID_STATE);
365 HOST_EXIT_CRITICAL();
366
367 esp_err_t ret;
368 host_lib_t *host_lib_obj = heap_caps_calloc(1, sizeof(host_lib_t), MALLOC_CAP_DEFAULT);
369 SemaphoreHandle_t event_sem = xSemaphoreCreateBinary();
370 SemaphoreHandle_t mux_lock = xSemaphoreCreateMutex();
371 if (host_lib_obj == NULL || event_sem == NULL || mux_lock == NULL) {
372 ret = ESP_ERR_NO_MEM;
373 goto alloc_err;
374 }
375 //Initialize host library object
376 TAILQ_INIT(&host_lib_obj->mux_protected.client_tailq);
377 host_lib_obj->constant.event_sem = event_sem;
378 host_lib_obj->constant.mux_lock = mux_lock;
379 //Setup the USB PHY if necessary (USB PHY driver will also enable the underlying Host Controller)
380 if (!config->skip_phy_setup) {
381 //Host Library defaults to internal PHY
382 usb_phy_config_t phy_config = {
383 .controller = USB_PHY_CTRL_OTG,
384 .target = USB_PHY_TARGET_INT,
385 .otg_mode = USB_OTG_MODE_HOST,
386 .otg_speed = USB_PHY_SPEED_UNDEFINED, //In Host mode, the speed is determined by the connected device
387 .gpio_conf = NULL,
388 };
389 ret = usb_new_phy(&phy_config, &host_lib_obj->constant.phy_handle);
390 if (ret != ESP_OK) {
391 goto phy_err;
392 }
393 }
394 //Install USBH
395 usbh_config_t usbh_config = {
396 .notif_cb = notif_callback,
397 .notif_cb_arg = NULL,
398 .ctrl_xfer_cb = ctrl_xfer_callback,
399 .ctrl_xfer_cb_arg = NULL,
400 .event_cb = dev_event_callback,
401 .event_cb_arg = NULL,
402 .hcd_config = {
403 .intr_flags = config->intr_flags,
404 },
405 };
406 ret = usbh_install(&usbh_config);
407 if (ret != ESP_OK) {
408 goto usbh_err;
409 }
410 //Install Hub
411 hub_config_t hub_config = {
412 .notif_cb = notif_callback,
413 .notif_cb_arg = NULL,
414 };
415 ret = hub_install(&hub_config);
416 if (ret != ESP_OK) {
417 goto hub_err;
418 }
419
420 //Assign host library object
421 HOST_ENTER_CRITICAL();
422 if (p_host_lib_obj != NULL) {
423 HOST_EXIT_CRITICAL();
424 ret = ESP_ERR_INVALID_STATE;
425 goto assign_err;
426 }
427 p_host_lib_obj = host_lib_obj;
428 HOST_EXIT_CRITICAL();
429
430 //Start the root hub
431 ESP_ERROR_CHECK(hub_root_start());
432 ret = ESP_OK;
433 return ret;
434
435 assign_err:
436 ESP_ERROR_CHECK(hub_uninstall());
437 hub_err:
438 ESP_ERROR_CHECK(usbh_uninstall());
439 usbh_err:
440 if (p_host_lib_obj->constant.phy_handle) {
441 ESP_ERROR_CHECK(usb_del_phy(p_host_lib_obj->constant.phy_handle));
442 }
443 phy_err:
444 alloc_err:
445 if (mux_lock) {
446 vSemaphoreDelete(mux_lock);
447 }
448 if (event_sem) {
449 vSemaphoreDelete(event_sem);
450 }
451 heap_caps_free(host_lib_obj);
452 return ret;
453 }
454
usb_host_uninstall(void)455 esp_err_t usb_host_uninstall(void)
456 {
457 //All devices must have been freed at this point
458 HOST_ENTER_CRITICAL();
459 HOST_CHECK_FROM_CRIT(p_host_lib_obj != NULL, ESP_ERR_INVALID_STATE);
460 HOST_CHECK_FROM_CRIT(p_host_lib_obj->dynamic.process_pending_flags == 0 &&
461 p_host_lib_obj->dynamic.lib_event_flags == 0 &&
462 p_host_lib_obj->dynamic.flags.val == 0,
463 ESP_ERR_INVALID_STATE);
464 HOST_EXIT_CRITICAL();
465
466 //Stop the root hub
467 ESP_ERROR_CHECK(hub_root_stop());
468 //Uninstall Hub and USBH
469 ESP_ERROR_CHECK(hub_uninstall());
470 ESP_ERROR_CHECK(usbh_uninstall());
471
472 HOST_ENTER_CRITICAL();
473 host_lib_t *host_lib_obj = p_host_lib_obj;
474 p_host_lib_obj = NULL;
475 HOST_EXIT_CRITICAL();
476
477 //If the USB PHY was setup, then delete it
478 if (host_lib_obj->constant.phy_handle) {
479 ESP_ERROR_CHECK(usb_del_phy(host_lib_obj->constant.phy_handle));
480 }
481 //Free memory objects
482 vSemaphoreDelete(host_lib_obj->constant.mux_lock);
483 vSemaphoreDelete(host_lib_obj->constant.event_sem);
484 heap_caps_free(host_lib_obj);
485 return ESP_OK;
486 }
487
usb_host_lib_handle_events(TickType_t timeout_ticks,uint32_t * event_flags_ret)488 esp_err_t usb_host_lib_handle_events(TickType_t timeout_ticks, uint32_t *event_flags_ret)
489 {
490 esp_err_t ret;
491 uint32_t event_flags = 0;
492
493 HOST_ENTER_CRITICAL();
494 if (!p_host_lib_obj->dynamic.flags.process_pending) {
495 //There is currently processing that needs to be done. Wait for some processing
496 HOST_EXIT_CRITICAL();
497 BaseType_t sem_ret = xSemaphoreTake(p_host_lib_obj->constant.event_sem, timeout_ticks);
498 if (sem_ret == pdFALSE) {
499 ret = ESP_ERR_TIMEOUT;
500 goto exit;
501 }
502 HOST_ENTER_CRITICAL();
503 }
504 //Read and clear process pending flags
505 uint32_t process_pending_flags = p_host_lib_obj->dynamic.process_pending_flags;
506 p_host_lib_obj->dynamic.process_pending_flags = 0;
507 p_host_lib_obj->dynamic.flags.handling_events = 1;
508 while (process_pending_flags) {
509 HOST_EXIT_CRITICAL();
510 if (process_pending_flags & PROCESS_PENDING_FLAG_USBH) {
511 ESP_ERROR_CHECK(usbh_process());
512 }
513 if (process_pending_flags & PROCESS_PENDING_FLAG_HUB) {
514 ESP_ERROR_CHECK(hub_process());
515 }
516 HOST_ENTER_CRITICAL();
517 //Read and clear process pending flags again, and loop back if there is more to process
518 process_pending_flags = p_host_lib_obj->dynamic.process_pending_flags;
519 p_host_lib_obj->dynamic.process_pending_flags = 0;
520 }
521 p_host_lib_obj->dynamic.flags.process_pending = 0;
522 p_host_lib_obj->dynamic.flags.handling_events = 0;
523 event_flags = p_host_lib_obj->dynamic.lib_event_flags;
524 p_host_lib_obj->dynamic.lib_event_flags = 0;
525 HOST_EXIT_CRITICAL();
526
527 ret = ESP_OK;
528 exit:
529 if (event_flags_ret != NULL) {
530 *event_flags_ret = event_flags;
531 }
532 return ret;
533 }
534
usb_host_lib_unblock(void)535 esp_err_t usb_host_lib_unblock(void)
536 {
537 //All devices must have been freed at this point
538 HOST_ENTER_CRITICAL();
539 HOST_CHECK_FROM_CRIT(p_host_lib_obj != NULL, ESP_ERR_INVALID_STATE);
540 _unblock_lib(false);
541 HOST_EXIT_CRITICAL();
542 return ESP_OK;
543 }
544
usb_host_lib_info(usb_host_lib_info_t * info_ret)545 esp_err_t usb_host_lib_info(usb_host_lib_info_t *info_ret)
546 {
547 HOST_CHECK(info_ret != NULL, ESP_ERR_INVALID_ARG);
548 int num_devs_temp;
549 int num_clients_temp;
550 HOST_ENTER_CRITICAL();
551 HOST_CHECK_FROM_CRIT(p_host_lib_obj != NULL, ESP_ERR_INVALID_STATE);
552 num_clients_temp = p_host_lib_obj->dynamic.flags.num_clients;
553 HOST_EXIT_CRITICAL();
554 usbh_num_devs(&num_devs_temp);
555
556 //Write back return values
557 info_ret->num_devices = num_devs_temp;
558 info_ret->num_clients = num_clients_temp;
559 return ESP_OK;
560 }
561
562 // ------------------------------------------------ Client Functions ---------------------------------------------------
563
564 // ----------------------- Private -------------------------
565
_handle_pending_ep(client_t * client_obj)566 static void _handle_pending_ep(client_t *client_obj)
567 {
568 //Handle each EP on the pending list
569 while (!TAILQ_EMPTY(&client_obj->dynamic.pending_ep_tailq)) {
570 //Get the next pending EP.
571 endpoint_t *ep_obj = TAILQ_FIRST(&client_obj->dynamic.pending_ep_tailq);
572 TAILQ_REMOVE(&client_obj->dynamic.pending_ep_tailq, ep_obj, dynamic.tailq_entry);
573 TAILQ_INSERT_TAIL(&client_obj->dynamic.idle_ep_tailq, ep_obj, dynamic.tailq_entry);
574 ep_obj->dynamic.flags.pending = 0;
575 hcd_pipe_event_t last_event = ep_obj->dynamic.last_event;
576 uint32_t num_urb_dequeued = 0;
577
578 HOST_EXIT_CRITICAL();
579 //Handle pipe event
580 switch (last_event) {
581 case HCD_PIPE_EVENT_ERROR_XFER:
582 case HCD_PIPE_EVENT_ERROR_URB_NOT_AVAIL:
583 case HCD_PIPE_EVENT_ERROR_OVERFLOW:
584 case HCD_PIPE_EVENT_ERROR_STALL:
585 //The pipe is now stalled. Flush all pending URBs
586 ESP_ERROR_CHECK(hcd_pipe_command(ep_obj->constant.pipe_hdl, HCD_PIPE_CMD_FLUSH));
587 //All URBs in this pipe are now retired waiting to be dequeued. Fall through to dequeue them
588 __attribute__((fallthrough));
589 case HCD_PIPE_EVENT_URB_DONE: {
590 //Dequeue all URBs and run their transfer callback
591 urb_t *urb = hcd_urb_dequeue(ep_obj->constant.pipe_hdl);
592 while (urb != NULL) {
593 urb->transfer.callback(&urb->transfer);
594 num_urb_dequeued++;
595 urb = hcd_urb_dequeue(ep_obj->constant.pipe_hdl);
596 }
597 break;
598 }
599 default:
600 abort(); //Should never occur
601 break;
602 }
603 HOST_ENTER_CRITICAL();
604
605 //Update the endpoint's number of URB's inflight
606 assert(num_urb_dequeued <= ep_obj->dynamic.num_urb_inflight);
607 ep_obj->dynamic.num_urb_inflight -= num_urb_dequeued;
608 }
609 }
610
611 // ----------------------- Public --------------------------
612
usb_host_client_register(const usb_host_client_config_t * client_config,usb_host_client_handle_t * client_hdl_ret)613 esp_err_t usb_host_client_register(const usb_host_client_config_t *client_config, usb_host_client_handle_t *client_hdl_ret)
614 {
615 HOST_CHECK(p_host_lib_obj, ESP_ERR_INVALID_STATE);
616 HOST_CHECK(client_config != NULL && client_hdl_ret != NULL, ESP_ERR_INVALID_ARG);
617 HOST_CHECK(client_config->max_num_event_msg > 0, ESP_ERR_INVALID_ARG);
618 if (!client_config->is_synchronous) {
619 //Asynchronous clients must provide a
620 HOST_CHECK(client_config->async.client_event_callback != NULL, ESP_ERR_INVALID_ARG);
621 }
622
623 esp_err_t ret;
624 //Create client object
625 client_t *client_obj = heap_caps_calloc(1, sizeof(client_t), MALLOC_CAP_DEFAULT);
626 SemaphoreHandle_t event_sem = xSemaphoreCreateBinary();
627 QueueHandle_t event_msg_queue = xQueueCreate(client_config->max_num_event_msg, sizeof(usb_host_client_event_msg_t));
628 if (client_obj == NULL || event_sem == NULL || event_msg_queue == NULL) {
629 ret = ESP_ERR_NO_MEM;
630 goto alloc_err;
631 }
632 //Initialize client object
633 TAILQ_INIT(&client_obj->dynamic.pending_ep_tailq);
634 TAILQ_INIT(&client_obj->dynamic.idle_ep_tailq);
635 TAILQ_INIT(&client_obj->mux_protected.interface_tailq);
636 TAILQ_INIT(&client_obj->dynamic.done_ctrl_xfer_tailq);
637 client_obj->constant.event_sem = event_sem;
638 client_obj->constant.event_callback = client_config->async.client_event_callback;
639 client_obj->constant.callback_arg = client_config->async.callback_arg;
640 client_obj->constant.event_msg_queue = event_msg_queue;
641
642 //Add client to the host library's list of clients
643 xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY);
644 HOST_ENTER_CRITICAL();
645 p_host_lib_obj->dynamic.flags.num_clients++;
646 HOST_EXIT_CRITICAL();
647 TAILQ_INSERT_TAIL(&p_host_lib_obj->mux_protected.client_tailq, client_obj, dynamic.tailq_entry);
648 xSemaphoreGive(p_host_lib_obj->constant.mux_lock);
649
650 //Write back client handle
651 *client_hdl_ret = (usb_host_client_handle_t)client_obj;
652 ret = ESP_OK;
653 return ret;
654
655 alloc_err:
656 if (event_msg_queue) {
657 vQueueDelete(event_msg_queue);
658 }
659 if (event_sem) {
660 vSemaphoreDelete(event_sem);
661 }
662 heap_caps_free(client_obj);
663 return ESP_OK;
664 }
665
usb_host_client_deregister(usb_host_client_handle_t client_hdl)666 esp_err_t usb_host_client_deregister(usb_host_client_handle_t client_hdl)
667 {
668 HOST_CHECK(client_hdl != NULL, ESP_ERR_INVALID_ARG);
669 client_t *client_obj = (client_t *)client_hdl;
670 esp_err_t ret;
671
672 //We take the mux_lock because we need to access the host library's client_tailq
673 xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY);
674 HOST_ENTER_CRITICAL();
675 //Check that client can currently deregistered
676 bool can_deregister;
677 if (!TAILQ_EMPTY(&client_obj->dynamic.pending_ep_tailq) ||
678 !TAILQ_EMPTY(&client_obj->dynamic.idle_ep_tailq) ||
679 !TAILQ_EMPTY(&client_obj->dynamic.done_ctrl_xfer_tailq) ||
680 client_obj->dynamic.flags.handling_events ||
681 client_obj->dynamic.flags.blocked ||
682 client_obj->dynamic.flags.taking_mux ||
683 client_obj->dynamic.flags.num_intf_claimed != 0 ||
684 client_obj->dynamic.num_done_ctrl_xfer != 0 ||
685 client_obj->dynamic.opened_dev_addr_map != 0) {
686 can_deregister = false;
687 } else {
688 can_deregister = true;
689 }
690 HOST_EXIT_CRITICAL();
691 if (!can_deregister) {
692 ret = ESP_ERR_INVALID_STATE;
693 goto exit;
694 }
695
696 //Remove client object from the library's list of clients
697 TAILQ_REMOVE(&p_host_lib_obj->mux_protected.client_tailq, client_obj, dynamic.tailq_entry);
698 HOST_ENTER_CRITICAL();
699 p_host_lib_obj->dynamic.flags.num_clients--;
700 if (p_host_lib_obj->dynamic.flags.num_clients == 0) {
701 //This is the last client being deregistered. Notify the lib handler
702 p_host_lib_obj->dynamic.lib_event_flags |= USB_HOST_LIB_EVENT_FLAGS_NO_CLIENTS;
703 _unblock_lib(false);
704 }
705 HOST_EXIT_CRITICAL();
706 //Free client object
707 vQueueDelete(client_obj->constant.event_msg_queue);
708 vSemaphoreDelete(client_obj->constant.event_sem);
709 heap_caps_free(client_obj);
710 ret = ESP_OK;
711 exit:
712 xSemaphoreGive(p_host_lib_obj->constant.mux_lock);
713 return ret;
714 }
715
usb_host_client_handle_events(usb_host_client_handle_t client_hdl,TickType_t timeout_ticks)716 esp_err_t usb_host_client_handle_events(usb_host_client_handle_t client_hdl, TickType_t timeout_ticks)
717 {
718 HOST_CHECK(client_hdl != NULL, ESP_ERR_INVALID_ARG);
719 esp_err_t ret;
720 client_t *client_obj = (client_t *)client_hdl;
721
722 HOST_ENTER_CRITICAL();
723 if (!client_obj->dynamic.flags.events_pending) {
724 //There are currently no events, wait for one to occur
725 client_obj->dynamic.flags.blocked = 1;
726 HOST_EXIT_CRITICAL();
727 BaseType_t sem_ret = xSemaphoreTake(client_obj->constant.event_sem, timeout_ticks);
728 HOST_ENTER_CRITICAL();
729 client_obj->dynamic.flags.blocked = 0;
730 if (sem_ret == pdFALSE) {
731 HOST_EXIT_CRITICAL();
732 //Timed out waiting for semaphore
733 ret = ESP_ERR_TIMEOUT;
734 goto exit;
735 }
736 }
737 //Mark that we're processing events
738 client_obj->dynamic.flags.handling_events = 1;
739 while (client_obj->dynamic.flags.handling_events) {
740 //Handle pending endpoints
741 if (!TAILQ_EMPTY(&client_obj->dynamic.pending_ep_tailq)) {
742 _handle_pending_ep(client_obj);
743 }
744 //Handle any done control transfers
745 while (client_obj->dynamic.num_done_ctrl_xfer > 0) {
746 urb_t *urb = TAILQ_FIRST(&client_obj->dynamic.done_ctrl_xfer_tailq);
747 TAILQ_REMOVE(&client_obj->dynamic.done_ctrl_xfer_tailq, urb, tailq_entry);
748 client_obj->dynamic.num_done_ctrl_xfer--;
749 HOST_EXIT_CRITICAL();
750 //Call the transfer's callback
751 urb->transfer.callback(&urb->transfer);
752 HOST_ENTER_CRITICAL();
753 }
754 //Handle event messages
755 while (uxQueueMessagesWaiting(client_obj->constant.event_msg_queue) > 0) {
756 HOST_EXIT_CRITICAL();
757 //Dequeue the event message and call the client event callback
758 usb_host_client_event_msg_t event_msg;
759 BaseType_t queue_ret = xQueueReceive(client_obj->constant.event_msg_queue, &event_msg, 0);
760 assert(queue_ret == pdTRUE);
761 client_obj->constant.event_callback(&event_msg, client_obj->constant.callback_arg);
762 HOST_ENTER_CRITICAL();
763 }
764 //Check each event again to see any new events occurred
765 if (TAILQ_EMPTY(&client_obj->dynamic.pending_ep_tailq) &&
766 client_obj->dynamic.num_done_ctrl_xfer == 0 &&
767 uxQueueMessagesWaiting(client_obj->constant.event_msg_queue) == 0) {
768 //All pending endpoints and event messages handled
769 client_obj->dynamic.flags.events_pending = 0;
770 client_obj->dynamic.flags.handling_events = 0;
771 }
772 }
773 HOST_EXIT_CRITICAL();
774
775 ret = ESP_OK;
776 exit:
777 return ret;
778 }
779
usb_host_client_unblock(usb_host_client_handle_t client_hdl)780 esp_err_t usb_host_client_unblock(usb_host_client_handle_t client_hdl)
781 {
782 HOST_CHECK(client_hdl != NULL, ESP_ERR_INVALID_ARG);
783 client_t *client_obj = (client_t *)client_hdl;
784
785 HOST_ENTER_CRITICAL();
786 _unblock_client(client_obj, false);
787 HOST_EXIT_CRITICAL();
788
789 return ESP_OK;
790 }
791
792 // ------------------------------------------------- Device Handling ---------------------------------------------------
793
usb_host_device_open(usb_host_client_handle_t client_hdl,uint8_t dev_addr,usb_device_handle_t * dev_hdl_ret)794 esp_err_t usb_host_device_open(usb_host_client_handle_t client_hdl, uint8_t dev_addr, usb_device_handle_t *dev_hdl_ret)
795 {
796 HOST_CHECK(dev_addr > 0 && client_hdl != NULL && dev_hdl_ret != NULL, ESP_ERR_INVALID_ARG);
797 client_t *client_obj = (client_t *)client_hdl;
798
799 esp_err_t ret;
800 usb_device_handle_t dev_hdl;
801 ret = usbh_dev_open(dev_addr, &dev_hdl);
802 if (ret != ESP_OK) {
803 goto exit;
804 }
805
806 HOST_ENTER_CRITICAL();
807 if (_check_client_opened_device(client_obj, dev_addr)) {
808 //Client has already opened the device. Close it and return an error
809 ret = ESP_ERR_INVALID_STATE;
810 HOST_EXIT_CRITICAL();
811 goto already_opened;
812 }
813 //Record in client object that we have opened the device of this address
814 _record_client_opened_device(client_obj, dev_addr);
815 HOST_EXIT_CRITICAL();
816
817 *dev_hdl_ret = dev_hdl;
818 ret = ESP_OK;
819 return ret;
820
821 already_opened:
822 ESP_ERROR_CHECK(usbh_dev_close(dev_hdl));
823 exit:
824 return ret;
825 }
826
usb_host_device_close(usb_host_client_handle_t client_hdl,usb_device_handle_t dev_hdl)827 esp_err_t usb_host_device_close(usb_host_client_handle_t client_hdl, usb_device_handle_t dev_hdl)
828 {
829 HOST_CHECK(dev_hdl != NULL && client_hdl != NULL, ESP_ERR_INVALID_ARG);
830 client_t *client_obj = (client_t *)client_hdl;
831
832 //We take the lock because we need to walk the interface list
833 xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY);
834 esp_err_t ret;
835 //Check that all interfaces claimed by this client do not belong to this device
836 bool all_released = true;
837 interface_t *intf_obj;
838 TAILQ_FOREACH(intf_obj, &client_obj->mux_protected.interface_tailq, mux_protected.tailq_entry) {
839 if (intf_obj->constant.dev_hdl == dev_hdl) {
840 all_released = false;
841 break;
842 }
843 }
844 if (!all_released) {
845 ret = ESP_ERR_INVALID_STATE;
846 goto exit;
847 }
848
849 //Check that client actually opened the device in the first place
850 HOST_ENTER_CRITICAL();
851 uint8_t dev_addr;
852 ESP_ERROR_CHECK(usbh_dev_get_addr(dev_hdl, &dev_addr));
853 HOST_CHECK_FROM_CRIT(_check_client_opened_device(client_obj, dev_addr), ESP_ERR_NOT_FOUND);
854 if (!_check_client_opened_device(client_obj, dev_addr)) {
855 //Client never opened this device
856 ret = ESP_ERR_INVALID_STATE;
857 HOST_EXIT_CRITICAL();
858 goto exit;
859 }
860 //Proceed to clear the record of the device form the client
861 _clear_client_opened_device(client_obj, dev_addr);
862 HOST_EXIT_CRITICAL();
863
864 ESP_ERROR_CHECK(usbh_dev_close(dev_hdl));
865 ret = ESP_OK;
866 exit:
867 xSemaphoreGive(p_host_lib_obj->constant.mux_lock);
868 return ret;
869 }
870
usb_host_device_free_all(void)871 esp_err_t usb_host_device_free_all(void)
872 {
873 HOST_ENTER_CRITICAL();
874 HOST_CHECK_FROM_CRIT(p_host_lib_obj->dynamic.flags.num_clients == 0, ESP_ERR_INVALID_STATE); //All clients must have been deregistered
875 HOST_EXIT_CRITICAL();
876 esp_err_t ret;
877 ret = usbh_dev_mark_all_free();
878 //If ESP_ERR_NOT_FINISHED is returned, caller must wait for USB_HOST_LIB_EVENT_FLAGS_ALL_FREE to confirm all devices are free
879 return ret;
880 }
881
usb_host_device_addr_list_fill(int list_len,uint8_t * dev_addr_list,int * num_dev_ret)882 esp_err_t usb_host_device_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *num_dev_ret)
883 {
884 HOST_CHECK(dev_addr_list != NULL && num_dev_ret != NULL, ESP_ERR_INVALID_ARG);
885 return usbh_dev_addr_list_fill(list_len, dev_addr_list, num_dev_ret);
886 }
887
888 // ------------------------------------------------- Device Requests ---------------------------------------------------
889
890 // ------------------- Cached Requests ---------------------
891
usb_host_device_info(usb_device_handle_t dev_hdl,usb_device_info_t * dev_info)892 esp_err_t usb_host_device_info(usb_device_handle_t dev_hdl, usb_device_info_t *dev_info)
893 {
894 HOST_CHECK(dev_hdl != NULL && dev_info != NULL, ESP_ERR_INVALID_ARG);
895 return usbh_dev_get_info(dev_hdl, dev_info);
896 }
897
898 // ----------------------------------------------- Descriptor Requests -------------------------------------------------
899
900 // ----------------- Cached Descriptors --------------------
901
usb_host_get_device_descriptor(usb_device_handle_t dev_hdl,const usb_device_desc_t ** device_desc)902 esp_err_t usb_host_get_device_descriptor(usb_device_handle_t dev_hdl, const usb_device_desc_t **device_desc)
903 {
904 HOST_CHECK(dev_hdl != NULL && device_desc != NULL, ESP_ERR_INVALID_ARG);
905 return usbh_dev_get_desc(dev_hdl, device_desc);
906 }
907
usb_host_get_active_config_descriptor(usb_device_handle_t dev_hdl,const usb_config_desc_t ** config_desc)908 esp_err_t usb_host_get_active_config_descriptor(usb_device_handle_t dev_hdl, const usb_config_desc_t **config_desc)
909 {
910 HOST_CHECK(dev_hdl != NULL && config_desc != NULL, ESP_ERR_INVALID_ARG);
911 return usbh_dev_get_config_desc(dev_hdl, config_desc);
912 }
913
914 // ----------------------------------------------- Interface Functions -------------------------------------------------
915
916 // ----------------------- Private -------------------------
917
endpoint_alloc(usb_device_handle_t dev_hdl,const usb_ep_desc_t * ep_desc,interface_t * intf_obj,endpoint_t ** ep_obj_ret)918 static esp_err_t endpoint_alloc(usb_device_handle_t dev_hdl, const usb_ep_desc_t *ep_desc, interface_t *intf_obj, endpoint_t **ep_obj_ret)
919 {
920 endpoint_t *ep_obj = heap_caps_calloc(1, sizeof(endpoint_t), MALLOC_CAP_DEFAULT);
921 if (ep_obj == NULL) {
922 return ESP_ERR_NO_MEM;
923 }
924 esp_err_t ret;
925 usbh_ep_config_t ep_config = {
926 .ep_desc = ep_desc,
927 .pipe_cb = pipe_callback,
928 .pipe_cb_arg = (void *)ep_obj,
929 .context = (void *)ep_obj,
930 };
931 hcd_pipe_handle_t pipe_hdl;
932 ret = usbh_ep_alloc(dev_hdl, &ep_config, &pipe_hdl);
933 if (ret != ESP_OK) {
934 goto ep_alloc_err;
935 }
936 //Initialize endpoint object
937 ep_obj->constant.pipe_hdl = pipe_hdl;
938 ep_obj->constant.ep_desc = ep_desc;
939 ep_obj->constant.intf_obj = intf_obj;
940 //Write back result
941 *ep_obj_ret = ep_obj;
942 ret = ESP_OK;
943 return ret;
944
945 ep_alloc_err:
946 heap_caps_free(ep_obj);
947 return ret;
948 }
949
endpoint_free(usb_device_handle_t dev_hdl,endpoint_t * ep_obj)950 static void endpoint_free(usb_device_handle_t dev_hdl, endpoint_t *ep_obj)
951 {
952 if (ep_obj == NULL) {
953 return;
954 }
955 //Free the underlying endpoint
956 ESP_ERROR_CHECK(usbh_ep_free(dev_hdl, ep_obj->constant.ep_desc->bEndpointAddress));
957 //Free the endpoint object
958 heap_caps_free(ep_obj);
959 }
960
interface_alloc(client_t * client_obj,usb_device_handle_t dev_hdl,const usb_intf_desc_t * intf_desc)961 static interface_t *interface_alloc(client_t *client_obj, usb_device_handle_t dev_hdl, const usb_intf_desc_t *intf_desc)
962 {
963 interface_t *intf_obj = heap_caps_calloc(1, sizeof(interface_t) + (sizeof(endpoint_t *) * intf_desc->bNumEndpoints), MALLOC_CAP_DEFAULT);
964 if (intf_obj == NULL) {
965 return NULL;
966 }
967 intf_obj->constant.intf_desc = intf_desc;
968 intf_obj->constant.client_obj = client_obj;
969 intf_obj->constant.dev_hdl = dev_hdl;
970 return intf_obj;
971 }
972
interface_free(interface_t * intf_obj)973 static void interface_free(interface_t *intf_obj)
974 {
975 if (intf_obj == NULL) {
976 return;
977 }
978 for (int i = 0; i < intf_obj->constant.intf_desc->bNumEndpoints; i++) {
979 assert(intf_obj->constant.endpoints[i] == NULL);
980 }
981 heap_caps_free(intf_obj);
982 }
983
interface_claim(client_t * client_obj,usb_device_handle_t dev_hdl,const usb_config_desc_t * config_desc,uint8_t bInterfaceNumber,uint8_t bAlternateSetting,interface_t ** intf_obj_ret)984 static esp_err_t interface_claim(client_t *client_obj, usb_device_handle_t dev_hdl, const usb_config_desc_t *config_desc, uint8_t bInterfaceNumber, uint8_t bAlternateSetting, interface_t **intf_obj_ret)
985 {
986 esp_err_t ret;
987 //We need to walk to configuration descriptor to find the correct interface descriptor, and each of its constituent endpoint descriptors
988 //Find the interface descriptor and allocate the interface object
989 int offset_intf;
990 const usb_intf_desc_t *intf_desc = usb_parse_interface_descriptor(config_desc, bInterfaceNumber, bAlternateSetting, &offset_intf);
991 if (intf_desc == NULL) {
992 ret = ESP_ERR_NOT_FOUND;
993 goto exit;
994 }
995 //Allocate interface object
996 interface_t *intf_obj = interface_alloc(client_obj, dev_hdl, intf_desc);
997 if (intf_obj == NULL) {
998 ret = ESP_ERR_NO_MEM;
999 goto exit;
1000 }
1001 //Find each endpoint descriptor in the interface by index, and allocate those endpoints
1002 for (int i = 0; i < intf_desc->bNumEndpoints; i++) {
1003 int offset_ep = offset_intf;
1004 const usb_ep_desc_t *ep_desc = usb_parse_endpoint_descriptor_by_index(intf_desc, i, config_desc->wTotalLength, &offset_ep);
1005 if (ep_desc == NULL) {
1006 ret = ESP_ERR_NOT_FOUND;
1007 goto ep_alloc_err;
1008 }
1009 //Allocate the endpoint
1010 endpoint_t *ep_obj;
1011 ret = endpoint_alloc(dev_hdl, ep_desc, intf_obj, &ep_obj);
1012 if (ret != ESP_OK) {
1013 goto ep_alloc_err;
1014 }
1015 //Fill the interface object with the allocated endpoints
1016 intf_obj->constant.endpoints[i] = ep_obj;
1017 }
1018 //Add interface object to client (safe because we have already taken the mutex)
1019 TAILQ_INSERT_TAIL(&client_obj->mux_protected.interface_tailq, intf_obj, mux_protected.tailq_entry);
1020 //Add each endpoint to the client's endpoint list
1021 HOST_ENTER_CRITICAL();
1022 for (int i = 0; i < intf_desc->bNumEndpoints; i++) {
1023 TAILQ_INSERT_TAIL(&client_obj->dynamic.idle_ep_tailq, intf_obj->constant.endpoints[i], dynamic.tailq_entry);
1024 }
1025 HOST_EXIT_CRITICAL();
1026 //Write back result
1027 *intf_obj_ret = intf_obj;
1028 ret = ESP_OK;
1029 return ret;
1030
1031 ep_alloc_err:
1032 for (int i = 0; i < intf_desc->bNumEndpoints; i++) {
1033 endpoint_free(dev_hdl, intf_obj->constant.endpoints[i]);
1034 intf_obj->constant.endpoints[i] = NULL;
1035 }
1036 interface_free(intf_obj);
1037 exit:
1038 return ret;
1039 }
1040
interface_release(client_t * client_obj,usb_device_handle_t dev_hdl,uint8_t bInterfaceNumber)1041 static esp_err_t interface_release(client_t *client_obj, usb_device_handle_t dev_hdl, uint8_t bInterfaceNumber)
1042 {
1043 esp_err_t ret;
1044 //Find the interface object
1045 interface_t *intf_obj_iter;
1046 interface_t *intf_obj = NULL;
1047 TAILQ_FOREACH(intf_obj_iter, &client_obj->mux_protected.interface_tailq, mux_protected.tailq_entry) {
1048 if (intf_obj_iter->constant.dev_hdl == dev_hdl && intf_obj_iter->constant.intf_desc->bInterfaceNumber == bInterfaceNumber) {
1049 intf_obj = intf_obj_iter;
1050 break;
1051 }
1052 }
1053 if (intf_obj == NULL) {
1054 ret = ESP_ERR_NOT_FOUND;
1055 goto exit;
1056 }
1057
1058 //Check that all endpoints in the interface are in a state to be freed
1059 HOST_ENTER_CRITICAL();
1060 bool can_free = true;
1061 for (int i = 0; i < intf_obj->constant.intf_desc->bNumEndpoints; i++) {
1062 endpoint_t *ep_obj = intf_obj->constant.endpoints[i];
1063 //Endpoint must not be on the pending list and must not have inflight URBs
1064 if (ep_obj->dynamic.num_urb_inflight != 0 || ep_obj->dynamic.flags.pending) {
1065 can_free = false;
1066 break;
1067 }
1068 }
1069 if (!can_free) {
1070 HOST_EXIT_CRITICAL();
1071 ret = ESP_ERR_INVALID_STATE;
1072 goto exit;
1073 }
1074 //Proceed to remove all endpoint objects from list
1075 for (int i = 0; i < intf_obj->constant.intf_desc->bNumEndpoints; i++) {
1076 TAILQ_REMOVE(&client_obj->dynamic.idle_ep_tailq, intf_obj->constant.endpoints[i], dynamic.tailq_entry);
1077 }
1078 HOST_EXIT_CRITICAL();
1079
1080 //Remove the interface object from the list (safe because we have already taken the mutex)
1081 TAILQ_REMOVE(&client_obj->mux_protected.interface_tailq, intf_obj, mux_protected.tailq_entry);
1082
1083 //Free each endpoint in the interface
1084 for (int i = 0; i < intf_obj->constant.intf_desc->bNumEndpoints; i++) {
1085 endpoint_free(dev_hdl, intf_obj->constant.endpoints[i]);
1086 intf_obj->constant.endpoints[i] = NULL;
1087 }
1088 //Free the interface object itself
1089 interface_free(intf_obj);
1090 ret = ESP_OK;
1091 exit:
1092 return ret;
1093 }
1094
1095 // ----------------------- Public --------------------------
1096
usb_host_interface_claim(usb_host_client_handle_t client_hdl,usb_device_handle_t dev_hdl,uint8_t bInterfaceNumber,uint8_t bAlternateSetting)1097 esp_err_t usb_host_interface_claim(usb_host_client_handle_t client_hdl, usb_device_handle_t dev_hdl, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)
1098 {
1099 HOST_CHECK(client_hdl != NULL && dev_hdl != NULL, ESP_ERR_INVALID_ARG);
1100 client_t *client_obj = (client_t *)client_hdl;
1101
1102 HOST_ENTER_CRITICAL();
1103 uint8_t dev_addr;
1104 ESP_ERROR_CHECK(usbh_dev_get_addr(dev_hdl, &dev_addr));
1105 //Check if client actually opened device
1106 HOST_CHECK_FROM_CRIT(_check_client_opened_device(client_obj, dev_addr), ESP_ERR_INVALID_STATE);
1107 client_obj->dynamic.flags.taking_mux = 1;
1108 HOST_EXIT_CRITICAL();
1109
1110 //Take mux lock. This protects the client being released or other clients from claiming interfaces
1111 xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY);
1112 esp_err_t ret;
1113 const usb_config_desc_t *config_desc;
1114 ESP_ERROR_CHECK(usbh_dev_get_config_desc(dev_hdl, &config_desc));
1115 interface_t *intf_obj;
1116 //Claim interface
1117 ret = interface_claim(client_obj, dev_hdl, config_desc, bInterfaceNumber, bAlternateSetting, &intf_obj);
1118 if (ret != ESP_OK) {
1119 goto exit;
1120 }
1121 ret = ESP_OK;
1122 exit:
1123 xSemaphoreGive(p_host_lib_obj->constant.mux_lock);
1124
1125 HOST_ENTER_CRITICAL();
1126 if (ret == ESP_OK) {
1127 client_obj->dynamic.flags.num_intf_claimed++;
1128 }
1129 client_obj->dynamic.flags.taking_mux = 0;
1130 HOST_EXIT_CRITICAL();
1131 return ret;
1132 }
1133
usb_host_interface_release(usb_host_client_handle_t client_hdl,usb_device_handle_t dev_hdl,uint8_t bInterfaceNumber)1134 esp_err_t usb_host_interface_release(usb_host_client_handle_t client_hdl, usb_device_handle_t dev_hdl, uint8_t bInterfaceNumber)
1135 {
1136 HOST_CHECK(client_hdl != NULL && dev_hdl != NULL, ESP_ERR_INVALID_ARG);
1137 client_t *client_obj = (client_t *)client_hdl;
1138
1139 HOST_ENTER_CRITICAL();
1140 uint8_t dev_addr;
1141 ESP_ERROR_CHECK(usbh_dev_get_addr(dev_hdl, &dev_addr));
1142 //Check if client actually opened device
1143 HOST_CHECK_FROM_CRIT(_check_client_opened_device(client_obj, dev_addr), ESP_ERR_INVALID_STATE);
1144 client_obj->dynamic.flags.taking_mux = 1;
1145 HOST_EXIT_CRITICAL();
1146
1147 //Take mux lock. This protects the client being released or other clients from claiming interfaces
1148 xSemaphoreTake(p_host_lib_obj->constant.mux_lock, portMAX_DELAY);
1149 esp_err_t ret = interface_release(client_obj, dev_hdl, bInterfaceNumber);
1150 xSemaphoreGive(p_host_lib_obj->constant.mux_lock);
1151
1152 HOST_ENTER_CRITICAL();
1153 if (ret == ESP_OK) {
1154 client_obj->dynamic.flags.num_intf_claimed--;
1155 }
1156 client_obj->dynamic.flags.taking_mux = 0;
1157 HOST_EXIT_CRITICAL();
1158
1159 return ret;
1160 }
1161
usb_host_endpoint_halt(usb_device_handle_t dev_hdl,uint8_t bEndpointAddress)1162 esp_err_t usb_host_endpoint_halt(usb_device_handle_t dev_hdl, uint8_t bEndpointAddress)
1163 {
1164 esp_err_t ret;
1165 endpoint_t *ep_obj = NULL;
1166 ret = usbh_ep_get_context(dev_hdl, bEndpointAddress, (void **)&ep_obj);
1167 if (ret != ESP_OK) {
1168 goto exit;
1169 }
1170 assert(ep_obj != NULL);
1171 ret = hcd_pipe_command(ep_obj->constant.pipe_hdl, HCD_PIPE_CMD_HALT);
1172 exit:
1173 return ret;
1174 }
1175
usb_host_endpoint_flush(usb_device_handle_t dev_hdl,uint8_t bEndpointAddress)1176 esp_err_t usb_host_endpoint_flush(usb_device_handle_t dev_hdl, uint8_t bEndpointAddress)
1177 {
1178 esp_err_t ret;
1179 endpoint_t *ep_obj = NULL;
1180 ret = usbh_ep_get_context(dev_hdl, bEndpointAddress, (void **)&ep_obj);
1181 if (ret != ESP_OK) {
1182 goto exit;
1183 }
1184 assert(ep_obj != NULL);
1185 ret = hcd_pipe_command(ep_obj->constant.pipe_hdl, HCD_PIPE_CMD_FLUSH);
1186 exit:
1187 return ret;
1188 }
1189
usb_host_endpoint_clear(usb_device_handle_t dev_hdl,uint8_t bEndpointAddress)1190 esp_err_t usb_host_endpoint_clear(usb_device_handle_t dev_hdl, uint8_t bEndpointAddress)
1191 {
1192 esp_err_t ret;
1193 endpoint_t *ep_obj = NULL;
1194 ret = usbh_ep_get_context(dev_hdl, bEndpointAddress, (void **)&ep_obj);
1195 if (ret != ESP_OK) {
1196 goto exit;
1197 }
1198 assert(ep_obj != NULL);
1199 ret = hcd_pipe_command(ep_obj->constant.pipe_hdl, HCD_PIPE_CMD_CLEAR);
1200 exit:
1201 return ret;
1202 }
1203
1204 // ------------------------------------------------ Asynchronous I/O ---------------------------------------------------
1205
1206 // ----------------------- Private -------------------------
1207
transfer_check(usb_transfer_t * transfer,usb_transfer_type_t type,int mps,bool is_in)1208 static bool transfer_check(usb_transfer_t *transfer, usb_transfer_type_t type, int mps, bool is_in)
1209 {
1210 if (transfer->callback == NULL) {
1211 ESP_LOGE(USB_HOST_TAG, "Transfer callback is NULL");
1212 return false;
1213 }
1214 //Check that the total transfer length does not exceed data buffer size
1215 if (transfer->num_bytes > transfer->data_buffer_size) {
1216 ESP_LOGE(USB_HOST_TAG, "Transfer num_bytes > data_buffer_size");
1217 return false;
1218 }
1219 if (type == USB_TRANSFER_TYPE_CTRL) {
1220 //Check that num_bytes and wLength are set correctly
1221 usb_setup_packet_t *setup_pkt = (usb_setup_packet_t *)transfer->data_buffer;
1222 if (transfer->num_bytes != sizeof(usb_setup_packet_t) + setup_pkt->wLength) {
1223 ESP_LOGE(USB_HOST_TAG, "Control transfer num_bytes wLength mismatch");
1224 return false;
1225 }
1226 } else if (type == USB_TRANSFER_TYPE_ISOCHRONOUS) {
1227 //Check that there is at least one isochronous packet descriptor
1228 if (transfer->num_isoc_packets <= 0) {
1229 ESP_LOGE(USB_HOST_TAG, "ISOC transfer has 0 packet descriptors");
1230 return false;
1231 }
1232 //Check that sum of all packet lengths add up to transfer length
1233 //If IN, check that each packet length is integer multiple of MPS
1234 int total_num_bytes = 0;
1235 bool mod_mps_all_zero = true;
1236 for (int i = 0; i < transfer->num_isoc_packets; i++) {
1237 total_num_bytes += transfer->isoc_packet_desc[i].num_bytes;
1238 if (transfer->isoc_packet_desc[i].num_bytes % mps != 0) {
1239 mod_mps_all_zero = false;
1240 }
1241 }
1242 if (transfer->num_bytes != total_num_bytes) {
1243 ESP_LOGE(USB_HOST_TAG, "ISOC transfer num_bytes not equal to total num_bytes of all packets");
1244 return false;
1245 }
1246 if (is_in && !mod_mps_all_zero) {
1247 ESP_LOGE(USB_HOST_TAG, "ISOC IN transfer all packets num_bytes must be integer multiple of MPS");
1248 return false;
1249 }
1250 } else {
1251 //Check that IN transfers are integer multiple of MPS
1252 if (is_in && (transfer->num_bytes % mps != 0)) {
1253 ESP_LOGE(USB_HOST_TAG, "IN transfer num_bytes must be integer multiple of MPS");
1254 return false;
1255 }
1256 }
1257 return true;
1258 }
1259
1260 // ----------------------- Public --------------------------
1261
usb_host_transfer_alloc(size_t data_buffer_size,int num_isoc_packets,usb_transfer_t ** transfer)1262 esp_err_t usb_host_transfer_alloc(size_t data_buffer_size, int num_isoc_packets, usb_transfer_t **transfer)
1263 {
1264 urb_t *urb = urb_alloc(data_buffer_size, 0, num_isoc_packets);
1265 if (urb == NULL) {
1266 return ESP_ERR_NO_MEM;
1267 }
1268 *transfer = &urb->transfer;
1269 return ESP_OK;
1270 }
1271
usb_host_transfer_free(usb_transfer_t * transfer)1272 esp_err_t usb_host_transfer_free(usb_transfer_t *transfer)
1273 {
1274 if (transfer == NULL) {
1275 return ESP_OK;
1276 }
1277 urb_t *urb = __containerof(transfer, urb_t, transfer);
1278 urb_free(urb);
1279 return ESP_OK;
1280 }
1281
usb_host_transfer_submit(usb_transfer_t * transfer)1282 esp_err_t usb_host_transfer_submit(usb_transfer_t *transfer)
1283 {
1284 HOST_CHECK(transfer != NULL, ESP_ERR_INVALID_ARG);
1285 //Check that transfer and target endpoint are valid
1286 HOST_CHECK(transfer->device_handle != NULL, ESP_ERR_INVALID_ARG); //Target device must be set
1287 HOST_CHECK((transfer->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK) != 0, ESP_ERR_INVALID_ARG);
1288 endpoint_t *ep_obj = NULL;
1289 urb_t *urb_obj = __containerof(transfer, urb_t, transfer);
1290 esp_err_t ret;
1291 ret = usbh_ep_get_context(transfer->device_handle, transfer->bEndpointAddress, (void **)&ep_obj);
1292 if (ret != ESP_OK) {
1293 goto err;
1294 }
1295 assert(ep_obj != NULL);
1296 HOST_CHECK(transfer_check(transfer,
1297 USB_EP_DESC_GET_XFERTYPE(ep_obj->constant.ep_desc),
1298 USB_EP_DESC_GET_MPS(ep_obj->constant.ep_desc),
1299 transfer->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK), ESP_ERR_INVALID_ARG);
1300 HOST_ENTER_CRITICAL();
1301 ep_obj->dynamic.num_urb_inflight++;
1302 HOST_EXIT_CRITICAL();
1303 //Check if pipe is in a state to enqueue URBs
1304 if (hcd_pipe_get_state(ep_obj->constant.pipe_hdl) != HCD_PIPE_STATE_ACTIVE) {
1305 ret = ESP_ERR_INVALID_STATE;
1306 goto hcd_err;
1307 }
1308 ret = hcd_urb_enqueue(ep_obj->constant.pipe_hdl, urb_obj);
1309 if (ret != ESP_OK) {
1310 goto hcd_err;
1311 }
1312 ret = ESP_OK;
1313 return ret;
1314
1315 hcd_err:
1316 HOST_ENTER_CRITICAL();
1317 ep_obj->dynamic.num_urb_inflight--;
1318 HOST_EXIT_CRITICAL();
1319 err:
1320 return ret;
1321 }
1322
usb_host_transfer_submit_control(usb_host_client_handle_t client_hdl,usb_transfer_t * transfer)1323 esp_err_t usb_host_transfer_submit_control(usb_host_client_handle_t client_hdl, usb_transfer_t *transfer)
1324 {
1325 HOST_CHECK(client_hdl != NULL && transfer != NULL, ESP_ERR_INVALID_ARG);
1326 //Check that control transfer is valid
1327 HOST_CHECK(transfer->device_handle != NULL, ESP_ERR_INVALID_ARG); //Target device must be set
1328 usb_device_handle_t dev_hdl = transfer->device_handle;
1329 bool xfer_is_in = ((usb_setup_packet_t *)transfer->data_buffer)->bmRequestType & USB_BM_REQUEST_TYPE_DIR_OUT;
1330 usb_device_info_t dev_info;
1331 ESP_ERROR_CHECK(usbh_dev_get_info(dev_hdl, &dev_info));
1332 HOST_CHECK(transfer_check(transfer, USB_TRANSFER_TYPE_CTRL, dev_info.bMaxPacketSize0, xfer_is_in), ESP_ERR_INVALID_ARG);
1333 //Control transfers must be targeted at EP 0
1334 HOST_CHECK((transfer->bEndpointAddress & USB_B_ENDPOINT_ADDRESS_EP_NUM_MASK) == 0, ESP_ERR_INVALID_ARG);
1335 //Save client handle into URB
1336 urb_t *urb_obj = __containerof(transfer, urb_t, transfer);
1337 urb_obj->usb_host_client = (void *)client_hdl;
1338 return usbh_dev_submit_ctrl_urb(dev_hdl, urb_obj);
1339 }
1340