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