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