aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--sound/core/pcm_lib.c31
-rw-r--r--sound/core/pcm_local.h2
-rw-r--r--sound/core/pcm_native.c150
-rw-r--r--sound/core/pcm_trace.h50
4 files changed, 145 insertions, 88 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 9dc7bbfe8853..e73b6e4135f6 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -42,6 +42,7 @@
#define trace_hwptr(substream, pos, in_interrupt)
#define trace_xrun(substream)
#define trace_hw_ptr_error(substream, reason)
+#define trace_applptr(substream, prev, curr)
#endif
static int fill_silence_frames(struct snd_pcm_substream *substream,
@@ -2101,6 +2102,30 @@ static int pcm_accessible_state(struct snd_pcm_runtime *runtime)
}
}
+/* update to the given appl_ptr and call ack callback if needed;
+ * when an error is returned, take back to the original value
+ */
+int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream,
+ snd_pcm_uframes_t appl_ptr)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ snd_pcm_uframes_t old_appl_ptr = runtime->control->appl_ptr;
+ int ret;
+
+ runtime->control->appl_ptr = appl_ptr;
+ if (substream->ops->ack) {
+ ret = substream->ops->ack(substream);
+ if (ret < 0) {
+ runtime->control->appl_ptr = old_appl_ptr;
+ return ret;
+ }
+ }
+
+ trace_applptr(substream, old_appl_ptr, appl_ptr);
+
+ return 0;
+}
+
/* the common loop for read/write data */
snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
void *data, bool interleaved,
@@ -2220,9 +2245,9 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
appl_ptr += frames;
if (appl_ptr >= runtime->boundary)
appl_ptr -= runtime->boundary;
- runtime->control->appl_ptr = appl_ptr;
- if (substream->ops->ack)
- substream->ops->ack(substream);
+ err = pcm_lib_apply_appl_ptr(substream, appl_ptr);
+ if (err < 0)
+ goto _end_unlock;
offset += frames;
size -= frames;
diff --git a/sound/core/pcm_local.h b/sound/core/pcm_local.h
index e4bf2af62b02..16f254732b2a 100644
--- a/sound/core/pcm_local.h
+++ b/sound/core/pcm_local.h
@@ -27,6 +27,8 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream);
int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime,
snd_pcm_hw_param_t var, u_int32_t mask);
+int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream,
+ snd_pcm_uframes_t appl_ptr);
int snd_pcm_update_state(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime);
int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 076187ae8859..07995e645327 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -276,14 +276,14 @@ static int constrain_mask_params(struct snd_pcm_substream *substream,
old_mask = *m;
changed = snd_mask_refine(m, constrs_mask(constrs, k));
-
- trace_hw_mask_param(substream, k, 0, &old_mask, m);
-
- /* Set corresponding flag so that the caller gets it. */
- if (changed)
- params->cmask |= 1 << k;
if (changed < 0)
return changed;
+ if (changed == 0)
+ continue;
+
+ /* Set corresponding flag so that the caller gets it. */
+ trace_hw_mask_param(substream, k, 0, &old_mask, m);
+ params->cmask |= 1 << k;
}
return 0;
@@ -312,14 +312,14 @@ static int constrain_interval_params(struct snd_pcm_substream *substream,
old_interval = *i;
changed = snd_interval_refine(i, constrs_interval(constrs, k));
-
- trace_hw_interval_param(substream, k, 0, &old_interval, i);
-
- /* Set corresponding flag so that the caller gets it. */
- if (changed)
- params->cmask |= 1 << k;
if (changed < 0)
return changed;
+ if (changed == 0)
+ continue;
+
+ /* Set corresponding flag so that the caller gets it. */
+ trace_hw_interval_param(substream, k, 0, &old_interval, i);
+ params->cmask |= 1 << k;
}
return 0;
@@ -406,31 +406,32 @@ retry:
}
changed = r->func(params, r);
-
- if (hw_is_mask(r->var)) {
- trace_hw_mask_param(substream, r->var, k + 1,
- &old_mask, hw_param_mask(params, r->var));
- }
- if (hw_is_interval(r->var)) {
- trace_hw_interval_param(substream, r->var, k + 1,
- &old_interval, hw_param_interval(params, r->var));
- }
-
- rstamps[k] = stamp;
+ if (changed < 0)
+ return changed;
/*
- * When the parameters is changed, notify it to the caller
+ * When the parameter is changed, notify it to the caller
* by corresponding returned bit, then preparing for next
* iteration.
*/
if (changed && r->var >= 0) {
+ if (hw_is_mask(r->var)) {
+ trace_hw_mask_param(substream, r->var,
+ k + 1, &old_mask,
+ hw_param_mask(params, r->var));
+ }
+ if (hw_is_interval(r->var)) {
+ trace_hw_interval_param(substream, r->var,
+ k + 1, &old_interval,
+ hw_param_interval(params, r->var));
+ }
+
params->cmask |= (1 << r->var);
vstamps[r->var] = stamp;
again = true;
}
- if (changed < 0)
- return changed;
- stamp++;
+
+ rstamps[k] = stamp++;
}
/* Iterate to evaluate all rules till no parameters are changed. */
@@ -527,13 +528,16 @@ static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
return PTR_ERR(params);
err = snd_pcm_hw_refine(substream, params);
- if (err >= 0)
- err = fixup_unreferenced_params(substream, params);
- if (copy_to_user(_params, params, sizeof(*params))) {
- if (!err)
- err = -EFAULT;
- }
+ if (err < 0)
+ goto end;
+ err = fixup_unreferenced_params(substream, params);
+ if (err < 0)
+ goto end;
+
+ if (copy_to_user(_params, params, sizeof(*params)))
+ err = -EFAULT;
+end:
kfree(params);
return err;
}
@@ -600,7 +604,7 @@ static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
const int *v;
struct snd_mask old_mask;
struct snd_interval old_interval;
- int err;
+ int changed;
for (v = vars; *v != -1; v++) {
/* Keep old parameter to trace. */
@@ -613,13 +617,15 @@ static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
old_interval = *hw_param_interval(params, *v);
}
if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE)
- err = snd_pcm_hw_param_first(pcm, params, *v, NULL);
+ changed = snd_pcm_hw_param_first(pcm, params, *v, NULL);
else
- err = snd_pcm_hw_param_last(pcm, params, *v, NULL);
- if (snd_BUG_ON(err < 0))
- return err;
+ changed = snd_pcm_hw_param_last(pcm, params, *v, NULL);
+ if (snd_BUG_ON(changed < 0))
+ return changed;
+ if (changed == 0)
+ continue;
- /* Trace the parameter. */
+ /* Trace the changed parameter. */
if (hw_is_mask(*v)) {
trace_hw_mask_param(pcm, *v, 0, &old_mask,
hw_param_mask(params, *v));
@@ -749,11 +755,12 @@ static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
return PTR_ERR(params);
err = snd_pcm_hw_params(substream, params);
- if (copy_to_user(_params, params, sizeof(*params))) {
- if (!err)
- err = -EFAULT;
- }
+ if (err < 0)
+ goto end;
+ if (copy_to_user(_params, params, sizeof(*params)))
+ err = -EFAULT;
+end:
kfree(params);
return err;
}
@@ -2591,27 +2598,6 @@ static int do_pcm_hwsync(struct snd_pcm_substream *substream)
}
}
-/* update to the given appl_ptr and call ack callback if needed;
- * when an error is returned, take back to the original value
- */
-static int apply_appl_ptr(struct snd_pcm_substream *substream,
- snd_pcm_uframes_t appl_ptr)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- snd_pcm_uframes_t old_appl_ptr = runtime->control->appl_ptr;
- int ret;
-
- runtime->control->appl_ptr = appl_ptr;
- if (substream->ops->ack) {
- ret = substream->ops->ack(substream);
- if (ret < 0) {
- runtime->control->appl_ptr = old_appl_ptr;
- return ret;
- }
- }
- return 0;
-}
-
/* increase the appl_ptr; returns the processed frames or a negative error */
static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream,
snd_pcm_uframes_t frames,
@@ -2628,7 +2614,7 @@ static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream,
appl_ptr = runtime->control->appl_ptr + frames;
if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary)
appl_ptr -= runtime->boundary;
- ret = apply_appl_ptr(substream, appl_ptr);
+ ret = pcm_lib_apply_appl_ptr(substream, appl_ptr);
return ret < 0 ? ret : frames;
}
@@ -2648,7 +2634,7 @@ static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream,
appl_ptr = runtime->control->appl_ptr - frames;
if (appl_ptr < 0)
appl_ptr += runtime->boundary;
- ret = apply_appl_ptr(substream, appl_ptr);
+ ret = pcm_lib_apply_appl_ptr(substream, appl_ptr);
return ret < 0 ? ret : frames;
}
@@ -2776,7 +2762,8 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
}
snd_pcm_stream_lock_irq(substream);
if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
- err = apply_appl_ptr(substream, sync_ptr.c.control.appl_ptr);
+ err = pcm_lib_apply_appl_ptr(substream,
+ sync_ptr.c.control.appl_ptr);
if (err < 0) {
snd_pcm_stream_unlock_irq(substream);
return err;
@@ -3699,14 +3686,17 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
}
snd_pcm_hw_convert_from_old_params(params, oparams);
err = snd_pcm_hw_refine(substream, params);
- if (err >= 0)
- err = fixup_unreferenced_params(substream, params);
- snd_pcm_hw_convert_to_old_params(oparams, params);
- if (copy_to_user(_oparams, oparams, sizeof(*oparams))) {
- if (!err)
- err = -EFAULT;
- }
+ if (err < 0)
+ goto out_old;
+ err = fixup_unreferenced_params(substream, params);
+ if (err < 0)
+ goto out_old;
+
+ snd_pcm_hw_convert_to_old_params(oparams, params);
+ if (copy_to_user(_oparams, oparams, sizeof(*oparams)))
+ err = -EFAULT;
+out_old:
kfree(oparams);
out:
kfree(params);
@@ -3729,14 +3719,16 @@ static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
err = PTR_ERR(oparams);
goto out;
}
+
snd_pcm_hw_convert_from_old_params(params, oparams);
err = snd_pcm_hw_params(substream, params);
- snd_pcm_hw_convert_to_old_params(oparams, params);
- if (copy_to_user(_oparams, oparams, sizeof(*oparams))) {
- if (!err)
- err = -EFAULT;
- }
+ if (err < 0)
+ goto out_old;
+ snd_pcm_hw_convert_to_old_params(oparams, params);
+ if (copy_to_user(_oparams, oparams, sizeof(*oparams)))
+ err = -EFAULT;
+out_old:
kfree(oparams);
out:
kfree(params);
diff --git a/sound/core/pcm_trace.h b/sound/core/pcm_trace.h
index b63b654da5ff..3ddec1b8ae46 100644
--- a/sound/core/pcm_trace.h
+++ b/sound/core/pcm_trace.h
@@ -34,9 +34,9 @@ TRACE_EVENT(hwptr,
__entry->old_hw_ptr = (substream)->runtime->status->hw_ptr;
__entry->hw_ptr_base = (substream)->runtime->hw_ptr_base;
),
- TP_printk("pcmC%dD%d%c/sub%d: %s: pos=%lu, old=%lu, base=%lu, period=%lu, buf=%lu",
+ TP_printk("pcmC%dD%d%s/sub%d: %s: pos=%lu, old=%lu, base=%lu, period=%lu, buf=%lu",
__entry->card, __entry->device,
- __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c',
+ __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? "p" : "c",
__entry->number,
__entry->in_interrupt ? "IRQ" : "POS",
(unsigned long)__entry->pos,
@@ -69,9 +69,9 @@ TRACE_EVENT(xrun,
__entry->old_hw_ptr = (substream)->runtime->status->hw_ptr;
__entry->hw_ptr_base = (substream)->runtime->hw_ptr_base;
),
- TP_printk("pcmC%dD%d%c/sub%d: XRUN: old=%lu, base=%lu, period=%lu, buf=%lu",
+ TP_printk("pcmC%dD%d%s/sub%d: XRUN: old=%lu, base=%lu, period=%lu, buf=%lu",
__entry->card, __entry->device,
- __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c',
+ __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? "p" : "c",
__entry->number,
(unsigned long)__entry->old_hw_ptr,
(unsigned long)__entry->hw_ptr_base,
@@ -96,12 +96,50 @@ TRACE_EVENT(hw_ptr_error,
__entry->stream = (substream)->stream;
__entry->reason = (why);
),
- TP_printk("pcmC%dD%d%c/sub%d: ERROR: %s",
+ TP_printk("pcmC%dD%d%s/sub%d: ERROR: %s",
__entry->card, __entry->device,
- __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c',
+ __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? "p" : "c",
__entry->number, __entry->reason)
);
+TRACE_EVENT(applptr,
+ TP_PROTO(struct snd_pcm_substream *substream, snd_pcm_uframes_t prev, snd_pcm_uframes_t curr),
+ TP_ARGS(substream, prev, curr),
+ TP_STRUCT__entry(
+ __field( unsigned int, card )
+ __field( unsigned int, device )
+ __field( unsigned int, number )
+ __field( unsigned int, stream )
+ __field( snd_pcm_uframes_t, prev )
+ __field( snd_pcm_uframes_t, curr )
+ __field( snd_pcm_uframes_t, avail )
+ __field( snd_pcm_uframes_t, period_size )
+ __field( snd_pcm_uframes_t, buffer_size )
+ ),
+ TP_fast_assign(
+ __entry->card = (substream)->pcm->card->number;
+ __entry->device = (substream)->pcm->device;
+ __entry->number = (substream)->number;
+ __entry->stream = (substream)->stream;
+ __entry->prev = (prev);
+ __entry->curr = (curr);
+ __entry->avail = (substream)->stream ? snd_pcm_capture_avail(substream->runtime) : snd_pcm_playback_avail(substream->runtime);
+ __entry->period_size = (substream)->runtime->period_size;
+ __entry->buffer_size = (substream)->runtime->buffer_size;
+ ),
+ TP_printk("pcmC%dD%d%s/sub%d: prev=%lu, curr=%lu, avail=%lu, period=%lu, buf=%lu",
+ __entry->card,
+ __entry->device,
+ __entry->stream ? "c" : "p",
+ __entry->number,
+ __entry->prev,
+ __entry->curr,
+ __entry->avail,
+ __entry->period_size,
+ __entry->buffer_size
+ )
+);
+
#endif /* _PCM_TRACE_H */
/* This part must be outside protection */