Skip to content

Commit d2d247e

Browse files
committed
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>
1 parent 4025f0e commit d2d247e

5 files changed

Lines changed: 153 additions & 2 deletions

File tree

include/uapi/sound/asequencer.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,18 @@ struct snd_seq_query_subs {
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 {
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

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
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,
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)
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,
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,
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,
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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
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 {
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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ static long snd_seq_ioctl_compat(struct file *file, unsigned int cmd, unsigned l
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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ struct seq_ump_client {
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)
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)
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)
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;

0 commit comments

Comments
 (0)