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