Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs
[linux-2.6] / sound / oss / aedsp16.c
1 /*
2    sound/oss/aedsp16.c
3
4    Audio Excel DSP 16 software configuration routines
5    Copyright (C) 1995,1996,1997,1998  Riccardo Facchetti (fizban@tin.it)
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21  */
22 /*
23  * Include the main OSS Lite header file. It include all the os, OSS Lite, etc
24  * headers needed by this source.
25  */
26 #include <linux/delay.h>
27 #include <linux/module.h>
28 #include <linux/init.h>
29 #include "sound_config.h"
30
31 /*
32
33    READ THIS
34
35    This module started to configure the Audio Excel DSP 16 Sound Card.
36    Now works with the SC-6000 (old aedsp16) and new SC-6600 based cards.
37
38    NOTE: I have NO idea about Audio Excel DSP 16 III. If someone owns this
39    audio card and want to see the kernel support for it, please contact me.
40
41    Audio Excel DSP 16 is an SB pro II, Microsoft Sound System and MPU-401
42    compatible card.
43    It is software-only configurable (no jumpers to hard-set irq/dma/mpu-irq),
44    so before this module, the only way to configure the DSP under linux was
45    boot the MS-DOS loading the sound.sys device driver (this driver soft-
46    configure the sound board hardware by massaging someone of its registers),
47    and then ctrl-alt-del to boot linux with the DSP configured by the DOS
48    driver.
49
50    This module works configuring your Audio Excel DSP 16's irq, dma and
51    mpu-401-irq. The OSS Lite routines rely on the fact that if the
52    hardware is there, they can detect it. The problem with AEDSP16 is
53    that no hardware can be found by the probe routines if the sound card
54    is not configured properly. Sometimes the kernel probe routines can find
55    an SBPRO even when the card is not configured (this is the standard setup
56    of the card), but the SBPRO emulation don't work well if the card is not
57    properly initialized. For this reason
58
59    aedsp16_init_board()
60
61    routine is called before the OSS Lite probe routines try to detect the
62    hardware.
63
64    NOTE (READ THE NOTE TOO, IT CONTAIN USEFUL INFORMATIONS)
65
66    NOTE: Now it works with SC-6000 and SC-6600 based audio cards. The new cards
67    have no jumper switch at all. No more WSS or MPU-401 I/O port switches. They
68    have to be configured by software.
69
70    NOTE: The driver is merged with the new OSS Lite sound driver. It works
71    as a lowlevel driver.
72
73    The Audio Excel DSP 16 Sound Card emulates both SBPRO and MSS;
74    the OSS Lite sound driver can be configured for SBPRO and MSS cards
75    at the same time, but the aedsp16 can't be two cards!!
76    When we configure it, we have to choose the SBPRO or the MSS emulation
77    for AEDSP16. We also can install a *REAL* card of the other type (see [1]).
78
79    NOTE: If someone can test the combination AEDSP16+MSS or AEDSP16+SBPRO
80    please let me know if it works.
81
82    The MPU-401 support can be compiled in together with one of the other
83    two operating modes.
84
85    NOTE: This is something like plug-and-play: we have only to plug
86    the AEDSP16 board in the socket, and then configure and compile
87    a kernel that uses the AEDSP16 software configuration capability.
88    No jumper setting is needed!
89
90    For example, if you want AEDSP16 to be an SBPro, on irq 10, dma 3
91    you have just to make config the OSS Lite package, configuring
92    the AEDSP16 sound card, then activating the SBPro emulation mode
93    and at last configuring IRQ and DMA.
94    Compile the kernel and run it.
95
96    NOTE: This means for SC-6000 cards that you can choose irq and dma,
97    but not the I/O addresses. To change I/O addresses you have to set
98    them with jumpers. For SC-6600 cards you have no jumpers so you have
99    to set up your full card configuration in the make config.
100
101    You can change the irq/dma/mirq settings WITHOUT THE NEED to open
102    your computer and massage the jumpers (there are no irq/dma/mirq
103    jumpers to be configured anyway, only I/O BASE values have to be
104    configured with jumpers)
105
106    For some ununderstandable reason, the card default of irq 7, dma 1,
107    don't work for me. Seems to be an IRQ or DMA conflict. Under heavy
108    HDD work, the kernel start to erupt out a lot of messages like:
109
110    'Sound: DMA timed out - IRQ/DRQ config error?'
111
112    For what I can say, I have NOT any conflict at irq 7 (under linux I'm
113    using the lp polling driver), and dma line 1 is unused as stated by
114    /proc/dma. I can suppose this is a bug of AEDSP16. I know my hardware so
115    I'm pretty sure I have not any conflict, but may be I'm wrong. Who knows!
116    Anyway a setting of irq 10, dma 3 works really fine.
117
118    NOTE: if someone can use AEDSP16 with irq 7, dma 1, please let me know
119    the emulation mode, all the installed hardware and the hardware
120    configuration (irq and dma settings of all the hardware).
121
122    This init module should work with SBPRO+MSS, when one of the two is
123    the AEDSP16 emulation and the other the real card. (see [1])
124    For example:
125
126    AEDSP16 (0x220) in SBPRO emu (0x220) + real MSS + other
127    AEDSP16 (0x220) in MSS emu + real SBPRO (0x240) + other
128
129    MPU401 should work. (see [2])
130
131    [1]
132        ---
133        Date: Mon, 29 Jul 1997 08:35:40 +0100
134        From: Mr S J Greenaway <sjg95@unixfe.rl.ac.uk>
135
136        [...]
137        Just to let you know got my Audio Excel (emulating a MSS) working
138        with my original SB16, thanks for the driver!
139        [...]
140        ---
141
142    [2] Not tested by me for lack of hardware.
143
144    TODO, WISHES AND TECH
145
146    - About I/O ports allocation -
147
148    Request the 2x0h region (port base) in any case if we are using this card.
149
150    NOTE: the "aedsp16 (base)" string with which we are requesting the aedsp16
151    port base region (see code) does not mean necessarily that we are emulating
152    sbpro.  Even if this region is the sbpro I/O ports region, we use this
153    region to access the control registers of the card, and if emulating
154    sbpro, I/O sbpro registers too. If we are emulating MSS, the sbpro
155    registers are not used, in no way, to emulate an sbpro: they are
156    used only for configuration purposes.
157
158    Started Fri Mar 17 16:13:18 MET 1995
159
160    v0.1 (ALPHA, was a user-level program called AudioExcelDSP16.c)
161    - Initial code.
162    v0.2 (ALPHA)
163    - Cleanups.
164    - Integrated with Linux voxware v 2.90-2 kernel sound driver.
165    - SoundBlaster Pro mode configuration.
166    - Microsoft Sound System mode configuration.
167    - MPU-401 mode configuration.
168    v0.3 (ALPHA)
169    - Cleanups.
170    - Rearranged the code to let aedsp16_init_board be more general.
171    - Erased the REALLY_SLOW_IO. We don't need it. Erased the linux/io.h
172    inclusion too. We rely on os.h
173    - Used the  to get a variable
174    len string (we are not sure about the len of Copyright string).
175    This works with any SB and compatible.
176    - Added the code to request_region at device init (should go in
177    the main body of voxware).
178    v0.4 (BETA)
179    - Better configure.c patch for aedsp16 configuration (better
180    logic of inclusion of AEDSP16 support)
181    - Modified the conditional compilation to better support more than
182    one sound card of the emulated type (read the NOTES above)
183    - Moved the sb init routine from the attach to the very first
184    probe in sb_card.c
185    - Rearrangements and cleanups
186    - Wiped out some unnecessary code and variables: this is kernel
187    code so it is better save some TEXT and DATA
188    - Fixed the request_region code. We must allocate the aedsp16 (sbpro)
189    I/O ports in any case because they are used to access the DSP
190    configuration registers and we can not allow anyone to get them.
191    v0.5
192    - cleanups on comments
193    - prep for diffs against v3.0-proto-950402
194    v0.6
195    - removed the request_region()s when compiling the MODULE sound.o
196    because we are not allowed (by the actual voxware structure) to
197    release_region()
198    v0.7 (pre ALPHA, not distributed)
199    - started porting this module to kernel 1.3.84. Dummy probe/attach
200    routines.
201    v0.8 (ALPHA)
202    - attached all the init routines.
203    v0.9 (BETA)
204    - Integrated with linux-pre2.0.7
205    - Integrated with configuration scripts.
206    - Cleaned up and beautyfied the code.
207    v0.9.9 (BETA)
208    - Thanks to Piercarlo Grandi: corrected the conditonal compilation code.
209      Now only the code configured is compiled in, with some memory saving.
210    v0.9.10
211    - Integration into the sound/lowlevel/ section of the sound driver.
212    - Re-organized the code.
213    v0.9.11 (not distributed)
214    - Rewritten the init interface-routines to initialize the AEDSP16 in
215      one shot.
216    - More cosmetics.
217    - SC-6600 support.
218    - More soft/hard configuration.
219    v0.9.12
220    - Refined the v0.9.11 code with conditional compilation to distinguish
221      between SC-6000 and SC-6600 code.
222    v1.0.0
223    - Prep for merging with OSS Lite and Linux kernel 2.1.13
224    - Corrected a bug in request/check/release region calls (thanks to the
225      new kernel exception handling).
226    v1.1
227    - Revamped for integration with new modularized sound drivers: to enhance
228      the flexibility of modular version, I have removed all the conditional
229      compilation for SBPRO, MPU and MSS code. Now it is all managed with
230      the ae_config structure.
231    v1.2
232    - Module informations added.
233    - Removed aedsp16_delay_10msec(), now using mdelay(10)
234    - All data and funcs moved to .*.init section.
235    v1.3
236    Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 2000/09/27
237    - got rid of check_region
238
239    Known Problems:
240    - Audio Excel DSP 16 III don't work with this driver.
241
242    Credits:
243    Many thanks to Gerald Britton <gbritton@CapAccess.org>. He helped me a
244    lot in testing the 0.9.11 and 0.9.12 versions of this driver.
245
246  */
247
248
249 #define VERSION "1.3"           /* Version of Audio Excel DSP 16 driver */
250
251 #undef  AEDSP16_DEBUG           /* Define this to 1 to enable debug code     */
252 #undef  AEDSP16_DEBUG_MORE      /* Define this to 1 to enable more debug     */
253 #undef  AEDSP16_INFO            /* Define this to 1 to enable info code      */
254
255 #if defined(AEDSP16_DEBUG)
256 # define DBG(x)  printk x
257 # if defined(AEDSP16_DEBUG_MORE)
258 #  define DBG1(x) printk x
259 # else
260 #  define DBG1(x)
261 # endif
262 #else
263 # define DBG(x)
264 # define DBG1(x)
265 #endif
266
267 /*
268  * Misc definitions
269  */
270 #define TRUE    1
271 #define FALSE   0
272
273 /*
274  * Region Size for request/check/release region.
275  */
276 #define IOBASE_REGION_SIZE      0x10
277
278 /*
279  * Hardware related defaults
280  */
281 #define DEF_AEDSP16_IOB 0x220   /* 0x220(default) 0x240                 */
282 #define DEF_AEDSP16_IRQ 7       /* 5 7(default) 9 10 11                 */
283 #define DEF_AEDSP16_MRQ 0       /* 5 7 9 10 0(default), 0 means disable */
284 #define DEF_AEDSP16_DMA 1       /* 0 1(default) 3                       */
285
286 /*
287  * Commands of AEDSP16's DSP (SBPRO+special).
288  * Some of them are COMMAND_xx, in the future they may change.
289  */
290 #define WRITE_MDIRQ_CFG   0x50  /* Set M&I&DRQ mask (the real config)   */
291 #define COMMAND_52        0x52  /*                                      */
292 #define READ_HARD_CFG     0x58  /* Read Hardware Config (I/O base etc)  */
293 #define COMMAND_5C        0x5c  /*                                      */
294 #define COMMAND_60        0x60  /*                                      */
295 #define COMMAND_66        0x66  /*                                      */
296 #define COMMAND_6C        0x6c  /*                                      */
297 #define COMMAND_6E        0x6e  /*                                      */
298 #define COMMAND_88        0x88  /*                                      */
299 #define DSP_INIT_MSS      0x8c  /* Enable Microsoft Sound System mode   */
300 #define COMMAND_C5        0xc5  /*                                      */
301 #define GET_DSP_VERSION   0xe1  /* Get DSP Version                      */
302 #define GET_DSP_COPYRIGHT 0xe3  /* Get DSP Copyright                    */
303
304 /*
305  * Offsets of AEDSP16 DSP I/O ports. The offset is added to base I/O port
306  * to have the actual I/O port.
307  * Register permissions are:
308  * (wo) == Write Only
309  * (ro) == Read  Only
310  * (w-) == Write
311  * (r-) == Read
312  */
313 #define DSP_RESET    0x06       /* offset of DSP RESET             (wo) */
314 #define DSP_READ     0x0a       /* offset of DSP READ              (ro) */
315 #define DSP_WRITE    0x0c       /* offset of DSP WRITE             (w-) */
316 #define DSP_COMMAND  0x0c       /* offset of DSP COMMAND           (w-) */
317 #define DSP_STATUS   0x0c       /* offset of DSP STATUS            (r-) */
318 #define DSP_DATAVAIL 0x0e       /* offset of DSP DATA AVAILABLE    (ro) */
319
320
321 #define RETRY           10      /* Various retry values on I/O opera-   */
322 #define STATUSRETRY   1000      /* tions. Sometimes we have to          */
323 #define HARDRETRY   500000      /* wait for previous cmd to complete    */
324
325 /*
326  * Size of character arrays that store name and version of sound card
327  */
328 #define CARDNAMELEN     15      /* Size of the card's name in chars     */
329 #define CARDVERLEN      10      /* Size of the card's version in chars  */
330 #define CARDVERDIGITS   2       /* Number of digits in the version      */
331
332 #if defined(CONFIG_SC6600)
333 /*
334  * Bitmapped flags of hard configuration
335  */
336 /*
337  * Decode macros (xl == low byte, xh = high byte)
338  */
339 #define IOBASE(xl)              ((xl & 0x01)?0x240:0x220)
340 #define JOY(xl)                 (xl & 0x02)
341 #define MPUADDR(xl)             (                       \
342                                 (xl & 0x0C)?0x330:      \
343                                 (xl & 0x08)?0x320:      \
344                                 (xl & 0x04)?0x310:      \
345                                                 0x300)
346 #define WSSADDR(xl)             ((xl & 0x10)?0xE80:0x530)
347 #define CDROM(xh)               (xh & 0x20)
348 #define CDROMADDR(xh)           (((xh & 0x1F) << 4) + 0x200)
349 /*
350  * Encode macros
351  */
352 #define BLDIOBASE(xl, val) {            \
353         xl &= ~0x01;                    \
354         if (val == 0x240)               \
355                 xl |= 0x01;             \
356         }
357 #define BLDJOY(xl, val) {               \
358         xl &= ~0x02;                    \
359         if (val == 1)                   \
360                 xl |= 0x02;             \
361         }
362 #define BLDMPUADDR(xl, val) {           \
363         xl &= ~0x0C;                    \
364         switch (val) {                  \
365                 case 0x330:             \
366                         xl |= 0x0C;     \
367                         break;          \
368                 case 0x320:             \
369                         xl |= 0x08;     \
370                         break;          \
371                 case 0x310:             \
372                         xl |= 0x04;     \
373                         break;          \
374                 case 0x300:             \
375                         xl |= 0x00;     \
376                         break;          \
377                 default:                \
378                         xl |= 0x00;     \
379                         break;          \
380                 }                       \
381         }
382 #define BLDWSSADDR(xl, val) {           \
383         xl &= ~0x10;                    \
384         if (val == 0xE80)               \
385                 xl |= 0x10;             \
386         }
387 #define BLDCDROM(xh, val) {             \
388         xh &= ~0x20;                    \
389         if (val == 1)                   \
390                 xh |= 0x20;             \
391         }
392 #define BLDCDROMADDR(xh, val) {         \
393         int tmp = val;                  \
394         tmp -= 0x200;                   \
395         tmp >>= 4;                      \
396         tmp &= 0x1F;                    \
397         xh |= tmp;                      \
398         xh &= 0x7F;                     \
399         xh |= 0x40;                     \
400         }
401 #endif /* CONFIG_SC6600 */
402
403 /*
404  * Bit mapped flags for calling aedsp16_init_board(), and saving the current
405  * emulation mode.
406  */
407 #define INIT_NONE   (0   )
408 #define INIT_SBPRO  (1<<0)
409 #define INIT_MSS    (1<<1)
410 #define INIT_MPU401 (1<<2)
411
412 static int      soft_cfg __initdata = 0;        /* bitmapped config */
413 static int      soft_cfg_mss __initdata = 0;    /* bitmapped mss config */
414 static int      ver[CARDVERDIGITS] __initdata = {0, 0}; /* DSP Ver:
415                                                    hi->ver[0] lo->ver[1] */
416
417 #if defined(CONFIG_SC6600)
418 static int      hard_cfg[2]     /* lo<-hard_cfg[0] hi<-hard_cfg[1]      */
419                      __initdata = { 0, 0};
420 #endif /* CONFIG_SC6600 */
421
422 #if defined(CONFIG_SC6600)
423 /* Decoded hard configuration */
424 struct  d_hcfg {
425         int iobase;
426         int joystick;
427         int mpubase;
428         int wssbase;
429         int cdrom;
430         int cdrombase;
431 };
432
433 static struct d_hcfg decoded_hcfg __initdata = {0, };
434
435 #endif /* CONFIG_SC6600 */
436
437 /* orVals contain the values to be or'ed                                */
438 struct orVals {
439         int     val;            /* irq|mirq|dma                         */
440         int     or;             /* soft_cfg |= TheStruct.or             */
441 };
442
443 /* aedsp16_info contain the audio card configuration                  */
444 struct aedsp16_info {
445         int base_io;            /* base I/O address for accessing card  */
446         int irq;                /* irq value for DSP I/O                */
447         int mpu_irq;            /* irq for mpu401 interface I/O         */
448         int dma;                /* dma value for DSP I/O                */
449         int mss_base;           /* base I/O for Microsoft Sound System  */
450         int mpu_base;           /* base I/O for MPU-401 emulation       */
451         int init;               /* Initialization status of the card    */
452 };
453
454 /*
455  * Magic values that the DSP will eat when configuring irq/mirq/dma
456  */
457 /* DSP IRQ conversion array             */
458 static struct orVals orIRQ[] __initdata = {
459         {0x05, 0x28},
460         {0x07, 0x08},
461         {0x09, 0x10},
462         {0x0a, 0x18},
463         {0x0b, 0x20},
464         {0x00, 0x00}
465 };
466
467 /* MPU-401 IRQ conversion array         */
468 static struct orVals orMIRQ[] __initdata = {
469         {0x05, 0x04},
470         {0x07, 0x44},
471         {0x09, 0x84},
472         {0x0a, 0xc4},
473         {0x00, 0x00}
474 };
475
476 /* DMA Channels conversion array        */
477 static struct orVals orDMA[] __initdata = {
478         {0x00, 0x01},
479         {0x01, 0x02},
480         {0x03, 0x03},
481         {0x00, 0x00}
482 };
483
484 static struct aedsp16_info ae_config = {
485         DEF_AEDSP16_IOB,
486         DEF_AEDSP16_IRQ,
487         DEF_AEDSP16_MRQ,
488         DEF_AEDSP16_DMA,
489         -1,
490         -1,
491         INIT_NONE
492 };
493
494 /*
495  * Buffers to store audio card informations
496  */
497 static char     DSPCopyright[CARDNAMELEN + 1] __initdata = {0, };
498 static char     DSPVersion[CARDVERLEN + 1] __initdata = {0, };
499
500 static int __init aedsp16_wait_data(int port)
501 {
502         int             loop = STATUSRETRY;
503         unsigned char   ret = 0;
504
505         DBG1(("aedsp16_wait_data (0x%x): ", port));
506
507         do {
508                   ret = inb(port + DSP_DATAVAIL);
509         /*
510          * Wait for data available (bit 7 of ret == 1)
511          */
512           } while (!(ret & 0x80) && loop--);
513
514         if (ret & 0x80) {
515                 DBG1(("success.\n"));
516                 return TRUE;
517         }
518
519         DBG1(("failure.\n"));
520         return FALSE;
521 }
522
523 static int __init aedsp16_read(int port)
524 {
525         int inbyte;
526
527         DBG(("    Read DSP Byte (0x%x): ", port));
528
529         if (aedsp16_wait_data(port) == FALSE) {
530                 DBG(("failure.\n"));
531                 return -1;
532         }
533
534         inbyte = inb(port + DSP_READ);
535
536         DBG(("read [0x%x]/{%c}.\n", inbyte, inbyte));
537
538         return inbyte;
539 }
540
541 static int __init aedsp16_test_dsp(int port)
542 {
543         return ((aedsp16_read(port) == 0xaa) ? TRUE : FALSE);
544 }
545
546 static int __init aedsp16_dsp_reset(int port)
547 {
548         /*
549          * Reset DSP
550          */
551
552         DBG(("Reset DSP:\n"));
553
554         outb(1, (port + DSP_RESET));
555         udelay(10);
556         outb(0, (port + DSP_RESET));
557         udelay(10);
558         udelay(10);
559         if (aedsp16_test_dsp(port) == TRUE) {
560                 DBG(("success.\n"));
561                 return TRUE;
562         } else
563                 DBG(("failure.\n"));
564         return FALSE;
565 }
566
567 static int __init aedsp16_write(int port, int cmd)
568 {
569         unsigned char   ret;
570         int             loop = HARDRETRY;
571
572         DBG(("    Write DSP Byte (0x%x) [0x%x]: ", port, cmd));
573
574         do {
575                 ret = inb(port + DSP_STATUS);
576                 /*
577                  * DSP ready to receive data if bit 7 of ret == 0
578                  */
579                 if (!(ret & 0x80)) {
580                         outb(cmd, port + DSP_COMMAND);
581                         DBG(("success.\n"));
582                         return 0;
583                 }
584         } while (loop--);
585
586         DBG(("timeout.\n"));
587         printk("[AEDSP16] DSP Command (0x%x) timeout.\n", cmd);
588
589         return -1;
590 }
591
592 #if defined(CONFIG_SC6600)
593
594 #if defined(AEDSP16_INFO) || defined(AEDSP16_DEBUG)
595 void __init aedsp16_pinfo(void) {
596         DBG(("\n Base address:  %x\n", decoded_hcfg.iobase));
597         DBG((" Joystick    : %s present\n", decoded_hcfg.joystick?"":" not"));
598         DBG((" WSS addr    :  %x\n", decoded_hcfg.wssbase));
599         DBG((" MPU-401 addr:  %x\n", decoded_hcfg.mpubase));
600         DBG((" CDROM       : %s present\n", (decoded_hcfg.cdrom!=4)?"":" not"));
601         DBG((" CDROMADDR   :  %x\n\n", decoded_hcfg.cdrombase));
602 }
603 #endif
604
605 static void __init aedsp16_hard_decode(void) {
606
607         DBG((" aedsp16_hard_decode: 0x%x, 0x%x\n", hard_cfg[0], hard_cfg[1]));
608
609 /*
610  * Decode Cfg Bytes.
611  */
612         decoded_hcfg.iobase     = IOBASE(hard_cfg[0]);
613         decoded_hcfg.joystick   = JOY(hard_cfg[0]);
614         decoded_hcfg.wssbase    = WSSADDR(hard_cfg[0]);
615         decoded_hcfg.mpubase    = MPUADDR(hard_cfg[0]);
616         decoded_hcfg.cdrom      = CDROM(hard_cfg[1]);
617         decoded_hcfg.cdrombase  = CDROMADDR(hard_cfg[1]);
618
619 #if defined(AEDSP16_INFO) || defined(AEDSP16_DEBUG)
620         printk(" Original sound card configuration:\n");
621         aedsp16_pinfo();
622 #endif
623
624 /*
625  * Now set up the real kernel configuration.
626  */
627         decoded_hcfg.iobase     = ae_config.base_io;
628         decoded_hcfg.wssbase    = ae_config.mss_base;
629         decoded_hcfg.mpubase    = ae_config.mpu_base;
630
631 #if defined(CONFIG_SC6600_JOY)
632         decoded_hcfg.joystick   = CONFIG_SC6600_JOY; /* Enable */
633 #endif
634 #if defined(CONFIG_SC6600_CDROM)
635         decoded_hcfg.cdrom      = CONFIG_SC6600_CDROM; /* 4:N-3:I-2:G-1:P-0:S */
636 #endif
637 #if defined(CONFIG_SC6600_CDROMBASE)
638         decoded_hcfg.cdrombase  = CONFIG_SC6600_CDROMBASE; /* 0 Disable */
639 #endif
640
641 #if defined(AEDSP16_DEBUG)
642         DBG((" New Values:\n"));
643         aedsp16_pinfo();
644 #endif
645
646         DBG(("success.\n"));
647 }
648
649 static void __init aedsp16_hard_encode(void) {
650
651         DBG((" aedsp16_hard_encode: 0x%x, 0x%x\n", hard_cfg[0], hard_cfg[1]));
652
653         hard_cfg[0] = 0;
654         hard_cfg[1] = 0;
655
656         hard_cfg[0] |= 0x20;
657
658         BLDIOBASE (hard_cfg[0], decoded_hcfg.iobase);
659         BLDWSSADDR(hard_cfg[0], decoded_hcfg.wssbase);
660         BLDMPUADDR(hard_cfg[0], decoded_hcfg.mpubase);
661         BLDJOY(hard_cfg[0], decoded_hcfg.joystick);
662         BLDCDROM(hard_cfg[1], decoded_hcfg.cdrom);
663         BLDCDROMADDR(hard_cfg[1], decoded_hcfg.cdrombase);
664
665 #if defined(AEDSP16_DEBUG)
666         aedsp16_pinfo();
667 #endif
668
669         DBG((" aedsp16_hard_encode: 0x%x, 0x%x\n", hard_cfg[0], hard_cfg[1]));
670         DBG(("success.\n"));
671
672 }
673
674 static int __init aedsp16_hard_write(int port) {
675
676         DBG(("aedsp16_hard_write:\n"));
677
678         if (aedsp16_write(port, COMMAND_6C)) {
679                 printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_6C);
680                 DBG(("failure.\n"));
681                 return FALSE;
682         }
683         if (aedsp16_write(port, COMMAND_5C)) {
684                 printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_5C);
685                 DBG(("failure.\n"));
686                 return FALSE;
687         }
688         if (aedsp16_write(port, hard_cfg[0])) {
689                 printk("[AEDSP16] DATA 0x%x: failed!\n", hard_cfg[0]);
690                 DBG(("failure.\n"));
691                 return FALSE;
692         }
693         if (aedsp16_write(port, hard_cfg[1])) {
694                 printk("[AEDSP16] DATA 0x%x: failed!\n", hard_cfg[1]);
695                 DBG(("failure.\n"));
696                 return FALSE;
697         }
698         if (aedsp16_write(port, COMMAND_C5)) {
699                 printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_C5);
700                 DBG(("failure.\n"));
701                 return FALSE;
702         }
703
704         DBG(("success.\n"));
705
706         return TRUE;
707 }
708
709 static int __init aedsp16_hard_read(int port) {
710
711         DBG(("aedsp16_hard_read:\n"));
712
713         if (aedsp16_write(port, READ_HARD_CFG)) {
714                 printk("[AEDSP16] CMD 0x%x: failed!\n", READ_HARD_CFG);
715                 DBG(("failure.\n"));
716                 return FALSE;
717         }
718
719         if ((hard_cfg[0] = aedsp16_read(port)) == -1) {
720                 printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n",
721                         READ_HARD_CFG);
722                 DBG(("failure.\n"));
723                 return FALSE;
724         }
725         if ((hard_cfg[1] = aedsp16_read(port)) == -1) {
726                 printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n",
727                         READ_HARD_CFG);
728                 DBG(("failure.\n"));
729                 return FALSE;
730         }
731         if (aedsp16_read(port) == -1) {
732                 printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n",
733                         READ_HARD_CFG);
734                 DBG(("failure.\n"));
735                 return FALSE;
736         }
737
738         DBG(("success.\n"));
739
740         return TRUE;
741 }
742
743 static int __init aedsp16_ext_cfg_write(int port) {
744
745         int extcfg, val;
746
747         if (aedsp16_write(port, COMMAND_66)) {
748                 printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_66);
749                 return FALSE;
750         }
751
752         extcfg = 7;
753         if (decoded_hcfg.cdrom != 2)
754                 extcfg = 0x0F;
755         if ((decoded_hcfg.cdrom == 4) ||
756             (decoded_hcfg.cdrom == 3))
757                 extcfg &= ~2;
758         if (decoded_hcfg.cdrombase == 0)
759                 extcfg &= ~2;
760         if (decoded_hcfg.mpubase == 0)
761                 extcfg &= ~1;
762
763         if (aedsp16_write(port, extcfg)) {
764                 printk("[AEDSP16] Write extcfg: failed!\n");
765                 return FALSE;
766         }
767         if (aedsp16_write(port, 0)) {
768                 printk("[AEDSP16] Write extcfg: failed!\n");
769                 return FALSE;
770         }
771         if (decoded_hcfg.cdrom == 3) {
772                 if (aedsp16_write(port, COMMAND_52)) {
773                         printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_52);
774                         return FALSE;
775                 }
776                 if ((val = aedsp16_read(port)) == -1) {
777                         printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n"
778                                         , COMMAND_52);
779                         return FALSE;
780                 }
781                 val &= 0x7F;
782                 if (aedsp16_write(port, COMMAND_60)) {
783                         printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_60);
784                         return FALSE;
785                 }
786                 if (aedsp16_write(port, val)) {
787                         printk("[AEDSP16] Write val: failed!\n");
788                         return FALSE;
789                 }
790         }
791
792         return TRUE;
793 }
794
795 #endif /* CONFIG_SC6600 */
796
797 static int __init aedsp16_cfg_write(int port) {
798         if (aedsp16_write(port, WRITE_MDIRQ_CFG)) {
799                 printk("[AEDSP16] CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG);
800                 return FALSE;
801         }
802         if (aedsp16_write(port, soft_cfg)) {
803                 printk("[AEDSP16] Initialization of (M)IRQ and DMA: failed!\n");
804                 return FALSE;
805         }
806         return TRUE;
807 }
808
809 static int __init aedsp16_init_mss(int port)
810 {
811         DBG(("aedsp16_init_mss:\n"));
812
813         mdelay(10);
814
815         if (aedsp16_write(port, DSP_INIT_MSS)) {
816                 printk("[AEDSP16] aedsp16_init_mss [0x%x]: failed!\n",
817                                 DSP_INIT_MSS);
818                 DBG(("failure.\n"));
819                 return FALSE;
820         }
821         
822         mdelay(10);
823
824         if (aedsp16_cfg_write(port) == FALSE)
825                 return FALSE;
826
827         outb(soft_cfg_mss, ae_config.mss_base);
828
829         DBG(("success.\n"));
830
831         return TRUE;
832 }
833
834 static int __init aedsp16_setup_board(int port) {
835         int     loop = RETRY;
836
837 #if defined(CONFIG_SC6600)
838         int     val = 0;
839
840         if (aedsp16_hard_read(port) == FALSE) {
841                 printk("[AEDSP16] aedsp16_hard_read: failed!\n");
842                 return FALSE;
843         }
844
845         if (aedsp16_write(port, COMMAND_52)) {
846                 printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_52);
847                 return FALSE;
848         }
849
850         if ((val = aedsp16_read(port)) == -1) {
851                 printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n",
852                                 COMMAND_52);
853                 return FALSE;
854         }
855 #endif
856
857         do {
858                 if (aedsp16_write(port, COMMAND_88)) {
859                         printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_88);
860                         return FALSE;
861                 }
862                 mdelay(10);
863         } while ((aedsp16_wait_data(port) == FALSE) && loop--);
864
865         if (aedsp16_read(port) == -1) {
866                 printk("[AEDSP16] aedsp16_read after CMD 0x%x: failed\n",
867                                 COMMAND_88);
868                 return FALSE;
869         }
870
871 #if !defined(CONFIG_SC6600)
872         if (aedsp16_write(port, COMMAND_5C)) {
873                 printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_5C);
874                 return FALSE;
875         }
876 #endif
877
878         if (aedsp16_cfg_write(port) == FALSE)
879                 return FALSE;
880
881 #if defined(CONFIG_SC6600)
882         if (aedsp16_write(port, COMMAND_60)) {
883                 printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_60);
884                 return FALSE;
885         }
886         if (aedsp16_write(port, val)) {
887                 printk("[AEDSP16] DATA 0x%x: failed!\n", val);
888                 return FALSE;
889         }
890         if (aedsp16_write(port, COMMAND_6E)) {
891                 printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_6E);
892                 return FALSE;
893         }
894         if (aedsp16_write(port, ver[0])) {
895                 printk("[AEDSP16] DATA 0x%x: failed!\n", ver[0]);
896                 return FALSE;
897         }
898         if (aedsp16_write(port, ver[1])) {
899                 printk("[AEDSP16] DATA 0x%x: failed!\n", ver[1]);
900                 return FALSE;
901         }
902
903         if (aedsp16_hard_write(port) == FALSE) {
904                 printk("[AEDSP16] aedsp16_hard_write: failed!\n");
905                 return FALSE;
906         }
907
908         if (aedsp16_write(port, COMMAND_5C)) {
909                 printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_5C);
910                 return FALSE;
911         }
912
913 #if defined(THIS_IS_A_THING_I_HAVE_NOT_TESTED_YET)
914         if (aedsp16_cfg_write(port) == FALSE)
915                 return FALSE;
916 #endif
917
918 #endif
919
920         return TRUE;
921 }
922
923 static int __init aedsp16_stdcfg(int port) {
924         if (aedsp16_write(port, WRITE_MDIRQ_CFG)) {
925                 printk("[AEDSP16] CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG);
926                 return FALSE;
927         }
928         /*
929          * 0x0A == (IRQ 7, DMA 1, MIRQ 0)
930          */
931         if (aedsp16_write(port, 0x0A)) {
932                 printk("[AEDSP16] aedsp16_stdcfg: failed!\n");
933                 return FALSE;
934         }
935         return TRUE;
936 }
937
938 static int __init aedsp16_dsp_version(int port)
939 {
940         int             len = 0;
941         int             ret;
942
943         DBG(("Get DSP Version:\n"));
944
945         if (aedsp16_write(ae_config.base_io, GET_DSP_VERSION)) {
946                 printk("[AEDSP16] CMD 0x%x: failed!\n", GET_DSP_VERSION);
947                 DBG(("failed.\n"));
948                 return FALSE;
949         }
950
951         do {
952                 if ((ret = aedsp16_read(port)) == -1) {
953                         DBG(("failed.\n"));
954                         return FALSE;
955                 }
956         /*
957          * We already know how many int are stored (2), so we know when the
958          * string is finished.
959          */
960                 ver[len++] = ret;
961           } while (len < CARDVERDIGITS);
962         sprintf(DSPVersion, "%d.%d", ver[0], ver[1]);
963
964         DBG(("success.\n"));
965
966         return TRUE;
967 }
968
969 static int __init aedsp16_dsp_copyright(int port)
970 {
971         int             len = 0;
972         int             ret;
973
974         DBG(("Get DSP Copyright:\n"));
975
976         if (aedsp16_write(ae_config.base_io, GET_DSP_COPYRIGHT)) {
977                 printk("[AEDSP16] CMD 0x%x: failed!\n", GET_DSP_COPYRIGHT);
978                 DBG(("failed.\n"));
979                 return FALSE;
980         }
981
982         do {
983                 if ((ret = aedsp16_read(port)) == -1) {
984         /*
985          * If no more data available, return to the caller, no error if len>0.
986          * We have no other way to know when the string is finished.
987          */
988                         if (len)
989                                 break;
990                         else {
991                                 DBG(("failed.\n"));
992                                 return FALSE;
993                         }
994                 }
995
996                 DSPCopyright[len++] = ret;
997
998           } while (len < CARDNAMELEN);
999
1000         DBG(("success.\n"));
1001
1002         return TRUE;
1003 }
1004
1005 static void __init aedsp16_init_tables(void)
1006 {
1007         int i = 0;
1008
1009         memset(DSPCopyright, 0, CARDNAMELEN + 1);
1010         memset(DSPVersion, 0, CARDVERLEN + 1);
1011
1012         for (i = 0; orIRQ[i].or; i++)
1013                 if (orIRQ[i].val == ae_config.irq) {
1014                         soft_cfg |= orIRQ[i].or;
1015                         soft_cfg_mss |= orIRQ[i].or;
1016                 }
1017
1018         for (i = 0; orMIRQ[i].or; i++)
1019                 if (orMIRQ[i].or == ae_config.mpu_irq)
1020                         soft_cfg |= orMIRQ[i].or;
1021
1022         for (i = 0; orDMA[i].or; i++)
1023                 if (orDMA[i].val == ae_config.dma) {
1024                         soft_cfg |= orDMA[i].or;
1025                         soft_cfg_mss |= orDMA[i].or;
1026                 }
1027 }
1028
1029 static int __init aedsp16_init_board(void)
1030 {
1031         aedsp16_init_tables();
1032
1033         if (aedsp16_dsp_reset(ae_config.base_io) == FALSE) {
1034                 printk("[AEDSP16] aedsp16_dsp_reset: failed!\n");
1035                 return FALSE;
1036         }
1037         if (aedsp16_dsp_copyright(ae_config.base_io) == FALSE) {
1038                 printk("[AEDSP16] aedsp16_dsp_copyright: failed!\n");
1039                 return FALSE;
1040         }
1041
1042         /*
1043          * My AEDSP16 card return SC-6000 in DSPCopyright, so
1044          * if we have something different, we have to be warned.
1045          */
1046         if (strcmp("SC-6000", DSPCopyright))
1047                 printk("[AEDSP16] Warning: non SC-6000 audio card!\n");
1048
1049         if (aedsp16_dsp_version(ae_config.base_io) == FALSE) {
1050                 printk("[AEDSP16] aedsp16_dsp_version: failed!\n");
1051                 return FALSE;
1052         }
1053
1054         if (aedsp16_stdcfg(ae_config.base_io) == FALSE) {
1055                 printk("[AEDSP16] aedsp16_stdcfg: failed!\n");
1056                 return FALSE;
1057         }
1058
1059 #if defined(CONFIG_SC6600)
1060         if (aedsp16_hard_read(ae_config.base_io) == FALSE) {
1061                 printk("[AEDSP16] aedsp16_hard_read: failed!\n");
1062                 return FALSE;
1063         }
1064
1065         aedsp16_hard_decode();
1066
1067         aedsp16_hard_encode();
1068
1069         if (aedsp16_hard_write(ae_config.base_io) == FALSE) {
1070                 printk("[AEDSP16] aedsp16_hard_write: failed!\n");
1071                 return FALSE;
1072         }
1073
1074         if (aedsp16_ext_cfg_write(ae_config.base_io) == FALSE) {
1075                 printk("[AEDSP16] aedsp16_ext_cfg_write: failed!\n");
1076                 return FALSE;
1077         }
1078 #endif /* CONFIG_SC6600 */
1079
1080         if (aedsp16_setup_board(ae_config.base_io) == FALSE) {
1081                 printk("[AEDSP16] aedsp16_setup_board: failed!\n");
1082                 return FALSE;
1083         }
1084
1085         if (ae_config.mss_base != -1) {
1086                 if (ae_config.init & INIT_MSS) {
1087                         if (aedsp16_init_mss(ae_config.base_io) == FALSE) {
1088                                 printk("[AEDSP16] Can not initialize"
1089                                        "Microsoft Sound System mode.\n");
1090                                 return FALSE;
1091                         }
1092                 }
1093         }
1094
1095 #if !defined(MODULE) || defined(AEDSP16_INFO) || defined(AEDSP16_DEBUG)
1096
1097         printk("Audio Excel DSP 16 init v%s (%s %s) [",
1098                 VERSION, DSPCopyright,
1099                 DSPVersion);
1100
1101         if (ae_config.mpu_base != -1) {
1102                 if (ae_config.init & INIT_MPU401) {
1103                         printk("MPU401");
1104                         if ((ae_config.init & INIT_MSS) ||
1105                             (ae_config.init & INIT_SBPRO))
1106                                 printk(" ");
1107                 }
1108         }
1109
1110         if (ae_config.mss_base == -1) {
1111                 if (ae_config.init & INIT_SBPRO) {
1112                         printk("SBPro");
1113                         if (ae_config.init & INIT_MSS)
1114                                 printk(" ");
1115                 }
1116         }
1117
1118         if (ae_config.mss_base != -1)
1119                 if (ae_config.init & INIT_MSS)
1120                         printk("MSS");
1121
1122         printk("]\n");
1123 #endif /* MODULE || AEDSP16_INFO || AEDSP16_DEBUG */
1124
1125         mdelay(10);
1126
1127         return TRUE;
1128 }
1129
1130 static int __init init_aedsp16_sb(void)
1131 {
1132         DBG(("init_aedsp16_sb: "));
1133
1134 /*
1135  * If the card is already init'ed MSS, we can not init it to SBPRO too
1136  * because the board can not emulate simultaneously MSS and SBPRO.
1137  */
1138         if (ae_config.init & INIT_MSS)
1139                 return FALSE;
1140         if (ae_config.init & INIT_SBPRO)
1141                 return FALSE;
1142
1143         ae_config.init |= INIT_SBPRO;
1144
1145         DBG(("done.\n"));
1146
1147         return TRUE;
1148 }
1149
1150 static void uninit_aedsp16_sb(void)
1151 {
1152         DBG(("uninit_aedsp16_sb: "));
1153
1154         ae_config.init &= ~INIT_SBPRO;
1155
1156         DBG(("done.\n"));
1157 }
1158
1159 static int __init init_aedsp16_mss(void)
1160 {
1161         DBG(("init_aedsp16_mss: "));
1162
1163 /*
1164  * If the card is already init'ed SBPRO, we can not init it to MSS too
1165  * because the board can not emulate simultaneously MSS and SBPRO.
1166  */
1167         if (ae_config.init & INIT_SBPRO)
1168                 return FALSE;
1169         if (ae_config.init & INIT_MSS)
1170                 return FALSE;
1171 /*
1172  * We must allocate the CONFIG_AEDSP16_BASE region too because these are the 
1173  * I/O ports to access card's control registers.
1174  */
1175         if (!(ae_config.init & INIT_MPU401)) {
1176                 if (!request_region(ae_config.base_io, IOBASE_REGION_SIZE,
1177                                 "aedsp16 (base)")) {
1178                         printk(
1179                         "AEDSP16 BASE I/O port region is already in use.\n");
1180                         return FALSE;
1181                 }
1182         }
1183
1184         ae_config.init |= INIT_MSS;
1185
1186         DBG(("done.\n"));
1187
1188         return TRUE;
1189 }
1190
1191 static void uninit_aedsp16_mss(void)
1192 {
1193         DBG(("uninit_aedsp16_mss: "));
1194
1195         if ((!(ae_config.init & INIT_MPU401)) &&
1196            (ae_config.init & INIT_MSS)) {
1197                 release_region(ae_config.base_io, IOBASE_REGION_SIZE);
1198                 DBG(("AEDSP16 base region released.\n"));
1199         }
1200
1201         ae_config.init &= ~INIT_MSS;
1202         DBG(("done.\n"));
1203 }
1204
1205 static int __init init_aedsp16_mpu(void)
1206 {
1207         DBG(("init_aedsp16_mpu: "));
1208
1209         if (ae_config.init & INIT_MPU401)
1210                 return FALSE;
1211
1212 /*
1213  * We must request the CONFIG_AEDSP16_BASE region too because these are the I/O 
1214  * ports to access card's control registers.
1215  */
1216         if (!(ae_config.init & (INIT_MSS | INIT_SBPRO))) {
1217                 if (!request_region(ae_config.base_io, IOBASE_REGION_SIZE,
1218                                         "aedsp16 (base)")) {
1219                         printk(
1220                         "AEDSP16 BASE I/O port region is already in use.\n");
1221                         return FALSE;
1222                 }
1223         }
1224
1225         ae_config.init |= INIT_MPU401;
1226
1227         DBG(("done.\n"));
1228
1229         return TRUE;
1230 }
1231
1232 static void uninit_aedsp16_mpu(void)
1233 {
1234         DBG(("uninit_aedsp16_mpu: "));
1235
1236         if ((!(ae_config.init & (INIT_MSS | INIT_SBPRO))) &&
1237            (ae_config.init & INIT_MPU401)) {
1238                 release_region(ae_config.base_io, IOBASE_REGION_SIZE);
1239                 DBG(("AEDSP16 base region released.\n"));
1240         }
1241
1242         ae_config.init &= ~INIT_MPU401;
1243
1244         DBG(("done.\n"));
1245 }
1246
1247 static int __init init_aedsp16(void)
1248 {
1249         int initialized = FALSE;
1250
1251         DBG(("Initializing BASE[0x%x] IRQ[%d] DMA[%d] MIRQ[%d]\n",
1252              ae_config.base_io,ae_config.irq,ae_config.dma,ae_config.mpu_irq));
1253
1254         if (ae_config.mss_base == -1) {
1255                 if (init_aedsp16_sb() == FALSE) {
1256                         uninit_aedsp16_sb();
1257                 } else {
1258                         initialized = TRUE;
1259                 }
1260         }
1261
1262         if (ae_config.mpu_base != -1) {
1263                 if (init_aedsp16_mpu() == FALSE) {
1264                         uninit_aedsp16_mpu();
1265                 } else {
1266                         initialized = TRUE;
1267                 }
1268         }
1269
1270 /*
1271  * In the sequence of init routines, the MSS init MUST be the last!
1272  * This because of the special register programming the MSS mode needs.
1273  * A board reset would disable the MSS mode restoring the default SBPRO
1274  * mode.
1275  */
1276         if (ae_config.mss_base != -1) {
1277                 if (init_aedsp16_mss() == FALSE) {
1278                         uninit_aedsp16_mss();
1279                 } else {
1280                         initialized = TRUE;
1281                 }
1282         }
1283
1284         if (initialized)
1285                 initialized = aedsp16_init_board();
1286         return initialized;
1287 }
1288
1289 static void __exit uninit_aedsp16(void)
1290 {
1291         if (ae_config.mss_base != -1)
1292                 uninit_aedsp16_mss();
1293         else
1294                 uninit_aedsp16_sb();
1295         if (ae_config.mpu_base != -1)
1296                 uninit_aedsp16_mpu();
1297 }
1298
1299 static int __initdata io = -1;
1300 static int __initdata irq = -1;
1301 static int __initdata dma = -1;
1302 static int __initdata mpu_irq = -1;
1303 static int __initdata mss_base = -1;
1304 static int __initdata mpu_base = -1;
1305
1306 module_param(io, int, 0);
1307 MODULE_PARM_DESC(io, "I/O base address (0x220 0x240)");
1308 module_param(irq, int, 0);
1309 MODULE_PARM_DESC(irq, "IRQ line (5 7 9 10 11)");
1310 module_param(dma, int, 0);
1311 MODULE_PARM_DESC(dma, "dma line (0 1 3)");
1312 module_param(mpu_irq, int, 0);
1313 MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ line (5 7 9 10 0)");
1314 module_param(mss_base, int, 0);
1315 MODULE_PARM_DESC(mss_base, "MSS emulation I/O base address (0x530 0xE80)");
1316 module_param(mpu_base, int, 0);
1317 MODULE_PARM_DESC(mpu_base,"MPU-401 I/O base address (0x300 0x310 0x320 0x330)");
1318 MODULE_AUTHOR("Riccardo Facchetti <fizban@tin.it>");
1319 MODULE_DESCRIPTION("Audio Excel DSP 16 Driver Version " VERSION);
1320 MODULE_LICENSE("GPL");
1321
1322 static int __init do_init_aedsp16(void) {
1323         printk("Audio Excel DSP 16 init driver Copyright (C) Riccardo Facchetti 1995-98\n");
1324         if (io == -1 || dma == -1 || irq == -1) {
1325                 printk(KERN_INFO "aedsp16: I/O, IRQ and DMA are mandatory\n");
1326                 return -EINVAL;
1327         }
1328
1329         ae_config.base_io = io;
1330         ae_config.irq = irq;
1331         ae_config.dma = dma;
1332
1333         ae_config.mss_base = mss_base;
1334         ae_config.mpu_base = mpu_base;
1335         ae_config.mpu_irq = mpu_irq;
1336
1337         if (init_aedsp16() == FALSE) {
1338                 printk(KERN_ERR "aedsp16: initialization failed\n");
1339                 /*
1340                  * XXX
1341                  * What error should we return here ?
1342                  */
1343                 return -EINVAL;
1344         }
1345         return 0;
1346 }
1347
1348 static void __exit cleanup_aedsp16(void) {
1349         uninit_aedsp16();
1350 }
1351
1352 module_init(do_init_aedsp16);
1353 module_exit(cleanup_aedsp16);
1354
1355 #ifndef MODULE
1356 static int __init setup_aedsp16(char *str)
1357 {
1358         /* io, irq, dma, mss_io, mpu_io, mpu_irq */
1359         int ints[7];
1360         
1361         str = get_options(str, ARRAY_SIZE(ints), ints);
1362
1363         io       = ints[1];
1364         irq      = ints[2];
1365         dma      = ints[3];
1366         mss_base = ints[4];
1367         mpu_base = ints[5];
1368         mpu_irq  = ints[6];
1369         return 1;
1370 }
1371
1372 __setup("aedsp16=", setup_aedsp16);
1373 #endif