linux/sound/sound_core.c
<<
>>
Prefs
   1/*
   2 *      Sound core.  This file is composed of two parts.  sound_class
   3 *      which is common to both OSS and ALSA and OSS sound core which
   4 *      is used OSS or emulation of it.
   5 */
   6
   7/*
   8 * First, the common part.
   9 */
  10#include <linux/module.h>
  11#include <linux/device.h>
  12#include <linux/err.h>
  13#include <linux/kdev_t.h>
  14#include <linux/major.h>
  15#include <sound/core.h>
  16
  17#ifdef CONFIG_SOUND_OSS_CORE
  18static int __init init_oss_soundcore(void);
  19static void cleanup_oss_soundcore(void);
  20#else
  21static inline int init_oss_soundcore(void)      { return 0; }
  22static inline void cleanup_oss_soundcore(void)  { }
  23#endif
  24
  25struct class *sound_class;
  26EXPORT_SYMBOL(sound_class);
  27
  28MODULE_DESCRIPTION("Core sound module");
  29MODULE_AUTHOR("Alan Cox");
  30MODULE_LICENSE("GPL");
  31
  32static char *sound_devnode(struct device *dev, umode_t *mode)
  33{
  34        if (MAJOR(dev->devt) == SOUND_MAJOR)
  35                return NULL;
  36        return kasprintf(GFP_KERNEL, "snd/%s", dev_name(dev));
  37}
  38
  39static int __init init_soundcore(void)
  40{
  41        int rc;
  42
  43        rc = init_oss_soundcore();
  44        if (rc)
  45                return rc;
  46
  47        sound_class = class_create(THIS_MODULE, "sound");
  48        if (IS_ERR(sound_class)) {
  49                cleanup_oss_soundcore();
  50                return PTR_ERR(sound_class);
  51        }
  52
  53        sound_class->devnode = sound_devnode;
  54
  55        return 0;
  56}
  57
  58static void __exit cleanup_soundcore(void)
  59{
  60        cleanup_oss_soundcore();
  61        class_destroy(sound_class);
  62}
  63
  64subsys_initcall(init_soundcore);
  65module_exit(cleanup_soundcore);
  66
  67
  68#ifdef CONFIG_SOUND_OSS_CORE
  69/*
  70 *      OSS sound core handling. Breaks out sound functions to submodules
  71 *      
  72 *      Author:         Alan Cox <alan@lxorguk.ukuu.org.uk>
  73 *
  74 *      Fixes:
  75 *
  76 *
  77 *      This program is free software; you can redistribute it and/or
  78 *      modify it under the terms of the GNU General Public License
  79 *      as published by the Free Software Foundation; either version
  80 *      2 of the License, or (at your option) any later version.
  81 *
  82 *                         --------------------
  83 * 
  84 *      Top level handler for the sound subsystem. Various devices can
  85 *      plug into this. The fact they don't all go via OSS doesn't mean 
  86 *      they don't have to implement the OSS API. There is a lot of logic
  87 *      to keeping much of the OSS weight out of the code in a compatibility
  88 *      module, but it's up to the driver to rember to load it...
  89 *
  90 *      The code provides a set of functions for registration of devices
  91 *      by type. This is done rather than providing a single call so that
  92 *      we can hide any future changes in the internals (eg when we go to
  93 *      32bit dev_t) from the modules and their interface.
  94 *
  95 *      Secondly we need to allocate the dsp, dsp16 and audio devices as
  96 *      one. Thus we misuse the chains a bit to simplify this.
  97 *
  98 *      Thirdly to make it more fun and for 2.3.x and above we do all
  99 *      of this using fine grained locking.
 100 *
 101 *      FIXME: we have to resolve modules and fine grained load/unload
 102 *      locking at some point in 2.3.x.
 103 */
 104
 105#include <linux/init.h>
 106#include <linux/slab.h>
 107#include <linux/types.h>
 108#include <linux/kernel.h>
 109#include <linux/sound.h>
 110#include <linux/kmod.h>
 111
 112#define SOUND_STEP 16
 113
 114struct sound_unit
 115{
 116        int unit_minor;
 117        const struct file_operations *unit_fops;
 118        struct sound_unit *next;
 119        char name[32];
 120};
 121
 122#ifdef CONFIG_SOUND_MSNDCLAS
 123extern int msnd_classic_init(void);
 124#endif
 125#ifdef CONFIG_SOUND_MSNDPIN
 126extern int msnd_pinnacle_init(void);
 127#endif
 128
 129/*
 130 * By default, OSS sound_core claims full legacy minor range (0-255)
 131 * of SOUND_MAJOR to trap open attempts to any sound minor and
 132 * requests modules using custom sound-slot/service-* module aliases.
 133 * The only benefit of doing this is allowing use of custom module
 134 * aliases instead of the standard char-major-* ones.  This behavior
 135 * prevents alternative OSS implementation and is scheduled to be
 136 * removed.
 137 *
 138 * CONFIG_SOUND_OSS_CORE_PRECLAIM and soundcore.preclaim_oss kernel
 139 * parameter are added to allow distros and developers to try and
 140 * switch to alternative implementations without needing to rebuild
 141 * the kernel in the meantime.  If preclaim_oss is non-zero, the
 142 * kernel will behave the same as before.  All SOUND_MAJOR minors are
 143 * preclaimed and the custom module aliases along with standard chrdev
 144 * ones are emitted if a missing device is opened.  If preclaim_oss is
 145 * zero, sound_core only grabs what's actually in use and for missing
 146 * devices only the standard chrdev aliases are requested.
 147 *
 148 * All these clutters are scheduled to be removed along with
 149 * sound-slot/service-* module aliases.  Please take a look at
 150 * feature-removal-schedule.txt for details.
 151 */
 152#ifdef CONFIG_SOUND_OSS_CORE_PRECLAIM
 153static int preclaim_oss = 1;
 154#else
 155static int preclaim_oss = 0;
 156#endif
 157
 158module_param(preclaim_oss, int, 0444);
 159
 160static int soundcore_open(struct inode *, struct file *);
 161
 162static const struct file_operations soundcore_fops =
 163{
 164        /* We must have an owner or the module locking fails */
 165        .owner  = THIS_MODULE,
 166        .open   = soundcore_open,
 167        .llseek = noop_llseek,
 168};
 169
 170/*
 171 *      Low level list operator. Scan the ordered list, find a hole and
 172 *      join into it. Called with the lock asserted
 173 */
 174
 175static int __sound_insert_unit(struct sound_unit * s, struct sound_unit **list, const struct file_operations *fops, int index, int low, int top)
 176{
 177        int n=low;
 178
 179        if (index < 0) {        /* first free */
 180
 181                while (*list && (*list)->unit_minor<n)
 182                        list=&((*list)->next);
 183
 184                while(n<top)
 185                {
 186                        /* Found a hole ? */
 187                        if(*list==NULL || (*list)->unit_minor>n)
 188                                break;
 189                        list=&((*list)->next);
 190                        n+=SOUND_STEP;
 191                }
 192
 193                if(n>=top)
 194                        return -ENOENT;
 195        } else {
 196                n = low+(index*16);
 197                while (*list) {
 198                        if ((*list)->unit_minor==n)
 199                                return -EBUSY;
 200                        if ((*list)->unit_minor>n)
 201                                break;
 202                        list=&((*list)->next);
 203                }
 204        }       
 205                
 206        /*
 207         *      Fill it in
 208         */
 209         
 210        s->unit_minor=n;
 211        s->unit_fops=fops;
 212        
 213        /*
 214         *      Link it
 215         */
 216         
 217        s->next=*list;
 218        *list=s;
 219        
 220        
 221        return n;
 222}
 223
 224/*
 225 *      Remove a node from the chain. Called with the lock asserted
 226 */
 227 
 228static struct sound_unit *__sound_remove_unit(struct sound_unit **list, int unit)
 229{
 230        while(*list)
 231        {
 232                struct sound_unit *p=*list;
 233                if(p->unit_minor==unit)
 234                {
 235                        *list=p->next;
 236                        return p;
 237                }
 238                list=&(p->next);
 239        }
 240        printk(KERN_ERR "Sound device %d went missing!\n", unit);
 241        return NULL;
 242}
 243
 244/*
 245 *      This lock guards the sound loader list.
 246 */
 247
 248static DEFINE_SPINLOCK(sound_loader_lock);
 249
 250/*
 251 *      Allocate the controlling structure and add it to the sound driver
 252 *      list. Acquires locks as needed
 253 */
 254
 255static int sound_insert_unit(struct sound_unit **list, const struct file_operations *fops, int index, int low, int top, const char *name, umode_t mode, struct device *dev)
 256{
 257        struct sound_unit *s = kmalloc(sizeof(*s), GFP_KERNEL);
 258        int r;
 259
 260        if (!s)
 261                return -ENOMEM;
 262
 263        spin_lock(&sound_loader_lock);
 264retry:
 265        r = __sound_insert_unit(s, list, fops, index, low, top);
 266        spin_unlock(&sound_loader_lock);
 267        
 268        if (r < 0)
 269                goto fail;
 270        else if (r < SOUND_STEP)
 271                sprintf(s->name, "sound/%s", name);
 272        else
 273                sprintf(s->name, "sound/%s%d", name, r / SOUND_STEP);
 274
 275        if (!preclaim_oss) {
 276                /*
 277                 * Something else might have grabbed the minor.  If
 278                 * first free slot is requested, rescan with @low set
 279                 * to the next unit; otherwise, -EBUSY.
 280                 */
 281                r = __register_chrdev(SOUND_MAJOR, s->unit_minor, 1, s->name,
 282                                      &soundcore_fops);
 283                if (r < 0) {
 284                        spin_lock(&sound_loader_lock);
 285                        __sound_remove_unit(list, s->unit_minor);
 286                        if (index < 0) {
 287                                low = s->unit_minor + SOUND_STEP;
 288                                goto retry;
 289                        }
 290                        spin_unlock(&sound_loader_lock);
 291                        return -EBUSY;
 292                }
 293        }
 294
 295        device_create(sound_class, dev, MKDEV(SOUND_MAJOR, s->unit_minor),
 296                      NULL, s->name+6);
 297        return s->unit_minor;
 298
 299fail:
 300        kfree(s);
 301        return r;
 302}
 303
 304/*
 305 *      Remove a unit. Acquires locks as needed. The drivers MUST have
 306 *      completed the removal before their file operations become
 307 *      invalid.
 308 */
 309        
 310static void sound_remove_unit(struct sound_unit **list, int unit)
 311{
 312        struct sound_unit *p;
 313
 314        spin_lock(&sound_loader_lock);
 315        p = __sound_remove_unit(list, unit);
 316        spin_unlock(&sound_loader_lock);
 317        if (p) {
 318                if (!preclaim_oss)
 319                        __unregister_chrdev(SOUND_MAJOR, p->unit_minor, 1,
 320                                            p->name);
 321                device_destroy(sound_class, MKDEV(SOUND_MAJOR, p->unit_minor));
 322                kfree(p);
 323        }
 324}
 325
 326/*
 327 *      Allocations
 328 *
 329 *      0       *16             Mixers
 330 *      1       *8              Sequencers
 331 *      2       *16             Midi
 332 *      3       *16             DSP
 333 *      4       *16             SunDSP
 334 *      5       *16             DSP16
 335 *      6       --              sndstat (obsolete)
 336 *      7       *16             unused
 337 *      8       --              alternate sequencer (see above)
 338 *      9       *16             raw synthesizer access
 339 *      10      *16             unused
 340 *      11      *16             unused
 341 *      12      *16             unused
 342 *      13      *16             unused
 343 *      14      *16             unused
 344 *      15      *16             unused
 345 */
 346
 347static struct sound_unit *chains[SOUND_STEP];
 348
 349/**
 350 *      register_sound_special_device - register a special sound node
 351 *      @fops: File operations for the driver
 352 *      @unit: Unit number to allocate
 353 *      @dev: device pointer
 354 *
 355 *      Allocate a special sound device by minor number from the sound
 356 *      subsystem. The allocated number is returned on success. On failure
 357 *      a negative error code is returned.
 358 */
 359 
 360int register_sound_special_device(const struct file_operations *fops, int unit,
 361                                  struct device *dev)
 362{
 363        const int chain = unit % SOUND_STEP;
 364        int max_unit = 256;
 365        const char *name;
 366        char _name[16];
 367
 368        switch (chain) {
 369            case 0:
 370                name = "mixer";
 371                break;
 372            case 1:
 373                name = "sequencer";
 374                if (unit >= SOUND_STEP)
 375                        goto __unknown;
 376                max_unit = unit + 1;
 377                break;
 378            case 2:
 379                name = "midi";
 380                break;
 381            case 3:
 382                name = "dsp";
 383                break;
 384            case 4:
 385                name = "audio";
 386                break;
 387            case 5:
 388                name = "dspW";
 389                break;
 390            case 8:
 391                name = "sequencer2";
 392                if (unit >= SOUND_STEP)
 393                        goto __unknown;
 394                max_unit = unit + 1;
 395                break;
 396            case 9:
 397                name = "dmmidi";
 398                break;
 399            case 10:
 400                name = "dmfm";
 401                break;
 402            case 12:
 403                name = "adsp";
 404                break;
 405            case 13:
 406                name = "amidi";
 407                break;
 408            case 14:
 409                name = "admmidi";
 410                break;
 411            default:
 412                {
 413                    __unknown:
 414                        sprintf(_name, "unknown%d", chain);
 415                        if (unit >= SOUND_STEP)
 416                                strcat(_name, "-");
 417                        name = _name;
 418                }
 419                break;
 420        }
 421        return sound_insert_unit(&chains[chain], fops, -1, unit, max_unit,
 422                                 name, S_IRUSR | S_IWUSR, dev);
 423}
 424 
 425EXPORT_SYMBOL(register_sound_special_device);
 426
 427int register_sound_special(const struct file_operations *fops, int unit)
 428{
 429        return register_sound_special_device(fops, unit, NULL);
 430}
 431
 432EXPORT_SYMBOL(register_sound_special);
 433
 434/**
 435 *      register_sound_mixer - register a mixer device
 436 *      @fops: File operations for the driver
 437 *      @dev: Unit number to allocate
 438 *
 439 *      Allocate a mixer device. Unit is the number of the mixer requested.
 440 *      Pass -1 to request the next free mixer unit. On success the allocated
 441 *      number is returned, on failure a negative error code is returned.
 442 */
 443
 444int register_sound_mixer(const struct file_operations *fops, int dev)
 445{
 446        return sound_insert_unit(&chains[0], fops, dev, 0, 128,
 447                                 "mixer", S_IRUSR | S_IWUSR, NULL);
 448}
 449
 450EXPORT_SYMBOL(register_sound_mixer);
 451
 452/**
 453 *      register_sound_midi - register a midi device
 454 *      @fops: File operations for the driver
 455 *      @dev: Unit number to allocate
 456 *
 457 *      Allocate a midi device. Unit is the number of the midi device requested.
 458 *      Pass -1 to request the next free midi unit. On success the allocated
 459 *      number is returned, on failure a negative error code is returned.
 460 */
 461
 462int register_sound_midi(const struct file_operations *fops, int dev)
 463{
 464        return sound_insert_unit(&chains[2], fops, dev, 2, 130,
 465                                 "midi", S_IRUSR | S_IWUSR, NULL);
 466}
 467
 468EXPORT_SYMBOL(register_sound_midi);
 469
 470/*
 471 *      DSP's are registered as a triple. Register only one and cheat
 472 *      in open - see below.
 473 */
 474 
 475/**
 476 *      register_sound_dsp - register a DSP device
 477 *      @fops: File operations for the driver
 478 *      @dev: Unit number to allocate
 479 *
 480 *      Allocate a DSP device. Unit is the number of the DSP requested.
 481 *      Pass -1 to request the next free DSP unit. On success the allocated
 482 *      number is returned, on failure a negative error code is returned.
 483 *
 484 *      This function allocates both the audio and dsp device entries together
 485 *      and will always allocate them as a matching pair - eg dsp3/audio3
 486 */
 487
 488int register_sound_dsp(const struct file_operations *fops, int dev)
 489{
 490        return sound_insert_unit(&chains[3], fops, dev, 3, 131,
 491                                 "dsp", S_IWUSR | S_IRUSR, NULL);
 492}
 493
 494EXPORT_SYMBOL(register_sound_dsp);
 495
 496/**
 497 *      unregister_sound_special - unregister a special sound device
 498 *      @unit: unit number to allocate
 499 *
 500 *      Release a sound device that was allocated with
 501 *      register_sound_special(). The unit passed is the return value from
 502 *      the register function.
 503 */
 504
 505
 506void unregister_sound_special(int unit)
 507{
 508        sound_remove_unit(&chains[unit % SOUND_STEP], unit);
 509}
 510 
 511EXPORT_SYMBOL(unregister_sound_special);
 512
 513/**
 514 *      unregister_sound_mixer - unregister a mixer
 515 *      @unit: unit number to allocate
 516 *
 517 *      Release a sound device that was allocated with register_sound_mixer().
 518 *      The unit passed is the return value from the register function.
 519 */
 520
 521void unregister_sound_mixer(int unit)
 522{
 523        sound_remove_unit(&chains[0], unit);
 524}
 525
 526EXPORT_SYMBOL(unregister_sound_mixer);
 527
 528/**
 529 *      unregister_sound_midi - unregister a midi device
 530 *      @unit: unit number to allocate
 531 *
 532 *      Release a sound device that was allocated with register_sound_midi().
 533 *      The unit passed is the return value from the register function.
 534 */
 535
 536void unregister_sound_midi(int unit)
 537{
 538        sound_remove_unit(&chains[2], unit);
 539}
 540
 541EXPORT_SYMBOL(unregister_sound_midi);
 542
 543/**
 544 *      unregister_sound_dsp - unregister a DSP device
 545 *      @unit: unit number to allocate
 546 *
 547 *      Release a sound device that was allocated with register_sound_dsp().
 548 *      The unit passed is the return value from the register function.
 549 *
 550 *      Both of the allocated units are released together automatically.
 551 */
 552
 553void unregister_sound_dsp(int unit)
 554{
 555        sound_remove_unit(&chains[3], unit);
 556}
 557
 558
 559EXPORT_SYMBOL(unregister_sound_dsp);
 560
 561static struct sound_unit *__look_for_unit(int chain, int unit)
 562{
 563        struct sound_unit *s;
 564        
 565        s=chains[chain];
 566        while(s && s->unit_minor <= unit)
 567        {
 568                if(s->unit_minor==unit)
 569                        return s;
 570                s=s->next;
 571        }
 572        return NULL;
 573}
 574
 575static int soundcore_open(struct inode *inode, struct file *file)
 576{
 577        int chain;
 578        int unit = iminor(inode);
 579        struct sound_unit *s;
 580        const struct file_operations *new_fops = NULL;
 581
 582        chain=unit&0x0F;
 583        if(chain==4 || chain==5)        /* dsp/audio/dsp16 */
 584        {
 585                unit&=0xF0;
 586                unit|=3;
 587                chain=3;
 588        }
 589        
 590        spin_lock(&sound_loader_lock);
 591        s = __look_for_unit(chain, unit);
 592        if (s)
 593                new_fops = fops_get(s->unit_fops);
 594        if (preclaim_oss && !new_fops) {
 595                spin_unlock(&sound_loader_lock);
 596
 597                /*
 598                 *  Please, don't change this order or code.
 599                 *  For ALSA slot means soundcard and OSS emulation code
 600                 *  comes as add-on modules which aren't depend on
 601                 *  ALSA toplevel modules for soundcards, thus we need
 602                 *  load them at first.   [Jaroslav Kysela <perex@jcu.cz>]
 603                 */
 604                request_module("sound-slot-%i", unit>>4);
 605                request_module("sound-service-%i-%i", unit>>4, chain);
 606
 607                /*
 608                 * sound-slot/service-* module aliases are scheduled
 609                 * for removal in favor of the standard char-major-*
 610                 * module aliases.  For the time being, generate both
 611                 * the legacy and standard module aliases to ease
 612                 * transition.
 613                 */
 614                if (request_module("char-major-%d-%d", SOUND_MAJOR, unit) > 0)
 615                        request_module("char-major-%d", SOUND_MAJOR);
 616
 617                spin_lock(&sound_loader_lock);
 618                s = __look_for_unit(chain, unit);
 619                if (s)
 620                        new_fops = fops_get(s->unit_fops);
 621        }
 622        if (new_fops) {
 623                /*
 624                 * We rely upon the fact that we can't be unloaded while the
 625                 * subdriver is there, so if ->open() is successful we can
 626                 * safely drop the reference counter and if it is not we can
 627                 * revert to old ->f_op. Ugly, indeed, but that's the cost of
 628                 * switching ->f_op in the first place.
 629                 */
 630                int err = 0;
 631                const struct file_operations *old_fops = file->f_op;
 632                file->f_op = new_fops;
 633                spin_unlock(&sound_loader_lock);
 634
 635                if (file->f_op->open)
 636                        err = file->f_op->open(inode,file);
 637
 638                if (err) {
 639                        fops_put(file->f_op);
 640                        file->f_op = fops_get(old_fops);
 641                }
 642
 643                fops_put(old_fops);
 644                return err;
 645        }
 646        spin_unlock(&sound_loader_lock);
 647        return -ENODEV;
 648}
 649
 650MODULE_ALIAS_CHARDEV_MAJOR(SOUND_MAJOR);
 651
 652static void cleanup_oss_soundcore(void)
 653{
 654        /* We have nothing to really do here - we know the lists must be
 655           empty */
 656        unregister_chrdev(SOUND_MAJOR, "sound");
 657}
 658
 659static int __init init_oss_soundcore(void)
 660{
 661        if (preclaim_oss &&
 662            register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops) == -1) {
 663                printk(KERN_ERR "soundcore: sound device already in use.\n");
 664                return -EBUSY;
 665        }
 666
 667        return 0;
 668}
 669
 670#endif /* CONFIG_SOUND_OSS_CORE */
 671
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.