aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@perex.cz>2010-08-18 08:16:54 -0400
committerJaroslav Kysela <perex@perex.cz>2010-08-19 03:15:24 -0400
commitd7d28bc29f4ea7c2d23ed002a9973c64a92bcdb8 (patch)
tree74bd0f5fc69f1b2b937921d01dcc5e3b52b77efc
parent597603d615d2b19a9e451d8cfac24372856a522d (diff)
ALSA: pcm midlevel code - add time check for double interrupt acknowledge
The current code in pcm_lib.c do all checks using only the position in the ring buffer. Unfortunately, where the interrupts gets delayed or merged into one, we need another timing source to check when the buffer size boundary overlaps to avoid the wrong updating of the ring buffer pointers. This code uses jiffies to check the right time window without any performance impact. Signed-off-by: Jaroslav Kysela <perex@perex.cz>
-rw-r--r--include/sound/pcm.h1
-rw-r--r--sound/core/pcm_lib.c14
-rw-r--r--sound/core/pcm_native.c2
3 files changed, 12 insertions, 5 deletions
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index dd76cdede64d..54c4ccf6fec2 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -274,6 +274,7 @@ struct snd_pcm_runtime {
274 snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */ 274 snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */
275 snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */ 275 snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */
276 unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */ 276 unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */
277 unsigned long hw_ptr_buffer_jiffies; /* buffer time in jiffies */
277 snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */ 278 snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */
278 279
279 /* -- HW params -- */ 280 /* -- HW params -- */
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index e9d98be190c5..d6ecca27bb68 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -329,11 +329,15 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
329 /* delta = "expected next hw_ptr" for in_interrupt != 0 */ 329 /* delta = "expected next hw_ptr" for in_interrupt != 0 */
330 delta = runtime->hw_ptr_interrupt + runtime->period_size; 330 delta = runtime->hw_ptr_interrupt + runtime->period_size;
331 if (delta > new_hw_ptr) { 331 if (delta > new_hw_ptr) {
332 hw_base += runtime->buffer_size; 332 /* check for double acknowledged interrupts */
333 if (hw_base >= runtime->boundary) 333 hdelta = jiffies - runtime->hw_ptr_jiffies;
334 hw_base = 0; 334 if (hdelta > runtime->hw_ptr_buffer_jiffies/2) {
335 new_hw_ptr = hw_base + pos; 335 hw_base += runtime->buffer_size;
336 goto __delta; 336 if (hw_base >= runtime->boundary)
337 hw_base = 0;
338 new_hw_ptr = hw_base + pos;
339 goto __delta;
340 }
337 } 341 }
338 } 342 }
339 /* new_hw_ptr might be lower than old_hw_ptr in case when */ 343 /* new_hw_ptr might be lower than old_hw_ptr in case when */
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 303ac04ff6e4..2d2e1b65ee9a 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -867,6 +867,8 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state)
867 struct snd_pcm_runtime *runtime = substream->runtime; 867 struct snd_pcm_runtime *runtime = substream->runtime;
868 snd_pcm_trigger_tstamp(substream); 868 snd_pcm_trigger_tstamp(substream);
869 runtime->hw_ptr_jiffies = jiffies; 869 runtime->hw_ptr_jiffies = jiffies;
870 runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) /
871 runtime->rate;
870 runtime->status->state = state; 872 runtime->status->state = state;
871 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && 873 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
872 runtime->silence_size > 0) 874 runtime->silence_size > 0)