← Documents Documentation/sound/designs/midi-2.0.rst GitHub 원문 ↗

Linux 6.18.37 · Sound

Linux의 MIDI 2.0

Linux MIDI 2.0의 UMP rawmidi·sequencer ABI, Endpoint·Function Block 정보, MIDI 1.0/2.0 자동 변환과 configfs USB gadget 설정을 설명합니다.

Source pathDocumentation/sound/designs/midi-2.0.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

midi-2.0.rst:1-584

Linux MIDI 2.0의 UMP rawmidi·sequencer ABI, Endpoint·Function Block 정보, MIDI 1.0/2.0 자동 변환과 configfs USB gadget 설정을 설명합니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 =================
2 MIDI 2.0 on Linux
3 =================
4
5 General
6 =======
7
8 MIDI 2.0 is an extended protocol for providing higher resolutions and
9 more fine controls over the legacy MIDI 1.0. The fundamental changes
10 introduced for supporting MIDI 2.0 are:
11
12 - Support of Universal MIDI Packet (UMP)
13 - Support of MIDI 2.0 protocol messages
14 - Transparent conversions between UMP and legacy MIDI 1.0 byte stream
15 - MIDI-CI for property and profile configurations
16
17 UMP is a new container format to hold all MIDI protocol 1.0 and MIDI
18 2.0 protocol messages. Unlike the former byte stream, it's 32bit
19 aligned, and each message can be put in a single packet. UMP can send
20 the events up to 16 "UMP Groups", where each UMP Group contain up to
21 16 MIDI channels.
22
23 MIDI 2.0 protocol is an extended protocol to achieve the higher
24 resolution and more controls over the old MIDI 1.0 protocol.
25
26 MIDI-CI is a high-level protocol that can talk with the MIDI device
27 for the flexible profiles and configurations. It's represented in the
28 form of special SysEx.
29
30 For Linux implementations, the kernel supports the UMP transport and
31 the encoding/decoding of MIDI protocols on UMP, while MIDI-CI is
32 supported in user-space over the standard SysEx.
33
34 As of this writing, only USB MIDI device supports the UMP and Linux
35 2.0 natively. The UMP support itself is pretty generic, hence it
36 could be used by other transport layers, although it could be
37 implemented differently (e.g. as a ALSA sequencer client), too.
38
39 The access to UMP devices are provided in two ways: the access via
40 rawmidi device and the access via ALSA sequencer API.
41
42 ALSA sequencer API was extended to allow the payload of UMP packets.
43 It's allowed to connect freely between MIDI 1.0 and MIDI 2.0 sequencer
44 clients, and the events are converted transparently.
45
46
47 Kernel Configuration
48 ====================
49
50 The following new configs are added for supporting MIDI 2.0:
51 `CONFIG_SND_UMP`, `CONFIG_SND_UMP_LEGACY_RAWMIDI`,
52 `CONFIG_SND_SEQ_UMP`, `CONFIG_SND_SEQ_UMP_CLIENT`, and
53 `CONFIG_SND_USB_AUDIO_MIDI_V2`. The first visible one is
54 `CONFIG_SND_USB_AUDIO_MIDI_V2`, and when you choose it (to set `=y`),
55 the core support for UMP (`CONFIG_SND_UMP`) and the sequencer binding
56 (`CONFIG_SND_SEQ_UMP_CLIENT`) will be automatically selected.
57
58 Additionally, `CONFIG_SND_UMP_LEGACY_RAWMIDI=y` will enable the
59 support for the legacy raw MIDI device for UMP Endpoints.
60
61
62 Rawmidi Device with USB MIDI 2.0
63 ================================
64
65 When a device supports MIDI 2.0, the USB-audio driver probes and uses
66 the MIDI 2.0 interface (that is found always at the altset 1) as
67 default instead of the MIDI 1.0 interface (at altset 0). You can
68 switch back to the binding with the old MIDI 1.0 interface by passing
69 `midi2_enable=0` option to snd-usb-audio driver module, too.
70
71 The USB audio driver tries to query the UMP Endpoint and UMP Function
72 Block information that are provided since UMP v1.1, and builds up the
73 topology based on those information. When the device is older and
74 doesn't respond to the new UMP inquiries, the driver falls back and
75 builds the topology based on Group Terminal Block (GTB) information
76 from the USB descriptor. Some device might be screwed up by the
77 unexpected UMP command; in such a case, pass `midi2_ump_probe=0`
78 option to snd-usb-audio driver for skipping the UMP v1.1 inquiries.
79
80 When the MIDI 2.0 device is probed, the kernel creates a rawmidi
81 device for each UMP Endpoint of the device. Its device name is
82 `/dev/snd/umpC*D*` and different from the standard rawmidi device name
83 `/dev/snd/midiC*D*` for MIDI 1.0, in order to avoid confusing the
84 legacy applications accessing mistakenly to UMP devices.
85
86 You can read and write UMP packet data directly from/to this UMP
87 rawmidi device. For example, reading via `hexdump` like below will
88 show the incoming UMP packets of the card 0 device 0 in the hex
89 format::
90
91 % hexdump -C /dev/snd/umpC0D0
92 00000000 01 07 b0 20 00 07 b0 20 64 3c 90 20 64 3c 80 20 |... ... d<. d<. |
93
94 Unlike the MIDI 1.0 byte stream, UMP is a 32bit packet, and the size
95 for reading or writing the device is also aligned to 32bit (which is 4
96 bytes).
97
98 The 32-bit words in the UMP packet payload are always in CPU native
99 endianness. Transport drivers are responsible to convert UMP words
100 from / to system endianness to required transport endianness / byte
101 order.
102
103 When `CONFIG_SND_UMP_LEGACY_RAWMIDI` is set, the driver creates
104 another standard raw MIDI device additionally as `/dev/snd/midiC*D*`.
105 This contains 16 substreams, and each substream corresponds to a
106 (0-based) UMP Group. Legacy applications can access to the specified
107 group via each substream in MIDI 1.0 byte stream format. With the
108 ALSA rawmidi API, you can open the arbitrary substream, while just
109 opening `/dev/snd/midiC*D*` will end up with opening the first
110 substream.
111
112 Each UMP Endpoint can provide the additional information, constructed
113 from the information inquired via UMP 1.1 Stream messages or USB MIDI
114 2.0 descriptors. And a UMP Endpoint may contain one or more UMP
115 Blocks, where UMP Block is an abstraction introduced in the ALSA UMP
116 implementations to represent the associations among UMP Groups. UMP
117 Block corresponds to Function Block in UMP 1.1 specification. When
118 UMP 1.1 Function Block information isn't available, it's filled
119 partially from Group Terminal Block (GTB) as defined in USB MIDI 2.0
120 specifications.
121
122 The information of UMP Endpoints and UMP Blocks are found in the proc
123 file `/proc/asound/card*/midi*`. For example::
124
125 % cat /proc/asound/card1/midi0
126 ProtoZOA MIDI
127
128 Type: UMP
129 EP Name: ProtoZOA
130 EP Product ID: ABCD12345678
131 UMP Version: 0x0000
132 Protocol Caps: 0x00000100
133 Protocol: 0x00000100
134 Num Blocks: 3
135
136 Block 0 (ProtoZOA Main)
137 Direction: bidirection
138 Active: Yes
139 Groups: 1-1
140 Is MIDI1: No
141
142 Block 1 (ProtoZOA Ext IN)
143 Direction: output
144 Active: Yes
145 Groups: 2-2
146 Is MIDI1: Yes (Low Speed)
147 ....
148
149 Note that `Groups` field shown in the proc file above indicates the
150 1-based UMP Group numbers (from-to).
151
152 Those additional UMP Endpoint and UMP Block information can be
153 obtained via the new ioctls `SNDRV_UMP_IOCTL_ENDPOINT_INFO` and
154 `SNDRV_UMP_IOCTL_BLOCK_INFO`, respectively.
155
156 The rawmidi name and the UMP Endpoint name are usually identical, and
157 in the case of USB MIDI, it's taken from `iInterface` of the
158 corresponding USB MIDI interface descriptor. If it's not provided,
159 it's copied from `iProduct` of the USB device descriptor as a
160 fallback.
161
162 The Endpoint Product ID is a string field and supposed to be unique.
163 It's copied from `iSerialNumber` of the device for USB MIDI.
164
165 The protocol capabilities and the actual protocol bits are defined in
166 `asound.h`.
167
168
169 ALSA Sequencer with USB MIDI 2.0
170 ================================
171
172 In addition to the rawmidi interfaces, ALSA sequencer interface
173 supports the new UMP MIDI 2.0 device, too. Now, each ALSA sequencer
174 client may set its MIDI version (0, 1 or 2) to declare itself being
175 either the legacy, UMP MIDI 1.0 or UMP MIDI 2.0 device, respectively.
176 The first, legacy client is the one that sends/receives the old
177 sequencer event as was. Meanwhile, UMP MIDI 1.0 and 2.0 clients send
178 and receive in the extended event record for UMP. The MIDI version is
179 seen in the new `midi_version` field of `snd_seq_client_info`.
180
181 A UMP packet can be sent/received in a sequencer event embedded by
182 specifying the new event flag bit `SNDRV_SEQ_EVENT_UMP`. When this
183 flag is set, the event has 16 byte (128 bit) data payload for holding
184 the UMP packet. Without the `SNDRV_SEQ_EVENT_UMP` bit flag, the event
185 is treated as a legacy event as it was (with max 12 byte data
186 payload).
187
188 With `SNDRV_SEQ_EVENT_UMP` flag set, the type field of a UMP sequencer
189 event is ignored (but it should be set to 0 as default).
190
191 The type of each client can be seen in `/proc/asound/seq/clients`.
192 For example::
193
194 % cat /proc/asound/seq/clients
195 Client info
196 cur clients : 3
197 ....
198 Client 14 : "Midi Through" [Kernel Legacy]
199 Port 0 : "Midi Through Port-0" (RWe-)
200 Client 20 : "ProtoZOA" [Kernel UMP MIDI1]
201 UMP Endpoint: ProtoZOA
202 UMP Block 0: ProtoZOA Main [Active]
203 Groups: 1-1
204 UMP Block 1: ProtoZOA Ext IN [Active]
205 Groups: 2-2
206 UMP Block 2: ProtoZOA Ext OUT [Active]
207 Groups: 3-3
208 Port 0 : "MIDI 2.0" (RWeX) [In/Out]
209 Port 1 : "ProtoZOA Main" (RWeX) [In/Out]
210 Port 2 : "ProtoZOA Ext IN" (-We-) [Out]
211 Port 3 : "ProtoZOA Ext OUT" (R-e-) [In]
212
213 Here you can find two types of kernel clients, "Legacy" for client 14,
214 and "UMP MIDI1" for client 20, which is a USB MIDI 2.0 device.
215 A USB MIDI 2.0 client gives always the port 0 as "MIDI 2.0" and the
216 rest ports from 1 for each UMP Group (e.g. port 1 for Group 1).
217 In this example, the device has three active groups (Main, Ext IN and
218 Ext OUT), and those are exposed as sequencer ports from 1 to 3.
219 The "MIDI 2.0" port is for a UMP Endpoint, and its difference from
220 other UMP Group ports is that UMP Endpoint port sends the events from
221 the all ports on the device ("catch-all"), while each UMP Group port
222 sends only the events from the given UMP Group.
223 Also, UMP groupless messages (such as the UMP message type 0x0f) are
224 sent only to the UMP Endpoint port.
225
226 Note that, although each UMP sequencer client usually creates 16
227 ports, those ports that don't belong to any UMP Blocks (or belonging
228 to inactive UMP Blocks) are marked as inactive, and they don't appear
229 in the proc outputs. In the example above, the sequencer ports from 4
230 to 16 are present but not shown there.
231
232 The proc file above shows the UMP Block information, too. The same
233 entry (but with more detailed information) is found in the rawmidi
234 proc output.
235
236 When clients are connected between different MIDI versions, the events
237 are translated automatically depending on the client's version, not
238 only between the legacy and the UMP MIDI 1.0/2.0 types, but also
239 between UMP MIDI 1.0 and 2.0 types, too. For example, running
240 `aseqdump` program on the ProtoZOA Main port in the legacy mode will
241 give you the output like::
242
243 % aseqdump -p 20:1
244 Waiting for data. Press Ctrl+C to end.
245 Source Event Ch Data
246 20:1 Note on 0, note 60, velocity 100
247 20:1 Note off 0, note 60, velocity 100
248 20:1 Control change 0, controller 11, value 4
249
250 When you run `aseqdump` in MIDI 2.0 mode, it'll receive the high
251 precision data like::
252
253 % aseqdump -u 2 -p 20:1
254 Waiting for data. Press Ctrl+C to end.
255 Source Event Ch Data
256 20:1 Note on 0, note 60, velocity 0xc924, attr type = 0, data = 0x0
257 20:1 Note off 0, note 60, velocity 0xc924, attr type = 0, data = 0x0
258 20:1 Control change 0, controller 11, value 0x2000000
259
260 while the data is automatically converted by ALSA sequencer core.
261
262
263 Rawmidi API Extensions
264 ======================
265
266 * The additional UMP Endpoint information can be obtained via the new
267 ioctl `SNDRV_UMP_IOCTL_ENDPOINT_INFO`. It contains the associated
268 card and device numbers, the bit flags, the protocols, the number of
269 UMP Blocks, the name string of the endpoint, etc.
270
271 The protocols are specified in two field, the protocol capabilities
272 and the current protocol. Both contain the bit flags specifying the
273 MIDI protocol version (`SNDRV_UMP_EP_INFO_PROTO_MIDI1` or
274 `SNDRV_UMP_EP_INFO_PROTO_MIDI2`) in the upper byte and the jitter
275 reduction timestamp (`SNDRV_UMP_EP_INFO_PROTO_JRTS_TX` and
276 `SNDRV_UMP_EP_INFO_PROTO_JRTS_RX`) in the lower byte.
277
278 A UMP Endpoint may contain up to 32 UMP Blocks, and the number of
279 the currently assigned blocks are shown in the Endpoint information.
280
281 * Each UMP Block information can be obtained via another new ioctl
282 `SNDRV_UMP_IOCTL_BLOCK_INFO`. The block ID number (0-based) has to
283 be passed for the block to query. The received data contains the
284 associated the direction of the block, the first associated group ID
285 (0-based) and the number of groups, the name string of the block,
286 etc.
287
288 The direction is either `SNDRV_UMP_DIR_INPUT`,
289 `SNDRV_UMP_DIR_OUTPUT` or `SNDRV_UMP_DIR_BIDIRECTION`.
290
291 * For the device supports UMP v1.1, the UMP MIDI protocol can be
292 switched via "Stream Configuration Request" message (UMP type 0x0f,
293 status 0x05). When UMP core receives such a message, it updates the
294 UMP EP info and the corresponding sequencer clients as well.
295
296 * The legacy rawmidi device number is found in the new `tied_device`
297 field of the rawmidi info.
298 On the other hand, the UMP rawmidi device number is found in
299 `tied_device` field of the legacy rawmidi info, too.
300
301 * Each substream of the legacy rawmidi may be enabled / disabled
302 dynamically depending on the UMP FB state.
303 When the selected substream is inactive, it's indicated by the bit
304 0x10 (`SNDRV_RAWMIDI_INFO_STREAM_INACTIVE`) in the `flags` field of
305 the legacy rawmidi info.
306
307
308 Control API Extensions
309 ======================
310
311 * The new ioctl `SNDRV_CTL_IOCTL_UMP_NEXT_DEVICE` is introduced for
312 querying the next UMP rawmidi device, while the existing ioctl
313 `SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE` queries only the legacy
314 rawmidi devices.
315
316 For setting the subdevice (substream number) to be opened, use the
317 ioctl `SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE` like the normal
318 rawmidi.
319
320 * Two new ioctls `SNDRV_CTL_IOCTL_UMP_ENDPOINT_INFO` and
321 `SNDRV_CTL_IOCTL_UMP_BLOCK_INFO` provide the UMP Endpoint and UMP
322 Block information of the specified UMP device via ALSA control API
323 without opening the actual (UMP) rawmidi device.
324 The `card` field is ignored upon inquiry, always tied with the card
325 of the control interface.
326
327
328 Sequencer API Extensions
329 ========================
330
331 * `midi_version` field is added to `snd_seq_client_info` to indicate
332 the current MIDI version (either 0, 1 or 2) of each client.
333 When `midi_version` is 1 or 2, the alignment of read from a UMP
334 sequencer client is also changed from the former 28 bytes to 32
335 bytes for the extended payload. The alignment size for the write
336 isn't changed, but each event size may differ depending on the new
337 bit flag below.
338
339 * `SNDRV_SEQ_EVENT_UMP` flag bit is added for each sequencer event
340 flags. When this bit flag is set, the sequencer event is extended
341 to have a larger payload of 16 bytes instead of the legacy 12
342 bytes, and the event contains the UMP packet in the payload.
343
344 * The new sequencer port type bit (`SNDRV_SEQ_PORT_TYPE_MIDI_UMP`)
345 indicates the port being UMP-capable.
346
347 * The sequencer ports have new capability bits to indicate the
348 inactive ports (`SNDRV_SEQ_PORT_CAP_INACTIVE`) and the UMP Endpoint
349 port (`SNDRV_SEQ_PORT_CAP_UMP_ENDPOINT`).
350
351 * The event conversion of ALSA sequencer clients can be suppressed the
352 new filter bit `SNDRV_SEQ_FILTER_NO_CONVERT` set to the client info.
353 For example, the kernel pass-through client (`snd-seq-dummy`) sets
354 this flag internally.
355
356 * The port information gained the new field `direction` to indicate
357 the direction of the port (either `SNDRV_SEQ_PORT_DIR_INPUT`,
358 `SNDRV_SEQ_PORT_DIR_OUTPUT` or `SNDRV_SEQ_PORT_DIR_BIDIRECTION`).
359
360 * Another additional field for the port information is `ump_group`
361 which specifies the associated UMP Group Number (1-based).
362 When it's non-zero, the UMP group field in the UMP packet updated
363 upon delivery to the specified group (corrected to be 0-based).
364 Each sequencer port is supposed to set this field if it's a port to
365 specific to a certain UMP group.
366
367 * Each client may set the additional event filter for UMP Groups in
368 `group_filter` bitmap. The filter consists of bitmap from 1-based
369 Group numbers. For example, when the bit 1 is set, messages from
370 Group 1 (i.e. the very first group) are filtered and not delivered.
371 The bit 0 is used for filtering UMP groupless messages.
372
373 * Two new ioctls are added for UMP-capable clients:
374 `SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO` and
375 `SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO`. They are used to get and set
376 either `snd_ump_endpoint_info` or `snd_ump_block_info` data
377 associated with the sequencer client. The USB MIDI driver provides
378 those information from the underlying UMP rawmidi, while a
379 user-space client may provide its own data via `*_SET` ioctl.
380 For an Endpoint data, pass 0 to the `type` field, while for a Block
381 data, pass the block number + 1 to the `type` field.
382 Setting the data for a kernel client shall result in an error.
383
384 * With UMP 1.1, Function Block information may be changed
385 dynamically. When the update of Function Block is received from the
386 device, ALSA sequencer core changes the corresponding sequencer port
387 name and attributes accordingly, and notifies the changes via the
388 announcement to the ALSA sequencer system port, similarly like the
389 normal port change notification.
390
391 * There are two extended event types for notifying the UMP Endpoint and
392 Function Block changes via the system announcement port:
393 type 68 (`SNDRV_SEQ_EVENT_UMP_EP_CHANGE`) and type 69
394 (`SNDRV_SEQ_EVENT_UMP_BLOCK_CHANGE`). They take the new type,
395 `snd_seq_ev_ump_notify` in the payload, indicating the client number
396 and the FB number that are changed.
397
398
399 MIDI2 USB Gadget Function Driver
400 ================================
401
402 The latest kernel contains the support for USB MIDI 2.0 gadget
403 function driver, which can be used for prototyping and debugging MIDI
404 2.0 features.
405
406 `CONFIG_USB_GADGET`, `CONFIG_USB_CONFIGFS` and
407 `CONFIG_USB_CONFIGFS_F_MIDI2` need to be enabled for the MIDI2 gadget
408 driver.
409
410 In addition, for using a gadget driver, you need a working UDC driver.
411 In the example below, we use `dummy_hcd` driver (enabled via
412 `CONFIG_USB_DUMMY_HCD`) that is available on PC and VM for debugging
413 purpose. There are other UDC drivers depending on the platform, and
414 those can be used for a real device, instead, too.
415
416 At first, on a system to run the gadget, load `libcomposite` module::
417
418 % modprobe libcomposite
419
420 and you'll have `usb_gadget` subdirectory under configfs space
421 (typically `/sys/kernel/config` on modern OS). Then create a gadget
422 instance and add configurations there, for example::
423
424 % cd /sys/kernel/config
425 % mkdir usb_gadget/g1
426
427 % cd usb_gadget/g1
428 % mkdir configs/c.1
429 % mkdir functions/midi2.usb0
430
431 % echo 0x0004 > idProduct
432 % echo 0x17b3 > idVendor
433 % mkdir strings/0x409
434 % echo "ACME Enterprises" > strings/0x409/manufacturer
435 % echo "ACMESynth" > strings/0x409/product
436 % echo "ABCD12345" > strings/0x409/serialnumber
437
438 % mkdir configs/c.1/strings/0x409
439 % echo "Monosynth" > configs/c.1/strings/0x409/configuration
440 % echo 120 > configs/c.1/MaxPower
441
442 At this point, there must be a subdirectory `ep.0`, and that is the
443 configuration for a UMP Endpoint. You can fill the Endpoint
444 information like::
445
446 % echo "ACMESynth" > functions/midi2.usb0/iface_name
447 % echo "ACMESynth" > functions/midi2.usb0/ep.0/ep_name
448 % echo "ABCD12345" > functions/midi2.usb0/ep.0/product_id
449 % echo 0x0123 > functions/midi2.usb0/ep.0/family
450 % echo 0x4567 > functions/midi2.usb0/ep.0/model
451 % echo 0x123456 > functions/midi2.usb0/ep.0/manufacturer
452 % echo 0x12345678 > functions/midi2.usb0/ep.0/sw_revision
453
454 The default MIDI protocol can be set either 1 or 2::
455
456 % echo 2 > functions/midi2.usb0/ep.0/protocol
457
458 And, you can find a subdirectory `block.0` under this Endpoint
459 subdirectory. This defines the Function Block information::
460
461 % echo "Monosynth" > functions/midi2.usb0/ep.0/block.0/name
462 % echo 0 > functions/midi2.usb0/ep.0/block.0/first_group
463 % echo 1 > functions/midi2.usb0/ep.0/block.0/num_groups
464
465 Finally, link the configuration and enable it::
466
467 % ln -s functions/midi2.usb0 configs/c.1
468 % echo dummy_udc.0 > UDC
469
470 where `dummy_udc.0` is an example case and it differs depending on the
471 system. You can find the UDC instances in `/sys/class/udc` and pass
472 the found name instead::
473
474 % ls /sys/class/udc
475 dummy_udc.0
476
477 Now, the MIDI 2.0 gadget device is enabled, and the gadget host
478 creates a new sound card instance containing a UMP rawmidi device by
479 `f_midi2` driver::
480
481 % cat /proc/asound/cards
482 ....
483 1 [Gadget ]: f_midi2 - MIDI 2.0 Gadget
484 MIDI 2.0 Gadget
485
486 And on the connected host, a similar card should appear, too, but with
487 the card and device names given in the configfs above::
488
489 % cat /proc/asound/cards
490 ....
491 2 [ACMESynth ]: USB-Audio - ACMESynth
492 ACME Enterprises ACMESynth at usb-dummy_hcd.0-1, high speed
493
494 You can play a MIDI file on the gadget side::
495
496 % aplaymidi -p 20:1 to_host.mid
497
498 and this will appear as an input from a MIDI device on the connected
499 host::
500
501 % aseqdump -p 20:0 -u 2
502
503 Vice versa, a playback on the connected host will work as an input on
504 the gadget, too.
505
506 Each Function Block may have different direction and UI-hint,
507 specified via `direction` and `ui_hint` attributes.
508 Passing `1` is for input-only, `2` for out-only and `3` for
509 bidirectional (the default value). For example::
510
511 % echo 2 > functions/midi2.usb0/ep.0/block.0/direction
512 % echo 2 > functions/midi2.usb0/ep.0/block.0/ui_hint
513
514 When you need more than one Function Blocks, you can create
515 subdirectories `block.1`, `block.2`, etc dynamically, and configure
516 them in the configuration procedure above before linking.
517 For example, to create a second Function Block for a keyboard::
518
519 % mkdir functions/midi2.usb0/ep.0/block.1
520 % echo "Keyboard" > functions/midi2.usb0/ep.0/block.1/name
521 % echo 1 > functions/midi2.usb0/ep.0/block.1/first_group
522 % echo 1 > functions/midi2.usb0/ep.0/block.1/num_groups
523 % echo 1 > functions/midi2.usb0/ep.0/block.1/direction
524 % echo 1 > functions/midi2.usb0/ep.0/block.1/ui_hint
525
526 The `block.*` subdirectories can be removed dynamically, too (except
527 for `block.0` which is persistent).
528
529 For assigning a Function Block for MIDI 1.0 I/O, set up in `is_midi1`
530 attribute. 1 is for MIDI 1.0, and 2 is for MIDI 1.0 with low speed
531 connection::
532
533 % echo 2 > functions/midi2.usb0/ep.0/block.1/is_midi1
534
535 For disabling the processing of UMP Stream messages in the gadget
536 driver, pass `0` to `process_ump` attribute in the top-level config::
537
538 % echo 0 > functions/midi2.usb0/process_ump
539
540 The MIDI 1.0 interface at altset 0 is supported by the gadget driver,
541 too. When MIDI 1.0 interface is selected by the connected host, the
542 UMP I/O on the gadget is translated from/to USB MIDI 1.0 packets
543 accordingly while the gadget driver keeps communicating with the
544 user-space over UMP rawmidi.
545
546 MIDI 1.0 ports are set up from the config in each Function Block.
547 For example::
548
549 % echo 0 > functions/midi2.usb0/ep.0/block.0/midi1_first_group
550 % echo 1 > functions/midi2.usb0/ep.0/block.0/midi1_num_groups
551
552 The configuration above will enable the Group 1 (the index 0) for MIDI
553 1.0 interface. Note that those groups must be in the groups defined
554 for the Function Block itself.
555
556 The gadget driver supports more than one UMP Endpoints, too.
557 Similarly like the Function Blocks, you can create a new subdirectory
558 `ep.1` (but under the card top-level config) to enable a new Endpoint::
559
560 % mkdir functions/midi2.usb0/ep.1
561
562 and create a new Function Block there. For example, to create 4
563 Groups for the Function Block of this new Endpoint::
564
565 % mkdir functions/midi2.usb0/ep.1/block.0
566 % echo 4 > functions/midi2.usb0/ep.1/block.0/num_groups
567
568 Now, you'll have 4 rawmidi devices in total: the first two are UMP
569 rawmidi devices for Endpoint 0 and Endpoint 1, and other two for the
570 legacy MIDI 1.0 rawmidi devices corresponding to both EP 0 and EP 1.
571
572 The current altsetting on the gadget can be informed via a control
573 element "Operation Mode" with `RAWMIDI` iface. e.g. you can read it
574 via `amixer` program running on the gadget host like::
575
576 % amixer -c1 cget iface=RAWMIDI,name='Operation Mode'
577 ; type=INTEGER,access=r--v----,values=1,min=0,max=2,step=0
578 : values=2
579
580 The value (shown in the second returned line with `: values=`)
581 indicates 1 for MIDI 1.0 (altset 0), 2 for MIDI 2.0 (altset 1) and 0
582 for unset.
583
584 As of now, the configurations can't be changed after binding.
585

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

UMP, MIDI 2.0과 Linux 역할

1-46

MIDI 2.0은 기존 MIDI 1.0보다 높은 해상도와 세밀한 제어를 제공하는 확장 protocol이다. 핵심 변화는 Universal MIDI Packet(UMP), MIDI 2.0 protocol message, UMP와 MIDI 1.0 byte stream 사이의 투명한 변환, property·profile 구성을 위한 MIDI-CI 지원이다.

UMP는 MIDI 1.0과 MIDI 2.0 protocol message를 모두 담는 새 container 형식이다. 기존 byte stream과 달리 32bit 정렬이며 각 message를 단일 packet에 넣을 수 있다. 최대 16개 UMP Group으로 event를 보내고, 각 Group은 최대 16 MIDI channel을 포함한다.

MIDI 2.0 protocol은 MIDI 1.0을 확장해 해상도와 control을 높인다. MIDI-CI는 장치와 flexible profile·configuration을 협상하는 상위 protocol이며 특별한 SysEx 형태로 표현된다. Linux kernel은 UMP transport와 UMP상의 MIDI protocol encoding/decoding을 지원하고 MIDI-CI는 표준 SysEx 위에서 사용자 공간이 처리한다.

작성 시점에는 USB MIDI 장치만 UMP와 MIDI 2.0을 Linux에서 native로 지원한다. UMP 자체는 범용이므로 다른 transport layer에서도 사용할 수 있고 ALSA sequencer client처럼 다른 방식으로 구현할 수도 있다.

UMP 장치는 rawmidi 장치와 ALSA sequencer API 두 경로로 접근한다. Sequencer API는 UMP packet payload를 수용하도록 확장됐으며 MIDI 1.0과 MIDI 2.0 client를 자유롭게 연결하면 event를 투명하게 변환한다.

MIDI 2.0 Linux 구성
요소역할
UMP32bit 정렬 packet, 16 Group x Group당 16 channel
MIDI 2.0높은 해상도와 확장 control
MIDI-CISysEx 기반 property/profile configuration
KernelUMP transport와 MIDI protocol encode/decode
User space표준 SysEx 위 MIDI-CI
접근UMP rawmidi 또는 ALSA sequencer

Protocol 계층과 kernel·user-space 책임을 구분한다.

=================
MIDI 2.0 on Linux
=================

General
=======

MIDI 2.0 is an extended protocol for providing higher resolutions and
more fine controls over the legacy MIDI 1.0.  The fundamental changes
introduced for supporting MIDI 2.0 are:

- Support of Universal MIDI Packet (UMP)
- Support of MIDI 2.0 protocol messages
- Transparent conversions between UMP and legacy MIDI 1.0 byte stream
- MIDI-CI for property and profile configurations

UMP is a new container format to hold all MIDI protocol 1.0 and MIDI
2.0 protocol messages.  Unlike the former byte stream, it's 32bit
aligned, and each message can be put in a single packet.  UMP can send
the events up to 16 "UMP Groups", where each UMP Group contain up to
16 MIDI channels.

MIDI 2.0 protocol is an extended protocol to achieve the higher
resolution and more controls over the old MIDI 1.0 protocol.

MIDI-CI is a high-level protocol that can talk with the MIDI device
for the flexible profiles and configurations.  It's represented in the
form of special SysEx.

For Linux implementations, the kernel supports the UMP transport and
the encoding/decoding of MIDI protocols on UMP, while MIDI-CI is
supported in user-space over the standard SysEx.

As of this writing, only USB MIDI device supports the UMP and Linux
2.0 natively.  The UMP support itself is pretty generic, hence it
could be used by other transport layers, although it could be
implemented differently (e.g. as a ALSA sequencer client), too.

The access to UMP devices are provided in two ways: the access via
rawmidi device and the access via ALSA sequencer API.

ALSA sequencer API was extended to allow the payload of UMP packets.
It's allowed to connect freely between MIDI 1.0 and MIDI 2.0 sequencer
clients, and the events are converted transparently.

Kernel 설정

47-61

MIDI 2.0 지원을 위해 `CONFIG_SND_UMP`, `CONFIG_SND_UMP_LEGACY_RAWMIDI`, `CONFIG_SND_SEQ_UMP`, `CONFIG_SND_SEQ_UMP_CLIENT`, `CONFIG_SND_USB_AUDIO_MIDI_V2`가 추가됐다.

사용자에게 보이는 첫 선택은 `CONFIG_SND_USB_AUDIO_MIDI_V2`다. 이를 `y`로 설정하면 UMP core인 `CONFIG_SND_UMP`와 sequencer binding인 `CONFIG_SND_SEQ_UMP_CLIENT`가 자동 선택된다. `CONFIG_SND_UMP_LEGACY_RAWMIDI=y`는 UMP Endpoint용 기존 raw MIDI 장치 호환 경로를 활성화한다.

MIDI 2.0 Kconfig
Config역할
CONFIG_SND_USB_AUDIO_MIDI_V2USB MIDI 2.0 사용자 선택
CONFIG_SND_UMPUMP core, 자동 선택
CONFIG_SND_SEQ_UMP / CONFIG_SND_SEQ_UMP_CLIENTsequencer와 client binding
CONFIG_SND_UMP_LEGACY_RAWMIDIUMP Endpoint의 legacy rawmidi 호환

직접 선택과 자동·호환 기능을 정리한다.

Kernel Configuration
====================

The following new configs are added for supporting MIDI 2.0:
`CONFIG_SND_UMP`, `CONFIG_SND_UMP_LEGACY_RAWMIDI`,
`CONFIG_SND_SEQ_UMP`, `CONFIG_SND_SEQ_UMP_CLIENT`, and
`CONFIG_SND_USB_AUDIO_MIDI_V2`.  The first visible one is
`CONFIG_SND_USB_AUDIO_MIDI_V2`, and when you choose it (to set `=y`),
the core support for UMP (`CONFIG_SND_UMP`) and the sequencer binding
(`CONFIG_SND_SEQ_UMP_CLIENT`) will be automatically selected.

Additionally, `CONFIG_SND_UMP_LEGACY_RAWMIDI=y` will enable the
support for the legacy raw MIDI device for UMP Endpoints.

USB probe, UMP rawmidi와 legacy substream

62-120

장치가 MIDI 2.0을 지원하면 USB-audio driver는 기본적으로 altset 0의 MIDI 1.0 interface 대신 항상 altset 1에 있는 MIDI 2.0 interface를 probe해 사용한다. `snd-usb-audio`에 `midi2_enable=0`을 주면 옛 MIDI 1.0 binding으로 되돌릴 수 있다.

Driver는 UMP v1.1부터 제공되는 UMP Endpoint와 Function Block 정보를 질의해 topology를 만든다. 오래된 장치가 새 질의에 응답하지 않으면 USB descriptor의 Group Terminal Block(GTB) 정보로 fallback한다. 예상하지 못한 UMP command 때문에 오동작하는 장치는 `midi2_ump_probe=0`으로 v1.1 질의를 건너뛸 수 있다.

MIDI 2.0 장치를 probe하면 UMP Endpoint마다 `/dev/snd/umpC*D*` rawmidi 장치를 만든다. MIDI 1.0의 `/dev/snd/midiC*D*`와 이름을 분리해 legacy 응용 프로그램이 UMP 장치를 실수로 열지 않게 한다. UMP rawmidi에서 packet을 직접 읽고 쓸 수 있다.

% hexdump -C /dev/snd/umpC0D0
00000000  01 07 b0 20 00 07 b0 20  64 3c 90 20 64 3c 80 20  |... ... d<. d<. |

UMP는 32bit packet이므로 read/write 크기도 4byte 단위로 정렬해야 한다. Payload의 32bit word는 항상 CPU native endianness다. Transport driver가 system endianness와 transport가 요구하는 endianness 또는 byte order 사이를 변환한다.

`CONFIG_SND_UMP_LEGACY_RAWMIDI`를 켜면 `/dev/snd/midiC*D*` 표준 raw MIDI 장치도 추가한다. 16개 substream이 0-based UMP Group에 각각 대응하며 legacy 응용 프로그램은 MIDI 1.0 byte stream으로 특정 Group에 접근한다. ALSA rawmidi API는 임의 substream을 열 수 있지만 device node만 열면 첫 substream을 연다.

UMP Endpoint에는 UMP v1.1 Stream message 또는 USB MIDI 2.0 descriptor에서 얻은 추가 정보가 있다. ALSA의 UMP Block은 여러 UMP Group의 연관을 나타내는 추상화이며 UMP v1.1 Function Block에 대응한다. Function Block 정보가 없으면 USB MIDI 2.0 GTB에서 일부를 채운다.

USB MIDI 2.0 probe와 장치 생성
USB MIDI 2.0 altset 1UMP v1.1 Endpoint/Function Block 질의UMP topology/dev/snd/umpC*D*
v1.1 응답 없음GTB fallback부분 topology
CONFIG_SND_UMP_LEGACY_RAWMIDI16 Group substream/dev/snd/midiC*D*

질의 지원 여부와 legacy 호환 설정에 따른 경로다.

UMP rawmidi I/O 규칙
항목UMPLegacy MIDI 1.0
장치/dev/snd/umpC*D*/dev/snd/midiC*D*
Data32bit packetbyte stream
정렬4bytebyte
호환 substreamEndpoint 장치16개가 UMP Group 0~15에 대응

장치 이름과 data 표현을 MIDI 1.0과 비교한다.

Rawmidi Device with USB MIDI 2.0
================================

When a device supports MIDI 2.0, the USB-audio driver probes and uses
the MIDI 2.0 interface (that is found always at the altset 1) as
default instead of the MIDI 1.0 interface (at altset 0).  You can
switch back to the binding with the old MIDI 1.0 interface by passing
`midi2_enable=0` option to snd-usb-audio driver module, too.

The USB audio driver tries to query the UMP Endpoint and UMP Function
Block information that are provided since UMP v1.1, and builds up the
topology based on those information.  When the device is older and
doesn't respond to the new UMP inquiries, the driver falls back and
builds the topology based on Group Terminal Block (GTB) information
from the USB descriptor.  Some device might be screwed up by the
unexpected UMP command; in such a case, pass `midi2_ump_probe=0`
option to snd-usb-audio driver for skipping the UMP v1.1 inquiries.

When the MIDI 2.0 device is probed, the kernel creates a rawmidi
device for each UMP Endpoint of the device.  Its device name is
`/dev/snd/umpC*D*` and different from the standard rawmidi device name
`/dev/snd/midiC*D*` for MIDI 1.0, in order to avoid confusing the
legacy applications accessing mistakenly to UMP devices.

You can read and write UMP packet data directly from/to this UMP
rawmidi device.  For example, reading via `hexdump` like below will
show the incoming UMP packets of the card 0 device 0 in the hex
format::

  % hexdump -C /dev/snd/umpC0D0
  00000000  01 07 b0 20 00 07 b0 20  64 3c 90 20 64 3c 80 20  |... ... d<. d<. |

Unlike the MIDI 1.0 byte stream, UMP is a 32bit packet, and the size
for reading or writing the device is also aligned to 32bit (which is 4
bytes).

The 32-bit words in the UMP packet payload are always in CPU native
endianness.  Transport drivers are responsible to convert UMP words
from / to system endianness to required transport endianness / byte
order.

When `CONFIG_SND_UMP_LEGACY_RAWMIDI` is set, the driver creates
another standard raw MIDI device additionally as `/dev/snd/midiC*D*`.
This contains 16 substreams, and each substream corresponds to a
(0-based) UMP Group.  Legacy applications can access to the specified
group via each substream in MIDI 1.0 byte stream format.  With the
ALSA rawmidi API, you can open the arbitrary substream, while just
opening `/dev/snd/midiC*D*` will end up with opening the first
substream.

Each UMP Endpoint can provide the additional information, constructed
from the information inquired via UMP 1.1 Stream messages or USB MIDI
2.0 descriptors.  And a UMP Endpoint may contain one or more UMP
Blocks, where UMP Block is an abstraction introduced in the ALSA UMP
implementations to represent the associations among UMP Groups.  UMP
Block corresponds to Function Block in UMP 1.1 specification.  When
UMP 1.1 Function Block information isn't available, it's filled
partially from Group Terminal Block (GTB) as defined in USB MIDI 2.0
specifications.

Endpoint·Block 정보와 ioctl

121-168

UMP Endpoint와 Block 정보는 `/proc/asound/card*/midi*`에서 볼 수 있다. 출력에는 Endpoint 이름·product ID·UMP version·protocol capability·현재 protocol·Block 수와 각 Block의 direction, active 상태, Group 범위, MIDI 1.0 여부가 나온다.

% cat /proc/asound/card1/midi0
ProtoZOA MIDI

Type: UMP
EP Name: ProtoZOA
EP Product ID: ABCD12345678
UMP Version: 0x0000
Protocol Caps: 0x00000100
Protocol: 0x00000100
Num Blocks: 3

Block 0 (ProtoZOA Main)
  Direction: bidirection
  Active: Yes
  Groups: 1-1
  Is MIDI1: No

Block 1 (ProtoZOA Ext IN)
  Direction: output
  Active: Yes
  Groups: 2-2
  Is MIDI1: Yes (Low Speed)

Proc의 `Groups`는 1-based UMP Group 번호 범위다. Endpoint와 Block 정보는 각각 `SNDRV_UMP_IOCTL_ENDPOINT_INFO`, `SNDRV_UMP_IOCTL_BLOCK_INFO` ioctl로 얻을 수 있다.

Rawmidi 이름과 Endpoint 이름은 보통 같다. USB MIDI에서는 해당 interface descriptor의 `iInterface`를 사용하고 없으면 USB device descriptor의 `iProduct`를 fallback으로 복사한다. Endpoint Product ID는 unique string이며 USB MIDI에서는 `iSerialNumber`에서 가져온다. Protocol capability와 실제 protocol bit는 `asound.h`에 정의된다.

UMP Endpoint와 Block 정보
대상정보조회
Endpointname, product ID, version, protocol caps/current, block countSNDRV_UMP_IOCTL_ENDPOINT_INFO
Blockdirection, active, 1-based Group 범위, MIDI1 여부SNDRV_UMP_IOCTL_BLOCK_INFO
USB 이름iInterface, 없으면 iProductdescriptor
Product IDiSerialNumberdescriptor

Proc와 ioctl에서 노출하는 대표 field다.


The information of UMP Endpoints and UMP Blocks are found in the proc
file `/proc/asound/card*/midi*`.  For example::

  % cat /proc/asound/card1/midi0
  ProtoZOA MIDI
  
  Type: UMP
  EP Name: ProtoZOA
  EP Product ID: ABCD12345678
  UMP Version: 0x0000
  Protocol Caps: 0x00000100
  Protocol: 0x00000100
  Num Blocks: 3
  
  Block 0 (ProtoZOA Main)
    Direction: bidirection
    Active: Yes
    Groups: 1-1
    Is MIDI1: No

  Block 1 (ProtoZOA Ext IN)
    Direction: output
    Active: Yes
    Groups: 2-2
    Is MIDI1: Yes (Low Speed)
  ....

Note that `Groups` field shown in the proc file above indicates the
1-based UMP Group numbers (from-to).

Those additional UMP Endpoint and UMP Block information can be
obtained via the new ioctls `SNDRV_UMP_IOCTL_ENDPOINT_INFO` and
`SNDRV_UMP_IOCTL_BLOCK_INFO`, respectively.

The rawmidi name and the UMP Endpoint name are usually identical, and
in the case of USB MIDI, it's taken from `iInterface` of the
corresponding USB MIDI interface descriptor.  If it's not provided,
it's copied from `iProduct` of the USB device descriptor as a
fallback.

The Endpoint Product ID is a string field and supposed to be unique.
It's copied from `iSerialNumber` of the device for USB MIDI.

The protocol capabilities and the actual protocol bits are defined in
`asound.h`.

ALSA Sequencer client·port와 자동 변환

169-262

ALSA sequencer client는 `midi_version`을 0, 1, 2 중 하나로 설정해 legacy, UMP MIDI 1.0, UMP MIDI 2.0 장치임을 선언한다. Legacy client는 기존 sequencer event를 사용하고 UMP MIDI 1.0/2.0 client는 UMP용 확장 event record를 사용한다. 값은 `snd_seq_client_info.midi_version`에서 확인한다.

Sequencer event에 `SNDRV_SEQ_EVENT_UMP` flag를 설정하면 16byte(128bit) payload에 UMP packet을 담는다. Flag가 없으면 최대 12byte payload의 legacy event다. UMP event에서는 type field를 무시하지만 기본값 0으로 설정해야 한다.

% cat /proc/asound/seq/clients
Client  14 : "Midi Through" [Kernel Legacy]
  Port   0 : "Midi Through Port-0" (RWe-)
Client  20 : "ProtoZOA" [Kernel UMP MIDI1]
  UMP Endpoint: ProtoZOA
  UMP Block 0: ProtoZOA Main [Active]
    Groups: 1-1
  UMP Block 1: ProtoZOA Ext IN [Active]
    Groups: 2-2
  UMP Block 2: ProtoZOA Ext OUT [Active]
    Groups: 3-3
  Port   0 : "MIDI 2.0" (RWeX) [In/Out]
  Port   1 : "ProtoZOA Main" (RWeX) [In/Out]
  Port   2 : "ProtoZOA Ext IN" (-We-) [Out]
  Port   3 : "ProtoZOA Ext OUT" (R-e-) [In]

USB MIDI 2.0 client는 항상 port 0을 `MIDI 2.0` Endpoint port로 만들고, 각 UMP Group을 port 1부터 노출한다. Endpoint port는 장치 모든 port event를 받는 catch-all이고 Group port는 지정 Group event만 받는다. UMP type `0x0f` 같은 groupless message는 Endpoint port에만 전달한다.

UMP client는 보통 16개 port를 만들지만 어떤 Block에도 속하지 않거나 inactive Block에 속한 port는 inactive로 표시되어 proc에 나오지 않는다. 예의 port 4~16도 존재하지만 숨겨져 있다. Proc에는 Block 정보도 나오며 rawmidi proc 출력에서 더 자세히 볼 수 있다.

서로 다른 MIDI version의 client를 연결하면 legacy와 UMP MIDI 1.0/2.0 사이뿐 아니라 UMP MIDI 1.0과 2.0 사이도 client version에 맞춰 자동 변환한다. 같은 event를 legacy `aseqdump`로 보면 정수 velocity·controller 값이고 `-u 2`에서는 고정밀 16/32bit 값을 받는다.

% aseqdump -p 20:1
Source  Event                  Ch  Data
 20:1   Note on                 0, note 60, velocity 100
 20:1   Note off                0, note 60, velocity 100
 20:1   Control change          0, controller 11, value 4

% aseqdump -u 2 -p 20:1
Source  Event                  Ch  Data
 20:1   Note on                 0, note 60, velocity 0xc924, attr type = 0, data = 0x0
 20:1   Note off                0, note 60, velocity 0xc924, attr type = 0, data = 0x0
 20:1   Control change          0, controller 11, value 0x2000000
UMP sequencer port 전달
장치의 모든 Group eventPort 0 MIDI 2.0 Endpoint
Group 1 eventPort 1 Group 전용
Group 2 eventPort 2 Group 전용
Groupless type 0x0fPort 0에만 전달

Endpoint catch-all과 Group 전용 port의 차이다.

Sequencer event 형식
형식FlagPayload변환
Legacy없음최대 12byte기존 event
UMP MIDI 1.0/2.0SNDRV_SEQ_EVENT_UMP16byteclient midi_version에 맞춰 자동 변환

Client version과 UMP flag에 따른 payload다.

ALSA Sequencer with USB MIDI 2.0
================================

In addition to the rawmidi interfaces, ALSA sequencer interface
supports the new UMP MIDI 2.0 device, too.  Now, each ALSA sequencer
client may set its MIDI version (0, 1 or 2) to declare itself being
either the legacy, UMP MIDI 1.0 or UMP MIDI 2.0 device, respectively.
The first, legacy client is the one that sends/receives the old
sequencer event as was.  Meanwhile, UMP MIDI 1.0 and 2.0 clients send
and receive in the extended event record for UMP.  The MIDI version is
seen in the new `midi_version` field of `snd_seq_client_info`.

A UMP packet can be sent/received in a sequencer event embedded by
specifying the new event flag bit `SNDRV_SEQ_EVENT_UMP`.  When this
flag is set, the event has 16 byte (128 bit) data payload for holding
the UMP packet.  Without the `SNDRV_SEQ_EVENT_UMP` bit flag, the event
is treated as a legacy event as it was (with max 12 byte data
payload).

With `SNDRV_SEQ_EVENT_UMP` flag set, the type field of a UMP sequencer
event is ignored (but it should be set to 0 as default).

The type of each client can be seen in `/proc/asound/seq/clients`.
For example::

  % cat /proc/asound/seq/clients
  Client info
    cur  clients : 3
  ....
  Client  14 : "Midi Through" [Kernel Legacy]
    Port   0 : "Midi Through Port-0" (RWe-)
  Client  20 : "ProtoZOA" [Kernel UMP MIDI1]
    UMP Endpoint: ProtoZOA
    UMP Block 0: ProtoZOA Main [Active]
      Groups: 1-1
    UMP Block 1: ProtoZOA Ext IN [Active]
      Groups: 2-2
    UMP Block 2: ProtoZOA Ext OUT [Active]
      Groups: 3-3
    Port   0 : "MIDI 2.0" (RWeX) [In/Out]
    Port   1 : "ProtoZOA Main" (RWeX) [In/Out]
    Port   2 : "ProtoZOA Ext IN" (-We-) [Out]
    Port   3 : "ProtoZOA Ext OUT" (R-e-) [In]

Here you can find two types of kernel clients, "Legacy" for client 14,
and "UMP MIDI1" for client 20, which is a USB MIDI 2.0 device.
A USB MIDI 2.0 client gives always the port 0 as "MIDI 2.0" and the
rest ports from 1 for each UMP Group (e.g. port 1 for Group 1).
In this example, the device has three active groups (Main, Ext IN and
Ext OUT), and those are exposed as sequencer ports from 1 to 3.
The "MIDI 2.0" port is for a UMP Endpoint, and its difference from
other UMP Group ports is that UMP Endpoint port sends the events from
the all ports on the device ("catch-all"), while each UMP Group port
sends only the events from the given UMP Group.
Also, UMP groupless messages (such as the UMP message type 0x0f) are
sent only to the UMP Endpoint port.

Note that, although each UMP sequencer client usually creates 16
ports, those ports that don't belong to any UMP Blocks (or belonging
to inactive UMP Blocks) are marked as inactive, and they don't appear
in the proc outputs.  In the example above, the sequencer ports from 4
to 16 are present but not shown there.

The proc file above shows the UMP Block information, too.  The same
entry (but with more detailed information) is found in the rawmidi
proc output.

When clients are connected between different MIDI versions, the events
are translated automatically depending on the client's version, not
only between the legacy and the UMP MIDI 1.0/2.0 types, but also
between UMP MIDI 1.0 and 2.0 types, too.  For example, running
`aseqdump` program on the ProtoZOA Main port in the legacy mode will
give you the output like::

  % aseqdump -p 20:1
  Waiting for data. Press Ctrl+C to end.
  Source  Event                  Ch  Data
   20:1   Note on                 0, note 60, velocity 100
   20:1   Note off                0, note 60, velocity 100
   20:1   Control change          0, controller 11, value 4

When you run `aseqdump` in MIDI 2.0 mode, it'll receive the high
precision data like::

  % aseqdump -u 2 -p 20:1
  Waiting for data. Press Ctrl+C to end.
  Source  Event                  Ch  Data
   20:1   Note on                 0, note 60, velocity 0xc924, attr type = 0, data = 0x0
   20:1   Note off                0, note 60, velocity 0xc924, attr type = 0, data = 0x0
   20:1   Control change          0, controller 11, value 0x2000000

while the data is automatically converted by ALSA sequencer core.

Rawmidi API 확장

263-307

`SNDRV_UMP_IOCTL_ENDPOINT_INFO`는 연결 card·device 번호, flag, protocol, Block 수, Endpoint 이름 등을 반환한다. Protocol capability와 current protocol field는 상위 byte에 `SNDRV_UMP_EP_INFO_PROTO_MIDI1` 또는 `...MIDI2`, 하위 byte에 jitter reduction timestamp인 `...JRTS_TX`, `...JRTS_RX` bit를 담는다. Endpoint는 최대 32개 UMP Block을 가질 수 있고 현재 할당 수가 정보에 표시된다.

`SNDRV_UMP_IOCTL_BLOCK_INFO`는 0-based Block ID를 입력받아 direction, 0-based 첫 Group ID, Group 수, 이름 등을 반환한다. Direction은 `SNDRV_UMP_DIR_INPUT`, `SNDRV_UMP_DIR_OUTPUT`, `SNDRV_UMP_DIR_BIDIRECTION` 중 하나다.

UMP v1.1 장치는 UMP type `0x0f`, status `0x05`인 Stream Configuration Request로 MIDI protocol을 바꿀 수 있다. UMP core가 message를 받으면 Endpoint 정보와 대응 sequencer client도 갱신한다.

Rawmidi info의 새 `tied_device` field는 UMP 쪽에서 legacy rawmidi device 번호를, legacy 쪽에서는 UMP rawmidi 번호를 서로 가리킨다. Legacy rawmidi substream은 UMP Function Block 상태에 따라 동적으로 enable/disable될 수 있으며 inactive면 info `flags`에 bit `0x10`, 즉 `SNDRV_RAWMIDI_INFO_STREAM_INACTIVE`를 설정한다.

Rawmidi API 확장
항목Symbol / 규칙
Endpoint 조회SNDRV_UMP_IOCTL_ENDPOINT_INFO, 최대 32 Blocks
Protocol bitMIDI1/MIDI2 + JRTS_TX/JRTS_RX
Block 조회SNDRV_UMP_IOCTL_BLOCK_INFO, 0-based ID
DirectionINPUT / OUTPUT / BIDIRECTION
Protocol 전환Stream Configuration Request type 0x0f status 0x05
상호 연결tied_device
Inactive substreamSNDRV_RAWMIDI_INFO_STREAM_INACTIVE (0x10)

Endpoint·Block·연결 장치와 active 상태를 제공한다.

Rawmidi API Extensions
======================

* The additional UMP Endpoint information can be obtained via the new
  ioctl `SNDRV_UMP_IOCTL_ENDPOINT_INFO`.  It contains the associated
  card and device numbers, the bit flags, the protocols, the number of
  UMP Blocks, the name string of the endpoint, etc.

  The protocols are specified in two field, the protocol capabilities
  and the current protocol.  Both contain the bit flags specifying the
  MIDI protocol version (`SNDRV_UMP_EP_INFO_PROTO_MIDI1` or
  `SNDRV_UMP_EP_INFO_PROTO_MIDI2`) in the upper byte and the jitter
  reduction timestamp (`SNDRV_UMP_EP_INFO_PROTO_JRTS_TX` and
  `SNDRV_UMP_EP_INFO_PROTO_JRTS_RX`) in the lower byte.

  A UMP Endpoint may contain up to 32 UMP Blocks, and the number of
  the currently assigned blocks are shown in the Endpoint information.

* Each UMP Block information can be obtained via another new ioctl
  `SNDRV_UMP_IOCTL_BLOCK_INFO`.  The block ID number (0-based) has to
  be passed for the block to query.  The received data contains the
  associated the direction of the block, the first associated group ID
  (0-based) and the number of groups, the name string of the block,
  etc.

  The direction is either `SNDRV_UMP_DIR_INPUT`,
  `SNDRV_UMP_DIR_OUTPUT` or `SNDRV_UMP_DIR_BIDIRECTION`.

* For the device supports UMP v1.1, the UMP MIDI protocol can be
  switched via "Stream Configuration Request" message (UMP type 0x0f,
  status 0x05).  When UMP core receives such a message, it updates the
  UMP EP info and the corresponding sequencer clients as well.

* The legacy rawmidi device number is found in the new `tied_device`
  field of the rawmidi info.
  On the other hand, the UMP rawmidi device number is found in
  `tied_device` field of the legacy rawmidi info, too.

* Each substream of the legacy rawmidi may be enabled / disabled
  dynamically depending on the UMP FB state.
  When the selected substream is inactive, it's indicated by the bit
  0x10 (`SNDRV_RAWMIDI_INFO_STREAM_INACTIVE`) in the `flags` field of
  the legacy rawmidi info.

Control API 확장

308-327

`SNDRV_CTL_IOCTL_UMP_NEXT_DEVICE`는 다음 UMP rawmidi device를 조회한다. 기존 `SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE`는 legacy rawmidi만 조회한다. 열 subdevice 번호 설정은 일반 rawmidi와 같이 `SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE`를 사용한다.

`SNDRV_CTL_IOCTL_UMP_ENDPOINT_INFO`와 `SNDRV_CTL_IOCTL_UMP_BLOCK_INFO`는 실제 UMP rawmidi device를 열지 않고 ALSA control API를 통해 지정 장치의 Endpoint와 Block 정보를 제공한다. 조회 시 `card` field는 무시하고 control interface의 card에 항상 연결한다.

UMP Control ioctl
ioctl역할
SNDRV_CTL_IOCTL_UMP_NEXT_DEVICE다음 UMP rawmidi
SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICElegacy rawmidi만
SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE열 substream 선택
SNDRV_CTL_IOCTL_UMP_ENDPOINT_INFO장치를 열지 않고 Endpoint 정보
SNDRV_CTL_IOCTL_UMP_BLOCK_INFO장치를 열지 않고 Block 정보

장치 열거와 정보 조회 역할을 구분한다.

Control API Extensions
======================

* The new ioctl `SNDRV_CTL_IOCTL_UMP_NEXT_DEVICE` is introduced for
  querying the next UMP rawmidi device, while the existing ioctl
  `SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE` queries only the legacy
  rawmidi devices.

  For setting the subdevice (substream number) to be opened, use the
  ioctl `SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE` like the normal
  rawmidi.

* Two new ioctls `SNDRV_CTL_IOCTL_UMP_ENDPOINT_INFO` and
  `SNDRV_CTL_IOCTL_UMP_BLOCK_INFO` provide the UMP Endpoint and UMP
  Block information of the specified UMP device via ALSA control API
  without opening the actual (UMP) rawmidi device.
  The `card` field is ignored upon inquiry, always tied with the card
  of the control interface.

Sequencer API 확장

328-398

`snd_seq_client_info`에 client의 현재 MIDI version 0/1/2를 나타내는 `midi_version`을 추가했다. 값이 1 또는 2면 UMP sequencer client read 정렬이 확장 payload를 위해 28byte에서 32byte로 바뀐다. Write 정렬은 같지만 event 크기는 `SNDRV_SEQ_EVENT_UMP` flag에 따라 달라진다. 이 flag가 있으면 legacy 12byte 대신 16byte payload에 UMP packet을 담는다.

새 port type `SNDRV_SEQ_PORT_TYPE_MIDI_UMP`는 UMP 가능 port를 나타낸다. Capability bit `SNDRV_SEQ_PORT_CAP_INACTIVE`와 `SNDRV_SEQ_PORT_CAP_UMP_ENDPOINT`는 inactive port와 Endpoint port를 표시한다. Client info에 `SNDRV_SEQ_FILTER_NO_CONVERT` filter를 설정하면 event 변환을 막으며 kernel pass-through client `snd-seq-dummy`가 내부적으로 사용한다.

Port info의 `direction`은 `SNDRV_SEQ_PORT_DIR_INPUT`, `...OUTPUT`, `...BIDIRECTION` 중 하나다. `ump_group`은 연결된 1-based UMP Group 번호다. 0이 아니면 지정 Group으로 전달할 때 packet의 Group field를 0-based 값으로 보정한다.

Client는 `group_filter` bitmap으로 UMP Group event를 추가 filtering할 수 있다. 1-based Group 번호의 bit를 사용하며 bit 1은 첫 Group인 Group 1을 차단한다. Bit 0은 groupless message filtering에 쓴다.

UMP client용 `SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO`와 `SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO`는 client의 `snd_ump_endpoint_info` 또는 `snd_ump_block_info`를 조회·설정한다. Endpoint는 `type=0`, Block은 `type=block number + 1`을 전달한다. USB MIDI driver는 기반 UMP rawmidi 정보를 제공하고 user-space client는 `*_SET`으로 자체 정보를 제공할 수 있지만 kernel client 설정은 오류다.

UMP 1.1 Function Block 정보는 동적으로 변할 수 있다. Update를 받으면 sequencer core가 대응 port 이름과 attribute를 바꾸고 일반 port change처럼 system announcement port에 알린다. Endpoint와 Block 변경 event는 type 68 `SNDRV_SEQ_EVENT_UMP_EP_CHANGE`, type 69 `SNDRV_SEQ_EVENT_UMP_BLOCK_CHANGE`이며 payload의 `snd_seq_ev_ump_notify`가 변경된 client와 FB 번호를 나타낸다.

Sequencer API 확장 field
항목내용
midi_version0/1/2, UMP read는 32byte 정렬
SNDRV_SEQ_EVENT_UMP16byte UMP payload
MIDI_UMP port typeUMP-capable 표시
INACTIVE / UMP_ENDPOINT capsport 상태·역할
NO_CONVERT자동 event 변환 억제
direction / ump_groupport 방향과 1-based Group
group_filterGroup별 차단, bit 0은 groupless
GET/SET_CLIENT_UMP_INFOEndpoint 또는 Block 정보
EP_CHANGE / BLOCK_CHANGEtype 68/69 system announcement

UMP client·event·port·notification을 구성하는 새 ABI다.

Sequencer API Extensions
========================

* `midi_version` field is added to `snd_seq_client_info` to indicate
  the current MIDI version (either 0, 1 or 2) of each client.
  When `midi_version` is 1 or 2, the alignment of read from a UMP
  sequencer client is also changed from the former 28 bytes to 32
  bytes for the extended payload.  The alignment size for the write
  isn't changed, but each event size may differ depending on the new
  bit flag below.

* `SNDRV_SEQ_EVENT_UMP` flag bit is added for each sequencer event
  flags.  When this bit flag is set, the sequencer event is extended
  to have a larger payload of 16 bytes instead of the legacy 12
  bytes, and the event contains the UMP packet in the payload.

* The new sequencer port type bit (`SNDRV_SEQ_PORT_TYPE_MIDI_UMP`)
  indicates the port being UMP-capable.

* The sequencer ports have new capability bits to indicate the
  inactive ports (`SNDRV_SEQ_PORT_CAP_INACTIVE`) and the UMP Endpoint
  port (`SNDRV_SEQ_PORT_CAP_UMP_ENDPOINT`).

* The event conversion of ALSA sequencer clients can be suppressed the
  new filter bit `SNDRV_SEQ_FILTER_NO_CONVERT` set to the client info.
  For example, the kernel pass-through client (`snd-seq-dummy`) sets
  this flag internally.

* The port information gained the new field `direction` to indicate
  the direction of the port (either `SNDRV_SEQ_PORT_DIR_INPUT`,
  `SNDRV_SEQ_PORT_DIR_OUTPUT` or `SNDRV_SEQ_PORT_DIR_BIDIRECTION`).

* Another additional field for the port information is `ump_group`
  which specifies the associated UMP Group Number (1-based).
  When it's non-zero, the UMP group field in the UMP packet updated
  upon delivery to the specified group (corrected to be 0-based).
  Each sequencer port is supposed to set this field if it's a port to
  specific to a certain UMP group.

* Each client may set the additional event filter for UMP Groups in
  `group_filter` bitmap.  The filter consists of bitmap from 1-based
  Group numbers.  For example, when the bit 1 is set, messages from
  Group 1 (i.e. the very first group) are filtered and not delivered.
  The bit 0 is used for filtering UMP groupless messages.

* Two new ioctls are added for UMP-capable clients:
  `SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO` and
  `SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO`.  They are used to get and set
  either `snd_ump_endpoint_info` or `snd_ump_block_info` data
  associated with the sequencer client.  The USB MIDI driver provides
  those information from the underlying UMP rawmidi, while a
  user-space client may provide its own data via `*_SET` ioctl.
  For an Endpoint data, pass 0 to the `type` field, while for a Block
  data, pass the block number + 1 to the `type` field.
  Setting the data for a kernel client shall result in an error.

* With UMP 1.1, Function Block information may be changed
  dynamically.  When the update of Function Block is received from the
  device, ALSA sequencer core changes the corresponding sequencer port
  name and attributes accordingly, and notifies the changes via the
  announcement to the ALSA sequencer system port, similarly like the
  normal port change notification.

* There are two extended event types for notifying the UMP Endpoint and
  Function Block changes via the system announcement port:
  type 68 (`SNDRV_SEQ_EVENT_UMP_EP_CHANGE`) and type 69
  (`SNDRV_SEQ_EVENT_UMP_BLOCK_CHANGE`). They take the new type,
  `snd_seq_ev_ump_notify` in the payload, indicating the client number
  and the FB number that are changed.

USB MIDI 2.0 gadget 준비와 instance 생성

399-445

최신 kernel의 USB MIDI 2.0 gadget function driver는 MIDI 2.0 기능 prototype과 debugging에 사용할 수 있다. `CONFIG_USB_GADGET`, `CONFIG_USB_CONFIGFS`, `CONFIG_USB_CONFIGFS_F_MIDI2`가 필요하고 동작하는 UDC driver도 있어야 한다. 예에서는 PC와 VM에서 debugging 가능한 `CONFIG_USB_DUMMY_HCD`의 `dummy_hcd`를 사용하지만 실제 장치는 플랫폼 UDC를 쓸 수 있다.

먼저 gadget 시스템에서 `libcomposite`를 적재하면 보통 `/sys/kernel/config`인 configfs에 `usb_gadget` directory가 생긴다. Gadget instance, configuration, `midi2.usb0` function과 USB 식별·문자열을 만든다.

% modprobe libcomposite
% cd /sys/kernel/config
% mkdir usb_gadget/g1
% cd usb_gadget/g1
% mkdir configs/c.1
% mkdir functions/midi2.usb0
% echo 0x0004 > idProduct
% echo 0x17b3 > idVendor
% mkdir strings/0x409
% echo "ACME Enterprises" > strings/0x409/manufacturer
% echo "ACMESynth" > strings/0x409/product
% echo "ABCD12345" > strings/0x409/serialnumber
% mkdir configs/c.1/strings/0x409
% echo "Monosynth" > configs/c.1/strings/0x409/configuration
% echo 120 > configs/c.1/MaxPower
MIDI2 gadget 기본 생성
필수 Kconfig + UDCmodprobe libcomposite/sys/kernel/config/usb_gadget/g1configs/c.1functions/midi2.usb0USB ID·string 설정

Configfs에서 function과 USB descriptor 정보를 준비한다.

MIDI2 USB Gadget Function Driver
================================

The latest kernel contains the support for USB MIDI 2.0 gadget
function driver, which can be used for prototyping and debugging MIDI
2.0 features.

`CONFIG_USB_GADGET`, `CONFIG_USB_CONFIGFS` and
`CONFIG_USB_CONFIGFS_F_MIDI2` need to be enabled for the MIDI2 gadget
driver.

In addition, for using a gadget driver, you need a working UDC driver.
In the example below, we use `dummy_hcd` driver (enabled via
`CONFIG_USB_DUMMY_HCD`) that is available on PC and VM for debugging
purpose.  There are other UDC drivers depending on the platform, and
those can be used for a real device, instead, too.

At first, on a system to run the gadget, load `libcomposite` module::

  % modprobe libcomposite

and you'll have `usb_gadget` subdirectory under configfs space
(typically `/sys/kernel/config` on modern OS).  Then create a gadget
instance and add configurations there, for example::

  % cd /sys/kernel/config
  % mkdir usb_gadget/g1

  % cd usb_gadget/g1
  % mkdir configs/c.1
  % mkdir functions/midi2.usb0

  % echo 0x0004 > idProduct
  % echo 0x17b3 > idVendor
  % mkdir strings/0x409
  % echo "ACME Enterprises" > strings/0x409/manufacturer
  % echo "ACMESynth" > strings/0x409/product
  % echo "ABCD12345" > strings/0x409/serialnumber

  % mkdir configs/c.1/strings/0x409
  % echo "Monosynth" > configs/c.1/strings/0x409/configuration
  % echo 120 > configs/c.1/MaxPower

At this point, there must be a subdirectory `ep.0`, and that is the
configuration for a UMP Endpoint.  You can fill the Endpoint
information like::

Endpoint·Function Block 구성과 연결 시험

446-505

`ep.0` directory가 UMP Endpoint 구성이다. Interface·Endpoint 이름, product ID, family, model, manufacturer, software revision을 설정하고 기본 MIDI protocol을 1 또는 2로 선택한다.

% echo "ACMESynth" > functions/midi2.usb0/iface_name
% echo "ACMESynth" > functions/midi2.usb0/ep.0/ep_name
% echo "ABCD12345" > functions/midi2.usb0/ep.0/product_id
% echo 0x0123 > functions/midi2.usb0/ep.0/family
% echo 0x4567 > functions/midi2.usb0/ep.0/model
% echo 0x123456 > functions/midi2.usb0/ep.0/manufacturer
% echo 0x12345678 > functions/midi2.usb0/ep.0/sw_revision
% echo 2 > functions/midi2.usb0/ep.0/protocol

Endpoint 아래 `block.0`에서 Function Block 이름, 첫 Group과 Group 수를 지정한다. Function을 configuration에 link한 뒤 UDC 이름을 써서 활성화한다. 실제 UDC instance 이름은 `/sys/class/udc`에서 찾는다.

% echo "Monosynth" > functions/midi2.usb0/ep.0/block.0/name
% echo 0 > functions/midi2.usb0/ep.0/block.0/first_group
% echo 1 > functions/midi2.usb0/ep.0/block.0/num_groups
% ln -s functions/midi2.usb0 configs/c.1
% echo dummy_udc.0 > UDC
% ls /sys/class/udc
dummy_udc.0

활성화되면 gadget 쪽에는 `f_midi2 - MIDI 2.0 Gadget`, 연결 host에는 configfs 이름을 사용한 `USB-Audio - ACMESynth` sound card가 생긴다. Gadget에서 `aplaymidi -p 20:1 to_host.mid`를 실행하면 host의 `aseqdump -p 20:0 -u 2` 입력으로 보인다. 반대로 host playback도 gadget input으로 전달된다.

% aplaymidi -p 20:1 to_host.mid
% aseqdump -p 20:0 -u 2
Gadget 연결과 MIDI 전달
Endpoint ep.0Function Block block.0config linkUDC bindgadget와 host sound card 생성aplaymidi ↔ aseqdump

Configfs 설정부터 양방향 sequencer data까지의 흐름이다.

  % echo "ACMESynth" > functions/midi2.usb0/iface_name
  % echo "ACMESynth" > functions/midi2.usb0/ep.0/ep_name
  % echo "ABCD12345" > functions/midi2.usb0/ep.0/product_id
  % echo 0x0123 > functions/midi2.usb0/ep.0/family
  % echo 0x4567 > functions/midi2.usb0/ep.0/model
  % echo 0x123456 > functions/midi2.usb0/ep.0/manufacturer
  % echo 0x12345678 > functions/midi2.usb0/ep.0/sw_revision

The default MIDI protocol can be set either 1 or 2::

  % echo 2 > functions/midi2.usb0/ep.0/protocol

And, you can find a subdirectory `block.0` under this Endpoint
subdirectory.  This defines the Function Block information::

  % echo "Monosynth" > functions/midi2.usb0/ep.0/block.0/name
  % echo 0 > functions/midi2.usb0/ep.0/block.0/first_group
  % echo 1 > functions/midi2.usb0/ep.0/block.0/num_groups

Finally, link the configuration and enable it::

  % ln -s functions/midi2.usb0 configs/c.1
  % echo dummy_udc.0 > UDC

where `dummy_udc.0` is an example case and it differs depending on the
system.  You can find the UDC instances in `/sys/class/udc` and pass
the found name instead::

  % ls /sys/class/udc
  dummy_udc.0

Now, the MIDI 2.0 gadget device is enabled, and the gadget host
creates a new sound card instance containing a UMP rawmidi device by
`f_midi2` driver::

  % cat /proc/asound/cards
  ....
  1 [Gadget         ]: f_midi2 - MIDI 2.0 Gadget
                       MIDI 2.0 Gadget

And on the connected host, a similar card should appear, too, but with
the card and device names given in the configfs above::

  % cat /proc/asound/cards
  ....
  2 [ACMESynth      ]: USB-Audio - ACMESynth
                       ACME Enterprises ACMESynth at usb-dummy_hcd.0-1, high speed

You can play a MIDI file on the gadget side::

  % aplaymidi -p 20:1 to_host.mid

and this will appear as an input from a MIDI device on the connected
host::

  % aseqdump -p 20:0 -u 2

Vice versa, a playback on the connected host will work as an input on
the gadget, too.

Function Block 속성과 MIDI 1.0 altset

506-555

각 Function Block은 `direction`과 `ui_hint`를 따로 가질 수 있다. 값 1은 input-only, 2는 output-only, 3은 bidirectional이며 기본값은 3이다.

% echo 2 > functions/midi2.usb0/ep.0/block.0/direction
% echo 2 > functions/midi2.usb0/ep.0/block.0/ui_hint

Block이 여러 개 필요하면 link 전에 `block.1`, `block.2` 등을 동적으로 만들고 같은 방식으로 설정한다. 예의 두 번째 keyboard Block은 Group index 1 하나를 input-only로 사용한다. `block.*`는 동적으로 제거할 수도 있지만 `block.0`은 persistent라 제거할 수 없다.

% mkdir functions/midi2.usb0/ep.0/block.1
% echo "Keyboard" > functions/midi2.usb0/ep.0/block.1/name
% echo 1 > functions/midi2.usb0/ep.0/block.1/first_group
% echo 1 > functions/midi2.usb0/ep.0/block.1/num_groups
% echo 1 > functions/midi2.usb0/ep.0/block.1/direction
% echo 1 > functions/midi2.usb0/ep.0/block.1/ui_hint

Function Block을 MIDI 1.0 I/O에 할당하려면 `is_midi1`을 설정한다. 1은 MIDI 1.0, 2는 low-speed MIDI 1.0 연결이다. Gadget driver의 UMP Stream message 처리를 끄려면 top-level `process_ump`에 0을 쓴다.

% echo 2 > functions/midi2.usb0/ep.0/block.1/is_midi1
% echo 0 > functions/midi2.usb0/process_ump

Gadget driver는 altset 0의 MIDI 1.0 interface도 지원한다. Host가 이를 선택하면 gadget driver는 USB MIDI 1.0 packet과 UMP I/O를 서로 변환하지만 사용자 공간과는 계속 UMP rawmidi로 통신한다. MIDI 1.0 port는 각 Function Block 설정에서 만들며 다음은 Group 1(index 0)을 활성화한다. 선택 Group은 반드시 Function Block 자체가 정의한 Group 범위 안에 있어야 한다.

% echo 0 > functions/midi2.usb0/ep.0/block.0/midi1_first_group
% echo 1 > functions/midi2.usb0/ep.0/block.0/midi1_num_groups
Function Block 설정
속성값 / 규칙
direction / ui_hint1 input, 2 output, 3 bidirectional
block.1+link 전 동적 생성·삭제 가능
block.0persistent
is_midi11 MIDI1, 2 low-speed MIDI1
process_ump=0UMP Stream message 처리 중지
midi1_first_group / num_groupsFunction Block 범위 안의 MIDI1 Group

방향, MIDI 1.0 호환과 동적 생명주기다.

Each Function Block may have different direction and UI-hint,
specified via `direction` and `ui_hint` attributes.
Passing `1` is for input-only, `2` for out-only and `3` for
bidirectional (the default value).  For example::

  % echo 2 > functions/midi2.usb0/ep.0/block.0/direction
  % echo 2 > functions/midi2.usb0/ep.0/block.0/ui_hint

When you need more than one Function Blocks, you can create
subdirectories `block.1`, `block.2`, etc dynamically, and configure
them in the configuration procedure above before linking.
For example, to create a second Function Block for a keyboard::

  % mkdir functions/midi2.usb0/ep.0/block.1
  % echo "Keyboard" > functions/midi2.usb0/ep.0/block.1/name
  % echo 1 > functions/midi2.usb0/ep.0/block.1/first_group
  % echo 1 > functions/midi2.usb0/ep.0/block.1/num_groups
  % echo 1 > functions/midi2.usb0/ep.0/block.1/direction
  % echo 1 > functions/midi2.usb0/ep.0/block.1/ui_hint

The `block.*` subdirectories can be removed dynamically, too (except
for `block.0` which is persistent).

For assigning a Function Block for MIDI 1.0 I/O, set up in `is_midi1`
attribute.  1 is for MIDI 1.0, and 2 is for MIDI 1.0 with low speed
connection::

  % echo 2 > functions/midi2.usb0/ep.0/block.1/is_midi1

For disabling the processing of UMP Stream messages in the gadget
driver, pass `0` to `process_ump` attribute in the top-level config::

  % echo 0 > functions/midi2.usb0/process_ump

The MIDI 1.0 interface at altset 0 is supported by the gadget driver,
too.  When MIDI 1.0 interface is selected by the connected host, the
UMP I/O on the gadget is translated from/to USB MIDI 1.0 packets
accordingly while the gadget driver keeps communicating with the
user-space over UMP rawmidi.

MIDI 1.0 ports are set up from the config in each Function Block.
For example::

  % echo 0 > functions/midi2.usb0/ep.0/block.0/midi1_first_group
  % echo 1 > functions/midi2.usb0/ep.0/block.0/midi1_num_groups

The configuration above will enable the Group 1 (the index 0) for MIDI
1.0 interface.  Note that those groups must be in the groups defined
for the Function Block itself.

여러 Endpoint와 Operation Mode

556-584

Gadget driver는 UMP Endpoint를 여러 개 지원한다. Card top-level 아래 `ep.1`을 만들고 그 안에 Function Block을 생성한다. 예에서는 새 Endpoint Block에 4개 Group을 둔다.

% mkdir functions/midi2.usb0/ep.1
% mkdir functions/midi2.usb0/ep.1/block.0
% echo 4 > functions/midi2.usb0/ep.1/block.0/num_groups

이 구성은 rawmidi 장치 총 4개를 만든다. 앞의 두 개는 Endpoint 0과 1의 UMP rawmidi, 나머지 두 개는 각 Endpoint에 대응하는 legacy MIDI 1.0 rawmidi다.

Gadget의 현재 altsetting은 `RAWMIDI` iface의 `Operation Mode` control element로 알 수 있다. `amixer` 결과 `values=1`은 MIDI 1.0 altset 0, `2`는 MIDI 2.0 altset 1, `0`은 미설정이다. 현재는 binding 뒤 configuration을 바꿀 수 없다.

% amixer -c1 cget iface=RAWMIDI,name='Operation Mode'
; type=INTEGER,access=r--v----,values=1,min=0,max=2,step=0
: values=2
Multi-Endpoint 장치와 mode
Endpoint 0UMP rawmidi 0legacy MIDI1 rawmidi 0
Endpoint 1UMP rawmidi 1legacy MIDI1 rawmidi 1
Operation Mode0 unset | 1 MIDI 1.0 altset 0 | 2 MIDI 2.0 altset 1
UDC bind 완료configuration 변경 불가

두 Endpoint가 UMP와 legacy 장치를 각각 만든다.

The gadget driver supports more than one UMP Endpoints, too.
Similarly like the Function Blocks, you can create a new subdirectory
`ep.1` (but under the card top-level config) to enable a new Endpoint::

  % mkdir functions/midi2.usb0/ep.1

and create a new Function Block there.  For example, to create 4
Groups for the Function Block of this new Endpoint::

  % mkdir functions/midi2.usb0/ep.1/block.0
  % echo 4 > functions/midi2.usb0/ep.1/block.0/num_groups

Now, you'll have 4 rawmidi devices in total: the first two are UMP
rawmidi devices for Endpoint 0 and Endpoint 1, and other two for the
legacy MIDI 1.0 rawmidi devices corresponding to both EP 0 and EP 1.

The current altsetting on the gadget can be informed via a control
element "Operation Mode" with `RAWMIDI` iface.  e.g. you can read it
via `amixer` program running on the gadget host like::

  % amixer -c1 cget iface=RAWMIDI,name='Operation Mode'
  ; type=INTEGER,access=r--v----,values=1,min=0,max=2,step=0
  : values=2

The value (shown in the second returned line with `: values=`)
indicates 1 for MIDI 1.0 (altset 0), 2 for MIDI 2.0 (altset 1) and 0
for unset.

As of now, the configurations can't be changed after binding.