aboutsummaryrefslogtreecommitdiff
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.c34
1 files changed, 31 insertions, 3 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index b75db8e9cc0..64449cb8f87 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);