Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later
2 : : /*
3 : : * ALSA sequencer Client Manager
4 : : * Copyright (c) 1998-2001 by Frank van de Pol <fvdpol@coil.demon.nl>
5 : : * Jaroslav Kysela <perex@perex.cz>
6 : : * Takashi Iwai <tiwai@suse.de>
7 : : */
8 : :
9 : : #include <linux/init.h>
10 : : #include <linux/export.h>
11 : : #include <linux/slab.h>
12 : : #include <sound/core.h>
13 : : #include <sound/minors.h>
14 : : #include <linux/kmod.h>
15 : :
16 : : #include <sound/seq_kernel.h>
17 : : #include "seq_clientmgr.h"
18 : : #include "seq_memory.h"
19 : : #include "seq_queue.h"
20 : : #include "seq_timer.h"
21 : : #include "seq_info.h"
22 : : #include "seq_system.h"
23 : : #include <sound/seq_device.h>
24 : : #ifdef CONFIG_COMPAT
25 : : #include <linux/compat.h>
26 : : #endif
27 : :
28 : : /* Client Manager
29 : :
30 : : * this module handles the connections of userland and kernel clients
31 : : *
32 : : */
33 : :
34 : : /*
35 : : * There are four ranges of client numbers (last two shared):
36 : : * 0..15: global clients
37 : : * 16..127: statically allocated client numbers for cards 0..27
38 : : * 128..191: dynamically allocated client numbers for cards 28..31
39 : : * 128..191: dynamically allocated client numbers for applications
40 : : */
41 : :
42 : : /* number of kernel non-card clients */
43 : : #define SNDRV_SEQ_GLOBAL_CLIENTS 16
44 : : /* clients per cards, for static clients */
45 : : #define SNDRV_SEQ_CLIENTS_PER_CARD 4
46 : : /* dynamically allocated client numbers (both kernel drivers and user space) */
47 : : #define SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN 128
48 : :
49 : : #define SNDRV_SEQ_LFLG_INPUT 0x0001
50 : : #define SNDRV_SEQ_LFLG_OUTPUT 0x0002
51 : : #define SNDRV_SEQ_LFLG_OPEN (SNDRV_SEQ_LFLG_INPUT|SNDRV_SEQ_LFLG_OUTPUT)
52 : :
53 : : static DEFINE_SPINLOCK(clients_lock);
54 : : static DEFINE_MUTEX(register_mutex);
55 : :
56 : : /*
57 : : * client table
58 : : */
59 : : static char clienttablock[SNDRV_SEQ_MAX_CLIENTS];
60 : : static struct snd_seq_client *clienttab[SNDRV_SEQ_MAX_CLIENTS];
61 : : static struct snd_seq_usage client_usage;
62 : :
63 : : /*
64 : : * prototypes
65 : : */
66 : : static int bounce_error_event(struct snd_seq_client *client,
67 : : struct snd_seq_event *event,
68 : : int err, int atomic, int hop);
69 : : static int snd_seq_deliver_single_event(struct snd_seq_client *client,
70 : : struct snd_seq_event *event,
71 : : int filter, int atomic, int hop);
72 : :
73 : : /*
74 : : */
75 : 0 : static inline unsigned short snd_seq_file_flags(struct file *file)
76 : : {
77 : 0 : switch (file->f_mode & (FMODE_READ | FMODE_WRITE)) {
78 : : case FMODE_WRITE:
79 : : return SNDRV_SEQ_LFLG_OUTPUT;
80 : 0 : case FMODE_READ:
81 : 0 : return SNDRV_SEQ_LFLG_INPUT;
82 : 0 : default:
83 : 0 : return SNDRV_SEQ_LFLG_OPEN;
84 : : }
85 : : }
86 : :
87 : 0 : static inline int snd_seq_write_pool_allocated(struct snd_seq_client *client)
88 : : {
89 [ # # ]: 0 : return snd_seq_total_cells(client->pool) > 0;
90 : : }
91 : :
92 : : /* return pointer to client structure for specified id */
93 : 105 : static struct snd_seq_client *clientptr(int clientid)
94 : : {
95 : 105 : if (clientid < 0 || clientid >= SNDRV_SEQ_MAX_CLIENTS) {
96 : : pr_debug("ALSA: seq: oops. Trying to get pointer to client %d\n",
97 : : clientid);
98 : : return NULL;
99 : : }
100 : 105 : return clienttab[clientid];
101 : : }
102 : :
103 : 42 : struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
104 : : {
105 : 42 : unsigned long flags;
106 : 42 : struct snd_seq_client *client;
107 : :
108 [ + - ]: 42 : if (clientid < 0 || clientid >= SNDRV_SEQ_MAX_CLIENTS) {
109 : : pr_debug("ALSA: seq: oops. Trying to get pointer to client %d\n",
110 : : clientid);
111 : : return NULL;
112 : : }
113 : 42 : spin_lock_irqsave(&clients_lock, flags);
114 : 42 : client = clientptr(clientid);
115 [ + - ]: 42 : if (client)
116 : 42 : goto __lock;
117 [ # # ]: 0 : if (clienttablock[clientid]) {
118 : 0 : spin_unlock_irqrestore(&clients_lock, flags);
119 : 0 : return NULL;
120 : : }
121 : 0 : spin_unlock_irqrestore(&clients_lock, flags);
122 : : #ifdef CONFIG_MODULES
123 [ # # ]: 0 : if (!in_interrupt()) {
124 : 0 : static char client_requested[SNDRV_SEQ_GLOBAL_CLIENTS];
125 : 0 : static char card_requested[SNDRV_CARDS];
126 [ # # ]: 0 : if (clientid < SNDRV_SEQ_GLOBAL_CLIENTS) {
127 : 0 : int idx;
128 : :
129 [ # # ]: 0 : if (!client_requested[clientid]) {
130 : 0 : client_requested[clientid] = 1;
131 [ # # ]: 0 : for (idx = 0; idx < 15; idx++) {
132 [ # # ]: 0 : if (seq_client_load[idx] < 0)
133 : : break;
134 [ # # ]: 0 : if (seq_client_load[idx] == clientid) {
135 : 0 : request_module("snd-seq-client-%i",
136 : : clientid);
137 : 0 : break;
138 : : }
139 : : }
140 : : }
141 [ # # ]: 0 : } else if (clientid < SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN) {
142 : 0 : int card = (clientid - SNDRV_SEQ_GLOBAL_CLIENTS) /
143 : : SNDRV_SEQ_CLIENTS_PER_CARD;
144 [ # # ]: 0 : if (card < snd_ecards_limit) {
145 [ # # ]: 0 : if (! card_requested[card]) {
146 : 0 : card_requested[card] = 1;
147 : 0 : snd_request_card(card);
148 : : }
149 : 0 : snd_seq_device_load_drivers();
150 : : }
151 : : }
152 : 0 : spin_lock_irqsave(&clients_lock, flags);
153 : 0 : client = clientptr(clientid);
154 [ # # ]: 0 : if (client)
155 : 0 : goto __lock;
156 : 0 : spin_unlock_irqrestore(&clients_lock, flags);
157 : : }
158 : : #endif
159 : : return NULL;
160 : :
161 : 42 : __lock:
162 : 42 : snd_use_lock_use(&client->use_lock);
163 : 42 : spin_unlock_irqrestore(&clients_lock, flags);
164 : 42 : return client;
165 : : }
166 : :
167 : : /* Take refcount and perform ioctl_mutex lock on the given client;
168 : : * used only for OSS sequencer
169 : : * Unlock via snd_seq_client_ioctl_unlock() below
170 : : */
171 : 0 : bool snd_seq_client_ioctl_lock(int clientid)
172 : : {
173 : 0 : struct snd_seq_client *client;
174 : :
175 : 0 : client = snd_seq_client_use_ptr(clientid);
176 [ # # ]: 0 : if (!client)
177 : : return false;
178 : 0 : mutex_lock(&client->ioctl_mutex);
179 : : /* The client isn't unrefed here; see snd_seq_client_ioctl_unlock() */
180 : 0 : return true;
181 : : }
182 : : EXPORT_SYMBOL_GPL(snd_seq_client_ioctl_lock);
183 : :
184 : : /* Unlock and unref the given client; for OSS sequencer use only */
185 : 0 : void snd_seq_client_ioctl_unlock(int clientid)
186 : : {
187 : 0 : struct snd_seq_client *client;
188 : :
189 : 0 : client = snd_seq_client_use_ptr(clientid);
190 [ # # # # ]: 0 : if (WARN_ON(!client))
191 : : return;
192 : 0 : mutex_unlock(&client->ioctl_mutex);
193 : : /* The doubly unrefs below are intentional; the first one releases the
194 : : * leftover from snd_seq_client_ioctl_lock() above, and the second one
195 : : * is for releasing snd_seq_client_use_ptr() in this function
196 : : */
197 : 0 : snd_seq_client_unlock(client);
198 : 0 : snd_seq_client_unlock(client);
199 : : }
200 : : EXPORT_SYMBOL_GPL(snd_seq_client_ioctl_unlock);
201 : :
202 : 42 : static void usage_alloc(struct snd_seq_usage *res, int num)
203 : : {
204 : 42 : res->cur += num;
205 : 42 : if (res->cur > res->peak)
206 : 42 : res->peak = res->cur;
207 : : }
208 : :
209 : 0 : static void usage_free(struct snd_seq_usage *res, int num)
210 : : {
211 : 0 : res->cur -= num;
212 : 0 : }
213 : :
214 : : /* initialise data structures */
215 : 21 : int __init client_init_data(void)
216 : : {
217 : : /* zap out the client table */
218 : 21 : memset(&clienttablock, 0, sizeof(clienttablock));
219 : 21 : memset(&clienttab, 0, sizeof(clienttab));
220 : 21 : return 0;
221 : : }
222 : :
223 : :
224 : 42 : static struct snd_seq_client *seq_create_client1(int client_index, int poolsize)
225 : : {
226 : 42 : int c;
227 : 42 : struct snd_seq_client *client;
228 : :
229 : : /* init client data */
230 : 42 : client = kzalloc(sizeof(*client), GFP_KERNEL);
231 [ + - ]: 42 : if (client == NULL)
232 : : return NULL;
233 : 42 : client->pool = snd_seq_pool_new(poolsize);
234 [ - + ]: 42 : if (client->pool == NULL) {
235 : 0 : kfree(client);
236 : 0 : return NULL;
237 : : }
238 : 42 : client->type = NO_CLIENT;
239 : 42 : snd_use_lock_init(&client->use_lock);
240 : 42 : rwlock_init(&client->ports_lock);
241 : 42 : mutex_init(&client->ports_mutex);
242 : 42 : INIT_LIST_HEAD(&client->ports_list_head);
243 : 42 : mutex_init(&client->ioctl_mutex);
244 : :
245 : : /* find free slot in the client table */
246 : 42 : spin_lock_irq(&clients_lock);
247 [ - + ]: 42 : if (client_index < 0) {
248 : 0 : for (c = SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN;
249 [ # # ]: 0 : c < SNDRV_SEQ_MAX_CLIENTS;
250 : 0 : c++) {
251 [ # # # # ]: 0 : if (clienttab[c] || clienttablock[c])
252 : 0 : continue;
253 : 0 : clienttab[client->number = c] = client;
254 : 0 : spin_unlock_irq(&clients_lock);
255 : 0 : return client;
256 : : }
257 : : } else {
258 [ + - + - ]: 42 : if (clienttab[client_index] == NULL && !clienttablock[client_index]) {
259 : 42 : clienttab[client->number = client_index] = client;
260 : 42 : spin_unlock_irq(&clients_lock);
261 : 42 : return client;
262 : : }
263 : : }
264 : 0 : spin_unlock_irq(&clients_lock);
265 : 0 : snd_seq_pool_delete(&client->pool);
266 : 0 : kfree(client);
267 : 0 : return NULL; /* no free slot found or busy, return failure code */
268 : : }
269 : :
270 : :
271 : 0 : static int seq_free_client1(struct snd_seq_client *client)
272 : : {
273 [ # # ]: 0 : if (!client)
274 : : return 0;
275 : 0 : spin_lock_irq(&clients_lock);
276 : 0 : clienttablock[client->number] = 1;
277 : 0 : clienttab[client->number] = NULL;
278 : 0 : spin_unlock_irq(&clients_lock);
279 : 0 : snd_seq_delete_all_ports(client);
280 : 0 : snd_seq_queue_client_leave(client->number);
281 : 0 : snd_use_lock_sync(&client->use_lock);
282 : 0 : snd_seq_queue_client_termination(client->number);
283 [ # # ]: 0 : if (client->pool)
284 : 0 : snd_seq_pool_delete(&client->pool);
285 : 0 : spin_lock_irq(&clients_lock);
286 : 0 : clienttablock[client->number] = 0;
287 : 0 : spin_unlock_irq(&clients_lock);
288 : 0 : return 0;
289 : : }
290 : :
291 : :
292 : 0 : static void seq_free_client(struct snd_seq_client * client)
293 : : {
294 : 0 : mutex_lock(®ister_mutex);
295 [ # # # ]: 0 : switch (client->type) {
296 : 0 : case NO_CLIENT:
297 : 0 : pr_warn("ALSA: seq: Trying to free unused client %d\n",
298 : : client->number);
299 : 0 : break;
300 : 0 : case USER_CLIENT:
301 : : case KERNEL_CLIENT:
302 : 0 : seq_free_client1(client);
303 : 0 : usage_free(&client_usage, 1);
304 : : break;
305 : :
306 : 0 : default:
307 : 0 : pr_err("ALSA: seq: Trying to free client %d with undefined type = %d\n",
308 : : client->number, client->type);
309 : : }
310 : 0 : mutex_unlock(®ister_mutex);
311 : :
312 : 0 : snd_seq_system_client_ev_client_exit(client->number);
313 : 0 : }
314 : :
315 : :
316 : :
317 : : /* -------------------------------------------------------- */
318 : :
319 : : /* create a user client */
320 : 0 : static int snd_seq_open(struct inode *inode, struct file *file)
321 : : {
322 : 0 : int c, mode; /* client id */
323 : 0 : struct snd_seq_client *client;
324 : 0 : struct snd_seq_user_client *user;
325 : 0 : int err;
326 : :
327 : 0 : err = stream_open(inode, file);
328 [ # # ]: 0 : if (err < 0)
329 : : return err;
330 : :
331 : 0 : mutex_lock(®ister_mutex);
332 : 0 : client = seq_create_client1(-1, SNDRV_SEQ_DEFAULT_EVENTS);
333 [ # # ]: 0 : if (!client) {
334 : 0 : mutex_unlock(®ister_mutex);
335 : 0 : return -ENOMEM; /* failure code */
336 : : }
337 : :
338 [ # # # ]: 0 : mode = snd_seq_file_flags(file);
339 [ # # ]: 0 : if (mode & SNDRV_SEQ_LFLG_INPUT)
340 : 0 : client->accept_input = 1;
341 [ # # ]: 0 : if (mode & SNDRV_SEQ_LFLG_OUTPUT)
342 : 0 : client->accept_output = 1;
343 : :
344 : 0 : user = &client->data.user;
345 : 0 : user->fifo = NULL;
346 : 0 : user->fifo_pool_size = 0;
347 : :
348 [ # # ]: 0 : if (mode & SNDRV_SEQ_LFLG_INPUT) {
349 : 0 : user->fifo_pool_size = SNDRV_SEQ_DEFAULT_CLIENT_EVENTS;
350 : 0 : user->fifo = snd_seq_fifo_new(user->fifo_pool_size);
351 [ # # ]: 0 : if (user->fifo == NULL) {
352 : 0 : seq_free_client1(client);
353 : 0 : kfree(client);
354 : 0 : mutex_unlock(®ister_mutex);
355 : 0 : return -ENOMEM;
356 : : }
357 : : }
358 : :
359 [ # # ]: 0 : usage_alloc(&client_usage, 1);
360 : 0 : client->type = USER_CLIENT;
361 : 0 : mutex_unlock(®ister_mutex);
362 : :
363 : 0 : c = client->number;
364 : 0 : file->private_data = client;
365 : :
366 : : /* fill client data */
367 : 0 : user->file = file;
368 : 0 : sprintf(client->name, "Client-%d", c);
369 [ # # ]: 0 : client->data.user.owner = get_pid(task_pid(current));
370 : :
371 : : /* make others aware this new client */
372 : 0 : snd_seq_system_client_ev_client_start(c);
373 : :
374 : 0 : return 0;
375 : : }
376 : :
377 : : /* delete a user client */
378 : 0 : static int snd_seq_release(struct inode *inode, struct file *file)
379 : : {
380 : 0 : struct snd_seq_client *client = file->private_data;
381 : :
382 [ # # ]: 0 : if (client) {
383 : 0 : seq_free_client(client);
384 [ # # ]: 0 : if (client->data.user.fifo)
385 : 0 : snd_seq_fifo_delete(&client->data.user.fifo);
386 : 0 : put_pid(client->data.user.owner);
387 : 0 : kfree(client);
388 : : }
389 : :
390 : 0 : return 0;
391 : : }
392 : :
393 : :
394 : : /* handle client read() */
395 : : /* possible error values:
396 : : * -ENXIO invalid client or file open mode
397 : : * -ENOSPC FIFO overflow (the flag is cleared after this error report)
398 : : * -EINVAL no enough user-space buffer to write the whole event
399 : : * -EFAULT seg. fault during copy to user space
400 : : */
401 : 0 : static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count,
402 : : loff_t *offset)
403 : : {
404 : 0 : struct snd_seq_client *client = file->private_data;
405 : 0 : struct snd_seq_fifo *fifo;
406 : 0 : int err;
407 : 0 : long result = 0;
408 : 0 : struct snd_seq_event_cell *cell;
409 : :
410 [ # # # # : 0 : if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_INPUT))
# ]
411 : : return -ENXIO;
412 : :
413 [ # # # # ]: 0 : if (!access_ok(buf, count))
414 : : return -EFAULT;
415 : :
416 : : /* check client structures are in place */
417 [ # # ]: 0 : if (snd_BUG_ON(!client))
418 : : return -ENXIO;
419 : :
420 [ # # # # ]: 0 : if (!client->accept_input || (fifo = client->data.user.fifo) == NULL)
421 : : return -ENXIO;
422 : :
423 [ # # ]: 0 : if (atomic_read(&fifo->overflow) > 0) {
424 : : /* buffer overflow is detected */
425 : 0 : snd_seq_fifo_clear(fifo);
426 : : /* return error code */
427 : 0 : return -ENOSPC;
428 : : }
429 : :
430 : 0 : cell = NULL;
431 : 0 : err = 0;
432 : 0 : snd_seq_fifo_lock(fifo);
433 : :
434 : : /* while data available in queue */
435 [ # # ]: 0 : while (count >= sizeof(struct snd_seq_event)) {
436 : 0 : int nonblock;
437 : :
438 [ # # # # ]: 0 : nonblock = (file->f_flags & O_NONBLOCK) || result > 0;
439 [ # # ]: 0 : if ((err = snd_seq_fifo_cell_out(fifo, &cell, nonblock)) < 0) {
440 : : break;
441 : : }
442 [ # # ]: 0 : if (snd_seq_ev_is_variable(&cell->event)) {
443 : 0 : struct snd_seq_event tmpev;
444 : 0 : tmpev = cell->event;
445 : 0 : tmpev.data.ext.len &= ~SNDRV_SEQ_EXT_MASK;
446 [ # # ]: 0 : if (copy_to_user(buf, &tmpev, sizeof(struct snd_seq_event))) {
447 : : err = -EFAULT;
448 : 0 : break;
449 : : }
450 : 0 : count -= sizeof(struct snd_seq_event);
451 : 0 : buf += sizeof(struct snd_seq_event);
452 : 0 : err = snd_seq_expand_var_event(&cell->event, count,
453 : : (char __force *)buf, 0,
454 : : sizeof(struct snd_seq_event));
455 [ # # ]: 0 : if (err < 0)
456 : : break;
457 : 0 : result += err;
458 : 0 : count -= err;
459 : 0 : buf += err;
460 : : } else {
461 [ # # # # ]: 0 : if (copy_to_user(buf, &cell->event, sizeof(struct snd_seq_event))) {
462 : : err = -EFAULT;
463 : : break;
464 : : }
465 : 0 : count -= sizeof(struct snd_seq_event);
466 : 0 : buf += sizeof(struct snd_seq_event);
467 : : }
468 : 0 : snd_seq_cell_free(cell);
469 : 0 : cell = NULL; /* to be sure */
470 : 0 : result += sizeof(struct snd_seq_event);
471 : : }
472 : :
473 [ # # ]: 0 : if (err < 0) {
474 [ # # ]: 0 : if (cell)
475 : 0 : snd_seq_fifo_cell_putback(fifo, cell);
476 [ # # ]: 0 : if (err == -EAGAIN && result > 0)
477 : 0 : err = 0;
478 : : }
479 : 0 : snd_seq_fifo_unlock(fifo);
480 : :
481 [ # # ]: 0 : return (err < 0) ? err : result;
482 : : }
483 : :
484 : :
485 : : /*
486 : : * check access permission to the port
487 : : */
488 : 0 : static int check_port_perm(struct snd_seq_client_port *port, unsigned int flags)
489 : : {
490 : 0 : if ((port->capability & flags) != flags)
491 : : return 0;
492 : 0 : return flags;
493 : : }
494 : :
495 : : /*
496 : : * check if the destination client is available, and return the pointer
497 : : * if filter is non-zero, client filter bitmap is tested.
498 : : */
499 : : static struct snd_seq_client *get_event_dest_client(struct snd_seq_event *event,
500 : : int filter)
501 : : {
502 : : struct snd_seq_client *dest;
503 : :
504 : : dest = snd_seq_client_use_ptr(event->dest.client);
505 : : if (dest == NULL)
506 : : return NULL;
507 : : if (! dest->accept_input)
508 : : goto __not_avail;
509 : : if ((dest->filter & SNDRV_SEQ_FILTER_USE_EVENT) &&
510 : : ! test_bit(event->type, dest->event_filter))
511 : : goto __not_avail;
512 : : if (filter && !(dest->filter & filter))
513 : : goto __not_avail;
514 : :
515 : : return dest; /* ok - accessible */
516 : : __not_avail:
517 : : snd_seq_client_unlock(dest);
518 : : return NULL;
519 : : }
520 : :
521 : :
522 : : /*
523 : : * Return the error event.
524 : : *
525 : : * If the receiver client is a user client, the original event is
526 : : * encapsulated in SNDRV_SEQ_EVENT_BOUNCE as variable length event. If
527 : : * the original event is also variable length, the external data is
528 : : * copied after the event record.
529 : : * If the receiver client is a kernel client, the original event is
530 : : * quoted in SNDRV_SEQ_EVENT_KERNEL_ERROR, since this requires no extra
531 : : * kmalloc.
532 : : */
533 : 0 : static int bounce_error_event(struct snd_seq_client *client,
534 : : struct snd_seq_event *event,
535 : : int err, int atomic, int hop)
536 : : {
537 : 0 : struct snd_seq_event bounce_ev;
538 : 0 : int result;
539 : :
540 [ # # ]: 0 : if (client == NULL ||
541 [ # # ]: 0 : ! (client->filter & SNDRV_SEQ_FILTER_BOUNCE) ||
542 [ # # ]: 0 : ! client->accept_input)
543 : : return 0; /* ignored */
544 : :
545 : : /* set up quoted error */
546 : 0 : memset(&bounce_ev, 0, sizeof(bounce_ev));
547 : 0 : bounce_ev.type = SNDRV_SEQ_EVENT_KERNEL_ERROR;
548 : 0 : bounce_ev.flags = SNDRV_SEQ_EVENT_LENGTH_FIXED;
549 : 0 : bounce_ev.queue = SNDRV_SEQ_QUEUE_DIRECT;
550 : 0 : bounce_ev.source.client = SNDRV_SEQ_CLIENT_SYSTEM;
551 : 0 : bounce_ev.source.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
552 : 0 : bounce_ev.dest.client = client->number;
553 : 0 : bounce_ev.dest.port = event->source.port;
554 : 0 : bounce_ev.data.quote.origin = event->dest;
555 : 0 : bounce_ev.data.quote.event = event;
556 : 0 : bounce_ev.data.quote.value = -err; /* use positive value */
557 : 0 : result = snd_seq_deliver_single_event(NULL, &bounce_ev, 0, atomic, hop + 1);
558 [ # # ]: 0 : if (result < 0) {
559 : 0 : client->event_lost++;
560 : 0 : return result;
561 : : }
562 : :
563 : : return result;
564 : : }
565 : :
566 : :
567 : : /*
568 : : * rewrite the time-stamp of the event record with the curren time
569 : : * of the given queue.
570 : : * return non-zero if updated.
571 : : */
572 : 0 : static int update_timestamp_of_queue(struct snd_seq_event *event,
573 : : int queue, int real_time)
574 : : {
575 : 0 : struct snd_seq_queue *q;
576 : :
577 : 0 : q = queueptr(queue);
578 [ # # ]: 0 : if (! q)
579 : : return 0;
580 : 0 : event->queue = queue;
581 : 0 : event->flags &= ~SNDRV_SEQ_TIME_STAMP_MASK;
582 [ # # ]: 0 : if (real_time) {
583 : 0 : event->time.time = snd_seq_timer_get_cur_time(q->timer, true);
584 : 0 : event->flags |= SNDRV_SEQ_TIME_STAMP_REAL;
585 : : } else {
586 : 0 : event->time.tick = snd_seq_timer_get_cur_tick(q->timer);
587 : 0 : event->flags |= SNDRV_SEQ_TIME_STAMP_TICK;
588 : : }
589 : 0 : queuefree(q);
590 : 0 : return 1;
591 : : }
592 : :
593 : :
594 : : /*
595 : : * deliver an event to the specified destination.
596 : : * if filter is non-zero, client filter bitmap is tested.
597 : : *
598 : : * RETURN VALUE: 0 : if succeeded
599 : : * <0 : error
600 : : */
601 : 0 : static int snd_seq_deliver_single_event(struct snd_seq_client *client,
602 : : struct snd_seq_event *event,
603 : : int filter, int atomic, int hop)
604 : : {
605 : 0 : struct snd_seq_client *dest = NULL;
606 : 0 : struct snd_seq_client_port *dest_port = NULL;
607 : 0 : int result = -ENOENT;
608 : 0 : int direct;
609 : :
610 : 0 : direct = snd_seq_ev_is_direct(event);
611 : :
612 : 0 : dest = get_event_dest_client(event, filter);
613 [ # # ]: 0 : if (dest == NULL)
614 : 0 : goto __skip;
615 : 0 : dest_port = snd_seq_port_use_ptr(dest, event->dest.port);
616 [ # # ]: 0 : if (dest_port == NULL)
617 : 0 : goto __skip;
618 : :
619 : : /* check permission */
620 [ # # ]: 0 : if (! check_port_perm(dest_port, SNDRV_SEQ_PORT_CAP_WRITE)) {
621 : 0 : result = -EPERM;
622 : 0 : goto __skip;
623 : : }
624 : :
625 [ # # ]: 0 : if (dest_port->timestamping)
626 : 0 : update_timestamp_of_queue(event, dest_port->time_queue,
627 : 0 : dest_port->time_real);
628 : :
629 [ # # # ]: 0 : switch (dest->type) {
630 : 0 : case USER_CLIENT:
631 [ # # ]: 0 : if (dest->data.user.fifo)
632 : 0 : result = snd_seq_fifo_event_in(dest->data.user.fifo, event);
633 : : break;
634 : :
635 : 0 : case KERNEL_CLIENT:
636 [ # # ]: 0 : if (dest_port->event_input == NULL)
637 : : break;
638 : 0 : result = dest_port->event_input(event, direct,
639 : : dest_port->private_data,
640 : : atomic, hop);
641 : 0 : break;
642 : : default:
643 : : break;
644 : : }
645 : :
646 : 0 : __skip:
647 [ # # ]: 0 : if (dest_port)
648 : 0 : snd_seq_port_unlock(dest_port);
649 [ # # ]: 0 : if (dest)
650 : 0 : snd_seq_client_unlock(dest);
651 : :
652 [ # # ]: 0 : if (result < 0 && !direct) {
653 : 0 : result = bounce_error_event(client, event, result, atomic, hop);
654 : : }
655 : 0 : return result;
656 : : }
657 : :
658 : :
659 : : /*
660 : : * send the event to all subscribers:
661 : : */
662 : 42 : static int deliver_to_subscribers(struct snd_seq_client *client,
663 : : struct snd_seq_event *event,
664 : : int atomic, int hop)
665 : : {
666 : 42 : struct snd_seq_subscribers *subs;
667 : 42 : int err, result = 0, num_ev = 0;
668 : 42 : struct snd_seq_event event_saved;
669 : 42 : struct snd_seq_client_port *src_port;
670 : 42 : struct snd_seq_port_subs_info *grp;
671 : :
672 : 42 : src_port = snd_seq_port_use_ptr(client, event->source.port);
673 [ + - ]: 42 : if (src_port == NULL)
674 : : return -EINVAL; /* invalid source port */
675 : : /* save original event record */
676 : 42 : event_saved = *event;
677 : 42 : grp = &src_port->c_src;
678 : :
679 : : /* lock list */
680 [ - + ]: 42 : if (atomic)
681 : 0 : read_lock(&grp->list_lock);
682 : : else
683 : 42 : down_read_nested(&grp->list_mutex, hop);
684 [ - + ]: 42 : list_for_each_entry(subs, &grp->list_head, src_list) {
685 : : /* both ports ready? */
686 [ # # ]: 0 : if (atomic_read(&subs->ref_count) != 2)
687 : 0 : continue;
688 : 0 : event->dest = subs->info.dest;
689 [ # # ]: 0 : if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP)
690 : : /* convert time according to flag with subscription */
691 : 0 : update_timestamp_of_queue(event, subs->info.queue,
692 : 0 : subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIME_REAL);
693 : 0 : err = snd_seq_deliver_single_event(client, event,
694 : : 0, atomic, hop);
695 [ # # ]: 0 : if (err < 0) {
696 : : /* save first error that occurs and continue */
697 [ # # ]: 0 : if (!result)
698 : 0 : result = err;
699 : 0 : continue;
700 : : }
701 : 0 : num_ev++;
702 : : /* restore original event record */
703 : 0 : *event = event_saved;
704 : : }
705 [ - + ]: 42 : if (atomic)
706 : 0 : read_unlock(&grp->list_lock);
707 : : else
708 : 42 : up_read(&grp->list_mutex);
709 : 42 : *event = event_saved; /* restore */
710 : 42 : snd_seq_port_unlock(src_port);
711 [ + - ]: 42 : return (result < 0) ? result : num_ev;
712 : : }
713 : :
714 : :
715 : : #ifdef SUPPORT_BROADCAST
716 : : /*
717 : : * broadcast to all ports:
718 : : */
719 : : static int port_broadcast_event(struct snd_seq_client *client,
720 : : struct snd_seq_event *event,
721 : : int atomic, int hop)
722 : : {
723 : : int num_ev = 0, err, result = 0;
724 : : struct snd_seq_client *dest_client;
725 : : struct snd_seq_client_port *port;
726 : :
727 : : dest_client = get_event_dest_client(event, SNDRV_SEQ_FILTER_BROADCAST);
728 : : if (dest_client == NULL)
729 : : return 0; /* no matching destination */
730 : :
731 : : read_lock(&dest_client->ports_lock);
732 : : list_for_each_entry(port, &dest_client->ports_list_head, list) {
733 : : event->dest.port = port->addr.port;
734 : : /* pass NULL as source client to avoid error bounce */
735 : : err = snd_seq_deliver_single_event(NULL, event,
736 : : SNDRV_SEQ_FILTER_BROADCAST,
737 : : atomic, hop);
738 : : if (err < 0) {
739 : : /* save first error that occurs and continue */
740 : : if (!result)
741 : : result = err;
742 : : continue;
743 : : }
744 : : num_ev++;
745 : : }
746 : : read_unlock(&dest_client->ports_lock);
747 : : snd_seq_client_unlock(dest_client);
748 : : event->dest.port = SNDRV_SEQ_ADDRESS_BROADCAST; /* restore */
749 : : return (result < 0) ? result : num_ev;
750 : : }
751 : :
752 : : /*
753 : : * send the event to all clients:
754 : : * if destination port is also ADDRESS_BROADCAST, deliver to all ports.
755 : : */
756 : : static int broadcast_event(struct snd_seq_client *client,
757 : : struct snd_seq_event *event, int atomic, int hop)
758 : : {
759 : : int err, result = 0, num_ev = 0;
760 : : int dest;
761 : : struct snd_seq_addr addr;
762 : :
763 : : addr = event->dest; /* save */
764 : :
765 : : for (dest = 0; dest < SNDRV_SEQ_MAX_CLIENTS; dest++) {
766 : : /* don't send to itself */
767 : : if (dest == client->number)
768 : : continue;
769 : : event->dest.client = dest;
770 : : event->dest.port = addr.port;
771 : : if (addr.port == SNDRV_SEQ_ADDRESS_BROADCAST)
772 : : err = port_broadcast_event(client, event, atomic, hop);
773 : : else
774 : : /* pass NULL as source client to avoid error bounce */
775 : : err = snd_seq_deliver_single_event(NULL, event,
776 : : SNDRV_SEQ_FILTER_BROADCAST,
777 : : atomic, hop);
778 : : if (err < 0) {
779 : : /* save first error that occurs and continue */
780 : : if (!result)
781 : : result = err;
782 : : continue;
783 : : }
784 : : num_ev += err;
785 : : }
786 : : event->dest = addr; /* restore */
787 : : return (result < 0) ? result : num_ev;
788 : : }
789 : :
790 : :
791 : : /* multicast - not supported yet */
792 : : static int multicast_event(struct snd_seq_client *client, struct snd_seq_event *event,
793 : : int atomic, int hop)
794 : : {
795 : : pr_debug("ALSA: seq: multicast not supported yet.\n");
796 : : return 0; /* ignored */
797 : : }
798 : : #endif /* SUPPORT_BROADCAST */
799 : :
800 : :
801 : : /* deliver an event to the destination port(s).
802 : : * if the event is to subscribers or broadcast, the event is dispatched
803 : : * to multiple targets.
804 : : *
805 : : * RETURN VALUE: n > 0 : the number of delivered events.
806 : : * n == 0 : the event was not passed to any client.
807 : : * n < 0 : error - event was not processed.
808 : : */
809 : 42 : static int snd_seq_deliver_event(struct snd_seq_client *client, struct snd_seq_event *event,
810 : : int atomic, int hop)
811 : : {
812 : 42 : int result;
813 : :
814 : 42 : hop++;
815 [ + - ]: 42 : if (hop >= SNDRV_SEQ_MAX_HOPS) {
816 : : pr_debug("ALSA: seq: too long delivery path (%d:%d->%d:%d)\n",
817 : : event->source.client, event->source.port,
818 : : event->dest.client, event->dest.port);
819 : : return -EMLINK;
820 : : }
821 : :
822 [ - + ]: 42 : if (snd_seq_ev_is_variable(event) &&
823 [ # # # # : 0 : snd_BUG_ON(atomic && (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR)))
# # ]
824 : : return -EINVAL;
825 : :
826 [ + - ]: 42 : if (event->queue == SNDRV_SEQ_ADDRESS_SUBSCRIBERS ||
827 [ + - ]: 42 : event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS)
828 : 42 : result = deliver_to_subscribers(client, event, atomic, hop);
829 : : #ifdef SUPPORT_BROADCAST
830 : : else if (event->queue == SNDRV_SEQ_ADDRESS_BROADCAST ||
831 : : event->dest.client == SNDRV_SEQ_ADDRESS_BROADCAST)
832 : : result = broadcast_event(client, event, atomic, hop);
833 : : else if (event->dest.client >= SNDRV_SEQ_MAX_CLIENTS)
834 : : result = multicast_event(client, event, atomic, hop);
835 : : else if (event->dest.port == SNDRV_SEQ_ADDRESS_BROADCAST)
836 : : result = port_broadcast_event(client, event, atomic, hop);
837 : : #endif
838 : : else
839 : 0 : result = snd_seq_deliver_single_event(client, event, 0, atomic, hop);
840 : :
841 : : return result;
842 : : }
843 : :
844 : : /*
845 : : * dispatch an event cell:
846 : : * This function is called only from queue check routines in timer
847 : : * interrupts or after enqueued.
848 : : * The event cell shall be released or re-queued in this function.
849 : : *
850 : : * RETURN VALUE: n > 0 : the number of delivered events.
851 : : * n == 0 : the event was not passed to any client.
852 : : * n < 0 : error - event was not processed.
853 : : */
854 : 0 : int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop)
855 : : {
856 : 0 : struct snd_seq_client *client;
857 : 0 : int result;
858 : :
859 [ # # ]: 0 : if (snd_BUG_ON(!cell))
860 : : return -EINVAL;
861 : :
862 : 0 : client = snd_seq_client_use_ptr(cell->event.source.client);
863 [ # # ]: 0 : if (client == NULL) {
864 : 0 : snd_seq_cell_free(cell); /* release this cell */
865 : 0 : return -EINVAL;
866 : : }
867 : :
868 [ # # ]: 0 : if (cell->event.type == SNDRV_SEQ_EVENT_NOTE) {
869 : : /* NOTE event:
870 : : * the event cell is re-used as a NOTE-OFF event and
871 : : * enqueued again.
872 : : */
873 : 0 : struct snd_seq_event tmpev, *ev;
874 : :
875 : : /* reserve this event to enqueue note-off later */
876 : 0 : tmpev = cell->event;
877 : 0 : tmpev.type = SNDRV_SEQ_EVENT_NOTEON;
878 : 0 : result = snd_seq_deliver_event(client, &tmpev, atomic, hop);
879 : :
880 : : /*
881 : : * This was originally a note event. We now re-use the
882 : : * cell for the note-off event.
883 : : */
884 : :
885 : 0 : ev = &cell->event;
886 : 0 : ev->type = SNDRV_SEQ_EVENT_NOTEOFF;
887 : 0 : ev->flags |= SNDRV_SEQ_PRIORITY_HIGH;
888 : :
889 : : /* add the duration time */
890 [ # # ]: 0 : switch (ev->flags & SNDRV_SEQ_TIME_STAMP_MASK) {
891 : 0 : case SNDRV_SEQ_TIME_STAMP_TICK:
892 : 0 : ev->time.tick += ev->data.note.duration;
893 : 0 : break;
894 : 0 : case SNDRV_SEQ_TIME_STAMP_REAL:
895 : : /* unit for duration is ms */
896 : 0 : ev->time.time.tv_nsec += 1000000 * (ev->data.note.duration % 1000);
897 : 0 : ev->time.time.tv_sec += ev->data.note.duration / 1000 +
898 : 0 : ev->time.time.tv_nsec / 1000000000;
899 : 0 : ev->time.time.tv_nsec %= 1000000000;
900 : 0 : break;
901 : : }
902 : 0 : ev->data.note.velocity = ev->data.note.off_velocity;
903 : :
904 : : /* Now queue this cell as the note off event */
905 [ # # ]: 0 : if (snd_seq_enqueue_event(cell, atomic, hop) < 0)
906 : 0 : snd_seq_cell_free(cell); /* release this cell */
907 : :
908 : : } else {
909 : : /* Normal events:
910 : : * event cell is freed after processing the event
911 : : */
912 : :
913 : 0 : result = snd_seq_deliver_event(client, &cell->event, atomic, hop);
914 : 0 : snd_seq_cell_free(cell);
915 : : }
916 : :
917 : 0 : snd_seq_client_unlock(client);
918 : 0 : return result;
919 : : }
920 : :
921 : :
922 : : /* Allocate a cell from client pool and enqueue it to queue:
923 : : * if pool is empty and blocking is TRUE, sleep until a new cell is
924 : : * available.
925 : : */
926 : 0 : static int snd_seq_client_enqueue_event(struct snd_seq_client *client,
927 : : struct snd_seq_event *event,
928 : : struct file *file, int blocking,
929 : : int atomic, int hop,
930 : : struct mutex *mutexp)
931 : : {
932 : 0 : struct snd_seq_event_cell *cell;
933 : 0 : int err;
934 : :
935 : : /* special queue values - force direct passing */
936 [ # # ]: 0 : if (event->queue == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) {
937 : 0 : event->dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
938 : 0 : event->queue = SNDRV_SEQ_QUEUE_DIRECT;
939 : : } else
940 : : #ifdef SUPPORT_BROADCAST
941 : : if (event->queue == SNDRV_SEQ_ADDRESS_BROADCAST) {
942 : : event->dest.client = SNDRV_SEQ_ADDRESS_BROADCAST;
943 : : event->queue = SNDRV_SEQ_QUEUE_DIRECT;
944 : : }
945 : : #endif
946 [ # # ]: 0 : if (event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) {
947 : : /* check presence of source port */
948 : 0 : struct snd_seq_client_port *src_port = snd_seq_port_use_ptr(client, event->source.port);
949 [ # # ]: 0 : if (src_port == NULL)
950 : : return -EINVAL;
951 : 0 : snd_seq_port_unlock(src_port);
952 : : }
953 : :
954 : : /* direct event processing without enqueued */
955 [ # # ]: 0 : if (snd_seq_ev_is_direct(event)) {
956 [ # # ]: 0 : if (event->type == SNDRV_SEQ_EVENT_NOTE)
957 : : return -EINVAL; /* this event must be enqueued! */
958 : 0 : return snd_seq_deliver_event(client, event, atomic, hop);
959 : : }
960 : :
961 : : /* Not direct, normal queuing */
962 [ # # ]: 0 : if (snd_seq_queue_is_used(event->queue, client->number) <= 0)
963 : : return -EINVAL; /* invalid queue */
964 [ # # # # ]: 0 : if (! snd_seq_write_pool_allocated(client))
965 : : return -ENXIO; /* queue is not allocated */
966 : :
967 : : /* allocate an event cell */
968 : 0 : err = snd_seq_event_dup(client->pool, event, &cell, !blocking || atomic,
969 : : file, mutexp);
970 [ # # ]: 0 : if (err < 0)
971 : : return err;
972 : :
973 : : /* we got a cell. enqueue it. */
974 [ # # ]: 0 : if ((err = snd_seq_enqueue_event(cell, atomic, hop)) < 0) {
975 : 0 : snd_seq_cell_free(cell);
976 : 0 : return err;
977 : : }
978 : :
979 : : return 0;
980 : : }
981 : :
982 : :
983 : : /*
984 : : * check validity of event type and data length.
985 : : * return non-zero if invalid.
986 : : */
987 : 42 : static int check_event_type_and_length(struct snd_seq_event *ev)
988 : : {
989 [ + - - - ]: 42 : switch (snd_seq_ev_length_type(ev)) {
990 : 42 : case SNDRV_SEQ_EVENT_LENGTH_FIXED:
991 [ - + ]: 42 : if (snd_seq_ev_is_variable_type(ev))
992 : 0 : return -EINVAL;
993 : : break;
994 : 0 : case SNDRV_SEQ_EVENT_LENGTH_VARIABLE:
995 [ # # ]: 0 : if (! snd_seq_ev_is_variable_type(ev) ||
996 [ # # ]: 0 : (ev->data.ext.len & ~SNDRV_SEQ_EXT_MASK) >= SNDRV_SEQ_MAX_EVENT_LEN)
997 : 0 : return -EINVAL;
998 : : break;
999 : 0 : case SNDRV_SEQ_EVENT_LENGTH_VARUSR:
1000 [ # # ]: 0 : if (! snd_seq_ev_is_direct(ev))
1001 : 0 : return -EINVAL;
1002 : : break;
1003 : : }
1004 : : return 0;
1005 : : }
1006 : :
1007 : :
1008 : : /* handle write() */
1009 : : /* possible error values:
1010 : : * -ENXIO invalid client or file open mode
1011 : : * -ENOMEM malloc failed
1012 : : * -EFAULT seg. fault during copy from user space
1013 : : * -EINVAL invalid event
1014 : : * -EAGAIN no space in output pool
1015 : : * -EINTR interrupts while sleep
1016 : : * -EMLINK too many hops
1017 : : * others depends on return value from driver callback
1018 : : */
1019 : 0 : static ssize_t snd_seq_write(struct file *file, const char __user *buf,
1020 : : size_t count, loff_t *offset)
1021 : : {
1022 : 0 : struct snd_seq_client *client = file->private_data;
1023 : 0 : int written = 0, len;
1024 : 0 : int err, handled;
1025 : 0 : struct snd_seq_event event;
1026 : :
1027 [ # # # # : 0 : if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT))
# ]
1028 : : return -ENXIO;
1029 : :
1030 : : /* check client structures are in place */
1031 [ # # ]: 0 : if (snd_BUG_ON(!client))
1032 : : return -ENXIO;
1033 : :
1034 [ # # # # ]: 0 : if (!client->accept_output || client->pool == NULL)
1035 : : return -ENXIO;
1036 : :
1037 : 0 : repeat:
1038 : 0 : handled = 0;
1039 : : /* allocate the pool now if the pool is not allocated yet */
1040 : 0 : mutex_lock(&client->ioctl_mutex);
1041 [ # # # # ]: 0 : if (client->pool->size > 0 && !snd_seq_write_pool_allocated(client)) {
1042 : 0 : err = snd_seq_pool_init(client->pool);
1043 [ # # ]: 0 : if (err < 0)
1044 : 0 : goto out;
1045 : : }
1046 : :
1047 : : /* only process whole events */
1048 : : err = -EINVAL;
1049 [ # # ]: 0 : while (count >= sizeof(struct snd_seq_event)) {
1050 : : /* Read in the event header from the user */
1051 : 0 : len = sizeof(event);
1052 [ # # ]: 0 : if (copy_from_user(&event, buf, len)) {
1053 : : err = -EFAULT;
1054 : : break;
1055 : : }
1056 : 0 : event.source.client = client->number; /* fill in client number */
1057 : : /* Check for extension data length */
1058 [ # # ]: 0 : if (check_event_type_and_length(&event)) {
1059 : : err = -EINVAL;
1060 : : break;
1061 : : }
1062 : :
1063 : : /* check for special events */
1064 [ # # ]: 0 : if (event.type == SNDRV_SEQ_EVENT_NONE)
1065 : 0 : goto __skip_event;
1066 [ # # ]: 0 : else if (snd_seq_ev_is_reserved(&event)) {
1067 : : err = -EINVAL;
1068 : : break;
1069 : : }
1070 : :
1071 [ # # ]: 0 : if (snd_seq_ev_is_variable(&event)) {
1072 : 0 : int extlen = event.data.ext.len & ~SNDRV_SEQ_EXT_MASK;
1073 [ # # ]: 0 : if ((size_t)(extlen + len) > count) {
1074 : : /* back out, will get an error this time or next */
1075 : : err = -EINVAL;
1076 : : break;
1077 : : }
1078 : : /* set user space pointer */
1079 : 0 : event.data.ext.len = extlen | SNDRV_SEQ_EXT_USRPTR;
1080 : 0 : event.data.ext.ptr = (char __force *)buf
1081 : 0 : + sizeof(struct snd_seq_event);
1082 : 0 : len += extlen; /* increment data length */
1083 : : } else {
1084 : : #ifdef CONFIG_COMPAT
1085 [ # # # # ]: 0 : if (client->convert32 && snd_seq_ev_is_varusr(&event)) {
1086 : 0 : void *ptr = (void __force *)compat_ptr(event.data.raw32.d[1]);
1087 : 0 : event.data.ext.ptr = ptr;
1088 : : }
1089 : : #endif
1090 : : }
1091 : :
1092 : : /* ok, enqueue it */
1093 : 0 : err = snd_seq_client_enqueue_event(client, &event, file,
1094 : 0 : !(file->f_flags & O_NONBLOCK),
1095 : : 0, 0, &client->ioctl_mutex);
1096 [ # # ]: 0 : if (err < 0)
1097 : : break;
1098 : 0 : handled++;
1099 : :
1100 : 0 : __skip_event:
1101 : : /* Update pointers and counts */
1102 : 0 : count -= len;
1103 : 0 : buf += len;
1104 : 0 : written += len;
1105 : :
1106 : : /* let's have a coffee break if too many events are queued */
1107 [ # # ]: 0 : if (++handled >= 200) {
1108 : 0 : mutex_unlock(&client->ioctl_mutex);
1109 : 0 : goto repeat;
1110 : : }
1111 : : }
1112 : :
1113 : 0 : out:
1114 : 0 : mutex_unlock(&client->ioctl_mutex);
1115 [ # # ]: 0 : return written ? written : err;
1116 : : }
1117 : :
1118 : :
1119 : : /*
1120 : : * handle polling
1121 : : */
1122 : 0 : static __poll_t snd_seq_poll(struct file *file, poll_table * wait)
1123 : : {
1124 : 0 : struct snd_seq_client *client = file->private_data;
1125 : 0 : __poll_t mask = 0;
1126 : :
1127 : : /* check client structures are in place */
1128 [ # # ]: 0 : if (snd_BUG_ON(!client))
1129 : : return EPOLLERR;
1130 : :
1131 [ # # # # : 0 : if ((snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_INPUT) &&
# ]
1132 [ # # ]: 0 : client->data.user.fifo) {
1133 : :
1134 : : /* check if data is available in the outqueue */
1135 [ # # ]: 0 : if (snd_seq_fifo_poll_wait(client->data.user.fifo, file, wait))
1136 : 0 : mask |= EPOLLIN | EPOLLRDNORM;
1137 : : }
1138 : :
1139 [ # # # # : 0 : if (snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT) {
# ]
1140 : :
1141 : : /* check if data is available in the pool */
1142 [ # # # # : 0 : if (!snd_seq_write_pool_allocated(client) ||
# # ]
1143 : 0 : snd_seq_pool_poll_wait(client->pool, file, wait))
1144 : 0 : mask |= EPOLLOUT | EPOLLWRNORM;
1145 : : }
1146 : :
1147 : : return mask;
1148 : : }
1149 : :
1150 : :
1151 : : /*-----------------------------------------------------*/
1152 : :
1153 : 0 : static int snd_seq_ioctl_pversion(struct snd_seq_client *client, void *arg)
1154 : : {
1155 : 0 : int *pversion = arg;
1156 : :
1157 : 0 : *pversion = SNDRV_SEQ_VERSION;
1158 : 0 : return 0;
1159 : : }
1160 : :
1161 : 0 : static int snd_seq_ioctl_client_id(struct snd_seq_client *client, void *arg)
1162 : : {
1163 : 0 : int *client_id = arg;
1164 : :
1165 : 0 : *client_id = client->number;
1166 : 0 : return 0;
1167 : : }
1168 : :
1169 : : /* SYSTEM_INFO ioctl() */
1170 : 0 : static int snd_seq_ioctl_system_info(struct snd_seq_client *client, void *arg)
1171 : : {
1172 : 0 : struct snd_seq_system_info *info = arg;
1173 : :
1174 : 0 : memset(info, 0, sizeof(*info));
1175 : : /* fill the info fields */
1176 : 0 : info->queues = SNDRV_SEQ_MAX_QUEUES;
1177 : 0 : info->clients = SNDRV_SEQ_MAX_CLIENTS;
1178 : 0 : info->ports = SNDRV_SEQ_MAX_PORTS;
1179 : 0 : info->channels = 256; /* fixed limit */
1180 : 0 : info->cur_clients = client_usage.cur;
1181 : 0 : info->cur_queues = snd_seq_queue_get_cur_queues();
1182 : :
1183 : 0 : return 0;
1184 : : }
1185 : :
1186 : :
1187 : : /* RUNNING_MODE ioctl() */
1188 : 0 : static int snd_seq_ioctl_running_mode(struct snd_seq_client *client, void *arg)
1189 : : {
1190 : 0 : struct snd_seq_running_info *info = arg;
1191 : 0 : struct snd_seq_client *cptr;
1192 : 0 : int err = 0;
1193 : :
1194 : : /* requested client number */
1195 : 0 : cptr = snd_seq_client_use_ptr(info->client);
1196 [ # # ]: 0 : if (cptr == NULL)
1197 : : return -ENOENT; /* don't change !!! */
1198 : :
1199 : : #ifdef SNDRV_BIG_ENDIAN
1200 : : if (!info->big_endian) {
1201 : : err = -EINVAL;
1202 : : goto __err;
1203 : : }
1204 : : #else
1205 [ # # ]: 0 : if (info->big_endian) {
1206 : 0 : err = -EINVAL;
1207 : 0 : goto __err;
1208 : : }
1209 : :
1210 : : #endif
1211 [ # # ]: 0 : if (info->cpu_mode > sizeof(long)) {
1212 : 0 : err = -EINVAL;
1213 : 0 : goto __err;
1214 : : }
1215 : 0 : cptr->convert32 = (info->cpu_mode < sizeof(long));
1216 : 0 : __err:
1217 : 0 : snd_seq_client_unlock(cptr);
1218 : 0 : return err;
1219 : : }
1220 : :
1221 : : /* CLIENT_INFO ioctl() */
1222 : 0 : static void get_client_info(struct snd_seq_client *cptr,
1223 : : struct snd_seq_client_info *info)
1224 : : {
1225 : 0 : info->client = cptr->number;
1226 : :
1227 : : /* fill the info fields */
1228 : 0 : info->type = cptr->type;
1229 : 0 : strcpy(info->name, cptr->name);
1230 : 0 : info->filter = cptr->filter;
1231 : 0 : info->event_lost = cptr->event_lost;
1232 : 0 : memcpy(info->event_filter, cptr->event_filter, 32);
1233 : 0 : info->num_ports = cptr->num_ports;
1234 : :
1235 [ # # ]: 0 : if (cptr->type == USER_CLIENT)
1236 : 0 : info->pid = pid_vnr(cptr->data.user.owner);
1237 : : else
1238 : 0 : info->pid = -1;
1239 : :
1240 [ # # ]: 0 : if (cptr->type == KERNEL_CLIENT)
1241 [ # # ]: 0 : info->card = cptr->data.kernel.card ? cptr->data.kernel.card->number : -1;
1242 : : else
1243 : 0 : info->card = -1;
1244 : :
1245 : 0 : memset(info->reserved, 0, sizeof(info->reserved));
1246 : 0 : }
1247 : :
1248 : 0 : static int snd_seq_ioctl_get_client_info(struct snd_seq_client *client,
1249 : : void *arg)
1250 : : {
1251 : 0 : struct snd_seq_client_info *client_info = arg;
1252 : 0 : struct snd_seq_client *cptr;
1253 : :
1254 : : /* requested client number */
1255 : 0 : cptr = snd_seq_client_use_ptr(client_info->client);
1256 [ # # ]: 0 : if (cptr == NULL)
1257 : : return -ENOENT; /* don't change !!! */
1258 : :
1259 : 0 : get_client_info(cptr, client_info);
1260 : 0 : snd_seq_client_unlock(cptr);
1261 : :
1262 : 0 : return 0;
1263 : : }
1264 : :
1265 : :
1266 : : /* CLIENT_INFO ioctl() */
1267 : 0 : static int snd_seq_ioctl_set_client_info(struct snd_seq_client *client,
1268 : : void *arg)
1269 : : {
1270 : 0 : struct snd_seq_client_info *client_info = arg;
1271 : :
1272 : : /* it is not allowed to set the info fields for an another client */
1273 [ # # ]: 0 : if (client->number != client_info->client)
1274 : : return -EPERM;
1275 : : /* also client type must be set now */
1276 [ # # ]: 0 : if (client->type != client_info->type)
1277 : : return -EINVAL;
1278 : :
1279 : : /* fill the info fields */
1280 [ # # ]: 0 : if (client_info->name[0])
1281 : 0 : strscpy(client->name, client_info->name, sizeof(client->name));
1282 : :
1283 : 0 : client->filter = client_info->filter;
1284 : 0 : client->event_lost = client_info->event_lost;
1285 : 0 : memcpy(client->event_filter, client_info->event_filter, 32);
1286 : :
1287 : 0 : return 0;
1288 : : }
1289 : :
1290 : :
1291 : : /*
1292 : : * CREATE PORT ioctl()
1293 : : */
1294 : 63 : static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg)
1295 : : {
1296 : 63 : struct snd_seq_port_info *info = arg;
1297 : 63 : struct snd_seq_client_port *port;
1298 : 63 : struct snd_seq_port_callback *callback;
1299 : 63 : int port_idx;
1300 : :
1301 : : /* it is not allowed to create the port for an another client */
1302 [ + - ]: 63 : if (info->addr.client != client->number)
1303 : : return -EPERM;
1304 : :
1305 [ + + ]: 63 : port = snd_seq_create_port(client, (info->flags & SNDRV_SEQ_PORT_FLG_GIVEN_PORT) ? info->addr.port : -1);
1306 [ + - ]: 63 : if (port == NULL)
1307 : : return -ENOMEM;
1308 : :
1309 [ - + - - ]: 63 : if (client->type == USER_CLIENT && info->kernel) {
1310 : 0 : port_idx = port->addr.port;
1311 : 0 : snd_seq_port_unlock(port);
1312 : 0 : snd_seq_delete_port(client, port_idx);
1313 : 0 : return -EINVAL;
1314 : : }
1315 [ + - ]: 63 : if (client->type == KERNEL_CLIENT) {
1316 [ + + ]: 63 : if ((callback = info->kernel) != NULL) {
1317 [ - + ]: 42 : if (callback->owner)
1318 : 0 : port->owner = callback->owner;
1319 : 42 : port->private_data = callback->private_data;
1320 : 42 : port->private_free = callback->private_free;
1321 : 42 : port->event_input = callback->event_input;
1322 : 42 : port->c_src.open = callback->subscribe;
1323 : 42 : port->c_src.close = callback->unsubscribe;
1324 : 42 : port->c_dest.open = callback->use;
1325 : 42 : port->c_dest.close = callback->unuse;
1326 : : }
1327 : : }
1328 : :
1329 : 63 : info->addr = port->addr;
1330 : :
1331 : 63 : snd_seq_set_port_info(port, info);
1332 : 63 : snd_seq_system_client_ev_port_start(port->addr.client, port->addr.port);
1333 : 63 : snd_seq_port_unlock(port);
1334 : :
1335 : 63 : return 0;
1336 : : }
1337 : :
1338 : : /*
1339 : : * DELETE PORT ioctl()
1340 : : */
1341 : 0 : static int snd_seq_ioctl_delete_port(struct snd_seq_client *client, void *arg)
1342 : : {
1343 : 0 : struct snd_seq_port_info *info = arg;
1344 : 0 : int err;
1345 : :
1346 : : /* it is not allowed to remove the port for an another client */
1347 [ # # ]: 0 : if (info->addr.client != client->number)
1348 : : return -EPERM;
1349 : :
1350 : 0 : err = snd_seq_delete_port(client, info->addr.port);
1351 [ # # ]: 0 : if (err >= 0)
1352 : 0 : snd_seq_system_client_ev_port_exit(client->number, info->addr.port);
1353 : : return err;
1354 : : }
1355 : :
1356 : :
1357 : : /*
1358 : : * GET_PORT_INFO ioctl() (on any client)
1359 : : */
1360 : 0 : static int snd_seq_ioctl_get_port_info(struct snd_seq_client *client, void *arg)
1361 : : {
1362 : 0 : struct snd_seq_port_info *info = arg;
1363 : 0 : struct snd_seq_client *cptr;
1364 : 0 : struct snd_seq_client_port *port;
1365 : :
1366 : 0 : cptr = snd_seq_client_use_ptr(info->addr.client);
1367 [ # # ]: 0 : if (cptr == NULL)
1368 : : return -ENXIO;
1369 : :
1370 : 0 : port = snd_seq_port_use_ptr(cptr, info->addr.port);
1371 [ # # ]: 0 : if (port == NULL) {
1372 : 0 : snd_seq_client_unlock(cptr);
1373 : 0 : return -ENOENT; /* don't change */
1374 : : }
1375 : :
1376 : : /* get port info */
1377 : 0 : snd_seq_get_port_info(port, info);
1378 : 0 : snd_seq_port_unlock(port);
1379 : 0 : snd_seq_client_unlock(cptr);
1380 : :
1381 : 0 : return 0;
1382 : : }
1383 : :
1384 : :
1385 : : /*
1386 : : * SET_PORT_INFO ioctl() (only ports on this/own client)
1387 : : */
1388 : 0 : static int snd_seq_ioctl_set_port_info(struct snd_seq_client *client, void *arg)
1389 : : {
1390 : 0 : struct snd_seq_port_info *info = arg;
1391 : 0 : struct snd_seq_client_port *port;
1392 : :
1393 [ # # ]: 0 : if (info->addr.client != client->number) /* only set our own ports ! */
1394 : : return -EPERM;
1395 : 0 : port = snd_seq_port_use_ptr(client, info->addr.port);
1396 [ # # ]: 0 : if (port) {
1397 : 0 : snd_seq_set_port_info(port, info);
1398 : 0 : snd_seq_port_unlock(port);
1399 : : }
1400 : : return 0;
1401 : : }
1402 : :
1403 : :
1404 : : /*
1405 : : * port subscription (connection)
1406 : : */
1407 : : #define PERM_RD (SNDRV_SEQ_PORT_CAP_READ|SNDRV_SEQ_PORT_CAP_SUBS_READ)
1408 : : #define PERM_WR (SNDRV_SEQ_PORT_CAP_WRITE|SNDRV_SEQ_PORT_CAP_SUBS_WRITE)
1409 : :
1410 : : static int check_subscription_permission(struct snd_seq_client *client,
1411 : : struct snd_seq_client_port *sport,
1412 : : struct snd_seq_client_port *dport,
1413 : : struct snd_seq_port_subscribe *subs)
1414 : : {
1415 : : if (client->number != subs->sender.client &&
1416 : : client->number != subs->dest.client) {
1417 : : /* connection by third client - check export permission */
1418 : : if (check_port_perm(sport, SNDRV_SEQ_PORT_CAP_NO_EXPORT))
1419 : : return -EPERM;
1420 : : if (check_port_perm(dport, SNDRV_SEQ_PORT_CAP_NO_EXPORT))
1421 : : return -EPERM;
1422 : : }
1423 : :
1424 : : /* check read permission */
1425 : : /* if sender or receiver is the subscribing client itself,
1426 : : * no permission check is necessary
1427 : : */
1428 : : if (client->number != subs->sender.client) {
1429 : : if (! check_port_perm(sport, PERM_RD))
1430 : : return -EPERM;
1431 : : }
1432 : : /* check write permission */
1433 : : if (client->number != subs->dest.client) {
1434 : : if (! check_port_perm(dport, PERM_WR))
1435 : : return -EPERM;
1436 : : }
1437 : : return 0;
1438 : : }
1439 : :
1440 : : /*
1441 : : * send an subscription notify event to user client:
1442 : : * client must be user client.
1443 : : */
1444 : 0 : int snd_seq_client_notify_subscription(int client, int port,
1445 : : struct snd_seq_port_subscribe *info,
1446 : : int evtype)
1447 : : {
1448 : 0 : struct snd_seq_event event;
1449 : :
1450 : 0 : memset(&event, 0, sizeof(event));
1451 : 0 : event.type = evtype;
1452 : 0 : event.data.connect.dest = info->dest;
1453 : 0 : event.data.connect.sender = info->sender;
1454 : :
1455 : 0 : return snd_seq_system_notify(client, port, &event); /* non-atomic */
1456 : : }
1457 : :
1458 : :
1459 : : /*
1460 : : * add to port's subscription list IOCTL interface
1461 : : */
1462 : 0 : static int snd_seq_ioctl_subscribe_port(struct snd_seq_client *client,
1463 : : void *arg)
1464 : : {
1465 : 0 : struct snd_seq_port_subscribe *subs = arg;
1466 : 0 : int result = -EINVAL;
1467 : 0 : struct snd_seq_client *receiver = NULL, *sender = NULL;
1468 : 0 : struct snd_seq_client_port *sport = NULL, *dport = NULL;
1469 : :
1470 [ # # ]: 0 : if ((receiver = snd_seq_client_use_ptr(subs->dest.client)) == NULL)
1471 : 0 : goto __end;
1472 [ # # ]: 0 : if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL)
1473 : 0 : goto __end;
1474 [ # # ]: 0 : if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL)
1475 : 0 : goto __end;
1476 [ # # ]: 0 : if ((dport = snd_seq_port_use_ptr(receiver, subs->dest.port)) == NULL)
1477 : 0 : goto __end;
1478 : :
1479 : 0 : result = check_subscription_permission(client, sport, dport, subs);
1480 [ # # ]: 0 : if (result < 0)
1481 : 0 : goto __end;
1482 : :
1483 : : /* connect them */
1484 : 0 : result = snd_seq_port_connect(client, sender, sport, receiver, dport, subs);
1485 [ # # ]: 0 : if (! result) /* broadcast announce */
1486 : 0 : snd_seq_client_notify_subscription(SNDRV_SEQ_ADDRESS_SUBSCRIBERS, 0,
1487 : : subs, SNDRV_SEQ_EVENT_PORT_SUBSCRIBED);
1488 : 0 : __end:
1489 [ # # ]: 0 : if (sport)
1490 : 0 : snd_seq_port_unlock(sport);
1491 [ # # ]: 0 : if (dport)
1492 : 0 : snd_seq_port_unlock(dport);
1493 [ # # ]: 0 : if (sender)
1494 : 0 : snd_seq_client_unlock(sender);
1495 [ # # ]: 0 : if (receiver)
1496 : 0 : snd_seq_client_unlock(receiver);
1497 : 0 : return result;
1498 : : }
1499 : :
1500 : :
1501 : : /*
1502 : : * remove from port's subscription list
1503 : : */
1504 : 0 : static int snd_seq_ioctl_unsubscribe_port(struct snd_seq_client *client,
1505 : : void *arg)
1506 : : {
1507 : 0 : struct snd_seq_port_subscribe *subs = arg;
1508 : 0 : int result = -ENXIO;
1509 : 0 : struct snd_seq_client *receiver = NULL, *sender = NULL;
1510 : 0 : struct snd_seq_client_port *sport = NULL, *dport = NULL;
1511 : :
1512 [ # # ]: 0 : if ((receiver = snd_seq_client_use_ptr(subs->dest.client)) == NULL)
1513 : 0 : goto __end;
1514 [ # # ]: 0 : if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL)
1515 : 0 : goto __end;
1516 [ # # ]: 0 : if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL)
1517 : 0 : goto __end;
1518 [ # # ]: 0 : if ((dport = snd_seq_port_use_ptr(receiver, subs->dest.port)) == NULL)
1519 : 0 : goto __end;
1520 : :
1521 : 0 : result = check_subscription_permission(client, sport, dport, subs);
1522 [ # # ]: 0 : if (result < 0)
1523 : 0 : goto __end;
1524 : :
1525 : 0 : result = snd_seq_port_disconnect(client, sender, sport, receiver, dport, subs);
1526 [ # # ]: 0 : if (! result) /* broadcast announce */
1527 : 0 : snd_seq_client_notify_subscription(SNDRV_SEQ_ADDRESS_SUBSCRIBERS, 0,
1528 : : subs, SNDRV_SEQ_EVENT_PORT_UNSUBSCRIBED);
1529 : 0 : __end:
1530 [ # # ]: 0 : if (sport)
1531 : 0 : snd_seq_port_unlock(sport);
1532 [ # # ]: 0 : if (dport)
1533 : 0 : snd_seq_port_unlock(dport);
1534 [ # # ]: 0 : if (sender)
1535 : 0 : snd_seq_client_unlock(sender);
1536 [ # # ]: 0 : if (receiver)
1537 : 0 : snd_seq_client_unlock(receiver);
1538 : 0 : return result;
1539 : : }
1540 : :
1541 : :
1542 : : /* CREATE_QUEUE ioctl() */
1543 : 0 : static int snd_seq_ioctl_create_queue(struct snd_seq_client *client, void *arg)
1544 : : {
1545 : 0 : struct snd_seq_queue_info *info = arg;
1546 : 0 : struct snd_seq_queue *q;
1547 : :
1548 : 0 : q = snd_seq_queue_alloc(client->number, info->locked, info->flags);
1549 [ # # ]: 0 : if (IS_ERR(q))
1550 : 0 : return PTR_ERR(q);
1551 : :
1552 : 0 : info->queue = q->queue;
1553 : 0 : info->locked = q->locked;
1554 : 0 : info->owner = q->owner;
1555 : :
1556 : : /* set queue name */
1557 [ # # ]: 0 : if (!info->name[0])
1558 : 0 : snprintf(info->name, sizeof(info->name), "Queue-%d", q->queue);
1559 : 0 : strscpy(q->name, info->name, sizeof(q->name));
1560 : 0 : snd_use_lock_free(&q->use_lock);
1561 : :
1562 : 0 : return 0;
1563 : : }
1564 : :
1565 : : /* DELETE_QUEUE ioctl() */
1566 : 0 : static int snd_seq_ioctl_delete_queue(struct snd_seq_client *client, void *arg)
1567 : : {
1568 : 0 : struct snd_seq_queue_info *info = arg;
1569 : :
1570 : 0 : return snd_seq_queue_delete(client->number, info->queue);
1571 : : }
1572 : :
1573 : : /* GET_QUEUE_INFO ioctl() */
1574 : 0 : static int snd_seq_ioctl_get_queue_info(struct snd_seq_client *client,
1575 : : void *arg)
1576 : : {
1577 : 0 : struct snd_seq_queue_info *info = arg;
1578 : 0 : struct snd_seq_queue *q;
1579 : :
1580 : 0 : q = queueptr(info->queue);
1581 [ # # ]: 0 : if (q == NULL)
1582 : : return -EINVAL;
1583 : :
1584 : 0 : memset(info, 0, sizeof(*info));
1585 : 0 : info->queue = q->queue;
1586 : 0 : info->owner = q->owner;
1587 : 0 : info->locked = q->locked;
1588 : 0 : strlcpy(info->name, q->name, sizeof(info->name));
1589 : 0 : queuefree(q);
1590 : :
1591 : 0 : return 0;
1592 : : }
1593 : :
1594 : : /* SET_QUEUE_INFO ioctl() */
1595 : 0 : static int snd_seq_ioctl_set_queue_info(struct snd_seq_client *client,
1596 : : void *arg)
1597 : : {
1598 : 0 : struct snd_seq_queue_info *info = arg;
1599 : 0 : struct snd_seq_queue *q;
1600 : :
1601 [ # # ]: 0 : if (info->owner != client->number)
1602 : : return -EINVAL;
1603 : :
1604 : : /* change owner/locked permission */
1605 [ # # ]: 0 : if (snd_seq_queue_check_access(info->queue, client->number)) {
1606 [ # # ]: 0 : if (snd_seq_queue_set_owner(info->queue, client->number, info->locked) < 0)
1607 : : return -EPERM;
1608 [ # # ]: 0 : if (info->locked)
1609 : 0 : snd_seq_queue_use(info->queue, client->number, 1);
1610 : : } else {
1611 : : return -EPERM;
1612 : : }
1613 : :
1614 : 0 : q = queueptr(info->queue);
1615 [ # # ]: 0 : if (! q)
1616 : : return -EINVAL;
1617 [ # # ]: 0 : if (q->owner != client->number) {
1618 : 0 : queuefree(q);
1619 : 0 : return -EPERM;
1620 : : }
1621 : 0 : strscpy(q->name, info->name, sizeof(q->name));
1622 : 0 : queuefree(q);
1623 : :
1624 : 0 : return 0;
1625 : : }
1626 : :
1627 : : /* GET_NAMED_QUEUE ioctl() */
1628 : 0 : static int snd_seq_ioctl_get_named_queue(struct snd_seq_client *client,
1629 : : void *arg)
1630 : : {
1631 : 0 : struct snd_seq_queue_info *info = arg;
1632 : 0 : struct snd_seq_queue *q;
1633 : :
1634 : 0 : q = snd_seq_queue_find_name(info->name);
1635 [ # # ]: 0 : if (q == NULL)
1636 : : return -EINVAL;
1637 : 0 : info->queue = q->queue;
1638 : 0 : info->owner = q->owner;
1639 : 0 : info->locked = q->locked;
1640 : 0 : queuefree(q);
1641 : :
1642 : 0 : return 0;
1643 : : }
1644 : :
1645 : : /* GET_QUEUE_STATUS ioctl() */
1646 : 0 : static int snd_seq_ioctl_get_queue_status(struct snd_seq_client *client,
1647 : : void *arg)
1648 : : {
1649 : 0 : struct snd_seq_queue_status *status = arg;
1650 : 0 : struct snd_seq_queue *queue;
1651 : 0 : struct snd_seq_timer *tmr;
1652 : :
1653 : 0 : queue = queueptr(status->queue);
1654 [ # # ]: 0 : if (queue == NULL)
1655 : : return -EINVAL;
1656 : 0 : memset(status, 0, sizeof(*status));
1657 : 0 : status->queue = queue->queue;
1658 : :
1659 : 0 : tmr = queue->timer;
1660 : 0 : status->events = queue->tickq->cells + queue->timeq->cells;
1661 : :
1662 : 0 : status->time = snd_seq_timer_get_cur_time(tmr, true);
1663 : 0 : status->tick = snd_seq_timer_get_cur_tick(tmr);
1664 : :
1665 : 0 : status->running = tmr->running;
1666 : :
1667 : 0 : status->flags = queue->flags;
1668 : 0 : queuefree(queue);
1669 : :
1670 : 0 : return 0;
1671 : : }
1672 : :
1673 : :
1674 : : /* GET_QUEUE_TEMPO ioctl() */
1675 : 0 : static int snd_seq_ioctl_get_queue_tempo(struct snd_seq_client *client,
1676 : : void *arg)
1677 : : {
1678 : 0 : struct snd_seq_queue_tempo *tempo = arg;
1679 : 0 : struct snd_seq_queue *queue;
1680 : 0 : struct snd_seq_timer *tmr;
1681 : :
1682 : 0 : queue = queueptr(tempo->queue);
1683 [ # # ]: 0 : if (queue == NULL)
1684 : : return -EINVAL;
1685 : 0 : memset(tempo, 0, sizeof(*tempo));
1686 : 0 : tempo->queue = queue->queue;
1687 : :
1688 : 0 : tmr = queue->timer;
1689 : :
1690 : 0 : tempo->tempo = tmr->tempo;
1691 : 0 : tempo->ppq = tmr->ppq;
1692 : 0 : tempo->skew_value = tmr->skew;
1693 : 0 : tempo->skew_base = tmr->skew_base;
1694 : 0 : queuefree(queue);
1695 : :
1696 : 0 : return 0;
1697 : : }
1698 : :
1699 : :
1700 : : /* SET_QUEUE_TEMPO ioctl() */
1701 : 0 : int snd_seq_set_queue_tempo(int client, struct snd_seq_queue_tempo *tempo)
1702 : : {
1703 [ # # ]: 0 : if (!snd_seq_queue_check_access(tempo->queue, client))
1704 : : return -EPERM;
1705 : 0 : return snd_seq_queue_timer_set_tempo(tempo->queue, client, tempo);
1706 : : }
1707 : : EXPORT_SYMBOL(snd_seq_set_queue_tempo);
1708 : :
1709 : 0 : static int snd_seq_ioctl_set_queue_tempo(struct snd_seq_client *client,
1710 : : void *arg)
1711 : : {
1712 : 0 : struct snd_seq_queue_tempo *tempo = arg;
1713 : 0 : int result;
1714 : :
1715 : 0 : result = snd_seq_set_queue_tempo(client->number, tempo);
1716 : 0 : return result < 0 ? result : 0;
1717 : : }
1718 : :
1719 : :
1720 : : /* GET_QUEUE_TIMER ioctl() */
1721 : 0 : static int snd_seq_ioctl_get_queue_timer(struct snd_seq_client *client,
1722 : : void *arg)
1723 : : {
1724 : 0 : struct snd_seq_queue_timer *timer = arg;
1725 : 0 : struct snd_seq_queue *queue;
1726 : 0 : struct snd_seq_timer *tmr;
1727 : :
1728 : 0 : queue = queueptr(timer->queue);
1729 [ # # ]: 0 : if (queue == NULL)
1730 : : return -EINVAL;
1731 : :
1732 : 0 : mutex_lock(&queue->timer_mutex);
1733 : 0 : tmr = queue->timer;
1734 : 0 : memset(timer, 0, sizeof(*timer));
1735 : 0 : timer->queue = queue->queue;
1736 : :
1737 : 0 : timer->type = tmr->type;
1738 [ # # ]: 0 : if (tmr->type == SNDRV_SEQ_TIMER_ALSA) {
1739 : 0 : timer->u.alsa.id = tmr->alsa_id;
1740 : 0 : timer->u.alsa.resolution = tmr->preferred_resolution;
1741 : : }
1742 : 0 : mutex_unlock(&queue->timer_mutex);
1743 : 0 : queuefree(queue);
1744 : :
1745 : 0 : return 0;
1746 : : }
1747 : :
1748 : :
1749 : : /* SET_QUEUE_TIMER ioctl() */
1750 : 0 : static int snd_seq_ioctl_set_queue_timer(struct snd_seq_client *client,
1751 : : void *arg)
1752 : : {
1753 : 0 : struct snd_seq_queue_timer *timer = arg;
1754 : 0 : int result = 0;
1755 : :
1756 [ # # ]: 0 : if (timer->type != SNDRV_SEQ_TIMER_ALSA)
1757 : : return -EINVAL;
1758 : :
1759 [ # # ]: 0 : if (snd_seq_queue_check_access(timer->queue, client->number)) {
1760 : 0 : struct snd_seq_queue *q;
1761 : 0 : struct snd_seq_timer *tmr;
1762 : :
1763 : 0 : q = queueptr(timer->queue);
1764 [ # # ]: 0 : if (q == NULL)
1765 : : return -ENXIO;
1766 : 0 : mutex_lock(&q->timer_mutex);
1767 : 0 : tmr = q->timer;
1768 : 0 : snd_seq_queue_timer_close(timer->queue);
1769 : 0 : tmr->type = timer->type;
1770 [ # # ]: 0 : if (tmr->type == SNDRV_SEQ_TIMER_ALSA) {
1771 : 0 : tmr->alsa_id = timer->u.alsa.id;
1772 : 0 : tmr->preferred_resolution = timer->u.alsa.resolution;
1773 : : }
1774 : 0 : result = snd_seq_queue_timer_open(timer->queue);
1775 : 0 : mutex_unlock(&q->timer_mutex);
1776 : 0 : queuefree(q);
1777 : : } else {
1778 : : return -EPERM;
1779 : : }
1780 : :
1781 : 0 : return result;
1782 : : }
1783 : :
1784 : :
1785 : : /* GET_QUEUE_CLIENT ioctl() */
1786 : 0 : static int snd_seq_ioctl_get_queue_client(struct snd_seq_client *client,
1787 : : void *arg)
1788 : : {
1789 : 0 : struct snd_seq_queue_client *info = arg;
1790 : 0 : int used;
1791 : :
1792 : 0 : used = snd_seq_queue_is_used(info->queue, client->number);
1793 [ # # # # ]: 0 : if (used < 0)
1794 : : return -EINVAL;
1795 : 0 : info->used = used;
1796 : 0 : info->client = client->number;
1797 : :
1798 : 0 : return 0;
1799 : : }
1800 : :
1801 : :
1802 : : /* SET_QUEUE_CLIENT ioctl() */
1803 : 0 : static int snd_seq_ioctl_set_queue_client(struct snd_seq_client *client,
1804 : : void *arg)
1805 : : {
1806 : 0 : struct snd_seq_queue_client *info = arg;
1807 : 0 : int err;
1808 : :
1809 [ # # ]: 0 : if (info->used >= 0) {
1810 : 0 : err = snd_seq_queue_use(info->queue, client->number, info->used);
1811 [ # # ]: 0 : if (err < 0)
1812 : : return err;
1813 : : }
1814 : :
1815 : 0 : return snd_seq_ioctl_get_queue_client(client, arg);
1816 : : }
1817 : :
1818 : :
1819 : : /* GET_CLIENT_POOL ioctl() */
1820 : 0 : static int snd_seq_ioctl_get_client_pool(struct snd_seq_client *client,
1821 : : void *arg)
1822 : : {
1823 : 0 : struct snd_seq_client_pool *info = arg;
1824 : 0 : struct snd_seq_client *cptr;
1825 : :
1826 : 0 : cptr = snd_seq_client_use_ptr(info->client);
1827 [ # # ]: 0 : if (cptr == NULL)
1828 : : return -ENOENT;
1829 : 0 : memset(info, 0, sizeof(*info));
1830 : 0 : info->client = cptr->number;
1831 : 0 : info->output_pool = cptr->pool->size;
1832 : 0 : info->output_room = cptr->pool->room;
1833 : 0 : info->output_free = info->output_pool;
1834 [ # # ]: 0 : info->output_free = snd_seq_unused_cells(cptr->pool);
1835 [ # # ]: 0 : if (cptr->type == USER_CLIENT) {
1836 : 0 : info->input_pool = cptr->data.user.fifo_pool_size;
1837 : 0 : info->input_free = info->input_pool;
1838 : 0 : info->input_free = snd_seq_fifo_unused_cells(cptr->data.user.fifo);
1839 : : } else {
1840 : 0 : info->input_pool = 0;
1841 : 0 : info->input_free = 0;
1842 : : }
1843 : 0 : snd_seq_client_unlock(cptr);
1844 : :
1845 : 0 : return 0;
1846 : : }
1847 : :
1848 : : /* SET_CLIENT_POOL ioctl() */
1849 : 0 : static int snd_seq_ioctl_set_client_pool(struct snd_seq_client *client,
1850 : : void *arg)
1851 : : {
1852 : 0 : struct snd_seq_client_pool *info = arg;
1853 : 0 : int rc;
1854 : :
1855 [ # # ]: 0 : if (client->number != info->client)
1856 : : return -EINVAL; /* can't change other clients */
1857 : :
1858 [ # # # # ]: 0 : if (info->output_pool >= 1 && info->output_pool <= SNDRV_SEQ_MAX_EVENTS &&
1859 [ # # ]: 0 : (! snd_seq_write_pool_allocated(client) ||
1860 [ # # ]: 0 : info->output_pool != client->pool->size)) {
1861 [ # # # # ]: 0 : if (snd_seq_write_pool_allocated(client)) {
1862 : : /* is the pool in use? */
1863 [ # # ]: 0 : if (atomic_read(&client->pool->counter))
1864 : : return -EBUSY;
1865 : : /* remove all existing cells */
1866 : 0 : snd_seq_pool_mark_closing(client->pool);
1867 : 0 : snd_seq_pool_done(client->pool);
1868 : : }
1869 : 0 : client->pool->size = info->output_pool;
1870 : 0 : rc = snd_seq_pool_init(client->pool);
1871 [ # # ]: 0 : if (rc < 0)
1872 : : return rc;
1873 : : }
1874 [ # # # # ]: 0 : if (client->type == USER_CLIENT && client->data.user.fifo != NULL &&
1875 [ # # # # ]: 0 : info->input_pool >= 1 &&
1876 : 0 : info->input_pool <= SNDRV_SEQ_MAX_CLIENT_EVENTS &&
1877 [ # # ]: 0 : info->input_pool != client->data.user.fifo_pool_size) {
1878 : : /* change pool size */
1879 : 0 : rc = snd_seq_fifo_resize(client->data.user.fifo, info->input_pool);
1880 [ # # ]: 0 : if (rc < 0)
1881 : : return rc;
1882 : 0 : client->data.user.fifo_pool_size = info->input_pool;
1883 : : }
1884 [ # # ]: 0 : if (info->output_room >= 1 &&
1885 [ # # ]: 0 : info->output_room <= client->pool->size) {
1886 : 0 : client->pool->room = info->output_room;
1887 : : }
1888 : :
1889 : 0 : return snd_seq_ioctl_get_client_pool(client, arg);
1890 : : }
1891 : :
1892 : :
1893 : : /* REMOVE_EVENTS ioctl() */
1894 : 0 : static int snd_seq_ioctl_remove_events(struct snd_seq_client *client,
1895 : : void *arg)
1896 : : {
1897 : 0 : struct snd_seq_remove_events *info = arg;
1898 : :
1899 : : /*
1900 : : * Input mostly not implemented XXX.
1901 : : */
1902 [ # # ]: 0 : if (info->remove_mode & SNDRV_SEQ_REMOVE_INPUT) {
1903 : : /*
1904 : : * No restrictions so for a user client we can clear
1905 : : * the whole fifo
1906 : : */
1907 [ # # # # ]: 0 : if (client->type == USER_CLIENT && client->data.user.fifo)
1908 : 0 : snd_seq_fifo_clear(client->data.user.fifo);
1909 : : }
1910 : :
1911 [ # # ]: 0 : if (info->remove_mode & SNDRV_SEQ_REMOVE_OUTPUT)
1912 : 0 : snd_seq_queue_remove_cells(client->number, info);
1913 : :
1914 : 0 : return 0;
1915 : : }
1916 : :
1917 : :
1918 : : /*
1919 : : * get subscription info
1920 : : */
1921 : 0 : static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client,
1922 : : void *arg)
1923 : : {
1924 : 0 : struct snd_seq_port_subscribe *subs = arg;
1925 : 0 : int result;
1926 : 0 : struct snd_seq_client *sender = NULL;
1927 : 0 : struct snd_seq_client_port *sport = NULL;
1928 : :
1929 : 0 : result = -EINVAL;
1930 [ # # ]: 0 : if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL)
1931 : 0 : goto __end;
1932 [ # # ]: 0 : if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL)
1933 : 0 : goto __end;
1934 : 0 : result = snd_seq_port_get_subscription(&sport->c_src, &subs->dest,
1935 : : subs);
1936 : 0 : __end:
1937 [ # # ]: 0 : if (sport)
1938 : 0 : snd_seq_port_unlock(sport);
1939 [ # # ]: 0 : if (sender)
1940 : 0 : snd_seq_client_unlock(sender);
1941 : :
1942 : 0 : return result;
1943 : : }
1944 : :
1945 : :
1946 : : /*
1947 : : * get subscription info - check only its presence
1948 : : */
1949 : 0 : static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg)
1950 : : {
1951 : 0 : struct snd_seq_query_subs *subs = arg;
1952 : 0 : int result = -ENXIO;
1953 : 0 : struct snd_seq_client *cptr = NULL;
1954 : 0 : struct snd_seq_client_port *port = NULL;
1955 : 0 : struct snd_seq_port_subs_info *group;
1956 : 0 : struct list_head *p;
1957 : 0 : int i;
1958 : :
1959 [ # # ]: 0 : if ((cptr = snd_seq_client_use_ptr(subs->root.client)) == NULL)
1960 : 0 : goto __end;
1961 [ # # ]: 0 : if ((port = snd_seq_port_use_ptr(cptr, subs->root.port)) == NULL)
1962 : 0 : goto __end;
1963 : :
1964 [ # # # ]: 0 : switch (subs->type) {
1965 : 0 : case SNDRV_SEQ_QUERY_SUBS_READ:
1966 : 0 : group = &port->c_src;
1967 : 0 : break;
1968 : 0 : case SNDRV_SEQ_QUERY_SUBS_WRITE:
1969 : 0 : group = &port->c_dest;
1970 : 0 : break;
1971 : 0 : default:
1972 : 0 : goto __end;
1973 : : }
1974 : :
1975 : 0 : down_read(&group->list_mutex);
1976 : : /* search for the subscriber */
1977 : 0 : subs->num_subs = group->count;
1978 : 0 : i = 0;
1979 : 0 : result = -ENOENT;
1980 [ # # ]: 0 : list_for_each(p, &group->list_head) {
1981 [ # # ]: 0 : if (i++ == subs->index) {
1982 : : /* found! */
1983 : 0 : struct snd_seq_subscribers *s;
1984 [ # # ]: 0 : if (subs->type == SNDRV_SEQ_QUERY_SUBS_READ) {
1985 : 0 : s = list_entry(p, struct snd_seq_subscribers, src_list);
1986 : 0 : subs->addr = s->info.dest;
1987 : : } else {
1988 : 0 : s = list_entry(p, struct snd_seq_subscribers, dest_list);
1989 : 0 : subs->addr = s->info.sender;
1990 : : }
1991 : 0 : subs->flags = s->info.flags;
1992 : 0 : subs->queue = s->info.queue;
1993 : 0 : result = 0;
1994 : 0 : break;
1995 : : }
1996 : : }
1997 : 0 : up_read(&group->list_mutex);
1998 : :
1999 : 0 : __end:
2000 [ # # ]: 0 : if (port)
2001 : 0 : snd_seq_port_unlock(port);
2002 [ # # ]: 0 : if (cptr)
2003 : 0 : snd_seq_client_unlock(cptr);
2004 : :
2005 : 0 : return result;
2006 : : }
2007 : :
2008 : :
2009 : : /*
2010 : : * query next client
2011 : : */
2012 : 0 : static int snd_seq_ioctl_query_next_client(struct snd_seq_client *client,
2013 : : void *arg)
2014 : : {
2015 : 0 : struct snd_seq_client_info *info = arg;
2016 : 0 : struct snd_seq_client *cptr = NULL;
2017 : :
2018 : : /* search for next client */
2019 [ # # ]: 0 : if (info->client < INT_MAX)
2020 : 0 : info->client++;
2021 [ # # ]: 0 : if (info->client < 0)
2022 : 0 : info->client = 0;
2023 [ # # ]: 0 : for (; info->client < SNDRV_SEQ_MAX_CLIENTS; info->client++) {
2024 : 0 : cptr = snd_seq_client_use_ptr(info->client);
2025 [ # # ]: 0 : if (cptr)
2026 : : break; /* found */
2027 : : }
2028 [ # # ]: 0 : if (cptr == NULL)
2029 : : return -ENOENT;
2030 : :
2031 : 0 : get_client_info(cptr, info);
2032 : 0 : snd_seq_client_unlock(cptr);
2033 : :
2034 : 0 : return 0;
2035 : : }
2036 : :
2037 : : /*
2038 : : * query next port
2039 : : */
2040 : 0 : static int snd_seq_ioctl_query_next_port(struct snd_seq_client *client,
2041 : : void *arg)
2042 : : {
2043 : 0 : struct snd_seq_port_info *info = arg;
2044 : 0 : struct snd_seq_client *cptr;
2045 : 0 : struct snd_seq_client_port *port = NULL;
2046 : :
2047 : 0 : cptr = snd_seq_client_use_ptr(info->addr.client);
2048 [ # # ]: 0 : if (cptr == NULL)
2049 : : return -ENXIO;
2050 : :
2051 : : /* search for next port */
2052 : 0 : info->addr.port++;
2053 : 0 : port = snd_seq_port_query_nearest(cptr, info);
2054 [ # # ]: 0 : if (port == NULL) {
2055 : 0 : snd_seq_client_unlock(cptr);
2056 : 0 : return -ENOENT;
2057 : : }
2058 : :
2059 : : /* get port info */
2060 : 0 : info->addr = port->addr;
2061 : 0 : snd_seq_get_port_info(port, info);
2062 : 0 : snd_seq_port_unlock(port);
2063 : 0 : snd_seq_client_unlock(cptr);
2064 : :
2065 : 0 : return 0;
2066 : : }
2067 : :
2068 : : /* -------------------------------------------------------- */
2069 : :
2070 : : static const struct ioctl_handler {
2071 : : unsigned int cmd;
2072 : : int (*func)(struct snd_seq_client *client, void *arg);
2073 : : } ioctl_handlers[] = {
2074 : : { SNDRV_SEQ_IOCTL_PVERSION, snd_seq_ioctl_pversion },
2075 : : { SNDRV_SEQ_IOCTL_CLIENT_ID, snd_seq_ioctl_client_id },
2076 : : { SNDRV_SEQ_IOCTL_SYSTEM_INFO, snd_seq_ioctl_system_info },
2077 : : { SNDRV_SEQ_IOCTL_RUNNING_MODE, snd_seq_ioctl_running_mode },
2078 : : { SNDRV_SEQ_IOCTL_GET_CLIENT_INFO, snd_seq_ioctl_get_client_info },
2079 : : { SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, snd_seq_ioctl_set_client_info },
2080 : : { SNDRV_SEQ_IOCTL_CREATE_PORT, snd_seq_ioctl_create_port },
2081 : : { SNDRV_SEQ_IOCTL_DELETE_PORT, snd_seq_ioctl_delete_port },
2082 : : { SNDRV_SEQ_IOCTL_GET_PORT_INFO, snd_seq_ioctl_get_port_info },
2083 : : { SNDRV_SEQ_IOCTL_SET_PORT_INFO, snd_seq_ioctl_set_port_info },
2084 : : { SNDRV_SEQ_IOCTL_SUBSCRIBE_PORT, snd_seq_ioctl_subscribe_port },
2085 : : { SNDRV_SEQ_IOCTL_UNSUBSCRIBE_PORT, snd_seq_ioctl_unsubscribe_port },
2086 : : { SNDRV_SEQ_IOCTL_CREATE_QUEUE, snd_seq_ioctl_create_queue },
2087 : : { SNDRV_SEQ_IOCTL_DELETE_QUEUE, snd_seq_ioctl_delete_queue },
2088 : : { SNDRV_SEQ_IOCTL_GET_QUEUE_INFO, snd_seq_ioctl_get_queue_info },
2089 : : { SNDRV_SEQ_IOCTL_SET_QUEUE_INFO, snd_seq_ioctl_set_queue_info },
2090 : : { SNDRV_SEQ_IOCTL_GET_NAMED_QUEUE, snd_seq_ioctl_get_named_queue },
2091 : : { SNDRV_SEQ_IOCTL_GET_QUEUE_STATUS, snd_seq_ioctl_get_queue_status },
2092 : : { SNDRV_SEQ_IOCTL_GET_QUEUE_TEMPO, snd_seq_ioctl_get_queue_tempo },
2093 : : { SNDRV_SEQ_IOCTL_SET_QUEUE_TEMPO, snd_seq_ioctl_set_queue_tempo },
2094 : : { SNDRV_SEQ_IOCTL_GET_QUEUE_TIMER, snd_seq_ioctl_get_queue_timer },
2095 : : { SNDRV_SEQ_IOCTL_SET_QUEUE_TIMER, snd_seq_ioctl_set_queue_timer },
2096 : : { SNDRV_SEQ_IOCTL_GET_QUEUE_CLIENT, snd_seq_ioctl_get_queue_client },
2097 : : { SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT, snd_seq_ioctl_set_queue_client },
2098 : : { SNDRV_SEQ_IOCTL_GET_CLIENT_POOL, snd_seq_ioctl_get_client_pool },
2099 : : { SNDRV_SEQ_IOCTL_SET_CLIENT_POOL, snd_seq_ioctl_set_client_pool },
2100 : : { SNDRV_SEQ_IOCTL_GET_SUBSCRIPTION, snd_seq_ioctl_get_subscription },
2101 : : { SNDRV_SEQ_IOCTL_QUERY_NEXT_CLIENT, snd_seq_ioctl_query_next_client },
2102 : : { SNDRV_SEQ_IOCTL_QUERY_NEXT_PORT, snd_seq_ioctl_query_next_port },
2103 : : { SNDRV_SEQ_IOCTL_REMOVE_EVENTS, snd_seq_ioctl_remove_events },
2104 : : { SNDRV_SEQ_IOCTL_QUERY_SUBS, snd_seq_ioctl_query_subs },
2105 : : { 0, NULL },
2106 : : };
2107 : :
2108 : 0 : static long snd_seq_ioctl(struct file *file, unsigned int cmd,
2109 : : unsigned long arg)
2110 : : {
2111 : 0 : struct snd_seq_client *client = file->private_data;
2112 : : /* To use kernel stack for ioctl data. */
2113 : 0 : union {
2114 : : int pversion;
2115 : : int client_id;
2116 : : struct snd_seq_system_info system_info;
2117 : : struct snd_seq_running_info running_info;
2118 : : struct snd_seq_client_info client_info;
2119 : : struct snd_seq_port_info port_info;
2120 : : struct snd_seq_port_subscribe port_subscribe;
2121 : : struct snd_seq_queue_info queue_info;
2122 : : struct snd_seq_queue_status queue_status;
2123 : : struct snd_seq_queue_tempo tempo;
2124 : : struct snd_seq_queue_timer queue_timer;
2125 : : struct snd_seq_queue_client queue_client;
2126 : : struct snd_seq_client_pool client_pool;
2127 : : struct snd_seq_remove_events remove_events;
2128 : : struct snd_seq_query_subs query_subs;
2129 : : } buf;
2130 : 0 : const struct ioctl_handler *handler;
2131 : 0 : unsigned long size;
2132 : 0 : int err;
2133 : :
2134 [ # # ]: 0 : if (snd_BUG_ON(!client))
2135 : : return -ENXIO;
2136 : :
2137 [ # # ]: 0 : for (handler = ioctl_handlers; handler->cmd > 0; ++handler) {
2138 [ # # ]: 0 : if (handler->cmd == cmd)
2139 : : break;
2140 : : }
2141 [ # # ]: 0 : if (handler->cmd == 0)
2142 : : return -ENOTTY;
2143 : :
2144 : 0 : memset(&buf, 0, sizeof(buf));
2145 : :
2146 : : /*
2147 : : * All of ioctl commands for ALSA sequencer get an argument of size
2148 : : * within 13 bits. We can safely pick up the size from the command.
2149 : : */
2150 : 0 : size = _IOC_SIZE(handler->cmd);
2151 [ # # ]: 0 : if (handler->cmd & IOC_IN) {
2152 [ # # # # ]: 0 : if (copy_from_user(&buf, (const void __user *)arg, size))
2153 : : return -EFAULT;
2154 : : }
2155 : :
2156 : 0 : mutex_lock(&client->ioctl_mutex);
2157 : 0 : err = handler->func(client, &buf);
2158 : 0 : mutex_unlock(&client->ioctl_mutex);
2159 [ # # ]: 0 : if (err >= 0) {
2160 : : /* Some commands includes a bug in 'dir' field. */
2161 [ # # ]: 0 : if (handler->cmd == SNDRV_SEQ_IOCTL_SET_QUEUE_CLIENT ||
2162 [ # # ]: 0 : handler->cmd == SNDRV_SEQ_IOCTL_SET_CLIENT_POOL ||
2163 : : (handler->cmd & IOC_OUT))
2164 [ # # # # ]: 0 : if (copy_to_user((void __user *)arg, &buf, size))
2165 : : return -EFAULT;
2166 : : }
2167 : :
2168 : 0 : return err;
2169 : : }
2170 : :
2171 : : #ifdef CONFIG_COMPAT
2172 : : #include "seq_compat.c"
2173 : : #else
2174 : : #define snd_seq_ioctl_compat NULL
2175 : : #endif
2176 : :
2177 : : /* -------------------------------------------------------- */
2178 : :
2179 : :
2180 : : /* exported to kernel modules */
2181 : 42 : int snd_seq_create_kernel_client(struct snd_card *card, int client_index,
2182 : : const char *name_fmt, ...)
2183 : : {
2184 : 42 : struct snd_seq_client *client;
2185 : 42 : va_list args;
2186 : :
2187 [ + - ]: 42 : if (snd_BUG_ON(in_interrupt()))
2188 : : return -EBUSY;
2189 : :
2190 [ + - ]: 42 : if (card && client_index >= SNDRV_SEQ_CLIENTS_PER_CARD)
2191 : : return -EINVAL;
2192 [ + - ]: 42 : if (card == NULL && client_index >= SNDRV_SEQ_GLOBAL_CLIENTS)
2193 : : return -EINVAL;
2194 : :
2195 : 42 : mutex_lock(®ister_mutex);
2196 : :
2197 [ - + ]: 42 : if (card) {
2198 : 0 : client_index += SNDRV_SEQ_GLOBAL_CLIENTS
2199 : 0 : + card->number * SNDRV_SEQ_CLIENTS_PER_CARD;
2200 [ # # ]: 0 : if (client_index >= SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN)
2201 : 0 : client_index = -1;
2202 : : }
2203 : :
2204 : : /* empty write queue as default */
2205 : 42 : client = seq_create_client1(client_index, 0);
2206 [ - + ]: 42 : if (client == NULL) {
2207 : 0 : mutex_unlock(®ister_mutex);
2208 : 0 : return -EBUSY; /* failure code */
2209 : : }
2210 [ + - ]: 42 : usage_alloc(&client_usage, 1);
2211 : :
2212 : 42 : client->accept_input = 1;
2213 : 42 : client->accept_output = 1;
2214 : 42 : client->data.kernel.card = card;
2215 : :
2216 : 42 : va_start(args, name_fmt);
2217 : 42 : vsnprintf(client->name, sizeof(client->name), name_fmt, args);
2218 : 42 : va_end(args);
2219 : :
2220 : 42 : client->type = KERNEL_CLIENT;
2221 : 42 : mutex_unlock(®ister_mutex);
2222 : :
2223 : : /* make others aware this new client */
2224 : 42 : snd_seq_system_client_ev_client_start(client->number);
2225 : :
2226 : : /* return client number to caller */
2227 : 42 : return client->number;
2228 : : }
2229 : : EXPORT_SYMBOL(snd_seq_create_kernel_client);
2230 : :
2231 : : /* exported to kernel modules */
2232 : 0 : int snd_seq_delete_kernel_client(int client)
2233 : : {
2234 : 0 : struct snd_seq_client *ptr;
2235 : :
2236 [ # # ]: 0 : if (snd_BUG_ON(in_interrupt()))
2237 : : return -EBUSY;
2238 : :
2239 [ # # ]: 0 : ptr = clientptr(client);
2240 [ # # ]: 0 : if (ptr == NULL)
2241 : : return -EINVAL;
2242 : :
2243 : 0 : seq_free_client(ptr);
2244 : 0 : kfree(ptr);
2245 : 0 : return 0;
2246 : : }
2247 : : EXPORT_SYMBOL(snd_seq_delete_kernel_client);
2248 : :
2249 : : /*
2250 : : * exported, called by kernel clients to enqueue events (w/o blocking)
2251 : : *
2252 : : * RETURN VALUE: zero if succeed, negative if error
2253 : : */
2254 : 0 : int snd_seq_kernel_client_enqueue(int client, struct snd_seq_event *ev,
2255 : : struct file *file, bool blocking)
2256 : : {
2257 : 0 : struct snd_seq_client *cptr;
2258 : 0 : int result;
2259 : :
2260 [ # # ]: 0 : if (snd_BUG_ON(!ev))
2261 : : return -EINVAL;
2262 : :
2263 [ # # ]: 0 : if (ev->type == SNDRV_SEQ_EVENT_NONE)
2264 : : return 0; /* ignore this */
2265 [ # # ]: 0 : if (ev->type == SNDRV_SEQ_EVENT_KERNEL_ERROR)
2266 : : return -EINVAL; /* quoted events can't be enqueued */
2267 : :
2268 : : /* fill in client number */
2269 : 0 : ev->source.client = client;
2270 : :
2271 [ # # ]: 0 : if (check_event_type_and_length(ev))
2272 : : return -EINVAL;
2273 : :
2274 : 0 : cptr = snd_seq_client_use_ptr(client);
2275 [ # # ]: 0 : if (cptr == NULL)
2276 : : return -EINVAL;
2277 : :
2278 [ # # ]: 0 : if (!cptr->accept_output) {
2279 : : result = -EPERM;
2280 : : } else { /* send it */
2281 : 0 : mutex_lock(&cptr->ioctl_mutex);
2282 : 0 : result = snd_seq_client_enqueue_event(cptr, ev, file, blocking,
2283 : : false, 0,
2284 : : &cptr->ioctl_mutex);
2285 : 0 : mutex_unlock(&cptr->ioctl_mutex);
2286 : : }
2287 : :
2288 : 0 : snd_seq_client_unlock(cptr);
2289 : 0 : return result;
2290 : : }
2291 : : EXPORT_SYMBOL(snd_seq_kernel_client_enqueue);
2292 : :
2293 : : /*
2294 : : * exported, called by kernel clients to dispatch events directly to other
2295 : : * clients, bypassing the queues. Event time-stamp will be updated.
2296 : : *
2297 : : * RETURN VALUE: negative = delivery failed,
2298 : : * zero, or positive: the number of delivered events
2299 : : */
2300 : 42 : int snd_seq_kernel_client_dispatch(int client, struct snd_seq_event * ev,
2301 : : int atomic, int hop)
2302 : : {
2303 : 42 : struct snd_seq_client *cptr;
2304 : 42 : int result;
2305 : :
2306 [ + - ]: 42 : if (snd_BUG_ON(!ev))
2307 : : return -EINVAL;
2308 : :
2309 : : /* fill in client number */
2310 : 42 : ev->queue = SNDRV_SEQ_QUEUE_DIRECT;
2311 : 42 : ev->source.client = client;
2312 : :
2313 [ + - ]: 42 : if (check_event_type_and_length(ev))
2314 : : return -EINVAL;
2315 : :
2316 : 42 : cptr = snd_seq_client_use_ptr(client);
2317 [ + - ]: 42 : if (cptr == NULL)
2318 : : return -EINVAL;
2319 : :
2320 [ + - ]: 42 : if (!cptr->accept_output)
2321 : : result = -EPERM;
2322 : : else
2323 : 42 : result = snd_seq_deliver_event(cptr, ev, atomic, hop);
2324 : :
2325 : 42 : snd_seq_client_unlock(cptr);
2326 : 42 : return result;
2327 : : }
2328 : : EXPORT_SYMBOL(snd_seq_kernel_client_dispatch);
2329 : :
2330 : : /**
2331 : : * snd_seq_kernel_client_ctl - operate a command for a client with data in
2332 : : * kernel space.
2333 : : * @clientid: A numerical ID for a client.
2334 : : * @cmd: An ioctl(2) command for ALSA sequencer operation.
2335 : : * @arg: A pointer to data in kernel space.
2336 : : *
2337 : : * Against its name, both kernel/application client can be handled by this
2338 : : * kernel API. A pointer of 'arg' argument should be in kernel space.
2339 : : *
2340 : : * Return: 0 at success. Negative error code at failure.
2341 : : */
2342 : 63 : int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg)
2343 : : {
2344 : 63 : const struct ioctl_handler *handler;
2345 : 63 : struct snd_seq_client *client;
2346 : :
2347 [ + - ]: 63 : client = clientptr(clientid);
2348 [ + - ]: 63 : if (client == NULL)
2349 : : return -ENXIO;
2350 : :
2351 [ + - ]: 441 : for (handler = ioctl_handlers; handler->cmd > 0; ++handler) {
2352 [ + + ]: 441 : if (handler->cmd == cmd)
2353 : 63 : return handler->func(client, arg);
2354 : : }
2355 : :
2356 : : pr_debug("ALSA: seq unknown ioctl() 0x%x (type='%c', number=0x%02x)\n",
2357 : : cmd, _IOC_TYPE(cmd), _IOC_NR(cmd));
2358 : : return -ENOTTY;
2359 : : }
2360 : : EXPORT_SYMBOL(snd_seq_kernel_client_ctl);
2361 : :
2362 : : /* exported (for OSS emulator) */
2363 : 0 : int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table *wait)
2364 : : {
2365 : 0 : struct snd_seq_client *client;
2366 : :
2367 [ # # ]: 0 : client = clientptr(clientid);
2368 [ # # ]: 0 : if (client == NULL)
2369 : : return -ENXIO;
2370 : :
2371 [ # # # # ]: 0 : if (! snd_seq_write_pool_allocated(client))
2372 : : return 1;
2373 [ # # ]: 0 : if (snd_seq_pool_poll_wait(client->pool, file, wait))
2374 : 0 : return 1;
2375 : : return 0;
2376 : : }
2377 : : EXPORT_SYMBOL(snd_seq_kernel_client_write_poll);
2378 : :
2379 : : /*---------------------------------------------------------------------------*/
2380 : :
2381 : : #ifdef CONFIG_SND_PROC_FS
2382 : : /*
2383 : : * /proc interface
2384 : : */
2385 : : static void snd_seq_info_dump_subscribers(struct snd_info_buffer *buffer,
2386 : : struct snd_seq_port_subs_info *group,
2387 : : int is_src, char *msg)
2388 : : {
2389 : : struct list_head *p;
2390 : : struct snd_seq_subscribers *s;
2391 : : int count = 0;
2392 : :
2393 : : down_read(&group->list_mutex);
2394 : : if (list_empty(&group->list_head)) {
2395 : : up_read(&group->list_mutex);
2396 : : return;
2397 : : }
2398 : : snd_iprintf(buffer, msg);
2399 : : list_for_each(p, &group->list_head) {
2400 : : if (is_src)
2401 : : s = list_entry(p, struct snd_seq_subscribers, src_list);
2402 : : else
2403 : : s = list_entry(p, struct snd_seq_subscribers, dest_list);
2404 : : if (count++)
2405 : : snd_iprintf(buffer, ", ");
2406 : : snd_iprintf(buffer, "%d:%d",
2407 : : is_src ? s->info.dest.client : s->info.sender.client,
2408 : : is_src ? s->info.dest.port : s->info.sender.port);
2409 : : if (s->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP)
2410 : : snd_iprintf(buffer, "[%c:%d]", ((s->info.flags & SNDRV_SEQ_PORT_SUBS_TIME_REAL) ? 'r' : 't'), s->info.queue);
2411 : : if (group->exclusive)
2412 : : snd_iprintf(buffer, "[ex]");
2413 : : }
2414 : : up_read(&group->list_mutex);
2415 : : snd_iprintf(buffer, "\n");
2416 : : }
2417 : :
2418 : : #define FLAG_PERM_RD(perm) ((perm) & SNDRV_SEQ_PORT_CAP_READ ? ((perm) & SNDRV_SEQ_PORT_CAP_SUBS_READ ? 'R' : 'r') : '-')
2419 : : #define FLAG_PERM_WR(perm) ((perm) & SNDRV_SEQ_PORT_CAP_WRITE ? ((perm) & SNDRV_SEQ_PORT_CAP_SUBS_WRITE ? 'W' : 'w') : '-')
2420 : : #define FLAG_PERM_EX(perm) ((perm) & SNDRV_SEQ_PORT_CAP_NO_EXPORT ? '-' : 'e')
2421 : :
2422 : : #define FLAG_PERM_DUPLEX(perm) ((perm) & SNDRV_SEQ_PORT_CAP_DUPLEX ? 'X' : '-')
2423 : :
2424 : 0 : static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer,
2425 : : struct snd_seq_client *client)
2426 : : {
2427 : 0 : struct snd_seq_client_port *p;
2428 : :
2429 : 0 : mutex_lock(&client->ports_mutex);
2430 [ # # ]: 0 : list_for_each_entry(p, &client->ports_list_head, list) {
2431 [ # # # # : 0 : snd_iprintf(buffer, " Port %3d : \"%s\" (%c%c%c%c)\n",
# # # # #
# # # ]
2432 : : p->addr.port, p->name,
2433 : : FLAG_PERM_RD(p->capability),
2434 : : FLAG_PERM_WR(p->capability),
2435 : : FLAG_PERM_EX(p->capability),
2436 : : FLAG_PERM_DUPLEX(p->capability));
2437 : 0 : snd_seq_info_dump_subscribers(buffer, &p->c_src, 1, " Connecting To: ");
2438 : 0 : snd_seq_info_dump_subscribers(buffer, &p->c_dest, 0, " Connected From: ");
2439 : : }
2440 : 0 : mutex_unlock(&client->ports_mutex);
2441 : 0 : }
2442 : :
2443 : :
2444 : : /* exported to seq_info.c */
2445 : 0 : void snd_seq_info_clients_read(struct snd_info_entry *entry,
2446 : : struct snd_info_buffer *buffer)
2447 : : {
2448 : 0 : int c;
2449 : 0 : struct snd_seq_client *client;
2450 : :
2451 : 0 : snd_iprintf(buffer, "Client info\n");
2452 : 0 : snd_iprintf(buffer, " cur clients : %d\n", client_usage.cur);
2453 : 0 : snd_iprintf(buffer, " peak clients : %d\n", client_usage.peak);
2454 : 0 : snd_iprintf(buffer, " max clients : %d\n", SNDRV_SEQ_MAX_CLIENTS);
2455 : 0 : snd_iprintf(buffer, "\n");
2456 : :
2457 : : /* list the client table */
2458 [ # # ]: 0 : for (c = 0; c < SNDRV_SEQ_MAX_CLIENTS; c++) {
2459 : 0 : client = snd_seq_client_use_ptr(c);
2460 [ # # ]: 0 : if (client == NULL)
2461 : 0 : continue;
2462 [ # # ]: 0 : if (client->type == NO_CLIENT) {
2463 : 0 : snd_seq_client_unlock(client);
2464 : 0 : continue;
2465 : : }
2466 : :
2467 [ # # ]: 0 : snd_iprintf(buffer, "Client %3d : \"%s\" [%s]\n",
2468 : : c, client->name,
2469 : : client->type == USER_CLIENT ? "User" : "Kernel");
2470 : 0 : snd_seq_info_dump_ports(buffer, client);
2471 [ # # # # ]: 0 : if (snd_seq_write_pool_allocated(client)) {
2472 : 0 : snd_iprintf(buffer, " Output pool :\n");
2473 : 0 : snd_seq_info_pool(buffer, client->pool, " ");
2474 : : }
2475 [ # # # # ]: 0 : if (client->type == USER_CLIENT && client->data.user.fifo &&
2476 [ # # ]: 0 : client->data.user.fifo->pool) {
2477 : 0 : snd_iprintf(buffer, " Input pool :\n");
2478 : 0 : snd_seq_info_pool(buffer, client->data.user.fifo->pool, " ");
2479 : : }
2480 : 0 : snd_seq_client_unlock(client);
2481 : : }
2482 : 0 : }
2483 : : #endif /* CONFIG_SND_PROC_FS */
2484 : :
2485 : : /*---------------------------------------------------------------------------*/
2486 : :
2487 : :
2488 : : /*
2489 : : * REGISTRATION PART
2490 : : */
2491 : :
2492 : : static const struct file_operations snd_seq_f_ops =
2493 : : {
2494 : : .owner = THIS_MODULE,
2495 : : .read = snd_seq_read,
2496 : : .write = snd_seq_write,
2497 : : .open = snd_seq_open,
2498 : : .release = snd_seq_release,
2499 : : .llseek = no_llseek,
2500 : : .poll = snd_seq_poll,
2501 : : .unlocked_ioctl = snd_seq_ioctl,
2502 : : .compat_ioctl = snd_seq_ioctl_compat,
2503 : : };
2504 : :
2505 : : static struct device seq_dev;
2506 : :
2507 : : /*
2508 : : * register sequencer device
2509 : : */
2510 : 21 : int __init snd_sequencer_device_init(void)
2511 : : {
2512 : 21 : int err;
2513 : :
2514 : 21 : snd_device_initialize(&seq_dev, NULL);
2515 : 21 : dev_set_name(&seq_dev, "seq");
2516 : :
2517 : 21 : mutex_lock(®ister_mutex);
2518 : 21 : err = snd_register_device(SNDRV_DEVICE_TYPE_SEQUENCER, NULL, 0,
2519 : : &snd_seq_f_ops, NULL, &seq_dev);
2520 : 21 : mutex_unlock(®ister_mutex);
2521 [ - + ]: 21 : if (err < 0) {
2522 : 0 : put_device(&seq_dev);
2523 : 0 : return err;
2524 : : }
2525 : :
2526 : : return 0;
2527 : : }
2528 : :
2529 : :
2530 : :
2531 : : /*
2532 : : * unregister sequencer device
2533 : : */
2534 : 0 : void snd_sequencer_device_done(void)
2535 : : {
2536 : 0 : snd_unregister_device(&seq_dev);
2537 : 0 : put_device(&seq_dev);
2538 : 0 : }
|