summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sound/soc/soc-dapm.c106
1 files changed, 75 insertions, 31 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 79b836c..456617e 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -324,6 +324,28 @@ static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
return -ENODEV;
}
+static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
+ const struct snd_kcontrol_new *kcontrol_new,
+ struct snd_kcontrol **kcontrol)
+{
+ struct snd_soc_dapm_widget *w;
+ int i;
+
+ *kcontrol = NULL;
+
+ list_for_each_entry(w, &dapm->card->widgets, list) {
+ for (i = 0; i < w->num_kcontrols; i++) {
+ if (&w->kcontrol_news[i] == kcontrol_new) {
+ if (w->kcontrols)
+ *kcontrol = w->kcontrols[i];
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
/* create new dapm mixer control */
static int dapm_new_mixer(struct snd_soc_dapm_context *dapm,
struct snd_soc_dapm_widget *w)
@@ -433,58 +455,80 @@ static int dapm_new_mux(struct snd_soc_dapm_context *dapm,
struct snd_card *card = dapm->card->snd_card;
const char *prefix;
size_t prefix_len;
- int ret = 0;
+ int ret;
struct snd_soc_dapm_widget_list *wlist;
+ int shared, wlistentries;
size_t wlistsize;
+ char *name;
- if (!w->num_kcontrols) {
- dev_err(dapm->dev, "asoc: mux %s has no controls\n", w->name);
+ if (w->num_kcontrols != 1) {
+ dev_err(dapm->dev,
+ "asoc: mux %s has incorrect number of controls\n",
+ w->name);
return -EINVAL;
}
+ shared = dapm_is_shared_kcontrol(dapm, &w->kcontrol_news[0],
+ &kcontrol);
+ if (kcontrol) {
+ wlist = kcontrol->private_data;
+ wlistentries = wlist->num_widgets + 1;
+ } else {
+ wlist = NULL;
+ wlistentries = 1;
+ }
wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
- sizeof(struct snd_soc_dapm_widget *),
- wlist = kzalloc(wlistsize, GFP_KERNEL);
+ wlistentries * sizeof(struct snd_soc_dapm_widget *),
+ wlist = krealloc(wlist, wlistsize, GFP_KERNEL);
if (wlist == NULL) {
dev_err(dapm->dev,
"asoc: can't allocate widget list for %s\n", w->name);
return -ENOMEM;
}
- wlist->num_widgets = 1;
- wlist->widgets[0] = w;
+ wlist->num_widgets = wlistentries;
+ wlist->widgets[wlistentries - 1] = w;
- if (dapm->codec)
- prefix = dapm->codec->name_prefix;
- else
- prefix = NULL;
-
- if (prefix)
- prefix_len = strlen(prefix) + 1;
- else
- prefix_len = 0;
+ if (!kcontrol) {
+ if (dapm->codec)
+ prefix = dapm->codec->name_prefix;
+ else
+ prefix = NULL;
+
+ if (shared) {
+ name = w->kcontrol_news[0].name;
+ prefix_len = 0;
+ } else {
+ name = w->name;
+ if (prefix)
+ prefix_len = strlen(prefix) + 1;
+ else
+ prefix_len = 0;
+ }
- /* The control will get a prefix from the control creation
- * process but we're also using the same prefix for widgets so
- * cut the prefix off the front of the widget name.
- */
- kcontrol = snd_soc_cnew(&w->kcontrol_news[0], wlist,
- w->name + prefix_len, prefix);
- ret = snd_ctl_add(card, kcontrol);
+ /*
+ * The control will get a prefix from the control creation
+ * process but we're also using the same prefix for widgets so
+ * cut the prefix off the front of the widget name.
+ */
+ kcontrol = snd_soc_cnew(&w->kcontrol_news[0], wlist,
+ name + prefix_len, prefix);
+ ret = snd_ctl_add(card, kcontrol);
+ if (ret < 0) {
+ dev_err(dapm->dev,
+ "asoc: failed to add kcontrol %s\n", w->name);
+ kfree(wlist);
+ return ret;
+ }
+ }
- if (ret < 0)
- goto err;
+ kcontrol->private_data = wlist;
w->kcontrols[0] = kcontrol;
list_for_each_entry(path, &w->sources, list_sink)
path->kcontrol = kcontrol;
- return ret;
-
-err:
- dev_err(dapm->dev, "asoc: failed to add kcontrol %s\n", w->name);
- kfree(wlist);
- return ret;
+ return 0;
}
/* create new dapm volume control */
OpenPOWER on IntegriCloud