ALSA: seq: Fix delivery of UMP events to group ports
[ Upstream commit ff7b190aef6cccdb6f14d20c5753081fe6420e0b ]
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: 177ccf811d
("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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
e4d8a51732
commit
8a8dc7fd1e
@@ -736,15 +736,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);
|
||||
@@ -780,6 +786,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;
|
||||
}
|
||||
@@ -788,25 +795,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;
|
||||
int ret;
|
||||
#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
|
||||
int ret2;
|
||||
#endif
|
||||
|
||||
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)
|
||||
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)
|
||||
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).
|
||||
|
@@ -1284,3 +1284,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;
|
||||
}
|
||||
|
@@ -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 */
|
||||
|
Reference in New Issue
Block a user