Skip to content

Commit 4a16a3a

Browse files
committed
ALSA: seq: ump: Handle FB info update
This patch implements the handling of the dynamic update of FB info. When the FB info update is received after the initial parsing, it means the dynamic FB info update. We compare the result, and if the actual update is detected, it's notified via a new ops, notify_fb_change, to the sequencer client, and the corresponding sequencer ports are updated accordingly. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent 5437ac9 commit 4a16a3a

File tree

3 files changed

+106
-6
lines changed

3 files changed

+106
-6
lines changed

include/sound/ump.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ struct snd_ump_ops {
7070
struct snd_seq_ump_ops {
7171
void (*input_receive)(struct snd_ump_endpoint *ump,
7272
const u32 *data, int words);
73+
int (*notify_fb_change)(struct snd_ump_endpoint *ump,
74+
struct snd_ump_block *fb);
7375
};
7476

7577
struct snd_ump_block {

sound/core/seq/seq_ump_client.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ struct seq_ump_client {
4848
struct seq_ump_input_buffer input; /* input parser context */
4949
struct seq_ump_group groups[SNDRV_UMP_MAX_GROUPS]; /* table of groups */
5050
void *ump_info[SNDRV_UMP_MAX_BLOCKS + 1]; /* shadow of seq client ump_info */
51+
struct work_struct group_notify_work; /* FB change notification */
5152
};
5253

5354
/* number of 32bit words for each UMP message type */
@@ -244,6 +245,40 @@ static int seq_ump_group_init(struct seq_ump_client *client, int group_index)
244245
return err;
245246
}
246247

248+
/* update the sequencer ports; called from notify_fb_change callback */
249+
static void update_port_infos(struct seq_ump_client *client)
250+
{
251+
struct snd_seq_port_info *old, *new;
252+
int i, err;
253+
254+
old = kzalloc(sizeof(*old), GFP_KERNEL);
255+
new = kzalloc(sizeof(*new), GFP_KERNEL);
256+
if (!old || !new)
257+
goto error;
258+
259+
for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) {
260+
old->addr.client = client->seq_client;
261+
old->addr.port = i;
262+
err = snd_seq_kernel_client_ctl(client->seq_client,
263+
SNDRV_SEQ_IOCTL_GET_PORT_INFO,
264+
old);
265+
if (err < 0)
266+
goto error;
267+
fill_port_info(new, client, &client->groups[i]);
268+
if (old->capability == new->capability &&
269+
!strcmp(old->name, new->name))
270+
continue;
271+
err = snd_seq_kernel_client_ctl(client->seq_client,
272+
SNDRV_SEQ_IOCTL_SET_PORT_INFO,
273+
new);
274+
if (err < 0)
275+
goto error;
276+
}
277+
error:
278+
kfree(new);
279+
kfree(old);
280+
}
281+
247282
/* update dir_bits and active flag for all groups in the client */
248283
static void update_group_attrs(struct seq_ump_client *client)
249284
{
@@ -353,6 +388,8 @@ static int create_ump_endpoint_port(struct seq_ump_client *client)
353388
/* release the client resources */
354389
static void seq_ump_client_free(struct seq_ump_client *client)
355390
{
391+
cancel_work_sync(&client->group_notify_work);
392+
356393
if (client->seq_client >= 0)
357394
snd_seq_delete_kernel_client(client->seq_client);
358395

@@ -377,8 +414,31 @@ static void setup_client_midi_version(struct seq_ump_client *client)
377414
snd_seq_kernel_client_put(cptr);
378415
}
379416

417+
/* UMP group change notification */
418+
static void handle_group_notify(struct work_struct *work)
419+
{
420+
struct seq_ump_client *client =
421+
container_of(work, struct seq_ump_client, group_notify_work);
422+
423+
update_group_attrs(client);
424+
update_port_infos(client);
425+
}
426+
427+
/* UMP FB change notification */
428+
static int seq_ump_notify_fb_change(struct snd_ump_endpoint *ump,
429+
struct snd_ump_block *fb)
430+
{
431+
struct seq_ump_client *client = ump->seq_client;
432+
433+
if (!client)
434+
return -ENODEV;
435+
schedule_work(&client->group_notify_work);
436+
return 0;
437+
}
438+
380439
static const struct snd_seq_ump_ops seq_ump_ops = {
381440
.input_receive = seq_ump_input_receive,
441+
.notify_fb_change = seq_ump_notify_fb_change,
382442
};
383443

384444
/* create a sequencer client and ports for the given UMP endpoint */
@@ -396,6 +456,7 @@ static int snd_seq_ump_probe(struct device *_dev)
396456
if (!client)
397457
return -ENOMEM;
398458

459+
INIT_WORK(&client->group_notify_work, handle_group_notify);
399460
client->ump = ump;
400461

401462
client->seq_client =

sound/core/ump.c

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,28 @@ static void fill_fb_info(struct snd_ump_endpoint *ump,
688688
info->sysex8_streams, info->flags);
689689
}
690690

691+
/* check whether the FB info gets updated by the current message */
692+
static bool is_fb_info_updated(struct snd_ump_endpoint *ump,
693+
struct snd_ump_block *fb,
694+
const union snd_ump_stream_msg *buf)
695+
{
696+
char tmpbuf[offsetof(struct snd_ump_block_info, name)];
697+
698+
memcpy(tmpbuf, &fb->info, sizeof(tmpbuf));
699+
fill_fb_info(ump, (struct snd_ump_block_info *)tmpbuf, buf);
700+
return memcmp(&fb->info, tmpbuf, sizeof(tmpbuf)) != 0;
701+
}
702+
703+
/* notify the FB info/name change to sequencer */
704+
static void seq_notify_fb_change(struct snd_ump_endpoint *ump,
705+
struct snd_ump_block *fb)
706+
{
707+
#if IS_ENABLED(CONFIG_SND_SEQUENCER)
708+
if (ump->seq_ops && ump->seq_ops->notify_fb_change)
709+
ump->seq_ops->notify_fb_change(ump, fb);
710+
#endif
711+
}
712+
691713
/* handle FB info message; update FB info if the block is present */
692714
static int ump_handle_fb_info_msg(struct snd_ump_endpoint *ump,
693715
const union snd_ump_stream_msg *buf)
@@ -697,14 +719,24 @@ static int ump_handle_fb_info_msg(struct snd_ump_endpoint *ump,
697719

698720
blk = buf->fb_info.function_block_id;
699721
fb = snd_ump_get_block(ump, blk);
700-
if (fb) {
701-
fill_fb_info(ump, &fb->info, buf);
702-
} else if (ump->parsed) {
703-
/* complain only if updated after parsing */
722+
723+
/* complain only if updated after parsing */
724+
if (!fb && ump->parsed) {
704725
ump_info(ump, "Function Block Info Update for non-existing block %d\n",
705726
blk);
706727
return -ENODEV;
707728
}
729+
730+
/* When updated after the initial parse, check the FB info update */
731+
if (ump->parsed && !is_fb_info_updated(ump, fb, buf))
732+
return 1; /* no content change */
733+
734+
if (fb) {
735+
fill_fb_info(ump, &fb->info, buf);
736+
if (ump->parsed)
737+
seq_notify_fb_change(ump, fb);
738+
}
739+
708740
return 1; /* finished */
709741
}
710742

@@ -714,14 +746,19 @@ static int ump_handle_fb_name_msg(struct snd_ump_endpoint *ump,
714746
{
715747
unsigned char blk;
716748
struct snd_ump_block *fb;
749+
int ret;
717750

718751
blk = buf->fb_name.function_block_id;
719752
fb = snd_ump_get_block(ump, blk);
720753
if (!fb)
721754
return -ENODEV;
722755

723-
return ump_append_string(ump, fb->info.name, sizeof(fb->info.name),
724-
buf->raw, 3);
756+
ret = ump_append_string(ump, fb->info.name, sizeof(fb->info.name),
757+
buf->raw, 3);
758+
/* notify the FB name update to sequencer, too */
759+
if (ret > 0 && ump->parsed)
760+
seq_notify_fb_change(ump, fb);
761+
return ret;
725762
}
726763

727764
static int create_block_from_fb_info(struct snd_ump_endpoint *ump, int blk)

0 commit comments

Comments
 (0)