~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/sound/sound_core.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.