OpenCloudOS-Kernel/sound/oss/mad16.c

1098 lines
23 KiB
C
Raw Normal View History

/*
* Copyright (C) by Hannu Savolainen 1993-1997
*
* mad16.c
*
* Initialization code for OPTi MAD16 compatible audio chips. Including
*
* OPTi 82C928 MAD16 (replaced by C929)
* OAK OTI-601D Mozart
* OAK OTI-605 Mozart (later version with MPU401 Midi)
* OPTi 82C929 MAD16 Pro
* OPTi 82C930
* OPTi 82C924
*
* These audio interface chips don't produce sound themselves. They just
* connect some other components (OPL-[234] and a WSS compatible codec)
* to the PC bus and perform I/O, DMA and IRQ address decoding. There is
* also a UART for the MPU-401 mode (not 82C928/Mozart).
* The Mozart chip appears to be compatible with the 82C928, although later
* issues of the card, using the OTI-605 chip, have an MPU-401 compatible Midi
* port. This port is configured differently to that of the OPTi audio chips.
*
* Changes
*
* Alan Cox Clean up, added module selections.
*
* A. Wik Added support for Opti924 PnP.
* Improved debugging support. 16-May-1998
* Fixed bug. 16-Jun-1998
*
* Torsten Duwe Made Opti924 PnP support non-destructive
* 23-Dec-1998
*
* Paul Grayson Added support for Midi on later Mozart cards.
* 25-Nov-1999
* Christoph Hellwig Adapted to module_init/module_exit.
* Arnaldo C. de Melo got rid of attach_uart401 21-Sep-2000
*
* Pavel Rabel Clean up Nov-2000
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/gameport.h>
#include <linux/spinlock.h>
#include "sound_config.h"
#include "ad1848.h"
#include "sb.h"
#include "mpu401.h"
static int mad16_conf;
static int mad16_cdsel;
static struct gameport *gameport;
static DEFINE_SPINLOCK(lock);
#define C928 1
#define MOZART 2
#define C929 3
#define C930 4
#define C924 5
/*
* Registers
*
* The MAD16 occupies I/O ports 0xf8d to 0xf93 (fixed locations).
* All ports are inactive by default. They can be activated by
* writing 0xE2 or 0xE3 to the password register. The password is valid
* only until the next I/O read or write.
*
* 82C930 uses 0xE4 as the password and indirect addressing to access
* the config registers.
*/
#define MC0_PORT 0xf8c /* Dummy port */
#define MC1_PORT 0xf8d /* SB address, CD-ROM interface type, joystick */
#define MC2_PORT 0xf8e /* CD-ROM address, IRQ, DMA, plus OPL4 bit */
#define MC3_PORT 0xf8f
#define PASSWD_REG 0xf8f
#define MC4_PORT 0xf90
#define MC5_PORT 0xf91
#define MC6_PORT 0xf92
#define MC7_PORT 0xf93
#define MC8_PORT 0xf94
#define MC9_PORT 0xf95
#define MC10_PORT 0xf96
#define MC11_PORT 0xf97
#define MC12_PORT 0xf98
static int board_type = C928;
static int *mad16_osp;
static int c931_detected; /* minor differences from C930 */
static char c924pnp; /* " " " C924 */
static int debug; /* debugging output */
#ifdef DDB
#undef DDB
#endif
#define DDB(x) do {if (debug) x;} while (0)
static unsigned char mad_read(int port)
{
unsigned long flags;
unsigned char tmp;
spin_lock_irqsave(&lock,flags);
switch (board_type) /* Output password */
{
case C928:
case MOZART:
outb((0xE2), PASSWD_REG);
break;
case C929:
outb((0xE3), PASSWD_REG);
break;
case C930:
/* outb(( 0xE4), PASSWD_REG); */
break;
case C924:
/* the c924 has its ports relocated by -128 if
PnP is enabled -aw */
if (!c924pnp)
outb((0xE5), PASSWD_REG); else
outb((0xE5), PASSWD_REG - 0x80);
break;
}
if (board_type == C930)
{
outb((port - MC0_PORT), 0xe0e); /* Write to index reg */
tmp = inb(0xe0f); /* Read from data reg */
}
else
if (!c924pnp)
tmp = inb(port); else
tmp = inb(port-0x80);
spin_unlock_irqrestore(&lock,flags);
return tmp;
}
static void mad_write(int port, int value)
{
unsigned long flags;
spin_lock_irqsave(&lock,flags);
switch (board_type) /* Output password */
{
case C928:
case MOZART:
outb((0xE2), PASSWD_REG);
break;
case C929:
outb((0xE3), PASSWD_REG);
break;
case C930:
/* outb(( 0xE4), PASSWD_REG); */
break;
case C924:
if (!c924pnp)
outb((0xE5), PASSWD_REG); else
outb((0xE5), PASSWD_REG - 0x80);
break;
}
if (board_type == C930)
{
outb((port - MC0_PORT), 0xe0e); /* Write to index reg */
outb(((unsigned char) (value & 0xff)), 0xe0f);
}
else
if (!c924pnp)
outb(((unsigned char) (value & 0xff)), port); else
outb(((unsigned char) (value & 0xff)), port-0x80);
spin_unlock_irqrestore(&lock,flags);
}
static int __init detect_c930(void)
{
unsigned char tmp = mad_read(MC1_PORT);
if ((tmp & 0x06) != 0x06)
{
DDB(printk("Wrong C930 signature (%x)\n", tmp));
/* return 0; */
}
mad_write(MC1_PORT, 0);
if (mad_read(MC1_PORT) != 0x06)
{
DDB(printk("Wrong C930 signature2 (%x)\n", tmp));
/* return 0; */
}
mad_write(MC1_PORT, tmp); /* Restore bits */
mad_write(MC7_PORT, 0);
if ((tmp = mad_read(MC7_PORT)) != 0)
{
DDB(printk("MC7 not writable (%x)\n", tmp));
return 0;
}
mad_write(MC7_PORT, 0xcb);
if ((tmp = mad_read(MC7_PORT)) != 0xcb)
{
DDB(printk("MC7 not writable2 (%x)\n", tmp));
return 0;
}
tmp = mad_read(MC0_PORT+18);
if (tmp == 0xff || tmp == 0x00)
return 1;
/* We probably have a C931 */
DDB(printk("Detected C931 config=0x%02x\n", tmp));
c931_detected = 1;
/*
* We cannot configure the chip if it is in PnP mode.
* If we have a CSN assigned (bit 8 in MC13) we first try
* a software reset, then a software power off, finally
* Clearing PnP mode. The last option is not
* Bit 8 in MC13
*/
if ((mad_read(MC0_PORT+13) & 0x80) == 0)
return 1;
/* Software reset */
mad_write(MC9_PORT, 0x02);
mad_write(MC9_PORT, 0x00);
if ((mad_read(MC0_PORT+13) & 0x80) == 0)
return 1;
/* Power off, and on again */
mad_write(MC9_PORT, 0xc2);
mad_write(MC9_PORT, 0xc0);
if ((mad_read(MC0_PORT+13) & 0x80) == 0)
return 1;
#if 0
/* Force off PnP mode. This is not recommended because
* the PnP bios will not recognize the chip on the next
* warm boot and may assignd different resources to other
* PnP/PCI cards.
*/
mad_write(MC0_PORT+17, 0x04);
#endif
return 1;
}
static int __init detect_mad16(void)
{
unsigned char tmp, tmp2, bit;
int i, port;
/*
* Check that reading a register doesn't return bus float (0xff)
* when the card is accessed using password. This may fail in case
* the card is in low power mode. Normally at least the power saving
* mode bit should be 0.
*/
if ((tmp = mad_read(MC1_PORT)) == 0xff)
{
DDB(printk("MC1_PORT returned 0xff\n"));
return 0;
}
for (i = 0xf8d; i <= 0xf98; i++)
if (!c924pnp)
DDB(printk("Port %0x (init value) = %0x\n", i, mad_read(i)));
else
DDB(printk("Port %0x (init value) = %0x\n", i-0x80, mad_read(i)));
if (board_type == C930)
return detect_c930();
/*
* Now check that the gate is closed on first I/O after writing
* the password. (This is how a MAD16 compatible card works).
*/
if ((tmp2 = inb(MC1_PORT)) == tmp) /* It didn't close */
{
DDB(printk("MC1_PORT didn't close after read (0x%02x)\n", tmp2));
return 0;
}
bit = (c924pnp) ? 0x20 : 0x80;
port = (c924pnp) ? MC2_PORT : MC1_PORT;
tmp = mad_read(port);
mad_write(port, tmp ^ bit); /* Toggle a bit */
if ((tmp2 = mad_read(port)) != (tmp ^ bit)) /* Compare the bit */
{
mad_write(port, tmp); /* Restore */
DDB(printk("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2));
return 0;
}
mad_write(port, tmp); /* Restore */
return 1; /* Bingo */
}
static int __init wss_init(struct address_info *hw_config)
{
/*
* Check if the IO port returns valid signature. The original MS Sound
* system returns 0x04 while some cards (AudioTrix Pro for example)
* return 0x00.
*/
if ((inb(hw_config->io_base + 3) & 0x3f) != 0x04 &&
(inb(hw_config->io_base + 3) & 0x3f) != 0x00)
{
DDB(printk("No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, inb(hw_config->io_base + 3)));
return 0;
}
/*
* Check that DMA0 is not in use with a 8 bit board.
*/
if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80)
{
printk("MSS: Can't use DMA0 with a 8 bit card/slot\n");
return 0;
}
if (hw_config->irq > 9 && inb(hw_config->io_base + 3) & 0x80)
printk(KERN_ERR "MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq);
return 1;
}
static void __init init_c930(struct address_info *hw_config, int base)
{
unsigned char cfg = 0;
cfg |= (0x0f & mad16_conf);
if(c931_detected)
{
/* Bit 0 has reversd meaning. Bits 1 and 2 sese
reversed on write.
Support only IDE cdrom. IDE port programmed
somewhere else. */
cfg = (cfg & 0x09) ^ 0x07;
}
cfg |= base << 4;
mad_write(MC1_PORT, cfg);
/* MC2 is CD configuration. Don't touch it. */
mad_write(MC3_PORT, 0); /* Disable SB mode IRQ and DMA */
/* bit 2 of MC4 reverses it's meaning between the C930
and the C931. */
cfg = c931_detected ? 0x04 : 0x00;
if(mad16_cdsel & 0x20)
mad_write(MC4_PORT, 0x62|cfg); /* opl4 */
else
mad_write(MC4_PORT, 0x52|cfg); /* opl3 */
mad_write(MC5_PORT, 0x3C); /* Init it into mode2 */
mad_write(MC6_PORT, 0x02); /* Enable WSS, Disable MPU and SB */
mad_write(MC7_PORT, 0xCB);
mad_write(MC10_PORT, 0x11);
}
static int __init chip_detect(void)
{
int i;
/*
* Then try to detect with the old password
*/
board_type = C924;
DDB(printk("Detect using password = 0xE5\n"));
if (detect_mad16()) {
return 1;
}
board_type = C928;
DDB(printk("Detect using password = 0xE2\n"));
if (detect_mad16())
{
unsigned char model;
if (((model = mad_read(MC3_PORT)) & 0x03) == 0x03) {
DDB(printk("mad16.c: Mozart detected\n"));
board_type = MOZART;
} else {
DDB(printk("mad16.c: 82C928 detected???\n"));
board_type = C928;
}
return 1;
}
board_type = C929;
DDB(printk("Detect using password = 0xE3\n"));
if (detect_mad16())
{
DDB(printk("mad16.c: 82C929 detected\n"));
return 1;
}
if (inb(PASSWD_REG) != 0xff)
return 0;
/*
* First relocate MC# registers to 0xe0e/0xe0f, disable password
*/
outb((0xE4), PASSWD_REG);
outb((0x80), PASSWD_REG);
board_type = C930;
DDB(printk("Detect using password = 0xE4\n"));
for (i = 0xf8d; i <= 0xf93; i++)
DDB(printk("port %03x = %02x\n", i, mad_read(i)));
if(detect_mad16()) {
DDB(printk("mad16.c: 82C930 detected\n"));
return 1;
}
/* The C931 has the password reg at F8D */
outb((0xE4), 0xF8D);
outb((0x80), 0xF8D);
DDB(printk("Detect using password = 0xE4 for C931\n"));
if (detect_mad16()) {
return 1;
}
board_type = C924;
c924pnp++;
DDB(printk("Detect using password = 0xE5 (again), port offset -0x80\n"));
if (detect_mad16()) {
DDB(printk("mad16.c: 82C924 PnP detected\n"));
return 1;
}
c924pnp=0;
return 0;
}
static int __init probe_mad16(struct address_info *hw_config)
{
int i;
unsigned char tmp;
unsigned char cs4231_mode = 0;
int ad_flags = 0;
signed char bits;
static char dma_bits[4] = {
1, 2, 0, 3
};
int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3;
int dma = hw_config->dma, dma2 = hw_config->dma2;
unsigned char dma2_bit = 0;
int base;
struct resource *ports;
mad16_osp = hw_config->osp;
switch (hw_config->io_base) {
case 0x530:
base = 0;
break;
case 0xe80:
base = 1;
break;
case 0xf40:
base = 2;
break;
case 0x604:
base = 3;
break;
default:
printk(KERN_ERR "MAD16/Mozart: Bad WSS base address 0x%x\n", hw_config->io_base);
return 0;
}
if (dma != 0 && dma != 1 && dma != 3) {
printk(KERN_ERR "MSS: Bad DMA %d\n", dma);
return 0;
}
/*
* Check that all ports return 0xff (bus float) when no password
* is written to the password register.
*/
DDB(printk("--- Detecting MAD16 / Mozart ---\n"));
if (!chip_detect())
return 0;
switch (hw_config->irq) {
case 7:
bits = 8;
break;
case 9:
bits = 0x10;
break;
case 10:
bits = 0x18;
break;
case 12:
bits = 0x20;
break;
case 5: /* Also IRQ5 is possible on C930 */
if (board_type == C930 || c924pnp) {
bits = 0x28;
break;
}
default:
printk(KERN_ERR "MAD16/Mozart: Bad IRQ %d\n", hw_config->irq);
return 0;
}
ports = request_region(hw_config->io_base + 4, 4, "ad1848");
if (!ports) {
printk(KERN_ERR "MSS: I/O port conflict\n");
return 0;
}
if (!request_region(hw_config->io_base, 4, "mad16 WSS config")) {
release_region(hw_config->io_base + 4, 4);
printk(KERN_ERR "MSS: I/O port conflict\n");
return 0;
}
if (board_type == C930) {
init_c930(hw_config, base);
goto got_it;
}
for (i = 0xf8d; i <= 0xf93; i++) {
if (!c924pnp)
DDB(printk("port %03x = %02x\n", i, mad_read(i)));
else
DDB(printk("port %03x = %02x\n", i-0x80, mad_read(i)));
}
/*
* Set the WSS address
*/
tmp = (mad_read(MC1_PORT) & 0x0f) | 0x80; /* Enable WSS, Disable SB */
tmp |= base << 4; /* WSS port select bits */
/*
* Set optional CD-ROM and joystick settings.
*/
tmp &= ~0x0f;
tmp |= (mad16_conf & 0x0f); /* CD-ROM and joystick bits */
mad_write(MC1_PORT, tmp);
tmp = mad16_cdsel;
mad_write(MC2_PORT, tmp);
mad_write(MC3_PORT, 0xf0); /* Disable SB */
if (board_type == C924) /* Specific C924 init values */
{
mad_write(MC4_PORT, 0xA0);
mad_write(MC5_PORT, 0x05);
mad_write(MC6_PORT, 0x03);
}
if (!ad1848_detect(ports, &ad_flags, mad16_osp))
goto fail;
if (ad_flags & (AD_F_CS4231 | AD_F_CS4248))
cs4231_mode = 0x02; /* CS4248/CS4231 sync delay switch */
if (board_type == C929)
{
mad_write(MC4_PORT, 0xa2);
mad_write(MC5_PORT, 0xA5 | cs4231_mode);
mad_write(MC6_PORT, 0x03); /* Disable MPU401 */
}
else
{
mad_write(MC4_PORT, 0x02);
mad_write(MC5_PORT, 0x30 | cs4231_mode);
}
for (i = 0xf8d; i <= 0xf93; i++) {
if (!c924pnp)
DDB(printk("port %03x after init = %02x\n", i, mad_read(i)));
else
DDB(printk("port %03x after init = %02x\n", i-0x80, mad_read(i)));
}
got_it:
ad_flags = 0;
if (!ad1848_detect(ports, &ad_flags, mad16_osp))
goto fail;
if (!wss_init(hw_config))
goto fail;
/*
* Set the IRQ and DMA addresses.
*/
outb((bits | 0x40), config_port);
if ((inb(version_port) & 0x40) == 0)
printk(KERN_ERR "[IRQ Conflict?]\n");
/*
* Handle the capture DMA channel
*/
if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma)
{
if (!((dma == 0 && dma2 == 1) ||
(dma == 1 && dma2 == 0) ||
(dma == 3 && dma2 == 0)))
{ /* Unsupported combination. Try to swap channels */
int tmp = dma;
dma = dma2;
dma2 = tmp;
}
if ((dma == 0 && dma2 == 1) || (dma == 1 && dma2 == 0) ||
(dma == 3 && dma2 == 0))
{
dma2_bit = 0x04; /* Enable capture DMA */
}
else
{
printk("MAD16: Invalid capture DMA\n");
dma2 = dma;
}
}
else dma2 = dma;
outb((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */
hw_config->slots[0] = ad1848_init("mad16 WSS", ports,
hw_config->irq,
dma,
dma2, 0,
hw_config->osp,
THIS_MODULE);
return 1;
fail:
release_region(hw_config->io_base + 4, 4);
release_region(hw_config->io_base, 4);
return 0;
}
static int __init probe_mad16_mpu(struct address_info *hw_config)
{
unsigned char tmp;
if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */
{
#ifdef CONFIG_MAD16_OLDCARD
tmp = mad_read(MC3_PORT);
/*
* MAD16 SB base is defined by the WSS base. It cannot be changed
* alone.
* Ignore configured I/O base. Use the active setting.
*/
if (mad_read(MC1_PORT) & 0x20)
hw_config->io_base = 0x240;
else
hw_config->io_base = 0x220;
switch (hw_config->irq)
{
case 5:
tmp = (tmp & 0x3f) | 0x80;
break;
case 7:
tmp = (tmp & 0x3f);
break;
case 11:
tmp = (tmp & 0x3f) | 0x40;
break;
default:
printk(KERN_ERR "mad16/Mozart: Invalid MIDI IRQ\n");
return 0;
}
mad_write(MC3_PORT, tmp | 0x04);
hw_config->driver_use_1 = SB_MIDI_ONLY;
if (!request_region(hw_config->io_base, 16, "soundblaster"))
return 0;
if (!sb_dsp_detect(hw_config, 0, 0, NULL)) {
release_region(hw_config->io_base, 16);
return 0;
}
if (mad_read(MC1_PORT) & 0x20)
hw_config->io_base = 0x240;
else
hw_config->io_base = 0x220;
hw_config->name = "Mad16/Mozart";
sb_dsp_init(hw_config, THIS_MODULE);
return 1;
#else
/* assuming all later Mozart cards are identified as
* either 82C928 or Mozart. If so, following code attempts
* to set MPU register. TODO - add probing
*/
tmp = mad_read(MC8_PORT);
switch (hw_config->irq)
{
case 5:
tmp |= 0x08;
break;
case 7:
tmp |= 0x10;
break;
case 9:
tmp |= 0x18;
break;
case 10:
tmp |= 0x20;
break;
case 11:
tmp |= 0x28;
break;
default:
printk(KERN_ERR "mad16/MOZART: invalid mpu_irq\n");
return 0;
}
switch (hw_config->io_base)
{
case 0x300:
tmp |= 0x01;
break;
case 0x310:
tmp |= 0x03;
break;
case 0x320:
tmp |= 0x05;
break;
case 0x330:
tmp |= 0x07;
break;
default:
printk(KERN_ERR "mad16/MOZART: invalid mpu_io\n");
return 0;
}
mad_write(MC8_PORT, tmp); /* write MPU port parameters */
goto probe_401;
#endif
}
tmp = mad_read(MC6_PORT) & 0x83;
tmp |= 0x80; /* MPU-401 enable */
/* Set the MPU base bits */
switch (hw_config->io_base)
{
case 0x300:
tmp |= 0x60;
break;
case 0x310:
tmp |= 0x40;
break;
case 0x320:
tmp |= 0x20;
break;
case 0x330:
tmp |= 0x00;
break;
default:
printk(KERN_ERR "MAD16: Invalid MIDI port 0x%x\n", hw_config->io_base);
return 0;
}
/* Set the MPU IRQ bits */
switch (hw_config->irq)
{
case 5:
tmp |= 0x10;
break;
case 7:
tmp |= 0x18;
break;
case 9:
tmp |= 0x00;
break;
case 10:
tmp |= 0x08;
break;
default:
printk(KERN_ERR "MAD16: Invalid MIDI IRQ %d\n", hw_config->irq);
break;
}
mad_write(MC6_PORT, tmp); /* Write MPU401 config */
#ifndef CONFIG_MAD16_OLDCARD
probe_401:
#endif
hw_config->driver_use_1 = SB_MIDI_ONLY;
hw_config->name = "Mad16/Mozart";
return probe_uart401(hw_config, THIS_MODULE);
}
static void __exit unload_mad16(struct address_info *hw_config)
{
ad1848_unload(hw_config->io_base + 4,
hw_config->irq,
hw_config->dma,
hw_config->dma2, 0);
release_region(hw_config->io_base, 4);
sound_unload_audiodev(hw_config->slots[0]);
}
static void __exit unload_mad16_mpu(struct address_info *hw_config)
{
#ifdef CONFIG_MAD16_OLDCARD
if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */
{
sb_dsp_unload(hw_config, 0);
return;
}
#endif
unload_uart401(hw_config);
}
static struct address_info cfg;
static struct address_info cfg_mpu;
static int found_mpu;
static int __initdata mpu_io = 0;
static int __initdata mpu_irq = 0;
static int __initdata io = -1;
static int __initdata dma = -1;
static int __initdata dma16 = -1; /* Set this for modules that need it */
static int __initdata irq = -1;
static int __initdata cdtype = 0;
static int __initdata cdirq = 0;
static int __initdata cdport = 0x340;
static int __initdata cddma = -1;
static int __initdata opl4 = 0;
static int __initdata joystick = 0;
module_param(mpu_io, int, 0);
module_param(mpu_irq, int, 0);
module_param(io, int, 0);
module_param(dma, int, 0);
module_param(dma16, int, 0);
module_param(irq, int, 0);
module_param(cdtype, int, 0);
module_param(cdirq, int, 0);
module_param(cdport, int, 0);
module_param(cddma, int, 0);
module_param(opl4, int, 0);
module_param(joystick, bool, 0);
module_param(debug, bool, 0644);
static int __initdata dma_map[2][8] =
{
{0x03, -1, -1, -1, -1, 0x00, 0x01, 0x02},
{0x03, -1, 0x01, 0x00, -1, -1, -1, -1}
};
static int __initdata irq_map[16] =
{
0x00, -1, -1, 0x0A,
-1, 0x04, -1, 0x08,
-1, 0x10, 0x14, 0x18,
-1, -1, -1, -1
};
static int __devinit mad16_register_gameport(int io_port)
{
if (!request_region(io_port, 1, "mad16 gameport")) {
printk(KERN_ERR "mad16: gameport address 0x%#x already in use\n", io_port);
return -EBUSY;
}
gameport = gameport_allocate_port();
if (!gameport) {
printk(KERN_ERR "mad16: can not allocate memory for gameport\n");
release_region(io_port, 1);
return -ENOMEM;
}
gameport_set_name(gameport, "MAD16 Gameport");
gameport_set_phys(gameport, "isa%04x/gameport0", io_port);
gameport->io = io_port;
gameport_register_port(gameport);
return 0;
}
static int __devinit init_mad16(void)
{
int dmatype = 0;
printk(KERN_INFO "MAD16 audio driver Copyright (C) by Hannu Savolainen 1993-1996\n");
printk(KERN_INFO "CDROM ");
switch (cdtype)
{
case 0x00:
printk("Disabled");
cdirq = 0;
break;
case 0x02:
printk("Sony CDU31A");
dmatype = 1;
if(cddma == -1) cddma = 3;
break;
case 0x04:
printk("Mitsumi");
dmatype = 0;
if(cddma == -1) cddma = 5;
break;
case 0x06:
printk("Panasonic Lasermate");
dmatype = 1;
if(cddma == -1) cddma = 3;
break;
case 0x08:
printk("Secondary IDE");
dmatype = 0;
if(cddma == -1) cddma = 5;
break;
case 0x0A:
printk("Primary IDE");
dmatype = 0;
if(cddma == -1) cddma = 5;
break;
default:
printk("\n");
printk(KERN_ERR "Invalid CDROM type\n");
return -EINVAL;
}
/*
* Build the config words
*/
mad16_conf = (joystick ^ 1) | cdtype;
mad16_cdsel = 0;
if (opl4)
mad16_cdsel |= 0x20;
if(cdtype){
if (cddma > 7 || cddma < 0 || dma_map[dmatype][cddma] == -1)
{
printk("\n");
printk(KERN_ERR "Invalid CDROM DMA\n");
return -EINVAL;
}
if (cddma)
printk(", DMA %d", cddma);
else
printk(", no DMA");
if (!cdirq)
printk(", no IRQ");
else if (cdirq < 0 || cdirq > 15 || irq_map[cdirq] == -1)
{
printk(", invalid IRQ (disabling)");
cdirq = 0;
}
else printk(", IRQ %d", cdirq);
mad16_cdsel |= dma_map[dmatype][cddma];
if (cdtype < 0x08)
{
switch (cdport)
{
case 0x340:
mad16_cdsel |= 0x00;
break;
case 0x330:
mad16_cdsel |= 0x40;
break;
case 0x360:
mad16_cdsel |= 0x80;
break;
case 0x320:
mad16_cdsel |= 0xC0;
break;
default:
printk(KERN_ERR "Unknown CDROM I/O base %d\n", cdport);
return -EINVAL;
}
}
mad16_cdsel |= irq_map[cdirq];
}
printk(".\n");
cfg.io_base = io;
cfg.irq = irq;
cfg.dma = dma;
cfg.dma2 = dma16;
if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) {
printk(KERN_ERR "I/O, DMA and irq are mandatory\n");
return -EINVAL;
}
if (!request_region(MC0_PORT, 12, "mad16"))
return -EBUSY;
if (!probe_mad16(&cfg)) {
release_region(MC0_PORT, 12);
return -ENODEV;
}
cfg_mpu.io_base = mpu_io;
cfg_mpu.irq = mpu_irq;
found_mpu = probe_mad16_mpu(&cfg_mpu);
if (joystick)
mad16_register_gameport(0x201);
return 0;
}
static void __exit cleanup_mad16(void)
{
if (found_mpu)
unload_mad16_mpu(&cfg_mpu);
if (gameport) {
/* the gameport was initialized so we must free it up */
gameport_unregister_port(gameport);
gameport = NULL;
release_region(0x201, 1);
}
unload_mad16(&cfg);
release_region(MC0_PORT, 12);
}
module_init(init_mad16);
module_exit(cleanup_mad16);
#ifndef MODULE
static int __init setup_mad16(char *str)
{
/* io, irq */
int ints[8];
str = get_options(str, ARRAY_SIZE(ints), ints);
io = ints[1];
irq = ints[2];
dma = ints[3];
dma16 = ints[4];
mpu_io = ints[5];
mpu_irq = ints[6];
joystick = ints[7];
return 1;
}
__setup("mad16=", setup_mad16);
#endif
MODULE_LICENSE("GPL");