Coverage Report

Created: 2026-10-28 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tinyusb/src/device/usbd.c
Line
Count
Source
1
/*
2
 * SPDX-FileCopyrightText: Copyright (c) 2019 Ha Thach (tinyusb.org)
3
 * SPDX-License-Identifier: MIT
4
 *
5
 * This file is part of the TinyUSB stack.
6
 */
7
8
#include "tusb_option.h"
9
10
#if CFG_TUD_ENABLED
11
12
#include "tusb.h"
13
#include "device/dcd.h"
14
#include "common/tusb_private.h"
15
16
#include "device/usbd.h"
17
#include "device/usbd_pvt.h"
18
19
//--------------------------------------------------------------------+
20
// USBD Configuration
21
//--------------------------------------------------------------------+
22
#ifndef CFG_TUD_TASK_QUEUE_SZ
23
  #define CFG_TUD_TASK_QUEUE_SZ   16
24
#endif
25
26
//--------------------------------------------------------------------+
27
// Weak stubs: invoked if no strong implementation is available
28
//--------------------------------------------------------------------+
29
118k
TU_ATTR_WEAK void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) {
30
118k
  (void) rhport; (void) eventid; (void) in_isr;
31
118k
}
32
33
0
TU_ATTR_WEAK void tud_sof_cb(uint32_t frame_count) {
34
0
  (void) frame_count;
35
0
}
36
37
607
TU_ATTR_WEAK uint8_t const* tud_descriptor_bos_cb(void) {
38
607
  return NULL;
39
607
}
40
41
594
TU_ATTR_WEAK uint8_t const* tud_descriptor_device_qualifier_cb(void) {
42
594
  return NULL;
43
594
}
44
45
620
TU_ATTR_WEAK uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) {
46
620
  (void) index;
47
620
  return NULL;
48
620
}
49
50
2.99k
TU_ATTR_WEAK void tud_mount_cb(void) {
51
2.99k
}
52
53
14.9k
TU_ATTR_WEAK void tud_umount_cb(void) {
54
14.9k
}
55
56
5.16k
TU_ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en) {
57
5.16k
  (void) remote_wakeup_en;
58
5.16k
}
59
60
4.99k
TU_ATTR_WEAK void tud_resume_cb(void) {
61
4.99k
}
62
63
1.24k
TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const* request) {
64
1.24k
  (void) rhport; (void) stage; (void) request;
65
1.24k
  return false;
66
1.24k
}
67
68
0
TU_ATTR_WEAK bool dcd_deinit(uint8_t rhport) {
69
0
  (void) rhport;
70
0
  return false;
71
0
}
72
73
0
TU_ATTR_WEAK void dcd_connect(uint8_t rhport) {
74
0
  (void) rhport;
75
0
}
76
77
0
TU_ATTR_WEAK void dcd_disconnect(uint8_t rhport) {
78
0
  (void) rhport;
79
0
}
80
81
0
TU_ATTR_WEAK bool dcd_dcache_clean(const void* addr, uint32_t data_size) {
82
0
  (void) addr; (void) data_size;
83
0
  return true;
84
0
}
85
86
0
TU_ATTR_WEAK bool dcd_dcache_invalidate(const void* addr, uint32_t data_size) {
87
0
  (void) addr; (void) data_size;
88
0
  return true;
89
0
}
90
91
0
TU_ATTR_WEAK bool dcd_dcache_clean_invalidate(const void* addr, uint32_t data_size) {
92
0
  (void) addr; (void) data_size;
93
0
  return true;
94
0
}
95
96
//--------------------------------------------------------------------+
97
// Device Data
98
//--------------------------------------------------------------------+
99
100
// Per-control-transfer state: populated at process_setup_received() entry,
101
// consumed asynchronously by usbd_control_xfer_cb() when the EP0 transfer completes.
102
typedef struct {
103
  tusb_control_request_t request;
104
  uint8_t* buffer;
105
  uint16_t data_len;
106
  uint16_t total_xferred;
107
  usbd_control_xfer_cb_t complete_cb;
108
} usbd_control_xfer_t;
109
110
typedef struct {
111
  usbd_control_xfer_t ctrl_xfer;
112
113
  // Note: these may share an enum state
114
  volatile uint8_t connected;
115
  volatile uint8_t addressed;
116
  volatile uint8_t suspended;
117
118
  union {
119
    struct TU_ATTR_PACKED {
120
      uint8_t self_powered     : 1; // configuration descriptor's attribute;
121
      uint8_t remote_wakeup_en : 1; // enable/disable by host
122
    };
123
    uint8_t dev_state_bm;
124
  };
125
126
  uint8_t          cfg_num; // current active configuration (0x00 is not configured)
127
  uint8_t          speed;
128
  volatile uint8_t sof_consumer;
129
130
  uint8_t itf2drv[CFG_TUD_INTERFACE_MAX];   // map interface number to driver (0xff is invalid)
131
  uint8_t ep2drv[CFG_TUD_ENDPPOINT_MAX][2]; // map endpoint to driver ( 0xff is invalid ), can use only 4-bit each
132
133
  volatile uint8_t ep_status[CFG_TUD_ENDPPOINT_MAX][2];
134
} usbd_device_t;
135
136
static usbd_device_t    _usbd_dev;
137
static volatile uint8_t _usbd_queued_setup;
138
139
CFG_TUD_MEM_SECTION static struct {
140
  TUD_EPBUF_DEF(buf, CFG_TUD_ENDPOINT0_BUFSIZE);
141
} _ctrl_epbuf;
142
143
//--------------------------------------------------------------------+
144
// Class Driver
145
//--------------------------------------------------------------------+
146
  #if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
147
    #define DRIVER_NAME(_name) _name
148
  #else
149
    #define DRIVER_NAME(_name) NULL
150
  #endif
151
152
// Built-in class drivers
153
static const usbd_class_driver_t _usbd_driver[] = {
154
  #if CFG_TUD_CDC
155
    {
156
        .name             = DRIVER_NAME("CDC"),
157
        .init             = cdcd_init,
158
        .deinit           = cdcd_deinit,
159
        .reset            = cdcd_reset,
160
        .open             = cdcd_open,
161
        .control_xfer_cb  = cdcd_control_xfer_cb,
162
        .xfer_cb          = cdcd_xfer_cb,
163
        .xfer_isr         = NULL,
164
        .sof              = NULL
165
    },
166
    #endif
167
168
    #if CFG_TUD_MSC
169
    {
170
        .name             = DRIVER_NAME("MSC"),
171
        .init             = mscd_init,
172
        .deinit           = NULL,
173
        .reset            = mscd_reset,
174
        .open             = mscd_open,
175
        .control_xfer_cb  = mscd_control_xfer_cb,
176
        .xfer_cb          = mscd_xfer_cb,
177
        .xfer_isr         = NULL,
178
        .sof              = NULL
179
    },
180
    #endif
181
182
    #if CFG_TUD_HID
183
    {
184
        .name             = DRIVER_NAME("HID"),
185
        .init             = hidd_init,
186
        .deinit           = hidd_deinit,
187
        .reset            = hidd_reset,
188
        .open             = hidd_open,
189
        .control_xfer_cb  = hidd_control_xfer_cb,
190
        .xfer_cb          = hidd_xfer_cb,
191
        .xfer_isr         = NULL,
192
        .sof              = NULL
193
    },
194
    #endif
195
196
    #if CFG_TUD_AUDIO
197
    {
198
        .name             = DRIVER_NAME("AUDIO"),
199
        .init             = audiod_init,
200
        .deinit           = audiod_deinit,
201
        .reset            = audiod_reset,
202
        .open             = audiod_open,
203
        .control_xfer_cb  = audiod_control_xfer_cb,
204
        .xfer_cb          = audiod_xfer_cb,
205
        .xfer_isr         = audiod_xfer_isr,
206
        .sof              = audiod_sof_isr
207
    },
208
    #endif
209
210
    #if CFG_TUD_VIDEO
211
    {
212
        .name             = DRIVER_NAME("VIDEO"),
213
        .init             = videod_init,
214
        .deinit           = videod_deinit,
215
        .reset            = videod_reset,
216
        .open             = videod_open,
217
        .control_xfer_cb  = videod_control_xfer_cb,
218
        .xfer_cb          = videod_xfer_cb,
219
        .xfer_isr         = NULL,
220
        .sof              = NULL
221
    },
222
    #endif
223
224
    #if CFG_TUD_MIDI
225
    {
226
        .name             = DRIVER_NAME("MIDI"),
227
        .init             = midid_init,
228
        .deinit           = midid_deinit,
229
        .open             = midid_open,
230
        .reset            = midid_reset,
231
        .control_xfer_cb  = midid_control_xfer_cb,
232
        .xfer_cb          = midid_xfer_cb,
233
        .xfer_isr         = NULL,
234
        .sof              = NULL
235
    },
236
    #endif
237
238
    #if CFG_TUD_MIDI2
239
    {
240
        .name             = DRIVER_NAME("MIDI2"),
241
        .init             = midi2d_init,
242
        .deinit           = midi2d_deinit,
243
        .open             = midi2d_open,
244
        .reset            = midi2d_reset,
245
        .control_xfer_cb  = midi2d_control_xfer_cb,
246
        .xfer_cb          = midi2d_xfer_cb,
247
        .xfer_isr         = NULL,
248
        .sof              = NULL
249
    },
250
    #endif
251
252
    #if CFG_TUD_VENDOR
253
    {
254
        .name             = DRIVER_NAME("VENDOR"),
255
        .init             = vendord_init,
256
        .deinit           = vendord_deinit,
257
        .reset            = vendord_reset,
258
        .open             = vendord_open,
259
        .control_xfer_cb  = vendord_control_xfer_cb,
260
        .xfer_cb          = vendord_xfer_cb,
261
        .xfer_isr         = NULL,
262
        .sof              = NULL
263
    },
264
    #endif
265
266
    #if CFG_TUD_USBTMC
267
    {
268
        .name             = DRIVER_NAME("TMC"),
269
        .init             = usbtmcd_init_cb,
270
        .deinit           = usbtmcd_deinit,
271
        .reset            = usbtmcd_reset_cb,
272
        .open             = usbtmcd_open_cb,
273
        .control_xfer_cb  = usbtmcd_control_xfer_cb,
274
        .xfer_cb          = usbtmcd_xfer_cb,
275
        .xfer_isr         = NULL,
276
        .sof              = NULL
277
    },
278
    #endif
279
280
    #if CFG_TUD_DFU_RUNTIME
281
    {
282
        .name             = DRIVER_NAME("DFU-RUNTIME"),
283
        .init             = dfu_rtd_init,
284
        .deinit           = dfu_rtd_deinit,
285
        .reset            = dfu_rtd_reset,
286
        .open             = dfu_rtd_open,
287
        .control_xfer_cb  = dfu_rtd_control_xfer_cb,
288
        .xfer_cb          = NULL,
289
        .xfer_isr         = NULL,
290
        .sof              = NULL
291
    },
292
    #endif
293
294
    #if CFG_TUD_DFU
295
    {
296
        .name             = DRIVER_NAME("DFU"),
297
        .init             = dfu_moded_init,
298
        .deinit           = dfu_moded_deinit,
299
        .reset            = dfu_moded_reset,
300
        .open             = dfu_moded_open,
301
        .control_xfer_cb  = dfu_moded_control_xfer_cb,
302
        .xfer_cb          = NULL,
303
        .xfer_isr         = NULL,
304
        .sof              = NULL
305
    },
306
    #endif
307
308
    #if CFG_TUD_ECM_RNDIS || CFG_TUD_NCM
309
    {
310
        .name             = DRIVER_NAME("NET"),
311
        .init             = netd_init,
312
        .deinit           = netd_deinit,
313
        .reset            = netd_reset,
314
        .open             = netd_open,
315
        .control_xfer_cb  = netd_control_xfer_cb,
316
        .xfer_cb          = netd_xfer_cb,
317
        .xfer_isr         = NULL,
318
        .sof              = NULL,
319
    },
320
    #endif
321
322
    #if CFG_TUD_BTH
323
    {
324
        .name             = DRIVER_NAME("BTH"),
325
        .init             = btd_init,
326
        .deinit           = btd_deinit,
327
        .reset            = btd_reset,
328
        .open             = btd_open,
329
        .control_xfer_cb  = btd_control_xfer_cb,
330
        .xfer_cb          = btd_xfer_cb,
331
        .xfer_isr         = NULL,
332
        .sof              = NULL
333
    },
334
    #endif
335
336
    #if CFG_TUD_MTP
337
    {
338
        .name             = DRIVER_NAME("MTP"),
339
        .init             = mtpd_init,
340
        .deinit           = mtpd_deinit,
341
        .reset            = mtpd_reset,
342
        .open             = mtpd_open,
343
        .control_xfer_cb  = mtpd_control_xfer_cb,
344
        .xfer_cb          = mtpd_xfer_cb,
345
        .xfer_isr         = NULL,
346
        .sof              = NULL
347
    },
348
    #endif
349
350
    #if CFG_TUD_PRINTER
351
    {
352
        .name             = DRIVER_NAME("PRINTER"),
353
        .init             = printerd_init,
354
        .deinit           = printerd_deinit,
355
        .reset            = printerd_reset,
356
        .open             = printerd_open,
357
        .control_xfer_cb  = printerd_control_xfer_cb,
358
        .xfer_cb          = printerd_xfer_cb,
359
        .sof              = NULL
360
    },
361
    #endif
362
};
363
364
// Additional class drivers implemented by application
365
static const usbd_class_driver_t *_app_driver = NULL;
366
static const uint8_t _builtin_driver_count    = TU_ARRAY_SIZE(_usbd_driver);
367
static uint8_t              _app_driver_count = 0;
368
369
119k
#define TOTAL_DRIVER_COUNT    ((uint8_t) (_app_driver_count + _builtin_driver_count))
370
371
// virtually joins built-in and application drivers together.
372
// Application is positioned first to allow overwriting built-in ones.
373
82.8k
TU_ATTR_ALWAYS_INLINE static inline usbd_class_driver_t const * get_driver(uint8_t drvid) {
374
82.8k
  usbd_class_driver_t const *driver = NULL;
375
82.8k
  if (drvid < _app_driver_count) {
376
    // Application drivers
377
0
    driver = &_app_driver[drvid];
378
82.8k
  } else{
379
82.8k
    drvid -= _app_driver_count;
380
82.8k
    if (_builtin_driver_count > 0 && drvid < _builtin_driver_count) {
381
75.0k
      driver = &_usbd_driver[drvid];
382
75.0k
    }
383
82.8k
  }
384
385
82.8k
  return driver;
386
82.8k
}
387
388
//--------------------------------------------------------------------+
389
// DCD Event
390
//--------------------------------------------------------------------+
391
enum {
392
  RHPORT_INVALID = 0xFFu
393
};
394
static uint8_t _usbd_rhport = RHPORT_INVALID;
395
396
static OSAL_SPINLOCK_DEF(_usbd_spin, usbd_int_set);
397
398
// Event queue: usbd_int_set() is used as mutex in OS NONE config
399
OSAL_QUEUE_DEF(usbd_int_set, _usbd_qdef, CFG_TUD_TASK_QUEUE_SZ, dcd_event_t);
400
static osal_queue_t _usbd_q;
401
402
// held by usbd_defer_func_after_queue(), set and run by the usbd task only
403
static struct {
404
  osal_task_func_t func;
405
  void* param;
406
} _usbd_after_queue;
407
408
// Mutex for claiming endpoint
409
#if OSAL_MUTEX_REQUIRED
410
  static osal_mutex_def_t _ubsd_mutexdef;
411
  static osal_mutex_t _usbd_mutex;
412
#else
413
7.09k
  #define _usbd_mutex   NULL
414
#endif
415
416
118k
TU_ATTR_ALWAYS_INLINE static inline bool queue_event(dcd_event_t const * event, bool in_isr) {
417
118k
  TU_ASSERT(osal_queue_send(_usbd_q, event, in_isr));
418
118k
  tud_event_hook_cb(event->rhport, event->event_id, in_isr);
419
118k
  return true;
420
118k
}
421
422
//--------------------------------------------------------------------+
423
// Prototypes
424
//--------------------------------------------------------------------+
425
static bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
426
static bool process_setup_received(uint8_t rhport, tusb_control_request_t const * p_request);
427
static bool process_get_status(uint8_t rhport, tusb_control_request_t const * request, uint16_t status);
428
static bool process_set_config(uint8_t rhport, uint8_t cfg_num);
429
static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request);
430
431
#if CFG_TUD_TEST_MODE
432
static bool process_test_mode_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) {
433
  TU_VERIFY(CONTROL_STAGE_ACK == stage);
434
  uint8_t const selector = tu_u16_high(request->wIndex);
435
  TU_LOG_USBD("    Enter Test Mode (test selector index: %d)\r\n", selector);
436
  dcd_enter_test_mode(rhport, (tusb_feature_test_mode_t) selector);
437
  return true;
438
}
439
#endif
440
441
//--------------------------------------------------------------------+
442
// Weak stubs: invoked if no strong implementation is available
443
//--------------------------------------------------------------------+
444
3
TU_ATTR_WEAK usbd_class_driver_t const* usbd_app_driver_get_cb(uint8_t* driver_count) {
445
3
  *driver_count = 0;
446
3
  return NULL;
447
3
}
448
449
0
TU_ATTR_WEAK bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes, bool is_isr) {
450
0
  (void) rhport; (void) ep_addr; (void) ff; (void) total_bytes; (void) is_isr;
451
0
  return false;
452
0
}
453
454
0
TU_ATTR_WEAK bool dcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) {
455
0
  (void) rhport; (void) cfg_id; (void) cfg_param;
456
0
  return false;
457
0
}
458
459
//--------------------------------------------------------------------+
460
// Debug
461
//--------------------------------------------------------------------+
462
#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
463
static char const *const _usbd_event_str[DCD_EVENT_COUNT] = {
464
    "Invalid",
465
    "Bus Reset Start",
466
    "Bus Reset End",
467
    "Unplugged",
468
    "SOF",
469
    "Suspend",
470
    "Resume",
471
    "Setup Received",
472
    "Xfer Complete",
473
    "Func Call"
474
};
475
476
#endif
477
478
//--------------------------------------------------------------------+
479
// Application API
480
//--------------------------------------------------------------------+
481
0
tusb_speed_t tud_speed_get(void) {
482
0
  return (tusb_speed_t) _usbd_dev.speed;
483
0
}
484
485
0
bool tud_connected(void) {
486
0
  return _usbd_dev.connected;
487
0
}
488
489
30.9k
bool tud_mounted(void) {
490
30.9k
  return _usbd_dev.cfg_num ? true : false;
491
30.9k
}
492
493
30.9k
bool tud_suspended(void) {
494
30.9k
  return _usbd_dev.suspended;
495
30.9k
}
496
497
0
bool tud_remote_wakeup(void) {
498
  // only wake up host if this feature is enabled and we are suspended
499
0
  TU_VERIFY(_usbd_dev.suspended && _usbd_dev.remote_wakeup_en);
500
0
  dcd_remote_wakeup(_usbd_rhport);
501
0
  return true;
502
0
}
503
504
0
bool tud_disconnect(void) {
505
0
  dcd_disconnect(_usbd_rhport);
506
0
  return true;
507
0
}
508
509
0
bool tud_connect(void) {
510
0
  dcd_connect(_usbd_rhport);
511
0
  return true;
512
0
}
513
514
0
void tud_sof_cb_enable(bool en) {
515
0
  usbd_sof_enable(_usbd_rhport, SOF_CONSUMER_USER, en);
516
0
}
517
518
206k
bool tud_inited(void) {
519
206k
  return _usbd_rhport != RHPORT_INVALID;
520
206k
}
521
522
0
bool tud_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) {
523
0
  return dcd_configure(rhport, cfg_id, cfg_param);
524
0
}
525
526
4.30k
bool tud_rhport_init(uint8_t rhport, const tusb_rhport_init_t* rh_init) {
527
4.30k
  if (tud_inited()) {
528
4.30k
    return true; // skip if already initialized
529
4.30k
  }
530
3
  TU_ASSERT(rh_init);
531
 #if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
532
  char const* speed_str = 0;
533
  switch (rh_init->speed) {
534
    case TUSB_SPEED_HIGH:
535
      speed_str = "High";
536
    break;
537
    case TUSB_SPEED_FULL:
538
      speed_str = "Full";
539
    break;
540
    case TUSB_SPEED_LOW:
541
      speed_str = "Low";
542
    break;
543
    case TUSB_SPEED_AUTO:
544
      speed_str = "Auto";
545
    break;
546
  default:
547
    break;
548
  }
549
  TU_LOG_USBD("USBD init on controller %u, speed = %s\r\n", rhport, speed_str);
550
  TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(usbd_device_t));
551
  TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(dcd_event_t));
552
  TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_fifo_t));
553
  TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_edpt_stream_t));
554
#endif
555
556
3
  tu_varclr(&_usbd_dev);
557
3
  _usbd_queued_setup = 0;
558
559
3
  osal_spin_init(&_usbd_spin);
560
561
#if OSAL_MUTEX_REQUIRED
562
  // Init device mutex
563
  _usbd_mutex = osal_mutex_create(&_ubsd_mutexdef);
564
  TU_ASSERT(_usbd_mutex);
565
#endif
566
567
  // Init device queue & task
568
3
  _usbd_q = osal_queue_create(&_usbd_qdef);
569
3
  TU_ASSERT(_usbd_q);
570
571
  // Get application driver if available
572
3
  _app_driver = usbd_app_driver_get_cb(&_app_driver_count);
573
3
  TU_ASSERT(_app_driver_count + _builtin_driver_count <= UINT8_MAX);
574
575
  // Init class drivers
576
7
  for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) {
577
4
    usbd_class_driver_t const* driver = get_driver(i);
578
4
    TU_ASSERT(driver && driver->init);
579
4
    TU_LOG_USBD("%s init\r\n", driver->name);
580
4
    driver->init();
581
4
  }
582
583
3
  _usbd_rhport = rhport;
584
585
  // Init device controller driver
586
3
  TU_ASSERT(dcd_init(rhport, rh_init));
587
3
  dcd_int_enable(rhport);
588
589
3
  return true;
590
3
}
591
592
0
bool tud_deinit(uint8_t rhport) {
593
0
  if (!tud_inited()) {
594
0
    return true; // skip if not initialized
595
0
  }
596
597
0
  TU_LOG_USBD("USBD deinit on controller %u\r\n", rhport);
598
599
0
  const uint8_t cfg_num = _usbd_dev.cfg_num;
600
601
  // Deinit device controller driver
602
0
  dcd_int_disable(rhport);
603
0
  dcd_disconnect(rhport);
604
0
  TU_ASSERT(dcd_deinit(rhport));
605
606
  // Deinit class drivers
607
0
  for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) {
608
0
    usbd_class_driver_t const* driver = get_driver(i);
609
0
    if(driver && driver->deinit) {
610
0
      TU_LOG_USBD("%s deinit\r\n", driver->name);
611
0
      driver->deinit();
612
0
    }
613
0
  }
614
615
0
  tu_varclr(&_usbd_dev); // Clear device data
616
617
  // Deinit device queue & task
618
0
  osal_queue_delete(_usbd_q);
619
0
  _usbd_q = NULL;
620
0
  tu_varclr(&_usbd_after_queue);
621
622
#if OSAL_MUTEX_REQUIRED
623
  // TODO make sure there is no task waiting on this mutex
624
  osal_mutex_delete(_usbd_mutex);
625
  _usbd_mutex = NULL;
626
#endif
627
628
0
  osal_spin_deinit(&_usbd_spin);
629
630
0
  _usbd_rhport = RHPORT_INVALID;
631
632
0
  if (cfg_num > 0) {
633
0
    tud_umount_cb();
634
0
  }
635
636
0
  return true;
637
0
}
638
639
45.2k
static void configuration_reset(uint8_t rhport) {
640
107k
  for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) {
641
61.7k
    usbd_class_driver_t const* driver = get_driver(i);
642
61.7k
    TU_ASSERT(driver,);
643
61.7k
    driver->reset(rhport);
644
61.7k
  }
645
646
45.2k
  tu_varclr(&_usbd_dev);
647
45.2k
  (void)memset(_usbd_dev.itf2drv, TUSB_INDEX_INVALID_8, sizeof(_usbd_dev.itf2drv)); // invalid mapping
648
45.2k
  (void)memset(_usbd_dev.ep2drv, TUSB_INDEX_INVALID_8, sizeof(_usbd_dev.ep2drv));   // invalid mapping
649
45.2k
}
650
651
43.3k
static void usbd_reset(uint8_t rhport) {
652
43.3k
  configuration_reset(rhport);
653
  // discard any pre-reset SETUP still counted: a stale count skips post-reset SETUPs
654
43.3k
  _usbd_queued_setup = 0;
655
43.3k
}
656
657
0
bool tud_task_event_ready(void) {
658
0
  TU_VERIFY(tud_inited()); // Skip if stack is not initialized
659
0
  return !osal_queue_empty(_usbd_q) || _usbd_after_queue.func != NULL;
660
0
}
661
662
// the call usbd_defer_func_after_queue() holds; false if none
663
202k
static bool run_after_queue_call(void) {
664
202k
  osal_task_func_t const func = _usbd_after_queue.func;
665
202k
  if (func == NULL) {
666
202k
    return false;
667
202k
  }
668
0
  _usbd_after_queue.func = NULL;
669
0
  func(_usbd_after_queue.param);
670
0
  return true;
671
202k
}
672
673
//--------------------------------------------------------------------+
674
// USBD Task
675
//--------------------------------------------------------------------+
676
/* USB Device Driver task
677
 * This top level thread manages all device controller event and delegates events to class-specific drivers.
678
 * This should be called periodically within the mainloop or rtos thread.
679
 *
680
    int main(void) {
681
      application_init();
682
      tusb_init(0, TUSB_ROLE_DEVICE);
683
684
      while(1) { // the mainloop
685
        application_code();
686
        tud_task(); // tinyusb device task
687
      }
688
    }
689
 */
690
202k
void tud_task_ext(uint32_t timeout_ms, bool in_isr) {
691
202k
  (void) in_isr; // not implemented yet
692
693
  // Skip if stack is not initialized
694
202k
  if (!tud_inited()) {
695
0
    return;
696
0
  }
697
698
  // Loop until there are no more events in the queue or CFG_TUD_TASK_EVENTS_PER_RUN is reached
699
320k
  for (unsigned epr = 0;; epr++) {
700
320k
#if CFG_TUD_TASK_EVENTS_PER_RUN > 0
701
320k
    if (epr >= CFG_TUD_TASK_EVENTS_PER_RUN) {
702
0
      TU_LOG_USBD("USBD event limit (" TU_XSTRING(CFG_TUD_TASK_EVENTS_PER_RUN) ") reached\r\n");
703
0
      break;
704
0
    }
705
320k
#endif
706
320k
    dcd_event_t event;
707
320k
    if (!osal_queue_receive(_usbd_q, &event, (_usbd_after_queue.func != NULL) ? 0 : timeout_ms)) {
708
202k
      if (!run_after_queue_call()) {
709
202k
        return;
710
202k
      }
711
0
      timeout_ms = 0;
712
0
      continue;
713
202k
    }
714
715
#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
716
    if (event.event_id == DCD_EVENT_SETUP_RECEIVED) {
717
      TU_LOG_USBD("\r\n"); // extra line for setup
718
    }
719
    TU_LOG_USBD("USBD %s ", event.event_id < DCD_EVENT_COUNT ? _usbd_event_str[event.event_id] : "CORRUPTED");
720
#endif
721
722
118k
    switch (event.event_id) {
723
0
      case DCD_EVENT_BUS_RESET_START:
724
0
        TU_LOG_USBD("\r\n");
725
0
        usbd_reset(event.rhport);
726
0
        break;
727
728
28.5k
      case DCD_EVENT_BUS_RESET_END:
729
28.5k
        TU_LOG_USBD(": %s Speed\r\n", tu_str_speed[event.bus_reset.speed]);
730
        // TODO a DCD that reports both edges pays for two teardowns: track a per-rhport
731
        // "start seen" flag and skip this reset, keeping it for the single-event DCDs.
732
28.5k
        usbd_reset(event.rhport);
733
28.5k
        _usbd_dev.speed = event.bus_reset.speed;
734
28.5k
        break;
735
736
14.8k
      case DCD_EVENT_UNPLUGGED:
737
14.8k
        TU_LOG_USBD("\r\n");
738
14.8k
        usbd_reset(event.rhport);
739
14.8k
        tud_umount_cb();
740
14.8k
        break;
741
742
64.8k
      case DCD_EVENT_SETUP_RECEIVED:
743
64.8k
        if (_usbd_queued_setup == 0) {
744
17.1k
          break;
745
17.1k
        }
746
47.7k
        _usbd_queued_setup--;
747
47.7k
        TU_LOG_BUF(CFG_TUD_LOG_LEVEL, &event.setup_received, 8);
748
47.7k
        if (_usbd_queued_setup != 0) {
749
0
          TU_LOG_USBD("  Skipped since there is other SETUP in queue\r\n");
750
0
          break;
751
0
        }
752
47.7k
        if (!dcd_edpt0_setup_begin(event.rhport, event.setup_tagid)) {
753
0
          TU_LOG_USBD("  Skipped since DCD saw a newer SETUP or bus reset\r\n");
754
0
          break;
755
0
        }
756
757
        // Mark as connected after receiving 1st setup packet.
758
        // But it is easier to set it every time instead of wasting time to check then set
759
47.7k
        _usbd_dev.connected = 1;
760
761
        // reset ep state
762
47.7k
        _usbd_dev.ep_status[0][TUSB_DIR_OUT] = 0;
763
47.7k
        _usbd_dev.ep_status[0][TUSB_DIR_IN] = 0;
764
765
        // Process control request
766
47.7k
        if (!process_setup_received(event.rhport, &event.setup_received)) {
767
31.5k
          TU_LOG_USBD("  Stall EP0\r\n");
768
          // Failed -> stall both control endpoint IN and OUT
769
31.5k
          dcd_edpt_stall(event.rhport, TU_EP0_OUT);
770
31.5k
          dcd_edpt_stall(event.rhport, TU_EP0_IN);
771
31.5k
        }
772
47.7k
        break;
773
774
0
      case DCD_EVENT_XFER_COMPLETE: {
775
        // Invoke the class callback associated with the endpoint address
776
0
        uint8_t const ep_addr = event.xfer_complete.ep_addr;
777
0
        uint8_t const epnum = tu_edpt_number(ep_addr);
778
0
        uint8_t const ep_dir = tu_edpt_dir(ep_addr);
779
780
0
        TU_LOG_USBD("on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len);
781
782
0
        usbd_class_driver_t const* driver = NULL; // EP0 has no class driver
783
0
        if (0 != epnum) {
784
0
          driver = get_driver(_usbd_dev.ep2drv[epnum][ep_dir]);
785
0
          TU_ASSERT(driver,);
786
0
        }
787
788
        // Clear busy + claimed. An OUT endpoint changed to RX_PENDING, so no other task can claim and re-arm it before
789
        // its buffer is consumed
790
0
        uint8_t const rx_pending = (0 != epnum && ep_dir == TUSB_DIR_OUT) ? TU_EDPT_STATE_RX_PENDING : 0u;
791
0
        _usbd_dev.ep_status[epnum][ep_dir] = (uint8_t) (
792
0
          (_usbd_dev.ep_status[epnum][ep_dir] & ~(TU_EDPT_STATE_BUSY | TU_EDPT_STATE_CLAIMED)) | rx_pending);
793
794
0
        if (driver == NULL) {
795
          // Not stalled on failure: a DCD refuses an EP0 prime when a newer setup is already
796
          // latched, and EP0 stalls are cleared by hardware when that setup arrives - so a stall
797
          // issued here lands after the auto-clear and would stall the transfer that superseded
798
          // this one. The pending setup re-drives EP0 by itself.
799
0
          if (!usbd_control_xfer_cb(event.rhport, ep_addr, (xfer_result_t) event.xfer_complete.result,
800
0
                                    event.xfer_complete.len)) {
801
0
            TU_LOG_USBD("  Control stage not continued\r\n");
802
0
          }
803
0
        } else {
804
0
          TU_LOG_USBD("  %s xfer callback\r\n", driver->name);
805
0
          driver->xfer_cb(event.rhport, ep_addr, (xfer_result_t) event.xfer_complete.result, event.xfer_complete.len);
806
0
        }
807
0
        break;
808
0
      }
809
810
5.16k
      case DCD_EVENT_SUSPEND:
811
        // NOTE: When plugging/unplugging device, the D+/D- state are unstable and
812
        // can accidentally meet the SUSPEND condition ( Bus Idle for 3ms ), which result in a series of event
813
        // e.g suspend -> resume -> unplug/plug. Skip suspend/resume if not connected
814
5.16k
        if (_usbd_dev.connected) {
815
5.16k
          TU_LOG_USBD(": Remote Wakeup = %u\r\n", _usbd_dev.remote_wakeup_en);
816
5.16k
          tud_suspend_cb(_usbd_dev.remote_wakeup_en);
817
5.16k
        } else {
818
0
          TU_LOG_USBD(" Skipped\r\n");
819
0
        }
820
5.16k
        break;
821
822
4.99k
      case DCD_EVENT_RESUME:
823
4.99k
        if (_usbd_dev.connected) {
824
4.99k
          TU_LOG_USBD("\r\n");
825
4.99k
          tud_resume_cb();
826
4.99k
        } else {
827
0
          TU_LOG_USBD(" Skipped\r\n");
828
0
        }
829
4.99k
        break;
830
831
0
      case USBD_EVENT_FUNC_CALL:
832
0
        TU_LOG_USBD("\r\n");
833
0
        if (event.func_call.func != NULL) {
834
0
          event.func_call.func(event.func_call.param);
835
0
        }
836
0
        break;
837
838
0
      case DCD_EVENT_SOF:
839
0
        if (tu_bit_test(_usbd_dev.sof_consumer, SOF_CONSUMER_USER)) {
840
0
          TU_LOG_USBD("\r\n");
841
0
          tud_sof_cb(event.sof.frame_count);
842
0
        }
843
0
      break;
844
845
0
      default:
846
0
        TU_BREAKPOINT();
847
0
        break;
848
118k
    }
849
850
    // allow to exit tud_task() if there is no event in the next run
851
118k
    timeout_ms = 0;
852
118k
  }
853
202k
}
854
855
//--------------------------------------------------------------------+
856
// Control Endpoint
857
//--------------------------------------------------------------------+
858
859
// Weak hook: invoked when the stack starts processing a SETUP
860
47.7k
TU_ATTR_WEAK bool dcd_edpt0_setup_begin(uint8_t rhport, uint8_t setup_tagid) {
861
47.7k
  (void) rhport;
862
47.7k
  (void) setup_tagid;
863
47.7k
  return true;
864
47.7k
}
865
866
// Weak hook: invoked when the control transfer's status stage completes
867
0
TU_ATTR_WEAK void dcd_edpt0_status_complete(uint8_t rhport, const tusb_control_request_t* request) {
868
0
  (void) rhport;
869
0
  (void) request;
870
0
}
871
872
0
uint8_t* usbd_get_ctrl_buf(void) {
873
0
  return _ctrl_epbuf.buf;
874
0
}
875
876
// Endpoint used for the Status stage of a control transfer.
877
// Per USB 2.0 §9.3.1, when wLength == 0 the Direction bit is ignored and the Status
878
// stage is always IN. Otherwise the Status stage is opposite of the Data stage direction.
879
11.0k
TU_ATTR_ALWAYS_INLINE static inline uint8_t status_stage_ep(const tusb_control_request_t* request) {
880
11.0k
  return (request->wLength != 0 && request->bmRequestType_bit.direction) ? TU_EP0_OUT : TU_EP0_IN;
881
11.0k
}
882
883
// Queue ZLP status transaction
884
12.6k
TU_ATTR_ALWAYS_INLINE static inline bool status_stage_xact(uint8_t rhport, uint8_t ep_status) {
885
12.6k
  return usbd_edpt_xfer(rhport, ep_status, NULL, 0, false);
886
12.6k
}
887
888
// Queue a transaction in Data Stage. Each transaction has up to Endpoint0's max
889
// packet size. This function can also transfer a zero-length packet.
890
17.6k
static bool data_stage_xact(uint8_t rhport) {
891
17.6k
  usbd_control_xfer_t* const ctrl_xfer = &_usbd_dev.ctrl_xfer;
892
17.6k
  const uint16_t xact_len = tu_min16(ctrl_xfer->data_len - ctrl_xfer->total_xferred, CFG_TUD_ENDPOINT0_BUFSIZE);
893
17.6k
  uint8_t ep_addr = TU_EP0_OUT;
894
895
17.6k
  if (ctrl_xfer->request.bmRequestType_bit.direction == TUSB_DIR_IN) {
896
5.39k
    ep_addr = TU_EP0_IN;
897
5.39k
    if (0u != xact_len && ctrl_xfer->buffer != _ctrl_epbuf.buf) {
898
5.39k
      TU_VERIFY(0 == tu_memcpy_s(_ctrl_epbuf.buf, CFG_TUD_ENDPOINT0_BUFSIZE, ctrl_xfer->buffer, xact_len));
899
5.39k
    }
900
5.39k
  }
901
902
17.6k
  return usbd_edpt_xfer(rhport, ep_addr, xact_len ? _ctrl_epbuf.buf : NULL, xact_len, false);
903
17.6k
}
usbd.c:data_stage_xact
Line
Count
Source
890
5.87k
static bool data_stage_xact(uint8_t rhport) {
891
5.87k
  usbd_control_xfer_t* const ctrl_xfer = &_usbd_dev.ctrl_xfer;
892
5.87k
  const uint16_t xact_len = tu_min16(ctrl_xfer->data_len - ctrl_xfer->total_xferred, CFG_TUD_ENDPOINT0_BUFSIZE);
893
5.87k
  uint8_t ep_addr = TU_EP0_OUT;
894
895
5.87k
  if (ctrl_xfer->request.bmRequestType_bit.direction == TUSB_DIR_IN) {
896
1.79k
    ep_addr = TU_EP0_IN;
897
1.79k
    if (0u != xact_len && ctrl_xfer->buffer != _ctrl_epbuf.buf) {
898
1.79k
      TU_VERIFY(0 == tu_memcpy_s(_ctrl_epbuf.buf, CFG_TUD_ENDPOINT0_BUFSIZE, ctrl_xfer->buffer, xact_len));
899
1.79k
    }
900
1.79k
  }
901
902
5.87k
  return usbd_edpt_xfer(rhport, ep_addr, xact_len ? _ctrl_epbuf.buf : NULL, xact_len, false);
903
5.87k
}
usbd.c:data_stage_xact
Line
Count
Source
890
5.87k
static bool data_stage_xact(uint8_t rhport) {
891
5.87k
  usbd_control_xfer_t* const ctrl_xfer = &_usbd_dev.ctrl_xfer;
892
5.87k
  const uint16_t xact_len = tu_min16(ctrl_xfer->data_len - ctrl_xfer->total_xferred, CFG_TUD_ENDPOINT0_BUFSIZE);
893
5.87k
  uint8_t ep_addr = TU_EP0_OUT;
894
895
5.87k
  if (ctrl_xfer->request.bmRequestType_bit.direction == TUSB_DIR_IN) {
896
1.79k
    ep_addr = TU_EP0_IN;
897
1.79k
    if (0u != xact_len && ctrl_xfer->buffer != _ctrl_epbuf.buf) {
898
1.79k
      TU_VERIFY(0 == tu_memcpy_s(_ctrl_epbuf.buf, CFG_TUD_ENDPOINT0_BUFSIZE, ctrl_xfer->buffer, xact_len));
899
1.79k
    }
900
1.79k
  }
901
902
5.87k
  return usbd_edpt_xfer(rhport, ep_addr, xact_len ? _ctrl_epbuf.buf : NULL, xact_len, false);
903
5.87k
}
usbd.c:data_stage_xact
Line
Count
Source
890
5.87k
static bool data_stage_xact(uint8_t rhport) {
891
5.87k
  usbd_control_xfer_t* const ctrl_xfer = &_usbd_dev.ctrl_xfer;
892
5.87k
  const uint16_t xact_len = tu_min16(ctrl_xfer->data_len - ctrl_xfer->total_xferred, CFG_TUD_ENDPOINT0_BUFSIZE);
893
5.87k
  uint8_t ep_addr = TU_EP0_OUT;
894
895
5.87k
  if (ctrl_xfer->request.bmRequestType_bit.direction == TUSB_DIR_IN) {
896
1.79k
    ep_addr = TU_EP0_IN;
897
1.79k
    if (0u != xact_len && ctrl_xfer->buffer != _ctrl_epbuf.buf) {
898
1.79k
      TU_VERIFY(0 == tu_memcpy_s(_ctrl_epbuf.buf, CFG_TUD_ENDPOINT0_BUFSIZE, ctrl_xfer->buffer, xact_len));
899
1.79k
    }
900
1.79k
  }
901
902
5.87k
  return usbd_edpt_xfer(rhport, ep_addr, xact_len ? _ctrl_epbuf.buf : NULL, xact_len, false);
903
5.87k
}
904
905
// Status phase
906
11.0k
bool tud_control_status(uint8_t rhport, const tusb_control_request_t* request) {
907
  // _usbd_dev.ctrl_xfer fields are pre-initialized at process_setup_received entry
908
11.0k
  (void) request;
909
11.0k
  return status_stage_xact(rhport, status_stage_ep(&_usbd_dev.ctrl_xfer.request));
910
11.0k
}
911
912
// Transmit data to/from the control endpoint. If wLength is zero, a status packet is sent instead.
913
7.47k
bool tud_control_xfer(uint8_t rhport, const tusb_control_request_t* request, void* buffer, uint16_t len) {
914
  // _usbd_dev.ctrl_xfer.request and reset fields are pre-initialized at process_setup_received entry
915
7.47k
  (void) request;
916
7.47k
  usbd_control_xfer_t* const ctrl_xfer = &_usbd_dev.ctrl_xfer;
917
7.47k
  ctrl_xfer->buffer = (uint8_t*) buffer;
918
7.47k
  ctrl_xfer->data_len = tu_min16(len, ctrl_xfer->request.wLength);
919
920
7.47k
  if (ctrl_xfer->request.wLength > 0U) {
921
5.87k
    if (ctrl_xfer->data_len > 0U) {
922
5.87k
      TU_ASSERT(buffer);
923
5.87k
    }
924
5.87k
    TU_VERIFY(data_stage_xact(rhport));
925
5.87k
  } else {
926
    // wLength == 0: Status stage is always IN per USB 2.0 §9.3.1
927
1.59k
    TU_VERIFY(status_stage_xact(rhport, TU_EP0_IN));
928
1.59k
  }
929
930
3.17k
  return true;
931
7.47k
}
932
933
// Callback when a transaction completes on the DATA stage or Status stage of EP0
934
0
static bool usbd_control_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
935
0
  (void) result;
936
0
  usbd_control_xfer_t* const ctrl_xfer = &_usbd_dev.ctrl_xfer;
937
938
  // Status Stage complete: ep_addr matches the resolved Status stage endpoint
939
0
  uint8_t const ep_status = status_stage_ep(&ctrl_xfer->request);
940
0
  if (ep_addr == ep_status) {
941
0
    TU_ASSERT(0 == xferred_bytes);
942
943
    // invoke optional dcd hook if available
944
0
    dcd_edpt0_status_complete(rhport, &ctrl_xfer->request);
945
946
0
    if (NULL != ctrl_xfer->complete_cb) {
947
0
      ctrl_xfer->complete_cb(rhport, CONTROL_STAGE_ACK, &ctrl_xfer->request);
948
0
    }
949
950
0
    return true;
951
0
  }
952
953
  // Data stage progress
954
0
  if (ctrl_xfer->request.bmRequestType_bit.direction == TUSB_DIR_OUT) {
955
0
    TU_VERIFY(ctrl_xfer->buffer);
956
    // Clamp host overrun to remaining capacity (data_len) so memcpy can't overflow the caller buffer
957
0
    xferred_bytes = tu_min32(xferred_bytes, ctrl_xfer->data_len - ctrl_xfer->total_xferred);
958
0
    if (ctrl_xfer->buffer != _ctrl_epbuf.buf) {
959
0
      memcpy(ctrl_xfer->buffer, _ctrl_epbuf.buf, xferred_bytes);
960
0
    }
961
0
    TU_LOG_MEM(CFG_TUD_LOG_LEVEL, ctrl_xfer->buffer, xferred_bytes, 2);
962
0
  }
963
964
0
  ctrl_xfer->total_xferred += (uint16_t) xferred_bytes;
965
0
  ctrl_xfer->buffer += xferred_bytes;
966
967
  // Data Stage complete when wLength reached or short packet (incl. ZLP) seen
968
0
  if ((ctrl_xfer->request.wLength == ctrl_xfer->total_xferred) ||
969
0
      (xferred_bytes < CFG_TUD_ENDPOINT0_BUFSIZE)) {
970
0
    bool is_ok = true;
971
972
0
    if (NULL != ctrl_xfer->complete_cb) {
973
      // Callback can still stall control in status phase, e.g. OUT data doesn't make sense
974
0
      is_ok = ctrl_xfer->complete_cb(rhport, CONTROL_STAGE_DATA, &ctrl_xfer->request);
975
0
    }
976
977
0
    if (is_ok) {
978
0
      TU_VERIFY(status_stage_xact(rhport, ep_status));
979
0
    } else {
980
      // Stall both IN and OUT control endpoint
981
0
      dcd_edpt_stall(rhport, TU_EP0_OUT);
982
0
      dcd_edpt_stall(rhport, TU_EP0_IN);
983
0
    }
984
0
  } else {
985
    // More data to transfer
986
0
    TU_VERIFY(data_stage_xact(rhport));
987
0
  }
988
989
0
  return true;
990
0
}
Unexecuted instantiation: usbd.c:usbd_control_xfer_cb
Unexecuted instantiation: usbd.c:usbd_control_xfer_cb
Unexecuted instantiation: usbd.c:usbd_control_xfer_cb
991
992
//--------------------------------------------------------------------+
993
// Control Request Parser & Handling
994
//--------------------------------------------------------------------+
995
996
// Helper to invoke class driver control request handler
997
4.56k
static bool invoke_class_control(uint8_t rhport, usbd_class_driver_t const * driver, tusb_control_request_t const * request) {
998
4.56k
  _usbd_dev.ctrl_xfer.complete_cb = driver->control_xfer_cb;
999
4.56k
  TU_LOG_USBD("  %s control request\r\n", driver->name);
1000
4.56k
  return driver->control_xfer_cb(rhport, CONTROL_STAGE_SETUP, request);
1001
4.56k
}
1002
1003
// Process a standard request to the device recipient.
1004
27.2k
static bool process_std_device_request(uint8_t rhport, tusb_control_request_t const * p_request) {
1005
27.2k
  switch (p_request->bRequest) { //-V2520
1006
677
    case TUSB_REQ_SET_ADDRESS:
1007
      // Depending on mcu, status phase could be sent either before or after changing device address,
1008
      // or even require stack to not response with status at all
1009
      // Therefore DCD must take full responsibility to response and include zlp status packet if needed.
1010
677
      dcd_set_address(rhport, (uint8_t) p_request->wValue);
1011
677
      _usbd_dev.addressed = 1;
1012
677
      return true;
1013
1014
987
    case TUSB_REQ_GET_CONFIGURATION: {
1015
987
      uint8_t cfg_num = _usbd_dev.cfg_num;
1016
987
      tud_control_xfer(rhport, p_request, &cfg_num, 1);
1017
987
      return true;
1018
0
    }
1019
1020
9.13k
    case TUSB_REQ_SET_CONFIGURATION: {
1021
9.13k
      uint8_t const cfg_num = (uint8_t) p_request->wValue;
1022
1023
      // Only process if new configure is different
1024
9.13k
      if (_usbd_dev.cfg_num != cfg_num) {
1025
6.95k
        if (_usbd_dev.cfg_num != 0) {
1026
          // already configured: need to clear all endpoints and driver first
1027
1.89k
          TU_LOG_USBD("  Clear current Configuration (%u) before switching\r\n", _usbd_dev.cfg_num);
1028
1029
1.89k
          dcd_sof_enable(rhport, false);
1030
1.89k
          dcd_edpt_close_all(rhport);
1031
1032
          // close all drivers and current configured state except bus speed
1033
1.89k
          const uint8_t speed = _usbd_dev.speed;
1034
1.89k
          configuration_reset(rhport);
1035
1036
1.89k
          _usbd_dev.speed = speed; // restore speed
1037
1.89k
        }
1038
1039
6.95k
        _usbd_dev.cfg_num = cfg_num;
1040
1041
        // Handle the new configuration
1042
6.95k
        if (cfg_num == 0) {
1043
145
          tud_umount_cb();
1044
6.80k
        } else {
1045
6.80k
          if (!process_set_config(rhport, cfg_num)) {
1046
3.81k
            _usbd_dev.cfg_num = 0;
1047
3.81k
            TU_ASSERT(false);
1048
3.81k
          }
1049
2.99k
          tud_mount_cb();
1050
2.99k
        }
1051
6.95k
      }
1052
1053
5.31k
      tud_control_status(rhport, p_request);
1054
5.31k
      return true;
1055
9.13k
    }
1056
1057
6.90k
    case TUSB_REQ_GET_DESCRIPTOR:
1058
6.90k
      return process_get_descriptor(rhport, p_request);
1059
1060
2.94k
    case TUSB_REQ_SET_FEATURE:
1061
2.94k
      switch (p_request->wValue) { //-V2520
1062
2.21k
        case TUSB_REQ_FEATURE_REMOTE_WAKEUP:
1063
2.21k
          TU_LOG_USBD("    Enable Remote Wakeup\r\n");
1064
          // Host may enable remote wake up before suspending especially HID device
1065
2.21k
          _usbd_dev.remote_wakeup_en = 1;
1066
2.21k
          tud_control_status(rhport, p_request);
1067
2.21k
          return true;
1068
1069
        #if CFG_TUD_TEST_MODE
1070
        case TUSB_REQ_FEATURE_TEST_MODE: {
1071
          // Only handle the test mode if supported and valid
1072
          TU_VERIFY(0 == tu_u16_low(p_request->wIndex));
1073
1074
          uint8_t const selector = tu_u16_high(p_request->wIndex);
1075
          TU_VERIFY(TUSB_FEATURE_TEST_J <= selector && selector <= TUSB_FEATURE_TEST_FORCE_ENABLE);
1076
1077
          _usbd_dev.ctrl_xfer.complete_cb = process_test_mode_cb;
1078
          tud_control_status(rhport, p_request);
1079
          return true;
1080
        }
1081
        #endif
1082
1083
        // Stall unsupported feature selector
1084
733
        default: return false;
1085
2.94k
      }
1086
1087
2.79k
    case TUSB_REQ_CLEAR_FEATURE:
1088
      // Only support remote wakeup for device feature
1089
2.79k
      TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue);
1090
2.04k
      TU_LOG_USBD("    Disable Remote Wakeup\r\n");
1091
1092
      // Host may disable remote wake up after resuming
1093
2.04k
      _usbd_dev.remote_wakeup_en = 0;
1094
2.04k
      tud_control_status(rhport, p_request);
1095
2.04k
      return true;
1096
1097
2.27k
    case TUSB_REQ_GET_STATUS: {
1098
      // Device status bit mask
1099
      // - Bit 0: Self Powered TODO must invoke callback to get actual status
1100
      // - Bit 1: Remote Wakeup enabled
1101
2.27k
      return process_get_status(rhport, p_request, (uint16_t) _usbd_dev.dev_state_bm);
1102
2.79k
    }
1103
1104
1.49k
    default:
1105
1.49k
      TU_BREAKPOINT();
1106
1.49k
      return false;
1107
27.2k
  }
1108
27.2k
}
1109
1110
1111
// Reply to a standard GET_STATUS (device/interface/endpoint) with its 2-byte status word.
1112
// GET_STATUS is Device-to-host only; reject a mis-directed (OUT) request rather than handing
1113
// usbd the address of a stack local to write host data into after this frame has returned.
1114
4.92k
static bool process_get_status(uint8_t rhport, tusb_control_request_t const * request, uint16_t status) {
1115
4.92k
  TU_VERIFY(request->bmRequestType_bit.direction == TUSB_DIR_IN);
1116
2.10k
  return tud_control_xfer(rhport, request, &status, 2);
1117
4.92k
}
1118
1119
// This handles the actual request and its response.
1120
// Returns false if unable to complete the request, causing caller to stall control endpoints.
1121
47.7k
static bool process_setup_received(uint8_t rhport, tusb_control_request_t const * p_request) {
1122
  // Initialize control transfer state for this request. The request copy must be
1123
  // visible to usbd_control_xfer_cb when the (asynchronous) status ZLP completes,
1124
  // since the SETUP packet event has already gone out of scope by then.
1125
47.7k
  usbd_control_xfer_t* const ctrl_xfer = &_usbd_dev.ctrl_xfer;
1126
47.7k
  ctrl_xfer->request = *p_request;
1127
47.7k
  ctrl_xfer->buffer = NULL;
1128
47.7k
  ctrl_xfer->total_xferred = 0;
1129
47.7k
  ctrl_xfer->data_len = 0;
1130
47.7k
  ctrl_xfer->complete_cb = NULL;
1131
1132
47.7k
  p_request = &ctrl_xfer->request; // re-direct request pointer to internal copy (modifiable for hacking)
1133
47.7k
  TU_ASSERT(p_request->bmRequestType_bit.type < TUSB_REQ_TYPE_INVALID);
1134
1135
  // Vendor request
1136
45.8k
  if ( p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_VENDOR ) {
1137
1.24k
    ctrl_xfer->complete_cb = tud_vendor_control_xfer_cb;
1138
1.24k
    return tud_vendor_control_xfer_cb(rhport, CONTROL_STAGE_SETUP, p_request);
1139
1.24k
  }
1140
1141
#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
1142
  if (TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type && p_request->bRequest <= TUSB_REQ_SYNCH_FRAME) {
1143
    TU_LOG_USBD("  %s", tu_str_std_request[p_request->bRequest]);
1144
    if (TUSB_REQ_GET_DESCRIPTOR != p_request->bRequest) {
1145
      TU_LOG_USBD("\r\n");
1146
    }
1147
  }
1148
#endif
1149
1150
44.5k
  switch (p_request->bmRequestType_bit.recipient) { //-V2520
1151
    //------------- Device Requests e.g in enumeration -------------//
1152
29.9k
    case TUSB_REQ_RCPT_DEVICE:
1153
29.9k
      if ( TUSB_REQ_TYPE_CLASS == p_request->bmRequestType_bit.type ) {
1154
2.72k
        uint8_t const itf = tu_u16_low(p_request->wIndex);
1155
2.72k
        TU_VERIFY(itf < TU_ARRAY_SIZE(_usbd_dev.itf2drv));
1156
1157
2.00k
        usbd_class_driver_t const * driver = get_driver(_usbd_dev.itf2drv[itf]);
1158
2.00k
        TU_VERIFY(driver);
1159
1160
        // forward to class driver: "non-STD request to Interface"
1161
1.35k
        return invoke_class_control(rhport, driver, p_request);
1162
2.00k
      }
1163
1164
27.2k
      if (TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type) {
1165
        // Non-standard request is not supported
1166
0
        TU_BREAKPOINT();
1167
0
        return false;
1168
0
      }
1169
1170
27.2k
      return process_std_device_request(rhport, p_request);
1171
1172
    //------------- Class/Interface Specific Request -------------//
1173
4.26k
    case TUSB_REQ_RCPT_INTERFACE: {
1174
4.26k
      uint8_t itf;
1175
      #if CFG_TUD_PRINTER
1176
      // Printer GET_DEVICE_ID has a weird wIndex = interface (high) | alt (low)
1177
      // attempt to interpret this as a printer request if matched
1178
      if (TUSB_REQ_TYPE_CLASS == p_request->bmRequestType_bit.type &&
1179
          TUSB_DIR_IN == p_request->bmRequestType_bit.direction &&
1180
          TUSB_PRINTER_REQUEST_GET_DEVICE_ID == p_request->bRequest) {
1181
        itf = tu_u16_high(p_request->wIndex);
1182
        if (itf < TU_ARRAY_SIZE(_usbd_dev.itf2drv)) {
1183
          const usbd_class_driver_t * driver = get_driver(_usbd_dev.itf2drv[itf]);
1184
          if (driver != NULL && driver->control_xfer_cb == printerd_control_xfer_cb) {
1185
            if (invoke_class_control(rhport, driver, p_request)) {
1186
              return true;
1187
            }
1188
          }
1189
        }
1190
      }
1191
      #endif
1192
4.26k
      itf = tu_u16_low(p_request->wIndex);
1193
4.26k
      TU_VERIFY(itf < TU_ARRAY_SIZE(_usbd_dev.itf2drv));
1194
1195
3.40k
      usbd_class_driver_t const * driver = get_driver(_usbd_dev.itf2drv[itf]);
1196
3.40k
      TU_VERIFY(driver);
1197
1198
      // all requests to Interface (STD or Class) is forwarded to class driver.
1199
      // notable requests are: GET HID REPORT DESCRIPTOR, SET_INTERFACE, GET_INTERFACE
1200
2.36k
      if (!invoke_class_control(rhport, driver, p_request)) {
1201
        // For GET_INTERFACE and SET_INTERFACE, it is mandatory to respond even if the class
1202
        // driver doesn't use alternate settings or implement this
1203
2.15k
        TU_VERIFY(TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type);
1204
1205
        // Clear complete callback if driver set since it can also stall the request.
1206
1.68k
        ctrl_xfer->complete_cb = NULL;
1207
1208
1.68k
        switch (p_request->bRequest) { //-V2520
1209
124
          case TUSB_REQ_GET_INTERFACE: {
1210
124
            uint8_t alternate = 0;
1211
124
            tud_control_xfer(rhport, p_request, &alternate, 1);
1212
124
            break;
1213
0
          }
1214
1215
348
          case TUSB_REQ_SET_INTERFACE:
1216
            // A class that implements altsettings handles SET_INTERFACE itself and returns true,
1217
            // so reaching here means the class does not — where only alt 0 is valid. Any non-zero
1218
            // alt (unimplemented, or rejected as invalid by the class) is a Request Error (stall).
1219
348
            TU_VERIFY(tu_u16_low(p_request->wValue) == 0);
1220
214
            tud_control_status(rhport, p_request);
1221
214
            break;
1222
1223
708
          case TUSB_REQ_GET_STATUS:
1224
            // USB 2.0 9.4.5: interface GET_STATUS returns 2 reserved (zero) bytes
1225
708
            TU_VERIFY(process_get_status(rhport, p_request, 0x0000));
1226
79
            break;
1227
1228
504
          default: return false;
1229
1.68k
        }
1230
1.68k
      }
1231
632
      break;
1232
2.36k
    }
1233
1234
    //------------- Endpoint Request -------------//
1235
7.77k
    case TUSB_REQ_RCPT_ENDPOINT: {
1236
7.77k
      uint8_t const ep_addr = tu_u16_low(p_request->wIndex);
1237
7.77k
      uint8_t const ep_num  = tu_edpt_number(ep_addr);
1238
7.77k
      uint8_t const ep_dir  = tu_edpt_dir(ep_addr);
1239
1240
7.77k
      TU_ASSERT(ep_num < TU_ARRAY_SIZE(_usbd_dev.ep2drv) );
1241
7.08k
      usbd_class_driver_t const * driver = get_driver(_usbd_dev.ep2drv[ep_num][ep_dir]);
1242
1243
7.08k
      if (TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type) {
1244
        // Forward class request to its driver
1245
1.12k
        TU_VERIFY(driver);
1246
451
        return invoke_class_control(rhport, driver, p_request);
1247
5.96k
      } else {
1248
        // Handle STD request to endpoint
1249
5.96k
        switch (p_request->bRequest) { //-V2520
1250
1.94k
          case TUSB_REQ_GET_STATUS:
1251
            // USB 2.0 9.4.5: endpoint GET_STATUS bit 0 = Halt
1252
1.94k
            TU_VERIFY(process_get_status(rhport, p_request, usbd_edpt_stalled(rhport, ep_addr) ? 0x0001u : 0x0000u));
1253
644
            break;
1254
1255
1.44k
          case TUSB_REQ_CLEAR_FEATURE:
1256
3.07k
          case TUSB_REQ_SET_FEATURE: {
1257
            // ENDPOINT_HALT is the only endpoint feature; it exists only on a non-control endpoint
1258
            // that an interface actually owns. Any other selector, the control endpoint (EP0 has no
1259
            // Halt feature, USB 2.0 9.4.9), or an endpoint no driver owns is a Request Error (stall).
1260
3.07k
            TU_VERIFY(TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue);
1261
1.91k
            TU_VERIFY(ep_num != 0);
1262
1.23k
            TU_VERIFY(driver != NULL);
1263
1264
397
            if ( TUSB_REQ_CLEAR_FEATURE == p_request->bRequest ) {
1265
192
              usbd_edpt_clear_stall(rhport, ep_addr);
1266
205
            } else {
1267
205
              usbd_edpt_stall(rhport, ep_addr);
1268
205
            }
1269
1270
            // Some classes such as USBTMC need to clear/re-init their buffer on CLEAR_FEATURE.
1271
            // Clear complete callback if driver set since it can also stall the request.
1272
397
            (void) invoke_class_control(rhport, driver, p_request);
1273
397
            ctrl_xfer->complete_cb = NULL;
1274
1275
            // STD request must always be ACKed; skip ZLP status if driver already did that.
1276
397
            if (!(_usbd_dev.ep_status[0][TUSB_DIR_IN] & TU_EDPT_STATE_BUSY)) {
1277
397
              tud_control_status(rhport, p_request);
1278
397
            }
1279
397
          }
1280
0
          break;
1281
1282
          // Unknown/Unsupported request
1283
943
          default:
1284
943
            TU_BREAKPOINT();
1285
943
            return false;
1286
5.96k
        }
1287
5.96k
      }
1288
1.04k
      break;
1289
7.08k
    }
1290
1291
    // Unknown recipient
1292
2.60k
    default:
1293
2.60k
      TU_BREAKPOINT();
1294
2.60k
      return false;
1295
44.5k
  }
1296
1297
1.67k
  return true;
1298
44.5k
}
1299
1300
// Process Set Configure Request
1301
// This function parse configuration descriptor & open drivers accordingly
1302
6.80k
static bool process_set_config(uint8_t rhport, uint8_t cfg_num) {
1303
  // index is cfg_num-1
1304
6.80k
  const tusb_desc_configuration_t *desc_cfg =
1305
6.80k
    (const tusb_desc_configuration_t *)tud_descriptor_configuration_cb(cfg_num - 1);
1306
6.80k
  TU_ASSERT(desc_cfg != NULL && desc_cfg->bDescriptorType == TUSB_DESC_CONFIGURATION);
1307
1308
  // Parse configuration descriptor
1309
6.80k
  _usbd_dev.self_powered = (desc_cfg->bmAttributes & TUSB_DESC_CONFIG_ATT_SELF_POWERED) ? 1u : 0u;
1310
1311
  // Parse interface descriptor
1312
6.80k
  const uint8_t *p_desc   = ((const uint8_t *)desc_cfg) + sizeof(tusb_desc_configuration_t);
1313
6.80k
  const uint8_t *desc_end = ((const uint8_t *)desc_cfg) + tu_le16toh(desc_cfg->wTotalLength);
1314
1315
16.3k
  while (tu_desc_in_bounds(p_desc, desc_end)) {
1316
    // Class will always start with Interface Association (if any) and then Interface descriptor
1317
13.3k
    if (TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc)) {
1318
6.56k
      p_desc = tu_desc_next(p_desc); // next to Interface
1319
6.56k
      continue;
1320
6.56k
    }
1321
1322
6.80k
    TU_ASSERT(TUSB_DESC_INTERFACE == tu_desc_type(p_desc));
1323
6.80k
    const tusb_desc_interface_t *desc_itf = (const tusb_desc_interface_t *)p_desc;
1324
1325
    // Find driver for this interface
1326
6.80k
    const uint16_t remaining_len = (uint16_t)(desc_end - p_desc);
1327
6.80k
    uint8_t        drv_id;
1328
12.4k
    for (drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++) {
1329
8.61k
      const usbd_class_driver_t *driver = get_driver(drv_id);
1330
8.61k
      TU_ASSERT(driver);
1331
8.61k
      const uint16_t drv_len = driver->open(rhport, desc_itf, remaining_len);
1332
1333
8.61k
      if ((sizeof(tusb_desc_interface_t) <= drv_len) && (drv_len <= remaining_len)) {
1334
        // Open successfully
1335
2.99k
        TU_LOG_USBD("  %s opened\r\n", driver->name);
1336
1337
        // bind found driver to all interfaces and endpoint within drv_len
1338
2.99k
        TU_ASSERT(tu_bind_driver_to_ep_itf(drv_id, _usbd_dev.ep2drv, _usbd_dev.itf2drv, CFG_TUD_INTERFACE_MAX,
1339
2.99k
                                           CFG_TUD_ENDPPOINT_MAX, p_desc, drv_len));
1340
1341
2.99k
        p_desc += drv_len; // next Interface
1342
2.99k
        break; // exit driver find loop
1343
2.99k
      }
1344
8.61k
    }
1345
1346
    // Failed if there is no supported drivers
1347
6.80k
    TU_ASSERT(drv_id < TOTAL_DRIVER_COUNT);
1348
6.80k
  }
1349
1350
2.99k
  return true;
1351
6.80k
}
1352
1353
// return descriptor's buffer and update desc_len
1354
20.7k
static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request) {
1355
20.7k
  tusb_desc_type_t const desc_type = (tusb_desc_type_t) tu_u16_high(p_request->wValue);
1356
20.7k
  uint8_t const desc_index = tu_u16_low( p_request->wValue );
1357
1358
20.7k
  switch(desc_type) { //-V2520
1359
3.15k
    case TUSB_DESC_DEVICE: {
1360
3.15k
      TU_LOG_USBD(" Device\r\n");
1361
1362
3.15k
      void *desc_device = (void *)(uintptr_t)tud_descriptor_device_cb();
1363
3.15k
      TU_ASSERT(desc_device);
1364
1365
      // Only response with exactly 1 Packet if: not addressed and host requested more data than device descriptor has.
1366
      // This only happens with the very first get device descriptor and EP0 size = 8 or 16.
1367
3.15k
      if ((CFG_TUD_ENDPOINT0_SIZE < sizeof(tusb_desc_device_t)) && !_usbd_dev.addressed &&
1368
0
          p_request->wLength > sizeof(tusb_desc_device_t)) {
1369
        // Hack here: we modify the request length to prevent usbd_control response with zlp
1370
        // since we are responding with 1 packet & less data than wLength.
1371
0
        ((tusb_control_request_t *)(uintptr_t)p_request)->wLength = CFG_TUD_ENDPOINT0_SIZE;
1372
0
        return tud_control_xfer(rhport, p_request, desc_device, CFG_TUD_ENDPOINT0_SIZE);
1373
3.15k
      } else {
1374
3.15k
        return tud_control_xfer(rhport, p_request, desc_device, sizeof(tusb_desc_device_t));
1375
3.15k
      }
1376
3.15k
    }
1377
    // break; // unreachable
1378
1379
1.82k
    case TUSB_DESC_BOS: {
1380
1.82k
      TU_LOG_USBD(" BOS\r\n");
1381
1382
      // requested by host if USB > 2.0 ( i.e 2.1 or 3.x )
1383
1.82k
      uintptr_t desc_bos = (uintptr_t) tud_descriptor_bos_cb();
1384
1.82k
      TU_VERIFY(desc_bos != 0);
1385
1386
      // Use offsetof to avoid pointer to the odd/misaligned address
1387
0
      uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_bos + offsetof(tusb_desc_bos_t, wTotalLength))) );
1388
1389
0
      return tud_control_xfer(rhport, p_request, (void*) desc_bos, total_len);
1390
1.82k
    }
1391
    // break; // unreachable
1392
1393
2.69k
    case TUSB_DESC_CONFIGURATION:
1394
4.55k
    case TUSB_DESC_OTHER_SPEED_CONFIG: {
1395
4.55k
      uintptr_t desc_config;
1396
1397
4.55k
      if ( desc_type == TUSB_DESC_CONFIGURATION ) {
1398
2.69k
        TU_LOG_USBD(" Configuration[%u]\r\n", desc_index);
1399
2.69k
        desc_config = (uintptr_t) tud_descriptor_configuration_cb(desc_index);
1400
2.69k
        TU_ASSERT(desc_config != 0);
1401
2.69k
      }else {
1402
        // Host only request this after getting Device Qualifier descriptor
1403
1.86k
        TU_LOG_USBD(" Other Speed Configuration\r\n");
1404
1.86k
        desc_config = (uintptr_t) tud_descriptor_other_speed_configuration_cb(desc_index);
1405
1.86k
        TU_VERIFY(desc_config != 0);
1406
1.86k
      }
1407
1408
      // Use offsetof to avoid pointer to the odd/misaligned address
1409
2.69k
      uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_config + offsetof(tusb_desc_configuration_t, wTotalLength))) );
1410
1411
2.69k
      return tud_control_xfer(rhport, p_request, (void*) desc_config, total_len);
1412
4.55k
    }
1413
    // break; // unreachable
1414
1415
7.34k
    case TUSB_DESC_STRING: {
1416
7.34k
      TU_LOG_USBD(" String[%u]\r\n", desc_index);
1417
1418
      // String Descriptor always uses the desc set from user
1419
7.34k
      uint8_t const* desc_str = (uint8_t const*) tud_descriptor_string_cb(desc_index, p_request->wIndex);
1420
7.34k
      TU_VERIFY(desc_str);
1421
1422
      // first byte of descriptor is its size
1423
5.33k
      return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_str, tu_desc_len(desc_str));
1424
7.34k
    }
1425
    // break; // unreachable
1426
1427
1.78k
    case TUSB_DESC_DEVICE_QUALIFIER: {
1428
1.78k
      TU_LOG_USBD(" Device Qualifier\r\n");
1429
1.78k
      uint8_t const* desc_qualifier = tud_descriptor_device_qualifier_cb();
1430
1.78k
      TU_VERIFY(desc_qualifier);
1431
0
      return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_qualifier, tu_desc_len(desc_qualifier));
1432
1.78k
    }
1433
    // break; // unreachable
1434
1435
2.05k
    default: return false;
1436
20.7k
  }
1437
20.7k
}
usbd.c:process_get_descriptor
Line
Count
Source
1354
6.90k
static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request) {
1355
6.90k
  tusb_desc_type_t const desc_type = (tusb_desc_type_t) tu_u16_high(p_request->wValue);
1356
6.90k
  uint8_t const desc_index = tu_u16_low( p_request->wValue );
1357
1358
6.90k
  switch(desc_type) { //-V2520
1359
1.05k
    case TUSB_DESC_DEVICE: {
1360
1.05k
      TU_LOG_USBD(" Device\r\n");
1361
1362
1.05k
      void *desc_device = (void *)(uintptr_t)tud_descriptor_device_cb();
1363
1.05k
      TU_ASSERT(desc_device);
1364
1365
      // Only response with exactly 1 Packet if: not addressed and host requested more data than device descriptor has.
1366
      // This only happens with the very first get device descriptor and EP0 size = 8 or 16.
1367
1.05k
      if ((CFG_TUD_ENDPOINT0_SIZE < sizeof(tusb_desc_device_t)) && !_usbd_dev.addressed &&
1368
0
          p_request->wLength > sizeof(tusb_desc_device_t)) {
1369
        // Hack here: we modify the request length to prevent usbd_control response with zlp
1370
        // since we are responding with 1 packet & less data than wLength.
1371
0
        ((tusb_control_request_t *)(uintptr_t)p_request)->wLength = CFG_TUD_ENDPOINT0_SIZE;
1372
0
        return tud_control_xfer(rhport, p_request, desc_device, CFG_TUD_ENDPOINT0_SIZE);
1373
1.05k
      } else {
1374
1.05k
        return tud_control_xfer(rhport, p_request, desc_device, sizeof(tusb_desc_device_t));
1375
1.05k
      }
1376
1.05k
    }
1377
    // break; // unreachable
1378
1379
607
    case TUSB_DESC_BOS: {
1380
607
      TU_LOG_USBD(" BOS\r\n");
1381
1382
      // requested by host if USB > 2.0 ( i.e 2.1 or 3.x )
1383
607
      uintptr_t desc_bos = (uintptr_t) tud_descriptor_bos_cb();
1384
607
      TU_VERIFY(desc_bos != 0);
1385
1386
      // Use offsetof to avoid pointer to the odd/misaligned address
1387
0
      uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_bos + offsetof(tusb_desc_bos_t, wTotalLength))) );
1388
1389
0
      return tud_control_xfer(rhport, p_request, (void*) desc_bos, total_len);
1390
607
    }
1391
    // break; // unreachable
1392
1393
899
    case TUSB_DESC_CONFIGURATION:
1394
1.51k
    case TUSB_DESC_OTHER_SPEED_CONFIG: {
1395
1.51k
      uintptr_t desc_config;
1396
1397
1.51k
      if ( desc_type == TUSB_DESC_CONFIGURATION ) {
1398
899
        TU_LOG_USBD(" Configuration[%u]\r\n", desc_index);
1399
899
        desc_config = (uintptr_t) tud_descriptor_configuration_cb(desc_index);
1400
899
        TU_ASSERT(desc_config != 0);
1401
899
      }else {
1402
        // Host only request this after getting Device Qualifier descriptor
1403
620
        TU_LOG_USBD(" Other Speed Configuration\r\n");
1404
620
        desc_config = (uintptr_t) tud_descriptor_other_speed_configuration_cb(desc_index);
1405
620
        TU_VERIFY(desc_config != 0);
1406
620
      }
1407
1408
      // Use offsetof to avoid pointer to the odd/misaligned address
1409
899
      uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_config + offsetof(tusb_desc_configuration_t, wTotalLength))) );
1410
1411
899
      return tud_control_xfer(rhport, p_request, (void*) desc_config, total_len);
1412
1.51k
    }
1413
    // break; // unreachable
1414
1415
2.44k
    case TUSB_DESC_STRING: {
1416
2.44k
      TU_LOG_USBD(" String[%u]\r\n", desc_index);
1417
1418
      // String Descriptor always uses the desc set from user
1419
2.44k
      uint8_t const* desc_str = (uint8_t const*) tud_descriptor_string_cb(desc_index, p_request->wIndex);
1420
2.44k
      TU_VERIFY(desc_str);
1421
1422
      // first byte of descriptor is its size
1423
1.77k
      return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_str, tu_desc_len(desc_str));
1424
2.44k
    }
1425
    // break; // unreachable
1426
1427
594
    case TUSB_DESC_DEVICE_QUALIFIER: {
1428
594
      TU_LOG_USBD(" Device Qualifier\r\n");
1429
594
      uint8_t const* desc_qualifier = tud_descriptor_device_qualifier_cb();
1430
594
      TU_VERIFY(desc_qualifier);
1431
0
      return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_qualifier, tu_desc_len(desc_qualifier));
1432
594
    }
1433
    // break; // unreachable
1434
1435
685
    default: return false;
1436
6.90k
  }
1437
6.90k
}
usbd.c:process_get_descriptor
Line
Count
Source
1354
6.90k
static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request) {
1355
6.90k
  tusb_desc_type_t const desc_type = (tusb_desc_type_t) tu_u16_high(p_request->wValue);
1356
6.90k
  uint8_t const desc_index = tu_u16_low( p_request->wValue );
1357
1358
6.90k
  switch(desc_type) { //-V2520
1359
1.05k
    case TUSB_DESC_DEVICE: {
1360
1.05k
      TU_LOG_USBD(" Device\r\n");
1361
1362
1.05k
      void *desc_device = (void *)(uintptr_t)tud_descriptor_device_cb();
1363
1.05k
      TU_ASSERT(desc_device);
1364
1365
      // Only response with exactly 1 Packet if: not addressed and host requested more data than device descriptor has.
1366
      // This only happens with the very first get device descriptor and EP0 size = 8 or 16.
1367
1.05k
      if ((CFG_TUD_ENDPOINT0_SIZE < sizeof(tusb_desc_device_t)) && !_usbd_dev.addressed &&
1368
0
          p_request->wLength > sizeof(tusb_desc_device_t)) {
1369
        // Hack here: we modify the request length to prevent usbd_control response with zlp
1370
        // since we are responding with 1 packet & less data than wLength.
1371
0
        ((tusb_control_request_t *)(uintptr_t)p_request)->wLength = CFG_TUD_ENDPOINT0_SIZE;
1372
0
        return tud_control_xfer(rhport, p_request, desc_device, CFG_TUD_ENDPOINT0_SIZE);
1373
1.05k
      } else {
1374
1.05k
        return tud_control_xfer(rhport, p_request, desc_device, sizeof(tusb_desc_device_t));
1375
1.05k
      }
1376
1.05k
    }
1377
    // break; // unreachable
1378
1379
607
    case TUSB_DESC_BOS: {
1380
607
      TU_LOG_USBD(" BOS\r\n");
1381
1382
      // requested by host if USB > 2.0 ( i.e 2.1 or 3.x )
1383
607
      uintptr_t desc_bos = (uintptr_t) tud_descriptor_bos_cb();
1384
607
      TU_VERIFY(desc_bos != 0);
1385
1386
      // Use offsetof to avoid pointer to the odd/misaligned address
1387
0
      uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_bos + offsetof(tusb_desc_bos_t, wTotalLength))) );
1388
1389
0
      return tud_control_xfer(rhport, p_request, (void*) desc_bos, total_len);
1390
607
    }
1391
    // break; // unreachable
1392
1393
899
    case TUSB_DESC_CONFIGURATION:
1394
1.51k
    case TUSB_DESC_OTHER_SPEED_CONFIG: {
1395
1.51k
      uintptr_t desc_config;
1396
1397
1.51k
      if ( desc_type == TUSB_DESC_CONFIGURATION ) {
1398
899
        TU_LOG_USBD(" Configuration[%u]\r\n", desc_index);
1399
899
        desc_config = (uintptr_t) tud_descriptor_configuration_cb(desc_index);
1400
899
        TU_ASSERT(desc_config != 0);
1401
899
      }else {
1402
        // Host only request this after getting Device Qualifier descriptor
1403
620
        TU_LOG_USBD(" Other Speed Configuration\r\n");
1404
620
        desc_config = (uintptr_t) tud_descriptor_other_speed_configuration_cb(desc_index);
1405
620
        TU_VERIFY(desc_config != 0);
1406
620
      }
1407
1408
      // Use offsetof to avoid pointer to the odd/misaligned address
1409
899
      uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_config + offsetof(tusb_desc_configuration_t, wTotalLength))) );
1410
1411
899
      return tud_control_xfer(rhport, p_request, (void*) desc_config, total_len);
1412
1.51k
    }
1413
    // break; // unreachable
1414
1415
2.44k
    case TUSB_DESC_STRING: {
1416
2.44k
      TU_LOG_USBD(" String[%u]\r\n", desc_index);
1417
1418
      // String Descriptor always uses the desc set from user
1419
2.44k
      uint8_t const* desc_str = (uint8_t const*) tud_descriptor_string_cb(desc_index, p_request->wIndex);
1420
2.44k
      TU_VERIFY(desc_str);
1421
1422
      // first byte of descriptor is its size
1423
1.77k
      return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_str, tu_desc_len(desc_str));
1424
2.44k
    }
1425
    // break; // unreachable
1426
1427
594
    case TUSB_DESC_DEVICE_QUALIFIER: {
1428
594
      TU_LOG_USBD(" Device Qualifier\r\n");
1429
594
      uint8_t const* desc_qualifier = tud_descriptor_device_qualifier_cb();
1430
594
      TU_VERIFY(desc_qualifier);
1431
0
      return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_qualifier, tu_desc_len(desc_qualifier));
1432
594
    }
1433
    // break; // unreachable
1434
1435
685
    default: return false;
1436
6.90k
  }
1437
6.90k
}
usbd.c:process_get_descriptor
Line
Count
Source
1354
6.90k
static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request) {
1355
6.90k
  tusb_desc_type_t const desc_type = (tusb_desc_type_t) tu_u16_high(p_request->wValue);
1356
6.90k
  uint8_t const desc_index = tu_u16_low( p_request->wValue );
1357
1358
6.90k
  switch(desc_type) { //-V2520
1359
1.05k
    case TUSB_DESC_DEVICE: {
1360
1.05k
      TU_LOG_USBD(" Device\r\n");
1361
1362
1.05k
      void *desc_device = (void *)(uintptr_t)tud_descriptor_device_cb();
1363
1.05k
      TU_ASSERT(desc_device);
1364
1365
      // Only response with exactly 1 Packet if: not addressed and host requested more data than device descriptor has.
1366
      // This only happens with the very first get device descriptor and EP0 size = 8 or 16.
1367
1.05k
      if ((CFG_TUD_ENDPOINT0_SIZE < sizeof(tusb_desc_device_t)) && !_usbd_dev.addressed &&
1368
0
          p_request->wLength > sizeof(tusb_desc_device_t)) {
1369
        // Hack here: we modify the request length to prevent usbd_control response with zlp
1370
        // since we are responding with 1 packet & less data than wLength.
1371
0
        ((tusb_control_request_t *)(uintptr_t)p_request)->wLength = CFG_TUD_ENDPOINT0_SIZE;
1372
0
        return tud_control_xfer(rhport, p_request, desc_device, CFG_TUD_ENDPOINT0_SIZE);
1373
1.05k
      } else {
1374
1.05k
        return tud_control_xfer(rhport, p_request, desc_device, sizeof(tusb_desc_device_t));
1375
1.05k
      }
1376
1.05k
    }
1377
    // break; // unreachable
1378
1379
607
    case TUSB_DESC_BOS: {
1380
607
      TU_LOG_USBD(" BOS\r\n");
1381
1382
      // requested by host if USB > 2.0 ( i.e 2.1 or 3.x )
1383
607
      uintptr_t desc_bos = (uintptr_t) tud_descriptor_bos_cb();
1384
607
      TU_VERIFY(desc_bos != 0);
1385
1386
      // Use offsetof to avoid pointer to the odd/misaligned address
1387
0
      uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_bos + offsetof(tusb_desc_bos_t, wTotalLength))) );
1388
1389
0
      return tud_control_xfer(rhport, p_request, (void*) desc_bos, total_len);
1390
607
    }
1391
    // break; // unreachable
1392
1393
899
    case TUSB_DESC_CONFIGURATION:
1394
1.51k
    case TUSB_DESC_OTHER_SPEED_CONFIG: {
1395
1.51k
      uintptr_t desc_config;
1396
1397
1.51k
      if ( desc_type == TUSB_DESC_CONFIGURATION ) {
1398
899
        TU_LOG_USBD(" Configuration[%u]\r\n", desc_index);
1399
899
        desc_config = (uintptr_t) tud_descriptor_configuration_cb(desc_index);
1400
899
        TU_ASSERT(desc_config != 0);
1401
899
      }else {
1402
        // Host only request this after getting Device Qualifier descriptor
1403
620
        TU_LOG_USBD(" Other Speed Configuration\r\n");
1404
620
        desc_config = (uintptr_t) tud_descriptor_other_speed_configuration_cb(desc_index);
1405
620
        TU_VERIFY(desc_config != 0);
1406
620
      }
1407
1408
      // Use offsetof to avoid pointer to the odd/misaligned address
1409
899
      uint16_t const total_len = tu_le16toh( tu_unaligned_read16((const void*) (desc_config + offsetof(tusb_desc_configuration_t, wTotalLength))) );
1410
1411
899
      return tud_control_xfer(rhport, p_request, (void*) desc_config, total_len);
1412
1.51k
    }
1413
    // break; // unreachable
1414
1415
2.44k
    case TUSB_DESC_STRING: {
1416
2.44k
      TU_LOG_USBD(" String[%u]\r\n", desc_index);
1417
1418
      // String Descriptor always uses the desc set from user
1419
2.44k
      uint8_t const* desc_str = (uint8_t const*) tud_descriptor_string_cb(desc_index, p_request->wIndex);
1420
2.44k
      TU_VERIFY(desc_str);
1421
1422
      // first byte of descriptor is its size
1423
1.77k
      return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_str, tu_desc_len(desc_str));
1424
2.44k
    }
1425
    // break; // unreachable
1426
1427
594
    case TUSB_DESC_DEVICE_QUALIFIER: {
1428
594
      TU_LOG_USBD(" Device Qualifier\r\n");
1429
594
      uint8_t const* desc_qualifier = tud_descriptor_device_qualifier_cb();
1430
594
      TU_VERIFY(desc_qualifier);
1431
0
      return tud_control_xfer(rhport, p_request, (void*) (uintptr_t) desc_qualifier, tu_desc_len(desc_qualifier));
1432
594
    }
1433
    // break; // unreachable
1434
1435
685
    default: return false;
1436
6.90k
  }
1437
6.90k
}
1438
1439
//--------------------------------------------------------------------+
1440
// DCD Event Handler
1441
//--------------------------------------------------------------------+
1442
133k
TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const* event, bool in_isr) {
1443
133k
  bool send = false;
1444
133k
  switch (event->event_id) {
1445
14.8k
    case DCD_EVENT_UNPLUGGED:
1446
14.8k
      _usbd_dev.connected = 0;
1447
14.8k
      _usbd_dev.addressed = 0;
1448
14.8k
      _usbd_dev.cfg_num = 0;
1449
14.8k
      _usbd_dev.suspended = 0;
1450
14.8k
      send = true;
1451
14.8k
      break;
1452
1453
14.3k
    case DCD_EVENT_SUSPEND:
1454
      // NOTE: When plugging/unplugging device, the D+/D- state are unstable and
1455
      // can accidentally meet the SUSPEND condition ( Bus Idle for 3ms ).
1456
      // In addition, some MCUs such as SAMD or boards that haven no VBUS detection cannot distinguish
1457
      // suspended vs disconnected. We will skip handling SUSPEND/RESUME event if not currently connected
1458
14.3k
      if (_usbd_dev.connected) {
1459
5.16k
        _usbd_dev.suspended = 1;
1460
5.16k
        send = true;
1461
5.16k
      }
1462
14.3k
      break;
1463
1464
10.4k
    case DCD_EVENT_RESUME:
1465
      // skip event if not connected (especially required for SAMD)
1466
10.4k
      if (_usbd_dev.connected) {
1467
4.99k
        _usbd_dev.suspended = 0;
1468
4.99k
        send = true;
1469
4.99k
      }
1470
10.4k
      break;
1471
1472
0
    case DCD_EVENT_SOF:
1473
      // SOF driver handler in ISR context
1474
0
      for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) {
1475
0
        usbd_class_driver_t const* driver = get_driver(i);
1476
0
        if (driver && driver->sof) {
1477
0
          driver->sof(event->rhport, event->sof.frame_count);
1478
0
        }
1479
0
      }
1480
1481
      // Some MCUs after running dcd_remote_wakeup() does not have way to detect the end of remote wakeup
1482
      // which last 1-15 ms. DCD can use SOF as a clear indicator that bus is back to operational
1483
0
      if (_usbd_dev.suspended) {
1484
0
        _usbd_dev.suspended = 0;
1485
1486
0
        dcd_event_t const event_resume = {.rhport = event->rhport, .event_id = DCD_EVENT_RESUME};
1487
0
        queue_event(&event_resume, in_isr);
1488
0
      }
1489
1490
0
      if (tu_bit_test(_usbd_dev.sof_consumer, SOF_CONSUMER_USER)) {
1491
0
        dcd_event_t const event_sof = {.rhport = event->rhport, .event_id = DCD_EVENT_SOF, .sof.frame_count = event->sof.frame_count};
1492
0
        queue_event(&event_sof, in_isr);
1493
0
      }
1494
0
      break;
1495
1496
64.8k
    case DCD_EVENT_SETUP_RECEIVED:
1497
64.8k
      _usbd_queued_setup++;
1498
64.8k
      send = true;
1499
64.8k
      break;
1500
1501
0
    case DCD_EVENT_XFER_COMPLETE: {
1502
      // Invoke the class callback associated with the endpoint address
1503
0
      uint8_t const ep_addr = event->xfer_complete.ep_addr;
1504
0
      uint8_t const epnum = tu_edpt_number(ep_addr);
1505
0
      uint8_t const ep_dir = tu_edpt_dir(ep_addr);
1506
1507
0
      send = true;
1508
0
      if(epnum > 0) {
1509
0
        usbd_class_driver_t const* driver = get_driver(_usbd_dev.ep2drv[epnum][ep_dir]);
1510
1511
0
        if (driver && driver->xfer_isr) {
1512
          // Clear busy + claimed
1513
0
          _usbd_dev.ep_status[epnum][ep_dir] &= (uint8_t) ~(TU_EDPT_STATE_BUSY | TU_EDPT_STATE_CLAIMED);
1514
1515
0
          send = !driver->xfer_isr(event->rhport, ep_addr, (xfer_result_t) event->xfer_complete.result, event->xfer_complete.len);
1516
1517
          // xfer_isr() is deferred to xfer_cb(), revert busy/claimed status
1518
0
          if (send) {
1519
            // set busy + claimed
1520
0
            _usbd_dev.ep_status[epnum][ep_dir] |= (TU_EDPT_STATE_BUSY | TU_EDPT_STATE_CLAIMED);
1521
0
          }
1522
0
        }
1523
0
      }
1524
0
      break;
1525
0
    }
1526
1527
28.5k
    default:
1528
28.5k
      send = true;
1529
28.5k
      break;
1530
133k
  }
1531
1532
133k
  if (send && !queue_event(event, in_isr)) {
1533
    // event dropped by a full queue: undo state that would otherwise wedge permanently
1534
0
    if (event->event_id == DCD_EVENT_SETUP_RECEIVED) {
1535
      // undo the increment, else every later SETUP is skipped as "other SETUP in queue"
1536
      // and EP0 is deaf until re-init
1537
0
      _usbd_queued_setup--;
1538
0
    } else if (event->event_id == DCD_EVENT_XFER_COMPLETE) {
1539
      // clear busy + claimed, else the endpoint can never be claimed or re-armed again
1540
0
      uint8_t const epnum = tu_edpt_number(event->xfer_complete.ep_addr);
1541
0
      uint8_t const ep_dir = tu_edpt_dir(event->xfer_complete.ep_addr);
1542
0
      _usbd_dev.ep_status[epnum][ep_dir] &= (uint8_t) ~(TU_EDPT_STATE_BUSY | TU_EDPT_STATE_CLAIMED);
1543
0
    }
1544
0
  }
1545
133k
}
1546
1547
//--------------------------------------------------------------------+
1548
// USBD API For Class Driver
1549
//--------------------------------------------------------------------+
1550
1551
750k
void usbd_int_set(bool enabled) {
1552
750k
  if (enabled) {
1553
375k
    dcd_int_enable(_usbd_rhport);
1554
375k
  } else {
1555
375k
    dcd_int_disable(_usbd_rhport);
1556
375k
  }
1557
750k
}
1558
1559
0
void usbd_spin_lock(bool in_isr) {
1560
0
  osal_spin_lock(&_usbd_spin, in_isr);
1561
0
}
1562
0
void usbd_spin_unlock(bool in_isr) {
1563
0
  osal_spin_unlock(&_usbd_spin, in_isr);
1564
0
}
1565
1566
// Parse consecutive endpoint descriptors (IN & OUT)
1567
bool usbd_open_edpt_pair(uint8_t rhport, const uint8_t *p_desc, uint8_t ep_count, uint8_t xfer_type, uint8_t *ep_out,
1568
243
                         uint8_t *ep_in) {
1569
243
  for (int i = 0; i < ep_count; i++) {
1570
243
    const tusb_desc_endpoint_t *desc_ep = (const tusb_desc_endpoint_t *)p_desc;
1571
1572
243
    TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && xfer_type == desc_ep->bmAttributes.xfer);
1573
243
    TU_ASSERT(usbd_edpt_open(rhport, desc_ep));
1574
1575
0
    if (tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN) {
1576
0
      (*ep_in) = desc_ep->bEndpointAddress;
1577
0
    } else {
1578
0
      (*ep_out) = desc_ep->bEndpointAddress;
1579
0
    }
1580
1581
0
    p_desc = tu_desc_next(p_desc);
1582
0
  }
1583
1584
0
  return true;
1585
243
}
1586
1587
// Helper to defer an isr function
1588
0
void usbd_defer_func(osal_task_func_t func, void* param, bool in_isr) {
1589
0
  dcd_event_t event = {
1590
0
      .rhport   = 0,
1591
0
      .event_id = USBD_EVENT_FUNC_CALL,
1592
0
  };
1593
0
  event.func_call.func  = func;
1594
0
  event.func_call.param = param;
1595
1596
0
  queue_event(&event, in_isr);
1597
0
}
1598
1599
0
bool usbd_defer_func_after_queue(osal_task_func_t func, void* param) {
1600
0
  if (_usbd_after_queue.func != NULL) {
1601
0
    return _usbd_after_queue.func == func && _usbd_after_queue.param == param;
1602
0
  }
1603
0
  _usbd_after_queue.func = func;
1604
0
  _usbd_after_queue.param = param;
1605
0
  return true;
1606
0
}
1607
1608
//--------------------------------------------------------------------+
1609
// USBD Endpoint API
1610
//--------------------------------------------------------------------+
1611
1612
15.2k
bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) {
1613
15.2k
  rhport = _usbd_rhport;
1614
1615
15.2k
  TU_ASSERT(tu_edpt_number(desc_ep->bEndpointAddress) < CFG_TUD_ENDPPOINT_MAX);
1616
15.0k
  TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t)_usbd_dev.speed));
1617
1618
15.0k
  return dcd_edpt_open(rhport, desc_ep);
1619
15.0k
}
1620
1621
7.09k
bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr) {
1622
7.09k
  (void) rhport;
1623
1624
  // TODO add this check later, also make sure we don't starve an out endpoint while suspending
1625
  // TU_VERIFY(tud_ready());
1626
1627
7.09k
  uint8_t const epnum = tu_edpt_number(ep_addr);
1628
7.09k
  uint8_t const dir = tu_edpt_dir(ep_addr);
1629
7.09k
  return tu_edpt_claim(&_usbd_dev.ep_status[epnum][dir], _usbd_mutex);
1630
7.09k
}
1631
1632
0
bool usbd_edpt_release(uint8_t rhport, uint8_t ep_addr) {
1633
0
  (void) rhport;
1634
1635
0
  uint8_t const epnum = tu_edpt_number(ep_addr);
1636
0
  uint8_t const dir = tu_edpt_dir(ep_addr);
1637
0
  return tu_edpt_release(&_usbd_dev.ep_status[epnum][dir], _usbd_mutex);
1638
0
}
1639
1640
0
void usbd_edpt_rx_consume(uint8_t rhport, uint8_t ep_addr) {
1641
0
  (void) rhport;
1642
1643
0
  uint8_t const epnum = tu_edpt_number(ep_addr);
1644
0
  uint8_t const dir = tu_edpt_dir(ep_addr);
1645
0
  volatile uint8_t *ep_state = &_usbd_dev.ep_status[epnum][dir];
1646
1647
0
  TU_VERIFY((*ep_state & TU_EDPT_STATE_RX_PENDING) != 0,);
1648
0
  (void) osal_mutex_lock(_usbd_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
1649
0
  if ((*ep_state & TU_EDPT_STATE_RX_PENDING) != 0) {
1650
0
    *ep_state &= (uint8_t) ~TU_EDPT_STATE_RX_PENDING;
1651
0
  }
1652
0
  (void) osal_mutex_unlock(_usbd_mutex);
1653
0
}
1654
1655
45.4k
bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes, bool is_isr) {
1656
45.4k
  rhport = _usbd_rhport;
1657
1658
45.4k
  uint8_t const epnum = tu_edpt_number(ep_addr);
1659
45.4k
  uint8_t const dir = tu_edpt_dir(ep_addr);
1660
1661
  // TODO skip ready() check for now since enumeration also use this API
1662
  // TU_VERIFY(tud_ready());
1663
1664
45.4k
  TU_LOG_USBD("  Queue EP %02X with %u bytes ...\r\n", ep_addr, total_bytes);
1665
#if CFG_TUD_LOG_LEVEL >= 3
1666
  if(dir == TUSB_DIR_IN) {
1667
    TU_LOG_MEM(CFG_TUD_LOG_LEVEL, buffer, total_bytes, 2);
1668
  }
1669
#endif
1670
1671
  // Attempt to transfer on a busy endpoint, sound like an race condition !
1672
45.4k
  TU_ASSERT((_usbd_dev.ep_status[epnum][dir] & TU_EDPT_STATE_BUSY) == 0);
1673
1674
  // Set busy first since the actual transfer can be complete before dcd_edpt_xfer()
1675
  // could return and USBD task can preempt and clear the busy
1676
41.6k
  _usbd_dev.ep_status[epnum][dir] =
1677
41.6k
    (uint8_t) ((_usbd_dev.ep_status[epnum][dir] & ~TU_EDPT_STATE_RX_PENDING) | TU_EDPT_STATE_BUSY);
1678
1679
41.6k
  if (dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes, is_isr)) {
1680
12.1k
    return true;
1681
29.4k
  } else {
1682
    // Driver refused the transfer, mark endpoint as ready to allow next transfer. This is a
1683
    // recoverable condition (e.g. a new setup superseding a control response), not a bug, so
1684
    // do not break into the debugger - TU_BREAKPOINT() halts the CPU whenever a probe is
1685
    // attached, which on a test rig is always.
1686
29.4k
    _usbd_dev.ep_status[epnum][dir] &= (uint8_t) ~(TU_EDPT_STATE_BUSY | TU_EDPT_STATE_CLAIMED);
1687
29.4k
    TU_LOG_USBD("FAILED\r\n");
1688
29.4k
    return false;
1689
29.4k
  }
1690
41.6k
}
1691
1692
// The number of bytes has to be given explicitly to allow more flexible control of how many
1693
// bytes should be written and second to keep the return value free to give back a boolean
1694
// success message. If total_bytes is too big, the FIFO will copy only what is available
1695
// into the USB buffer!
1696
0
bool usbd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t* ff, uint16_t total_bytes, bool is_isr) {
1697
  #if CFG_TUD_EDPT_DEDICATED_HWFIFO
1698
  rhport = _usbd_rhport;
1699
1700
  uint8_t const epnum = tu_edpt_number(ep_addr);
1701
  uint8_t const dir = tu_edpt_dir(ep_addr);
1702
1703
  TU_LOG_USBD("  Queue FIFO EP %02X with %u bytes ... ", ep_addr, total_bytes);
1704
1705
  // Attempt to transfer on a busy endpoint, sound like a race condition !
1706
  TU_ASSERT((_usbd_dev.ep_status[epnum][dir] & TU_EDPT_STATE_BUSY) == 0);
1707
1708
  // Set busy first since the actual transfer can be complete before dcd_edpt_xfer() could return
1709
  // and usbd task can preempt and clear the busy
1710
  _usbd_dev.ep_status[epnum][dir] =
1711
    (uint8_t) ((_usbd_dev.ep_status[epnum][dir] & ~TU_EDPT_STATE_RX_PENDING) | TU_EDPT_STATE_BUSY);
1712
1713
  if (dcd_edpt_xfer_fifo(rhport, ep_addr, ff, total_bytes, is_isr)) {
1714
    TU_LOG_USBD("OK\r\n");
1715
    return true;
1716
  } else {
1717
    // DCD error, mark endpoint as ready to allow next transfer
1718
    _usbd_dev.ep_status[epnum][dir] &= (uint8_t) ~(TU_EDPT_STATE_BUSY | TU_EDPT_STATE_CLAIMED);
1719
    TU_LOG_USBD("failed\r\n");
1720
    TU_BREAKPOINT();
1721
    return false;
1722
  }
1723
  #else
1724
0
  (void)rhport;
1725
0
  (void)ep_addr;
1726
0
  (void)ff;
1727
0
  (void)total_bytes;
1728
0
  (void)is_isr;
1729
0
  return false;
1730
0
  #endif
1731
0
}
1732
1733
0
bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr) {
1734
0
  (void) rhport;
1735
1736
0
  uint8_t const epnum = tu_edpt_number(ep_addr);
1737
0
  uint8_t const dir = tu_edpt_dir(ep_addr);
1738
1739
0
  return (_usbd_dev.ep_status[epnum][dir] & TU_EDPT_STATE_BUSY) != 0;
1740
0
}
1741
1742
450
void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
1743
450
  rhport = _usbd_rhport;
1744
1745
450
  uint8_t const epnum = tu_edpt_number(ep_addr);
1746
450
  uint8_t const dir = tu_edpt_dir(ep_addr);
1747
1748
  // only stalled if currently cleared
1749
450
  TU_LOG_USBD("    Stall EP %02X\r\n", ep_addr);
1750
450
  dcd_edpt_stall(rhport, ep_addr);
1751
450
  _usbd_dev.ep_status[epnum][dir] |= (TU_EDPT_STATE_STALLED | TU_EDPT_STATE_BUSY);
1752
450
}
1753
1754
192
void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
1755
192
  rhport = _usbd_rhport;
1756
1757
192
  uint8_t const epnum = tu_edpt_number(ep_addr);
1758
192
  uint8_t const dir = tu_edpt_dir(ep_addr);
1759
1760
192
  TU_LOG_USBD("    Clear Stall EP %02X\r\n", ep_addr);
1761
192
  const bool was_stalled = (_usbd_dev.ep_status[epnum][dir] & TU_EDPT_STATE_STALLED) != 0;
1762
192
  dcd_edpt_clear_stall(rhport, ep_addr);
1763
  // Clear STALLED|BUSY unconditionally (long-standing behavior; some classes, e.g. audio's
1764
  // set-interface, call this on a non-stalled endpoint solely to drop a leftover BUSY bit).
1765
  // Only release the CLAIMED ownership bit when the endpoint was actually stalled: the stall
1766
  // aborts the in-flight transfer in the dcd with no completion event to release the claim, so
1767
  // clearing it here prevents starvation. On a non-stalled clear (e.g. a data-toggle reset) a
1768
  // transfer may still be legitimately claimed by another task, so keep CLAIMED to preserve the
1769
  // claim->xfer mutual exclusion.
1770
192
  uint8_t clear_mask = TU_EDPT_STATE_STALLED | TU_EDPT_STATE_BUSY;
1771
192
  if (was_stalled) {
1772
51
    clear_mask |= TU_EDPT_STATE_CLAIMED;
1773
51
  }
1774
192
  _usbd_dev.ep_status[epnum][dir] &= (uint8_t) ~clear_mask;
1775
192
}
1776
1777
// Not valid for EP0, where dcd_edpt_stall() means "stall the control transfer" rather than "cancel".
1778
// TODO replace this stall/clear-stall stand-in with a dcd_edpt_abort_xfer() returning bool, like
1779
// hcd_edpt_abort_xfer(): the stall is wire-visible and the clear resets the toggle.
1780
0
void usbd_edpt_abort(uint8_t rhport, uint8_t ep_addr) {
1781
0
  usbd_edpt_stall(rhport, ep_addr);
1782
0
  usbd_edpt_clear_stall(rhport, ep_addr);
1783
0
}
1784
1785
1.94k
bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr) {
1786
1.94k
  (void) rhport;
1787
1788
1.94k
  uint8_t const epnum = tu_edpt_number(ep_addr);
1789
1.94k
  uint8_t const dir = tu_edpt_dir(ep_addr);
1790
1791
1.94k
  return (_usbd_dev.ep_status[epnum][dir] & TU_EDPT_STATE_STALLED) != 0;
1792
1.94k
}
1793
1794
/**
1795
 * usbd_edpt_close will disable an endpoint.
1796
 * In progress transfers on this EP may be delivered after this call.
1797
 */
1798
0
void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
1799
0
#ifdef TUP_DCD_EDPT_ISO_ALLOC
1800
0
  (void) rhport; (void) ep_addr;
1801
  // ISO alloc/activate Should be used instead
1802
#else
1803
  rhport = _usbd_rhport;
1804
1805
  TU_LOG_USBD("  CLOSING Endpoint: 0x%02X\r\n", ep_addr);
1806
1807
  uint8_t const epnum = tu_edpt_number(ep_addr);
1808
  uint8_t const dir = tu_edpt_dir(ep_addr);
1809
1810
  dcd_edpt_close(rhport, ep_addr);
1811
  _usbd_dev.ep_status[epnum][dir] = 0;
1812
#endif
1813
1814
0
  return;
1815
0
}
1816
1817
0
void usbd_sof_enable(uint8_t rhport, sof_consumer_t consumer, bool en) {
1818
0
  rhport = _usbd_rhport;
1819
1820
0
  uint8_t consumer_old = _usbd_dev.sof_consumer;
1821
  // Keep track how many class instances need the SOF interrupt
1822
0
  if (en) {
1823
0
    _usbd_dev.sof_consumer |= (uint8_t)(1 << consumer);
1824
0
  } else {
1825
0
    _usbd_dev.sof_consumer &= (uint8_t)(~(1 << consumer));
1826
0
  }
1827
1828
  // Test logically unequal
1829
0
  if(!_usbd_dev.sof_consumer != !consumer_old) {
1830
0
    dcd_sof_enable(rhport, _usbd_dev.sof_consumer);
1831
0
  }
1832
0
}
1833
1834
0
bool usbd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) {
1835
0
#ifdef TUP_DCD_EDPT_ISO_ALLOC
1836
0
  rhport = _usbd_rhport;
1837
1838
0
  TU_ASSERT(tu_edpt_number(ep_addr) < CFG_TUD_ENDPPOINT_MAX);
1839
0
  return dcd_edpt_iso_alloc(rhport, ep_addr, largest_packet_size);
1840
#else
1841
  (void) rhport; (void) ep_addr; (void) largest_packet_size;
1842
  return false;
1843
#endif
1844
0
}
1845
1846
0
bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) {
1847
0
#ifdef TUP_DCD_EDPT_ISO_ALLOC
1848
0
  rhport = _usbd_rhport;
1849
1850
0
  uint8_t const epnum = tu_edpt_number(desc_ep->bEndpointAddress);
1851
0
  uint8_t const dir = tu_edpt_dir(desc_ep->bEndpointAddress);
1852
1853
0
  TU_ASSERT(epnum < CFG_TUD_ENDPPOINT_MAX);
1854
0
  TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t)_usbd_dev.speed));
1855
1856
0
  _usbd_dev.ep_status[epnum][dir] = 0;
1857
0
  return dcd_edpt_iso_activate(rhport, desc_ep);
1858
#else
1859
  (void) rhport; (void) desc_ep;
1860
  return false;
1861
#endif
1862
0
}
1863
1864
#endif