diff options
| author | Saulo VerĂssimo <[email protected]> | 2026-03-25 07:05:56 -0300 |
|---|---|---|
| committer | Saulo VerĂssimo <[email protected]> | 2026-05-12 11:07:44 -0300 |
| commit | fa9edeff9c00ee1fc4ee7ab9938b1a5955a6281a (patch) | |
| tree | 4655c751abefbf5ebd65ad0265904754d5552a96 | |
| parent | d5c5ac586bfdbf53e18a8cdbb11b978f53b6d059 (diff) | |
fix: address PR review feedback for MIDI 2.0 drivers
Host driver (midi2_host.c):
- midih2_open() now returns actual parsed length instead of max_len,
preventing composite device interface conflicts
- Parsers (alt0/alt1) refactored to return const uint8_t* end pointer
following midi_host.c switch/case pattern
- Alt 1 CS Endpoint now parses MIDI 2.0 layout (bNumGrpTrmBlk at
offset 3 with MIDI_CS_ENDPOINT_GENERAL_2_0 subtype check) instead
of reusing MIDI 1.0 struct (bNumEmbMIDIJack)
- midih2_set_config() now issues SET_INTERFACE control request via
tuh_interface_set() before completing configuration. Falls back to
alt 0 if SET_INTERFACE fails
- Extracted midih2_set_config_complete() and midih2_set_interface_cb()
for async SET_INTERFACE handling
Device driver (midi2_device.c):
- midi2d_open() skip loop now checks bInterfaceNumber, stopping at
interfaces that belong to other functions in composite devices
- SET_INTERFACE handler now rejects alt > 1 (returns false/stall)
- Named constants for GTB descriptor types and MIDI protocol values
Descriptor macros (usbd.h):
- TUD_MIDI2_DESC_ALT1_HEAD: iInterface set to 0 (consistent with
Alt 0), wTotalLength now uses TUD_MIDI2_DESC_ALT1_CS_LEN to cover
all Alt 1 class-specific descriptors
- TUD_MIDI2_DESC_ALT1_EP: now accepts GTB ID list via variadic args,
emitting complete CS endpoint descriptor
Host example:
- CMakeLists.txt restricted to rp2040 family (display.c requires
Pico SDK headers)
- display.c: null terminator after strncpy in log scroll
Documentation:
- class_drivers.rst updated to reflect SET_INTERFACE behavior and
auto-select with fallback
Addresses: Codex P1 (#1, #2, #3), Copilot (#4-#9)
| -rw-r--r-- | docs/reference/class_drivers.rst | 8 | ||||
| -rw-r--r-- | examples/host/midi2_host/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | examples/host/midi2_host/src/display.c | 1 | ||||
| -rw-r--r-- | src/class/midi/midi2_device.c | 14 | ||||
| -rw-r--r-- | src/class/midi/midi2_host.c | 213 | ||||
| -rw-r--r-- | src/device/usbd.h | 24 |
6 files changed, 166 insertions, 97 deletions
diff --git a/docs/reference/class_drivers.rst b/docs/reference/class_drivers.rst index 9ed332acb..3ac0d8d4e 100644 --- a/docs/reference/class_drivers.rst +++ b/docs/reference/class_drivers.rst @@ -87,7 +87,7 @@ The MIDI 2.0 Host driver enables TinyUSB to enumerate and communicate with USB M **Key Features:** - **Reactive Architecture**: Auto-detects Alt Setting 1 (MIDI 2.0) capability during enumeration -- **Auto-Selection**: Automatically selects the highest available protocol (MIDI 2.0 preferred) +- **Auto-Selection**: Automatically selects the highest available protocol and issues SET_INTERFACE to activate Alt Setting 1 when MIDI 2.0 is detected - **Transparent Stream Messages**: All data (UMP packets + Stream Messages) flow through callbacks - **Memory Safe**: No dynamic allocation, fixed-size instances per device @@ -271,9 +271,9 @@ Architecture The MIDI 2.0 Host driver uses a **reactive, callback-driven architecture** that mirrors the proven patterns in TinyUSB's existing device drivers (CDC, HID, etc.): - **Auto-Detection**: Host automatically detects Alt Setting 1 capability -- **Auto-Selection**: Selects highest protocol available (MIDI 2.0 preferred) -- **Application Control**: App makes protocol behavior decisions via callbacks -- **Transparent I/O**: Stream Messages and UMP packets flow transparently +- **Auto-Selection**: Selects highest protocol available and issues SET_INTERFACE +- **Transparent I/O**: Stream Messages and UMP packets flow through callbacks +- **Callback-Driven**: App receives events via callbacks (descriptor, mount, rx, tx, unmount) Differences from MIDI 1.0 Host ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/examples/host/midi2_host/CMakeLists.txt b/examples/host/midi2_host/CMakeLists.txt index 221de7adf..cd70d122a 100644 --- a/examples/host/midi2_host/CMakeLists.txt +++ b/examples/host/midi2_host/CMakeLists.txt @@ -6,7 +6,8 @@ project(midi2_host C CXX ASM) family_initialize_project(${PROJECT_NAME} ${CMAKE_CURRENT_LIST_DIR}) -if(FAMILY STREQUAL "espressif") +# This example requires PIO-USB and Pico SDK (I2C, SSD1306 display) +if(NOT FAMILY STREQUAL "rp2040") return() endif() diff --git a/examples/host/midi2_host/src/display.c b/examples/host/midi2_host/src/display.c index 6d81bcd5c..4745c2961 100644 --- a/examples/host/midi2_host/src/display.c +++ b/examples/host/midi2_host/src/display.c @@ -190,6 +190,7 @@ void display_log(const char* text, uint16_t color) { if (log_count >= LOG_LINES) { for (int i = 0; i < LOG_LINES - 1; i++) { strncpy(log_lines[i], log_lines[i + 1], CHARS_PER_LINE); + log_lines[i][CHARS_PER_LINE] = '\0'; } log_count = LOG_LINES - 1; } diff --git a/src/class/midi/midi2_device.c b/src/class/midi/midi2_device.c index 9363aac11..aecbda4c5 100644 --- a/src/class/midi/midi2_device.c +++ b/src/class/midi/midi2_device.c @@ -505,12 +505,19 @@ uint16_t midi2d_open(uint8_t rhport, const tusb_desc_interface_t* desc_itf, uint } // Skip remaining descriptors (alt setting 1, CS endpoints, GTB) + // Stop at any interface descriptor that is not our MIDI Streaming alt setting while (tu_desc_in_bounds(p_desc, desc_end)) { uint8_t dtype = tu_desc_type(p_desc); - if (dtype != TUSB_DESC_CS_INTERFACE && dtype != TUSB_DESC_CS_ENDPOINT && - dtype != TUSB_DESC_INTERFACE && dtype != TUSB_DESC_ENDPOINT) { + + if (dtype == TUSB_DESC_INTERFACE) { + const tusb_desc_interface_t* next_itf = (const tusb_desc_interface_t*) p_desc; + // Continue only if this is an alternate setting of our own interface + if (next_itf->bInterfaceNumber != desc_midi->bInterfaceNumber) break; + } else if (dtype != TUSB_DESC_CS_INTERFACE && dtype != TUSB_DESC_CS_ENDPOINT && + dtype != TUSB_DESC_ENDPOINT) { break; } + p_desc = tu_desc_next(p_desc); } @@ -528,6 +535,9 @@ bool midi2d_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_re uint8_t itf_num = tu_u16_low(request->wIndex); uint8_t alt = tu_u16_low(request->wValue); + // Only Alt Setting 0 (MIDI 1.0) and 1 (UMP) are valid + if (alt > 1) return false; + uint8_t idx = find_midi2_itf_by_num(itf_num); if (idx >= CFG_TUD_MIDI2) return false; diff --git a/src/class/midi/midi2_host.c b/src/class/midi/midi2_host.c index beb441b56..5b9f98f8b 100644 --- a/src/class/midi/midi2_host.c +++ b/src/class/midi/midi2_host.c @@ -125,9 +125,10 @@ static inline uint8_t get_idx_by_ep_addr(uint8_t daddr, uint8_t ep_addr) { // Descriptor parsing //--------------------------------------------------------------------+ -static void midih2_parse_descriptors_alt0(midih2_interface_t *p_midi, +// Parse Alt Setting 0 (MIDI 1.0) descriptors. Returns pointer past last consumed descriptor. +static const uint8_t* midih2_parse_descriptors_alt0(midih2_interface_t *p_midi, const tusb_desc_interface_t *desc_itf, const uint8_t *desc_end) { - TU_VERIFY(AUDIO_SUBCLASS_MIDI_STREAMING == desc_itf->bInterfaceSubClass,); + TU_VERIFY(AUDIO_SUBCLASS_MIDI_STREAMING == desc_itf->bInterfaceSubClass, NULL); p_midi->bInterfaceNumber = desc_itf->bInterfaceNumber; @@ -136,93 +137,113 @@ static void midih2_parse_descriptors_alt0(midih2_interface_t *p_midi, uint8_t rx_cable_count = 0; uint8_t tx_cable_count = 0; + bool found_new_interface = false; - while (tu_desc_in_bounds(p_desc, desc_end)) { - if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) { - break; - } - - if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) { - const tusb_desc_endpoint_t *p_ep = (const tusb_desc_endpoint_t *) p_desc; - - // Open endpoint and stream - TU_ASSERT(tuh_edpt_open(p_midi->daddr, p_ep),); - if (tu_edpt_dir(p_ep->bEndpointAddress) == TUSB_DIR_IN) { - tu_edpt_stream_open(&p_midi->ep_stream.rx, p_midi->daddr, p_ep, tu_edpt_packet_size(p_ep)); - tu_edpt_stream_clear(&p_midi->ep_stream.rx); - } else { - tu_edpt_stream_open(&p_midi->ep_stream.tx, p_midi->daddr, p_ep, tu_edpt_packet_size(p_ep)); - tu_edpt_stream_clear(&p_midi->ep_stream.tx); - } - - p_desc = tu_desc_next(p_desc); + while (tu_desc_in_bounds(p_desc, desc_end) && !found_new_interface) { + switch (tu_desc_type(p_desc)) { + case TUSB_DESC_INTERFACE: + found_new_interface = true; + break; - if (tu_desc_in_bounds(p_desc, desc_end) && tu_desc_type(p_desc) == TUSB_DESC_CS_ENDPOINT) { - const midi_desc_cs_endpoint_t *p_csep = (const midi_desc_cs_endpoint_t *) p_desc; + case TUSB_DESC_ENDPOINT: { + const tusb_desc_endpoint_t *p_ep = (const tusb_desc_endpoint_t *) p_desc; - if (tu_edpt_dir(p_ep->bEndpointAddress) == TUSB_DIR_OUT) { - tx_cable_count = p_csep->bNumEmbMIDIJack; + TU_ASSERT(tuh_edpt_open(p_midi->daddr, p_ep), NULL); + if (tu_edpt_dir(p_ep->bEndpointAddress) == TUSB_DIR_IN) { + tu_edpt_stream_open(&p_midi->ep_stream.rx, p_midi->daddr, p_ep, tu_edpt_packet_size(p_ep)); + tu_edpt_stream_clear(&p_midi->ep_stream.rx); } else { - rx_cable_count = p_csep->bNumEmbMIDIJack; + tu_edpt_stream_open(&p_midi->ep_stream.tx, p_midi->daddr, p_ep, tu_edpt_packet_size(p_ep)); + tu_edpt_stream_clear(&p_midi->ep_stream.tx); + } + + p_desc = tu_desc_next(p_desc); + if (tu_desc_in_bounds(p_desc, desc_end) && tu_desc_type(p_desc) == TUSB_DESC_CS_ENDPOINT) { + const midi_desc_cs_endpoint_t *p_csep = (const midi_desc_cs_endpoint_t *) p_desc; + if (tu_edpt_dir(p_ep->bEndpointAddress) == TUSB_DIR_OUT) { + tx_cable_count = p_csep->bNumEmbMIDIJack; + } else { + rx_cable_count = p_csep->bNumEmbMIDIJack; + } } + break; } + + default: + break; } - p_desc = tu_desc_next(p_desc); + if (!found_new_interface) { + p_desc = tu_desc_next(p_desc); + } } p_midi->rx_cable_count_alt0 = rx_cable_count; p_midi->tx_cable_count_alt0 = tx_cable_count; + return p_desc; } -static void midih2_parse_descriptors_alt1(midih2_interface_t *p_midi, +// Parse Alt Setting 1 (MIDI 2.0 UMP) descriptors. Returns pointer past last consumed descriptor. +static const uint8_t* midih2_parse_descriptors_alt1(midih2_interface_t *p_midi, const tusb_desc_interface_t *desc_itf, const uint8_t *desc_end) { - TU_VERIFY(AUDIO_SUBCLASS_MIDI_STREAMING == desc_itf->bInterfaceSubClass,); - TU_VERIFY(desc_itf->bAlternateSetting == 1,); + TU_VERIFY(AUDIO_SUBCLASS_MIDI_STREAMING == desc_itf->bInterfaceSubClass, NULL); + TU_VERIFY(desc_itf->bAlternateSetting == 1, NULL); const uint8_t *p_desc = (const uint8_t *) desc_itf; p_desc = tu_desc_next(p_desc); uint8_t rx_cable_count = 0; uint8_t tx_cable_count = 0; + bool found_new_interface = false; - while (tu_desc_in_bounds(p_desc, desc_end)) { - if (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) { - break; - } - - if (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE) { - if (tu_desc_subtype(p_desc) == MIDI_CS_INTERFACE_HEADER) { - const uint8_t *bcd_ptr = p_desc + 3; - p_midi->bcdMSC_lo = bcd_ptr[0]; - p_midi->bcdMSC_hi = bcd_ptr[1]; + while (tu_desc_in_bounds(p_desc, desc_end) && !found_new_interface) { + switch (tu_desc_type(p_desc)) { + case TUSB_DESC_INTERFACE: + found_new_interface = true; + break; - if (p_midi->bcdMSC_hi == 0x02) { - p_midi->protocol_version = 1; + case TUSB_DESC_CS_INTERFACE: + if (tu_desc_subtype(p_desc) == MIDI_CS_INTERFACE_HEADER) { + // bcdMSC at offset 3-4 in CS Interface Header + const uint8_t *bcd_ptr = p_desc + 3; + p_midi->bcdMSC_lo = bcd_ptr[0]; + p_midi->bcdMSC_hi = bcd_ptr[1]; + if (p_midi->bcdMSC_hi == 0x02) { // bcdMSC 0x0200 = USB-MIDI 2.0 + p_midi->protocol_version = 1; + } } - } - } - - if (tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT) { - const tusb_desc_endpoint_t *p_ep = (const tusb_desc_endpoint_t *) p_desc; - p_desc = tu_desc_next(p_desc); + break; - if (tu_desc_in_bounds(p_desc, desc_end) && tu_desc_type(p_desc) == TUSB_DESC_CS_ENDPOINT) { - const midi_desc_cs_endpoint_t *p_csep = (const midi_desc_cs_endpoint_t *) p_desc; + case TUSB_DESC_ENDPOINT: { + const tusb_desc_endpoint_t *p_ep = (const tusb_desc_endpoint_t *) p_desc; + p_desc = tu_desc_next(p_desc); - if (tu_edpt_dir(p_ep->bEndpointAddress) == TUSB_DIR_OUT) { - tx_cable_count = p_csep->bNumEmbMIDIJack; - } else { - rx_cable_count = p_csep->bNumEmbMIDIJack; + if (tu_desc_in_bounds(p_desc, desc_end) && tu_desc_type(p_desc) == TUSB_DESC_CS_ENDPOINT) { + // MIDI 2.0 CS Endpoint General 2.0: bNumGrpTrmBlk at offset 3 + if (p_desc[0] >= 4 && p_desc[2] == MIDI_CS_ENDPOINT_GENERAL_2_0) { + uint8_t num_grp_trm_blk = p_desc[3]; + if (tu_edpt_dir(p_ep->bEndpointAddress) == TUSB_DIR_OUT) { + tx_cable_count = num_grp_trm_blk; + } else { + rx_cable_count = num_grp_trm_blk; + } + } } + break; } + + default: + break; } - p_desc = tu_desc_next(p_desc); + if (!found_new_interface) { + p_desc = tu_desc_next(p_desc); + } } p_midi->rx_cable_count_alt1 = rx_cable_count; p_midi->tx_cable_count_alt1 = tx_cable_count; + return p_desc; } //--------------------------------------------------------------------+ @@ -327,33 +348,20 @@ uint16_t midih2_open(uint8_t rhport, uint8_t dev_addr, const tusb_desc_interface desc_itf->bInterfaceNumber, desc_itf->bAlternateSetting, dev_addr); // Dispatch to appropriate parser based on Alt Setting + const uint8_t *p_end = NULL; if (desc_itf->bAlternateSetting == 0) { - midih2_parse_descriptors_alt0(p_midi, desc_itf, desc_end); + p_end = midih2_parse_descriptors_alt0(p_midi, desc_itf, desc_end); } else if (desc_itf->bAlternateSetting == 1) { - midih2_parse_descriptors_alt1(p_midi, desc_itf, desc_end); + p_end = midih2_parse_descriptors_alt1(p_midi, desc_itf, desc_end); } - return max_len; + // Return number of bytes consumed (following midi_host.c pattern) + uint16_t const parsed_len = (p_end != NULL) ? (uint16_t)(p_end - desc_start) : 0; + return parsed_len; } -bool midih2_set_config(uint8_t dev_addr, uint8_t itf_num) { - uint8_t idx = 0; - for (idx = 0; idx < CFG_TUH_MIDI2; idx++) { - if (_midi2_host[idx].daddr == dev_addr && _midi2_host[idx].bInterfaceNumber == itf_num) { - break; - } - } - - if (idx >= CFG_TUH_MIDI2) { - // Not our interface (e.g. Audio Control) - pass through to next - usbh_driver_set_config_complete(dev_addr, itf_num); - return true; - } - - midih2_interface_t *p_midi = &_midi2_host[idx]; - - // Auto-select alt setting - midih2_auto_select_alt_setting(p_midi); +static void midih2_set_config_complete(midih2_interface_t *p_midi, uint8_t idx) { + uint8_t dev_addr = p_midi->daddr; // Invoke descriptor_cb tuh_midi2_descriptor_cb_t desc_cb = { @@ -374,7 +382,7 @@ bool midih2_set_config(uint8_t dev_addr, uint8_t itf_num) { // Invoke mount_cb tuh_midi2_mount_cb_t mount_cb = { - .daddr = p_midi->daddr, + .daddr = dev_addr, .bInterfaceNumber = p_midi->bInterfaceNumber, .protocol_version = p_midi->protocol_version, .alt_setting_active = p_midi->alt_setting_current, @@ -387,7 +395,56 @@ bool midih2_set_config(uint8_t dev_addr, uint8_t itf_num) { tu_edpt_stream_read_xfer(&p_midi->ep_stream.rx); // Signal USBH that configuration is complete - usbh_driver_set_config_complete(dev_addr, itf_num); + usbh_driver_set_config_complete(dev_addr, p_midi->bInterfaceNumber); +} + +static void midih2_set_interface_cb(tuh_xfer_t *xfer) { + uint8_t const dev_addr = xfer->daddr; + uint8_t const itf_num = (uint8_t) tu_le16toh(xfer->setup->wIndex); + + // Find our interface + for (uint8_t idx = 0; idx < CFG_TUH_MIDI2; idx++) { + if (_midi2_host[idx].daddr == dev_addr && _midi2_host[idx].bInterfaceNumber == itf_num) { + if (xfer->result == XFER_RESULT_SUCCESS) { + midih2_set_config_complete(&_midi2_host[idx], idx); + } else { + // SET_INTERFACE failed, fall back to alt 0 + TU_LOG_DRV("MIDI2 SET_INTERFACE failed, falling back to alt 0\r\n"); + _midi2_host[idx].alt_setting_current = 0; + midih2_set_config_complete(&_midi2_host[idx], idx); + } + return; + } + } +} + +bool midih2_set_config(uint8_t dev_addr, uint8_t itf_num) { + uint8_t idx = 0; + for (idx = 0; idx < CFG_TUH_MIDI2; idx++) { + if (_midi2_host[idx].daddr == dev_addr && _midi2_host[idx].bInterfaceNumber == itf_num) { + break; + } + } + + if (idx >= CFG_TUH_MIDI2) { + // Not our interface (e.g. Audio Control) - pass through to next + usbh_driver_set_config_complete(dev_addr, itf_num); + return true; + } + + midih2_interface_t *p_midi = &_midi2_host[idx]; + + // Auto-select alt setting + midih2_auto_select_alt_setting(p_midi); + + // If MIDI 2.0 detected, issue SET_INTERFACE to activate Alt Setting 1 + if (p_midi->alt_setting_current == 1) { + TU_LOG_DRV("MIDI2 requesting SET_INTERFACE alt 1 for itf %u\r\n", itf_num); + TU_ASSERT(tuh_interface_set(dev_addr, itf_num, 1, midih2_set_interface_cb, 0)); + } else { + // MIDI 1.0 only, complete immediately + midih2_set_config_complete(p_midi, idx); + } return true; } diff --git a/src/device/usbd.h b/src/device/usbd.h index af37eff56..a9f4c5f08 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -429,18 +429,20 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ //--------------------------------------------------------------------+ // Alt Setting 1: MS Interface + MS Header (bcdMSC=0x0200) +// wTotalLength covers MS Header + all CS Endpoint descriptors +#define TUD_MIDI2_DESC_ALT1_CS_LEN(_numgtbs) (7 + (4 + (_numgtbs)) * 2) #define TUD_MIDI2_DESC_ALT1_HEAD_LEN (9 + 7) -#define TUD_MIDI2_DESC_ALT1_HEAD(_itfnum, _stridx) \ +#define TUD_MIDI2_DESC_ALT1_HEAD(_itfnum, _stridx, _numgtbs) \ /* MIDI Streaming Interface, Alt Setting 1 */\ - 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum) + 1), 1, 2, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_MIDI_STREAMING, AUDIO_FUNC_PROTOCOL_CODE_UNDEF, _stridx,\ - /* MS Header (MIDI 2.0) */\ - 7, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_HEADER, U16_TO_U8S_LE(0x0200), U16_TO_U8S_LE(7) + 9, TUSB_DESC_INTERFACE, (uint8_t)((_itfnum) + 1), 1, 2, TUSB_CLASS_AUDIO, AUDIO_SUBCLASS_MIDI_STREAMING, AUDIO_FUNC_PROTOCOL_CODE_UNDEF, 0,\ + /* MS Header (MIDI 2.0): wTotalLength = header + 2x CS Endpoint */\ + 7, TUSB_DESC_CS_INTERFACE, MIDI_CS_INTERFACE_HEADER, U16_TO_U8S_LE(0x0200), U16_TO_U8S_LE(TUD_MIDI2_DESC_ALT1_CS_LEN(_numgtbs)) -// Alt Setting 1: Standard USB Endpoint (7 bytes) + CS Endpoint (subtype 0x02) +// Alt Setting 1: Standard USB Endpoint (7 bytes) + CS Endpoint General 2.0 #define TUD_MIDI2_DESC_ALT1_EP_LEN(_numgtbs) (7 + 4 + (_numgtbs)) -#define TUD_MIDI2_DESC_ALT1_EP(_ep, _epsize, _numgtbs) \ +#define TUD_MIDI2_DESC_ALT1_EP(_ep, _epsize, _numgtbs, ...) \ 7, TUSB_DESC_ENDPOINT, _ep, TUSB_XFER_BULK, U16_TO_U8S_LE(_epsize), 0, \ - (uint8_t)(4 + (_numgtbs)), TUSB_DESC_CS_ENDPOINT, MIDI_CS_ENDPOINT_GENERAL_2_0, _numgtbs + (uint8_t)(4 + (_numgtbs)), TUSB_DESC_CS_ENDPOINT, MIDI_CS_ENDPOINT_GENERAL_2_0, _numgtbs, ## __VA_ARGS__ // Total length: Alt 0 (MIDI 1.0) + Alt 1 (UMP) #define TUD_MIDI2_DESC_LEN (TUD_MIDI_DESC_LEN + TUD_MIDI2_DESC_ALT1_HEAD_LEN + TUD_MIDI2_DESC_ALT1_EP_LEN(1) * 2) @@ -455,11 +457,9 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ TUD_MIDI_DESC_EP(_epin, _epsize, 1),\ TUD_MIDI_JACKID_OUT_EMB(1),\ /* Alt Setting 1 (UMP) */\ - TUD_MIDI2_DESC_ALT1_HEAD(_itfnum, _stridx),\ - TUD_MIDI2_DESC_ALT1_EP(_epout, _epsize, 1),\ - 1, /* bAssoGrpTrmBlkID = 1 */\ - TUD_MIDI2_DESC_ALT1_EP(_epin, _epsize, 1),\ - 1 /* bAssoGrpTrmBlkID = 1 */ + TUD_MIDI2_DESC_ALT1_HEAD(_itfnum, _stridx, 1),\ + TUD_MIDI2_DESC_ALT1_EP(_epout, _epsize, 1, 1 /* bAssoGrpTrmBlkID */),\ + TUD_MIDI2_DESC_ALT1_EP(_epin, _epsize, 1, 1 /* bAssoGrpTrmBlkID */) //--------------------------------------------------------------------+ // Audio Descriptor Templates |
