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