summaryrefslogtreecommitdiff
path: root/sound/pci/ca0106
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2009-07-16 18:19:12 +0200
committerTakashi Iwai <tiwai@suse.de>2010-09-07 11:54:16 +0200
commitadd7c0a6a4b8669ebd726f9c08ba6002900ca671 (patch)
tree81c28ffce3985feafc2a6d07f33a7052c763c425 /sound/pci/ca0106
parent9fe856e47e1751204faf3d604c6d20ab24bd3b93 (diff)
ALSA: ca0106 - clean up playback pointer callback
Clean up the playback pointer callback function a bit, and make the pointer check more strictly to avoid bogus pointers. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/ca0106')
-rw-r--r--sound/pci/ca0106/ca0106_main.c34
1 files changed, 16 insertions, 18 deletions
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 0a3d3d6e77b4..8e69620da20b 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -1002,29 +1002,27 @@ snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream)
struct snd_ca0106 *emu = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_ca0106_pcm *epcm = runtime->private_data;
- snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0;
+ unsigned int ptr, prev_ptr;
int channel = epcm->channel_id;
+ int timeout = 10;
if (!epcm->running)
return 0;
- ptr3 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
- ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel);
- ptr4 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
- if (ptr3 != ptr4) ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel);
- ptr2 = bytes_to_frames(runtime, ptr1);
- ptr2+= (ptr4 >> 3) * runtime->period_size;
- ptr=ptr2;
- if (ptr >= runtime->buffer_size)
- ptr -= runtime->buffer_size;
- /*
- printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
- "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n",
- ptr1, ptr2, ptr, (int)runtime->buffer_size,
- (int)runtime->period_size, (int)runtime->frame_bits,
- (int)runtime->rate);
- */
- return ptr;
+ prev_ptr = -1;
+ do {
+ ptr = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
+ ptr = (ptr >> 3) * runtime->period_size;
+ ptr += bytes_to_frames(runtime,
+ snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel));
+ if (ptr >= runtime->buffer_size)
+ ptr -= runtime->buffer_size;
+ if (prev_ptr == ptr)
+ return ptr;
+ prev_ptr = ptr;
+ } while (--timeout);
+ snd_printk(KERN_WARNING "ca0106: unstable DMA pointer!\n");
+ return 0;
}
/* pointer_capture callback */