Commit 7b451962 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branch 'asoc/topic/dapm' into asoc-next

parents 69976189 1059ecfa
...@@ -504,17 +504,27 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm, ...@@ -504,17 +504,27 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
return 0; 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; 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; struct snd_card *card = dapm->card->snd_card;
const char *prefix; const char *prefix;
size_t prefix_len;
int shared;
struct snd_kcontrol *kcontrol;
struct snd_soc_dapm_widget_list *wlist; struct snd_soc_dapm_widget_list *wlist;
int wlistentries;
size_t wlistsize; 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) if (dapm->codec)
prefix = dapm->codec->name_prefix; prefix = dapm->codec->name_prefix;
...@@ -526,103 +536,141 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w) ...@@ -526,103 +536,141 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
else else
prefix_len = 0; prefix_len = 0;
/* add kcontrol */ shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
for (i = 0; i < w->num_kcontrols; i++) { &kcontrol);
/* match name */ if (kcontrol) {
list_for_each_entry(path, &w->sources, list_sink) { wlist = kcontrol->private_data;
wlistentries = wlist->num_widgets + 1;
} else {
wlist = NULL;
wlistentries = 1;
}
/* mixer/mux paths name must match control name */ wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
if (path->name != (char *)w->kcontrol_news[i].name) wlistentries * sizeof(struct snd_soc_dapm_widget *);
continue; 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]) { if (!kcontrol) {
path->kcontrol = w->kcontrols[i]; if (shared) {
continue; 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) + long_name = kmalloc(name_len, GFP_KERNEL);
sizeof(struct snd_soc_dapm_widget *), if (long_name == NULL) {
wlist = kzalloc(wlistsize, GFP_KERNEL); kfree(wlist);
if (wlist == NULL) {
dev_err(dapm->dev,
"ASoC: can't allocate widget list for %s\n",
w->name);
return -ENOMEM; return -ENOMEM;
} }
wlist->num_widgets = 1;
wlist->widgets[0] = w; /*
* The control will get a prefix from the control
/* add dapm control with long name. * creation process but we're also using the same
* for dapm_mixer this is the concatenation of the * prefix for widgets so cut the prefix off the
* mixer and kcontrol name. * front of the widget name.
* for dapm_mixer_named_ctl this is simply the
* kcontrol name.
*/ */
name_len = strlen(w->kcontrol_news[i].name) + 1; snprintf(long_name, name_len, "%s %s",
if (w->id != snd_soc_dapm_mixer_named_ctl) w->name + prefix_len,
name_len += 1 + strlen(w->name); 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) { path->long_name = long_name;
kfree(wlist); }
return -ENOMEM;
}
switch (w->id) { kcontrol->private_data = wlist;
default: w->kcontrols[kci] = kcontrol;
/* The control will get a prefix from path->kcontrol = kcontrol;
* 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;
}
((char *)path->long_name)[name_len - 1] = '\0'; return 0;
}
path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i], /* create new dapm mixer control */
wlist, path->long_name, static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
prefix); {
ret = snd_ctl_add(card, path->kcontrol); int i, ret;
if (ret < 0) { struct snd_soc_dapm_path *path;
dev_err(dapm->dev, "ASoC: failed to add widget"
" %s dapm kcontrol %s: %d\n", /* add kcontrol */
w->name, path->long_name, ret); for (i = 0; i < w->num_kcontrols; i++) {
kfree(wlist); /* match name */
kfree(path->long_name); list_for_each_entry(path, &w->sources, list_sink) {
path->long_name = NULL; /* mixer/mux paths name must match control name */
return ret; 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 */ /* create new dapm mux control */
static int dapm_new_mux(struct snd_soc_dapm_widget *w) static int dapm_new_mux(struct snd_soc_dapm_widget *w)
{ {
struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_dapm_context *dapm = w->dapm;
struct snd_soc_dapm_path *path = NULL; struct snd_soc_dapm_path *path;
struct snd_kcontrol *kcontrol;
struct snd_card *card = dapm->card->snd_card;
const char *prefix;
size_t prefix_len;
int ret; int ret;
struct snd_soc_dapm_widget_list *wlist;
int shared, wlistentries;
size_t wlistsize;
const char *name;
if (w->num_kcontrols != 1) { if (w->num_kcontrols != 1) {
dev_err(dapm->dev, dev_err(dapm->dev,
...@@ -631,65 +679,19 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) ...@@ -631,65 +679,19 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
return -EINVAL; return -EINVAL;
} }
shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[0], path = list_first_entry(&w->sources, struct snd_soc_dapm_path,
&kcontrol); list_sink);
if (kcontrol) { if (!path) {
wlist = kcontrol->private_data; dev_err(dapm->dev, "ASoC: mux %s has no paths\n", w->name);
wlistentries = wlist->num_widgets + 1; return -EINVAL;
} 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;
}
} }
kcontrol->private_data = wlist; ret = dapm_create_or_share_mixmux_kcontrol(w, 0, path);
if (ret < 0)
w->kcontrols[0] = kcontrol; return ret;
list_for_each_entry(path, &w->sources, list_sink) list_for_each_entry(path, &w->sources, list_sink)
path->kcontrol = kcontrol; path->kcontrol = w->kcontrols[0];
return 0; return 0;
} }
...@@ -705,14 +707,33 @@ static int dapm_new_pga(struct snd_soc_dapm_widget *w) ...@@ -705,14 +707,33 @@ static int dapm_new_pga(struct snd_soc_dapm_widget *w)
} }
/* reset 'walked' bit for each dapm path */ /* reset 'walked' bit for each dapm path */
static inline void dapm_clear_walk(struct snd_soc_dapm_context *dapm) static void dapm_clear_walk_output(struct snd_soc_dapm_context *dapm,
struct list_head *sink)
{ {
struct snd_soc_dapm_path *p; struct snd_soc_dapm_path *p;
list_for_each_entry(p, &dapm->card->paths, list) list_for_each_entry(p, sink, list_source) {
p->walked = 0; if (p->walked) {
p->walked = 0;
dapm_clear_walk_output(dapm, &p->sink->sinks);
}
}
} }
static void dapm_clear_walk_input(struct snd_soc_dapm_context *dapm,
struct list_head *source)
{
struct snd_soc_dapm_path *p;
list_for_each_entry(p, source, list_sink) {
if (p->walked) {
p->walked = 0;
dapm_clear_walk_input(dapm, &p->source->sources);
}
}
}
/* We implement power down on suspend by checking the power state of /* We implement power down on suspend by checking the power state of
* the ALSA card - when we are suspending the ALSA state for the card * the ALSA card - when we are suspending the ALSA state for the card
* is set to D3. * is set to D3.
...@@ -995,13 +1016,17 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, ...@@ -995,13 +1016,17 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
dapm_reset(card); dapm_reset(card);
if (stream == SNDRV_PCM_STREAM_PLAYBACK) if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
paths = is_connected_output_ep(dai->playback_widget, list); paths = is_connected_output_ep(dai->playback_widget, list);
else dapm_clear_walk_output(&card->dapm,
&dai->playback_widget->sinks);
} else {
paths = is_connected_input_ep(dai->capture_widget, list); paths = is_connected_input_ep(dai->capture_widget, list);
dapm_clear_walk_input(&card->dapm,
&dai->capture_widget->sources);
}
trace_snd_soc_dapm_connected(paths, stream); trace_snd_soc_dapm_connected(paths, stream);
dapm_clear_walk(&card->dapm);
mutex_unlock(&card->dapm_mutex); mutex_unlock(&card->dapm_mutex);
return paths; return paths;
...@@ -1104,9 +1129,9 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w) ...@@ -1104,9 +1129,9 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
DAPM_UPDATE_STAT(w, power_checks); DAPM_UPDATE_STAT(w, power_checks);
in = is_connected_input_ep(w, NULL); in = is_connected_input_ep(w, NULL);
dapm_clear_walk(w->dapm); dapm_clear_walk_input(w->dapm, &w->sources);
out = is_connected_output_ep(w, NULL); out = is_connected_output_ep(w, NULL);
dapm_clear_walk(w->dapm); dapm_clear_walk_output(w->dapm, &w->sinks);
return out != 0 && in != 0; return out != 0 && in != 0;
} }
...@@ -1129,7 +1154,7 @@ static int dapm_adc_check_power(struct snd_soc_dapm_widget *w) ...@@ -1129,7 +1154,7 @@ static int dapm_adc_check_power(struct snd_soc_dapm_widget *w)
if (w->active) { if (w->active) {
in = is_connected_input_ep(w, NULL); in = is_connected_input_ep(w, NULL);
dapm_clear_walk(w->dapm); dapm_clear_walk_input(w->dapm, &w->sources);
return in != 0; return in != 0;
} else { } else {
return dapm_generic_check_power(w); return dapm_generic_check_power(w);
...@@ -1145,7 +1170,7 @@ static int dapm_dac_check_power(struct snd_soc_dapm_widget *w) ...@@ -1145,7 +1170,7 @@ static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
if (w->active) { if (w->active) {
out = is_connected_output_ep(w, NULL); out = is_connected_output_ep(w, NULL);
dapm_clear_walk(w->dapm); dapm_clear_walk_output(w->dapm, &w->sinks);
return out != 0; return out != 0;
} else { } else {
return dapm_generic_check_power(w); return dapm_generic_check_power(w);
...@@ -1177,8 +1202,6 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) ...@@ -1177,8 +1202,6 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
return 1; return 1;
} }
dapm_clear_walk(w->dapm);
return 0; return 0;
} }
...@@ -1759,9 +1782,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file, ...@@ -1759,9 +1782,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
return -ENOMEM; return -ENOMEM;
in = is_connected_input_ep(w, NULL); in = is_connected_input_ep(w, NULL);
dapm_clear_walk(w->dapm); dapm_clear_walk_input(w->dapm, &w->sources);
out = is_connected_output_ep(w, NULL); out = is_connected_output_ep(w, NULL);
dapm_clear_walk(w->dapm); dapm_clear_walk_output(w->dapm, &w->sinks);
ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d", ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d",
w->name, w->power ? "On" : "Off", w->name, w->power ? "On" : "Off",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment