diff options
Diffstat (limited to 'sound/core/pcm_lib.c')
-rw-r--r-- | sound/core/pcm_lib.c | 34 |
1 files changed, 31 insertions, 3 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index b75db8e9cc0f..64449cb8f873 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -373,6 +373,29 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, (unsigned long)new_hw_ptr, (unsigned long)runtime->hw_ptr_base); } + + if (runtime->no_period_wakeup) { + snd_pcm_sframes_t xrun_threshold; + /* + * Without regular period interrupts, we have to check + * the elapsed time to detect xruns. + */ + jdelta = jiffies - runtime->hw_ptr_jiffies; + if (jdelta < runtime->hw_ptr_buffer_jiffies / 2) + goto no_delta_check; + hdelta = jdelta - delta * HZ / runtime->rate; + xrun_threshold = runtime->hw_ptr_buffer_jiffies / 2 + 1; + while (hdelta > xrun_threshold) { + delta += runtime->buffer_size; + hw_base += runtime->buffer_size; + if (hw_base >= runtime->boundary) + hw_base = 0; + new_hw_ptr = hw_base + pos; + hdelta -= runtime->hw_ptr_buffer_jiffies; + } + goto no_delta_check; + } + /* something must be really wrong */ if (delta >= runtime->buffer_size + runtime->period_size) { hw_ptr_error(substream, @@ -442,6 +465,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, (long)old_hw_ptr); } + no_delta_check: if (runtime->status->hw_ptr == new_hw_ptr) return 0; @@ -1070,8 +1094,10 @@ int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond, struct snd_pcm_hw_rule *new; unsigned int new_rules = constrs->rules_all + 16; new = kcalloc(new_rules, sizeof(*c), GFP_KERNEL); - if (!new) + if (!new) { + va_end(args); return -ENOMEM; + } if (constrs->rules) { memcpy(new, constrs->rules, constrs->rules_num * sizeof(*c)); @@ -1087,8 +1113,10 @@ int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond, c->private = private; k = 0; while (1) { - if (snd_BUG_ON(k >= ARRAY_SIZE(c->deps))) + if (snd_BUG_ON(k >= ARRAY_SIZE(c->deps))) { + va_end(args); return -EINVAL; + } c->deps[k++] = dep; if (dep < 0) break; @@ -1097,7 +1125,7 @@ int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond, constrs->rules_num++; va_end(args); return 0; -} +} EXPORT_SYMBOL(snd_pcm_hw_rule_add); |