~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/core/oss/mixer_oss.c

Version: ~ [ linux-5.7 ] ~ [ linux-5.6.15 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.43 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.125 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.182 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.225 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.225 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.84 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp