diff options
-rw-r--r-- | include/sound/pcm.h | 1 | ||||
-rw-r--r-- | include/sound/pcm_oss.h | 2 | ||||
-rw-r--r-- | sound/core/oss/pcm_oss.c | 32 | ||||
-rw-r--r-- | sound/core/pcm_lib.c | 279 | ||||
-rw-r--r-- | sound/core/pcm_native.c | 2 |
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 | ||
67 | struct snd_pcm_oss_file { | 67 | struct 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 | ||
635 | static inline | ||
636 | snd_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 | ||
1953 | static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream, snd_pcm_uframes_t hw_ptr) | 1960 | static 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 | ||
2681 | static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream) | 2693 | static 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 | ||
2690 | static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait) | 2704 | static 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 | ||
194 | struct snd_pcm_hwptr_log { | 194 | struct 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 | ||
268 | static snd_pcm_uframes_t | ||
269 | snd_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 | |||
295 | static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, | 266 | static 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 | ||
322 | static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) | 293 | static 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 */ |
457 | int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) | 448 | int 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; |