diff options
author | Takashi Iwai <tiwai@suse.de> | 2009-07-16 12:19:12 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2010-09-07 05:54:16 -0400 |
commit | add7c0a6a4b8669ebd726f9c08ba6002900ca671 (patch) | |
tree | 81c28ffce3985feafc2a6d07f33a7052c763c425 | |
parent | 9fe856e47e1751204faf3d604c6d20ab24bd3b93 (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>
-rw-r--r-- | sound/pci/ca0106/ca0106_main.c | 34 |
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) | |||
1002 | struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); | 1002 | struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); |
1003 | struct snd_pcm_runtime *runtime = substream->runtime; | 1003 | struct snd_pcm_runtime *runtime = substream->runtime; |
1004 | struct snd_ca0106_pcm *epcm = runtime->private_data; | 1004 | struct snd_ca0106_pcm *epcm = runtime->private_data; |
1005 | snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0; | 1005 | unsigned int ptr, prev_ptr; |
1006 | int channel = epcm->channel_id; | 1006 | int channel = epcm->channel_id; |
1007 | int timeout = 10; | ||
1007 | 1008 | ||
1008 | if (!epcm->running) | 1009 | if (!epcm->running) |
1009 | return 0; | 1010 | return 0; |
1010 | 1011 | ||
1011 | ptr3 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); | 1012 | prev_ptr = -1; |
1012 | ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel); | 1013 | do { |
1013 | ptr4 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); | 1014 | ptr = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); |
1014 | if (ptr3 != ptr4) ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel); | 1015 | ptr = (ptr >> 3) * runtime->period_size; |
1015 | ptr2 = bytes_to_frames(runtime, ptr1); | 1016 | ptr += bytes_to_frames(runtime, |
1016 | ptr2+= (ptr4 >> 3) * runtime->period_size; | 1017 | snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel)); |
1017 | ptr=ptr2; | 1018 | if (ptr >= runtime->buffer_size) |
1018 | if (ptr >= runtime->buffer_size) | 1019 | ptr -= runtime->buffer_size; |
1019 | ptr -= runtime->buffer_size; | 1020 | if (prev_ptr == ptr) |
1020 | /* | 1021 | return ptr; |
1021 | printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, " | 1022 | prev_ptr = ptr; |
1022 | "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", | 1023 | } while (--timeout); |
1023 | ptr1, ptr2, ptr, (int)runtime->buffer_size, | 1024 | snd_printk(KERN_WARNING "ca0106: unstable DMA pointer!\n"); |
1024 | (int)runtime->period_size, (int)runtime->frame_bits, | 1025 | return 0; |
1025 | (int)runtime->rate); | ||
1026 | */ | ||
1027 | return ptr; | ||
1028 | } | 1026 | } |
1029 | 1027 | ||
1030 | /* pointer_capture callback */ | 1028 | /* pointer_capture callback */ |