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