When there is an event on codec to codec dai_link, we only need to deal with params if the event is SND_SOC_DAPM_PRE_PMU, when .hw_params() is called. For the other events, it is useless.
Also, params does not need to be dynamically allocated as it does not need to survive the event.
Last, dealing with the codec to codec params just before calling .hw_params() callbacks give change to either party on the link to alter params content in .startup(), which might be useful in some cases
Signed-off-by: Jerome Brunet jbrunet@baylibre.com --- sound/soc/soc-dapm.c | 81 ++++++++++++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 30 deletions(-)
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index d20cd89513a4..aa6e47beaec3 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3764,25 +3764,12 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, } EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
-static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) +static int +snd_soc_dai_link_prepare_params(struct snd_soc_dapm_widget *w, + struct snd_pcm_hw_params *params, + const struct snd_soc_pcm_stream *config) { - struct snd_soc_dapm_path *path; - struct snd_soc_dai *source, *sink; - struct snd_soc_pcm_runtime *rtd = w->priv; - const struct snd_soc_pcm_stream *config; - struct snd_pcm_substream substream; - struct snd_pcm_hw_params *params = NULL; - struct snd_pcm_runtime *runtime = NULL; unsigned int fmt; - int ret = 0; - - config = rtd->dai_link->params + rtd->params_select; - - if (WARN_ON(!config) || - WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) || - list_empty(&w->edges[SND_SOC_DAPM_DIR_IN]))) - return -EINVAL;
/* Be a little careful as we don't want to overflow the mask array */ if (config->formats) { @@ -3791,26 +3778,41 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n", config->formats); fmt = 0; - }
- /* Currently very limited parameter selection */ - params = kzalloc(sizeof(*params), GFP_KERNEL); - if (!params) { - ret = -ENOMEM; - goto out; + return -EINVAL; } - snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
+ memset(params, 0, sizeof(*params)); + + snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt); hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min = config->rate_min; hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max = config->rate_max; - hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min = config->channels_min; hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max = config->channels_max;
+ return 0; +} + +static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_dapm_path *path; + struct snd_soc_dai *source, *sink; + struct snd_soc_pcm_runtime *rtd = w->priv; + const struct snd_soc_pcm_stream *config; + struct snd_pcm_substream substream; + struct snd_pcm_hw_params params; + struct snd_pcm_runtime *runtime = NULL; + int ret = 0; + + if (WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) || + list_empty(&w->edges[SND_SOC_DAPM_DIR_IN]))) + return -EINVAL; + memset(&substream, 0, sizeof(substream));
/* Allocate a dummy snd_pcm_runtime for startup() and other ops() */ @@ -3850,27 +3852,47 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, sink->active++; }
+ /* + * Note: getting the config after .startup() gives a chance to + * either party on the link to alter the configuration if + * necessary + */ + config = rtd->dai_link->params + rtd->params_select; + if (WARN_ON(!config)) { + dev_err(w->dapm->dev, "ASoC: link config missing\n"); + ret = -EINVAL; + goto out; + } + + ret = snd_soc_dai_link_prepare_params(w, ¶ms, config); + if (ret < 0) { + dev_err(w->dapm->dev, "ASoC: link params prepare failed: %d\n", + ret); + goto out; + } + substream.stream = SNDRV_PCM_STREAM_CAPTURE; snd_soc_dapm_widget_for_each_source_path(w, path) { source = path->source->priv;
- ret = soc_dai_hw_params(&substream, params, source); + ret = soc_dai_hw_params(&substream, ¶ms, source); if (ret < 0) goto out;
- dapm_update_dai_unlocked(&substream, params, source); + dapm_update_dai_unlocked(&substream, ¶ms, source); }
substream.stream = SNDRV_PCM_STREAM_PLAYBACK; snd_soc_dapm_widget_for_each_sink_path(w, path) { sink = path->sink->priv;
- ret = soc_dai_hw_params(&substream, params, sink); + ret = soc_dai_hw_params(&substream, ¶ms, sink); if (ret < 0) goto out;
- dapm_update_dai_unlocked(&substream, params, sink); + dapm_update_dai_unlocked(&substream, ¶ms, sink); } + break;
case SND_SOC_DAPM_POST_PMU: @@ -3932,7 +3954,6 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
out: kfree(runtime); - kfree(params); return ret; }