root/drivers/sound/cs4232.c

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

DEFINITIONS

This source file includes following definitions.
  1. CS_OUT
  2. probe_cs4232_mpu
  3. attach_cs4232_mpu
  4. probe_cs4232
  5. attach_cs4232
  6. unload_cs4232
  7. unload_cs4232_mpu

   1 /*
   2  * sound/cs4232.c
   3  *
   4  * The low level driver for Crystal CS4232 based cards. The CS4232 is
   5  * a PnP compatible chip which contains a CS4231A codec, SB emulation,
   6  * a MPU401 compatible MIDI port, joystick and synthesizer and IDE CD-ROM 
   7  * interfaces. This is just a temporary driver until full PnP support
   8  * gets implemented. Just the WSS codec, FM synth and the MIDI ports are
   9  * supported. Other interfaces are left uninitialized.
  10  */
  11 /*
  12  * Copyright by Hannu Savolainen 1993-1996
  13  *
  14  * Redistribution and use in source and binary forms, with or without
  15  * modification, are permitted provided that the following conditions are
  16  * met: 1. Redistributions of source code must retain the above copyright
  17  * notice, this list of conditions and the following disclaimer. 2.
  18  * Redistributions in binary form must reproduce the above copyright notice,
  19  * this list of conditions and the following disclaimer in the documentation
  20  * and/or other materials provided with the distribution.
  21  *
  22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
  23  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  24  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  25  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
  26  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32  * SUCH DAMAGE.
  33  */
  34 #include <linux/config.h>
  35 
  36 
  37 #include "sound_config.h"
  38 
  39 #if defined(CONFIG_CS4232)
  40 
  41 #define KEY_PORT        0x279   /* Same as LPT1 status port */
  42 #define CSN_NUM         0x99    /* Just a random number */
  43 
  44 static int     *osp;
  45 
  46 static void 
  47 CS_OUT (unsigned char a)
     /* [previous][next][first][last][top][bottom][index][help] */
  48 {
  49   outb (a, KEY_PORT);
  50 }
  51 #define CS_OUT2(a, b)           {CS_OUT(a);CS_OUT(b);}
  52 #define CS_OUT3(a, b, c)        {CS_OUT(a);CS_OUT(b);CS_OUT(c);}
  53 
  54 static int      mpu_base = 0, mpu_irq = 0;
  55 static int      mpu_detected = 0;
  56 
  57 int
  58 probe_cs4232_mpu (struct address_info *hw_config)
     /* [previous][next][first][last][top][bottom][index][help] */
  59 {
  60 /*
  61  * Just write down the config values.
  62  */
  63 
  64   mpu_base = hw_config->io_base;
  65   mpu_irq = hw_config->irq;
  66 
  67   return 0;
  68 }
  69 
  70 long
  71 attach_cs4232_mpu (long mem_start, struct address_info *hw_config)
     /* [previous][next][first][last][top][bottom][index][help] */
  72 {
  73   return mem_start;
  74 }
  75 
  76 static unsigned char crystal_key[] =    /* A 32 byte magic key sequence */
  77 {
  78   0x96, 0x35, 0x9a, 0xcd, 0xe6, 0xf3, 0x79, 0xbc,
  79   0x5e, 0xaf, 0x57, 0x2b, 0x15, 0x8a, 0xc5, 0xe2,
  80   0xf1, 0xf8, 0x7c, 0x3e, 0x9f, 0x4f, 0x27, 0x13,
  81   0x09, 0x84, 0x42, 0xa1, 0xd0, 0x68, 0x34, 0x1a
  82 };
  83 
  84 int
  85 probe_cs4232 (struct address_info *hw_config)
     /* [previous][next][first][last][top][bottom][index][help] */
  86 {
  87   int             i, n;
  88   int             base = hw_config->io_base, irq = hw_config->irq;
  89   int             dma1 = hw_config->dma, dma2 = hw_config->dma2;
  90 
  91   static wait_handle *cs_sleeper = NULL;
  92   static volatile struct snd_wait cs_sleep_flag =
  93   {0};
  94 
  95   osp = hw_config->osp;
  96 
  97 /*
  98  * Verify that the I/O port range is free.
  99  */
 100 
 101   if (check_region (base, 4))
 102     {
 103       printk ("cs4232.c: I/O port 0x%03x not free\n", base);
 104       return 0;
 105     }
 106 
 107   if (ad1848_detect (hw_config->io_base, NULL, hw_config->osp))
 108     return 1;                   /* The card is already active */
 109 
 110 /*
 111  * This version of the driver doesn't use the PnP method when configuring
 112  * the card but a simplified method defined by Crystal. This means that
 113  * just one CS4232 compatible device can exist on the system. Also this
 114  * method conflicts with possible PnP support in the OS. For this reason 
 115  * driver is just a temporary kludge.
 116  */
 117 
 118 /*
 119  * Repeat initialization few times since it doesn't always succeed in
 120  * first time.
 121  */
 122 
 123   for (n = 0; n < 4; n++)
 124     {
 125       cs_sleep_flag.mode = WK_NONE;
 126 /*
 127  * Wake up the card by sending a 32 byte Crystal key to the key port.
 128  */
 129       for (i = 0; i < 32; i++)
 130         CS_OUT (crystal_key[i]);
 131 
 132 
 133       {
 134         unsigned long   tl;
 135 
 136         if (HZ / 10)
 137           current_set_timeout (tl = jiffies + (HZ / 10));
 138         else
 139           tl = (unsigned long) -1;
 140         cs_sleep_flag.mode = WK_SLEEP;
 141         module_interruptible_sleep_on (&cs_sleeper);
 142         if (!(cs_sleep_flag.mode & WK_WAKEUP))
 143           {
 144             if (jiffies >= tl)
 145               cs_sleep_flag.mode |= WK_TIMEOUT;
 146           }
 147         cs_sleep_flag.mode &= ~WK_SLEEP;
 148       };                        /* Delay */
 149 
 150 /*
 151  * Now set the CSN (Card Select Number).
 152  */
 153 
 154       CS_OUT2 (0x06, CSN_NUM);
 155 
 156 
 157 /*
 158  * Then set some config bytes. First logical device 0 
 159  */
 160 
 161       CS_OUT2 (0x15, 0x00);     /* Select logical device 0 (WSS/SB/FM) */
 162       CS_OUT3 (0x47, (base >> 8) & 0xff, base & 0xff);  /* WSSbase */
 163 
 164       if (check_region (0x388, 4))      /* Not free */
 165         CS_OUT3 (0x48, 0x00, 0x00)      /* FMbase off */
 166           else
 167         CS_OUT3 (0x48, 0x03, 0x88);     /* FMbase 0x388 */
 168 
 169       CS_OUT3 (0x42, 0x00, 0x00);       /* SBbase off */
 170       CS_OUT2 (0x22, irq);      /* SB+WSS IRQ */
 171       CS_OUT2 (0x2a, dma1);     /* SB+WSS DMA */
 172 
 173       if (dma2 != -1)
 174         CS_OUT2 (0x25, dma2)    /* WSS DMA2 */
 175           else
 176         CS_OUT2 (0x25, 4);      /* No WSS DMA2 */
 177 
 178       CS_OUT2 (0x33, 0x01);     /* Activate logical dev 0 */
 179 
 180 
 181       {
 182         unsigned long   tl;
 183 
 184         if (HZ / 10)
 185           current_set_timeout (tl = jiffies + (HZ / 10));
 186         else
 187           tl = (unsigned long) -1;
 188         cs_sleep_flag.mode = WK_SLEEP;
 189         module_interruptible_sleep_on (&cs_sleeper);
 190         if (!(cs_sleep_flag.mode & WK_WAKEUP))
 191           {
 192             if (jiffies >= tl)
 193               cs_sleep_flag.mode |= WK_TIMEOUT;
 194           }
 195         cs_sleep_flag.mode &= ~WK_SLEEP;
 196       };                        /* Delay */
 197 
 198 /*
 199  * Initialize logical device 3 (MPU)
 200  */
 201 
 202 #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
 203       if (mpu_base != 0 && mpu_irq != 0)
 204         {
 205           CS_OUT2 (0x15, 0x03); /* Select logical device 3 (MPU) */
 206           CS_OUT3 (0x47, (mpu_base >> 8) & 0xff, mpu_base & 0xff);      /* MPUbase */
 207           CS_OUT2 (0x22, mpu_irq);      /* MPU IRQ */
 208           CS_OUT2 (0x33, 0x01); /* Activate logical dev 3 */
 209         }
 210 #endif
 211 
 212 /*
 213  * Finally activate the chip
 214  */
 215       CS_OUT (0x79);
 216 
 217 
 218       {
 219         unsigned long   tl;
 220 
 221         if (HZ / 5)
 222           current_set_timeout (tl = jiffies + (HZ / 5));
 223         else
 224           tl = (unsigned long) -1;
 225         cs_sleep_flag.mode = WK_SLEEP;
 226         module_interruptible_sleep_on (&cs_sleeper);
 227         if (!(cs_sleep_flag.mode & WK_WAKEUP))
 228           {
 229             if (jiffies >= tl)
 230               cs_sleep_flag.mode |= WK_TIMEOUT;
 231           }
 232         cs_sleep_flag.mode &= ~WK_SLEEP;
 233       };                        /* Delay */
 234 
 235 /*
 236  * Then try to detect the codec part of the chip
 237  */
 238 
 239       if (ad1848_detect (hw_config->io_base, NULL, hw_config->osp))
 240         return 1;
 241 
 242 
 243       {
 244         unsigned long   tl;
 245 
 246         if (HZ)
 247           current_set_timeout (tl = jiffies + (HZ));
 248         else
 249           tl = (unsigned long) -1;
 250         cs_sleep_flag.mode = WK_SLEEP;
 251         module_interruptible_sleep_on (&cs_sleeper);
 252         if (!(cs_sleep_flag.mode & WK_WAKEUP))
 253           {
 254             if (jiffies >= tl)
 255               cs_sleep_flag.mode |= WK_TIMEOUT;
 256           }
 257         cs_sleep_flag.mode &= ~WK_SLEEP;
 258       };                        /* Longer delay */
 259     }
 260 
 261   return 0;
 262 }
 263 
 264 long
 265 attach_cs4232 (long mem_start, struct address_info *hw_config)
     /* [previous][next][first][last][top][bottom][index][help] */
 266 {
 267   int             base = hw_config->io_base, irq = hw_config->irq;
 268   int             dma1 = hw_config->dma, dma2 = hw_config->dma2;
 269 
 270   if (dma2 == -1)
 271     dma2 = dma1;
 272 
 273   ad1848_init ("CS4232", base,
 274                irq,
 275                dma1,            /* Playback DMA */
 276                dma2,            /* Capture DMA */
 277                0,
 278                hw_config->osp);
 279 
 280 #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
 281   if (mpu_base != 0 && mpu_irq != 0)
 282     {
 283       static struct address_info hw_config2 =
 284       {0};                      /* Ensure it's initialized */
 285 
 286       hw_config2.io_base = mpu_base;
 287       hw_config2.irq = mpu_irq;
 288       hw_config2.dma = -1;
 289       hw_config2.dma2 = -1;
 290       hw_config2.always_detect = 0;
 291       hw_config2.name = NULL;
 292       hw_config2.driver_use_1 = 0;
 293       hw_config2.driver_use_2 = 0;
 294       hw_config2.card_subtype = 0;
 295       hw_config2.osp = hw_config->osp;
 296 
 297       if (probe_mpu401 (&hw_config2))
 298         {
 299           mpu_detected = 1;
 300           mem_start = attach_mpu401 (mem_start, &hw_config2);
 301         }
 302       else
 303         {
 304           mpu_base = mpu_irq = 0;
 305         }
 306     }
 307 #endif
 308   return mem_start;
 309 }
 310 
 311 void
 312 unload_cs4232 (struct address_info *hw_config)
     /* [previous][next][first][last][top][bottom][index][help] */
 313 {
 314   int             base = hw_config->io_base, irq = hw_config->irq;
 315   int             dma1 = hw_config->dma, dma2 = hw_config->dma2;
 316 
 317   if (dma2 == -1)
 318     dma2 = dma1;
 319 
 320   ad1848_unload (base,
 321                  irq,
 322                  dma1,          /* Playback DMA */
 323                  dma2,          /* Capture DMA */
 324                  0);
 325 
 326 #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI)
 327   if (mpu_base != 0 && mpu_irq != 0 && mpu_detected)
 328     {
 329       static struct address_info hw_config2 =
 330       {0};                      /* Ensure it's initialized */
 331 
 332       hw_config2.io_base = mpu_base;
 333       hw_config2.irq = mpu_irq;
 334       hw_config2.dma = -1;
 335       hw_config2.dma2 = -1;
 336       hw_config2.always_detect = 0;
 337       hw_config2.name = NULL;
 338       hw_config2.driver_use_1 = 0;
 339       hw_config2.driver_use_2 = 0;
 340       hw_config2.card_subtype = 0;
 341       hw_config2.osp = hw_config->osp;
 342 
 343       unload_mpu401 (&hw_config2);
 344     }
 345 #endif
 346 }
 347 
 348 void
 349 unload_cs4232_mpu (struct address_info *hw_config)
     /* [previous][next][first][last][top][bottom][index][help] */
 350 {
 351   /* Not required. Handled by cs4232_unload */
 352 }
 353 
 354 
 355 #endif

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