History

ALSA: seq: Add ioctls for client UMP info query and setup

Add new ioctls for sequencer clients to query and set the UMP endpoint and block information. As a sequencer client corresponds to a UMP Endpoint, one UMP Endpoint information can be assigned at most to a single sequencer client while multiple UMP block infos can be assigned by passing the type with the offset of block id (i.e. type = block_id + 1). For the kernel client, only SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO is allowed.

Takashi Iwai committed 3 years ago

Commit d2d247e1 parent 4025f0e5 files · +153 −2Browse files

Unified · Split

5 files
  1. include/uapi/sound/asequencer.h +14 −0
  2. sound/core/seq/seq_clientmgr.c +119 −1
  3. sound/core/seq/seq_clientmgr.h +3 −1
  4. sound/core/seq/seq_compat.c +2 −0
  5. sound/core/seq/seq_ump_client.c +15 −0
include/uapi/sound/asequencer.h+14−0
@@ -585,6 +585,18 @@ struct snd_seq_query_subs { · 584 unmodified lines
585585 char reserved[64]; /* for future use */
586586 };
587587
588+/*
589+ * UMP-specific information
590+ */
591+/* type of UMP info query */
592+#define SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT 0
593+#define SNDRV_SEQ_CLIENT_UMP_INFO_BLOCK 1
594+
595+struct snd_seq_client_ump_info {
596+ int client; /* client number to inquire/set */
597+ int type; /* type to inquire/set */
598+ unsigned char info[512]; /* info (either UMP ep or block info) */
599+} __packed;
588600
589601 /*
590602 * IOCTL commands
@@ -598,6 +610,8 @@ struct snd_seq_query_subs { · 7 unmodified lines
598610
599611 #define SNDRV_SEQ_IOCTL_GET_CLIENT_INFO _IOWR('S', 0x10, struct snd_seq_client_info)
600612 #define SNDRV_SEQ_IOCTL_SET_CLIENT_INFO _IOW ('S', 0x11, struct snd_seq_client_info)
613+#define SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO _IOWR('S', 0x12, struct snd_seq_client_ump_info)
614+#define SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO _IOWR('S', 0x13, struct snd_seq_client_ump_info)
601615
602616 #define SNDRV_SEQ_IOCTL_CREATE_PORT _IOWR('S', 0x20, struct snd_seq_port_info)
603617 #define SNDRV_SEQ_IOCTL_DELETE_PORT _IOW ('S', 0x21, struct snd_seq_port_info)
sound/core/seq/seq_clientmgr.c+119−1
@@ -14,6 +14,7 @@ · 13 unmodified lines
1414 #include <linux/kmod.h>
1515
1616 #include <sound/seq_kernel.h>
17+#include <sound/ump.h>
1718 #include "seq_clientmgr.h"
1819 #include "seq_memory.h"
1920 #include "seq_queue.h"
@@ -71,6 +72,10 @@ static int snd_seq_deliver_single_event(struct snd_seq_client *client, · 51 unmodified lines
7172 struct snd_seq_event *event,
7273 int filter, int atomic, int hop);
7374
75+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
76+static void free_ump_info(struct snd_seq_client *client);
77+#endif
78+
7479 /*
7580 */
7681 static inline unsigned short snd_seq_file_flags(struct file *file)
@@ -382,6 +387,9 @@ static int snd_seq_release(struct inode *inode, struct file *file) · 305 unmodified lines
382387 seq_free_client(client);
383388 if (client->data.user.fifo)
384389 snd_seq_fifo_delete(&client->data.user.fifo);
390+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
391+ free_ump_info(client);
392+#endif
385393 put_pid(client->data.user.owner);
386394 kfree(client);
387395 }
@@ -1282,7 +1290,6 @@ static int snd_seq_ioctl_set_client_info(struct snd_seq_client *client, · 894 unmodified lines
12821290 if (client->user_pversion >= SNDRV_PROTOCOL_VERSION(1, 0, 3))
12831291 client->midi_version = client_info->midi_version;
12841292 memcpy(client->event_filter, client_info->event_filter, 32);
1285−
12861293 return 0;
12871294 }
12881295
@@ -2087,6 +2094,108 @@ static int snd_seq_ioctl_query_next_port(struct snd_seq_client *client, · 798 unmodified lines
20872094 return 0;
20882095 }
20892096
2097+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
2098+#define NUM_UMP_INFOS (SNDRV_UMP_MAX_BLOCKS + 1)
2099+
2100+static void free_ump_info(struct snd_seq_client *client)
2101+{
2102+ int i;
2103+
2104+ if (!client->ump_info)
2105+ return;
2106+ for (i = 0; i < NUM_UMP_INFOS; i++)
2107+ kfree(client->ump_info[i]);
2108+ kfree(client->ump_info);
2109+ client->ump_info = NULL;
2110+}
2111+
2112+static void terminate_ump_info_strings(void *p, int type)
2113+{
2114+ if (type == SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT) {
2115+ struct snd_ump_endpoint_info *ep = p;
2116+ ep->name[sizeof(ep->name) - 1] = 0;
2117+ } else {
2118+ struct snd_ump_block_info *bp = p;
2119+ bp->name[sizeof(bp->name) - 1] = 0;
2120+ }
2121+}
2122+
2123+/* UMP-specific ioctls -- called directly without data copy */
2124+static int snd_seq_ioctl_client_ump_info(struct snd_seq_client *caller,
2125+ unsigned int cmd,
2126+ unsigned long arg)
2127+{
2128+ struct snd_seq_client_ump_info __user *argp =
2129+ (struct snd_seq_client_ump_info __user *)arg;
2130+ struct snd_seq_client *cptr;
2131+ int client, type, err = 0;
2132+ size_t size;
2133+ void *p;
2134+
2135+ if (get_user(client, &argp->client) || get_user(type, &argp->type))
2136+ return -EFAULT;
2137+ if (cmd == SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO &&
2138+ caller->number != client)
2139+ return -EPERM;
2140+ if (type < 0 || type >= NUM_UMP_INFOS)
2141+ return -EINVAL;
2142+ if (type == SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT)
2143+ size = sizeof(struct snd_ump_endpoint_info);
2144+ else
2145+ size = sizeof(struct snd_ump_block_info);
2146+ cptr = snd_seq_client_use_ptr(client);
2147+ if (!cptr)
2148+ return -ENOENT;
2149+
2150+ mutex_lock(&cptr->ioctl_mutex);
2151+ if (!cptr->midi_version) {
2152+ err = -EBADFD;
2153+ goto error;
2154+ }
2155+
2156+ if (cmd == SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO) {
2157+ if (!cptr->ump_info)
2158+ p = NULL;
2159+ else
2160+ p = cptr->ump_info[type];
2161+ if (!p) {
2162+ err = -ENODEV;
2163+ goto error;
2164+ }
2165+ if (copy_to_user(argp->info, p, size)) {
2166+ err = -EFAULT;
2167+ goto error;
2168+ }
2169+ } else {
2170+ if (cptr->type != USER_CLIENT) {
2171+ err = -EBADFD;
2172+ goto error;
2173+ }
2174+ if (!cptr->ump_info) {
2175+ cptr->ump_info = kcalloc(NUM_UMP_INFOS,
2176+ sizeof(void *), GFP_KERNEL);
2177+ if (!cptr->ump_info) {
2178+ err = -ENOMEM;
2179+ goto error;
2180+ }
2181+ }
2182+ p = memdup_user(argp->info, size);
2183+ if (IS_ERR(p)) {
2184+ err = PTR_ERR(p);
2185+ goto error;
2186+ }
2187+ kfree(cptr->ump_info[type]);
2188+ terminate_ump_info_strings(p, type);
2189+ cptr->ump_info[type] = p;
2190+ }
2191+
2192+ error:
2193+ mutex_unlock(&cptr->ioctl_mutex);
2194+ snd_seq_client_unlock(cptr);
2195+ return err;
2196+}
2197+#endif
2198+
20902199 /* -------------------------------------------------------- */
20912200
20922201 static const struct ioctl_handler {
@@ -2157,6 +2266,15 @@ static long snd_seq_ioctl(struct file *file, unsigned int cmd, · 64 unmodified lines
21572266 if (snd_BUG_ON(!client))
21582267 return -ENXIO;
21592268
2269+#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
2270+ /* exception - handling large data */
2271+ switch (cmd) {
2272+ case SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO:
2273+ case SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO:
2274+ return snd_seq_ioctl_client_ump_info(client, cmd, arg);
2275+ }
2276+#endif
2277+
21602278 for (handler = ioctl_handlers; handler->cmd > 0; ++handler) {
21612279 if (handler->cmd == cmd)
21622280 break;
sound/core/seq/seq_clientmgr.h+3−1
@@ -12,7 +12,6 @@ · 11 unmodified lines
1212 #include "seq_ports.h"
1313 #include "seq_lock.h"
1414
15−
1615 /* client manager */
1716
1817 struct snd_seq_user_client {
@@ -59,6 +58,9 @@ struct snd_seq_client { · 40 unmodified lines
5958 struct snd_seq_user_client user;
6059 struct snd_seq_kernel_client kernel;
6160 } data;
61+
62+ /* for UMP */
63+ void **ump_info;
6264 };
6365
6466 /* usage statistics */
sound/core/seq/seq_compat.c+2−0
@@ -86,6 +86,8 @@ static long snd_seq_ioctl_compat(struct file *file, unsigned int cmd, unsigned l · 85 unmodified lines
8686 case SNDRV_SEQ_IOCTL_SYSTEM_INFO:
8787 case SNDRV_SEQ_IOCTL_GET_CLIENT_INFO:
8888 case SNDRV_SEQ_IOCTL_SET_CLIENT_INFO:
89+ case SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO:
90+ case SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO:
8991 case SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT:
9092 case SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT:
9193 case SNDRV_SEQ_IOCTL_CREATE_QUEUE:
sound/core/seq/seq_ump_client.c+15−0
@@ -47,6 +47,7 @@ struct seq_ump_client { · 46 unmodified lines
4747 struct snd_rawmidi_file out_rfile; /* rawmidi for output */
4848 struct seq_ump_input_buffer input; /* input parser context */
4949 struct seq_ump_group groups[SNDRV_UMP_MAX_GROUPS]; /* table of groups */
50+ void *ump_info[SNDRV_UMP_MAX_BLOCKS + 1]; /* shadow of seq client ump_info */
5051 };
5152
5253 /* number of 32bit words for each UMP message type */
@@ -384,6 +385,8 @@ static int snd_seq_ump_probe(struct device *_dev) · 331 unmodified lines
384385 struct snd_ump_endpoint *ump = dev->private_data;
385386 struct snd_card *card = dev->card;
386387 struct seq_ump_client *client;
388+ struct snd_ump_block *fb;
389+ struct snd_seq_client *cptr;
387390 int p, err;
388391
389392 client = kzalloc(sizeof(*client), GFP_KERNEL);
@@ -400,6 +403,10 @@ static int snd_seq_ump_probe(struct device *_dev) · 10 unmodified lines
400403 goto error;
401404 }
402405
406+ client->ump_info[0] = &ump->info;
407+ list_for_each_entry(fb, &ump->block_list, list)
408+ client->ump_info[fb->info.block_id + 1] = &fb->info;
409+
403410 setup_client_midi_version(client);
404411 update_group_attrs(client);
405412
@@ -413,6 +420,14 @@ static int snd_seq_ump_probe(struct device *_dev) · 7 unmodified lines
413420 if (err < 0)
414421 goto error;
415422
423+ cptr = snd_seq_kernel_client_get(client->seq_client);
424+ if (!cptr) {
425+ err = -EINVAL;
426+ goto error;
427+ }
428+ cptr->ump_info = client->ump_info;
429+ snd_seq_kernel_client_put(cptr);
430+
416431 ump->seq_client = client;
417432 ump->seq_ops = &seq_ump_ops;
418433 return 0;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t