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