aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/pcm_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/pcm_lib.c')
-rw-r--r--sound/core/pcm_lib.c54
1 files changed, 46 insertions, 8 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index fbb2e391591e..a2a792c18c40 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -209,9 +209,11 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
209{ 209{
210 struct snd_pcm_runtime *runtime = substream->runtime; 210 struct snd_pcm_runtime *runtime = substream->runtime;
211 snd_pcm_uframes_t pos; 211 snd_pcm_uframes_t pos;
212 snd_pcm_uframes_t new_hw_ptr, hw_ptr_interrupt, hw_base; 212 snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_ptr_interrupt, hw_base;
213 snd_pcm_sframes_t delta; 213 snd_pcm_sframes_t hdelta, delta;
214 unsigned long jdelta;
214 215
216 old_hw_ptr = runtime->status->hw_ptr;
215 pos = snd_pcm_update_hw_ptr_pos(substream, runtime); 217 pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
216 if (pos == SNDRV_PCM_POS_XRUN) { 218 if (pos == SNDRV_PCM_POS_XRUN) {
217 xrun(substream); 219 xrun(substream);
@@ -247,7 +249,37 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
247 new_hw_ptr = hw_base + pos; 249 new_hw_ptr = hw_base + pos;
248 } 250 }
249 } 251 }
250 if (delta > runtime->period_size) { 252 /* Skip the jiffies check for hardwares with BATCH flag.
253 * Such hardware usually just increases the position at each IRQ,
254 * thus it can't give any strange position.
255 */
256 if (runtime->hw.info & SNDRV_PCM_INFO_BATCH)
257 goto no_jiffies_check;
258 hdelta = new_hw_ptr - old_hw_ptr;
259 jdelta = jiffies - runtime->hw_ptr_jiffies;
260 if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/100) {
261 delta = jdelta /
262 (((runtime->period_size * HZ) / runtime->rate)
263 + HZ/100);
264 hw_ptr_error(substream,
265 "hw_ptr skipping! [Q] "
266 "(pos=%ld, delta=%ld, period=%ld, "
267 "jdelta=%lu/%lu/%lu)\n",
268 (long)pos, (long)hdelta,
269 (long)runtime->period_size, jdelta,
270 ((hdelta * HZ) / runtime->rate), delta);
271 hw_ptr_interrupt = runtime->hw_ptr_interrupt +
272 runtime->period_size * delta;
273 if (hw_ptr_interrupt >= runtime->boundary)
274 hw_ptr_interrupt -= runtime->boundary;
275 /* rebase to interrupt position */
276 hw_base = new_hw_ptr = hw_ptr_interrupt;
277 /* align hw_base to buffer_size */
278 hw_base -= hw_base % runtime->buffer_size;
279 delta = 0;
280 }
281 no_jiffies_check:
282 if (delta > runtime->period_size + runtime->period_size / 2) {
251 hw_ptr_error(substream, 283 hw_ptr_error(substream,
252 "Lost interrupts? " 284 "Lost interrupts? "
253 "(stream=%i, delta=%ld, intr_ptr=%ld)\n", 285 "(stream=%i, delta=%ld, intr_ptr=%ld)\n",
@@ -263,6 +295,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
263 295
264 runtime->hw_ptr_base = hw_base; 296 runtime->hw_ptr_base = hw_base;
265 runtime->status->hw_ptr = new_hw_ptr; 297 runtime->status->hw_ptr = new_hw_ptr;
298 runtime->hw_ptr_jiffies = jiffies;
266 runtime->hw_ptr_interrupt = hw_ptr_interrupt; 299 runtime->hw_ptr_interrupt = hw_ptr_interrupt;
267 300
268 return snd_pcm_update_hw_ptr_post(substream, runtime); 301 return snd_pcm_update_hw_ptr_post(substream, runtime);
@@ -275,6 +308,7 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
275 snd_pcm_uframes_t pos; 308 snd_pcm_uframes_t pos;
276 snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base; 309 snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
277 snd_pcm_sframes_t delta; 310 snd_pcm_sframes_t delta;
311 unsigned long jdelta;
278 312
279 old_hw_ptr = runtime->status->hw_ptr; 313 old_hw_ptr = runtime->status->hw_ptr;
280 pos = snd_pcm_update_hw_ptr_pos(substream, runtime); 314 pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
@@ -286,14 +320,15 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
286 new_hw_ptr = hw_base + pos; 320 new_hw_ptr = hw_base + pos;
287 321
288 delta = new_hw_ptr - old_hw_ptr; 322 delta = new_hw_ptr - old_hw_ptr;
323 jdelta = jiffies - runtime->hw_ptr_jiffies;
289 if (delta < 0) { 324 if (delta < 0) {
290 delta += runtime->buffer_size; 325 delta += runtime->buffer_size;
291 if (delta < 0) { 326 if (delta < 0) {
292 hw_ptr_error(substream, 327 hw_ptr_error(substream,
293 "Unexpected hw_pointer value [2] " 328 "Unexpected hw_pointer value [2] "
294 "(stream=%i, pos=%ld, old_ptr=%ld)\n", 329 "(stream=%i, pos=%ld, old_ptr=%ld, jdelta=%li)\n",
295 substream->stream, (long)pos, 330 substream->stream, (long)pos,
296 (long)old_hw_ptr); 331 (long)old_hw_ptr, jdelta);
297 return 0; 332 return 0;
298 } 333 }
299 hw_base += runtime->buffer_size; 334 hw_base += runtime->buffer_size;
@@ -301,12 +336,13 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
301 hw_base = 0; 336 hw_base = 0;
302 new_hw_ptr = hw_base + pos; 337 new_hw_ptr = hw_base + pos;
303 } 338 }
304 if (delta > runtime->period_size && runtime->periods > 1) { 339 if (((delta * HZ) / runtime->rate) > jdelta + HZ/100) {
305 hw_ptr_error(substream, 340 hw_ptr_error(substream,
306 "hw_ptr skipping! " 341 "hw_ptr skipping! "
307 "(pos=%ld, delta=%ld, period=%ld)\n", 342 "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n",
308 (long)pos, (long)delta, 343 (long)pos, (long)delta,
309 (long)runtime->period_size); 344 (long)runtime->period_size, jdelta,
345 ((delta * HZ) / runtime->rate));
310 return 0; 346 return 0;
311 } 347 }
312 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && 348 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
@@ -315,6 +351,7 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
315 351
316 runtime->hw_ptr_base = hw_base; 352 runtime->hw_ptr_base = hw_base;
317 runtime->status->hw_ptr = new_hw_ptr; 353 runtime->status->hw_ptr = new_hw_ptr;
354 runtime->hw_ptr_jiffies = jiffies;
318 355
319 return snd_pcm_update_hw_ptr_post(substream, runtime); 356 return snd_pcm_update_hw_ptr_post(substream, runtime);
320} 357}
@@ -1441,6 +1478,7 @@ static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
1441 runtime->status->hw_ptr %= runtime->buffer_size; 1478 runtime->status->hw_ptr %= runtime->buffer_size;
1442 else 1479 else
1443 runtime->status->hw_ptr = 0; 1480 runtime->status->hw_ptr = 0;
1481 runtime->hw_ptr_jiffies = jiffies;
1444 snd_pcm_stream_unlock_irqrestore(substream, flags); 1482 snd_pcm_stream_unlock_irqrestore(substream, flags);
1445 return 0; 1483 return 0;
1446} 1484}