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>
42 #include <linux/malloc.h>
44 #include <linux/sound.h>
45 #include <linux/major.h>
51 struct file_operations
*unit_fops
;
52 struct sound_unit
*next
;
56 * Low level list operator. Scan the ordered list, find a hole and
57 * join into it. Called with the lock asserted
60 static int __sound_insert_unit(struct sound_unit
* s
, struct sound_unit
**list
, struct file_operations
*fops
, int low
, int top
)
67 if(*list
==NULL
|| (*list
)->unit_minor
>n
)
69 list
=&((*list
)->next
);
99 * Remove a node from the chain. Called with the lock asserted
102 static void __sound_remove_unit(struct sound_unit
**list
, int unit
)
106 struct sound_unit
*p
=*list
;
107 if(p
->unit_minor
==unit
)
116 printk(KERN_ERR
"Sound device %d went missing!\n", unit
);
120 * This lock guards the sound loader list.
123 static spinlock_t sound_loader_lock
= SPIN_LOCK_UNLOCKED
;
126 * Allocate the controlling structure and add it to the sound driver
127 * list. Acquires locks as needed
130 static int sound_insert_unit(struct sound_unit
**list
, struct file_operations
*fops
, int low
, int top
)
133 struct sound_unit
*s
=(struct sound_unit
*)kmalloc(sizeof(struct sound_unit
), GFP_KERNEL
);
137 spin_lock(&sound_loader_lock
);
138 r
=__sound_insert_unit(s
,list
,fops
,low
,top
);
139 spin_unlock(&sound_loader_lock
);
147 * Remove a unit. Acquires locks as needed. The drivers MUST have
148 * completed the removal before their file operations become
152 static void sound_remove_unit(struct sound_unit
**list
, int unit
)
154 spin_lock(&sound_loader_lock
);
155 __sound_remove_unit(list
, unit
);
156 spin_unlock(&sound_loader_lock
);
168 * 6 -- sndstat (obsolete)
170 * 8 -- alternate sequencer (see above)
180 static struct sound_unit
*chains
[16];
182 int register_sound_special(struct file_operations
*fops
, int unit
)
184 return sound_insert_unit(&chains
[unit
&15], fops
, unit
, unit
+1);
187 EXPORT_SYMBOL(register_sound_special
);
189 int register_sound_mixer(struct file_operations
*fops
)
191 return sound_insert_unit(&chains
[0], fops
, 0, 128);
194 EXPORT_SYMBOL(register_sound_mixer
);
196 int register_sound_midi(struct file_operations
*fops
)
198 return sound_insert_unit(&chains
[2], fops
, 2, 130);
201 EXPORT_SYMBOL(register_sound_midi
);
204 * DSP's are registered as a triple. Register only one and cheat
205 * in open - see below.
208 int register_sound_dsp(struct file_operations
*fops
)
210 return sound_insert_unit(&chains
[3], fops
, 3, 131);
213 EXPORT_SYMBOL(register_sound_dsp
);
215 void unregister_sound_special(int unit
)
217 sound_remove_unit(&chains
[unit
&15], unit
);
220 EXPORT_SYMBOL(unregister_sound_special
);
222 void unregister_sound_mixer(int unit
)
224 sound_remove_unit(&chains
[0], unit
);
227 EXPORT_SYMBOL(unregister_sound_mixer
);
229 void unregister_sound_midi(int unit
)
231 return sound_remove_unit(&chains
[2], unit
);
234 EXPORT_SYMBOL(unregister_sound_midi
);
236 void unregister_sound_dsp(int unit
)
238 return sound_remove_unit(&chains
[3], unit
);
241 EXPORT_SYMBOL(unregister_sound_dsp
);
245 * Now our file operations
248 static int soundcore_open(struct inode
*, struct file
*);
250 static struct file_operations soundcore_fops
=
269 int soundcore_open(struct inode
*inode
, struct file
*file
)
272 int unit
=MINOR(inode
->i_rdev
);
273 struct sound_unit
*s
;
276 if(chain
==4 || chain
==5) /* dsp/audio/dsp16 */
283 spin_lock(&sound_loader_lock
);
287 while(s
&& s
->unit_minor
<= unit
)
289 if(s
->unit_minor
==unit
)
291 file
->f_op
=s
->unit_fops
;
292 spin_unlock(&sound_loader_lock
);
294 return file
->f_op
->open(inode
,file
);
301 spin_unlock(&sound_loader_lock
);
306 void cleanup_module(void)
308 /* We have nothing to really do here - we know the lists must be
310 unregister_chrdev(SOUND_MAJOR
, "sound");
313 int init_module(void)
315 int soundcore_init(void)
318 if(register_chrdev(SOUND_MAJOR
, "sound", &soundcore_fops
)==-1)
320 printk(KERN_ERR
"soundcore: sound device already in use.\n");
324 * Now init non OSS drivers
326 #ifdef CONFIG_SOUND_SONICVIBES
329 #ifdef CONFIG_SOUND_ES1370
332 #ifdef CONFIG_SOUND_ES1371
335 #ifdef CONFIG_SOUND_MSNDCLAS
338 #ifdef CONFIG_SOUND_MSNDPIN
339 msnd_pinnacle_init();