summaryrefslogtreecommitdiff
path: root/sound/core/seq/seq_ump_client.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/seq/seq_ump_client.c')
-rw-r--r--sound/core/seq/seq_ump_client.c79
1 files changed, 78 insertions, 1 deletions
diff --git a/sound/core/seq/seq_ump_client.c b/sound/core/seq/seq_ump_client.c
index e24833804094..fe21c801af74 100644
--- a/sound/core/seq/seq_ump_client.c
+++ b/sound/core/seq/seq_ump_client.c
@@ -13,6 +13,7 @@
#include <sound/seq_kernel.h>
#include <sound/seq_device.h>
#include "seq_clientmgr.h"
+#include "seq_system.h"
struct seq_ump_client;
struct seq_ump_group;
@@ -48,6 +49,7 @@ struct seq_ump_client {
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 */
};
/* number of 32bit words for each UMP message type */
@@ -73,7 +75,10 @@ static void seq_ump_input_receive(struct snd_ump_endpoint *ump,
if (!client->opened[STR_IN])
return;
- ev.source.port = ump_group_to_seq_port(ump_message_group(*val));
+ if (ump_is_groupless_msg(ump_message_type(*val)))
+ ev.source.port = 0; /* UMP EP port */
+ else
+ ev.source.port = ump_group_to_seq_port(ump_message_group(*val));
ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
ev.flags = SNDRV_SEQ_EVENT_UMP;
memcpy(ev.ump, val, words << 2);
@@ -241,6 +246,42 @@ static int seq_ump_group_init(struct seq_ump_client *client, int group_index)
return err;
}
+/* update the sequencer ports; called from notify_fb_change callback */
+static void update_port_infos(struct seq_ump_client *client)
+{
+ struct snd_seq_port_info *old, *new;
+ int i, err;
+
+ old = kzalloc(sizeof(*old), GFP_KERNEL);
+ new = kzalloc(sizeof(*new), GFP_KERNEL);
+ if (!old || !new)
+ goto error;
+
+ for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) {
+ old->addr.client = client->seq_client;
+ old->addr.port = i;
+ err = snd_seq_kernel_client_ctl(client->seq_client,
+ SNDRV_SEQ_IOCTL_GET_PORT_INFO,
+ old);
+ if (err < 0)
+ goto error;
+ fill_port_info(new, client, &client->groups[i]);
+ if (old->capability == new->capability &&
+ !strcmp(old->name, new->name))
+ continue;
+ err = snd_seq_kernel_client_ctl(client->seq_client,
+ SNDRV_SEQ_IOCTL_SET_PORT_INFO,
+ new);
+ if (err < 0)
+ goto error;
+ /* notify to system port */
+ snd_seq_system_client_ev_port_change(client->seq_client, i);
+ }
+ error:
+ kfree(new);
+ kfree(old);
+}
+
/* update dir_bits and active flag for all groups in the client */
static void update_group_attrs(struct seq_ump_client *client)
{
@@ -350,6 +391,8 @@ static int create_ump_endpoint_port(struct seq_ump_client *client)
/* release the client resources */
static void seq_ump_client_free(struct seq_ump_client *client)
{
+ cancel_work_sync(&client->group_notify_work);
+
if (client->seq_client >= 0)
snd_seq_delete_kernel_client(client->seq_client);
@@ -374,8 +417,41 @@ static void setup_client_midi_version(struct seq_ump_client *client)
snd_seq_kernel_client_put(cptr);
}
+/* UMP group change notification */
+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);
+}
+
+/* UMP FB change notification */
+static int seq_ump_notify_fb_change(struct snd_ump_endpoint *ump,
+ struct snd_ump_block *fb)
+{
+ struct seq_ump_client *client = ump->seq_client;
+
+ if (!client)
+ return -ENODEV;
+ schedule_work(&client->group_notify_work);
+ return 0;
+}
+
+/* UMP protocol change notification; just update the midi_version field */
+static int seq_ump_switch_protocol(struct snd_ump_endpoint *ump)
+{
+ if (!ump->seq_client)
+ return -ENODEV;
+ setup_client_midi_version(ump->seq_client);
+ return 0;
+}
+
static const struct snd_seq_ump_ops seq_ump_ops = {
.input_receive = seq_ump_input_receive,
+ .notify_fb_change = seq_ump_notify_fb_change,
+ .switch_protocol = seq_ump_switch_protocol,
};
/* create a sequencer client and ports for the given UMP endpoint */
@@ -393,6 +469,7 @@ static int snd_seq_ump_probe(struct device *_dev)
if (!client)
return -ENOMEM;
+ INIT_WORK(&client->group_notify_work, handle_group_notify);
client->ump = ump;
client->seq_client =