Merge remote-tracking branch 'asoc/topic/dapm' into asoc-next
This commit is contained in:
commit
7b451962c7
1 changed files with 171 additions and 148 deletions
|
@ -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,12 +536,117 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
|
||||||
else
|
else
|
||||||
prefix_len = 0;
|
prefix_len = 0;
|
||||||
|
|
||||||
|
shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
|
||||||
|
&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 (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;
|
||||||
|
|
||||||
|
long_name = kmalloc(name_len, GFP_KERNEL);
|
||||||
|
if (long_name == NULL) {
|
||||||
|
kfree(wlist);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 */
|
/* add kcontrol */
|
||||||
for (i = 0; i < w->num_kcontrols; i++) {
|
for (i = 0; i < w->num_kcontrols; i++) {
|
||||||
|
|
||||||
/* match name */
|
/* match name */
|
||||||
list_for_each_entry(path, &w->sources, list_sink) {
|
list_for_each_entry(path, &w->sources, list_sink) {
|
||||||
|
|
||||||
/* mixer/mux paths name must match control name */
|
/* mixer/mux paths name must match control name */
|
||||||
if (path->name != (char *)w->kcontrol_news[i].name)
|
if (path->name != (char *)w->kcontrol_news[i].name)
|
||||||
continue;
|
continue;
|
||||||
|
@ -541,88 +656,21 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
|
ret = dapm_create_or_share_mixmux_kcontrol(w, i, path);
|
||||||
sizeof(struct snd_soc_dapm_widget *),
|
if (ret < 0)
|
||||||
wlist = kzalloc(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;
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
|
|
||||||
path->long_name = kmalloc(name_len, GFP_KERNEL);
|
|
||||||
|
|
||||||
if (path->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.
|
|
||||||
*/
|
|
||||||
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';
|
|
||||||
|
|
||||||
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;
|
return ret;
|
||||||
}
|
|
||||||
w->kcontrols[i] = path->kcontrol;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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,
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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,
|
||||||
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",
|
||||||
|
|
Loading…
Reference in a new issue