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