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