root/drivers/sound/pas2_card.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pas_read
  2. pas_write
  3. pas2_msg
  4. pasintr
  5. pas_set_intr
  6. pas_remove_intr
  7. config_pas_hw
  8. detect_pas_hw
  9. attach_pas_card
  10. probe_pas

   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)
     /* [previous][next][first][last][top][bottom][index][help] */
  58 {
  59   return INB (ioaddr ^ translat_code);
  60 }
  61 
  62 void
  63 pas_write (unsigned char data, int ioaddr)
     /* [previous][next][first][last][top][bottom][index][help] */
  64 {
  65   OUTB (data, ioaddr ^ translat_code);
  66 }
  67 
  68 void
  69 pas2_msg (char *foo)
     /* [previous][next][first][last][top][bottom][index][help] */
  70 {
  71   printk ("    PAS2: %s.\n", foo);
  72 }
  73 
  74 /******************* Begin of the Interrupt Handler ********************/
  75 
  76 void
  77 pasintr (int unused)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 355 {
 356   return detect_pas_hw (hw_config);
 357 }
 358 
 359 #endif

/* [previous][next][first][last][top][bottom][index][help] */