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_card.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-17  |  9.5 KB  |  408 lines

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