root/drivers/sound/sb_mixer.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sb_setmixer
  2. sb_getmixer
  3. sb_mixer_set_stereo
  4. detect_mixer
  5. change_bits
  6. sb_mixer_get
  7. smw_mixer_init
  8. smw_mixer_set
  9. sb_mixer_set
  10. set_recsrc
  11. set_recmask
  12. sb_mixer_ioctl
  13. sb_mixer_reset
  14. sb_mixer_init

   1 
   2 /*
   3  * sound/sb_mixer.c
   4  *
   5  * The low level mixer driver for the SoundBlaster Pro and SB16 cards.
   6  *
   7  * Copyright by Hannu Savolainen 1994
   8  *
   9  * Redistribution and use in source and binary forms, with or without
  10  * modification, are permitted provided that the following conditions are
  11  * met: 1. Redistributions of source code must retain the above copyright
  12  * notice, this list of conditions and the following disclaimer. 2.
  13  * Redistributions in binary form must reproduce the above copyright notice,
  14  * this list of conditions and the following disclaimer in the documentation
  15  * and/or other materials provided with the distribution.
  16  *
  17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
  18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
  21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  24  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27  * SUCH DAMAGE.
  28  *
  29  * Modified:
  30  *      Hunyue Yau      Jan 6 1994
  31  *      Added code to support the Sound Galaxy NX Pro mixer.
  32  *
  33  */
  34 
  35 #include "sound_config.h"
  36 
  37 #if defined(CONFIG_SB)
  38 #define __SB_MIXER_C__
  39 
  40 #include "sb.h"
  41 #include "sb_mixer.h"
  42 #undef SB_TEST_IRQ
  43 
  44 extern int      sbc_base;
  45 extern int      Jazz16_detected;
  46 extern sound_os_info *sb_osp;
  47 extern int      AudioDrive;
  48 
  49 static int      mixer_initialized = 0;
  50 
  51 static int      supported_rec_devices;
  52 static int      supported_devices;
  53 static int      recmask = 0;
  54 static int      mixer_model;
  55 static int      mixer_caps;
  56 static mixer_tab *iomap;
  57 
  58 void
  59 sb_setmixer (unsigned int port, unsigned int value)
     /* [previous][next][first][last][top][bottom][index][help] */
  60 {
  61   unsigned long   flags;
  62 
  63   save_flags (flags);
  64   cli ();
  65   outb ((unsigned char) (port & 0xff), MIXER_ADDR);     /*
  66                                                            * Select register
  67                                                          */
  68   tenmicrosec (sb_osp);
  69   outb ((unsigned char) (value & 0xff), MIXER_DATA);
  70   tenmicrosec (sb_osp);
  71   restore_flags (flags);
  72 }
  73 
  74 int
  75 sb_getmixer (unsigned int port)
     /* [previous][next][first][last][top][bottom][index][help] */
  76 {
  77   int             val;
  78   unsigned long   flags;
  79 
  80   save_flags (flags);
  81   cli ();
  82   outb ((unsigned char) (port & 0xff), MIXER_ADDR);     /*
  83                                                            * Select register
  84                                                          */
  85   tenmicrosec (sb_osp);
  86   val = inb (MIXER_DATA);
  87   tenmicrosec (sb_osp);
  88   restore_flags (flags);
  89 
  90   return val;
  91 }
  92 
  93 void
  94 sb_mixer_set_stereo (int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
  95 {
  96   if (!mixer_initialized)
  97     return;
  98 
  99   sb_setmixer (OUT_FILTER, ((sb_getmixer (OUT_FILTER) & ~STEREO_DAC)
 100                             | (mode ? STEREO_DAC : MONO_DAC)));
 101 }
 102 
 103 /*
 104  * Returns:
 105  *      0       No mixer detected.
 106  *      1       Only a plain Sound Blaster Pro style mixer detected.
 107  *      2       The Sound Galaxy NX Pro mixer detected.
 108  */
 109 static int
 110 detect_mixer (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 111 {
 112 #ifdef __SGNXPRO__
 113   int             oldbass, oldtreble;
 114   extern int      sbc_major;
 115 
 116 #endif
 117   int             retcode = 1;
 118 
 119   /*
 120    * Detect the mixer by changing parameters of two volume channels. If the
 121    * values read back match with the values written, the mixer is there (is
 122    * it?)
 123    */
 124   sb_setmixer (FM_VOL, 0xff);
 125   sb_setmixer (VOC_VOL, 0x33);
 126 
 127   if (sb_getmixer (FM_VOL) != 0xff)
 128     return 0;                   /*
 129                                  * No match
 130                                  */
 131   if (sb_getmixer (VOC_VOL) != 0x33)
 132     return 0;
 133 
 134 #ifdef __SGNXPRO__
 135   /* Attempt to detect the SG NX Pro by check for valid bass/treble
 136      * registers.
 137    */
 138   oldbass = sb_getmixer (BASS_LVL);
 139   oldtreble = sb_getmixer (TREBLE_LVL);
 140 
 141   sb_setmixer (BASS_LVL, 0xaa);
 142   sb_setmixer (TREBLE_LVL, 0x55);
 143 
 144   if ((sb_getmixer (BASS_LVL) != 0xaa) ||
 145       (sb_getmixer (TREBLE_LVL) != 0x55))
 146     {
 147       retcode = 1;              /* 1 == Only SB Pro detected */
 148     }
 149   else
 150     retcode = 2;                /* 2 == SG NX Pro detected */
 151   /* Restore register in either case since SG NX Pro has EEPROM with
 152    * 'preferred' values stored.
 153    */
 154   sb_setmixer (BASS_LVL, oldbass);
 155   sb_setmixer (TREBLE_LVL, oldtreble);
 156 
 157   /*
 158      * If the SB version is 3.X (SB Pro), assume we have a SG NX Pro 16.
 159      * In this case it's good idea to disable the Disney Sound Source
 160      * compatibility mode. It's useless and just causes noise every time the
 161      * LPT-port is accessed.
 162      *
 163      * Also place the card into WSS mode.
 164    */
 165   if (sbc_major == 3)
 166     {
 167       outb (0x01, sbc_base + 0x1c);
 168       outb (0x00, sbc_base + 0x1a);
 169     }
 170 
 171 #endif
 172   return retcode;
 173 }
 174 
 175 static void
 176 change_bits (unsigned char *regval, int dev, int chn, int newval)
     /* [previous][next][first][last][top][bottom][index][help] */
 177 {
 178   unsigned char   mask;
 179   int             shift;
 180 
 181   mask = (1 << (*iomap)[dev][chn].nbits) - 1;
 182   newval = (int) ((newval * mask) + 50) / 100;  /*
 183                                                  * Scale it
 184                                                  */
 185 
 186   shift = (*iomap)[dev][chn].bitoffs - (*iomap)[dev][LEFT_CHN].nbits + 1;
 187 
 188   *regval &= ~(mask << shift);  /*
 189                                  * Filter out the previous value
 190                                  */
 191   *regval |= (newval & mask) << shift;  /*
 192                                          * Set the new value
 193                                          */
 194 }
 195 
 196 static int
 197 sb_mixer_get (int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 198 {
 199   if (!((1 << dev) & supported_devices))
 200     return -EINVAL;
 201 
 202   return levels[dev];
 203 }
 204 
 205 static char     smw_mix_regs[] =        /* Left mixer registers */
 206 {
 207   0x0b,                         /* SOUND_MIXER_VOLUME */
 208   0x0d,                         /* SOUND_MIXER_BASS */
 209   0x0d,                         /* SOUND_MIXER_TREBLE */
 210   0x05,                         /* SOUND_MIXER_SYNTH */
 211   0x09,                         /* SOUND_MIXER_PCM */
 212   0x00,                         /* SOUND_MIXER_SPEAKER */
 213   0x03,                         /* SOUND_MIXER_LINE */
 214   0x01,                         /* SOUND_MIXER_MIC */
 215   0x07,                         /* SOUND_MIXER_CD */
 216   0x00,                         /* SOUND_MIXER_IMIX */
 217   0x00,                         /* SOUND_MIXER_ALTPCM */
 218   0x00,                         /* SOUND_MIXER_RECLEV */
 219   0x00,                         /* SOUND_MIXER_IGAIN */
 220   0x00,                         /* SOUND_MIXER_OGAIN */
 221   0x00,                         /* SOUND_MIXER_LINE1 */
 222   0x00,                         /* SOUND_MIXER_LINE2 */
 223   0x00                          /* SOUND_MIXER_LINE3 */
 224 };
 225 
 226 static void
 227 smw_mixer_init (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 228 {
 229   int             i;
 230 
 231   sb_setmixer (0x00, 0x18);     /* Mute unused (Telephone) line */
 232   sb_setmixer (0x10, 0x38);     /* Config register 2 */
 233 
 234   supported_devices = 0;
 235   for (i = 0; i < sizeof (smw_mix_regs); i++)
 236     if (smw_mix_regs[i] != 0)
 237       supported_devices |= (1 << i);
 238 
 239   supported_rec_devices = supported_devices &
 240     ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_PCM |
 241       SOUND_MASK_VOLUME);
 242 }
 243 
 244 static int
 245 smw_mixer_set (int dev, int value)
     /* [previous][next][first][last][top][bottom][index][help] */
 246 {
 247   int             left = value & 0x000000ff;
 248   int             right = (value & 0x0000ff00) >> 8;
 249   int             reg, val;
 250 
 251   if (left > 100)
 252     left = 100;
 253   if (right > 100)
 254     right = 100;
 255 
 256   if (dev > 31)
 257     return -EINVAL;
 258 
 259   if (!(supported_devices & (1 << dev)))        /* Not supported */
 260     return -EINVAL;
 261 
 262   switch (dev)
 263     {
 264     case SOUND_MIXER_VOLUME:
 265       sb_setmixer (0x0b, 96 - (96 * left / 100));       /* 96=mute, 0=max */
 266       sb_setmixer (0x0c, 96 - (96 * right / 100));
 267       break;
 268 
 269     case SOUND_MIXER_BASS:
 270     case SOUND_MIXER_TREBLE:
 271       levels[dev] = left | (right << 8);
 272 
 273       /* Set left bass and treble values */
 274       val = ((levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / 100) << 4;
 275       val |= ((levels[SOUND_MIXER_BASS] & 0xff) * 16 / 100) & 0x0f;
 276       sb_setmixer (0x0d, val);
 277 
 278       /* Set right bass and treble values */
 279       val = (((levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / 100) << 4;
 280       val |= (((levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / 100) & 0x0f;
 281       sb_setmixer (0x0e, val);
 282       break;
 283 
 284     default:
 285       reg = smw_mix_regs[dev];
 286       if (reg == 0)
 287         return -EINVAL;
 288       sb_setmixer (reg, (24 - (24 * left / 100)) | 0x20);       /* 24=mute, 0=max */
 289       sb_setmixer (reg + 1, (24 - (24 * right / 100)) | 0x40);
 290     }
 291 
 292   levels[dev] = left | (right << 8);
 293   return left | (right << 8);
 294 }
 295 
 296 static int
 297 sb_mixer_set (int dev, int value)
     /* [previous][next][first][last][top][bottom][index][help] */
 298 {
 299   int             left = value & 0x000000ff;
 300   int             right = (value & 0x0000ff00) >> 8;
 301 
 302   int             regoffs;
 303   unsigned char   val;
 304 
 305   if (Jazz16_detected == 2)
 306     return smw_mixer_set (dev, value);
 307 
 308   if (left > 100)
 309     left = 100;
 310   if (right > 100)
 311     right = 100;
 312 
 313   if (dev > 31)
 314     return -EINVAL;
 315 
 316   if (!(supported_devices & (1 << dev)))        /*
 317                                                  * Not supported
 318                                                  */
 319     return -EINVAL;
 320 
 321   regoffs = (*iomap)[dev][LEFT_CHN].regno;
 322 
 323   if (regoffs == 0)
 324     return -EINVAL;
 325 
 326   val = sb_getmixer (regoffs);
 327   change_bits (&val, dev, LEFT_CHN, left);
 328 
 329   levels[dev] = left | (left << 8);
 330 
 331   if ((*iomap)[dev][RIGHT_CHN].regno != regoffs)        /*
 332                                                          * Change register
 333                                                          */
 334     {
 335       sb_setmixer (regoffs, val);       /*
 336                                          * Save the old one
 337                                          */
 338       regoffs = (*iomap)[dev][RIGHT_CHN].regno;
 339 
 340       if (regoffs == 0)
 341         return left | (left << 8);      /*
 342                                          * Just left channel present
 343                                          */
 344 
 345       val = sb_getmixer (regoffs);      /*
 346                                          * Read the new one
 347                                          */
 348     }
 349 
 350   change_bits (&val, dev, RIGHT_CHN, right);
 351 
 352   sb_setmixer (regoffs, val);
 353 
 354   levels[dev] = left | (right << 8);
 355   return left | (right << 8);
 356 }
 357 
 358 static void
 359 set_recsrc (int src)
     /* [previous][next][first][last][top][bottom][index][help] */
 360 {
 361   sb_setmixer (RECORD_SRC, (sb_getmixer (RECORD_SRC) & ~7) | (src & 0x7));
 362 }
 363 
 364 static int
 365 set_recmask (int mask)
     /* [previous][next][first][last][top][bottom][index][help] */
 366 {
 367   int             devmask, i;
 368   unsigned char   regimageL, regimageR;
 369 
 370   devmask = mask & supported_rec_devices;
 371 
 372   switch (mixer_model)
 373     {
 374     case 3:
 375 
 376       if (devmask != SOUND_MASK_MIC &&
 377           devmask != SOUND_MASK_LINE &&
 378           devmask != SOUND_MASK_CD)
 379         {                       /*
 380                                  * More than one devices selected. Drop the *
 381                                  * previous selection
 382                                  */
 383           devmask &= ~recmask;
 384         }
 385 
 386       if (devmask != SOUND_MASK_MIC &&
 387           devmask != SOUND_MASK_LINE &&
 388           devmask != SOUND_MASK_CD)
 389         {                       /*
 390                                  * More than one devices selected. Default to
 391                                  * * mic
 392                                  */
 393           devmask = SOUND_MASK_MIC;
 394         }
 395 
 396 
 397       if (devmask ^ recmask)    /*
 398                                  * Input source changed
 399                                  */
 400         {
 401           switch (devmask)
 402             {
 403 
 404             case SOUND_MASK_MIC:
 405               set_recsrc (SRC_MIC);
 406               break;
 407 
 408             case SOUND_MASK_LINE:
 409               set_recsrc (SRC_LINE);
 410               break;
 411 
 412             case SOUND_MASK_CD:
 413               set_recsrc (SRC_CD);
 414               break;
 415 
 416             default:
 417               set_recsrc (SRC_MIC);
 418             }
 419         }
 420 
 421       break;
 422 
 423     case 4:
 424       if (!devmask)
 425         devmask = SOUND_MASK_MIC;
 426 
 427       regimageL = regimageR = 0;
 428       for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
 429         if ((1 << i) & devmask)
 430           {
 431             regimageL |= sb16_recmasks_L[i];
 432             regimageR |= sb16_recmasks_R[i];
 433           }
 434       sb_setmixer (SB16_IMASK_L, regimageL);
 435       sb_setmixer (SB16_IMASK_R, regimageR);
 436       break;
 437     }
 438 
 439   recmask = devmask;
 440   return recmask;
 441 }
 442 
 443 static int
 444 sb_mixer_ioctl (int dev, unsigned int cmd, ioctl_arg arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 445 {
 446   if (((cmd >> 8) & 0xff) == 'M')
 447     {
 448       if (_IOC_DIR (cmd) & _IOC_WRITE)
 449         switch (cmd & 0xff)
 450           {
 451           case SOUND_MIXER_RECSRC:
 452             return snd_ioctl_return ((int *) arg, set_recmask (get_fs_long ((long *) arg)));
 453             break;
 454 
 455           default:
 456 
 457             return snd_ioctl_return ((int *) arg, sb_mixer_set (cmd & 0xff, get_fs_long ((long *) arg)));
 458           }
 459       else
 460         switch (cmd & 0xff)     /*
 461                                  * Return parameters
 462                                  */
 463           {
 464 
 465           case SOUND_MIXER_RECSRC:
 466             return snd_ioctl_return ((int *) arg, recmask);
 467             break;
 468 
 469           case SOUND_MIXER_DEVMASK:
 470             return snd_ioctl_return ((int *) arg, supported_devices);
 471             break;
 472 
 473           case SOUND_MIXER_STEREODEVS:
 474             if (Jazz16_detected)
 475               return snd_ioctl_return ((int *) arg, supported_devices);
 476             else
 477               return snd_ioctl_return ((int *) arg, supported_devices & ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
 478             break;
 479 
 480           case SOUND_MIXER_RECMASK:
 481             return snd_ioctl_return ((int *) arg, supported_rec_devices);
 482             break;
 483 
 484           case SOUND_MIXER_CAPS:
 485             return snd_ioctl_return ((int *) arg, mixer_caps);
 486             break;
 487 
 488           default:
 489             return snd_ioctl_return ((int *) arg, sb_mixer_get (cmd & 0xff));
 490           }
 491     }
 492   else
 493     return -EINVAL;
 494 }
 495 
 496 static struct mixer_operations sb_mixer_operations =
 497 {
 498   "SoundBlaster",
 499   sb_mixer_ioctl
 500 };
 501 
 502 static void
 503 sb_mixer_reset (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 504 {
 505   int             i;
 506 
 507   for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
 508     sb_mixer_set (i, levels[i]);
 509   set_recmask (SOUND_MASK_MIC);
 510 }
 511 
 512 /*
 513  * Returns a code depending on whether a SG NX Pro was detected.
 514  * 1 == Plain SB Pro
 515  * 2 == SG NX Pro detected.
 516  * 3 == SB16
 517  *
 518  * Used to update message.
 519  */
 520 int
 521 sb_mixer_init (int major_model)
     /* [previous][next][first][last][top][bottom][index][help] */
 522 {
 523   int             mixer_type = 0;
 524 
 525   sb_setmixer (0x00, 0);        /* Reset mixer */
 526 
 527   if (!(mixer_type = detect_mixer ()))
 528     return 0;                   /* No mixer. Why? */
 529 
 530   mixer_initialized = 1;
 531   mixer_model = major_model;
 532 
 533   switch (major_model)
 534     {
 535     case 3:
 536       mixer_caps = SOUND_CAP_EXCL_INPUT;
 537 
 538       if (AudioDrive)
 539         {
 540           supported_devices = ES688_MIXER_DEVICES;
 541           supported_rec_devices = ES688_RECORDING_DEVICES;
 542           iomap = &es688_mix;
 543         }
 544       else if (Jazz16_detected == 2)    /* SM Wave */
 545         {
 546           supported_devices = 0;
 547           supported_rec_devices = 0;
 548           iomap = &sbpro_mix;
 549           smw_mixer_init ();
 550           mixer_type = 1;
 551         }
 552       else
 553 #ifdef __SGNXPRO__
 554       if (mixer_type == 2)      /* A SGNXPRO was detected */
 555         {
 556           supported_devices = SGNXPRO_MIXER_DEVICES;
 557           supported_rec_devices = SGNXPRO_RECORDING_DEVICES;
 558           iomap = &sgnxpro_mix;
 559         }
 560       else
 561 #endif
 562         {
 563           supported_devices = SBPRO_MIXER_DEVICES;
 564           supported_rec_devices = SBPRO_RECORDING_DEVICES;
 565           iomap = &sbpro_mix;
 566           mixer_type = 1;
 567         }
 568       break;
 569 
 570     case 4:
 571       mixer_caps = 0;
 572       supported_devices = SB16_MIXER_DEVICES;
 573       supported_rec_devices = SB16_RECORDING_DEVICES;
 574       iomap = &sb16_mix;
 575       mixer_type = 3;
 576       break;
 577 
 578     default:
 579       printk ("SB Warning: Unsupported mixer type\n");
 580       return 0;
 581     }
 582 
 583   if (num_mixers < MAX_MIXER_DEV)
 584     mixer_devs[num_mixers++] = &sb_mixer_operations;
 585   sb_mixer_reset ();
 586   return mixer_type;
 587 }
 588 
 589 #endif

/* [previous][next][first][last][top][bottom][index][help] */