linux/sound/core/sound.c
<<
>>
Prefs
   1/*
   2 *  Advanced Linux Sound Architecture
   3 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
   4 *
   5 *
   6 *   This program is free software; you can redistribute it and/or modify
   7 *   it under the terms of the GNU General Public License as published by
   8 *   the Free Software Foundation; either version 2 of the License, or
   9 *   (at your option) any later version.
  10 *
  11 *   This program is distributed in the hope that it will be useful,
  12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 *   GNU General Public License for more details.
  15 *
  16 *   You should have received a copy of the GNU General Public License
  17 *   along with this program; if not, write to the Free Software
  18 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  19 *
  20 */
  21
  22#include <sound/driver.h>
  23#include <linux/init.h>
  24#include <linux/slab.h>
  25#include <linux/time.h>
  26#include <linux/device.h>
  27#include <linux/moduleparam.h>
  28#include <sound/core.h>
  29#include <sound/minors.h>
  30#include <sound/info.h>
  31#include <sound/version.h>
  32#include <sound/control.h>
  33#include <sound/initval.h>
  34#include <linux/kmod.h>
  35#include <linux/mutex.h>
  36
  37#define SNDRV_OS_MINORS 256
  38
  39static int major = CONFIG_SND_MAJOR;
  40int snd_major;
  41EXPORT_SYMBOL(snd_major);
  42
  43static int cards_limit = 1;
  44
  45MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
  46MODULE_DESCRIPTION("Advanced Linux Sound Architecture driver for soundcards.");
  47MODULE_LICENSE("GPL");
  48module_param(major, int, 0444);
  49MODULE_PARM_DESC(major, "Major # for sound driver.");
  50module_param(cards_limit, int, 0444);
  51MODULE_PARM_DESC(cards_limit, "Count of auto-loadable soundcards.");
  52MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR);
  53
  54/* this one holds the actual max. card number currently available.
  55 * as default, it's identical with cards_limit option.  when more
  56 * modules are loaded manually, this limit number increases, too.
  57 */
  58int snd_ecards_limit;
  59EXPORT_SYMBOL(snd_ecards_limit);
  60
  61static struct snd_minor *snd_minors[SNDRV_OS_MINORS];
  62static DEFINE_MUTEX(sound_mutex);
  63
  64#ifdef CONFIG_KMOD
  65
  66/**
  67 * snd_request_card - try to load the card module
  68 * @card: the card number
  69 *
  70 * Tries to load the module "snd-card-X" for the given card number
  71 * via KMOD.  Returns immediately if already loaded.
  72 */
  73void snd_request_card(int card)
  74{
  75        if (! current->fs->root)
  76                return;
  77        if (snd_card_locked(card))
  78                return;
  79        if (card < 0 || card >= cards_limit)
  80                return;
  81        request_module("snd-card-%i", card);
  82}
  83
  84EXPORT_SYMBOL(snd_request_card);
  85
  86static void snd_request_other(int minor)
  87{
  88        char *str;
  89
  90        if (! current->fs->root)
  91                return;
  92        switch (minor) {
  93        case SNDRV_MINOR_SEQUENCER:     str = "snd-seq";        break;
  94        case SNDRV_MINOR_TIMER:         str = "snd-timer";      break;
  95        default:                        return;
  96        }
  97        request_module(str);
  98}
  99
 100#endif                          /* request_module support */
 101
 102/**
 103 * snd_lookup_minor_data - get user data of a registered device
 104 * @minor: the minor number
 105 * @type: device type (SNDRV_DEVICE_TYPE_XXX)
 106 *
 107 * Checks that a minor device with the specified type is registered, and returns
 108 * its user data pointer.
 109 */
 110void *snd_lookup_minor_data(unsigned int minor, int type)
 111{
 112        struct snd_minor *mreg;
 113        void *private_data;
 114
 115        if (minor >= ARRAY_SIZE(snd_minors))
 116                return NULL;
 117        mutex_lock(&sound_mutex);
 118        mreg = snd_minors[minor];
 119        if (mreg && mreg->type == type)
 120                private_data = mreg->private_data;
 121        else
 122                private_data = NULL;
 123        mutex_unlock(&sound_mutex);
 124        return private_data;
 125}
 126
 127EXPORT_SYMBOL(snd_lookup_minor_data);
 128
 129static int snd_open(struct inode *inode, struct file *file)
 130{
 131        unsigned int minor = iminor(inode);
 132        struct snd_minor *mptr = NULL;
 133        const struct file_operations *old_fops;
 134        int err = 0;
 135
 136        if (minor >= ARRAY_SIZE(snd_minors))
 137                return -ENODEV;
 138        mptr = snd_minors[minor];
 139        if (mptr == NULL) {
 140#ifdef CONFIG_KMOD
 141                int dev = SNDRV_MINOR_DEVICE(minor);
 142                if (dev == SNDRV_MINOR_CONTROL) {
 143                        /* /dev/aloadC? */
 144                        int card = SNDRV_MINOR_CARD(minor);
 145                        if (snd_cards[card] == NULL)
 146                                snd_request_card(card);
 147                } else if (dev == SNDRV_MINOR_GLOBAL) {
 148                        /* /dev/aloadSEQ */
 149                        snd_request_other(minor);
 150                }
 151#ifndef CONFIG_SND_DYNAMIC_MINORS
 152                /* /dev/snd/{controlC?,seq} */
 153                mptr = snd_minors[minor];
 154                if (mptr == NULL)
 155#endif
 156#endif
 157                        return -ENODEV;
 158        }
 159        old_fops = file->f_op;
 160        file->f_op = fops_get(mptr->f_ops);
 161        if (file->f_op->open)
 162                err = file->f_op->open(inode, file);
 163        if (err) {
 164                fops_put(file->f_op);
 165                file->f_op = fops_get(old_fops);
 166        }
 167        fops_put(old_fops);
 168        return err;
 169}
 170
 171static const struct file_operations snd_fops =
 172{
 173        .owner =        THIS_MODULE,
 174        .open =         snd_open
 175};
 176
 177#ifdef CONFIG_SND_DYNAMIC_MINORS
 178static int snd_find_free_minor(void)
 179{
 180        int minor;
 181
 182        for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) {
 183                /* skip minors still used statically for autoloading devices */
 184                if (SNDRV_MINOR_DEVICE(minor) == SNDRV_MINOR_CONTROL ||
 185                    minor == SNDRV_MINOR_SEQUENCER)
 186                        continue;
 187                if (!snd_minors[minor])
 188                        return minor;
 189        }
 190        return -EBUSY;
 191}
 192#else
 193static int snd_kernel_minor(int type, struct snd_card *card, int dev)
 194{
 195        int minor;
 196
 197        switch (type) {
 198        case SNDRV_DEVICE_TYPE_SEQUENCER:
 199        case SNDRV_DEVICE_TYPE_TIMER:
 200                minor = type;
 201                break;
 202        case SNDRV_DEVICE_TYPE_CONTROL:
 203                snd_assert(card != NULL, return -EINVAL);
 204                minor = SNDRV_MINOR(card->number, type);
 205                break;
 206        case SNDRV_DEVICE_TYPE_HWDEP:
 207        case SNDRV_DEVICE_TYPE_RAWMIDI:
 208        case SNDRV_DEVICE_TYPE_PCM_PLAYBACK:
 209        case SNDRV_DEVICE_TYPE_PCM_CAPTURE:
 210                snd_assert(card != NULL, return -EINVAL);
 211                minor = SNDRV_MINOR(card->number, type + dev);
 212                break;
 213        default:
 214                return -EINVAL;
 215        }
 216        snd_assert(minor >= 0 && minor < SNDRV_OS_MINORS, return -EINVAL);
 217        return minor;
 218}
 219#endif
 220
 221/**
 222 * snd_register_device_for_dev - Register the ALSA device file for the card
 223 * @type: the device type, SNDRV_DEVICE_TYPE_XXX
 224 * @card: the card instance
 225 * @dev: the device index
 226 * @f_ops: the file operations
 227 * @private_data: user pointer for f_ops->open()
 228 * @name: the device file name
 229 * @device: the &struct device to link this new device to
 230 *
 231 * Registers an ALSA device file for the given card.
 232 * The operators have to be set in reg parameter.
 233 *
 234 * Returns zero if successful, or a negative error code on failure.
 235 */
 236int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
 237                                const struct file_operations *f_ops,
 238                                void *private_data,
 239                                const char *name, struct device *device)
 240{
 241        int minor;
 242        struct snd_minor *preg;
 243
 244        snd_assert(name, return -EINVAL);
 245        preg = kmalloc(sizeof *preg, GFP_KERNEL);
 246        if (preg == NULL)
 247                return -ENOMEM;
 248        preg->type = type;
 249        preg->card = card ? card->number : -1;
 250        preg->device = dev;
 251        preg->f_ops = f_ops;
 252        preg->private_data = private_data;
 253        mutex_lock(&sound_mutex);
 254#ifdef CONFIG_SND_DYNAMIC_MINORS
 255        minor = snd_find_free_minor();
 256#else
 257        minor = snd_kernel_minor(type, card, dev);
 258        if (minor >= 0 && snd_minors[minor])
 259                minor = -EBUSY;
 260#endif
 261        if (minor < 0) {
 262                mutex_unlock(&sound_mutex);
 263                kfree(preg);
 264                return minor;
 265        }
 266        snd_minors[minor] = preg;
 267        preg->dev = device_create(sound_class, device, MKDEV(major, minor),
 268                                  "%s", name);
 269        if (IS_ERR(preg->dev)) {
 270                snd_minors[minor] = NULL;
 271                mutex_unlock(&sound_mutex);
 272                minor = PTR_ERR(preg->dev);
 273                kfree(preg);
 274                return minor;
 275        }
 276
 277        if (preg->dev)
 278                dev_set_drvdata(preg->dev, private_data);
 279
 280        mutex_unlock(&sound_mutex);
 281        return 0;
 282}
 283
 284EXPORT_SYMBOL(snd_register_device_for_dev);
 285
 286/* find the matching minor record
 287 * return the index of snd_minor, or -1 if not found
 288 */
 289static int find_snd_minor(int type, struct snd_card *card, int dev)
 290{
 291        int cardnum, minor;
 292        struct snd_minor *mptr;
 293
 294        cardnum = card ? card->number : -1;
 295        for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor)
 296                if ((mptr = snd_minors[minor]) != NULL &&
 297                    mptr->type == type &&
 298                    mptr->card == cardnum &&
 299                    mptr->device == dev)
 300                        return minor;
 301        return -1;
 302}
 303
 304/**
 305 * snd_unregister_device - unregister the device on the given card
 306 * @type: the device type, SNDRV_DEVICE_TYPE_XXX
 307 * @card: the card instance
 308 * @dev: the device index
 309 *
 310 * Unregisters the device file already registered via
 311 * snd_register_device().
 312 *
 313 * Returns zero if sucecessful, or a negative error code on failure
 314 */
 315int snd_unregister_device(int type, struct snd_card *card, int dev)
 316{
 317        int minor;
 318
 319        mutex_lock(&sound_mutex);
 320        minor = find_snd_minor(type, card, dev);
 321        if (minor < 0) {
 322                mutex_unlock(&sound_mutex);
 323                return -EINVAL;
 324        }
 325
 326        device_destroy(sound_class, MKDEV(major, minor));
 327
 328        kfree(snd_minors[minor]);
 329        snd_minors[minor] = NULL;
 330        mutex_unlock(&sound_mutex);
 331        return 0;
 332}
 333
 334EXPORT_SYMBOL(snd_unregister_device);
 335
 336int snd_add_device_sysfs_file(int type, struct snd_card *card, int dev,
 337                              struct device_attribute *attr)
 338{
 339        int minor, ret = -EINVAL;
 340        struct device *d;
 341
 342        mutex_lock(&sound_mutex);
 343        minor = find_snd_minor(type, card, dev);
 344        if (minor >= 0 && (d = snd_minors[minor]->dev) != NULL)
 345                ret = device_create_file(d, attr);
 346        mutex_unlock(&sound_mutex);
 347        return ret;
 348
 349}
 350
 351EXPORT_SYMBOL(snd_add_device_sysfs_file);
 352
 353#ifdef CONFIG_PROC_FS
 354/*
 355 *  INFO PART
 356 */
 357
 358static struct snd_info_entry *snd_minor_info_entry;
 359
 360static const char *snd_device_type_name(int type)
 361{
 362        switch (type) {
 363        case SNDRV_DEVICE_TYPE_CONTROL:
 364                return "control";
 365        case SNDRV_DEVICE_TYPE_HWDEP:
 366                return "hardware dependent";
 367        case SNDRV_DEVICE_TYPE_RAWMIDI:
 368                return "raw midi";
 369        case SNDRV_DEVICE_TYPE_PCM_PLAYBACK:
 370                return "digital audio playback";
 371        case SNDRV_DEVICE_TYPE_PCM_CAPTURE:
 372                return "digital audio capture";
 373        case SNDRV_DEVICE_TYPE_SEQUENCER:
 374                return "sequencer";
 375        case SNDRV_DEVICE_TYPE_TIMER:
 376                return "timer";
 377        default:
 378                return "?";
 379        }
 380}
 381
 382static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 383{
 384        int minor;
 385        struct snd_minor *mptr;
 386
 387        mutex_lock(&sound_mutex);
 388        for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) {
 389                if (!(mptr = snd_minors[minor]))
 390                        continue;
 391                if (mptr->card >= 0) {
 392                        if (mptr->device >= 0)
 393                                snd_iprintf(buffer, "%3i: [%2i-%2i]: %s\n",
 394                                            minor, mptr->card, mptr->device,
 395                                            snd_device_type_name(mptr->type));
 396                        else
 397                                snd_iprintf(buffer, "%3i: [%2i]   : %s\n",
 398                                            minor, mptr->card,
 399                                            snd_device_type_name(mptr->type));
 400                } else
 401                        snd_iprintf(buffer, "%3i:        : %s\n", minor,
 402                                    snd_device_type_name(mptr->type));
 403        }
 404        mutex_unlock(&sound_mutex);
 405}
 406
 407int __init snd_minor_info_init(void)
 408{
 409        struct snd_info_entry *entry;
 410
 411        entry = snd_info_create_module_entry(THIS_MODULE, "devices", NULL);
 412        if (entry) {
 413                entry->c.text.read = snd_minor_info_read;
 414                if (snd_info_register(entry) < 0) {
 415                        snd_info_free_entry(entry);
 416                        entry = NULL;
 417                }
 418        }
 419        snd_minor_info_entry = entry;
 420        return 0;
 421}
 422
 423int __exit snd_minor_info_done(void)
 424{
 425        snd_info_free_entry(snd_minor_info_entry);
 426        return 0;
 427}
 428#endif /* CONFIG_PROC_FS */
 429
 430/*
 431 *  INIT PART
 432 */
 433
 434static int __init alsa_sound_init(void)
 435{
 436        snd_major = major;
 437        snd_ecards_limit = cards_limit;
 438        if (register_chrdev(major, "alsa", &snd_fops)) {
 439                snd_printk(KERN_ERR "unable to register native major device number %d\n", major);
 440                return -EIO;
 441        }
 442        if (snd_info_init() < 0) {
 443                unregister_chrdev(major, "alsa");
 444                return -ENOMEM;
 445        }
 446        snd_info_minor_register();
 447#ifndef MODULE
 448        printk(KERN_INFO "Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n");
 449#endif
 450        return 0;
 451}
 452
 453static void __exit alsa_sound_exit(void)
 454{
 455        snd_info_minor_unregister();
 456        snd_info_done();
 457        unregister_chrdev(major, "alsa");
 458}
 459
 460module_init(alsa_sound_init)
 461module_exit(alsa_sound_exit)
 462