root/drivers/sound/pas2_mixer.c

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

DEFINITIONS

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

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