summaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-dapm.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-07-04 04:52:22 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-04 04:52:22 +0200
commit1286da8bc009cb2aee7f285e94623fc974c0c983 (patch)
tree51ec0a79c3de63fa809b831ae0cbb5b85e44482f /sound/soc/soc-dapm.c
parentMerge branch 'for-3.11' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/l... (diff)
parentALSA: vmaster: Fix the regression of missing vmaster hook call (diff)
downloadlinux-1286da8bc009cb2aee7f285e94623fc974c0c983.tar.xz
linux-1286da8bc009cb2aee7f285e94623fc974c0c983.zip
Merge tag 'sound-3.11' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai: "A relative calm release at this time with a flat diffstat. The only significant change in the ALSA core side is the support for more than 32 card instances, configurable via kconfig. Other than that, in both ASoC and other parts, mostly some improvements and fixes on the driver side. - hda: More quirks for ALC269-variants on Dell & co, VIA codec fixes - hda: Haswell HDMI audio fixes, runtime PM improvements - hda: Intel BayTrail support, ALC5505 DSP support - es1968: MediaForte M56VAP support - usb-audio: Improved support for Yamaha/Roland devices - usb-audio: M2Tech hiFace, Audio Advantage Micro II support - hdspm: wordclock fixes - ASoC: Pending fixes for WM8962 - ASoC: Cleanups and fixes for Blackfin, SGTL5000 and UX500 - ASoC: Generalisation of the Bluetooth and HDMI stub drivers - ASoC: SSM2518 and RT5640 codec drivers. - ASoC: Tegra CPUs with RT5640 machine driver - ASoC: AC'97 refactoring bug fixes - ASoC: ADAU1701 driver fixes - Clean up of *_set_drvdata() in a wide range of drivers" * tag 'sound-3.11' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (284 commits) ALSA: vmaster: Fix the regression of missing vmaster hook call ALSA: hda - Add Dell SSID to support Headset Mic recording ASoC: adau1701: remove control_data assignment ASoC: adau1701: more direct regmap usage ASoC: ac97: fixup multi-platform AC'97 module build failure ASoC: pxa2xx: fixup multi-platform AC'97 build failures ASoC: tegra20-ac97: Remove unused variable ASoC: tegra20-ac97: Remove duplicate error message ALSA: usb-audio: Add Audio Advantage Micro II ASoC: tas5086: fix Mid-Z implementation ASoC: tas5086: fix TAS5086_CLOCK_CONTROL register size ALSA: Replace the magic number 44 with const ALSA: hda - Fix the max length of control name in generic parser ALSA: hda - Guess what, it's two more Dell headset mic quirks ALSA: hda - Yet another Dell headset mic quirk ALSA: hda - Add support for ALC5505 DSP power-save mode ASoC: mfld: Remove unused variable ALSA: usb-audio: add quirks for Roland QUAD/OCTO-CAPTURE ALSA: usb-audio: claim autodetected PCM interfaces all at once ALSA: usb-audio: remove superfluous Roland quirks ...
Diffstat (limited to 'sound/soc/soc-dapm.c')
-rw-r--r--sound/soc/soc-dapm.c110
1 files changed, 58 insertions, 52 deletions
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index c7051c457b75..b94190820e8c 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -64,6 +64,7 @@ static int dapm_up_seq[] = {
[snd_soc_dapm_virt_mux] = 5,
[snd_soc_dapm_value_mux] = 5,
[snd_soc_dapm_dac] = 6,
+ [snd_soc_dapm_switch] = 7,
[snd_soc_dapm_mixer] = 7,
[snd_soc_dapm_mixer_named_ctl] = 7,
[snd_soc_dapm_pga] = 8,
@@ -83,6 +84,7 @@ static int dapm_down_seq[] = {
[snd_soc_dapm_line] = 2,
[snd_soc_dapm_out_drv] = 2,
[snd_soc_dapm_pga] = 4,
+ [snd_soc_dapm_switch] = 5,
[snd_soc_dapm_mixer_named_ctl] = 5,
[snd_soc_dapm_mixer] = 5,
[snd_soc_dapm_dac] = 6,
@@ -365,11 +367,10 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
val = soc_widget_read(w, e->reg);
item = (val >> e->shift_l) & e->mask;
- p->connect = 0;
- for (i = 0; i < e->max; i++) {
- if (!(strcmp(p->name, e->texts[i])) && item == i)
- p->connect = 1;
- }
+ if (item < e->max && !strcmp(p->name, e->texts[item]))
+ p->connect = 1;
+ else
+ p->connect = 0;
}
break;
case snd_soc_dapm_virt_mux: {
@@ -399,11 +400,10 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
break;
}
- p->connect = 0;
- for (i = 0; i < e->max; i++) {
- if (!(strcmp(p->name, e->texts[i])) && item == i)
- p->connect = 1;
- }
+ if (item < e->max && !strcmp(p->name, e->texts[item]))
+ p->connect = 1;
+ else
+ p->connect = 0;
}
break;
/* does not affect routing - always connected */
@@ -507,6 +507,11 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
return 0;
}
+static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
+{
+ kfree(kctl->private_data);
+}
+
/*
* 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
@@ -524,7 +529,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
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;
@@ -589,25 +593,19 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
}
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",
+ long_name = kasprintf(GFP_KERNEL, "%s %s",
w->name + prefix_len,
w->kcontrol_news[kci].name);
- long_name[name_len - 1] = '\0';
+ if (long_name == NULL) {
+ kfree(wlist);
+ return -ENOMEM;
+ }
name = long_name;
} else if (wname_in_long_name) {
@@ -620,17 +618,16 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name,
prefix);
+ kcontrol->private_free = dapm_kcontrol_free;
+ kfree(long_name);
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;
@@ -1270,6 +1267,14 @@ static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm,
ev_name = "POST_PMD";
power = 0;
break;
+ case SND_SOC_DAPM_WILL_PMU:
+ ev_name = "WILL_PMU";
+ power = 1;
+ break;
+ case SND_SOC_DAPM_WILL_PMD:
+ ev_name = "WILL_PMD";
+ power = 0;
+ break;
default:
BUG();
return;
@@ -1730,6 +1735,14 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
&async_domain);
async_synchronize_full_domain(&async_domain);
+ list_for_each_entry(w, &down_list, power_list) {
+ dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMD);
+ }
+
+ list_for_each_entry(w, &up_list, power_list) {
+ dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMU);
+ }
+
/* Power down widgets first; try to avoid amplifying pops. */
dapm_seq_run(dapm, &down_list, event, false);
@@ -2094,6 +2107,14 @@ static void snd_soc_dapm_sys_remove(struct device *dev)
device_remove_file(dev, &dev_attr_dapm_widget);
}
+static void dapm_free_path(struct snd_soc_dapm_path *path)
+{
+ list_del(&path->list_sink);
+ list_del(&path->list_source);
+ list_del(&path->list);
+ kfree(path);
+}
+
/* free all dapm widgets and resources */
static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
{
@@ -2109,20 +2130,12 @@ static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
* While removing the path, remove reference to it from both
* source and sink widgets so that path is removed only once.
*/
- list_for_each_entry_safe(p, next_p, &w->sources, list_sink) {
- list_del(&p->list_sink);
- list_del(&p->list_source);
- list_del(&p->list);
- kfree(p->long_name);
- kfree(p);
- }
- list_for_each_entry_safe(p, next_p, &w->sinks, list_source) {
- list_del(&p->list_sink);
- list_del(&p->list_source);
- list_del(&p->list);
- kfree(p->long_name);
- kfree(p);
- }
+ list_for_each_entry_safe(p, next_p, &w->sources, list_sink)
+ dapm_free_path(p);
+
+ list_for_each_entry_safe(p, next_p, &w->sinks, list_source)
+ dapm_free_path(p);
+
kfree(w->kcontrols);
kfree(w->name);
kfree(w);
@@ -2398,10 +2411,7 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
dapm_mark_dirty(path->source, "Route removed");
dapm_mark_dirty(path->sink, "Route removed");
- list_del(&path->list);
- list_del(&path->list_sink);
- list_del(&path->list_source);
- kfree(path);
+ dapm_free_path(path);
} else {
dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n",
source, sink);
@@ -3055,7 +3065,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_widget *widget)
{
struct snd_soc_dapm_widget *w;
- size_t name_len;
int ret;
if ((w = dapm_cnew_widget(widget)) == NULL)
@@ -3096,19 +3105,16 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
break;
}
- name_len = strlen(widget->name) + 1;
if (dapm->codec && dapm->codec->name_prefix)
- name_len += 1 + strlen(dapm->codec->name_prefix);
- w->name = kmalloc(name_len, GFP_KERNEL);
+ w->name = kasprintf(GFP_KERNEL, "%s %s",
+ dapm->codec->name_prefix, widget->name);
+ else
+ w->name = kasprintf(GFP_KERNEL, "%s", widget->name);
+
if (w->name == NULL) {
kfree(w);
return NULL;
}
- if (dapm->codec && dapm->codec->name_prefix)
- snprintf((char *)w->name, name_len, "%s %s",
- dapm->codec->name_prefix, widget->name);
- else
- snprintf((char *)w->name, name_len, "%s", widget->name);
switch (w->id) {
case snd_soc_dapm_switch: