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