Open FFBoard
Open source force feedback firmware
video_device.c
Go to the documentation of this file.
1/*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2021 Koji KITAYAMA
5 * Copyright (c) 2019 Ha Thach (tinyusb.org)
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 *
25 * This file is part of the TinyUSB stack.
26 */
27
28#include "tusb_option.h"
29
30#if (CFG_TUD_ENABLED && CFG_TUD_VIDEO && CFG_TUD_VIDEO_STREAMING)
31
32#include "device/usbd.h"
33#include "device/usbd_pvt.h"
34
35#include "video_device.h"
36
37// Level where CFG_TUSB_DEBUG must be at least for this driver is logged
38#ifndef CFG_TUD_VIDEO_LOG_LEVEL
39 #define CFG_TUD_VIDEO_LOG_LEVEL CFG_TUD_LOG_LEVEL
40#endif
41
42#define TU_LOG_DRV(...) TU_LOG(CFG_TUD_VIDEO_LOG_LEVEL, __VA_ARGS__)
43
44//--------------------------------------------------------------------+
45// MACRO CONSTANT TYPEDEF
46//--------------------------------------------------------------------+
47#define VS_STATE_PROBING 0 /* Configuration in progress */
48#define VS_STATE_COMMITTED 1 /* Ready for streaming or Streaming via bulk endpoint */
49#define VS_STATE_STREAMING 2 /* Streaming via isochronous endpoint */
50
51typedef struct {
53 tusb_desc_video_control_header_t ctl;
55
56typedef struct {
60
61typedef union {
62 tusb_desc_video_control_header_t ctl;
65
66typedef struct TU_ATTR_PACKED {
67 uint8_t bLength;
68 uint8_t bDescriptorType;
70 uint8_t bEntityId;
72
73typedef union {
75 uint8_t bLength;
78 uint8_t bFormatIndex;
80 };
85
86typedef union {
88 uint8_t bLength;
91 uint8_t bFrameIndex;
95 };
96 tusb_desc_video_frame_uncompressed_t uncompressed;
100
101/* video streaming interface */
102typedef struct TU_ATTR_PACKED {
103 uint8_t index_vc; /* index of bound video control interface */
104 uint8_t index_vs; /* index from the video control interface */
105 struct {
106 uint16_t beg; /* Offset of the begging of video streaming interface descriptor */
107 uint16_t end; /* Offset of the end of video streaming interface descriptor */
108 uint16_t cur; /* Offset of the current settings */
109 uint16_t ep[2]; /* Offset of endpoint descriptors. 0: streaming, 1: still capture */
111 uint8_t *buffer; /* frame buffer. assume linear buffer. no support for stride access */
112 uint32_t bufsize; /* frame buffer size */
113 uint32_t offset; /* offset for the next payload transfer */
115 uint8_t error_code;/* error code */
116 uint8_t state; /* 0:probing 1:committed 2:streaming */
117
119 /*------------- From this point, data is not cleared by bus reset -------------*/
120 CFG_TUSB_MEM_ALIGN uint8_t ep_buf[CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE]; /* EP transfer buffer for streaming */
122
123/* video control interface */
124typedef struct TU_ATTR_PACKED {
125 uint8_t const *beg; /* The head of the first video control interface descriptor */
126 uint16_t len; /* Byte length of the descriptors */
127 uint16_t cur; /* offset for current video control interface */
128 uint8_t stm[CFG_TUD_VIDEO_STREAMING]; /* Indices of streaming interface */
129 uint8_t error_code; /* error code */
130 uint8_t power_mode;
131
132 /*------------- From this point, data is not cleared by bus reset -------------*/
133 // CFG_TUSB_MEM_ALIGN uint8_t ctl_buf[64]; /* EP transfer buffer for interrupt transfer */
134
136
137#define ITF_STM_MEM_RESET_SIZE offsetof(videod_streaming_interface_t, ep_buf)
138
139//--------------------------------------------------------------------+
140// INTERNAL OBJECT & FUNCTION DECLARATION
141//--------------------------------------------------------------------+
142CFG_TUD_MEM_SECTION tu_static videod_interface_t _videod_itf[CFG_TUD_VIDEO];
143CFG_TUD_MEM_SECTION tu_static videod_streaming_interface_t _videod_streaming_itf[CFG_TUD_VIDEO_STREAMING];
144
145tu_static uint8_t const _cap_get = 0x1u; /* support for GET */
146tu_static uint8_t const _cap_get_set = 0x3u; /* support for GET and SET */
147
148//--------------------------------------------------------------------+
149// Debug
150//--------------------------------------------------------------------+
151#if CFG_TUSB_DEBUG >= CFG_TUD_VIDEO_LOG_LEVEL
152
154 {.key = VIDEO_REQUEST_UNDEFINED, .data = "Undefined"},
155 {.key = VIDEO_REQUEST_SET_CUR, .data = "SetCur"},
156 {.key = VIDEO_REQUEST_SET_CUR_ALL, .data = "SetCurAll"},
157 {.key = VIDEO_REQUEST_GET_CUR, .data = "GetCur"},
158 {.key = VIDEO_REQUEST_GET_MIN, .data = "GetMin"},
159 {.key = VIDEO_REQUEST_GET_MAX, .data = "GetMax"},
160 {.key = VIDEO_REQUEST_GET_RES, .data = "GetRes"},
161 {.key = VIDEO_REQUEST_GET_LEN, .data = "GetLen"},
162 {.key = VIDEO_REQUEST_GET_INFO, .data = "GetInfo"},
163 {.key = VIDEO_REQUEST_GET_DEF, .data = "GetDef"},
164 {.key = VIDEO_REQUEST_GET_CUR_ALL, .data = "GetCurAll"},
165 {.key = VIDEO_REQUEST_GET_MIN_ALL, .data = "GetMinAll"},
166 {.key = VIDEO_REQUEST_GET_MAX_ALL, .data = "GetMaxAll"},
167 {.key = VIDEO_REQUEST_GET_RES_ALL, .data = "GetResAll"},
168 {.key = VIDEO_REQUEST_GET_DEF_ALL, .data = "GetDefAll"},
169};
170
172 .count = TU_ARRAY_SIZE(tu_lookup_video_request),
174};
175
176static char const* const tu_str_video_vc_control_selector[] = {
177 "Undefined",
178 "Video Power Mode",
179 "Request Error Code",
180};
181
182static char const* const tu_str_video_vs_control_selector[] = {
183 "Undefined",
184 "Probe",
185 "Commit",
186 "Still Probe",
187 "Still Commit",
188 "Still Image Trigger",
189 "Stream Error Code",
190 "Generate Key Frame",
191 "Update Frame Segment",
192 "Sync Delay",
193};
194
195#endif
196
197//--------------------------------------------------------------------+
198//
199//--------------------------------------------------------------------+
200
206static inline uint8_t _desc_itfnum(void const *desc) {
207 return ((uint8_t const*)desc)[2];
208}
209
215static inline uint8_t _desc_ep_addr(void const *desc) {
216 return ((uint8_t const*)desc)[2];
217}
218
225static videod_streaming_interface_t* _get_instance_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx) {
226 videod_interface_t *ctl = &_videod_itf[ctl_idx];
227 if (!ctl->beg) return NULL;
229 if (!stm->desc.beg) return NULL;
230 return stm;
231}
232
234 return (tusb_desc_vc_itf_t const *)(self->beg + self->cur);
235}
236
238 if (!self->desc.cur) return NULL;
239 uint8_t const *desc = _videod_itf[self->index_vc].beg;
240 return (tusb_desc_vs_itf_t const*)(desc + self->desc.cur);
241}
242
251static void const* _find_desc(void const *beg, void const *end, uint_fast8_t desc_type) {
252 void const *cur = beg;
253 while ((cur < end) && (desc_type != tu_desc_type(cur))) {
254 cur = tu_desc_next(cur);
255 }
256 return cur;
257}
258
268static void const* _find_desc_2_type(void const *beg, void const *end, uint_fast8_t desc_type_0, uint_fast8_t desc_type_1)
269{
270 void const *cur = beg;
271 while ((cur < end) && (desc_type_0 != tu_desc_type(cur)) && (desc_type_1 != tu_desc_type(cur))) {
272 cur = tu_desc_next(cur);
273 }
274 return cur;
275}
276
287static void const* _find_desc_3(void const *beg, void const *end,
288 uint_fast8_t desc_type,
289 uint_fast8_t element_0,
290 uint_fast8_t element_1) {
291 for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, desc_type)) {
292 uint8_t const *p = (uint8_t const *)cur;
293 if ((p[2] == element_0) && (p[3] == element_1)) {
294 return cur;
295 }
296 cur = tu_desc_next(cur);
297 }
298 return end;
299}
300
312static void const* _next_desc_itf(void const *beg, void const *end) {
313 void const *cur = beg;
314 uint_fast8_t itfnum = ((tusb_desc_interface_t const*)cur)->bInterfaceNumber;
315 while ((cur < end) &&
316 (itfnum == ((tusb_desc_interface_t const*)cur)->bInterfaceNumber)) {
318 }
319 return cur;
320}
321
331static inline uint8_t const* _find_desc_itf(void const *beg, void const *end, uint_fast8_t itfnum, uint_fast8_t altnum)
332{
333 return (uint8_t const*) _find_desc_3(beg, end, TUSB_DESC_INTERFACE, itfnum, altnum);
334}
335
345static void const* _find_desc_ep(void const *beg, void const *end)
346{
347 for (void const *cur = beg; cur < end; cur = tu_desc_next(cur)) {
348 uint_fast8_t desc_type = tu_desc_type(cur);
349 if (TUSB_DESC_ENDPOINT == desc_type) return cur;
350 if (TUSB_DESC_INTERFACE == desc_type) break;
351 }
352 return end;
353}
354
356static inline void const* _end_of_control_descriptor(void const *desc)
357{
358 tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const *)desc;
359 return ((uint8_t const*) desc) + vc->std.bLength + tu_le16toh(vc->ctl.wTotalLength);
360}
361
370static void const* _find_desc_entity(void const *desc, uint_fast8_t entityid)
371{
372 void const *end = _end_of_control_descriptor(desc);
373 for (void const *cur = desc; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) {
375 if ((VIDEO_CS_ITF_VC_INPUT_TERMINAL <= itf->bDescriptorSubtype
377 && itf->bEntityId == entityid) {
378 return itf;
379 }
380 cur = tu_desc_next(cur);
381 }
382 return end;
383}
384
386static inline void const* _end_of_streaming_descriptor(void const *desc)
387{
388 tusb_desc_vs_itf_t const *vs = (tusb_desc_vs_itf_t const *)desc;
389 return ((uint8_t const*) desc) + vs->std.bLength + tu_le16toh(vs->stm.wTotalLength);
390}
391
393static inline void const *_find_desc_format(void const *beg, void const *end, uint_fast8_t fmtnum)
394{
395 for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) {
396 uint8_t const *p = (uint8_t const *)cur;
397 uint_fast8_t fmt = p[2];
402 fmtnum == p[3]) {
403 return cur;
404 }
405 cur = tu_desc_next(cur);
406 }
407 return end;
408}
409
411static inline void const *_find_desc_frame(void const *beg, void const *end, uint_fast8_t frmnum)
412{
413 for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) {
414 uint8_t const *p = (uint8_t const *)cur;
415 uint_fast8_t frm = p[2];
419 frmnum == p[3]) {
420 return cur;
421 }
422 cur = tu_desc_next(cur);
423 }
424 return end;
425}
426
432{
433 tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm);
434 uint_fast8_t fmtnum = param->bFormatIndex;
435 TU_ASSERT(vs && fmtnum <= vs->stm.bNumFormats);
436 if (!fmtnum) {
437 if (1 < vs->stm.bNumFormats) return true; /* Need to negotiate all variables. */
438 fmtnum = 1;
439 param->bFormatIndex = 1;
440 }
441
442 /* Set the parameters determined by the format */
443 param->wKeyFrameRate = 1;
444 param->wPFrameRate = 0;
445 param->wCompWindowSize = 1; /* GOP size? */
446 param->wDelay = 0; /* milliseconds */
447 param->dwClockFrequency = 27000000; /* same as MPEG-2 system time clock */
448 param->bmFramingInfo = 0x3; /* enables FrameID and EndOfFrame */
449 param->bPreferedVersion = 1;
450 param->bMinVersion = 1;
451 param->bMaxVersion = 1;
452 param->bUsage = 0;
453 param->bBitDepthLuma = 8;
454
455 void const *end = _end_of_streaming_descriptor(vs);
456 tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum);
457 TU_ASSERT(fmt != end);
458
459 switch (fmt->bDescriptorSubType) {
461 param->wCompQuality = 1; /* 1 to 10000 */
462 break;
463
465 break;
466
467 default: return false;
468 }
469
470 uint_fast8_t frmnum = param->bFrameIndex;
471 TU_ASSERT(frmnum <= fmt->bNumFrameDescriptors);
472 if (!frmnum) {
473 if (1 < fmt->bNumFrameDescriptors) return true;
474 frmnum = 1;
475 param->bFrameIndex = 1;
476 }
477 tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum);
478 TU_ASSERT(frm != end);
479
480 /* Set the parameters determined by the frame */
481 uint_fast32_t frame_size = param->dwMaxVideoFrameSize;
482 if (!frame_size) {
483 switch (fmt->bDescriptorSubType) {
485 frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->uncompressed.bBitsPerPixel / 8;
486 break;
487
489 frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */
490 break;
491
492 default: break;
493 }
494 param->dwMaxVideoFrameSize = frame_size;
495 }
496
497 uint_fast32_t interval = param->dwFrameInterval;
498 if (!interval) {
499 if ((1 < frm->uncompressed.bFrameIntervalType) ||
500 ((0 == frm->uncompressed.bFrameIntervalType) &&
501 (frm->uncompressed.dwFrameInterval[1] != frm->uncompressed.dwFrameInterval[0]))) {
502 return true;
503 }
504 interval = frm->uncompressed.dwFrameInterval[0];
505 param->dwFrameInterval = interval;
506 }
507 uint_fast32_t interval_ms = interval / 10000;
508 TU_ASSERT(interval_ms);
509 uint_fast32_t payload_size = (frame_size + interval_ms - 1) / interval_ms + 2;
510 if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size) {
511 payload_size = CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE;
512 }
513 param->dwMaxPayloadTransferSize = payload_size;
514 return true;
515}
516
524{
525 uint_fast8_t const fmtnum = param->bFormatIndex;
526 if (!fmtnum) {
527 switch (request) {
529 if (_get_desc_vs(stm))
531 break;
532
535 param->bFormatIndex = 1;
536 break;
537
538 default: return false;
539 }
540 /* Set the parameters determined by the format */
541 param->wKeyFrameRate = 1;
542 param->wPFrameRate = 0;
543 param->wCompQuality = 1; /* 1 to 10000 */
544 param->wCompWindowSize = 1; /* GOP size? */
545 param->wDelay = 0; /* milliseconds */
546 param->dwClockFrequency = 27000000; /* same as MPEG-2 system time clock */
547 param->bmFramingInfo = 0x3; /* enables FrameID and EndOfFrame */
548 param->bPreferedVersion = 1;
549 param->bMinVersion = 1;
550 param->bMaxVersion = 1;
551 param->bUsage = 0;
552 param->bBitDepthLuma = 8;
553 return true;
554 }
555
556 uint_fast8_t frmnum = param->bFrameIndex;
557 if (!frmnum) {
558 tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm);
559 TU_ASSERT(vs);
560 void const *end = _end_of_streaming_descriptor(vs);
561 tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum);
562 switch (request) {
564 frmnum = fmt->bNumFrameDescriptors;
565 break;
566
568 frmnum = 1;
569 break;
570
572 switch (fmt->bDescriptorSubType) {
574 frmnum = fmt->uncompressed.bDefaultFrameIndex;
575 break;
576
578 frmnum = fmt->mjpeg.bDefaultFrameIndex;
579 break;
580
581 default: return false;
582 }
583 break;
584 default: return false;
585 }
586 param->bFrameIndex = (uint8_t)frmnum;
587 /* Set the parameters determined by the frame */
588 tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum);
589 uint_fast32_t frame_size;
590 switch (fmt->bDescriptorSubType) {
592 frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->uncompressed.bBitsPerPixel / 8;
593 break;
594
596 frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8; /* YUV422 */
597 break;
598
599 default: return false;
600 }
601 param->dwMaxVideoFrameSize = frame_size;
602 return true;
603 }
604
605 if (!param->dwFrameInterval) {
606 tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm);
607 TU_ASSERT(vs);
608 void const *end = _end_of_streaming_descriptor(vs);
609 tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum);
610 tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum);
611
612 uint_fast32_t interval, interval_ms;
613 switch (request) {
615 uint_fast32_t min_interval, max_interval;
616 uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType;
617 max_interval = num_intervals ? frm->uncompressed.dwFrameInterval[num_intervals - 1]: frm->uncompressed.dwFrameInterval[1];
618 min_interval = frm->uncompressed.dwFrameInterval[0];
619 interval = max_interval;
620 interval_ms = min_interval / 10000;
621 break;
622 }
623
625 uint_fast32_t min_interval, max_interval;
626 uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType;
627 max_interval = num_intervals ? frm->uncompressed.dwFrameInterval[num_intervals - 1]: frm->uncompressed.dwFrameInterval[1];
628 min_interval = frm->uncompressed.dwFrameInterval[0];
629 interval = min_interval;
630 interval_ms = max_interval / 10000;
631 break;
632 }
633
635 interval = frm->uncompressed.dwDefaultFrameInterval;
636 interval_ms = interval / 10000;
637 break;
638
640 uint_fast8_t num_intervals = frm->uncompressed.bFrameIntervalType;
641 if (num_intervals) {
642 interval = 0;
643 interval_ms = 0;
644 } else {
645 interval = frm->uncompressed.dwFrameInterval[2];
646 interval_ms = interval / 10000;
647 }
648 break;
649 }
650
651 default: return false;
652 }
653 param->dwFrameInterval = interval;
654 if (!interval) {
655 param->dwMaxPayloadTransferSize = 0;
656 } else {
657 uint_fast32_t frame_size = param->dwMaxVideoFrameSize;
658 uint_fast32_t payload_size;
659 if (!interval_ms) {
660 payload_size = frame_size + 2;
661 } else {
662 payload_size = (frame_size + interval_ms - 1) / interval_ms + 2;
663 }
664 if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size) {
665 payload_size = CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE;
666 }
667 param->dwMaxPayloadTransferSize = payload_size;
668 }
669 return true;
670 }
671 return true;
672}
673
678static bool _close_vc_itf(uint8_t rhport, videod_interface_t *self)
679{
680 tusb_desc_vc_itf_t const *vc = _get_desc_vc(self);
681
682 /* The next descriptor after the class-specific VC interface header descriptor. */
683 void const *cur = (uint8_t const*)vc + vc->std.bLength + vc->ctl.bLength;
684
685 /* The end of the video control interface descriptor. */
686 void const *end = _end_of_control_descriptor(vc);
687 if (vc->std.bNumEndpoints) {
688 /* Find the notification endpoint descriptor. */
689 cur = _find_desc(cur, end, TUSB_DESC_ENDPOINT);
690 TU_ASSERT(cur < end);
691 tusb_desc_endpoint_t const *notif = (tusb_desc_endpoint_t const *)cur;
692 usbd_edpt_close(rhport, notif->bEndpointAddress);
693 }
694 self->cur = 0;
695 return true;
696}
697
702static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t altnum)
703{
704 TU_LOG_DRV(" open VC %d\r\n", altnum);
705 uint8_t const *beg = self->beg;
706 uint8_t const *end = beg + self->len;
707
708 /* The first descriptor is a video control interface descriptor. */
709 uint8_t const *cur = _find_desc_itf(beg, end, _desc_itfnum(beg), altnum);
710 TU_LOG_DRV(" cur %" PRId32 "\r\n", (int32_t) (cur - beg));
711 TU_VERIFY(cur < end);
712
713 tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const *)cur;
714 TU_LOG_DRV(" bInCollection %d\r\n", vc->ctl.bInCollection);
715 /* Support for up to 2 streaming interfaces only. */
716 TU_ASSERT(vc->ctl.bInCollection <= CFG_TUD_VIDEO_STREAMING);
717
718 /* Update to point the end of the video control interface descriptor. */
720
721 /* Advance to the next descriptor after the class-specific VC interface header descriptor. */
722 cur += vc->std.bLength + vc->ctl.bLength;
723 TU_LOG_DRV(" bNumEndpoints %d\r\n", vc->std.bNumEndpoints);
724 /* Open the notification endpoint if it exist. */
725 if (vc->std.bNumEndpoints) {
726 /* Support for 1 endpoint only. */
727 TU_VERIFY(1 == vc->std.bNumEndpoints);
728 /* Find the notification endpoint descriptor. */
729 cur = _find_desc(cur, end, TUSB_DESC_ENDPOINT);
730 TU_VERIFY(cur < end);
731 tusb_desc_endpoint_t const *notif = (tusb_desc_endpoint_t const *)cur;
732 /* Open the notification endpoint */
733 TU_ASSERT(usbd_edpt_open(rhport, notif));
734 }
735 self->cur = (uint16_t) ((uint8_t const*)vc - beg);
736 return true;
737}
738
740 /* initialize streaming settings */
741 stm->state = VS_STATE_PROBING;
744 tu_memclr(param, sizeof(*param));
745 return _update_streaming_parameters(stm, param);
746}
747
752static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint_fast8_t altnum)
753{
754 uint_fast8_t i;
755 TU_LOG_DRV(" reopen VS %d\r\n", altnum);
756 uint8_t const *desc = _videod_itf[stm->index_vc].beg;
757
758#ifndef TUP_DCD_EDPT_ISO_ALLOC
759 /* Close endpoints of previous settings. */
760 for (i = 0; i < TU_ARRAY_SIZE(stm->desc.ep); ++i) {
761 uint_fast16_t ofs_ep = stm->desc.ep[i];
762 if (!ofs_ep) break;
763 tusb_desc_endpoint_t const *ep = (tusb_desc_endpoint_t const*)(desc + ofs_ep);
764 /* Only ISO endpoints needs to be closed */
765 if(ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) {
766 stm->desc.ep[i] = 0;
768 TU_LOG_DRV(" close EP%02x\r\n", ep->bEndpointAddress);
769 }
770 }
771#endif
772
773 /* clear transfer management information */
774 stm->buffer = NULL;
775 stm->bufsize = 0;
776 stm->offset = 0;
777
778 /* Find a alternate interface */
779 uint8_t const *beg = desc + stm->desc.beg;
780 uint8_t const *end = desc + stm->desc.end;
781 uint8_t const *cur = _find_desc_itf(beg, end, _desc_itfnum(beg), altnum);
782 TU_VERIFY(cur < end);
783
784 uint_fast8_t numeps = ((tusb_desc_interface_t const *)cur)->bNumEndpoints;
785 TU_ASSERT(numeps <= TU_ARRAY_SIZE(stm->desc.ep));
786 stm->desc.cur = (uint16_t)(cur - desc); /* Save the offset of the new settings */
787 if (!altnum && (VS_STATE_COMMITTED != stm->state)) {
788 TU_VERIFY(_init_vs_configuration(stm));
789 }
790 /* Open bulk or isochronous endpoints of the new settings. */
791 for (i = 0, cur = tu_desc_next(cur); i < numeps; ++i, cur = tu_desc_next(cur)) {
792 cur = _find_desc_ep(cur, end);
793 TU_ASSERT(cur < end);
794 tusb_desc_endpoint_t const *ep = (tusb_desc_endpoint_t const*)cur;
795 uint_fast32_t max_size = stm->max_payload_transfer_size;
796 if (altnum && (TUSB_XFER_ISOCHRONOUS == ep->bmAttributes.xfer)) {
797 /* FS must be less than or equal to max packet size */
798 TU_VERIFY (tu_edpt_packet_size(ep) >= max_size);
799#ifdef TUP_DCD_EDPT_ISO_ALLOC
800 usbd_edpt_iso_activate(rhport, ep);
801#else
802 TU_ASSERT(usbd_edpt_open(rhport, ep));
803#endif
804 } else {
805 TU_VERIFY(TUSB_XFER_BULK == ep->bmAttributes.xfer);
806 TU_ASSERT(usbd_edpt_open(rhport, ep));
807 }
808 stm->desc.ep[i] = (uint16_t) (cur - desc);
809 TU_LOG_DRV(" open EP%02x\r\n", _desc_ep_addr(cur));
810 }
811 if (altnum) {
812 stm->state = VS_STATE_STREAMING;
813 }
814 TU_LOG_DRV(" done\r\n");
815 return true;
816}
817
820{
821 uint_fast16_t remaining = stm->bufsize - stm->offset;
822 uint_fast16_t hdr_len = stm->ep_buf[0];
823 uint_fast16_t pkt_len = stm->max_payload_transfer_size;
824 if (hdr_len + remaining < pkt_len) {
825 pkt_len = hdr_len + remaining;
826 }
827 TU_ASSERT(pkt_len >= hdr_len);
828 uint_fast16_t data_len = pkt_len - hdr_len;
829 memcpy(&stm->ep_buf[hdr_len], stm->buffer + stm->offset, data_len);
830 stm->offset += data_len;
831 remaining -= data_len;
832 if (!remaining) {
834 hdr->EndOfFrame = 1;
835 }
836 return hdr_len + data_len;
837}
838
840static int handle_video_ctl_std_req(uint8_t rhport, uint8_t stage,
842 uint_fast8_t ctl_idx)
843{
844 TU_LOG_DRV("\r\n");
845 switch (request->bRequest) {
848 {
849 TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN);
850 tusb_desc_vc_itf_t const *vc = _get_desc_vc(&_videod_itf[ctl_idx]);
851 TU_VERIFY(vc, VIDEO_ERROR_UNKNOWN);
852
853 uint8_t alt_num = vc->std.bAlternateSetting;
854
855 TU_VERIFY(tud_control_xfer(rhport, request, &alt_num, sizeof(alt_num)), VIDEO_ERROR_UNKNOWN);
856 }
857 return VIDEO_ERROR_NONE;
858
861 {
862 TU_VERIFY(0 == request->wLength, VIDEO_ERROR_UNKNOWN);
863 TU_VERIFY(_close_vc_itf(rhport, &_videod_itf[ctl_idx]), VIDEO_ERROR_UNKNOWN);
864 TU_VERIFY(_open_vc_itf(rhport, &_videod_itf[ctl_idx], request->wValue), VIDEO_ERROR_UNKNOWN);
866 }
867 return VIDEO_ERROR_NONE;
868
869 default: /* Unknown/Unsupported request */
870 TU_BREAKPOINT();
872 }
873}
874
875static int handle_video_ctl_cs_req(uint8_t rhport, uint8_t stage,
877 uint_fast8_t ctl_idx)
878{
879 videod_interface_t *self = &_videod_itf[ctl_idx];
880
881 /* 4.2.1 Interface Control Request */
882 uint8_t const ctrl_sel = TU_U16_HIGH(request->wValue);
883 TU_LOG_DRV("%s_Control(%s)\r\n", tu_str_video_vc_control_selector[ctrl_sel], tu_lookup_find(&tu_table_video_request, request->bRequest));
884
885 switch (ctrl_sel) {
887 switch (request->bRequest) {
889 if (stage == CONTROL_STAGE_SETUP) {
890 TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN);
891 TU_VERIFY(tud_control_xfer(rhport, request, &self->power_mode, sizeof(self->power_mode)), VIDEO_ERROR_UNKNOWN);
892 } else if (stage == CONTROL_STAGE_DATA) {
893 if (tud_video_power_mode_cb) return tud_video_power_mode_cb(ctl_idx, self->power_mode);
894 }
895 return VIDEO_ERROR_NONE;
896
899 {
900 TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN);
901 TU_VERIFY(tud_control_xfer(rhport, request, &self->power_mode, sizeof(self->power_mode)), VIDEO_ERROR_UNKNOWN);
902 }
903 return VIDEO_ERROR_NONE;
904
907 {
908 TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN);
909 TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN);
910 }
911 return VIDEO_ERROR_NONE;
912
913 default: break;
914 }
915 break;
916
918 switch (request->bRequest) {
921 {
922 TU_VERIFY(tud_control_xfer(rhport, request, &self->error_code, sizeof(uint8_t)), VIDEO_ERROR_UNKNOWN);
923 }
924 return VIDEO_ERROR_NONE;
925
928 {
929 TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get, sizeof(_cap_get)), VIDEO_ERROR_UNKNOWN);
930 }
931 return VIDEO_ERROR_NONE;
932
933 default: break;
934 }
935 break;
936
937 default: break;
938 }
939
940 /* Unknown/Unsupported request */
941 TU_BREAKPOINT();
943}
944
945static int handle_video_ctl_req(uint8_t rhport, uint8_t stage,
947 uint_fast8_t ctl_idx)
948{
949 switch (request->bmRequestType_bit.type) {
951 return handle_video_ctl_std_req(rhport, stage, request, ctl_idx);
952
953 case TUSB_REQ_TYPE_CLASS: {
954 uint_fast8_t entity_id = TU_U16_HIGH(request->wIndex);
955 if (!entity_id) {
956 return handle_video_ctl_cs_req(rhport, stage, request, ctl_idx);
957 } else {
959 return VIDEO_ERROR_NONE;
960 }
961 }
962
963 default:
965 }
966}
967
968static int handle_video_stm_std_req(uint8_t rhport, uint8_t stage,
970 uint_fast8_t stm_idx)
971{
972 TU_LOG_DRV("\r\n");
974 switch (request->bRequest) {
977 {
978 TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN);
979 tusb_desc_vs_itf_t const *vs = _get_desc_vs(self);
980 TU_VERIFY(vs, VIDEO_ERROR_UNKNOWN);
981 uint8_t alt_num = vs->std.bAlternateSetting;
982
983 TU_VERIFY(tud_control_xfer(rhport, request, &alt_num, sizeof(alt_num)), VIDEO_ERROR_UNKNOWN);
984 }
985 return VIDEO_ERROR_NONE;
986
988 if (stage == CONTROL_STAGE_SETUP) {
989 TU_VERIFY(_open_vs_itf(rhport, self, request->wValue), VIDEO_ERROR_UNKNOWN);
991 }
992 return VIDEO_ERROR_NONE;
993
994 default: /* Unknown/Unsupported request */
995 TU_BREAKPOINT();
997 }
998}
999
1000static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
1002 uint_fast8_t stm_idx) {
1003 (void)rhport;
1005
1006 uint8_t const ctrl_sel = TU_U16_HIGH(request->wValue);
1007 TU_LOG_DRV("%s_Control(%s)\r\n", tu_str_video_vs_control_selector[ctrl_sel], tu_lookup_find(&tu_table_video_request, request->bRequest));
1008
1009 /* 4.2.1 Interface Control Request */
1010 switch (ctrl_sel) {
1012 switch (request->bRequest) {
1014 if (stage == CONTROL_STAGE_SETUP) {
1015 /* TODO */
1016 TU_VERIFY(tud_control_xfer(rhport, request, &self->error_code, sizeof(uint8_t)), VIDEO_ERROR_UNKNOWN);
1017 }
1018 return VIDEO_ERROR_NONE;
1019
1021 if (stage == CONTROL_STAGE_SETUP) {
1022 TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get, sizeof(_cap_get)), VIDEO_ERROR_UNKNOWN);
1023 }
1024 return VIDEO_ERROR_NONE;
1025
1026 default: break;
1027 }
1028 break;
1029
1030 case VIDEO_VS_CTL_PROBE:
1031 if (self->state != VS_STATE_PROBING) {
1032 self->state = VS_STATE_PROBING;
1033 }
1034
1035 switch (request->bRequest) {
1037 if (stage == CONTROL_STAGE_SETUP) {
1040 } else if (stage == CONTROL_STAGE_DATA) {
1041 TU_VERIFY(_update_streaming_parameters(self, &self->probe_commit_payload),
1043 }
1044 return VIDEO_ERROR_NONE;
1045
1047 if (stage == CONTROL_STAGE_SETUP) {
1048 TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN);
1050 }
1051 return VIDEO_ERROR_NONE;
1052
1057 if (stage == CONTROL_STAGE_SETUP) {
1058 TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN);
1061 TU_VERIFY(tud_control_xfer(rhport, request, &tmp, sizeof(tmp)), VIDEO_ERROR_UNKNOWN);
1062 }
1063 return VIDEO_ERROR_NONE;
1064
1066 if (stage == CONTROL_STAGE_SETUP) {
1067 TU_VERIFY(2 == request->wLength, VIDEO_ERROR_UNKNOWN);
1068 uint16_t len = sizeof(video_probe_and_commit_control_t);
1069 TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)&len, sizeof(len)), VIDEO_ERROR_UNKNOWN);
1070 }
1071 return VIDEO_ERROR_NONE;
1072
1074 if (stage == CONTROL_STAGE_SETUP) {
1075 TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN);
1076 TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t)&_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN);
1077 }
1078 return VIDEO_ERROR_NONE;
1079
1080 default: break;
1081 }
1082 break;
1083
1085 switch (request->bRequest) {
1087 if (stage == CONTROL_STAGE_SETUP) {
1089 } else if (stage == CONTROL_STAGE_DATA) {
1092 /* Set the negotiated value */
1093 self->max_payload_transfer_size = param->dwMaxPayloadTransferSize;
1094 int ret = VIDEO_ERROR_NONE;
1095 if (tud_video_commit_cb) {
1096 ret = tud_video_commit_cb(self->index_vc, self->index_vs, param);
1097 }
1098 if (VIDEO_ERROR_NONE == ret) {
1099 self->state = VS_STATE_COMMITTED;
1100 self->buffer = NULL;
1101 self->bufsize = 0;
1102 self->offset = 0;
1103 /* initialize payload header */
1105 hdr->bHeaderLength = sizeof(*hdr);
1106 hdr->bmHeaderInfo = 0;
1107 }
1108 }
1109 return VIDEO_ERROR_NONE;
1110
1112 if (stage == CONTROL_STAGE_SETUP) {
1113 TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN);
1115 }
1116 return VIDEO_ERROR_NONE;
1117
1119 if (stage == CONTROL_STAGE_SETUP) {
1120 TU_VERIFY(2 == request->wLength, VIDEO_ERROR_UNKNOWN);
1121 uint16_t len = sizeof(video_probe_and_commit_control_t);
1122 TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)&len, sizeof(len)), VIDEO_ERROR_UNKNOWN);
1123 }
1124 return VIDEO_ERROR_NONE;
1125
1127 if (stage == CONTROL_STAGE_SETUP) {
1128 TU_VERIFY(1 == request->wLength, VIDEO_ERROR_UNKNOWN);
1129 TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)(uintptr_t) &_cap_get_set, sizeof(_cap_get_set)), VIDEO_ERROR_UNKNOWN);
1130 }
1131 return VIDEO_ERROR_NONE;
1132
1133 default: break;
1134 }
1135 break;
1136
1143 /* TODO */
1144 break;
1145
1146 default: break;
1147 }
1148
1149 /* Unknown/Unsupported request */
1150 TU_BREAKPOINT();
1152}
1153
1154static int handle_video_stm_req(uint8_t rhport, uint8_t stage,
1156 uint_fast8_t stm_idx)
1157{
1158 switch (request->bmRequestType_bit.type) {
1160 return handle_video_stm_std_req(rhport, stage, request, stm_idx);
1161
1163 if (TU_U16_HIGH(request->wIndex)) return VIDEO_ERROR_INVALID_REQUEST;
1164 return handle_video_stm_cs_req(rhport, stage, request, stm_idx);
1165
1166 default: return VIDEO_ERROR_INVALID_REQUEST;
1167 }
1168}
1169
1170//--------------------------------------------------------------------+
1171// APPLICATION API
1172//--------------------------------------------------------------------+
1173
1174bool tud_video_n_connected(uint_fast8_t ctl_idx)
1175{
1176 TU_ASSERT(ctl_idx < CFG_TUD_VIDEO);
1178 if (stm) return true;
1179 return false;
1180}
1181
1182bool tud_video_n_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx)
1183{
1184 TU_ASSERT(ctl_idx < CFG_TUD_VIDEO);
1185 TU_ASSERT(stm_idx < CFG_TUD_VIDEO_STREAMING);
1187 if (!stm || !stm->desc.ep[0]) return false;
1188 if (stm->state == VS_STATE_PROBING) return false;
1189
1190#ifdef TUP_DCD_EDPT_ISO_ALLOC
1191 uint8_t const *desc = _videod_itf[stm->index_vc].beg;
1192 uint_fast16_t ofs_ep = stm->desc.ep[0];
1193 tusb_desc_endpoint_t const *ep = (tusb_desc_endpoint_t const*)(desc + ofs_ep);
1194 if (ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) {
1195 if (stm->state == VS_STATE_COMMITTED) return false;
1196 }
1197#endif
1198
1199 return true;
1200}
1201
1202bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *buffer, size_t bufsize)
1203{
1204 TU_ASSERT(ctl_idx < CFG_TUD_VIDEO);
1205 TU_ASSERT(stm_idx < CFG_TUD_VIDEO_STREAMING);
1206 if (!buffer || !bufsize) return false;
1208 if (!stm || !stm->desc.ep[0] || stm->buffer) return false;
1209 if (stm->state == VS_STATE_PROBING) return false;
1210
1211 /* Find EP address */
1212 uint8_t const *desc = _videod_itf[stm->index_vc].beg;
1213 uint8_t ep_addr = 0;
1214 for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) {
1215 uint_fast16_t ofs_ep = stm->desc.ep[i];
1216 if (!ofs_ep) continue;
1217 ep_addr = _desc_ep_addr(desc + ofs_ep);
1218 break;
1219 }
1220 if (!ep_addr) return false;
1221
1222 TU_VERIFY( usbd_edpt_claim(0, ep_addr) );
1223 /* update the packet header */
1225 hdr->FrameID ^= 1;
1226 hdr->EndOfFrame = 0;
1227 /* update the packet data */
1228 stm->buffer = (uint8_t*)buffer;
1229 stm->bufsize = bufsize;
1230 uint_fast16_t pkt_len = _prepare_in_payload(stm);
1231 TU_ASSERT( usbd_edpt_xfer(0, ep_addr, stm->ep_buf, (uint16_t) pkt_len), 0);
1232 return true;
1233}
1234
1235//--------------------------------------------------------------------+
1236// USBD Driver API
1237//--------------------------------------------------------------------+
1238void videod_init(void) {
1239 for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO; ++i) {
1241 tu_memclr(ctl, sizeof(*ctl));
1242 }
1243 for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) {
1245 tu_memclr(stm, ITF_STM_MEM_RESET_SIZE);
1246 }
1247}
1248
1249bool videod_deinit(void) {
1250 return true;
1251}
1252
1253void videod_reset(uint8_t rhport) {
1254 (void) rhport;
1255 for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO; ++i) {
1257 tu_memclr(ctl, sizeof(*ctl));
1258 }
1259 for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) {
1261 tu_memclr(stm, ITF_STM_MEM_RESET_SIZE);
1262 }
1263}
1264
1265uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len) {
1266 TU_VERIFY((TUSB_CLASS_VIDEO == itf_desc->bInterfaceClass) &&
1268 (VIDEO_ITF_PROTOCOL_15 == itf_desc->bInterfaceProtocol), 0);
1269
1270 /* Find available interface */
1271 videod_interface_t *self = NULL;
1272 uint8_t ctl_idx;
1273 for (ctl_idx = 0; ctl_idx < CFG_TUD_VIDEO; ++ctl_idx) {
1274 if (_videod_itf[ctl_idx].beg) continue;
1275 self = &_videod_itf[ctl_idx];
1276 break;
1277 }
1278 TU_ASSERT(ctl_idx < CFG_TUD_VIDEO, 0);
1279
1280 uint8_t const *end = (uint8_t const*)itf_desc + max_len;
1281 self->beg = (uint8_t const*) itf_desc;
1282 self->len = max_len;
1283
1284 /*------------- Video Control Interface -------------*/
1285 TU_VERIFY(_open_vc_itf(rhport, self, 0), 0);
1286 tusb_desc_vc_itf_t const *vc = _get_desc_vc(self);
1287 uint_fast8_t bInCollection = vc->ctl.bInCollection;
1288
1289 /* Find the end of the video interface descriptor */
1290 void const *cur = _next_desc_itf(itf_desc, end);
1291 for (uint8_t stm_idx = 0; stm_idx < bInCollection; ++stm_idx) {
1292 videod_streaming_interface_t *stm = NULL;
1293 /* find free streaming interface handle */
1294 for (uint8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) {
1295 if (_videod_streaming_itf[i].desc.beg) continue;
1296 stm = &_videod_streaming_itf[i];
1297 self->stm[stm_idx] = i;
1298 break;
1299 }
1300 TU_ASSERT(stm, 0);
1301 stm->index_vc = ctl_idx;
1302 stm->index_vs = stm_idx;
1303 stm->desc.beg = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc);
1304 cur = _next_desc_itf(cur, end);
1305 stm->desc.end = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc);
1306 stm->state = VS_STATE_PROBING;
1307#ifdef TUP_DCD_EDPT_ISO_ALLOC
1308 /* Allocate ISO endpoints */
1309 uint16_t ep_size = 0;
1310 uint16_t ep_addr = 0;
1311 uint8_t const *p_desc = (uint8_t const*)itf_desc + stm->desc.beg;
1312 uint8_t const *p_desc_end = (uint8_t const*)itf_desc + stm->desc.end;
1313 while (p_desc < p_desc_end) {
1314 if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) {
1315 tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc;
1316 if (desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) {
1317 ep_addr = desc_ep->bEndpointAddress;
1318 ep_size = TU_MAX(tu_edpt_packet_size(desc_ep), ep_size);
1319 }
1320 }
1321 p_desc = tu_desc_next(p_desc);
1322 }
1323 if(ep_addr > 0 && ep_size > 0) usbd_edpt_iso_alloc(rhport, ep_addr, ep_size);
1324#endif
1325 if (0 == stm_idx && 1 == bInCollection) {
1326 /* If there is only one streaming interface and no alternate settings,
1327 * host may not issue set_interface so open the streaming interface here. */
1328 uint8_t const *sbeg = (uint8_t const*)itf_desc + stm->desc.beg;
1329 uint8_t const *send = (uint8_t const*)itf_desc + stm->desc.end;
1330 if (send == _find_desc_itf(sbeg, send, _desc_itfnum(sbeg), 1)) {
1331 TU_VERIFY(_open_vs_itf(rhport, stm, 0), 0);
1332 }
1333 }
1334 }
1335 self->len = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc);
1336 return (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc);
1337}
1338
1339// Invoked when a control transfer occurred on an interface of this class
1340// Driver response accordingly to the request and the transfer stage (setup/data/ack)
1341// return false to stall control endpoint (e.g unsupported request)
1342bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) {
1343 int err;
1344 TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE);
1345 uint_fast8_t itfnum = tu_u16_low(request->wIndex);
1346 /* Identify which control interface to use */
1347 uint_fast8_t itf;
1348 for (itf = 0; itf < CFG_TUD_VIDEO; ++itf) {
1349 void const *desc = _videod_itf[itf].beg;
1350 if (!desc) continue;
1351 if (itfnum == _desc_itfnum(desc)) break;
1352 }
1353
1354 if (itf < CFG_TUD_VIDEO) {
1355 TU_LOG_DRV(" VC[%d]: ", itf);
1356 err = handle_video_ctl_req(rhport, stage, request, itf);
1357 _videod_itf[itf].error_code = (uint8_t)err;
1358 if (err) return false;
1359 return true;
1360 }
1361
1362 /* Identify which streaming interface to use */
1363 for (itf = 0; itf < CFG_TUD_VIDEO_STREAMING; ++itf) {
1365 if (!stm->desc.beg) continue;
1366 uint8_t const *desc = _videod_itf[stm->index_vc].beg;
1367 if (itfnum == _desc_itfnum(desc + stm->desc.beg)) break;
1368 }
1369
1370 if (itf < CFG_TUD_VIDEO_STREAMING) {
1371 TU_LOG_DRV(" VS[%d]: ", itf);
1372 err = handle_video_stm_req(rhport, stage, request, itf);
1373 _videod_streaming_itf[itf].error_code = (uint8_t)err;
1374 if (err) return false;
1375 return true;
1376 }
1377 return false;
1378}
1379
1380bool videod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
1381 (void)result; (void)xferred_bytes;
1382
1383 /* find streaming handle */
1384 uint_fast8_t itf;
1385 videod_interface_t *ctl;
1387 for (itf = 0; itf < CFG_TUD_VIDEO_STREAMING; ++itf) {
1388 stm = &_videod_streaming_itf[itf];
1389 uint_fast16_t const ep_ofs = stm->desc.ep[0];
1390 if (!ep_ofs) continue;
1391 ctl = &_videod_itf[stm->index_vc];
1392 uint8_t const *desc = ctl->beg;
1393 if (ep_addr == _desc_ep_addr(desc + ep_ofs)) break;
1394 }
1395
1396 TU_ASSERT(itf < CFG_TUD_VIDEO_STREAMING);
1397 if (stm->offset < stm->bufsize) {
1398 /* Claim the endpoint */
1399 TU_VERIFY( usbd_edpt_claim(rhport, ep_addr), 0);
1400 uint_fast16_t pkt_len = _prepare_in_payload(stm);
1401 TU_ASSERT( usbd_edpt_xfer(rhport, ep_addr, stm->ep_buf, (uint16_t) pkt_len), 0);
1402 } else {
1403 stm->buffer = NULL;
1404 stm->bufsize = 0;
1405 stm->offset = 0;
1408 }
1409 }
1410 return true;
1411}
1412
1413#endif
static usb_descriptor_buffers_t desc
Definition: dcd_pio_usb.c:46
uint8_t const * buffer
Definition: midi_device.h:100
uint32_t bufsize
Definition: midi_device.h:95
static void * memcpy(void *dst, const void *src, size_t n)
Definition: ringbuffer.c:8
AUDIO Channel Cluster Descriptor (4.1)
Definition: audio.h:647
uint8_t EndOfFrame
Definition: video.h:486
uint8_t index_vc
Definition: video_device.c:103
uint8_t bNumFormats
Definition: video.h:304
uint8_t bEntityId
Definition: video_device.c:70
struct TU_ATTR_PACKED::@66 desc
uint32_t max_payload_transfer_size
Definition: video_device.c:114
uint32_t bufsize
Definition: video_device.c:112
uint16_t wCompQuality
Definition: video.h:505
uint32_t dwFrameInterval[]
Definition: video.h:472
uint32_t dwMaxVideoFrameSize
Definition: video.h:518
uint32_t dwMaxPayloadTransferSize
Definition: video.h:519
CFG_TUSB_MEM_ALIGN uint8_t ep_buf[CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE]
Definition: video_device.c:120
uint16_t wTotalLength
Total number of bytes returned for the class-specific AudioControl interface descriptor....
Definition: audio.h:661
uint8_t bBitDepthLuma
Definition: video.h:534
uint16_t wCompWindowSize
Definition: video.h:506
uint8_t bFrameIndex
Definition: video.h:463
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
uint8_t bFormatIndex
Definition: video.h:361
uint8_t error_code
Definition: video_device.c:115
uint8_t bUsage
Definition: video.h:533
uint8_t bMinVersion
Definition: video.h:531
uint8_t bmFramingInfo
Definition: video.h:522
uint8_t bDefaultFrameIndex
Definition: video.h:365
uint32_t dwClockFrequency
Definition: video.h:520
uint16_t wLength
Definition: audio.h:840
uint32_t offset
Definition: video_device.c:113
uint8_t stm[CFG_TUD_VIDEO_STREAMING]
Definition: video_device.c:128
volatile uint16_t
Definition: hcd_rusb2.c:58
uint8_t * buffer
Definition: video_device.c:111
uint8_t bBitsPerPixel
Definition: video.h:364
uint16_t wDelay
Definition: video.h:517
uint16_t wIndex
Definition: audio.h:943
uint8_t bDescriptorType
Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
Definition: audio.h:657
uint16_t wPFrameRate
Definition: video.h:504
uint8_t bInterfaceClass
Class code (assigned by the USB-IF).
Definition: tusb_types.h:349
uint8_t bLength
Size of this descriptor in bytes: 9.
Definition: audio.h:656
uint8_t bmHeaderInfo
Definition: video.h:483
uint8_t bHeaderLength
Definition: video.h:481
uint8_t bMaxVersion
Definition: video.h:532
uint8_t FrameID
Definition: video.h:485
uint8_t const * beg
Definition: video_device.c:125
uint8_t index_vs
Definition: video_device.c:104
uint8_t power_mode
Definition: video_device.c:130
uint8_t bEndpointAddress
Definition: video.h:306
uint8_t bInterfaceSubClass
Subclass code (assigned by the USB-IF). These codes are qualified by the value of the bInterfaceCla...
Definition: tusb_types.h:350
uint8_t bPreferedVersion
Definition: video.h:530
uint8_t bRequest
Request type audio_cs_req_t.
Definition: audio.h:831
uint8_t bNumEndpoints
Number of endpoints used by this interface (excluding endpoint zero). If this value is zero,...
Definition: tusb_types.h:348
uint8_t bInterfaceProtocol
Protocol code (assigned by the USB). These codes are qualified by the value of the bInterfaceClass ...
Definition: tusb_types.h:351
uint16_t ep[2]
Definition: video_device.c:109
uint16_t wKeyFrameRate
Definition: video.h:513
uint8_t bDescriptorSubtype
Definition: video_device.c:69
uint8_t bAlternateSetting
Value used to select this alternate setting for the interface identified in the prior field.
Definition: tusb_types.h:347
video_probe_and_commit_control_t probe_commit_payload
Definition: video_device.c:118
Definition: tusb_debug.h:100
uint32_t key
Definition: tusb_debug.h:101
tusb_desc_interface_t std
Definition: video_device.c:52
tusb_desc_video_control_header_t ctl
Definition: video_device.c:53
tusb_desc_interface_t std
Definition: video_device.c:57
tusb_desc_video_streaming_inout_header_t stm
Definition: video_device.c:58
static TU_ATTR_ALWAYS_INLINE uint8_t tu_u16_low(uint16_t ui16)
Definition: tusb_common.h:146
static const char * tu_lookup_find(tu_lookup_table_t const *p_table, uint32_t key)
Definition: tusb_debug.h:110
@ TUSB_REQ_SET_INTERFACE
Definition: tusb_types.h:133
@ TUSB_REQ_GET_INTERFACE
Definition: tusb_types.h:132
@ TUSB_CLASS_VIDEO
Definition: tusb_types.h:173
xfer_result_t
Definition: tusb_types.h:236
@ TUSB_REQ_RCPT_INTERFACE
Definition: tusb_types.h:152
static TU_ATTR_ALWAYS_INLINE uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const *desc_ep)
Definition: tusb_types.h:515
@ TUSB_XFER_ISOCHRONOUS
Definition: tusb_types.h:60
@ TUSB_XFER_BULK
Definition: tusb_types.h:61
@ CONTROL_STAGE_DATA
Definition: tusb_types.h:269
@ 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_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_INTERFACE_ASSOCIATION
Definition: tusb_types.h:103
@ TUSB_DESC_CS_INTERFACE
Definition: tusb_types.h:114
@ TUSB_DESC_ENDPOINT
Definition: tusb_types.h:97
@ TUSB_DESC_INTERFACE
Definition: tusb_types.h:96
tusb_desc_video_format_mjpeg_t mjpeg
Definition: video_device.c:82
tusb_desc_video_format_framebased_t frame_based
Definition: video_device.c:83
tusb_desc_video_format_uncompressed_t uncompressed
Definition: video_device.c:81
tusb_desc_video_frame_mjpeg_t mjpeg
Definition: video_device.c:97
tusb_desc_video_frame_framebased_t frame_based
Definition: video_device.c:98
tusb_desc_video_frame_uncompressed_t uncompressed
Definition: video_device.c:96
tusb_desc_video_streaming_inout_header_t stm
Definition: video_device.c:63
tusb_desc_video_control_header_t ctl
Definition: video_device.c:62
void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr)
Definition: usbd.c:1424
bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
Definition: usbd.c:1309
bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep)
Definition: usbd.c:1277
bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr)
Definition: usbd.c:1286
bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep)
Definition: usbd.c:1474
bool usbd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size)
Definition: usbd.c:1462
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
CFG_TUH_MEM_ALIGN tusb_control_request_t request
Definition: usbh.c:259
volatile uint8_t stage
Definition: usbh.c:265
@ VIDEO_CS_ITF_VC_MAX
Definition: video.h:106
@ VIDEO_VS_CTL_UPDATE_FRAME_SEGMENT
Definition: video.h:177
@ VIDEO_VS_CTL_PROBE
Definition: video.h:170
@ VIDEO_VS_CTL_COMMIT
Definition: video.h:171
@ VIDEO_VS_CTL_STILL_IMAGE_TRIGGER
Definition: video.h:174
@ VIDEO_VS_CTL_STREAM_ERROR_CODE
Definition: video.h:175
@ VIDEO_VS_CTL_STILL_PROBE
Definition: video.h:172
@ VIDEO_VS_CTL_STILL_COMMIT
Definition: video.h:173
@ VIDEO_VS_CTL_GENERATE_KEY_FRAME
Definition: video.h:176
@ VIDEO_VS_CTL_SYNCH_DELAY_CONTROL
Definition: video.h:178
tusb_desc_video_frame_uncompressed_t tusb_desc_video_frame_mjpeg_t
Definition: video.h:422
@ VIDEO_CS_ITF_VS_FORMAT_FRAME_BASED
Definition: video.h:122
@ VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED
Definition: video.h:115
@ VIDEO_CS_ITF_VS_FORMAT_MJPEG
Definition: video.h:117
@ VIDEO_CS_ITF_VS_FORMAT_DV
Definition: video.h:120
@ VIDEO_CS_ITF_VS_FRAME_FRAME_BASED
Definition: video.h:123
@ VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED
Definition: video.h:116
@ VIDEO_CS_ITF_VS_FRAME_MJPEG
Definition: video.h:118
struct TU_ATTR_PACKED video_probe_and_commit_control_t
@ VIDEO_REQUEST_SET_CUR_ALL
Definition: video.h:145
@ VIDEO_REQUEST_GET_INFO
Definition: video.h:151
@ VIDEO_REQUEST_GET_DEF_ALL
Definition: video.h:157
@ VIDEO_REQUEST_UNDEFINED
Definition: video.h:143
@ VIDEO_REQUEST_GET_LEN
Definition: video.h:150
@ VIDEO_REQUEST_GET_DEF
Definition: video.h:152
@ VIDEO_REQUEST_GET_CUR_ALL
Definition: video.h:153
@ VIDEO_REQUEST_GET_MIN
Definition: video.h:147
@ VIDEO_REQUEST_GET_RES
Definition: video.h:149
@ VIDEO_REQUEST_GET_MIN_ALL
Definition: video.h:154
@ VIDEO_REQUEST_SET_CUR
Definition: video.h:144
@ VIDEO_REQUEST_GET_CUR
Definition: video.h:146
@ VIDEO_REQUEST_GET_MAX
Definition: video.h:148
@ VIDEO_REQUEST_GET_RES_ALL
Definition: video.h:156
@ VIDEO_REQUEST_GET_MAX_ALL
Definition: video.h:155
@ VIDEO_ITF_PROTOCOL_15
Definition: video.h:93
@ VIDEO_SUBCLASS_CONTROL
Definition: video.h:85
@ VIDEO_ERROR_NONE
Definition: video.h:70
@ VIDEO_ERROR_UNKNOWN
Definition: video.h:79
@ VIDEO_ERROR_INVALID_REQUEST
Definition: video.h:77
@ VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE
Definition: video.h:78
@ VIDEO_VC_CTL_VIDEO_POWER_MODE
Definition: video.h:163
@ VIDEO_VC_CTL_REQUEST_ERROR_CODE
Definition: video.h:164
static bool _close_vc_itf(uint8_t rhport, videod_interface_t *self)
Definition: video_device.c:678
static void const * _find_desc_entity(void const *desc, uint_fast8_t entityid)
Definition: video_device.c:370
static tu_lookup_entry_t const tu_lookup_video_request[]
Definition: video_device.c:153
static int handle_video_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, uint_fast8_t ctl_idx)
Definition: video_device.c:945
struct TU_ATTR_PACKED videod_interface_t
static void const * _next_desc_itf(void const *beg, void const *end)
Definition: video_device.c:312
struct TU_ATTR_PACKED tusb_desc_cs_video_entity_itf_t
bool tud_video_n_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx)
void videod_init(void)
static bool _update_streaming_parameters(videod_streaming_interface_t const *stm, video_probe_and_commit_control_t *param)
Definition: video_device.c:430
CFG_TUD_MEM_SECTION tu_static videod_streaming_interface_t _videod_streaming_itf[CFG_TUD_VIDEO_STREAMING]
Definition: video_device.c:143
static char const *const tu_str_video_vc_control_selector[]
Definition: video_device.c:176
static void const * _find_desc_frame(void const *beg, void const *end, uint_fast8_t frmnum)
Definition: video_device.c:411
bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint_fast8_t altnum)
Definition: video_device.c:752
static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t altnum)
Definition: video_device.c:702
static void const * _end_of_streaming_descriptor(void const *desc)
Definition: video_device.c:386
void videod_reset(uint8_t rhport)
static bool _init_vs_configuration(videod_streaming_interface_t *stm)
Definition: video_device.c:739
uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
static tu_lookup_table_t const tu_table_video_request
Definition: video_device.c:171
bool videod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
static void const * _find_desc_3(void const *beg, void const *end, uint_fast8_t desc_type, uint_fast8_t element_0, uint_fast8_t element_1)
Definition: video_device.c:287
bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *buffer, size_t bufsize)
static char const *const tu_str_video_vs_control_selector[]
Definition: video_device.c:182
static uint8_t const * _find_desc_itf(void const *beg, void const *end, uint_fast8_t itfnum, uint_fast8_t altnum)
Definition: video_device.c:331
static int handle_video_stm_std_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, uint_fast8_t stm_idx)
Definition: video_device.c:968
static void const * _find_desc_2_type(void const *beg, void const *end, uint_fast8_t desc_type_0, uint_fast8_t desc_type_1)
Definition: video_device.c:268
tu_static uint8_t const _cap_get_set
Definition: video_device.c:146
CFG_TUD_MEM_SECTION tu_static videod_interface_t _videod_itf[CFG_TUD_VIDEO]
Definition: video_device.c:142
static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *stm, uint_fast8_t request, video_probe_and_commit_control_t *param)
Definition: video_device.c:522
bool tud_video_n_connected(uint_fast8_t ctl_idx)
struct TU_ATTR_PACKED videod_streaming_interface_t
static uint_fast16_t _prepare_in_payload(videod_streaming_interface_t *stm)
Definition: video_device.c:819
static void const * _find_desc_ep(void const *beg, void const *end)
Definition: video_device.c:345
bool videod_deinit(void)
static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, uint_fast8_t stm_idx)
static uint8_t _desc_itfnum(void const *desc)
Definition: video_device.c:206
static videod_streaming_interface_t * _get_instance_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx)
Definition: video_device.c:225
static void const * _find_desc_format(void const *beg, void const *end, uint_fast8_t fmtnum)
Definition: video_device.c:393
static int handle_video_ctl_cs_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, uint_fast8_t ctl_idx)
Definition: video_device.c:875
static void const * _end_of_control_descriptor(void const *desc)
Definition: video_device.c:356
static uint8_t _desc_ep_addr(void const *desc)
Definition: video_device.c:215
static int handle_video_stm_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, uint_fast8_t stm_idx)
static tusb_desc_vs_itf_t const * _get_desc_vs(videod_streaming_interface_t const *self)
Definition: video_device.c:237
static void const * _find_desc(void const *beg, void const *end, uint_fast8_t desc_type)
Definition: video_device.c:251
static tusb_desc_vc_itf_t const * _get_desc_vc(videod_interface_t const *self)
Definition: video_device.c:233
tu_static uint8_t const _cap_get
Definition: video_device.c:145
static int handle_video_ctl_std_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, uint_fast8_t ctl_idx)
Definition: video_device.c:840
TU_ATTR_WEAK int tud_video_power_mode_cb(uint_fast8_t ctl_idx, uint8_t power_mod)
TU_ATTR_WEAK void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx)
TU_ATTR_WEAK int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, video_probe_and_commit_control_t const *parameters)