root/drivers/sound/pas2_mixer.c

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

DEFINITIONS

This source file includes following definitions.
  1. mixer_output
  2. set_mode
  3. pas_mixer_set
  4. pas_mixer_reset
  5. pas_mixer_ioctl
  6. pas_init_mixer

   1 #define _PAS2_MIXER_C_
   2 
   3 /*
   4  * sound/pas2_mixer.c
   5  *
   6  * Mixer routines for the Pro Audio Spectrum cards.
   7  *
   8  * Copyright by Hannu Savolainen 1993
   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  */
  31 
  32 #include "sound_config.h"
  33 
  34 #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PAS)
  35 
  36 #include "pas.h"
  37 
  38 #define TRACE(what)             /*
  39                                    * * * (what)   */
  40 
  41 extern int      translat_code;
  42 
  43 static int      rec_devices = (SOUND_MASK_MIC); /*
  44 
  45 
  46                                                          * *  * * Default *
  47                                                          * recording * source
  48                                                          *
  49                                                          * *  */
  50 static int      mode_control = 0;
  51 
  52 #define POSSIBLE_RECORDING_DEVICES      (SOUND_MASK_SYNTH | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
  53                                          SOUND_MASK_CD | SOUND_MASK_ALTPCM)
  54 
  55 #define SUPPORTED_MIXER_DEVICES         (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
  56                                          SOUND_MASK_CD | SOUND_MASK_ALTPCM | SOUND_MASK_IMIX | \
  57                                          SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV | \
  58                                          SOUND_MASK_MUTE | SOUND_MASK_ENHANCE | SOUND_MASK_LOUD)
  59 
  60 static unsigned short levels[SOUND_MIXER_NRDEVICES] =
  61 {
  62   0x3232,                       /*
  63                                  * Master Volume
  64                                  */
  65   0x3232,                       /*
  66                                  * Bass
  67                                  */
  68   0x3232,                       /*
  69                                  * Treble
  70                                  */
  71   0x5050,                       /*
  72                                  * FM
  73                                  */
  74   0x4b4b,                       /*
  75                                  * PCM
  76                                  */
  77   0x3232,                       /*
  78                                  * PC Speaker
  79                                  */
  80   0x4b4b,                       /*
  81                                  * Ext Line
  82                                  */
  83   0x4b4b,                       /*
  84                                  * Mic
  85                                  */
  86   0x4b4b,                       /*
  87                                  * CD
  88                                  */
  89   0x6464,                       /*
  90                                  * Recording monitor
  91                                  */
  92   0x4b4b,                       /*
  93                                  * SB PCM
  94                                  */
  95   0x6464};                      /*
  96 
  97 
  98                                  * *  * * Recording level   */
  99 
 100 static int
 101 mixer_output (int right_vol, int left_vol, int div, int bits,
     /* [previous][next][first][last][top][bottom][index][help] */
 102               int mixer         /*
 103                                  * Input or output mixer
 104                                                                          */ )
 105 {
 106   int             left = left_vol * div / 100;
 107   int             right = right_vol * div / 100;
 108 
 109   /*
 110    * The Revision D cards have a problem with their MVA508 interface. The
 111    * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and
 112    * MSBs out of the output byte and to do a 16-bit out to the mixer port -
 113    * 1. We don't need to do this because the call to pas_write more than
 114    * compensates for the timing problems.
 115    */
 116 
 117   if (bits & P_M_MV508_MIXER)
 118     {                           /*
 119                                  * Select input or output mixer
 120                                  */
 121       left |= mixer;
 122       right |= mixer;
 123     }
 124 
 125   if (bits == P_M_MV508_BASS || bits == P_M_MV508_TREBLE)
 126     {                           /*
 127                                  * Bass and trebble are mono devices
 128                                  */
 129       pas_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER);
 130       pas_write (left, PARALLEL_MIXER);
 131       right_vol = left_vol;
 132     }
 133   else
 134     {
 135       pas_write (P_M_MV508_ADDRESS | P_M_MV508_LEFT | bits, PARALLEL_MIXER);
 136       pas_write (left, PARALLEL_MIXER);
 137       pas_write (P_M_MV508_ADDRESS | P_M_MV508_RIGHT | bits, PARALLEL_MIXER);
 138       pas_write (right, PARALLEL_MIXER);
 139     }
 140 
 141   return (left_vol | (right_vol << 8));
 142 }
 143 
 144 void
 145 set_mode (int new_mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 146 {
 147   pas_write (P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER);
 148   pas_write (new_mode, PARALLEL_MIXER);
 149 
 150   mode_control = new_mode;
 151 }
 152 
 153 static int
 154 pas_mixer_set (int whichDev, unsigned int level)
     /* [previous][next][first][last][top][bottom][index][help] */
 155 {
 156   int             left, right, devmask, changed, i, mixer = 0;
 157 
 158   TRACE (printk ("static int pas_mixer_set(int whichDev = %d, unsigned int level = %X)\n", whichDev, level));
 159 
 160   left = level & 0x7f;
 161   right = (level & 0x7f00) >> 8;
 162 
 163   if (whichDev < SOUND_MIXER_NRDEVICES)
 164     if ((1 << whichDev) & rec_devices)
 165       mixer = P_M_MV508_INPUTMIX;
 166     else
 167       mixer = P_M_MV508_OUTPUTMIX;
 168 
 169   switch (whichDev)
 170     {
 171     case SOUND_MIXER_VOLUME:    /*
 172                                  * Master volume (0-63)
 173                                  */
 174       levels[whichDev] = mixer_output (right, left, 63, P_M_MV508_MASTER_A, 0);
 175       break;
 176 
 177       /*
 178        * Note! Bass and Treble are mono devices. Will use just the left
 179        * channel.
 180        */
 181     case SOUND_MIXER_BASS:      /*
 182                                  * Bass (0-12)
 183                                  */
 184       levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_BASS, 0);
 185       break;
 186     case SOUND_MIXER_TREBLE:    /*
 187                                  * Treble (0-12)
 188                                  */
 189       levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_TREBLE, 0);
 190       break;
 191 
 192     case SOUND_MIXER_SYNTH:     /*
 193                                  * Internal synthesizer (0-31)
 194                                  */
 195       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_FM, mixer);
 196       break;
 197     case SOUND_MIXER_PCM:       /*
 198                                  * PAS PCM (0-31)
 199                                  */
 200       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_PCM, mixer);
 201       break;
 202     case SOUND_MIXER_ALTPCM:    /*
 203                                  * SB PCM (0-31)
 204                                  */
 205       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SB, mixer);
 206       break;
 207     case SOUND_MIXER_SPEAKER:   /*
 208                                  * PC speaker (0-31)
 209                                  */
 210       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SPEAKER, mixer);
 211       break;
 212     case SOUND_MIXER_LINE:      /*
 213                                  * External line (0-31)
 214                                  */
 215       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_LINE, mixer);
 216       break;
 217     case SOUND_MIXER_CD:        /*
 218                                  * CD (0-31)
 219                                  */
 220       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_CDROM, mixer);
 221       break;
 222     case SOUND_MIXER_MIC:       /*
 223                                  * External microphone (0-31)
 224                                  */
 225       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_MIC, mixer);
 226       break;
 227     case SOUND_MIXER_IMIX:      /*
 228                                  * Recording monitor (0-31) (Only available *
 229                                  * on the Output Mixer)
 230                                  */
 231       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_IMIXER,
 232                                        P_M_MV508_OUTPUTMIX);
 233       break;
 234     case SOUND_MIXER_RECLEV:    /*
 235                                  * Recording level (0-15)
 236                                  */
 237       levels[whichDev] = mixer_output (right, left, 15, P_M_MV508_MASTER_B, 0);
 238       break;
 239 
 240     case SOUND_MIXER_MUTE:
 241       return 0;
 242       break;
 243 
 244     case SOUND_MIXER_ENHANCE:
 245       i = 0;
 246       level &= 0x7f;
 247       if (level)
 248         i = (level / 20) - 1;
 249 
 250       mode_control &= ~P_M_MV508_ENHANCE_BITS;
 251       mode_control |= P_M_MV508_ENHANCE_BITS;
 252       set_mode (mode_control);
 253 
 254       if (i)
 255         i = (i + 1) * 20;
 256       return i;
 257       break;
 258 
 259     case SOUND_MIXER_LOUD:
 260       mode_control &= ~P_M_MV508_LOUDNESS;
 261       if (level)
 262         mode_control |= P_M_MV508_LOUDNESS;
 263       set_mode (mode_control);
 264       return !!level;           /*
 265                                  * 0 or 1
 266                                  */
 267       break;
 268 
 269     case SOUND_MIXER_RECSRC:
 270       devmask = level & POSSIBLE_RECORDING_DEVICES;
 271 
 272       changed = devmask ^ rec_devices;
 273       rec_devices = devmask;
 274 
 275       for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
 276         if (changed & (1 << i))
 277           {
 278             pas_mixer_set (i, levels[i]);
 279           }
 280       return rec_devices;
 281       break;
 282 
 283     default:
 284       return RET_ERROR (EINVAL);
 285     }
 286 
 287   return (levels[whichDev]);
 288 }
 289 
 290 /*****/
 291 
 292 static void
 293 pas_mixer_reset (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 294 {
 295   int             foo;
 296 
 297   TRACE (printk ("pas2_mixer.c: void pas_mixer_reset(void)\n"));
 298 
 299   for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++)
 300     pas_mixer_set (foo, levels[foo]);
 301 
 302   set_mode (P_M_MV508_LOUDNESS | P_M_MV508_ENHANCE_40);
 303 }
 304 
 305 int
 306 pas_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 307 {
 308   TRACE (printk ("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
 309 
 310   if (((cmd >> 8) & 0xff) == 'M')
 311     {
 312       if (cmd & IOC_IN)
 313         return IOCTL_OUT (arg, pas_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
 314       else
 315         {                       /*
 316                                  * Read parameters
 317                                  */
 318 
 319           switch (cmd & 0xff)
 320             {
 321 
 322             case SOUND_MIXER_RECSRC:
 323               return IOCTL_OUT (arg, rec_devices);
 324               break;
 325 
 326             case SOUND_MIXER_STEREODEVS:
 327               return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE));
 328               break;
 329 
 330             case SOUND_MIXER_DEVMASK:
 331               return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES);
 332               break;
 333 
 334             case SOUND_MIXER_RECMASK:
 335               return IOCTL_OUT (arg, POSSIBLE_RECORDING_DEVICES & SUPPORTED_MIXER_DEVICES);
 336               break;
 337 
 338             case SOUND_MIXER_CAPS:
 339               return IOCTL_OUT (arg, 0);        /*
 340                                                  * No special capabilities
 341                                                  */
 342               break;
 343 
 344             case SOUND_MIXER_MUTE:
 345               return IOCTL_OUT (arg, 0);        /*
 346                                                  * No mute yet
 347                                                  */
 348               break;
 349 
 350             case SOUND_MIXER_ENHANCE:
 351               if (!(mode_control & P_M_MV508_ENHANCE_BITS))
 352                 return IOCTL_OUT (arg, 0);
 353               return IOCTL_OUT (arg, ((mode_control & P_M_MV508_ENHANCE_BITS) + 1) * 20);
 354               break;
 355 
 356             case SOUND_MIXER_LOUD:
 357               if (mode_control & P_M_MV508_LOUDNESS)
 358                 return IOCTL_OUT (arg, 1);
 359               return IOCTL_OUT (arg, 0);
 360               break;
 361 
 362             default:
 363               return IOCTL_OUT (arg, levels[cmd & 0xff]);
 364             }
 365         }
 366     }
 367   return RET_ERROR (EINVAL);
 368 }
 369 
 370 static struct mixer_operations pas_mixer_operations =
 371 {
 372   pas_mixer_ioctl
 373 };
 374 
 375 int
 376 pas_init_mixer (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 377 {
 378   pas_mixer_reset ();
 379 
 380   if (num_mixers < MAX_MIXER_DEV)
 381     mixer_devs[num_mixers++] = &pas_mixer_operations;
 382   return 1;
 383 }
 384 
 385 #endif

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