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

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