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 sound_os_info *gus_osp;
  41 extern int      gus_base;
  42 static int      volumes[ICS_MIXDEVS];
  43 static int      left_fix[ICS_MIXDEVS] =
  44 {1, 1, 1, 2, 1, 2};
  45 static int      right_fix[ICS_MIXDEVS] =
  46 {2, 2, 2, 1, 2, 1};
  47 
  48 static int
  49 scale_vol (int vol)
     /* [previous][next][first][last][top][bottom][index][help] */
  50 {
  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 }
  76 
  77 static void
  78 write_mix (int dev, int chn, int vol)
     /* [previous][next][first][last][top][bottom][index][help] */
  79 {
  80   int            *selector;
  81   unsigned long   flags;
  82   int             ctrl_addr = dev << 3;
  83   int             attn_addr = dev << 3;
  84 
  85   vol = scale_vol (vol);
  86 
  87   if (chn == CHN_LEFT)
  88     {
  89       selector = left_fix;
  90       ctrl_addr |= 0x00;
  91       attn_addr |= 0x02;
  92     }
  93   else
  94     {
  95       selector = right_fix;
  96       ctrl_addr |= 0x01;
  97       attn_addr |= 0x03;
  98     }
  99 
 100   save_flags (flags);
 101   cli ();
 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_flags (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, ioctl_arg 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 snd_ioctl_return ((int *) arg, set_volumes (DEV_MIC, get_fs_long ((long *) arg)));
 146             break;
 147 
 148           case SOUND_MIXER_CD:
 149             return snd_ioctl_return ((int *) arg, set_volumes (DEV_CD, get_fs_long ((long *) arg)));
 150             break;
 151 
 152           case SOUND_MIXER_LINE:
 153             return snd_ioctl_return ((int *) arg, set_volumes (DEV_LINE, get_fs_long ((long *) arg)));
 154             break;
 155 
 156           case SOUND_MIXER_SYNTH:
 157             return snd_ioctl_return ((int *) arg, set_volumes (DEV_GF1, get_fs_long ((long *) arg)));
 158             break;
 159 
 160           case SOUND_MIXER_VOLUME:
 161             return snd_ioctl_return ((int *) arg, set_volumes (DEV_VOL, get_fs_long ((long *) arg)));
 162             break;
 163 
 164           default:
 165             return -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 snd_ioctl_return ((int *) arg, MIX_DEVS);
 179             break;
 180 
 181           case SOUND_MIXER_STEREODEVS:
 182             return snd_ioctl_return ((int *) arg, SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_SYNTH | SOUND_MASK_VOLUME | SOUND_MASK_MIC);
 183             break;
 184 
 185           case SOUND_MIXER_RECMASK:
 186             return snd_ioctl_return ((int *) arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
 187             break;
 188 
 189           case SOUND_MIXER_CAPS:
 190             return snd_ioctl_return ((int *) arg, 0);
 191             break;
 192 
 193           case SOUND_MIXER_MIC:
 194             return snd_ioctl_return ((int *) arg, volumes[DEV_MIC]);
 195             break;
 196 
 197           case SOUND_MIXER_LINE:
 198             return snd_ioctl_return ((int *) arg, volumes[DEV_LINE]);
 199             break;
 200 
 201           case SOUND_MIXER_CD:
 202             return snd_ioctl_return ((int *) arg, volumes[DEV_CD]);
 203             break;
 204 
 205           case SOUND_MIXER_VOLUME:
 206             return snd_ioctl_return ((int *) arg, volumes[DEV_VOL]);
 207             break;
 208 
 209           case SOUND_MIXER_SYNTH:
 210             return snd_ioctl_return ((int *) arg, volumes[DEV_GF1]);
 211             break;
 212 
 213           default:
 214             return -EINVAL;
 215           }
 216     }
 217 
 218   return -EINVAL;
 219 }
 220 
 221 static struct mixer_operations ics2101_mixer_operations =
 222 {
 223   "ICS2101 Multimedia Mixer",
 224   ics2101_mixer_ioctl
 225 };
 226 
 227 long
 228 ics2101_mixer_init (long mem_start)
     /* [previous][next][first][last][top][bottom][index][help] */
 229 {
 230   int             i;
 231 
 232   if (num_mixers < MAX_MIXER_DEV)
 233     {
 234       mixer_devs[num_mixers++] = &ics2101_mixer_operations;
 235 
 236       /*
 237          * Some GUS v3.7 cards had some channels flipped. Disable
 238          * the flipping feature if the model id is other than 5.
 239        */
 240 
 241       if (inb (u_MixSelect) != 5)
 242         {
 243           for (i = 0; i < ICS_MIXDEVS; i++)
 244             left_fix[i] = 1;
 245           for (i = 0; i < ICS_MIXDEVS; i++)
 246             right_fix[i] = 2;
 247         }
 248 
 249       set_volumes (DEV_GF1, 0x5a5a);
 250       set_volumes (DEV_CD, 0x5a5a);
 251       set_volumes (DEV_MIC, 0x0000);
 252       set_volumes (DEV_LINE, 0x5a5a);
 253       set_volumes (DEV_VOL, 0x5a5a);
 254       set_volumes (DEV_UNUSED, 0x0000);
 255     }
 256 
 257   return mem_start;
 258 }
 259 
 260 #endif

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