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