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, umode_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#ifdef CONFIG_SOUND_OSS_CORE_PRECLAIM
152static int preclaim_oss = 1;
153#else
154static int preclaim_oss = 0;
155#endif
156
157module_param(preclaim_oss, int, 0444);
158
159static int soundcore_open(struct inode *, struct file *);
160
161static const struct file_operations soundcore_fops =
162{
163
164 .owner = THIS_MODULE,
165 .open = soundcore_open,
166 .llseek = noop_llseek,
167};
168
169
170
171
172
173
174static int __sound_insert_unit(struct sound_unit * s, struct sound_unit **list, const struct file_operations *fops, int index, int low, int top)
175{
176 int n=low;
177
178 if (index < 0) {
179
180 while (*list && (*list)->unit_minor<n)
181 list=&((*list)->next);
182
183 while(n<top)
184 {
185
186 if(*list==NULL || (*list)->unit_minor>n)
187 break;
188 list=&((*list)->next);
189 n+=SOUND_STEP;
190 }
191
192 if(n>=top)
193 return -ENOENT;
194 } else {
195 n = low+(index*16);
196 while (*list) {
197 if ((*list)->unit_minor==n)
198 return -EBUSY;
199 if ((*list)->unit_minor>n)
200 break;
201 list=&((*list)->next);
202 }
203 }
204
205
206
207
208
209 s->unit_minor=n;
210 s->unit_fops=fops;
211
212
213
214
215
216 s->next=*list;
217 *list=s;
218
219
220 return n;
221}
222
223
224
225
226
227static struct sound_unit *__sound_remove_unit(struct sound_unit **list, int unit)
228{
229 while(*list)
230 {
231 struct sound_unit *p=*list;
232 if(p->unit_minor==unit)
233 {
234 *list=p->next;
235 return p;
236 }
237 list=&(p->next);
238 }
239 printk(KERN_ERR "Sound device %d went missing!\n", unit);
240 return NULL;
241}
242
243
244
245
246
247static DEFINE_SPINLOCK(sound_loader_lock);
248
249
250
251
252
253
254static 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)
255{
256 struct sound_unit *s = kmalloc(sizeof(*s), GFP_KERNEL);
257 int r;
258
259 if (!s)
260 return -ENOMEM;
261
262 spin_lock(&sound_loader_lock);
263retry:
264 r = __sound_insert_unit(s, list, fops, index, low, top);
265 spin_unlock(&sound_loader_lock);
266
267 if (r < 0)
268 goto fail;
269 else if (r < SOUND_STEP)
270 sprintf(s->name, "sound/%s", name);
271 else
272 sprintf(s->name, "sound/%s%d", name, r / SOUND_STEP);
273
274 if (!preclaim_oss) {
275
276
277
278
279
280 r = __register_chrdev(SOUND_MAJOR, s->unit_minor, 1, s->name,
281 &soundcore_fops);
282 if (r < 0) {
283 spin_lock(&sound_loader_lock);
284 __sound_remove_unit(list, s->unit_minor);
285 if (index < 0) {
286 low = s->unit_minor + SOUND_STEP;
287 goto retry;
288 }
289 spin_unlock(&sound_loader_lock);
290 return -EBUSY;
291 }
292 }
293
294 device_create(sound_class, dev, MKDEV(SOUND_MAJOR, s->unit_minor),
295 NULL, s->name+6);
296 return s->unit_minor;
297
298fail:
299 kfree(s);
300 return r;
301}
302
303
304
305
306
307
308
309static void sound_remove_unit(struct sound_unit **list, int unit)
310{
311 struct sound_unit *p;
312
313 spin_lock(&sound_loader_lock);
314 p = __sound_remove_unit(list, unit);
315 spin_unlock(&sound_loader_lock);
316 if (p) {
317 if (!preclaim_oss)
318 __unregister_chrdev(SOUND_MAJOR, p->unit_minor, 1,
319 p->name);
320 device_destroy(sound_class, MKDEV(SOUND_MAJOR, p->unit_minor));
321 kfree(p);
322 }
323}
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346static struct sound_unit *chains[SOUND_STEP];
347
348
349
350
351
352
353
354
355
356
357
358
359int register_sound_special_device(const struct file_operations *fops, int unit,
360 struct device *dev)
361{
362 const int chain = unit % SOUND_STEP;
363 int max_unit = 256;
364 const char *name;
365 char _name[16];
366
367 switch (chain) {
368 case 0:
369 name = "mixer";
370 break;
371 case 1:
372 name = "sequencer";
373 if (unit >= SOUND_STEP)
374 goto __unknown;
375 max_unit = unit + 1;
376 break;
377 case 2:
378 name = "midi";
379 break;
380 case 3:
381 name = "dsp";
382 break;
383 case 4:
384 name = "audio";
385 break;
386 case 5:
387 name = "dspW";
388 break;
389 case 8:
390 name = "sequencer2";
391 if (unit >= SOUND_STEP)
392 goto __unknown;
393 max_unit = unit + 1;
394 break;
395 case 9:
396 name = "dmmidi";
397 break;
398 case 10:
399 name = "dmfm";
400 break;
401 case 12:
402 name = "adsp";
403 break;
404 case 13:
405 name = "amidi";
406 break;
407 case 14:
408 name = "admmidi";
409 break;
410 default:
411 {
412 __unknown:
413 sprintf(_name, "unknown%d", chain);
414 if (unit >= SOUND_STEP)
415 strcat(_name, "-");
416 name = _name;
417 }
418 break;
419 }
420 return sound_insert_unit(&chains[chain], fops, -1, unit, max_unit,
421 name, S_IRUSR | S_IWUSR, dev);
422}
423
424EXPORT_SYMBOL(register_sound_special_device);
425
426int register_sound_special(const struct file_operations *fops, int unit)
427{
428 return register_sound_special_device(fops, unit, NULL);
429}
430
431EXPORT_SYMBOL(register_sound_special);
432
433
434
435
436
437
438
439
440
441
442
443int register_sound_mixer(const struct file_operations *fops, int dev)
444{
445 return sound_insert_unit(&chains[0], fops, dev, 0, 128,
446 "mixer", S_IRUSR | S_IWUSR, NULL);
447}
448
449EXPORT_SYMBOL(register_sound_mixer);
450
451
452
453
454
455
456
457
458
459
460
461int register_sound_midi(const struct file_operations *fops, int dev)
462{
463 return sound_insert_unit(&chains[2], fops, dev, 2, 130,
464 "midi", S_IRUSR | S_IWUSR, NULL);
465}
466
467EXPORT_SYMBOL(register_sound_midi);
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487int register_sound_dsp(const struct file_operations *fops, int dev)
488{
489 return sound_insert_unit(&chains[3], fops, dev, 3, 131,
490 "dsp", S_IWUSR | S_IRUSR, NULL);
491}
492
493EXPORT_SYMBOL(register_sound_dsp);
494
495
496
497
498
499
500
501
502
503
504
505void unregister_sound_special(int unit)
506{
507 sound_remove_unit(&chains[unit % SOUND_STEP], unit);
508}
509
510EXPORT_SYMBOL(unregister_sound_special);
511
512
513
514
515
516
517
518
519
520void unregister_sound_mixer(int unit)
521{
522 sound_remove_unit(&chains[0], unit);
523}
524
525EXPORT_SYMBOL(unregister_sound_mixer);
526
527
528
529
530
531
532
533
534
535void unregister_sound_midi(int unit)
536{
537 sound_remove_unit(&chains[2], unit);
538}
539
540EXPORT_SYMBOL(unregister_sound_midi);
541
542
543
544
545
546
547
548
549
550
551
552void unregister_sound_dsp(int unit)
553{
554 sound_remove_unit(&chains[3], unit);
555}
556
557
558EXPORT_SYMBOL(unregister_sound_dsp);
559
560static struct sound_unit *__look_for_unit(int chain, int unit)
561{
562 struct sound_unit *s;
563
564 s=chains[chain];
565 while(s && s->unit_minor <= unit)
566 {
567 if(s->unit_minor==unit)
568 return s;
569 s=s->next;
570 }
571 return NULL;
572}
573
574static int soundcore_open(struct inode *inode, struct file *file)
575{
576 int chain;
577 int unit = iminor(inode);
578 struct sound_unit *s;
579 const struct file_operations *new_fops = NULL;
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
634 if (file->f_op->open)
635 err = file->f_op->open(inode,file);
636
637 if (err) {
638 fops_put(file->f_op);
639 file->f_op = fops_get(old_fops);
640 }
641
642 fops_put(old_fops);
643 return err;
644 }
645 spin_unlock(&sound_loader_lock);
646 return -ENODEV;
647}
648
649MODULE_ALIAS_CHARDEV_MAJOR(SOUND_MAJOR);
650
651static void cleanup_oss_soundcore(void)
652{
653
654
655 unregister_chrdev(SOUND_MAJOR, "sound");
656}
657
658static int __init init_oss_soundcore(void)
659{
660 if (preclaim_oss &&
661 register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops) == -1) {
662 printk(KERN_ERR "soundcore: sound device already in use.\n");
663 return -EBUSY;
664 }
665
666 return 0;
667}
668
669#endif
670