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