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