Commit 244e2936 authored by Charles Keepax's avatar Charles Keepax Committed by Mark Brown

ASoC: pcm: Tidy up open/hw_params handling

Currently, the core will continue processing open/hw_params
component callbacks after one has failed even though it will abort
immediately afterwards. This is unnecessary and also has the issue
that close/hw_free will be called on the component which failed
open/hw_params which could result in issues if the driver doesn't
expect this behaviour.

Update the core to abort processing open/hw_params when an error
is hit and only call close/hw_free for those components that were
successfully opened.
Signed-off-by: default avatarCharles Keepax <ckeepax@opensource.cirrus.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent f0d9034b
...@@ -448,6 +448,29 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream) ...@@ -448,6 +448,29 @@ static void soc_pcm_init_runtime_hw(struct snd_pcm_substream *substream)
hw->rate_max = min_not_zero(hw->rate_max, rate_max); hw->rate_max = min_not_zero(hw->rate_max, rate_max);
} }
static int soc_pcm_components_close(struct snd_pcm_substream *substream,
struct snd_soc_component *last)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_component *component;
for_each_rtdcom(rtd, rtdcom) {
component = rtdcom->component;
if (component == last)
break;
if (!component->driver->ops ||
!component->driver->ops->close)
continue;
component->driver->ops->close(substream);
}
return 0;
}
/* /*
* Called by ALSA when a PCM substream is opened, the runtime->hw record is * Called by ALSA when a PCM substream is opened, the runtime->hw record is
* then initialized and any private data can be allocated. This also calls * then initialized and any private data can be allocated. This also calls
...@@ -462,7 +485,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) ...@@ -462,7 +485,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai; struct snd_soc_dai *codec_dai;
const char *codec_dai_name = "multicodec"; const char *codec_dai_name = "multicodec";
int i, ret = 0, __ret; int i, ret = 0;
pinctrl_pm_select_default_state(cpu_dai->dev); pinctrl_pm_select_default_state(cpu_dai->dev);
for (i = 0; i < rtd->num_codecs; i++) for (i = 0; i < rtd->num_codecs; i++)
...@@ -486,7 +509,6 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) ...@@ -486,7 +509,6 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
} }
} }
ret = 0;
for_each_rtdcom(rtd, rtdcom) { for_each_rtdcom(rtd, rtdcom) {
component = rtdcom->component; component = rtdcom->component;
...@@ -494,16 +516,15 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) ...@@ -494,16 +516,15 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
!component->driver->ops->open) !component->driver->ops->open)
continue; continue;
__ret = component->driver->ops->open(substream); ret = component->driver->ops->open(substream);
if (__ret < 0) { if (ret < 0) {
dev_err(component->dev, dev_err(component->dev,
"ASoC: can't open component %s: %d\n", "ASoC: can't open component %s: %d\n",
component->name, __ret); component->name, ret);
ret = __ret; goto component_err;
} }
} }
if (ret < 0) component = NULL;
goto component_err;
for (i = 0; i < rtd->num_codecs; i++) { for (i = 0; i < rtd->num_codecs; i++) {
codec_dai = rtd->codec_dais[i]; codec_dai = rtd->codec_dais[i];
...@@ -612,15 +633,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) ...@@ -612,15 +633,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
} }
component_err: component_err:
for_each_rtdcom(rtd, rtdcom) { soc_pcm_components_close(substream, component);
component = rtdcom->component;
if (!component->driver->ops ||
!component->driver->ops->close)
continue;
component->driver->ops->close(substream);
}
if (cpu_dai->driver->ops->shutdown) if (cpu_dai->driver->ops->shutdown)
cpu_dai->driver->ops->shutdown(substream, cpu_dai); cpu_dai->driver->ops->shutdown(substream, cpu_dai);
...@@ -714,15 +727,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) ...@@ -714,15 +727,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
if (rtd->dai_link->ops->shutdown) if (rtd->dai_link->ops->shutdown)
rtd->dai_link->ops->shutdown(substream); rtd->dai_link->ops->shutdown(substream);
for_each_rtdcom(rtd, rtdcom) { soc_pcm_components_close(substream, NULL);
component = rtdcom->component;
if (!component->driver->ops ||
!component->driver->ops->close)
continue;
component->driver->ops->close(substream);
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (snd_soc_runtime_ignore_pmdown_time(rtd)) { if (snd_soc_runtime_ignore_pmdown_time(rtd)) {
...@@ -874,6 +879,29 @@ int soc_dai_hw_params(struct snd_pcm_substream *substream, ...@@ -874,6 +879,29 @@ int soc_dai_hw_params(struct snd_pcm_substream *substream,
return 0; return 0;
} }
static int soc_pcm_components_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_component *last)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_component *component;
for_each_rtdcom(rtd, rtdcom) {
component = rtdcom->component;
if (component == last)
break;
if (!component->driver->ops ||
!component->driver->ops->hw_free)
continue;
component->driver->ops->hw_free(substream);
}
return 0;
}
/* /*
* Called by ALSA when the hardware params are set by application. This * Called by ALSA when the hardware params are set by application. This
* function can also be called multiple times and can allocate buffers * function can also be called multiple times and can allocate buffers
...@@ -886,7 +914,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -886,7 +914,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_component *component; struct snd_soc_component *component;
struct snd_soc_rtdcom_list *rtdcom; struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int i, ret = 0, __ret; int i, ret = 0;
mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass);
if (rtd->dai_link->ops->hw_params) { if (rtd->dai_link->ops->hw_params) {
...@@ -944,7 +972,6 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -944,7 +972,6 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
if (ret < 0) if (ret < 0)
goto interface_err; goto interface_err;
ret = 0;
for_each_rtdcom(rtd, rtdcom) { for_each_rtdcom(rtd, rtdcom) {
component = rtdcom->component; component = rtdcom->component;
...@@ -952,16 +979,15 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -952,16 +979,15 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
!component->driver->ops->hw_params) !component->driver->ops->hw_params)
continue; continue;
__ret = component->driver->ops->hw_params(substream, params); ret = component->driver->ops->hw_params(substream, params);
if (__ret < 0) { if (ret < 0) {
dev_err(component->dev, dev_err(component->dev,
"ASoC: %s hw params failed: %d\n", "ASoC: %s hw params failed: %d\n",
component->name, __ret); component->name, ret);
ret = __ret; goto component_err;
} }
} }
if (ret < 0) component = NULL;
goto component_err;
/* store the parameters for each DAIs */ /* store the parameters for each DAIs */
cpu_dai->rate = params_rate(params); cpu_dai->rate = params_rate(params);
...@@ -977,15 +1003,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -977,15 +1003,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
return ret; return ret;
component_err: component_err:
for_each_rtdcom(rtd, rtdcom) { soc_pcm_components_hw_free(substream, component);
component = rtdcom->component;
if (!component->driver->ops ||
!component->driver->ops->hw_free)
continue;
component->driver->ops->hw_free(substream);
}
if (cpu_dai->driver->ops->hw_free) if (cpu_dai->driver->ops->hw_free)
cpu_dai->driver->ops->hw_free(substream, cpu_dai); cpu_dai->driver->ops->hw_free(substream, cpu_dai);
...@@ -1014,8 +1032,6 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, ...@@ -1014,8 +1032,6 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream,
static int soc_pcm_hw_free(struct snd_pcm_substream *substream) static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
{ {
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_component *component;
struct snd_soc_rtdcom_list *rtdcom;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_dai *codec_dai; struct snd_soc_dai *codec_dai;
bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; bool playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
...@@ -1052,15 +1068,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) ...@@ -1052,15 +1068,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
rtd->dai_link->ops->hw_free(substream); rtd->dai_link->ops->hw_free(substream);
/* free any component resources */ /* free any component resources */
for_each_rtdcom(rtd, rtdcom) { soc_pcm_components_hw_free(substream, NULL);
component = rtdcom->component;
if (!component->driver->ops ||
!component->driver->ops->hw_free)
continue;
component->driver->ops->hw_free(substream);
}
/* now free hw params for the DAIs */ /* now free hw params for the DAIs */
for (i = 0; i < rtd->num_codecs; i++) { for (i = 0; i < rtd->num_codecs; i++) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment