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

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