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