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