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
64subsys_initcall(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/types.h>
108#include <linux/kernel.h>
109#include <linux/sound.h>
110#include <linux/kmod.h>
111
112#define SOUND_STEP 16
113
114struct sound_unit
115{
116 int unit_minor;
117 const struct file_operations *unit_fops;
118 struct sound_unit *next;
119 char name[32];
120};
121
122#ifdef CONFIG_SOUND_MSNDCLAS
123extern int msnd_classic_init(void);
124#endif
125#ifdef CONFIG_SOUND_MSNDPIN
126extern int msnd_pinnacle_init(void);
127#endif
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152#ifdef CONFIG_SOUND_OSS_CORE_PRECLAIM
153static int preclaim_oss = 1;
154#else
155static int preclaim_oss = 0;
156#endif
157
158module_param(preclaim_oss, int, 0444);
159
160static int soundcore_open(struct inode *, struct file *);
161
162static const struct file_operations soundcore_fops =
163{
164
165 .owner = THIS_MODULE,
166 .open = soundcore_open,
167 .llseek = noop_llseek,
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 chain=unit&0x0F;
580 if(chain==4 || chain==5)
581 {
582 unit&=0xF0;
583 unit|=3;
584 chain=3;
585 }
586
587 spin_lock(&sound_loader_lock);
588 s = __look_for_unit(chain, unit);
589 if (s)
590 new_fops = fops_get(s->unit_fops);
591 if (preclaim_oss && !new_fops) {
592 spin_unlock(&sound_loader_lock);
593
594
595
596
597
598
599
600
601 request_module("sound-slot-%i", unit>>4);
602 request_module("sound-service-%i-%i", unit>>4, chain);
603
604
605
606
607
608
609
610
611 if (request_module("char-major-%d-%d", SOUND_MAJOR, unit) > 0)
612 request_module("char-major-%d", SOUND_MAJOR);
613
614 spin_lock(&sound_loader_lock);
615 s = __look_for_unit(chain, unit);
616 if (s)
617 new_fops = fops_get(s->unit_fops);
618 }
619 if (new_fops) {
620
621
622
623
624
625
626
627 int err = 0;
628 const struct file_operations *old_fops = file->f_op;
629 file->f_op = new_fops;
630 spin_unlock(&sound_loader_lock);
631
632 if (file->f_op->open)
633 err = file->f_op->open(inode,file);
634
635 if (err) {
636 fops_put(file->f_op);
637 file->f_op = fops_get(old_fops);
638 }
639
640 fops_put(old_fops);
641 return err;
642 }
643 spin_unlock(&sound_loader_lock);
644 return -ENODEV;
645}
646
647MODULE_ALIAS_CHARDEV_MAJOR(SOUND_MAJOR);
648
649static void cleanup_oss_soundcore(void)
650{
651
652
653 unregister_chrdev(SOUND_MAJOR, "sound");
654}
655
656static int __init init_oss_soundcore(void)
657{
658 if (preclaim_oss &&
659 register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops) == -1) {
660 printk(KERN_ERR "soundcore: sound device already in use.\n");
661 return -EBUSY;
662 }
663
664 return 0;
665}
666
667#endif
668