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 <sound/core.h>
  41#include <sound/info.h>
  42#include <sound/seq_device.h>
  43#include <sound/seq_kernel.h>
  44#include <sound/initval.h>
  45#include <linux/kmod.h>
  46#include <linux/slab.h>
  47#include <linux/mutex.h>
  48
  49MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
  50MODULE_DESCRIPTION("ALSA sequencer device management");
  51MODULE_LICENSE("GPL");
  52
  53/* driver state */
  54#define DRIVER_EMPTY            0
  55#define DRIVER_LOADED           (1<<0)
  56#define DRIVER_REQUESTED        (1<<1)
  57#define DRIVER_LOCKED           (1<<2)
  58
  59struct ops_list {
  60        char id[ID_LEN];        /* driver id */
  61        int driver;             /* driver state */
  62        int used;               /* reference counter */
  63        int argsize;            /* argument size */
  64
  65        /* operators */
  66        struct snd_seq_dev_ops ops;
  67
  68        /* registred devices */
  69        struct list_head dev_list;      /* list of devices */
  70        int num_devices;        /* number of associated devices */
  71        int num_init_devices;   /* number of initialized devices */
  72        struct mutex reg_mutex;
  73
  74        struct list_head list;  /* next driver */
  75};
  76
  77
  78static LIST_HEAD(opslist);
  79static int num_ops;
  80static DEFINE_MUTEX(ops_mutex);
  81#ifdef CONFIG_PROC_FS
  82static struct snd_info_entry *info_entry;
  83#endif
  84
  85/*
  86 * prototypes
  87 */
  88static int snd_seq_device_free(struct snd_seq_device *dev);
  89static int snd_seq_device_dev_free(struct snd_device *device);
  90static int snd_seq_device_dev_register(struct snd_device *device);
  91static int snd_seq_device_dev_disconnect(struct snd_device *device);
  92
  93static int init_device(struct snd_seq_device *dev, struct ops_list *ops);
  94static int free_device(struct snd_seq_device *dev, struct ops_list *ops);
  95static struct ops_list *find_driver(char *id, int create_if_empty);
  96static struct ops_list *create_driver(char *id);
  97static void unlock_driver(struct ops_list *ops);
  98static void remove_drivers(void);
  99
 100/*
 101 * show all drivers and their status
 102 */
 103
 104#ifdef CONFIG_PROC_FS
 105static void snd_seq_device_info(struct snd_info_entry *entry,
 106                                struct snd_info_buffer *buffer)
 107{
 108        struct ops_list *ops;
 109
 110        mutex_lock(&ops_mutex);
 111        list_for_each_entry(ops, &opslist, list) {
 112                snd_iprintf(buffer, "snd-%s%s%s%s,%d\n",
 113                                ops->id,
 114                                ops->driver & DRIVER_LOADED ? ",loaded" : (ops->driver == DRIVER_EMPTY ? ",empty" : ""),
 115                                ops->driver & DRIVER_REQUESTED ? ",requested" : "",
 116                                ops->driver & DRIVER_LOCKED ? ",locked" : "",
 117                                ops->num_devices);
 118        }
 119        mutex_unlock(&ops_mutex);
 120}
 121#endif
 122 
 123/*
 124 * load all registered drivers (called from seq_clientmgr.c)
 125 */
 126
 127#ifdef CONFIG_MODULES
 128/* avoid auto-loading during module_init() */
 129static int snd_seq_in_init;
 130void snd_seq_autoload_lock(void)
 131{
 132        snd_seq_in_init++;
 133}
 134
 135void snd_seq_autoload_unlock(void)
 136{
 137        snd_seq_in_init--;
 138}
 139#endif
 140
 141void snd_seq_device_load_drivers(void)
 142{
 143#ifdef CONFIG_MODULES
 144        struct ops_list *ops;
 145
 146        /* Calling request_module during module_init()
 147         * may cause blocking.
 148         */
 149        if (snd_seq_in_init)
 150                return;
 151
 152        mutex_lock(&ops_mutex);
 153        list_for_each_entry(ops, &opslist, list) {
 154                if (! (ops->driver & DRIVER_LOADED) &&
 155                    ! (ops->driver & DRIVER_REQUESTED)) {
 156                        ops->used++;
 157                        mutex_unlock(&ops_mutex);
 158                        ops->driver |= DRIVER_REQUESTED;
 159                        request_module("snd-%s", ops->id);
 160                        mutex_lock(&ops_mutex);
 161                        ops->used--;
 162                }
 163        }
 164        mutex_unlock(&ops_mutex);
 165#endif
 166}
 167
 168/*
 169 * register a sequencer device
 170 * card = card info (NULL allowed)
 171 * device = device number (if any)
 172 * id = id of driver
 173 * result = return pointer (NULL allowed if unnecessary)
 174 */
 175int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize,
 176                       struct snd_seq_device **result)
 177{
 178        struct snd_seq_device *dev;
 179        struct ops_list *ops;
 180        int err;
 181        static struct snd_device_ops dops = {
 182                .dev_free = snd_seq_device_dev_free,
 183                .dev_register = snd_seq_device_dev_register,
 184                .dev_disconnect = snd_seq_device_dev_disconnect,
 185        };
 186
 187        if (result)
 188                *result = NULL;
 189
 190        if (snd_BUG_ON(!id))
 191                return -EINVAL;
 192
 193        ops = find_driver(id, 1);
 194        if (ops == NULL)
 195                return -ENOMEM;
 196
 197        dev = kzalloc(sizeof(*dev)*2 + argsize, GFP_KERNEL);
 198        if (dev == NULL) {
 199                unlock_driver(ops);
 200                return -ENOMEM;
 201        }
 202
 203        /* set up device info */
 204        dev->card = card;
 205        dev->device = device;
 206        strlcpy(dev->id, id, sizeof(dev->id));
 207        dev->argsize = argsize;
 208        dev->status = SNDRV_SEQ_DEVICE_FREE;
 209
 210        /* add this device to the list */
 211        mutex_lock(&ops->reg_mutex);
 212        list_add_tail(&dev->list, &ops->dev_list);
 213        ops->num_devices++;
 214        mutex_unlock(&ops->reg_mutex);
 215
 216        unlock_driver(ops);
 217        
 218        if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) {
 219                snd_seq_device_free(dev);
 220                return err;
 221        }
 222        
 223        if (result)
 224                *result = dev;
 225
 226        return 0;
 227}
 228
 229/*
 230 * free the existing device
 231 */
 232static int snd_seq_device_free(struct snd_seq_device *dev)
 233{
 234        struct ops_list *ops;
 235
 236        if (snd_BUG_ON(!dev))
 237                return -EINVAL;
 238
 239        ops = find_driver(dev->id, 0);
 240        if (ops == NULL)
 241                return -ENXIO;
 242
 243        /* remove the device from the list */
 244        mutex_lock(&ops->reg_mutex);
 245        list_del(&dev->list);
 246        ops->num_devices--;
 247        mutex_unlock(&ops->reg_mutex);
 248
 249        free_device(dev, ops);
 250        if (dev->private_free)
 251                dev->private_free(dev);
 252        kfree(dev);
 253
 254        unlock_driver(ops);
 255
 256        return 0;
 257}
 258
 259static int snd_seq_device_dev_free(struct snd_device *device)
 260{
 261        struct snd_seq_device *dev = device->device_data;
 262        return snd_seq_device_free(dev);
 263}
 264
 265/*
 266 * register the device
 267 */
 268static int snd_seq_device_dev_register(struct snd_device *device)
 269{
 270        struct snd_seq_device *dev = device->device_data;
 271        struct ops_list *ops;
 272
 273        ops = find_driver(dev->id, 0);
 274        if (ops == NULL)
 275                return -ENOENT;
 276
 277        /* initialize this device if the corresponding driver was
 278         * already loaded
 279         */
 280        if (ops->driver & DRIVER_LOADED)
 281                init_device(dev, ops);
 282
 283        unlock_driver(ops);
 284        return 0;
 285}
 286
 287/*
 288 * disconnect the device
 289 */
 290static int snd_seq_device_dev_disconnect(struct snd_device *device)
 291{
 292        struct snd_seq_device *dev = device->device_data;
 293        struct ops_list *ops;
 294
 295        ops = find_driver(dev->id, 0);
 296        if (ops == NULL)
 297                return -ENOENT;
 298
 299        free_device(dev, ops);
 300
 301        unlock_driver(ops);
 302        return 0;
 303}
 304
 305/*
 306 * register device driver
 307 * id = driver id
 308 * entry = driver operators - duplicated to each instance
 309 */
 310int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
 311                                   int argsize)
 312{
 313        struct ops_list *ops;
 314        struct snd_seq_device *dev;
 315
 316        if (id == NULL || entry == NULL ||
 317            entry->init_device == NULL || entry->free_device == NULL)
 318                return -EINVAL;
 319
 320        snd_seq_autoload_lock();
 321        ops = find_driver(id, 1);
 322        if (ops == NULL) {
 323                snd_seq_autoload_unlock();
 324                return -ENOMEM;
 325        }
 326        if (ops->driver & DRIVER_LOADED) {
 327                snd_printk(KERN_WARNING "driver_register: driver '%s' already exists\n", id);
 328                unlock_driver(ops);
 329                snd_seq_autoload_unlock();
 330                return -EBUSY;
 331        }
 332
 333        mutex_lock(&ops->reg_mutex);
 334        /* copy driver operators */
 335        ops->ops = *entry;
 336        ops->driver |= DRIVER_LOADED;
 337        ops->argsize = argsize;
 338
 339        /* initialize existing devices if necessary */
 340        list_for_each_entry(dev, &ops->dev_list, list) {
 341                init_device(dev, ops);
 342        }
 343        mutex_unlock(&ops->reg_mutex);
 344
 345        unlock_driver(ops);
 346        snd_seq_autoload_unlock();
 347
 348        return 0;
 349}
 350
 351
 352/*
 353 * create driver record
 354 */
 355static struct ops_list * create_driver(char *id)
 356{
 357        struct ops_list *ops;
 358
 359        ops = kzalloc(sizeof(*ops), GFP_KERNEL);
 360        if (ops == NULL)
 361                return ops;
 362
 363        /* set up driver entry */
 364        strlcpy(ops->id, id, sizeof(ops->id));
 365        mutex_init(&ops->reg_mutex);
 366        /*
 367         * The ->reg_mutex locking rules are per-driver, so we create
 368         * separate per-driver lock classes:
 369         */
 370        lockdep_set_class(&ops->reg_mutex, (struct lock_class_key *)id);
 371
 372        ops->driver = DRIVER_EMPTY;
 373        INIT_LIST_HEAD(&ops->dev_list);
 374        /* lock this instance */
 375        ops->used = 1;
 376
 377        /* register driver entry */
 378        mutex_lock(&ops_mutex);
 379        list_add_tail(&ops->list, &opslist);
 380        num_ops++;
 381        mutex_unlock(&ops_mutex);
 382
 383        return ops;
 384}
 385
 386
 387/*
 388 * unregister the specified driver
 389 */
 390int snd_seq_device_unregister_driver(char *id)
 391{
 392        struct ops_list *ops;
 393        struct snd_seq_device *dev;
 394
 395        ops = find_driver(id, 0);
 396        if (ops == NULL)
 397                return -ENXIO;
 398        if (! (ops->driver & DRIVER_LOADED) ||
 399            (ops->driver & DRIVER_LOCKED)) {
 400                snd_printk(KERN_ERR "driver_unregister: cannot unload driver '%s': status=%x\n",
 401                           id, ops->driver);
 402                unlock_driver(ops);
 403                return -EBUSY;
 404        }
 405
 406        /* close and release all devices associated with this driver */
 407        mutex_lock(&ops->reg_mutex);
 408        ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */
 409        list_for_each_entry(dev, &ops->dev_list, list) {
 410                free_device(dev, ops);
 411        }
 412
 413        ops->driver = 0;
 414        if (ops->num_init_devices > 0)
 415                snd_printk(KERN_ERR "free_driver: init_devices > 0!! (%d)\n",
 416                           ops->num_init_devices);
 417        mutex_unlock(&ops->reg_mutex);
 418
 419        unlock_driver(ops);
 420
 421        /* remove empty driver entries */
 422        remove_drivers();
 423
 424        return 0;
 425}
 426
 427
 428/*
 429 * remove empty driver entries
 430 */
 431static void remove_drivers(void)
 432{
 433        struct list_head *head;
 434
 435        mutex_lock(&ops_mutex);
 436        head = opslist.next;
 437        while (head != &opslist) {
 438                struct ops_list *ops = list_entry(head, struct ops_list, list);
 439                if (! (ops->driver & DRIVER_LOADED) &&
 440                    ops->used == 0 && ops->num_devices == 0) {
 441                        head = head->next;
 442                        list_del(&ops->list);
 443                        kfree(ops);
 444                        num_ops--;
 445                } else
 446                        head = head->next;
 447        }
 448        mutex_unlock(&ops_mutex);
 449}
 450
 451/*
 452 * initialize the device - call init_device operator
 453 */
 454static int init_device(struct snd_seq_device *dev, struct ops_list *ops)
 455{
 456        if (! (ops->driver & DRIVER_LOADED))
 457                return 0; /* driver is not loaded yet */
 458        if (dev->status != SNDRV_SEQ_DEVICE_FREE)
 459                return 0; /* already initialized */
 460        if (ops->argsize != dev->argsize) {
 461                snd_printk(KERN_ERR "incompatible device '%s' for plug-in '%s' (%d %d)\n",
 462                           dev->name, ops->id, ops->argsize, dev->argsize);
 463                return -EINVAL;
 464        }
 465        if (ops->ops.init_device(dev) >= 0) {
 466                dev->status = SNDRV_SEQ_DEVICE_REGISTERED;
 467                ops->num_init_devices++;
 468        } else {
 469                snd_printk(KERN_ERR "init_device failed: %s: %s\n",
 470                           dev->name, dev->id);
 471        }
 472
 473        return 0;
 474}
 475
 476/*
 477 * release the device - call free_device operator
 478 */
 479static int free_device(struct snd_seq_device *dev, struct ops_list *ops)
 480{
 481        int result;
 482
 483        if (! (ops->driver & DRIVER_LOADED))
 484                return 0; /* driver is not loaded yet */
 485        if (dev->status != SNDRV_SEQ_DEVICE_REGISTERED)
 486                return 0; /* not registered */
 487        if (ops->argsize != dev->argsize) {
 488                snd_printk(KERN_ERR "incompatible device '%s' for plug-in '%s' (%d %d)\n",
 489                           dev->name, ops->id, ops->argsize, dev->argsize);
 490                return -EINVAL;
 491        }
 492        if ((result = ops->ops.free_device(dev)) >= 0 || result == -ENXIO) {
 493                dev->status = SNDRV_SEQ_DEVICE_FREE;
 494                dev->driver_data = NULL;
 495                ops->num_init_devices--;
 496        } else {
 497                snd_printk(KERN_ERR "free_device failed: %s: %s\n",
 498                           dev->name, dev->id);
 499        }
 500
 501        return 0;
 502}
 503
 504/*
 505 * find the matching driver with given id
 506 */
 507static struct ops_list * find_driver(char *id, int create_if_empty)
 508{
 509        struct ops_list *ops;
 510
 511        mutex_lock(&ops_mutex);
 512        list_for_each_entry(ops, &opslist, list) {
 513                if (strcmp(ops->id, id) == 0) {
 514                        ops->used++;
 515                        mutex_unlock(&ops_mutex);
 516                        return ops;
 517                }
 518        }
 519        mutex_unlock(&ops_mutex);
 520        if (create_if_empty)
 521                return create_driver(id);
 522        return NULL;
 523}
 524
 525static void unlock_driver(struct ops_list *ops)
 526{
 527        mutex_lock(&ops_mutex);
 528        ops->used--;
 529        mutex_unlock(&ops_mutex);
 530}
 531
 532
 533/*
 534 * module part
 535 */
 536
 537static int __init alsa_seq_device_init(void)
 538{
 539#ifdef CONFIG_PROC_FS
 540        info_entry = snd_info_create_module_entry(THIS_MODULE, "drivers",
 541                                                  snd_seq_root);
 542        if (info_entry == NULL)
 543                return -ENOMEM;
 544        info_entry->content = SNDRV_INFO_CONTENT_TEXT;
 545        info_entry->c.text.read = snd_seq_device_info;
 546        if (snd_info_register(info_entry) < 0) {
 547                snd_info_free_entry(info_entry);
 548                return -ENOMEM;
 549        }
 550#endif
 551        return 0;
 552}
 553
 554static void __exit alsa_seq_device_exit(void)
 555{
 556        remove_drivers();
 557#ifdef CONFIG_PROC_FS
 558        snd_info_free_entry(info_entry);
 559#endif
 560        if (num_ops)
 561                snd_printk(KERN_ERR "drivers not released (%d)\n", num_ops);
 562}
 563
 564module_init(alsa_seq_device_init)
 565module_exit(alsa_seq_device_exit)
 566
 567EXPORT_SYMBOL(snd_seq_device_load_drivers);
 568EXPORT_SYMBOL(snd_seq_device_new);
 569EXPORT_SYMBOL(snd_seq_device_register_driver);
 570EXPORT_SYMBOL(snd_seq_device_unregister_driver);
 571EXPORT_SYMBOL(snd_seq_autoload_lock);
 572EXPORT_SYMBOL(snd_seq_autoload_unlock);
 573