summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/soc-dapm.c159
1 files changed, 92 insertions, 67 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 7db4abd9a0a5..6dcaf9ff6eb5 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -3764,25 +3764,59 @@ 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_event_pre_pmu(struct snd_soc_dapm_widget *w,
+ struct snd_pcm_substream *substream)
{
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_soc_pcm_runtime *rtd = substream->private_data;
struct snd_pcm_hw_params *params = NULL;
- struct snd_pcm_runtime *runtime = NULL;
+ const struct snd_soc_pcm_stream *config = NULL;
unsigned int fmt;
- int ret = 0;
+ int ret;
- config = rtd->dai_link->params + rtd->params_select;
+ params = kzalloc(sizeof(*params), GFP_KERNEL);
+ if (!params)
+ return -ENOMEM;
- 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;
+ substream->stream = SNDRV_PCM_STREAM_CAPTURE;
+ snd_soc_dapm_widget_for_each_source_path(w, path) {
+ source = path->source->priv;
+
+ ret = snd_soc_dai_startup(source, substream);
+ if (ret < 0) {
+ dev_err(source->dev,
+ "ASoC: startup() failed: %d\n", ret);
+ goto out;
+ }
+ source->active++;
+ }
+
+ substream->stream = SNDRV_PCM_STREAM_PLAYBACK;
+ snd_soc_dapm_widget_for_each_sink_path(w, path) {
+ sink = path->sink->priv;
+
+ ret = snd_soc_dai_startup(sink, substream);
+ if (ret < 0) {
+ dev_err(sink->dev,
+ "ASoC: startup() failed: %d\n", ret);
+ goto out;
+ }
+ 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;
+ }
/* Be a little careful as we don't want to overflow the mask array */
if (config->formats) {
@@ -3790,27 +3824,62 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
} else {
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;
+ ret = -EINVAL;
goto out;
}
- snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
+ 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;
+ substream->stream = SNDRV_PCM_STREAM_CAPTURE;
+ snd_soc_dapm_widget_for_each_source_path(w, path) {
+ source = path->source->priv;
+
+ ret = snd_soc_dai_hw_params(source, substream, params);
+ if (ret < 0)
+ goto out;
+
+ dapm_update_dai_unlocked(substream, params, source);
+ }
+
+ substream->stream = SNDRV_PCM_STREAM_PLAYBACK;
+ snd_soc_dapm_widget_for_each_sink_path(w, path) {
+ sink = path->sink->priv;
+
+ ret = snd_soc_dai_hw_params(sink, substream, params);
+ if (ret < 0)
+ goto out;
+
+ dapm_update_dai_unlocked(substream, params, sink);
+ }
+
+out:
+ kfree(params);
+ 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;
+ struct snd_pcm_substream substream;
+ 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() */
@@ -3824,53 +3893,10 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- substream.stream = SNDRV_PCM_STREAM_CAPTURE;
- snd_soc_dapm_widget_for_each_source_path(w, path) {
- source = path->source->priv;
-
- ret = snd_soc_dai_startup(source, &substream);
- if (ret < 0) {
- dev_err(source->dev,
- "ASoC: startup() failed: %d\n", ret);
- goto out;
- }
- source->active++;
- }
-
- substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
- snd_soc_dapm_widget_for_each_sink_path(w, path) {
- sink = path->sink->priv;
-
- ret = snd_soc_dai_startup(sink, &substream);
- if (ret < 0) {
- dev_err(sink->dev,
- "ASoC: startup() failed: %d\n", ret);
- goto out;
- }
- sink->active++;
- }
-
- substream.stream = SNDRV_PCM_STREAM_CAPTURE;
- snd_soc_dapm_widget_for_each_source_path(w, path) {
- source = path->source->priv;
-
- ret = snd_soc_dai_hw_params(source, &substream, params);
- if (ret < 0)
- goto out;
-
- dapm_update_dai_unlocked(&substream, params, source);
- }
-
- substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
- snd_soc_dapm_widget_for_each_sink_path(w, path) {
- sink = path->sink->priv;
-
- ret = snd_soc_dai_hw_params(sink, &substream, params);
- if (ret < 0)
- goto out;
+ ret = snd_soc_dai_link_event_pre_pmu(w, &substream);
+ if (ret < 0)
+ goto out;
- dapm_update_dai_unlocked(&substream, params, sink);
- }
break;
case SND_SOC_DAPM_POST_PMU:
@@ -3932,7 +3958,6 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
out:
kfree(runtime);
- kfree(params);
return ret;
}