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

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