home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / drivers / sound / ics2101.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-18  |  6.0 KB  |  264 lines

  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)
  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)
  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)
  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)
  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_mixer_ioctl
  228. };
  229.  
  230. long
  231. ics2101_mixer_init (long mem_start)
  232. {
  233.   int             i;
  234.  
  235.   if (num_mixers < MAX_MIXER_DEV)
  236.     {
  237.       mixer_devs[num_mixers++] = &ics2101_mixer_operations;
  238.  
  239.       /*
  240.  * Some GUS v3.7 cards had some channels flipped. Disable
  241.  * the flipping feature if the model id is other than 5.
  242.  */
  243.  
  244.       if (INB (u_MixSelect) != 5)
  245.     {
  246.       for (i = 0; i < ICS_MIXDEVS; i++)
  247.         left_fix[i] = 1;
  248.       for (i = 0; i < ICS_MIXDEVS; i++)
  249.         right_fix[i] = 2;
  250.     }
  251.  
  252.       set_volumes (DEV_GF1, 0x5a5a);
  253.       set_volumes (DEV_CD, 0x5a5a);
  254.       set_volumes (DEV_MIC, 0x0000);
  255.       set_volumes (DEV_LINE, 0x5a5a);
  256.       set_volumes (DEV_VOL, 0x5a5a);
  257.       set_volumes (DEV_UNUSED, 0x0000);
  258.     }
  259.  
  260.   return mem_start;
  261. }
  262.  
  263. #endif
  264.