#include "sb.h"
#include "mpu401.h"
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK 1
+#endif
+
static int mad16_conf;
static int mad16_cdsel;
-static struct gameport gameport;
-static spinlock_t lock=SPIN_LOCK_UNLOCKED;
-static int already_initialized;
+static DEFINE_SPINLOCK(lock);
#define C928 1
#define MOZART 2
static int __init wss_init(struct address_info *hw_config)
{
- int ad_flags = 0;
-
- /*
- * Verify the WSS parameters
- */
-
- if (check_region(hw_config->io_base, 8))
- {
- printk(KERN_ERR "MSS: I/O port conflict\n");
- return 0;
- }
- if (!ad1848_detect(hw_config->io_base + 4, &ad_flags, mad16_osp))
- return 0;
/*
* Check if the IO port returns valid signature. The original MS Sound
* system returns 0x04 while some cards (AudioTrix Pro for example)
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;
}
- if (hw_config->irq > 11)
- {
- printk(KERN_ERR "MSS: Bad IRQ %d\n", hw_config->irq);
- return 0;
- }
- if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3)
- {
- printk(KERN_ERR "MSS: Bad DMA %d\n", hw_config->dma);
- 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 > 7 && hw_config->irq != 9 && inb(hw_config->io_base + 3) & 0x80)
+ 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 int __init init_c930(struct address_info *hw_config)
+static void __init init_c930(struct address_info *hw_config, int base)
{
unsigned char cfg = 0;
somewhere else. */
cfg = (cfg & 0x09) ^ 0x07;
}
-
- switch (hw_config->io_base)
- {
- case 0x530:
- cfg |= 0x00;
- break;
- case 0xe80:
- cfg |= 0x10;
- break;
- case 0xf40:
- cfg |= 0x20;
- break;
- case 0x604:
- cfg |= 0x30;
- break;
- default:
- printk(KERN_ERR "MAD16: Invalid codec port %x\n", hw_config->io_base);
- return 0;
- }
+ cfg |= base << 4;
mad_write(MC1_PORT, cfg);
/* MC2 is CD configuration. Don't touch it. */
mad_write(MC6_PORT, 0x02); /* Enable WSS, Disable MPU and SB */
mad_write(MC7_PORT, 0xCB);
mad_write(MC10_PORT, 0x11);
-
- return wss_init(hw_config);
}
static int __init chip_detect(void)
static int __init probe_mad16(struct address_info *hw_config)
{
int i;
- static int valid_ports[] =
- {
- 0x530, 0xe80, 0xf40, 0x604
- };
unsigned char tmp;
unsigned char cs4231_mode = 0;
int ad_flags = 0;
- if (already_initialized)
- return 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.
if (!chip_detect())
return 0;
- if (board_type == C930)
- return init_c930(hw_config);
+ 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)
*/
tmp = (mad_read(MC1_PORT) & 0x0f) | 0x80; /* Enable WSS, Disable SB */
-
- for (i = 0; i < 5; i++)
- {
- if (i > 3) /* Not a valid port */
- {
- printk(KERN_ERR "MAD16/Mozart: Bad WSS base address 0x%x\n", hw_config->io_base);
- return 0;
- }
- if (valid_ports[i] == hw_config->io_base)
- {
- tmp |= i << 4; /* WSS port select bits */
- break;
- }
- }
+ tmp |= base << 4; /* WSS port select bits */
/*
* Set optional CD-ROM and joystick settings.
mad_write(MC5_PORT, 0x05);
mad_write(MC6_PORT, 0x03);
}
- if (!ad1848_detect(hw_config->io_base + 4, &ad_flags, mad16_osp))
- return 0;
+ 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 */
else
DDB(printk("port %03x after init = %02x\n", i-0x80, mad_read(i)));
}
- wss_init(hw_config);
- return 1;
-}
+got_it:
+ ad_flags = 0;
+ if (!ad1848_detect(ports, &ad_flags, mad16_osp))
+ goto fail;
-static void __init attach_mad16(struct address_info *hw_config)
-{
-
- static signed char interrupt_bits[12] = {
- -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20
- };
- 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 ad_flags = 0, dma = hw_config->dma, dma2 = hw_config->dma2;
- unsigned char dma2_bit = 0;
-
- already_initialized = 1;
-
- if (!ad1848_detect(hw_config->io_base + 4, &ad_flags, mad16_osp))
- return;
+ if (!wss_init(hw_config))
+ goto fail;
/*
* Set the IRQ and DMA addresses.
*/
- if (board_type == C930 || c924pnp)
- interrupt_bits[5] = 0x28; /* Also IRQ5 is possible on C930 */
-
- bits = interrupt_bits[hw_config->irq];
- if (bits == -1)
- return;
-
outb((bits | 0x40), config_port);
if ((inb(version_port) & 0x40) == 0)
printk(KERN_ERR "[IRQ Conflict?]\n");
outb((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */
- hw_config->slots[0] = ad1848_init("mad16 WSS", hw_config->io_base + 4,
+ hw_config->slots[0] = ad1848_init("mad16 WSS", ports,
hw_config->irq,
dma,
dma2, 0,
hw_config->osp,
THIS_MODULE);
- request_region(hw_config->io_base, 4, "mad16 WSS config");
+ 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)
{
- static int mpu_attached;
unsigned char tmp;
- if (!already_initialized) /* The MSS port must be initialized first */
- return 0;
-
- if (mpu_attached) /* Don't let them call this twice */
- return 0;
- mpu_attached = 1;
-
if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */
{
mad_write(MC3_PORT, tmp | 0x04);
hw_config->driver_use_1 = SB_MIDI_ONLY;
- if (!sb_dsp_detect(hw_config, 0, 0, NULL))
+ 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;
static int __initdata opl4 = 0;
static int __initdata joystick = 0;
-MODULE_PARM(mpu_io, "i");
-MODULE_PARM(mpu_irq, "i");
-MODULE_PARM(io,"i");
-MODULE_PARM(dma,"i");
-MODULE_PARM(dma16,"i");
-MODULE_PARM(irq,"i");
-MODULE_PARM(cdtype,"i");
-MODULE_PARM(cdirq,"i");
-MODULE_PARM(cdport,"i");
-MODULE_PARM(cddma,"i");
-MODULE_PARM(opl4,"i");
-MODULE_PARM(joystick,"i");
-MODULE_PARM(debug,"i");
+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] =
{
-1, -1, -1, -1
};
-static int __init init_mad16(void)
+#ifdef SUPPORT_JOYSTICK
+
+static struct gameport *gameport;
+
+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 inline void mad16_unregister_gameport(void)
+{
+ if (gameport) {
+ /* the gameport was initialized so we must free it up */
+ gameport_unregister_port(gameport);
+ gameport = NULL;
+ release_region(0x201, 1);
+ }
+}
+#else
+static inline int mad16_register_gameport(int io_port) { return -ENOSYS; }
+static inline void mad16_unregister_gameport(void) { }
+#endif
+
+static int __devinit init_mad16(void)
{
int dmatype = 0;
printk(KERN_ERR "I/O, DMA and irq are mandatory\n");
return -EINVAL;
}
-
- if (!probe_mad16(&cfg))
+
+ 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;
- attach_mad16(&cfg);
-
found_mpu = probe_mad16_mpu(&cfg_mpu);
- if (joystick == 1) {
- /* register gameport */
- if (!request_region(0x201, 1, "mad16 gameport"))
- printk(KERN_ERR "mad16: gameport address 0x201 already in use\n");
- else {
- printk(KERN_ERR "mad16: gameport enabled at 0x201\n");
- gameport.io = 0x201;
- gameport_register_port(&gameport);
- }
- }
- else printk(KERN_ERR "mad16: gameport disabled.\n");
+ if (joystick)
+ mad16_register_gameport(0x201);
+
return 0;
}
{
if (found_mpu)
unload_mad16_mpu(&cfg_mpu);
- if (gameport.io) {
- /* the gameport was initialized so we must free it up */
- gameport_unregister_port(&gameport);
- gameport.io = 0;
- release_region(0x201, 1);
- }
+ mad16_unregister_gameport();
unload_mad16(&cfg);
+ release_region(MC0_PORT, 12);
}
module_init(init_mad16);