linux/sound/core/oss/mixer_oss.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  OSS emulation layer for the mixer interface
   4 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
   5 */
   6
   7#include <linux/init.h>
   8#include <linux/slab.h>
   9#include <linux/time.h>
  10#include <linux/string.h>
  11#include <linux/module.h>
  12#include <linux/compat.h>
  13#include <sound/core.h>
  14#include <sound/minors.h>
  15#include <sound/control.h>
  16#include <sound/info.h>
  17#include <sound/mixer_oss.h>
  18#include <linux/soundcard.h>
  19
  20#define OSS_ALSAEMULVER         _SIOR ('M', 249, int)
  21
  22MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
  23MODULE_DESCRIPTION("Mixer OSS emulation for ALSA.");
  24MODULE_LICENSE("GPL");
  25MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MIXER);
  26
  27static int snd_mixer_oss_open(struct inode *inode, struct file *file)
  28{
  29        struct snd_card *card;
  30        struct snd_mixer_oss_file *fmixer;
  31        int err;
  32
  33        err = nonseekable_open(inode, file);
  34        if (err < 0)
  35                return err;
  36
  37        card = snd_lookup_oss_minor_data(iminor(inode),
  38                                         SNDRV_OSS_DEVICE_TYPE_MIXER);
  39        if (card == NULL)
  40                return -ENODEV;
  41        if (card->mixer_oss == NULL) {
  42                snd_card_unref(card);
  43                return -ENODEV;
  44        }
  45        err = snd_card_file_add(card, file);
  46        if (err < 0) {
  47                snd_card_unref(card);
  48                return err;
  49        }
  50        fmixer = kzalloc(sizeof(*fmixer), GFP_KERNEL);
  51        if (fmixer == NULL) {
  52                snd_card_file_remove(card, file);
  53                snd_card_unref(card);
  54                return -ENOMEM;
  55        }
  56        fmixer->card = card;
  57        fmixer->mixer = card->mixer_oss;
  58        file->private_data = fmixer;
  59        if (!try_module_get(card->module)) {
  60                kfree(fmixer);
  61                snd_card_file_remove(card, file);
  62                snd_card_unref(card);
  63                return -EFAULT;
  64        }
  65        snd_card_unref(card);
  66        return 0;
  67}
  68
  69static int snd_mixer_oss_release(struct inode *inode, struct file *file)
  70{
  71        struct snd_mixer_oss_file *fmixer;
  72
  73        if (file->private_data) {
  74                fmixer = file->private_data;
  75                module_put(fmixer->card->module);
  76                snd_card_file_remove(fmixer->card, file);
  77                kfree(fmixer);
  78        }
  79        return 0;
  80}
  81
  82static int snd_mixer_oss_info(struct snd_mixer_oss_file *fmixer,
  83                              mixer_info __user *_info)
  84{
  85        struct snd_card *card = fmixer->card;
  86        struct snd_mixer_oss *mixer = fmixer->mixer;
  87        struct mixer_info info;
  88        
  89        memset(&info, 0, sizeof(info));
  90        strscpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
  91        strscpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
  92        info.modify_counter = card->mixer_oss_change_count;
  93        if (copy_to_user(_info, &info, sizeof(info)))
  94                return -EFAULT;
  95        return 0;
  96}
  97
  98static int snd_mixer_oss_info_obsolete(struct snd_mixer_oss_file *fmixer,
  99                                       _old_mixer_info __user *_info)
 100{
 101        struct snd_card *card = fmixer->card;
 102        struct snd_mixer_oss *mixer = fmixer->mixer;
 103        _old_mixer_info info;
 104        
 105        memset(&info, 0, sizeof(info));
 106        strscpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
 107        strscpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
 108        if (copy_to_user(_info, &info, sizeof(info)))
 109                return -EFAULT;
 110        return 0;
 111}
 112
 113static int snd_mixer_oss_caps(struct snd_mixer_oss_file *fmixer)
 114{
 115        struct snd_mixer_oss *mixer = fmixer->mixer;
 116        int result = 0;
 117
 118        if (mixer == NULL)
 119                return -EIO;
 120        if (mixer->get_recsrc && mixer->put_recsrc)
 121                result |= SOUND_CAP_EXCL_INPUT;
 122        return result;
 123}
 124
 125static int snd_mixer_oss_devmask(struct snd_mixer_oss_file *fmixer)
 126{
 127        struct snd_mixer_oss *mixer = fmixer->mixer;
 128        struct snd_mixer_oss_slot *pslot;
 129        int result = 0, chn;
 130
 131        if (mixer == NULL)
 132                return -EIO;
 133        mutex_lock(&mixer->reg_mutex);
 134        for (chn = 0; chn < 31; chn++) {
 135                pslot = &mixer->slots[chn];
 136                if (pslot->put_volume || pslot->put_recsrc)
 137                        result |= 1 << chn;
 138        }
 139        mutex_unlock(&mixer->reg_mutex);
 140        return result;
 141}
 142
 143static int snd_mixer_oss_stereodevs(struct snd_mixer_oss_file *fmixer)
 144{
 145        struct snd_mixer_oss *mixer = fmixer->mixer;
 146        struct snd_mixer_oss_slot *pslot;
 147        int result = 0, chn;
 148
 149        if (mixer == NULL)
 150                return -EIO;
 151        mutex_lock(&mixer->reg_mutex);
 152        for (chn = 0; chn < 31; chn++) {
 153                pslot = &mixer->slots[chn];
 154                if (pslot->put_volume && pslot->stereo)
 155                        result |= 1 << chn;
 156        }
 157        mutex_unlock(&mixer->reg_mutex);
 158        return result;
 159}
 160
 161static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer)
 162{
 163        struct snd_mixer_oss *mixer = fmixer->mixer;
 164        int result = 0;
 165
 166        if (mixer == NULL)
 167                return -EIO;
 168        mutex_lock(&mixer->reg_mutex);
 169        if (mixer->put_recsrc && mixer->get_recsrc) {   /* exclusive */
 170                result = mixer->mask_recsrc;
 171        } else {
 172                struct snd_mixer_oss_slot *pslot;
 173                int chn;
 174                for (chn = 0; chn < 31; chn++) {
 175                        pslot = &mixer->slots[chn];
 176                        if (pslot->put_recsrc)
 177                                result |= 1 << chn;
 178                }
 179        }
 180        mutex_unlock(&mixer->reg_mutex);
 181        return result;
 182}
 183
 184static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
 185{
 186        struct snd_mixer_oss *mixer = fmixer->mixer;
 187        int result = 0;
 188
 189        if (mixer == NULL)
 190                return -EIO;
 191        mutex_lock(&mixer->reg_mutex);
 192        if (mixer->put_recsrc && mixer->get_recsrc) {   /* exclusive */
 193                unsigned int index;
 194                result = mixer->get_recsrc(fmixer, &index);
 195                if (result < 0)
 196                        goto unlock;
 197                result = 1 << index;
 198        } else {
 199                struct snd_mixer_oss_slot *pslot;
 200                int chn;
 201                for (chn = 0; chn < 31; chn++) {
 202                        pslot = &mixer->slots[chn];
 203                        if (pslot->get_recsrc) {
 204                                int active = 0;
 205                                pslot->get_recsrc(fmixer, pslot, &active);
 206                                if (active)
 207                                        result |= 1 << chn;
 208                        }
 209                }
 210        }
 211        mixer->oss_recsrc = result;
 212 unlock:
 213        mutex_unlock(&mixer->reg_mutex);
 214        return result;
 215}
 216
 217static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsrc)
 218{
 219        struct snd_mixer_oss *mixer = fmixer->mixer;
 220        struct snd_mixer_oss_slot *pslot;
 221        int chn, active;
 222        unsigned int index;
 223        int result = 0;
 224
 225        if (mixer == NULL)
 226                return -EIO;
 227        mutex_lock(&mixer->reg_mutex);
 228        if (mixer->get_recsrc && mixer->put_recsrc) {   /* exclusive input */
 229                if (recsrc & ~mixer->oss_recsrc)
 230                        recsrc &= ~mixer->oss_recsrc;
 231                mixer->put_recsrc(fmixer, ffz(~recsrc));
 232                mixer->get_recsrc(fmixer, &index);
 233                result = 1 << index;
 234        }
 235        for (chn = 0; chn < 31; chn++) {
 236                pslot = &mixer->slots[chn];
 237                if (pslot->put_recsrc) {
 238                        active = (recsrc & (1 << chn)) ? 1 : 0;
 239                        pslot->put_recsrc(fmixer, pslot, active);
 240                }
 241        }
 242        if (! result) {
 243                for (chn = 0; chn < 31; chn++) {
 244                        pslot = &mixer->slots[chn];
 245                        if (pslot->get_recsrc) {
 246                                active = 0;
 247                                pslot->get_recsrc(fmixer, pslot, &active);
 248                                if (active)
 249                                        result |= 1 << chn;
 250                        }
 251                }
 252        }
 253        mutex_unlock(&mixer->reg_mutex);
 254        return result;
 255}
 256
 257static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
 258{
 259        struct snd_mixer_oss *mixer = fmixer->mixer;
 260        struct snd_mixer_oss_slot *pslot;
 261        int result = 0, left, right;
 262
 263        if (mixer == NULL || slot > 30)
 264                return -EIO;
 265        mutex_lock(&mixer->reg_mutex);
 266        pslot = &mixer->slots[slot];
 267        left = pslot->volume[0];
 268        right = pslot->volume[1];
 269        if (pslot->get_volume)
 270                result = pslot->get_volume(fmixer, pslot, &left, &right);
 271        if (!pslot->stereo)
 272                right = left;
 273        if (snd_BUG_ON(left < 0 || left > 100)) {
 274                result = -EIO;
 275                goto unlock;
 276        }
 277        if (snd_BUG_ON(right < 0 || right > 100)) {
 278                result = -EIO;
 279                goto unlock;
 280        }
 281        if (result >= 0) {
 282                pslot->volume[0] = left;
 283                pslot->volume[1] = right;
 284                result = (left & 0xff) | ((right & 0xff) << 8);
 285        }
 286 unlock:
 287        mutex_unlock(&mixer->reg_mutex);
 288        return result;
 289}
 290
 291static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
 292                                    int slot, int volume)
 293{
 294        struct snd_mixer_oss *mixer = fmixer->mixer;
 295        struct snd_mixer_oss_slot *pslot;
 296        int result = 0, left = volume & 0xff, right = (volume >> 8) & 0xff;
 297
 298        if (mixer == NULL || slot > 30)
 299                return -EIO;
 300        mutex_lock(&mixer->reg_mutex);
 301        pslot = &mixer->slots[slot];
 302        if (left > 100)
 303                left = 100;
 304        if (right > 100)
 305                right = 100;
 306        if (!pslot->stereo)
 307                right = left;
 308        if (pslot->put_volume)
 309                result = pslot->put_volume(fmixer, pslot, left, right);
 310        if (result < 0)
 311                goto unlock;
 312        pslot->volume[0] = left;
 313        pslot->volume[1] = right;
 314        result = (left & 0xff) | ((right & 0xff) << 8);
 315 unlock:
 316        mutex_unlock(&mixer->reg_mutex);
 317        return result;
 318}
 319
 320static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int cmd, unsigned long arg)
 321{
 322        void __user *argp = (void __user *)arg;
 323        int __user *p = argp;
 324        int tmp;
 325
 326        if (snd_BUG_ON(!fmixer))
 327                return -ENXIO;
 328        if (((cmd >> 8) & 0xff) == 'M') {
 329                switch (cmd) {
 330                case SOUND_MIXER_INFO:
 331                        return snd_mixer_oss_info(fmixer, argp);
 332                case SOUND_OLD_MIXER_INFO:
 333                        return snd_mixer_oss_info_obsolete(fmixer, argp);
 334                case SOUND_MIXER_WRITE_RECSRC:
 335                        if (get_user(tmp, p))
 336                                return -EFAULT;
 337                        tmp = snd_mixer_oss_set_recsrc(fmixer, tmp);
 338                        if (tmp < 0)
 339                                return tmp;
 340                        return put_user(tmp, p);
 341                case OSS_GETVERSION:
 342                        return put_user(SNDRV_OSS_VERSION, p);
 343                case OSS_ALSAEMULVER:
 344                        return put_user(1, p);
 345                case SOUND_MIXER_READ_DEVMASK:
 346                        tmp = snd_mixer_oss_devmask(fmixer);
 347                        if (tmp < 0)
 348                                return tmp;
 349                        return put_user(tmp, p);
 350                case SOUND_MIXER_READ_STEREODEVS:
 351                        tmp = snd_mixer_oss_stereodevs(fmixer);
 352                        if (tmp < 0)
 353                                return tmp;
 354                        return put_user(tmp, p);
 355                case SOUND_MIXER_READ_RECMASK:
 356                        tmp = snd_mixer_oss_recmask(fmixer);
 357                        if (tmp < 0)
 358                                return tmp;
 359                        return put_user(tmp, p);
 360                case SOUND_MIXER_READ_CAPS:
 361                        tmp = snd_mixer_oss_caps(fmixer);
 362                        if (tmp < 0)
 363                                return tmp;
 364                        return put_user(tmp, p);
 365                case SOUND_MIXER_READ_RECSRC:
 366                        tmp = snd_mixer_oss_get_recsrc(fmixer);
 367                        if (tmp < 0)
 368                                return tmp;
 369                        return put_user(tmp, p);
 370                }
 371        }
 372        if (cmd & SIOC_IN) {
 373                if (get_user(tmp, p))
 374                        return -EFAULT;
 375                tmp = snd_mixer_oss_set_volume(fmixer, cmd & 0xff, tmp);
 376                if (tmp < 0)
 377                        return tmp;
 378                return put_user(tmp, p);
 379        } else if (cmd & SIOC_OUT) {
 380                tmp = snd_mixer_oss_get_volume(fmixer, cmd & 0xff);
 381                if (tmp < 0)
 382                        return tmp;
 383                return put_user(tmp, p);
 384        }
 385        return -ENXIO;
 386}
 387
 388static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 389{
 390        return snd_mixer_oss_ioctl1(file->private_data, cmd, arg);
 391}
 392
 393int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg)
 394{
 395        struct snd_mixer_oss_file fmixer;
 396        
 397        if (snd_BUG_ON(!card))
 398                return -ENXIO;
 399        if (card->mixer_oss == NULL)
 400                return -ENXIO;
 401        memset(&fmixer, 0, sizeof(fmixer));
 402        fmixer.card = card;
 403        fmixer.mixer = card->mixer_oss;
 404        return snd_mixer_oss_ioctl1(&fmixer, cmd, arg);
 405}
 406EXPORT_SYMBOL(snd_mixer_oss_ioctl_card);
 407
 408#ifdef CONFIG_COMPAT
 409/* all compatible */
 410static long snd_mixer_oss_ioctl_compat(struct file *file, unsigned int cmd,
 411                                       unsigned long arg)
 412{
 413        return snd_mixer_oss_ioctl1(file->private_data, cmd,
 414                                    (unsigned long)compat_ptr(arg));
 415}
 416#else
 417#define snd_mixer_oss_ioctl_compat      NULL
 418#endif
 419
 420/*
 421 *  REGISTRATION PART
 422 */
 423
 424static const struct file_operations snd_mixer_oss_f_ops =
 425{
 426        .owner =        THIS_MODULE,
 427        .open =         snd_mixer_oss_open,
 428        .release =      snd_mixer_oss_release,
 429        .llseek =       no_llseek,
 430        .unlocked_ioctl =       snd_mixer_oss_ioctl,
 431        .compat_ioctl = snd_mixer_oss_ioctl_compat,
 432};
 433
 434/*
 435 *  utilities
 436 */
 437
 438static long snd_mixer_oss_conv(long val, long omin, long omax, long nmin, long nmax)
 439{
 440        long orange = omax - omin, nrange = nmax - nmin;
 441        
 442        if (orange == 0)
 443                return 0;
 444        return DIV_ROUND_CLOSEST(nrange * (val - omin), orange) + nmin;
 445}
 446
 447/* convert from alsa native to oss values (0-100) */
 448static long snd_mixer_oss_conv1(long val, long min, long max, int *old)
 449{
 450        if (val == snd_mixer_oss_conv(*old, 0, 100, min, max))
 451                return *old;
 452        return snd_mixer_oss_conv(val, min, max, 0, 100);
 453}
 454
 455/* convert from oss to alsa native values */
 456static long snd_mixer_oss_conv2(long val, long min, long max)
 457{
 458        return snd_mixer_oss_conv(val, 0, 100, min, max);
 459}
 460
 461#if 0
 462static void snd_mixer_oss_recsrce_set(struct snd_card *card, int slot)
 463{
 464        struct snd_mixer_oss *mixer = card->mixer_oss;
 465        if (mixer)
 466                mixer->mask_recsrc |= 1 << slot;
 467}
 468
 469static int snd_mixer_oss_recsrce_get(struct snd_card *card, int slot)
 470{
 471        struct snd_mixer_oss *mixer = card->mixer_oss;
 472        if (mixer && (mixer->mask_recsrc & (1 << slot)))
 473                return 1;
 474        return 0;
 475}
 476#endif
 477
 478#define SNDRV_MIXER_OSS_SIGNATURE               0x65999250
 479
 480#define SNDRV_MIXER_OSS_ITEM_GLOBAL     0
 481#define SNDRV_MIXER_OSS_ITEM_GSWITCH    1
 482#define SNDRV_MIXER_OSS_ITEM_GROUTE     2
 483#define SNDRV_MIXER_OSS_ITEM_GVOLUME    3
 484#define SNDRV_MIXER_OSS_ITEM_PSWITCH    4
 485#define SNDRV_MIXER_OSS_ITEM_PROUTE     5
 486#define SNDRV_MIXER_OSS_ITEM_PVOLUME    6
 487#define SNDRV_MIXER_OSS_ITEM_CSWITCH    7
 488#define SNDRV_MIXER_OSS_ITEM_CROUTE     8
 489#define SNDRV_MIXER_OSS_ITEM_CVOLUME    9
 490#define SNDRV_MIXER_OSS_ITEM_CAPTURE    10
 491
 492#define SNDRV_MIXER_OSS_ITEM_COUNT      11
 493
 494#define SNDRV_MIXER_OSS_PRESENT_GLOBAL  (1<<0)
 495#define SNDRV_MIXER_OSS_PRESENT_GSWITCH (1<<1)
 496#define SNDRV_MIXER_OSS_PRESENT_GROUTE  (1<<2)
 497#define SNDRV_MIXER_OSS_PRESENT_GVOLUME (1<<3)
 498#define SNDRV_MIXER_OSS_PRESENT_PSWITCH (1<<4)
 499#define SNDRV_MIXER_OSS_PRESENT_PROUTE  (1<<5)
 500#define SNDRV_MIXER_OSS_PRESENT_PVOLUME (1<<6)
 501#define SNDRV_MIXER_OSS_PRESENT_CSWITCH (1<<7)
 502#define SNDRV_MIXER_OSS_PRESENT_CROUTE  (1<<8)
 503#define SNDRV_MIXER_OSS_PRESENT_CVOLUME (1<<9)
 504#define SNDRV_MIXER_OSS_PRESENT_CAPTURE (1<<10)
 505
 506struct slot {
 507        unsigned int signature;
 508        unsigned int present;
 509        unsigned int channels;
 510        unsigned int numid[SNDRV_MIXER_OSS_ITEM_COUNT];
 511        unsigned int capture_item;
 512        const struct snd_mixer_oss_assign_table *assigned;
 513        unsigned int allocated: 1;
 514};
 515
 516#define ID_UNKNOWN      ((unsigned int)-1)
 517
 518static struct snd_kcontrol *snd_mixer_oss_test_id(struct snd_mixer_oss *mixer, const char *name, int index)
 519{
 520        struct snd_card *card = mixer->card;
 521        struct snd_ctl_elem_id id;
 522        
 523        memset(&id, 0, sizeof(id));
 524        id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
 525        strscpy(id.name, name, sizeof(id.name));
 526        id.index = index;
 527        return snd_ctl_find_id(card, &id);
 528}
 529
 530static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer,
 531                                          struct snd_mixer_oss_slot *pslot,
 532                                          unsigned int numid,
 533                                          int *left, int *right)
 534{
 535        struct snd_ctl_elem_info *uinfo;
 536        struct snd_ctl_elem_value *uctl;
 537        struct snd_kcontrol *kctl;
 538        struct snd_card *card = fmixer->card;
 539
 540        if (numid == ID_UNKNOWN)
 541                return;
 542        down_read(&card->controls_rwsem);
 543        kctl = snd_ctl_find_numid(card, numid);
 544        if (!kctl) {
 545                up_read(&card->controls_rwsem);
 546                return;
 547        }
 548        uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
 549        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
 550        if (uinfo == NULL || uctl == NULL)
 551                goto __unalloc;
 552        if (kctl->info(kctl, uinfo))
 553                goto __unalloc;
 554        if (kctl->get(kctl, uctl))
 555                goto __unalloc;
 556        if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
 557            uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
 558                goto __unalloc;
 559        *left = snd_mixer_oss_conv1(uctl->value.integer.value[0], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[0]);
 560        if (uinfo->count > 1)
 561                *right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]);
 562      __unalloc:
 563        up_read(&card->controls_rwsem);
 564        kfree(uctl);
 565        kfree(uinfo);
 566}
 567
 568static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
 569                                         struct snd_mixer_oss_slot *pslot,
 570                                         unsigned int numid,
 571                                         int *left, int *right,
 572                                         int route)
 573{
 574        struct snd_ctl_elem_info *uinfo;
 575        struct snd_ctl_elem_value *uctl;
 576        struct snd_kcontrol *kctl;
 577        struct snd_card *card = fmixer->card;
 578
 579        if (numid == ID_UNKNOWN)
 580                return;
 581        down_read(&card->controls_rwsem);
 582        kctl = snd_ctl_find_numid(card, numid);
 583        if (!kctl) {
 584                up_read(&card->controls_rwsem);
 585                return;
 586        }
 587        uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
 588        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
 589        if (uinfo == NULL || uctl == NULL)
 590                goto __unalloc;
 591        if (kctl->info(kctl, uinfo))
 592                goto __unalloc;
 593        if (kctl->get(kctl, uctl))
 594                goto __unalloc;
 595        if (!uctl->value.integer.value[0]) {
 596                *left = 0;
 597                if (uinfo->count == 1)
 598                        *right = 0;
 599        }
 600        if (uinfo->count > 1 && !uctl->value.integer.value[route ? 3 : 1])
 601                *right = 0;
 602      __unalloc:
 603        up_read(&card->controls_rwsem);
 604        kfree(uctl);
 605        kfree(uinfo);
 606}
 607
 608static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer,
 609                                     struct snd_mixer_oss_slot *pslot,
 610                                     int *left, int *right)
 611{
 612        struct slot *slot = pslot->private_data;
 613        
 614        *left = *right = 100;
 615        if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
 616                snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
 617        } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) {
 618                snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right);
 619        } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) {
 620                snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right);
 621        }
 622        if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) {
 623                snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0);
 624        } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) {
 625                snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0);
 626        } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) {
 627                snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1);
 628        } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) {
 629                snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1);
 630        }
 631        return 0;
 632}
 633
 634static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
 635                                          struct snd_mixer_oss_slot *pslot,
 636                                          unsigned int numid,
 637                                          int left, int right)
 638{
 639        struct snd_ctl_elem_info *uinfo;
 640        struct snd_ctl_elem_value *uctl;
 641        struct snd_kcontrol *kctl;
 642        struct snd_card *card = fmixer->card;
 643        int res;
 644
 645        if (numid == ID_UNKNOWN)
 646                return;
 647        down_read(&card->controls_rwsem);
 648        kctl = snd_ctl_find_numid(card, numid);
 649        if (!kctl) {
 650                up_read(&card->controls_rwsem);
 651                return;
 652        }
 653        uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
 654        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
 655        if (uinfo == NULL || uctl == NULL)
 656                goto __unalloc;
 657        if (kctl->info(kctl, uinfo))
 658                goto __unalloc;
 659        if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
 660            uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
 661                goto __unalloc;
 662        uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max);
 663        if (uinfo->count > 1)
 664                uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max);
 665        res = kctl->put(kctl, uctl);
 666        if (res < 0)
 667                goto __unalloc;
 668        if (res > 0)
 669                snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
 670      __unalloc:
 671        up_read(&card->controls_rwsem);
 672        kfree(uctl);
 673        kfree(uinfo);
 674}
 675
 676static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
 677                                         struct snd_mixer_oss_slot *pslot,
 678                                         unsigned int numid,
 679                                         int left, int right,
 680                                         int route)
 681{
 682        struct snd_ctl_elem_info *uinfo;
 683        struct snd_ctl_elem_value *uctl;
 684        struct snd_kcontrol *kctl;
 685        struct snd_card *card = fmixer->card;
 686        int res;
 687
 688        if (numid == ID_UNKNOWN)
 689                return;
 690        down_read(&card->controls_rwsem);
 691        kctl = snd_ctl_find_numid(card, numid);
 692        if (!kctl) {
 693                up_read(&card->controls_rwsem);
 694                return;
 695        }
 696        uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
 697        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
 698        if (uinfo == NULL || uctl == NULL)
 699                goto __unalloc;
 700        if (kctl->info(kctl, uinfo))
 701                goto __unalloc;
 702        if (uinfo->count > 1) {
 703                uctl->value.integer.value[0] = left > 0 ? 1 : 0;
 704                uctl->value.integer.value[route ? 3 : 1] = right > 0 ? 1 : 0;
 705                if (route) {
 706                        uctl->value.integer.value[1] =
 707                        uctl->value.integer.value[2] = 0;
 708                }
 709        } else {
 710                uctl->value.integer.value[0] = (left > 0 || right > 0) ? 1 : 0;
 711        }
 712        res = kctl->put(kctl, uctl);
 713        if (res < 0)
 714                goto __unalloc;
 715        if (res > 0)
 716                snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
 717      __unalloc:
 718        up_read(&card->controls_rwsem);
 719        kfree(uctl);
 720        kfree(uinfo);
 721}
 722
 723static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer,
 724                                     struct snd_mixer_oss_slot *pslot,
 725                                     int left, int right)
 726{
 727        struct slot *slot = pslot->private_data;
 728        
 729        if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
 730                snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
 731                if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME)
 732                        snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right);
 733        } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME) {
 734                snd_mixer_oss_put_volume1_vol(fmixer, pslot,
 735                        slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right);
 736        } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) {
 737                snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right);
 738        } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) {
 739                snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right);
 740        }
 741        if (left || right) {
 742                if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH)
 743                        snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0);
 744                if (slot->present & SNDRV_MIXER_OSS_PRESENT_CSWITCH)
 745                        snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], left, right, 0);
 746                if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH)
 747                        snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0);
 748                if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE)
 749                        snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1);
 750                if (slot->present & SNDRV_MIXER_OSS_PRESENT_CROUTE)
 751                        snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], left, right, 1);
 752                if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE)
 753                        snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1);
 754        } else {
 755                if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) {
 756                        snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0);
 757                } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CSWITCH) {
 758                        snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], left, right, 0);
 759                } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) {
 760                        snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0);
 761                } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) {
 762                        snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1);
 763                } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CROUTE) {
 764                        snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], left, right, 1);
 765                } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) {
 766                        snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1);
 767                }
 768        }
 769        return 0;
 770}
 771
 772static int snd_mixer_oss_get_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
 773                                        struct snd_mixer_oss_slot *pslot,
 774                                        int *active)
 775{
 776        struct slot *slot = pslot->private_data;
 777        int left, right;
 778        
 779        left = right = 1;
 780        snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], &left, &right, 0);
 781        *active = (left || right) ? 1 : 0;
 782        return 0;
 783}
 784
 785static int snd_mixer_oss_get_recsrc1_route(struct snd_mixer_oss_file *fmixer,
 786                                           struct snd_mixer_oss_slot *pslot,
 787                                           int *active)
 788{
 789        struct slot *slot = pslot->private_data;
 790        int left, right;
 791        
 792        left = right = 1;
 793        snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], &left, &right, 1);
 794        *active = (left || right) ? 1 : 0;
 795        return 0;
 796}
 797
 798static int snd_mixer_oss_put_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
 799                                        struct snd_mixer_oss_slot *pslot,
 800                                        int active)
 801{
 802        struct slot *slot = pslot->private_data;
 803        
 804        snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0);
 805        return 0;
 806}
 807
 808static int snd_mixer_oss_put_recsrc1_route(struct snd_mixer_oss_file *fmixer,
 809                                           struct snd_mixer_oss_slot *pslot,
 810                                           int active)
 811{
 812        struct slot *slot = pslot->private_data;
 813        
 814        snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1);
 815        return 0;
 816}
 817
 818static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int *active_index)
 819{
 820        struct snd_card *card = fmixer->card;
 821        struct snd_mixer_oss *mixer = fmixer->mixer;
 822        struct snd_kcontrol *kctl;
 823        struct snd_mixer_oss_slot *pslot;
 824        struct slot *slot;
 825        struct snd_ctl_elem_info *uinfo;
 826        struct snd_ctl_elem_value *uctl;
 827        int err, idx;
 828        
 829        uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
 830        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
 831        if (uinfo == NULL || uctl == NULL) {
 832                err = -ENOMEM;
 833                goto __free_only;
 834        }
 835        down_read(&card->controls_rwsem);
 836        kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
 837        if (! kctl) {
 838                err = -ENOENT;
 839                goto __unlock;
 840        }
 841        err = kctl->info(kctl, uinfo);
 842        if (err < 0)
 843                goto __unlock;
 844        err = kctl->get(kctl, uctl);
 845        if (err < 0)
 846                goto __unlock;
 847        for (idx = 0; idx < 32; idx++) {
 848                if (!(mixer->mask_recsrc & (1 << idx)))
 849                        continue;
 850                pslot = &mixer->slots[idx];
 851                slot = pslot->private_data;
 852                if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
 853                        continue;
 854                if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
 855                        continue;
 856                if (slot->capture_item == uctl->value.enumerated.item[0]) {
 857                        *active_index = idx;
 858                        break;
 859                }
 860        }
 861        err = 0;
 862      __unlock:
 863        up_read(&card->controls_rwsem);
 864      __free_only:
 865        kfree(uctl);
 866        kfree(uinfo);
 867        return err;
 868}
 869
 870static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int active_index)
 871{
 872        struct snd_card *card = fmixer->card;
 873        struct snd_mixer_oss *mixer = fmixer->mixer;
 874        struct snd_kcontrol *kctl;
 875        struct snd_mixer_oss_slot *pslot;
 876        struct slot *slot = NULL;
 877        struct snd_ctl_elem_info *uinfo;
 878        struct snd_ctl_elem_value *uctl;
 879        int err;
 880        unsigned int idx;
 881
 882        uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
 883        uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
 884        if (uinfo == NULL || uctl == NULL) {
 885                err = -ENOMEM;
 886                goto __free_only;
 887        }
 888        down_read(&card->controls_rwsem);
 889        kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
 890        if (! kctl) {
 891                err = -ENOENT;
 892                goto __unlock;
 893        }
 894        err = kctl->info(kctl, uinfo);
 895        if (err < 0)
 896                goto __unlock;
 897        for (idx = 0; idx < 32; idx++) {
 898                if (!(mixer->mask_recsrc & (1 << idx)))
 899                        continue;
 900                pslot = &mixer->slots[idx];
 901                slot = pslot->private_data;
 902                if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
 903                        continue;
 904                if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
 905                        continue;
 906                if (idx == active_index)
 907                        break;
 908                slot = NULL;
 909        }
 910        if (! slot)
 911                goto __unlock;
 912        for (idx = 0; idx < uinfo->count; idx++)
 913                uctl->value.enumerated.item[idx] = slot->capture_item;
 914        err = kctl->put(kctl, uctl);
 915        if (err > 0)
 916                snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
 917        err = 0;
 918      __unlock:
 919        up_read(&card->controls_rwsem);
 920      __free_only:
 921        kfree(uctl);
 922        kfree(uinfo);
 923        return err;
 924}
 925
 926struct snd_mixer_oss_assign_table {
 927        int oss_id;
 928        const char *name;
 929        int index;
 930};
 931
 932static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *slot, const char *name, int index, int item)
 933{
 934        struct snd_ctl_elem_info *info;
 935        struct snd_kcontrol *kcontrol;
 936        struct snd_card *card = mixer->card;
 937        int err;
 938
 939        down_read(&card->controls_rwsem);
 940        kcontrol = snd_mixer_oss_test_id(mixer, name, index);
 941        if (kcontrol == NULL) {
 942                up_read(&card->controls_rwsem);
 943                return 0;
 944        }
 945        info = kmalloc(sizeof(*info), GFP_KERNEL);
 946        if (! info) {
 947                up_read(&card->controls_rwsem);
 948                return -ENOMEM;
 949        }
 950        err = kcontrol->info(kcontrol, info);
 951        if (err < 0) {
 952                up_read(&card->controls_rwsem);
 953                kfree(info);
 954                return err;
 955        }
 956        slot->numid[item] = kcontrol->id.numid;
 957        up_read(&card->controls_rwsem);
 958        if (info->count > slot->channels)
 959                slot->channels = info->count;
 960        slot->present |= 1 << item;
 961        kfree(info);
 962        return 0;
 963}
 964
 965static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn)
 966{
 967        struct slot *p = chn->private_data;
 968        if (p) {
 969                if (p->allocated && p->assigned) {
 970                        kfree_const(p->assigned->name);
 971                        kfree_const(p->assigned);
 972                }
 973                kfree(p);
 974        }
 975}
 976
 977static void mixer_slot_clear(struct snd_mixer_oss_slot *rslot)
 978{
 979        int idx = rslot->number; /* remember this */
 980        if (rslot->private_free)
 981                rslot->private_free(rslot);
 982        memset(rslot, 0, sizeof(*rslot));
 983        rslot->number = idx;
 984}
 985
 986/* In a separate function to keep gcc 3.2 happy - do NOT merge this in
 987   snd_mixer_oss_build_input! */
 988static int snd_mixer_oss_build_test_all(struct snd_mixer_oss *mixer,
 989                                        const struct snd_mixer_oss_assign_table *ptr,
 990                                        struct slot *slot)
 991{
 992        char str[64];
 993        int err;
 994
 995        err = snd_mixer_oss_build_test(mixer, slot, ptr->name, ptr->index,
 996                                       SNDRV_MIXER_OSS_ITEM_GLOBAL);
 997        if (err)
 998                return err;
 999        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 */
1053static 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
1148static 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
1180static 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
1204static 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
1264static 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
1284static 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
1294static 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
1350static 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
1371static 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
1428static 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
1444static 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
1459module_init(alsa_mixer_oss_init)
1460module_exit(alsa_mixer_oss_exit)
1461