1 2 3#include <linux/config.h> 4#include <linux/module.h> 5#include <linux/init.h> 6#include <linux/slab.h> 7#include <linux/types.h> 8#include <linux/kernel.h> 9#include <linux/fs.h> 10#include <linux/sound.h> 11#include <linux/major.h> 12#include <linux/kmod.h> 13#include <linux/devfs_fs_kernel.h> 14 15#define SOUND_STEP 16 16 17 18struct sound_unit 19{ 20 int unit_minor; 21 struct file_operations *unit_fops; 22 struct sound_unit *next; 23 devfs_handle_t de; 24}; 25 26#ifdef CONFIG_SOUND_MSNDCLAS 27extern int msnd_classic_init(void); 28#endif 29#ifdef CONFIG_SOUND_MSNDPIN 30extern int msnd_pinnacle_init(void); 31#endif 32 33/* 34 * Low level list operator. Scan the ordered list, find a hole and 35 * join into it. Called with the lock asserted 36 */ 37 38static int __sound_insert_unit(struct sound_unit * s, struct sound_unit **list, struct file_operations *fops, int index, int low, int top) 39{ 40 int n=low; 41 42 if (index < 0) { /* first free */ 43 44 while (*list && (*list)->unit_minor<n) 45 list=&((*list)->next); 46 47 while(n<top) 48 { 49 /* Found a hole ? */ 50 if(*list==NULL || (*list)->unit_minor>n) 51 break; 52 list=&((*list)->next); 53 n+=SOUND_STEP; 54 } 55 56 if(n>=top) 57 return -ENOENT; 58 } else { 59 n = low+(index*16); 60 while (*list) { 61 if ((*list)->unit_minor==n) 62 return -EBUSY; 63 if ((*list)->unit_minor>n) 64 break; 65 list=&((*list)->next); 66 } 67 } 68 69 /* 70 * Fill it in 71 */ 72 73 s->unit_minor=n; 74 s->unit_fops=fops; 75 76 /* 77 * Link it 78 */ 79 80 s->next=*list; 81 *list=s; 82 83 84 MOD_INC_USE_COUNT; 85 return n; 86} 87 88/* 89 * Remove a node from the chain. Called with the lock asserted 90 */ 91 92static void __sound_remove_unit(struct sound_unit **list, int unit) 93{ 94 while(*list) 95 { 96 struct sound_unit *p=*list; 97 if(p->unit_minor==unit) 98 { 99 *list=p->next; 100 devfs_unregister (p->de); 101 kfree(p); 102 MOD_DEC_USE_COUNT; 103 return; 104 } 105 list=&(p->next); 106 } 107 printk(KERN_ERR "Sound device %d went missing!\n", unit); 108} 109 110/* 111 * This lock guards the sound loader list. 112 */ 113 114static spinlock_t sound_loader_lock = SPIN_LOCK_UNLOCKED; 115 116/* 117 * Allocate the controlling structure and add it to the sound driver 118 * list. Acquires locks as needed 119 */ 120 121static devfs_handle_t devfs_handle; 122 123static int sound_insert_unit(struct sound_unit **list, struct file_operations *fops, int index, int low, int top, const char *name, umode_t mode) 124{ 125 int r; 126 struct sound_unit *s=(struct sound_unit *)kmalloc(sizeof(struct sound_unit), GFP_KERNEL); 127 char name_buf[16]; 128 129 if(s==NULL) 130 return -ENOMEM; 131 132 spin_lock(&sound_loader_lock); 133 r=__sound_insert_unit(s,list,fops,index,low,top); 134 spin_unlock(&sound_loader_lock); 135 136 if(r<0) 137 { 138 kfree(s); 139 return r; 140 } 141 142 if (r == low) 143 sprintf (name_buf, "%s", name); 144 else 145 sprintf (name_buf, "%s%d", name, (r - low) / SOUND_STEP); 146 s->de = devfs_register (devfs_handle, name_buf, 147 DEVFS_FL_NONE, SOUND_MAJOR, s->unit_minor, 148 S_IFCHR | mode, fops, NULL); 149 return r; 150} 151 152/* 153 * Remove a unit. Acquires locks as needed. The drivers MUST have 154 * completed the removal before their file operations become 155 * invalid. 156 */ 157 158static void sound_remove_unit(struct sound_unit **list, int unit) 159{ 160 spin_lock(&sound_loader_lock); 161 __sound_remove_unit(list, unit); 162 spin_unlock(&sound_loader_lock); 163} 164 165/* 166 * Allocations 167 * 168 * 0 *16 Mixers 169 * 1 *8 Sequencers 170 * 2 *16 Midi 171 * 3 *16 DSP 172 * 4 *16 SunDSP 173 * 5 *16 DSP16 174 * 6 -- sndstat (obsolete) 175 * 7 *16 unused 176 * 8 -- alternate sequencer (see above) 177 * 9 *16 raw synthesizer access 178 * 10 *16 unused 179 * 11 *16 unused 180 * 12 *16 unused 181 * 13 *16 unused 182 * 14 *16 unused 183 * 15 *16 unused 184 */ 185 186static struct sound_unit *chains[16]; 187 188/** 189 * register_sound_special - register a special sound node 190 * @fops: File operations for the driver 191 * @unit: Unit number to allocate 192 * 193 * Allocate a special sound device by minor number from the sound 194 * subsystem. The allocated number is returned on succes. On failure 195 * a negative error code is returned. 196 */ 197 198int register_sound_special(struct file_operations *fops, int unit) 199{ 200 char *name; 201 202 switch (unit) { 203 case 0: 204 name = "mixer"; 205 break; 206 case 1: 207 name = "sequencer"; 208 break; 209 case 2: 210 name = "midi00"; 211 break; 212 case 3: 213 name = "dsp"; 214 break; 215 case 4: 216 name = "audio"; 217 break; 218 case 5: 219 name = "unknown5"; 220 break; 221 case 6: /* Was once sndstat */ 222 name = "unknown6"; 223 break; 224 case 7: 225 name = "unknown7"; 226 break; 227 case 8: 228 name = "sequencer2"; 229 break; 230 case 9: 231 name = "dmmidi"; 232 break; 233 case 10: 234 name = "dmfm"; 235 break; 236 case 11: 237 name = "unknown11"; 238 break; 239 case 12: 240 name = "adsp"; 241 break; 242 case 13: 243 name = "amidi"; 244 break; 245 case 14: 246 name = "admmidi"; 247 break; 248 default: 249 name = "unknown"; 250 break; 251 } 252 return sound_insert_unit(&chains[unit&15], fops, -1, unit, unit+1, 253 name, S_IRUSR | S_IWUSR); 254} 255 256EXPORT_SYMBOL(register_sound_special); 257 258/** 259 * register_sound_mixer - register a mixer device 260 * @fops: File operations for the driver 261 * @dev: Unit number to allocate 262 * 263 * Allocate a mixer device. Unit is the number of the mixer requested. 264 * Pass -1 to request the next free mixer unit. On success the allocated 265 * number is returned, on failure a negative error code is returned. 266 */ 267 268int register_sound_mixer(struct file_operations *fops, int dev) 269{ 270 return sound_insert_unit(&chains[0], fops, dev, 0, 128, 271 "mixer", S_IRUSR | S_IWUSR); 272} 273 274EXPORT_SYMBOL(register_sound_mixer); 275 276/** 277 * register_sound_midi - register a midi device 278 * @fops: File operations for the driver 279 * @dev: Unit number to allocate 280 * 281 * Allocate a midi device. Unit is the number of the midi device requested. 282 * Pass -1 to request the next free midi unit. On success the allocated 283 * number is returned, on failure a negative error code is returned. 284 */ 285 286int register_sound_midi(struct file_operations *fops, int dev) 287{ 288 return sound_insert_unit(&chains[2], fops, dev, 2, 130, 289 "midi", S_IRUSR | S_IWUSR); 290} 291 292EXPORT_SYMBOL(register_sound_midi); 293 294/* 295 * DSP's are registered as a triple. Register only one and cheat 296 * in open - see below. 297 */ 298 299/** 300 * register_sound_dsp - register a DSP device 301 * @fops: File operations for the driver 302 * @dev: Unit number to allocate 303 * 304 * Allocate a DSP device. Unit is the number of the DSP requested. 305 * Pass -1 to request the next free DSP unit. On success the allocated 306 * number is returned, on failure a negative error code is returned. 307 * 308 * This function allocates both the audio and dsp device entries together 309 * and will always allocate them as a matching pair - eg dsp3/audio3 310 */ 311 312int register_sound_dsp(struct file_operations *fops, int dev) 313{ 314 return sound_insert_unit(&chains[3], fops, dev, 3, 131, 315 "dsp", S_IWUSR | S_IRUSR); 316} 317 318EXPORT_SYMBOL(register_sound_dsp); 319 320/** 321 * register_sound_synth - register a synth device 322 * @fops: File operations for the driver 323 * @dev: Unit number to allocate 324 * 325 * Allocate a synth device. Unit is the number of the synth device requested. 326 * Pass -1 to request the next free synth unit. On success the allocated 327 * number is returned, on failure a negative error code is returned. 328 */ 329 330 331int register_sound_synth(struct file_operations *fops, int dev) 332{ 333 return sound_insert_unit(&chains[9], fops, dev, 9, 137, 334 "synth", S_IRUSR | S_IWUSR); 335} 336 337EXPORT_SYMBOL(register_sound_synth); 338 339/** 340 * unregister_sound_special - unregister a special sound device 341 * @unit: unit number to allocate 342 * 343 * Release a sound device that was allocated with 344 * register_sound_special(). The unit passed is the return value from 345 * the register function. 346 */ 347 348 349void unregister_sound_special(int unit) 350{ 351 sound_remove_unit(&chains[unit&15], unit); 352} 353 354EXPORT_SYMBOL(unregister_sound_special); 355 356/** 357 * unregister_sound_mixer - unregister a mixer 358 * @unit: unit number to allocate 359 * 360 * Release a sound device that was allocated with register_sound_mixer(). 361 * The unit passed is the return value from the register function. 362 */ 363 364void unregister_sound_mixer(int unit) 365{ 366 sound_remove_unit(&chains[0], unit); 367} 368 369EXPORT_SYMBOL(unregister_sound_mixer); 370 371/** 372 * unregister_sound_midi - unregister a midi device 373 * @unit: unit number to allocate 374 * 375 * Release a sound device that was allocated with register_sound_midi(). 376 * The unit passed is the return value from the register function. 377 */ 378 379void unregister_sound_midi(int unit) 380{ 381 return sound_remove_unit(&chains[2], unit); 382} 383 384EXPORT_SYMBOL(unregister_sound_midi); 385 386/** 387 * unregister_sound_dsp - unregister a DSP device 388 * @unit: unit number to allocate 389 * 390 * Release a sound device that was allocated with register_sound_dsp(). 391 * The unit passed is the return value from the register function. 392 * 393 * Both of the allocated units are released together automatically. 394 */ 395 396void unregister_sound_dsp(int unit) 397{ 398 return sound_remove_unit(&chains[3], unit); 399} 400 401 402EXPORT_SYMBOL(unregister_sound_dsp); 403 404/** 405 * unregister_sound_synth - unregister a synth device 406 * @unit: unit number to allocate 407 * 408 * Release a sound device that was allocated with register_sound_synth(). 409 * The unit passed is the return value from the register function. 410 */ 411 412void unregister_sound_synth(int unit) 413{ 414 return sound_remove_unit(&chains[9], unit); 415} 416 417EXPORT_SYMBOL(unregister_sound_synth); 418 419/* 420 * Now our file operations 421 */ 422 423static int soundcore_open(struct inode *, struct file *); 424 425static struct file_operations soundcore_fops= 426{ 427 /* We must have an owner or the module locking fails */ 428 owner: THIS_MODULE, 429 open: soundcore_open, 430}; 431 432static struct sound_unit *__look_for_unit(int chain, int unit) 433{ 434 struct sound_unit *s; 435 436 s=chains[chain]; 437 while(s && s->unit_minor <= unit) 438 { 439 if(s->unit_minor==unit) 440 return s; 441 s=s->next; 442 } 443 return NULL; 444} 445 446int soundcore_open(struct inode *inode, struct file *file) 447{ 448 int chain; 449 int unit=MINOR(inode->i_rdev); 450 struct sound_unit *s; 451 struct file_operations *new_fops = NULL; 452 453 chain=unit&0x0F; 454 if(chain==4 || chain==5) /* dsp/audio/dsp16 */ 455 { 456 unit&=0xF0; 457 unit|=3; 458 chain=3; 459 } 460 461 spin_lock(&sound_loader_lock); 462 s = __look_for_unit(chain, unit); 463 if (s) 464 new_fops = fops_get(s->unit_fops); 465 if (!new_fops) { 466 char mod[32]; 467 468 spin_unlock(&sound_loader_lock); 469 /* 470 * Please, don't change this order or code. 471 * For ALSA slot means soundcard and OSS emulation code 472 * comes as add-on modules which aren't depend on 473 * ALSA toplevel modules for soundcards, thus we need 474 * load them at first. [Jaroslav Kysela <perex@jcu.cz>] 475 */ 476 sprintf(mod, "sound-slot-%i", unit>>4); 477 request_module(mod); 478 sprintf(mod, "sound-service-%i-%i", unit>>4, chain); 479 request_module(mod); 480 spin_lock(&sound_loader_lock); 481 s = __look_for_unit(chain, unit); 482 if (s) 483 new_fops = fops_get(s->unit_fops); 484 } 485 if (new_fops) { 486 /* 487 * We rely upon the fact that we can't be unloaded while the 488 * subdriver is there, so if ->open() is successful we can 489 * safely drop the reference counter and if it is not we can 490 * revert to old ->f_op. Ugly, indeed, but that's the cost of 491 * switching ->f_op in the first place. 492 */ 493 int err = 0; 494 struct file_operations *old_fops = file->f_op; 495 file->f_op = new_fops; 496 spin_unlock(&sound_loader_lock); 497 if(file->f_op->open) 498 err = file->f_op->open(inode,file); 499 if (err) { 500 fops_put(file->f_op); 501 file->f_op = fops_get(old_fops); 502 } 503 fops_put(old_fops); 504 return err; 505 } 506 spin_unlock(&sound_loader_lock); 507 return -ENODEV; 508} 509 510extern int mod_firmware_load(const char *, char **); 511EXPORT_SYMBOL(mod_firmware_load); 512 513 514MODULE_DESCRIPTION("Core sound module"); 515MODULE_AUTHOR("Alan Cox"); 516MODULE_LICENSE("GPL"); 517 518static void __exit cleanup_soundcore(void) 519{ 520 /* We have nothing to really do here - we know the lists must be 521 empty */ 522 devfs_unregister_chrdev(SOUND_MAJOR, "sound"); 523 devfs_unregister (devfs_handle); 524} 525 526static int __init init_soundcore(void) 527{ 528 if(devfs_register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops)==-1) 529 { 530 printk(KERN_ERR "soundcore: sound device already in use.\n"); 531 return -EBUSY; 532 } 533 devfs_handle = devfs_mk_dir (NULL, "sound", NULL); 534 535 return 0; 536} 537 538module_init(init_soundcore); 539module_exit(cleanup_soundcore); 540