linux/sound/oss/aedsp16.c
<<
>>
Prefs
   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
 412static int      soft_cfg __initdata = 0;        /* bitmapped config */
 413static int      soft_cfg_mss __initdata = 0;    /* bitmapped mss config */
 414static int      ver[CARDVERDIGITS] __initdata = {0, 0}; /* DSP Ver:
 415                                                   hi->ver[0] lo->ver[1] */
 416
 417#if defined(CONFIG_SC6600)
 418static 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 */
 424struct  d_hcfg {
 425        int iobase;
 426        int joystick;
 427        int mpubase;
 428        int wssbase;
 429        int cdrom;
 430        int cdrombase;
 431};
 432
 433static struct d_hcfg decoded_hcfg __initdata = {0, };
 434
 435#endif /* CONFIG_SC6600 */
 436
 437/* orVals contain the values to be or'ed                                */
 438struct orVals {
 439        int     val;            /* irq|mirq|dma                         */
 440        int     or;             /* soft_cfg |= TheStruct.or             */
 441};
 442
 443/* aedsp16_info contain the audio card configuration                  */
 444struct 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             */
 458static 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         */
 468static 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        */
 477static struct orVals orDMA[] __initdata = {
 478        {0x00, 0x01},
 479        {0x01, 0x02},
 480        {0x03, 0x03},
 481        {0x00, 0x00}
 482};
 483
 484static 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 */
 497static char     DSPCopyright[CARDNAMELEN + 1] __initdata = {0, };
 498static char     DSPVersion[CARDVERLEN + 1] __initdata = {0, };
 499
 500static 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
 523static 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
 541static int __init aedsp16_test_dsp(int port)
 542{
 543        return ((aedsp16_read(port) == 0xaa) ? TRUE : FALSE);
 544}
 545
 546static 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
 567static 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)
 595void __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
 605static 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
 649static 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
 674static 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
 709static 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
 743static 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
 797static 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
 809static 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
 834static 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
 923static 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
 938static 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
 969static 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
1005static 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
1029static 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
1130static 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
1150static 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
1159static 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
1191static 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
1205static 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
1232static 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
1247static 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
1289static 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
1299static int __initdata io = -1;
1300static int __initdata irq = -1;
1301static int __initdata dma = -1;
1302static int __initdata mpu_irq = -1;
1303static int __initdata mss_base = -1;
1304static int __initdata mpu_base = -1;
1305
1306module_param(io, int, 0);
1307MODULE_PARM_DESC(io, "I/O base address (0x220 0x240)");
1308module_param(irq, int, 0);
1309MODULE_PARM_DESC(irq, "IRQ line (5 7 9 10 11)");
1310module_param(dma, int, 0);
1311MODULE_PARM_DESC(dma, "dma line (0 1 3)");
1312module_param(mpu_irq, int, 0);
1313MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ line (5 7 9 10 0)");
1314module_param(mss_base, int, 0);
1315MODULE_PARM_DESC(mss_base, "MSS emulation I/O base address (0x530 0xE80)");
1316module_param(mpu_base, int, 0);
1317MODULE_PARM_DESC(mpu_base,"MPU-401 I/O base address (0x300 0x310 0x320 0x330)");
1318MODULE_AUTHOR("Riccardo Facchetti <fizban@tin.it>");
1319MODULE_DESCRIPTION("Audio Excel DSP 16 Driver Version " VERSION);
1320MODULE_LICENSE("GPL");
1321
1322static 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
1348static void __exit cleanup_aedsp16(void) {
1349        uninit_aedsp16();
1350}
1351
1352module_init(do_init_aedsp16);
1353module_exit(cleanup_aedsp16);
1354
1355#ifndef MODULE
1356static 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
1374