root/sound/core/oss/mixer_oss.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. snd_mixer_oss_open
  2. snd_mixer_oss_release
  3. snd_mixer_oss_info
  4. snd_mixer_oss_info_obsolete
  5. snd_mixer_oss_caps
  6. snd_mixer_oss_devmask
  7. snd_mixer_oss_stereodevs
  8. snd_mixer_oss_recmask
  9. snd_mixer_oss_get_recsrc
  10. snd_mixer_oss_set_recsrc
  11. snd_mixer_oss_get_volume
  12. snd_mixer_oss_set_volume
  13. snd_mixer_oss_ioctl1
  14. snd_mixer_oss_ioctl
  15. snd_mixer_oss_ioctl_card
  16. snd_mixer_oss_ioctl_compat
  17. snd_mixer_oss_conv
  18. snd_mixer_oss_conv1
  19. snd_mixer_oss_conv2
  20. snd_mixer_oss_recsrce_set
  21. snd_mixer_oss_recsrce_get
  22. snd_mixer_oss_test_id
  23. snd_mixer_oss_get_volume1_vol
  24. snd_mixer_oss_get_volume1_sw
  25. snd_mixer_oss_get_volume1
  26. snd_mixer_oss_put_volume1_vol
  27. snd_mixer_oss_put_volume1_sw
  28. snd_mixer_oss_put_volume1
  29. snd_mixer_oss_get_recsrc1_sw
  30. snd_mixer_oss_get_recsrc1_route
  31. snd_mixer_oss_put_recsrc1_sw
  32. snd_mixer_oss_put_recsrc1_route
  33. snd_mixer_oss_get_recsrc2
  34. snd_mixer_oss_put_recsrc2
  35. snd_mixer_oss_build_test
  36. snd_mixer_oss_slot_free
  37. mixer_slot_clear
  38. snd_mixer_oss_build_test_all
  39. snd_mixer_oss_build_input
  40. snd_mixer_oss_proc_read
  41. snd_mixer_oss_proc_write
  42. snd_mixer_oss_proc_init
  43. snd_mixer_oss_proc_done
  44. snd_mixer_oss_build
  45. snd_mixer_oss_free1
  46. snd_mixer_oss_notify_handler
  47. alsa_mixer_oss_init
  48. alsa_mixer_oss_exit

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

/* [<][>][^][v][top][bottom][index][help] */