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