/sound/core/seq/seq_clientmgr.c
C | 2587 lines | 1845 code | 407 blank | 335 comment | 443 complexity | 97f18edf8b2ca43fb7205d9da84547d0 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, GPL-2.0, LGPL-2.0, AGPL-1.0
Large files files are truncated, but you can click here to view the full file
- /*
- * ALSA sequencer Client Manager
- * Copyright (c) 1998-2001 by Frank van de Pol <fvdpol@coil.demon.nl>
- * Jaroslav Kysela <perex@perex.cz>
- * Takashi Iwai <tiwai@suse.de>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
- #include <linux/init.h>
- #include <linux/slab.h>
- #include <sound/core.h>
- #include <sound/minors.h>
- #include <linux/kmod.h>
- #include <sound/seq_kernel.h>
- #include "seq_clientmgr.h"
- #include "seq_memory.h"
- #include "seq_queue.h"
- #include "seq_timer.h"
- #include "seq_info.h"
- #include "seq_system.h"
- #include <sound/seq_device.h>
- #ifdef CONFIG_COMPAT
- #include <linux/compat.h>
- #endif
- /* Client Manager
- * this module handles the connections of userland and kernel clients
- *
- */
- /*
- * There are four ranges of client numbers (last two shared):
- * 0..15: global clients
- * 16..127: statically allocated client numbers for cards 0..27
- * 128..191: dynamically allocated client numbers for cards 28..31
- * 128..191: dynamically allocated client numbers for applications
- */
- /* number of kernel non-card clients */
- #define SNDRV_SEQ_GLOBAL_CLIENTS 16
- /* clients per cards, for static clients */
- #define SNDRV_SEQ_CLIENTS_PER_CARD 4
- /* dynamically allocated client numbers (both kernel drivers and user space) */
- #define SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN 128
- #define SNDRV_SEQ_LFLG_INPUT 0x0001
- #define SNDRV_SEQ_LFLG_OUTPUT 0x0002
- #define SNDRV_SEQ_LFLG_OPEN (SNDRV_SEQ_LFLG_INPUT|SNDRV_SEQ_LFLG_OUTPUT)
- static DEFINE_SPINLOCK(clients_lock);
- static DEFINE_MUTEX(register_mutex);
- /*
- * client table
- */
- static char clienttablock[SNDRV_SEQ_MAX_CLIENTS];
- static struct snd_seq_client *clienttab[SNDRV_SEQ_MAX_CLIENTS];
- static struct snd_seq_usage client_usage;
- /*
- * prototypes
- */
- static int bounce_error_event(struct snd_seq_client *client,
- struct snd_seq_event *event,
- int err, int atomic, int hop);
- static int snd_seq_deliver_single_event(struct snd_seq_client *client,
- struct snd_seq_event *event,
- int filter, int atomic, int hop);
- /*
- */
-
- static inline mm_segment_t snd_enter_user(void)
- {
- mm_segment_t fs = get_fs();
- set_fs(get_ds());
- return fs;
- }
- static inline void snd_leave_user(mm_segment_t fs)
- {
- set_fs(fs);
- }
- /*
- */
- static inline unsigned short snd_seq_file_flags(struct file *file)
- {
- switch (file->f_mode & (FMODE_READ | FMODE_WRITE)) {
- case FMODE_WRITE:
- return SNDRV_SEQ_LFLG_OUTPUT;
- case FMODE_READ:
- return SNDRV_SEQ_LFLG_INPUT;
- default:
- return SNDRV_SEQ_LFLG_OPEN;
- }
- }
- static inline int snd_seq_write_pool_allocated(struct snd_seq_client *client)
- {
- return snd_seq_total_cells(client->pool) > 0;
- }
- /* return pointer to client structure for specified id */
- static struct snd_seq_client *clientptr(int clientid)
- {
- if (clientid < 0 || clientid >= SNDRV_SEQ_MAX_CLIENTS) {
- snd_printd("Seq: oops. Trying to get pointer to client %d\n",
- clientid);
- return NULL;
- }
- return clienttab[clientid];
- }
- struct snd_seq_client *snd_seq_client_use_ptr(int clientid)
- {
- unsigned long flags;
- struct snd_seq_client *client;
- if (clientid < 0 || clientid >= SNDRV_SEQ_MAX_CLIENTS) {
- snd_printd("Seq: oops. Trying to get pointer to client %d\n",
- clientid);
- return NULL;
- }
- spin_lock_irqsave(&clients_lock, flags);
- client = clientptr(clientid);
- if (client)
- goto __lock;
- if (clienttablock[clientid]) {
- spin_unlock_irqrestore(&clients_lock, flags);
- return NULL;
- }
- spin_unlock_irqrestore(&clients_lock, flags);
- #ifdef CONFIG_MODULES
- if (!in_interrupt()) {
- static char client_requested[SNDRV_SEQ_GLOBAL_CLIENTS];
- static char card_requested[SNDRV_CARDS];
- if (clientid < SNDRV_SEQ_GLOBAL_CLIENTS) {
- int idx;
-
- if (!client_requested[clientid]) {
- client_requested[clientid] = 1;
- for (idx = 0; idx < 15; idx++) {
- if (seq_client_load[idx] < 0)
- break;
- if (seq_client_load[idx] == clientid) {
- request_module("snd-seq-client-%i",
- clientid);
- break;
- }
- }
- }
- } else if (clientid < SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN) {
- int card = (clientid - SNDRV_SEQ_GLOBAL_CLIENTS) /
- SNDRV_SEQ_CLIENTS_PER_CARD;
- if (card < snd_ecards_limit) {
- if (! card_requested[card]) {
- card_requested[card] = 1;
- snd_request_card(card);
- }
- snd_seq_device_load_drivers();
- }
- }
- spin_lock_irqsave(&clients_lock, flags);
- client = clientptr(clientid);
- if (client)
- goto __lock;
- spin_unlock_irqrestore(&clients_lock, flags);
- }
- #endif
- return NULL;
- __lock:
- snd_use_lock_use(&client->use_lock);
- spin_unlock_irqrestore(&clients_lock, flags);
- return client;
- }
- static void usage_alloc(struct snd_seq_usage *res, int num)
- {
- res->cur += num;
- if (res->cur > res->peak)
- res->peak = res->cur;
- }
- static void usage_free(struct snd_seq_usage *res, int num)
- {
- res->cur -= num;
- }
- /* initialise data structures */
- int __init client_init_data(void)
- {
- /* zap out the client table */
- memset(&clienttablock, 0, sizeof(clienttablock));
- memset(&clienttab, 0, sizeof(clienttab));
- return 0;
- }
- static struct snd_seq_client *seq_create_client1(int client_index, int poolsize)
- {
- unsigned long flags;
- int c;
- struct snd_seq_client *client;
- /* init client data */
- client = kzalloc(sizeof(*client), GFP_KERNEL);
- if (client == NULL)
- return NULL;
- client->pool = snd_seq_pool_new(poolsize);
- if (client->pool == NULL) {
- kfree(client);
- return NULL;
- }
- client->type = NO_CLIENT;
- snd_use_lock_init(&client->use_lock);
- rwlock_init(&client->ports_lock);
- mutex_init(&client->ports_mutex);
- INIT_LIST_HEAD(&client->ports_list_head);
- /* find free slot in the client table */
- spin_lock_irqsave(&clients_lock, flags);
- if (client_index < 0) {
- for (c = SNDRV_SEQ_DYNAMIC_CLIENTS_BEGIN;
- c < SNDRV_SEQ_MAX_CLIENTS;
- c++) {
- if (clienttab[c] || clienttablock[c])
- continue;
- clienttab[client->number = c] = client;
-