Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: 177ccf811df4 ("ALSA: seq: Support MIDI 2.0 UMP Endpoint port")
Link: https://patch.msgid.link/20250511134528.6314-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>

+52 -19
+33 -19
sound/core/seq/seq_clientmgr.c
··· 732 732 */ 733 733 static int __deliver_to_subscribers(struct snd_seq_client *client, 734 734 struct snd_seq_event *event, 735 - struct snd_seq_client_port *src_port, 736 - int atomic, int hop) 735 + int port, int atomic, int hop) 737 736 { 737 + struct snd_seq_client_port *src_port; 738 738 struct snd_seq_subscribers *subs; 739 739 int err, result = 0, num_ev = 0; 740 740 union __snd_seq_event event_saved; 741 741 size_t saved_size; 742 742 struct snd_seq_port_subs_info *grp; 743 + 744 + if (port < 0) 745 + return 0; 746 + src_port = snd_seq_port_use_ptr(client, port); 747 + if (!src_port) 748 + return 0; 743 749 744 750 /* save original event record */ 745 751 saved_size = snd_seq_event_packet_size(event); ··· 781 775 read_unlock(&grp->list_lock); 782 776 else 783 777 up_read(&grp->list_mutex); 778 + snd_seq_port_unlock(src_port); 784 779 memcpy(event, &event_saved, saved_size); 785 780 return (result < 0) ? result : num_ev; 786 781 } ··· 790 783 struct snd_seq_event *event, 791 784 int atomic, int hop) 792 785 { 793 - struct snd_seq_client_port *src_port; 794 - int ret = 0, ret2; 786 + int ret; 787 + #if IS_ENABLED(CONFIG_SND_SEQ_UMP) 788 + int ret2; 789 + #endif 795 790 796 - src_port = snd_seq_port_use_ptr(client, event->source.port); 797 - if (src_port) { 798 - ret = __deliver_to_subscribers(client, event, src_port, atomic, hop); 799 - snd_seq_port_unlock(src_port); 800 - } 801 - 802 - if (client->ump_endpoint_port < 0 || 803 - event->source.port == client->ump_endpoint_port) 791 + ret = __deliver_to_subscribers(client, event, 792 + event->source.port, atomic, hop); 793 + #if IS_ENABLED(CONFIG_SND_SEQ_UMP) 794 + if (!snd_seq_client_is_ump(client) || client->ump_endpoint_port < 0) 804 795 return ret; 805 - 806 - src_port = snd_seq_port_use_ptr(client, client->ump_endpoint_port); 807 - if (!src_port) 808 - return ret; 809 - ret2 = __deliver_to_subscribers(client, event, src_port, atomic, hop); 810 - snd_seq_port_unlock(src_port); 811 - return ret2 < 0 ? ret2 : ret; 796 + /* If it's an event from EP port (and with a UMP group), 797 + * deliver to subscribers of the corresponding UMP group port, too. 798 + * Or, if it's from non-EP port, deliver to subscribers of EP port, too. 799 + */ 800 + if (event->source.port == client->ump_endpoint_port) 801 + ret2 = __deliver_to_subscribers(client, event, 802 + snd_seq_ump_group_port(event), 803 + atomic, hop); 804 + else 805 + ret2 = __deliver_to_subscribers(client, event, 806 + client->ump_endpoint_port, 807 + atomic, hop); 808 + if (ret2 < 0) 809 + return ret2; 810 + #endif 811 + return ret; 812 812 } 813 813 814 814 /* deliver an event to the destination port(s).
+18
sound/core/seq/seq_ump_convert.c
··· 1285 1285 else 1286 1286 return cvt_to_ump_midi1(dest, dest_port, event, atomic, hop); 1287 1287 } 1288 + 1289 + /* return the UMP group-port number of the event; 1290 + * return -1 if groupless or non-UMP event 1291 + */ 1292 + int snd_seq_ump_group_port(const struct snd_seq_event *event) 1293 + { 1294 + const struct snd_seq_ump_event *ump_ev = 1295 + (const struct snd_seq_ump_event *)event; 1296 + unsigned char type; 1297 + 1298 + if (!snd_seq_ev_is_ump(event)) 1299 + return -1; 1300 + type = ump_message_type(ump_ev->ump[0]); 1301 + if (ump_is_groupless_msg(type)) 1302 + return -1; 1303 + /* group-port number starts from 1 */ 1304 + return ump_message_group(ump_ev->ump[0]) + 1; 1305 + }
+1
sound/core/seq/seq_ump_convert.h
··· 18 18 struct snd_seq_client_port *dest_port, 19 19 struct snd_seq_event *event, 20 20 int atomic, int hop); 21 + int snd_seq_ump_group_port(const struct snd_seq_event *event); 21 22 22 23 #endif /* __SEQ_UMP_CONVERT_H */