sound: Add module.h to the previously silent sound users
[pandora-kernel.git] / sound / core / oss / mixer_oss.c
1 /*
2  *  OSS emulation layer for the mixer interface
3  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
4  *
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19  *
20  */
21
22 #include <linux/init.h>
23 #include <linux/slab.h>
24 #include <linux/time.h>
25 #include <linux/string.h>
26 #include <linux/module.h>
27 #include <sound/core.h>
28 #include <sound/minors.h>
29 #include <sound/control.h>
30 #include <sound/info.h>
31 #include <sound/mixer_oss.h>
32 #include <linux/soundcard.h>
33
34 #define OSS_ALSAEMULVER         _SIOR ('M', 249, int)
35
36 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
37 MODULE_DESCRIPTION("Mixer OSS emulation for ALSA.");
38 MODULE_LICENSE("GPL");
39 MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MIXER);
40
41 static int snd_mixer_oss_open(struct inode *inode, struct file *file)
42 {
43         struct snd_card *card;
44         struct snd_mixer_oss_file *fmixer;
45         int err;
46
47         err = nonseekable_open(inode, file);
48         if (err < 0)
49                 return err;
50
51         card = snd_lookup_oss_minor_data(iminor(inode),
52                                          SNDRV_OSS_DEVICE_TYPE_MIXER);
53         if (card == NULL)
54                 return -ENODEV;
55         if (card->mixer_oss == NULL)
56                 return -ENODEV;
57         err = snd_card_file_add(card, file);
58         if (err < 0)
59                 return err;
60         fmixer = kzalloc(sizeof(*fmixer), GFP_KERNEL);
61         if (fmixer == NULL) {
62                 snd_card_file_remove(card, file);
63                 return -ENOMEM;
64         }
65         fmixer->card = card;
66         fmixer->mixer = card->mixer_oss;
67         file->private_data = fmixer;
68         if (!try_module_get(card->module)) {
69                 kfree(fmixer);
70                 snd_card_file_remove(card, file);
71                 return -EFAULT;
72         }
73         return 0;
74 }
75
76 static int snd_mixer_oss_release(struct inode *inode, struct file *file)
77 {
78         struct snd_mixer_oss_file *fmixer;
79
80         if (file->private_data) {
81                 fmixer = file->private_data;
82                 module_put(fmixer->card->module);
83                 snd_card_file_remove(fmixer->card, file);
84                 kfree(fmixer);
85         }
86         return 0;
87 }
88
89 static int snd_mixer_oss_info(struct snd_mixer_oss_file *fmixer,
90                               mixer_info __user *_info)
91 {
92         struct snd_card *card = fmixer->card;
93         struct snd_mixer_oss *mixer = fmixer->mixer;
94         struct mixer_info info;
95         
96         memset(&info, 0, sizeof(info));
97         strlcpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
98         strlcpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
99         info.modify_counter = card->mixer_oss_change_count;
100         if (copy_to_user(_info, &info, sizeof(info)))
101                 return -EFAULT;
102         return 0;
103 }
104
105 static int snd_mixer_oss_info_obsolete(struct snd_mixer_oss_file *fmixer,
106                                        _old_mixer_info __user *_info)
107 {
108         struct snd_card *card = fmixer->card;
109         struct snd_mixer_oss *mixer = fmixer->mixer;
110         _old_mixer_info info;
111         
112         memset(&info, 0, sizeof(info));
113         strlcpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
114         strlcpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
115         if (copy_to_user(_info, &info, sizeof(info)))
116                 return -EFAULT;
117         return 0;
118 }
119
120 static int snd_mixer_oss_caps(struct snd_mixer_oss_file *fmixer)
121 {
122         struct snd_mixer_oss *mixer = fmixer->mixer;
123         int result = 0;
124
125         if (mixer == NULL)
126                 return -EIO;
127         if (mixer->get_recsrc && mixer->put_recsrc)
128                 result |= SOUND_CAP_EXCL_INPUT;
129         return result;
130 }
131
132 static int snd_mixer_oss_devmask(struct snd_mixer_oss_file *fmixer)
133 {
134         struct snd_mixer_oss *mixer = fmixer->mixer;
135         struct snd_mixer_oss_slot *pslot;
136         int result = 0, chn;
137
138         if (mixer == NULL)
139                 return -EIO;
140         for (chn = 0; chn < 31; chn++) {
141                 pslot = &mixer->slots[chn];
142                 if (pslot->put_volume || pslot->put_recsrc)
143                         result |= 1 << chn;
144         }
145         return result;
146 }
147
148 static int snd_mixer_oss_stereodevs(struct snd_mixer_oss_file *fmixer)
149 {
150         struct snd_mixer_oss *mixer = fmixer->mixer;
151         struct snd_mixer_oss_slot *pslot;
152         int result = 0, chn;
153
154         if (mixer == NULL)
155                 return -EIO;
156         for (chn = 0; chn < 31; chn++) {
157                 pslot = &mixer->slots[chn];
158                 if (pslot->put_volume && pslot->stereo)
159                         result |= 1 << chn;
160         }
161         return result;
162 }
163
164 static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer)
165 {
166         struct snd_mixer_oss *mixer = fmixer->mixer;
167         int result = 0;
168
169         if (mixer == NULL)
170                 return -EIO;
171         if (mixer->put_recsrc && mixer->get_recsrc) {   /* exclusive */
172                 result = mixer->mask_recsrc;
173         } else {
174                 struct snd_mixer_oss_slot *pslot;
175                 int chn;
176                 for (chn = 0; chn < 31; chn++) {
177                         pslot = &mixer->slots[chn];
178                         if (pslot->put_recsrc)
179                                 result |= 1 << chn;
180                 }
181         }
182         return result;
183 }
184
185 static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
186 {
187         struct snd_mixer_oss *mixer = fmixer->mixer;
188         int result = 0;
189
190         if (mixer == NULL)
191                 return -EIO;
192         if (mixer->put_recsrc && mixer->get_recsrc) {   /* exclusive */
193                 int err;
194                 unsigned int index;
195                 if ((err = mixer->get_recsrc(fmixer, &index)) < 0)
196                         return err;
197                 result = 1 << index;
198         } else {
199                 struct snd_mixer_oss_slot *pslot;
200                 int chn;
201                 for (chn = 0; chn < 31; chn++) {
202                         pslot = &mixer->slots[chn];
203                         if (pslot->get_recsrc) {
204                                 int active = 0;
205                                 pslot->get_recsrc(fmixer, pslot, &active);
206                                 if (active)
207                                         result |= 1 << chn;
208                         }
209                 }
210         }
211         return mixer->oss_recsrc = result;
212 }
213
214 static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsrc)
215 {
216         struct snd_mixer_oss *mixer = fmixer->mixer;
217         struct snd_mixer_oss_slot *pslot;
218         int chn, active;
219         unsigned int index;
220         int result = 0;
221
222         if (mixer == NULL)
223                 return -EIO;
224         if (mixer->get_recsrc && mixer->put_recsrc) {   /* exclusive input */
225                 if (recsrc & ~mixer->oss_recsrc)
226                         recsrc &= ~mixer->oss_recsrc;
227                 mixer->put_recsrc(fmixer, ffz(~recsrc));
228                 mixer->get_recsrc(fmixer, &index);
229                 result = 1 << index;
230         }
231         for (chn = 0; chn < 31; chn++) {
232                 pslot = &mixer->slots[chn];
233                 if (pslot->put_recsrc) {
234                         active = (recsrc & (1 << chn)) ? 1 : 0;
235                         pslot->put_recsrc(fmixer, pslot, active);
236                 }
237         }
238         if (! result) {
239                 for (chn = 0; chn < 31; chn++) {
240                         pslot = &mixer->slots[chn];
241                         if (pslot->get_recsrc) {
242                                 active = 0;
243                                 pslot->get_recsrc(fmixer, pslot, &active);
244                                 if (active)
245                                         result |= 1 << chn;
246                         }
247                 }
248         }
249         return result;
250 }
251
252 static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
253 {
254         struct snd_mixer_oss *mixer = fmixer->mixer;
255         struct snd_mixer_oss_slot *pslot;
256         int result = 0, left, right;
257
258         if (mixer == NULL || slot > 30)
259                 return -EIO;
260         pslot = &mixer->slots[slot];
261         left = pslot->volume[0];
262         right = pslot->volume[1];
263         if (pslot->get_volume)
264                 result = pslot->get_volume(fmixer, pslot, &left, &right);
265         if (!pslot->stereo)
266                 right = left;
267         if (snd_BUG_ON(left < 0 || left > 100))
268                 return -EIO;
269         if (snd_BUG_ON(right < 0 || right > 100))
270                 return -EIO;
271         if (result >= 0) {
272                 pslot->volume[0] = left;
273                 pslot->volume[1] = right;
274                 result = (left & 0xff) | ((right & 0xff) << 8);
275         }
276         return result;
277 }
278
279 static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
280                                     int slot, int volume)
281 {
282         struct snd_mixer_oss *mixer = fmixer->mixer;
283         struct snd_mixer_oss_slot *pslot;
284         int result = 0, left = volume & 0xff, right = (volume >> 8) & 0xff;
285
286         if (mixer == NULL || slot > 30)
287                 return -EIO;
288         pslot = &mixer->slots[slot];
289         if (left > 100)
290                 left = 100;
291         if (right > 100)
292                 right = 100;
293         if (!pslot->stereo)
294                 right = left;
295         if (pslot->put_volume)
296                 result = pslot->put_volume(fmixer, pslot, left, right);
297         if (result < 0)
298                 return result;
299         pslot->volume[0] = left;
300         pslot->volume[1] = right;
301         return (left & 0xff) | ((right & 0xff) << 8);
302 }
303
304 static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int cmd, unsigned long arg)
305 {
306         void __user *argp = (void __user *)arg;
307         int __user *p = argp;
308         int tmp;
309
310         if (snd_BUG_ON(!fmixer))
311                 return -ENXIO;
312         if (((cmd >> 8) & 0xff) == 'M') {
313                 switch (cmd) {
314                 case SOUND_MIXER_INFO:
315                         return snd_mixer_oss_info(fmixer, argp);
316                 case SOUND_OLD_MIXER_INFO:
317                         return snd_mixer_oss_info_obsolete(fmixer, argp);
318                 case SOUND_MIXER_WRITE_RECSRC:
319                         if (get_user(tmp, p))
320                                 return -EFAULT;
321                         tmp = snd_mixer_oss_set_recsrc(fmixer, tmp);
322                         if (tmp < 0)
323                                 return tmp;
324                         return put_user(tmp, p);
325                 case OSS_GETVERSION:
326                         return put_user(SNDRV_OSS_VERSION, p);
327                 case OSS_ALSAEMULVER:
328                         return put_user(1, p);
329                 case SOUND_MIXER_READ_DEVMASK:
330                         tmp = snd_mixer_oss_devmask(fmixer);
331                         if (tmp < 0)
332                                 return tmp;
333                         return put_user(tmp, p);
334                 case SOUND_MIXER_READ_STEREODEVS:
335                         tmp = snd_mixer_oss_stereodevs(fmixer);
336                         if (tmp < 0)
337                                 return tmp;
338                         return put_user(tmp, p);
339                 case SOUND_MIXER_READ_RECMASK:
340                         tmp = snd_mixer_oss_recmask(fmixer);
341                         if (tmp < 0)
342                                 return tmp;
343                         return put_user(tmp, p);
344                 case SOUND_MIXER_READ_CAPS:
345                         tmp = snd_mixer_oss_caps(fmixer);
346                         if (tmp < 0)
347                                 return tmp;
348                         return put_user(tmp, p);
349                 case SOUND_MIXER_READ_RECSRC:
350                         tmp = snd_mixer_oss_get_recsrc(fmixer);
351                         if (tmp < 0)
352                                 return tmp;
353                         return put_user(tmp, p);
354                 }
355         }
356         if (cmd & SIOC_IN) {
357                 if (get_user(tmp, p))
358                         return -EFAULT;
359                 tmp = snd_mixer_oss_set_volume(fmixer, cmd & 0xff, tmp);
360                 if (tmp < 0)
361                         return tmp;
362                 return put_user(tmp, p);
363         } else if (cmd & SIOC_OUT) {
364                 tmp = snd_mixer_oss_get_volume(fmixer, cmd & 0xff);
365                 if (tmp < 0)
366                         return tmp;
367                 return put_user(tmp, p);
368         }
369         return -ENXIO;
370 }
371
372 static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
373 {
374         return snd_mixer_oss_ioctl1(file->private_data, cmd, arg);
375 }
376
377 int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg)
378 {
379         struct snd_mixer_oss_file fmixer;
380         
381         if (snd_BUG_ON(!card))
382                 return -ENXIO;
383         if (card->mixer_oss == NULL)
384                 return -ENXIO;
385         memset(&fmixer, 0, sizeof(fmixer));
386         fmixer.card = card;
387         fmixer.mixer = card->mixer_oss;
388         return snd_mixer_oss_ioctl1(&fmixer, cmd, arg);
389 }
390
391 #ifdef CONFIG_COMPAT
392 /* all compatible */
393 #define snd_mixer_oss_ioctl_compat      snd_mixer_oss_ioctl
394 #else
395 #define snd_mixer_oss_ioctl_compat      NULL
396 #endif
397
398 /*
399  *  REGISTRATION PART
400  */
401
402 static const struct file_operations snd_mixer_oss_f_ops =
403 {
404         .owner =        THIS_MODULE,
405         .open =         snd_mixer_oss_open,
406         .release =      snd_mixer_oss_release,
407         .llseek =       no_llseek,
408         .unlocked_ioctl =       snd_mixer_oss_ioctl,
409         .compat_ioctl = snd_mixer_oss_ioctl_compat,
410 };
411
412 /*
413  *  utilities
414  */
415
416 static long snd_mixer_oss_conv(long val, long omin, long omax, long nmin, long nmax)
417 {
418         long orange = omax - omin, nrange = nmax - nmin;
419         
420         if (orange == 0)
421                 return 0;
422         return ((nrange * (val - omin)) + (orange / 2)) / orange + nmin;
423 }
424
425 /* convert from alsa native to oss values (0-100) */
426 static long snd_mixer_oss_conv1(long val, long min, long max, int *old)
427 {
428         if (val == snd_mixer_oss_conv(*old, 0, 100, min, max))
429                 return *old;
430         return snd_mixer_oss_conv(val, min, max, 0, 100);
431 }
432
433 /* convert from oss to alsa native values */
434 static long snd_mixer_oss_conv2(long val, long min, long max)
435 {
436         return snd_mixer_oss_conv(val, 0, 100, min, max);
437 }
438
439 #if 0
440 static void snd_mixer_oss_recsrce_set(struct snd_card *card, int slot)
441 {
442         struct snd_mixer_oss *mixer = card->mixer_oss;
443         if (mixer)
444                 mixer->mask_recsrc |= 1 << slot;
445 }
446
447 static int snd_mixer_oss_recsrce_get(struct snd_card *card, int slot)
448 {
449         struct snd_mixer_oss *mixer = card->mixer_oss;
450         if (mixer && (mixer->mask_recsrc & (1 << slot)))
451                 return 1;
452         return 0;
453 }
454 #endif
455
456 #define SNDRV_MIXER_OSS_SIGNATURE               0x65999250
457
458 #define SNDRV_MIXER_OSS_ITEM_GLOBAL     0
459 #define SNDRV_MIXER_OSS_ITEM_GSWITCH    1
460 #define SNDRV_MIXER_OSS_ITEM_GROUTE     2
461 #define SNDRV_MIXER_OSS_ITEM_GVOLUME    3
462 #define SNDRV_MIXER_OSS_ITEM_PSWITCH    4
463 #define SNDRV_MIXER_OSS_ITEM_PROUTE     5
464 #define SNDRV_MIXER_OSS_ITEM_PVOLUME    6
465 #define SNDRV_MIXER_OSS_ITEM_CSWITCH    7
466 #define SNDRV_MIXER_OSS_ITEM_CROUTE     8
467 #define SNDRV_MIXER_OSS_ITEM_CVOLUME    9
468 #define SNDRV_MIXER_OSS_ITEM_CAPTURE    10
469
470 #define SNDRV_MIXER_OSS_ITEM_COUNT      11
471
472 #define SNDRV_MIXER_OSS_PRESENT_GLOBAL  (1<<0)
473 #define SNDRV_MIXER_OSS_PRESENT_GSWITCH (1<<1)
474 #define SNDRV_MIXER_OSS_PRESENT_GROUTE  (1<<2)
475 #define SNDRV_MIXER_OSS_PRESENT_GVOLUME (1<<3)
476 #define SNDRV_MIXER_OSS_PRESENT_PSWITCH (1<<4)
477 #define SNDRV_MIXER_OSS_PRESENT_PROUTE  (1<<5)
478 #define SNDRV_MIXER_OSS_PRESENT_PVOLUME (1<<6)
479 #define SNDRV_MIXER_OSS_PRESENT_CSWITCH (1<<7)
480 #define SNDRV_MIXER_OSS_PRESENT_CROUTE  (1<<8)
481 #define SNDRV_MIXER_OSS_PRESENT_CVOLUME (1<<9)
482 #define SNDRV_MIXER_OSS_PRESENT_CAPTURE (1<<10)
483
484 struct slot {
485         unsigned int signature;
486         unsigned int present;
487         unsigned int channels;
488         unsigned int numid[SNDRV_MIXER_OSS_ITEM_COUNT];
489         unsigned int capture_item;
490         struct snd_mixer_oss_assign_table *assigned;
491         unsigned int allocated: 1;
492 };
493
494 #define ID_UNKNOWN      ((unsigned int)-1)
495
496 static struct snd_kcontrol *snd_mixer_oss_test_id(struct snd_mixer_oss *mixer, const char *name, int index)
497 {
498         struct snd_card *card = mixer->card;
499         struct snd_ctl_elem_id id;
500         
501         memset(&id, 0, sizeof(id));
502         id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
503         strlcpy(id.name, name, sizeof(id.name));
504         id.index = index;
505         return snd_ctl_find_id(card, &id);
506 }
507
508 static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer,
509                                           struct snd_mixer_oss_slot *pslot,
510                                           unsigned int numid,
511                                           int *left, int *right)
512 {
513         struct snd_ctl_elem_info *uinfo;
514         struct snd_ctl_elem_value *uctl;
515         struct snd_kcontrol *kctl;
516         struct snd_card *card = fmixer->card;
517
518         if (numid == ID_UNKNOWN)
519                 return;
520         down_read(&card->controls_rwsem);
521         if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
522                 up_read(&card->controls_rwsem);
523                 return;
524         }
525         uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
526         uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
527         if (uinfo == NULL || uctl == NULL)
528                 goto __unalloc;
529         if (kctl->info(kctl, uinfo))
530                 goto __unalloc;
531         if (kctl->get(kctl, uctl))
532                 goto __unalloc;
533         if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
534             uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
535                 goto __unalloc;
536         *left = snd_mixer_oss_conv1(uctl->value.integer.value[0], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[0]);
537         if (uinfo->count > 1)
538                 *right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]);
539       __unalloc:
540         up_read(&card->controls_rwsem);
541         kfree(uctl);
542         kfree(uinfo);
543 }
544
545 static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
546                                          struct snd_mixer_oss_slot *pslot,
547                                          unsigned int numid,
548                                          int *left, int *right,
549                                          int route)
550 {
551         struct snd_ctl_elem_info *uinfo;
552         struct snd_ctl_elem_value *uctl;
553         struct snd_kcontrol *kctl;
554         struct snd_card *card = fmixer->card;
555
556         if (numid == ID_UNKNOWN)
557                 return;
558         down_read(&card->controls_rwsem);
559         if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
560                 up_read(&card->controls_rwsem);
561                 return;
562         }
563         uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
564         uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
565         if (uinfo == NULL || uctl == NULL)
566                 goto __unalloc;
567         if (kctl->info(kctl, uinfo))
568                 goto __unalloc;
569         if (kctl->get(kctl, uctl))
570                 goto __unalloc;
571         if (!uctl->value.integer.value[0]) {
572                 *left = 0;
573                 if (uinfo->count == 1)
574                         *right = 0;
575         }
576         if (uinfo->count > 1 && !uctl->value.integer.value[route ? 3 : 1])
577                 *right = 0;
578       __unalloc:
579         up_read(&card->controls_rwsem);
580         kfree(uctl);
581         kfree(uinfo);
582 }
583
584 static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer,
585                                      struct snd_mixer_oss_slot *pslot,
586                                      int *left, int *right)
587 {
588         struct slot *slot = pslot->private_data;
589         
590         *left = *right = 100;
591         if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
592                 snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
593         } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) {
594                 snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right);
595         } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) {
596                 snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right);
597         }
598         if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) {
599                 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0);
600         } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) {
601                 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0);
602         } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) {
603                 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1);
604         } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) {
605                 snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1);
606         }
607         return 0;
608 }
609
610 static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
611                                           struct snd_mixer_oss_slot *pslot,
612                                           unsigned int numid,
613                                           int left, int right)
614 {
615         struct snd_ctl_elem_info *uinfo;
616         struct snd_ctl_elem_value *uctl;
617         struct snd_kcontrol *kctl;
618         struct snd_card *card = fmixer->card;
619         int res;
620
621         if (numid == ID_UNKNOWN)
622                 return;
623         down_read(&card->controls_rwsem);
624         if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
625                 up_read(&card->controls_rwsem);
626                 return;
627         }
628         uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
629         uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
630         if (uinfo == NULL || uctl == NULL)
631                 goto __unalloc;
632         if (kctl->info(kctl, uinfo))
633                 goto __unalloc;
634         if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
635             uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
636                 goto __unalloc;
637         uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max);
638         if (uinfo->count > 1)
639                 uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max);
640         if ((res = kctl->put(kctl, uctl)) < 0)
641                 goto __unalloc;
642         if (res > 0)
643                 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
644       __unalloc:
645         up_read(&card->controls_rwsem);
646         kfree(uctl);
647         kfree(uinfo);
648 }
649
650 static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
651                                          struct snd_mixer_oss_slot *pslot,
652                                          unsigned int numid,
653                                          int left, int right,
654                                          int route)
655 {
656         struct snd_ctl_elem_info *uinfo;
657         struct snd_ctl_elem_value *uctl;
658         struct snd_kcontrol *kctl;
659         struct snd_card *card = fmixer->card;
660         int res;
661
662         if (numid == ID_UNKNOWN)
663                 return;
664         down_read(&card->controls_rwsem);
665         if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
666                 up_read(&card->controls_rwsem);
667                 return;
668         }
669         uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
670         uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
671         if (uinfo == NULL || uctl == NULL)
672                 goto __unalloc;
673         if (kctl->info(kctl, uinfo))
674                 goto __unalloc;
675         if (uinfo->count > 1) {
676                 uctl->value.integer.value[0] = left > 0 ? 1 : 0;
677                 uctl->value.integer.value[route ? 3 : 1] = right > 0 ? 1 : 0;
678                 if (route) {
679                         uctl->value.integer.value[1] =
680                         uctl->value.integer.value[2] = 0;
681                 }
682         } else {
683                 uctl->value.integer.value[0] = (left > 0 || right > 0) ? 1 : 0;
684         }
685         if ((res = kctl->put(kctl, uctl)) < 0)
686                 goto __unalloc;
687         if (res > 0)
688                 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
689       __unalloc:
690         up_read(&card->controls_rwsem);
691         kfree(uctl);
692         kfree(uinfo);
693 }
694
695 static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer,
696                                      struct snd_mixer_oss_slot *pslot,
697                                      int left, int right)
698 {
699         struct slot *slot = pslot->private_data;
700         
701         if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
702                 snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
703                 if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME)
704                         snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right);
705         } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME) {
706                 snd_mixer_oss_put_volume1_vol(fmixer, pslot,
707                         slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right);
708         } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) {
709                 snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right);
710         } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) {
711                 snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right);
712         }
713         if (left || right) {
714                 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH)
715                         snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0);
716                 if (slot->present & SNDRV_MIXER_OSS_PRESENT_CSWITCH)
717                         snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], left, right, 0);
718                 if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH)
719                         snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0);
720                 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE)
721                         snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1);
722                 if (slot->present & SNDRV_MIXER_OSS_PRESENT_CROUTE)
723                         snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], left, right, 1);
724                 if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE)
725                         snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1);
726         } else {
727                 if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) {
728                         snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0);
729                 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CSWITCH) {
730                         snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], left, right, 0);
731                 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) {
732                         snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0);
733                 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) {
734                         snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1);
735                 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CROUTE) {
736                         snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], left, right, 1);
737                 } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) {
738                         snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1);
739                 }
740         }
741         return 0;
742 }
743
744 static int snd_mixer_oss_get_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
745                                         struct snd_mixer_oss_slot *pslot,
746                                         int *active)
747 {
748         struct slot *slot = pslot->private_data;
749         int left, right;
750         
751         left = right = 1;
752         snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], &left, &right, 0);
753         *active = (left || right) ? 1 : 0;
754         return 0;
755 }
756
757 static int snd_mixer_oss_get_recsrc1_route(struct snd_mixer_oss_file *fmixer,
758                                            struct snd_mixer_oss_slot *pslot,
759                                            int *active)
760 {
761         struct slot *slot = pslot->private_data;
762         int left, right;
763         
764         left = right = 1;
765         snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], &left, &right, 1);
766         *active = (left || right) ? 1 : 0;
767         return 0;
768 }
769
770 static int snd_mixer_oss_put_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
771                                         struct snd_mixer_oss_slot *pslot,
772                                         int active)
773 {
774         struct slot *slot = pslot->private_data;
775         
776         snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0);
777         return 0;
778 }
779
780 static int snd_mixer_oss_put_recsrc1_route(struct snd_mixer_oss_file *fmixer,
781                                            struct snd_mixer_oss_slot *pslot,
782                                            int active)
783 {
784         struct slot *slot = pslot->private_data;
785         
786         snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1);
787         return 0;
788 }
789
790 static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int *active_index)
791 {
792         struct snd_card *card = fmixer->card;
793         struct snd_mixer_oss *mixer = fmixer->mixer;
794         struct snd_kcontrol *kctl;
795         struct snd_mixer_oss_slot *pslot;
796         struct slot *slot;
797         struct snd_ctl_elem_info *uinfo;
798         struct snd_ctl_elem_value *uctl;
799         int err, idx;
800         
801         uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
802         uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
803         if (uinfo == NULL || uctl == NULL) {
804                 err = -ENOMEM;
805                 goto __free_only;
806         }
807         down_read(&card->controls_rwsem);
808         kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
809         if (! kctl) {
810                 err = -ENOENT;
811                 goto __unlock;
812         }
813         if ((err = kctl->info(kctl, uinfo)) < 0)
814                 goto __unlock;
815         if ((err = kctl->get(kctl, uctl)) < 0)
816                 goto __unlock;
817         for (idx = 0; idx < 32; idx++) {
818                 if (!(mixer->mask_recsrc & (1 << idx)))
819                         continue;
820                 pslot = &mixer->slots[idx];
821                 slot = pslot->private_data;
822                 if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
823                         continue;
824                 if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
825                         continue;
826                 if (slot->capture_item == uctl->value.enumerated.item[0]) {
827                         *active_index = idx;
828                         break;
829                 }
830         }
831         err = 0;
832       __unlock:
833         up_read(&card->controls_rwsem);
834       __free_only:
835         kfree(uctl);
836         kfree(uinfo);
837         return err;
838 }
839
840 static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int active_index)
841 {
842         struct snd_card *card = fmixer->card;
843         struct snd_mixer_oss *mixer = fmixer->mixer;
844         struct snd_kcontrol *kctl;
845         struct snd_mixer_oss_slot *pslot;
846         struct slot *slot = NULL;
847         struct snd_ctl_elem_info *uinfo;
848         struct snd_ctl_elem_value *uctl;
849         int err;
850         unsigned int idx;
851
852         uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
853         uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
854         if (uinfo == NULL || uctl == NULL) {
855                 err = -ENOMEM;
856                 goto __free_only;
857         }
858         down_read(&card->controls_rwsem);
859         kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
860         if (! kctl) {
861                 err = -ENOENT;
862                 goto __unlock;
863         }
864         if ((err = kctl->info(kctl, uinfo)) < 0)
865                 goto __unlock;
866         for (idx = 0; idx < 32; idx++) {
867                 if (!(mixer->mask_recsrc & (1 << idx)))
868                         continue;
869                 pslot = &mixer->slots[idx];
870                 slot = pslot->private_data;
871                 if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
872                         continue;
873                 if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
874                         continue;
875                 if (idx == active_index)
876                         break;
877                 slot = NULL;
878         }
879         if (! slot)
880                 goto __unlock;
881         for (idx = 0; idx < uinfo->count; idx++)
882                 uctl->value.enumerated.item[idx] = slot->capture_item;
883         err = kctl->put(kctl, uctl);
884         if (err > 0)
885                 snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
886         err = 0;
887       __unlock:
888         up_read(&card->controls_rwsem);
889       __free_only:
890         kfree(uctl);
891         kfree(uinfo);
892         return err;
893 }
894
895 struct snd_mixer_oss_assign_table {
896         int oss_id;
897         const char *name;
898         int index;
899 };
900
901 static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *slot, const char *name, int index, int item)
902 {
903         struct snd_ctl_elem_info *info;
904         struct snd_kcontrol *kcontrol;
905         struct snd_card *card = mixer->card;
906         int err;
907
908         down_read(&card->controls_rwsem);
909         kcontrol = snd_mixer_oss_test_id(mixer, name, index);
910         if (kcontrol == NULL) {
911                 up_read(&card->controls_rwsem);
912                 return 0;
913         }
914         info = kmalloc(sizeof(*info), GFP_KERNEL);
915         if (! info) {
916                 up_read(&card->controls_rwsem);
917                 return -ENOMEM;
918         }
919         if ((err = kcontrol->info(kcontrol, info)) < 0) {
920                 up_read(&card->controls_rwsem);
921                 kfree(info);
922                 return err;
923         }
924         slot->numid[item] = kcontrol->id.numid;
925         up_read(&card->controls_rwsem);
926         if (info->count > slot->channels)
927                 slot->channels = info->count;
928         slot->present |= 1 << item;
929         kfree(info);
930         return 0;
931 }
932
933 static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn)
934 {
935         struct slot *p = chn->private_data;
936         if (p) {
937                 if (p->allocated && p->assigned) {
938                         kfree(p->assigned->name);
939                         kfree(p->assigned);
940                 }
941                 kfree(p);
942         }
943 }
944
945 static void mixer_slot_clear(struct snd_mixer_oss_slot *rslot)
946 {
947         int idx = rslot->number; /* remember this */
948         if (rslot->private_free)
949                 rslot->private_free(rslot);
950         memset(rslot, 0, sizeof(*rslot));
951         rslot->number = idx;
952 }
953
954 /* In a separate function to keep gcc 3.2 happy - do NOT merge this in
955    snd_mixer_oss_build_input! */
956 static int snd_mixer_oss_build_test_all(struct snd_mixer_oss *mixer,
957                                         struct snd_mixer_oss_assign_table *ptr,
958                                         struct slot *slot)
959 {
960         char str[64];
961         int err;
962
963         err = snd_mixer_oss_build_test(mixer, slot, ptr->name, ptr->index,
964                                        SNDRV_MIXER_OSS_ITEM_GLOBAL);
965         if (err)
966                 return err;
967         sprintf(str, "%s Switch", ptr->name);
968         err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
969                                        SNDRV_MIXER_OSS_ITEM_GSWITCH);
970         if (err)
971                 return err;
972         sprintf(str, "%s Route", ptr->name);
973         err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
974                                        SNDRV_MIXER_OSS_ITEM_GROUTE);
975         if (err)
976                 return err;
977         sprintf(str, "%s Volume", ptr->name);
978         err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
979                                        SNDRV_MIXER_OSS_ITEM_GVOLUME);
980         if (err)
981                 return err;
982         sprintf(str, "%s Playback Switch", ptr->name);
983         err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
984                                        SNDRV_MIXER_OSS_ITEM_PSWITCH);
985         if (err)
986                 return err;
987         sprintf(str, "%s Playback Route", ptr->name);
988         err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
989                                        SNDRV_MIXER_OSS_ITEM_PROUTE);
990         if (err)
991                 return err;
992         sprintf(str, "%s Playback Volume", ptr->name);
993         err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
994                                        SNDRV_MIXER_OSS_ITEM_PVOLUME);
995         if (err)
996                 return err;
997         sprintf(str, "%s Capture Switch", ptr->name);
998         err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
999                                        SNDRV_MIXER_OSS_ITEM_CSWITCH);
1000         if (err)
1001                 return err;
1002         sprintf(str, "%s Capture Route", ptr->name);
1003         err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
1004                                        SNDRV_MIXER_OSS_ITEM_CROUTE);
1005         if (err)
1006                 return err;
1007         sprintf(str, "%s Capture Volume", ptr->name);
1008         err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
1009                                        SNDRV_MIXER_OSS_ITEM_CVOLUME);
1010         if (err)
1011                 return err;
1012
1013         return 0;
1014 }
1015
1016 /*
1017  * build an OSS mixer element.
1018  * ptr_allocated means the entry is dynamically allocated (change via proc file).
1019  * when replace_old = 1, the old entry is replaced with the new one.
1020  */
1021 static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_mixer_oss_assign_table *ptr, int ptr_allocated, int replace_old)
1022 {
1023         struct slot slot;
1024         struct slot *pslot;
1025         struct snd_kcontrol *kctl;
1026         struct snd_mixer_oss_slot *rslot;
1027         char str[64];   
1028         
1029         /* check if already assigned */
1030         if (mixer->slots[ptr->oss_id].get_volume && ! replace_old)
1031                 return 0;
1032
1033         memset(&slot, 0, sizeof(slot));
1034         memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */
1035         if (snd_mixer_oss_build_test_all(mixer, ptr, &slot))
1036                 return 0;
1037         down_read(&mixer->card->controls_rwsem);
1038         if (ptr->index == 0 && (kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0)) != NULL) {
1039                 struct snd_ctl_elem_info *uinfo;
1040
1041                 uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
1042                 if (! uinfo) {
1043                         up_read(&mixer->card->controls_rwsem);
1044                         return -ENOMEM;
1045                 }
1046                         
1047                 if (kctl->info(kctl, uinfo)) {
1048                         up_read(&mixer->card->controls_rwsem);
1049                         return 0;
1050                 }
1051                 strcpy(str, ptr->name);
1052                 if (!strcmp(str, "Master"))
1053                         strcpy(str, "Mix");
1054                 if (!strcmp(str, "Master Mono"))
1055                         strcpy(str, "Mix Mono");
1056                 slot.capture_item = 0;
1057                 if (!strcmp(uinfo->value.enumerated.name, str)) {
1058                         slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
1059                 } else {
1060                         for (slot.capture_item = 1; slot.capture_item < uinfo->value.enumerated.items; slot.capture_item++) {
1061                                 uinfo->value.enumerated.item = slot.capture_item;
1062                                 if (kctl->info(kctl, uinfo)) {
1063                                         up_read(&mixer->card->controls_rwsem);
1064                                         return 0;
1065                                 }
1066                                 if (!strcmp(uinfo->value.enumerated.name, str)) {
1067                                         slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
1068                                         break;
1069                                 }
1070                         }
1071                 }
1072                 kfree(uinfo);
1073         }
1074         up_read(&mixer->card->controls_rwsem);
1075         if (slot.present != 0) {
1076                 pslot = kmalloc(sizeof(slot), GFP_KERNEL);
1077                 if (! pslot)
1078                         return -ENOMEM;
1079                 *pslot = slot;
1080                 pslot->signature = SNDRV_MIXER_OSS_SIGNATURE;
1081                 pslot->assigned = ptr;
1082                 pslot->allocated = ptr_allocated;
1083                 rslot = &mixer->slots[ptr->oss_id];
1084                 mixer_slot_clear(rslot);
1085                 rslot->stereo = slot.channels > 1 ? 1 : 0;
1086                 rslot->get_volume = snd_mixer_oss_get_volume1;
1087                 rslot->put_volume = snd_mixer_oss_put_volume1;
1088                 /* note: ES18xx have both Capture Source and XX Capture Volume !!! */
1089                 if (slot.present & SNDRV_MIXER_OSS_PRESENT_CSWITCH) {
1090                         rslot->get_recsrc = snd_mixer_oss_get_recsrc1_sw;
1091                         rslot->put_recsrc = snd_mixer_oss_put_recsrc1_sw;
1092                 } else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CROUTE) {
1093                         rslot->get_recsrc = snd_mixer_oss_get_recsrc1_route;
1094                         rslot->put_recsrc = snd_mixer_oss_put_recsrc1_route;
1095                 } else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CAPTURE) {
1096                         mixer->mask_recsrc |= 1 << ptr->oss_id;
1097                 }
1098                 rslot->private_data = pslot;
1099                 rslot->private_free = snd_mixer_oss_slot_free;
1100                 return 1;
1101         }
1102         return 0;
1103 }
1104
1105 #ifdef CONFIG_PROC_FS
1106 /*
1107  */
1108 #define MIXER_VOL(name) [SOUND_MIXER_##name] = #name
1109 static char *oss_mixer_names[SNDRV_OSS_MAX_MIXERS] = {
1110         MIXER_VOL(VOLUME),
1111         MIXER_VOL(BASS),
1112         MIXER_VOL(TREBLE),
1113         MIXER_VOL(SYNTH),
1114         MIXER_VOL(PCM),
1115         MIXER_VOL(SPEAKER),
1116         MIXER_VOL(LINE),
1117         MIXER_VOL(MIC),
1118         MIXER_VOL(CD),
1119         MIXER_VOL(IMIX),
1120         MIXER_VOL(ALTPCM),
1121         MIXER_VOL(RECLEV),
1122         MIXER_VOL(IGAIN),
1123         MIXER_VOL(OGAIN),
1124         MIXER_VOL(LINE1),
1125         MIXER_VOL(LINE2),
1126         MIXER_VOL(LINE3),
1127         MIXER_VOL(DIGITAL1),
1128         MIXER_VOL(DIGITAL2),
1129         MIXER_VOL(DIGITAL3),
1130         MIXER_VOL(PHONEIN),
1131         MIXER_VOL(PHONEOUT),
1132         MIXER_VOL(VIDEO),
1133         MIXER_VOL(RADIO),
1134         MIXER_VOL(MONITOR),
1135 };
1136         
1137 /*
1138  *  /proc interface
1139  */
1140
1141 static void snd_mixer_oss_proc_read(struct snd_info_entry *entry,
1142                                     struct snd_info_buffer *buffer)
1143 {
1144         struct snd_mixer_oss *mixer = entry->private_data;
1145         int i;
1146
1147         mutex_lock(&mixer->reg_mutex);
1148         for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) {
1149                 struct slot *p;
1150
1151                 if (! oss_mixer_names[i])
1152                         continue;
1153                 p = (struct slot *)mixer->slots[i].private_data;
1154                 snd_iprintf(buffer, "%s ", oss_mixer_names[i]);
1155                 if (p && p->assigned)
1156                         snd_iprintf(buffer, "\"%s\" %d\n",
1157                                     p->assigned->name,
1158                                     p->assigned->index);
1159                 else
1160                         snd_iprintf(buffer, "\"\" 0\n");
1161         }
1162         mutex_unlock(&mixer->reg_mutex);
1163 }
1164
1165 static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
1166                                      struct snd_info_buffer *buffer)
1167 {
1168         struct snd_mixer_oss *mixer = entry->private_data;
1169         char line[128], str[32], idxstr[16];
1170         const char *cptr;
1171         int ch, idx;
1172         struct snd_mixer_oss_assign_table *tbl;
1173         struct slot *slot;
1174
1175         while (!snd_info_get_line(buffer, line, sizeof(line))) {
1176                 cptr = snd_info_get_str(str, line, sizeof(str));
1177                 for (ch = 0; ch < SNDRV_OSS_MAX_MIXERS; ch++)
1178                         if (oss_mixer_names[ch] && strcmp(oss_mixer_names[ch], str) == 0)
1179                                 break;
1180                 if (ch >= SNDRV_OSS_MAX_MIXERS) {
1181                         snd_printk(KERN_ERR "mixer_oss: invalid OSS volume '%s'\n", str);
1182                         continue;
1183                 }
1184                 cptr = snd_info_get_str(str, cptr, sizeof(str));
1185                 if (! *str) {
1186                         /* remove the entry */
1187                         mutex_lock(&mixer->reg_mutex);
1188                         mixer_slot_clear(&mixer->slots[ch]);
1189                         mutex_unlock(&mixer->reg_mutex);
1190                         continue;
1191                 }
1192                 snd_info_get_str(idxstr, cptr, sizeof(idxstr));
1193                 idx = simple_strtoul(idxstr, NULL, 10);
1194                 if (idx >= 0x4000) { /* too big */
1195                         snd_printk(KERN_ERR "mixer_oss: invalid index %d\n", idx);
1196                         continue;
1197                 }
1198                 mutex_lock(&mixer->reg_mutex);
1199                 slot = (struct slot *)mixer->slots[ch].private_data;
1200                 if (slot && slot->assigned &&
1201                     slot->assigned->index == idx && ! strcmp(slot->assigned->name, str))
1202                         /* not changed */
1203                         goto __unlock;
1204                 tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
1205                 if (! tbl) {
1206                         snd_printk(KERN_ERR "mixer_oss: no memory\n");
1207                         goto __unlock;
1208                 }
1209                 tbl->oss_id = ch;
1210                 tbl->name = kstrdup(str, GFP_KERNEL);
1211                 if (! tbl->name) {
1212                         kfree(tbl);
1213                         goto __unlock;
1214                 }
1215                 tbl->index = idx;
1216                 if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) {
1217                         kfree(tbl->name);
1218                         kfree(tbl);
1219                 }
1220         __unlock:
1221                 mutex_unlock(&mixer->reg_mutex);
1222         }
1223 }
1224
1225 static void snd_mixer_oss_proc_init(struct snd_mixer_oss *mixer)
1226 {
1227         struct snd_info_entry *entry;
1228
1229         entry = snd_info_create_card_entry(mixer->card, "oss_mixer",
1230                                            mixer->card->proc_root);
1231         if (! entry)
1232                 return;
1233         entry->content = SNDRV_INFO_CONTENT_TEXT;
1234         entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
1235         entry->c.text.read = snd_mixer_oss_proc_read;
1236         entry->c.text.write = snd_mixer_oss_proc_write;
1237         entry->private_data = mixer;
1238         if (snd_info_register(entry) < 0) {
1239                 snd_info_free_entry(entry);
1240                 entry = NULL;
1241         }
1242         mixer->proc_entry = entry;
1243 }
1244
1245 static void snd_mixer_oss_proc_done(struct snd_mixer_oss *mixer)
1246 {
1247         snd_info_free_entry(mixer->proc_entry);
1248         mixer->proc_entry = NULL;
1249 }
1250 #else /* !CONFIG_PROC_FS */
1251 #define snd_mixer_oss_proc_init(mix)
1252 #define snd_mixer_oss_proc_done(mix)
1253 #endif /* CONFIG_PROC_FS */
1254
1255 static void snd_mixer_oss_build(struct snd_mixer_oss *mixer)
1256 {
1257         static struct snd_mixer_oss_assign_table table[] = {
1258                 { SOUND_MIXER_VOLUME,   "Master",               0 },
1259                 { SOUND_MIXER_VOLUME,   "Front",                0 }, /* fallback */
1260                 { SOUND_MIXER_BASS,     "Tone Control - Bass",  0 },
1261                 { SOUND_MIXER_TREBLE,   "Tone Control - Treble", 0 },
1262                 { SOUND_MIXER_SYNTH,    "Synth",                0 },
1263                 { SOUND_MIXER_SYNTH,    "FM",                   0 }, /* fallback */
1264                 { SOUND_MIXER_SYNTH,    "Music",                0 }, /* fallback */
1265                 { SOUND_MIXER_PCM,      "PCM",                  0 },
1266                 { SOUND_MIXER_SPEAKER,  "Beep",                 0 },
1267                 { SOUND_MIXER_SPEAKER,  "PC Speaker",           0 }, /* fallback */
1268                 { SOUND_MIXER_SPEAKER,  "Speaker",              0 }, /* fallback */
1269                 { SOUND_MIXER_LINE,     "Line",                 0 },
1270                 { SOUND_MIXER_MIC,      "Mic",                  0 },
1271                 { SOUND_MIXER_CD,       "CD",                   0 },
1272                 { SOUND_MIXER_IMIX,     "Monitor Mix",          0 },
1273                 { SOUND_MIXER_ALTPCM,   "PCM",                  1 },
1274                 { SOUND_MIXER_ALTPCM,   "Headphone",            0 }, /* fallback */
1275                 { SOUND_MIXER_ALTPCM,   "Wave",                 0 }, /* fallback */
1276                 { SOUND_MIXER_RECLEV,   "-- nothing --",        0 },
1277                 { SOUND_MIXER_IGAIN,    "Capture",              0 },
1278                 { SOUND_MIXER_OGAIN,    "Playback",             0 },
1279                 { SOUND_MIXER_LINE1,    "Aux",                  0 },
1280                 { SOUND_MIXER_LINE2,    "Aux",                  1 },
1281                 { SOUND_MIXER_LINE3,    "Aux",                  2 },
1282                 { SOUND_MIXER_DIGITAL1, "Digital",              0 },
1283                 { SOUND_MIXER_DIGITAL1, "IEC958",               0 }, /* fallback */
1284                 { SOUND_MIXER_DIGITAL1, "IEC958 Optical",       0 }, /* fallback */
1285                 { SOUND_MIXER_DIGITAL1, "IEC958 Coaxial",       0 }, /* fallback */
1286                 { SOUND_MIXER_DIGITAL2, "Digital",              1 },
1287                 { SOUND_MIXER_DIGITAL3, "Digital",              2 },
1288                 { SOUND_MIXER_PHONEIN,  "Phone",                0 },
1289                 { SOUND_MIXER_PHONEOUT, "Master Mono",          0 },
1290                 { SOUND_MIXER_PHONEOUT, "Speaker",              0 }, /*fallback*/
1291                 { SOUND_MIXER_PHONEOUT, "Mono",                 0 }, /*fallback*/
1292                 { SOUND_MIXER_PHONEOUT, "Phone",                0 }, /* fallback */
1293                 { SOUND_MIXER_VIDEO,    "Video",                0 },
1294                 { SOUND_MIXER_RADIO,    "Radio",                0 },
1295                 { SOUND_MIXER_MONITOR,  "Monitor",              0 }
1296         };
1297         unsigned int idx;
1298         
1299         for (idx = 0; idx < ARRAY_SIZE(table); idx++)
1300                 snd_mixer_oss_build_input(mixer, &table[idx], 0, 0);
1301         if (mixer->mask_recsrc) {
1302                 mixer->get_recsrc = snd_mixer_oss_get_recsrc2;
1303                 mixer->put_recsrc = snd_mixer_oss_put_recsrc2;
1304         }
1305 }
1306
1307 /*
1308  *
1309  */
1310
1311 static int snd_mixer_oss_free1(void *private)
1312 {
1313         struct snd_mixer_oss *mixer = private;
1314         struct snd_card *card;
1315         int idx;
1316  
1317         if (!mixer)
1318                 return 0;
1319         card = mixer->card;
1320         if (snd_BUG_ON(mixer != card->mixer_oss))
1321                 return -ENXIO;
1322         card->mixer_oss = NULL;
1323         for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) {
1324                 struct snd_mixer_oss_slot *chn = &mixer->slots[idx];
1325                 if (chn->private_free)
1326                         chn->private_free(chn);
1327         }
1328         kfree(mixer);
1329         return 0;
1330 }
1331
1332 static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
1333 {
1334         struct snd_mixer_oss *mixer;
1335
1336         if (cmd == SND_MIXER_OSS_NOTIFY_REGISTER) {
1337                 char name[128];
1338                 int idx, err;
1339
1340                 mixer = kcalloc(2, sizeof(*mixer), GFP_KERNEL);
1341                 if (mixer == NULL)
1342                         return -ENOMEM;
1343                 mutex_init(&mixer->reg_mutex);
1344                 sprintf(name, "mixer%i%i", card->number, 0);
1345                 if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER,
1346                                                    card, 0,
1347                                                    &snd_mixer_oss_f_ops, card,
1348                                                    name)) < 0) {
1349                         snd_printk(KERN_ERR "unable to register OSS mixer device %i:%i\n",
1350                                    card->number, 0);
1351                         kfree(mixer);
1352                         return err;
1353                 }
1354                 mixer->oss_dev_alloc = 1;
1355                 mixer->card = card;
1356                 if (*card->mixername)
1357                         strlcpy(mixer->name, card->mixername, sizeof(mixer->name));
1358                 else
1359                         strlcpy(mixer->name, name, sizeof(mixer->name));
1360 #ifdef SNDRV_OSS_INFO_DEV_MIXERS
1361                 snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIXERS,
1362                                       card->number,
1363                                       mixer->name);
1364 #endif
1365                 for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++)
1366                         mixer->slots[idx].number = idx;
1367                 card->mixer_oss = mixer;
1368                 snd_mixer_oss_build(mixer);
1369                 snd_mixer_oss_proc_init(mixer);
1370         } else {
1371                 mixer = card->mixer_oss;
1372                 if (mixer == NULL)
1373                         return 0;
1374                 if (mixer->oss_dev_alloc) {
1375 #ifdef SNDRV_OSS_INFO_DEV_MIXERS
1376                         snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
1377 #endif
1378                         snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
1379                         mixer->oss_dev_alloc = 0;
1380                 }
1381                 if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT)
1382                         return 0;
1383                 snd_mixer_oss_proc_done(mixer);
1384                 return snd_mixer_oss_free1(mixer);
1385         }
1386         return 0;
1387 }
1388
1389 static int __init alsa_mixer_oss_init(void)
1390 {
1391         int idx;
1392         
1393         snd_mixer_oss_notify_callback = snd_mixer_oss_notify_handler;
1394         for (idx = 0; idx < SNDRV_CARDS; idx++) {
1395                 if (snd_cards[idx])
1396                         snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_REGISTER);
1397         }
1398         return 0;
1399 }
1400
1401 static void __exit alsa_mixer_oss_exit(void)
1402 {
1403         int idx;
1404
1405         snd_mixer_oss_notify_callback = NULL;
1406         for (idx = 0; idx < SNDRV_CARDS; idx++) {
1407                 if (snd_cards[idx])
1408                         snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_FREE);
1409         }
1410 }
1411
1412 module_init(alsa_mixer_oss_init)
1413 module_exit(alsa_mixer_oss_exit)
1414
1415 EXPORT_SYMBOL(snd_mixer_oss_ioctl_card);