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  */
  30 
  31 #include "sound_config.h"
  32 
  33 #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_SBPRO)
  34 #define __SB_MIXER_C__
  35 
  36 #include "sb.h"
  37 #include "sb_mixer.h"
  38 #undef SB_TEST_IRQ
  39 
  40 extern int      sbc_base;
  41 
  42 static int mixer_initialized = 0;
  43 
  44 static int supported_rec_devices;
  45 static int supported_devices;
  46 static int recmask = 0;
  47 static int mixer_model;
  48 static int mixer_caps;
  49 static mixer_tab *iomap;
  50 
  51 void
  52 sb_setmixer (unsigned char port, unsigned char value)
     /* [previous][next][first][last][top][bottom][index][help] */
  53 {
  54   unsigned long flags;
  55 
  56   DISABLE_INTR(flags);
  57   OUTB (port, MIXER_ADDR);      /* Select register */
  58   tenmicrosec ();
  59   OUTB (value, MIXER_DATA);
  60   tenmicrosec ();
  61   RESTORE_INTR(flags);
  62 }
  63 
  64 int
  65 sb_getmixer (unsigned char port)
     /* [previous][next][first][last][top][bottom][index][help] */
  66 {
  67   int             val;
  68   unsigned long flags;
  69 
  70   DISABLE_INTR(flags);
  71   OUTB (port, MIXER_ADDR);      /* Select register */
  72   tenmicrosec ();
  73   val = INB (MIXER_DATA);
  74   tenmicrosec ();
  75   RESTORE_INTR(flags);
  76 
  77   return val;
  78 }
  79 
  80 void
  81 sb_mixer_set_stereo(int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
  82 {
  83   if (!mixer_initialized) return;
  84 
  85   sb_setmixer (OUT_FILTER, ((sb_getmixer (OUT_FILTER) & ~STEREO_DAC)
  86                          | (mode ? STEREO_DAC : MONO_DAC)));
  87 }
  88 
  89 static int
  90 detect_mixer (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  91 {
  92   /*
  93    * Detect the mixer by changing parameters of two volume channels. If the
  94    * values read back match with the values written, the mixer is there (is
  95    * it?)
  96    */
  97   sb_setmixer (FM_VOL, 0xff);
  98   sb_setmixer (VOC_VOL, 0x33);
  99 
 100   if (sb_getmixer (FM_VOL) != 0xff)
 101     return 0;                   /* No match */
 102   if (sb_getmixer (VOC_VOL) != 0x33)
 103     return 0;
 104 
 105   return 1;
 106 }
 107 
 108 static void
 109 change_bits(unsigned char *regval, int dev, int chn, int newval)
     /* [previous][next][first][last][top][bottom][index][help] */
 110 {
 111         unsigned char mask;
 112         int shift;
 113 
 114         mask = (1 << (*iomap)[dev][chn].nbits)-1;
 115         newval = ((newval * mask) + 50) / 100;  /* Scale it */
 116 
 117         shift = (*iomap)[dev][chn].bitoffs-(*iomap)[dev][LEFT_CHN].nbits+1;
 118 
 119         *regval &= ~(mask << shift);    /* Filter out the previous value */
 120         *regval |= (newval & mask) << shift; /* Set the new value */
 121 }
 122 
 123 static int
 124 sb_mixer_get(int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 125 {
 126         if (!((1<<dev) & supported_devices)) 
 127            return RET_ERROR(EINVAL);
 128 
 129         return levels[dev];
 130 }
 131 
 132 static int
 133 sb_mixer_set (int dev, int value)
     /* [previous][next][first][last][top][bottom][index][help] */
 134 {
 135         int left = value & 0x000000ff;
 136         int right = (value & 0x0000ff00) >> 8;
 137 
 138         int regoffs;
 139         unsigned char val;
 140 
 141         if (left > 100) left = 100;
 142         if (right > 100) right = 100;
 143 
 144         if (dev > 31) return RET_ERROR(EINVAL);
 145 
 146         if (!(supported_devices & (1 << dev)))  /* Not supported */
 147            return RET_ERROR(EINVAL);
 148 
 149         regoffs = (*iomap)[dev][LEFT_CHN].regno;
 150 
 151         if (regoffs == 0)
 152            return RET_ERROR(EINVAL);
 153 
 154         val = sb_getmixer(regoffs);
 155         change_bits(&val, dev, LEFT_CHN, left);
 156 
 157         levels[dev] = left|(left << 8);
 158 
 159         if ((*iomap)[dev][RIGHT_CHN].regno != regoffs) /* Change register */
 160         {
 161                 sb_setmixer(regoffs, val);      /* Save the old one */
 162                 regoffs = (*iomap)[dev][RIGHT_CHN].regno;
 163 
 164                 if (regoffs == 0)
 165                    return left|(left << 8); /* Just left channel present */
 166 
 167                 val = sb_getmixer(regoffs);     /* Read the new one */
 168         }
 169 
 170         change_bits(&val, dev, RIGHT_CHN, right);
 171         sb_setmixer(regoffs, val);
 172 
 173         levels[dev] = left | (right << 8);
 174         return left | (right << 8);
 175 }
 176 
 177 static void
 178 set_recsrc(int src)
     /* [previous][next][first][last][top][bottom][index][help] */
 179 {
 180         sb_setmixer(RECORD_SRC, (sb_getmixer(RECORD_SRC)&~7) | (src&0x7));
 181 }
 182 
 183 static int
 184 set_recmask(int mask)
     /* [previous][next][first][last][top][bottom][index][help] */
 185 {
 186       int devmask, i;
 187       unsigned char regimage;
 188 
 189       devmask = mask & supported_rec_devices;
 190 
 191       switch (mixer_model)
 192       {
 193       case 3:
 194 
 195       if (devmask != SOUND_MASK_MIC &&
 196           devmask != SOUND_MASK_LINE &&
 197           devmask != SOUND_MASK_CD)
 198         {                       /* More than one devices selected. Drop the
 199                                  * previous selection */
 200           devmask &= ~recmask;
 201         }
 202 
 203       if (devmask != SOUND_MASK_MIC &&
 204           devmask != SOUND_MASK_LINE &&
 205           devmask != SOUND_MASK_CD)
 206         {                       /* More than one devices selected. Default to
 207                                  * mic */
 208           devmask = SOUND_MASK_MIC;
 209         }
 210 
 211 
 212       if (devmask ^ recmask)/* Input source changed */
 213         {
 214           switch (devmask)
 215             {
 216 
 217             case SOUND_MASK_MIC:
 218               set_recsrc (SRC_MIC);
 219               break;
 220 
 221             case SOUND_MASK_LINE:
 222               set_recsrc (SRC_LINE);
 223               break;
 224 
 225             case SOUND_MASK_CD:
 226               set_recsrc (SRC_CD);
 227               break;
 228 
 229             default:
 230               set_recsrc (SRC_MIC);
 231             }
 232         }
 233 
 234       break;
 235 
 236       case 4:
 237         if (!devmask) devmask = SOUND_MASK_MIC;
 238 
 239         regimage = 0;
 240         for (i=0;i<SOUND_MIXER_NRDEVICES;i++)
 241           if ((1<<i) & devmask)
 242             regimage |= sb16_recmasks[i];
 243         sb_setmixer(SB16_IMASK_L, regimage);
 244         sb_setmixer(SB16_IMASK_R, regimage);
 245       break;
 246       }
 247 
 248       recmask = devmask;
 249       return recmask;
 250 }
 251 
 252 static int
 253 sb_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 254 {
 255   if (((cmd >> 8) & 0xff) == 'M')
 256     {
 257       if (cmd & IOC_IN)
 258         switch (cmd & 0xff)
 259         {
 260         case SOUND_MIXER_RECSRC:
 261            return IOCTL_OUT(arg, set_recmask(IOCTL_IN(arg)));
 262            break;
 263 
 264         default:
 265            return IOCTL_OUT (arg, sb_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
 266         }
 267       else
 268           switch (cmd & 0xff)   /* Return parameters */
 269             {
 270 
 271             case SOUND_MIXER_RECSRC:
 272               return IOCTL_OUT (arg, recmask);
 273               break;
 274 
 275             case SOUND_MIXER_DEVMASK:
 276               return IOCTL_OUT (arg, supported_devices);
 277               break;
 278 
 279             case SOUND_MIXER_STEREODEVS:
 280               return IOCTL_OUT (arg, supported_devices & ~SOUND_MASK_MIC);
 281               break;
 282 
 283             case SOUND_MIXER_RECMASK:
 284               return IOCTL_OUT (arg, supported_rec_devices);
 285               break;
 286 
 287             case SOUND_MIXER_CAPS:
 288               return IOCTL_OUT (arg, mixer_caps);
 289               break;
 290 
 291             default:
 292               return IOCTL_OUT (arg, sb_mixer_get (cmd & 0xff));
 293             }
 294     }
 295   else
 296     return RET_ERROR (EINVAL);
 297 }
 298 
 299 static struct mixer_operations sb_mixer_operations =
 300 {
 301   sb_mixer_ioctl
 302 };
 303 
 304 static void
 305 sb_mixer_reset(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 306 {
 307   int i;
 308 
 309   for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
 310     sb_mixer_set (i, levels[i]);
 311   set_recmask(SOUND_MASK_MIC);
 312 }
 313 
 314 void
 315 sb_mixer_init(int major_model)
     /* [previous][next][first][last][top][bottom][index][help] */
 316 {
 317         sb_setmixer(0x00, 0);   /* Reset mixer */
 318 
 319         if (!detect_mixer()) return;    /* No mixer. Why? */
 320 
 321         mixer_initialized = 1;
 322         mixer_model = major_model;
 323 
 324         switch (major_model)
 325         {
 326         case 3:
 327           mixer_caps = SOUND_CAP_EXCL_INPUT;
 328           supported_devices = SBPRO_MIXER_DEVICES;
 329           supported_rec_devices = SBPRO_RECORDING_DEVICES;
 330           iomap = &sbpro_mix;
 331           break;
 332 
 333         case 4:
 334           mixer_caps = 0;
 335           supported_devices = SB16_MIXER_DEVICES;
 336           supported_rec_devices = SB16_RECORDING_DEVICES;
 337           iomap = &sb16_mix;
 338           break;
 339 
 340         default:
 341           printk("SB Warning: Unsupported mixer type\n");
 342           return;
 343         }
 344 
 345         mixer_devs[num_mixers++] = &sb_mixer_operations;
 346         sb_mixer_reset();
 347 }
 348 
 349 #endif

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