Open FFBoard
Open source force feedback firmware
usbd.c
Go to the documentation of this file.
1/*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2019 Ha Thach (tinyusb.org)
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 * This file is part of the TinyUSB stack.
25 */
26
27#include "tusb_option.h"
28
29#if CFG_TUD_ENABLED
30
31#include "device/dcd.h"
32#include "tusb.h"
33#include "common/tusb_private.h"
34
35#include "device/usbd.h"
36#include "device/usbd_pvt.h"
37
38//--------------------------------------------------------------------+
39// USBD Configuration
40//--------------------------------------------------------------------+
41#ifndef CFG_TUD_TASK_QUEUE_SZ
42 #define CFG_TUD_TASK_QUEUE_SZ 16
43#endif
44
45//--------------------------------------------------------------------+
46// Weak stubs: invoked if no strong implementation is available
47//--------------------------------------------------------------------+
48TU_ATTR_WEAK void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) {
49 (void) rhport;
50 (void) eventid;
51 (void) in_isr;
52}
53
54TU_ATTR_WEAK void tud_sof_cb(uint32_t frame_count) {
55 (void) frame_count;
56}
57
58TU_ATTR_WEAK uint8_t const* tud_descriptor_bos_cb(void) {
59 return NULL;
60}
61
62TU_ATTR_WEAK uint8_t const* tud_descriptor_device_qualifier_cb(void) {
63 return NULL;
64}
65
66TU_ATTR_WEAK uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) {
67 (void) index;
68 return NULL;
69}
70
71TU_ATTR_WEAK void tud_mount_cb(void) {
72}
73
74TU_ATTR_WEAK void tud_umount_cb(void) {
75}
76
77TU_ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en) {
78 (void) remote_wakeup_en;
79}
80
81TU_ATTR_WEAK void tud_resume_cb(void) {
82}
83
84TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request) {
85 (void) rhport;
86 (void) stage;
87 (void) request;
88 return false;
89}
90
91TU_ATTR_WEAK bool dcd_deinit(uint8_t rhport) {
92 (void) rhport;
93 return false;
94}
95
96TU_ATTR_WEAK void dcd_connect(uint8_t rhport) {
97 (void) rhport;
98}
99
100TU_ATTR_WEAK void dcd_disconnect(uint8_t rhport) {
101 (void) rhport;
102}
103
104//--------------------------------------------------------------------+
105// Device Data
106//--------------------------------------------------------------------+
107
108// Invalid driver ID in itf2drv[] ep2drv[][] mapping
109enum { DRVID_INVALID = 0xFFu };
110
111typedef struct {
113 volatile uint8_t connected : 1;
114 volatile uint8_t addressed : 1;
115 volatile uint8_t suspended : 1;
116
117 uint8_t remote_wakeup_en : 1; // enable/disable by host
118 uint8_t remote_wakeup_support : 1; // configuration descriptor's attribute
119 uint8_t self_powered : 1; // configuration descriptor's attribute
120 };
121 volatile uint8_t cfg_num; // current active configuration (0x00 is not configured)
122 uint8_t speed;
123 volatile uint8_t sof_consumer;
124
125 uint8_t itf2drv[CFG_TUD_INTERFACE_MAX]; // map interface number to driver (0xff is invalid)
126 uint8_t ep2drv[CFG_TUD_ENDPPOINT_MAX][2]; // map endpoint to driver ( 0xff is invalid ), can use only 4-bit each
127
128 tu_edpt_state_t ep_status[CFG_TUD_ENDPPOINT_MAX][2];
129
131
133static volatile uint8_t _usbd_queued_setup;
134
135//--------------------------------------------------------------------+
136// Class Driver
137//--------------------------------------------------------------------+
138#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
139 #define DRIVER_NAME(_name) _name
140#else
141 #define DRIVER_NAME(_name) NULL
142#endif
143
144// Built-in class drivers
146 #if CFG_TUD_CDC
147 {
148 .name = DRIVER_NAME("CDC"),
149 .init = cdcd_init,
150 .deinit = cdcd_deinit,
151 .reset = cdcd_reset,
152 .open = cdcd_open,
153 .control_xfer_cb = cdcd_control_xfer_cb,
154 .xfer_cb = cdcd_xfer_cb,
155 .sof = NULL
156 },
157 #endif
158
159 #if CFG_TUD_MSC
160 {
161 .name = DRIVER_NAME("MSC"),
162 .init = mscd_init,
163 .deinit = NULL,
164 .reset = mscd_reset,
165 .open = mscd_open,
166 .control_xfer_cb = mscd_control_xfer_cb,
167 .xfer_cb = mscd_xfer_cb,
168 .sof = NULL
169 },
170 #endif
171
172 #if CFG_TUD_HID
173 {
174 .name = DRIVER_NAME("HID"),
175 .init = hidd_init,
176 .deinit = hidd_deinit,
177 .reset = hidd_reset,
178 .open = hidd_open,
179 .control_xfer_cb = hidd_control_xfer_cb,
180 .xfer_cb = hidd_xfer_cb,
181 .sof = NULL
182 },
183 #endif
184
185 #if CFG_TUD_AUDIO
186 {
187 .name = DRIVER_NAME("AUDIO"),
188 .init = audiod_init,
189 .deinit = audiod_deinit,
190 .reset = audiod_reset,
191 .open = audiod_open,
192 .control_xfer_cb = audiod_control_xfer_cb,
193 .xfer_cb = audiod_xfer_cb,
194 .sof = audiod_sof_isr
195 },
196 #endif
197
198 #if CFG_TUD_VIDEO
199 {
200 .name = DRIVER_NAME("VIDEO"),
201 .init = videod_init,
202 .deinit = videod_deinit,
203 .reset = videod_reset,
204 .open = videod_open,
205 .control_xfer_cb = videod_control_xfer_cb,
206 .xfer_cb = videod_xfer_cb,
207 .sof = NULL
208 },
209 #endif
210
211 #if CFG_TUD_MIDI
212 {
213 .name = DRIVER_NAME("MIDI"),
214 .init = midid_init,
215 .deinit = midid_deinit,
216 .open = midid_open,
217 .reset = midid_reset,
218 .control_xfer_cb = midid_control_xfer_cb,
219 .xfer_cb = midid_xfer_cb,
220 .sof = NULL
221 },
222 #endif
223
224 #if CFG_TUD_VENDOR
225 {
226 .name = DRIVER_NAME("VENDOR"),
227 .init = vendord_init,
228 .deinit = vendord_deinit,
229 .reset = vendord_reset,
230 .open = vendord_open,
231 .control_xfer_cb = tud_vendor_control_xfer_cb,
232 .xfer_cb = vendord_xfer_cb,
233 .sof = NULL
234 },
235 #endif
236
237 #if CFG_TUD_USBTMC
238 {
239 .name = DRIVER_NAME("TMC"),
240 .init = usbtmcd_init_cb,
241 .deinit = usbtmcd_deinit,
242 .reset = usbtmcd_reset_cb,
243 .open = usbtmcd_open_cb,
244 .control_xfer_cb = usbtmcd_control_xfer_cb,
245 .xfer_cb = usbtmcd_xfer_cb,
246 .sof = NULL
247 },
248 #endif
249
250 #if CFG_TUD_DFU_RUNTIME
251 {
252 .name = DRIVER_NAME("DFU-RUNTIME"),
253 .init = dfu_rtd_init,
254 .deinit = dfu_rtd_deinit,
255 .reset = dfu_rtd_reset,
256 .open = dfu_rtd_open,
257 .control_xfer_cb = dfu_rtd_control_xfer_cb,
258 .xfer_cb = NULL,
259 .sof = NULL
260 },
261 #endif
262
263 #if CFG_TUD_DFU
264 {
265 .name = DRIVER_NAME("DFU"),
266 .init = dfu_moded_init,
267 .deinit = dfu_moded_deinit,
268 .reset = dfu_moded_reset,
269 .open = dfu_moded_open,
270 .control_xfer_cb = dfu_moded_control_xfer_cb,
271 .xfer_cb = NULL,
272 .sof = NULL
273 },
274 #endif
275
276 #if CFG_TUD_ECM_RNDIS || CFG_TUD_NCM
277 {
278 .name = DRIVER_NAME("NET"),
279 .init = netd_init,
280 .deinit = netd_deinit,
281 .reset = netd_reset,
282 .open = netd_open,
283 .control_xfer_cb = netd_control_xfer_cb,
284 .xfer_cb = netd_xfer_cb,
285 .sof = NULL,
286 },
287 #endif
288
289 #if CFG_TUD_BTH
290 {
291 .name = DRIVER_NAME("BTH"),
292 .init = btd_init,
293 .deinit = btd_deinit,
294 .reset = btd_reset,
295 .open = btd_open,
296 .control_xfer_cb = btd_control_xfer_cb,
297 .xfer_cb = btd_xfer_cb,
298 .sof = NULL
299 },
300 #endif
301};
302
303enum { BUILTIN_DRIVER_COUNT = TU_ARRAY_SIZE(_usbd_driver) };
304
305// Additional class drivers implemented by application
306tu_static usbd_class_driver_t const * _app_driver = NULL;
307tu_static uint8_t _app_driver_count = 0;
308
309#define TOTAL_DRIVER_COUNT (_app_driver_count + BUILTIN_DRIVER_COUNT)
310
311// virtually joins built-in and application drivers together.
312// Application is positioned first to allow overwriting built-in ones.
313TU_ATTR_ALWAYS_INLINE static inline usbd_class_driver_t const * get_driver(uint8_t drvid) {
314 usbd_class_driver_t const * driver = NULL;
315 if ( drvid < _app_driver_count ) {
316 // Application drivers
317 driver = &_app_driver[drvid];
318 } else if ( drvid < TOTAL_DRIVER_COUNT && BUILTIN_DRIVER_COUNT > 0 ){
319 driver = &_usbd_driver[drvid - _app_driver_count];
320 }
321 return driver;
322}
323
324
325//--------------------------------------------------------------------+
326// DCD Event
327//--------------------------------------------------------------------+
328
329enum { RHPORT_INVALID = 0xFFu };
330tu_static uint8_t _usbd_rhport = RHPORT_INVALID;
331
332// Event queue
333// usbd_int_set() is used as mutex in OS NONE config
334OSAL_QUEUE_DEF(usbd_int_set, _usbd_qdef, CFG_TUD_TASK_QUEUE_SZ, dcd_event_t);
336
337// Mutex for claiming endpoint
338#if OSAL_MUTEX_REQUIRED
341#else
342 #define _usbd_mutex NULL
343#endif
344
345TU_ATTR_ALWAYS_INLINE static inline bool queue_event(dcd_event_t const * event, bool in_isr) {
346 TU_ASSERT(osal_queue_send(_usbd_q, event, in_isr));
347 tud_event_hook_cb(event->rhport, event->event_id, in_isr);
348 return true;
349}
350
351//--------------------------------------------------------------------+
352// Prototypes
353//--------------------------------------------------------------------+
354static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request);
355static bool process_set_config(uint8_t rhport, uint8_t cfg_num);
356static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request);
357
358#if CFG_TUD_TEST_MODE
359static bool process_test_mode_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) {
360 TU_VERIFY(CONTROL_STAGE_ACK == stage);
361 uint8_t const selector = tu_u16_high(request->wIndex);
362 TU_LOG_USBD(" Enter Test Mode (test selector index: %d)\r\n", selector);
364 return true;
365}
366#endif
367
368// from usbd_control.c
369void usbd_control_reset(void);
372bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
373
374
375//--------------------------------------------------------------------+
376// Debug
377//--------------------------------------------------------------------+
378#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
379tu_static char const* const _usbd_event_str[DCD_EVENT_COUNT] = {
380 "Invalid",
381 "Bus Reset",
382 "Unplugged",
383 "SOF",
384 "Suspend",
385 "Resume",
386 "Setup Received",
387 "Xfer Complete",
388 "Func Call"
389};
390
391// for usbd_control to print the name of control complete driver
393 for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) {
394 usbd_class_driver_t const* driver = get_driver(i);
395 if (driver && driver->control_xfer_cb == callback) {
396 TU_LOG_USBD("%s control complete\r\n", driver->name);
397 return;
398 }
399 }
400}
401
402#endif
403
404//--------------------------------------------------------------------+
405// Application API
406//--------------------------------------------------------------------+
409}
410
411bool tud_connected(void) {
412 return _usbd_dev.connected;
413}
414
415bool tud_mounted(void) {
416 return _usbd_dev.cfg_num ? true : false;
417}
418
419bool tud_suspended(void) {
420 return _usbd_dev.suspended;
421}
422
424 // only wake up host if this feature is supported and enabled and we are suspended
425 TU_VERIFY (_usbd_dev.suspended && _usbd_dev.remote_wakeup_support && _usbd_dev.remote_wakeup_en);
427 return true;
428}
429
430bool tud_disconnect(void) {
432 return true;
433}
434
435bool tud_connect(void) {
437 return true;
438}
439
440void tud_sof_cb_enable(bool en) {
441 usbd_sof_enable(_usbd_rhport, SOF_CONSUMER_USER, en);
442}
443
444//--------------------------------------------------------------------+
445// USBD Task
446//--------------------------------------------------------------------+
447bool tud_inited(void) {
449}
450
451bool tud_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
452 if (tud_inited()) {
453 return true; // skip if already initialized
454 }
455 TU_ASSERT(rh_init);
456
457 TU_LOG_USBD("USBD init on controller %u, speed = %s\r\n", rhport,
458 rh_init->speed == TUSB_SPEED_HIGH ? "High" : "Full");
459 TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(usbd_device_t));
460 TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(dcd_event_t));
461 TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_fifo_t));
462 TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_edpt_stream_t));
463
464 tu_varclr(&_usbd_dev);
466
467#if OSAL_MUTEX_REQUIRED
468 // Init device mutex
470 TU_ASSERT(_usbd_mutex);
471#endif
472
473 // Init device queue & task
474 _usbd_q = osal_queue_create(&_usbd_qdef);
475 TU_ASSERT(_usbd_q);
476
477 // Get application driver if available
480 }
481
482 // Init class drivers
483 for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) {
484 usbd_class_driver_t const* driver = get_driver(i);
485 TU_ASSERT(driver && driver->init);
486 TU_LOG_USBD("%s init\r\n", driver->name);
487 driver->init();
488 }
489
490 _usbd_rhport = rhport;
491
492 // Init device controller driver
493 TU_ASSERT(dcd_init(rhport, rh_init));
494 dcd_int_enable(rhport);
495
496 return true;
497}
498
499bool tud_deinit(uint8_t rhport) {
500 if (!tud_inited()) {
501 return true; // skip if not initialized
502 }
503
504 TU_LOG_USBD("USBD deinit on controller %u\r\n", rhport);
505
506 // Deinit device controller driver
507 dcd_int_disable(rhport);
508 dcd_disconnect(rhport);
509 dcd_deinit(rhport);
510
511 // Deinit class drivers
512 for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) {
513 usbd_class_driver_t const* driver = get_driver(i);
514 if(driver && driver->deinit) {
515 TU_LOG_USBD("%s deinit\r\n", driver->name);
516 driver->deinit();
517 }
518 }
519
520 // Deinit device queue & task
522 _usbd_q = NULL;
523
524#if OSAL_MUTEX_REQUIRED
525 // TODO make sure there is no task waiting on this mutex
527 _usbd_mutex = NULL;
528#endif
529
531
532 return true;
533}
534
535static void configuration_reset(uint8_t rhport) {
536 for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) {
537 usbd_class_driver_t const* driver = get_driver(i);
538 TU_ASSERT(driver,);
539 driver->reset(rhport);
540 }
541
542 tu_varclr(&_usbd_dev);
543 memset(_usbd_dev.itf2drv, DRVID_INVALID, sizeof(_usbd_dev.itf2drv)); // invalid mapping
544 memset(_usbd_dev.ep2drv, DRVID_INVALID, sizeof(_usbd_dev.ep2drv)); // invalid mapping
545}
546
547static void usbd_reset(uint8_t rhport) {
548 configuration_reset(rhport);
550}
551
553 // Skip if stack is not initialized
554 if (!tud_inited()) return false;
555 return !osal_queue_empty(_usbd_q);
556}
557
558/* USB Device Driver task
559 * This top level thread manages all device controller event and delegates events to class-specific drivers.
560 * This should be called periodically within the mainloop or rtos thread.
561 *
562 int main(void) {
563 application_init();
564 tusb_init(0, TUSB_ROLE_DEVICE);
565
566 while(1) { // the mainloop
567 application_code();
568 tud_task(); // tinyusb device task
569 }
570 }
571 */
572void tud_task_ext(uint32_t timeout_ms, bool in_isr) {
573 (void) in_isr; // not implemented yet
574
575 // Skip if stack is not initialized
576 if (!tud_inited()) return;
577
578 // Loop until there is no more events in the queue
579 while (1) {
580 dcd_event_t event;
581 if (!osal_queue_receive(_usbd_q, &event, timeout_ms)) return;
582
583#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
584 if (event.event_id == DCD_EVENT_SETUP_RECEIVED) TU_LOG_USBD("\r\n"); // extra line for setup
585 TU_LOG_USBD("USBD %s ", event.event_id < DCD_EVENT_COUNT ? _usbd_event_str[event.event_id] : "CORRUPTED");
586#endif
587
588 switch (event.event_id) {
589 case DCD_EVENT_BUS_RESET:
590 TU_LOG_USBD(": %s Speed\r\n", tu_str_speed[event.bus_reset.speed]);
591 usbd_reset(event.rhport);
592 _usbd_dev.speed = event.bus_reset.speed;
593 break;
594
595 case DCD_EVENT_UNPLUGGED:
596 TU_LOG_USBD("\r\n");
597 usbd_reset(event.rhport);
599 break;
600
601 case DCD_EVENT_SETUP_RECEIVED:
602 TU_ASSERT(_usbd_queued_setup > 0,);
604 TU_LOG_BUF(CFG_TUD_LOG_LEVEL, &event.setup_received, 8);
605 if (_usbd_queued_setup) {
606 TU_LOG_USBD(" Skipped since there is other SETUP in queue\r\n");
607 break;
608 }
609
610 // Mark as connected after receiving 1st setup packet.
611 // But it is easier to set it every time instead of wasting time to check then set
612 _usbd_dev.connected = 1;
613
614 // mark both in & out control as free
619
620 // Process control request
621 if (!process_control_request(event.rhport, &event.setup_received)) {
622 TU_LOG_USBD(" Stall EP0\r\n");
623 // Failed -> stall both control endpoint IN and OUT
624 dcd_edpt_stall(event.rhport, 0);
625 dcd_edpt_stall(event.rhport, 0 | TUSB_DIR_IN_MASK);
626 }
627 break;
628
629 case DCD_EVENT_XFER_COMPLETE: {
630 // Invoke the class callback associated with the endpoint address
631 uint8_t const ep_addr = event.xfer_complete.ep_addr;
632 uint8_t const epnum = tu_edpt_number(ep_addr);
633 uint8_t const ep_dir = tu_edpt_dir(ep_addr);
634
635 TU_LOG_USBD("on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len);
636
637 _usbd_dev.ep_status[epnum][ep_dir].busy = 0;
638 _usbd_dev.ep_status[epnum][ep_dir].claimed = 0;
639
640 if (0 == epnum) {
641 usbd_control_xfer_cb(event.rhport, ep_addr, (xfer_result_t) event.xfer_complete.result,
642 event.xfer_complete.len);
643 } else {
644 usbd_class_driver_t const* driver = get_driver(_usbd_dev.ep2drv[epnum][ep_dir]);
645 TU_ASSERT(driver,);
646
647 TU_LOG_USBD(" %s xfer callback\r\n", driver->name);
648 driver->xfer_cb(event.rhport, ep_addr, (xfer_result_t) event.xfer_complete.result, event.xfer_complete.len);
649 }
650 break;
651 }
652
653 case DCD_EVENT_SUSPEND:
654 // NOTE: When plugging/unplugging device, the D+/D- state are unstable and
655 // can accidentally meet the SUSPEND condition ( Bus Idle for 3ms ), which result in a series of event
656 // e.g suspend -> resume -> unplug/plug. Skip suspend/resume if not connected
657 if (_usbd_dev.connected) {
658 TU_LOG_USBD(": Remote Wakeup = %u\r\n", _usbd_dev.remote_wakeup_en);
659 tud_suspend_cb(_usbd_dev.remote_wakeup_en);
660 } else {
661 TU_LOG_USBD(" Skipped\r\n");
662 }
663 break;
664
665 case DCD_EVENT_RESUME:
666 if (_usbd_dev.connected) {
667 TU_LOG_USBD("\r\n");
669 } else {
670 TU_LOG_USBD(" Skipped\r\n");
671 }
672 break;
673
674 case USBD_EVENT_FUNC_CALL:
675 TU_LOG_USBD("\r\n");
676 if (event.func_call.func) event.func_call.func(event.func_call.param);
677 break;
678
679 case DCD_EVENT_SOF:
680 if (tu_bit_test(_usbd_dev.sof_consumer, SOF_CONSUMER_USER)) {
681 TU_LOG_USBD("\r\n");
682 tud_sof_cb(event.sof.frame_count);
683 }
684 break;
685
686 default:
687 TU_BREAKPOINT();
688 break;
689 }
690
691#if CFG_TUSB_OS != OPT_OS_NONE && CFG_TUSB_OS != OPT_OS_PICO
692 // return if there is no more events, for application to run other background
693 if (osal_queue_empty(_usbd_q)) return;
694#endif
695 }
696}
697
698//--------------------------------------------------------------------+
699// Control Request Parser & Handling
700//--------------------------------------------------------------------+
701
702// Helper to invoke class driver control request handler
703static bool invoke_class_control(uint8_t rhport, usbd_class_driver_t const * driver, tusb_control_request_t const * request) {
705 TU_LOG_USBD(" %s control request\r\n", driver->name);
706 return driver->control_xfer_cb(rhport, CONTROL_STAGE_SETUP, request);
707}
708
709// This handles the actual request and its response.
710// Returns false if unable to complete the request, causing caller to stall control endpoints.
711static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request) {
713 TU_ASSERT(p_request->bmRequestType_bit.type < TUSB_REQ_TYPE_INVALID);
714
715 // Vendor request
716 if ( p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR ) {
718 return tud_vendor_control_xfer_cb(rhport, CONTROL_STAGE_SETUP, p_request);
719 }
720
721#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
722 if (TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type && p_request->bRequest <= TUSB_REQ_SYNCH_FRAME) {
723 TU_LOG_USBD(" %s", tu_str_std_request[p_request->bRequest]);
724 if (TUSB_REQ_GET_DESCRIPTOR != p_request->bRequest) TU_LOG_USBD("\r\n");
725 }
726#endif
727
728 switch ( p_request->bmRequestType_bit.recipient ) {
729 //------------- Device Requests e.g in enumeration -------------//
731 if ( TUSB_REQ_TYPE_CLASS == p_request->bmRequestType_bit.type ) {
732 uint8_t const itf = tu_u16_low(p_request->wIndex);
733 TU_VERIFY(itf < TU_ARRAY_SIZE(_usbd_dev.itf2drv));
734
735 usbd_class_driver_t const * driver = get_driver(_usbd_dev.itf2drv[itf]);
736 TU_VERIFY(driver);
737
738 // forward to class driver: "non-STD request to Interface"
739 return invoke_class_control(rhport, driver, p_request);
740 }
741
742 if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) {
743 // Non-standard request is not supported
744 TU_BREAKPOINT();
745 return false;
746 }
747
748 switch ( p_request->bRequest ) {
750 // Depending on mcu, status phase could be sent either before or after changing device address,
751 // or even require stack to not response with status at all
752 // Therefore DCD must take full responsibility to response and include zlp status packet if needed.
753 usbd_control_set_request(p_request); // set request since DCD has no access to tud_control_status() API
754 dcd_set_address(rhport, (uint8_t) p_request->wValue);
755 // skip tud_control_status()
756 _usbd_dev.addressed = 1;
757 break;
758
760 uint8_t cfg_num = _usbd_dev.cfg_num;
761 tud_control_xfer(rhport, p_request, &cfg_num, 1);
762 }
763 break;
764
766 uint8_t const cfg_num = (uint8_t) p_request->wValue;
767
768 // Only process if new configure is different
769 if (_usbd_dev.cfg_num != cfg_num) {
770 if ( _usbd_dev.cfg_num ) {
771 // already configured: need to clear all endpoints and driver first
772 TU_LOG_USBD(" Clear current Configuration (%u) before switching\r\n", _usbd_dev.cfg_num);
773
774 // disable SOF
775 dcd_sof_enable(rhport, false);
776
777 // close all non-control endpoints, cancel all pending transfers if any
778 dcd_edpt_close_all(rhport);
779
780 // close all drivers and current configured state except bus speed
781 uint8_t const speed = _usbd_dev.speed;
782 configuration_reset(rhport);
783
784 _usbd_dev.speed = speed; // restore speed
785 }
786
787 _usbd_dev.cfg_num = cfg_num;
788
789 // Handle the new configuration and execute the corresponding callback
790 if ( cfg_num ) {
791 // switch to new configuration if not zero
792 if (!process_set_config(rhport, cfg_num)) {
793 TU_MESS_FAILED();
794 TU_BREAKPOINT();
795 _usbd_dev.cfg_num = 0;
796 return false;
797 }
798 tud_mount_cb();
799 } else {
801 }
802 }
803
804 tud_control_status(rhport, p_request);
805 }
806 break;
807
809 TU_VERIFY( process_get_descriptor(rhport, p_request) );
810 break;
811
813 switch(p_request->wValue) {
815 TU_LOG_USBD(" Enable Remote Wakeup\r\n");
816 // Host may enable remote wake up before suspending especially HID device
817 _usbd_dev.remote_wakeup_en = true;
818 tud_control_status(rhport, p_request);
819 break;
820
821 #if CFG_TUD_TEST_MODE
823 // Only handle the test mode if supported and valid
824 TU_VERIFY(0 == tu_u16_low(p_request->wIndex));
825
826 uint8_t const selector = tu_u16_high(p_request->wIndex);
827 TU_VERIFY(TUSB_FEATURE_TEST_J <= selector && selector <= TUSB_FEATURE_TEST_FORCE_ENABLE);
828
830 tud_control_status(rhport, p_request);
831 break;
832 }
833 #endif /* CFG_TUD_TEST_MODE */
834
835 // Stall unsupported feature selector
836 default: return false;
837 }
838 break;
839
841 // Only support remote wakeup for device feature
842 TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue);
843
844 TU_LOG_USBD(" Disable Remote Wakeup\r\n");
845
846 // Host may disable remote wake up after resuming
847 _usbd_dev.remote_wakeup_en = false;
848 tud_control_status(rhport, p_request);
849 break;
850
851 case TUSB_REQ_GET_STATUS: {
852 // Device status bit mask
853 // - Bit 0: Self Powered
854 // - Bit 1: Remote Wakeup enabled
855 uint16_t status = (uint16_t) ((_usbd_dev.self_powered ? 1u : 0u) | (_usbd_dev.remote_wakeup_en ? 2u : 0u));
856 tud_control_xfer(rhport, p_request, &status, 2);
857 break;
858 }
859
860 // Unknown/Unsupported request
861 default: TU_BREAKPOINT(); return false;
862 }
863 break;
864
865 //------------- Class/Interface Specific Request -------------//
867 uint8_t const itf = tu_u16_low(p_request->wIndex);
868 TU_VERIFY(itf < TU_ARRAY_SIZE(_usbd_dev.itf2drv));
869
870 usbd_class_driver_t const * driver = get_driver(_usbd_dev.itf2drv[itf]);
871 TU_VERIFY(driver);
872
873 // all requests to Interface (STD or Class) is forwarded to class driver.
874 // notable requests are: GET HID REPORT DESCRIPTOR, SET_INTERFACE, GET_INTERFACE
875 if ( !invoke_class_control(rhport, driver, p_request) ) {
876 // For GET_INTERFACE and SET_INTERFACE, it is mandatory to respond even if the class
877 // driver doesn't use alternate settings or implement this
878 TU_VERIFY(TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type);
879
880 switch(p_request->bRequest) {
883 // Clear complete callback if driver set since it can also stall the request.
885
886 if (TUSB_REQ_GET_INTERFACE == p_request->bRequest) {
887 uint8_t alternate = 0;
888 tud_control_xfer(rhport, p_request, &alternate, 1);
889 }else {
890 tud_control_status(rhport, p_request);
891 }
892 break;
893
894 default: return false;
895 }
896 }
897 break;
898 }
899
900 //------------- Endpoint Request -------------//
902 uint8_t const ep_addr = tu_u16_low(p_request->wIndex);
903 uint8_t const ep_num = tu_edpt_number(ep_addr);
904 uint8_t const ep_dir = tu_edpt_dir(ep_addr);
905
906 TU_ASSERT(ep_num < TU_ARRAY_SIZE(_usbd_dev.ep2drv) );
907 usbd_class_driver_t const * driver = get_driver(_usbd_dev.ep2drv[ep_num][ep_dir]);
908
909 if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type ) {
910 // Forward class request to its driver
911 TU_VERIFY(driver);
912 return invoke_class_control(rhport, driver, p_request);
913 } else {
914 // Handle STD request to endpoint
915 switch ( p_request->bRequest ) {
916 case TUSB_REQ_GET_STATUS: {
917 uint16_t status = usbd_edpt_stalled(rhport, ep_addr) ? 0x0001 : 0x0000;
918 tud_control_xfer(rhport, p_request, &status, 2);
919 }
920 break;
921
924 if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue ) {
925 if ( TUSB_REQ_CLEAR_FEATURE == p_request->bRequest ) {
926 usbd_edpt_clear_stall(rhport, ep_addr);
927 }else {
928 usbd_edpt_stall(rhport, ep_addr);
929 }
930 }
931
932 if (driver) {
933 // Some classes such as USBTMC needs to clear/re-init its buffer when receiving CLEAR_FEATURE request
934 // We will also forward std request targeted endpoint to class drivers as well
935
936 // STD request must always be ACKed regardless of driver returned value
937 // Also clear complete callback if driver set since it can also stall the request.
938 (void) invoke_class_control(rhport, driver, p_request);
940
941 // skip ZLP status if driver already did that
942 if ( !_usbd_dev.ep_status[0][TUSB_DIR_IN].busy ) tud_control_status(rhport, p_request);
943 }
944 }
945 break;
946
947 // Unknown/Unsupported request
948 default:
949 TU_BREAKPOINT();
950 return false;
951 }
952 }
953 }
954 break;
955
956 // Unknown recipient
957 default:
958 TU_BREAKPOINT();
959 return false;
960 }
961
962 return true;
963}
964
965// Process Set Configure Request
966// This function parse configuration descriptor & open drivers accordingly
967static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
968{
969 // index is cfg_num-1
971 TU_ASSERT(desc_cfg != NULL && desc_cfg->bDescriptorType == TUSB_DESC_CONFIGURATION);
972
973 // Parse configuration descriptor
974 _usbd_dev.remote_wakeup_support = (desc_cfg->bmAttributes & TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP) ? 1u : 0u;
975 _usbd_dev.self_powered = (desc_cfg->bmAttributes & TUSB_DESC_CONFIG_ATT_SELF_POWERED ) ? 1u : 0u;
976
977 // Parse interface descriptor
978 uint8_t const * p_desc = ((uint8_t const*) desc_cfg) + sizeof(tusb_desc_configuration_t);
979 uint8_t const * desc_end = ((uint8_t const*) desc_cfg) + tu_le16toh(desc_cfg->wTotalLength);
980
981 while( p_desc < desc_end )
982 {
983 uint8_t assoc_itf_count = 1;
984
985 // Class will always starts with Interface Association (if any) and then Interface descriptor
987 {
988 tusb_desc_interface_assoc_t const * desc_iad = (tusb_desc_interface_assoc_t const *) p_desc;
989 assoc_itf_count = desc_iad->bInterfaceCount;
990
991 p_desc = tu_desc_next(p_desc); // next to Interface
992
993 // IAD's first interface number and class should match with opened interface
994 //TU_ASSERT(desc_iad->bFirstInterface == desc_itf->bInterfaceNumber &&
995 // desc_iad->bFunctionClass == desc_itf->bInterfaceClass);
996 }
997
998 TU_ASSERT( TUSB_DESC_INTERFACE == tu_desc_type(p_desc) );
999 tusb_desc_interface_t const * desc_itf = (tusb_desc_interface_t const*) p_desc;
1000
1001 // Find driver for this interface
1002 uint16_t const remaining_len = (uint16_t) (desc_end-p_desc);
1003 uint8_t drv_id;
1004 for (drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++)
1005 {
1006 usbd_class_driver_t const *driver = get_driver(drv_id);
1007 TU_ASSERT(driver);
1008 uint16_t const drv_len = driver->open(rhport, desc_itf, remaining_len);
1009
1010 if ( (sizeof(tusb_desc_interface_t) <= drv_len) && (drv_len <= remaining_len) )
1011 {
1012 // Open successfully
1013 TU_LOG_USBD(" %s opened\r\n", driver->name);
1014
1015 // Some drivers use 2 or more interfaces but may not have IAD e.g MIDI (always) or
1016 // BTH (even CDC) with class in device descriptor (single interface)
1017 if ( assoc_itf_count == 1)
1018 {
1019 #if CFG_TUD_CDC
1020 if ( driver->open == cdcd_open ) assoc_itf_count = 2;
1021 #endif
1022
1023 #if CFG_TUD_MIDI
1024 if ( driver->open == midid_open ) assoc_itf_count = 2;
1025 #endif
1026
1027 #if CFG_TUD_BTH && CFG_TUD_BTH_ISO_ALT_COUNT
1028 if ( driver->open == btd_open ) assoc_itf_count = 2;
1029 #endif
1030 }
1031
1032 // bind (associated) interfaces to found driver
1033 for(uint8_t i=0; i<assoc_itf_count; i++)
1034 {
1035 uint8_t const itf_num = desc_itf->bInterfaceNumber+i;
1036
1037 // Interface number must not be used already
1038 TU_ASSERT(DRVID_INVALID == _usbd_dev.itf2drv[itf_num]);
1039 _usbd_dev.itf2drv[itf_num] = drv_id;
1040 }
1041
1042 // bind all endpoints to found driver
1043 tu_edpt_bind_driver(_usbd_dev.ep2drv, desc_itf, drv_len, drv_id);
1044
1045 // next Interface
1046 p_desc += drv_len;
1047
1048 break; // exit driver find loop
1049 }
1050 }
1051
1052 // Failed if there is no supported drivers
1053 TU_ASSERT(drv_id < TOTAL_DRIVER_COUNT);
1054 }
1055
1056 return true;
1057}
1058
1059// return descriptor's buffer and update desc_len
1060static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request)
1061{
1062 tusb_desc_type_t const desc_type = (tusb_desc_type_t) tu_u16_high(p_request->wValue);
1063 uint8_t const desc_index = tu_u16_low( p_request->wValue );
1064
1065 switch(desc_type)
1066 {
1067 case TUSB_DESC_DEVICE: {
1068 TU_LOG_USBD(" Device\r\n");
1069
1070 void* desc_device = (void*) (uintptr_t) tud_descriptor_device_cb();
1071 TU_ASSERT(desc_device);
1072
1073 // Only response with exactly 1 Packet if: not addressed and host requested more data than device descriptor has.
1074 // This only happens with the very first get device descriptor and EP0 size = 8 or 16.
1075 if ((CFG_TUD_ENDPOINT0_SIZE < sizeof(tusb_desc_device_t)) && !_usbd_dev.addressed &&
1076 ((tusb_control_request_t const*) p_request)->wLength > sizeof(tusb_desc_device_t)) {
1077 // Hack here: we modify the request length to prevent usbd_control response with zlp
1078 // since we are responding with 1 packet & less data than wLength.
1079 tusb_control_request_t mod_request = *p_request;
1080 mod_request.wLength = CFG_TUD_ENDPOINT0_SIZE;
1081
1082 return tud_control_xfer(rhport, &mod_request, desc_device, CFG_TUD_ENDPOINT0_SIZE);
1083 }else {
1084 return tud_control_xfer(rhport, p_request, desc_device, sizeof(tusb_desc_device_t));
1085 }
1086 }
1087 // break; // unreachable
1088
1089 case TUSB_DESC_BOS: {
1090 TU_LOG_USBD(" BOS\r\n");
1091
1092 // requested by host if USB > 2.0 ( i.e 2.1 or 3.x )
1093 uintptr_t desc_bos = (uintptr_t) tud_descriptor_bos_cb();
1094 TU_VERIFY(desc_bos);
1095
1096 // Use offsetof to avoid pointer to the odd/misaligned address
1097 uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_bos + offsetof(tusb_desc_bos_t, wTotalLength))) );
1098
1099 return tud_control_xfer(rhport, p_request, (void*) desc_bos, total_len);
1100 }
1101 // break; // unreachable
1102
1105 uintptr_t desc_config;
1106
1107 if ( desc_type == TUSB_DESC_CONFIGURATION ) {
1108 TU_LOG_USBD(" Configuration[%u]\r\n", desc_index);
1109 desc_config = (uintptr_t) tud_descriptor_configuration_cb(desc_index);
1110 TU_ASSERT(desc_config);
1111 }else {
1112 // Host only request this after getting Device Qualifier descriptor
1113 TU_LOG_USBD(" Other Speed Configuration\r\n");
1114 desc_config = (uintptr_t) tud_descriptor_other_speed_configuration_cb(desc_index);
1115 TU_VERIFY(desc_config);
1116 }
1117
1118 // Use offsetof to avoid pointer to the odd/misaligned address
1119 uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_config + offsetof(tusb_desc_configuration_t, wTotalLength))) );
1120
1121 return tud_control_xfer(rhport, p_request, (void*) desc_config, total_len);
1122 }
1123 // break; // unreachable
1124
1125 case TUSB_DESC_STRING:
1126 {
1127 TU_LOG_USBD(" String[%u]\r\n", desc_index);
1128
1129 // String Descriptor always uses the desc set from user
1130 uint8_t const* desc_str = (uint8_t const*) tud_descriptor_string_cb(desc_index, tu_le16toh(p_request->wIndex));
1131 TU_VERIFY(desc_str);
1132
1133 // first byte of descriptor is its size
1134 return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_str, tu_desc_len(desc_str));
1135 }
1136 // break; // unreachable
1137
1139 TU_LOG_USBD(" Device Qualifier\r\n");
1140 uint8_t const* desc_qualifier = tud_descriptor_device_qualifier_cb();
1141 TU_VERIFY(desc_qualifier);
1142 return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_qualifier, tu_desc_len(desc_qualifier));
1143 }
1144 // break; // unreachable
1145
1146 default: return false;
1147 }
1148}
1149
1150//--------------------------------------------------------------------+
1151// DCD Event Handler
1152//--------------------------------------------------------------------+
1153TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const* event, bool in_isr) {
1154 bool send = false;
1155 switch (event->event_id) {
1156 case DCD_EVENT_UNPLUGGED:
1157 _usbd_dev.connected = 0;
1158 _usbd_dev.addressed = 0;
1159 _usbd_dev.cfg_num = 0;
1160 _usbd_dev.suspended = 0;
1161 send = true;
1162 break;
1163
1164 case DCD_EVENT_SUSPEND:
1165 // NOTE: When plugging/unplugging device, the D+/D- state are unstable and
1166 // can accidentally meet the SUSPEND condition ( Bus Idle for 3ms ).
1167 // In addition, some MCUs such as SAMD or boards that haven no VBUS detection cannot distinguish
1168 // suspended vs disconnected. We will skip handling SUSPEND/RESUME event if not currently connected
1169 if (_usbd_dev.connected) {
1170 _usbd_dev.suspended = 1;
1171 send = true;
1172 }
1173 break;
1174
1175 case DCD_EVENT_RESUME:
1176 // skip event if not connected (especially required for SAMD)
1177 if (_usbd_dev.connected) {
1178 _usbd_dev.suspended = 0;
1179 send = true;
1180 }
1181 break;
1182
1183 case DCD_EVENT_SOF:
1184 // SOF driver handler in ISR context
1185 for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) {
1186 usbd_class_driver_t const* driver = get_driver(i);
1187 if (driver && driver->sof) {
1188 driver->sof(event->rhport, event->sof.frame_count);
1189 }
1190 }
1191
1192 // Some MCUs after running dcd_remote_wakeup() does not have way to detect the end of remote wakeup
1193 // which last 1-15 ms. DCD can use SOF as a clear indicator that bus is back to operational
1194 if (_usbd_dev.suspended) {
1195 _usbd_dev.suspended = 0;
1196
1197 dcd_event_t const event_resume = {.rhport = event->rhport, .event_id = DCD_EVENT_RESUME};
1198 queue_event(&event_resume, in_isr);
1199 }
1200
1201 if (tu_bit_test(_usbd_dev.sof_consumer, SOF_CONSUMER_USER)) {
1202 dcd_event_t const event_sof = {.rhport = event->rhport, .event_id = DCD_EVENT_SOF, .sof.frame_count = event->sof.frame_count};
1203 queue_event(&event_sof, in_isr);
1204 }
1205 break;
1206
1207 case DCD_EVENT_SETUP_RECEIVED:
1209 send = true;
1210 break;
1211
1212 default:
1213 send = true;
1214 break;
1215 }
1216
1217 if (send) {
1218 queue_event(event, in_isr);
1219 }
1220}
1221
1222//--------------------------------------------------------------------+
1223// USBD API For Class Driver
1224//--------------------------------------------------------------------+
1225
1226void usbd_int_set(bool enabled)
1227{
1228 if (enabled)
1229 {
1231 }else
1232 {
1234 }
1235}
1236
1237// Parse consecutive endpoint descriptors (IN & OUT)
1238bool usbd_open_edpt_pair(uint8_t rhport, uint8_t const* p_desc, uint8_t ep_count, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in)
1239{
1240 for(int i=0; i<ep_count; i++)
1241 {
1242 tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
1243
1244 TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && xfer_type == desc_ep->bmAttributes.xfer);
1245 TU_ASSERT(usbd_edpt_open(rhport, desc_ep));
1246
1247 if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN )
1248 {
1249 (*ep_in) = desc_ep->bEndpointAddress;
1250 }else
1251 {
1252 (*ep_out) = desc_ep->bEndpointAddress;
1253 }
1254
1255 p_desc = tu_desc_next(p_desc);
1256 }
1257
1258 return true;
1259}
1260
1261// Helper to defer an isr function
1262void usbd_defer_func(osal_task_func_t func, void* param, bool in_isr) {
1263 dcd_event_t event = {
1264 .rhport = 0,
1265 .event_id = USBD_EVENT_FUNC_CALL,
1266 };
1267 event.func_call.func = func;
1268 event.func_call.param = param;
1269
1270 queue_event(&event, in_isr);
1271}
1272
1273//--------------------------------------------------------------------+
1274// USBD Endpoint API
1275//--------------------------------------------------------------------+
1276
1277bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) {
1278 rhport = _usbd_rhport;
1279
1280 TU_ASSERT(tu_edpt_number(desc_ep->bEndpointAddress) < CFG_TUD_ENDPPOINT_MAX);
1281 TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) _usbd_dev.speed));
1282
1283 return dcd_edpt_open(rhport, desc_ep);
1284}
1285
1286bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr) {
1287 (void) rhport;
1288
1289 // TODO add this check later, also make sure we don't starve an out endpoint while suspending
1290 // TU_VERIFY(tud_ready());
1291
1292 uint8_t const epnum = tu_edpt_number(ep_addr);
1293 uint8_t const dir = tu_edpt_dir(ep_addr);
1294 tu_edpt_state_t* ep_state = &_usbd_dev.ep_status[epnum][dir];
1295
1296 return tu_edpt_claim(ep_state, _usbd_mutex);
1297}
1298
1299bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr) {
1300 (void) rhport;
1301
1302 uint8_t const epnum = tu_edpt_number(ep_addr);
1303 uint8_t const dir = tu_edpt_dir(ep_addr);
1304 tu_edpt_state_t* ep_state = &_usbd_dev.ep_status[epnum][dir];
1305
1306 return tu_edpt_release(ep_state, _usbd_mutex);
1307}
1308
1309bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
1310 rhport = _usbd_rhport;
1311
1312 uint8_t const epnum = tu_edpt_number(ep_addr);
1313 uint8_t const dir = tu_edpt_dir(ep_addr);
1314
1315 // TODO skip ready() check for now since enumeration also use this API
1316 // TU_VERIFY(tud_ready());
1317
1318 TU_LOG_USBD(" Queue EP %02X with %u bytes ...\r\n", ep_addr, total_bytes);
1319#if CFG_TUD_LOG_LEVEL >= 3
1320 if(dir == TUSB_DIR_IN) {
1321 TU_LOG_MEM(CFG_TUD_LOG_LEVEL, buffer, total_bytes, 2);
1322 }
1323#endif
1324
1325 // Attempt to transfer on a busy endpoint, sound like an race condition !
1326 TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0);
1327
1328 // Set busy first since the actual transfer can be complete before dcd_edpt_xfer()
1329 // could return and USBD task can preempt and clear the busy
1330 _usbd_dev.ep_status[epnum][dir].busy = 1;
1331
1332 if (dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes)) {
1333 return true;
1334 } else {
1335 // DCD error, mark endpoint as ready to allow next transfer
1336 _usbd_dev.ep_status[epnum][dir].busy = 0;
1337 _usbd_dev.ep_status[epnum][dir].claimed = 0;
1338 TU_LOG_USBD("FAILED\r\n");
1339 TU_BREAKPOINT();
1340 return false;
1341 }
1342}
1343
1344// The number of bytes has to be given explicitly to allow more flexible control of how many
1345// bytes should be written and second to keep the return value free to give back a boolean
1346// success message. If total_bytes is too big, the FIFO will copy only what is available
1347// into the USB buffer!
1348bool usbd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t total_bytes) {
1349 rhport = _usbd_rhport;
1350
1351 uint8_t const epnum = tu_edpt_number(ep_addr);
1352 uint8_t const dir = tu_edpt_dir(ep_addr);
1353
1354 TU_LOG_USBD(" Queue ISO EP %02X with %u bytes ... ", ep_addr, total_bytes);
1355
1356 // Attempt to transfer on a busy endpoint, sound like an race condition !
1357 TU_ASSERT(_usbd_dev.ep_status[epnum][dir].busy == 0);
1358
1359 // Set busy first since the actual transfer can be complete before dcd_edpt_xfer() could return
1360 // and usbd task can preempt and clear the busy
1361 _usbd_dev.ep_status[epnum][dir].busy = 1;
1362
1363 if (dcd_edpt_xfer_fifo(rhport, ep_addr, ff, total_bytes)) {
1364 TU_LOG_USBD("OK\r\n");
1365 return true;
1366 } else {
1367 // DCD error, mark endpoint as ready to allow next transfer
1368 _usbd_dev.ep_status[epnum][dir].busy = 0;
1369 _usbd_dev.ep_status[epnum][dir].claimed = 0;
1370 TU_LOG_USBD("failed\r\n");
1371 TU_BREAKPOINT();
1372 return false;
1373 }
1374}
1375
1376bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr) {
1377 (void) rhport;
1378
1379 uint8_t const epnum = tu_edpt_number(ep_addr);
1380 uint8_t const dir = tu_edpt_dir(ep_addr);
1381
1382 return _usbd_dev.ep_status[epnum][dir].busy;
1383}
1384
1385void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
1386 rhport = _usbd_rhport;
1387
1388 uint8_t const epnum = tu_edpt_number(ep_addr);
1389 uint8_t const dir = tu_edpt_dir(ep_addr);
1390
1391 // only stalled if currently cleared
1392 TU_LOG_USBD(" Stall EP %02X\r\n", ep_addr);
1393 dcd_edpt_stall(rhport, ep_addr);
1394 _usbd_dev.ep_status[epnum][dir].stalled = 1;
1395 _usbd_dev.ep_status[epnum][dir].busy = 1;
1396}
1397
1398void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
1399 rhport = _usbd_rhport;
1400
1401 uint8_t const epnum = tu_edpt_number(ep_addr);
1402 uint8_t const dir = tu_edpt_dir(ep_addr);
1403
1404 // only clear if currently stalled
1405 TU_LOG_USBD(" Clear Stall EP %02X\r\n", ep_addr);
1406 dcd_edpt_clear_stall(rhport, ep_addr);
1407 _usbd_dev.ep_status[epnum][dir].stalled = 0;
1408 _usbd_dev.ep_status[epnum][dir].busy = 0;
1409}
1410
1411bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr) {
1412 (void) rhport;
1413
1414 uint8_t const epnum = tu_edpt_number(ep_addr);
1415 uint8_t const dir = tu_edpt_dir(ep_addr);
1416
1417 return _usbd_dev.ep_status[epnum][dir].stalled;
1418}
1419
1424void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
1425#ifdef TUP_DCD_EDPT_ISO_ALLOC
1426 (void) rhport; (void) ep_addr;
1427 // ISO alloc/activate Should be used instead
1428#else
1429 rhport = _usbd_rhport;
1430
1431 TU_LOG_USBD(" CLOSING Endpoint: 0x%02X\r\n", ep_addr);
1432
1433 uint8_t const epnum = tu_edpt_number(ep_addr);
1434 uint8_t const dir = tu_edpt_dir(ep_addr);
1435
1436 dcd_edpt_close(rhport, ep_addr);
1437 _usbd_dev.ep_status[epnum][dir].stalled = 0;
1438 _usbd_dev.ep_status[epnum][dir].busy = 0;
1439 _usbd_dev.ep_status[epnum][dir].claimed = 0;
1440#endif
1441
1442 return;
1443}
1444
1445void usbd_sof_enable(uint8_t rhport, sof_consumer_t consumer, bool en) {
1446 rhport = _usbd_rhport;
1447
1448 uint8_t consumer_old = _usbd_dev.sof_consumer;
1449 // Keep track how many class instances need the SOF interrupt
1450 if (en) {
1451 _usbd_dev.sof_consumer |= (uint8_t)(1 << consumer);
1452 } else {
1453 _usbd_dev.sof_consumer &= (uint8_t)(~(1 << consumer));
1454 }
1455
1456 // Test logically unequal
1457 if(!_usbd_dev.sof_consumer != !consumer_old) {
1459 }
1460}
1461
1462bool usbd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) {
1463#ifdef TUP_DCD_EDPT_ISO_ALLOC
1464 rhport = _usbd_rhport;
1465
1466 TU_ASSERT(tu_edpt_number(ep_addr) < CFG_TUD_ENDPPOINT_MAX);
1467 return dcd_edpt_iso_alloc(rhport, ep_addr, largest_packet_size);
1468#else
1469 (void) rhport; (void) ep_addr; (void) largest_packet_size;
1470 return false;
1471#endif
1472}
1473
1474bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) {
1475#ifdef TUP_DCD_EDPT_ISO_ALLOC
1476 rhport = _usbd_rhport;
1477
1478 uint8_t const epnum = tu_edpt_number(desc_ep->bEndpointAddress);
1479 uint8_t const dir = tu_edpt_dir(desc_ep->bEndpointAddress);
1480
1481 TU_ASSERT(epnum < CFG_TUD_ENDPPOINT_MAX);
1482 TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) _usbd_dev.speed));
1483
1484 _usbd_dev.ep_status[epnum][dir].stalled = 0;
1485 _usbd_dev.ep_status[epnum][dir].busy = 0;
1486 _usbd_dev.ep_status[epnum][dir].claimed = 0;
1487 return dcd_edpt_iso_activate(rhport, desc_ep);
1488#else
1489 (void) rhport; (void) desc_ep;
1490 return false;
1491#endif
1492}
1493
1494#endif
void btd_init(void)
Definition: bth_device.c:98
void btd_reset(uint8_t rhport)
Definition: bth_device.c:106
bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
Definition: bth_device.c:218
bool btd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
Definition: bth_device.c:259
uint16_t btd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
Definition: bth_device.c:111
bool btd_deinit(void)
Definition: bth_device.c:102
uint16_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
Definition: cdc_device.c:295
bool cdcd_deinit(void)
Definition: cdc_device.c:260
void cdcd_reset(uint8_t rhport)
Definition: cdc_device.c:282
void cdcd_init(void)
Definition: cdc_device.c:226
bool cdcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
Definition: cdc_device.c:355
bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
Definition: cdc_device.c:426
bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep)
Definition: dcd_musb.c:707
bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes) TU_ATTR_WEAK
Definition: dcd_ft9xx.c:894
void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
Definition: dcd_ft9xx.c:905
void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr)
Definition: dcd_ci_fs.c:402
void dcd_enter_test_mode(uint8_t rhport, tusb_feature_test_mode_t test_selector)
Definition: dcd_dwc2.c:1008
void dcd_edpt_close_all(uint8_t rhport)
Definition: dcd_ft9xx.c:802
void dcd_int_disable(uint8_t rhport)
Definition: dcd_samd.c:138
void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
Definition: dcd_ft9xx.c:927
bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
Definition: dcd_ft9xx.c:810
dcd_event_t
Definition: dcd.h:86
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
Definition: dcd_ft9xx.c:553
bool dcd_init(uint8_t rhport, const tusb_rhport_init_t *rh_init)
Definition: dcd_ft9xx.c:520
bool dcd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size)
Definition: dcd_musb.c:697
void dcd_int_enable(uint8_t rhport)
Definition: dcd_samd.c:132
void dcd_remote_wakeup(uint8_t rhport)
Definition: dcd_ft9xx.c:593
void dcd_sof_enable(uint8_t rhport, bool en)
Definition: dcd_ft9xx.c:661
bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep)
Definition: dcd_ft9xx.c:674
static bool in_isr
uint16_t total_bytes
Definition: dcd_nuc505.c:113
void dfu_moded_init(void)
Definition: dfu_device.c:163
bool dfu_moded_deinit(void)
Definition: dfu_device.c:167
uint16_t dfu_moded_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
Definition: dfu_device.c:171
bool dfu_moded_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
Definition: dfu_device.c:214
void dfu_moded_reset(uint8_t rhport)
Definition: dfu_device.c:153
void dfu_rtd_init(void)
Definition: dfu_rt_device.c:54
uint16_t dfu_rtd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
Definition: dfu_rt_device.c:66
bool dfu_rtd_deinit(void)
Definition: dfu_rt_device.c:57
bool dfu_rtd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
Definition: dfu_rt_device.c:90
void dfu_rtd_reset(uint8_t rhport)
Definition: dfu_rt_device.c:61
void netd_reset(uint8_t rhport)
uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
bool netd_deinit(void)
void netd_init(void)
uint16_t const * tud_descriptor_string_cb(uint8_t index, uint16_t langid)
uint8_t const * tud_descriptor_device_cb(void)
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
uint16_t audiod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
TU_ATTR_FAST_FUNC void audiod_sof_isr(uint8_t rhport, uint32_t frame_count)
bool audiod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
bool audiod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
void audiod_init(void)
bool audiod_deinit(void)
void audiod_reset(uint8_t rhport)
void hidd_reset(uint8_t rhport)
Definition: hid_device.c:203
void hidd_init(void)
Definition: hid_device.c:195
uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
Definition: hid_device.c:208
bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
Definition: hid_device.c:373
bool hidd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
Definition: hid_device.c:262
bool hidd_deinit(void)
Definition: hid_device.c:199
void midid_init(void)
Definition: midi_device.c:376
bool midid_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
Definition: midi_device.c:522
uint16_t midid_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
Definition: midi_device.c:432
void midid_reset(uint8_t rhport)
Definition: midi_device.c:419
bool midid_deinit(void)
Definition: midi_device.c:397
bool midid_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
Definition: midi_device.c:512
uint8_t const * buffer
Definition: midi_device.h:100
bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
Definition: msc_device.c:393
void mscd_reset(uint8_t rhport)
Definition: msc_device.c:263
bool mscd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
Definition: msc_device.c:308
uint16_t mscd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
Definition: msc_device.c:269
void mscd_init(void)
Definition: msc_device.c:254
static TU_ATTR_ALWAYS_INLINE bool osal_queue_empty(osal_queue_t qhdl)
static TU_ATTR_ALWAYS_INLINE osal_queue_t osal_queue_create(osal_queue_def_t *qdef)
StaticSemaphore_t osal_mutex_def_t
Definition: osal_freertos.h:46
QueueHandle_t osal_queue_t
Definition: osal_freertos.h:55
static TU_ATTR_ALWAYS_INLINE bool osal_queue_send(osal_queue_t qhdl, void const *data, bool in_isr)
static TU_ATTR_ALWAYS_INLINE bool osal_mutex_delete(osal_mutex_t mutex_hdl)
static TU_ATTR_ALWAYS_INLINE bool osal_queue_receive(osal_queue_t qhdl, void *data, uint32_t msec)
static TU_ATTR_ALWAYS_INLINE bool osal_queue_delete(osal_queue_t qhdl)
SemaphoreHandle_t osal_mutex_t
Definition: osal_freertos.h:54
static TU_ATTR_ALWAYS_INLINE osal_mutex_t osal_mutex_create(osal_mutex_def_t *mdef)
AUDIO Channel Cluster Descriptor (4.1)
Definition: audio.h:647
uint16_t wTotalLength
Total number of bytes returned for the class-specific AudioControl interface descriptor....
Definition: audio.h:661
volatile uint8_t busy
Definition: tusb_private.h:44
uint16_t wValue
Definition: audio.h:934
struct TU_ATTR_PACKED::@16::TU_ATTR_PACKED bmRequestType_bit
uint8_t bmAttributes
See: audio_clock_source_attribute_t.
Definition: audio.h:672
uint16_t wLength
Definition: audio.h:840
uint8_t bInterfaceCount
Total number of associated interfaces.
Definition: tusb_types.h:413
uint16_t wIndex
Definition: audio.h:943
uint8_t bDescriptorType
Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
Definition: audio.h:657
volatile uint8_t claimed
Definition: tusb_private.h:46
volatile uint8_t stalled
Definition: tusb_private.h:45
uint8_t bEndpointAddress
Definition: video.h:306
uint8_t bRequest
Request type audio_cs_req_t.
Definition: audio.h:831
uint8_t bInterfaceNumber
Number of this interface. Zero-based value identifying the index in the array of concurrent interface...
Definition: tusb_types.h:346
tusb_speed_t speed
Definition: tusb_types.h:282
bool(* deinit)(void)
Definition: usbd_pvt.h:55
void(* sof)(uint8_t rhport, uint32_t frame_count)
Definition: usbd_pvt.h:60
void(* reset)(uint8_t rhport)
Definition: usbd_pvt.h:56
void(* init)(void)
Definition: usbd_pvt.h:54
bool(* xfer_cb)(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
Definition: usbd_pvt.h:59
bool(* control_xfer_cb)(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
Definition: usbd_pvt.h:58
uint16_t(* open)(uint8_t rhport, tusb_desc_interface_t const *desc_intf, uint16_t max_len)
Definition: usbd_pvt.h:57
char const * name
Definition: usbd_pvt.h:53
volatile uint8_t addressed
Definition: usbd.c:114
volatile uint8_t suspended
Definition: usbd.c:115
volatile uint8_t connected
Definition: usbd.c:113
uint8_t ep2drv[CFG_TUD_ENDPPOINT_MAX][2]
Definition: usbd.c:126
tu_edpt_state_t ep_status[CFG_TUD_ENDPPOINT_MAX][2]
Definition: usbd.c:128
uint8_t itf2drv[CFG_TUD_INTERFACE_MAX]
Definition: usbd.c:125
volatile uint8_t cfg_num
Definition: usbd.c:121
volatile uint8_t sof_consumer
Definition: usbd.c:123
uint8_t speed
Definition: usbd.c:122
char const *const tu_str_speed[]
Definition: tusb.c:475
static TU_ATTR_ALWAYS_INLINE uint8_t tu_u16_low(uint16_t ui16)
Definition: tusb_common.h:146
static TU_ATTR_ALWAYS_INLINE uint8_t tu_u16_high(uint16_t ui16)
Definition: tusb_common.h:145
static TU_ATTR_ALWAYS_INLINE uint16_t tu_unaligned_read16(const void *mem)
Definition: tusb_common.h:219
static TU_ATTR_ALWAYS_INLINE bool tu_bit_test(uint32_t value, uint8_t pos)
Definition: tusb_common.h:151
char const *const tu_str_std_request[]
Definition: tusb.c:476
bool tu_edpt_validate(tusb_desc_endpoint_t const *desc_ep, tusb_speed_t speed)
Definition: tusb.c:202
bool tu_edpt_claim(tu_edpt_state_t *ep_state, osal_mutex_t mutex)
Definition: tusb.c:171
bool tu_edpt_release(tu_edpt_state_t *ep_state, osal_mutex_t mutex)
Definition: tusb.c:188
void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const *p_desc, uint16_t desc_len, uint8_t driver_id)
Definition: tusb.c:236
@ TUSB_DIR_IN
Definition: tusb_types.h:67
@ TUSB_DIR_OUT
Definition: tusb_types.h:66
@ TUSB_DIR_IN_MASK
Definition: tusb_types.h:69
@ TUSB_REQ_GET_STATUS
Definition: tusb_types.h:122
@ TUSB_REQ_SET_ADDRESS
Definition: tusb_types.h:127
@ TUSB_REQ_SET_FEATURE
Definition: tusb_types.h:125
@ TUSB_REQ_GET_DESCRIPTOR
Definition: tusb_types.h:128
@ TUSB_REQ_CLEAR_FEATURE
Definition: tusb_types.h:123
@ TUSB_REQ_SET_CONFIGURATION
Definition: tusb_types.h:131
@ TUSB_REQ_GET_CONFIGURATION
Definition: tusb_types.h:130
@ TUSB_REQ_SET_INTERFACE
Definition: tusb_types.h:133
@ TUSB_REQ_GET_INTERFACE
Definition: tusb_types.h:132
@ TUSB_REQ_SYNCH_FRAME
Definition: tusb_types.h:134
tusb_speed_t
defined base on EHCI specs value for Endpoint Speed
Definition: tusb_types.h:49
@ TUSB_SPEED_HIGH
Definition: tusb_types.h:52
static TU_ATTR_ALWAYS_INLINE uint8_t tu_edpt_number(uint8_t addr)
Definition: tusb_types.h:507
tusb_feature_test_mode_t
Definition: tusb_types.h:225
@ TUSB_FEATURE_TEST_FORCE_ENABLE
Definition: tusb_types.h:230
@ TUSB_FEATURE_TEST_J
Definition: tusb_types.h:226
static TU_ATTR_ALWAYS_INLINE uint8_t tu_desc_len(void const *desc)
Definition: tusb_types.h:542
@ TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP
Definition: tusb_types.h:218
@ TUSB_DESC_CONFIG_ATT_SELF_POWERED
Definition: tusb_types.h:219
TU_ATTR_PACKED_BEGIN TU_ATTR_BIT_FIELD_ORDER_BEGIN struct TU_ATTR_PACKED tusb_desc_device_t
USB Device Descriptor.
xfer_result_t
Definition: tusb_types.h:236
@ TUSB_REQ_RCPT_ENDPOINT
Definition: tusb_types.h:153
@ TUSB_REQ_RCPT_DEVICE
Definition: tusb_types.h:151
@ TUSB_REQ_RCPT_INTERFACE
Definition: tusb_types.h:152
TU_ATTR_PACKED_END TU_ATTR_BIT_FIELD_ORDER_END static TU_ATTR_ALWAYS_INLINE tusb_dir_t tu_edpt_dir(uint8_t addr)
Definition: tusb_types.h:502
@ CONTROL_STAGE_ACK
Definition: tusb_types.h:270
@ CONTROL_STAGE_SETUP
Definition: tusb_types.h:268
static TU_ATTR_ALWAYS_INLINE uint8_t tu_desc_type(void const *desc)
Definition: tusb_types.h:537
@ TUSB_REQ_TYPE_STANDARD
Definition: tusb_types.h:144
@ TUSB_REQ_TYPE_VENDOR
Definition: tusb_types.h:146
@ TUSB_REQ_TYPE_INVALID
Definition: tusb_types.h:147
@ TUSB_REQ_TYPE_CLASS
Definition: tusb_types.h:145
static TU_ATTR_ALWAYS_INLINE uint8_t const * tu_desc_next(void const *desc)
Definition: tusb_types.h:531
tusb_desc_type_t
USB Descriptor Types.
Definition: tusb_types.h:92
@ TUSB_DESC_STRING
Definition: tusb_types.h:95
@ TUSB_DESC_BOS
Definition: tusb_types.h:105
@ TUSB_DESC_INTERFACE_ASSOCIATION
Definition: tusb_types.h:103
@ TUSB_DESC_CONFIGURATION
Definition: tusb_types.h:94
@ TUSB_DESC_DEVICE_QUALIFIER
Definition: tusb_types.h:98
@ TUSB_DESC_ENDPOINT
Definition: tusb_types.h:97
@ TUSB_DESC_INTERFACE
Definition: tusb_types.h:96
@ TUSB_DESC_OTHER_SPEED_CONFIG
Definition: tusb_types.h:99
@ TUSB_DESC_DEVICE
Definition: tusb_types.h:93
@ TUSB_REQ_FEATURE_EDPT_HALT
Definition: tusb_types.h:138
@ TUSB_REQ_FEATURE_REMOTE_WAKEUP
Definition: tusb_types.h:139
@ TUSB_REQ_FEATURE_TEST_MODE
Definition: tusb_types.h:140
struct TU_ATTR_PACKED tusb_desc_configuration_t
USB Configuration Descriptor.
tu_static osal_queue_t _usbd_q
Definition: usbd.c:335
static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
Definition: usbd.c:967
tu_static char const *const _usbd_event_str[DCD_EVENT_COUNT]
Definition: usbd.c:379
void tud_sof_cb_enable(bool en)
Definition: usbd.c:440
bool tud_disconnect(void)
Definition: usbd.c:430
static bool process_test_mode_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
Definition: usbd.c:359
bool tud_connect(void)
Definition: usbd.c:435
TU_ATTR_WEAK uint8_t const * tud_descriptor_device_qualifier_cb(void)
Definition: usbd.c:62
static void configuration_reset(uint8_t rhport)
Definition: usbd.c:535
void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
Definition: usbd.c:1398
void usbd_control_set_request(tusb_control_request_t const *request)
Definition: usbd_control.c:152
void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr)
Definition: usbd.c:1424
bool tud_deinit(uint8_t rhport)
Definition: usbd.c:499
tusb_speed_t tud_speed_get(void)
Definition: usbd.c:407
bool tud_remote_wakeup(void)
Definition: usbd.c:423
bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
Definition: usbd.c:1309
void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
Definition: usbd.c:1385
tu_static osal_mutex_def_t _ubsd_mutexdef
Definition: usbd.c:339
bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep)
Definition: usbd.c:1277
static volatile uint8_t _usbd_queued_setup
Definition: usbd.c:133
bool tud_mounted(void)
Definition: usbd.c:415
tu_static uint8_t _usbd_rhport
Definition: usbd.c:330
bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr)
Definition: usbd.c:1286
tu_static usbd_class_driver_t const * _app_driver
Definition: usbd.c:306
void usbd_driver_print_control_complete_name(usbd_control_xfer_cb_t callback)
Definition: usbd.c:392
void usbd_defer_func(osal_task_func_t func, void *param, bool in_isr)
Definition: usbd.c:1262
tu_static osal_mutex_t _usbd_mutex
Definition: usbd.c:340
static bool invoke_class_control(uint8_t rhport, usbd_class_driver_t const *driver, tusb_control_request_t const *request)
Definition: usbd.c:703
TU_ATTR_WEAK uint8_t const * tud_descriptor_bos_cb(void)
Definition: usbd.c:58
void tud_task_ext(uint32_t timeout_ms, bool in_isr)
Definition: usbd.c:572
bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr)
Definition: usbd.c:1376
tu_static usbd_class_driver_t const _usbd_driver[]
Definition: usbd.c:145
bool tud_rhport_init(uint8_t rhport, const tusb_rhport_init_t *rh_init)
Definition: usbd.c:451
static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const *p_request)
Definition: usbd.c:1060
@ DRVID_INVALID
Definition: usbd.c:109
static TU_ATTR_ALWAYS_INLINE bool queue_event(dcd_event_t const *event, bool in_isr)
Definition: usbd.c:345
tu_static uint8_t _app_driver_count
Definition: usbd.c:307
@ BUILTIN_DRIVER_COUNT
Definition: usbd.c:303
bool tud_task_event_ready(void)
Definition: usbd.c:552
bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr)
Definition: usbd.c:1299
TU_ATTR_WEAK uint8_t const * tud_descriptor_other_speed_configuration_cb(uint8_t index)
Definition: usbd.c:66
TU_ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en)
Definition: usbd.c:77
static bool process_control_request(uint8_t rhport, tusb_control_request_t const *p_request)
Definition: usbd.c:711
TU_ATTR_WEAK void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr)
Definition: usbd.c:48
bool usbd_open_edpt_pair(uint8_t rhport, uint8_t const *p_desc, uint8_t ep_count, uint8_t xfer_type, uint8_t *ep_out, uint8_t *ep_in)
Definition: usbd.c:1238
TU_ATTR_WEAK void dcd_connect(uint8_t rhport)
Definition: usbd.c:96
tu_static usbd_device_t _usbd_dev
Definition: usbd.c:132
bool usbd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t *ff, uint16_t total_bytes)
Definition: usbd.c:1348
TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const *event, bool in_isr)
Definition: usbd.c:1153
bool tud_suspended(void)
Definition: usbd.c:419
OSAL_QUEUE_DEF(usbd_int_set, _usbd_qdef, CFG_TUD_TASK_QUEUE_SZ, dcd_event_t)
@ RHPORT_INVALID
Definition: usbd.c:329
void usbd_int_set(bool enabled)
Definition: usbd.c:1226
TU_ATTR_WEAK void dcd_disconnect(uint8_t rhport)
Definition: usbd.c:100
void usbd_control_reset(void)
Definition: usbd_control.c:142
void usbd_control_set_complete_callback(usbd_control_xfer_cb_t fp)
Definition: usbd_control.c:147
void usbd_sof_enable(uint8_t rhport, sof_consumer_t consumer, bool en)
Definition: usbd.c:1445
TU_ATTR_WEAK void tud_umount_cb(void)
Definition: usbd.c:74
TU_ATTR_WEAK bool dcd_deinit(uint8_t rhport)
Definition: usbd.c:91
bool tud_inited(void)
Definition: usbd.c:447
bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr)
Definition: usbd.c:1411
static void usbd_reset(uint8_t rhport)
Definition: usbd.c:547
bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep)
Definition: usbd.c:1474
TU_ATTR_WEAK void tud_mount_cb(void)
Definition: usbd.c:71
static TU_ATTR_ALWAYS_INLINE usbd_class_driver_t const * get_driver(uint8_t drvid)
Definition: usbd.c:313
bool usbd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size)
Definition: usbd.c:1462
bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
Definition: usbd_control.c:162
bool tud_connected(void)
Definition: usbd.c:411
TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
Definition: usbd.c:84
TU_ATTR_WEAK void tud_resume_cb(void)
Definition: usbd.c:81
TU_ATTR_WEAK void tud_sof_cb(uint32_t frame_count)
Definition: usbd.c:54
bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const *request, void *buffer, uint16_t len)
Definition: usbd_control.c:111
bool tud_control_status(uint8_t rhport, tusb_control_request_t const *request)
Definition: usbd_control.c:81
usbd_class_driver_t const * usbd_app_driver_get_cb(uint8_t *driver_count) TU_ATTR_WEAK
bool(* usbd_control_xfer_cb_t)(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
Definition: usbd_pvt.h:68
CFG_TUH_MEM_ALIGN tusb_control_request_t request
Definition: usbh.c:259
volatile uint8_t stage
Definition: usbh.c:265
bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
void usbtmcd_init_cb(void)
uint16_t usbtmcd_open_cb(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
bool usbtmcd_deinit(void)
void usbtmcd_reset_cb(uint8_t rhport)
bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
bool vendord_deinit(void)
void vendord_reset(uint8_t rhport)
uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
void vendord_init(void)
void videod_init(void)
bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
void videod_reset(uint8_t rhport)
uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
bool videod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
bool videod_deinit(void)