diff options
| author | Saulo VerĂssimo <[email protected]> | 2026-04-22 18:04:56 -0300 |
|---|---|---|
| committer | Saulo VerĂssimo <[email protected]> | 2026-05-12 11:07:45 -0300 |
| commit | 97852816e873bf7f91f3a81f093ad08f96179656 (patch) | |
| tree | 2674623ed18af99f131b31f03f713705e5fd5bd1 /src/class | |
| parent | 0c68ca8c1de45e24ae022ab58934c6930bad7b4b (diff) | |
midi2: align descriptors with USB-MIDI 2.0 spec
Brings the MIDI 2.0 device driver into full conformance with USB
Device Class Definition for MIDI Devices v2.0 (USB-IF, May 2020).
- Alt 1 MS Interface Header wTotalLength now reports 0x0007 per
Table 5-2 ("set to match bLength"), replacing the prior 0x0011
carried over from USB-MIDI 1.0 conventions.
- GET_DESCRIPTOR class request now validates bmRequestType direction,
type and recipient plus wIndex and wValue high byte per Section 6.
- iBlockItem in the default Group Terminal Block is driven by
CFG_TUD_MIDI2_BLOCK_STRIDX so applications can attach a UI string
descriptor to the block per Table 5-6.
- UMP word byte order assumption (little-endian host per Section
3.2.2) is documented inline so future big-endian ports know where
to wrap access with tu_htole32 / tu_le32toh.
Validated on RP2040 and ESP32-P4 under Linux kernel 6.17: lsusb -v
reports wTotalLength = 0x0007 on Alt 1 MS Header (raw bytes
07 24 01 00 02 07 00). amidi -l enumerates Group Terminals exposed
via the class-specific GET_DESCRIPTOR response.
Diffstat (limited to 'src/class')
| -rw-r--r-- | src/class/midi/midi2_device.c | 45 |
1 files changed, 33 insertions, 12 deletions
diff --git a/src/class/midi/midi2_device.c b/src/class/midi/midi2_device.c index 34e467fc6..15daad096 100644 --- a/src/class/midi/midi2_device.c +++ b/src/class/midi/midi2_device.c @@ -44,6 +44,16 @@ TU_ATTR_WEAK bool tud_midi2_get_req_itf_cb(uint8_t rhport, const tusb_control_re } //--------------------------------------------------------------------+ +// Byte order note +//--------------------------------------------------------------------+ +// Per USB-MIDI 2.0 Section 3.2.2, each 32-bit UMP word is transmitted with the +// least significant byte first. This driver reads and writes UMP words as +// native uint32_t through tu_edpt_stream_read/write. All TinyUSB targets are +// little-endian, so the in-memory layout already matches the wire order and no +// swap is needed. If a big-endian target is ever supported, wrap access with +// tu_htole32 / tu_le32toh at the buffer boundary. + +//--------------------------------------------------------------------+ // UMP Stream Message Constants //--------------------------------------------------------------------+ // UMP Message Type for Stream messages (bits 31:28) @@ -133,7 +143,7 @@ static const uint8_t _default_gtb_desc[] = { 0x00, // bGrpTrmBlkType: bidirectional 0x00, // nGroupTrm: first group (0) CFG_TUD_MIDI2_NUM_GROUPS, // nNumGroupTrm - 0, // iBlockItem: no string + CFG_TUD_MIDI2_BLOCK_STRIDX, // iBlockItem: string descriptor index (0 = none) 0x00, // bMIDIProtocol: unknown/not fixed 0, 0, // wMaxInputBandwidth: unknown 0, 0 // wMaxOutputBandwidth: unknown @@ -554,19 +564,30 @@ bool midi2d_control_xfer_cb(uint8_t rhport, uint8_t stage, const tusb_control_re } case TUSB_REQ_GET_DESCRIPTOR: { - // wValue: descriptor type (high) | index (low) - // 0x26 = CS_GRP_TRM_BLOCK, index 0x01 - if (request->wValue == ((uint16_t)MIDI2_CS_GRP_TRM_BLOCK << 8 | 0x01)) { - if (tud_midi2_get_req_itf_cb(rhport, request)) return true; + // USB-MIDI 2.0 Section 6: GTB descriptor retrieval + // bmRequestType = 0x81 (Device-to-Host, Standard, Interface) + // wValue = CS_GR_TRM_BLOCK (0x26) in high byte, alt setting in low byte + // wIndex = interface number + if (request->bmRequestType_bit.direction != TUSB_DIR_IN) return false; + if (request->bmRequestType_bit.type != TUSB_REQ_TYPE_STANDARD) return false; + if (request->bmRequestType_bit.recipient != TUSB_REQ_RCPT_INTERFACE) return false; + if (tu_u16_high(request->wValue) != MIDI2_CS_GRP_TRM_BLOCK) return false; - uint16_t len = request->wLength; - if (len > sizeof(_default_gtb_desc)) { - len = sizeof(_default_gtb_desc); - } - tud_control_xfer(rhport, request, (void*)(uintptr_t) _default_gtb_desc, len); - return true; + uint8_t itf_num = tu_u16_low(request->wIndex); + uint8_t idx = find_midi2_itf_by_num(itf_num); + if (idx >= CFG_TUD_MIDI2) return false; + + // Only Alt Setting 1 exposes Group Terminal Block descriptors. + if (tu_u16_low(request->wValue) != 0x01) return false; + + if (tud_midi2_get_req_itf_cb(rhport, request)) return true; + + uint16_t len = request->wLength; + if (len > sizeof(_default_gtb_desc)) { + len = sizeof(_default_gtb_desc); } - return false; + tud_control_xfer(rhport, request, (void*)(uintptr_t) _default_gtb_desc, len); + return true; } default: |
