mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-08 06:03:24 +00:00
ALSA: documentation: Add description for USB MIDI 2.0 gadget driver
The USB MIDI 2.0 gadget driver is now supported for 6.6 kernel, and here we show a brief instruction how to enable and use it. Link: https://lore.kernel.org/r/20230824075108.29958-5-tiwai@suse.de Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
b2bcbd031d
commit
e240cff9e6
@ -376,3 +376,191 @@ Sequencer API Extensions
|
|||||||
name and attributes accordingly, and notifies the changes via the
|
name and attributes accordingly, and notifies the changes via the
|
||||||
announcement to the ALSA sequencer system port, similarly like the
|
announcement to the ALSA sequencer system port, similarly like the
|
||||||
normal port change notification.
|
normal port change notification.
|
||||||
|
|
||||||
|
|
||||||
|
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::
|
||||||
|
|
||||||
|
% 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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
Loading…
Reference in New Issue
Block a user