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

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