2 * Sound core handling. Breaks out sound functions to submodules
4 * Author: Alan Cox <alan.cox@linux.org>
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.
14 * --------------------
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...
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.
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.
30 * Thirdly to make it more fun and for 2.3.x and above we do all
31 * of this using fine grained locking.
33 * FIXME: we have to resolve modules and fine grained load/unload
34 * locking at some point in 2.3.x.
37 #include <linux/config.h>
38 #include <linux/module.h>
39 #include <linux/malloc.h>
40 #include <linux/types.h>
41 #include <linux/kernel.h>
43 #include <linux/sound.h>
44 #include <linux/major.h>
45 #include <linux/kmod.h>
51 struct file_operations
*unit_fops
;
52 struct sound_unit
*next
;
55 #ifdef CONFIG_SOUND_MSNDCLAS
56 extern int msnd_classic_init(void);
58 #ifdef CONFIG_SOUND_MSNDPIN
59 extern int msnd_pinnacle_init(void);
63 * Low level list operator. Scan the ordered list, find a hole and
64 * join into it. Called with the lock asserted
67 static int __sound_insert_unit(struct sound_unit
* s
, struct sound_unit
**list
, struct file_operations
*fops
, int index
, int low
, int top
)
71 if (index
< 0) { /* first free */
73 while (*list
&& (*list
)->unit_minor
<n
)
74 list
=&((*list
)->next
);
79 if(*list
==NULL
|| (*list
)->unit_minor
>n
)
81 list
=&((*list
)->next
);
90 if ((*list
)->unit_minor
==n
)
92 if ((*list
)->unit_minor
>n
)
94 list
=&((*list
)->next
);
118 * Remove a node from the chain. Called with the lock asserted
121 static void __sound_remove_unit(struct sound_unit
**list
, int unit
)
125 struct sound_unit
*p
=*list
;
126 if(p
->unit_minor
==unit
)
135 printk(KERN_ERR
"Sound device %d went missing!\n", unit
);
139 * This lock guards the sound loader list.
142 spinlock_t sound_loader_lock
= SPIN_LOCK_UNLOCKED
;
145 * Allocate the controlling structure and add it to the sound driver
146 * list. Acquires locks as needed
149 static int sound_insert_unit(struct sound_unit
**list
, struct file_operations
*fops
, int index
, int low
, int top
)
152 struct sound_unit
*s
=(struct sound_unit
*)kmalloc(sizeof(struct sound_unit
), GFP_KERNEL
);
156 spin_lock(&sound_loader_lock
);
157 r
=__sound_insert_unit(s
,list
,fops
,index
,low
,top
);
158 spin_unlock(&sound_loader_lock
);
166 * Remove a unit. Acquires locks as needed. The drivers MUST have
167 * completed the removal before their file operations become
171 static void sound_remove_unit(struct sound_unit
**list
, int unit
)
173 spin_lock(&sound_loader_lock
);
174 __sound_remove_unit(list
, unit
);
175 spin_unlock(&sound_loader_lock
);
187 * 6 -- sndstat (obsolete)
189 * 8 -- alternate sequencer (see above)
190 * 9 *16 raw synthesizer access
199 static struct sound_unit
*chains
[16];
201 int register_sound_special(struct file_operations
*fops
, int unit
)
203 return sound_insert_unit(&chains
[unit
&15], fops
, -1, unit
, unit
+1);
206 EXPORT_SYMBOL(register_sound_special
);
208 int register_sound_mixer(struct file_operations
*fops
, int dev
)
210 return sound_insert_unit(&chains
[0], fops
, dev
, 0, 128);
213 EXPORT_SYMBOL(register_sound_mixer
);
215 int register_sound_midi(struct file_operations
*fops
, int dev
)
217 return sound_insert_unit(&chains
[2], fops
, dev
, 2, 130);
220 EXPORT_SYMBOL(register_sound_midi
);
223 * DSP's are registered as a triple. Register only one and cheat
224 * in open - see below.
227 int register_sound_dsp(struct file_operations
*fops
, int dev
)
229 return sound_insert_unit(&chains
[3], fops
, dev
, 3, 131);
232 EXPORT_SYMBOL(register_sound_dsp
);
234 int register_sound_synth(struct file_operations
*fops
, int dev
)
236 return sound_insert_unit(&chains
[9], fops
, dev
, 9, 137);
239 EXPORT_SYMBOL(register_sound_synth
);
241 void unregister_sound_special(int unit
)
243 sound_remove_unit(&chains
[unit
&15], unit
);
246 EXPORT_SYMBOL(unregister_sound_special
);
248 void unregister_sound_mixer(int unit
)
250 sound_remove_unit(&chains
[0], unit
);
253 EXPORT_SYMBOL(unregister_sound_mixer
);
255 void unregister_sound_midi(int unit
)
257 return sound_remove_unit(&chains
[2], unit
);
260 EXPORT_SYMBOL(unregister_sound_midi
);
262 void unregister_sound_dsp(int unit
)
264 return sound_remove_unit(&chains
[3], unit
);
267 EXPORT_SYMBOL(unregister_sound_dsp
);
269 void unregister_sound_synth(int unit
)
271 return sound_remove_unit(&chains
[9], unit
);
274 EXPORT_SYMBOL(unregister_sound_synth
);
277 * Now our file operations
280 static int soundcore_open(struct inode
*, struct file
*);
282 static struct file_operations soundcore_fops
=
301 static struct sound_unit
*__look_for_unit(int chain
, int unit
)
303 struct sound_unit
*s
;
306 while(s
&& s
->unit_minor
<= unit
)
308 if(s
->unit_minor
==unit
)
315 int soundcore_open(struct inode
*inode
, struct file
*file
)
318 int unit
=MINOR(inode
->i_rdev
);
319 struct sound_unit
*s
;
322 if(chain
==4 || chain
==5) /* dsp/audio/dsp16 */
329 spin_lock(&sound_loader_lock
);
330 s
= __look_for_unit(chain
, unit
);
334 spin_unlock(&sound_loader_lock
);
336 * Please, don't change this order or code.
337 * For ALSA slot means soundcard and OSS emulation code
338 * comes as add-on modules which aren't depend on
339 * ALSA toplevel modules for soundcards, thus we need
340 * load them at first. [Jaroslav Kysela <perex@jcu.cz>]
342 sprintf(mod
, "sound-slot-%i", unit
>>4);
344 sprintf(mod
, "sound-service-%i-%i", unit
>>4, chain
);
346 spin_lock(&sound_loader_lock
);
347 s
= __look_for_unit(chain
, unit
);
350 file
->f_op
=s
->unit_fops
;
351 spin_unlock(&sound_loader_lock
);
353 return file
->f_op
->open(inode
,file
);
357 spin_unlock(&sound_loader_lock
);
361 extern int mod_firmware_load(const char *, char **);
362 EXPORT_SYMBOL(mod_firmware_load
);
366 MODULE_DESCRIPTION("Core sound module");
367 MODULE_AUTHOR("Alan Cox");
369 void cleanup_module(void)
371 /* We have nothing to really do here - we know the lists must be
373 unregister_chrdev(SOUND_MAJOR
, "sound");
376 int init_module(void)
378 int soundcore_init(void)
381 if(register_chrdev(SOUND_MAJOR
, "sound", &soundcore_fops
)==-1)
383 printk(KERN_ERR
"soundcore: sound device already in use.\n");
387 * Now init non OSS drivers
389 #ifdef CONFIG_SOUND_CMPCI
392 #ifdef CONFIG_SOUND_MSNDCLAS
395 #ifdef CONFIG_SOUND_MSNDPIN
396 msnd_pinnacle_init();