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