/*
- * sound/sscape.c
+ * sound/oss/sscape.c
*
* Low level driver for Ensoniq SoundScape
*
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
+#include <linux/mm.h>
#include <linux/spinlock.h>
#include "coproc.h"
return val;
}
+static void __sscape_write(int reg, int data)
+{
+ outb(reg, PORT(ODIE_ADDR));
+ outb(data, PORT(ODIE_DATA));
+}
+
static void sscape_write(struct sscape_info *devc, int reg, int data)
{
unsigned long flags;
spin_lock_irqsave(&devc->lock,flags);
- outb(reg, PORT(ODIE_ADDR));
- outb(data, PORT(ODIE_DATA));
+ __sscape_write(reg, data);
spin_unlock_irqrestore(&devc->lock,flags);
}
spin_lock_irqsave(&devc->lock,flags);
if (devc->dma_allocated)
{
- sscape_write(devc, GA_DMAA_REG, 0x20); /* DMA channel disabled */
+ __sscape_write(GA_DMAA_REG, 0x20); /* DMA channel disabled */
devc->dma_allocated = 0;
}
spin_unlock_irqrestore(&devc->lock,flags);
return 0;
}
-static int sscape_coproc_ioctl(void *dev_info, unsigned int cmd, caddr_t arg, int local)
+static int sscape_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg, int local)
{
copr_buffer *buf;
int err;
&adev_info
};
-static int sscape_detected;
+static struct resource *sscape_ports;
static int sscape_is_pnp;
-void __init attach_sscape(struct address_info *hw_config)
+static void __init attach_sscape(struct address_info *hw_config)
{
#ifndef SSCAPE_REGS
/*
int i, irq_bits = 0xff;
- if (sscape_detected != hw_config->io_base)
- return;
-
- request_region(devc->base + 2, 6, "SoundScape");
if (old_hardware)
{
valid_interrupts = valid_interrupts_old;
else
conf_printf("Ensoniq SoundScape", hw_config);
- for (i = 0; i < sizeof(valid_interrupts); i++)
+ for (i = 0; i < 4; i++)
{
if (hw_config->irq == valid_interrupts[i])
{
if (hw_config->irq > 15 || (regs[4] = irq_bits == 0xff))
{
printk(KERN_ERR "Invalid IRQ%d\n", hw_config->irq);
+ release_region(devc->base, 2);
+ release_region(devc->base + 2, 6);
+ if (sscape_is_pnp)
+ release_region(devc->codec, 2);
return;
}
if (!sscape_is_pnp) {
spin_lock_irqsave(&devc->lock,flags);
- for (i = 1; i < 10; i++)
- {
- switch (i)
- {
- case 1: /* Host interrupt enable */
- sscape_write(devc, i, 0xf0); /* All interrupts enabled */
- break;
-
- case 2: /* DMA A status/trigger register */
- case 3: /* DMA B status/trigger register */
- sscape_write(devc, i, 0x20); /* DMA channel disabled */
- break;
-
- case 4: /* Host interrupt config reg */
- sscape_write(devc, i, 0xf0 | (irq_bits << 2) | irq_bits);
- break;
-
- case 5: /* Don't destroy CD-ROM DMA config bits (0xc0) */
- sscape_write(devc, i, (regs[i] & 0x3f) | (sscape_read(devc, i) & 0xc0));
- break;
-
- case 6: /* CD-ROM config (WSS codec actually) */
- sscape_write(devc, i, regs[i]);
- break;
-
- case 9: /* Master control reg. Don't modify CR-ROM bits. Disable SB emul */
- sscape_write(devc, i, (sscape_read(devc, i) & 0xf0) | 0x08);
- break;
-
- default:
- sscape_write(devc, i, regs[i]);
- }
- }
+ /* Host interrupt enable */
+ sscape_write(devc, 1, 0xf0); /* All interrupts enabled */
+ /* DMA A status/trigger register */
+ sscape_write(devc, 2, 0x20); /* DMA channel disabled */
+ /* DMA B status/trigger register */
+ sscape_write(devc, 3, 0x20); /* DMA channel disabled */
+ /* Host interrupt config reg */
+ sscape_write(devc, 4, 0xf0 | (irq_bits << 2) | irq_bits);
+ /* Don't destroy CD-ROM DMA config bits (0xc0) */
+ sscape_write(devc, 5, (regs[5] & 0x3f) | (sscape_read(devc, 5) & 0xc0));
+ /* CD-ROM config (WSS codec actually) */
+ sscape_write(devc, 6, regs[6]);
+ sscape_write(devc, 7, regs[7]);
+ sscape_write(devc, 8, regs[8]);
+ /* Master control reg. Don't modify CR-ROM bits. Disable SB emul */
+ sscape_write(devc, 9, (sscape_read(devc, 9) & 0xf0) | 0x08);
spin_unlock_irqrestore(&devc->lock,flags);
}
#ifdef SSCAPE_DEBUG2
}
#endif
- if (probe_mpu401(hw_config))
+ if (probe_mpu401(hw_config, sscape_ports))
hw_config->always_detect = 1;
hw_config->name = "SoundScape";
DDB(printk("Entered Soundscape detect_ga(%x)\n", devc->base));
- if (check_region(devc->base, 8))
- return 0;
-
/*
* First check that the address register of "ODIE" is
* there and that it has exactly 4 writable bits.
unsigned i;
static char code_file_name[23] = "/sndscape/sndscape.cox";
- int sscape_sb_enable = 0;
int sscape_joystic_enable = 0x7f;
int sscape_mic_enable = 0;
int sscape_ext_midi = 0;
sscape_write( devc, 2, devc->ic_type == IC_ODIE ? 0x70 : 0x40);
sscape_write( devc, 3, ( devc -> dma << 4) | 0x80);
- if ( sscape_sb_enable )
- sscape_write (devc, 4, 0xF0 | (sb_irq << 2) | midi_irq);
- else
- sscape_write (devc, 4, 0xF0 | (midi_irq<<2) | midi_irq);
+ sscape_write (devc, 4, 0xF0 | (midi_irq<<2) | midi_irq);
i = 0x10; //sscape_read(devc, 9) & (devc->ic_type == IC_ODIE ? 0xf0 : 0xc0);
- if ( sscape_sb_enable )
- i |= devc->ic_type == IC_ODIE ? 0x05 : 0x07;
if (sscape_joystic_enable) i |= 8;
sscape_write (devc, 9, i);
sscape_write( devc, 9, i | 3 );
sscape_write( devc, 3, 0x40);
- if (check_region(0x228, 1)) {
- outb(0, 0x228);
- release_region(0x228,1);
+ if (request_region(0x228, 1, "sscape setup junk")) {
+ outb(0, 0x228);
+ release_region(0x228,1);
}
sscape_write( devc, 3, (devc -> dma << 4) | 0x80);
sscape_write( devc, 9, i );
DDB(printk("Entered detect_sscape_pnp(%x)\n", devc->base));
- if (check_region(devc->base, 8)) {
- printk(KERN_ERR "detect_sscape_pnp: port %x is not free\n", devc->base);
- return 0;
- }
-
- if (check_region(devc->codec, 2)) {
+ if (!request_region(devc->codec, 2, "sscape codec")) {
printk(KERN_ERR "detect_sscape_pnp: port %x is not free\n", devc->codec);
return 0;
}
- if ( (inb( devc -> base + 2) & 0x78) != 0) return 0;
+ if ((inb(devc->base + 2) & 0x78) != 0)
+ goto fail;
d = inb ( devc -> base + 4) & 0xF0;
- if ( (d & 0x80) != 0) return 0;
+ if (d & 0x80)
+ goto fail;
if (d == 0) {
- devc->codec_type = 1;
- devc->ic_type = IC_ODIE;
- }
- else if ( (d & 0x60) != 0) {
- devc->codec_type = 2;
- devc->ic_type = IC_OPUS;
- }
- else if ( (d & 0x40) != 0) {
- devc->codec_type = 2;
- devc->ic_type = IC_ODIE;
- }
- else return 0;
+ devc->codec_type = 1;
+ devc->ic_type = IC_ODIE;
+ } else if ( (d & 0x60) != 0) {
+ devc->codec_type = 2;
+ devc->ic_type = IC_OPUS;
+ } else if ( (d & 0x40) != 0) { /* WTF? */
+ devc->codec_type = 2;
+ devc->ic_type = IC_ODIE;
+ } else
+ goto fail;
sscape_is_pnp = 1;
outb(0xFA, devc -> base+4);
if ((inb( devc -> base+4) & 0x9F) != 0x0A)
- return 0;
+ goto fail;
outb(0xFE, devc -> base+4);
if ( (inb(devc -> base+4) & 0x9F) != 0x0E)
- return 0;
+ goto fail;
if ( (inb(devc -> base+5) & 0x9F) != 0x0E)
- return 0;
+ goto fail;
if (devc->codec_type == 2) {
- if (devc -> codec != devc -> base + 8)
+ if (devc->codec != devc->base + 8) {
printk("soundscape warning: incorrect codec port specified\n");
- devc -> codec = devc -> base + 8;
+ goto fail;
+ }
d = 0x10 | (sscape_read(devc, 9) & 0xCF);
sscape_write(devc, 9, d);
sscape_write(devc, 6, 0x80);
d = inb(devc -> codec);
if (d & 0x80)
- return 0;
+ goto fail;
if ( inb(devc -> codec + 2) == 0xFF)
- return 0;
+ goto fail;
sscape_write(devc, 9, sscape_read(devc, 9) & 0x3F );
sscape_pnp_init_hw(devc);
- for (i = 0; i < sizeof(valid_interrupts); i++)
+ for (i = 0; i < 4; i++)
{
if (devc->codec_irq == valid_interrupts[i]) {
irq_bits = i;
sscape_pnp_write_codec( devc, 0, sscape_pnp_read_codec( devc, 0) | 0x20);
sscape_pnp_write_codec( devc, 0, sscape_pnp_read_codec( devc, 1) | 0x20);
- return 1;
+ return 1;
+fail:
+ release_region(devc->codec, 2);
+ return 0;
}
static int __init probe_sscape(struct address_info *hw_config)
{
-
- if (sscape_detected != 0 && sscape_detected != hw_config->io_base)
- return 0;
-
devc->base = hw_config->io_base;
devc->irq = hw_config->irq;
devc->dma = hw_config->dma;
#endif
devc->failed = 1;
+ sscape_ports = request_region(devc->base, 2, "mpu401");
+ if (!sscape_ports)
+ return 0;
+
+ if (!request_region(devc->base + 2, 6, "SoundScape")) {
+ release_region(devc->base, 2);
+ return 0;
+ }
+
if (!detect_ga(devc)) {
- if (detect_sscape_pnp(devc)) {
- sscape_detected = hw_config->io_base;
+ if (detect_sscape_pnp(devc))
return 1;
- }
- else return 0;
+ release_region(devc->base, 2);
+ release_region(devc->base + 2, 6);
+ return 0;
}
if (old_hardware) /* Check that it's really an old Spea/Reveal card. */
inb(devc->base + ODIE_ADDR);
}
}
- sscape_detected = hw_config->io_base;
return 1;
}
-static int __init probe_ss_ms_sound(struct address_info *hw_config)
+static int __init init_ss_ms_sound(struct address_info *hw_config)
{
int i, irq_bits = 0xff;
int ad_flags = 0;
+ struct resource *ports;
if (devc->failed)
{
printk(KERN_ERR "soundscape: Invalid initialization order.\n");
return 0;
}
- for (i = 0; i < sizeof(valid_interrupts); i++)
+ for (i = 0; i < 4; i++)
{
if (hw_config->irq == valid_interrupts[i])
{
break;
}
}
- if (hw_config->irq > 15 || irq_bits == 0xff)
- {
+ if (irq_bits == 0xff) {
printk(KERN_ERR "soundscape: Invalid MSS IRQ%d\n", hw_config->irq);
return 0;
}
- if (!sscape_is_pnp) {
- if (old_hardware)
- ad_flags = 0x12345677; /* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */
- return ad1848_detect(hw_config->io_base, &ad_flags, hw_config->osp);
- }
- else {
- if (old_hardware)
- ad_flags = 0x12345677; /* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */
- else
- ad_flags = 0x87654321; /* Tell that we have a soundscape pnp with 1845 chip */
- return ad1848_detect(hw_config->io_base, &ad_flags, hw_config->osp);
- }
-}
+ if (old_hardware)
+ ad_flags = 0x12345677; /* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */
+ else if (sscape_is_pnp)
+ ad_flags = 0x87654321; /* Tell that we have a soundscape pnp with 1845 chip */
-static void __init attach_ss_ms_sound(struct address_info *hw_config)
-{
- /*
- * This routine configures the SoundScape card for use with the
- * Win Sound System driver. The AD1848 codec interface uses the CD-ROM
- * config registers of the "ODIE".
- */
+ ports = request_region(hw_config->io_base, 4, "ad1848");
+ if (!ports) {
+ printk(KERN_ERR "soundscape: ports busy\n");
+ return 0;
+ }
- int i, irq_bits = 0xff;
+ if (!ad1848_detect(ports, &ad_flags, hw_config->osp)) {
+ release_region(hw_config->io_base, 4);
+ return 0;
+ }
-
if (!sscape_is_pnp) /*pnp is already setup*/
{
/*
/*
* Init the AD1848 (CD-ROM) config reg.
*/
- for (i = 0; i < sizeof(valid_interrupts); i++)
- {
- if (hw_config->irq == valid_interrupts[i])
- {
- irq_bits = i;
- break;
- }
- }
sscape_write(devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) | (irq_bits << 1));
}
hw_config->slots[0] = ad1848_init(
sscape_is_pnp ? "SoundScape" : "SoundScape PNP",
- hw_config->io_base,
+ ports,
hw_config->irq,
hw_config->dma,
hw_config->dma,
printk("I%d = %02x\n", i, sscape_read(devc, i));
}
#endif
-
+ return 1;
}
static void __exit unload_sscape(struct address_info *hw_config)
{
release_region(devc->base + 2, 6);
unload_mpu401(hw_config);
+ if (sscape_is_pnp)
+ release_region(devc->codec, 2);
}
static void __exit unload_ss_ms_sound(struct address_info *hw_config)
static struct address_info cfg_mpu;
static int __initdata spea = -1;
-static int __initdata mss = 0;
+static int mss = 0;
static int __initdata dma = -1;
static int __initdata irq = -1;
static int __initdata io = -1;
static int __initdata mpu_irq = -1;
static int __initdata mpu_io = -1;
-MODULE_PARM(dma, "i");
-MODULE_PARM(irq, "i");
-MODULE_PARM(io, "i");
-MODULE_PARM(spea, "i"); /* spea=0/1 set the old_hardware */
-MODULE_PARM(mpu_irq, "i");
-MODULE_PARM(mpu_io, "i");
-MODULE_PARM(mss, "i");
+module_param(dma, int, 0);
+module_param(irq, int, 0);
+module_param(io, int, 0);
+module_param(spea, int, 0); /* spea=0/1 set the old_hardware */
+module_param(mpu_irq, int, 0);
+module_param(mpu_io, int, 0);
+module_param(mss, int, 0);
static int __init init_sscape(void)
{
attach_sscape(&cfg_mpu);
- mss = probe_ss_ms_sound(&cfg);
-
- if (mss)
- attach_ss_ms_sound(&cfg);
+ mss = init_ss_ms_sound(&cfg);
return 0;
}