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_card.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-14  |  9.1 KB  |  360 lines

  1. #define _PAS2_CARD_C_
  2. #define SND_SA_INTERRUPT
  3. /*
  4.  * sound/pas2_card.c
  5.  * 
  6.  * Detection routine 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. #define DEFINE_TRANSLATIONS
  37. #include "pas.h"
  38.  
  39. /*
  40.  * The Address Translation code is used to convert I/O register addresses to
  41.  * be relative to the given base -register
  42.  */
  43.  
  44. int             translat_code;
  45. static int      pas_intr_mask = 0;
  46. static int      pas_irq = 0;
  47.  
  48. static char     pas_model;
  49. static char    *pas_model_names[] =
  50. {"", "Pro AudioSpectrum+", "CDPC", "Pro AudioSpectrum 16", "Pro AudioSpectrum 16D"};
  51.  
  52. /* pas_read() and pas_write() are equivalents of INB() and OUTB() */
  53. /* These routines perform the I/O address translation required */
  54. /* to support other than the default base address */
  55.  
  56. unsigned char
  57. pas_read (int ioaddr)
  58. {
  59.   return INB (ioaddr ^ translat_code);
  60. }
  61.  
  62. void
  63. pas_write (unsigned char data, int ioaddr)
  64. {
  65.   OUTB (data, ioaddr ^ translat_code);
  66. }
  67.  
  68. void
  69. pas2_msg (char *foo)
  70. {
  71.   printk ("    PAS2: %s.\n", foo);
  72. }
  73.  
  74. /******************* Begin of the Interrupt Handler ********************/
  75.  
  76. void
  77. pasintr (int unused)
  78. {
  79.   int             status;
  80.  
  81.   status = pas_read (INTERRUPT_STATUS);
  82.   pas_write (status, INTERRUPT_STATUS);    /* Clear interrupt */
  83.  
  84.   if (status & I_S_PCM_SAMPLE_BUFFER_IRQ)
  85.     {
  86. #ifndef EXCLUDE_AUDIO
  87.       pas_pcm_interrupt (status, 1);
  88. #endif
  89.       status &= ~I_S_PCM_SAMPLE_BUFFER_IRQ;
  90.     }
  91.   if (status & I_S_MIDI_IRQ)
  92.     {
  93. #ifndef EXCLUDE_MIDI
  94. #ifdef EXCLUDE_PRO_MIDI
  95.       pas_midi_interrupt ();
  96. #endif
  97. #endif
  98.       status &= ~I_S_MIDI_IRQ;
  99.     }
  100.  
  101. }
  102.  
  103. int
  104. pas_set_intr (int mask)
  105. {
  106.   int             err;
  107.  
  108.   if (!mask)
  109.     return 0;
  110.  
  111.   if (!pas_intr_mask)
  112.     {
  113.       if ((err = snd_set_irq_handler (pas_irq, pasintr)) < 0)
  114.     return err;
  115.     }
  116.   pas_intr_mask |= mask;
  117.  
  118.   pas_write (pas_intr_mask, INTERRUPT_MASK);
  119.   return 0;
  120. }
  121.  
  122. int
  123. pas_remove_intr (int mask)
  124. {
  125.   if (!mask)
  126.     return 0;
  127.  
  128.   pas_intr_mask &= ~mask;
  129.   pas_write (pas_intr_mask, INTERRUPT_MASK);
  130.  
  131.   if (!pas_intr_mask)
  132.     {
  133.       snd_release_irq (pas_irq);
  134.     }
  135.   return 0;
  136. }
  137.  
  138. /******************* End of the Interrupt handler **********************/
  139.  
  140. /******************* Begin of the Initialization Code ******************/
  141.  
  142. int
  143. config_pas_hw (struct address_info *hw_config)
  144. {
  145.   char            ok = 1;
  146.  
  147.   pas_irq = hw_config->irq;
  148.  
  149.   pas_write (0x00, INTERRUPT_MASK);
  150.  
  151.   pas_write (0x36, SAMPLE_COUNTER_CONTROL);    /* Local timer control
  152.                          * register */
  153.  
  154.   pas_write (0x36, SAMPLE_RATE_TIMER);    /* Sample rate timer (16 bit) */
  155.   pas_write (0, SAMPLE_RATE_TIMER);
  156.  
  157.   pas_write (0x74, SAMPLE_COUNTER_CONTROL);    /* Local timer control
  158.                          * register */
  159.  
  160.   pas_write (0x74, SAMPLE_BUFFER_COUNTER);    /* Sample count register (16
  161.                          * bit) */
  162.   pas_write (0, SAMPLE_BUFFER_COUNTER);
  163.  
  164.   pas_write (F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER | F_F_MIXER_UNMUTE | 1, FILTER_FREQUENCY);
  165.   pas_write (P_C_PCM_DMA_ENABLE | P_C_PCM_MONO | P_C_PCM_DAC_MODE | P_C_MIXER_CROSS_L_TO_L | P_C_MIXER_CROSS_R_TO_R, PCM_CONTROL);
  166.   pas_write (S_M_PCM_RESET | S_M_FM_RESET | S_M_SB_RESET | S_M_MIXER_RESET /* | S_M_OPL3_DUAL_MONO */ , SERIAL_MIXER);
  167.  
  168.   pas_write (I_C_1_BOOT_RESET_ENABLE, IO_CONFIGURATION_1);
  169.  
  170.   if (pas_irq < 0 || pas_irq > 15)
  171.     {
  172.       printk ("PAS2: Invalid IRQ %d", pas_irq);
  173.       ok = 0;
  174.     }
  175.   else
  176.     {
  177.       pas_write (I_C_3_PCM_IRQ_translate[pas_irq], IO_CONFIGURATION_3);
  178.       if (!I_C_3_PCM_IRQ_translate[pas_irq])
  179.     {
  180.       printk ("PAS2: Invalid IRQ %d", pas_irq);
  181.       ok = 0;
  182.     }
  183.     }
  184.  
  185.   if (hw_config->dma < 0 || hw_config->dma > 7)
  186.     {
  187.       printk ("PAS2: Invalid DMA selection %d", hw_config->dma);
  188.       ok = 0;
  189.     }
  190.   else
  191.     {
  192.       pas_write (I_C_2_PCM_DMA_translate[hw_config->dma], IO_CONFIGURATION_2);
  193.       if (!I_C_2_PCM_DMA_translate[hw_config->dma])
  194.     {
  195.       printk ("PAS2: Invalid DMA selection %d", hw_config->dma);
  196.       ok = 0;
  197.     }
  198.     }
  199.   
  200. /*
  201.  * This fixes the timing problems of the PAS due to the Symphony chipset
  202.  * as per Media Vision.  Only define this if your PAS doesn't work correctly.
  203.  */
  204. #ifdef SYMPHONY_PAS
  205.     OUTB(0x05,0xa8);
  206.     OUTB(0x60,0xa9);
  207. #endif
  208.  
  209. #ifdef BROKEN_BUS_CLOCK
  210.   pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND | S_C_1_FM_EMULATE_CLOCK, SYSTEM_CONFIGURATION_1);
  211. #else
  212.   /* pas_write(S_C_1_PCS_ENABLE, SYSTEM_CONFIGURATION_1);     */
  213.   pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND, SYSTEM_CONFIGURATION_1);
  214. #endif
  215.   pas_write (0x18, SYSTEM_CONFIGURATION_3);    /* ??? */
  216.  
  217.   pas_write (F_F_MIXER_UNMUTE | 0x01, FILTER_FREQUENCY);    /* Sets mute off and
  218.                                  * selects filter rate
  219.                                  * of 17.897 kHz */
  220.  
  221.   if (pas_model == PAS_16 || pas_model == PAS_16D)
  222.     pas_write (8, PRESCALE_DIVIDER);
  223.   else
  224.     pas_write (0, PRESCALE_DIVIDER);
  225.  
  226.   pas_write (P_M_MV508_ADDRESS | 5, PARALLEL_MIXER);
  227.   pas_write (5, PARALLEL_MIXER);
  228.  
  229. #if !defined(EXCLUDE_SB_EMULATION) || !defined(EXCLUDE_SB)
  230.  
  231.     {
  232.     struct address_info *sb_config;
  233.  
  234.     if ((sb_config=sound_getconf(SNDCARD_SB)))
  235.         {
  236.         unsigned char irq_dma;
  237.  
  238.   /* Turn on Sound Blaster compatibility */
  239.   /* bit 1 = SB emulation */
  240.   /* bit 0 = MPU401 emulation (CDPC only :-( ) */
  241.   pas_write (0x02, COMPATIBILITY_ENABLE);
  242.  
  243.   /* "Emulation address"     */
  244.             pas_write ((sb_config->io_base >> 4) & 0x0f, EMULATION_ADDRESS);
  245.  
  246.         if (!E_C_SB_DMA_translate[sb_config->dma]) 
  247.                printk("\n\nPAS16 Warning: Invalid SB DMA %d\n\n",
  248.             sb_config->dma);
  249.  
  250.         if (!E_C_SB_IRQ_translate[sb_config->irq]) 
  251.                printk("\n\nPAS16 Warning: Invalid SB IRQ %d\n\n",
  252.             sb_config->irq);
  253.  
  254.         irq_dma = E_C_SB_DMA_translate[sb_config->dma] | 
  255.               E_C_SB_IRQ_translate[sb_config->irq];
  256.  
  257.         pas_write(irq_dma, EMULATION_CONFIGURATION);
  258.         }
  259.    }
  260. #endif
  261.  
  262.   if (!ok)
  263.     pas2_msg ("Driver not enabled");
  264.  
  265.   return ok;
  266. }
  267.  
  268. int
  269. detect_pas_hw (struct address_info *hw_config)
  270. {
  271.   unsigned char   board_id, foo;
  272.  
  273.   /*
  274.    * WARNING: Setting an option like W:1 or so that disables warm boot reset
  275.    * of the card will screw up this detect code something fierce. Adding code
  276.    * to handle this means possibly interfering with other cards on the bus if
  277.    * you have something on base port 0x388. SO be forewarned.
  278.    */
  279.  
  280.   OUTB (0xBC, MASTER_DECODE);    /* Talk to first board */
  281.   OUTB (hw_config->io_base >> 2, MASTER_DECODE);    /* Set base address */
  282.   translat_code = PAS_DEFAULT_BASE ^ hw_config->io_base;
  283.   pas_write (1, WAIT_STATE);    /* One wait-state */
  284.  
  285.   board_id = pas_read (INTERRUPT_MASK);
  286.  
  287.   if (board_id == 0xff)
  288.     return 0;
  289.  
  290.   /*
  291.    * We probably have a PAS-series board, now check for a PAS2-series board
  292.    * by trying to change the board revision bits. PAS2-series hardware won't
  293.    * let you do this - the bits are read-only.
  294.    */
  295.  
  296.   foo = board_id ^ 0xe0;
  297.  
  298.   pas_write (foo, INTERRUPT_MASK);
  299.   foo = INB (INTERRUPT_MASK);
  300.   pas_write (board_id, INTERRUPT_MASK);
  301.  
  302.   if (board_id != foo)        /* Not a PAS2 */
  303.     return 0;
  304.  
  305.   pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f];
  306.  
  307.   return pas_model;
  308. }
  309.  
  310. long
  311. attach_pas_card (long mem_start, struct address_info *hw_config)
  312. {
  313.   pas_irq = hw_config->irq;
  314.  
  315.   if (detect_pas_hw (hw_config))
  316.     {
  317.  
  318.       if ((pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f]))
  319.     {
  320.       printk (" <%s rev %d>", pas_model_names[(int) pas_model], pas_read (BOARD_REV_ID));
  321.     }
  322.  
  323.       if (config_pas_hw (hw_config))
  324.     {
  325.  
  326. #ifndef EXCLUDE_AUDIO
  327.       mem_start = pas_pcm_init (mem_start, hw_config);
  328. #endif
  329.  
  330. # if !defined(EXCLUDE_SB_EMULATION) && !defined(EXCLUDE_SB)
  331.  
  332.       sb_dsp_disable_midi ();    /* The SB emulation don't support
  333.                      * midi */
  334. # endif
  335.  
  336. #ifndef EXCLUDE_YM3812
  337.       enable_opl3_mode (0x388, 0x38a, 0);
  338. #endif
  339.  
  340. #ifndef EXCLUDE_MIDI
  341. #ifdef EXCLUDE_PRO_MIDI
  342.       mem_start = pas_midi_init (mem_start);
  343. #endif
  344. #endif
  345.  
  346.       pas_init_mixer ();
  347.     }
  348.     }
  349.  
  350.   return mem_start;
  351. }
  352.  
  353. int
  354. probe_pas (struct address_info *hw_config)
  355. {
  356.   return detect_pas_hw (hw_config);
  357. }
  358.  
  359. #endif
  360.