aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core
diff options
context:
space:
mode:
authorJaroslav Kysela <perex@perex.cz>2010-01-05 11:19:34 -0500
committerJaroslav Kysela <perex@perex.cz>2010-01-07 09:47:38 -0500
commitf240406babfe1526998e10583ea5eccc2676a433 (patch)
tree311f0dd33f0ec87bd0ac48d4871f67ad78b9ee36 /sound/core
parent4d96eb255c53ab5e39b37fd4d484ea3dc39ab456 (diff)
ALSA: pcm_lib - cleanup & merge hw_ptr update functions
Do general cleanup in snd_pcm_update_hw_ptr*() routines and merge them. The main change is hw_ptr_interrupt variable removal to simplify code logic. This variable can be computed directly from hw_ptr. Ensure that updated hw_ptr is not lower than previous one (it was possible with old code in some obscure situations when interrupt was delayed or the lowlevel driver returns wrong ring buffer position value). Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/core')
-rw-r--r--sound/core/oss/pcm_oss.c32
-rw-r--r--sound/core/pcm_lib.c279
-rw-r--r--sound/core/pcm_native.c2
3 files changed, 120 insertions, 193 deletions
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index d9c96353121a..255ad910077a 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -632,6 +632,13 @@ static long snd_pcm_alsa_frames(struct snd_pcm_substream *substream, long bytes)
632 return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes); 632 return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes);
633} 633}
634 634
635static inline
636snd_pcm_uframes_t get_hw_ptr_period(struct snd_pcm_runtime *runtime)
637{
638 snd_pcm_uframes_t ptr = runtime->status->hw_ptr;
639 return ptr - (ptr % runtime->period_size);
640}
641
635/* define extended formats in the recent OSS versions (if any) */ 642/* define extended formats in the recent OSS versions (if any) */
636/* linear formats */ 643/* linear formats */
637#define AFMT_S32_LE 0x00001000 644#define AFMT_S32_LE 0x00001000
@@ -1102,7 +1109,7 @@ static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
1102 return err; 1109 return err;
1103 } 1110 }
1104 runtime->oss.prepare = 0; 1111 runtime->oss.prepare = 0;
1105 runtime->oss.prev_hw_ptr_interrupt = 0; 1112 runtime->oss.prev_hw_ptr_period = 0;
1106 runtime->oss.period_ptr = 0; 1113 runtime->oss.period_ptr = 0;
1107 runtime->oss.buffer_used = 0; 1114 runtime->oss.buffer_used = 0;
1108 1115
@@ -1950,7 +1957,8 @@ static int snd_pcm_oss_get_caps(struct snd_pcm_oss_file *pcm_oss_file)
1950 return result; 1957 return result;
1951} 1958}
1952 1959
1953static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream, snd_pcm_uframes_t hw_ptr) 1960static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream,
1961 snd_pcm_uframes_t hw_ptr)
1954{ 1962{
1955 struct snd_pcm_runtime *runtime = substream->runtime; 1963 struct snd_pcm_runtime *runtime = substream->runtime;
1956 snd_pcm_uframes_t appl_ptr; 1964 snd_pcm_uframes_t appl_ptr;
@@ -1986,7 +1994,8 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
1986 if (runtime->oss.trigger) 1994 if (runtime->oss.trigger)
1987 goto _skip1; 1995 goto _skip1;
1988 if (atomic_read(&psubstream->mmap_count)) 1996 if (atomic_read(&psubstream->mmap_count))
1989 snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt); 1997 snd_pcm_oss_simulate_fill(psubstream,
1998 get_hw_ptr_period(runtime));
1990 runtime->oss.trigger = 1; 1999 runtime->oss.trigger = 1;
1991 runtime->start_threshold = 1; 2000 runtime->start_threshold = 1;
1992 cmd = SNDRV_PCM_IOCTL_START; 2001 cmd = SNDRV_PCM_IOCTL_START;
@@ -2105,11 +2114,12 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream
2105 info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size); 2114 info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size);
2106 if (atomic_read(&substream->mmap_count)) { 2115 if (atomic_read(&substream->mmap_count)) {
2107 snd_pcm_sframes_t n; 2116 snd_pcm_sframes_t n;
2108 n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt; 2117 delay = get_hw_ptr_period(runtime);
2118 n = delay - runtime->oss.prev_hw_ptr_period;
2109 if (n < 0) 2119 if (n < 0)
2110 n += runtime->boundary; 2120 n += runtime->boundary;
2111 info.blocks = n / runtime->period_size; 2121 info.blocks = n / runtime->period_size;
2112 runtime->oss.prev_hw_ptr_interrupt = delay; 2122 runtime->oss.prev_hw_ptr_period = delay;
2113 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 2123 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
2114 snd_pcm_oss_simulate_fill(substream, delay); 2124 snd_pcm_oss_simulate_fill(substream, delay);
2115 info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX; 2125 info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX;
@@ -2673,18 +2683,22 @@ static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream)
2673{ 2683{
2674 struct snd_pcm_runtime *runtime = substream->runtime; 2684 struct snd_pcm_runtime *runtime = substream->runtime;
2675 if (atomic_read(&substream->mmap_count)) 2685 if (atomic_read(&substream->mmap_count))
2676 return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; 2686 return runtime->oss.prev_hw_ptr_period !=
2687 get_hw_ptr_period(runtime);
2677 else 2688 else
2678 return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames; 2689 return snd_pcm_playback_avail(runtime) >=
2690 runtime->oss.period_frames;
2679} 2691}
2680 2692
2681static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream) 2693static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream)
2682{ 2694{
2683 struct snd_pcm_runtime *runtime = substream->runtime; 2695 struct snd_pcm_runtime *runtime = substream->runtime;
2684 if (atomic_read(&substream->mmap_count)) 2696 if (atomic_read(&substream->mmap_count))
2685 return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; 2697 return runtime->oss.prev_hw_ptr_period !=
2698 get_hw_ptr_period(runtime);
2686 else 2699 else
2687 return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames; 2700 return snd_pcm_capture_avail(runtime) >=
2701 runtime->oss.period_frames;
2688} 2702}
2689 2703
2690static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait) 2704static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait)
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 1990afb8a735..70a4f7428d78 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -172,6 +172,7 @@ static void xrun(struct snd_pcm_substream *substream)
172#define hw_ptr_error(substream, fmt, args...) \ 172#define hw_ptr_error(substream, fmt, args...) \
173 do { \ 173 do { \
174 if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \ 174 if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \
175 xrun_log_show(substream); \
175 if (printk_ratelimit()) { \ 176 if (printk_ratelimit()) { \
176 snd_printd("PCM: " fmt, ##args); \ 177 snd_printd("PCM: " fmt, ##args); \
177 } \ 178 } \
@@ -188,7 +189,6 @@ struct hwptr_log_entry {
188 snd_pcm_uframes_t buffer_size; 189 snd_pcm_uframes_t buffer_size;
189 snd_pcm_uframes_t old_hw_ptr; 190 snd_pcm_uframes_t old_hw_ptr;
190 snd_pcm_uframes_t hw_ptr_base; 191 snd_pcm_uframes_t hw_ptr_base;
191 snd_pcm_uframes_t hw_ptr_interrupt;
192}; 192};
193 193
194struct snd_pcm_hwptr_log { 194struct snd_pcm_hwptr_log {
@@ -220,7 +220,6 @@ static void xrun_log(struct snd_pcm_substream *substream,
220 entry->buffer_size = runtime->buffer_size;; 220 entry->buffer_size = runtime->buffer_size;;
221 entry->old_hw_ptr = runtime->status->hw_ptr; 221 entry->old_hw_ptr = runtime->status->hw_ptr;
222 entry->hw_ptr_base = runtime->hw_ptr_base; 222 entry->hw_ptr_base = runtime->hw_ptr_base;
223 entry->hw_ptr_interrupt = runtime->hw_ptr_interrupt;;
224 log->idx = (log->idx + 1) % XRUN_LOG_CNT; 223 log->idx = (log->idx + 1) % XRUN_LOG_CNT;
225} 224}
226 225
@@ -241,14 +240,13 @@ static void xrun_log_show(struct snd_pcm_substream *substream)
241 entry = &log->entries[idx]; 240 entry = &log->entries[idx];
242 if (entry->period_size == 0) 241 if (entry->period_size == 0)
243 break; 242 break;
244 snd_printd("hwptr log: %s: j=%lu, pos=0x%lx/0x%lx/0x%lx, " 243 snd_printd("hwptr log: %s: j=%lu, pos=%ld/%ld/%ld, "
245 "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n", 244 "hwptr=%ld/%ld\n",
246 name, entry->jiffies, (unsigned long)entry->pos, 245 name, entry->jiffies, (unsigned long)entry->pos,
247 (unsigned long)entry->period_size, 246 (unsigned long)entry->period_size,
248 (unsigned long)entry->buffer_size, 247 (unsigned long)entry->buffer_size,
249 (unsigned long)entry->old_hw_ptr, 248 (unsigned long)entry->old_hw_ptr,
250 (unsigned long)entry->hw_ptr_base, 249 (unsigned long)entry->hw_ptr_base);
251 (unsigned long)entry->hw_ptr_interrupt);
252 idx++; 250 idx++;
253 idx %= XRUN_LOG_CNT; 251 idx %= XRUN_LOG_CNT;
254 } 252 }
@@ -265,33 +263,6 @@ static void xrun_log_show(struct snd_pcm_substream *substream)
265 263
266#endif 264#endif
267 265
268static snd_pcm_uframes_t
269snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream,
270 struct snd_pcm_runtime *runtime)
271{
272 snd_pcm_uframes_t pos;
273
274 pos = substream->ops->pointer(substream);
275 if (pos == SNDRV_PCM_POS_XRUN)
276 return pos; /* XRUN */
277 if (pos >= runtime->buffer_size) {
278 if (printk_ratelimit()) {
279 char name[16];
280 pcm_debug_name(substream, name, sizeof(name));
281 xrun_log_show(substream);
282 snd_printd(KERN_ERR "BUG: %s, pos = 0x%lx, "
283 "buffer size = 0x%lx, period size = 0x%lx\n",
284 name, pos, runtime->buffer_size,
285 runtime->period_size);
286 }
287 pos = 0;
288 }
289 pos -= pos % runtime->min_align;
290 if (xrun_debug(substream, XRUN_DEBUG_LOG))
291 xrun_log(substream, pos);
292 return pos;
293}
294
295static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, 266static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
296 struct snd_pcm_runtime *runtime) 267 struct snd_pcm_runtime *runtime)
297{ 268{
@@ -319,72 +290,88 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
319 return 0; 290 return 0;
320} 291}
321 292
322static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) 293static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
294 unsigned int in_interrupt)
323{ 295{
324 struct snd_pcm_runtime *runtime = substream->runtime; 296 struct snd_pcm_runtime *runtime = substream->runtime;
325 snd_pcm_uframes_t pos; 297 snd_pcm_uframes_t pos;
326 snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_ptr_interrupt, hw_base; 298 snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
327 snd_pcm_sframes_t hdelta, delta; 299 snd_pcm_sframes_t hdelta, delta;
328 unsigned long jdelta; 300 unsigned long jdelta;
329 301
330 old_hw_ptr = runtime->status->hw_ptr; 302 old_hw_ptr = runtime->status->hw_ptr;
331 pos = snd_pcm_update_hw_ptr_pos(substream, runtime); 303 pos = substream->ops->pointer(substream);
332 if (pos == SNDRV_PCM_POS_XRUN) { 304 if (pos == SNDRV_PCM_POS_XRUN) {
333 xrun(substream); 305 xrun(substream);
334 return -EPIPE; 306 return -EPIPE;
335 } 307 }
336 if (xrun_debug(substream, XRUN_DEBUG_PERIODUPDATE)) { 308 if (pos >= runtime->buffer_size) {
337 char name[16]; 309 if (printk_ratelimit()) {
338 pcm_debug_name(substream, name, sizeof(name)); 310 char name[16];
339 snd_printd("period_update: %s: pos=0x%x/0x%x/0x%x, " 311 pcm_debug_name(substream, name, sizeof(name));
340 "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n", 312 xrun_log_show(substream);
341 name, (unsigned int)pos, 313 snd_printd(KERN_ERR "BUG: %s, pos = %ld, "
342 (unsigned int)runtime->period_size, 314 "buffer size = %ld, period size = %ld\n",
343 (unsigned int)runtime->buffer_size, 315 name, pos, runtime->buffer_size,
344 (unsigned long)old_hw_ptr, 316 runtime->period_size);
345 (unsigned long)runtime->hw_ptr_base, 317 }
346 (unsigned long)runtime->hw_ptr_interrupt); 318 pos = 0;
347 } 319 }
320 pos -= pos % runtime->min_align;
321 if (xrun_debug(substream, XRUN_DEBUG_LOG))
322 xrun_log(substream, pos);
348 hw_base = runtime->hw_ptr_base; 323 hw_base = runtime->hw_ptr_base;
349 new_hw_ptr = hw_base + pos; 324 new_hw_ptr = hw_base + pos;
350 hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size; 325 if (in_interrupt) {
351 delta = new_hw_ptr - hw_ptr_interrupt; 326 /* we know that one period was processed */
352 if (hw_ptr_interrupt >= runtime->boundary) { 327 /* delta = "expected next hw_ptr" for in_interrupt != 0 */
353 hw_ptr_interrupt -= runtime->boundary; 328 delta = old_hw_ptr - (old_hw_ptr % runtime->period_size)
354 if (hw_base < runtime->boundary / 2) 329 + runtime->period_size;
355 /* hw_base was already lapped; recalc delta */ 330 if (delta > new_hw_ptr) {
356 delta = new_hw_ptr - hw_ptr_interrupt;
357 }
358 if (delta < 0) {
359 if (runtime->periods == 1 || new_hw_ptr < old_hw_ptr)
360 delta += runtime->buffer_size;
361 if (delta < 0) {
362 xrun_log_show(substream);
363 hw_ptr_error(substream,
364 "Unexpected hw_pointer value "
365 "(stream=%i, pos=%ld, intr_ptr=%ld)\n",
366 substream->stream, (long)pos,
367 (long)hw_ptr_interrupt);
368#if 1
369 /* simply skipping the hwptr update seems more
370 * robust in some cases, e.g. on VMware with
371 * inaccurate timer source
372 */
373 return 0; /* skip this update */
374#else
375 /* rebase to interrupt position */
376 hw_base = new_hw_ptr = hw_ptr_interrupt;
377 /* align hw_base to buffer_size */
378 hw_base -= hw_base % runtime->buffer_size;
379 delta = 0;
380#endif
381 } else {
382 hw_base += runtime->buffer_size; 331 hw_base += runtime->buffer_size;
383 if (hw_base >= runtime->boundary) 332 if (hw_base >= runtime->boundary)
384 hw_base = 0; 333 hw_base = 0;
385 new_hw_ptr = hw_base + pos; 334 new_hw_ptr = hw_base + pos;
335 goto __delta;
386 } 336 }
387 } 337 }
338 /* new_hw_ptr might be lower than old_hw_ptr in case when */
339 /* pointer crosses the end of the ring buffer */
340 if (new_hw_ptr < old_hw_ptr) {
341 hw_base += runtime->buffer_size;
342 if (hw_base >= runtime->boundary)
343 hw_base = 0;
344 new_hw_ptr = hw_base + pos;
345 }
346 __delta:
347 delta = (new_hw_ptr - old_hw_ptr) % runtime->boundary;
348 if (xrun_debug(substream, in_interrupt ?
349 XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) {
350 char name[16];
351 pcm_debug_name(substream, name, sizeof(name));
352 snd_printd("%s_update: %s: pos=%u/%u/%u, "
353 "hwptr=%ld/%ld/%ld/%ld\n",
354 in_interrupt ? "period" : "hwptr",
355 name,
356 (unsigned int)pos,
357 (unsigned int)runtime->period_size,
358 (unsigned int)runtime->buffer_size,
359 (unsigned long)delta,
360 (unsigned long)old_hw_ptr,
361 (unsigned long)new_hw_ptr,
362 (unsigned long)runtime->hw_ptr_base);
363 }
364 /* something must be really wrong */
365 if (delta >= runtime->buffer_size) {
366 hw_ptr_error(substream,
367 "Unexpected hw_pointer value %s"
368 "(stream=%i, pos=%ld, new_hw_ptr=%ld, "
369 "old_hw_ptr=%ld)\n",
370 in_interrupt ? "[Q] " : "[P]",
371 substream->stream, (long)pos,
372 (long)new_hw_ptr, (long)old_hw_ptr);
373 return 0;
374 }
388 375
389 /* Do jiffies check only in xrun_debug mode */ 376 /* Do jiffies check only in xrun_debug mode */
390 if (!xrun_debug(substream, XRUN_DEBUG_JIFFIESCHECK)) 377 if (!xrun_debug(substream, XRUN_DEBUG_JIFFIESCHECK))
@@ -396,7 +383,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
396 */ 383 */
397 if (runtime->hw.info & SNDRV_PCM_INFO_BATCH) 384 if (runtime->hw.info & SNDRV_PCM_INFO_BATCH)
398 goto no_jiffies_check; 385 goto no_jiffies_check;
399 hdelta = new_hw_ptr - old_hw_ptr; 386 hdelta = delta;
400 if (hdelta < runtime->delay) 387 if (hdelta < runtime->delay)
401 goto no_jiffies_check; 388 goto no_jiffies_check;
402 hdelta -= runtime->delay; 389 hdelta -= runtime->delay;
@@ -405,45 +392,49 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
405 delta = jdelta / 392 delta = jdelta /
406 (((runtime->period_size * HZ) / runtime->rate) 393 (((runtime->period_size * HZ) / runtime->rate)
407 + HZ/100); 394 + HZ/100);
408 xrun_log_show(substream); 395 /* move new_hw_ptr according jiffies not pos variable */
396 new_hw_ptr = old_hw_ptr;
397 /* use loop to avoid checks for delta overflows */
398 /* the delta value is small or zero in most cases */
399 while (delta > 0) {
400 new_hw_ptr += runtime->period_size;
401 if (new_hw_ptr >= runtime->boundary)
402 new_hw_ptr -= runtime->boundary;
403 delta--;
404 }
405 /* align hw_base to buffer_size */
406 hw_base = new_hw_ptr - (new_hw_ptr % runtime->buffer_size);
407 delta = 0;
409 hw_ptr_error(substream, 408 hw_ptr_error(substream,
410 "hw_ptr skipping! [Q] " 409 "hw_ptr skipping! %s"
411 "(pos=%ld, delta=%ld, period=%ld, " 410 "(pos=%ld, delta=%ld, period=%ld, "
412 "jdelta=%lu/%lu/%lu)\n", 411 "jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n",
412 in_interrupt ? "[Q] " : "",
413 (long)pos, (long)hdelta, 413 (long)pos, (long)hdelta,
414 (long)runtime->period_size, jdelta, 414 (long)runtime->period_size, jdelta,
415 ((hdelta * HZ) / runtime->rate), delta); 415 ((hdelta * HZ) / runtime->rate), delta,
416 hw_ptr_interrupt = runtime->hw_ptr_interrupt + 416 (unsigned long)old_hw_ptr,
417 runtime->period_size * delta; 417 (unsigned long)new_hw_ptr);
418 if (hw_ptr_interrupt >= runtime->boundary)
419 hw_ptr_interrupt -= runtime->boundary;
420 /* rebase to interrupt position */
421 hw_base = new_hw_ptr = hw_ptr_interrupt;
422 /* align hw_base to buffer_size */
423 hw_base -= hw_base % runtime->buffer_size;
424 delta = 0;
425 } 418 }
426 no_jiffies_check: 419 no_jiffies_check:
427 if (delta > runtime->period_size + runtime->period_size / 2) { 420 if (delta > runtime->period_size + runtime->period_size / 2) {
428 xrun_log_show(substream);
429 hw_ptr_error(substream, 421 hw_ptr_error(substream,
430 "Lost interrupts? " 422 "Lost interrupts? %s"
431 "(stream=%i, delta=%ld, intr_ptr=%ld)\n", 423 "(stream=%i, delta=%ld, new_hw_ptr=%ld, "
424 "old_hw_ptr=%ld)\n",
425 in_interrupt ? "[Q] " : "",
432 substream->stream, (long)delta, 426 substream->stream, (long)delta,
433 (long)hw_ptr_interrupt); 427 (long)new_hw_ptr,
434 /* rebase hw_ptr_interrupt */ 428 (long)old_hw_ptr);
435 hw_ptr_interrupt =
436 new_hw_ptr - new_hw_ptr % runtime->period_size;
437 } 429 }
438 runtime->hw_ptr_interrupt = hw_ptr_interrupt; 430
431 if (runtime->status->hw_ptr == new_hw_ptr)
432 return 0;
439 433
440 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && 434 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
441 runtime->silence_size > 0) 435 runtime->silence_size > 0)
442 snd_pcm_playback_silence(substream, new_hw_ptr); 436 snd_pcm_playback_silence(substream, new_hw_ptr);
443 437
444 if (runtime->status->hw_ptr == new_hw_ptr)
445 return 0;
446
447 runtime->hw_ptr_base = hw_base; 438 runtime->hw_ptr_base = hw_base;
448 runtime->status->hw_ptr = new_hw_ptr; 439 runtime->status->hw_ptr = new_hw_ptr;
449 runtime->hw_ptr_jiffies = jiffies; 440 runtime->hw_ptr_jiffies = jiffies;
@@ -456,83 +447,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
456/* CAUTION: call it with irq disabled */ 447/* CAUTION: call it with irq disabled */
457int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) 448int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
458{ 449{
459 struct snd_pcm_runtime *runtime = substream->runtime; 450 return snd_pcm_update_hw_ptr0(substream, 0);
460 snd_pcm_uframes_t pos;
461 snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
462 snd_pcm_sframes_t delta;
463 unsigned long jdelta;
464
465 old_hw_ptr = runtime->status->hw_ptr;
466 pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
467 if (pos == SNDRV_PCM_POS_XRUN) {
468 xrun(substream);
469 return -EPIPE;
470 }
471 if (xrun_debug(substream, XRUN_DEBUG_HWPTRUPDATE)) {
472 char name[16];
473 pcm_debug_name(substream, name, sizeof(name));
474 snd_printd("hw_update: %s: pos=0x%x/0x%x/0x%x, "
475 "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n",
476 name, (unsigned int)pos,
477 (unsigned int)runtime->period_size,
478 (unsigned int)runtime->buffer_size,
479 (unsigned long)old_hw_ptr,
480 (unsigned long)runtime->hw_ptr_base,
481 (unsigned long)runtime->hw_ptr_interrupt);
482 }
483
484 hw_base = runtime->hw_ptr_base;
485 new_hw_ptr = hw_base + pos;
486
487 delta = new_hw_ptr - old_hw_ptr;
488 jdelta = jiffies - runtime->hw_ptr_jiffies;
489 if (delta < 0) {
490 delta += runtime->buffer_size;
491 if (delta < 0) {
492 xrun_log_show(substream);
493 hw_ptr_error(substream,
494 "Unexpected hw_pointer value [2] "
495 "(stream=%i, pos=%ld, old_ptr=%ld, jdelta=%li)\n",
496 substream->stream, (long)pos,
497 (long)old_hw_ptr, jdelta);
498 return 0;
499 }
500 hw_base += runtime->buffer_size;
501 if (hw_base >= runtime->boundary)
502 hw_base = 0;
503 new_hw_ptr = hw_base + pos;
504 }
505 /* Do jiffies check only in xrun_debug mode */
506 if (!xrun_debug(substream, XRUN_DEBUG_JIFFIESCHECK))
507 goto no_jiffies_check;
508 if (delta < runtime->delay)
509 goto no_jiffies_check;
510 delta -= runtime->delay;
511 if (((delta * HZ) / runtime->rate) > jdelta + HZ/100) {
512 xrun_log_show(substream);
513 hw_ptr_error(substream,
514 "hw_ptr skipping! "
515 "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n",
516 (long)pos, (long)delta,
517 (long)runtime->period_size, jdelta,
518 ((delta * HZ) / runtime->rate));
519 return 0;
520 }
521 no_jiffies_check:
522 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
523 runtime->silence_size > 0)
524 snd_pcm_playback_silence(substream, new_hw_ptr);
525
526 if (runtime->status->hw_ptr == new_hw_ptr)
527 return 0;
528
529 runtime->hw_ptr_base = hw_base;
530 runtime->status->hw_ptr = new_hw_ptr;
531 runtime->hw_ptr_jiffies = jiffies;
532 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
533 snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
534
535 return snd_pcm_update_hw_ptr_post(substream, runtime);
536} 451}
537 452
538/** 453/**
@@ -1744,7 +1659,7 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
1744 1659
1745 snd_pcm_stream_lock_irqsave(substream, flags); 1660 snd_pcm_stream_lock_irqsave(substream, flags);
1746 if (!snd_pcm_running(substream) || 1661 if (!snd_pcm_running(substream) ||
1747 snd_pcm_update_hw_ptr_interrupt(substream) < 0) 1662 snd_pcm_update_hw_ptr0(substream, 1) < 0)
1748 goto _end; 1663 goto _end;
1749 1664
1750 if (substream->timer_running) 1665 if (substream->timer_running)
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 29ab46a12e11..8e777f71717c 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1247,8 +1247,6 @@ static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int state)
1247 if (err < 0) 1247 if (err < 0)
1248 return err; 1248 return err;
1249 runtime->hw_ptr_base = 0; 1249 runtime->hw_ptr_base = 0;
1250 runtime->hw_ptr_interrupt = runtime->status->hw_ptr -
1251 runtime->status->hw_ptr % runtime->period_size;
1252 runtime->silence_start = runtime->status->hw_ptr; 1250 runtime->silence_start = runtime->status->hw_ptr;
1253 runtime->silence_filled = 0; 1251 runtime->silence_filled = 0;
1254 return 0; 1252 return 0;