Commit ff7b190a authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: seq: Fix delivery of UMP events to group ports

When an event with UMP message is sent to a UMP client, the EP port
receives always no matter where the event is sent to, as it's a
catch-all port.  OTOH, if an event is sent to EP port, and if the
event has a certain UMP Group, it should have been delivered to the
associated UMP Group port, too, but this was ignored, so far.

This patch addresses the behavior.  Now a UMP event sent to the
Endpoint port will be delivered to the subscribers of the UMP group
port the event is associated with.

The patch also does a bit of refactoring to simplify the code about
__deliver_to_subscribers().

Fixes: 177ccf81 ("ALSA: seq: Support MIDI 2.0 UMP Endpoint port")
Link: https://patch.msgid.link/20250511134528.6314-1-tiwai@suse.de


Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 6e5bea1c
Loading
Loading
Loading
Loading
+33 −19
Original line number Diff line number Diff line
@@ -732,15 +732,21 @@ static int snd_seq_deliver_single_event(struct snd_seq_client *client,
 */
static int __deliver_to_subscribers(struct snd_seq_client *client,
				    struct snd_seq_event *event,
				    struct snd_seq_client_port *src_port,
				    int atomic, int hop)
				    int port, int atomic, int hop)
{
	struct snd_seq_client_port *src_port;
	struct snd_seq_subscribers *subs;
	int err, result = 0, num_ev = 0;
	union __snd_seq_event event_saved;
	size_t saved_size;
	struct snd_seq_port_subs_info *grp;

	if (port < 0)
		return 0;
	src_port = snd_seq_port_use_ptr(client, port);
	if (!src_port)
		return 0;

	/* save original event record */
	saved_size = snd_seq_event_packet_size(event);
	memcpy(&event_saved, event, saved_size);
@@ -775,6 +781,7 @@ static int __deliver_to_subscribers(struct snd_seq_client *client,
		read_unlock(&grp->list_lock);
	else
		up_read(&grp->list_mutex);
	snd_seq_port_unlock(src_port);
	memcpy(event, &event_saved, saved_size);
	return (result < 0) ? result : num_ev;
}
@@ -783,25 +790,32 @@ static int deliver_to_subscribers(struct snd_seq_client *client,
				  struct snd_seq_event *event,
				  int atomic, int hop)
{
	struct snd_seq_client_port *src_port;
	int ret = 0, ret2;

	src_port = snd_seq_port_use_ptr(client, event->source.port);
	if (src_port) {
		ret = __deliver_to_subscribers(client, event, src_port, atomic, hop);
		snd_seq_port_unlock(src_port);
	}
	int ret;
#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
	int ret2;
#endif

	if (client->ump_endpoint_port < 0 ||
	    event->source.port == client->ump_endpoint_port)
	ret = __deliver_to_subscribers(client, event,
				       event->source.port, atomic, hop);
#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
	if (!snd_seq_client_is_ump(client) || client->ump_endpoint_port < 0)
		return ret;

	src_port = snd_seq_port_use_ptr(client, client->ump_endpoint_port);
	if (!src_port)
	/* If it's an event from EP port (and with a UMP group),
	 * deliver to subscribers of the corresponding UMP group port, too.
	 * Or, if it's from non-EP port, deliver to subscribers of EP port, too.
	 */
	if (event->source.port == client->ump_endpoint_port)
		ret2 = __deliver_to_subscribers(client, event,
						snd_seq_ump_group_port(event),
						atomic, hop);
	else
		ret2 = __deliver_to_subscribers(client, event,
						client->ump_endpoint_port,
						atomic, hop);
	if (ret2 < 0)
		return ret2;
#endif
	return ret;
	ret2 = __deliver_to_subscribers(client, event, src_port, atomic, hop);
	snd_seq_port_unlock(src_port);
	return ret2 < 0 ? ret2 : ret;
}

/* deliver an event to the destination port(s).
+18 −0
Original line number Diff line number Diff line
@@ -1285,3 +1285,21 @@ int snd_seq_deliver_to_ump(struct snd_seq_client *source,
	else
		return cvt_to_ump_midi1(dest, dest_port, event, atomic, hop);
}

/* return the UMP group-port number of the event;
 * return -1 if groupless or non-UMP event
 */
int snd_seq_ump_group_port(const struct snd_seq_event *event)
{
	const struct snd_seq_ump_event *ump_ev =
		(const struct snd_seq_ump_event *)event;
	unsigned char type;

	if (!snd_seq_ev_is_ump(event))
		return -1;
	type = ump_message_type(ump_ev->ump[0]);
	if (ump_is_groupless_msg(type))
		return -1;
	/* group-port number starts from 1 */
	return ump_message_group(ump_ev->ump[0]) + 1;
}
+1 −0
Original line number Diff line number Diff line
@@ -18,5 +18,6 @@ int snd_seq_deliver_to_ump(struct snd_seq_client *source,
			   struct snd_seq_client_port *dest_port,
			   struct snd_seq_event *event,
			   int atomic, int hop);
int snd_seq_ump_group_port(const struct snd_seq_event *event);

#endif /* __SEQ_UMP_CONVERT_H */