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                 while (vol < 16) {
  66                         vol <<= 1;
  67                         e--;
  68                 }
  69                 vol -= 16;
  70                 e += 7;
  71         }
  72         return ((e << 4) + vol);
  73 #else
  74   return ((vol*127)+50)/100;
  75 #endif
  76 }
  77 
  78 static void
  79 write_mix (int dev, int chn, int vol)
     /* [previous][next][first][last][top][bottom][index][help] */
  80 {
  81   int            *selector;
  82   unsigned long   flags;
  83   int             ctrl_addr = dev << 3;
  84   int             attn_addr = dev << 3;
  85 
  86   vol=scale_vol(vol);
  87 
  88   if (chn == CHN_LEFT)
  89     {
  90       selector = left_fix;
  91       ctrl_addr |= 0x00;
  92       attn_addr |= 0x02;
  93     }
  94   else
  95     {
  96       selector = right_fix;
  97       ctrl_addr |= 0x01;
  98       attn_addr |= 0x03;
  99     }
 100 
 101   DISABLE_INTR (flags);
 102   OUTB (ctrl_addr, u_MixSelect);
 103   OUTB (selector[dev], u_MixData);
 104   OUTB (attn_addr, u_MixSelect);
 105   OUTB ((unsigned char) vol, u_MixData);
 106   RESTORE_INTR (flags);
 107 }
 108 
 109 static int
 110 set_volumes (int dev, int vol)
     /* [previous][next][first][last][top][bottom][index][help] */
 111 {
 112   int             left = vol & 0x00ff;
 113   int             right = (vol >> 8) & 0x00ff;
 114 
 115   if (left < 0)
 116     left = 0;
 117   if (left > 100)
 118     left = 100;
 119   if (right < 0)
 120     right = 0;
 121   if (right > 100)
 122     right = 100;
 123 
 124   write_mix (dev, CHN_LEFT, left);
 125   write_mix (dev, CHN_RIGHT, right);
 126 
 127   vol = left + (right << 8);
 128   volumes[dev] = vol;
 129   return vol;
 130 }
 131 
 132 static int
 133 ics2101_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 134 {
 135   if (((cmd >> 8) & 0xff) == 'M')
 136     {
 137       if (cmd & IOC_IN)
 138         switch (cmd & 0xff)
 139           {
 140           case SOUND_MIXER_RECSRC:
 141             return gus_default_mixer_ioctl (dev, cmd, arg);
 142             break;
 143 
 144           case SOUND_MIXER_MIC:
 145             return IOCTL_OUT (arg, set_volumes (DEV_MIC, IOCTL_IN (arg)));
 146             break;
 147 
 148           case SOUND_MIXER_CD:
 149             return IOCTL_OUT (arg, set_volumes (DEV_CD, IOCTL_IN (arg)));
 150             break;
 151 
 152           case SOUND_MIXER_LINE:
 153             return IOCTL_OUT (arg, set_volumes (DEV_LINE, IOCTL_IN (arg)));
 154             break;
 155 
 156           case SOUND_MIXER_SYNTH:
 157             return IOCTL_OUT (arg, set_volumes (DEV_GF1, IOCTL_IN (arg)));
 158             break;
 159 
 160           case SOUND_MIXER_VOLUME:
 161             return IOCTL_OUT (arg, set_volumes (DEV_VOL, IOCTL_IN (arg)));
 162             break;
 163 
 164           default:
 165             return RET_ERROR (EINVAL);
 166           }
 167       else
 168         switch (cmd & 0xff)     /*
 169                                  * Return parameters
 170                                  */
 171           {
 172 
 173           case SOUND_MIXER_RECSRC:
 174             return gus_default_mixer_ioctl (dev, cmd, arg);
 175             break;
 176 
 177           case SOUND_MIXER_DEVMASK:
 178             return IOCTL_OUT (arg, MIX_DEVS);
 179             break;
 180 
 181           case SOUND_MIXER_STEREODEVS:
 182             return IOCTL_OUT (arg, SOUND_MASK_LINE | SOUND_MASK_CD |
 183                               SOUND_MASK_SYNTH | SOUND_MASK_VOLUME|
 184                               SOUND_MASK_MIC);
 185             break;
 186 
 187           case SOUND_MIXER_RECMASK:
 188             return IOCTL_OUT (arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
 189             break;
 190 
 191           case SOUND_MIXER_CAPS:
 192             return IOCTL_OUT (arg, 0);
 193             break;
 194 
 195           case SOUND_MIXER_MIC:
 196             return IOCTL_OUT (arg, volumes[DEV_MIC]);
 197             break;
 198 
 199           case SOUND_MIXER_LINE:
 200             return IOCTL_OUT (arg, volumes[DEV_LINE]);
 201             break;
 202 
 203           case SOUND_MIXER_CD:
 204             return IOCTL_OUT (arg, volumes[DEV_CD]);
 205             break;
 206 
 207           case SOUND_MIXER_VOLUME:
 208             return IOCTL_OUT (arg, volumes[DEV_VOL]);
 209             break;
 210 
 211           case SOUND_MIXER_SYNTH:
 212             return IOCTL_OUT (arg, volumes[DEV_GF1]);
 213             break;
 214 
 215           default:
 216             return RET_ERROR (EINVAL);
 217           }
 218     }
 219 
 220   return RET_ERROR (EINVAL);
 221 }
 222 
 223 static struct mixer_operations ics2101_mixer_operations =
 224 {
 225   ics2101_mixer_ioctl
 226 };
 227 
 228 long
 229 ics2101_mixer_init (long mem_start)
     /* [previous][next][first][last][top][bottom][index][help] */
 230 {
 231   int             i;
 232 
 233   if (num_mixers < MAX_MIXER_DEV)
 234     {
 235       mixer_devs[num_mixers++] = &ics2101_mixer_operations;
 236 
 237       /*
 238  * Some GUS v3.7 cards had some channels flipped. Disable
 239  * the flipping feature if the model id is other than 5.
 240  */
 241 
 242       if (INB (u_MixSelect) != 5)
 243         {
 244           for (i = 0; i < ICS_MIXDEVS; i++)
 245             left_fix[i] = 1;
 246           for (i = 0; i < ICS_MIXDEVS; i++)
 247             right_fix[i] = 2;
 248         }
 249 
 250       set_volumes (DEV_GF1, 0x5a5a);
 251       set_volumes (DEV_CD, 0x5a5a);
 252       set_volumes (DEV_MIC, 0x0000);
 253       set_volumes (DEV_LINE, 0x5a5a);
 254       set_volumes (DEV_VOL, 0x5a5a);
 255       set_volumes (DEV_UNUSED, 0x0000);
 256     }
 257 
 258   return mem_start;
 259 }
 260 
 261 #endif

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