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