diff options
author | Jaroslav Kysela <perex@suse.cz> | 2004-04-24 19:45:05 +0200 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2004-04-24 19:45:05 +0200 |
commit | 9cd65233188e34055076b26fd0ceb0a90c901203 (patch) | |
tree | 64c8383d39da7461cc183979a3c6be657716c2dc /sound | |
parent | 37051c28a867644d7a5125578638c47c92707c8d (diff) | |
download | history-9cd65233188e34055076b26fd0ceb0a90c901203.tar.gz |
ALSA CVS update - Takashi Iwai <tiwai@suse.de>
ATIIXP driver
- fixed SPDIF support.
restricted only 48k sample rate.
- fixed the address assignment for bigendian (not existing, though)
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/atiixp.c | 125 |
1 files changed, 82 insertions, 43 deletions
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 677bfbaaef8b54..68a0cc892996d6 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -246,9 +246,10 @@ struct snd_atiixp_dma { snd_pcm_substream_t *substream; /* assigned PCM substream */ unsigned int buf_addr, buf_bytes; /* DMA buffer address, bytes */ unsigned int period_bytes, periods; + int opened; int running; - struct ac97_pcm *pcm; int pcm_open_flag; + int ac97_pcm_type; /* index # of ac97_pcm to access, -1 = not used */ }; /* @@ -270,12 +271,14 @@ struct snd_atiixp { spinlock_t ac97_lock; atiixp_dma_t dmas[3]; /* playback, capture, spdif */ + struct ac97_pcm *pcms[3]; /* playback, capture, spdif */ int max_channels; /* max. channels for PCM out */ unsigned int codec_not_ready_bits; /* for codec detection */ int spdif_over_aclink; /* passed from the module option */ + struct semaphore open_mutex; /* playback open mutex */ }; @@ -393,7 +396,7 @@ static int atiixp_build_dma_packets(atiixp_t *chip, atiixp_dma_t *dma, addr += period_bytes; } - writel(cpu_to_le32((u32)dma->desc_buf.addr | ATI_REG_LINKPTR_EN), + writel((u32)dma->desc_buf.addr | ATI_REG_LINKPTR_EN, chip->remap_addr + dma->ops->llp_offset); dma->period_bytes = period_bytes; @@ -452,7 +455,9 @@ static unsigned short snd_atiixp_codec_read(atiixp_t *chip, unsigned short codec return data >> ATI_REG_PHYS_IN_DATA_SHIFT; udelay(1); } while (--timeout); - snd_printk(KERN_WARNING "atiixp: codec read timeout\n"); + /* time out may happen during reset */ + if (reg < 0x7c) + snd_printk(KERN_WARNING "atiixp: codec read timeout (reg %x)\n", reg); return 0xffff; } @@ -585,12 +590,16 @@ static int snd_atiixp_chip_start(atiixp_t *chip) { unsigned int reg; - /* enable burst mode */ + /* set up spdif, enable burst mode */ reg = atiixp_read(chip, CMD); reg |= 0x02 << ATI_REG_CMD_SPDF_THRESHOLD_SHIFT; reg |= ATI_REG_CMD_BURST_EN; atiixp_write(chip, CMD, reg); + reg = atiixp_read(chip, SPDF_CMD); + reg &= ~(ATI_REG_SPDF_CMD_LFSR|ATI_REG_SPDF_CMD_SINGLE_CH); + atiixp_write(chip, SPDF_CMD, reg); + /* clear all interrupt source */ atiixp_write(chip, ISR, 0xffffffff); /* enable irqs */ @@ -657,7 +666,7 @@ static void snd_atiixp_xrun_dma(atiixp_t *chip, atiixp_dma_t *dma) { if (! dma->substream || ! dma->running) return; - snd_printd(KERN_DEBUG "atiixp: XRUN detected (DMA %d)\n", dma->ops->type); + snd_printdd("atiixp: XRUN detected (DMA %d)\n", dma->ops->type); snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN); } @@ -800,15 +809,10 @@ static void atiixp_spdif_enable_transfer(atiixp_t *chip, int on) { unsigned int data; data = atiixp_read(chip, CMD); - if (on) { + if (on) data |= ATI_REG_CMD_SPDF_OUT_EN; - if (chip->spdif_over_aclink) - data |= ATI_REG_CMD_SEND_EN; - } else { + else data &= ~ATI_REG_CMD_SPDF_OUT_EN; - if (chip->spdif_over_aclink) - data &= ~ATI_REG_CMD_SEND_EN; - } atiixp_write(chip, CMD, data); } @@ -835,25 +839,27 @@ static void atiixp_spdif_flush_dma(atiixp_t *chip) static int snd_atiixp_spdif_prepare(snd_pcm_substream_t *substream) { atiixp_t *chip = snd_pcm_substream_chip(substream); - unsigned int data; spin_lock(&chip->reg_lock); if (chip->spdif_over_aclink) { + unsigned int data; /* enable slots 10/11 */ atiixp_update(chip, CMD, ATI_REG_CMD_SPDF_CONFIG_MASK, ATI_REG_CMD_SPDF_CONFIG_01); - data = atiixp_read(chip, OUT_DMA_SLOT); + data = atiixp_read(chip, OUT_DMA_SLOT) & ~ATI_REG_OUT_DMA_SLOT_MASK; data |= ATI_REG_OUT_DMA_SLOT_BIT(10) | ATI_REG_OUT_DMA_SLOT_BIT(11); data |= 0x04 << ATI_REG_OUT_DMA_THRESHOLD_SHIFT; atiixp_write(chip, OUT_DMA_SLOT, data); + atiixp_update(chip, CMD, ATI_REG_CMD_INTERLEAVE_OUT, + substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE ? + ATI_REG_CMD_INTERLEAVE_OUT : 0); } else { atiixp_update(chip, CMD, ATI_REG_CMD_SPDF_CONFIG_MASK, 0); + atiixp_update(chip, CMD, ATI_REG_CMD_INTERLEAVE_SPDF, + substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE ? + ATI_REG_CMD_INTERLEAVE_SPDF : 0); } - - atiixp_update(chip, CMD, ATI_REG_CMD_INTERLEAVE_SPDF, - substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE ? - ATI_REG_CMD_INTERLEAVE_SPDF : 0); spin_unlock(&chip->reg_lock); return 0; } @@ -938,17 +944,18 @@ static int snd_atiixp_pcm_hw_params(snd_pcm_substream_t *substream, if (err < 0) return err; - if (dma->pcm) { + if (dma->ac97_pcm_type >= 0) { + struct ac97_pcm *pcm = chip->pcms[dma->ac97_pcm_type]; /* PCM is bound to AC97 codec(s) * set up the AC97 codecs */ if (dma->pcm_open_flag) { - snd_ac97_pcm_close(dma->pcm); + snd_ac97_pcm_close(pcm); dma->pcm_open_flag = 0; } - err = snd_ac97_pcm_open(dma->pcm, params_rate(hw_params), + err = snd_ac97_pcm_open(pcm, params_rate(hw_params), params_channels(hw_params), - dma->pcm->r[0].slots); + pcm->r[0].slots); if (err >= 0) dma->pcm_open_flag = 1; } @@ -962,7 +969,8 @@ static int snd_atiixp_pcm_hw_free(snd_pcm_substream_t * substream) atiixp_dma_t *dma = (atiixp_dma_t *)substream->runtime->private_data; if (dma->pcm_open_flag) { - snd_ac97_pcm_close(dma->pcm); + struct ac97_pcm *pcm = chip->pcms[dma->ac97_pcm_type]; + snd_ac97_pcm_close(pcm); dma->pcm_open_flag = 0; } atiixp_clear_dma_packets(chip, dma, substream); @@ -992,7 +1000,7 @@ static snd_pcm_hardware_t snd_atiixp_pcm_hw = .periods_max = ATI_MAX_DESCRIPTORS, }; -static int snd_atiixp_pcm_open(snd_pcm_substream_t *substream, atiixp_dma_t *dma) +static int snd_atiixp_pcm_open(snd_pcm_substream_t *substream, atiixp_dma_t *dma, int pcm_type) { atiixp_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; @@ -1001,10 +1009,13 @@ static int snd_atiixp_pcm_open(snd_pcm_substream_t *substream, atiixp_dma_t *dma snd_assert(dma->ops && dma->ops->enable_dma, return -EINVAL); + if (dma->opened) + return -EBUSY; dma->substream = substream; runtime->hw = snd_atiixp_pcm_hw; - if (dma->pcm) { - runtime->hw.rates = dma->pcm->rates; + dma->ac97_pcm_type = pcm_type; + if (pcm_type >= 0) { + runtime->hw.rates = chip->pcms[pcm_type]->rates; snd_pcm_limit_hw_rates(runtime); } else { /* SPDIF */ @@ -1019,6 +1030,7 @@ static int snd_atiixp_pcm_open(snd_pcm_substream_t *substream, atiixp_dma_t *dma spin_lock_irqsave(&chip->reg_lock, flags); dma->ops->enable_dma(chip, 1); spin_unlock_irqrestore(&chip->reg_lock, flags); + dma->opened = 1; return 0; } @@ -1032,6 +1044,7 @@ static int snd_atiixp_pcm_close(snd_pcm_substream_t *substream, atiixp_dma_t *dm dma->ops->enable_dma(chip, 0); spin_unlock_irq(&chip->reg_lock); dma->substream = NULL; + dma->opened = 0; return 0; } @@ -1042,26 +1055,33 @@ static int snd_atiixp_playback_open(snd_pcm_substream_t *substream) atiixp_t *chip = snd_pcm_substream_chip(substream); int err; - err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK]); + down(&chip->open_mutex); + err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 0); + up(&chip->open_mutex); + if (err < 0) + return err; substream->runtime->hw.channels_max = chip->max_channels; if (chip->max_channels > 2) /* channels must be even */ snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2); - return 0; } static int snd_atiixp_playback_close(snd_pcm_substream_t *substream) { atiixp_t *chip = snd_pcm_substream_chip(substream); - return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]); + int err; + down(&chip->open_mutex); + err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]); + up(&chip->open_mutex); + return err; } static int snd_atiixp_capture_open(snd_pcm_substream_t *substream) { atiixp_t *chip = snd_pcm_substream_chip(substream); - return snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_CAPTURE]); + return snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_CAPTURE], 1); } static int snd_atiixp_capture_close(snd_pcm_substream_t *substream) @@ -1073,13 +1093,27 @@ static int snd_atiixp_capture_close(snd_pcm_substream_t *substream) static int snd_atiixp_spdif_open(snd_pcm_substream_t *substream) { atiixp_t *chip = snd_pcm_substream_chip(substream); - return snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_SPDIF]); + int err; + down(&chip->open_mutex); + if (chip->spdif_over_aclink) /* share DMA_PLAYBACK */ + err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 2); + else + err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_SPDIF], -1); + up(&chip->open_mutex); + return err; } static int snd_atiixp_spdif_close(snd_pcm_substream_t *substream) { atiixp_t *chip = snd_pcm_substream_chip(substream); - return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_SPDIF]); + int err; + down(&chip->open_mutex); + if (chip->spdif_over_aclink) + err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]); + else + err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_SPDIF]); + up(&chip->open_mutex); + return err; } /* AC97 playback */ @@ -1188,7 +1222,8 @@ static int __devinit snd_atiixp_pcm_new(atiixp_t *chip) /* initialize constants */ chip->dmas[ATI_DMA_PLAYBACK].ops = &snd_atiixp_playback_dma_ops; chip->dmas[ATI_DMA_CAPTURE].ops = &snd_atiixp_capture_dma_ops; - chip->dmas[ATI_DMA_SPDIF].ops = &snd_atiixp_spdif_dma_ops; + if (! chip->spdif_over_aclink) + chip->dmas[ATI_DMA_SPDIF].ops = &snd_atiixp_spdif_dma_ops; /* assign AC97 pcm */ if (chip->spdif_over_aclink) @@ -1198,6 +1233,8 @@ static int __devinit snd_atiixp_pcm_new(atiixp_t *chip) err = snd_ac97_pcm_assign(pbus, num_pcms, atiixp_pcm_defs); if (err < 0) return err; + for (i = 0; i < num_pcms; i++) + chip->pcms[i] = &pbus->pcms[i]; chip->max_channels = 2; if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_PCM_SLEFT)) { @@ -1207,11 +1244,6 @@ static int __devinit snd_atiixp_pcm_new(atiixp_t *chip) chip->max_channels = 4; } - chip->dmas[ATI_DMA_PLAYBACK].pcm = &pbus->pcms[0]; - chip->dmas[ATI_DMA_CAPTURE].pcm = &pbus->pcms[1]; - if (chip->spdif_over_aclink) - chip->dmas[ATI_DMA_SPDIF].pcm = &pbus->pcms[2]; - /* PCM #0: analog I/O */ err = snd_pcm_new(chip->card, "ATI IXP AC97", 0, 1, 1, &pcm); if (err < 0) @@ -1225,9 +1257,13 @@ static int __devinit snd_atiixp_pcm_new(atiixp_t *chip) snd_dma_pci_data(chip->pci), 64*1024, 128*1024); /* no SPDIF support on codec? */ - if (chip->dmas[ATI_DMA_SPDIF].pcm && ! chip->dmas[ATI_DMA_SPDIF].pcm->rates) + if (chip->pcms[2] && ! chip->pcms[2]->rates) return 0; + /* FIXME: non-48k sample rate doesn't work on my test machine with AD1888 */ + if (chip->pcms[2]) + chip->pcms[2]->rates = SNDRV_PCM_RATE_48000; + /* PCM #1: spdif playback */ err = snd_pcm_new(chip->card, "ATI IXP IEC958", 1, 1, 0, &pcm); if (err < 0) @@ -1272,10 +1308,12 @@ static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id, struct pt_regs *r snd_atiixp_xrun_dma(chip, &chip->dmas[ATI_DMA_CAPTURE]); else if (status & ATI_REG_ISR_IN_STATUS) snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_CAPTURE]); - if (status & ATI_REG_ISR_SPDF_XRUN) - snd_atiixp_xrun_dma(chip, &chip->dmas[ATI_DMA_SPDIF]); - else if (status & ATI_REG_ISR_SPDF_STATUS) - snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_SPDIF]); + if (! chip->spdif_over_aclink) { + if (status & ATI_REG_ISR_SPDF_XRUN) + snd_atiixp_xrun_dma(chip, &chip->dmas[ATI_DMA_SPDIF]); + else if (status & ATI_REG_ISR_SPDF_STATUS) + snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_SPDIF]); + } /* for codec detection */ if (status & CODEC_CHECK_BITS) { @@ -1412,6 +1450,7 @@ static int __devinit snd_atiixp_create(snd_card_t *card, spin_lock_init(&chip->reg_lock); spin_lock_init(&chip->ac97_lock); + init_MUTEX(&chip->open_mutex); chip->card = card; chip->pci = pci; chip->irq = -1; |