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 / sb_mixer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-20  |  9.8 KB  |  454 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 1994
  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.  * Modified:
  30.  *    Hunyue Yau    Jan 6 1994
  31.  *    Added code to support the Sound Galaxy NX Pro mixer.
  32.  *
  33.  */
  34.  
  35. #include "sound_config.h"
  36.  
  37. #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_SBPRO)
  38. #define __SB_MIXER_C__
  39.  
  40. #include "sb.h"
  41. #include "sb_mixer.h"
  42. #undef SB_TEST_IRQ
  43.  
  44. extern int      sbc_base;
  45.  
  46. static int      mixer_initialized = 0;
  47.  
  48. static int      supported_rec_devices;
  49. static int      supported_devices;
  50. static int      recmask = 0;
  51. static int      mixer_model;
  52. static int      mixer_caps;
  53. static mixer_tab *iomap;
  54.  
  55. void
  56. sb_setmixer (unsigned int port, unsigned int value)
  57. {
  58.   unsigned long   flags;
  59.  
  60.   DISABLE_INTR (flags);
  61.   OUTB ((unsigned char) (port & 0xff), MIXER_ADDR);    /*
  62.                              * Select register
  63.                              */
  64.   tenmicrosec ();
  65.   OUTB ((unsigned char) (value & 0xff), MIXER_DATA);
  66.   tenmicrosec ();
  67.   RESTORE_INTR (flags);
  68. }
  69.  
  70. int
  71. sb_getmixer (unsigned int port)
  72. {
  73.   int             val;
  74.   unsigned long   flags;
  75.  
  76.   DISABLE_INTR (flags);
  77.   OUTB ((unsigned char) (port & 0xff), MIXER_ADDR);    /*
  78.                              * Select register
  79.                              */
  80.   tenmicrosec ();
  81.   val = INB (MIXER_DATA);
  82.   tenmicrosec ();
  83.   RESTORE_INTR (flags);
  84.  
  85.   return val;
  86. }
  87.  
  88. void
  89. sb_mixer_set_stereo (int mode)
  90. {
  91.   if (!mixer_initialized)
  92.     return;
  93.  
  94.   sb_setmixer (OUT_FILTER, ((sb_getmixer (OUT_FILTER) & ~STEREO_DAC)
  95.                 | (mode ? STEREO_DAC : MONO_DAC)));
  96. }
  97.  
  98. /*
  99.  * Returns:
  100.  *    0    No mixer detected.
  101.  *    1    Only a plain Sound Blaster Pro style mixer detected.
  102.  *    2    The Sound Galaxy NX Pro mixer detected.
  103.  */
  104. static int
  105. detect_mixer (void)
  106. {
  107. #ifdef __SGNXPRO__
  108.   int             oldbass, oldtreble;
  109.  
  110. #endif
  111.   int             retcode = 1;
  112.  
  113.   /*
  114.    * Detect the mixer by changing parameters of two volume channels. If the
  115.    * values read back match with the values written, the mixer is there (is
  116.    * it?)
  117.    */
  118.   sb_setmixer (FM_VOL, 0xff);
  119.   sb_setmixer (VOC_VOL, 0x33);
  120.  
  121.   if (sb_getmixer (FM_VOL) != 0xff)
  122.     return 0;            /*
  123.                  * No match
  124.                  */
  125.   if (sb_getmixer (VOC_VOL) != 0x33)
  126.     return 0;
  127.  
  128. #ifdef __SGNXPRO__
  129.   /* Attempt to detect the SG NX Pro by check for valid bass/treble
  130.  * registers.
  131.  */
  132.   oldbass = sb_getmixer (BASS_LVL);
  133.   oldtreble = sb_getmixer (TREBLE_LVL);
  134.  
  135.   sb_setmixer (BASS_LVL, 0xaa);
  136.   sb_setmixer (TREBLE_LVL, 0x55);
  137.  
  138.   if ((sb_getmixer (BASS_LVL) != 0xaa) ||
  139.       (sb_getmixer (TREBLE_LVL) != 0x55))
  140.     {
  141.       retcode = 1;        /* 1 == Only SB Pro detected */
  142.     }
  143.   else
  144.     retcode = 2;        /* 2 == SG NX Pro detected */
  145.   /* Restore register in either case since SG NX Pro has EEPROM with
  146.    * 'preferred' values stored.
  147.    */
  148.   sb_setmixer (BASS_LVL, oldbass);
  149.   sb_setmixer (TREBLE_LVL, oldtreble);
  150. #endif
  151.   return retcode;
  152. }
  153.  
  154. static void
  155. change_bits (unsigned char *regval, int dev, int chn, int newval)
  156. {
  157.   unsigned char   mask;
  158.   int             shift;
  159.  
  160.   mask = (1 << (*iomap)[dev][chn].nbits) - 1;
  161.   newval = (int) ((newval * mask) + 50) / 100;    /*
  162.                          * Scale it
  163.                          */
  164.  
  165.   shift = (*iomap)[dev][chn].bitoffs - (*iomap)[dev][LEFT_CHN].nbits + 1;
  166.  
  167.   *regval &= ~(mask << shift);    /*
  168.                  * Filter out the previous value
  169.                  */
  170.   *regval |= (newval & mask) << shift;    /*
  171.                      * Set the new value
  172.                      */
  173. }
  174.  
  175. static int
  176. sb_mixer_get (int dev)
  177. {
  178.   if (!((1 << dev) & supported_devices))
  179.     return RET_ERROR (EINVAL);
  180.  
  181.   return levels[dev];
  182. }
  183.  
  184. static int
  185. sb_mixer_set (int dev, int value)
  186. {
  187.   int             left = value & 0x000000ff;
  188.   int             right = (value & 0x0000ff00) >> 8;
  189.  
  190.   int             regoffs;
  191.   unsigned char   val;
  192.  
  193.   if (left > 100)
  194.     left = 100;
  195.   if (right > 100)
  196.     right = 100;
  197.  
  198.   if (dev > 31)
  199.     return RET_ERROR (EINVAL);
  200.  
  201.   if (!(supported_devices & (1 << dev)))    /*
  202.                          * Not supported
  203.                          */
  204.     return RET_ERROR (EINVAL);
  205.  
  206.   regoffs = (*iomap)[dev][LEFT_CHN].regno;
  207.  
  208.   if (regoffs == 0)
  209.     return RET_ERROR (EINVAL);
  210.  
  211.   val = sb_getmixer (regoffs);
  212.   change_bits (&val, dev, LEFT_CHN, left);
  213.  
  214.   levels[dev] = left | (left << 8);
  215.  
  216.   if ((*iomap)[dev][RIGHT_CHN].regno != regoffs)    /*
  217.                              * Change register
  218.                              */
  219.     {
  220.       sb_setmixer (regoffs, val);    /*
  221.                      * Save the old one
  222.                      */
  223.       regoffs = (*iomap)[dev][RIGHT_CHN].regno;
  224.  
  225.       if (regoffs == 0)
  226.     return left | (left << 8);    /*
  227.                      * Just left channel present
  228.                      */
  229.  
  230.       val = sb_getmixer (regoffs);    /*
  231.                      * Read the new one
  232.                      */
  233.     }
  234.  
  235.   change_bits (&val, dev, RIGHT_CHN, right);
  236.   sb_setmixer (regoffs, val);
  237.  
  238.   levels[dev] = left | (right << 8);
  239.   return left | (right << 8);
  240. }
  241.  
  242. static void
  243. set_recsrc (int src)
  244. {
  245.   sb_setmixer (RECORD_SRC, (sb_getmixer (RECORD_SRC) & ~7) | (src & 0x7));
  246. }
  247.  
  248. static int
  249. set_recmask (int mask)
  250. {
  251.   int             devmask, i;
  252.   unsigned char   regimageL, regimageR;
  253.  
  254.   devmask = mask & supported_rec_devices;
  255.  
  256.   switch (mixer_model)
  257.     {
  258.     case 3:
  259.  
  260.       if (devmask != SOUND_MASK_MIC &&
  261.       devmask != SOUND_MASK_LINE &&
  262.       devmask != SOUND_MASK_CD)
  263.     {            /*
  264.                  * More than one devices selected. Drop the *
  265.                  * previous selection
  266.                  */
  267.       devmask &= ~recmask;
  268.     }
  269.  
  270.       if (devmask != SOUND_MASK_MIC &&
  271.       devmask != SOUND_MASK_LINE &&
  272.       devmask != SOUND_MASK_CD)
  273.     {            /*
  274.                  * More than one devices selected. Default to
  275.                  * * mic
  276.                  */
  277.       devmask = SOUND_MASK_MIC;
  278.     }
  279.  
  280.  
  281.       if (devmask ^ recmask)    /*
  282.                  * Input source changed
  283.                  */
  284.     {
  285.       switch (devmask)
  286.         {
  287.  
  288.         case SOUND_MASK_MIC:
  289.           set_recsrc (SRC_MIC);
  290.           break;
  291.  
  292.         case SOUND_MASK_LINE:
  293.           set_recsrc (SRC_LINE);
  294.           break;
  295.  
  296.         case SOUND_MASK_CD:
  297.           set_recsrc (SRC_CD);
  298.           break;
  299.  
  300.         default:
  301.           set_recsrc (SRC_MIC);
  302.         }
  303.     }
  304.  
  305.       break;
  306.  
  307.     case 4:
  308.       if (!devmask)
  309.     devmask = SOUND_MASK_MIC;
  310.  
  311.       regimageL = regimageR = 0;
  312.       for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
  313.     if ((1 << i) & devmask)
  314.       {
  315.         regimageL |= sb16_recmasks_L[i];
  316.         regimageR |= sb16_recmasks_R[i];
  317.       }
  318.       sb_setmixer (SB16_IMASK_L, regimageL);
  319.       sb_setmixer (SB16_IMASK_R, regimageR);
  320.       break;
  321.     }
  322.  
  323.   recmask = devmask;
  324.   return recmask;
  325. }
  326.  
  327. static int
  328. sb_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
  329. {
  330.   if (((cmd >> 8) & 0xff) == 'M')
  331.     {
  332.       if (cmd & IOC_IN)
  333.     switch (cmd & 0xff)
  334.       {
  335.       case SOUND_MIXER_RECSRC:
  336.         return IOCTL_OUT (arg, set_recmask (IOCTL_IN (arg)));
  337.         break;
  338.  
  339.       default:
  340.         return IOCTL_OUT (arg, sb_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
  341.       }
  342.       else
  343.     switch (cmd & 0xff)    /*
  344.                  * Return parameters
  345.                  */
  346.       {
  347.  
  348.       case SOUND_MIXER_RECSRC:
  349.         return IOCTL_OUT (arg, recmask);
  350.         break;
  351.  
  352.       case SOUND_MIXER_DEVMASK:
  353.         return IOCTL_OUT (arg, supported_devices);
  354.         break;
  355.  
  356.       case SOUND_MIXER_STEREODEVS:
  357.         return IOCTL_OUT (arg, supported_devices &
  358.                   ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
  359.         break;
  360.  
  361.       case SOUND_MIXER_RECMASK:
  362.         return IOCTL_OUT (arg, supported_rec_devices);
  363.         break;
  364.  
  365.       case SOUND_MIXER_CAPS:
  366.         return IOCTL_OUT (arg, mixer_caps);
  367.         break;
  368.  
  369.       default:
  370.         return IOCTL_OUT (arg, sb_mixer_get (cmd & 0xff));
  371.       }
  372.     }
  373.   else
  374.     return RET_ERROR (EINVAL);
  375. }
  376.  
  377. static struct mixer_operations sb_mixer_operations =
  378. {
  379.   sb_mixer_ioctl
  380. };
  381.  
  382. static void
  383. sb_mixer_reset (void)
  384. {
  385.   int             i;
  386.  
  387.   for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
  388.     sb_mixer_set (i, levels[i]);
  389.   set_recmask (SOUND_MASK_MIC);
  390. }
  391.  
  392. /*
  393.  * Returns a code depending on whether a SG NX Pro was detected.
  394.  * 1 == Plain SB Pro
  395.  * 2 == SG NX Pro detected.
  396.  * 3 == SB16
  397.  *
  398.  * Used to update message.
  399.  */
  400. int
  401. sb_mixer_init (int major_model)
  402. {
  403.   int             mixer_type = 0;
  404.  
  405.   sb_setmixer (0x00, 0);    /* Reset mixer */
  406.  
  407.   if (!(mixer_type = detect_mixer ()))
  408.     return 0;            /* No mixer. Why? */
  409.  
  410.   mixer_initialized = 1;
  411.   mixer_model = major_model;
  412.  
  413.   switch (major_model)
  414.     {
  415.     case 3:
  416.       mixer_caps = SOUND_CAP_EXCL_INPUT;
  417. #ifdef __SGNXPRO__
  418.       if (mixer_type == 2)    /* A SGNXPRO was detected */
  419.     {
  420.       supported_devices = SGNXPRO_MIXER_DEVICES;
  421.       supported_rec_devices = SGNXPRO_RECORDING_DEVICES;
  422.       iomap = &sgnxpro_mix;
  423.     }
  424.       else
  425. #endif
  426.     {
  427.       supported_devices = SBPRO_MIXER_DEVICES;
  428.       supported_rec_devices = SBPRO_RECORDING_DEVICES;
  429.       iomap = &sbpro_mix;
  430.       mixer_type = 1;
  431.     }
  432.       break;
  433.  
  434.     case 4:
  435.       mixer_caps = 0;
  436.       supported_devices = SB16_MIXER_DEVICES;
  437.       supported_rec_devices = SB16_RECORDING_DEVICES;
  438.       iomap = &sb16_mix;
  439.       mixer_type = 3;
  440.       break;
  441.  
  442.     default:
  443.       printk ("SB Warning: Unsupported mixer type\n");
  444.       return 0;
  445.     }
  446.  
  447.   if (num_mixers < MAX_MIXER_DEV)
  448.     mixer_devs[num_mixers++] = &sb_mixer_operations;
  449.   sb_mixer_reset ();
  450.   return mixer_type;
  451. }
  452.  
  453. #endif
  454.