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

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