diff options
| -rw-r--r-- | sound/soc/soc-dapm.c | 159 |
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 | } |
| 3765 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); | 3765 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); |
| 3766 | 3766 | ||
| 3767 | static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w, | 3767 | static int |
| 3768 | struct snd_kcontrol *kcontrol, int event) | 3768 | snd_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 | |||
| 3864 | out: | ||
| 3865 | kfree(params); | ||
| 3866 | return 0; | ||
| 3867 | } | ||
| 3868 | |||
| 3869 | static 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 | ||
| 3933 | out: | 3959 | out: |
| 3934 | kfree(runtime); | 3960 | kfree(runtime); |
| 3935 | kfree(params); | ||
| 3936 | return ret; | 3961 | return ret; |
| 3937 | } | 3962 | } |
| 3938 | 3963 | ||
