diff options
author | Jaroslav Kysela <perex@suse.cz> | 2005-01-12 22:29:54 +0100 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2005-01-12 22:29:54 +0100 |
commit | bdd03b88e1a318f7c50647b4dfe7d214c4e7a324 (patch) | |
tree | 5c4d852e4e2b4e16699a9def459b5eeeff7a9d0a /sound | |
parent | ffcce5e2f9bc2169b7611bbf3b5b5d37d959760a (diff) | |
download | history-bdd03b88e1a318f7c50647b4dfe7d214c4e7a324.tar.gz |
[ALSA] Fix DMA pointer read
ATIIXP driver
Try to reread DMA pointer register if the value is invalid.
The register shows bogus values on some broken hardwares.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/atiixp.c | 23 |
1 files changed, 11 insertions, 12 deletions
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index f05b51b23bdc7e..3cb1c33e5f2a75 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -630,21 +630,20 @@ static snd_pcm_uframes_t snd_atiixp_pcm_pointer(snd_pcm_substream_t *substream) snd_pcm_runtime_t *runtime = substream->runtime; atiixp_dma_t *dma = (atiixp_dma_t *)runtime->private_data; unsigned int curptr; + int timeout = 1000; - spin_lock(&chip->reg_lock); - curptr = readl(chip->remap_addr + dma->ops->dt_cur); - if (curptr < dma->buf_addr) { - snd_printdd("curptr = %x, base = %x\n", curptr, dma->buf_addr); - curptr = 0; - } else { + while (timeout--) { + curptr = readl(chip->remap_addr + dma->ops->dt_cur); + if (curptr < dma->buf_addr) + continue; curptr -= dma->buf_addr; - if (curptr >= dma->buf_bytes) { - snd_printdd("curptr = %x, size = %x\n", curptr, dma->buf_bytes); - curptr = 0; - } + if (curptr >= dma->buf_bytes) + continue; + return bytes_to_frames(runtime, curptr); } - spin_unlock(&chip->reg_lock); - return bytes_to_frames(runtime, curptr); + snd_printd("atiixp: invalid DMA pointer read 0x%x (buf=%x)\n", + readl(chip->remap_addr + dma->ops->dt_cur), dma->buf_addr); + return 0; } /* |