On Fri, 20 Aug 2010 11:51:44 +0300 Jarkko Nikula <jhnikula@xxxxxxxxx> wrote: > On Thu, 19 Aug 2010 18:20:49 +0300 > Jarkko Nikula <jhnikula@xxxxxxxxx> wrote: > > > cpu_dai->driver->probe > > codec->driver->probe > > -> Codec adds controls, widgets and routes (only controls > > are prefixed. E.g. "front.") > > platform->driver->probe > > codec_dai->driver->probe > > dai_link->init > > -> Machine adds controls, widgets and routes (no prefixes) > > -> Machine registers stuff from extra drivers (all > > controls, widgets and routes are prefixed per driver. > > E.g. "front-left-amp.", "front-right-amp." ) > > > > Codec and machine registrations are easy to separate e.g. by some flag > > and use only codec->kcontrol_prefix and continue using unmodified API. > > > > I think extra drivers could use own variants of those registration > > functions that have the name_prefix argument (and core would call them > > too). Then we don't need to patch all the codec and machine drivers. > > Does this sound feasible? > > > Ok, this was easy. I added functions variants that take the prefix and > that core calls also. So _snd_soc_add_controls, > _snd_soc_dapm_new_control, _snd_soc_dapm_new_controls and > _snd_soc_dapm_add_routes. > > This way there is no need to patch all existing drivers and core can > prefix nicely codec kcontrols based on codec->probed flag. Then > external drivers can use those function variants by passing custom > prefix that is different than codec->kcontrol_prefix. > > No other changes from previous version. I.e. dai_link->kcontrol_prefix > hack is still here. > Here's the recent version. I removed dai_link->kcontrol_prefix hack from this version, removed one unused spuriously added variable and added pointer to optional name prefix map into struct snd_soc_card that is used to associate prefix to codec. So if there's a machine with two bar-codecs, following code associated prefix 'b' to kcontrols of second codec. static struct snd_soc_prefix_map foo_codec_prefix[] = { { .codec_name = "bar-codec.2", .kcontrol_prefix = "b", }, }; static struct snd_soc_card foo_sound_card = { .name = "FOO, .dai_link = foo_dai, .num_links = ARRAY_SIZE(foo_dai), .prefix_map = foo_codec_prefix, .num_prefixes = ARRAY_SIZE(foo_codec_prefix), }; -- Jarkko ================== RFC =============== diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index c4a4456..44516de 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -314,8 +314,14 @@ 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_codec *codec, + const struct snd_soc_dapm_widget *widget, + const char *name_prefix); int snd_soc_dapm_new_control(struct snd_soc_codec *codec, const struct snd_soc_dapm_widget *widget); +int _snd_soc_dapm_new_controls(struct snd_soc_codec *codec, + const struct snd_soc_dapm_widget *widget, + int num, const char *name_prefix); int snd_soc_dapm_new_controls(struct snd_soc_codec *codec, const struct snd_soc_dapm_widget *widget, int num); @@ -323,6 +329,9 @@ int snd_soc_dapm_new_controls(struct snd_soc_codec *codec, /* dapm path setup */ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec); void snd_soc_dapm_free(struct snd_soc_codec *codec); +int _snd_soc_dapm_add_routes(struct snd_soc_codec *codec, + const struct snd_soc_dapm_route *route, int num, + const char *name_prefix); int snd_soc_dapm_add_routes(struct snd_soc_codec *codec, const struct snd_soc_dapm_route *route, int num); @@ -412,6 +421,7 @@ struct snd_soc_dapm_path { struct snd_soc_dapm_widget { enum snd_soc_dapm_type id; char *name; /* widget name */ + bool prefixed; /* set if widget name is prefixed */ char *sname; /* stream name */ struct snd_soc_codec *codec; struct list_head list; diff --git a/include/sound/soc.h b/include/sound/soc.h index d31e8b7..06c13ec 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -310,6 +310,9 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec); */ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, void *data, char *long_name); +int _snd_soc_add_controls(struct snd_soc_codec *codec, + const struct snd_kcontrol_new *controls, int num_controls, + const char *name_prefix); int snd_soc_add_controls(struct snd_soc_codec *codec, const struct snd_kcontrol_new *controls, int num_controls); int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, @@ -423,6 +426,7 @@ struct snd_soc_ops { /* SoC Audio Codec device */ struct snd_soc_codec { const char *name; + const char *kcontrol_prefix; int id; struct device *dev; struct snd_soc_codec_driver *driver; @@ -553,6 +557,11 @@ struct snd_soc_dai_link { struct snd_soc_ops *ops; }; +struct snd_soc_prefix_map { + const char *codec_name; + const char *kcontrol_prefix; +}; + /* SoC card */ struct snd_soc_card { const char *name; @@ -587,6 +596,10 @@ struct snd_soc_card { struct snd_soc_pcm_runtime *rtd; int num_rtd; + /* optional map of name prefixes that are associated per codec */ + struct snd_soc_prefix_map *prefix_map; + int num_prefixes; + struct work_struct deferred_resume_work; /* lists of probed devices belonging to this card */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 65352c7..5162bbe 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1266,6 +1266,23 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num) static void rtd_release(struct device *dev) {} +static void soc_set_name_prefix(struct snd_soc_card *card, + struct snd_soc_codec *codec) +{ + int i; + + if (card->prefix_map == NULL) + return; + + for (i = 0; i < card->num_prefixes; i++) { + struct snd_soc_prefix_map *map = &card->prefix_map[i]; + if (map->codec_name && !strcmp(codec->name, map->codec_name)) { + codec->kcontrol_prefix = map->kcontrol_prefix; + break; + } + } +} + static int soc_probe_dai_link(struct snd_soc_card *card, int num) { struct snd_soc_dai_link *dai_link = &card->dai_link[num]; @@ -1306,6 +1323,7 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) /* probe the CODEC */ if (!codec->probed) { + soc_set_name_prefix(card, codec); if (codec->driver->probe) { ret = codec->driver->probe(codec); if (ret < 0) { @@ -1881,34 +1899,68 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, EXPORT_SYMBOL_GPL(snd_soc_cnew); /** - * snd_soc_add_controls - add an array of controls to a codec. - * Convienience function to add a list of controls. Many codecs were - * duplicating this code. + * _snd_soc_add_controls - add an array of controls to a codec. + * This varian of snd_soc_add_controls allow to specify custom name prefix to + * controls. * * @codec: codec to add controls to * @controls: array of controls to add * @num_controls: number of elements in the array + * @name_prefix: prefix to kcontrol name or NULL * * Return 0 for success, else error. */ -int snd_soc_add_controls(struct snd_soc_codec *codec, - const struct snd_kcontrol_new *controls, int num_controls) +int _snd_soc_add_controls(struct snd_soc_codec *codec, + const struct snd_kcontrol_new *controls, int num_controls, + const char *name_prefix) { 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 (name_prefix) { + snprintf(prefixed_name, sizeof(prefixed_name), "%s.%s", + 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\n", - codec->name, control->name); + codec->name, name); return err; } } return 0; } +EXPORT_SYMBOL_GPL(_snd_soc_add_controls); + +/** + * snd_soc_add_controls - add an array of controls to a codec. + * Convienience function to add a list of controls. Many codecs were + * duplicating this code. + * + * @codec: codec to add controls to + * @controls: array of controls to add + * @num_controls: number of elements in the array + * + * Return 0 for success, else error. + */ +int snd_soc_add_controls(struct snd_soc_codec *codec, + const struct snd_kcontrol_new *controls, int num_controls) +{ + const char *prefix = NULL; + + /* Only codec controls are prefixed */ + if (!codec->probed) + prefix = codec->kcontrol_prefix; + + return _snd_soc_add_controls(codec, controls, num_controls, prefix); +} EXPORT_SYMBOL_GPL(snd_soc_add_controls); /** diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 035cab8..9a419b2 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -327,6 +327,7 @@ static int dapm_new_mixer(struct snd_soc_codec *codec, int i, ret = 0; size_t name_len; struct snd_soc_dapm_path *path; + char prefix[10]; /* add kcontrol */ for (i = 0; i < w->num_kcontrols; i++) { @@ -347,6 +348,13 @@ static int dapm_new_mixer(struct snd_soc_codec *codec, name_len = strlen(w->kcontrols[i].name) + 1; if (w->id != snd_soc_dapm_mixer_named_ctl) name_len += 1 + strlen(w->name); + if (codec->kcontrol_prefix && !w->prefixed) { + name_len += 1 + strlen(codec->kcontrol_prefix); + snprintf(prefix, sizeof(prefix), "%s.", + codec->kcontrol_prefix); + } else { + prefix[0] = '\0'; + } path->long_name = kmalloc(name_len, GFP_KERNEL); @@ -355,12 +363,12 @@ static int dapm_new_mixer(struct snd_soc_codec *codec, switch (w->id) { default: - snprintf(path->long_name, name_len, "%s %s", - w->name, w->kcontrols[i].name); + snprintf(path->long_name, name_len, "%s%s %s", + prefix, w->name, w->kcontrols[i].name); break; case snd_soc_dapm_mixer_named_ctl: - snprintf(path->long_name, name_len, "%s", - w->kcontrols[i].name); + snprintf(path->long_name, name_len, "%s%s", + prefix, w->kcontrols[i].name); break; } @@ -388,6 +396,7 @@ static int dapm_new_mux(struct snd_soc_codec *codec, { struct snd_soc_dapm_path *path = NULL; struct snd_kcontrol *kcontrol; + char prefixed_name[44], *name; int ret = 0; if (!w->num_kcontrols) { @@ -395,7 +404,14 @@ static int dapm_new_mux(struct snd_soc_codec *codec, return -EINVAL; } - kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name); + if (codec->kcontrol_prefix && !w->prefixed) { + snprintf(prefixed_name, sizeof(prefixed_name), "%s.%s", + codec->kcontrol_prefix, w->name); + name = prefixed_name; + } else { + name = w->name; + } + kcontrol = snd_soc_cnew(&w->kcontrols[0], w, name); ret = snd_ctl_add(codec->card->snd_card, kcontrol); if (ret < 0) goto err; @@ -406,7 +422,7 @@ static int dapm_new_mux(struct snd_soc_codec *codec, return ret; err: - printk(KERN_ERR "asoc: failed to add kcontrol %s\n", w->name); + printk(KERN_ERR "asoc: failed to add kcontrol %s\n", name); return ret; } @@ -1253,6 +1269,7 @@ static void dapm_free_widgets(struct snd_soc_codec *codec) list_for_each_entry_safe(w, next_w, &codec->dapm_widgets, list) { list_del(&w->list); + kfree(w->name); kfree(w); } @@ -1299,15 +1316,30 @@ int snd_soc_dapm_sync(struct snd_soc_codec *codec) EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, - const struct snd_soc_dapm_route *route) + const struct snd_soc_dapm_route *route, + const char *name_prefix) { struct snd_soc_dapm_path *path; struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; - 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 (name_prefix) { + snprintf(prefixed_sink, sizeof(prefixed_sink), "%s.%s", + name_prefix, route->sink); + sink = prefixed_sink; + snprintf(prefixed_source, sizeof(prefixed_source), "%s.%s", + name_prefix, route->source); + source = prefixed_source; + } else { + sink = route->sink; + source = route->source; + } + /* find src and dest widgets */ list_for_each_entry(w, &codec->dapm_widgets, list) { @@ -1412,25 +1444,28 @@ err: } /** - * snd_soc_dapm_add_routes - Add routes between DAPM widgets + * _snd_soc_dapm_add_routes - Add routes between DAPM widgets * @codec: codec * @route: audio routes * @num: number of routes + * @name_prefix: prefix to route name or NULL * * Connects 2 dapm widgets together via a named audio path. The sink is * the widget receiving the audio signal, whilst the source is the sender - * of the audio signal. + * of the audio signal. This variant of snd_soc_dapm_add_routes allow to + * specify custom prefix to source and sink names of route. * * Returns 0 for success else error. On error all resources can be freed * with a call to snd_soc_card_free(). */ -int snd_soc_dapm_add_routes(struct snd_soc_codec *codec, - const struct snd_soc_dapm_route *route, int num) +int _snd_soc_dapm_add_routes(struct snd_soc_codec *codec, + const struct snd_soc_dapm_route *route, int num, + const char *name_prefix) { int i, ret; for (i = 0; i < num; i++) { - ret = snd_soc_dapm_add_route(codec, route); + ret = snd_soc_dapm_add_route(codec, route, name_prefix); if (ret < 0) { printk(KERN_ERR "Failed to add route %s->%s\n", route->source, @@ -1442,6 +1477,26 @@ int snd_soc_dapm_add_routes(struct snd_soc_codec *codec, return 0; } +EXPORT_SYMBOL_GPL(_snd_soc_dapm_add_routes); + +/** + * snd_soc_dapm_add_routes - Add routes between DAPM widgets + * @codec: codec + * @route: audio routes + * @num: number of routes + * + * Connects 2 dapm widgets together via a named audio path. The sink is + * the widget receiving the audio signal, whilst the source is the sender + * of the audio signal. + * + * Returns 0 for success else error. On error all resources can be freed + * with a call to snd_soc_card_free(). + */ +int snd_soc_dapm_add_routes(struct snd_soc_codec *codec, + const struct snd_soc_dapm_route *route, int num) +{ + return _snd_soc_dapm_add_routes(codec, route, num, NULL); +} EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes); /** @@ -1924,22 +1979,40 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch); /** - * snd_soc_dapm_new_control - create new dapm control + * _snd_soc_dapm_new_control - create new dapm control * @codec: audio codec * @widget: widget template * - * Creates a new dapm control based upon the template. + * Creates a new dapm control based upon the template. This variant of + * snd_soc_dapm_new_control allow to specify custom prefix to widget name. * * Returns 0 for success else error. */ -int snd_soc_dapm_new_control(struct snd_soc_codec *codec, - const struct snd_soc_dapm_widget *widget) +int _snd_soc_dapm_new_control(struct snd_soc_codec *codec, + const struct snd_soc_dapm_widget *widget, const char *name_prefix) { 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 (name_prefix) + name_len += 1 + strlen(name_prefix); + w->name = kmalloc(name_len, GFP_KERNEL); + if (w->name == NULL) { + kfree(w); + return -ENOMEM; + } + if (name_prefix) { + snprintf(w->name, name_len, "%s.%s", + name_prefix, widget->name); + w->prefixed = 1; + } else { + snprintf(w->name, name_len, "%s", widget->name); + } + w->codec = codec; INIT_LIST_HEAD(&w->sources); INIT_LIST_HEAD(&w->sinks); @@ -1948,28 +2021,47 @@ int snd_soc_dapm_new_control(struct snd_soc_codec *codec, /* machine layer set ups unconnected pins and insertions */ w->connected = 1; + return 0; } +EXPORT_SYMBOL_GPL(_snd_soc_dapm_new_control); + +/** + * snd_soc_dapm_new_control - create new dapm control + * @codec: audio codec + * @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_codec *codec, + const struct snd_soc_dapm_widget *widget) +{ + return _snd_soc_dapm_new_control(codec, widget, NULL); +} EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); /** - * snd_soc_dapm_new_controls - create new dapm controls + * _snd_soc_dapm_new_controls - create new dapm controls * @codec: audio codec * @widget: widget array * @num: number of widgets + * @name_prefix: prefix to widget name or NULL * - * Creates new DAPM controls based upon the templates. + * Creates new DAPM controls based upon the templates. This variant of + * snd_soc_dapm_new_controls allow to specify custom prefix to widget names. * * Returns 0 for success else error. */ -int snd_soc_dapm_new_controls(struct snd_soc_codec *codec, +int _snd_soc_dapm_new_controls(struct snd_soc_codec *codec, const struct snd_soc_dapm_widget *widget, - int num) + int num, const char *name_prefix) { int i, ret; for (i = 0; i < num; i++) { - ret = snd_soc_dapm_new_control(codec, widget); + ret = _snd_soc_dapm_new_control(codec, widget, name_prefix); if (ret < 0) { printk(KERN_ERR "ASoC: Failed to create DAPM control %s: %d\n", @@ -1980,8 +2072,25 @@ int snd_soc_dapm_new_controls(struct snd_soc_codec *codec, } return 0; } -EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); +EXPORT_SYMBOL_GPL(_snd_soc_dapm_new_controls); +/** + * snd_soc_dapm_new_controls - create new dapm controls + * @codec: audio codec + * @widget: widget array + * @num: number of widgets + * + * Creates new DAPM controls based upon the templates. + * + * Returns 0 for success else error. + */ +int snd_soc_dapm_new_controls(struct snd_soc_codec *codec, + const struct snd_soc_dapm_widget *widget, + int num) +{ + return _snd_soc_dapm_new_controls(codec, widget, num, NULL); +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls); /** * snd_soc_dapm_stream_event - send a stream event to the dapm core _______________________________________________ Alsa-devel mailing list Alsa-devel@xxxxxxxxxxxxxxxx http://mailman.alsa-project.org/mailman/listinfo/alsa-devel