Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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.

Reviewed-by: Jaroslav Kysela <perex@perex.cz>
Link: https://lore.kernel.org/r/20230523075358.9672-35-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>

+153 -2
+14
include/uapi/sound/asequencer.h
··· 585 585 char reserved[64]; /* for future use */ 586 586 }; 587 587 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; 588 600 589 601 /* 590 602 * IOCTL commands ··· 610 598 611 599 #define SNDRV_SEQ_IOCTL_GET_CLIENT_INFO _IOWR('S', 0x10, struct snd_seq_client_info) 612 600 #define SNDRV_SEQ_IOCTL_SET_CLIENT_INFO _IOW ('S', 0x11, struct snd_seq_client_info) 601 + #define SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO _IOWR('S', 0x12, struct snd_seq_client_ump_info) 602 + #define SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO _IOWR('S', 0x13, struct snd_seq_client_ump_info) 613 603 614 604 #define SNDRV_SEQ_IOCTL_CREATE_PORT _IOWR('S', 0x20, struct snd_seq_port_info) 615 605 #define SNDRV_SEQ_IOCTL_DELETE_PORT _IOW ('S', 0x21, struct snd_seq_port_info)
+119 -1
sound/core/seq/seq_clientmgr.c
··· 14 14 #include <linux/kmod.h> 15 15 16 16 #include <sound/seq_kernel.h> 17 + #include <sound/ump.h> 17 18 #include "seq_clientmgr.h" 18 19 #include "seq_memory.h" 19 20 #include "seq_queue.h" ··· 71 70 static int snd_seq_deliver_single_event(struct snd_seq_client *client, 72 71 struct snd_seq_event *event, 73 72 int filter, int atomic, int hop); 73 + 74 + #if IS_ENABLED(CONFIG_SND_SEQ_UMP) 75 + static void free_ump_info(struct snd_seq_client *client); 76 + #endif 74 77 75 78 /* 76 79 */ ··· 387 382 seq_free_client(client); 388 383 if (client->data.user.fifo) 389 384 snd_seq_fifo_delete(&client->data.user.fifo); 385 + #if IS_ENABLED(CONFIG_SND_SEQ_UMP) 386 + free_ump_info(client); 387 + #endif 390 388 put_pid(client->data.user.owner); 391 389 kfree(client); 392 390 } ··· 1290 1282 if (client->user_pversion >= SNDRV_PROTOCOL_VERSION(1, 0, 3)) 1291 1283 client->midi_version = client_info->midi_version; 1292 1284 memcpy(client->event_filter, client_info->event_filter, 32); 1293 - 1294 1285 return 0; 1295 1286 } 1296 1287 ··· 2094 2087 return 0; 2095 2088 } 2096 2089 2090 + #if IS_ENABLED(CONFIG_SND_SEQ_UMP) 2091 + #define NUM_UMP_INFOS (SNDRV_UMP_MAX_BLOCKS + 1) 2092 + 2093 + static void free_ump_info(struct snd_seq_client *client) 2094 + { 2095 + int i; 2096 + 2097 + if (!client->ump_info) 2098 + return; 2099 + for (i = 0; i < NUM_UMP_INFOS; i++) 2100 + kfree(client->ump_info[i]); 2101 + kfree(client->ump_info); 2102 + client->ump_info = NULL; 2103 + } 2104 + 2105 + static void terminate_ump_info_strings(void *p, int type) 2106 + { 2107 + if (type == SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT) { 2108 + struct snd_ump_endpoint_info *ep = p; 2109 + ep->name[sizeof(ep->name) - 1] = 0; 2110 + } else { 2111 + struct snd_ump_block_info *bp = p; 2112 + bp->name[sizeof(bp->name) - 1] = 0; 2113 + } 2114 + } 2115 + 2116 + /* UMP-specific ioctls -- called directly without data copy */ 2117 + static int snd_seq_ioctl_client_ump_info(struct snd_seq_client *caller, 2118 + unsigned int cmd, 2119 + unsigned long arg) 2120 + { 2121 + struct snd_seq_client_ump_info __user *argp = 2122 + (struct snd_seq_client_ump_info __user *)arg; 2123 + struct snd_seq_client *cptr; 2124 + int client, type, err = 0; 2125 + size_t size; 2126 + void *p; 2127 + 2128 + if (get_user(client, &argp->client) || get_user(type, &argp->type)) 2129 + return -EFAULT; 2130 + if (cmd == SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO && 2131 + caller->number != client) 2132 + return -EPERM; 2133 + if (type < 0 || type >= NUM_UMP_INFOS) 2134 + return -EINVAL; 2135 + if (type == SNDRV_SEQ_CLIENT_UMP_INFO_ENDPOINT) 2136 + size = sizeof(struct snd_ump_endpoint_info); 2137 + else 2138 + size = sizeof(struct snd_ump_block_info); 2139 + cptr = snd_seq_client_use_ptr(client); 2140 + if (!cptr) 2141 + return -ENOENT; 2142 + 2143 + mutex_lock(&cptr->ioctl_mutex); 2144 + if (!cptr->midi_version) { 2145 + err = -EBADFD; 2146 + goto error; 2147 + } 2148 + 2149 + if (cmd == SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO) { 2150 + if (!cptr->ump_info) 2151 + p = NULL; 2152 + else 2153 + p = cptr->ump_info[type]; 2154 + if (!p) { 2155 + err = -ENODEV; 2156 + goto error; 2157 + } 2158 + if (copy_to_user(argp->info, p, size)) { 2159 + err = -EFAULT; 2160 + goto error; 2161 + } 2162 + } else { 2163 + if (cptr->type != USER_CLIENT) { 2164 + err = -EBADFD; 2165 + goto error; 2166 + } 2167 + if (!cptr->ump_info) { 2168 + cptr->ump_info = kcalloc(NUM_UMP_INFOS, 2169 + sizeof(void *), GFP_KERNEL); 2170 + if (!cptr->ump_info) { 2171 + err = -ENOMEM; 2172 + goto error; 2173 + } 2174 + } 2175 + p = memdup_user(argp->info, size); 2176 + if (IS_ERR(p)) { 2177 + err = PTR_ERR(p); 2178 + goto error; 2179 + } 2180 + kfree(cptr->ump_info[type]); 2181 + terminate_ump_info_strings(p, type); 2182 + cptr->ump_info[type] = p; 2183 + } 2184 + 2185 + error: 2186 + mutex_unlock(&cptr->ioctl_mutex); 2187 + snd_seq_client_unlock(cptr); 2188 + return err; 2189 + } 2190 + #endif 2191 + 2097 2192 /* -------------------------------------------------------- */ 2098 2193 2099 2194 static const struct ioctl_handler { ··· 2265 2156 2266 2157 if (snd_BUG_ON(!client)) 2267 2158 return -ENXIO; 2159 + 2160 + #if IS_ENABLED(CONFIG_SND_SEQ_UMP) 2161 + /* exception - handling large data */ 2162 + switch (cmd) { 2163 + case SNDRV_SEQ_IOCTL_GET_CLIENT_UMP_INFO: 2164 + case SNDRV_SEQ_IOCTL_SET_CLIENT_UMP_INFO: 2165 + return snd_seq_ioctl_client_ump_info(client, cmd, arg); 2166 + } 2167 + #endif 2268 2168 2269 2169 for (handler = ioctl_handlers; handler->cmd > 0; ++handler) { 2270 2170 if (handler->cmd == cmd)
+3 -1
sound/core/seq/seq_clientmgr.h
··· 12 12 #include "seq_ports.h" 13 13 #include "seq_lock.h" 14 14 15 - 16 15 /* client manager */ 17 16 18 17 struct snd_seq_user_client { ··· 58 59 struct snd_seq_user_client user; 59 60 struct snd_seq_kernel_client kernel; 60 61 } data; 62 + 63 + /* for UMP */ 64 + void **ump_info; 61 65 }; 62 66 63 67 /* usage statistics */
+2
sound/core/seq/seq_compat.c
··· 86 86 case SNDRV_SEQ_IOCTL_SYSTEM_INFO: 87 87 case SNDRV_SEQ_IOCTL_GET_CLIENT_INFO: 88 88 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: 89 91 case SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT: 90 92 case SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT: 91 93 case SNDRV_SEQ_IOCTL_CREATE_QUEUE:
+15
sound/core/seq/seq_ump_client.c
··· 47 47 struct snd_rawmidi_file out_rfile; /* rawmidi for output */ 48 48 struct seq_ump_input_buffer input; /* input parser context */ 49 49 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 */ 50 51 }; 51 52 52 53 /* number of 32bit words for each UMP message type */ ··· 385 384 struct snd_ump_endpoint *ump = dev->private_data; 386 385 struct snd_card *card = dev->card; 387 386 struct seq_ump_client *client; 387 + struct snd_ump_block *fb; 388 + struct snd_seq_client *cptr; 388 389 int p, err; 389 390 390 391 client = kzalloc(sizeof(*client), GFP_KERNEL); ··· 403 400 goto error; 404 401 } 405 402 403 + client->ump_info[0] = &ump->info; 404 + list_for_each_entry(fb, &ump->block_list, list) 405 + client->ump_info[fb->info.block_id + 1] = &fb->info; 406 + 406 407 setup_client_midi_version(client); 407 408 update_group_attrs(client); 408 409 ··· 419 412 err = create_ump_endpoint_port(client); 420 413 if (err < 0) 421 414 goto error; 415 + 416 + cptr = snd_seq_kernel_client_get(client->seq_client); 417 + if (!cptr) { 418 + err = -EINVAL; 419 + goto error; 420 + } 421 + cptr->ump_info = client->ump_info; 422 + snd_seq_kernel_client_put(cptr); 422 423 423 424 ump->seq_client = client; 424 425 ump->seq_ops = &seq_ump_ops;