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 int port, unsigned int value)
     /* [previous][next][first][last][top][bottom][index][help] */
  53 {
  54   unsigned long flags;
  55 
  56   DISABLE_INTR(flags);
  57   OUTB ((unsigned char)(port & 0xff), MIXER_ADDR);      /* Select register */
  58   tenmicrosec ();
  59   OUTB ((unsigned char)(value & 0xff), MIXER_DATA);
  60   tenmicrosec ();
  61   RESTORE_INTR(flags);
  62 }
  63 
  64 int
  65 sb_getmixer (unsigned int port)
     /* [previous][next][first][last][top][bottom][index][help] */
  66 {
  67   int             val;
  68   unsigned long flags;
  69 
  70   DISABLE_INTR(flags);
  71   OUTB ((unsigned char)(port & 0xff), 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 regimageL, regimageR;
 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         regimageL = regimageR = 0;
 240         for (i=0;i<SOUND_MIXER_NRDEVICES;i++)
 241           if ((1<<i) & devmask)
 242           {
 243             regimageL |= sb16_recmasks_L[i];
 244             regimageR |= sb16_recmasks_R[i];
 245           }
 246         sb_setmixer(SB16_IMASK_L, regimageL);
 247         sb_setmixer(SB16_IMASK_R, regimageR);
 248       break;
 249       }
 250 
 251       recmask = devmask;
 252       return recmask;
 253 }
 254 
 255 static int
 256 sb_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 257 {
 258   if (((cmd >> 8) & 0xff) == 'M')
 259     {
 260       if (cmd & IOC_IN)
 261         switch (cmd & 0xff)
 262         {
 263         case SOUND_MIXER_RECSRC:
 264            return IOCTL_OUT(arg, set_recmask(IOCTL_IN(arg)));
 265            break;
 266 
 267         default:
 268            return IOCTL_OUT (arg, sb_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
 269         }
 270       else
 271           switch (cmd & 0xff)   /* Return parameters */
 272             {
 273 
 274             case SOUND_MIXER_RECSRC:
 275               return IOCTL_OUT (arg, recmask);
 276               break;
 277 
 278             case SOUND_MIXER_DEVMASK:
 279               return IOCTL_OUT (arg, supported_devices);
 280               break;
 281 
 282             case SOUND_MIXER_STEREODEVS:
 283               return IOCTL_OUT (arg, supported_devices & 
 284                                       ~(SOUND_MASK_MIC|SOUND_MASK_SPEAKER));
 285               break;
 286 
 287             case SOUND_MIXER_RECMASK:
 288               return IOCTL_OUT (arg, supported_rec_devices);
 289               break;
 290 
 291             case SOUND_MIXER_CAPS:
 292               return IOCTL_OUT (arg, mixer_caps);
 293               break;
 294 
 295             default:
 296               return IOCTL_OUT (arg, sb_mixer_get (cmd & 0xff));
 297             }
 298     }
 299   else
 300     return RET_ERROR (EINVAL);
 301 }
 302 
 303 static struct mixer_operations sb_mixer_operations =
 304 {
 305   sb_mixer_ioctl
 306 };
 307 
 308 static void
 309 sb_mixer_reset(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 310 {
 311   int i;
 312 
 313   for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
 314     sb_mixer_set (i, levels[i]);
 315   set_recmask(SOUND_MASK_MIC);
 316 }
 317 
 318 void
 319 sb_mixer_init(int major_model)
     /* [previous][next][first][last][top][bottom][index][help] */
 320 {
 321         sb_setmixer(0x00, 0);   /* Reset mixer */
 322 
 323         if (!detect_mixer()) return;    /* No mixer. Why? */
 324 
 325         mixer_initialized = 1;
 326         mixer_model = major_model;
 327 
 328         switch (major_model)
 329         {
 330         case 3:
 331           mixer_caps = SOUND_CAP_EXCL_INPUT;
 332           supported_devices = SBPRO_MIXER_DEVICES;
 333           supported_rec_devices = SBPRO_RECORDING_DEVICES;
 334           iomap = &sbpro_mix;
 335           break;
 336 
 337         case 4:
 338           mixer_caps = 0;
 339           supported_devices = SB16_MIXER_DEVICES;
 340           supported_rec_devices = SB16_RECORDING_DEVICES;
 341           iomap = &sb16_mix;
 342           break;
 343 
 344         default:
 345           printk("SB Warning: Unsupported mixer type\n");
 346           return;
 347         }
 348 
 349         mixer_devs[num_mixers++] = &sb_mixer_operations;
 350         sb_mixer_reset();
 351 }
 352 
 353 #endif

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