root/drivers/sound/ics2101.c

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

DEFINITIONS

This source file includes following definitions.
  1. scale_vol
  2. write_mix
  3. set_volumes
  4. ics2101_mixer_ioctl
  5. ics2101_mixer_init

   1 /*
   2  * sound/ics2101.c
   3  *
   4  * Driver for the ICS2101 mixer of GUS v3.7.
   5  *
   6  * Copyright by Hannu Savolainen 1994
   7  *
   8  * Redistribution and use in source and binary forms, with or without
   9  * modification, are permitted provided that the following conditions are
  10  * met: 1. Redistributions of source code must retain the above copyright
  11  * notice, this list of conditions and the following disclaimer. 2.
  12  * Redistributions in binary form must reproduce the above copyright notice,
  13  * this list of conditions and the following disclaimer in the documentation
  14  * and/or other materials provided with the distribution.
  15  *
  16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
  17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
  20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  23  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  26  * SUCH DAMAGE.
  27  *
  28  */
  29 
  30 #include "sound_config.h"
  31 #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
  32 
  33 #include <linux/ultrasound.h>
  34 #include "gus_hw.h"
  35 
  36 #define MIX_DEVS        (SOUND_MASK_MIC|SOUND_MASK_LINE| \
  37                          SOUND_MASK_SYNTH| \
  38                          SOUND_MASK_CD | SOUND_MASK_VOLUME)
  39 
  40 extern int      gus_base;
  41 static int      volumes[ICS_MIXDEVS];
  42 static int      left_fix[ICS_MIXDEVS] =
  43 {1, 1, 1, 2, 1, 2};
  44 static int      right_fix[ICS_MIXDEVS] =
  45 {2, 2, 2, 1, 2, 1};
  46 
  47 static int
  48 scale_vol (int vol)
     /* [previous][next][first][last][top][bottom][index][help] */
  49 {
  50 #if 1
  51   /*
  52      *  Experimental volume scaling by Risto Kankkunen.
  53      *  This should give smoother volume response than just
  54      *  a plain multiplication.
  55    */
  56   int             e;
  57 
  58   if (vol < 0)
  59     vol = 0;
  60   if (vol > 100)
  61     vol = 100;
  62   vol = (31 * vol + 50) / 100;
  63   e = 0;
  64   if (vol)
  65     {
  66       while (vol < 16)
  67         {
  68           vol <<= 1;
  69           e--;
  70         }
  71       vol -= 16;
  72       e += 7;
  73     }
  74   return ((e << 4) + vol);
  75 #else
  76   return ((vol * 127) + 50) / 100;
  77 #endif
  78 }
  79 
  80 static void
  81 write_mix (int dev, int chn, int vol)
     /* [previous][next][first][last][top][bottom][index][help] */
  82 {
  83   int            *selector;
  84   unsigned long   flags;
  85   int             ctrl_addr = dev << 3;
  86   int             attn_addr = dev << 3;
  87 
  88   vol = scale_vol (vol);
  89 
  90   if (chn == CHN_LEFT)
  91     {
  92       selector = left_fix;
  93       ctrl_addr |= 0x00;
  94       attn_addr |= 0x02;
  95     }
  96   else
  97     {
  98       selector = right_fix;
  99       ctrl_addr |= 0x01;
 100       attn_addr |= 0x03;
 101     }
 102 
 103   DISABLE_INTR (flags);
 104   OUTB (ctrl_addr, u_MixSelect);
 105   OUTB (selector[dev], u_MixData);
 106   OUTB (attn_addr, u_MixSelect);
 107   OUTB ((unsigned char) vol, u_MixData);
 108   RESTORE_INTR (flags);
 109 }
 110 
 111 static int
 112 set_volumes (int dev, int vol)
     /* [previous][next][first][last][top][bottom][index][help] */
 113 {
 114   int             left = vol & 0x00ff;
 115   int             right = (vol >> 8) & 0x00ff;
 116 
 117   if (left < 0)
 118     left = 0;
 119   if (left > 100)
 120     left = 100;
 121   if (right < 0)
 122     right = 0;
 123   if (right > 100)
 124     right = 100;
 125 
 126   write_mix (dev, CHN_LEFT, left);
 127   write_mix (dev, CHN_RIGHT, right);
 128 
 129   vol = left + (right << 8);
 130   volumes[dev] = vol;
 131   return vol;
 132 }
 133 
 134 static int
 135 ics2101_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 136 {
 137   if (((cmd >> 8) & 0xff) == 'M')
 138     {
 139       if (cmd & IOC_IN)
 140         switch (cmd & 0xff)
 141           {
 142           case SOUND_MIXER_RECSRC:
 143             return gus_default_mixer_ioctl (dev, cmd, arg);
 144             break;
 145 
 146           case SOUND_MIXER_MIC:
 147             return IOCTL_OUT (arg, set_volumes (DEV_MIC, IOCTL_IN (arg)));
 148             break;
 149 
 150           case SOUND_MIXER_CD:
 151             return IOCTL_OUT (arg, set_volumes (DEV_CD, IOCTL_IN (arg)));
 152             break;
 153 
 154           case SOUND_MIXER_LINE:
 155             return IOCTL_OUT (arg, set_volumes (DEV_LINE, IOCTL_IN (arg)));
 156             break;
 157 
 158           case SOUND_MIXER_SYNTH:
 159             return IOCTL_OUT (arg, set_volumes (DEV_GF1, IOCTL_IN (arg)));
 160             break;
 161 
 162           case SOUND_MIXER_VOLUME:
 163             return IOCTL_OUT (arg, set_volumes (DEV_VOL, IOCTL_IN (arg)));
 164             break;
 165 
 166           default:
 167             return RET_ERROR (EINVAL);
 168           }
 169       else
 170         switch (cmd & 0xff)     /*
 171                                  * Return parameters
 172                                  */
 173           {
 174 
 175           case SOUND_MIXER_RECSRC:
 176             return gus_default_mixer_ioctl (dev, cmd, arg);
 177             break;
 178 
 179           case SOUND_MIXER_DEVMASK:
 180             return IOCTL_OUT (arg, MIX_DEVS);
 181             break;
 182 
 183           case SOUND_MIXER_STEREODEVS:
 184             return IOCTL_OUT (arg, SOUND_MASK_LINE | SOUND_MASK_CD |
 185                               SOUND_MASK_SYNTH | SOUND_MASK_VOLUME |
 186                               SOUND_MASK_MIC);
 187             break;
 188 
 189           case SOUND_MIXER_RECMASK:
 190             return IOCTL_OUT (arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
 191             break;
 192 
 193           case SOUND_MIXER_CAPS:
 194             return IOCTL_OUT (arg, 0);
 195             break;
 196 
 197           case SOUND_MIXER_MIC:
 198             return IOCTL_OUT (arg, volumes[DEV_MIC]);
 199             break;
 200 
 201           case SOUND_MIXER_LINE:
 202             return IOCTL_OUT (arg, volumes[DEV_LINE]);
 203             break;
 204 
 205           case SOUND_MIXER_CD:
 206             return IOCTL_OUT (arg, volumes[DEV_CD]);
 207             break;
 208 
 209           case SOUND_MIXER_VOLUME:
 210             return IOCTL_OUT (arg, volumes[DEV_VOL]);
 211             break;
 212 
 213           case SOUND_MIXER_SYNTH:
 214             return IOCTL_OUT (arg, volumes[DEV_GF1]);
 215             break;
 216 
 217           default:
 218             return RET_ERROR (EINVAL);
 219           }
 220     }
 221 
 222   return RET_ERROR (EINVAL);
 223 }
 224 
 225 static struct mixer_operations ics2101_mixer_operations =
 226 {
 227   "ICS2101 Multimedia Mixer",
 228   ics2101_mixer_ioctl
 229 };
 230 
 231 long
 232 ics2101_mixer_init (long mem_start)
     /* [previous][next][first][last][top][bottom][index][help] */
 233 {
 234   int             i;
 235 
 236   if (num_mixers < MAX_MIXER_DEV)
 237     {
 238       mixer_devs[num_mixers++] = &ics2101_mixer_operations;
 239 
 240       /*
 241          * Some GUS v3.7 cards had some channels flipped. Disable
 242          * the flipping feature if the model id is other than 5.
 243        */
 244 
 245       if (INB (u_MixSelect) != 5)
 246         {
 247           for (i = 0; i < ICS_MIXDEVS; i++)
 248             left_fix[i] = 1;
 249           for (i = 0; i < ICS_MIXDEVS; i++)
 250             right_fix[i] = 2;
 251         }
 252 
 253       set_volumes (DEV_GF1, 0x5a5a);
 254       set_volumes (DEV_CD, 0x5a5a);
 255       set_volumes (DEV_MIC, 0x0000);
 256       set_volumes (DEV_LINE, 0x5a5a);
 257       set_volumes (DEV_VOL, 0x5a5a);
 258       set_volumes (DEV_UNUSED, 0x0000);
 259     }
 260 
 261   return mem_start;
 262 }
 263 
 264 #endif

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