~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/sound/cs4232.c

Version: ~ [ 2.2.5 ] ~ [ 2.4.1 ] ~ [ 2.4.9 ] ~ [ 2.6.17.10 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Copyright (C) by Hannu Savolainen 1993-1997
  3  *
  4  *      cs4232.c
  5  *
  6  * The low level driver for Crystal CS4232 based cards. The CS4232 is
  7  * a PnP compatible chip which contains a CS4231A codec, SB emulation,
  8  * a MPU401 compatible MIDI port, joystick and synthesizer and IDE CD-ROM 
  9  * interfaces. This is just a temporary driver until full PnP support
 10  * gets implemented. Just the WSS codec, FM synth and the MIDI ports are
 11  * supported. Other interfaces are left uninitialized.
 12  *
 13  * ifdef ...WAVEFRONT...
 14  * 
 15  *   Support is provided for initializing the WaveFront synth
 16  *   interface as well, which is logical device #4. Note that if
 17  *   you have a Tropez+ card, you probably don't need to setup
 18  *   the CS4232-supported MIDI interface, since it corresponds to
 19  *   the internal 26-pin header that's hard to access. Using this
 20  *   requires an additional IRQ, a resource none too plentiful in
 21  *   this environment. Just don't set module parameters mpuio and
 22  *   mpuirq, and the MIDI port will be left uninitialized. You can
 23  *   still use the ICS2115 hosted MIDI interface which corresponds
 24  *   to the 9-pin D connector on the back of the card.
 25  *
 26  * endif  ...WAVEFRONT...
 27  *
 28  * Supported chips are:
 29  *      CS4232
 30  *      CS4236
 31  *      CS4236B
 32  *
 33  * Note: You will need a PnP config setup to initialise some CS4232 boards
 34  * anyway.
 35  *
 36  * Changes
 37  *      Alan Cox                Modularisation, Basic cleanups.
 38  *      Paul Barton-Davis       Separated MPU configuration, added
 39  *                                       Tropez+ (WaveFront) support
 40  *      Christoph Hellwig       Adapted to module_init/module_exit,
 41  *                                      simple cleanups
 42  *      Arnaldo C. de Melo      got rid of attach_uart401
 43  *      Bartlomiej Zolnierkiewicz
 44  *                              Added some __init/__initdata/__exit
 45  */
 46 
 47 #include <linux/config.h>
 48 #include <linux/module.h>
 49 #include <linux/init.h>
 50 
 51 #include "sound_config.h"
 52 
 53 #include "cs4232.h"
 54 #include "ad1848.h"
 55 #include "mpu401.h"
 56 
 57 #define KEY_PORT        0x279   /* Same as LPT1 status port */
 58 #define CSN_NUM         0x99    /* Just a random number */
 59 
 60 static void CS_OUT(unsigned char a)
 61 {
 62         outb(a, KEY_PORT);
 63 }
 64 
 65 #define CS_OUT2(a, b)           {CS_OUT(a);CS_OUT(b);}
 66 #define CS_OUT3(a, b, c)        {CS_OUT(a);CS_OUT(b);CS_OUT(c);}
 67 
 68 static int mpu_base = 0, mpu_irq = 0;
 69 static int synth_base = 0, synth_irq = 0;
 70 static int mpu_detected = 0;
 71 
 72 int __init probe_cs4232_mpu(struct address_info *hw_config)
 73 {
 74         /*
 75          *      Just write down the config values.
 76          */
 77 
 78         mpu_base = hw_config->io_base;
 79         mpu_irq = hw_config->irq;
 80 
 81         return 1;
 82 }
 83 
 84 static unsigned char crystal_key[] __initdata = /* A 32 byte magic key sequence */
 85 {
 86         0x96, 0x35, 0x9a, 0xcd, 0xe6, 0xf3, 0x79, 0xbc,
 87         0x5e, 0xaf, 0x57, 0x2b, 0x15, 0x8a, 0xc5, 0xe2,
 88         0xf1, 0xf8, 0x7c, 0x3e, 0x9f, 0x4f, 0x27, 0x13,
 89         0x09, 0x84, 0x42, 0xa1, 0xd0, 0x68, 0x34, 0x1a
 90 };
 91 
 92 static void sleep(unsigned howlong)
 93 {
 94         current->state = TASK_INTERRUPTIBLE;
 95         schedule_timeout(howlong);
 96 }
 97 
 98 int __init probe_cs4232(struct address_info *hw_config)
 99 {
100         int i, n;
101         int base = hw_config->io_base, irq = hw_config->irq;
102         int dma1 = hw_config->dma, dma2 = hw_config->dma2;
103 
104         /*
105          * Verify that the I/O port range is free.
106          */
107 
108         if (check_region(base, 4))
109         {
110                 printk(KERN_ERR "cs4232.c: I/O port 0x%03x not free\n", base);
111                 return 0;
112         }
113         if (ad1848_detect(hw_config->io_base, NULL, hw_config->osp))
114                 return 1;       /* The card is already active */
115 
116         /*
117          * This version of the driver doesn't use the PnP method when configuring
118          * the card but a simplified method defined by Crystal. This means that
119          * just one CS4232 compatible device can exist on the system. Also this
120          * method conflicts with possible PnP support in the OS. For this reason 
121          * driver is just a temporary kludge.
122          *
123          * Also the Cirrus/Crystal method doesnt always work. Try ISA PnP first ;)
124          */
125 
126         /*
127          * Repeat initialization few times since it doesn't always succeed in
128          * first time.
129          */
130 
131         for (n = 0; n < 4; n++)
132         {       
133                 /*
134                  *      Wake up the card by sending a 32 byte Crystal key to the key port.
135                  */
136                 
137                 for (i = 0; i < 32; i++)
138                         CS_OUT(crystal_key[i]);
139 
140                 sleep(HZ / 10);
141 
142                 /*
143                  *      Now set the CSN (Card Select Number).
144                  */
145 
146                 CS_OUT2(0x06, CSN_NUM);
147 
148                 /*
149                  *      Then set some config bytes. First logical device 0 
150                  */
151 
152                 CS_OUT2(0x15, 0x00);    /* Select logical device 0 (WSS/SB/FM) */
153                 CS_OUT3(0x47, (base >> 8) & 0xff, base & 0xff); /* WSS base */
154 
155                 if (check_region(0x388, 4))     /* Not free */
156                         CS_OUT3(0x48, 0x00, 0x00)       /* FM base off */
157                 else
158                         CS_OUT3(0x48, 0x03, 0x88);      /* FM base 0x388 */
159 
160                 CS_OUT3(0x42, 0x00, 0x00);      /* SB base off */
161                 CS_OUT2(0x22, irq);             /* SB+WSS IRQ */
162                 CS_OUT2(0x2a, dma1);            /* SB+WSS DMA */
163 
164                 if (dma2 != -1)
165                         CS_OUT2(0x25, dma2)     /* WSS DMA2 */
166                 else
167                         CS_OUT2(0x25, 4);       /* No WSS DMA2 */
168 
169                 CS_OUT2(0x33, 0x01);    /* Activate logical dev 0 */
170 
171                 sleep(HZ / 10);
172 
173                 /*
174                  * Initialize logical device 3 (MPU)
175                  */
176 
177                 if (mpu_base != 0 && mpu_irq != 0)
178                 {
179                         CS_OUT2(0x15, 0x03);    /* Select logical device 3 (MPU) */
180                         CS_OUT3(0x47, (mpu_base >> 8) & 0xff, mpu_base & 0xff); /* MPU base */
181                         CS_OUT2(0x22, mpu_irq); /* MPU IRQ */
182                         CS_OUT2(0x33, 0x01);    /* Activate logical dev 3 */
183                 }
184 
185                 if(synth_base != 0)
186                 {
187                     CS_OUT2 (0x15, 0x04);               /* logical device 4 (WaveFront) */
188                     CS_OUT3 (0x47, (synth_base >> 8) & 0xff,
189                              synth_base & 0xff);        /* base */
190                     CS_OUT2 (0x22, synth_irq);          /* IRQ */
191                     CS_OUT2 (0x33, 0x01);               /* Activate logical dev 4 */
192                 }
193 
194                 /*
195                  * Finally activate the chip
196                  */
197                 
198                 CS_OUT(0x79);
199 
200                 sleep(HZ / 5);
201 
202                 /*
203                  * Then try to detect the codec part of the chip
204                  */
205 
206                 if (ad1848_detect(hw_config->io_base, NULL, hw_config->osp))
207                         return 1;
208                 
209                 sleep(HZ);
210         }
211         return 0;
212 }
213 
214 void __init attach_cs4232(struct address_info *hw_config)
215 {
216         int base = hw_config->io_base,
217                 irq = hw_config->irq,
218                 dma1 = hw_config->dma,
219                 dma2 = hw_config->dma2;
220 
221         if (base == -1 || irq == -1 || dma1 == -1) {
222                 printk(KERN_ERR "cs4232: dma, irq and io must be set.\n");
223                 return;
224         }
225 
226         if (dma2 == -1)
227                 dma2 = dma1;
228 
229         hw_config->slots[0] = ad1848_init("Crystal audio controller", base,
230                                           irq,
231                                           dma1,         /* Playback DMA */
232                                           dma2,         /* Capture DMA */
233                                           0,
234                                           hw_config->osp,
235                                           THIS_MODULE);
236 
237         if (hw_config->slots[0] != -1 &&
238                 audio_devs[hw_config->slots[0]]->mixer_dev!=-1)
239         {       
240                 /* Assume the mixer map is as suggested in the CS4232 databook */
241                 AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE);
242                 AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD);
243                 AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH);           /* FM synth */
244         }
245         if (mpu_base != 0 && mpu_irq != 0)
246         {
247                 static struct address_info hw_config2 = {
248                         0
249                 };              /* Ensure it's initialized */
250 
251                 hw_config2.io_base = mpu_base;
252                 hw_config2.irq = mpu_irq;
253                 hw_config2.dma = -1;
254                 hw_config2.dma2 = -1;
255                 hw_config2.always_detect = 0;
256                 hw_config2.name = NULL;
257                 hw_config2.driver_use_1 = 0;
258                 hw_config2.driver_use_2 = 0;
259                 hw_config2.card_subtype = 0;
260 
261                 if (probe_uart401(&hw_config2, THIS_MODULE))
262                 {
263                         mpu_detected = 1;
264                 }
265                 else
266                 {
267                         mpu_base = mpu_irq = 0;
268                 }
269                 hw_config->slots[1] = hw_config2.slots[1];
270         }
271 }
272 
273 void __exit unload_cs4232(struct address_info *hw_config)
274 {
275         int base = hw_config->io_base, irq = hw_config->irq;
276         int dma1 = hw_config->dma, dma2 = hw_config->dma2;
277 
278         if (dma2 == -1)
279                 dma2 = dma1;
280 
281         ad1848_unload(base,
282                       irq,
283                       dma1,     /* Playback DMA */
284                       dma2,     /* Capture DMA */
285                       0);
286 
287         sound_unload_audiodev(hw_config->slots[0]);
288         if (mpu_base != 0 && mpu_irq != 0 && mpu_detected)
289         {
290                 static struct address_info hw_config2 =
291                 {
292                         0
293                 };              /* Ensure it's initialized */
294 
295                 hw_config2.io_base = mpu_base;
296                 hw_config2.irq = mpu_irq;
297                 hw_config2.dma = -1;
298                 hw_config2.dma2 = -1;
299                 hw_config2.always_detect = 0;
300                 hw_config2.name = NULL;
301                 hw_config2.driver_use_1 = 0;
302                 hw_config2.driver_use_2 = 0;
303                 hw_config2.card_subtype = 0;
304                 hw_config2.slots[1] = hw_config->slots[1];
305 
306                 unload_uart401(&hw_config2);
307         }
308 }
309 
310 static struct address_info cfg;
311 static struct address_info cfg_mpu;
312 
313 static int __initdata io        = -1;
314 static int __initdata irq       = -1;
315 static int __initdata dma       = -1;
316 static int __initdata dma2      = -1;
317 static int __initdata mpuio     = -1;
318 static int __initdata mpuirq    = -1;
319 static int __initdata synthio   = -1;
320 static int __initdata synthirq  = -1;
321 
322 
323 MODULE_PARM(io,"i");
324 MODULE_PARM(irq,"i");
325 MODULE_PARM(dma,"i");
326 MODULE_PARM(dma2,"i");
327 MODULE_PARM(mpuio,"i");
328 MODULE_PARM(mpuirq,"i");
329 MODULE_PARM(synthio,"i");
330 MODULE_PARM(synthirq,"i");
331 
332 /*
333  *      Install a CS4232 based card. Need to have ad1848 and mpu401
334  *      loaded ready.
335  */
336 
337 static int __init init_cs4232(void)
338 {
339 #ifdef CONFIG_SOUND_WAVEFRONT_MODULE
340         if(synthio == -1)
341                 printk(KERN_WARNING "cs4232: set synthio and synthirq to use the wavefront facilities.\n");
342         else {
343                 synth_base = synthio;
344                 synth_irq =  synthirq;  
345         }
346 #else
347         if(synthio != -1)
348                 printk(KERN_WARNING "cs4232: wavefront support not enabled in this driver.\n");
349 #endif
350         if(io==-1||irq==-1||dma==-1)
351         {
352                 printk(KERN_ERR "cs4232: Must set io, irq and dma.\n");
353                 return -ENODEV;
354         }
355 
356         cfg.io_base = io;
357         cfg.irq = irq;
358         cfg.dma = dma;
359         cfg.dma2 = dma2;
360 
361         cfg_mpu.io_base = -1;
362         cfg_mpu.irq = -1;
363 
364         if (mpuio != -1 && mpuirq != -1) {
365                 cfg_mpu.io_base = mpuio;
366                 cfg_mpu.irq = mpuirq;
367                 probe_cs4232_mpu(&cfg_mpu); /* Bug always returns 0 not OK -- AC */
368         }
369 
370         if (probe_cs4232(&cfg) == 0)
371                 return -ENODEV;
372         attach_cs4232(&cfg);
373         
374         return 0;
375 }
376 
377 static void __exit cleanup_cs4232(void)
378 {
379         unload_cs4232(&cfg); /* unloads MPU as well, if needed */
380 }
381 
382 module_init(init_cs4232);
383 module_exit(cleanup_cs4232);
384 
385 #ifndef MODULE
386 static int __init setup_cs4232(char *str)
387 {
388         /* io, irq, dma, dma2 mpuio, mpuirq*/
389         int ints[7];
390         
391         str = get_options(str, ARRAY_SIZE(ints), ints);
392         
393         io      = ints[1];
394         irq     = ints[2];
395         dma     = ints[3];
396         dma2    = ints[4];
397         mpuio   = ints[5];
398         mpuirq  = ints[6];
399 
400         return 1;
401 }
402 
403 __setup("cs4232=", setup_cs4232);
404 #endif
405 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.