home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / drivers / sound / sb_mixer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-09  |  7.9 KB  |  354 lines

  1.  
  2. /*
  3.  * sound/sb_mixer.c
  4.  * 
  5.  * The low level mixer driver for the SoundBlaster Pro and SB16 cards.
  6.  * 
  7.  * Copyright by Hannu Savolainen 1993
  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.  */
  30.  
  31. #include "sound_config.h"
  32.  
  33. #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_SBPRO)
  34. #define __SB_MIXER_C__
  35.  
  36. #include "sb.h"
  37. #include "sb_mixer.h"
  38. #undef SB_TEST_IRQ
  39.  
  40. extern int      sbc_base;
  41.  
  42. static int mixer_initialized = 0;
  43.  
  44. static int supported_rec_devices;
  45. static int supported_devices;
  46. static int recmask = 0;
  47. static int mixer_model;
  48. static int mixer_caps;
  49. static mixer_tab *iomap;
  50.  
  51. void
  52. sb_setmixer (unsigned int port, unsigned int value)
  53. {
  54.   unsigned long flags;
  55.  
  56.   DISABLE_INTR(flags);
  57.   OUTB ((unsigned char)(port & 0xff), MIXER_ADDR);    /* Select register */
  58.   tenmicrosec ();
  59.   OUTB ((unsigned char)(value & 0xff), MIXER_DATA);
  60.   tenmicrosec ();
  61.   RESTORE_INTR(flags);
  62. }
  63.  
  64. int
  65. sb_getmixer (unsigned int port)
  66. {
  67.   int             val;
  68.   unsigned long flags;
  69.  
  70.   DISABLE_INTR(flags);
  71.   OUTB ((unsigned char)(port & 0xff), MIXER_ADDR);    /* Select register */
  72.   tenmicrosec ();
  73.   val = INB (MIXER_DATA);
  74.   tenmicrosec ();
  75.   RESTORE_INTR(flags);
  76.  
  77.   return val;
  78. }
  79.  
  80. void
  81. sb_mixer_set_stereo(int mode)
  82. {
  83.   if (!mixer_initialized) return;
  84.  
  85.   sb_setmixer (OUT_FILTER, ((sb_getmixer (OUT_FILTER) & ~STEREO_DAC)
  86.              | (mode ? STEREO_DAC : MONO_DAC)));
  87. }
  88.  
  89. static int
  90. detect_mixer (void)
  91. {
  92.   /*
  93.    * Detect the mixer by changing parameters of two volume channels. If the
  94.    * values read back match with the values written, the mixer is there (is
  95.    * it?)
  96.    */
  97.   sb_setmixer (FM_VOL, 0xff);
  98.   sb_setmixer (VOC_VOL, 0x33);
  99.  
  100.   if (sb_getmixer (FM_VOL) != 0xff)
  101.     return 0;            /* No match */
  102.   if (sb_getmixer (VOC_VOL) != 0x33)
  103.     return 0;
  104.  
  105.   return 1;
  106. }
  107.  
  108. static void
  109. change_bits(unsigned char *regval, int dev, int chn, int newval)
  110. {
  111.     unsigned char mask;
  112.     int shift;
  113.  
  114.     mask = (1 << (*iomap)[dev][chn].nbits)-1;
  115.     newval = ((newval * mask) + 50) / 100;    /* Scale it */
  116.  
  117.     shift = (*iomap)[dev][chn].bitoffs-(*iomap)[dev][LEFT_CHN].nbits+1;
  118.  
  119.     *regval &= ~(mask << shift);    /* Filter out the previous value */
  120.     *regval |= (newval & mask) << shift; /* Set the new value */
  121. }
  122.  
  123. static int
  124. sb_mixer_get(int dev)
  125. {
  126.     if (!((1<<dev) & supported_devices)) 
  127.        return RET_ERROR(EINVAL);
  128.  
  129.     return levels[dev];
  130. }
  131.  
  132. static int
  133. sb_mixer_set (int dev, int value)
  134. {
  135.     int left = value & 0x000000ff;
  136.     int right = (value & 0x0000ff00) >> 8;
  137.  
  138.     int regoffs;
  139.     unsigned char val;
  140.  
  141.     if (left > 100) left = 100;
  142.     if (right > 100) right = 100;
  143.  
  144.     if (dev > 31) return RET_ERROR(EINVAL);
  145.  
  146.     if (!(supported_devices & (1 << dev)))    /* Not supported */
  147.        return RET_ERROR(EINVAL);
  148.  
  149.     regoffs = (*iomap)[dev][LEFT_CHN].regno;
  150.  
  151.     if (regoffs == 0)
  152.        return RET_ERROR(EINVAL);
  153.  
  154.     val = sb_getmixer(regoffs);
  155.     change_bits(&val, dev, LEFT_CHN, left);
  156.  
  157.     levels[dev] = left|(left << 8);
  158.  
  159.     if ((*iomap)[dev][RIGHT_CHN].regno != regoffs) /* Change register */
  160.     {
  161.         sb_setmixer(regoffs, val);    /* Save the old one */
  162.         regoffs = (*iomap)[dev][RIGHT_CHN].regno;
  163.  
  164.         if (regoffs == 0)
  165.            return left|(left << 8); /* Just left channel present */
  166.  
  167.         val = sb_getmixer(regoffs);    /* Read the new one */
  168.     }
  169.  
  170.     change_bits(&val, dev, RIGHT_CHN, right);
  171.     sb_setmixer(regoffs, val);
  172.  
  173.     levels[dev] = left | (right << 8);
  174.     return left | (right << 8);
  175. }
  176.  
  177. static void
  178. set_recsrc(int src)
  179. {
  180.     sb_setmixer(RECORD_SRC, (sb_getmixer(RECORD_SRC)&~7) | (src&0x7));
  181. }
  182.  
  183. static int
  184. set_recmask(int mask)
  185. {
  186.       int devmask, i;
  187.       unsigned char regimageL, regimageR;
  188.  
  189.       devmask = mask & supported_rec_devices;
  190.  
  191.       switch (mixer_model)
  192.       {
  193.       case 3:
  194.  
  195.       if (devmask != SOUND_MASK_MIC &&
  196.       devmask != SOUND_MASK_LINE &&
  197.       devmask != SOUND_MASK_CD)
  198.     {            /* More than one devices selected. Drop the
  199.                  * previous selection */
  200.       devmask &= ~recmask;
  201.     }
  202.  
  203.       if (devmask != SOUND_MASK_MIC &&
  204.       devmask != SOUND_MASK_LINE &&
  205.       devmask != SOUND_MASK_CD)
  206.     {            /* More than one devices selected. Default to
  207.                  * mic */
  208.       devmask = SOUND_MASK_MIC;
  209.     }
  210.  
  211.  
  212.       if (devmask ^ recmask)/* Input source changed */
  213.     {
  214.       switch (devmask)
  215.         {
  216.  
  217.         case SOUND_MASK_MIC:
  218.           set_recsrc (SRC_MIC);
  219.           break;
  220.  
  221.         case SOUND_MASK_LINE:
  222.           set_recsrc (SRC_LINE);
  223.           break;
  224.  
  225.         case SOUND_MASK_CD:
  226.           set_recsrc (SRC_CD);
  227.           break;
  228.  
  229.         default:
  230.           set_recsrc (SRC_MIC);
  231.         }
  232.     }
  233.  
  234.       break;
  235.  
  236.       case 4:
  237.     if (!devmask) devmask = SOUND_MASK_MIC;
  238.  
  239.         regimageL = regimageR = 0;
  240.     for (i=0;i<SOUND_MIXER_NRDEVICES;i++)
  241.       if ((1<<i) & devmask)
  242.       {
  243.         regimageL |= sb16_recmasks_L[i];
  244.         regimageR |= sb16_recmasks_R[i];
  245.       }
  246.     sb_setmixer(SB16_IMASK_L, regimageL);
  247.     sb_setmixer(SB16_IMASK_R, regimageR);
  248.       break;
  249.       }
  250.  
  251.       recmask = devmask;
  252.       return recmask;
  253. }
  254.  
  255. static int
  256. sb_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
  257. {
  258.   if (((cmd >> 8) & 0xff) == 'M')
  259.     {
  260.       if (cmd & IOC_IN)
  261.         switch (cmd & 0xff)
  262.         {
  263.         case SOUND_MIXER_RECSRC:
  264.            return IOCTL_OUT(arg, set_recmask(IOCTL_IN(arg)));
  265.            break;
  266.  
  267.     default:
  268.        return IOCTL_OUT (arg, sb_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
  269.         }
  270.       else
  271.       switch (cmd & 0xff)    /* Return parameters */
  272.         {
  273.  
  274.         case SOUND_MIXER_RECSRC:
  275.           return IOCTL_OUT (arg, recmask);
  276.           break;
  277.  
  278.         case SOUND_MIXER_DEVMASK:
  279.           return IOCTL_OUT (arg, supported_devices);
  280.           break;
  281.  
  282.         case SOUND_MIXER_STEREODEVS:
  283.           return IOCTL_OUT (arg, supported_devices & 
  284.                                   ~(SOUND_MASK_MIC|SOUND_MASK_SPEAKER));
  285.           break;
  286.  
  287.         case SOUND_MIXER_RECMASK:
  288.           return IOCTL_OUT (arg, supported_rec_devices);
  289.           break;
  290.  
  291.         case SOUND_MIXER_CAPS:
  292.           return IOCTL_OUT (arg, mixer_caps);
  293.           break;
  294.  
  295.         default:
  296.           return IOCTL_OUT (arg, sb_mixer_get (cmd & 0xff));
  297.         }
  298.     }
  299.   else
  300.     return RET_ERROR (EINVAL);
  301. }
  302.  
  303. static struct mixer_operations sb_mixer_operations =
  304. {
  305.   sb_mixer_ioctl
  306. };
  307.  
  308. static void
  309. sb_mixer_reset(void)
  310. {
  311.   int i;
  312.  
  313.   for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
  314.     sb_mixer_set (i, levels[i]);
  315.   set_recmask(SOUND_MASK_MIC);
  316. }
  317.  
  318. void
  319. sb_mixer_init(int major_model)
  320. {
  321.     sb_setmixer(0x00, 0);    /* Reset mixer */
  322.  
  323.     if (!detect_mixer()) return;    /* No mixer. Why? */
  324.  
  325.     mixer_initialized = 1;
  326.     mixer_model = major_model;
  327.  
  328.         switch (major_model)
  329.         {
  330.         case 3:
  331.       mixer_caps = SOUND_CAP_EXCL_INPUT;
  332.       supported_devices = SBPRO_MIXER_DEVICES;
  333.       supported_rec_devices = SBPRO_RECORDING_DEVICES;
  334.       iomap = &sbpro_mix;
  335.       break;
  336.  
  337.     case 4:
  338.       mixer_caps = 0;
  339.       supported_devices = SB16_MIXER_DEVICES;
  340.       supported_rec_devices = SB16_RECORDING_DEVICES;
  341.       iomap = &sb16_mix;
  342.       break;
  343.  
  344.     default:
  345.       printk("SB Warning: Unsupported mixer type\n");
  346.       return;
  347.     }
  348.  
  349.         mixer_devs[num_mixers++] = &sb_mixer_operations;
  350.         sb_mixer_reset();
  351. }
  352.  
  353. #endif
  354.