1

ALSA: ump: Update substream name from assigned FB names

We had a nice name scheme in ALSA sequencer UMP binding for each
sequencer port referring to each assigned Function Block name, while
the legacy rawmidi refers only to the UMP Endpoint name.  It's better
to align both.

This patch moves the UMP Group attribute update functions into the
core UMP code from the sequencer binding code, and improve the
substream name of the legacy rawmidi.

Link: https://patch.msgid.link/20240729141315.18253-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Iwai 2024-07-29 16:13:14 +02:00
parent 4e9652003b
commit 0642a3c5ca
3 changed files with 86 additions and 73 deletions

View File

@ -13,6 +13,14 @@ struct snd_ump_ops;
struct ump_cvt_to_ump; struct ump_cvt_to_ump;
struct snd_seq_ump_ops; struct snd_seq_ump_ops;
struct snd_ump_group {
int group; /* group index (0-based) */
unsigned int dir_bits; /* directions */
bool active; /* activeness */
bool valid; /* valid group (referred by blocks) */
char name[64]; /* group name */
};
struct snd_ump_endpoint { struct snd_ump_endpoint {
struct snd_rawmidi core; /* raw UMP access */ struct snd_rawmidi core; /* raw UMP access */
@ -41,6 +49,8 @@ struct snd_ump_endpoint {
struct mutex open_mutex; struct mutex open_mutex;
struct snd_ump_group groups[SNDRV_UMP_MAX_GROUPS]; /* table of groups */
#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI) #if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI)
spinlock_t legacy_locks[2]; spinlock_t legacy_locks[2];
struct snd_rawmidi *legacy_rmidi; struct snd_rawmidi *legacy_rmidi;

View File

@ -23,15 +23,6 @@ enum {
STR_OUT = SNDRV_RAWMIDI_STREAM_OUTPUT STR_OUT = SNDRV_RAWMIDI_STREAM_OUTPUT
}; };
/* object per UMP group; corresponding to a sequencer port */
struct seq_ump_group {
int group; /* group index (0-based) */
unsigned int dir_bits; /* directions */
bool active; /* activeness */
bool valid; /* valid group (referred by blocks) */
char name[64]; /* seq port name */
};
/* context for UMP input parsing, per EP */ /* context for UMP input parsing, per EP */
struct seq_ump_input_buffer { struct seq_ump_input_buffer {
unsigned char len; /* total length in words */ unsigned char len; /* total length in words */
@ -48,7 +39,6 @@ struct seq_ump_client {
int opened[2]; /* current opens for each direction */ int opened[2]; /* current opens for each direction */
struct snd_rawmidi_file out_rfile; /* rawmidi for output */ struct snd_rawmidi_file out_rfile; /* rawmidi for output */
struct seq_ump_input_buffer input; /* input parser context */ struct seq_ump_input_buffer input; /* input parser context */
struct seq_ump_group groups[SNDRV_UMP_MAX_GROUPS]; /* table of groups */
void *ump_info[SNDRV_UMP_MAX_BLOCKS + 1]; /* shadow of seq client ump_info */ void *ump_info[SNDRV_UMP_MAX_BLOCKS + 1]; /* shadow of seq client ump_info */
struct work_struct group_notify_work; /* FB change notification */ struct work_struct group_notify_work; /* FB change notification */
}; };
@ -175,7 +165,7 @@ static int seq_ump_unuse(void *pdata, struct snd_seq_port_subscribe *info)
/* fill port_info from the given UMP EP and group info */ /* fill port_info from the given UMP EP and group info */
static void fill_port_info(struct snd_seq_port_info *port, static void fill_port_info(struct snd_seq_port_info *port,
struct seq_ump_client *client, struct seq_ump_client *client,
struct seq_ump_group *group) struct snd_ump_group *group)
{ {
unsigned int rawmidi_info = client->ump->core.info_flags; unsigned int rawmidi_info = client->ump->core.info_flags;
@ -212,7 +202,7 @@ static void fill_port_info(struct snd_seq_port_info *port,
} }
/* skip non-existing group for static blocks */ /* skip non-existing group for static blocks */
static bool skip_group(struct seq_ump_client *client, struct seq_ump_group *group) static bool skip_group(struct seq_ump_client *client, struct snd_ump_group *group)
{ {
return !group->valid && return !group->valid &&
(client->ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS); (client->ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS);
@ -221,7 +211,7 @@ static bool skip_group(struct seq_ump_client *client, struct seq_ump_group *grou
/* create a new sequencer port per UMP group */ /* create a new sequencer port per UMP group */
static int seq_ump_group_init(struct seq_ump_client *client, int group_index) static int seq_ump_group_init(struct seq_ump_client *client, int group_index)
{ {
struct seq_ump_group *group = &client->groups[group_index]; struct snd_ump_group *group = &client->ump->groups[group_index];
struct snd_seq_port_info *port __free(kfree) = NULL; struct snd_seq_port_info *port __free(kfree) = NULL;
struct snd_seq_port_callback pcallbacks; struct snd_seq_port_callback pcallbacks;
@ -261,7 +251,7 @@ static void update_port_infos(struct seq_ump_client *client)
return; return;
for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) { for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) {
if (skip_group(client, &client->groups[i])) if (skip_group(client, &client->ump->groups[i]))
continue; continue;
old->addr.client = client->seq_client; old->addr.client = client->seq_client;
@ -271,7 +261,7 @@ static void update_port_infos(struct seq_ump_client *client)
old); old);
if (err < 0) if (err < 0)
return; return;
fill_port_info(new, client, &client->groups[i]); fill_port_info(new, client, &client->ump->groups[i]);
if (old->capability == new->capability && if (old->capability == new->capability &&
!strcmp(old->name, new->name)) !strcmp(old->name, new->name))
continue; continue;
@ -285,57 +275,6 @@ static void update_port_infos(struct seq_ump_client *client)
} }
} }
/* update dir_bits and active flag for all groups in the client */
static void update_group_attrs(struct seq_ump_client *client)
{
struct snd_ump_block *fb;
struct seq_ump_group *group;
int i;
for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) {
group = &client->groups[i];
*group->name = 0;
group->dir_bits = 0;
group->active = 0;
group->group = i;
group->valid = false;
}
list_for_each_entry(fb, &client->ump->block_list, list) {
if (fb->info.first_group + fb->info.num_groups > SNDRV_UMP_MAX_GROUPS)
break;
group = &client->groups[fb->info.first_group];
for (i = 0; i < fb->info.num_groups; i++, group++) {
group->valid = true;
if (fb->info.active)
group->active = 1;
switch (fb->info.direction) {
case SNDRV_UMP_DIR_INPUT:
group->dir_bits |= (1 << STR_IN);
break;
case SNDRV_UMP_DIR_OUTPUT:
group->dir_bits |= (1 << STR_OUT);
break;
case SNDRV_UMP_DIR_BIDIRECTION:
group->dir_bits |= (1 << STR_OUT) | (1 << STR_IN);
break;
}
if (!*fb->info.name)
continue;
if (!*group->name) {
/* store the first matching name */
strscpy(group->name, fb->info.name,
sizeof(group->name));
} else {
/* when overlapping, concat names */
strlcat(group->name, ", ", sizeof(group->name));
strlcat(group->name, fb->info.name,
sizeof(group->name));
}
}
}
}
/* create a UMP Endpoint port */ /* create a UMP Endpoint port */
static int create_ump_endpoint_port(struct seq_ump_client *client) static int create_ump_endpoint_port(struct seq_ump_client *client)
{ {
@ -432,7 +371,7 @@ static void setup_client_group_filter(struct seq_ump_client *client)
return; return;
filter = ~(1U << 0); /* always allow groupless messages */ filter = ~(1U << 0); /* always allow groupless messages */
for (p = 0; p < SNDRV_UMP_MAX_GROUPS; p++) { for (p = 0; p < SNDRV_UMP_MAX_GROUPS; p++) {
if (client->groups[p].active) if (client->ump->groups[p].active)
filter &= ~(1U << (p + 1)); filter &= ~(1U << (p + 1));
} }
cptr->group_filter = filter; cptr->group_filter = filter;
@ -445,7 +384,6 @@ static void handle_group_notify(struct work_struct *work)
struct seq_ump_client *client = struct seq_ump_client *client =
container_of(work, struct seq_ump_client, group_notify_work); container_of(work, struct seq_ump_client, group_notify_work);
update_group_attrs(client);
update_port_infos(client); update_port_infos(client);
setup_client_group_filter(client); setup_client_group_filter(client);
} }
@ -508,7 +446,6 @@ static int snd_seq_ump_probe(struct device *_dev)
client->ump_info[fb->info.block_id + 1] = &fb->info; client->ump_info[fb->info.block_id + 1] = &fb->info;
setup_client_midi_version(client); setup_client_midi_version(client);
update_group_attrs(client);
for (p = 0; p < SNDRV_UMP_MAX_GROUPS; p++) { for (p = 0; p < SNDRV_UMP_MAX_GROUPS; p++) {
err = seq_ump_group_init(client, p); err = seq_ump_group_init(client, p);

View File

@ -524,6 +524,58 @@ static void snd_ump_proc_read(struct snd_info_entry *entry,
} }
} }
/* update dir_bits and active flag for all groups in the client */
static void update_group_attrs(struct snd_ump_endpoint *ump)
{
struct snd_ump_block *fb;
struct snd_ump_group *group;
int i;
for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) {
group = &ump->groups[i];
*group->name = 0;
group->dir_bits = 0;
group->active = 0;
group->group = i;
group->valid = false;
}
list_for_each_entry(fb, &ump->block_list, list) {
if (fb->info.first_group + fb->info.num_groups > SNDRV_UMP_MAX_GROUPS)
break;
group = &ump->groups[fb->info.first_group];
for (i = 0; i < fb->info.num_groups; i++, group++) {
group->valid = true;
if (fb->info.active)
group->active = 1;
switch (fb->info.direction) {
case SNDRV_UMP_DIR_INPUT:
group->dir_bits |= (1 << SNDRV_RAWMIDI_STREAM_INPUT);
break;
case SNDRV_UMP_DIR_OUTPUT:
group->dir_bits |= (1 << SNDRV_RAWMIDI_STREAM_OUTPUT);
break;
case SNDRV_UMP_DIR_BIDIRECTION:
group->dir_bits |= (1 << SNDRV_RAWMIDI_STREAM_INPUT) |
(1 << SNDRV_RAWMIDI_STREAM_OUTPUT);
break;
}
if (!*fb->info.name)
continue;
if (!*group->name) {
/* store the first matching name */
strscpy(group->name, fb->info.name,
sizeof(group->name));
} else {
/* when overlapping, concat names */
strlcat(group->name, ", ", sizeof(group->name));
strlcat(group->name, fb->info.name,
sizeof(group->name));
}
}
}
}
/* /*
* UMP endpoint and function block handling * UMP endpoint and function block handling
*/ */
@ -792,9 +844,11 @@ static int ump_handle_fb_info_msg(struct snd_ump_endpoint *ump,
if (fb) { if (fb) {
fill_fb_info(ump, &fb->info, buf); fill_fb_info(ump, &fb->info, buf);
if (ump->parsed) if (ump->parsed) {
update_group_attrs(ump);
seq_notify_fb_change(ump, fb); seq_notify_fb_change(ump, fb);
} }
}
return 1; /* finished */ return 1; /* finished */
} }
@ -822,8 +876,10 @@ static int ump_handle_fb_name_msg(struct snd_ump_endpoint *ump,
ret = ump_append_string(ump, fb->info.name, sizeof(fb->info.name), ret = ump_append_string(ump, fb->info.name, sizeof(fb->info.name),
buf->raw, 3); buf->raw, 3);
/* notify the FB name update to sequencer, too */ /* notify the FB name update to sequencer, too */
if (ret > 0 && ump->parsed) if (ret > 0 && ump->parsed) {
update_group_attrs(ump);
seq_notify_fb_change(ump, fb); seq_notify_fb_change(ump, fb);
}
return ret; return ret;
} }
@ -995,6 +1051,9 @@ int snd_ump_parse_endpoint(struct snd_ump_endpoint *ump)
continue; continue;
} }
/* initialize group attributions */
update_group_attrs(ump);
error: error:
ump->parsed = true; ump->parsed = true;
ump_request_close(ump); ump_request_close(ump);
@ -1172,10 +1231,17 @@ static void fill_substream_names(struct snd_ump_endpoint *ump,
struct snd_rawmidi *rmidi, int dir) struct snd_rawmidi *rmidi, int dir)
{ {
struct snd_rawmidi_substream *s; struct snd_rawmidi_substream *s;
const char *name;
int idx;
list_for_each_entry(s, &rmidi->streams[dir].substreams, list) list_for_each_entry(s, &rmidi->streams[dir].substreams, list) {
idx = ump->legacy_mapping[s->number];
name = ump->groups[idx].name;
if (!*name)
name = ump->info.name;
snprintf(s->name, sizeof(s->name), "Group %d (%.16s)", snprintf(s->name, sizeof(s->name), "Group %d (%.16s)",
ump->legacy_mapping[s->number] + 1, ump->info.name); idx + 1, name);
}
} }
int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump, int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump,