Merge remote-tracking branch 'asoc/topic/dapm' into asoc-next
[sfrench/cifs-2.6.git] / sound / soc / soc-dapm.c
index 9d4748e2b67aa87def4cbba8f75459a3a695f8bf..a10b21cfc31ed2e5e6bafcc991682d9861fcfb4e 100644 (file)
@@ -2884,7 +2884,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
 {
        int i, r, ret = 0;
 
-       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
+       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
        for (i = 0; i < num; i++) {
                r = snd_soc_dapm_add_route(dapm, route);
                if (r < 0) {
@@ -2915,7 +2915,7 @@ int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
 {
        int i;
 
-       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
+       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
        for (i = 0; i < num; i++) {
                snd_soc_dapm_del_route(dapm, route);
                route++;
@@ -3778,18 +3778,27 @@ static int snd_soc_dapm_dai_link_put(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
-                        const struct snd_soc_pcm_stream *params,
-                        unsigned int num_params,
-                        struct snd_soc_dapm_widget *source,
-                        struct snd_soc_dapm_widget *sink)
+static void
+snd_soc_dapm_free_kcontrol(struct snd_soc_card *card,
+                       unsigned long *private_value,
+                       int num_params,
+                       const char **w_param_text)
+{
+       int count;
+
+       devm_kfree(card->dev, (void *)*private_value);
+       for (count = 0 ; count < num_params; count++)
+               devm_kfree(card->dev, (void *)w_param_text[count]);
+       devm_kfree(card->dev, w_param_text);
+}
+
+static struct snd_kcontrol_new *
+snd_soc_dapm_alloc_kcontrol(struct snd_soc_card *card,
+                       char *link_name,
+                       const struct snd_soc_pcm_stream *params,
+                       int num_params, const char **w_param_text,
+                       unsigned long *private_value)
 {
-       struct snd_soc_dapm_widget template;
-       struct snd_soc_dapm_widget *w;
-       char *link_name;
-       int ret, count;
-       unsigned long private_value;
-       const char **w_param_text;
        struct soc_enum w_param_enum[] = {
                SOC_ENUM_SINGLE(0, 0, 0, NULL),
        };
@@ -3798,19 +3807,9 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
                             snd_soc_dapm_dai_link_get,
                             snd_soc_dapm_dai_link_put),
        };
+       struct snd_kcontrol_new *kcontrol_news;
        const struct snd_soc_pcm_stream *config = params;
-
-       w_param_text = devm_kcalloc(card->dev, num_params,
-                                       sizeof(char *), GFP_KERNEL);
-       if (!w_param_text)
-               return -ENOMEM;
-
-       link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
-                                  source->name, sink->name);
-       if (!link_name) {
-               ret = -ENOMEM;
-               goto outfree_w_param;
-       }
+       int count;
 
        for (count = 0 ; count < num_params; count++) {
                if (!config->stream_name) {
@@ -3821,57 +3820,94 @@ int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
                                devm_kasprintf(card->dev, GFP_KERNEL,
                                               "Anonymous Configuration %d",
                                               count);
-                       if (!w_param_text[count]) {
-                               ret = -ENOMEM;
-                               goto outfree_link_name;
-                       }
                } else {
                        w_param_text[count] = devm_kmemdup(card->dev,
                                                config->stream_name,
                                                strlen(config->stream_name) + 1,
                                                GFP_KERNEL);
-                       if (!w_param_text[count]) {
-                               ret = -ENOMEM;
-                               goto outfree_link_name;
-                       }
                }
+               if (!w_param_text[count])
+                       goto outfree_w_param;
                config++;
        }
+
        w_param_enum[0].items = num_params;
        w_param_enum[0].texts = w_param_text;
 
-       memset(&template, 0, sizeof(template));
-       template.reg = SND_SOC_NOPM;
-       template.id = snd_soc_dapm_dai_link;
-       template.name = link_name;
-       template.event = snd_soc_dai_link_event;
-       template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
-               SND_SOC_DAPM_PRE_PMD;
-       template.num_kcontrols = 1;
-       /* duplicate w_param_enum on heap so that memory persists */
-       private_value =
+       *private_value =
                (unsigned long) devm_kmemdup(card->dev,
                        (void *)(kcontrol_dai_link[0].private_value),
                        sizeof(struct soc_enum), GFP_KERNEL);
-       if (!private_value) {
+       if (!*private_value) {
                dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
                        link_name);
-               ret = -ENOMEM;
-               goto outfree_link_name;
+               goto outfree_w_param;
        }
-       kcontrol_dai_link[0].private_value = private_value;
+       kcontrol_dai_link[0].private_value = *private_value;
        /* duplicate kcontrol_dai_link on heap so that memory persists */
-       template.kcontrol_news =
-                               devm_kmemdup(card->dev, &kcontrol_dai_link[0],
+       kcontrol_news = devm_kmemdup(card->dev, &kcontrol_dai_link[0],
                                        sizeof(struct snd_kcontrol_new),
                                        GFP_KERNEL);
-       if (!template.kcontrol_news) {
+       if (!kcontrol_news) {
                dev_err(card->dev, "ASoC: Failed to create control for %s widget\n",
                        link_name);
-               ret = -ENOMEM;
-               goto outfree_private_value;
+               goto outfree_w_param;
        }
+       return kcontrol_news;
+
+outfree_w_param:
+       snd_soc_dapm_free_kcontrol(card, private_value, num_params, w_param_text);
+       return NULL;
+}
+
+int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
+                        const struct snd_soc_pcm_stream *params,
+                        unsigned int num_params,
+                        struct snd_soc_dapm_widget *source,
+                        struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_dapm_widget template;
+       struct snd_soc_dapm_widget *w;
+       const char **w_param_text;
+       unsigned long private_value;
+       char *link_name;
+       int ret;
+
+       link_name = devm_kasprintf(card->dev, GFP_KERNEL, "%s-%s",
+                                  source->name, sink->name);
+       if (!link_name)
+               return -ENOMEM;
+
+       memset(&template, 0, sizeof(template));
+       template.reg = SND_SOC_NOPM;
+       template.id = snd_soc_dapm_dai_link;
+       template.name = link_name;
+       template.event = snd_soc_dai_link_event;
+       template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+               SND_SOC_DAPM_PRE_PMD;
+       template.kcontrol_news = NULL;
+
+       /* allocate memory for control, only in case of multiple configs */
+       if (num_params > 1) {
+               w_param_text = devm_kcalloc(card->dev, num_params,
+                                       sizeof(char *), GFP_KERNEL);
+               if (!w_param_text) {
+                       ret = -ENOMEM;
+                       goto param_fail;
+               }
 
+               template.num_kcontrols = 1;
+               template.kcontrol_news =
+                                       snd_soc_dapm_alloc_kcontrol(card,
+                                               link_name, params, num_params,
+                                               w_param_text, &private_value);
+               if (!template.kcontrol_news) {
+                       ret = -ENOMEM;
+                       goto param_fail;
+               }
+       } else {
+               w_param_text = NULL;
+       }
        dev_dbg(card->dev, "ASoC: adding %s widget\n", link_name);
 
        w = snd_soc_dapm_new_control_unlocked(&card->dapm, &template);
@@ -3903,15 +3939,9 @@ outfree_w:
        devm_kfree(card->dev, w);
 outfree_kcontrol_news:
        devm_kfree(card->dev, (void *)template.kcontrol_news);
-outfree_private_value:
-       devm_kfree(card->dev, (void *)private_value);
-outfree_link_name:
+       snd_soc_dapm_free_kcontrol(card, &private_value, num_params, w_param_text);
+param_fail:
        devm_kfree(card->dev, link_name);
-outfree_w_param:
-       for (count = 0 ; count < num_params; count++)
-               devm_kfree(card->dev, (void *)w_param_text[count]);
-       devm_kfree(card->dev, w_param_text);
-
        return ret;
 }