aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/pcm.h1
-rw-r--r--include/sound/pcm_oss.h2
-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
5 files changed, 121 insertions, 195 deletions
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 4e18a6dbe690..fe1b131842be 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -271,7 +271,6 @@ struct snd_pcm_runtime {
271 int overrange; 271 int overrange;
272 snd_pcm_uframes_t avail_max; 272 snd_pcm_uframes_t avail_max;
273 snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */ 273 snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */
274 snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */
275 unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */ 274 unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */
276 snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */ 275 snd_pcm_sframes_t delay; /* extra delay; typically FIFO size */
277 276
diff --git a/include/sound/pcm_oss.h b/include/sound/pcm_oss.h
index cc4e226f35fd..760c969d885d 100644
--- a/include/sound/pcm_oss.h
+++ b/include/sound/pcm_oss.h
@@ -61,7 +61,7 @@ struct snd_pcm_oss_runtime {
61 struct snd_pcm_plugin *plugin_first; 61 struct snd_pcm_plugin *plugin_first;
62 struct snd_pcm_plugin *plugin_last; 62 struct snd_pcm_plugin *plugin_last;
63#endif 63#endif
64 unsigned int prev_hw_ptr_interrupt; 64 unsigned int prev_hw_ptr_period;
65}; 65};
66 66
67struct snd_pcm_oss_file { 67struct snd_pcm_oss_file {
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;