Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
aedsp16.c
Go to the documentation of this file.
1 /*
2  sound/oss/aedsp16.c
3 
4  Audio Excel DSP 16 software configuration routines
5  Copyright (C) 1995,1996,1997,1998 Riccardo Facchetti ([email protected])
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 <[email protected]>
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 <[email protected]> - 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 <[email protected]>. 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 = {
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)) {
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)) {
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 <[email protected]>");
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