summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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,
3764} 3764}
3765EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); 3765EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
3766 3766
3767static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, 3767static int
3768 struct snd_kcontrol *kcontrol, int event) 3768snd_soc_dai_link_event_pre_pmu(struct snd_soc_dapm_widget *w,
3769 struct snd_pcm_substream *substream)
3769{ 3770{
3770 struct snd_soc_dapm_path *path; 3771 struct snd_soc_dapm_path *path;
3771 struct snd_soc_dai *source, *sink; 3772 struct snd_soc_dai *source, *sink;
3772 struct snd_soc_pcm_runtime *rtd = w->priv; 3773 struct snd_soc_pcm_runtime *rtd = substream->private_data;
3773 const struct snd_soc_pcm_stream *config;
3774 struct snd_pcm_substream substream;
3775 struct snd_pcm_hw_params *params = NULL; 3774 struct snd_pcm_hw_params *params = NULL;
3776 struct snd_pcm_runtime *runtime = NULL; 3775 const struct snd_soc_pcm_stream *config = NULL;
3777 unsigned int fmt; 3776 unsigned int fmt;
3778 int ret = 0; 3777 int ret;
3779 3778
3780 config = rtd->dai_link->params + rtd->params_select; 3779 params = kzalloc(sizeof(*params), GFP_KERNEL);
3780 if (!params)
3781 return -ENOMEM;
3781 3782
3782 if (WARN_ON(!config) || 3783 substream->stream = SNDRV_PCM_STREAM_CAPTURE;
3783 WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) || 3784 snd_soc_dapm_widget_for_each_source_path(w, path) {
3784 list_empty(&w->edges[SND_SOC_DAPM_DIR_IN]))) 3785 source = path->source->priv;
3785 return -EINVAL; 3786
3787 ret = snd_soc_dai_startup(source, substream);
3788 if (ret < 0) {
3789 dev_err(source->dev,
3790 "ASoC: startup() failed: %d\n", ret);
3791 goto out;
3792 }
3793 source->active++;
3794 }
3795
3796 substream->stream = SNDRV_PCM_STREAM_PLAYBACK;
3797 snd_soc_dapm_widget_for_each_sink_path(w, path) {
3798 sink = path->sink->priv;
3799
3800 ret = snd_soc_dai_startup(sink, substream);
3801 if (ret < 0) {
3802 dev_err(sink->dev,
3803 "ASoC: startup() failed: %d\n", ret);
3804 goto out;
3805 }
3806 sink->active++;
3807 }
3808
3809 /*
3810 * Note: getting the config after .startup() gives a chance to
3811 * either party on the link to alter the configuration if
3812 * necessary
3813 */
3814 config = rtd->dai_link->params + rtd->params_select;
3815 if (WARN_ON(!config)) {
3816 dev_err(w->dapm->dev, "ASoC: link config missing\n");
3817 ret = -EINVAL;
3818 goto out;
3819 }
3786 3820
3787 /* Be a little careful as we don't want to overflow the mask array */ 3821 /* Be a little careful as we don't want to overflow the mask array */
3788 if (config->formats) { 3822 if (config->formats) {
@@ -3790,27 +3824,62 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
3790 } else { 3824 } else {
3791 dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n", 3825 dev_warn(w->dapm->dev, "ASoC: Invalid format %llx specified\n",
3792 config->formats); 3826 config->formats);
3793 fmt = 0;
3794 }
3795 3827
3796 /* Currently very limited parameter selection */ 3828 ret = -EINVAL;
3797 params = kzalloc(sizeof(*params), GFP_KERNEL);
3798 if (!params) {
3799 ret = -ENOMEM;
3800 goto out; 3829 goto out;
3801 } 3830 }
3802 snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
3803 3831
3832 snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
3804 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min = 3833 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min =
3805 config->rate_min; 3834 config->rate_min;
3806 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max = 3835 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max =
3807 config->rate_max; 3836 config->rate_max;
3808
3809 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min 3837 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min
3810 = config->channels_min; 3838 = config->channels_min;
3811 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max 3839 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max
3812 = config->channels_max; 3840 = config->channels_max;
3813 3841
3842 substream->stream = SNDRV_PCM_STREAM_CAPTURE;
3843 snd_soc_dapm_widget_for_each_source_path(w, path) {
3844 source = path->source->priv;
3845
3846 ret = snd_soc_dai_hw_params(source, substream, params);
3847 if (ret < 0)
3848 goto out;
3849
3850 dapm_update_dai_unlocked(substream, params, source);
3851 }
3852
3853 substream->stream = SNDRV_PCM_STREAM_PLAYBACK;
3854 snd_soc_dapm_widget_for_each_sink_path(w, path) {
3855 sink = path->sink->priv;
3856
3857 ret = snd_soc_dai_hw_params(sink, substream, params);
3858 if (ret < 0)
3859 goto out;
3860
3861 dapm_update_dai_unlocked(substream, params, sink);
3862 }
3863
3864out:
3865 kfree(params);
3866 return 0;
3867}
3868
3869static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
3870 struct snd_kcontrol *kcontrol, int event)
3871{
3872 struct snd_soc_dapm_path *path;
3873 struct snd_soc_dai *source, *sink;
3874 struct snd_soc_pcm_runtime *rtd = w->priv;
3875 struct snd_pcm_substream substream;
3876 struct snd_pcm_runtime *runtime = NULL;
3877 int ret = 0;
3878
3879 if (WARN_ON(list_empty(&w->edges[SND_SOC_DAPM_DIR_OUT]) ||
3880 list_empty(&w->edges[SND_SOC_DAPM_DIR_IN])))
3881 return -EINVAL;
3882
3814 memset(&substream, 0, sizeof(substream)); 3883 memset(&substream, 0, sizeof(substream));
3815 3884
3816 /* Allocate a dummy snd_pcm_runtime for startup() and other ops() */ 3885 /* 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,
3824 3893
3825 switch (event) { 3894 switch (event) {
3826 case SND_SOC_DAPM_PRE_PMU: 3895 case SND_SOC_DAPM_PRE_PMU:
3827 substream.stream = SNDRV_PCM_STREAM_CAPTURE; 3896 ret = snd_soc_dai_link_event_pre_pmu(w, &substream);
3828 snd_soc_dapm_widget_for_each_source_path(w, path) { 3897 if (ret < 0)
3829 source = path->source->priv; 3898 goto out;
3830
3831 ret = snd_soc_dai_startup(source, &substream);
3832 if (ret < 0) {
3833 dev_err(source->dev,
3834 "ASoC: startup() failed: %d\n", ret);
3835 goto out;
3836 }
3837 source->active++;
3838 }
3839
3840 substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
3841 snd_soc_dapm_widget_for_each_sink_path(w, path) {
3842 sink = path->sink->priv;
3843
3844 ret = snd_soc_dai_startup(sink, &substream);
3845 if (ret < 0) {
3846 dev_err(sink->dev,
3847 "ASoC: startup() failed: %d\n", ret);
3848 goto out;
3849 }
3850 sink->active++;
3851 }
3852
3853 substream.stream = SNDRV_PCM_STREAM_CAPTURE;
3854 snd_soc_dapm_widget_for_each_source_path(w, path) {
3855 source = path->source->priv;
3856
3857 ret = snd_soc_dai_hw_params(source, &substream, params);
3858 if (ret < 0)
3859 goto out;
3860
3861 dapm_update_dai_unlocked(&substream, params, source);
3862 }
3863
3864 substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
3865 snd_soc_dapm_widget_for_each_sink_path(w, path) {
3866 sink = path->sink->priv;
3867
3868 ret = snd_soc_dai_hw_params(sink, &substream, params);
3869 if (ret < 0)
3870 goto out;
3871 3899
3872 dapm_update_dai_unlocked(&substream, params, sink);
3873 }
3874 break; 3900 break;
3875 3901
3876 case SND_SOC_DAPM_POST_PMU: 3902 case SND_SOC_DAPM_POST_PMU:
@@ -3932,7 +3958,6 @@ static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
3932 3958
3933out: 3959out:
3934 kfree(runtime); 3960 kfree(runtime);
3935 kfree(params);
3936 return ret; 3961 return ret;
3937} 3962}
3938 3963