1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37#include <linux/config.h>
38#include <linux/module.h>
39#include <linux/init.h>
40#include <linux/slab.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#include <linux/device.h>
49
50#define SOUND_STEP 16
51
52
53struct sound_unit
54{
55 int unit_minor;
56 struct file_operations *unit_fops;
57 struct sound_unit *next;
58 char name[32];
59};
60
61#ifdef CONFIG_SOUND_MSNDCLAS
62extern int msnd_classic_init(void);
63#endif
64#ifdef CONFIG_SOUND_MSNDPIN
65extern int msnd_pinnacle_init(void);
66#endif
67
68
69
70
71
72
73static int __sound_insert_unit(struct sound_unit * s, struct sound_unit **list, struct file_operations *fops, int index, int low, int top)
74{
75 int n=low;
76
77 if (index < 0) {
78
79 while (*list && (*list)->unit_minor<n)
80 list=&((*list)->next);
81
82 while(n<top)
83 {
84
85 if(*list==NULL || (*list)->unit_minor>n)
86 break;
87 list=&((*list)->next);
88 n+=SOUND_STEP;
89 }
90
91 if(n>=top)
92 return -ENOENT;
93 } else {
94 n = low+(index*16);
95 while (*list) {
96 if ((*list)->unit_minor==n)
97 return -EBUSY;
98 if ((*list)->unit_minor>n)
99 break;
100 list=&((*list)->next);
101 }
102 }
103
104
105
106
107
108 s->unit_minor=n;
109 s->unit_fops=fops;
110
111
112
113
114
115 s->next=*list;
116 *list=s;
117
118
119 return n;
120}
121
122
123
124
125
126static struct sound_unit *__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 return p;
135 }
136 list=&(p->next);
137 }
138 printk(KERN_ERR "Sound device %d went missing!\n", unit);
139 return NULL;
140}
141
142
143
144
145
146static spinlock_t sound_loader_lock = SPIN_LOCK_UNLOCKED;
147
148
149
150
151
152
153static int sound_insert_unit(struct sound_unit **list, struct file_operations *fops, int index, int low, int top, const char *name, umode_t mode)
154{
155 struct sound_unit *s = kmalloc(sizeof(*s), GFP_KERNEL);
156 int r;
157
158 if (!s)
159 return -ENOMEM;
160
161 spin_lock(&sound_loader_lock);
162 r = __sound_insert_unit(s, list, fops, index, low, top);
163 spin_unlock(&sound_loader_lock);
164
165 if (r < 0)
166 goto fail;
167 else if (r < SOUND_STEP)
168 sprintf(s->name, "sound/%s", name);
169 else
170 sprintf(s->name, "sound/%s%d", name, r / SOUND_STEP);
171
172 devfs_mk_cdev(MKDEV(SOUND_MAJOR, s->unit_minor),
173 S_IFCHR | mode, s->name);
174 return r;
175
176 fail:
177 kfree(s);
178 return r;
179}
180
181
182
183
184
185
186
187static void sound_remove_unit(struct sound_unit **list, int unit)
188{
189 struct sound_unit *p;
190
191 spin_lock(&sound_loader_lock);
192 p = __sound_remove_unit(list, unit);
193 spin_unlock(&sound_loader_lock);
194 if (p) {
195 devfs_remove(p->name);
196 kfree(p);
197 }
198}
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221static struct sound_unit *chains[SOUND_STEP];
222
223
224
225
226
227
228
229
230
231
232
233int register_sound_special(struct file_operations *fops, int unit)
234{
235 const int chain = unit % SOUND_STEP;
236 int max_unit = 128 + chain;
237 const char *name;
238 char _name[16];
239
240 switch (chain) {
241 case 0:
242 name = "mixer";
243 break;
244 case 1:
245 name = "sequencer";
246 if (unit >= SOUND_STEP)
247 goto __unknown;
248 max_unit = unit + 1;
249 break;
250 case 2:
251 name = "midi";
252 break;
253 case 3:
254 name = "dsp";
255 break;
256 case 4:
257 name = "audio";
258 break;
259 case 8:
260 name = "sequencer2";
261 if (unit >= SOUND_STEP)
262 goto __unknown;
263 max_unit = unit + 1;
264 break;
265 case 9:
266 name = "dmmidi";
267 break;
268 case 10:
269 name = "dmfm";
270 break;
271 case 12:
272 name = "adsp";
273 break;
274 case 13:
275 name = "amidi";
276 break;
277 case 14:
278 name = "admmidi";
279 break;
280 default:
281 {
282 __unknown:
283 sprintf(_name, "unknown%d", chain);
284 if (unit >= SOUND_STEP)
285 strcat(_name, "-");
286 name = _name;
287 }
288 break;
289 }
290 return sound_insert_unit(&chains[chain], fops, -1, unit, max_unit,
291 name, S_IRUSR | S_IWUSR);
292}
293
294EXPORT_SYMBOL(register_sound_special);
295
296
297
298
299
300
301
302
303
304
305
306int register_sound_mixer(struct file_operations *fops, int dev)
307{
308 return sound_insert_unit(&chains[0], fops, dev, 0, 128,
309 "mixer", S_IRUSR | S_IWUSR);
310}
311
312EXPORT_SYMBOL(register_sound_mixer);
313
314
315
316
317
318
319
320
321
322
323
324int register_sound_midi(struct file_operations *fops, int dev)
325{
326 return sound_insert_unit(&chains[2], fops, dev, 2, 130,
327 "midi", S_IRUSR | S_IWUSR);
328}
329
330EXPORT_SYMBOL(register_sound_midi);
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350int register_sound_dsp(struct file_operations *fops, int dev)
351{
352 return sound_insert_unit(&chains[3], fops, dev, 3, 131,
353 "dsp", S_IWUSR | S_IRUSR);
354}
355
356EXPORT_SYMBOL(register_sound_dsp);
357
358
359
360
361
362
363
364
365
366
367
368
369int register_sound_synth(struct file_operations *fops, int dev)
370{
371 return sound_insert_unit(&chains[9], fops, dev, 9, 137,
372 "synth", S_IRUSR | S_IWUSR);
373}
374
375EXPORT_SYMBOL(register_sound_synth);
376
377
378
379
380
381
382
383
384
385
386
387void unregister_sound_special(int unit)
388{
389 sound_remove_unit(&chains[unit % SOUND_STEP], unit);
390}
391
392EXPORT_SYMBOL(unregister_sound_special);
393
394
395
396
397
398
399
400
401
402void unregister_sound_mixer(int unit)
403{
404 sound_remove_unit(&chains[0], unit);
405}
406
407EXPORT_SYMBOL(unregister_sound_mixer);
408
409
410
411
412
413
414
415
416
417void unregister_sound_midi(int unit)
418{
419 return sound_remove_unit(&chains[2], unit);
420}
421
422EXPORT_SYMBOL(unregister_sound_midi);
423
424
425
426
427
428
429
430
431
432
433
434void unregister_sound_dsp(int unit)
435{
436 return sound_remove_unit(&chains[3], unit);
437}
438
439
440EXPORT_SYMBOL(unregister_sound_dsp);
441
442
443
444
445
446
447
448
449
450void unregister_sound_synth(int unit)
451{
452 return sound_remove_unit(&chains[9], unit);
453}
454
455EXPORT_SYMBOL(unregister_sound_synth);
456
457
458
459
460
461static int soundcore_open(struct inode *, struct file *);
462
463static struct file_operations soundcore_fops=
464{
465
466 .owner = THIS_MODULE,
467 .open = soundcore_open,
468};
469
470static struct sound_unit *__look_for_unit(int chain, int unit)
471{
472 struct sound_unit *s;
473
474 s=chains[chain];
475 while(s && s->unit_minor <= unit)
476 {
477 if(s->unit_minor==unit)
478 return s;
479 s=s->next;
480 }
481 return NULL;
482}
483
484int soundcore_open(struct inode *inode, struct file *file)
485{
486 int chain;
487 int unit = iminor(inode);
488 struct sound_unit *s;
489 struct file_operations *new_fops = NULL;
490
491 chain=unit&0x0F;
492 if(chain==4 || chain==5)
493 {
494 unit&=0xF0;
495 unit|=3;
496 chain=3;
497 }
498
499 spin_lock(&sound_loader_lock);
500 s = __look_for_unit(chain, unit);
501 if (s)
502 new_fops = fops_get(s->unit_fops);
503 if (!new_fops) {
504 spin_unlock(&sound_loader_lock);
505
506
507
508
509
510
511
512 request_module("sound-slot-%i", unit>>4);
513 request_module("sound-service-%i-%i", unit>>4, chain);
514 spin_lock(&sound_loader_lock);
515 s = __look_for_unit(chain, unit);
516 if (s)
517 new_fops = fops_get(s->unit_fops);
518 }
519 if (new_fops) {
520
521
522
523
524
525
526
527 int err = 0;
528 struct file_operations *old_fops = file->f_op;
529 file->f_op = new_fops;
530 spin_unlock(&sound_loader_lock);
531 if(file->f_op->open)
532 err = file->f_op->open(inode,file);
533 if (err) {
534 fops_put(file->f_op);
535 file->f_op = fops_get(old_fops);
536 }
537 fops_put(old_fops);
538 return err;
539 }
540 spin_unlock(&sound_loader_lock);
541 return -ENODEV;
542}
543
544extern int mod_firmware_load(const char *, char **);
545EXPORT_SYMBOL(mod_firmware_load);
546
547
548MODULE_DESCRIPTION("Core sound module");
549MODULE_AUTHOR("Alan Cox");
550MODULE_LICENSE("GPL");
551MODULE_ALIAS_CHARDEV_MAJOR(SOUND_MAJOR);
552
553static void __exit cleanup_soundcore(void)
554{
555
556
557 unregister_chrdev(SOUND_MAJOR, "sound");
558 devfs_remove("sound");
559}
560
561static int __init init_soundcore(void)
562{
563 if (register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops)==-1) {
564 printk(KERN_ERR "soundcore: sound device already in use.\n");
565 return -EBUSY;
566 }
567 devfs_mk_dir ("sound");
568
569 return 0;
570}
571
572module_init(init_soundcore);
573module_exit(cleanup_soundcore);
574