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.
 150 */
 151#ifdef CONFIG_SOUND_OSS_CORE_PRECLAIM
 152static int preclaim_oss = 1;
 153#else
 154static int preclaim_oss = 0;
 155#endif
 156
 157module_param(preclaim_oss, int, 0444);
 158
 159static int soundcore_open(struct inode *, struct file *);
 160
 161static const struct file_operations soundcore_fops =
 162{
 163        /* We must have an owner or the module locking fails */
 164        .owner  = THIS_MODULE,
 165        .open   = soundcore_open,
 166        .llseek = noop_llseek,
 167};
 168
 169/*
 170 *      Low level list operator. Scan the ordered list, find a hole and
 171 *      join into it. Called with the lock asserted
 172 */
 173
 174static int __sound_insert_unit(struct sound_unit * s, struct sound_unit **list, const struct file_operations *fops, int index, int low, int top)
 175{
 176        int n=low;
 177
 178        if (index < 0) {        /* first free */
 179
 180                while (*list && (*list)->unit_minor<n)
 181                        list=&((*list)->next);
 182
 183                while(n<top)
 184                {
 185                        /* Found a hole ? */
 186                        if(*list==NULL || (*list)->unit_minor>n)
 187                                break;
 188                        list=&((*list)->next);
 189                        n+=SOUND_STEP;
 190                }
 191
 192                if(n>=top)
 193                        return -ENOENT;
 194        } else {
 195                n = low+(index*16);
 196                while (*list) {
 197                        if ((*list)->unit_minor==n)
 198                                return -EBUSY;
 199                        if ((*list)->unit_minor>n)
 200                                break;
 201                        list=&((*list)->next);
 202                }
 203        }       
 204                
 205        /*
 206         *      Fill it in
 207         */
 208         
 209        s->unit_minor=n;
 210        s->unit_fops=fops;
 211        
 212        /*
 213         *      Link it
 214         */
 215         
 216        s->next=*list;
 217        *list=s;
 218        
 219        
 220        return n;
 221}
 222
 223/*
 224 *      Remove a node from the chain. Called with the lock asserted
 225 */
 226 
 227static struct sound_unit *__sound_remove_unit(struct sound_unit **list, int unit)
 228{
 229        while(*list)
 230        {
 231                struct sound_unit *p=*list;
 232                if(p->unit_minor==unit)
 233                {
 234                        *list=p->next;
 235                        return p;
 236                }
 237                list=&(p->next);
 238        }
 239        printk(KERN_ERR "Sound device %d went missing!\n", unit);
 240        return NULL;
 241}
 242
 243/*
 244 *      This lock guards the sound loader list.
 245 */
 246
 247static DEFINE_SPINLOCK(sound_loader_lock);
 248
 249/*
 250 *      Allocate the controlling structure and add it to the sound driver
 251 *      list. Acquires locks as needed
 252 */
 253
 254static 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)
 255{
 256        struct sound_unit *s = kmalloc(sizeof(*s), GFP_KERNEL);
 257        int r;
 258
 259        if (!s)
 260                return -ENOMEM;
 261
 262        spin_lock(&sound_loader_lock);
 263retry:
 264        r = __sound_insert_unit(s, list, fops, index, low, top);
 265        spin_unlock(&sound_loader_lock);
 266        
 267        if (r < 0)
 268                goto fail;
 269        else if (r < SOUND_STEP)
 270                sprintf(s->name, "sound/%s", name);
 271        else
 272                sprintf(s->name, "sound/%s%d", name, r / SOUND_STEP);
 273
 274        if (!preclaim_oss) {
 275                /*
 276                 * Something else might have grabbed the minor.  If
 277                 * first free slot is requested, rescan with @low set
 278                 * to the next unit; otherwise, -EBUSY.
 279                 */
 280                r = __register_chrdev(SOUND_MAJOR, s->unit_minor, 1, s->name,
 281                                      &soundcore_fops);
 282                if (r < 0) {
 283                        spin_lock(&sound_loader_lock);
 284                        __sound_remove_unit(list, s->unit_minor);
 285                        if (index < 0) {
 286                                low = s->unit_minor + SOUND_STEP;
 287                                goto retry;
 288                        }
 289                        spin_unlock(&sound_loader_lock);
 290                        return -EBUSY;
 291                }
 292        }
 293
 294        device_create(sound_class, dev, MKDEV(SOUND_MAJOR, s->unit_minor),
 295                      NULL, s->name+6);
 296        return s->unit_minor;
 297
 298fail:
 299        kfree(s);
 300        return r;
 301}
 302
 303/*
 304 *      Remove a unit. Acquires locks as needed. The drivers MUST have
 305 *      completed the removal before their file operations become
 306 *      invalid.
 307 */
 308        
 309static void sound_remove_unit(struct sound_unit **list, int unit)
 310{
 311        struct sound_unit *p;
 312
 313        spin_lock(&sound_loader_lock);
 314        p = __sound_remove_unit(list, unit);
 315        spin_unlock(&sound_loader_lock);
 316        if (p) {
 317                if (!preclaim_oss)
 318                        __unregister_chrdev(SOUND_MAJOR, p->unit_minor, 1,
 319                                            p->name);
 320                device_destroy(sound_class, MKDEV(SOUND_MAJOR, p->unit_minor));
 321                kfree(p);
 322        }
 323}
 324
 325/*
 326 *      Allocations
 327 *
 328 *      0       *16             Mixers
 329 *      1       *8              Sequencers
 330 *      2       *16             Midi
 331 *      3       *16             DSP
 332 *      4       *16             SunDSP
 333 *      5       *16             DSP16
 334 *      6       --              sndstat (obsolete)
 335 *      7       *16             unused
 336 *      8       --              alternate sequencer (see above)
 337 *      9       *16             raw synthesizer access
 338 *      10      *16             unused
 339 *      11      *16             unused
 340 *      12      *16             unused
 341 *      13      *16             unused
 342 *      14      *16             unused
 343 *      15      *16             unused
 344 */
 345
 346static struct sound_unit *chains[SOUND_STEP];
 347
 348/**
 349 *      register_sound_special_device - register a special sound node
 350 *      @fops: File operations for the driver
 351 *      @unit: Unit number to allocate
 352 *      @dev: device pointer
 353 *
 354 *      Allocate a special sound device by minor number from the sound
 355 *      subsystem. The allocated number is returned on success. On failure
 356 *      a negative error code is returned.
 357 */
 358 
 359int register_sound_special_device(const struct file_operations *fops, int unit,
 360                                  struct device *dev)
 361{
 362        const int chain = unit % SOUND_STEP;
 363        int max_unit = 256;
 364        const char *name;
 365        char _name[16];
 366
 367        switch (chain) {
 368            case 0:
 369                name = "mixer";
 370                break;
 371            case 1:
 372                name = "sequencer";
 373                if (unit >= SOUND_STEP)
 374                        goto __unknown;
 375                max_unit = unit + 1;
 376                break;
 377            case 2:
 378                name = "midi";
 379                break;
 380            case 3:
 381                name = "dsp";
 382                break;
 383            case 4:
 384                name = "audio";
 385                break;
 386            case 5:
 387                name = "dspW";
 388                break;
 389            case 8:
 390                name = "sequencer2";
 391                if (unit >= SOUND_STEP)
 392                        goto __unknown;
 393                max_unit = unit + 1;
 394                break;
 395            case 9:
 396                name = "dmmidi";
 397                break;
 398            case 10:
 399                name = "dmfm";
 400                break;
 401            case 12:
 402                name = "adsp";
 403                break;
 404            case 13:
 405                name = "amidi";
 406                break;
 407            case 14:
 408                name = "admmidi";
 409                break;
 410            default:
 411                {
 412                    __unknown:
 413                        sprintf(_name, "unknown%d", chain);
 414                        if (unit >= SOUND_STEP)
 415                                strcat(_name, "-");
 416                        name = _name;
 417                }
 418                break;
 419        }
 420        return sound_insert_unit(&chains[chain], fops, -1, unit, max_unit,
 421                                 name, S_IRUSR | S_IWUSR, dev);
 422}
 423 
 424EXPORT_SYMBOL(register_sound_special_device);
 425
 426int register_sound_special(const struct file_operations *fops, int unit)
 427{
 428        return register_sound_special_device(fops, unit, NULL);
 429}
 430
 431EXPORT_SYMBOL(register_sound_special);
 432
 433/**
 434 *      register_sound_mixer - register a mixer device
 435 *      @fops: File operations for the driver
 436 *      @dev: Unit number to allocate
 437 *
 438 *      Allocate a mixer device. Unit is the number of the mixer requested.
 439 *      Pass -1 to request the next free mixer unit. On success the allocated
 440 *      number is returned, on failure a negative error code is returned.
 441 */
 442
 443int register_sound_mixer(const struct file_operations *fops, int dev)
 444{
 445        return sound_insert_unit(&chains[0], fops, dev, 0, 128,
 446                                 "mixer", S_IRUSR | S_IWUSR, NULL);
 447}
 448
 449EXPORT_SYMBOL(register_sound_mixer);
 450
 451/**
 452 *      register_sound_midi - register a midi device
 453 *      @fops: File operations for the driver
 454 *      @dev: Unit number to allocate
 455 *
 456 *      Allocate a midi device. Unit is the number of the midi device requested.
 457 *      Pass -1 to request the next free midi unit. On success the allocated
 458 *      number is returned, on failure a negative error code is returned.
 459 */
 460
 461int register_sound_midi(const struct file_operations *fops, int dev)
 462{
 463        return sound_insert_unit(&chains[2], fops, dev, 2, 130,
 464                                 "midi", S_IRUSR | S_IWUSR, NULL);
 465}
 466
 467EXPORT_SYMBOL(register_sound_midi);
 468
 469/*
 470 *      DSP's are registered as a triple. Register only one and cheat
 471 *      in open - see below.
 472 */
 473 
 474/**
 475 *      register_sound_dsp - register a DSP device
 476 *      @fops: File operations for the driver
 477 *      @dev: Unit number to allocate
 478 *
 479 *      Allocate a DSP device. Unit is the number of the DSP requested.
 480 *      Pass -1 to request the next free DSP unit. On success the allocated
 481 *      number is returned, on failure a negative error code is returned.
 482 *
 483 *      This function allocates both the audio and dsp device entries together
 484 *      and will always allocate them as a matching pair - eg dsp3/audio3
 485 */
 486
 487int register_sound_dsp(const struct file_operations *fops, int dev)
 488{
 489        return sound_insert_unit(&chains[3], fops, dev, 3, 131,
 490                                 "dsp", S_IWUSR | S_IRUSR, NULL);
 491}
 492
 493EXPORT_SYMBOL(register_sound_dsp);
 494
 495/**
 496 *      unregister_sound_special - unregister a special sound device
 497 *      @unit: unit number to allocate
 498 *
 499 *      Release a sound device that was allocated with
 500 *      register_sound_special(). The unit passed is the return value from
 501 *      the register function.
 502 */
 503
 504
 505void unregister_sound_special(int unit)
 506{
 507        sound_remove_unit(&chains[unit % SOUND_STEP], unit);
 508}
 509 
 510EXPORT_SYMBOL(unregister_sound_special);
 511
 512/**
 513 *      unregister_sound_mixer - unregister a mixer
 514 *      @unit: unit number to allocate
 515 *
 516 *      Release a sound device that was allocated with register_sound_mixer().
 517 *      The unit passed is the return value from the register function.
 518 */
 519
 520void unregister_sound_mixer(int unit)
 521{
 522        sound_remove_unit(&chains[0], unit);
 523}
 524
 525EXPORT_SYMBOL(unregister_sound_mixer);
 526
 527/**
 528 *      unregister_sound_midi - unregister a midi device
 529 *      @unit: unit number to allocate
 530 *
 531 *      Release a sound device that was allocated with register_sound_midi().
 532 *      The unit passed is the return value from the register function.
 533 */
 534
 535void unregister_sound_midi(int unit)
 536{
 537        sound_remove_unit(&chains[2], unit);
 538}
 539
 540EXPORT_SYMBOL(unregister_sound_midi);
 541
 542/**
 543 *      unregister_sound_dsp - unregister a DSP device
 544 *      @unit: unit number to allocate
 545 *
 546 *      Release a sound device that was allocated with register_sound_dsp().
 547 *      The unit passed is the return value from the register function.
 548 *
 549 *      Both of the allocated units are released together automatically.
 550 */
 551
 552void unregister_sound_dsp(int unit)
 553{
 554        sound_remove_unit(&chains[3], unit);
 555}
 556
 557
 558EXPORT_SYMBOL(unregister_sound_dsp);
 559
 560static struct sound_unit *__look_for_unit(int chain, int unit)
 561{
 562        struct sound_unit *s;
 563        
 564        s=chains[chain];
 565        while(s && s->unit_minor <= unit)
 566        {
 567                if(s->unit_minor==unit)
 568                        return s;
 569                s=s->next;
 570        }
 571        return NULL;
 572}
 573
 574static int soundcore_open(struct inode *inode, struct file *file)
 575{
 576        int chain;
 577        int unit = iminor(inode);
 578        struct sound_unit *s;
 579        const struct file_operations *new_fops = NULL;
 580
 581        chain=unit&0x0F;
 582        if(chain==4 || chain==5)        /* dsp/audio/dsp16 */
 583        {
 584                unit&=0xF0;
 585                unit|=3;
 586                chain=3;
 587        }
 588        
 589        spin_lock(&sound_loader_lock);
 590        s = __look_for_unit(chain, unit);
 591        if (s)
 592                new_fops = fops_get(s->unit_fops);
 593        if (preclaim_oss && !new_fops) {
 594                spin_unlock(&sound_loader_lock);
 595
 596                /*
 597                 *  Please, don't change this order or code.
 598                 *  For ALSA slot means soundcard and OSS emulation code
 599                 *  comes as add-on modules which aren't depend on
 600                 *  ALSA toplevel modules for soundcards, thus we need
 601                 *  load them at first.   [Jaroslav Kysela <perex@jcu.cz>]
 602                 */
 603                request_module("sound-slot-%i", unit>>4);
 604                request_module("sound-service-%i-%i", unit>>4, chain);
 605
 606                /*
 607                 * sound-slot/service-* module aliases are scheduled
 608                 * for removal in favor of the standard char-major-*
 609                 * module aliases.  For the time being, generate both
 610                 * the legacy and standard module aliases to ease
 611                 * transition.
 612                 */
 613                if (request_module("char-major-%d-%d", SOUND_MAJOR, unit) > 0)
 614                        request_module("char-major-%d", SOUND_MAJOR);
 615
 616                spin_lock(&sound_loader_lock);
 617                s = __look_for_unit(chain, unit);
 618                if (s)
 619                        new_fops = fops_get(s->unit_fops);
 620        }
 621        if (new_fops) {
 622                /*
 623                 * We rely upon the fact that we can't be unloaded while the
 624                 * subdriver is there, so if ->open() is successful we can
 625                 * safely drop the reference counter and if it is not we can
 626                 * revert to old ->f_op. Ugly, indeed, but that's the cost of
 627                 * switching ->f_op in the first place.
 628                 */
 629                int err = 0;
 630                const struct file_operations *old_fops = file->f_op;
 631                file->f_op = new_fops;
 632                spin_unlock(&sound_loader_lock);
 633
 634                if (file->f_op->open)
 635                        err = file->f_op->open(inode,file);
 636
 637                if (err) {
 638                        fops_put(file->f_op);
 639                        file->f_op = fops_get(old_fops);
 640                }
 641
 642                fops_put(old_fops);
 643                return err;
 644        }
 645        spin_unlock(&sound_loader_lock);
 646        return -ENODEV;
 647}
 648
 649MODULE_ALIAS_CHARDEV_MAJOR(SOUND_MAJOR);
 650
 651static void cleanup_oss_soundcore(void)
 652{
 653        /* We have nothing to really do here - we know the lists must be
 654           empty */
 655        unregister_chrdev(SOUND_MAJOR, "sound");
 656}
 657
 658static int __init init_oss_soundcore(void)
 659{
 660        if (preclaim_oss &&
 661            register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops) == -1) {
 662                printk(KERN_ERR "soundcore: sound device already in use.\n");
 663                return -EBUSY;
 664        }
 665
 666        return 0;
 667}
 668
 669#endif /* CONFIG_SOUND_OSS_CORE */
 670
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.