return 0;
}
-/* create new dapm mixer control */
-static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
+/*
+ * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
+ * create it. Either way, add the widget into the control's widget list
+ */
+static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
+ int kci, struct snd_soc_dapm_path *path)
{
struct snd_soc_dapm_context *dapm = w->dapm;
- int i, ret = 0;
- size_t name_len, prefix_len;
- struct snd_soc_dapm_path *path;
struct snd_card *card = dapm->card->snd_card;
const char *prefix;
+ size_t prefix_len;
+ int shared;
+ struct snd_kcontrol *kcontrol;
struct snd_soc_dapm_widget_list *wlist;
+ int wlistentries;
size_t wlistsize;
+ bool wname_in_long_name, kcname_in_long_name;
+ size_t name_len;
+ char *long_name;
+ const char *name;
+ int ret;
if (dapm->codec)
prefix = dapm->codec->name_prefix;
else
prefix_len = 0;
- /* add kcontrol */
- for (i = 0; i < w->num_kcontrols; i++) {
+ shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
+ &kcontrol);
- /* match name */
- list_for_each_entry(path, &w->sources, list_sink) {
+ if (kcontrol) {
+ wlist = kcontrol->private_data;
+ wlistentries = wlist->num_widgets + 1;
+ } else {
+ wlist = NULL;
+ wlistentries = 1;
+ }
- /* mixer/mux paths name must match control name */
- if (path->name != (char *)w->kcontrol_news[i].name)
- continue;
+ wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
+ 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 = wlistentries;
+ wlist->widgets[wlistentries - 1] = w;
- if (w->kcontrols[i]) {
- path->kcontrol = w->kcontrols[i];
- continue;
+ if (!kcontrol) {
+ if (shared) {
+ wname_in_long_name = false;
+ kcname_in_long_name = true;
+ } else {
+ switch (w->id) {
+ case snd_soc_dapm_switch:
+ case snd_soc_dapm_mixer:
+ wname_in_long_name = true;
+ kcname_in_long_name = true;
+ break;
+ case snd_soc_dapm_mixer_named_ctl:
+ wname_in_long_name = false;
+ kcname_in_long_name = true;
+ break;
+ case snd_soc_dapm_mux:
+ case snd_soc_dapm_virt_mux:
+ case snd_soc_dapm_value_mux:
+ wname_in_long_name = true;
+ kcname_in_long_name = false;
+ break;
+ default:
+ kfree(wlist);
+ return -EINVAL;
}
+ }
+
+ if (wname_in_long_name && kcname_in_long_name) {
+ name_len = strlen(w->name) - prefix_len + 1 +
+ strlen(w->kcontrol_news[kci].name) + 1;
- wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
- sizeof(struct snd_soc_dapm_widget *),
- wlist = kzalloc(wlistsize, GFP_KERNEL);
- if (wlist == NULL) {
- dev_err(dapm->dev,
- "ASoC: can't allocate widget list for %s\n",
- w->name);
+ long_name = kmalloc(name_len, GFP_KERNEL);
+ if (long_name == NULL) {
+ kfree(wlist);
return -ENOMEM;
}
- wlist->num_widgets = 1;
- wlist->widgets[0] = w;
-
- /* add dapm control with long name.
- * for dapm_mixer this is the concatenation of the
- * mixer and kcontrol name.
- * for dapm_mixer_named_ctl this is simply the
- * kcontrol name.
+
+ /*
+ * 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.
*/
- name_len = strlen(w->kcontrol_news[i].name) + 1;
- if (w->id != snd_soc_dapm_mixer_named_ctl)
- name_len += 1 + strlen(w->name);
+ snprintf(long_name, name_len, "%s %s",
+ w->name + prefix_len,
+ w->kcontrol_news[kci].name);
+ long_name[name_len - 1] = '\0';
+
+ name = long_name;
+ } else if (wname_in_long_name) {
+ long_name = NULL;
+ name = w->name + prefix_len;
+ } else {
+ long_name = NULL;
+ name = w->kcontrol_news[kci].name;
+ }
- path->long_name = kmalloc(name_len, GFP_KERNEL);
+ kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name,
+ prefix);
+ ret = snd_ctl_add(card, kcontrol);
+ if (ret < 0) {
+ dev_err(dapm->dev,
+ "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
+ w->name, name, ret);
+ kfree(wlist);
+ kfree(long_name);
+ return ret;
+ }
- if (path->long_name == NULL) {
- kfree(wlist);
- return -ENOMEM;
- }
+ path->long_name = long_name;
+ }
- switch (w->id) {
- default:
- /* 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.
- */
- snprintf((char *)path->long_name, name_len,
- "%s %s", w->name + prefix_len,
- w->kcontrol_news[i].name);
- break;
- case snd_soc_dapm_mixer_named_ctl:
- snprintf((char *)path->long_name, name_len,
- "%s", w->kcontrol_news[i].name);
- break;
- }
+ kcontrol->private_data = wlist;
+ w->kcontrols[kci] = kcontrol;
+ path->kcontrol = kcontrol;
- ((char *)path->long_name)[name_len - 1] = '\0';
+ return 0;
+}
- path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i],
- wlist, path->long_name,
- prefix);
- ret = snd_ctl_add(card, path->kcontrol);
- if (ret < 0) {
- dev_err(dapm->dev, "ASoC: failed to add widget"
- " %s dapm kcontrol %s: %d\n",
- w->name, path->long_name, ret);
- kfree(wlist);
- kfree(path->long_name);
- path->long_name = NULL;
- return ret;
+/* create new dapm mixer control */
+static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
+{
+ int i, ret;
+ struct snd_soc_dapm_path *path;
+
+ /* add kcontrol */
+ for (i = 0; i < w->num_kcontrols; i++) {
+ /* match name */
+ list_for_each_entry(path, &w->sources, list_sink) {
+ /* mixer/mux paths name must match control name */
+ if (path->name != (char *)w->kcontrol_news[i].name)
+ continue;
+
+ if (w->kcontrols[i]) {
+ path->kcontrol = w->kcontrols[i];
+ continue;
}
- w->kcontrols[i] = path->kcontrol;
+
+ ret = dapm_create_or_share_mixmux_kcontrol(w, i, path);
+ if (ret < 0)
+ return ret;
}
}
- return ret;
+
+ return 0;
}
/* create new dapm mux control */
static int dapm_new_mux(struct snd_soc_dapm_widget *w)
{
struct snd_soc_dapm_context *dapm = w->dapm;
- struct snd_soc_dapm_path *path = NULL;
- struct snd_kcontrol *kcontrol;
- struct snd_card *card = dapm->card->snd_card;
- const char *prefix;
- size_t prefix_len;
+ struct snd_soc_dapm_path *path;
int ret;
- struct snd_soc_dapm_widget_list *wlist;
- int shared, wlistentries;
- size_t wlistsize;
- const char *name;
if (w->num_kcontrols != 1) {
dev_err(dapm->dev,
return -EINVAL;
}
- shared = dapm_is_shared_kcontrol(dapm, w, &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) +
- 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 = wlistentries;
- wlist->widgets[wlistentries - 1] = w;
-
- 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,
- name + prefix_len, prefix);
- ret = snd_ctl_add(card, kcontrol);
- if (ret < 0) {
- dev_err(dapm->dev, "ASoC: failed to add kcontrol %s: %d\n",
- w->name, ret);
- kfree(wlist);
- return ret;
- }
+ path = list_first_entry(&w->sources, struct snd_soc_dapm_path,
+ list_sink);
+ if (!path) {
+ dev_err(dapm->dev, "ASoC: mux %s has no paths\n", w->name);
+ return -EINVAL;
}
- kcontrol->private_data = wlist;
-
- w->kcontrols[0] = kcontrol;
+ ret = dapm_create_or_share_mixmux_kcontrol(w, 0, path);
+ if (ret < 0)
+ return ret;
list_for_each_entry(path, &w->sources, list_sink)
- path->kcontrol = kcontrol;
+ path->kcontrol = w->kcontrols[0];
return 0;
}