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