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

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