Import 2.1.118
[davej-history.git] / drivers / sound / sound_core.c
blob63322ec2ba12f75004e849fcdec5316e64914b00
1 /*
2 * Sound core handling. Breaks out sound functions to submodules
3 *
4 * Author: Alan Cox <alan.cox@linux.org>
6 * Fixes:
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>
43 #include <linux/fs.h>
44 #include <linux/sound.h>
45 #include <linux/major.h>
48 struct sound_unit
50 int unit_minor;
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)
62 int n=low;
64 while(n<top)
66 /* Found a hole ? */
67 if(*list==NULL || (*list)->unit_minor>n)
68 break;
69 list=&((*list)->next);
70 n+=16;
73 if(n==top)
75 return -1;
80 * Fill it in
83 s->unit_minor=n;
84 s->unit_fops=fops;
87 * Link it
90 s->next=*list;
91 *list=s;
94 MOD_INC_USE_COUNT;
95 return n;
99 * Remove a node from the chain. Called with the lock asserted
102 static void __sound_remove_unit(struct sound_unit **list, int unit)
104 while(*list)
106 struct sound_unit *p=*list;
107 if(p->unit_minor==unit)
109 *list=p->next;
110 kfree(p);
111 MOD_DEC_USE_COUNT;
112 return;
114 list=&(p->next);
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)
132 int r;
133 struct sound_unit *s=(struct sound_unit *)kmalloc(sizeof(struct sound_unit), GFP_KERNEL);
134 if(s==NULL)
135 return -1;
137 spin_lock(&sound_loader_lock);
138 r=__sound_insert_unit(s,list,fops,low,top);
139 spin_unlock(&sound_loader_lock);
141 if(r==-1)
142 kfree(s);
143 return r;
147 * Remove a unit. Acquires locks as needed. The drivers MUST have
148 * completed the removal before their file operations become
149 * invalid.
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);
160 * Allocations
162 * 0 *16 Mixers
163 * 1 *8 Sequencers
164 * 2 *16 Midi
165 * 3 *16 DSP
166 * 4 *16 SunDSP
167 * 5 *16 DSP16
168 * 6 -- sndstat (obsolete)
169 * 7 *16 unused
170 * 8 -- alternate sequencer (see above)
171 * 9 *16 unused
172 * 10 *16 unused
173 * 11 *16 unused
174 * 12 *16 unused
175 * 13 *16 unused
176 * 14 *16 unused
177 * 15 *16 unused
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=
252 NULL,
253 NULL,
254 NULL,
255 NULL,
256 NULL,
257 NULL,
258 NULL,
259 soundcore_open,
260 NULL,
261 NULL,
262 NULL,
263 NULL,
264 NULL,
265 NULL,
266 NULL
269 int soundcore_open(struct inode *inode, struct file *file)
271 int chain;
272 int unit=MINOR(inode->i_rdev);
273 struct sound_unit *s;
275 chain=unit&0x0F;
276 if(chain==4 || chain==5) /* dsp/audio/dsp16 */
278 unit&=0xF0;
279 unit|=3;
280 chain=3;
283 spin_lock(&sound_loader_lock);
285 s=chains[chain];
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);
293 if(file->f_op->open)
294 return file->f_op->open(inode,file);
295 else
296 return 0;
297 break;
299 s=s->next;
301 spin_unlock(&sound_loader_lock);
302 return -ENODEV;
305 #ifdef MODULE
306 void cleanup_module(void)
308 /* We have nothing to really do here - we know the lists must be
309 empty */
310 unregister_chrdev(SOUND_MAJOR, "sound");
313 int init_module(void)
314 #else
315 int soundcore_init(void)
316 #endif
318 if(register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops)==-1)
320 printk(KERN_ERR "soundcore: sound device already in use.\n");
321 return -EBUSY;
324 * Now init non OSS drivers
326 #ifdef CONFIG_SOUND_SONICVIBES
327 init_sonicvibes();
328 #endif
329 #ifdef CONFIG_SOUND_ES1370
330 init_es1370();
331 #endif
332 #ifdef CONFIG_SOUND_ES1371
333 init_es1371();
334 #endif
335 #ifdef CONFIG_SOUND_MSNDCLAS
336 msnd_classic_init();
337 #endif
338 #ifdef CONFIG_SOUND_MSNDPIN
339 msnd_pinnacle_init();
340 #endif
341 return 0;