]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ALSA: seq: Fix delivery of UMP events to group ports
authorTakashi Iwai <tiwai@suse.de>
Sun, 11 May 2025 13:45:27 +0000 (15:45 +0200)
committerTakashi Iwai <tiwai@suse.de>
Sun, 11 May 2025 13:58:06 +0000 (15:58 +0200)
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>
sound/core/seq/seq_clientmgr.c
sound/core/seq/seq_ump_convert.c
sound/core/seq/seq_ump_convert.h

index 198c598a539398deb636075d462fecd2b43c7e29..880240924bfd0526a61b991f261b49d12253e601 100644 (file)
@@ -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);
-       }
-
-       if (client->ump_endpoint_port < 0 ||
-           event->source.port == client->ump_endpoint_port)
-               return ret;
+       int ret;
+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
+       int ret2;
+#endif
 
-       src_port = snd_seq_port_use_ptr(client, client->ump_endpoint_port);
-       if (!src_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;
-       ret2 = __deliver_to_subscribers(client, event, src_port, atomic, hop);
-       snd_seq_port_unlock(src_port);
-       return ret2 < 0 ? ret2 : ret;
+       /* 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;
 }
 
 /* deliver an event to the destination port(s).
index ff7e558b4d51d044d212ec0b712ffa8c05d41f55..db2f169cae11ea99bdec2325bc2b427f405f313c 100644 (file)
@@ -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;
+}
index 6c146d8032804f370899b47f64b726abb8545d4d..4abf0a7637d70146e971e18f7d8a471e10781184 100644 (file)
@@ -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 */