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 extern sound_os_info *sb_osp;
  47 
  48 static int      mixer_initialized = 0;
  49 
  50 static int      supported_rec_devices;
  51 static int      supported_devices;
  52 static int      recmask = 0;
  53 static int      mixer_model;
  54 static int      mixer_caps;
  55 static mixer_tab *iomap;
  56 
  57 void
  58 sb_setmixer (unsigned int port, unsigned int value)
     /* [previous][next][first][last][top][bottom][index][help] */
  59 {
  60   unsigned long   flags;
  61 
  62   save_flags (flags);
  63   cli ();
  64   outb ((unsigned char) (port & 0xff), MIXER_ADDR);     /*
  65                                                            * Select register
  66                                                          */
  67   tenmicrosec ();
  68   outb ((unsigned char) (value & 0xff), MIXER_DATA);
  69   tenmicrosec ();
  70   restore_flags (flags);
  71 }
  72 
  73 int
  74 sb_getmixer (unsigned int port)
     /* [previous][next][first][last][top][bottom][index][help] */
  75 {
  76   int             val;
  77   unsigned long   flags;
  78 
  79   save_flags (flags);
  80   cli ();
  81   outb ((unsigned char) (port & 0xff), MIXER_ADDR);     /*
  82                                                            * Select register
  83                                                          */
  84   tenmicrosec ();
  85   val = inb (MIXER_DATA);
  86   tenmicrosec ();
  87   restore_flags (flags);
  88 
  89   return val;
  90 }
  91 
  92 void
  93 sb_mixer_set_stereo (int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
  94 {
  95   if (!mixer_initialized)
  96     return;
  97 
  98   sb_setmixer (OUT_FILTER, ((sb_getmixer (OUT_FILTER) & ~STEREO_DAC)
  99                             | (mode ? STEREO_DAC : MONO_DAC)));
 100 }
 101 
 102 /*
 103  * Returns:
 104  *      0       No mixer detected.
 105  *      1       Only a plain Sound Blaster Pro style mixer detected.
 106  *      2       The Sound Galaxy NX Pro mixer detected.
 107  */
 108 static int
 109 detect_mixer (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 110 {
 111 #ifdef __SGNXPRO__
 112   int             oldbass, oldtreble;
 113   extern int      sbc_major;
 114 
 115 #endif
 116   int             retcode = 1;
 117 
 118   /*
 119    * Detect the mixer by changing parameters of two volume channels. If the
 120    * values read back match with the values written, the mixer is there (is
 121    * it?)
 122    */
 123   sb_setmixer (FM_VOL, 0xff);
 124   sb_setmixer (VOC_VOL, 0x33);
 125 
 126   if (sb_getmixer (FM_VOL) != 0xff)
 127     return 0;                   /*
 128                                  * No match
 129                                  */
 130   if (sb_getmixer (VOC_VOL) != 0x33)
 131     return 0;
 132 
 133 #ifdef __SGNXPRO__
 134   /* Attempt to detect the SG NX Pro by check for valid bass/treble
 135      * registers.
 136    */
 137   oldbass = sb_getmixer (BASS_LVL);
 138   oldtreble = sb_getmixer (TREBLE_LVL);
 139 
 140   sb_setmixer (BASS_LVL, 0xaa);
 141   sb_setmixer (TREBLE_LVL, 0x55);
 142 
 143   if ((sb_getmixer (BASS_LVL) != 0xaa) ||
 144       (sb_getmixer (TREBLE_LVL) != 0x55))
 145     {
 146       retcode = 1;              /* 1 == Only SB Pro detected */
 147     }
 148   else
 149     retcode = 2;                /* 2 == SG NX Pro detected */
 150   /* Restore register in either case since SG NX Pro has EEPROM with
 151    * 'preferred' values stored.
 152    */
 153   sb_setmixer (BASS_LVL, oldbass);
 154   sb_setmixer (TREBLE_LVL, oldtreble);
 155 
 156   /*
 157      * If the SB version is 3.X (SB Pro), assume we have a SG NX Pro 16.
 158      * In this case it's good idea to disable the Disney Sound Source
 159      * compatibility mode. It's useless and just causes noise every time the
 160      * LPT-port is accessed.
 161      *
 162      * Also place the card into WSS mode.
 163    */
 164   if (sbc_major == 3)
 165     {
 166       outb (0x01, sbc_base + 0x1c);
 167       outb (0x00, sbc_base + 0x1a);
 168     }
 169 
 170 #endif
 171   return retcode;
 172 }
 173 
 174 static void
 175 change_bits (unsigned char *regval, int dev, int chn, int newval)
     /* [previous][next][first][last][top][bottom][index][help] */
 176 {
 177   unsigned char   mask;
 178   int             shift;
 179 
 180   mask = (1 << (*iomap)[dev][chn].nbits) - 1;
 181   newval = (int) ((newval * mask) + 50) / 100;  /*
 182                                                  * Scale it
 183                                                  */
 184 
 185   shift = (*iomap)[dev][chn].bitoffs - (*iomap)[dev][LEFT_CHN].nbits + 1;
 186 
 187   *regval &= ~(mask << shift);  /*
 188                                  * Filter out the previous value
 189                                  */
 190   *regval |= (newval & mask) << shift;  /*
 191                                          * Set the new value
 192                                          */
 193 }
 194 
 195 static int
 196 sb_mixer_get (int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 197 {
 198   if (!((1 << dev) & supported_devices))
 199     return -EINVAL;
 200 
 201   return levels[dev];
 202 }
 203 
 204 #ifdef JAZZ16
 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 #endif
 297 
 298 static int
 299 sb_mixer_set (int dev, int value)
     /* [previous][next][first][last][top][bottom][index][help] */
 300 {
 301   int             left = value & 0x000000ff;
 302   int             right = (value & 0x0000ff00) >> 8;
 303 
 304   int             regoffs;
 305   unsigned char   val;
 306 
 307 #ifdef JAZZ16
 308   if (Jazz16_detected == 2)
 309     return smw_mixer_set (dev, value);
 310 #endif
 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, ioctl_arg arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 449 {
 450   if (((cmd >> 8) & 0xff) == 'M')
 451     {
 452       if (cmd & IOC_IN)
 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 static 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 #ifdef JAZZ16
 543       if (Jazz16_detected == 2) /* SM Wave */
 544         {
 545           supported_devices = 0;
 546           supported_rec_devices = 0;
 547           iomap = &sbpro_mix;
 548           smw_mixer_init ();
 549           mixer_type = 1;
 550         }
 551       else
 552 #endif
 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] */