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. sb_mixer_set
  8. set_recsrc
  9. set_recmask
  10. sb_mixer_ioctl
  11. sb_mixer_reset
  12. 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 1993
   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 
  46 static int      mixer_initialized = 0;
  47 
  48 static int      supported_rec_devices;
  49 static int      supported_devices;
  50 static int      recmask = 0;
  51 static int      mixer_model;
  52 static int      mixer_caps;
  53 static mixer_tab *iomap;
  54 
  55 void
  56 sb_setmixer (unsigned int port, unsigned int value)
     /* [previous][next][first][last][top][bottom][index][help] */
  57 {
  58   unsigned long   flags;
  59 
  60   DISABLE_INTR (flags);
  61   OUTB ((unsigned char) (port & 0xff), MIXER_ADDR);     /* Select register */
  62   tenmicrosec ();
  63   OUTB ((unsigned char) (value & 0xff), MIXER_DATA);
  64   tenmicrosec ();
  65   RESTORE_INTR (flags);
  66 }
  67 
  68 int
  69 sb_getmixer (unsigned int port)
     /* [previous][next][first][last][top][bottom][index][help] */
  70 {
  71   int             val;
  72   unsigned long   flags;
  73 
  74   DISABLE_INTR (flags);
  75   OUTB ((unsigned char) (port & 0xff), MIXER_ADDR);     /* Select register */
  76   tenmicrosec ();
  77   val = INB (MIXER_DATA);
  78   tenmicrosec ();
  79   RESTORE_INTR (flags);
  80 
  81   return val;
  82 }
  83 
  84 void
  85 sb_mixer_set_stereo (int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
  86 {
  87   if (!mixer_initialized)
  88     return;
  89 
  90   sb_setmixer (OUT_FILTER, ((sb_getmixer (OUT_FILTER) & ~STEREO_DAC)
  91                             | (mode ? STEREO_DAC : MONO_DAC)));
  92 }
  93 
  94 /*
  95  * Returns:
  96  *      0       No mixer detected.
  97  *      1       Only a plain Sound Blaster Pro style mixer detected.
  98  *      2       The Sound Galaxy NX Pro mixer detected.
  99  */
 100 static int
 101 detect_mixer (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 102 {
 103 #ifdef __SGNXPRO__
 104   int             oldbass, oldtreble;
 105 
 106 #endif
 107   int             retcode = 1;
 108 
 109   /*
 110    * Detect the mixer by changing parameters of two volume channels. If the
 111    * values read back match with the values written, the mixer is there (is
 112    * it?)
 113    */
 114   sb_setmixer (FM_VOL, 0xff);
 115   sb_setmixer (VOC_VOL, 0x33);
 116 
 117   if (sb_getmixer (FM_VOL) != 0xff)
 118     return 0;                   /* No match */
 119   if (sb_getmixer (VOC_VOL) != 0x33)
 120     return 0;
 121 
 122 #ifdef __SGNXPRO__
 123   /* Attempt to detect the SG NX Pro by check for valid bass/treble
 124  * registers.
 125  */
 126   oldbass = sb_getmixer (BASS_LVL);
 127   oldtreble = sb_getmixer (TREBLE_LVL);
 128 
 129   sb_setmixer (BASS_LVL, 0xaa);
 130   sb_setmixer (TREBLE_LVL, 0x55);
 131 
 132   if ((sb_getmixer (BASS_LVL) != 0xaa) ||
 133       (sb_getmixer (TREBLE_LVL) != 0x55))
 134     {
 135       retcode = 1;              /* 1 == Only SB Pro detected */
 136     }
 137   else
 138     retcode = 2;                /* 2 == SG NX Pro detected */
 139   /* Restore register in either case since SG NX Pro has EEPROM with
 140    * 'preferred' values stored.
 141    */
 142   sb_setmixer (BASS_LVL, oldbass);
 143   sb_setmixer (TREBLE_LVL, oldtreble);
 144 #endif
 145   return retcode;
 146 }
 147 
 148 static void
 149 change_bits (unsigned char *regval, int dev, int chn, int newval)
     /* [previous][next][first][last][top][bottom][index][help] */
 150 {
 151   unsigned char   mask;
 152   int             shift;
 153 
 154   mask = (1 << (*iomap)[dev][chn].nbits) - 1;
 155   newval = ((newval * mask) + 50) / 100;        /* Scale it */
 156 
 157   shift = (*iomap)[dev][chn].bitoffs - (*iomap)[dev][LEFT_CHN].nbits + 1;
 158 
 159   *regval &= ~(mask << shift);  /* Filter out the previous value */
 160   *regval |= (newval & mask) << shift;  /* Set the new value */
 161 }
 162 
 163 static int
 164 sb_mixer_get (int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 165 {
 166   if (!((1 << dev) & supported_devices))
 167     return RET_ERROR (EINVAL);
 168 
 169   return levels[dev];
 170 }
 171 
 172 static int
 173 sb_mixer_set (int dev, int value)
     /* [previous][next][first][last][top][bottom][index][help] */
 174 {
 175   int             left = value & 0x000000ff;
 176   int             right = (value & 0x0000ff00) >> 8;
 177 
 178   int             regoffs;
 179   unsigned char   val;
 180 
 181   if (left > 100)
 182     left = 100;
 183   if (right > 100)
 184     right = 100;
 185 
 186   if (dev > 31)
 187     return RET_ERROR (EINVAL);
 188 
 189   if (!(supported_devices & (1 << dev)))        /* Not supported */
 190     return RET_ERROR (EINVAL);
 191 
 192   regoffs = (*iomap)[dev][LEFT_CHN].regno;
 193 
 194   if (regoffs == 0)
 195     return RET_ERROR (EINVAL);
 196 
 197   val = sb_getmixer (regoffs);
 198   change_bits (&val, dev, LEFT_CHN, left);
 199 
 200   levels[dev] = left | (left << 8);
 201 
 202   if ((*iomap)[dev][RIGHT_CHN].regno != regoffs)        /* Change register */
 203     {
 204       sb_setmixer (regoffs, val);       /* Save the old one */
 205       regoffs = (*iomap)[dev][RIGHT_CHN].regno;
 206 
 207       if (regoffs == 0)
 208         return left | (left << 8);      /* Just left channel present */
 209 
 210       val = sb_getmixer (regoffs);      /* Read the new one */
 211     }
 212 
 213   change_bits (&val, dev, RIGHT_CHN, right);
 214   sb_setmixer (regoffs, val);
 215 
 216   levels[dev] = left | (right << 8);
 217   return left | (right << 8);
 218 }
 219 
 220 static void
 221 set_recsrc (int src)
     /* [previous][next][first][last][top][bottom][index][help] */
 222 {
 223   sb_setmixer (RECORD_SRC, (sb_getmixer (RECORD_SRC) & ~7) | (src & 0x7));
 224 }
 225 
 226 static int
 227 set_recmask (int mask)
     /* [previous][next][first][last][top][bottom][index][help] */
 228 {
 229   int             devmask, i;
 230   unsigned char   regimageL, regimageR;
 231 
 232   devmask = mask & supported_rec_devices;
 233 
 234   switch (mixer_model)
 235     {
 236     case 3:
 237 
 238       if (devmask != SOUND_MASK_MIC &&
 239           devmask != SOUND_MASK_LINE &&
 240           devmask != SOUND_MASK_CD)
 241         {                       /* More than one devices selected. Drop the
 242                                  * previous selection */
 243           devmask &= ~recmask;
 244         }
 245 
 246       if (devmask != SOUND_MASK_MIC &&
 247           devmask != SOUND_MASK_LINE &&
 248           devmask != SOUND_MASK_CD)
 249         {                       /* More than one devices selected. Default to
 250                                  * mic */
 251           devmask = SOUND_MASK_MIC;
 252         }
 253 
 254 
 255       if (devmask ^ recmask)    /* Input source changed */
 256         {
 257           switch (devmask)
 258             {
 259 
 260             case SOUND_MASK_MIC:
 261               set_recsrc (SRC_MIC);
 262               break;
 263 
 264             case SOUND_MASK_LINE:
 265               set_recsrc (SRC_LINE);
 266               break;
 267 
 268             case SOUND_MASK_CD:
 269               set_recsrc (SRC_CD);
 270               break;
 271 
 272             default:
 273               set_recsrc (SRC_MIC);
 274             }
 275         }
 276 
 277       break;
 278 
 279     case 4:
 280       if (!devmask)
 281         devmask = SOUND_MASK_MIC;
 282 
 283       regimageL = regimageR = 0;
 284       for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
 285         if ((1 << i) & devmask)
 286           {
 287             regimageL |= sb16_recmasks_L[i];
 288             regimageR |= sb16_recmasks_R[i];
 289           }
 290       sb_setmixer (SB16_IMASK_L, regimageL);
 291       sb_setmixer (SB16_IMASK_R, regimageR);
 292       break;
 293     }
 294 
 295   recmask = devmask;
 296   return recmask;
 297 }
 298 
 299 static int
 300 sb_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 301 {
 302   if (((cmd >> 8) & 0xff) == 'M')
 303     {
 304       if (cmd & IOC_IN)
 305         switch (cmd & 0xff)
 306           {
 307           case SOUND_MIXER_RECSRC:
 308             return IOCTL_OUT (arg, set_recmask (IOCTL_IN (arg)));
 309             break;
 310 
 311           default:
 312             return IOCTL_OUT (arg, sb_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
 313           }
 314       else
 315         switch (cmd & 0xff)     /* Return parameters */
 316           {
 317 
 318           case SOUND_MIXER_RECSRC:
 319             return IOCTL_OUT (arg, recmask);
 320             break;
 321 
 322           case SOUND_MIXER_DEVMASK:
 323             return IOCTL_OUT (arg, supported_devices);
 324             break;
 325 
 326           case SOUND_MIXER_STEREODEVS:
 327             return IOCTL_OUT (arg, supported_devices &
 328                               ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
 329             break;
 330 
 331           case SOUND_MIXER_RECMASK:
 332             return IOCTL_OUT (arg, supported_rec_devices);
 333             break;
 334 
 335           case SOUND_MIXER_CAPS:
 336             return IOCTL_OUT (arg, mixer_caps);
 337             break;
 338 
 339           default:
 340             return IOCTL_OUT (arg, sb_mixer_get (cmd & 0xff));
 341           }
 342     }
 343   else
 344     return RET_ERROR (EINVAL);
 345 }
 346 
 347 static struct mixer_operations sb_mixer_operations =
 348 {
 349   sb_mixer_ioctl
 350 };
 351 
 352 static void
 353 sb_mixer_reset (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 354 {
 355   int             i;
 356 
 357   for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
 358     sb_mixer_set (i, levels[i]);
 359   set_recmask (SOUND_MASK_MIC);
 360 }
 361 
 362 /*
 363  * Returns a code depending on whether a SG NX Pro was detected.
 364  * 0 == Plain SB 16 or SB Pro
 365  * 1 == SG NX Pro detected.
 366  *
 367  * Used to update message.
 368  */
 369 int
 370 sb_mixer_init (int major_model)
     /* [previous][next][first][last][top][bottom][index][help] */
 371 {
 372   int             mixerstat;
 373 
 374   sb_setmixer (0x00, 0);        /* Reset mixer */
 375 
 376   mixerstat = detect_mixer ();
 377 
 378   if (!mixerstat)
 379     return 0;                   /* No mixer. Why? */
 380 
 381   mixer_initialized = 1;
 382   mixer_model = major_model;
 383 
 384   switch (major_model)
 385     {
 386     case 3:
 387       mixer_caps = SOUND_CAP_EXCL_INPUT;
 388 #ifdef __SGNXPRO__
 389       if (mixerstat == 2)
 390         {                       /* A SGNXPRO was detected */
 391           supported_devices = SGNXPRO_MIXER_DEVICES;
 392           supported_rec_devices = SGNXPRO_RECORDING_DEVICES;
 393           iomap = &sgnxpro_mix;
 394         }
 395       else
 396 #endif
 397         {                       /* Otherwise plain SB Pro */
 398           supported_devices = SBPRO_MIXER_DEVICES;
 399           supported_rec_devices = SBPRO_RECORDING_DEVICES;
 400           iomap = &sbpro_mix;
 401         }
 402 
 403       break;
 404 
 405     case 4:
 406       mixer_caps = 0;
 407       supported_devices = SB16_MIXER_DEVICES;
 408       supported_rec_devices = SB16_RECORDING_DEVICES;
 409       iomap = &sb16_mix;
 410       break;
 411 
 412     default:
 413       printk ("SB Warning: Unsupported mixer type\n");
 414       return 0;
 415     }
 416 
 417   mixer_devs[num_mixers++] = &sb_mixer_operations;
 418   sb_mixer_reset ();
 419   return (mixerstat == 2);
 420 }
 421 
 422 #endif

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