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 /*
   9  * Copyright by Hannu Savolainen 1993-1996
  10  *
  11  * Redistribution and use in source and binary forms, with or without
  12  * modification, are permitted provided that the following conditions are
  13  * met: 1. Redistributions of source code must retain the above copyright
  14  * notice, this list of conditions and the following disclaimer. 2.
  15  * Redistributions in binary form must reproduce the above copyright notice,
  16  * this list of conditions and the following disclaimer in the documentation
  17  * and/or other materials provided with the distribution.
  18  *
  19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
  20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  22  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
  23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  26  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  29  * SUCH DAMAGE.
  30  */
  31 #include <linux/config.h>
  32 
  33 
  34 #include "sound_config.h"
  35 
  36 #if defined(CONFIG_PAS)
  37 
  38 #include "pas.h"
  39 
  40 #define TRACE(what)             /* (what) */
  41 
  42 extern int      translat_code;
  43 extern char     pas_model;
  44 extern int     *pas_osp;
  45 
  46 static int      rec_devices = (SOUND_MASK_MIC);         /* Default recording source */
  47 static int      mode_control = 0;
  48 
  49 #define POSSIBLE_RECORDING_DEVICES      (SOUND_MASK_SYNTH | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
  50                                          SOUND_MASK_CD | SOUND_MASK_ALTPCM)
  51 
  52 #define SUPPORTED_MIXER_DEVICES         (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
  53                                          SOUND_MASK_CD | SOUND_MASK_ALTPCM | SOUND_MASK_IMIX | \
  54                                          SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV | \
  55                                          SOUND_MASK_MUTE | SOUND_MASK_ENHANCE | SOUND_MASK_LOUD)
  56 
  57 static unsigned short levels[SOUND_MIXER_NRDEVICES] =
  58 {
  59   0x3232,                       /* Master Volume */
  60   0x3232,                       /* Bass */
  61   0x3232,                       /* Treble */
  62   0x5050,                       /* FM */
  63   0x4b4b,                       /* PCM */
  64   0x3232,                       /* PC Speaker */
  65   0x4b4b,                       /* Ext Line */
  66   0x4b4b,                       /* Mic */
  67   0x4b4b,                       /* CD */
  68   0x6464,                       /* Recording monitor */
  69   0x4b4b,                       /* SB PCM */
  70   0x6464                        /* Recording level */
  71 };
  72 
  73 void
  74 mix_write (unsigned char data, int ioaddr)
     /* [previous][next][first][last][top][bottom][index][help] */
  75 {
  76   /*
  77    * The Revision D cards have a problem with their MVA508 interface. The
  78    * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and
  79    * MSBs out of the output byte and to do a 16-bit out to the mixer port -
  80    * 1. We need to do this because it isn't timing problem but chip access
  81    * sequence problem.
  82    */
  83 
  84   if (pas_model == PAS_16D)
  85     {
  86       outw (data | (data << 8), (ioaddr ^ translat_code) - 1);
  87       outb (0x80, 0);
  88     }
  89   else
  90     pas_write (data, ioaddr);
  91 }
  92 
  93 static int
  94 mixer_output (int right_vol, int left_vol, int div, int bits,
     /* [previous][next][first][last][top][bottom][index][help] */
  95               int mixer)        /* Input or output mixer */
  96 {
  97   int             left = left_vol * div / 100;
  98   int             right = right_vol * div / 100;
  99 
 100 
 101   if (bits & P_M_MV508_MIXER)
 102     {                           /*
 103                                  * Select input or output mixer
 104                                  */
 105       left |= mixer;
 106       right |= mixer;
 107     }
 108 
 109   if (bits == P_M_MV508_BASS || bits == P_M_MV508_TREBLE)
 110     {                           /*
 111                                  * Bass and treble are mono devices
 112                                  */
 113       mix_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER);
 114       mix_write (left, PARALLEL_MIXER);
 115       right_vol = left_vol;
 116     }
 117   else
 118     {
 119       mix_write (P_M_MV508_ADDRESS | P_M_MV508_LEFT | bits, PARALLEL_MIXER);
 120       mix_write (left, PARALLEL_MIXER);
 121       mix_write (P_M_MV508_ADDRESS | P_M_MV508_RIGHT | bits, PARALLEL_MIXER);
 122       mix_write (right, PARALLEL_MIXER);
 123     }
 124 
 125   return (left_vol | (right_vol << 8));
 126 }
 127 
 128 void
 129 set_mode (int new_mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 130 {
 131   mix_write (P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER);
 132   mix_write (new_mode, PARALLEL_MIXER);
 133 
 134   mode_control = new_mode;
 135 }
 136 
 137 static int
 138 pas_mixer_set (int whichDev, unsigned int level)
     /* [previous][next][first][last][top][bottom][index][help] */
 139 {
 140   int             left, right, devmask, changed, i, mixer = 0;
 141 
 142   TRACE (printk ("static int pas_mixer_set(int whichDev = %d, unsigned int level = %X)\n", whichDev, level));
 143 
 144   left = level & 0x7f;
 145   right = (level & 0x7f00) >> 8;
 146 
 147   if (whichDev < SOUND_MIXER_NRDEVICES)
 148     if ((1 << whichDev) & rec_devices)
 149       mixer = P_M_MV508_INPUTMIX;
 150     else
 151       mixer = P_M_MV508_OUTPUTMIX;
 152 
 153   switch (whichDev)
 154     {
 155     case SOUND_MIXER_VOLUME:    /* Master volume (0-63) */
 156       levels[whichDev] = mixer_output (right, left, 63, P_M_MV508_MASTER_A, 0);
 157       break;
 158 
 159       /*
 160        * Note! Bass and Treble are mono devices. Will use just the left
 161        * channel.
 162        */
 163     case SOUND_MIXER_BASS:      /* Bass (0-12) */
 164       levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_BASS, 0);
 165       break;
 166     case SOUND_MIXER_TREBLE:    /* Treble (0-12) */
 167       levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_TREBLE, 0);
 168       break;
 169 
 170     case SOUND_MIXER_SYNTH:     /* Internal synthesizer (0-31) */
 171       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_FM, mixer);
 172       break;
 173     case SOUND_MIXER_PCM:       /* PAS PCM (0-31) */
 174       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_PCM, mixer);
 175       break;
 176     case SOUND_MIXER_ALTPCM:    /* SB PCM (0-31) */
 177       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SB, mixer);
 178       break;
 179     case SOUND_MIXER_SPEAKER:   /* PC speaker (0-31) */
 180       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SPEAKER, mixer);
 181       break;
 182     case SOUND_MIXER_LINE:      /* External line (0-31) */
 183       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_LINE, mixer);
 184       break;
 185     case SOUND_MIXER_CD:        /* CD (0-31) */
 186       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_CDROM, mixer);
 187       break;
 188     case SOUND_MIXER_MIC:       /* External microphone (0-31) */
 189       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_MIC, mixer);
 190       break;
 191     case SOUND_MIXER_IMIX:      /* Recording monitor (0-31) (Output mixer only) */
 192       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_IMIXER,
 193                                        P_M_MV508_OUTPUTMIX);
 194       break;
 195     case SOUND_MIXER_RECLEV:    /* Recording level (0-15) */
 196       levels[whichDev] = mixer_output (right, left, 15, P_M_MV508_MASTER_B, 0);
 197       break;
 198 
 199     case SOUND_MIXER_MUTE:
 200       return 0;
 201       break;
 202 
 203     case SOUND_MIXER_ENHANCE:
 204       i = 0;
 205       level &= 0x7f;
 206       if (level)
 207         i = (level / 20) - 1;
 208 
 209       mode_control &= ~P_M_MV508_ENHANCE_BITS;
 210       mode_control |= P_M_MV508_ENHANCE_BITS;
 211       set_mode (mode_control);
 212 
 213       if (i)
 214         i = (i + 1) * 20;
 215       return i;
 216       break;
 217 
 218     case SOUND_MIXER_LOUD:
 219       mode_control &= ~P_M_MV508_LOUDNESS;
 220       if (level)
 221         mode_control |= P_M_MV508_LOUDNESS;
 222       set_mode (mode_control);
 223       return !!level;           /* 0 or 1 */
 224       break;
 225 
 226     case SOUND_MIXER_RECSRC:
 227       devmask = level & POSSIBLE_RECORDING_DEVICES;
 228 
 229       changed = devmask ^ rec_devices;
 230       rec_devices = devmask;
 231 
 232       for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
 233         if (changed & (1 << i))
 234           {
 235             pas_mixer_set (i, levels[i]);
 236           }
 237       return rec_devices;
 238       break;
 239 
 240     default:
 241       return -EINVAL;
 242     }
 243 
 244   return (levels[whichDev]);
 245 }
 246 
 247 /*****/
 248 
 249 static void
 250 pas_mixer_reset (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 251 {
 252   int             foo;
 253 
 254   TRACE (printk ("pas2_mixer.c: void pas_mixer_reset(void)\n"));
 255 
 256   for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++)
 257     pas_mixer_set (foo, levels[foo]);
 258 
 259   set_mode (P_M_MV508_LOUDNESS | P_M_MV508_ENHANCE_40);
 260 }
 261 
 262 int
 263 pas_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 264 {
 265   TRACE (printk ("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
 266 
 267   if (((cmd >> 8) & 0xff) == 'M')
 268     {
 269       if (_IOC_DIR (cmd) & _IOC_WRITE)
 270         return snd_ioctl_return ((int *) arg, pas_mixer_set (cmd & 0xff, get_fs_long ((long *) arg)));
 271       else
 272         {                       /*
 273                                    * Read parameters
 274                                  */
 275 
 276           switch (cmd & 0xff)
 277             {
 278 
 279             case SOUND_MIXER_RECSRC:
 280               return snd_ioctl_return ((int *) arg, rec_devices);
 281               break;
 282 
 283             case SOUND_MIXER_STEREODEVS:
 284               return snd_ioctl_return ((int *) arg, SUPPORTED_MIXER_DEVICES & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE));
 285               break;
 286 
 287             case SOUND_MIXER_DEVMASK:
 288               return snd_ioctl_return ((int *) arg, SUPPORTED_MIXER_DEVICES);
 289               break;
 290 
 291             case SOUND_MIXER_RECMASK:
 292               return snd_ioctl_return ((int *) arg, POSSIBLE_RECORDING_DEVICES & SUPPORTED_MIXER_DEVICES);
 293               break;
 294 
 295             case SOUND_MIXER_CAPS:
 296               return snd_ioctl_return ((int *) arg, 0);         /* No special capabilities */
 297               break;
 298 
 299             case SOUND_MIXER_MUTE:
 300               return snd_ioctl_return ((int *) arg, 0);         /* No mute yet */
 301               break;
 302 
 303             case SOUND_MIXER_ENHANCE:
 304               if (!(mode_control & P_M_MV508_ENHANCE_BITS))
 305                 return snd_ioctl_return ((int *) arg, 0);
 306               return snd_ioctl_return ((int *) arg, ((mode_control & P_M_MV508_ENHANCE_BITS) + 1) * 20);
 307               break;
 308 
 309             case SOUND_MIXER_LOUD:
 310               if (mode_control & P_M_MV508_LOUDNESS)
 311                 return snd_ioctl_return ((int *) arg, 1);
 312               return snd_ioctl_return ((int *) arg, 0);
 313               break;
 314 
 315             default:
 316               return snd_ioctl_return ((int *) arg, levels[cmd & 0xff]);
 317             }
 318         }
 319     }
 320   return -EINVAL;
 321 }
 322 
 323 static struct mixer_operations pas_mixer_operations =
 324 {
 325   "Pro Audio Spectrum 16",
 326   pas_mixer_ioctl
 327 };
 328 
 329 int
 330 pas_init_mixer (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 331 {
 332   pas_mixer_reset ();
 333 
 334   if (num_mixers < MAX_MIXER_DEV)
 335     mixer_devs[num_mixers++] = &pas_mixer_operations;
 336   return 1;
 337 }
 338 
 339 #endif

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