[ALSA] sscape: support for audio part of VIVO cards

This patch adds support for audio part of the Ensoniq
SoundScape VIVO cards. The MIDI part is not supported.

Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
This commit is contained in:
Krzysztof Helt 2007-09-17 17:57:37 +02:00 committed by Jaroslav Kysela
parent 1ea73412b2
commit ec1e794932
1 changed files with 146 additions and 76 deletions

View File

@ -142,10 +142,12 @@ enum card_type {
struct soundscape {
spinlock_t lock;
unsigned io_base;
unsigned wss_base;
int codec_type;
int ic_type;
enum card_type type;
struct resource *io_res;
struct resource *wss_res;
struct snd_cs4231 *chip;
struct snd_mpu401 *mpu;
struct snd_hwdep *hw;
@ -356,8 +358,9 @@ static inline void activate_ad1845_unsafe(unsigned io_base)
*/
static void soundscape_free(struct snd_card *c)
{
register struct soundscape *sscape = get_card_soundscape(c);
struct soundscape *sscape = get_card_soundscape(c);
release_and_free_resource(sscape->io_res);
release_and_free_resource(sscape->wss_res);
free_dma(sscape->chip->dma1);
}
@ -818,6 +821,7 @@ static int __devinit detect_sscape(struct soundscape *s)
unsigned long flags;
unsigned d;
int retval = 0;
int codec = s->wss_base;
spin_lock_irqsave(&s->lock, flags);
@ -849,9 +853,27 @@ static int __devinit detect_sscape(struct soundscape *s)
outb(0xfe, ODIE_ADDR_IO(s->io_base));
if ((inb(ODIE_ADDR_IO(s->io_base)) & 0x9f) != 0x0e)
goto _done;
if ((inb(ODIE_DATA_IO(s->io_base)) & 0x9f) != 0x0e)
outb(0xfe, ODIE_ADDR_IO(s->io_base));
d = inb(ODIE_DATA_IO(s->io_base));
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->type == SSCAPE_VIVO)
codec += 4;
/* wait for WSS codec */
for (d = 0; d < 500; d++) {
if ((inb(codec) & 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);
/*
* SoundScape successfully detected!
*/
@ -1018,6 +1040,9 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
struct snd_cs4231 *chip;
int err;
if (sscape->type == SSCAPE_VIVO)
port += 4;
if (dma1 == dma2)
dma2 = -1;
@ -1046,40 +1071,63 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
snd_cs4231_mce_down(chip);
*/
/*
* The input clock frequency on the SoundScape must
* be 14.31818 MHz, because we must set this register
* to get the playback to sound correct ...
*/
snd_cs4231_mce_up(chip);
spin_lock_irqsave(&chip->reg_lock, flags);
snd_cs4231_out(chip, AD1845_CRYS_CLOCK_SEL, 0x20);
spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_cs4231_mce_down(chip);
if (sscape->type != SSCAPE_VIVO) {
int val;
/*
* The input clock frequency on the SoundScape must
* be 14.31818 MHz, because we must set this register
* to get the playback to sound correct ...
*/
snd_cs4231_mce_up(chip);
spin_lock_irqsave(&chip->reg_lock, flags);
snd_cs4231_out(chip, AD1845_CRYS_CLOCK_SEL, 0x20);
spin_unlock_irqrestore(&chip->reg_lock, flags);
snd_cs4231_mce_down(chip);
/*
* More custom configuration:
* a) select "mode 2", and provide a current drive of 8 mA
* b) enable frequency selection (for capture/playback)
*/
spin_lock_irqsave(&chip->reg_lock, flags);
snd_cs4231_out(chip, CS4231_MISC_INFO, (CS4231_MODE2 | 0x10));
snd_cs4231_out(chip, AD1845_PWR_DOWN_CTRL, snd_cs4231_in(chip, AD1845_PWR_DOWN_CTRL) | AD1845_FREQ_SEL_ENABLE);
spin_unlock_irqrestore(&chip->reg_lock, flags);
/*
* More custom configuration:
* a) select "mode 2" and provide a current drive of 8mA
* b) enable frequency selection (for capture/playback)
*/
spin_lock_irqsave(&chip->reg_lock, flags);
snd_cs4231_out(chip, CS4231_MISC_INFO,
CS4231_MODE2 | 0x10);
val = snd_cs4231_in(chip, AD1845_PWR_DOWN_CTRL);
snd_cs4231_out(chip, AD1845_PWR_DOWN_CTRL,
val | AD1845_FREQ_SEL_ENABLE);
spin_unlock_irqrestore(&chip->reg_lock, flags);
}
if ((err = snd_cs4231_pcm(chip, 0, &pcm)) < 0) {
snd_printk(KERN_ERR "sscape: No PCM device for AD1845 chip\n");
err = snd_cs4231_pcm(chip, 0, &pcm);
if (err < 0) {
snd_printk(KERN_ERR "sscape: No PCM device "
"for AD1845 chip\n");
goto _error;
}
if ((err = snd_cs4231_mixer(chip)) < 0) {
snd_printk(KERN_ERR "sscape: No mixer device for AD1845 chip\n");
err = snd_cs4231_mixer(chip);
if (err < 0) {
snd_printk(KERN_ERR "sscape: No mixer device "
"for AD1845 chip\n");
goto _error;
}
err = snd_cs4231_timer(chip, 0, NULL);
if (err < 0) {
snd_printk(KERN_ERR "sscape: No timer device "
"for AD1845 chip\n");
goto _error;
}
if ((err = snd_ctl_add(card, snd_ctl_new1(&midi_mixer_ctl, chip))) < 0) {
snd_printk(KERN_ERR "sscape: Could not create MIDI mixer control\n");
goto _error;
if (sscape->type != SSCAPE_VIVO) {
err = snd_ctl_add(card,
snd_ctl_new1(&midi_mixer_ctl, chip));
if (err < 0) {
snd_printk(KERN_ERR "sscape: Could not create "
"MIDI mixer control\n");
goto _error;
}
chip->set_playback_format = ad1845_playback_format;
chip->set_capture_format = ad1845_capture_format;
}
strcpy(card->driver, "SoundScape");
@ -1088,8 +1136,7 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
"%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n",
pcm->name, chip->port, chip->irq,
chip->dma1, chip->dma2);
chip->set_playback_format = ad1845_playback_format;
chip->set_capture_format = ad1845_capture_format;
sscape->chip = chip;
}
@ -1104,12 +1151,13 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port,
*/
static int __devinit create_sscape(int dev, struct snd_card *card)
{
register struct soundscape *sscape;
register unsigned dma_cfg;
struct soundscape *sscape = get_card_soundscape(card);
unsigned dma_cfg;
unsigned irq_cfg;
unsigned mpu_irq_cfg;
unsigned xport;
struct resource *io_res;
struct resource *wss_res;
unsigned long flags;
int err;
@ -1133,13 +1181,24 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
* Grab IO ports that we will need to probe so that we
* can detect and control this hardware ...
*/
if ((io_res = request_region(xport, 8, "SoundScape")) == NULL) {
io_res = request_region(xport, 8, "SoundScape");
if (!io_res) {
snd_printk(KERN_ERR "sscape: can't grab port 0x%x\n", xport);
return -EBUSY;
}
wss_res = NULL;
if (sscape->type == SSCAPE_VIVO) {
wss_res = request_region(wss_port[dev], 4, "SoundScape");
if (!wss_res) {
snd_printk(KERN_ERR "sscape: can't grab port 0x%lx\n",
wss_port[dev]);
err = -EBUSY;
goto _release_region;
}
}
/*
* Grab both DMA channels (OK, only one for now) ...
* Grab one DMA channel ...
*/
err = request_dma(dma[dev], "SoundScape");
if (err < 0) {
@ -1147,11 +1206,12 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
goto _release_region;
}
sscape = get_card_soundscape(card);
spin_lock_init(&sscape->lock);
spin_lock_init(&sscape->fwlock);
sscape->io_res = io_res;
sscape->wss_res = wss_res;
sscape->io_base = xport;
sscape->wss_base = wss_port[dev];
if (!detect_sscape(sscape)) {
printk(KERN_ERR "sscape: hardware not detected at 0x%x\n", sscape->io_base);
@ -1162,23 +1222,28 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
printk(KERN_INFO "sscape: hardware detected at 0x%x, using IRQ %d, DMA %d\n",
sscape->io_base, irq[dev], dma[dev]);
/*
* Now create the hardware-specific device so that we can
* load the microcode into the on-board processor.
* We cannot use the MPU-401 MIDI system until this firmware
* has been loaded into the card.
*/
if ((err = snd_hwdep_new(card, "MC68EC000", 0, &(sscape->hw))) < 0) {
printk(KERN_ERR "sscape: Failed to create firmware device\n");
goto _release_dma;
if (sscape->type != SSCAPE_VIVO) {
/*
* Now create the hardware-specific device so that we can
* load the microcode into the on-board processor.
* We cannot use the MPU-401 MIDI system until this firmware
* has been loaded into the card.
*/
err = snd_hwdep_new(card, "MC68EC000", 0, &(sscape->hw));
if (err < 0) {
printk(KERN_ERR "sscape: Failed to create "
"firmware device\n");
goto _release_dma;
}
strlcpy(sscape->hw->name, "SoundScape M68K",
sizeof(sscape->hw->name));
sscape->hw->name[sizeof(sscape->hw->name) - 1] = '\0';
sscape->hw->iface = SNDRV_HWDEP_IFACE_SSCAPE;
sscape->hw->ops.open = sscape_hw_open;
sscape->hw->ops.release = sscape_hw_release;
sscape->hw->ops.ioctl = sscape_hw_ioctl;
sscape->hw->private_data = sscape;
}
strlcpy(sscape->hw->name, "SoundScape M68K", sizeof(sscape->hw->name));
sscape->hw->name[sizeof(sscape->hw->name) - 1] = '\0';
sscape->hw->iface = SNDRV_HWDEP_IFACE_SSCAPE;
sscape->hw->ops.open = sscape_hw_open;
sscape->hw->ops.release = sscape_hw_release;
sscape->hw->ops.ioctl = sscape_hw_ioctl;
sscape->hw->private_data = sscape;
/*
* Tell the on-board devices where their resources are (I think -
@ -1220,25 +1285,30 @@ static int __devinit create_sscape(int dev, struct snd_card *card)
goto _release_dma;
}
#define MIDI_DEVNUM 0
if ((err = create_mpu401(card, MIDI_DEVNUM, MPU401_IO(xport), mpu_irq[dev])) < 0) {
printk(KERN_ERR "sscape: Failed to create MPU-401 device at 0x%x\n",
MPU401_IO(xport));
goto _release_dma;
if (sscape->type != SSCAPE_VIVO) {
err = create_mpu401(card, MIDI_DEVNUM,
MPU401_IO(xport), mpu_irq[dev]);
if (err < 0) {
printk(KERN_ERR "sscape: Failed to create "
"MPU-401 device at 0x%x\n",
MPU401_IO(xport));
goto _release_dma;
}
/*
* Enable the master IRQ ...
*/
sscape_write(sscape, GA_INTENA_REG, 0x80);
/*
* Initialize mixer
*/
sscape->midi_vol = 0;
host_write_ctrl_unsafe(sscape->io_base, CMD_SET_MIDI_VOL, 100);
host_write_ctrl_unsafe(sscape->io_base, 0, 100);
host_write_ctrl_unsafe(sscape->io_base, CMD_XXX_MIDI_VOL, 100);
}
/*
* Enable the master IRQ ...
*/
sscape_write(sscape, GA_INTENA_REG, 0x80);
/*
* Initialize mixer
*/
sscape->midi_vol = 0;
host_write_ctrl_unsafe(sscape->io_base, CMD_SET_MIDI_VOL, 100);
host_write_ctrl_unsafe(sscape->io_base, 0, 100);
host_write_ctrl_unsafe(sscape->io_base, CMD_XXX_MIDI_VOL, 100);
/*
* Now that we have successfully created this sound card,
* it is safe to store the pointer.
@ -1253,6 +1323,7 @@ _release_dma:
free_dma(dma[dev]);
_release_region:
release_and_free_resource(wss_res);
release_and_free_resource(io_res);
return err;
@ -1404,12 +1475,6 @@ static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard,
else
sscape->type = SSCAPE_PNP;
/* VIVO fails for now */
if (sscape->type == SSCAPE_VIVO) {
ret = -ENODEV;
goto _release_card;
}
/*
* Read the correct parameters off the ISA PnP bus ...
*/
@ -1417,8 +1482,13 @@ static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard,
irq[idx] = pnp_irq(dev, 0);
mpu_irq[idx] = pnp_irq(dev, 1);
dma[idx] = pnp_dma(dev, 0) & 0x03;
dma2[idx] = dma[idx];
wss_port[idx] = CODEC_IO(port[idx]);
if (sscape->type == SSCAPE_PNP) {
dma2[idx] = dma[idx];
wss_port[idx] = CODEC_IO(port[idx]);
} else {
wss_port[idx] = pnp_port_start(dev, 1);
dma2[idx] = pnp_dma(dev, 1);
}
ret = create_sscape(idx, card);
if (ret < 0)