forked from Minki/linux
Merge series "ASoC: merge soc_pcm_hw_param() rollback and soc_pcm_hw_free()" from Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>:
Hi Mark soc_pcm_hw_params() does rollback when failed (A), but, it is almost same as soc_pcm_hw_free(). static int soc_pcm_hw_params(xxx) { ... if (ret < 0) goto xxx_err; ... return ret; ^ component_err: | ... | interface_err: (A) ... | codec_err: | ... v return ret; } This kind of duplicated code can be a hotbed of bugs, thus, this patch-set share soc_pcm_hw_free() and rollback. Kuninori Morimoto (6): ASoC: soc.h: remove for_each_rtd_dais_rollback() ASoC: soc-pcm: move soc_pcm_hw_free() next to soc_pcm_hw_params() ASoC: soc-link: add mark for snd_soc_link_hw_params/free() ASoC: soc-component: add mark for snd_soc_pcm_component_hw_params/free() ASoC: soc-dai: add mark for snd_soc_dai_hw_params/free() ASoC: soc-pcm: add soc_pcm_hw_clean() and call it from soc_pcm_hw_params/free() include/sound/soc-component.h | 6 +- include/sound/soc-dai.h | 4 +- include/sound/soc-link.h | 3 +- include/sound/soc.h | 7 +- sound/soc/soc-component.c | 19 ++--- sound/soc/soc-dai.c | 13 +++- sound/soc/soc-dapm.c | 4 +- sound/soc/soc-link.c | 12 +++- sound/soc/soc-pcm.c | 131 ++++++++++++++-------------------- 9 files changed, 97 insertions(+), 102 deletions(-) -- 2.25.1
This commit is contained in:
commit
0d8902d576
@ -220,6 +220,7 @@ struct snd_soc_component {
|
||||
/* function mark */
|
||||
struct snd_pcm_substream *mark_module;
|
||||
struct snd_pcm_substream *mark_open;
|
||||
struct snd_pcm_substream *mark_hw_params;
|
||||
void *mark_pm;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
@ -459,10 +460,9 @@ int snd_soc_pcm_component_new(struct snd_soc_pcm_runtime *rtd);
|
||||
void snd_soc_pcm_component_free(struct snd_soc_pcm_runtime *rtd);
|
||||
int snd_soc_pcm_component_prepare(struct snd_pcm_substream *substream);
|
||||
int snd_soc_pcm_component_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_component **last);
|
||||
struct snd_pcm_hw_params *params);
|
||||
void snd_soc_pcm_component_hw_free(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_component *last);
|
||||
int rollback);
|
||||
int snd_soc_pcm_component_trigger(struct snd_pcm_substream *substream,
|
||||
int cmd);
|
||||
int snd_soc_pcm_component_pm_runtime_get(struct snd_soc_pcm_runtime *rtd,
|
||||
|
@ -149,7 +149,8 @@ int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params);
|
||||
void snd_soc_dai_hw_free(struct snd_soc_dai *dai,
|
||||
struct snd_pcm_substream *substream);
|
||||
struct snd_pcm_substream *substream,
|
||||
int rollback);
|
||||
int snd_soc_dai_startup(struct snd_soc_dai *dai,
|
||||
struct snd_pcm_substream *substream);
|
||||
void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
|
||||
@ -390,6 +391,7 @@ struct snd_soc_dai {
|
||||
|
||||
/* function mark */
|
||||
struct snd_pcm_substream *mark_startup;
|
||||
struct snd_pcm_substream *mark_hw_params;
|
||||
|
||||
/* bit field */
|
||||
unsigned int probed:1;
|
||||
|
@ -19,7 +19,8 @@ void snd_soc_link_shutdown(struct snd_pcm_substream *substream,
|
||||
int snd_soc_link_prepare(struct snd_pcm_substream *substream);
|
||||
int snd_soc_link_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params);
|
||||
void snd_soc_link_hw_free(struct snd_pcm_substream *substream);
|
||||
void snd_soc_link_hw_free(struct snd_pcm_substream *substream,
|
||||
int rollback);
|
||||
int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd);
|
||||
|
||||
int snd_soc_link_compr_startup(struct snd_compr_stream *cstream);
|
||||
|
@ -1161,6 +1161,7 @@ struct snd_soc_pcm_runtime {
|
||||
|
||||
/* function mark */
|
||||
struct snd_pcm_substream *mark_startup;
|
||||
struct snd_pcm_substream *mark_hw_params;
|
||||
|
||||
/* bit field */
|
||||
unsigned int pop_wait:1;
|
||||
@ -1183,21 +1184,15 @@ struct snd_soc_pcm_runtime {
|
||||
for ((i) = 0; \
|
||||
((i) < rtd->num_cpus) && ((dai) = asoc_rtd_to_cpu(rtd, i)); \
|
||||
(i)++)
|
||||
#define for_each_rtd_cpu_dais_rollback(rtd, i, dai) \
|
||||
for (; (--(i) >= 0) && ((dai) = asoc_rtd_to_cpu(rtd, i));)
|
||||
#define for_each_rtd_codec_dais(rtd, i, dai) \
|
||||
for ((i) = 0; \
|
||||
((i) < rtd->num_codecs) && ((dai) = asoc_rtd_to_codec(rtd, i)); \
|
||||
(i)++)
|
||||
#define for_each_rtd_codec_dais_rollback(rtd, i, dai) \
|
||||
for (; (--(i) >= 0) && ((dai) = asoc_rtd_to_codec(rtd, i));)
|
||||
#define for_each_rtd_dais(rtd, i, dai) \
|
||||
for ((i) = 0; \
|
||||
((i) < (rtd)->num_cpus + (rtd)->num_codecs) && \
|
||||
((dai) = (rtd)->dais[i]); \
|
||||
(i)++)
|
||||
#define for_each_rtd_dais_rollback(rtd, i, dai) \
|
||||
for (; (--(i) >= 0) && ((dai) = (rtd)->dais[i]);)
|
||||
|
||||
void snd_soc_close_delayed_work(struct snd_soc_pcm_runtime *rtd);
|
||||
|
||||
|
@ -779,8 +779,7 @@ int snd_soc_pcm_component_prepare(struct snd_pcm_substream *substream)
|
||||
}
|
||||
|
||||
int snd_soc_pcm_component_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_component **last)
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
|
||||
struct snd_soc_component *component;
|
||||
@ -790,33 +789,35 @@ int snd_soc_pcm_component_hw_params(struct snd_pcm_substream *substream,
|
||||
if (component->driver->hw_params) {
|
||||
ret = component->driver->hw_params(component,
|
||||
substream, params);
|
||||
if (ret < 0) {
|
||||
*last = component;
|
||||
if (ret < 0)
|
||||
return soc_component_ret(component, ret);
|
||||
}
|
||||
}
|
||||
/* mark substream if succeeded */
|
||||
soc_component_mark_push(component, substream, hw_params);
|
||||
}
|
||||
|
||||
*last = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void snd_soc_pcm_component_hw_free(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_component *last)
|
||||
int rollback)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
|
||||
struct snd_soc_component *component;
|
||||
int i, ret;
|
||||
|
||||
for_each_rtd_components(rtd, i, component) {
|
||||
if (component == last)
|
||||
break;
|
||||
if (rollback && !soc_component_mark_match(component, substream, hw_params))
|
||||
continue;
|
||||
|
||||
if (component->driver->hw_free) {
|
||||
ret = component->driver->hw_free(component, substream);
|
||||
if (ret < 0)
|
||||
soc_component_ret(component, ret);
|
||||
}
|
||||
|
||||
/* remove marked substream */
|
||||
soc_component_mark_pop(component, substream, hw_params);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,16 +335,27 @@ int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
|
||||
if (dai->driver->ops &&
|
||||
dai->driver->ops->hw_params)
|
||||
ret = dai->driver->ops->hw_params(substream, params, dai);
|
||||
|
||||
/* mark substream if succeeded */
|
||||
if (ret == 0)
|
||||
soc_dai_mark_push(dai, substream, hw_params);
|
||||
end:
|
||||
return soc_dai_ret(dai, ret);
|
||||
}
|
||||
|
||||
void snd_soc_dai_hw_free(struct snd_soc_dai *dai,
|
||||
struct snd_pcm_substream *substream)
|
||||
struct snd_pcm_substream *substream,
|
||||
int rollback)
|
||||
{
|
||||
if (rollback && !soc_dai_mark_match(dai, substream, hw_params))
|
||||
return;
|
||||
|
||||
if (dai->driver->ops &&
|
||||
dai->driver->ops->hw_free)
|
||||
dai->driver->ops->hw_free(substream, dai);
|
||||
|
||||
/* remove marked substream */
|
||||
soc_dai_mark_pop(dai, substream, hw_params);
|
||||
}
|
||||
|
||||
int snd_soc_dai_startup(struct snd_soc_dai *dai,
|
||||
|
@ -3955,13 +3955,13 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
|
||||
substream->stream = SNDRV_PCM_STREAM_CAPTURE;
|
||||
snd_soc_dapm_widget_for_each_source_path(w, path) {
|
||||
source = path->source->priv;
|
||||
snd_soc_dai_hw_free(source, substream);
|
||||
snd_soc_dai_hw_free(source, substream, 0);
|
||||
}
|
||||
|
||||
substream->stream = SNDRV_PCM_STREAM_PLAYBACK;
|
||||
snd_soc_dapm_widget_for_each_sink_path(w, path) {
|
||||
sink = path->sink->priv;
|
||||
snd_soc_dai_hw_free(sink, substream);
|
||||
snd_soc_dai_hw_free(sink, substream, 0);
|
||||
}
|
||||
|
||||
substream->stream = SNDRV_PCM_STREAM_CAPTURE;
|
||||
|
@ -119,16 +119,26 @@ int snd_soc_link_hw_params(struct snd_pcm_substream *substream,
|
||||
rtd->dai_link->ops->hw_params)
|
||||
ret = rtd->dai_link->ops->hw_params(substream, params);
|
||||
|
||||
/* mark substream if succeeded */
|
||||
if (ret == 0)
|
||||
soc_link_mark_push(rtd, substream, hw_params);
|
||||
|
||||
return soc_link_ret(rtd, ret);
|
||||
}
|
||||
|
||||
void snd_soc_link_hw_free(struct snd_pcm_substream *substream)
|
||||
void snd_soc_link_hw_free(struct snd_pcm_substream *substream, int rollback)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
|
||||
|
||||
if (rollback && !soc_link_mark_match(rtd, substream, hw_params))
|
||||
return;
|
||||
|
||||
if (rtd->dai_link->ops &&
|
||||
rtd->dai_link->ops->hw_free)
|
||||
rtd->dai_link->ops->hw_free(substream);
|
||||
|
||||
/* remove marked substream */
|
||||
soc_link_mark_pop(rtd, substream, hw_params);
|
||||
}
|
||||
|
||||
int snd_soc_link_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
|
@ -860,6 +860,54 @@ static void soc_pcm_codec_params_fixup(struct snd_pcm_hw_params *params,
|
||||
interval->max = channels;
|
||||
}
|
||||
|
||||
static int soc_pcm_hw_clean(struct snd_pcm_substream *substream, int rollback)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
|
||||
struct snd_soc_dai *dai;
|
||||
int i;
|
||||
|
||||
mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
|
||||
|
||||
/* clear the corresponding DAIs parameters when going to be inactive */
|
||||
for_each_rtd_dais(rtd, i, dai) {
|
||||
int active = snd_soc_dai_stream_active(dai, substream->stream);
|
||||
|
||||
if (snd_soc_dai_active(dai) == 1) {
|
||||
dai->rate = 0;
|
||||
dai->channels = 0;
|
||||
dai->sample_bits = 0;
|
||||
}
|
||||
|
||||
if (active == 1)
|
||||
snd_soc_dai_digital_mute(dai, 1, substream->stream);
|
||||
}
|
||||
|
||||
/* free any machine hw params */
|
||||
snd_soc_link_hw_free(substream, rollback);
|
||||
|
||||
/* free any component resources */
|
||||
snd_soc_pcm_component_hw_free(substream, rollback);
|
||||
|
||||
/* now free hw params for the DAIs */
|
||||
for_each_rtd_dais(rtd, i, dai) {
|
||||
if (!snd_soc_dai_stream_valid(dai, substream->stream))
|
||||
continue;
|
||||
|
||||
snd_soc_dai_hw_free(dai, substream, rollback);
|
||||
}
|
||||
|
||||
mutex_unlock(&rtd->card->pcm_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Frees resources allocated by hw_params, can be called multiple times
|
||||
*/
|
||||
static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return soc_pcm_hw_clean(substream, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by ALSA when the hardware params are set by application. This
|
||||
* function can also be called multiple times and can allocate buffers
|
||||
@ -869,7 +917,6 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
|
||||
struct snd_soc_component *component;
|
||||
struct snd_soc_dai *cpu_dai;
|
||||
struct snd_soc_dai *codec_dai;
|
||||
int i, ret = 0;
|
||||
@ -921,7 +968,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
ret = snd_soc_dai_hw_params(codec_dai, substream,
|
||||
&codec_params);
|
||||
if(ret < 0)
|
||||
goto codec_err;
|
||||
goto out;
|
||||
|
||||
codec_dai->rate = params_rate(&codec_params);
|
||||
codec_dai->channels = params_channels(&codec_params);
|
||||
@ -941,7 +988,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
|
||||
ret = snd_soc_dai_hw_params(cpu_dai, substream, params);
|
||||
if (ret < 0)
|
||||
goto interface_err;
|
||||
goto out;
|
||||
|
||||
/* store the parameters for each DAI */
|
||||
cpu_dai->rate = params_rate(params);
|
||||
@ -952,86 +999,14 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
snd_soc_dapm_update_dai(substream, params, cpu_dai);
|
||||
}
|
||||
|
||||
ret = snd_soc_pcm_component_hw_params(substream, params, &component);
|
||||
if (ret < 0)
|
||||
goto component_err;
|
||||
|
||||
ret = snd_soc_pcm_component_hw_params(substream, params);
|
||||
out:
|
||||
mutex_unlock(&rtd->card->pcm_mutex);
|
||||
|
||||
if (ret < 0)
|
||||
soc_pcm_hw_clean(substream, 1);
|
||||
|
||||
return ret;
|
||||
|
||||
component_err:
|
||||
snd_soc_pcm_component_hw_free(substream, component);
|
||||
|
||||
i = rtd->num_cpus;
|
||||
|
||||
interface_err:
|
||||
for_each_rtd_cpu_dais_rollback(rtd, i, cpu_dai) {
|
||||
if (!snd_soc_dai_stream_valid(cpu_dai, substream->stream))
|
||||
continue;
|
||||
|
||||
snd_soc_dai_hw_free(cpu_dai, substream);
|
||||
cpu_dai->rate = 0;
|
||||
}
|
||||
|
||||
i = rtd->num_codecs;
|
||||
|
||||
codec_err:
|
||||
for_each_rtd_codec_dais_rollback(rtd, i, codec_dai) {
|
||||
if (!snd_soc_dai_stream_valid(codec_dai, substream->stream))
|
||||
continue;
|
||||
|
||||
snd_soc_dai_hw_free(codec_dai, substream);
|
||||
codec_dai->rate = 0;
|
||||
}
|
||||
|
||||
snd_soc_link_hw_free(substream);
|
||||
|
||||
mutex_unlock(&rtd->card->pcm_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Frees resources allocated by hw_params, can be called multiple times
|
||||
*/
|
||||
static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
|
||||
struct snd_soc_dai *dai;
|
||||
int i;
|
||||
|
||||
mutex_lock_nested(&rtd->card->pcm_mutex, rtd->card->pcm_subclass);
|
||||
|
||||
/* clear the corresponding DAIs parameters when going to be inactive */
|
||||
for_each_rtd_dais(rtd, i, dai) {
|
||||
int active = snd_soc_dai_stream_active(dai, substream->stream);
|
||||
|
||||
if (snd_soc_dai_active(dai) == 1) {
|
||||
dai->rate = 0;
|
||||
dai->channels = 0;
|
||||
dai->sample_bits = 0;
|
||||
}
|
||||
|
||||
if (active == 1)
|
||||
snd_soc_dai_digital_mute(dai, 1, substream->stream);
|
||||
}
|
||||
|
||||
/* free any machine hw params */
|
||||
snd_soc_link_hw_free(substream);
|
||||
|
||||
/* free any component resources */
|
||||
snd_soc_pcm_component_hw_free(substream, NULL);
|
||||
|
||||
/* now free hw params for the DAIs */
|
||||
for_each_rtd_dais(rtd, i, dai) {
|
||||
if (!snd_soc_dai_stream_valid(dai, substream->stream))
|
||||
continue;
|
||||
|
||||
snd_soc_dai_hw_free(dai, substream);
|
||||
}
|
||||
|
||||
mutex_unlock(&rtd->card->pcm_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
|
Loading…
Reference in New Issue
Block a user