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