Commit 4025f0e6 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

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: default avatarJaroslav Kysela <perex@perex.cz>
Link: https://lore.kernel.org/r/20230523075358.9672-34-tiwai@suse.de


Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 81fd444a
Loading
Loading
Loading
Loading
+60 −0
Original line number Diff line number Diff line
@@ -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;