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

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