[alsa-devel] [RFC_iv/iv 1/1] ASoC: Add optional name_prefix to struct snd_soc_dev_map
There is a need to prefix codec kcontrol, widget and internal route names in an ASoC machine that has multiple codecs with conflicting names. The name collision would occur when codec drivers try to registering kcontrols with the same name or when building the audio paths between codecs.
This patch solves the issue by introducing optional name_prefix field to struct snd_soc_dev_map that machine drivers can specify. ASoC core then uses that prefix for prefixing names for codec kcontrols, widgets and codec internal routes.
Following example illustrates how two same codec instances are registered in a machine driver. The name collision is avoided by specifying a name prefix for the second codec. That prefix is then used in audio map that connects output of first codec to the input of second and output of second codec to a machine widget.
static const struct snd_soc_dapm_route map0[] = { {"Spk", NULL, "MONO"}, };
static const struct snd_soc_dapm_route map1[] = { {"foo LINEIN", NULL, "MONO"}, {"Vibra", NULL, "foo MONO"}, };
static struct snd_soc_dev_map bar_dev[] = { { ... .codec_name = "simple-codec.0", .init = bar_codec0_init, ... }, { ... .codec_name = "simple-codec.1", .init = bar_codec1_init, .name_prefix = "foo", ... }, };
Signed-off-by: Jarkko Nikula jhnikula@gmail.com --- include/sound/soc.h | 4 ++++ sound/soc/soc-core.c | 16 ++++++++++++++-- sound/soc/soc-dapm.c | 34 ++++++++++++++++++++++++++++++++-- 3 files changed, 50 insertions(+), 4 deletions(-)
diff --git a/include/sound/soc.h b/include/sound/soc.h index 17f985c..18de502 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -424,6 +424,7 @@ struct snd_soc_ops { /* SoC Audio Codec device */ struct snd_soc_codec { const char *name; + const char *name_prefix; int id; struct device *dev; struct snd_soc_codec_driver *driver; @@ -547,6 +548,9 @@ struct snd_soc_dev_map {
/* machine stream operations */ struct snd_soc_ops *ops; + + /* optional name prefix for kcontrols and widgets */ + const char *name_prefix; };
/* SoC card */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b904a20..2c9b6ef 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1416,6 +1416,7 @@ static int soc_probe_dev_map(struct snd_soc_card *card, int num) /* probe the CODEC */ if (!codec->probed) { codec->dapm->card = card; + codec->name_prefix = dev_map->name_prefix; if (codec->driver->probe) { ret = codec->driver->probe(codec); if (ret < 0) { @@ -1469,11 +1470,14 @@ static int soc_probe_dev_map(struct snd_soc_card *card, int num)
/* now that all clients have probed, initialise the DAI link */ if (dev_map->init) { + /* machine controls, routes and widgets are not prefixed */ + rtd->codec->name_prefix = NULL; ret = dev_map->init(rtd); if (ret < 0) { printk(KERN_ERR "asoc: failed to init %s\n", dev_map->stream_name); return ret; } + rtd->codec->name_prefix = dev_map->name_prefix; }
/* Make sure all DAPM widgets are instantiated */ @@ -2030,14 +2034,22 @@ int snd_soc_add_controls(struct snd_soc_codec *codec, const struct snd_kcontrol_new *controls, int num_controls) { struct snd_card *card = codec->card->snd_card; + char prefixed_name[44], *name; int err, i;
for (i = 0; i < num_controls; i++) { const struct snd_kcontrol_new *control = &controls[i]; - err = snd_ctl_add(card, snd_soc_cnew(control, codec, NULL)); + if (codec->name_prefix) { + snprintf(prefixed_name, sizeof(prefixed_name), "%s %s", + codec->name_prefix, control->name); + name = prefixed_name; + } else { + name = control->name; + } + err = snd_ctl_add(card, snd_soc_cnew(control, codec, name)); if (err < 0) { dev_err(codec->dev, "%s: Failed to add %s: %d\n", - codec->name, control->name, err); + codec->name, name, err); return err; } } diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 2bccc9d..34bc7a8 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1291,6 +1291,7 @@ static void dapm_free_widgets(struct snd_soc_dapm_context *dapm) kfree(p->long_name); kfree(p); } + kfree(w->name); kfree(w); } } @@ -1339,11 +1340,25 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, struct snd_soc_dapm_path *path; struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL; - const char *sink = route->sink; + const char *sink; const char *control = route->control; - const char *source = route->source; + const char *source; + char prefixed_sink[80]; + char prefixed_source[80]; int ret = 0;
+ if (dapm->codec->name_prefix) { + snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", + dapm->codec->name_prefix, route->sink); + sink = prefixed_sink; + snprintf(prefixed_source, sizeof(prefixed_source), "%s %s", + dapm->codec->name_prefix, route->source); + source = prefixed_source; + } else { + sink = route->sink; + source = route->source; + } + /* * find src and dest widgets over all widgets but favor a widget from * current DAPM context @@ -1983,10 +1998,25 @@ 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;
if ((w = dapm_cnew_widget(widget)) == NULL) return -ENOMEM;
+ name_len = strlen(widget->name) + 1; + if (dapm->codec->name_prefix) + name_len += 1 + strlen(dapm->codec->name_prefix); + w->name = kmalloc(name_len, GFP_KERNEL); + if (w->name == NULL) { + kfree(w); + return -ENOMEM; + } + if (dapm->codec->name_prefix) + snprintf(w->name, name_len, "%s %s", + dapm->codec->name_prefix, widget->name); + else + snprintf(w->name, name_len, "%s", widget->name); + dapm->n_widgets++; w->dapm = dapm; w->codec = dapm->codec;
On Fri, Oct 29, 2010 at 03:03:43PM +0300, Jarkko Nikula wrote:
@@ -547,6 +548,9 @@ struct snd_soc_dev_map {
/* machine stream operations */ struct snd_soc_ops *ops;
- /* optional name prefix for kcontrols and widgets */
- const char *name_prefix;
This is another issue with using the DAI links to map these things - as previously discussed we want to be able to support CODEC<->CODEC DAI links, and we don't have a way to associate controls with specific DAI links on multi-DAI devices.
On Fri, 29 Oct 2010 14:42:45 -0700 Mark Brown broonie@opensource.wolfsonmicro.com wrote:
On Fri, Oct 29, 2010 at 03:03:43PM +0300, Jarkko Nikula wrote:
@@ -547,6 +548,9 @@ struct snd_soc_dev_map {
/* machine stream operations */ struct snd_soc_ops *ops;
- /* optional name prefix for kcontrols and widgets */
- const char *name_prefix;
This is another issue with using the DAI links to map these things - as previously discussed we want to be able to support CODEC<->CODEC DAI links, and we don't have a way to associate controls with specific DAI links on multi-DAI devices.
Indeed, I forgot these links and then name_prefix in snd_soc_dev_map/_dai_link is not the right place. One of my earlier version of this prefixing stuff implemented a prefix_map to snd_soc_card associating a prefix with codec name. Compile tested diff below.
I don't know would it fit to multi-DAI devices. Should those drivers differentiate inside their controls & widgets for different DAIs?
On Sun, Oct 31, 2010 at 08:12:43PM +0200, Jarkko Nikula wrote:
I don't know would it fit to multi-DAI devices. Should those drivers differentiate inside their controls & widgets for different DAIs?
As previously discussed that's not going to be possible in general - many of these devices will support mixing signals between the DAIs so for many of the controls it won't be possible to associate them with any particular DAI. This can happen very early within the chip so means that any per DAI naming ends up being ineffecitve.
On Sun, Oct 31, 2010 at 08:12:43PM +0200, Jarkko Nikula wrote:
associating a prefix with codec name. Compile tested diff below.
Oh, didn't spot this first time round due to sig sep - that diff looks a lot better at first glance. We need a way to get the data into the card I guess.
participants (2)
-
Jarkko Nikula
-
Mark Brown