Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  OSS emulation layer for the mixer interface
0004  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
0005  */
0006 
0007 #include <linux/init.h>
0008 #include <linux/slab.h>
0009 #include <linux/time.h>
0010 #include <linux/string.h>
0011 #include <linux/module.h>
0012 #include <linux/compat.h>
0013 #include <sound/core.h>
0014 #include <sound/minors.h>
0015 #include <sound/control.h>
0016 #include <sound/info.h>
0017 #include <sound/mixer_oss.h>
0018 #include <linux/soundcard.h>
0019 
0020 #define OSS_ALSAEMULVER         _SIOR ('M', 249, int)
0021 
0022 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
0023 MODULE_DESCRIPTION("Mixer OSS emulation for ALSA.");
0024 MODULE_LICENSE("GPL");
0025 MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MIXER);
0026 
0027 static int snd_mixer_oss_open(struct inode *inode, struct file *file)
0028 {
0029     struct snd_card *card;
0030     struct snd_mixer_oss_file *fmixer;
0031     int err;
0032 
0033     err = nonseekable_open(inode, file);
0034     if (err < 0)
0035         return err;
0036 
0037     card = snd_lookup_oss_minor_data(iminor(inode),
0038                      SNDRV_OSS_DEVICE_TYPE_MIXER);
0039     if (card == NULL)
0040         return -ENODEV;
0041     if (card->mixer_oss == NULL) {
0042         snd_card_unref(card);
0043         return -ENODEV;
0044     }
0045     err = snd_card_file_add(card, file);
0046     if (err < 0) {
0047         snd_card_unref(card);
0048         return err;
0049     }
0050     fmixer = kzalloc(sizeof(*fmixer), GFP_KERNEL);
0051     if (fmixer == NULL) {
0052         snd_card_file_remove(card, file);
0053         snd_card_unref(card);
0054         return -ENOMEM;
0055     }
0056     fmixer->card = card;
0057     fmixer->mixer = card->mixer_oss;
0058     file->private_data = fmixer;
0059     if (!try_module_get(card->module)) {
0060         kfree(fmixer);
0061         snd_card_file_remove(card, file);
0062         snd_card_unref(card);
0063         return -EFAULT;
0064     }
0065     snd_card_unref(card);
0066     return 0;
0067 }
0068 
0069 static int snd_mixer_oss_release(struct inode *inode, struct file *file)
0070 {
0071     struct snd_mixer_oss_file *fmixer;
0072 
0073     if (file->private_data) {
0074         fmixer = file->private_data;
0075         module_put(fmixer->card->module);
0076         snd_card_file_remove(fmixer->card, file);
0077         kfree(fmixer);
0078     }
0079     return 0;
0080 }
0081 
0082 static int snd_mixer_oss_info(struct snd_mixer_oss_file *fmixer,
0083                   mixer_info __user *_info)
0084 {
0085     struct snd_card *card = fmixer->card;
0086     struct snd_mixer_oss *mixer = fmixer->mixer;
0087     struct mixer_info info;
0088     
0089     memset(&info, 0, sizeof(info));
0090     strscpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
0091     strscpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
0092     info.modify_counter = card->mixer_oss_change_count;
0093     if (copy_to_user(_info, &info, sizeof(info)))
0094         return -EFAULT;
0095     return 0;
0096 }
0097 
0098 static int snd_mixer_oss_info_obsolete(struct snd_mixer_oss_file *fmixer,
0099                        _old_mixer_info __user *_info)
0100 {
0101     struct snd_card *card = fmixer->card;
0102     struct snd_mixer_oss *mixer = fmixer->mixer;
0103     _old_mixer_info info;
0104     
0105     memset(&info, 0, sizeof(info));
0106     strscpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
0107     strscpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
0108     if (copy_to_user(_info, &info, sizeof(info)))
0109         return -EFAULT;
0110     return 0;
0111 }
0112 
0113 static int snd_mixer_oss_caps(struct snd_mixer_oss_file *fmixer)
0114 {
0115     struct snd_mixer_oss *mixer = fmixer->mixer;
0116     int result = 0;
0117 
0118     if (mixer == NULL)
0119         return -EIO;
0120     if (mixer->get_recsrc && mixer->put_recsrc)
0121         result |= SOUND_CAP_EXCL_INPUT;
0122     return result;
0123 }
0124 
0125 static int snd_mixer_oss_devmask(struct snd_mixer_oss_file *fmixer)
0126 {
0127     struct snd_mixer_oss *mixer = fmixer->mixer;
0128     struct snd_mixer_oss_slot *pslot;
0129     int result = 0, chn;
0130 
0131     if (mixer == NULL)
0132         return -EIO;
0133     mutex_lock(&mixer->reg_mutex);
0134     for (chn = 0; chn < 31; chn++) {
0135         pslot = &mixer->slots[chn];
0136         if (pslot->put_volume || pslot->put_recsrc)
0137             result |= 1 << chn;
0138     }
0139     mutex_unlock(&mixer->reg_mutex);
0140     return result;
0141 }
0142 
0143 static int snd_mixer_oss_stereodevs(struct snd_mixer_oss_file *fmixer)
0144 {
0145     struct snd_mixer_oss *mixer = fmixer->mixer;
0146     struct snd_mixer_oss_slot *pslot;
0147     int result = 0, chn;
0148 
0149     if (mixer == NULL)
0150         return -EIO;
0151     mutex_lock(&mixer->reg_mutex);
0152     for (chn = 0; chn < 31; chn++) {
0153         pslot = &mixer->slots[chn];
0154         if (pslot->put_volume && pslot->stereo)
0155             result |= 1 << chn;
0156     }
0157     mutex_unlock(&mixer->reg_mutex);
0158     return result;
0159 }
0160 
0161 static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer)
0162 {
0163     struct snd_mixer_oss *mixer = fmixer->mixer;
0164     int result = 0;
0165 
0166     if (mixer == NULL)
0167         return -EIO;
0168     mutex_lock(&mixer->reg_mutex);
0169     if (mixer->put_recsrc && mixer->get_recsrc) {   /* exclusive */
0170         result = mixer->mask_recsrc;
0171     } else {
0172         struct snd_mixer_oss_slot *pslot;
0173         int chn;
0174         for (chn = 0; chn < 31; chn++) {
0175             pslot = &mixer->slots[chn];
0176             if (pslot->put_recsrc)
0177                 result |= 1 << chn;
0178         }
0179     }
0180     mutex_unlock(&mixer->reg_mutex);
0181     return result;
0182 }
0183 
0184 static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
0185 {
0186     struct snd_mixer_oss *mixer = fmixer->mixer;
0187     int result = 0;
0188 
0189     if (mixer == NULL)
0190         return -EIO;
0191     mutex_lock(&mixer->reg_mutex);
0192     if (mixer->put_recsrc && mixer->get_recsrc) {   /* exclusive */
0193         unsigned int index;
0194         result = mixer->get_recsrc(fmixer, &index);
0195         if (result < 0)
0196             goto unlock;
0197         result = 1 << index;
0198     } else {
0199         struct snd_mixer_oss_slot *pslot;
0200         int chn;
0201         for (chn = 0; chn < 31; chn++) {
0202             pslot = &mixer->slots[chn];
0203             if (pslot->get_recsrc) {
0204                 int active = 0;
0205                 pslot->get_recsrc(fmixer, pslot, &active);
0206                 if (active)
0207                     result |= 1 << chn;
0208             }
0209         }
0210     }
0211     mixer->oss_recsrc = result;
0212  unlock:
0213     mutex_unlock(&mixer->reg_mutex);
0214     return result;
0215 }
0216 
0217 static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsrc)
0218 {
0219     struct snd_mixer_oss *mixer = fmixer->mixer;
0220     struct snd_mixer_oss_slot *pslot;
0221     int chn, active;
0222     unsigned int index;
0223     int result = 0;
0224 
0225     if (mixer == NULL)
0226         return -EIO;
0227     mutex_lock(&mixer->reg_mutex);
0228     if (mixer->get_recsrc && mixer->put_recsrc) {   /* exclusive input */
0229         if (recsrc & ~mixer->oss_recsrc)
0230             recsrc &= ~mixer->oss_recsrc;
0231         mixer->put_recsrc(fmixer, ffz(~recsrc));
0232         mixer->get_recsrc(fmixer, &index);
0233         result = 1 << index;
0234     }
0235     for (chn = 0; chn < 31; chn++) {
0236         pslot = &mixer->slots[chn];
0237         if (pslot->put_recsrc) {
0238             active = (recsrc & (1 << chn)) ? 1 : 0;
0239             pslot->put_recsrc(fmixer, pslot, active);
0240         }
0241     }
0242     if (! result) {
0243         for (chn = 0; chn < 31; chn++) {
0244             pslot = &mixer->slots[chn];
0245             if (pslot->get_recsrc) {
0246                 active = 0;
0247                 pslot->get_recsrc(fmixer, pslot, &active);
0248                 if (active)
0249                     result |= 1 << chn;
0250             }
0251         }
0252     }
0253     mutex_unlock(&mixer->reg_mutex);
0254     return result;
0255 }
0256 
0257 static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
0258 {
0259     struct snd_mixer_oss *mixer = fmixer->mixer;
0260     struct snd_mixer_oss_slot *pslot;
0261     int result = 0, left, right;
0262 
0263     if (mixer == NULL || slot > 30)
0264         return -EIO;
0265     mutex_lock(&mixer->reg_mutex);
0266     pslot = &mixer->slots[slot];
0267     left = pslot->volume[0];
0268     right = pslot->volume[1];
0269     if (pslot->get_volume)
0270         result = pslot->get_volume(fmixer, pslot, &left, &right);
0271     if (!pslot->stereo)
0272         right = left;
0273     if (snd_BUG_ON(left < 0 || left > 100)) {
0274         result = -EIO;
0275         goto unlock;
0276     }
0277     if (snd_BUG_ON(right < 0 || right > 100)) {
0278         result = -EIO;
0279         goto unlock;
0280     }
0281     if (result >= 0) {
0282         pslot->volume[0] = left;
0283         pslot->volume[1] = right;
0284         result = (left & 0xff) | ((right & 0xff) << 8);
0285     }
0286  unlock:
0287     mutex_unlock(&mixer->reg_mutex);
0288     return result;
0289 }
0290 
0291 static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
0292                     int slot, int volume)
0293 {
0294     struct snd_mixer_oss *mixer = fmixer->mixer;
0295     struct snd_mixer_oss_slot *pslot;
0296     int result = 0, left = volume & 0xff, right = (volume >> 8) & 0xff;
0297 
0298     if (mixer == NULL || slot > 30)
0299         return -EIO;
0300     mutex_lock(&mixer->reg_mutex);
0301     pslot = &mixer->slots[slot];
0302     if (left > 100)
0303         left = 100;
0304     if (right > 100)
0305         right = 100;
0306     if (!pslot->stereo)
0307         right = left;
0308     if (pslot->put_volume)
0309         result = pslot->put_volume(fmixer, pslot, left, right);
0310     if (result < 0)
0311         goto unlock;
0312     pslot->volume[0] = left;
0313     pslot->volume[1] = right;
0314     result = (left & 0xff) | ((right & 0xff) << 8);
0315  unlock:
0316     mutex_unlock(&mixer->reg_mutex);
0317     return result;
0318 }
0319 
0320 static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int cmd, unsigned long arg)
0321 {
0322     void __user *argp = (void __user *)arg;
0323     int __user *p = argp;
0324     int tmp;
0325 
0326     if (snd_BUG_ON(!fmixer))
0327         return -ENXIO;
0328     if (((cmd >> 8) & 0xff) == 'M') {
0329         switch (cmd) {
0330         case SOUND_MIXER_INFO:
0331             return snd_mixer_oss_info(fmixer, argp);
0332         case SOUND_OLD_MIXER_INFO:
0333             return snd_mixer_oss_info_obsolete(fmixer, argp);
0334         case SOUND_MIXER_WRITE_RECSRC:
0335             if (get_user(tmp, p))
0336                 return -EFAULT;
0337             tmp = snd_mixer_oss_set_recsrc(fmixer, tmp);
0338             if (tmp < 0)
0339                 return tmp;
0340             return put_user(tmp, p);
0341         case OSS_GETVERSION:
0342             return put_user(SNDRV_OSS_VERSION, p);
0343         case OSS_ALSAEMULVER:
0344             return put_user(1, p);
0345         case SOUND_MIXER_READ_DEVMASK:
0346             tmp = snd_mixer_oss_devmask(fmixer);
0347             if (tmp < 0)
0348                 return tmp;
0349             return put_user(tmp, p);
0350         case SOUND_MIXER_READ_STEREODEVS:
0351             tmp = snd_mixer_oss_stereodevs(fmixer);
0352             if (tmp < 0)
0353                 return tmp;
0354             return put_user(tmp, p);
0355         case SOUND_MIXER_READ_RECMASK:
0356             tmp = snd_mixer_oss_recmask(fmixer);
0357             if (tmp < 0)
0358                 return tmp;
0359             return put_user(tmp, p);
0360         case SOUND_MIXER_READ_CAPS:
0361             tmp = snd_mixer_oss_caps(fmixer);
0362             if (tmp < 0)
0363                 return tmp;
0364             return put_user(tmp, p);
0365         case SOUND_MIXER_READ_RECSRC:
0366             tmp = snd_mixer_oss_get_recsrc(fmixer);
0367             if (tmp < 0)
0368                 return tmp;
0369             return put_user(tmp, p);
0370         }
0371     }
0372     if (cmd & SIOC_IN) {
0373         if (get_user(tmp, p))
0374             return -EFAULT;
0375         tmp = snd_mixer_oss_set_volume(fmixer, cmd & 0xff, tmp);
0376         if (tmp < 0)
0377             return tmp;
0378         return put_user(tmp, p);
0379     } else if (cmd & SIOC_OUT) {
0380         tmp = snd_mixer_oss_get_volume(fmixer, cmd & 0xff);
0381         if (tmp < 0)
0382             return tmp;
0383         return put_user(tmp, p);
0384     }
0385     return -ENXIO;
0386 }
0387 
0388 static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
0389 {
0390     return snd_mixer_oss_ioctl1(file->private_data, cmd, arg);
0391 }
0392 
0393 int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg)
0394 {
0395     struct snd_mixer_oss_file fmixer;
0396     
0397     if (snd_BUG_ON(!card))
0398         return -ENXIO;
0399     if (card->mixer_oss == NULL)
0400         return -ENXIO;
0401     memset(&fmixer, 0, sizeof(fmixer));
0402     fmixer.card = card;
0403     fmixer.mixer = card->mixer_oss;
0404     return snd_mixer_oss_ioctl1(&fmixer, cmd, arg);
0405 }
0406 EXPORT_SYMBOL(snd_mixer_oss_ioctl_card);
0407 
0408 #ifdef CONFIG_COMPAT
0409 /* all compatible */
0410 static long snd_mixer_oss_ioctl_compat(struct file *file, unsigned int cmd,
0411                        unsigned long arg)
0412 {
0413     return snd_mixer_oss_ioctl1(file->private_data, cmd,
0414                     (unsigned long)compat_ptr(arg));
0415 }
0416 #else
0417 #define snd_mixer_oss_ioctl_compat  NULL
0418 #endif
0419 
0420 /*
0421  *  REGISTRATION PART
0422  */
0423 
0424 static const struct file_operations snd_mixer_oss_f_ops =
0425 {
0426     .owner =    THIS_MODULE,
0427     .open =     snd_mixer_oss_open,
0428     .release =  snd_mixer_oss_release,
0429     .llseek =   no_llseek,
0430     .unlocked_ioctl =   snd_mixer_oss_ioctl,
0431     .compat_ioctl = snd_mixer_oss_ioctl_compat,
0432 };
0433 
0434 /*
0435  *  utilities
0436  */
0437 
0438 static long snd_mixer_oss_conv(long val, long omin, long omax, long nmin, long nmax)
0439 {
0440     long orange = omax - omin, nrange = nmax - nmin;
0441     
0442     if (orange == 0)
0443         return 0;
0444     return DIV_ROUND_CLOSEST(nrange * (val - omin), orange) + nmin;
0445 }
0446 
0447 /* convert from alsa native to oss values (0-100) */
0448 static long snd_mixer_oss_conv1(long val, long min, long max, int *old)
0449 {
0450     if (val == snd_mixer_oss_conv(*old, 0, 100, min, max))
0451         return *old;
0452     return snd_mixer_oss_conv(val, min, max, 0, 100);
0453 }
0454 
0455 /* convert from oss to alsa native values */
0456 static long snd_mixer_oss_conv2(long val, long min, long max)
0457 {
0458     return snd_mixer_oss_conv(val, 0, 100, min, max);
0459 }
0460 
0461 #if 0
0462 static void snd_mixer_oss_recsrce_set(struct snd_card *card, int slot)
0463 {
0464     struct snd_mixer_oss *mixer = card->mixer_oss;
0465     if (mixer)
0466         mixer->mask_recsrc |= 1 << slot;
0467 }
0468 
0469 static int snd_mixer_oss_recsrce_get(struct snd_card *card, int slot)
0470 {
0471     struct snd_mixer_oss *mixer = card->mixer_oss;
0472     if (mixer && (mixer->mask_recsrc & (1 << slot)))
0473         return 1;
0474     return 0;
0475 }
0476 #endif
0477 
0478 #define SNDRV_MIXER_OSS_SIGNATURE       0x65999250
0479 
0480 #define SNDRV_MIXER_OSS_ITEM_GLOBAL 0
0481 #define SNDRV_MIXER_OSS_ITEM_GSWITCH    1
0482 #define SNDRV_MIXER_OSS_ITEM_GROUTE 2
0483 #define SNDRV_MIXER_OSS_ITEM_GVOLUME    3
0484 #define SNDRV_MIXER_OSS_ITEM_PSWITCH    4
0485 #define SNDRV_MIXER_OSS_ITEM_PROUTE 5
0486 #define SNDRV_MIXER_OSS_ITEM_PVOLUME    6
0487 #define SNDRV_MIXER_OSS_ITEM_CSWITCH    7
0488 #define SNDRV_MIXER_OSS_ITEM_CROUTE 8
0489 #define SNDRV_MIXER_OSS_ITEM_CVOLUME    9
0490 #define SNDRV_MIXER_OSS_ITEM_CAPTURE    10
0491 
0492 #define SNDRV_MIXER_OSS_ITEM_COUNT  11
0493 
0494 #define SNDRV_MIXER_OSS_PRESENT_GLOBAL  (1<<0)
0495 #define SNDRV_MIXER_OSS_PRESENT_GSWITCH (1<<1)
0496 #define SNDRV_MIXER_OSS_PRESENT_GROUTE  (1<<2)
0497 #define SNDRV_MIXER_OSS_PRESENT_GVOLUME (1<<3)
0498 #define SNDRV_MIXER_OSS_PRESENT_PSWITCH (1<<4)
0499 #define SNDRV_MIXER_OSS_PRESENT_PROUTE  (1<<5)
0500 #define SNDRV_MIXER_OSS_PRESENT_PVOLUME (1<<6)
0501 #define SNDRV_MIXER_OSS_PRESENT_CSWITCH (1<<7)
0502 #define SNDRV_MIXER_OSS_PRESENT_CROUTE  (1<<8)
0503 #define SNDRV_MIXER_OSS_PRESENT_CVOLUME (1<<9)
0504 #define SNDRV_MIXER_OSS_PRESENT_CAPTURE (1<<10)
0505 
0506 struct slot {
0507     unsigned int signature;
0508     unsigned int present;
0509     unsigned int channels;
0510     unsigned int numid[SNDRV_MIXER_OSS_ITEM_COUNT];
0511     unsigned int capture_item;
0512     const struct snd_mixer_oss_assign_table *assigned;
0513     unsigned int allocated: 1;
0514 };
0515 
0516 #define ID_UNKNOWN  ((unsigned int)-1)
0517 
0518 static struct snd_kcontrol *snd_mixer_oss_test_id(struct snd_mixer_oss *mixer, const char *name, int index)
0519 {
0520     struct snd_card *card = mixer->card;
0521     struct snd_ctl_elem_id id;
0522     
0523     memset(&id, 0, sizeof(id));
0524     id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
0525     strscpy(id.name, name, sizeof(id.name));
0526     id.index = index;
0527     return snd_ctl_find_id(card, &id);
0528 }
0529 
0530 static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer,
0531                       struct snd_mixer_oss_slot *pslot,
0532                       unsigned int numid,
0533                       int *left, int *right)
0534 {
0535     struct snd_ctl_elem_info *uinfo;
0536     struct snd_ctl_elem_value *uctl;
0537     struct snd_kcontrol *kctl;
0538     struct snd_card *card = fmixer->card;
0539 
0540     if (numid == ID_UNKNOWN)
0541         return;
0542     down_read(&card->controls_rwsem);
0543     kctl = snd_ctl_find_numid(card, numid);
0544     if (!kctl) {
0545         up_read(&card->controls_rwsem);
0546         return;
0547     }
0548     uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
0549     uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
0550     if (uinfo == NULL || uctl == NULL)
0551         goto __unalloc;
0552     if (kctl->info(kctl, uinfo))
0553         goto __unalloc;
0554     if (kctl->get(kctl, uctl))
0555         goto __unalloc;
0556     if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
0557         uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
0558         goto __unalloc;
0559     *left = snd_mixer_oss_conv1(uctl->value.integer.value[0], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[0]);
0560     if (uinfo->count > 1)
0561         *right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]);
0562       __unalloc:
0563     up_read(&card->controls_rwsem);
0564         kfree(uctl);
0565         kfree(uinfo);
0566 }
0567 
0568 static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
0569                      struct snd_mixer_oss_slot *pslot,
0570                      unsigned int numid,
0571                      int *left, int *right,
0572                      int route)
0573 {
0574     struct snd_ctl_elem_info *uinfo;
0575     struct snd_ctl_elem_value *uctl;
0576     struct snd_kcontrol *kctl;
0577     struct snd_card *card = fmixer->card;
0578 
0579     if (numid == ID_UNKNOWN)
0580         return;
0581     down_read(&card->controls_rwsem);
0582     kctl = snd_ctl_find_numid(card, numid);
0583     if (!kctl) {
0584         up_read(&card->controls_rwsem);
0585         return;
0586     }
0587     uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
0588     uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
0589     if (uinfo == NULL || uctl == NULL)
0590         goto __unalloc;
0591     if (kctl->info(kctl, uinfo))
0592         goto __unalloc;
0593     if (kctl->get(kctl, uctl))
0594         goto __unalloc;
0595     if (!uctl->value.integer.value[0]) {
0596         *left = 0;
0597         if (uinfo->count == 1)
0598             *right = 0;
0599     }
0600     if (uinfo->count > 1 && !uctl->value.integer.value[route ? 3 : 1])
0601         *right = 0;
0602       __unalloc:
0603     up_read(&card->controls_rwsem);
0604         kfree(uctl);
0605     kfree(uinfo);
0606 }
0607 
0608 static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer,
0609                      struct snd_mixer_oss_slot *pslot,
0610                      int *left, int *right)
0611 {
0612     struct slot *slot = pslot->private_data;
0613     
0614     *left = *right = 100;
0615     if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
0616         snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
0617     } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) {
0618         snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right);
0619     } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) {
0620         snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right);
0621     }
0622     if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) {
0623         snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0);
0624     } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) {
0625         snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0);
0626     } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) {
0627         snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1);
0628     } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) {
0629         snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1);
0630     }
0631     return 0;
0632 }
0633 
0634 static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
0635                       struct snd_mixer_oss_slot *pslot,
0636                       unsigned int numid,
0637                       int left, int right)
0638 {
0639     struct snd_ctl_elem_info *uinfo;
0640     struct snd_ctl_elem_value *uctl;
0641     struct snd_kcontrol *kctl;
0642     struct snd_card *card = fmixer->card;
0643     int res;
0644 
0645     if (numid == ID_UNKNOWN)
0646         return;
0647     down_read(&card->controls_rwsem);
0648     kctl = snd_ctl_find_numid(card, numid);
0649     if (!kctl) {
0650         up_read(&card->controls_rwsem);
0651         return;
0652     }
0653     uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
0654     uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
0655     if (uinfo == NULL || uctl == NULL)
0656         goto __unalloc;
0657     if (kctl->info(kctl, uinfo))
0658         goto __unalloc;
0659     if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
0660         uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
0661         goto __unalloc;
0662     uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max);
0663     if (uinfo->count > 1)
0664         uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max);
0665     res = kctl->put(kctl, uctl);
0666     if (res < 0)
0667         goto __unalloc;
0668     if (res > 0)
0669         snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
0670       __unalloc:
0671     up_read(&card->controls_rwsem);
0672         kfree(uctl);
0673     kfree(uinfo);
0674 }
0675 
0676 static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
0677                      struct snd_mixer_oss_slot *pslot,
0678                      unsigned int numid,
0679                      int left, int right,
0680                      int route)
0681 {
0682     struct snd_ctl_elem_info *uinfo;
0683     struct snd_ctl_elem_value *uctl;
0684     struct snd_kcontrol *kctl;
0685     struct snd_card *card = fmixer->card;
0686     int res;
0687 
0688     if (numid == ID_UNKNOWN)
0689         return;
0690     down_read(&card->controls_rwsem);
0691     kctl = snd_ctl_find_numid(card, numid);
0692     if (!kctl) {
0693         up_read(&card->controls_rwsem);
0694         return;
0695     }
0696     uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
0697     uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
0698     if (uinfo == NULL || uctl == NULL)
0699         goto __unalloc;
0700     if (kctl->info(kctl, uinfo))
0701         goto __unalloc;
0702     if (uinfo->count > 1) {
0703         uctl->value.integer.value[0] = left > 0 ? 1 : 0;
0704         uctl->value.integer.value[route ? 3 : 1] = right > 0 ? 1 : 0;
0705         if (route) {
0706             uctl->value.integer.value[1] =
0707             uctl->value.integer.value[2] = 0;
0708         }
0709     } else {
0710         uctl->value.integer.value[0] = (left > 0 || right > 0) ? 1 : 0;
0711     }
0712     res = kctl->put(kctl, uctl);
0713     if (res < 0)
0714         goto __unalloc;
0715     if (res > 0)
0716         snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
0717       __unalloc:
0718     up_read(&card->controls_rwsem);
0719         kfree(uctl);
0720     kfree(uinfo);
0721 }
0722 
0723 static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer,
0724                      struct snd_mixer_oss_slot *pslot,
0725                      int left, int right)
0726 {
0727     struct slot *slot = pslot->private_data;
0728     
0729     if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
0730         snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
0731         if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME)
0732             snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right);
0733     } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME) {
0734         snd_mixer_oss_put_volume1_vol(fmixer, pslot,
0735             slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right);
0736     } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) {
0737         snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right);
0738     } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) {
0739         snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right);
0740     }
0741     if (left || right) {
0742         if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH)
0743             snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0);
0744         if (slot->present & SNDRV_MIXER_OSS_PRESENT_CSWITCH)
0745             snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], left, right, 0);
0746         if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH)
0747             snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0);
0748         if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE)
0749             snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1);
0750         if (slot->present & SNDRV_MIXER_OSS_PRESENT_CROUTE)
0751             snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], left, right, 1);
0752         if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE)
0753             snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1);
0754     } else {
0755         if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) {
0756             snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0);
0757         } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CSWITCH) {
0758             snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], left, right, 0);
0759         } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) {
0760             snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0);
0761         } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) {
0762             snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1);
0763         } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CROUTE) {
0764             snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], left, right, 1);
0765         } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) {
0766             snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1);
0767         }
0768     }
0769     return 0;
0770 }
0771 
0772 static int snd_mixer_oss_get_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
0773                     struct snd_mixer_oss_slot *pslot,
0774                     int *active)
0775 {
0776     struct slot *slot = pslot->private_data;
0777     int left, right;
0778     
0779     left = right = 1;
0780     snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], &left, &right, 0);
0781     *active = (left || right) ? 1 : 0;
0782     return 0;
0783 }
0784 
0785 static int snd_mixer_oss_get_recsrc1_route(struct snd_mixer_oss_file *fmixer,
0786                        struct snd_mixer_oss_slot *pslot,
0787                        int *active)
0788 {
0789     struct slot *slot = pslot->private_data;
0790     int left, right;
0791     
0792     left = right = 1;
0793     snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], &left, &right, 1);
0794     *active = (left || right) ? 1 : 0;
0795     return 0;
0796 }
0797 
0798 static int snd_mixer_oss_put_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
0799                     struct snd_mixer_oss_slot *pslot,
0800                     int active)
0801 {
0802     struct slot *slot = pslot->private_data;
0803     
0804     snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0);
0805     return 0;
0806 }
0807 
0808 static int snd_mixer_oss_put_recsrc1_route(struct snd_mixer_oss_file *fmixer,
0809                        struct snd_mixer_oss_slot *pslot,
0810                        int active)
0811 {
0812     struct slot *slot = pslot->private_data;
0813     
0814     snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1);
0815     return 0;
0816 }
0817 
0818 static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int *active_index)
0819 {
0820     struct snd_card *card = fmixer->card;
0821     struct snd_mixer_oss *mixer = fmixer->mixer;
0822     struct snd_kcontrol *kctl;
0823     struct snd_mixer_oss_slot *pslot;
0824     struct slot *slot;
0825     struct snd_ctl_elem_info *uinfo;
0826     struct snd_ctl_elem_value *uctl;
0827     int err, idx;
0828     
0829     uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
0830     uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
0831     if (uinfo == NULL || uctl == NULL) {
0832         err = -ENOMEM;
0833         goto __free_only;
0834     }
0835     down_read(&card->controls_rwsem);
0836     kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
0837     if (! kctl) {
0838         err = -ENOENT;
0839         goto __unlock;
0840     }
0841     err = kctl->info(kctl, uinfo);
0842     if (err < 0)
0843         goto __unlock;
0844     err = kctl->get(kctl, uctl);
0845     if (err < 0)
0846         goto __unlock;
0847     for (idx = 0; idx < 32; idx++) {
0848         if (!(mixer->mask_recsrc & (1 << idx)))
0849             continue;
0850         pslot = &mixer->slots[idx];
0851         slot = pslot->private_data;
0852         if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
0853             continue;
0854         if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
0855             continue;
0856         if (slot->capture_item == uctl->value.enumerated.item[0]) {
0857             *active_index = idx;
0858             break;
0859         }
0860     }
0861     err = 0;
0862       __unlock:
0863         up_read(&card->controls_rwsem);
0864       __free_only:
0865         kfree(uctl);
0866         kfree(uinfo);
0867         return err;
0868 }
0869 
0870 static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int active_index)
0871 {
0872     struct snd_card *card = fmixer->card;
0873     struct snd_mixer_oss *mixer = fmixer->mixer;
0874     struct snd_kcontrol *kctl;
0875     struct snd_mixer_oss_slot *pslot;
0876     struct slot *slot = NULL;
0877     struct snd_ctl_elem_info *uinfo;
0878     struct snd_ctl_elem_value *uctl;
0879     int err;
0880     unsigned int idx;
0881 
0882     uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
0883     uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
0884     if (uinfo == NULL || uctl == NULL) {
0885         err = -ENOMEM;
0886         goto __free_only;
0887     }
0888     down_read(&card->controls_rwsem);
0889     kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
0890     if (! kctl) {
0891         err = -ENOENT;
0892         goto __unlock;
0893     }
0894     err = kctl->info(kctl, uinfo);
0895     if (err < 0)
0896         goto __unlock;
0897     for (idx = 0; idx < 32; idx++) {
0898         if (!(mixer->mask_recsrc & (1 << idx)))
0899             continue;
0900         pslot = &mixer->slots[idx];
0901         slot = pslot->private_data;
0902         if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
0903             continue;
0904         if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
0905             continue;
0906         if (idx == active_index)
0907             break;
0908         slot = NULL;
0909     }
0910     if (! slot)
0911         goto __unlock;
0912     for (idx = 0; idx < uinfo->count; idx++)
0913         uctl->value.enumerated.item[idx] = slot->capture_item;
0914     err = kctl->put(kctl, uctl);
0915     if (err > 0)
0916         snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
0917     err = 0;
0918       __unlock:
0919     up_read(&card->controls_rwsem);
0920       __free_only:
0921     kfree(uctl);
0922     kfree(uinfo);
0923     return err;
0924 }
0925 
0926 struct snd_mixer_oss_assign_table {
0927     int oss_id;
0928     const char *name;
0929     int index;
0930 };
0931 
0932 static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *slot, const char *name, int index, int item)
0933 {
0934     struct snd_ctl_elem_info *info;
0935     struct snd_kcontrol *kcontrol;
0936     struct snd_card *card = mixer->card;
0937     int err;
0938 
0939     down_read(&card->controls_rwsem);
0940     kcontrol = snd_mixer_oss_test_id(mixer, name, index);
0941     if (kcontrol == NULL) {
0942         up_read(&card->controls_rwsem);
0943         return 0;
0944     }
0945     info = kmalloc(sizeof(*info), GFP_KERNEL);
0946     if (! info) {
0947         up_read(&card->controls_rwsem);
0948         return -ENOMEM;
0949     }
0950     err = kcontrol->info(kcontrol, info);
0951     if (err < 0) {
0952         up_read(&card->controls_rwsem);
0953         kfree(info);
0954         return err;
0955     }
0956     slot->numid[item] = kcontrol->id.numid;
0957     up_read(&card->controls_rwsem);
0958     if (info->count > slot->channels)
0959         slot->channels = info->count;
0960     slot->present |= 1 << item;
0961     kfree(info);
0962     return 0;
0963 }
0964 
0965 static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn)
0966 {
0967     struct slot *p = chn->private_data;
0968     if (p) {
0969         if (p->allocated && p->assigned) {
0970             kfree_const(p->assigned->name);
0971             kfree_const(p->assigned);
0972         }
0973         kfree(p);
0974     }
0975 }
0976 
0977 static void mixer_slot_clear(struct snd_mixer_oss_slot *rslot)
0978 {
0979     int idx = rslot->number; /* remember this */
0980     if (rslot->private_free)
0981         rslot->private_free(rslot);
0982     memset(rslot, 0, sizeof(*rslot));
0983     rslot->number = idx;
0984 }
0985 
0986 /* In a separate function to keep gcc 3.2 happy - do NOT merge this in
0987    snd_mixer_oss_build_input! */
0988 static int snd_mixer_oss_build_test_all(struct snd_mixer_oss *mixer,
0989                     const struct snd_mixer_oss_assign_table *ptr,
0990                     struct slot *slot)
0991 {
0992     char str[64];
0993     int err;
0994 
0995     err = snd_mixer_oss_build_test(mixer, slot, ptr->name, ptr->index,
0996                        SNDRV_MIXER_OSS_ITEM_GLOBAL);
0997     if (err)
0998         return err;
0999     sprintf(str, "%s Switch", ptr->name);
1000     err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
1001                        SNDRV_MIXER_OSS_ITEM_GSWITCH);
1002     if (err)
1003         return err;
1004     sprintf(str, "%s Route", ptr->name);
1005     err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
1006                        SNDRV_MIXER_OSS_ITEM_GROUTE);
1007     if (err)
1008         return err;
1009     sprintf(str, "%s Volume", ptr->name);
1010     err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
1011                        SNDRV_MIXER_OSS_ITEM_GVOLUME);
1012     if (err)
1013         return err;
1014     sprintf(str, "%s Playback Switch", ptr->name);
1015     err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
1016                        SNDRV_MIXER_OSS_ITEM_PSWITCH);
1017     if (err)
1018         return err;
1019     sprintf(str, "%s Playback Route", ptr->name);
1020     err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
1021                        SNDRV_MIXER_OSS_ITEM_PROUTE);
1022     if (err)
1023         return err;
1024     sprintf(str, "%s Playback Volume", ptr->name);
1025     err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
1026                        SNDRV_MIXER_OSS_ITEM_PVOLUME);
1027     if (err)
1028         return err;
1029     sprintf(str, "%s Capture Switch", ptr->name);
1030     err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
1031                        SNDRV_MIXER_OSS_ITEM_CSWITCH);
1032     if (err)
1033         return err;
1034     sprintf(str, "%s Capture Route", ptr->name);
1035     err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
1036                        SNDRV_MIXER_OSS_ITEM_CROUTE);
1037     if (err)
1038         return err;
1039     sprintf(str, "%s Capture Volume", ptr->name);
1040     err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
1041                        SNDRV_MIXER_OSS_ITEM_CVOLUME);
1042     if (err)
1043         return err;
1044 
1045     return 0;
1046 }
1047 
1048 /*
1049  * build an OSS mixer element.
1050  * ptr_allocated means the entry is dynamically allocated (change via proc file).
1051  * when replace_old = 1, the old entry is replaced with the new one.
1052  */
1053 static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer,
1054                      const struct snd_mixer_oss_assign_table *ptr,
1055                      int ptr_allocated, int replace_old)
1056 {
1057     struct slot slot;
1058     struct slot *pslot;
1059     struct snd_kcontrol *kctl;
1060     struct snd_mixer_oss_slot *rslot;
1061     char str[64];   
1062     
1063     /* check if already assigned */
1064     if (mixer->slots[ptr->oss_id].get_volume && ! replace_old)
1065         return 0;
1066 
1067     memset(&slot, 0, sizeof(slot));
1068     memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */
1069     if (snd_mixer_oss_build_test_all(mixer, ptr, &slot))
1070         return 0;
1071     down_read(&mixer->card->controls_rwsem);
1072     kctl = NULL;
1073     if (!ptr->index)
1074         kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
1075     if (kctl) {
1076         struct snd_ctl_elem_info *uinfo;
1077 
1078         uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
1079         if (! uinfo) {
1080             up_read(&mixer->card->controls_rwsem);
1081             return -ENOMEM;
1082         }
1083             
1084         if (kctl->info(kctl, uinfo)) {
1085             up_read(&mixer->card->controls_rwsem);
1086             kfree(uinfo);
1087             return 0;
1088         }
1089         strcpy(str, ptr->name);
1090         if (!strcmp(str, "Master"))
1091             strcpy(str, "Mix");
1092         if (!strcmp(str, "Master Mono"))
1093             strcpy(str, "Mix Mono");
1094         slot.capture_item = 0;
1095         if (!strcmp(uinfo->value.enumerated.name, str)) {
1096             slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
1097         } else {
1098             for (slot.capture_item = 1; slot.capture_item < uinfo->value.enumerated.items; slot.capture_item++) {
1099                 uinfo->value.enumerated.item = slot.capture_item;
1100                 if (kctl->info(kctl, uinfo)) {
1101                     up_read(&mixer->card->controls_rwsem);
1102                     kfree(uinfo);
1103                     return 0;
1104                 }
1105                 if (!strcmp(uinfo->value.enumerated.name, str)) {
1106                     slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
1107                     break;
1108                 }
1109             }
1110         }
1111         kfree(uinfo);
1112     }
1113     up_read(&mixer->card->controls_rwsem);
1114     if (slot.present != 0) {
1115         pslot = kmalloc(sizeof(slot), GFP_KERNEL);
1116         if (! pslot)
1117             return -ENOMEM;
1118         *pslot = slot;
1119         pslot->signature = SNDRV_MIXER_OSS_SIGNATURE;
1120         pslot->assigned = ptr;
1121         pslot->allocated = ptr_allocated;
1122         rslot = &mixer->slots[ptr->oss_id];
1123         mixer_slot_clear(rslot);
1124         rslot->stereo = slot.channels > 1 ? 1 : 0;
1125         rslot->get_volume = snd_mixer_oss_get_volume1;
1126         rslot->put_volume = snd_mixer_oss_put_volume1;
1127         /* note: ES18xx have both Capture Source and XX Capture Volume !!! */
1128         if (slot.present & SNDRV_MIXER_OSS_PRESENT_CSWITCH) {
1129             rslot->get_recsrc = snd_mixer_oss_get_recsrc1_sw;
1130             rslot->put_recsrc = snd_mixer_oss_put_recsrc1_sw;
1131         } else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CROUTE) {
1132             rslot->get_recsrc = snd_mixer_oss_get_recsrc1_route;
1133             rslot->put_recsrc = snd_mixer_oss_put_recsrc1_route;
1134         } else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CAPTURE) {
1135             mixer->mask_recsrc |= 1 << ptr->oss_id;
1136         }
1137         rslot->private_data = pslot;
1138         rslot->private_free = snd_mixer_oss_slot_free;
1139         return 1;
1140     }
1141     return 0;
1142 }
1143 
1144 #ifdef CONFIG_SND_PROC_FS
1145 /*
1146  */
1147 #define MIXER_VOL(name) [SOUND_MIXER_##name] = #name
1148 static const char * const oss_mixer_names[SNDRV_OSS_MAX_MIXERS] = {
1149     MIXER_VOL(VOLUME),
1150     MIXER_VOL(BASS),
1151     MIXER_VOL(TREBLE),
1152     MIXER_VOL(SYNTH),
1153     MIXER_VOL(PCM),
1154     MIXER_VOL(SPEAKER),
1155     MIXER_VOL(LINE),
1156     MIXER_VOL(MIC),
1157     MIXER_VOL(CD),
1158     MIXER_VOL(IMIX),
1159     MIXER_VOL(ALTPCM),
1160     MIXER_VOL(RECLEV),
1161     MIXER_VOL(IGAIN),
1162     MIXER_VOL(OGAIN),
1163     MIXER_VOL(LINE1),
1164     MIXER_VOL(LINE2),
1165     MIXER_VOL(LINE3),
1166     MIXER_VOL(DIGITAL1),
1167     MIXER_VOL(DIGITAL2),
1168     MIXER_VOL(DIGITAL3),
1169     MIXER_VOL(PHONEIN),
1170     MIXER_VOL(PHONEOUT),
1171     MIXER_VOL(VIDEO),
1172     MIXER_VOL(RADIO),
1173     MIXER_VOL(MONITOR),
1174 };
1175     
1176 /*
1177  *  /proc interface
1178  */
1179 
1180 static void snd_mixer_oss_proc_read(struct snd_info_entry *entry,
1181                     struct snd_info_buffer *buffer)
1182 {
1183     struct snd_mixer_oss *mixer = entry->private_data;
1184     int i;
1185 
1186     mutex_lock(&mixer->reg_mutex);
1187     for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) {
1188         struct slot *p;
1189 
1190         if (! oss_mixer_names[i])
1191             continue;
1192         p = (struct slot *)mixer->slots[i].private_data;
1193         snd_iprintf(buffer, "%s ", oss_mixer_names[i]);
1194         if (p && p->assigned)
1195             snd_iprintf(buffer, "\"%s\" %d\n",
1196                     p->assigned->name,
1197                     p->assigned->index);
1198         else
1199             snd_iprintf(buffer, "\"\" 0\n");
1200     }
1201     mutex_unlock(&mixer->reg_mutex);
1202 }
1203 
1204 static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
1205                      struct snd_info_buffer *buffer)
1206 {
1207     struct snd_mixer_oss *mixer = entry->private_data;
1208     char line[128], str[32], idxstr[16];
1209     const char *cptr;
1210     unsigned int idx;
1211     int ch;
1212     struct snd_mixer_oss_assign_table *tbl;
1213     struct slot *slot;
1214 
1215     while (!snd_info_get_line(buffer, line, sizeof(line))) {
1216         cptr = snd_info_get_str(str, line, sizeof(str));
1217         for (ch = 0; ch < SNDRV_OSS_MAX_MIXERS; ch++)
1218             if (oss_mixer_names[ch] && strcmp(oss_mixer_names[ch], str) == 0)
1219                 break;
1220         if (ch >= SNDRV_OSS_MAX_MIXERS) {
1221             pr_err("ALSA: mixer_oss: invalid OSS volume '%s'\n",
1222                    str);
1223             continue;
1224         }
1225         cptr = snd_info_get_str(str, cptr, sizeof(str));
1226         if (! *str) {
1227             /* remove the entry */
1228             mutex_lock(&mixer->reg_mutex);
1229             mixer_slot_clear(&mixer->slots[ch]);
1230             mutex_unlock(&mixer->reg_mutex);
1231             continue;
1232         }
1233         snd_info_get_str(idxstr, cptr, sizeof(idxstr));
1234         idx = simple_strtoul(idxstr, NULL, 10);
1235         if (idx >= 0x4000) { /* too big */
1236             pr_err("ALSA: mixer_oss: invalid index %d\n", idx);
1237             continue;
1238         }
1239         mutex_lock(&mixer->reg_mutex);
1240         slot = (struct slot *)mixer->slots[ch].private_data;
1241         if (slot && slot->assigned &&
1242             slot->assigned->index == idx && ! strcmp(slot->assigned->name, str))
1243             /* not changed */
1244             goto __unlock;
1245         tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
1246         if (!tbl)
1247             goto __unlock;
1248         tbl->oss_id = ch;
1249         tbl->name = kstrdup(str, GFP_KERNEL);
1250         if (! tbl->name) {
1251             kfree(tbl);
1252             goto __unlock;
1253         }
1254         tbl->index = idx;
1255         if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) {
1256             kfree(tbl->name);
1257             kfree(tbl);
1258         }
1259     __unlock:
1260         mutex_unlock(&mixer->reg_mutex);
1261     }
1262 }
1263 
1264 static void snd_mixer_oss_proc_init(struct snd_mixer_oss *mixer)
1265 {
1266     struct snd_info_entry *entry;
1267 
1268     entry = snd_info_create_card_entry(mixer->card, "oss_mixer",
1269                        mixer->card->proc_root);
1270     if (! entry)
1271         return;
1272     entry->content = SNDRV_INFO_CONTENT_TEXT;
1273     entry->mode = S_IFREG | 0644;
1274     entry->c.text.read = snd_mixer_oss_proc_read;
1275     entry->c.text.write = snd_mixer_oss_proc_write;
1276     entry->private_data = mixer;
1277     if (snd_info_register(entry) < 0) {
1278         snd_info_free_entry(entry);
1279         entry = NULL;
1280     }
1281     mixer->proc_entry = entry;
1282 }
1283 
1284 static void snd_mixer_oss_proc_done(struct snd_mixer_oss *mixer)
1285 {
1286     snd_info_free_entry(mixer->proc_entry);
1287     mixer->proc_entry = NULL;
1288 }
1289 #else /* !CONFIG_SND_PROC_FS */
1290 #define snd_mixer_oss_proc_init(mix)
1291 #define snd_mixer_oss_proc_done(mix)
1292 #endif /* CONFIG_SND_PROC_FS */
1293 
1294 static void snd_mixer_oss_build(struct snd_mixer_oss *mixer)
1295 {
1296     static const struct snd_mixer_oss_assign_table table[] = {
1297         { SOUND_MIXER_VOLUME,   "Master",       0 },
1298         { SOUND_MIXER_VOLUME,   "Front",        0 }, /* fallback */
1299         { SOUND_MIXER_BASS, "Tone Control - Bass",  0 },
1300         { SOUND_MIXER_TREBLE,   "Tone Control - Treble", 0 },
1301         { SOUND_MIXER_SYNTH,    "Synth",        0 },
1302         { SOUND_MIXER_SYNTH,    "FM",           0 }, /* fallback */
1303         { SOUND_MIXER_SYNTH,    "Music",        0 }, /* fallback */
1304         { SOUND_MIXER_PCM,  "PCM",          0 },
1305         { SOUND_MIXER_SPEAKER,  "Beep",         0 },
1306         { SOUND_MIXER_SPEAKER,  "PC Speaker",       0 }, /* fallback */
1307         { SOUND_MIXER_SPEAKER,  "Speaker",      0 }, /* fallback */
1308         { SOUND_MIXER_LINE, "Line",         0 },
1309         { SOUND_MIXER_MIC,  "Mic",          0 },
1310         { SOUND_MIXER_CD,   "CD",           0 },
1311         { SOUND_MIXER_IMIX, "Monitor Mix",      0 },
1312         { SOUND_MIXER_ALTPCM,   "PCM",          1 },
1313         { SOUND_MIXER_ALTPCM,   "Headphone",        0 }, /* fallback */
1314         { SOUND_MIXER_ALTPCM,   "Wave",         0 }, /* fallback */
1315         { SOUND_MIXER_RECLEV,   "-- nothing --",    0 },
1316         { SOUND_MIXER_IGAIN,    "Capture",      0 },
1317         { SOUND_MIXER_OGAIN,    "Playback",     0 },
1318         { SOUND_MIXER_LINE1,    "Aux",          0 },
1319         { SOUND_MIXER_LINE2,    "Aux",          1 },
1320         { SOUND_MIXER_LINE3,    "Aux",          2 },
1321         { SOUND_MIXER_DIGITAL1, "Digital",      0 },
1322         { SOUND_MIXER_DIGITAL1, "IEC958",       0 }, /* fallback */
1323         { SOUND_MIXER_DIGITAL1, "IEC958 Optical",   0 }, /* fallback */
1324         { SOUND_MIXER_DIGITAL1, "IEC958 Coaxial",   0 }, /* fallback */
1325         { SOUND_MIXER_DIGITAL2, "Digital",      1 },
1326         { SOUND_MIXER_DIGITAL3, "Digital",      2 },
1327         { SOUND_MIXER_PHONEIN,  "Phone",        0 },
1328         { SOUND_MIXER_PHONEOUT, "Master Mono",      0 },
1329         { SOUND_MIXER_PHONEOUT, "Speaker",      0 }, /*fallback*/
1330         { SOUND_MIXER_PHONEOUT, "Mono",         0 }, /*fallback*/
1331         { SOUND_MIXER_PHONEOUT, "Phone",        0 }, /* fallback */
1332         { SOUND_MIXER_VIDEO,    "Video",        0 },
1333         { SOUND_MIXER_RADIO,    "Radio",        0 },
1334         { SOUND_MIXER_MONITOR,  "Monitor",      0 }
1335     };
1336     unsigned int idx;
1337     
1338     for (idx = 0; idx < ARRAY_SIZE(table); idx++)
1339         snd_mixer_oss_build_input(mixer, &table[idx], 0, 0);
1340     if (mixer->mask_recsrc) {
1341         mixer->get_recsrc = snd_mixer_oss_get_recsrc2;
1342         mixer->put_recsrc = snd_mixer_oss_put_recsrc2;
1343     }
1344 }
1345 
1346 /*
1347  *
1348  */
1349 
1350 static int snd_mixer_oss_free1(void *private)
1351 {
1352     struct snd_mixer_oss *mixer = private;
1353     struct snd_card *card;
1354     int idx;
1355  
1356     if (!mixer)
1357         return 0;
1358     card = mixer->card;
1359     if (snd_BUG_ON(mixer != card->mixer_oss))
1360         return -ENXIO;
1361     card->mixer_oss = NULL;
1362     for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) {
1363         struct snd_mixer_oss_slot *chn = &mixer->slots[idx];
1364         if (chn->private_free)
1365             chn->private_free(chn);
1366     }
1367     kfree(mixer);
1368     return 0;
1369 }
1370 
1371 static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
1372 {
1373     struct snd_mixer_oss *mixer;
1374 
1375     if (cmd == SND_MIXER_OSS_NOTIFY_REGISTER) {
1376         int idx, err;
1377 
1378         mixer = kcalloc(2, sizeof(*mixer), GFP_KERNEL);
1379         if (mixer == NULL)
1380             return -ENOMEM;
1381         mutex_init(&mixer->reg_mutex);
1382         err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER,
1383                           card, 0,
1384                           &snd_mixer_oss_f_ops, card);
1385         if (err < 0) {
1386             dev_err(card->dev,
1387                 "unable to register OSS mixer device %i:%i\n",
1388                 card->number, 0);
1389             kfree(mixer);
1390             return err;
1391         }
1392         mixer->oss_dev_alloc = 1;
1393         mixer->card = card;
1394         if (*card->mixername)
1395             strscpy(mixer->name, card->mixername, sizeof(mixer->name));
1396         else
1397             snprintf(mixer->name, sizeof(mixer->name),
1398                  "mixer%i", card->number);
1399 #ifdef SNDRV_OSS_INFO_DEV_MIXERS
1400         snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIXERS,
1401                       card->number,
1402                       mixer->name);
1403 #endif
1404         for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++)
1405             mixer->slots[idx].number = idx;
1406         card->mixer_oss = mixer;
1407         snd_mixer_oss_build(mixer);
1408         snd_mixer_oss_proc_init(mixer);
1409     } else {
1410         mixer = card->mixer_oss;
1411         if (mixer == NULL)
1412             return 0;
1413         if (mixer->oss_dev_alloc) {
1414 #ifdef SNDRV_OSS_INFO_DEV_MIXERS
1415             snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
1416 #endif
1417             snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
1418             mixer->oss_dev_alloc = 0;
1419         }
1420         if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT)
1421             return 0;
1422         snd_mixer_oss_proc_done(mixer);
1423         return snd_mixer_oss_free1(mixer);
1424     }
1425     return 0;
1426 }
1427 
1428 static int __init alsa_mixer_oss_init(void)
1429 {
1430     struct snd_card *card;
1431     int idx;
1432     
1433     snd_mixer_oss_notify_callback = snd_mixer_oss_notify_handler;
1434     for (idx = 0; idx < SNDRV_CARDS; idx++) {
1435         card = snd_card_ref(idx);
1436         if (card) {
1437             snd_mixer_oss_notify_handler(card, SND_MIXER_OSS_NOTIFY_REGISTER);
1438             snd_card_unref(card);
1439         }
1440     }
1441     return 0;
1442 }
1443 
1444 static void __exit alsa_mixer_oss_exit(void)
1445 {
1446     struct snd_card *card;
1447     int idx;
1448 
1449     snd_mixer_oss_notify_callback = NULL;
1450     for (idx = 0; idx < SNDRV_CARDS; idx++) {
1451         card = snd_card_ref(idx);
1452         if (card) {
1453             snd_mixer_oss_notify_handler(card, SND_MIXER_OSS_NOTIFY_FREE);
1454             snd_card_unref(card);
1455         }
1456     }
1457 }
1458 
1459 module_init(alsa_mixer_oss_init)
1460 module_exit(alsa_mixer_oss_exit)