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 /*
   7  * Copyright by Hannu Savolainen 1993-1996
   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 #include <linux/config.h>
  30 
  31 
  32 #include "sound_config.h"
  33 #if defined(CONFIG_GUS)
  34 
  35 #include <linux/ultrasound.h>
  36 #include "gus_hw.h"
  37 
  38 #define MIX_DEVS        (SOUND_MASK_MIC|SOUND_MASK_LINE| \
  39                          SOUND_MASK_SYNTH| \
  40                          SOUND_MASK_CD | SOUND_MASK_VOLUME)
  41 
  42 extern int     *gus_osp;
  43 extern int      gus_base;
  44 static int      volumes[ICS_MIXDEVS];
  45 static int      left_fix[ICS_MIXDEVS] =
  46 {1, 1, 1, 2, 1, 2};
  47 static int      right_fix[ICS_MIXDEVS] =
  48 {2, 2, 2, 1, 2, 1};
  49 
  50 static int
  51 scale_vol (int vol)
     /* [previous][next][first][last][top][bottom][index][help] */
  52 {
  53   /*
  54      *  Experimental volume scaling by Risto Kankkunen.
  55      *  This should give smoother volume response than just
  56      *  a plain multiplication.
  57    */
  58   int             e;
  59 
  60   if (vol < 0)
  61     vol = 0;
  62   if (vol > 100)
  63     vol = 100;
  64   vol = (31 * vol + 50) / 100;
  65   e = 0;
  66   if (vol)
  67     {
  68       while (vol < 16)
  69         {
  70           vol <<= 1;
  71           e--;
  72         }
  73       vol -= 16;
  74       e += 7;
  75     }
  76   return ((e << 4) + vol);
  77 }
  78 
  79 static void
  80 write_mix (int dev, int chn, int vol)
     /* [previous][next][first][last][top][bottom][index][help] */
  81 {
  82   int            *selector;
  83   unsigned long   flags;
  84   int             ctrl_addr = dev << 3;
  85   int             attn_addr = dev << 3;
  86 
  87   vol = scale_vol (vol);
  88 
  89   if (chn == CHN_LEFT)
  90     {
  91       selector = left_fix;
  92       ctrl_addr |= 0x00;
  93       attn_addr |= 0x02;
  94     }
  95   else
  96     {
  97       selector = right_fix;
  98       ctrl_addr |= 0x01;
  99       attn_addr |= 0x03;
 100     }
 101 
 102   save_flags (flags);
 103   cli ();
 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_flags (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, caddr_t arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 136 {
 137   if (((cmd >> 8) & 0xff) == 'M')
 138     {
 139       if (_IOC_DIR (cmd) & _IOC_WRITE)
 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 snd_ioctl_return ((int *) arg, set_volumes (DEV_MIC, get_fs_long ((long *) arg)));
 148             break;
 149 
 150           case SOUND_MIXER_CD:
 151             return snd_ioctl_return ((int *) arg, set_volumes (DEV_CD, get_fs_long ((long *) arg)));
 152             break;
 153 
 154           case SOUND_MIXER_LINE:
 155             return snd_ioctl_return ((int *) arg, set_volumes (DEV_LINE, get_fs_long ((long *) arg)));
 156             break;
 157 
 158           case SOUND_MIXER_SYNTH:
 159             return snd_ioctl_return ((int *) arg, set_volumes (DEV_GF1, get_fs_long ((long *) arg)));
 160             break;
 161 
 162           case SOUND_MIXER_VOLUME:
 163             return snd_ioctl_return ((int *) arg, set_volumes (DEV_VOL, get_fs_long ((long *) arg)));
 164             break;
 165 
 166           default:
 167             return -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 snd_ioctl_return ((int *) arg, MIX_DEVS);
 181             break;
 182 
 183           case SOUND_MIXER_STEREODEVS:
 184             return snd_ioctl_return ((int *) arg, SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_SYNTH | SOUND_MASK_VOLUME | SOUND_MASK_MIC);
 185             break;
 186 
 187           case SOUND_MIXER_RECMASK:
 188             return snd_ioctl_return ((int *) arg, SOUND_MASK_MIC | SOUND_MASK_LINE);
 189             break;
 190 
 191           case SOUND_MIXER_CAPS:
 192             return snd_ioctl_return ((int *) arg, 0);
 193             break;
 194 
 195           case SOUND_MIXER_MIC:
 196             return snd_ioctl_return ((int *) arg, volumes[DEV_MIC]);
 197             break;
 198 
 199           case SOUND_MIXER_LINE:
 200             return snd_ioctl_return ((int *) arg, volumes[DEV_LINE]);
 201             break;
 202 
 203           case SOUND_MIXER_CD:
 204             return snd_ioctl_return ((int *) arg, volumes[DEV_CD]);
 205             break;
 206 
 207           case SOUND_MIXER_VOLUME:
 208             return snd_ioctl_return ((int *) arg, volumes[DEV_VOL]);
 209             break;
 210 
 211           case SOUND_MIXER_SYNTH:
 212             return snd_ioctl_return ((int *) arg, volumes[DEV_GF1]);
 213             break;
 214 
 215           default:
 216             return -EINVAL;
 217           }
 218     }
 219 
 220   return -EINVAL;
 221 }
 222 
 223 static struct mixer_operations ics2101_mixer_operations =
 224 {
 225   "ICS2101 Multimedia Mixer",
 226   ics2101_mixer_ioctl
 227 };
 228 
 229 long
 230 ics2101_mixer_init (long mem_start)
     /* [previous][next][first][last][top][bottom][index][help] */
 231 {
 232   int             i;
 233 
 234   if (num_mixers < MAX_MIXER_DEV)
 235     {
 236       mixer_devs[num_mixers++] = &ics2101_mixer_operations;
 237 
 238       /*
 239          * Some GUS v3.7 cards had some channels flipped. Disable
 240          * the flipping feature if the model id is other than 5.
 241        */
 242 
 243       if (inb (u_MixSelect) != 5)
 244         {
 245           for (i = 0; i < ICS_MIXDEVS; i++)
 246             left_fix[i] = 1;
 247           for (i = 0; i < ICS_MIXDEVS; i++)
 248             right_fix[i] = 2;
 249         }
 250 
 251       set_volumes (DEV_GF1, 0x5a5a);
 252       set_volumes (DEV_CD, 0x5a5a);
 253       set_volumes (DEV_MIC, 0x0000);
 254       set_volumes (DEV_LINE, 0x5a5a);
 255       set_volumes (DEV_VOL, 0x5a5a);
 256       set_volumes (DEV_UNUSED, 0x0000);
 257     }
 258 
 259   return mem_start;
 260 }
 261 
 262 #endif

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