linux/sound/core/seq/seq_device.c
<<
>>
Prefs
   1/*
   2 *  ALSA sequencer device management
   3 *  Copyright (c) 1999 by Takashi Iwai <tiwai@suse.de>
   4 *
   5 *   This program is free software; you can redistribute it and/or modify
   6 *   it under the terms of the GNU General Public License as published by
   7 *   the Free Software Foundation; either version 2 of the License, or
   8 *   (at your option) any later version.
   9 *
  10 *   This program is distributed in the hope that it will be useful,
  11 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 *   GNU General Public License for more details.
  14 *
  15 *   You should have received a copy of the GNU General Public License
  16 *   along with this program; if not, write to the Free Software
  17 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  18 *
  19 *
  20 *----------------------------------------------------------------
  21 *
  22 * This device handler separates the card driver module from sequencer
  23 * stuff (sequencer core, synth drivers, etc), so that user can avoid
  24 * to spend unnecessary resources e.g. if he needs only listening to
  25 * MP3s.
  26 *
  27 * The card (or lowlevel) driver creates a sequencer device entry
  28 * via snd_seq_device_new().  This is an entry pointer to communicate
  29 * with the sequencer device "driver", which is involved with the
  30 * actual part to communicate with the sequencer core.
  31 * Each sequencer device entry has an id string and the corresponding
  32 * driver with the same id is loaded when required.  For example,
  33 * lowlevel codes to access emu8000 chip on sbawe card are included in
  34 * emu8000-synth module.  To activate this module, the hardware
  35 * resources like i/o port are passed via snd_seq_device argument.
  36 *
  37 */
  38
  39#include <linux/init.h>
  40#include <linux/module.h>
  41#include <sound/core.h>
  42#include <sound/info.h>
  43#include <sound/seq_device.h>
  44#include <sound/seq_kernel.h>
  45#include <sound/initval.h>
  46#include <linux/kmod.h>
  47#include <linux/slab.h>
  48#include <linux/mutex.h>
  49
  50MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
  51MODULE_DESCRIPTION("ALSA sequencer device management");
  52MODULE_LICENSE("GPL");
  53
  54/* driver state */
  55#define DRIVER_EMPTY            0
  56#define DRIVER_LOADED           (1<<0)
  57#define DRIVER_REQUESTED        (1<<1)
  58#define DRIVER_LOCKED           (1<<2)
  59#define DRIVER_REQUESTING       (1<<3)
  60
  61struct ops_list {
  62        char id[ID_LEN];        /* driver id */
  63        int driver;             /* driver state */
  64        int used;               /* reference counter */
  65        int argsize;            /* argument size */
  66
  67        /* operators */
  68        struct snd_seq_dev_ops ops;
  69
  70        /* registered devices */
  71        struct list_head dev_list;      /* list of devices */
  72        int num_devices;        /* number of associated devices */
  73        int num_init_devices;   /* number of initialized devices */
  74        struct mutex reg_mutex;
  75
  76        struct list_head list;  /* next driver */
  77};
  78
  79
  80static LIST_HEAD(opslist);
  81static int num_ops;
  82static DEFINE_MUTEX(ops_mutex);
  83#ifdef CONFIG_PROC_FS
  84static struct snd_info_entry *info_entry;
  85#endif
  86
  87/*
  88 * prototypes
  89 */
  90static int snd_seq_device_free(struct snd_seq_device *dev);
  91static int snd_seq_device_dev_free(struct snd_device *device);
  92static int snd_seq_device_dev_register(struct snd_device *device);
  93static int snd_seq_device_dev_disconnect(struct snd_device *device);
  94
  95static int init_device(struct snd_seq_device *dev, struct ops_list *ops);
  96static int free_device(struct snd_seq_device *dev, struct ops_list *ops);
  97static struct ops_list *find_driver(char *id, int create_if_empty);
  98static struct ops_list *create_driver(char *id);
  99static void unlock_driver(struct ops_list *ops);
 100static void remove_drivers(void);
 101
 102/*
 103 * show all drivers and their status
 104 */
 105
 106#ifdef CONFIG_PROC_FS
 107static void snd_seq_device_info(struct snd_info_entry *entry,
 108                                struct snd_info_buffer *buffer)
 109{
 110        struct ops_list *ops;
 111
 112        mutex_lock(&ops_mutex);
 113        list_for_each_entry(ops, &opslist, list) {
 114                snd_iprintf(buffer, "snd-%s%s%s%s,%d\n",
 115                                ops->id,
 116                                ops->driver & DRIVER_LOADED ? ",loaded" : (ops->driver == DRIVER_EMPTY ? ",empty" : ""),
 117                                ops->driver & DRIVER_REQUESTED ? ",requested" : "",
 118                                ops->driver & DRIVER_LOCKED ? ",locked" : "",
 119                                ops->num_devices);
 120        }
 121        mutex_unlock(&ops_mutex);
 122}
 123#endif
 124 
 125/*
 126 * load all registered drivers (called from seq_clientmgr.c)
 127 */
 128
 129#ifdef CONFIG_MODULES
 130/* avoid auto-loading during module_init() */
 131static atomic_t snd_seq_in_init = ATOMIC_INIT(1); /* blocked as default */
 132void snd_seq_autoload_lock(void)
 133{
 134        atomic_inc(&snd_seq_in_init);
 135}
 136
 137void snd_seq_autoload_unlock(void)
 138{
 139        atomic_dec(&snd_seq_in_init);
 140}
 141
 142static void autoload_drivers(void)
 143{
 144        /* avoid reentrance */
 145        if (atomic_inc_return(&snd_seq_in_init) == 1) {
 146                struct ops_list *ops;
 147
 148                mutex_lock(&ops_mutex);
 149                list_for_each_entry(ops, &opslist, list) {
 150                        if ((ops->driver & DRIVER_REQUESTING) &&
 151                            !(ops->driver & DRIVER_REQUESTED)) {
 152                                ops->used++;
 153                                mutex_unlock(&ops_mutex);
 154                                ops->driver |= DRIVER_REQUESTED;
 155                                request_module("snd-%s", ops->id);
 156                                mutex_lock(&ops_mutex);
 157                                ops->used--;
 158                        }
 159                }
 160                mutex_unlock(&ops_mutex);
 161        }
 162        atomic_dec(&snd_seq_in_init);
 163}
 164
 165static void call_autoload(struct work_struct *work)
 166{
 167        autoload_drivers();
 168}
 169
 170static DECLARE_WORK(autoload_work, call_autoload);
 171
 172static void try_autoload(struct ops_list *ops)
 173{
 174        if (!ops->driver) {
 175                ops->driver |= DRIVER_REQUESTING;
 176                schedule_work(&autoload_work);
 177        }
 178}
 179
 180static void queue_autoload_drivers(void)
 181{
 182        struct ops_list *ops;
 183
 184        mutex_lock(&ops_mutex);
 185        list_for_each_entry(ops, &opslist, list)
 186                try_autoload(ops);
 187        mutex_unlock(&ops_mutex);
 188}
 189
 190void snd_seq_autoload_init(void)
 191{
 192        atomic_dec(&snd_seq_in_init);
 193#ifdef CONFIG_SND_SEQUENCER_MODULE
 194        /* initial autoload only when snd-seq is a module */
 195        queue_autoload_drivers();
 196#endif
 197}
 198#else
 199#define try_autoload(ops) /* NOP */
 200#endif
 201
 202void snd_seq_device_load_drivers(void)
 203{
 204#ifdef CONFIG_MODULES
 205        queue_autoload_drivers();
 206        flush_work(&autoload_work);
 207#endif
 208}
 209
 210/*
 211 * register a sequencer device
 212 * card = card info
 213 * device = device number (if any)
 214 * id = id of driver
 215 * result = return pointer (NULL allowed if unnecessary)
 216 */
 217int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize,
 218                       struct snd_seq_device **result)
 219{
 220        struct snd_seq_device *dev;
 221        struct ops_list *ops;
 222        int err;
 223        static struct snd_device_ops dops = {
 224                .dev_free = snd_seq_device_dev_free,
 225                .dev_register = snd_seq_device_dev_register,
 226                .dev_disconnect = snd_seq_device_dev_disconnect,
 227        };
 228
 229        if (result)
 230                *result = NULL;
 231
 232        if (snd_BUG_ON(!id))
 233                return -EINVAL;
 234
 235        ops = find_driver(id, 1);
 236        if (ops == NULL)
 237                return -ENOMEM;
 238
 239        dev = kzalloc(sizeof(*dev)*2 + argsize, GFP_KERNEL);
 240        if (dev == NULL) {
 241                unlock_driver(ops);
 242                return -ENOMEM;
 243        }
 244
 245        /* set up device info */
 246        dev->card = card;
 247        dev->device = device;
 248        strlcpy(dev->id, id, sizeof(dev->id));
 249        dev->argsize = argsize;
 250        dev->status = SNDRV_SEQ_DEVICE_FREE;
 251
 252        /* add this device to the list */
 253        mutex_lock(&ops->reg_mutex);
 254        list_add_tail(&dev->list, &ops->dev_list);
 255        ops->num_devices++;
 256        mutex_unlock(&ops->reg_mutex);
 257
 258        if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) {
 259                snd_seq_device_free(dev);
 260                return err;
 261        }
 262        
 263        try_autoload(ops);
 264        unlock_driver(ops);
 265
 266        if (result)
 267                *result = dev;
 268
 269        return 0;
 270}
 271
 272/*
 273 * free the existing device
 274 */
 275static int snd_seq_device_free(struct snd_seq_device *dev)
 276{
 277        struct ops_list *ops;
 278
 279        if (snd_BUG_ON(!dev))
 280                return -EINVAL;
 281
 282        ops = find_driver(dev->id, 0);
 283        if (ops == NULL)
 284                return -ENXIO;
 285
 286        /* remove the device from the list */
 287        mutex_lock(&ops->reg_mutex);
 288        list_del(&dev->list);
 289        ops->num_devices--;
 290        mutex_unlock(&ops->reg_mutex);
 291
 292        free_device(dev, ops);
 293        if (dev->private_free)
 294                dev->private_free(dev);
 295        kfree(dev);
 296
 297        unlock_driver(ops);
 298
 299        return 0;
 300}
 301
 302static int snd_seq_device_dev_free(struct snd_device *device)
 303{
 304        struct snd_seq_device *dev = device->device_data;
 305        return snd_seq_device_free(dev);
 306}
 307
 308/*
 309 * register the device
 310 */
 311static int snd_seq_device_dev_register(struct snd_device *device)
 312{
 313        struct snd_seq_device *dev = device->device_data;
 314        struct ops_list *ops;
 315
 316        ops = find_driver(dev->id, 0);
 317        if (ops == NULL)
 318                return -ENOENT;
 319
 320        /* initialize this device if the corresponding driver was
 321         * already loaded
 322         */
 323        if (ops->driver & DRIVER_LOADED)
 324                init_device(dev, ops);
 325
 326        unlock_driver(ops);
 327        return 0;
 328}
 329
 330/*
 331 * disconnect the device
 332 */
 333static int snd_seq_device_dev_disconnect(struct snd_device *device)
 334{
 335        struct snd_seq_device *dev = device->device_data;
 336        struct ops_list *ops;
 337
 338        ops = find_driver(dev->id, 0);
 339        if (ops == NULL)
 340                return -ENOENT;
 341
 342        free_device(dev, ops);
 343
 344        unlock_driver(ops);
 345        return 0;
 346}
 347
 348/*
 349 * register device driver
 350 * id = driver id
 351 * entry = driver operators - duplicated to each instance
 352 */
 353int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
 354                                   int argsize)
 355{
 356        struct ops_list *ops;
 357        struct snd_seq_device *dev;
 358
 359        if (id == NULL || entry == NULL ||
 360            entry->init_device == NULL || entry->free_device == NULL)
 361                return -EINVAL;
 362
 363        ops = find_driver(id, 1);
 364        if (ops == NULL)
 365                return -ENOMEM;
 366        if (ops->driver & DRIVER_LOADED) {
 367                pr_warn("ALSA: seq: driver_register: driver '%s' already exists\n", id);
 368                unlock_driver(ops);
 369                return -EBUSY;
 370        }
 371
 372        mutex_lock(&ops->reg_mutex);
 373        /* copy driver operators */
 374        ops->ops = *entry;
 375        ops->driver |= DRIVER_LOADED;
 376        ops->argsize = argsize;
 377
 378        /* initialize existing devices if necessary */
 379        list_for_each_entry(dev, &ops->dev_list, list) {
 380                init_device(dev, ops);
 381        }
 382        mutex_unlock(&ops->reg_mutex);
 383
 384        unlock_driver(ops);
 385
 386        return 0;
 387}
 388
 389
 390/*
 391 * create driver record
 392 */
 393static struct ops_list * create_driver(char *id)
 394{
 395        struct ops_list *ops;
 396
 397        ops = kzalloc(sizeof(*ops), GFP_KERNEL);
 398        if (ops == NULL)
 399                return ops;
 400
 401        /* set up driver entry */
 402        strlcpy(ops->id, id, sizeof(ops->id));
 403        mutex_init(&ops->reg_mutex);
 404        /*
 405         * The ->reg_mutex locking rules are per-driver, so we create
 406         * separate per-driver lock classes:
 407         */
 408        lockdep_set_class(&ops->reg_mutex, (struct lock_class_key *)id);
 409
 410        ops->driver = DRIVER_EMPTY;
 411        INIT_LIST_HEAD(&ops->dev_list);
 412        /* lock this instance */
 413        ops->used = 1;
 414
 415        /* register driver entry */
 416        mutex_lock(&ops_mutex);
 417        list_add_tail(&ops->list, &opslist);
 418        num_ops++;
 419        mutex_unlock(&ops_mutex);
 420
 421        return ops;
 422}
 423
 424
 425/*
 426 * unregister the specified driver
 427 */
 428int snd_seq_device_unregister_driver(char *id)
 429{
 430        struct ops_list *ops;
 431        struct snd_seq_device *dev;
 432
 433        ops = find_driver(id, 0);
 434        if (ops == NULL)
 435                return -ENXIO;
 436        if (! (ops->driver & DRIVER_LOADED) ||
 437            (ops->driver & DRIVER_LOCKED)) {
 438                pr_err("ALSA: seq: driver_unregister: cannot unload driver '%s': status=%x\n",
 439                           id, ops->driver);
 440                unlock_driver(ops);
 441                return -EBUSY;
 442        }
 443
 444        /* close and release all devices associated with this driver */
 445        mutex_lock(&ops->reg_mutex);
 446        ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */
 447        list_for_each_entry(dev, &ops->dev_list, list) {
 448                free_device(dev, ops);
 449        }
 450
 451        ops->driver = 0;
 452        if (ops->num_init_devices > 0)
 453                pr_err("ALSA: seq: free_driver: init_devices > 0!! (%d)\n",
 454                           ops->num_init_devices);
 455        mutex_unlock(&ops->reg_mutex);
 456
 457        unlock_driver(ops);
 458
 459        /* remove empty driver entries */
 460        remove_drivers();
 461
 462        return 0;
 463}
 464
 465
 466/*
 467 * remove empty driver entries
 468 */
 469static void remove_drivers(void)
 470{
 471        struct list_head *head;
 472
 473        mutex_lock(&ops_mutex);
 474        head = opslist.next;
 475        while (head != &opslist) {
 476                struct ops_list *ops = list_entry(head, struct ops_list, list);
 477                if (! (ops->driver & DRIVER_LOADED) &&
 478                    ops->used == 0 && ops->num_devices == 0) {
 479                        head = head->next;
 480                        list_del(&ops->list);
 481                        kfree(ops);
 482                        num_ops--;
 483                } else
 484                        head = head->next;
 485        }
 486        mutex_unlock(&ops_mutex);
 487}
 488
 489/*
 490 * initialize the device - call init_device operator
 491 */
 492static int init_device(struct snd_seq_device *dev, struct ops_list *ops)
 493{
 494        if (! (ops->driver & DRIVER_LOADED))
 495                return 0; /* driver is not loaded yet */
 496        if (dev->status != SNDRV_SEQ_DEVICE_FREE)
 497                return 0; /* already initialized */
 498        if (ops->argsize != dev->argsize) {
 499                pr_err("ALSA: seq: incompatible device '%s' for plug-in '%s' (%d %d)\n",
 500                           dev->name, ops->id, ops->argsize, dev->argsize);
 501                return -EINVAL;
 502        }
 503        if (ops->ops.init_device(dev) >= 0) {
 504                dev->status = SNDRV_SEQ_DEVICE_REGISTERED;
 505                ops->num_init_devices++;
 506        } else {
 507                pr_err("ALSA: seq: init_device failed: %s: %s\n",
 508                           dev->name, dev->id);
 509        }
 510
 511        return 0;
 512}
 513
 514/*
 515 * release the device - call free_device operator
 516 */
 517static int free_device(struct snd_seq_device *dev, struct ops_list *ops)
 518{
 519        int result;
 520
 521        if (! (ops->driver & DRIVER_LOADED))
 522                return 0; /* driver is not loaded yet */
 523        if (dev->status != SNDRV_SEQ_DEVICE_REGISTERED)
 524                return 0; /* not registered */
 525        if (ops->argsize != dev->argsize) {
 526                pr_err("ALSA: seq: incompatible device '%s' for plug-in '%s' (%d %d)\n",
 527                           dev->name, ops->id, ops->argsize, dev->argsize);
 528                return -EINVAL;
 529        }
 530        if ((result = ops->ops.free_device(dev)) >= 0 || result == -ENXIO) {
 531                dev->status = SNDRV_SEQ_DEVICE_FREE;
 532                dev->driver_data = NULL;
 533                ops->num_init_devices--;
 534        } else {
 535                pr_err("ALSA: seq: free_device failed: %s: %s\n",
 536                           dev->name, dev->id);
 537        }
 538
 539        return 0;
 540}
 541
 542/*
 543 * find the matching driver with given id
 544 */
 545static struct ops_list * find_driver(char *id, int create_if_empty)
 546{
 547        struct ops_list *ops;
 548
 549        mutex_lock(&ops_mutex);
 550        list_for_each_entry(ops, &opslist, list) {
 551                if (strcmp(ops->id, id) == 0) {
 552                        ops->used++;
 553                        mutex_unlock(&ops_mutex);
 554                        return ops;
 555                }
 556        }
 557        mutex_unlock(&ops_mutex);
 558        if (create_if_empty)
 559                return create_driver(id);
 560        return NULL;
 561}
 562
 563static void unlock_driver(struct ops_list *ops)
 564{
 565        mutex_lock(&ops_mutex);
 566        ops->used--;
 567        mutex_unlock(&ops_mutex);
 568}
 569
 570
 571/*
 572 * module part
 573 */
 574
 575static int __init alsa_seq_device_init(void)
 576{
 577#ifdef CONFIG_PROC_FS
 578        info_entry = snd_info_create_module_entry(THIS_MODULE, "drivers",
 579                                                  snd_seq_root);
 580        if (info_entry == NULL)
 581                return -ENOMEM;
 582        info_entry->content = SNDRV_INFO_CONTENT_TEXT;
 583        info_entry->c.text.read = snd_seq_device_info;
 584        if (snd_info_register(info_entry) < 0) {
 585                snd_info_free_entry(info_entry);
 586                return -ENOMEM;
 587        }
 588#endif
 589        return 0;
 590}
 591
 592static void __exit alsa_seq_device_exit(void)
 593{
 594#ifdef CONFIG_MODULES
 595        cancel_work_sync(&autoload_work);
 596#endif
 597        remove_drivers();
 598#ifdef CONFIG_PROC_FS
 599        snd_info_free_entry(info_entry);
 600#endif
 601        if (num_ops)
 602                pr_err("ALSA: seq: drivers not released (%d)\n", num_ops);
 603}
 604
 605module_init(alsa_seq_device_init)
 606module_exit(alsa_seq_device_exit)
 607
 608EXPORT_SYMBOL(snd_seq_device_load_drivers);
 609EXPORT_SYMBOL(snd_seq_device_new);
 610EXPORT_SYMBOL(snd_seq_device_register_driver);
 611EXPORT_SYMBOL(snd_seq_device_unregister_driver);
 612#ifdef CONFIG_MODULES
 613EXPORT_SYMBOL(snd_seq_autoload_init);
 614EXPORT_SYMBOL(snd_seq_autoload_lock);
 615EXPORT_SYMBOL(snd_seq_autoload_unlock);
 616#endif
 617