Import 2.3.15pre2
[davej-history.git] / drivers / sound / sound_core.c
blob970460938f8531e1da7c0b7621405a15b54ba3b9
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/fs.h>
43 #include <linux/sound.h>
44 #include <linux/major.h>
45 #include <linux/kmod.h>
48 struct sound_unit
50 int unit_minor;
51 struct file_operations *unit_fops;
52 struct sound_unit *next;
55 #ifdef CONFIG_SOUND_MSNDCLAS
56 extern int msnd_classic_init(void);
57 #endif
58 #ifdef CONFIG_SOUND_MSNDPIN
59 extern int msnd_pinnacle_init(void);
60 #endif
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)
69 int n=low;
71 if (index < 0) { /* first free */
73 while (*list && (*list)->unit_minor<n)
74 list=&((*list)->next);
76 while(n<top)
78 /* Found a hole ? */
79 if(*list==NULL || (*list)->unit_minor>n)
80 break;
81 list=&((*list)->next);
82 n+=16;
85 if(n>=top)
86 return -ENOENT;
87 } else {
88 n = low+(index*16);
89 while (*list) {
90 if ((*list)->unit_minor==n)
91 return -EBUSY;
92 if ((*list)->unit_minor>n)
93 break;
94 list=&((*list)->next);
99 * Fill it in
102 s->unit_minor=n;
103 s->unit_fops=fops;
106 * Link it
109 s->next=*list;
110 *list=s;
113 MOD_INC_USE_COUNT;
114 return n;
118 * Remove a node from the chain. Called with the lock asserted
121 static void __sound_remove_unit(struct sound_unit **list, int unit)
123 while(*list)
125 struct sound_unit *p=*list;
126 if(p->unit_minor==unit)
128 *list=p->next;
129 kfree(p);
130 MOD_DEC_USE_COUNT;
131 return;
133 list=&(p->next);
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)
151 int r;
152 struct sound_unit *s=(struct sound_unit *)kmalloc(sizeof(struct sound_unit), GFP_KERNEL);
153 if(s==NULL)
154 return -ENOMEM;
156 spin_lock(&sound_loader_lock);
157 r=__sound_insert_unit(s,list,fops,index,low,top);
158 spin_unlock(&sound_loader_lock);
160 if(r<0)
161 kfree(s);
162 return r;
166 * Remove a unit. Acquires locks as needed. The drivers MUST have
167 * completed the removal before their file operations become
168 * invalid.
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);
179 * Allocations
181 * 0 *16 Mixers
182 * 1 *8 Sequencers
183 * 2 *16 Midi
184 * 3 *16 DSP
185 * 4 *16 SunDSP
186 * 5 *16 DSP16
187 * 6 -- sndstat (obsolete)
188 * 7 *16 unused
189 * 8 -- alternate sequencer (see above)
190 * 9 *16 raw synthesizer access
191 * 10 *16 unused
192 * 11 *16 unused
193 * 12 *16 unused
194 * 13 *16 unused
195 * 14 *16 unused
196 * 15 *16 unused
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=
284 NULL,
285 NULL,
286 NULL,
287 NULL,
288 NULL,
289 NULL,
290 NULL,
291 soundcore_open,
292 NULL,
293 NULL,
294 NULL,
295 NULL,
296 NULL,
297 NULL,
298 NULL
301 static struct sound_unit *__look_for_unit(int chain, int unit)
303 struct sound_unit *s;
305 s=chains[chain];
306 while(s && s->unit_minor <= unit)
308 if(s->unit_minor==unit)
309 return s;
310 s=s->next;
312 return NULL;
315 int soundcore_open(struct inode *inode, struct file *file)
317 int chain;
318 int unit=MINOR(inode->i_rdev);
319 struct sound_unit *s;
321 chain=unit&0x0F;
322 if(chain==4 || chain==5) /* dsp/audio/dsp16 */
324 unit&=0xF0;
325 unit|=3;
326 chain=3;
329 spin_lock(&sound_loader_lock);
330 s = __look_for_unit(chain, unit);
331 if (s == NULL) {
332 char mod[32];
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);
343 request_module(mod);
344 sprintf(mod, "sound-service-%i-%i", unit>>4, chain);
345 request_module(mod);
346 spin_lock(&sound_loader_lock);
347 s = __look_for_unit(chain, unit);
349 if (s) {
350 file->f_op=s->unit_fops;
351 spin_unlock(&sound_loader_lock);
352 if(file->f_op->open)
353 return file->f_op->open(inode,file);
354 else
355 return 0;
357 spin_unlock(&sound_loader_lock);
358 return -ENODEV;
361 extern int mod_firmware_load(const char *, char **);
362 EXPORT_SYMBOL(mod_firmware_load);
364 #ifdef MODULE
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
372 empty */
373 unregister_chrdev(SOUND_MAJOR, "sound");
376 int init_module(void)
377 #else
378 int soundcore_init(void)
379 #endif
381 if(register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops)==-1)
383 printk(KERN_ERR "soundcore: sound device already in use.\n");
384 return -EBUSY;
387 * Now init non OSS drivers
389 #ifdef CONFIG_SOUND_CMPCI
390 init_cmpci();
391 #endif
392 #ifdef CONFIG_SOUND_MSNDCLAS
393 msnd_classic_init();
394 #endif
395 #ifdef CONFIG_SOUND_MSNDPIN
396 msnd_pinnacle_init();
397 #endif
398 return 0;