diff options
author | Takashi Iwai <tiwai@suse.de> | 2023-05-23 10:53:54 +0300 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2023-05-23 13:11:35 +0300 |
commit | 4025f0e627e127c79d372c6227b9a200406329f9 (patch) | |
tree | 204934494a29a2b3589b4bb193a79b27bba40488 | |
parent | 81fd444aa371261cd33f31d4ffd80faeeeab0cc9 (diff) | |
download | linux-4025f0e627e127c79d372c6227b9a200406329f9.tar.xz |
ALSA: seq: ump: Create UMP Endpoint port for broadcast
Create a sequencer port for broadcasting the all group inputs at the
port number 0. This corresponds to a UMP Endpoint connection;
application can read all UMP events from this port no matter which
group the UMP packet belongs to.
Unlike seq ports for other UMP groups, a UMP Endpoint port has no
SND_SEQ_PORT_TYPE_MIDI_GENERIC bit, so that it won't be treated as a
normal MIDI 1.0 device from legacy applications.
The port is named as "MIDI 2.0" to align with representations on other
operation systems.
Reviewed-by: Jaroslav Kysela <perex@perex.cz>
Link: https://lore.kernel.org/r/20230523075358.9672-34-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | sound/core/seq/seq_ump_client.c | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/sound/core/seq/seq_ump_client.c b/sound/core/seq/seq_ump_client.c index 8d360655ff5d..600b061ac8c3 100644 --- a/sound/core/seq/seq_ump_client.c +++ b/sound/core/seq/seq_ump_client.c @@ -290,6 +290,62 @@ static void update_group_attrs(struct seq_ump_client *client) } } +/* create a UMP Endpoint port */ +static int create_ump_endpoint_port(struct seq_ump_client *client) +{ + struct snd_seq_port_info *port; + struct snd_seq_port_callback pcallbacks; + unsigned int rawmidi_info = client->ump->core.info_flags; + int err; + + port = kzalloc(sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + port->addr.client = client->seq_client; + port->addr.port = 0; /* fixed */ + port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT; + port->capability = SNDRV_SEQ_PORT_CAP_UMP_ENDPOINT; + if (rawmidi_info & SNDRV_RAWMIDI_INFO_INPUT) { + port->capability |= SNDRV_SEQ_PORT_CAP_READ | + SNDRV_SEQ_PORT_CAP_SYNC_READ | + SNDRV_SEQ_PORT_CAP_SUBS_READ; + port->direction |= SNDRV_SEQ_PORT_DIR_INPUT; + } + if (rawmidi_info & SNDRV_RAWMIDI_INFO_OUTPUT) { + port->capability |= SNDRV_SEQ_PORT_CAP_WRITE | + SNDRV_SEQ_PORT_CAP_SYNC_WRITE | + SNDRV_SEQ_PORT_CAP_SUBS_WRITE; + port->direction |= SNDRV_SEQ_PORT_DIR_OUTPUT; + } + if (rawmidi_info & SNDRV_RAWMIDI_INFO_DUPLEX) + port->capability |= SNDRV_SEQ_PORT_CAP_DUPLEX; + port->ump_group = 0; /* no associated group, no conversion */ + port->type = SNDRV_SEQ_PORT_TYPE_MIDI_UMP | + SNDRV_SEQ_PORT_TYPE_HARDWARE | + SNDRV_SEQ_PORT_TYPE_PORT; + port->midi_channels = 16; + strcpy(port->name, "MIDI 2.0"); + memset(&pcallbacks, 0, sizeof(pcallbacks)); + pcallbacks.owner = THIS_MODULE; + pcallbacks.private_data = client; + if (rawmidi_info & SNDRV_RAWMIDI_INFO_INPUT) { + pcallbacks.subscribe = seq_ump_subscribe; + pcallbacks.unsubscribe = seq_ump_unsubscribe; + } + if (rawmidi_info & SNDRV_RAWMIDI_INFO_OUTPUT) { + pcallbacks.use = seq_ump_use; + pcallbacks.unuse = seq_ump_unuse; + pcallbacks.event_input = seq_ump_process_event; + } + port->kernel = &pcallbacks; + err = snd_seq_kernel_client_ctl(client->seq_client, + SNDRV_SEQ_IOCTL_CREATE_PORT, + port); + kfree(port); + return err; +} + /* release the client resources */ static void seq_ump_client_free(struct seq_ump_client *client) { @@ -353,6 +409,10 @@ static int snd_seq_ump_probe(struct device *_dev) goto error; } + err = create_ump_endpoint_port(client); + if (err < 0) + goto error; + ump->seq_client = client; ump->seq_ops = &seq_ump_ops; return 0; |