0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/module.h>
0012 #include <linux/device.h>
0013 #include <linux/err.h>
0014 #include <linux/kdev_t.h>
0015 #include <linux/major.h>
0016 #include <sound/core.h>
0017
0018 #ifdef CONFIG_SOUND_OSS_CORE
0019 static int __init init_oss_soundcore(void);
0020 static void cleanup_oss_soundcore(void);
0021 #else
0022 static inline int init_oss_soundcore(void) { return 0; }
0023 static inline void cleanup_oss_soundcore(void) { }
0024 #endif
0025
0026 struct class *sound_class;
0027 EXPORT_SYMBOL(sound_class);
0028
0029 MODULE_DESCRIPTION("Core sound module");
0030 MODULE_AUTHOR("Alan Cox");
0031 MODULE_LICENSE("GPL");
0032
0033 static char *sound_devnode(struct device *dev, umode_t *mode)
0034 {
0035 if (MAJOR(dev->devt) == SOUND_MAJOR)
0036 return NULL;
0037 return kasprintf(GFP_KERNEL, "snd/%s", dev_name(dev));
0038 }
0039
0040 static int __init init_soundcore(void)
0041 {
0042 int rc;
0043
0044 rc = init_oss_soundcore();
0045 if (rc)
0046 return rc;
0047
0048 sound_class = class_create(THIS_MODULE, "sound");
0049 if (IS_ERR(sound_class)) {
0050 cleanup_oss_soundcore();
0051 return PTR_ERR(sound_class);
0052 }
0053
0054 sound_class->devnode = sound_devnode;
0055
0056 return 0;
0057 }
0058
0059 static void __exit cleanup_soundcore(void)
0060 {
0061 cleanup_oss_soundcore();
0062 class_destroy(sound_class);
0063 }
0064
0065 subsys_initcall(init_soundcore);
0066 module_exit(cleanup_soundcore);
0067
0068
0069 #ifdef CONFIG_SOUND_OSS_CORE
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100 #include <linux/init.h>
0101 #include <linux/slab.h>
0102 #include <linux/types.h>
0103 #include <linux/kernel.h>
0104 #include <linux/sound.h>
0105 #include <linux/kmod.h>
0106
0107 #define SOUND_STEP 16
0108
0109 struct sound_unit
0110 {
0111 int unit_minor;
0112 const struct file_operations *unit_fops;
0113 struct sound_unit *next;
0114 char name[32];
0115 };
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139 static int preclaim_oss = IS_ENABLED(CONFIG_SOUND_OSS_CORE_PRECLAIM);
0140
0141 module_param(preclaim_oss, int, 0444);
0142
0143 static int soundcore_open(struct inode *, struct file *);
0144
0145 static const struct file_operations soundcore_fops =
0146 {
0147
0148 .owner = THIS_MODULE,
0149 .open = soundcore_open,
0150 .llseek = noop_llseek,
0151 };
0152
0153
0154
0155
0156
0157
0158 static int __sound_insert_unit(struct sound_unit * s, struct sound_unit **list, const struct file_operations *fops, int index, int low, int top)
0159 {
0160 int n=low;
0161
0162 if (index < 0) {
0163
0164 while (*list && (*list)->unit_minor<n)
0165 list=&((*list)->next);
0166
0167 while(n<top)
0168 {
0169
0170 if(*list==NULL || (*list)->unit_minor>n)
0171 break;
0172 list=&((*list)->next);
0173 n+=SOUND_STEP;
0174 }
0175
0176 if(n>=top)
0177 return -ENOENT;
0178 } else {
0179 n = low+(index*16);
0180 while (*list) {
0181 if ((*list)->unit_minor==n)
0182 return -EBUSY;
0183 if ((*list)->unit_minor>n)
0184 break;
0185 list=&((*list)->next);
0186 }
0187 }
0188
0189
0190
0191
0192
0193 s->unit_minor=n;
0194 s->unit_fops=fops;
0195
0196
0197
0198
0199
0200 s->next=*list;
0201 *list=s;
0202
0203
0204 return n;
0205 }
0206
0207
0208
0209
0210
0211 static struct sound_unit *__sound_remove_unit(struct sound_unit **list, int unit)
0212 {
0213 while(*list)
0214 {
0215 struct sound_unit *p=*list;
0216 if(p->unit_minor==unit)
0217 {
0218 *list=p->next;
0219 return p;
0220 }
0221 list=&(p->next);
0222 }
0223 printk(KERN_ERR "Sound device %d went missing!\n", unit);
0224 return NULL;
0225 }
0226
0227
0228
0229
0230
0231 static DEFINE_SPINLOCK(sound_loader_lock);
0232
0233
0234
0235
0236
0237
0238 static 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)
0239 {
0240 struct sound_unit *s = kmalloc(sizeof(*s), GFP_KERNEL);
0241 int r;
0242
0243 if (!s)
0244 return -ENOMEM;
0245
0246 spin_lock(&sound_loader_lock);
0247 retry:
0248 r = __sound_insert_unit(s, list, fops, index, low, top);
0249 spin_unlock(&sound_loader_lock);
0250
0251 if (r < 0)
0252 goto fail;
0253 else if (r < SOUND_STEP)
0254 sprintf(s->name, "sound/%s", name);
0255 else
0256 sprintf(s->name, "sound/%s%d", name, r / SOUND_STEP);
0257
0258 if (!preclaim_oss) {
0259
0260
0261
0262
0263
0264 r = __register_chrdev(SOUND_MAJOR, s->unit_minor, 1, s->name,
0265 &soundcore_fops);
0266 if (r < 0) {
0267 spin_lock(&sound_loader_lock);
0268 __sound_remove_unit(list, s->unit_minor);
0269 if (index < 0) {
0270 low = s->unit_minor + SOUND_STEP;
0271 goto retry;
0272 }
0273 spin_unlock(&sound_loader_lock);
0274 r = -EBUSY;
0275 goto fail;
0276 }
0277 }
0278
0279 device_create(sound_class, dev, MKDEV(SOUND_MAJOR, s->unit_minor),
0280 NULL, "%s", s->name+6);
0281 return s->unit_minor;
0282
0283 fail:
0284 kfree(s);
0285 return r;
0286 }
0287
0288
0289
0290
0291
0292
0293
0294 static void sound_remove_unit(struct sound_unit **list, int unit)
0295 {
0296 struct sound_unit *p;
0297
0298 spin_lock(&sound_loader_lock);
0299 p = __sound_remove_unit(list, unit);
0300 spin_unlock(&sound_loader_lock);
0301 if (p) {
0302 if (!preclaim_oss)
0303 __unregister_chrdev(SOUND_MAJOR, p->unit_minor, 1,
0304 p->name);
0305 device_destroy(sound_class, MKDEV(SOUND_MAJOR, p->unit_minor));
0306 kfree(p);
0307 }
0308 }
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331 static struct sound_unit *chains[SOUND_STEP];
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346 int register_sound_special_device(const struct file_operations *fops, int unit,
0347 struct device *dev)
0348 {
0349 const int chain = unit % SOUND_STEP;
0350 int max_unit = 256;
0351 const char *name;
0352 char _name[16];
0353
0354 switch (chain) {
0355 case 0:
0356 name = "mixer";
0357 break;
0358 case 1:
0359 name = "sequencer";
0360 if (unit >= SOUND_STEP)
0361 goto __unknown;
0362 max_unit = unit + 1;
0363 break;
0364 case 2:
0365 name = "midi";
0366 break;
0367 case 3:
0368 name = "dsp";
0369 break;
0370 case 4:
0371 name = "audio";
0372 break;
0373 case 5:
0374 name = "dspW";
0375 break;
0376 case 8:
0377 name = "sequencer2";
0378 if (unit >= SOUND_STEP)
0379 goto __unknown;
0380 max_unit = unit + 1;
0381 break;
0382 case 9:
0383 name = "dmmidi";
0384 break;
0385 case 10:
0386 name = "dmfm";
0387 break;
0388 case 12:
0389 name = "adsp";
0390 break;
0391 case 13:
0392 name = "amidi";
0393 break;
0394 case 14:
0395 name = "admmidi";
0396 break;
0397 default:
0398 {
0399 __unknown:
0400 sprintf(_name, "unknown%d", chain);
0401 if (unit >= SOUND_STEP)
0402 strcat(_name, "-");
0403 name = _name;
0404 }
0405 break;
0406 }
0407 return sound_insert_unit(&chains[chain], fops, -1, unit, max_unit,
0408 name, 0600, dev);
0409 }
0410
0411 EXPORT_SYMBOL(register_sound_special_device);
0412
0413 int register_sound_special(const struct file_operations *fops, int unit)
0414 {
0415 return register_sound_special_device(fops, unit, NULL);
0416 }
0417
0418 EXPORT_SYMBOL(register_sound_special);
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432 int register_sound_mixer(const struct file_operations *fops, int dev)
0433 {
0434 return sound_insert_unit(&chains[0], fops, dev, 0, 128,
0435 "mixer", 0600, NULL);
0436 }
0437
0438 EXPORT_SYMBOL(register_sound_mixer);
0439
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460 int register_sound_dsp(const struct file_operations *fops, int dev)
0461 {
0462 return sound_insert_unit(&chains[3], fops, dev, 3, 131,
0463 "dsp", 0600, NULL);
0464 }
0465
0466 EXPORT_SYMBOL(register_sound_dsp);
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476
0477
0478 void unregister_sound_special(int unit)
0479 {
0480 sound_remove_unit(&chains[unit % SOUND_STEP], unit);
0481 }
0482
0483 EXPORT_SYMBOL(unregister_sound_special);
0484
0485
0486
0487
0488
0489
0490
0491
0492
0493 void unregister_sound_mixer(int unit)
0494 {
0495 sound_remove_unit(&chains[0], unit);
0496 }
0497
0498 EXPORT_SYMBOL(unregister_sound_mixer);
0499
0500
0501
0502
0503
0504
0505
0506
0507
0508
0509
0510 void unregister_sound_dsp(int unit)
0511 {
0512 sound_remove_unit(&chains[3], unit);
0513 }
0514
0515
0516 EXPORT_SYMBOL(unregister_sound_dsp);
0517
0518 static struct sound_unit *__look_for_unit(int chain, int unit)
0519 {
0520 struct sound_unit *s;
0521
0522 s=chains[chain];
0523 while(s && s->unit_minor <= unit)
0524 {
0525 if(s->unit_minor==unit)
0526 return s;
0527 s=s->next;
0528 }
0529 return NULL;
0530 }
0531
0532 static int soundcore_open(struct inode *inode, struct file *file)
0533 {
0534 int chain;
0535 int unit = iminor(inode);
0536 struct sound_unit *s;
0537 const struct file_operations *new_fops = NULL;
0538
0539 chain=unit&0x0F;
0540 if(chain==4 || chain==5)
0541 {
0542 unit&=0xF0;
0543 unit|=3;
0544 chain=3;
0545 }
0546
0547 spin_lock(&sound_loader_lock);
0548 s = __look_for_unit(chain, unit);
0549 if (s)
0550 new_fops = fops_get(s->unit_fops);
0551 if (preclaim_oss && !new_fops) {
0552 spin_unlock(&sound_loader_lock);
0553
0554
0555
0556
0557
0558
0559
0560
0561 request_module("sound-slot-%i", unit>>4);
0562 request_module("sound-service-%i-%i", unit>>4, chain);
0563
0564
0565
0566
0567
0568
0569
0570
0571 if (request_module("char-major-%d-%d", SOUND_MAJOR, unit) > 0)
0572 request_module("char-major-%d", SOUND_MAJOR);
0573
0574 spin_lock(&sound_loader_lock);
0575 s = __look_for_unit(chain, unit);
0576 if (s)
0577 new_fops = fops_get(s->unit_fops);
0578 }
0579 spin_unlock(&sound_loader_lock);
0580
0581 if (!new_fops)
0582 return -ENODEV;
0583
0584
0585
0586
0587
0588 replace_fops(file, new_fops);
0589
0590 if (!file->f_op->open)
0591 return -ENODEV;
0592
0593 return file->f_op->open(inode, file);
0594 }
0595
0596 MODULE_ALIAS_CHARDEV_MAJOR(SOUND_MAJOR);
0597
0598 static void cleanup_oss_soundcore(void)
0599 {
0600
0601
0602 unregister_chrdev(SOUND_MAJOR, "sound");
0603 }
0604
0605 static int __init init_oss_soundcore(void)
0606 {
0607 if (preclaim_oss &&
0608 register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops) < 0) {
0609 printk(KERN_ERR "soundcore: sound device already in use.\n");
0610 return -EBUSY;
0611 }
0612
0613 return 0;
0614 }
0615
0616 #endif