summaryrefslogtreecommitdiffstats
path: root/sound/isa
diff options
context:
space:
mode:
authorKrzysztof Helt <krzysztof.h1@wp.pl>2009-09-27 23:08:40 +0200
committerTakashi Iwai <tiwai@suse.de>2009-09-28 11:31:36 +0200
commitf0968e3f7a8ea30728d2580d3043a30ea9994ec6 (patch)
tree4e9adca4a7b7b33e8497eeb5c21935f0538f7624 /sound/isa
parent4f272341c7a42a71586523f196b242bccde3be8c (diff)
downloadlinux-f0968e3f7a8ea30728d2580d3043a30ea9994ec6.tar.gz
linux-f0968e3f7a8ea30728d2580d3043a30ea9994ec6.tar.bz2
linux-f0968e3f7a8ea30728d2580d3043a30ea9994ec6.zip
ALSA: sscape: add supoort for SPEA Media FX/Reveal SC-600
Move code from the OSS sscape driver in order to support old Soundscape OEM models. Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/isa')
-rw-r--r--sound/isa/Kconfig6
-rw-r--r--sound/isa/sscape.c116
2 files changed, 86 insertions, 36 deletions
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index 51a7e3777e17..b90fc164a79c 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -377,10 +377,12 @@ config SND_SSCAPE
select SND_WSS_LIB
help
Say Y here to include support for Ensoniq SoundScape
- soundcards.
+ and Ensoniq OEM soundcards.
The PCM audio is supported on SoundScape Classic, Elite, PnP
- and VIVO cards. The MIDI support is very experimental.
+ and VIVO cards. The supported OEM cards are SPEA Media FX and
+ Reveal SC-600.
+ The MIDI support is very experimental.
To compile this driver as a module, choose M here: the module
will be called snd-sscape.
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c
index 66187122377c..b11c35f6aefe 100644
--- a/sound/isa/sscape.c
+++ b/sound/isa/sscape.c
@@ -127,7 +127,8 @@ enum GA_REG {
enum card_type {
- SSCAPE,
+ MEDIA_FX, /* Sequoia S-1000 */
+ SSCAPE, /* Sequoia S-2000 */
SSCAPE_PNP,
SSCAPE_VIVO,
};
@@ -784,20 +785,25 @@ static struct snd_kcontrol_new midi_mixer_ctl = {
* These IRQs are encoded as bit patterns so that they can be
* written to the control registers.
*/
-static unsigned __devinit get_irq_config(int irq)
+static unsigned __devinit get_irq_config(int sscape_type, int irq)
{
static const int valid_irq[] = { 9, 5, 7, 10 };
+ static const int old_irq[] = { 9, 7, 5, 15 };
unsigned cfg;
- for (cfg = 0; cfg < ARRAY_SIZE(valid_irq); ++cfg) {
- if (irq == valid_irq[cfg])
- return cfg;
- } /* for */
+ if (sscape_type == MEDIA_FX) {
+ for (cfg = 0; cfg < ARRAY_SIZE(old_irq); ++cfg)
+ if (irq == old_irq[cfg])
+ return cfg;
+ } else {
+ for (cfg = 0; cfg < ARRAY_SIZE(valid_irq); ++cfg)
+ if (irq == valid_irq[cfg])
+ return cfg;
+ }
return INVALID_IRQ;
}
-
/*
* Perform certain arcane port-checks to see whether there
* is a SoundScape board lurking behind the given ports.
@@ -842,11 +848,39 @@ static int __devinit detect_sscape(struct soundscape *s, long wss_io)
if (s->type != SSCAPE_VIVO && (d & 0x9f) != 0x0e)
goto _done;
- d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f;
- sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0);
+ if (s->ic_type == IC_OPUS)
+ activate_ad1845_unsafe(s->io_base);
if (s->type == SSCAPE_VIVO)
wss_io += 4;
+
+ d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f;
+ sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0);
+
+ /* wait for WSS codec */
+ for (d = 0; d < 500; d++) {
+ if ((inb(wss_io) & 0x80) == 0)
+ break;
+ spin_unlock_irqrestore(&s->lock, flags);
+ msleep(1);
+ spin_lock_irqsave(&s->lock, flags);
+ }
+ snd_printd(KERN_INFO "init delay = %d ms\n", d);
+
+ if ((inb(wss_io) & 0x80) != 0)
+ goto _done;
+
+ if (inb(wss_io + 2) == 0xff)
+ goto _done;
+
+ d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f;
+ sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d);
+
+ if ((inb(wss_io) & 0x80) != 0)
+ s->type = MEDIA_FX;
+
+ d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f;
+ sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0);
/* wait for WSS codec */
for (d = 0; d < 500; d++) {
if ((inb(wss_io) & 0x80) == 0)
@@ -954,9 +988,6 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
if (sscape->type == SSCAPE_VIVO)
port += 4;
- if (dma1 == dma2)
- dma2 = -1;
-
err = snd_wss_create(card, port, -1, irq, dma1, dma2,
WSS_HW_DETECT, WSS_HWSHARE_DMA1, &chip);
if (!err) {
@@ -1051,21 +1082,7 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
struct resource *wss_res;
unsigned long flags;
int err;
-
- /*
- * Check that the user didn't pass us garbage data ...
- */
- irq_cfg = get_irq_config(irq[dev]);
- if (irq_cfg == INVALID_IRQ) {
- snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", irq[dev]);
- return -ENXIO;
- }
-
- mpu_irq_cfg = get_irq_config(mpu_irq[dev]);
- if (mpu_irq_cfg == INVALID_IRQ) {
- printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]);
- return -ENXIO;
- }
+ const char *name;
/*
* Grab IO ports that we will need to probe so that we
@@ -1109,8 +1126,41 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
goto _release_dma;
}
- printk(KERN_INFO "sscape: hardware detected at 0x%x, using IRQ %d, DMA %d\n",
- sscape->io_base, irq[dev], dma[dev]);
+ switch (sscape->type) {
+ case MEDIA_FX:
+ name = "MediaFX/SoundFX";
+ break;
+ case SSCAPE:
+ name = "Soundscape";
+ break;
+ case SSCAPE_PNP:
+ name = "Soundscape PnP";
+ break;
+ case SSCAPE_VIVO:
+ name = "Soundscape VIVO";
+ break;
+ default:
+ name = "unknown Soundscape";
+ break;
+ }
+
+ printk(KERN_INFO "sscape: %s card detected at 0x%x, using IRQ %d, DMA %d\n",
+ name, sscape->io_base, irq[dev], dma[dev]);
+
+ /*
+ * Check that the user didn't pass us garbage data ...
+ */
+ irq_cfg = get_irq_config(sscape->type, irq[dev]);
+ if (irq_cfg == INVALID_IRQ) {
+ snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", irq[dev]);
+ return -ENXIO;
+ }
+
+ mpu_irq_cfg = get_irq_config(sscape->type, mpu_irq[dev]);
+ if (mpu_irq_cfg == INVALID_IRQ) {
+ printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]);
+ return -ENXIO;
+ }
if (sscape->type != SSCAPE_VIVO) {
/*
@@ -1141,8 +1191,6 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
*/
spin_lock_irqsave(&sscape->lock, flags);
- activate_ad1845_unsafe(sscape->io_base);
-
sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x00); /* disable */
sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e);
sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00);
@@ -1151,12 +1199,12 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
* Enable and configure the DMA channels ...
*/
sscape_write_unsafe(sscape->io_base, GA_DMACFG_REG, 0x50);
- dma_cfg = (sscape->ic_type == IC_ODIE ? 0x70 : 0x40);
+ dma_cfg = (sscape->ic_type == IC_OPUS ? 0x40 : 0x70);
sscape_write_unsafe(sscape->io_base, GA_DMAA_REG, dma_cfg);
sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20);
- sscape_write_unsafe(sscape->io_base,
- GA_INTCFG_REG, 0xf0 | (mpu_irq_cfg << 2) | mpu_irq_cfg);
+ mpu_irq_cfg |= mpu_irq_cfg << 2;
+ sscape_write_unsafe(sscape->io_base, GA_INTCFG_REG, 0xf0 | mpu_irq_cfg);
sscape_write_unsafe(sscape->io_base,
GA_CDCFG_REG, 0x09 | DMA_8BIT
| (dma[dev] << 4) | (irq_cfg << 1));