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

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