Commit 0642a3c5 authored by Takashi Iwai's avatar Takashi Iwai

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.deSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 4e965200
......@@ -13,6 +13,14 @@ struct snd_ump_ops;
struct ump_cvt_to_ump;
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_rawmidi core; /* raw UMP access */
......@@ -41,6 +49,8 @@ struct snd_ump_endpoint {
struct mutex open_mutex;
struct snd_ump_group groups[SNDRV_UMP_MAX_GROUPS]; /* table of groups */
#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI)
spinlock_t legacy_locks[2];
struct snd_rawmidi *legacy_rmidi;
......
......@@ -23,15 +23,6 @@ enum {
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 */
struct seq_ump_input_buffer {
unsigned char len; /* total length in words */
......@@ -48,7 +39,6 @@ struct seq_ump_client {
int opened[2]; /* current opens for each direction */
struct snd_rawmidi_file out_rfile; /* rawmidi for output */
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 */
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 */
static void fill_port_info(struct snd_seq_port_info *port,
struct seq_ump_client *client,
struct seq_ump_group *group)
struct snd_ump_group *group)
{
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 */
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 &&
(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 */
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_callback pcallbacks;
......@@ -261,7 +251,7 @@ static void update_port_infos(struct seq_ump_client *client)
return;
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;
old->addr.client = client->seq_client;
......@@ -271,7 +261,7 @@ static void update_port_infos(struct seq_ump_client *client)
old);
if (err < 0)
return;
fill_port_info(new, client, &client->groups[i]);
fill_port_info(new, client, &client->ump->groups[i]);
if (old->capability == new->capability &&
!strcmp(old->name, new->name))
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 */
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;
filter = ~(1U << 0); /* always allow groupless messages */
for (p = 0; p < SNDRV_UMP_MAX_GROUPS; p++) {
if (client->groups[p].active)
if (client->ump->groups[p].active)
filter &= ~(1U << (p + 1));
}
cptr->group_filter = filter;
......@@ -445,7 +384,6 @@ static void handle_group_notify(struct work_struct *work)
struct seq_ump_client *client =
container_of(work, struct seq_ump_client, group_notify_work);
update_group_attrs(client);
update_port_infos(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;
setup_client_midi_version(client);
update_group_attrs(client);
for (p = 0; p < SNDRV_UMP_MAX_GROUPS; p++) {
err = seq_ump_group_init(client, p);
......
......@@ -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
*/
......@@ -792,8 +844,10 @@ static int ump_handle_fb_info_msg(struct snd_ump_endpoint *ump,
if (fb) {
fill_fb_info(ump, &fb->info, buf);
if (ump->parsed)
if (ump->parsed) {
update_group_attrs(ump);
seq_notify_fb_change(ump, fb);
}
}
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),
buf->raw, 3);
/* 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);
}
return ret;
}
......@@ -995,6 +1051,9 @@ int snd_ump_parse_endpoint(struct snd_ump_endpoint *ump)
continue;
}
/* initialize group attributions */
update_group_attrs(ump);
error:
ump->parsed = true;
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_substream *s;
list_for_each_entry(s, &rmidi->streams[dir].substreams, list)
const char *name;
int idx;
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)",
ump->legacy_mapping[s->number] + 1, ump->info.name);
idx + 1, name);
}
}
int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment