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,
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;
......@@ -526,103 +536,141 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
else
prefix_len = 0;
/* 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;
shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
&kcontrol);
if (w->kcontrols[i]) {
path->kcontrol = w->kcontrols[i];
continue;
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",
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;
/* 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.
*/
name_len = strlen(w->kcontrol_news[i].name) + 1;
if (w->id != snd_soc_dapm_mixer_named_ctl)
name_len += 1 + strlen(w->name);
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;
}
}
path->long_name = kmalloc(name_len, GFP_KERNEL);
if (wname_in_long_name && kcname_in_long_name) {
name_len = strlen(w->name) - prefix_len + 1 +
strlen(w->kcontrol_news[kci].name) + 1;
if (path->long_name == NULL) {
long_name = kmalloc(name_len, GFP_KERNEL);
if (long_name == NULL) {
kfree(wlist);
return -ENOMEM;
}
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.
/*
* 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;
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;
}
((char *)path->long_name)[name_len - 1] = '\0';
path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i],
wlist, path->long_name,
kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name,
prefix);
ret = snd_ctl_add(card, path->kcontrol);
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, path->long_name, ret);
dev_err(dapm->dev,
"ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
w->name, name, ret);
kfree(wlist);
kfree(path->long_name);
path->long_name = NULL;
kfree(long_name);
return ret;
}
w->kcontrols[i] = path->kcontrol;
path->long_name = long_name;
}
kcontrol->private_data = wlist;
w->kcontrols[kci] = kcontrol;
path->kcontrol = kcontrol;
return 0;
}
/* 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;
}
ret = dapm_create_or_share_mixmux_kcontrol(w, i, path);
if (ret < 0)
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,
......@@ -631,65 +679,19 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
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;
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;
}
/*
* 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);
ret = dapm_create_or_share_mixmux_kcontrol(w, 0, path);
if (ret < 0)
return ret;
}
}
kcontrol->private_data = wlist;
w->kcontrols[0] = kcontrol;
list_for_each_entry(path, &w->sources, list_sink)
path->kcontrol = kcontrol;
path->kcontrol = w->kcontrols[0];
return 0;
}
......@@ -705,14 +707,33 @@ static int dapm_new_pga(struct snd_soc_dapm_widget *w)
}
/* 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;
list_for_each_entry(p, sink, list_source) {
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, &dapm->card->paths, list)
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
* the ALSA card - when we are suspending the ALSA state for the card
* is set to D3.
......@@ -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);
dapm_reset(card);
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
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);
dapm_clear_walk_input(&card->dapm,
&dai->capture_widget->sources);
}
trace_snd_soc_dapm_connected(paths, stream);
dapm_clear_walk(&card->dapm);
mutex_unlock(&card->dapm_mutex);
return paths;
......@@ -1104,9 +1129,9 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
DAPM_UPDATE_STAT(w, power_checks);
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);
dapm_clear_walk(w->dapm);
dapm_clear_walk_output(w->dapm, &w->sinks);
return out != 0 && in != 0;
}
......@@ -1129,7 +1154,7 @@ static int dapm_adc_check_power(struct snd_soc_dapm_widget *w)
if (w->active) {
in = is_connected_input_ep(w, NULL);
dapm_clear_walk(w->dapm);
dapm_clear_walk_input(w->dapm, &w->sources);
return in != 0;
} else {
return dapm_generic_check_power(w);
......@@ -1145,7 +1170,7 @@ static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
if (w->active) {
out = is_connected_output_ep(w, NULL);
dapm_clear_walk(w->dapm);
dapm_clear_walk_output(w->dapm, &w->sinks);
return out != 0;
} else {
return dapm_generic_check_power(w);
......@@ -1177,8 +1202,6 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
return 1;
}
dapm_clear_walk(w->dapm);
return 0;
}
......@@ -1759,9 +1782,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
return -ENOMEM;
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);
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",
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