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 / pas2_mixer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-19  |  9.8 KB  |  386 lines

  1. #define _PAS2_MIXER_C_
  2.  
  3. /*
  4.  * sound/pas2_mixer.c
  5.  *
  6.  * Mixer routines for the Pro Audio Spectrum cards.
  7.  *
  8.  * Copyright by Hannu Savolainen 1993
  9.  *
  10.  * Redistribution and use in source and binary forms, with or without
  11.  * modification, are permitted provided that the following conditions are
  12.  * met: 1. Redistributions of source code must retain the above copyright
  13.  * notice, this list of conditions and the following disclaimer. 2.
  14.  * Redistributions in binary form must reproduce the above copyright notice,
  15.  * this list of conditions and the following disclaimer in the documentation
  16.  * and/or other materials provided with the distribution.
  17.  *
  18.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
  19.  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21.  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
  22.  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  23.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  24.  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  25.  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  27.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28.  * SUCH DAMAGE.
  29.  *
  30.  */
  31.  
  32. #include "sound_config.h"
  33.  
  34. #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PAS)
  35.  
  36. #include "pas.h"
  37.  
  38. #define TRACE(what)        /*
  39.                    * * * (what)   */
  40.  
  41. extern int      translat_code;
  42.  
  43. static int      rec_devices = (SOUND_MASK_MIC);    /*
  44.  
  45.  
  46.                              * *  * * Default *
  47.                              * recording * source
  48.                              *
  49.                              * *  */
  50. static int      mode_control = 0;
  51.  
  52. #define POSSIBLE_RECORDING_DEVICES    (SOUND_MASK_SYNTH | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
  53.                      SOUND_MASK_CD | SOUND_MASK_ALTPCM)
  54.  
  55. #define SUPPORTED_MIXER_DEVICES        (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
  56.                      SOUND_MASK_CD | SOUND_MASK_ALTPCM | SOUND_MASK_IMIX | \
  57.                      SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV | \
  58.                      SOUND_MASK_MUTE | SOUND_MASK_ENHANCE | SOUND_MASK_LOUD)
  59.  
  60. static unsigned short levels[SOUND_MIXER_NRDEVICES] =
  61. {
  62.   0x3232,            /*
  63.                  * Master Volume
  64.                  */
  65.   0x3232,            /*
  66.                  * Bass
  67.                  */
  68.   0x3232,            /*
  69.                  * Treble
  70.                  */
  71.   0x5050,            /*
  72.                  * FM
  73.                  */
  74.   0x4b4b,            /*
  75.                  * PCM
  76.                  */
  77.   0x3232,            /*
  78.                  * PC Speaker
  79.                  */
  80.   0x4b4b,            /*
  81.                  * Ext Line
  82.                  */
  83.   0x4b4b,            /*
  84.                  * Mic
  85.                  */
  86.   0x4b4b,            /*
  87.                  * CD
  88.                  */
  89.   0x6464,            /*
  90.                  * Recording monitor
  91.                  */
  92.   0x4b4b,            /*
  93.                  * SB PCM
  94.                  */
  95.   0x6464};            /*
  96.  
  97.  
  98.                  * *  * * Recording level   */
  99.  
  100. static int
  101. mixer_output (int right_vol, int left_vol, int div, int bits,
  102.           int mixer        /*
  103.                  * Input or output mixer
  104.                                                                         */ )
  105. {
  106.   int             left = left_vol * div / 100;
  107.   int             right = right_vol * div / 100;
  108.  
  109.   /*
  110.    * The Revision D cards have a problem with their MVA508 interface. The
  111.    * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and
  112.    * MSBs out of the output byte and to do a 16-bit out to the mixer port -
  113.    * 1. We don't need to do this because the call to pas_write more than
  114.    * compensates for the timing problems.
  115.    */
  116.  
  117.   if (bits & P_M_MV508_MIXER)
  118.     {                /*
  119.                  * Select input or output mixer
  120.                  */
  121.       left |= mixer;
  122.       right |= mixer;
  123.     }
  124.  
  125.   if (bits == P_M_MV508_BASS || bits == P_M_MV508_TREBLE)
  126.     {                /*
  127.                  * Bass and treble are mono devices
  128.                  */
  129.       pas_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER);
  130.       pas_write (left, PARALLEL_MIXER);
  131.       right_vol = left_vol;
  132.     }
  133.   else
  134.     {
  135.       pas_write (P_M_MV508_ADDRESS | P_M_MV508_LEFT | bits, PARALLEL_MIXER);
  136.       pas_write (left, PARALLEL_MIXER);
  137.       pas_write (P_M_MV508_ADDRESS | P_M_MV508_RIGHT | bits, PARALLEL_MIXER);
  138.       pas_write (right, PARALLEL_MIXER);
  139.     }
  140.  
  141.   return (left_vol | (right_vol << 8));
  142. }
  143.  
  144. void
  145. set_mode (int new_mode)
  146. {
  147.   pas_write (P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER);
  148.   pas_write (new_mode, PARALLEL_MIXER);
  149.  
  150.   mode_control = new_mode;
  151. }
  152.  
  153. static int
  154. pas_mixer_set (int whichDev, unsigned int level)
  155. {
  156.   int             left, right, devmask, changed, i, mixer = 0;
  157.  
  158.   TRACE (printk ("static int pas_mixer_set(int whichDev = %d, unsigned int level = %X)\n", whichDev, level));
  159.  
  160.   left = level & 0x7f;
  161.   right = (level & 0x7f00) >> 8;
  162.  
  163.   if (whichDev < SOUND_MIXER_NRDEVICES)
  164.     if ((1 << whichDev) & rec_devices)
  165.       mixer = P_M_MV508_INPUTMIX;
  166.     else
  167.       mixer = P_M_MV508_OUTPUTMIX;
  168.  
  169.   switch (whichDev)
  170.     {
  171.     case SOUND_MIXER_VOLUME:    /*
  172.                  * Master volume (0-63)
  173.                  */
  174.       levels[whichDev] = mixer_output (right, left, 63, P_M_MV508_MASTER_A, 0);
  175.       break;
  176.  
  177.       /*
  178.        * Note! Bass and Treble are mono devices. Will use just the left
  179.        * channel.
  180.        */
  181.     case SOUND_MIXER_BASS:    /*
  182.                  * Bass (0-12)
  183.                  */
  184.       levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_BASS, 0);
  185.       break;
  186.     case SOUND_MIXER_TREBLE:    /*
  187.                  * Treble (0-12)
  188.                  */
  189.       levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_TREBLE, 0);
  190.       break;
  191.  
  192.     case SOUND_MIXER_SYNTH:    /*
  193.                  * Internal synthesizer (0-31)
  194.                  */
  195.       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_FM, mixer);
  196.       break;
  197.     case SOUND_MIXER_PCM:    /*
  198.                  * PAS PCM (0-31)
  199.                  */
  200.       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_PCM, mixer);
  201.       break;
  202.     case SOUND_MIXER_ALTPCM:    /*
  203.                  * SB PCM (0-31)
  204.                  */
  205.       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SB, mixer);
  206.       break;
  207.     case SOUND_MIXER_SPEAKER:    /*
  208.                  * PC speaker (0-31)
  209.                  */
  210.       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SPEAKER, mixer);
  211.       break;
  212.     case SOUND_MIXER_LINE:    /*
  213.                  * External line (0-31)
  214.                  */
  215.       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_LINE, mixer);
  216.       break;
  217.     case SOUND_MIXER_CD:    /*
  218.                  * CD (0-31)
  219.                  */
  220.       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_CDROM, mixer);
  221.       break;
  222.     case SOUND_MIXER_MIC:    /*
  223.                  * External microphone (0-31)
  224.                  */
  225.       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_MIC, mixer);
  226.       break;
  227.     case SOUND_MIXER_IMIX:    /*
  228.                  * Recording monitor (0-31) (Only available *
  229.                  * on the Output Mixer)
  230.                  */
  231.       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_IMIXER,
  232.                        P_M_MV508_OUTPUTMIX);
  233.       break;
  234.     case SOUND_MIXER_RECLEV:    /*
  235.                  * Recording level (0-15)
  236.                  */
  237.       levels[whichDev] = mixer_output (right, left, 15, P_M_MV508_MASTER_B, 0);
  238.       break;
  239.  
  240.     case SOUND_MIXER_MUTE:
  241.       return 0;
  242.       break;
  243.  
  244.     case SOUND_MIXER_ENHANCE:
  245.       i = 0;
  246.       level &= 0x7f;
  247.       if (level)
  248.     i = (level / 20) - 1;
  249.  
  250.       mode_control &= ~P_M_MV508_ENHANCE_BITS;
  251.       mode_control |= P_M_MV508_ENHANCE_BITS;
  252.       set_mode (mode_control);
  253.  
  254.       if (i)
  255.     i = (i + 1) * 20;
  256.       return i;
  257.       break;
  258.  
  259.     case SOUND_MIXER_LOUD:
  260.       mode_control &= ~P_M_MV508_LOUDNESS;
  261.       if (level)
  262.     mode_control |= P_M_MV508_LOUDNESS;
  263.       set_mode (mode_control);
  264.       return !!level;        /*
  265.                  * 0 or 1
  266.                  */
  267.       break;
  268.  
  269.     case SOUND_MIXER_RECSRC:
  270.       devmask = level & POSSIBLE_RECORDING_DEVICES;
  271.  
  272.       changed = devmask ^ rec_devices;
  273.       rec_devices = devmask;
  274.  
  275.       for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
  276.     if (changed & (1 << i))
  277.       {
  278.         pas_mixer_set (i, levels[i]);
  279.       }
  280.       return rec_devices;
  281.       break;
  282.  
  283.     default:
  284.       return RET_ERROR (EINVAL);
  285.     }
  286.  
  287.   return (levels[whichDev]);
  288. }
  289.  
  290. /*****/
  291.  
  292. static void
  293. pas_mixer_reset (void)
  294. {
  295.   int             foo;
  296.  
  297.   TRACE (printk ("pas2_mixer.c: void pas_mixer_reset(void)\n"));
  298.  
  299.   for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++)
  300.     pas_mixer_set (foo, levels[foo]);
  301.  
  302.   set_mode (P_M_MV508_LOUDNESS | P_M_MV508_ENHANCE_40);
  303. }
  304.  
  305. int
  306. pas_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
  307. {
  308.   TRACE (printk ("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
  309.  
  310.   if (((cmd >> 8) & 0xff) == 'M')
  311.     {
  312.       if (cmd & IOC_IN)
  313.     return IOCTL_OUT (arg, pas_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
  314.       else
  315.     {            /*
  316.                  * Read parameters
  317.                  */
  318.  
  319.       switch (cmd & 0xff)
  320.         {
  321.  
  322.         case SOUND_MIXER_RECSRC:
  323.           return IOCTL_OUT (arg, rec_devices);
  324.           break;
  325.  
  326.         case SOUND_MIXER_STEREODEVS:
  327.           return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE));
  328.           break;
  329.  
  330.         case SOUND_MIXER_DEVMASK:
  331.           return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES);
  332.           break;
  333.  
  334.         case SOUND_MIXER_RECMASK:
  335.           return IOCTL_OUT (arg, POSSIBLE_RECORDING_DEVICES & SUPPORTED_MIXER_DEVICES);
  336.           break;
  337.  
  338.         case SOUND_MIXER_CAPS:
  339.           return IOCTL_OUT (arg, 0);    /*
  340.                          * No special capabilities
  341.                          */
  342.           break;
  343.  
  344.         case SOUND_MIXER_MUTE:
  345.           return IOCTL_OUT (arg, 0);    /*
  346.                          * No mute yet
  347.                          */
  348.           break;
  349.  
  350.         case SOUND_MIXER_ENHANCE:
  351.           if (!(mode_control & P_M_MV508_ENHANCE_BITS))
  352.         return IOCTL_OUT (arg, 0);
  353.           return IOCTL_OUT (arg, ((mode_control & P_M_MV508_ENHANCE_BITS) + 1) * 20);
  354.           break;
  355.  
  356.         case SOUND_MIXER_LOUD:
  357.           if (mode_control & P_M_MV508_LOUDNESS)
  358.         return IOCTL_OUT (arg, 1);
  359.           return IOCTL_OUT (arg, 0);
  360.           break;
  361.  
  362.         default:
  363.           return IOCTL_OUT (arg, levels[cmd & 0xff]);
  364.         }
  365.     }
  366.     }
  367.   return RET_ERROR (EINVAL);
  368. }
  369.  
  370. static struct mixer_operations pas_mixer_operations =
  371. {
  372.   pas_mixer_ioctl
  373. };
  374.  
  375. int
  376. pas_init_mixer (void)
  377. {
  378.   pas_mixer_reset ();
  379.  
  380.   if (num_mixers < MAX_MIXER_DEV)
  381.     mixer_devs[num_mixers++] = &pas_mixer_operations;
  382.   return 1;
  383. }
  384.  
  385. #endif
  386.