From fffcf82ba1fb257cf52c2579031d7b22915dbefe Mon Sep 17 00:00:00 2001 From: Gopikrishnaiah Anandan Date: Fri, 15 Feb 2013 18:47:55 -0500 Subject: [PATCH] ASoC: Update alsa mixer/mux controls Change updates the way mux and mixer controls are registered with the Alsa core. Signed-off-by: Gopikrishnaiah Anandan --- include/sound/soc-dapm.h | 15 ++- include/sound/soc.h | 56 +++++----- sound/soc/soc-core.c | 177 +++++++++++--------------------- sound/soc/soc-dapm.c | 216 ++++++++++++++------------------------- 4 files changed, 175 insertions(+), 289 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index de29a95d670c..0a11e1ad8bb3 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -270,6 +270,12 @@ .put = snd_soc_dapm_put_enum_virt, \ .private_value = (unsigned long)&xenum } #define SOC_DAPM_ENUM_EXT(xname, xenum, xget, xput) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_info_enum_double, \ + .get = xget, \ + .put = xput, \ + .private_value = (unsigned long)&xenum } +#define SOC_DAPM_ENUM_EXT(xname, xenum, xget, xput) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_enum_double, \ .get = xget, \ @@ -319,6 +325,7 @@ struct snd_soc_dapm_path; struct snd_soc_dapm_pin; struct snd_soc_dapm_route; struct snd_soc_dapm_context; +struct snd_soc_dapm_widget_list; int dapm_reg_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); @@ -346,12 +353,11 @@ int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *uncontrol); int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *uncontrol); +int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, + const struct snd_soc_dapm_widget *widget); int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_widget *widget, int num); -int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, - struct snd_soc_dai *dai); -int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card); /* dapm path setup */ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm); @@ -371,7 +377,8 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card); int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget, struct snd_kcontrol *kcontrol, int connect); int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, - struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e); + struct snd_kcontrol *kcontrol, int change, + int mux, struct soc_enum *e); /* dapm sys fs - used by the core */ int snd_soc_dapm_sys_add(struct device *dev); diff --git a/include/sound/soc.h b/include/sound/soc.h index ad5756f2243c..055349ef17fd 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -55,6 +55,16 @@ .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ .put = snd_soc_put_volsw, \ .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } +#define SOC_SINGLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_READWRITE, \ + .tlv.p = (tlv_array), \ + .info = snd_soc_info_volsw_s8, .get = snd_soc_get_volsw_s8, \ + .put = snd_soc_put_volsw_s8, \ + .private_value = (unsigned long)&(struct soc_mixer_control) \ + {.reg = xreg, .min = xmin, .max = xmax, \ + .platform_max = xmax} } #define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ @@ -131,6 +141,14 @@ .get = xhandler_get, .put = xhandler_put, \ .private_value = \ SOC_DOUBLE_VALUE(reg, shift_left, shift_right, max, invert) } + #define SOC_SINGLE_MULTI_EXT(xname, xreg, xshift, xmax, xinvert, xcount,\ + xhandler_get, xhandler_put) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_info_multi_ext, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = (unsigned long)&(struct soc_multi_mixer_control) \ + {.reg = xreg, .shift = xshift, .rshift = xshift, .max = xmax, \ + .count = xcount, .platform_max = xmax, .invert = xinvert} } #define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\ xhandler_get, xhandler_put, tlv_array) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ @@ -185,20 +203,6 @@ .rreg = xreg_right, .shift = xshift, \ .min = xmin, .max = xmax} } -#define SND_SOC_BYTES(xname, xbase, xregs) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \ - .put = snd_soc_bytes_put, .private_value = \ - ((unsigned long)&(struct soc_bytes) \ - {.base = xbase, .num_regs = xregs }) } - -#define SND_SOC_BYTES_MASK(xname, xbase, xregs, xmask) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \ - .put = snd_soc_bytes_put, .private_value = \ - ((unsigned long)&(struct soc_bytes) \ - {.base = xbase, .num_regs = xregs, \ - .mask = xmask }) } /* * Simplified versions of above macros, declaring a struct and calculating @@ -222,6 +226,9 @@ #define SND_SOC_DAI_LINK_NO_HOST 0x1 #define SND_SOC_DAI_LINK_OPT_HOST 0x2 +#define snd_soc_get_enum_text(soc_enum, idx) \ + (soc_enum->texts ? soc_enum->texts[idx] : soc_enum->dtexts[idx]) + /* * Component probe and remove ordering levels for components with runtime @@ -421,7 +428,7 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec); *Controls */ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, - void *data, const char *long_name, + void *data, char *long_name, const char *prefix); int snd_soc_add_codec_controls(struct snd_soc_codec *codec, const struct snd_kcontrol_new *controls, int num_controls); @@ -445,6 +452,8 @@ int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); +int snd_soc_info_multi_ext(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); #define snd_soc_info_bool_ext snd_ctl_boolean_mono_info @@ -468,13 +477,6 @@ int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int snd_soc_bytes_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo); -int snd_soc_bytes_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); - /** * struct snd_soc_reg_access - Describes whether a given register is @@ -991,13 +993,12 @@ struct soc_mixer_control { int min, max, platform_max; unsigned int reg, rreg, shift, rshift, invert; }; - -struct soc_bytes { - int base; - int num_regs; - u32 mask; +struct soc_multi_mixer_control { + int min, max, platform_max, count; + unsigned int reg, rreg, shift, rshift, invert; }; + /* enumerated kcontrol */ struct soc_enum { unsigned short reg; @@ -1007,6 +1008,7 @@ struct soc_enum { unsigned int max; unsigned int mask; const char * const *texts; + char **dtexts; const unsigned int *values; void *dapm; }; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 590d7cf8dd4c..6001f350d6f1 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2177,7 +2177,7 @@ EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams); * Returns 0 for success, else error. */ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, - void *data, const char *long_name, + void *data, char *long_name, const char *prefix) { struct snd_kcontrol_new template; @@ -2334,7 +2334,8 @@ int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, if (uinfo->value.enumerated.item > e->max - 1) uinfo->value.enumerated.item = e->max - 1; strcpy(uinfo->value.enumerated.name, - e->texts[uinfo->value.enumerated.item]); + snd_soc_get_enum_text(e, uinfo->value.enumerated.item)); + return 0; } EXPORT_SYMBOL_GPL(snd_soc_info_enum_double); @@ -2498,7 +2499,7 @@ int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, if (uinfo->value.enumerated.item > e->max - 1) uinfo->value.enumerated.item = e->max - 1; strcpy(uinfo->value.enumerated.name, - e->texts[uinfo->value.enumerated.item]); + snd_soc_get_enum_text(e, uinfo->value.enumerated.item)); return 0; } EXPORT_SYMBOL_GPL(snd_soc_info_enum_ext); @@ -2529,6 +2530,39 @@ int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext); +/** + * snd_soc_info_multi_ext - external single mixer info callback + * @kcontrol: mixer control + * @uinfo: control element information + * + * Callback to provide information about a single external mixer control. + * that accepts multiple input. + * + * Returns 0 for success. + */ +int snd_soc_info_multi_ext(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct soc_multi_mixer_control *mc = + (struct soc_multi_mixer_control *)kcontrol->private_value; + int platform_max; + + if (!mc->platform_max) + mc->platform_max = mc->max; + platform_max = mc->platform_max; + + if (platform_max == 1 && !strnstr(kcontrol->id.name, " Volume", 30)) + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + else + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + + uinfo->count = mc->count; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = platform_max; + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_info_multi_ext); + /** * snd_soc_info_volsw - single mixer info callback * @kcontrol: mixer control @@ -2680,13 +2714,15 @@ int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; int platform_max; int min = mc->min; + unsigned int shift = mc->shift; + unsigned int rshift = mc->rshift; if (!mc->platform_max) mc->platform_max = mc->max; platform_max = mc->platform_max; uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 2; + uinfo->count = shift == rshift ? 1 : 2; uinfo->value.integer.min = 0; uinfo->value.integer.max = platform_max - min; return 0; @@ -2709,13 +2745,16 @@ int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); unsigned int reg = mc->reg; + unsigned int shift = mc->shift; + unsigned int rshift = mc->rshift; int min = mc->min; int val = snd_soc_read(codec, reg); ucontrol->value.integer.value[0] = - ((signed char)(val & 0xff))-min; - ucontrol->value.integer.value[1] = - ((signed char)((val >> 8) & 0xff))-min; + ((signed char)((val >> shift) & 0xff))-min; + if (shift != rshift) + ucontrol->value.integer.value[1] = + ((signed char)((val >> rshift) & 0xff))-min; return 0; } EXPORT_SYMBOL_GPL(snd_soc_get_volsw_s8); @@ -2736,13 +2775,20 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, (struct soc_mixer_control *)kcontrol->private_value; struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); unsigned int reg = mc->reg; + unsigned int shift = mc->shift; + unsigned int rshift = mc->rshift; int min = mc->min; - unsigned int val; + unsigned int val, val2, val_mask; - val = (ucontrol->value.integer.value[0]+min) & 0xff; - val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8; + val = ((ucontrol->value.integer.value[0]+min) & 0xff) << shift; + val_mask = 0xff << shift; + if (shift != rshift) { + val2 = (ucontrol->value.integer.value[1]+min) & 0xff; + val |= val2 << rshift; + val_mask |= 0xff << rshift; + } - return snd_soc_update_bits_locked(codec, reg, 0xffff, val); + return snd_soc_update_bits_locked(codec, reg, val_mask, val); } EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); @@ -2878,115 +2924,6 @@ int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx); -int snd_soc_bytes_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - struct soc_bytes *params = (void *)kcontrol->private_value; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; - uinfo->count = params->num_regs * codec->val_bytes; - - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_bytes_info); - -int snd_soc_bytes_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_bytes *params = (void *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - int ret; - - if (codec->using_regmap) - ret = regmap_raw_read(codec->control_data, params->base, - ucontrol->value.bytes.data, - params->num_regs * codec->val_bytes); - else - ret = -EINVAL; - - /* Hide any masked bytes to ensure consistent data reporting */ - if (ret == 0 && params->mask) { - switch (codec->val_bytes) { - case 1: - ucontrol->value.bytes.data[0] &= ~params->mask; - break; - case 2: - ((u16 *)(&ucontrol->value.bytes.data))[0] - &= ~params->mask; - break; - case 4: - ((u32 *)(&ucontrol->value.bytes.data))[0] - &= ~params->mask; - break; - default: - return -EINVAL; - } - } - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_bytes_get); - -int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_bytes *params = (void *)kcontrol->private_value; - struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - int ret, len; - unsigned int val; - void *data; - - if (!codec->using_regmap) - return -EINVAL; - - data = ucontrol->value.bytes.data; - len = params->num_regs * codec->val_bytes; - - /* - * If we've got a mask then we need to preserve the register - * bits. We shouldn't modify the incoming data so take a - * copy. - */ - if (params->mask) { - ret = regmap_read(codec->control_data, params->base, &val); - if (ret != 0) - return ret; - - val &= params->mask; - - data = kmemdup(data, len, GFP_KERNEL); - if (!data) - return -ENOMEM; - - switch (codec->val_bytes) { - case 1: - ((u8 *)data)[0] &= ~params->mask; - ((u8 *)data)[0] |= val; - break; - case 2: - ((u16 *)data)[0] &= cpu_to_be16(~params->mask); - ((u16 *)data)[0] |= cpu_to_be16(val); - break; - case 4: - ((u32 *)data)[0] &= cpu_to_be32(~params->mask); - ((u32 *)data)[0] |= cpu_to_be32(val); - break; - default: - return -EINVAL; - } - } - - ret = regmap_raw_write(codec->control_data, params->base, - data, len); - - if (params->mask) - kfree(data); - - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_bytes_put); - /** * snd_soc_dai_set_sysclk - configure DAI system or master clock. * @dai: DAI diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 124aab357879..dd1344917c16 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -316,7 +316,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, p->connect = 0; for (i = 0; i < e->max; i++) { - if (!(strcmp(p->name, e->texts[i])) && item == i) + if (!(strcmp(p->name, snd_soc_get_enum_text(e, i))) && item == i) p->connect = 1; } } @@ -332,7 +332,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, * that the default mux choice (the first) will be * correctly powered up during initialization. */ - if (!strcmp(p->name, e->texts[0])) + if (!strcmp(p->name, snd_soc_get_enum_text(e, 0))) p->connect = 1; } break; @@ -350,7 +350,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, p->connect = 0; for (i = 0; i < e->max; i++) { - if (!(strcmp(p->name, e->texts[i])) && item == i) + if (!(strcmp(p->name, snd_soc_get_enum_text(e, i))) && item == i) p->connect = 1; } } @@ -392,11 +392,11 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, int i; for (i = 0; i < e->max; i++) { - if (!(strcmp(control_name, e->texts[i]))) { + if (!(strcmp(control_name, snd_soc_get_enum_text(e, i)))) { list_add(&path->list, &dapm->card->paths); list_add(&path->list_sink, &dest->sources); list_add(&path->list_source, &src->sinks); - path->name = (char*)e->texts[i]; + path->name = (char*)snd_soc_get_enum_text(e, i); dapm_set_path_status(dest, path, 0); return 0; } @@ -569,7 +569,7 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) struct snd_soc_dapm_widget_list *wlist; int shared, wlistentries; size_t wlistsize; - const char *name; + char *name; if (w->num_kcontrols != 1) { dev_err(dapm->dev, @@ -1313,7 +1313,7 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie) dev_err(d->dev, "Failed to turn off bias: %d\n", ret); if (d->dev) - pm_runtime_put(d->dev); + pm_runtime_put_sync(d->dev); } /* If we just powered up then move to active bias */ @@ -1716,7 +1716,8 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) /* test and update the power status of a mux widget */ int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, - struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) + struct snd_kcontrol *kcontrol, int change, + int mux, struct soc_enum *e) { struct snd_soc_dapm_path *path; int found = 0; @@ -1726,17 +1727,21 @@ int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget, widget->id != snd_soc_dapm_value_mux) return -ENODEV; + if (!change) + return 0; + /* find dapm widget path assoc with kcontrol */ list_for_each_entry(path, &widget->dapm->card->paths, list) { + if (path->kcontrol != kcontrol) continue; - if (!path->name || !e->texts[mux]) + if (!path->name || !snd_soc_get_enum_text(e, mux)) continue; found = 1; /* we now need to match the string in the enum to the path */ - if (!(strcmp(path->name, e->texts[mux]))) { + if (!(strcmp(path->name, snd_soc_get_enum_text(e, mux)))) { path->connect = 1; /* new connection */ dapm_mark_dirty(path->source, "mux connection"); } else { @@ -2470,7 +2475,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, update.val = val; widget->dapm->update = &update; - snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e); + snd_soc_dapm_mux_update_power(widget, kcontrol, change, mux, e); widget->dapm->update = NULL; } @@ -2531,7 +2536,8 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, widget->value = ucontrol->value.enumerated.item[0]; - snd_soc_dapm_mux_update_power(widget, kcontrol, widget->value, e); + snd_soc_dapm_mux_update_power(widget, kcontrol, change, + widget->value, e); } } @@ -2634,7 +2640,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, update.val = val; widget->dapm->update = &update; - snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e); + snd_soc_dapm_mux_update_power(widget, kcontrol, change, mux, e); widget->dapm->update = NULL; } @@ -2715,16 +2721,23 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch); -static struct snd_soc_dapm_widget * -snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, - const struct snd_soc_dapm_widget *widget) +/** + * snd_soc_dapm_new_control - create new dapm control + * @dapm: DAPM context + * @widget: widget template + * + * Creates a new dapm control based upon the template. + * + * Returns 0 for success else error. + */ +int 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) - return NULL; + return -ENOMEM; name_len = strlen(widget->name) + 1; if (dapm->codec && dapm->codec->name_prefix) @@ -2732,13 +2745,13 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, w->name = kmalloc(name_len, GFP_KERNEL); if (w->name == NULL) { kfree(w); - return NULL; + return -ENOMEM; } if (dapm->codec && dapm->codec->name_prefix) - snprintf((char *)w->name, name_len, "%s %s", + snprintf(w->name, name_len, "%s %s", dapm->codec->name_prefix, widget->name); else - snprintf((char *)w->name, name_len, "%s", widget->name); + snprintf(w->name, name_len, "%s", widget->name); switch (w->id) { case snd_soc_dapm_switch: @@ -2809,16 +2822,15 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_widget *widget, int num) { - struct snd_soc_dapm_widget *w; - int i; + int i, ret; for (i = 0; i < num; i++) { - w = snd_soc_dapm_new_control(dapm, widget); - if (!w) { + ret = snd_soc_dapm_new_control(dapm, widget); + if (ret < 0) { dev_err(dapm->dev, - "ASoC: Failed to create DAPM control %s\n", - widget->name); - return -ENOMEM; + "ASoC: Failed to create DAPM control %s: %d\n", + widget->name, ret); + return ret; } widget++; } @@ -2826,126 +2838,54 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, } EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); -int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, - struct snd_soc_dai *dai) -{ - struct snd_soc_dapm_widget template; - struct snd_soc_dapm_widget *w; - - WARN_ON(dapm->dev != dai->dev); - - memset(&template, 0, sizeof(template)); - template.reg = SND_SOC_NOPM; - - if (dai->driver->playback.stream_name) { - template.id = snd_soc_dapm_dai; - template.name = dai->driver->playback.stream_name; - template.sname = dai->driver->playback.stream_name; - - dev_dbg(dai->dev, "adding %s widget\n", - template.name); - - w = snd_soc_dapm_new_control(dapm, &template); - if (!w) { - dev_err(dapm->dev, "Failed to create %s widget\n", - dai->driver->playback.stream_name); - } - - w->priv = dai; - dai->playback_widget = w; - } - - if (dai->driver->capture.stream_name) { - template.id = snd_soc_dapm_dai; - template.name = dai->driver->capture.stream_name; - template.sname = dai->driver->capture.stream_name; - - dev_dbg(dai->dev, "adding %s widget\n", - template.name); - - w = snd_soc_dapm_new_control(dapm, &template); - if (!w) { - dev_err(dapm->dev, "Failed to create %s widget\n", - dai->driver->capture.stream_name); - } - - w->priv = dai; - dai->capture_widget = w; - } - - return 0; -} - -int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card) -{ - struct snd_soc_dapm_widget *dai_w, *w; - struct snd_soc_dai *dai; - struct snd_soc_dapm_route r; - - memset(&r, 0, sizeof(r)); - - /* For each DAI widget... */ - list_for_each_entry(dai_w, &card->widgets, list) { - if (dai_w->id != snd_soc_dapm_dai) - continue; - - dai = dai_w->priv; - - /* ...find all widgets with the same stream and link them */ - list_for_each_entry(w, &card->widgets, list) { - if (w->dapm != dai_w->dapm) - continue; - - if (w->id == snd_soc_dapm_dai) - continue; - - if (!w->sname) - continue; - - if (dai->driver->playback.stream_name && - strstr(w->sname, - dai->driver->playback.stream_name)) { - r.source = dai->playback_widget->name; - r.sink = w->name; - dev_dbg(dai->dev, "%s -> %s\n", - r.source, r.sink); - - snd_soc_dapm_add_route(w->dapm, &r); - } - - if (dai->driver->capture.stream_name && - strstr(w->sname, - dai->driver->capture.stream_name)) { - r.source = w->name; - r.sink = dai->capture_widget->name; - dev_dbg(dai->dev, "%s -> %s\n", - r.source, r.sink); - - snd_soc_dapm_add_route(w->dapm, &r); - } - } - } - - return 0; -} - static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm, - int stream, struct snd_soc_dai *dai, - int event) + const char *stream, int event) { struct snd_soc_dapm_widget *w; - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - w = dai->playback_widget; - else - w = dai->capture_widget; + if (!dapm) + return; + list_for_each_entry(w, &dapm->card->widgets, list) + { + if (!w->sname || w->dapm != dapm) + continue; + dev_vdbg(w->dapm->dev, "widget %s\n %s stream %s event %d\n", + w->name, w->sname, stream, event); + if (strstr(w->sname, stream)) { + dapm_mark_dirty(w, "stream event"); + switch(event) { + case SND_SOC_DAPM_STREAM_START: + w->active = 1; + break; + case SND_SOC_DAPM_STREAM_STOP: + w->active = 0; + break; + case SND_SOC_DAPM_STREAM_SUSPEND: + case SND_SOC_DAPM_STREAM_RESUME: + case SND_SOC_DAPM_STREAM_PAUSE_PUSH: + case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: + break; + } + } + } + + dapm_power_widgets(dapm, event); + + /* do we need to notify any clients that DAPM stream is complete */ + if (dapm->stream_event) + dapm->stream_event(dapm, event); +} + +static void widget_stream_event(struct snd_soc_dapm_context *dapm, + struct snd_soc_dapm_widget *w, int event) +{ if (!w) return; dapm_mark_dirty(w, "stream event"); - switch (event) { + switch(event) { case SND_SOC_DAPM_STREAM_START: w->active = 1; break;