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 / pas2_mixer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-09  |  14.3 KB  |  501 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)        /* (what) */
  39.  
  40. extern int      translat_code;
  41.  
  42. static int      rec_devices = (SOUND_MASK_MIC);    /* Default recording source */
  43. static int      mode_control = 0;
  44.  
  45. #define POSSIBLE_RECORDING_DEVICES    (SOUND_MASK_SYNTH | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
  46.                      SOUND_MASK_CD | SOUND_MASK_ALTPCM)
  47.  
  48. #define SUPPORTED_MIXER_DEVICES        (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
  49.                      SOUND_MASK_CD | SOUND_MASK_ALTPCM | SOUND_MASK_IMIX | \
  50.                      SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV | \
  51.                      SOUND_MASK_MUTE | SOUND_MASK_ENHANCE | SOUND_MASK_LOUD)
  52.  
  53. static unsigned short levels[SOUND_MIXER_NRDEVICES] =
  54. {
  55.   0x3232,            /* Master Volume */
  56.   0x3232,            /* Bass */
  57.   0x3232,            /* Treble */
  58.   0x5050,            /* FM */
  59.   0x4b4b,            /* PCM */
  60.   0x3232,            /* PC Speaker */
  61.   0x4b4b,            /* Ext Line */
  62.   0x4b4b,            /* Mic */
  63.   0x4b4b,            /* CD */
  64.   0x6464,            /* Recording monitor */
  65.   0x4b4b,            /* SB PCM */
  66.   0x6464};            /* Recording level */
  67.  
  68. static int
  69. mixer_output (int right_vol, int left_vol, int div, int bits,
  70.           int mixer /* Input or output mixer */ )
  71. {
  72.   int             left = left_vol * div / 100;
  73.   int             right = right_vol * div / 100;
  74.  
  75.   /*
  76.    * The Revision D cards have a problem with their MVA508 interface. The
  77.    * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and
  78.    * MSBs out of the output byte and to do a 16-bit out to the mixer port -
  79.    * 1. We don't need to do this because the call to pas_write more than
  80.    * compensates for the timing problems.
  81.    */
  82.  
  83.   if (bits & P_M_MV508_MIXER)
  84.     {                /* Select input or output mixer */
  85.       left |= mixer;
  86.       right |= mixer;
  87.     }
  88.  
  89.   if (bits == P_M_MV508_BASS || bits == P_M_MV508_TREBLE)
  90.     {                /* Bass and trebble are mono devices     */
  91.       pas_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER);
  92.       pas_write (left, PARALLEL_MIXER);
  93.       right_vol = left_vol;
  94.     }
  95.   else
  96.     {
  97.       pas_write (P_M_MV508_ADDRESS | P_M_MV508_LEFT | bits, PARALLEL_MIXER);
  98.       pas_write (left, PARALLEL_MIXER);
  99.       pas_write (P_M_MV508_ADDRESS | P_M_MV508_RIGHT | bits, PARALLEL_MIXER);
  100.       pas_write (right, PARALLEL_MIXER);
  101.     }
  102.  
  103.   return (left_vol | (right_vol << 8));
  104. }
  105.  
  106. void
  107. set_mode (int new_mode)
  108. {
  109.   pas_write (P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER);
  110.   pas_write (new_mode, PARALLEL_MIXER);
  111.  
  112.   mode_control = new_mode;
  113. }
  114.  
  115. static int
  116. pas_mixer_set (int whichDev, unsigned int level)
  117. {
  118.   int             left, right, devmask, changed, i, mixer = 0;
  119.  
  120.   TRACE (printk ("static int pas_mixer_set(int whichDev = %d, unsigned int level = %X)\n", whichDev, level));
  121.  
  122.   left = level & 0x7f;
  123.   right = (level & 0x7f00) >> 8;
  124.  
  125.   if (whichDev < SOUND_MIXER_NRDEVICES)
  126.     if ((1 << whichDev) & rec_devices)
  127.       mixer = P_M_MV508_INPUTMIX;
  128.     else
  129.       mixer = P_M_MV508_OUTPUTMIX;
  130.  
  131.   switch (whichDev)
  132.     {
  133.     case SOUND_MIXER_VOLUME:    /* Master volume (0-63) */
  134.       levels[whichDev] = mixer_output (right, left, 63, P_M_MV508_MASTER_A, 0);
  135.       break;
  136.  
  137.       /*
  138.        * Note! Bass and Treble are mono devices. Will use just the left
  139.        * channel.
  140.        */
  141.     case SOUND_MIXER_BASS:    /* Bass (0-12) */
  142.       levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_BASS, 0);
  143.       break;
  144.     case SOUND_MIXER_TREBLE:    /* Treble (0-12) */
  145.       levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_TREBLE, 0);
  146.       break;
  147.  
  148.     case SOUND_MIXER_SYNTH:    /* Internal synthesizer (0-31) */
  149.       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_FM, mixer);
  150.       break;
  151.     case SOUND_MIXER_PCM:    /* PAS PCM (0-31) */
  152.       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_PCM, mixer);
  153.       break;
  154.     case SOUND_MIXER_ALTPCM:    /* SB PCM (0-31) */
  155.       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SB, mixer);
  156.       break;
  157.     case SOUND_MIXER_SPEAKER:    /* PC speaker (0-31) */
  158.       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SPEAKER, mixer);
  159.       break;
  160.     case SOUND_MIXER_LINE:    /* External line (0-31) */
  161.       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_LINE, mixer);
  162.       break;
  163.     case SOUND_MIXER_CD:    /* CD (0-31) */
  164.       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_CDROM, mixer);
  165.       break;
  166.     case SOUND_MIXER_MIC:    /* External microphone (0-31) */
  167.       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_MIC, mixer);
  168.       break;
  169.     case SOUND_MIXER_IMIX:    /* Recording monitor (0-31) (Only available
  170.                  * on the Output Mixer) */
  171.       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_IMIXER,
  172.                        P_M_MV508_OUTPUTMIX);
  173.       break;
  174.     case SOUND_MIXER_RECLEV:    /* Recording level (0-15) */
  175.       levels[whichDev] = mixer_output (right, left, 15, P_M_MV508_MASTER_B, 0);
  176.       break;
  177.  
  178.     case SOUND_MIXER_MUTE:
  179.       return 0;
  180.       break;
  181.  
  182.     case SOUND_MIXER_ENHANCE:
  183.       i = 0;
  184.       level &= 0x7f;
  185.       if (level)
  186.     i = (level / 20) - 1;
  187.  
  188.       mode_control &= ~P_M_MV508_ENHANCE_BITS;
  189.       mode_control |= P_M_MV508_ENHANCE_BITS;
  190.       set_mode (mode_control);
  191.  
  192.       if (i)
  193.     i = (i + 1) * 20;
  194.       return i;
  195.       break;
  196.  
  197.     case SOUND_MIXER_LOUD:
  198.       mode_control &= ~P_M_MV508_LOUDNESS;
  199.       if (level)
  200.     mode_control |= P_M_MV508_LOUDNESS;
  201.       set_mode (mode_control);
  202.       return !!level;        /* 0 or 1 */
  203.       break;
  204.  
  205.     case SOUND_MIXER_RECSRC:
  206.       devmask = level & POSSIBLE_RECORDING_DEVICES;
  207.  
  208.       changed = devmask ^ rec_devices;
  209.       rec_devices = devmask;
  210.  
  211.       for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
  212.     if (changed & (1 << i))
  213.       {
  214.         pas_mixer_set (i, levels[i]);
  215.       }
  216.       return rec_devices;
  217.       break;
  218.  
  219.     default:
  220.       return RET_ERROR (EINVAL);
  221.     }
  222.  
  223.   return (levels[whichDev]);
  224. }
  225.  
  226. /*****/
  227.  
  228. static int
  229. mixer_set_levels (struct sb_mixer_levels *user_l)
  230. {
  231. #define cmix(v) ((((v.r*100+7)/15)<<8)| ((v.l*100+7)/15))
  232.  
  233.   struct sb_mixer_levels l;
  234.  
  235.   IOCTL_FROM_USER ((char *) &l, (char *) user_l, 0, sizeof (l));
  236.  
  237.   if (l.master.l & ~0xF || l.master.r & ~0xF
  238.       || l.line.l & ~0xF || l.line.r & ~0xF
  239.       || l.voc.l & ~0xF || l.voc.r & ~0xF
  240.       || l.fm.l & ~0xF || l.fm.r & ~0xF
  241.       || l.cd.l & ~0xF || l.cd.r & ~0xF
  242.       || l.mic & ~0x7)
  243.     return (RET_ERROR (EINVAL));
  244.  
  245.   pas_mixer_set (SOUND_MIXER_VOLUME, cmix (l.master));
  246.   pas_mixer_set (SOUND_MIXER_LINE, cmix (l.line));
  247.   pas_mixer_set (SOUND_MIXER_PCM, cmix (l.voc));
  248.   pas_mixer_set (SOUND_MIXER_ALTPCM, cmix (l.voc));
  249.   pas_mixer_set (SOUND_MIXER_SYNTH, cmix (l.fm));
  250.   pas_mixer_set (SOUND_MIXER_CD, cmix (l.cd));
  251.   pas_mixer_set (SOUND_MIXER_MIC, ((l.mic * 100 + 3) / 7) | (((l.mic * 100 + 3) / 7) << 8));
  252.   return (0);
  253. }
  254.  
  255. /*
  256.  * This sets aspects of the Mixer that are not volume levels. (Recording
  257.  * source, filter level, I/O filtering, and stereo.)
  258.  */
  259. static int
  260. mixer_set_params (struct sb_mixer_params *user_p)
  261. {
  262.   struct sb_mixer_params p;
  263.   S_BYTE          val;
  264.   int             src;
  265.   unsigned long   flags;
  266.  
  267.   IOCTL_FROM_USER ((char *) &p, (char *) user_p, 0, sizeof (p));
  268.  
  269.   if (p.record_source != SRC_MIC
  270.       && p.record_source != SRC_CD
  271.       && p.record_source != SRC_LINE)
  272.     return (RET_ERROR (EINVAL));
  273.  
  274.   /*
  275.    * I'm not sure if this is The Right Thing.  Should stereo be entirely
  276.    * under control of DSP?  I like being able to toggle it while a sound is
  277.    * playing, so I do this... because I can.
  278.    */
  279.  
  280.   DISABLE_INTR (flags);
  281.  
  282.   val = (pas_read (PCM_CONTROL) & ~P_C_MIXER_CROSS_FIELD) | P_C_MIXER_CROSS_R_TO_R | P_C_MIXER_CROSS_L_TO_L;
  283.   if (!p.dsp_stereo)
  284.     val |= (P_C_MIXER_CROSS_R_TO_L | P_C_MIXER_CROSS_L_TO_R);    /* Mono */
  285.   pas_write (val, PCM_CONTROL);
  286.  
  287.   RESTORE_INTR (flags);
  288.  
  289.   switch (p.record_source)
  290.     {
  291.     case SRC_CD:
  292.       src = SOUND_MASK_CD;
  293.       break;
  294.  
  295.     case SRC_LINE:
  296.       src = SOUND_MASK_LINE;
  297.       break;
  298.  
  299.     default:
  300.       src = SOUND_MASK_MIC;
  301.       break;
  302.     }
  303.  
  304.   pas_mixer_set (SOUND_MIXER_RECSRC, src);
  305.  
  306.   /*
  307.    * setmixer (OUT_FILTER, ((dsp_stereo ? STEREO_DAC : MONO_DAC) |
  308.    * (p.filter_output ? FILT_ON : FILT_OFF)));
  309.    */
  310.   return (0);
  311. }
  312.  
  313. static int
  314. getmixer (int dev, int chn)
  315. {
  316.   if (chn == P_M_MV508_RIGHT)
  317.     {
  318.       return (levels[dev] >> 8) & 0x7f;
  319.     }
  320.   else
  321.     {
  322.       return levels[dev] & 0x7f;
  323.     }
  324. }
  325.  
  326. /* Read the current mixer level settings into the user's struct. */
  327. static int
  328. mixer_get_levels (struct sb_mixer_levels *user_l)
  329. {
  330.  
  331.   struct sb_mixer_levels l;
  332.  
  333.   l.master.r = ((((levels[SOUND_MIXER_VOLUME] >> 8) & 0x7f) * 15) + 50) / 100;    /* Master */
  334.   l.master.l = (((levels[SOUND_MIXER_VOLUME] & 0x7f) * 15) + 50) / 100;    /* Master */
  335.  
  336.   l.line.r = ((getmixer (SOUND_MIXER_LINE, P_M_MV508_RIGHT) * 15) + 50) / 100;    /* Line */
  337.   l.line.l = ((getmixer (SOUND_MIXER_LINE, P_M_MV508_LEFT) * 15) + 50) / 100;
  338.  
  339.   l.voc.r = ((getmixer (SOUND_MIXER_PCM, P_M_MV508_RIGHT) * 15) + 50) / 100;    /* DAC */
  340.   l.voc.l = ((getmixer (SOUND_MIXER_PCM, P_M_MV508_LEFT) * 15) + 50) / 100;
  341.  
  342.   l.fm.r = ((getmixer (SOUND_MIXER_SYNTH, P_M_MV508_RIGHT) * 15) + 50) / 100;    /* FM */
  343.   l.fm.l = ((getmixer (SOUND_MIXER_SYNTH, P_M_MV508_LEFT) * 15) + 50) / 100;
  344.  
  345.   l.cd.r = ((getmixer (SOUND_MIXER_CD, P_M_MV508_RIGHT) * 15) + 50) / 100;    /* CD */
  346.   l.cd.l = ((getmixer (SOUND_MIXER_CD, P_M_MV508_LEFT) * 15) + 50) / 100;
  347.  
  348.   l.mic = ((getmixer (SOUND_MIXER_MIC, P_M_MV508_LEFT) * 7) + 50) / 100;    /* Microphone */
  349.  
  350.   IOCTL_TO_USER ((char *) user_l, 0, (char *) &l, sizeof (l));
  351.   return (0);
  352. }
  353.  
  354. /* Read the current mixer parameters into the user's struct. */
  355. static int
  356. mixer_get_params (struct sb_mixer_params *user_params)
  357. {
  358.   S_BYTE          val;
  359.   struct sb_mixer_params params;
  360.  
  361.   switch (rec_devices)
  362.     {
  363.     case SOUND_MASK_CD:
  364.       params.record_source = SRC_CD;
  365.       break;
  366.  
  367.     case SOUND_MASK_LINE:
  368.       params.record_source = SRC_LINE;
  369.       break;
  370.  
  371.     case SOUND_MASK_MIC:
  372.       params.record_source = SRC_MIC;
  373.       break;
  374.  
  375.     default:
  376.       params.record_source = SRC_MIC;
  377.       pas_mixer_set (SOUND_MIXER_RECSRC, SOUND_MASK_MIC);    /* Adjust */
  378.     }
  379.  
  380.   params.hifreq_filter = OFF;
  381.   params.filter_input = OFF;
  382.   params.filter_output = OFF;
  383.  
  384.   val = INB (PCM_CONTROL);
  385.   params.dsp_stereo = ((val & P_C_MIXER_CROSS_FIELD) == (P_C_MIXER_CROSS_L_TO_L | P_C_MIXER_CROSS_R_TO_R));
  386.  
  387.   IOCTL_TO_USER ((char *) user_params, 0, (char *) ¶ms, sizeof (params));
  388.   return (0);
  389. }
  390.  
  391. /*****/
  392.  
  393. static void
  394. pas_mixer_reset (void)
  395. {
  396.   int             foo;
  397.  
  398.   TRACE (printk ("pas2_mixer.c: void pas_mixer_reset(void)\n"));
  399.  
  400.   for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++)
  401.     pas_mixer_set (foo, levels[foo]);
  402.  
  403.   set_mode (P_M_MV508_LOUDNESS | P_M_MV508_ENHANCE_40);
  404. }
  405.  
  406. int
  407. pas_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
  408. {
  409.   TRACE (printk ("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
  410.  
  411.   if (((cmd >> 8) & 0xff) == 'M')
  412.     {
  413.       if (cmd & IOC_IN)
  414.     return IOCTL_OUT (arg, pas_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
  415.       else
  416.     {            /* Read parameters */
  417.  
  418.       switch (cmd & 0xff)
  419.         {
  420.  
  421.         case SOUND_MIXER_RECSRC:
  422.           return IOCTL_OUT (arg, rec_devices);
  423.           break;
  424.  
  425.         case SOUND_MIXER_STEREODEVS:
  426.           return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE));
  427.           break;
  428.  
  429.         case SOUND_MIXER_DEVMASK:
  430.           return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES);
  431.           break;
  432.  
  433.         case SOUND_MIXER_RECMASK:
  434.           return IOCTL_OUT (arg, POSSIBLE_RECORDING_DEVICES & SUPPORTED_MIXER_DEVICES);
  435.           break;
  436.  
  437.         case SOUND_MIXER_CAPS:
  438.           return IOCTL_OUT (arg, 0);    /* No special capabilities */
  439.           break;
  440.  
  441.         case SOUND_MIXER_MUTE:
  442.           return IOCTL_OUT (arg, 0);    /* No mute yet */
  443.           break;
  444.  
  445.         case SOUND_MIXER_ENHANCE:
  446.           if (!(mode_control & P_M_MV508_ENHANCE_BITS))
  447.         return IOCTL_OUT (arg, 0);
  448.           return IOCTL_OUT (arg, ((mode_control & P_M_MV508_ENHANCE_BITS) + 1) * 20);
  449.           break;
  450.  
  451.         case SOUND_MIXER_LOUD:
  452.           if (mode_control & P_M_MV508_LOUDNESS)
  453.         return IOCTL_OUT (arg, 1);
  454.           return IOCTL_OUT (arg, 0);
  455.           break;
  456.  
  457.         default:
  458.           return IOCTL_OUT (arg, levels[cmd & 0xff]);
  459.         }
  460.     }
  461.     }
  462.   else
  463.     {
  464.       switch (cmd)
  465.     {
  466.     case MIXER_IOCTL_SET_LEVELS:
  467.       mixer_set_levels ((struct sb_mixer_levels *) arg);
  468.       return mixer_get_levels ((struct sb_mixer_levels *) arg);
  469.     case MIXER_IOCTL_SET_PARAMS:
  470.       mixer_set_params ((struct sb_mixer_params *) arg);
  471.       return mixer_get_params ((struct sb_mixer_params *) arg);
  472.     case MIXER_IOCTL_READ_LEVELS:
  473.       return mixer_get_levels ((struct sb_mixer_levels *) arg);
  474.     case MIXER_IOCTL_READ_PARAMS:
  475.       return mixer_get_params ((struct sb_mixer_params *) arg);
  476.     case MIXER_IOCTL_RESET:
  477.       pas_mixer_reset ();
  478.       return (0);
  479.     default:
  480.       return RET_ERROR (EINVAL);
  481.     }
  482.     }
  483.   return RET_ERROR (EINVAL);
  484. }
  485.  
  486. static struct mixer_operations pas_mixer_operations =
  487. {
  488.   pas_mixer_ioctl
  489. };
  490.  
  491. int
  492. pas_init_mixer (void)
  493. {
  494.   pas_mixer_reset ();
  495.  
  496.   mixer_devs[num_mixers++] = &pas_mixer_operations;
  497.   return 1;
  498. }
  499.  
  500. #endif
  501.