[alsa-devel] [PATCH v2 0/3] topology: Add external API for building topology data
Currently we can build topology binary data files from topology text files. However it is sometimes necessary for DSP FW vendors to build topology binary data within a toolset and create topology binary data directly from within vendor tools.
This series adds an API to the alsa-lib topology core so that vendor tools can create topology data directly.
Changes since V1:-
o Split out refactoring of OBJECT_TYPE to SND_TPLG_TYPE_ o Removed inclusing of type_compat.h from asoc.h
Liam Girdwood (1): topology: rename OBJECT_TYPE_ to SND_TPLG_TYPE_
Mengdong Lin (2): topology: Add C templates structure for building topology from C programs topology: A API calls to directly build topology data from templates
include/topology.h | 202 ++++++++++++++++++++++++++++ src/topology/builder.c | 38 +++--- src/topology/ctl.c | 329 +++++++++++++++++++++++++++++++++++++++++++--- src/topology/dapm.c | 223 ++++++++++++++++++++++++++----- src/topology/data.c | 10 +- src/topology/elem.c | 43 ++++-- src/topology/parser.c | 63 ++++++++- src/topology/pcm.c | 34 ++--- src/topology/text.c | 2 +- src/topology/tplg_local.h | 33 ++--- 10 files changed, 847 insertions(+), 130 deletions(-)
rename OBJECT_TYPE_ to SND_TPLG_TYPE_ in preparation for exporting via a new public API.
Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- src/topology/builder.c | 38 +++++++++++++++++++------------------- src/topology/ctl.c | 38 +++++++++++++++++++------------------- src/topology/dapm.c | 43 +++++++++++++++++++++++-------------------- src/topology/data.c | 10 +++++----- src/topology/elem.c | 26 +++++++++++++------------- src/topology/parser.c | 6 +++--- src/topology/pcm.c | 34 +++++++++++++++++----------------- src/topology/text.c | 2 +- src/topology/tplg_local.h | 36 ++++++++++++++++++------------------ 9 files changed, 118 insertions(+), 115 deletions(-)
diff --git a/src/topology/builder.c b/src/topology/builder.c index a944866..3bccd44 100644 --- a/src/topology/builder.c +++ b/src/topology/builder.c @@ -141,7 +141,7 @@ static int write_elem_block(snd_tplg_t *tplg, if (elem->compound_elem) continue;
- if (elem->type != OBJECT_TYPE_DAPM_GRAPH) + if (elem->type != SND_TPLG_TYPE_DAPM_GRAPH) verbose(tplg, " %s '%s': write %d bytes\n", obj_name, elem->id, elem->size); else @@ -202,31 +202,31 @@ static int write_block(snd_tplg_t *tplg, struct list_head *base,
/* write each elem for this block */ switch (type) { - case OBJECT_TYPE_MIXER: + case SND_TPLG_TYPE_MIXER: return write_elem_block(tplg, base, size, SND_SOC_TPLG_TYPE_MIXER, "mixer"); - case OBJECT_TYPE_BYTES: + case SND_TPLG_TYPE_BYTES: return write_elem_block(tplg, base, size, SND_SOC_TPLG_TYPE_BYTES, "bytes"); - case OBJECT_TYPE_ENUM: + case SND_TPLG_TYPE_ENUM: return write_elem_block(tplg, base, size, SND_SOC_TPLG_TYPE_ENUM, "enum"); - case OBJECT_TYPE_DAPM_GRAPH: + case SND_TPLG_TYPE_DAPM_GRAPH: return write_elem_block(tplg, base, size, SND_SOC_TPLG_TYPE_DAPM_GRAPH, "route"); - case OBJECT_TYPE_DAPM_WIDGET: + case SND_TPLG_TYPE_DAPM_WIDGET: return write_elem_block(tplg, base, size, SND_SOC_TPLG_TYPE_DAPM_WIDGET, "widget"); - case OBJECT_TYPE_PCM: + case SND_TPLG_TYPE_PCM: return write_elem_block(tplg, base, size, SND_SOC_TPLG_TYPE_PCM, "pcm"); - case OBJECT_TYPE_BE: + case SND_TPLG_TYPE_BE: return write_elem_block(tplg, base, size, SND_SOC_TPLG_TYPE_DAI_LINK, "be"); - case OBJECT_TYPE_CC: + case SND_TPLG_TYPE_CC: return write_elem_block(tplg, base, size, SND_SOC_TPLG_TYPE_DAI_LINK, "cc"); - case OBJECT_TYPE_DATA: + case SND_TPLG_TYPE_DATA: return write_elem_block(tplg, base, size, SND_SOC_TPLG_TYPE_PDATA, "data"); default: @@ -280,7 +280,7 @@ int tplg_write_data(snd_tplg_t *tplg)
/* write mixer elems. */ ret = write_block(tplg, &tplg->mixer_list, - OBJECT_TYPE_MIXER); + SND_TPLG_TYPE_MIXER); if (ret < 0) { SNDERR("failed to write control elems %d\n", ret); return ret; @@ -288,7 +288,7 @@ int tplg_write_data(snd_tplg_t *tplg)
/* write enum control elems. */ ret = write_block(tplg, &tplg->enum_list, - OBJECT_TYPE_ENUM); + SND_TPLG_TYPE_ENUM); if (ret < 0) { SNDERR("failed to write control elems %d\n", ret); return ret; @@ -296,7 +296,7 @@ int tplg_write_data(snd_tplg_t *tplg)
/* write bytes extended control elems. */ ret = write_block(tplg, &tplg->bytes_ext_list, - OBJECT_TYPE_BYTES); + SND_TPLG_TYPE_BYTES); if (ret < 0) { SNDERR("failed to write control elems %d\n", ret); return ret; @@ -304,7 +304,7 @@ int tplg_write_data(snd_tplg_t *tplg)
/* write widget elems */ ret = write_block(tplg, &tplg->widget_list, - OBJECT_TYPE_DAPM_WIDGET); + SND_TPLG_TYPE_DAPM_WIDGET); if (ret < 0) { SNDERR("failed to write widget elems %d\n", ret); return ret; @@ -312,7 +312,7 @@ int tplg_write_data(snd_tplg_t *tplg)
/* write pcm elems */ ret = write_block(tplg, &tplg->pcm_list, - OBJECT_TYPE_PCM); + SND_TPLG_TYPE_PCM); if (ret < 0) { SNDERR("failed to write pcm elems %d\n", ret); return ret; @@ -320,7 +320,7 @@ int tplg_write_data(snd_tplg_t *tplg)
/* write be elems */ ret = write_block(tplg, &tplg->be_list, - OBJECT_TYPE_BE); + SND_TPLG_TYPE_BE); if (ret < 0) { SNDERR("failed to write be elems %d\n", ret); return ret; @@ -328,7 +328,7 @@ int tplg_write_data(snd_tplg_t *tplg)
/* write cc elems */ ret = write_block(tplg, &tplg->cc_list, - OBJECT_TYPE_CC); + SND_TPLG_TYPE_CC); if (ret < 0) { SNDERR("failed to write cc elems %d\n", ret); return ret; @@ -336,7 +336,7 @@ int tplg_write_data(snd_tplg_t *tplg)
/* write route elems */ ret = write_block(tplg, &tplg->route_list, - OBJECT_TYPE_DAPM_GRAPH); + SND_TPLG_TYPE_DAPM_GRAPH); if (ret < 0) { SNDERR("failed to write graph elems %d\n", ret); return ret; @@ -344,7 +344,7 @@ int tplg_write_data(snd_tplg_t *tplg)
/* write private data */ ret = write_block(tplg, &tplg->pdata_list, - OBJECT_TYPE_DATA); + SND_TPLG_TYPE_DATA); if (ret < 0) { SNDERR("failed to write private data %d\n", ret); return ret; diff --git a/src/topology/ctl.c b/src/topology/ctl.c index 930b508..35f684b 100644 --- a/src/topology/ctl.c +++ b/src/topology/ctl.c @@ -49,15 +49,15 @@ static int tplg_build_mixer_control(snd_tplg_t *tplg, if (ref->id == NULL || ref->elem) continue;
- if (ref->type == OBJECT_TYPE_TLV) { + if (ref->type == SND_TPLG_TYPE_TLV) { ref->elem = tplg_elem_lookup(&tplg->tlv_list, - ref->id, OBJECT_TYPE_TLV); + ref->id, SND_TPLG_TYPE_TLV); if (ref->elem) err = copy_tlv(elem, ref->elem);
- } else if (ref->type == OBJECT_TYPE_DATA) { + } else if (ref->type == SND_TPLG_TYPE_DATA) { ref->elem = tplg_elem_lookup(&tplg->pdata_list, - ref->id, OBJECT_TYPE_DATA); + ref->id, SND_TPLG_TYPE_DATA); err = tplg_copy_data(elem, ref->elem); }
@@ -97,15 +97,15 @@ static int tplg_build_enum_control(snd_tplg_t *tplg, if (ref->id == NULL || ref->elem) continue;
- if (ref->type == OBJECT_TYPE_TEXT) { + if (ref->type == SND_TPLG_TYPE_TEXT) { ref->elem = tplg_elem_lookup(&tplg->text_list, - ref->id, OBJECT_TYPE_TEXT); + ref->id, SND_TPLG_TYPE_TEXT); if (ref->elem) copy_enum_texts(elem, ref->elem);
- } else if (ref->type == OBJECT_TYPE_DATA) { + } else if (ref->type == SND_TPLG_TYPE_DATA) { ref->elem = tplg_elem_lookup(&tplg->pdata_list, - ref->id, OBJECT_TYPE_DATA); + ref->id, SND_TPLG_TYPE_DATA); err = tplg_copy_data(elem, ref->elem); } if (!ref->elem) { @@ -135,7 +135,7 @@ static int tplg_build_bytes_control(snd_tplg_t *tplg, struct tplg_elem *elem)
/* bytes control only reference one private data section */ ref->elem = tplg_elem_lookup(&tplg->pdata_list, - ref->id, OBJECT_TYPE_DATA); + ref->id, SND_TPLG_TYPE_DATA); if (!ref->elem) { SNDERR("error: cannot find data '%s'" " referenced by control '%s'\n", @@ -260,7 +260,7 @@ int tplg_parse_tlv(snd_tplg_t *tplg, snd_config_t *cfg, int err = 0; struct tplg_elem *elem;
- elem = tplg_elem_new_common(tplg, cfg, NULL, OBJECT_TYPE_TLV); + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_TLV); if (!elem) return -ENOMEM;
@@ -294,7 +294,7 @@ int tplg_parse_control_bytes(snd_tplg_t *tplg, const char *id, *val = NULL; int err;
- elem = tplg_elem_new_common(tplg, cfg, NULL, OBJECT_TYPE_BYTES); + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_BYTES); if (!elem) return -ENOMEM;
@@ -365,7 +365,7 @@ int tplg_parse_control_bytes(snd_tplg_t *tplg, if (snd_config_get_string(n, &val) < 0) return -EINVAL;
- tplg_ref_add(elem, OBJECT_TYPE_DATA, val); + tplg_ref_add(elem, SND_TPLG_TYPE_DATA, val); tplg_dbg("\t%s: %s\n", id, val); continue; } @@ -374,7 +374,7 @@ int tplg_parse_control_bytes(snd_tplg_t *tplg, if (snd_config_get_string(n, &val) < 0) return -EINVAL;
- err = tplg_ref_add(elem, OBJECT_TYPE_TLV, val); + err = tplg_ref_add(elem, SND_TPLG_TYPE_TLV, val); if (err < 0) return err;
@@ -399,7 +399,7 @@ int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg, const char *id, *val = NULL; int err, j;
- elem = tplg_elem_new_common(tplg, cfg, NULL, OBJECT_TYPE_ENUM); + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_ENUM); if (!elem) return -ENOMEM;
@@ -440,7 +440,7 @@ int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg, if (snd_config_get_string(n, &val) < 0) return -EINVAL;
- tplg_ref_add(elem, OBJECT_TYPE_TEXT, val); + tplg_ref_add(elem, SND_TPLG_TYPE_TEXT, val); tplg_dbg("\t%s: %s\n", id, val); continue; } @@ -473,7 +473,7 @@ int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg, if (snd_config_get_string(n, &val) < 0) return -EINVAL;
- tplg_ref_add(elem, OBJECT_TYPE_DATA, val); + tplg_ref_add(elem, SND_TPLG_TYPE_DATA, val); tplg_dbg("\t%s: %s\n", id, val); continue; } @@ -496,7 +496,7 @@ int tplg_parse_control_mixer(snd_tplg_t *tplg, const char *id, *val = NULL; int err, j;
- elem = tplg_elem_new_common(tplg, cfg, NULL, OBJECT_TYPE_MIXER); + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_MIXER); if (!elem) return -ENOMEM;
@@ -584,7 +584,7 @@ int tplg_parse_control_mixer(snd_tplg_t *tplg, if (snd_config_get_string(n, &val) < 0) return -EINVAL;
- err = tplg_ref_add(elem, OBJECT_TYPE_TLV, val); + err = tplg_ref_add(elem, SND_TPLG_TYPE_TLV, val); if (err < 0) return err;
@@ -598,7 +598,7 @@ int tplg_parse_control_mixer(snd_tplg_t *tplg, if (snd_config_get_string(n, &val) < 0) return -EINVAL;
- tplg_ref_add(elem, OBJECT_TYPE_DATA, val); + tplg_ref_add(elem, SND_TPLG_TYPE_DATA, val); tplg_dbg("\t%s: %s\n", id, val); continue; } diff --git a/src/topology/dapm.c b/src/topology/dapm.c index a0a8b86..3458aa7 100644 --- a/src/topology/dapm.c +++ b/src/topology/dapm.c @@ -74,7 +74,7 @@ static int tplg_parse_dapm_mixers(snd_config_t *cfg, struct tplg_elem *elem) if (snd_config_get_string(n, &value) < 0) continue;
- tplg_ref_add(elem, OBJECT_TYPE_MIXER, value); + tplg_ref_add(elem, SND_TPLG_TYPE_MIXER, value); tplg_dbg("\t\t %s\n", value); }
@@ -96,7 +96,7 @@ static int tplg_parse_dapm_enums(snd_config_t *cfg, struct tplg_elem *elem) if (snd_config_get_string(n, &value) < 0) continue;
- tplg_ref_add(elem, OBJECT_TYPE_ENUM, value); + tplg_ref_add(elem, SND_TPLG_TYPE_ENUM, value); tplg_dbg("\t\t %s\n", value); }
@@ -146,23 +146,26 @@ static int tplg_build_widget(snd_tplg_t *tplg, continue;
switch (ref->type) { - case OBJECT_TYPE_MIXER: - ref->elem = tplg_elem_lookup(&tplg->mixer_list, - ref->id, OBJECT_TYPE_MIXER); + case SND_TPLG_TYPE_MIXER: + if (!ref->elem) + ref->elem = tplg_elem_lookup(&tplg->mixer_list, + ref->id, SND_TPLG_TYPE_MIXER); if (ref->elem) err = copy_dapm_control(elem, ref->elem); break;
- case OBJECT_TYPE_ENUM: - ref->elem = tplg_elem_lookup(&tplg->enum_list, - ref->id, OBJECT_TYPE_ENUM); + case SND_TPLG_TYPE_ENUM: + if (!ref->elem) + ref->elem = tplg_elem_lookup(&tplg->enum_list, + ref->id, SND_TPLG_TYPE_ENUM); if (ref->elem) err = copy_dapm_control(elem, ref->elem); break;
- case OBJECT_TYPE_DATA: - ref->elem = tplg_elem_lookup(&tplg->pdata_list, - ref->id, OBJECT_TYPE_DATA); + case SND_TPLG_TYPE_DATA: + if (!ref->elem) + ref->elem = tplg_elem_lookup(&tplg->pdata_list, + ref->id, SND_TPLG_TYPE_DATA); if (ref->elem) err = tplg_copy_data(elem, ref->elem); break; @@ -195,7 +198,7 @@ int tplg_build_widgets(snd_tplg_t *tplg) list_for_each(pos, base) {
elem = list_entry(pos, struct tplg_elem, list); - if (!elem->widget || elem->type != OBJECT_TYPE_DAPM_WIDGET) { + if (!elem->widget || elem->type != SND_TPLG_TYPE_DAPM_WIDGET) { SNDERR("error: invalid widget '%s'\n", elem->id); return -EINVAL; @@ -223,7 +226,7 @@ int tplg_build_routes(snd_tplg_t *tplg) list_for_each(pos, base) { elem = list_entry(pos, struct tplg_elem, list);
- if (!elem->route || elem->type != OBJECT_TYPE_DAPM_GRAPH) { + if (!elem->route || elem->type != SND_TPLG_TYPE_DAPM_GRAPH) { SNDERR("error: invalid route '%s'\n", elem->id); return -EINVAL; @@ -240,7 +243,7 @@ int tplg_build_routes(snd_tplg_t *tplg)
} if (!tplg_elem_lookup(&tplg->widget_list, route->sink, - OBJECT_TYPE_DAPM_WIDGET)) { + SND_TPLG_TYPE_DAPM_WIDGET)) { SNDERR("warning: undefined sink widget/stream '%s'\n", route->sink); } @@ -248,9 +251,9 @@ int tplg_build_routes(snd_tplg_t *tplg) /* validate control name */ if (strlen(route->control)) { if (!tplg_elem_lookup(&tplg->mixer_list, - route->control, OBJECT_TYPE_MIXER) && + route->control, SND_TPLG_TYPE_MIXER) && !tplg_elem_lookup(&tplg->enum_list, - route->control, OBJECT_TYPE_ENUM)) { + route->control, SND_TPLG_TYPE_ENUM)) { SNDERR("warning: Undefined mixer/enum control '%s'\n", route->control); } @@ -263,7 +266,7 @@ int tplg_build_routes(snd_tplg_t *tplg)
} if (!tplg_elem_lookup(&tplg->widget_list, route->source, - OBJECT_TYPE_DAPM_WIDGET)) { + SND_TPLG_TYPE_DAPM_WIDGET)) { SNDERR("warning: Undefined source widget/stream '%s'\n", route->source); } @@ -347,7 +350,7 @@ static int tplg_parse_routes(snd_tplg_t *tplg, snd_config_t *cfg)
list_add_tail(&elem->list, &tplg->route_list); strcpy(elem->id, "line"); - elem->type = OBJECT_TYPE_DAPM_GRAPH; + elem->type = SND_TPLG_TYPE_DAPM_GRAPH; elem->size = sizeof(*line);
line = calloc(1, sizeof(*line)); @@ -415,7 +418,7 @@ int tplg_parse_dapm_widget(snd_tplg_t *tplg, const char *id, *val = NULL; int widget_type, err;
- elem = tplg_elem_new_common(tplg, cfg, NULL, OBJECT_TYPE_DAPM_WIDGET); + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_DAPM_WIDGET); if (!elem) return -ENOMEM;
@@ -547,7 +550,7 @@ int tplg_parse_dapm_widget(snd_tplg_t *tplg, if (snd_config_get_string(n, &val) < 0) return -EINVAL;
- tplg_ref_add(elem, OBJECT_TYPE_DATA, val); + tplg_ref_add(elem, SND_TPLG_TYPE_DATA, val); tplg_dbg("\t%s: %s\n", id, val); continue; } diff --git a/src/topology/data.c b/src/topology/data.c index 0901851..4ee1f8a 100644 --- a/src/topology/data.c +++ b/src/topology/data.c @@ -268,7 +268,7 @@ int tplg_parse_data(snd_tplg_t *tplg, snd_config_t *cfg, int err = 0; struct tplg_elem *elem;
- elem = tplg_elem_new_common(tplg, cfg, NULL, OBJECT_TYPE_DATA); + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_DATA); if (!elem) return -ENOMEM;
@@ -350,7 +350,7 @@ int tplg_copy_data(struct tplg_elem *elem, struct tplg_elem *ref) priv_data_size = ref->data->size;
switch (elem->type) { - case OBJECT_TYPE_MIXER: + case SND_TPLG_TYPE_MIXER: elem->mixer_ctrl = realloc(elem->mixer_ctrl, elem->size + priv_data_size); if (!elem->mixer_ctrl) @@ -358,7 +358,7 @@ int tplg_copy_data(struct tplg_elem *elem, struct tplg_elem *ref) priv = &elem->mixer_ctrl->priv; break;
- case OBJECT_TYPE_ENUM: + case SND_TPLG_TYPE_ENUM: elem->enum_ctrl = realloc(elem->enum_ctrl, elem->size + priv_data_size); if (!elem->enum_ctrl) @@ -366,7 +366,7 @@ int tplg_copy_data(struct tplg_elem *elem, struct tplg_elem *ref) priv = &elem->enum_ctrl->priv; break;
- case OBJECT_TYPE_BYTES: + case SND_TPLG_TYPE_BYTES: elem->bytes_ext = realloc(elem->bytes_ext, elem->size + priv_data_size); if (!elem->bytes_ext) @@ -375,7 +375,7 @@ int tplg_copy_data(struct tplg_elem *elem, struct tplg_elem *ref) break;
- case OBJECT_TYPE_DAPM_WIDGET: + case SND_TPLG_TYPE_DAPM_WIDGET: elem->widget = realloc(elem->widget, elem->size + priv_data_size); if (!elem->widget) diff --git a/src/topology/elem.c b/src/topology/elem.c index 7fee653..daabe75 100644 --- a/src/topology/elem.c +++ b/src/topology/elem.c @@ -103,7 +103,7 @@ struct tplg_elem *tplg_elem_lookup(struct list_head *base, const char* id,
/* create a new common element and object */ struct tplg_elem* tplg_elem_new_common(snd_tplg_t *tplg, - snd_config_t *cfg, const char *name, enum object_type type) + snd_config_t *cfg, const char *name, enum snd_tplg_type type) { struct tplg_elem *elem; const char *id; @@ -126,49 +126,49 @@ struct tplg_elem* tplg_elem_new_common(snd_tplg_t *tplg, elem_copy_text(elem->id, name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
switch (type) { - case OBJECT_TYPE_DATA: + case SND_TPLG_TYPE_DATA: list_add_tail(&elem->list, &tplg->pdata_list); break; - case OBJECT_TYPE_TEXT: + case SND_TPLG_TYPE_TEXT: list_add_tail(&elem->list, &tplg->text_list); break; - case OBJECT_TYPE_TLV: + case SND_TPLG_TYPE_TLV: list_add_tail(&elem->list, &tplg->tlv_list); elem->size = sizeof(struct snd_soc_tplg_ctl_tlv); break; - case OBJECT_TYPE_BYTES: + case SND_TPLG_TYPE_BYTES: list_add_tail(&elem->list, &tplg->bytes_ext_list); obj_size = sizeof(struct snd_soc_tplg_bytes_control); break; - case OBJECT_TYPE_ENUM: + case SND_TPLG_TYPE_ENUM: list_add_tail(&elem->list, &tplg->enum_list); obj_size = sizeof(struct snd_soc_tplg_enum_control); break; - case OBJECT_TYPE_MIXER: + case SND_TPLG_TYPE_MIXER: list_add_tail(&elem->list, &tplg->mixer_list); obj_size = sizeof(struct snd_soc_tplg_mixer_control); break; - case OBJECT_TYPE_DAPM_WIDGET: + case SND_TPLG_TYPE_DAPM_WIDGET: list_add_tail(&elem->list, &tplg->widget_list); obj_size = sizeof(struct snd_soc_tplg_dapm_widget); break; - case OBJECT_TYPE_STREAM_CONFIG: + case SND_TPLG_TYPE_STREAM_CONFIG: list_add_tail(&elem->list, &tplg->pcm_config_list); obj_size = sizeof(struct snd_soc_tplg_stream_config); break; - case OBJECT_TYPE_STREAM_CAPS: + case SND_TPLG_TYPE_STREAM_CAPS: list_add_tail(&elem->list, &tplg->pcm_caps_list); obj_size = sizeof(struct snd_soc_tplg_stream_caps); break; - case OBJECT_TYPE_PCM: + case SND_TPLG_TYPE_PCM: list_add_tail(&elem->list, &tplg->pcm_list); obj_size = sizeof(struct snd_soc_tplg_pcm_dai); break; - case OBJECT_TYPE_BE: + case SND_TPLG_TYPE_BE: list_add_tail(&elem->list, &tplg->be_list); obj_size = sizeof(struct snd_soc_tplg_pcm_dai); break; - case OBJECT_TYPE_CC: + case SND_TPLG_TYPE_CC: list_add_tail(&elem->list, &tplg->cc_list); obj_size = sizeof(struct snd_soc_tplg_pcm_dai); break; diff --git a/src/topology/parser.c b/src/topology/parser.c index ed25bb8..3e3e2b3 100644 --- a/src/topology/parser.c +++ b/src/topology/parser.c @@ -241,15 +241,15 @@ static int tplg_build_integ(snd_tplg_t *tplg) if (err < 0) return err;
- err = tplg_build_pcm_dai(tplg, OBJECT_TYPE_PCM); + err = tplg_build_pcm_dai(tplg, SND_TPLG_TYPE_PCM); if (err < 0) return err;
- err = tplg_build_pcm_dai(tplg, OBJECT_TYPE_BE); + err = tplg_build_pcm_dai(tplg, SND_TPLG_TYPE_BE); if (err < 0) return err;
- err = tplg_build_pcm_dai(tplg, OBJECT_TYPE_CC); + err = tplg_build_pcm_dai(tplg, SND_TPLG_TYPE_CC); if (err < 0) return err;
diff --git a/src/topology/pcm.c b/src/topology/pcm.c index deae47b..6e42aa1 100644 --- a/src/topology/pcm.c +++ b/src/topology/pcm.c @@ -28,7 +28,7 @@ struct tplg_elem *lookup_pcm_dai_stream(struct list_head *base, const char* id) list_for_each(pos, base) {
elem = list_entry(pos, struct tplg_elem, list); - if (elem->type != OBJECT_TYPE_PCM) + if (elem->type != SND_TPLG_TYPE_PCM) return NULL;
pcm_dai = elem->pcm; @@ -74,13 +74,13 @@ static int tplg_build_pcm_cfg_caps(snd_tplg_t *tplg, struct tplg_elem *elem) unsigned int i, j;
switch (elem->type) { - case OBJECT_TYPE_PCM: + case SND_TPLG_TYPE_PCM: pcm_dai = elem->pcm; break; - case OBJECT_TYPE_BE: + case SND_TPLG_TYPE_BE: pcm_dai = elem->be; break; - case OBJECT_TYPE_CC: + case SND_TPLG_TYPE_CC: pcm_dai = elem->cc; break; default: @@ -91,7 +91,7 @@ static int tplg_build_pcm_cfg_caps(snd_tplg_t *tplg, struct tplg_elem *elem) capconf = &pcm_dai->capconf[i];
ref_elem = tplg_elem_lookup(&tplg->pcm_caps_list, - capconf->caps.name, OBJECT_TYPE_STREAM_CAPS); + capconf->caps.name, SND_TPLG_TYPE_STREAM_CAPS);
if (ref_elem != NULL) copy_pcm_caps(elem->id, &capconf->caps, ref_elem); @@ -99,7 +99,7 @@ static int tplg_build_pcm_cfg_caps(snd_tplg_t *tplg, struct tplg_elem *elem) for (j = 0; j < capconf->num_configs; j++) { ref_elem = tplg_elem_lookup(&tplg->pcm_config_list, capconf->configs[j].name, - OBJECT_TYPE_STREAM_CONFIG); + SND_TPLG_TYPE_STREAM_CONFIG);
if (ref_elem != NULL) copy_pcm_config(elem->id, @@ -118,13 +118,13 @@ int tplg_build_pcm_dai(snd_tplg_t *tplg, unsigned int type) int err = 0;
switch (type) { - case OBJECT_TYPE_PCM: + case SND_TPLG_TYPE_PCM: base = &tplg->pcm_list; break; - case OBJECT_TYPE_BE: + case SND_TPLG_TYPE_BE: base = &tplg->be_list; break; - case OBJECT_TYPE_CC: + case SND_TPLG_TYPE_CC: base = &tplg->cc_list; break; default: @@ -228,7 +228,7 @@ int tplg_parse_pcm_config(snd_tplg_t *tplg, const char *id; int err;
- elem = tplg_elem_new_common(tplg, cfg, NULL, OBJECT_TYPE_STREAM_CONFIG); + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_STREAM_CONFIG); if (!elem) return -ENOMEM;
@@ -294,7 +294,7 @@ int tplg_parse_pcm_caps(snd_tplg_t *tplg, char *s; int err;
- elem = tplg_elem_new_common(tplg, cfg, NULL, OBJECT_TYPE_STREAM_CAPS); + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_STREAM_CAPS); if (!elem) return -ENOMEM;
@@ -396,11 +396,11 @@ int tplg_parse_pcm_cap_cfg(snd_tplg_t *tplg, snd_config_t *cfg, const char *id, *value; int err, stream;
- if (elem->type == OBJECT_TYPE_PCM) + if (elem->type == SND_TPLG_TYPE_PCM) pcm_dai = elem->pcm; - else if (elem->type == OBJECT_TYPE_BE) + else if (elem->type == SND_TPLG_TYPE_BE) pcm_dai = elem->be; - else if (elem->type == OBJECT_TYPE_CC) + else if (elem->type == SND_TPLG_TYPE_CC) pcm_dai = elem->cc; else return -EINVAL; @@ -461,7 +461,7 @@ int tplg_parse_pcm(snd_tplg_t *tplg, const char *id, *val = NULL; int err;
- elem = tplg_elem_new_common(tplg, cfg, NULL, OBJECT_TYPE_PCM); + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_PCM); if (!elem) return -ENOMEM;
@@ -524,7 +524,7 @@ int tplg_parse_be(snd_tplg_t *tplg, const char *id, *val = NULL; int err;
- elem = tplg_elem_new_common(tplg, cfg, NULL, OBJECT_TYPE_BE); + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_BE); if (!elem) return -ENOMEM;
@@ -587,7 +587,7 @@ int tplg_parse_cc(snd_tplg_t *tplg, const char *id, *val = NULL; int err;
- elem = tplg_elem_new_common(tplg, cfg, NULL, OBJECT_TYPE_CC); + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_CC); if (!elem) return -ENOMEM;
diff --git a/src/topology/text.c b/src/topology/text.c index 7128056..0c6594a 100644 --- a/src/topology/text.c +++ b/src/topology/text.c @@ -64,7 +64,7 @@ int tplg_parse_text(snd_tplg_t *tplg, snd_config_t *cfg, int err = 0; struct tplg_elem *elem;
- elem = tplg_elem_new_common(tplg, cfg, NULL, OBJECT_TYPE_TEXT); + elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_TEXT); if (!elem) return -ENOMEM;
diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h index ad38945..febc177 100644 --- a/src/topology/tplg_local.h +++ b/src/topology/tplg_local.h @@ -40,22 +40,22 @@ struct tplg_ref; struct tplg_elem;
-/* internal topology object type not used by kernel */ -enum object_type { - OBJECT_TYPE_TLV = 0, - OBJECT_TYPE_MIXER, - OBJECT_TYPE_ENUM, - OBJECT_TYPE_TEXT, - OBJECT_TYPE_DATA, - OBJECT_TYPE_BYTES, - OBJECT_TYPE_STREAM_CONFIG, - OBJECT_TYPE_STREAM_CAPS, - OBJECT_TYPE_PCM, - OBJECT_TYPE_DAPM_WIDGET, - OBJECT_TYPE_DAPM_GRAPH, - OBJECT_TYPE_BE, - OBJECT_TYPE_CC, - OBJECT_TYPE_MANIFEST, +/** Topology object types */ +enum snd_tplg_type { + SND_TPLG_TYPE_TLV = 0, /*!< TLV Data */ + SND_TPLG_TYPE_MIXER, /*!< Mixer control*/ + SND_TPLG_TYPE_ENUM, /*!< Enumerated control */ + SND_TPLG_TYPE_TEXT, /*!< Text data */ + SND_TPLG_TYPE_DATA, /*!< Private data */ + SND_TPLG_TYPE_BYTES, /*!< Byte control */ + SND_TPLG_TYPE_STREAM_CONFIG, /*!< PCM Stream configuration */ + SND_TPLG_TYPE_STREAM_CAPS, /*!< PCM Stream capabilities */ + SND_TPLG_TYPE_PCM, /*!< PCM stream device */ + SND_TPLG_TYPE_DAPM_WIDGET, /*!< DAPM widget */ + SND_TPLG_TYPE_DAPM_GRAPH, /*!< DAPM graph elements */ + SND_TPLG_TYPE_BE, /*!< BE DAI link */ + SND_TPLG_TYPE_CC, /*!< Hostless codec <-> codec link */ + SND_TPLG_TYPE_MANIFEST, /*!< Topology manifest */ };
struct snd_tplg { @@ -114,7 +114,7 @@ struct tplg_elem { char texts[SND_SOC_TPLG_NUM_TEXTS][SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
int index; - enum object_type type; + enum snd_tplg_type type;
int size; /* total size of this object inc pdata and ref objects */ int compound_elem; /* dont write this element as individual elem */ @@ -217,7 +217,7 @@ struct tplg_elem *tplg_elem_lookup(struct list_head *base, const char* id, unsigned int type); struct tplg_elem* tplg_elem_new_common(snd_tplg_t *tplg, - snd_config_t *cfg, const char *name, enum object_type type); + snd_config_t *cfg, const char *name, enum snd_tplg_type type);
static inline void elem_copy_text(char *dest, const char *src, int len) {
From: Mengdong Lin mengdong.lin@intel.com
Define structures that can be used by applications to directly build topology data instead of using text files. The application will build up the topology data by populating the template structures for each object type and then registering the template with the topology core.
Signed-off-by: Mengdong Lin mengdong.lin@intel.com Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- include/topology.h | 176 ++++++++++++++++++++++++++++++++++++++++++++++ src/topology/tplg_local.h | 18 ----- 2 files changed, 176 insertions(+), 18 deletions(-)
diff --git a/include/topology.h b/include/topology.h index 0cb2d79..aee43de 100644 --- a/include/topology.h +++ b/include/topology.h @@ -456,9 +456,30 @@ extern "C" { * */
+/** Maximum number of channels supported in one control */ +#define SND_TPLG_MAX_CHAN 8 + /** Topology context */ typedef struct snd_tplg snd_tplg_t;
+/** Topology object types */ +enum snd_tplg_type { + SND_TPLG_TYPE_TLV = 0, /*!< TLV Data */ + SND_TPLG_TYPE_MIXER, /*!< Mixer control*/ + SND_TPLG_TYPE_ENUM, /*!< Enumerated control */ + SND_TPLG_TYPE_TEXT, /*!< Text data */ + SND_TPLG_TYPE_DATA, /*!< Private data */ + SND_TPLG_TYPE_BYTES, /*!< Byte control */ + SND_TPLG_TYPE_STREAM_CONFIG, /*!< PCM Stream configuration */ + SND_TPLG_TYPE_STREAM_CAPS, /*!< PCM Stream capabilities */ + SND_TPLG_TYPE_PCM, /*!< PCM stream device */ + SND_TPLG_TYPE_DAPM_WIDGET, /*!< DAPM widget */ + SND_TPLG_TYPE_DAPM_GRAPH, /*!< DAPM graph elements */ + SND_TPLG_TYPE_BE, /*!< BE DAI link */ + SND_TPLG_TYPE_CC, /*!< Hostless codec <-> codec link */ + SND_TPLG_TYPE_MANIFEST, /*!< Topology manifest */ +}; + /** * \brief Create a new topology parser instance. * \return New topology parser instance @@ -488,6 +509,161 @@ int snd_tplg_build_file(snd_tplg_t *tplg, const char *infile, */ void snd_tplg_verbose(snd_tplg_t *tplg, int verbose);
+/** \struct snd_tplg_tlv_template + * \brief Template type for all TLV objects. + */ +struct snd_tplg_tlv_template { + int type; /*!< TLV type SNDRV_CTL_TLVT_ */ +}; + +/** \struct snd_tplg_tlv_dbscale_template + * \brief Template type for TLV Scale objects. + */ +struct snd_tplg_tlv_dbscale_template { + struct snd_tplg_tlv_template hdr; /*!< TLV type header */ + int min; /*!< dB minimum value in 0.1dB */ + int step; /*!< dB step size in 0.1dB */ + int mute; /*!< is min dB value mute ? */ +}; + +/** \struct snd_tplg_channel_template + * \brief Template type for single channel mapping. + */ +struct snd_tplg_channel_elem { + int size; /*!< size in bytes of this structure */ + int reg; /*!< channel control register */ + int shift; /*!< channel shift for control bits */ + int id; /*!< ID maps to Left, Right, LFE etc */ +}; + +/** \struct snd_tplg_channel_map_template + * \brief Template type for channel mapping. + */ +struct snd_tplg_channel_map_template { + int num_channels; /*!< number of channel mappings */ + struct snd_tplg_channel_elem channel[SND_TPLG_MAX_CHAN]; /*!< mapping */ +}; + +/** \struct snd_tplg_pdata_template + * \brief Template type for private data objects. + */ +struct snd_tplg_pdata_template { + unsigned int length; /*!< data length */ + const void *data; /*!< data */ +}; + +/** \struct snd_tplg_io_ops_template + * \brief Template type for object operations mapping. + */ +struct snd_tplg_io_ops_template { + int get; /*!< get callback ID */ + int put; /*!< put callback ID */ + int info; /*!< info callback ID */ +}; + +/** \struct snd_tplg_ctl_template + * \brief Template type for control objects. + */ +struct snd_tplg_ctl_template { + int type; /*!< Control type */ + const char *name; /*!< Control name */ + int access; /*!< Control access */ + struct snd_tplg_io_ops_template ops; /*!< operations */ + struct snd_tplg_tlv_template *tlv; /*!< non NULL means we have TLV data */ +}; + +/** \struct snd_tplg_mixer_template + * \brief Template type for mixer control objects. + */ +struct snd_tplg_mixer_template { + struct snd_tplg_ctl_template hdr; /*!< control type header */ + struct snd_tplg_channel_map_template *map; /*!< channel map */ + int min; /*!< min value for mixer */ + int max; /*!< max value for mixer */ + int platform_max; /*!< max value for platform control */ + int invert; /*!< whether controls bits are inverted */ + struct snd_soc_tplg_private *priv; /*!< control private data */ +}; + +/** \struct snd_tplg_enum_template + * \brief Template type for enumerated control objects. + */ +struct snd_tplg_enum_template { + struct snd_tplg_ctl_template hdr; /*!< control type header */ + struct snd_tplg_channel_map_template *map; /*!< channel map */ + int items; /*!< number of enumerated items in control */ + int mask; /*!< register mask size */ + const char **texts; /*!< control text items */ + const int **values; /*!< control value items */ + struct snd_soc_tplg_private *priv; /*!< control private data */ +}; + +/** \struct snd_tplg_bytes_template + * \brief Template type for TLV Scale objects. + */ +struct snd_tplg_bytes_template { + struct snd_tplg_ctl_template hdr; /*!< control type header */ + int max; /*!< max byte control value */ + int mask; /*!< byte control mask */ + int base; /*!< base register */ + int num_regs; /*!< number of registers */ + struct snd_tplg_io_ops_template ext_ops; /*!< ops mapping */ + struct snd_soc_tplg_private *priv; /*!< control private data */ +}; + +/** \struct snd_tplg_graph_elem + * \brief Template type for single DAPM graph element. + */ +struct snd_tplg_graph_elem { + const char *src; /*!< source widget name */ + const char *ctl; /*!< control name or NULL if no control */ + const char *sink; /*!< sink widget name */ +}; + +/** \struct snd_tplg_graph_template + * \brief Template type for array of DAPM graph elements. + */ +struct snd_tplg_graph_template { + int count; /*!< Number of graph elements */ + struct snd_tplg_graph_elem elem[0]; /*!< graph elements */ +}; + +/** \struct snd_tplg_widget_template + * \brief Template type for DAPM widget objects. + */ +struct snd_tplg_widget_template { + int id; /*!< SND_SOC_DAPM_CTL */ + const char *name; /*!< widget name */ + const char *sname; /*!< stream name (certain widgets only) */ + int reg; /*!< negative reg = no direct dapm */ + int shift; /*!< bits to shift */ + int mask; /*!< non-shifted mask */ + int subseq; /*!< sort within widget type */ + unsigned int invert; /*!< invert the power bit */ + unsigned int ignore_suspend; /*!< kept enabled over suspend */ + unsigned short event_flags; /*!< PM event sequence flags */ + unsigned short event_type; /*!< PM event sequence type */ + struct snd_soc_tplg_private *priv; /*!< widget private data */ + int num_ctls; /*!< Number of controls used by widget */ + struct snd_tplg_ctl_template *ctl[0]; /*!< array of widget controls */ +}; + +/** \struct snd_tplg_obj_template + * \brief Generic Template Object + */ +typedef struct snd_tplg_obj_template { + enum snd_tplg_type type; /*!< template object type */ + int index; /*!< group index for object */ + int version; /*!< optional vendor specific version details */ + int vendor_type; /*!< optional vendor specific type info */ + union { + struct snd_tplg_widget_template *widget; /*!< DAPM widget */ + struct snd_tplg_mixer_template *mixer; /*!< Mixer control */ + struct snd_tplg_bytes_template *bytes_ctl; /*!< Bytes control */ + struct snd_tplg_enum_template *enum_ctl; /*!< Enum control */ + struct snd_tplg_graph_template *graph; /*!< Graph elements */ + }; +} snd_tplg_obj_template_t; /* } */
#ifdef __cplusplus diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h index febc177..953d822 100644 --- a/src/topology/tplg_local.h +++ b/src/topology/tplg_local.h @@ -40,24 +40,6 @@ struct tplg_ref; struct tplg_elem;
-/** Topology object types */ -enum snd_tplg_type { - SND_TPLG_TYPE_TLV = 0, /*!< TLV Data */ - SND_TPLG_TYPE_MIXER, /*!< Mixer control*/ - SND_TPLG_TYPE_ENUM, /*!< Enumerated control */ - SND_TPLG_TYPE_TEXT, /*!< Text data */ - SND_TPLG_TYPE_DATA, /*!< Private data */ - SND_TPLG_TYPE_BYTES, /*!< Byte control */ - SND_TPLG_TYPE_STREAM_CONFIG, /*!< PCM Stream configuration */ - SND_TPLG_TYPE_STREAM_CAPS, /*!< PCM Stream capabilities */ - SND_TPLG_TYPE_PCM, /*!< PCM stream device */ - SND_TPLG_TYPE_DAPM_WIDGET, /*!< DAPM widget */ - SND_TPLG_TYPE_DAPM_GRAPH, /*!< DAPM graph elements */ - SND_TPLG_TYPE_BE, /*!< BE DAI link */ - SND_TPLG_TYPE_CC, /*!< Hostless codec <-> codec link */ - SND_TPLG_TYPE_MANIFEST, /*!< Topology manifest */ -}; - struct snd_tplg {
/* opaque vendor data */
From: Mengdong Lin mengdong.lin@intel.com
Add some new API calls so that applications can directly build topology data using template structures.
Signed-off-by: Mengdong Lin mengdong.lin@intel.com Signed-off-by: Liam Girdwood liam.r.girdwood@linux.intel.com --- include/topology.h | 26 +++++ src/topology/ctl.c | 291 ++++++++++++++++++++++++++++++++++++++++++++++ src/topology/dapm.c | 182 ++++++++++++++++++++++++++--- src/topology/elem.c | 17 +++ src/topology/parser.c | 57 +++++++++ src/topology/tplg_local.h | 11 ++ 6 files changed, 570 insertions(+), 14 deletions(-)
diff --git a/include/topology.h b/include/topology.h index aee43de..6ff8c5f 100644 --- a/include/topology.h +++ b/include/topology.h @@ -664,6 +664,32 @@ typedef struct snd_tplg_obj_template { struct snd_tplg_graph_template *graph; /*!< Graph elements */ }; } snd_tplg_obj_template_t; + +/** + * \brief Register topology template object. + * \param tplg Topology instance. + * \param t Template object. + * \return Zero on success, otherwise a negative error code + */ +int snd_tplg_add_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t); + +/** + * \brief Build all registered topology data into binary file. + * \param tplg Topology instance. + * \param outfile Binary topology output file. + * \return Zero on success, otherwise a negative error code + */ +int snd_tplg_build(snd_tplg_t *tplg, const char *outfile); + +/** + * \brief Attach private data to topology manifest. + * \param tplg Topology instance. + * \param data Private data. + * \param len Length of data in bytes. + * \return Zero on success, otherwise a negative error code + */ +int snd_tplg_set_manifest_data(snd_tplg_t *tplg, const void *data, int len); + /* } */
#ifdef __cplusplus diff --git a/src/topology/ctl.c b/src/topology/ctl.c index 35f684b..14027a3 100644 --- a/src/topology/ctl.c +++ b/src/topology/ctl.c @@ -19,6 +19,8 @@ #include "list.h" #include "tplg_local.h"
+#define ENUM_VAL_SIZE (SNDRV_CTL_ELEM_ID_NAME_MAXLEN >> 2) + /* copy referenced TLV to the mixer control */ static int copy_tlv(struct tplg_elem *elem, struct tplg_elem *ref) { @@ -606,3 +608,292 @@ int tplg_parse_control_mixer(snd_tplg_t *tplg,
return 0; } + +static int init_ctl_hdr(struct snd_soc_tplg_ctl_hdr *hdr, + struct snd_tplg_ctl_template *t) +{ + hdr->size = sizeof(struct snd_soc_tplg_ctl_hdr); + hdr->type = t->type; + + elem_copy_text(hdr->name, t->name, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + + /* clean up access flag */ + if (t->access == 0) + t->access = SNDRV_CTL_ELEM_ACCESS_READWRITE; + t->access &= (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_VOLATILE | + SNDRV_CTL_ELEM_ACCESS_INACTIVE | + SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND | + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK); + + hdr->access = t->access; + hdr->ops.get = t->ops.get; + hdr->ops.put = t->ops.put; + hdr->ops.info = t->ops.info; + + /* TLV */ + if (hdr->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE + && !(hdr->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)) { + + struct snd_tplg_tlv_template *tlvt = t->tlv; + struct snd_soc_tplg_ctl_tlv *tlv = &hdr->tlv; + struct snd_tplg_tlv_dbscale_template *scalet; + struct snd_soc_tplg_tlv_dbscale *scale; + + if (!tlvt) { + SNDERR("error: missing TLV data\n"); + return -EINVAL; + } + + tlv->size = sizeof(struct snd_soc_tplg_ctl_tlv); + tlv->type = tlvt->type; + + switch (tlvt->type) { + case SNDRV_CTL_TLVT_DB_SCALE: + scalet = container_of(tlvt, + struct snd_tplg_tlv_dbscale_template, hdr); + scale = &tlv->scale; + scale->min = scalet->min; + scale->step = scalet->step; + scale->mute = scalet->mute; + break; + + /* TODO: add support for other TLV types */ + default: + SNDERR("error: unsupported TLV type %d\n", tlv->type); + break; + } + } + + return 0; +} + +int tplg_add_mixer(snd_tplg_t *tplg, struct snd_tplg_mixer_template *mixer, + struct tplg_elem **e) +{ + struct snd_soc_tplg_private *priv = mixer->priv; + struct snd_soc_tplg_mixer_control *mc; + struct tplg_elem *elem; + int ret, i; + + tplg_dbg(" Control Mixer: %s\n", mixer->hdr.name); + + if (mixer->hdr.type != SND_SOC_TPLG_TYPE_MIXER) { + SNDERR("error: invalid mixer type %d\n", mixer->hdr.type); + return -EINVAL; + } + + elem = tplg_elem_new_common(tplg, NULL, mixer->hdr.name, + SND_TPLG_TYPE_MIXER); + if (!elem) + return -ENOMEM; + + /* init new mixer */ + mc = elem->mixer_ctrl; + mc->size = elem->size; + ret = init_ctl_hdr(&mc->hdr, &mixer->hdr); + if (ret < 0) { + tplg_elem_free(elem); + return ret; + } + + mc->min = mixer->min; + mc->max = mixer->max; + mc->platform_max = mixer->platform_max; + mc->invert = mixer->invert; + + /* set channel reg to default state */ + for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++) + mc->channel[i].reg = -1; + + if (mixer->map) + mc->num_channels = mixer->map->num_channels; + for (i = 0; i < mc->num_channels; i++) { + struct snd_tplg_channel_elem *channel = &mixer->map->channel[i]; + + mc->channel[i].size = channel->size; + mc->channel[i].reg = channel->reg; + mc->channel[i].shift = channel->shift; + mc->channel[i].id = channel->id; + } + + /* priv data */ + if (priv) { + mc = realloc(mc, elem->size + priv->size); + if (!mc) { + tplg_elem_free(elem); + return -ENOMEM; + } + + elem->mixer_ctrl = mc; + elem->size += priv->size; + mc->priv.size = priv->size; + memcpy(mc->priv.data, priv->data, priv->size); + } + + if (e) + *e = elem; + return 0; +} + +int tplg_add_enum(snd_tplg_t *tplg, struct snd_tplg_enum_template *enum_ctl, + struct tplg_elem **e) +{ + struct snd_soc_tplg_enum_control *ec; + struct tplg_elem *elem; + int ret, i; + + tplg_dbg(" Control Enum: %s\n", enum_ctl->hdr.name); + + if (enum_ctl->hdr.type != SND_SOC_TPLG_TYPE_ENUM) { + SNDERR("error: invalid enum type %d\n", enum_ctl->hdr.type); + return -EINVAL; + } + + elem = tplg_elem_new_common(tplg, NULL, enum_ctl->hdr.name, + SND_TPLG_TYPE_ENUM); + if (!elem) + return -ENOMEM; + + ec = elem->enum_ctrl; + ec->size = elem->size; + ret = init_ctl_hdr(&ec->hdr, &enum_ctl->hdr); + if (ret < 0) { + tplg_elem_free(elem); + return ret; + } + + ec->items = enum_ctl->items; + if (ec->items > SND_SOC_TPLG_NUM_TEXTS) + ec->items = SND_SOC_TPLG_NUM_TEXTS; + + ec->mask = enum_ctl->mask; + ec->count = enum_ctl->items; + + if (enum_ctl->texts != NULL) { + for (i = 0; i < ec->items; i++) { + if (enum_ctl->texts[i] != NULL) + strncpy(ec->texts[i], enum_ctl->texts[i], + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + } + } + + if (enum_ctl->values != NULL) { + for (i = 0; i < ec->items; i++) { + if (enum_ctl->values[i]) + continue; + + memcpy(&ec->values[i * sizeof(int) * ENUM_VAL_SIZE], + enum_ctl->values[i], + sizeof(int) * ENUM_VAL_SIZE); + } + } + + if (enum_ctl->priv != NULL) { + ec = realloc(ec, + elem->size + enum_ctl->priv->size); + if (!ec) { + tplg_elem_free(elem); + return -ENOMEM; + } + + elem->enum_ctrl = ec; + elem->size += enum_ctl->priv->size; + + memcpy(ec->priv.data, enum_ctl->priv->data, + enum_ctl->priv->size); + + ec->priv.size = enum_ctl->priv->size; + } + + if (e) + *e = elem; + return 0; +} + +int tplg_add_bytes(snd_tplg_t *tplg, struct snd_tplg_bytes_template *bytes_ctl, + struct tplg_elem **e) +{ + struct snd_soc_tplg_bytes_control *be; + struct tplg_elem *elem; + int ret; + + tplg_dbg(" Control Bytes: %s\n", bytes_ctl->hdr.name); + + if (bytes_ctl->hdr.type != SND_SOC_TPLG_TYPE_BYTES) { + SNDERR("error: invalid bytes type %d\n", bytes_ctl->hdr.type); + return -EINVAL; + } + + elem = tplg_elem_new_common(tplg, NULL, bytes_ctl->hdr.name, + SND_TPLG_TYPE_BYTES); + if (!elem) + return -ENOMEM; + + be = elem->bytes_ext; + be->size = elem->size; + ret = init_ctl_hdr(&be->hdr, &bytes_ctl->hdr); + if (ret < 0) { + tplg_elem_free(elem); + return ret; + } + + be->max = bytes_ctl->max; + be->mask = bytes_ctl->mask; + be->base = bytes_ctl->base; + be->num_regs = bytes_ctl->num_regs; + be->ext_ops.put = bytes_ctl->ext_ops.put; + be->ext_ops.get = bytes_ctl->ext_ops.get; + + if (bytes_ctl->priv != NULL) { + be = realloc(be, + elem->size + bytes_ctl->priv->size); + if (!be) { + tplg_elem_free(elem); + return -ENOMEM; + } + elem->bytes_ext = be; + elem->size += bytes_ctl->priv->size; + + memcpy(be->priv.data, bytes_ctl->priv->data, + bytes_ctl->priv->size); + + be->priv.size = bytes_ctl->priv->size; + } + + /* check on TLV bytes control */ + if (be->hdr.access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { + if (be->hdr.access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE + != SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) { + SNDERR("error: Invalid TLV bytes control access 0x%x\n", + be->hdr.access); + return -EINVAL; + } + + if (!be->max) { + tplg_elem_free(elem); + return -EINVAL; + } + } + + if (e) + *e = elem; + return 0; +} + +int tplg_add_mixer_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) +{ + return tplg_add_mixer(tplg, t->mixer, NULL); +} + +int tplg_add_enum_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) +{ + return tplg_add_enum(tplg, t->enum_ctl, NULL); +} + +int tplg_add_bytes_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) +{ + return tplg_add_bytes(tplg, t->bytes_ctl, NULL); +} diff --git a/src/topology/dapm.c b/src/topology/dapm.c index 3458aa7..5b3500f 100644 --- a/src/topology/dapm.c +++ b/src/topology/dapm.c @@ -142,8 +142,6 @@ static int tplg_build_widget(snd_tplg_t *tplg, list_for_each(pos, base) {
ref = list_entry(pos, struct tplg_ref, list); - if (ref->id == NULL || ref->elem) - continue;
switch (ref->type) { case SND_TPLG_TYPE_MIXER: @@ -162,6 +160,14 @@ static int tplg_build_widget(snd_tplg_t *tplg, err = copy_dapm_control(elem, ref->elem); break;
+ case SND_TPLG_TYPE_BYTES: + if (!ref->elem) + ref->elem = tplg_elem_lookup(&tplg->bytes_ext_list, + ref->id, SND_TPLG_TYPE_BYTES); + if (ref->elem) + err = copy_dapm_control(elem, ref->elem); + break; + case SND_TPLG_TYPE_DATA: if (!ref->elem) ref->elem = tplg_elem_lookup(&tplg->pdata_list, @@ -278,6 +284,28 @@ int tplg_build_routes(snd_tplg_t *tplg) return 0; }
+struct tplg_elem* tplg_elem_new_route(snd_tplg_t *tplg) +{ + struct tplg_elem *elem; + struct snd_soc_tplg_dapm_graph_elem *line; + + elem = tplg_elem_new(); + if (!elem) + return NULL; + + list_add_tail(&elem->list, &tplg->route_list); + strcpy(elem->id, "line"); + elem->type = SND_TPLG_TYPE_DAPM_GRAPH; + elem->size = sizeof(*line); + + line = calloc(1, sizeof(*line)); + if (!line) + return NULL; + elem->route = line; + + return elem; +} + #define LINE_SIZE 1024
/* line is defined as '"source, control, sink"' */ @@ -334,7 +362,7 @@ static int tplg_parse_routes(snd_tplg_t *tplg, snd_config_t *cfg) snd_config_iterator_t i, next; snd_config_t *n; struct tplg_elem *elem; - struct snd_soc_tplg_dapm_graph_elem *line = NULL; + struct snd_soc_tplg_dapm_graph_elem *line; int err;
snd_config_for_each(i, next, cfg) { @@ -344,20 +372,11 @@ static int tplg_parse_routes(snd_tplg_t *tplg, snd_config_t *cfg) if (snd_config_get_string(n, &val) < 0) continue;
- elem = tplg_elem_new(); + elem = tplg_elem_new_route(tplg); if (!elem) return -ENOMEM;
- list_add_tail(&elem->list, &tplg->route_list); - strcpy(elem->id, "line"); - elem->type = SND_TPLG_TYPE_DAPM_GRAPH; - elem->size = sizeof(*line); - - line = calloc(1, sizeof(*line)); - if (!line) - return -ENOMEM; - - elem->route = line; + line = elem->route;
err = tplg_parse_line(val, line); if (err < 0) @@ -558,3 +577,138 @@ int tplg_parse_dapm_widget(snd_tplg_t *tplg,
return 0; } + +int tplg_add_route(snd_tplg_t *tplg, struct snd_tplg_graph_elem *t) +{ + struct tplg_elem *elem; + struct snd_soc_tplg_dapm_graph_elem *line; + + if (!t->src || !t->sink) + return -EINVAL; + + elem = tplg_elem_new_route(tplg); + if (!elem) + return -ENOMEM; + + line = elem->route; + elem_copy_text(line->source, t->src, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + if (t->ctl) + elem_copy_text(line->control, t->ctl, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + elem_copy_text(line->sink, t->sink, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + + return 0; +} + +int tplg_add_graph_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) +{ + struct snd_tplg_graph_template *gt = t->graph; + int i, ret; + + for (i = 0; i < gt->count; i++) { + ret = tplg_add_route(tplg, gt->elem + i); + if (ret < 0) + return ret; + } + + return 0; +} + +int tplg_add_widget_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) +{ + struct snd_tplg_widget_template *wt = t->widget; + struct snd_soc_tplg_dapm_widget *w; + struct tplg_elem *elem; + int i, ret = 0; + + tplg_dbg("Widget: %s\n", wt->name); + + elem = tplg_elem_new_common(tplg, NULL, wt->name, + SND_TPLG_TYPE_DAPM_WIDGET); + if (!elem) + return -ENOMEM; + + /* init new widget */ + w = elem->widget; + w->size = elem->size; + + w->id = wt->id; + elem_copy_text(w->name, wt->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + if (wt->sname) + elem_copy_text(w->sname, wt->sname, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + w->reg = wt->reg; + w->shift = wt->shift; + w->mask = wt->mask; + w->subseq = wt->subseq; + w->invert = wt->invert; + w->ignore_suspend = wt->ignore_suspend; + w->event_flags = wt->event_flags; + w->event_type = wt->event_type; + + if (wt->priv != NULL) { + w = realloc(w, + elem->size + wt->priv->size); + if (!w) { + tplg_elem_free(elem); + return -ENOMEM; + } + + elem->widget = w; + elem->size += wt->priv->size; + + memcpy(w->priv.data, wt->priv->data, + wt->priv->size); + w->priv.size = wt->priv->size; + } + + /* add controls to the widget's reference list */ + for (i = 0 ; i < wt->num_ctls; i++) { + struct snd_tplg_ctl_template *ct = wt->ctl[i]; + struct tplg_elem *elem_ctl; + struct snd_tplg_mixer_template *mt; + struct snd_tplg_bytes_template *bt; + struct snd_tplg_enum_template *et; + + if (!ct) { + tplg_elem_free(elem); + return -EINVAL; + } + + switch (ct->type) { + case SND_SOC_TPLG_TYPE_MIXER: + mt = container_of(ct, struct snd_tplg_mixer_template, hdr); + ret = tplg_add_mixer(tplg, mt, &elem_ctl); + break; + + case SND_SOC_TPLG_TYPE_BYTES: + bt = container_of(ct, struct snd_tplg_bytes_template, hdr); + ret = tplg_add_bytes(tplg, bt, &elem_ctl); + break; + + case SND_SOC_TPLG_TYPE_ENUM: + et = container_of(ct, struct snd_tplg_enum_template, hdr); + ret = tplg_add_enum(tplg, bt, &elem_ctl); + break; + + default: + SNDERR("error: widget %s: invalid type %d for ctl %d\n", + wt->name, ct->type, i); + ret = -EINVAL; + break; + } + + if (ret < 0) { + tplg_elem_free(elem); + return ret; + } + + ret = tplg_ref_add_elem(elem, elem_ctl); + if (ret < 0) { + tplg_elem_free(elem); + return ret; + } + } + + return 0; +} diff --git a/src/topology/elem.c b/src/topology/elem.c index daabe75..d784236 100644 --- a/src/topology/elem.c +++ b/src/topology/elem.c @@ -35,6 +35,23 @@ int tplg_ref_add(struct tplg_elem *elem, int type, const char* id) return 0; }
+/* directly add a reference elem */ +int tplg_ref_add_elem(struct tplg_elem *elem, struct tplg_elem *elem_ref) +{ + struct tplg_ref *ref; + + ref = calloc(1, sizeof(*ref)); + if (!ref) + return -ENOMEM; + + ref->type = elem_ref->type; + ref->elem = elem_ref; + elem_copy_text(ref->id, elem_ref->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + + list_add_tail(&ref->list, &elem->ref_list); + return 0; +} + void tplg_ref_free_list(struct list_head *base) { struct list_head *pos, *npos; diff --git a/src/topology/parser.c b/src/topology/parser.c index 3e3e2b3..497eb42 100644 --- a/src/topology/parser.c +++ b/src/topology/parser.c @@ -309,6 +309,63 @@ out_close: return err; }
+int snd_tplg_add_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) +{ + switch (t->type) { + case SND_TPLG_TYPE_MIXER: + return tplg_add_mixer_object(tplg, t); + case SND_TPLG_TYPE_ENUM: + return tplg_add_enum_object(tplg, t); + case SND_TPLG_TYPE_BYTES: + return tplg_add_bytes_object(tplg, t); + case SND_TPLG_TYPE_DAPM_WIDGET: + return tplg_add_widget_object(tplg, t); + case SND_TPLG_TYPE_DAPM_GRAPH: + return tplg_add_graph_object(tplg, t); + default: + SNDERR("error: invalid object type %d\n", t->type); + return -EINVAL; + }; +} + +int snd_tplg_build(snd_tplg_t *tplg, const char *outfile) +{ + int err; + + /* delete any old output files */ + unlink(outfile); + + tplg->out_fd = + open(outfile, O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO); + if (tplg->out_fd < 0) { + SNDERR("error: failed to open %s err %d\n", + outfile, -errno); + return -errno; + } + + err = tplg_build_integ(tplg); + if (err < 0) { + SNDERR("error: failed to check topology integrity\n"); + goto out; + } + + err = tplg_write_data(tplg); + if (err < 0) { + SNDERR("error: failed to write data %d\n", err); + goto out; + } + +out: + close(tplg->out_fd); + return err; +} + +int snd_tplg_set_manifest_data(snd_tplg_t *tplg, const void *data, int len) +{ + tplg->manifest.priv.size = len; + tplg->manifest_pdata = data; +} + void snd_tplg_verbose(snd_tplg_t *tplg, int verbose) { tplg->verbose = verbose; diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h index 953d822..97ee33e 100644 --- a/src/topology/tplg_local.h +++ b/src/topology/tplg_local.h @@ -34,6 +34,10 @@ #define ALSA_TPLG_DIR ALSA_CONFIG_DIR "/topology" #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + /** The name of the environment variable containing the tplg directory */ #define ALSA_CONFIG_TPLG_VAR "ALSA_CONFIG_TPLG"
@@ -191,6 +195,7 @@ int tplg_build_pcm_dai(snd_tplg_t *tplg, unsigned int type); int tplg_copy_data(struct tplg_elem *elem, struct tplg_elem *ref);
int tplg_ref_add(struct tplg_elem *elem, int type, const char* id); +int tplg_ref_add_elem(struct tplg_elem *elem, struct tplg_elem *elem_ref);
struct tplg_elem *tplg_elem_new(void); void tplg_elem_free(struct tplg_elem *elem); @@ -215,3 +220,9 @@ int tplg_parse_ops(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
struct tplg_elem *lookup_pcm_dai_stream(struct list_head *base, const char* id); + +int tplg_add_mixer_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t); +int tplg_add_enum_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t); +int tplg_add_bytes_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t); +int tplg_add_widget_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t); +int tplg_add_graph_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t);
On Mon, 10 Aug 2015 20:13:49 +0200, Liam Girdwood wrote:
+int tplg_add_bytes(snd_tplg_t *tplg, struct snd_tplg_bytes_template *bytes_ctl,
- struct tplg_elem **e)
+{
- struct snd_soc_tplg_bytes_control *be;
- struct tplg_elem *elem;
- int ret;
- tplg_dbg(" Control Bytes: %s\n", bytes_ctl->hdr.name);
- if (bytes_ctl->hdr.type != SND_SOC_TPLG_TYPE_BYTES) {
SNDERR("error: invalid bytes type %d\n", bytes_ctl->hdr.type);
return -EINVAL;
- }
- elem = tplg_elem_new_common(tplg, NULL, bytes_ctl->hdr.name,
SND_TPLG_TYPE_BYTES);
- if (!elem)
return -ENOMEM;
- be = elem->bytes_ext;
- be->size = elem->size;
- ret = init_ctl_hdr(&be->hdr, &bytes_ctl->hdr);
- if (ret < 0) {
tplg_elem_free(elem);
return ret;
- }
- be->max = bytes_ctl->max;
- be->mask = bytes_ctl->mask;
- be->base = bytes_ctl->base;
- be->num_regs = bytes_ctl->num_regs;
- be->ext_ops.put = bytes_ctl->ext_ops.put;
- be->ext_ops.get = bytes_ctl->ext_ops.get;
- if (bytes_ctl->priv != NULL) {
be = realloc(be,
elem->size + bytes_ctl->priv->size);
if (!be) {
tplg_elem_free(elem);
return -ENOMEM;
}
elem->bytes_ext = be;
elem->size += bytes_ctl->priv->size;
memcpy(be->priv.data, bytes_ctl->priv->data,
bytes_ctl->priv->size);
be->priv.size = bytes_ctl->priv->size;
- }
- /* check on TLV bytes control */
- if (be->hdr.access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
if (be->hdr.access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE
!= SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) {
SNDERR("error: Invalid TLV bytes control access 0x%x\n",
be->hdr.access);
return -EINVAL;
Missing tplg_elem_free()?
+struct tplg_elem* tplg_elem_new_route(snd_tplg_t *tplg) +{
- struct tplg_elem *elem;
- struct snd_soc_tplg_dapm_graph_elem *line;
- elem = tplg_elem_new();
- if (!elem)
return NULL;
- list_add_tail(&elem->list, &tplg->route_list);
- strcpy(elem->id, "line");
- elem->type = SND_TPLG_TYPE_DAPM_GRAPH;
- elem->size = sizeof(*line);
- line = calloc(1, sizeof(*line));
- if (!line)
return NULL;
Missing free of elem in the error path. Also, tplg->route_list still contains the stray elem.
I guess this was a bug in the original code, so you can address it before this patch.
+int tplg_add_widget_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t) +{
- struct snd_tplg_widget_template *wt = t->widget;
- struct snd_soc_tplg_dapm_widget *w;
- struct tplg_elem *elem;
- int i, ret = 0;
- tplg_dbg("Widget: %s\n", wt->name);
- elem = tplg_elem_new_common(tplg, NULL, wt->name,
SND_TPLG_TYPE_DAPM_WIDGET);
- if (!elem)
return -ENOMEM;
- /* init new widget */
- w = elem->widget;
- w->size = elem->size;
- w->id = wt->id;
- elem_copy_text(w->name, wt->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
- if (wt->sname)
elem_copy_text(w->sname, wt->sname,
SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Indentation problem.
- /* add controls to the widget's reference list */
- for (i = 0 ; i < wt->num_ctls; i++) {
struct snd_tplg_ctl_template *ct = wt->ctl[i];
struct tplg_elem *elem_ctl;
struct snd_tplg_mixer_template *mt;
struct snd_tplg_bytes_template *bt;
struct snd_tplg_enum_template *et;
if (!ct) {
tplg_elem_free(elem);
return -EINVAL;
}
switch (ct->type) {
case SND_SOC_TPLG_TYPE_MIXER:
mt = container_of(ct, struct snd_tplg_mixer_template, hdr);
ret = tplg_add_mixer(tplg, mt, &elem_ctl);
break;
case SND_SOC_TPLG_TYPE_BYTES:
bt = container_of(ct, struct snd_tplg_bytes_template, hdr);
ret = tplg_add_bytes(tplg, bt, &elem_ctl);
break;
case SND_SOC_TPLG_TYPE_ENUM:
et = container_of(ct, struct snd_tplg_enum_template, hdr);
ret = tplg_add_enum(tplg, bt, &elem_ctl);
et instead of bt?
+int snd_tplg_build(snd_tplg_t *tplg, const char *outfile) +{
- int err;
- /* delete any old output files */
- unlink(outfile);
- tplg->out_fd =
open(outfile, O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
- if (tplg->out_fd < 0) {
SNDERR("error: failed to open %s err %d\n",
outfile, -errno);
return -errno;
- }
- err = tplg_build_integ(tplg);
- if (err < 0) {
SNDERR("error: failed to check topology integrity\n");
goto out;
- }
- err = tplg_write_data(tplg);
- if (err < 0) {
SNDERR("error: failed to write data %d\n", err);
goto out;
- }
+out:
- close(tplg->out_fd);
It's a question whether we should unlink automatically at error or not. If we leave the file as is, it should be documented.
diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h index 953d822..97ee33e 100644 --- a/src/topology/tplg_local.h +++ b/src/topology/tplg_local.h @@ -34,6 +34,10 @@ #define ALSA_TPLG_DIR ALSA_CONFIG_DIR "/topology" #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - offsetof(type,member) );})
This is a pretty common macro, so I prefer having it in include/local.h.
thanks,
Takashi
On Tue, 2015-08-11 at 09:57 +0200, Takashi Iwai wrote:
@@ -34,6 +34,10 @@ #define ALSA_TPLG_DIR ALSA_CONFIG_DIR "/topology" #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
This is a pretty common macro, so I prefer having it in include/local.h.
I'll also move ARRAY_SIZE() to local.h too since it's common.
Liam
On Tue, 11 Aug 2015 10:04:48 +0200, Liam Girdwood wrote:
On Tue, 2015-08-11 at 09:57 +0200, Takashi Iwai wrote:
@@ -34,6 +34,10 @@ #define ALSA_TPLG_DIR ALSA_CONFIG_DIR "/topology" #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
+#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
This is a pretty common macro, so I prefer having it in include/local.h.
I'll also move ARRAY_SIZE() to local.h too since it's common.
Sounds reasonable.
thanks,
Takashi
On Tue, 2015-08-11 at 09:57 +0200, Takashi Iwai wrote:
On Mon, 10 Aug 2015 20:13:49 +0200, Liam Girdwood wrote:
+int snd_tplg_build(snd_tplg_t *tplg, const char *outfile) +{
- int err;
- /* delete any old output files */
- unlink(outfile);
- tplg->out_fd =
open(outfile, O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
- if (tplg->out_fd < 0) {
SNDERR("error: failed to open %s err %d\n",
outfile, -errno);
return -errno;
- }
- err = tplg_build_integ(tplg);
- if (err < 0) {
SNDERR("error: failed to check topology integrity\n");
goto out;
- }
- err = tplg_write_data(tplg);
- if (err < 0) {
SNDERR("error: failed to write data %d\n", err);
goto out;
- }
+out:
- close(tplg->out_fd);
It's a question whether we should unlink automatically at error or not. If we leave the file as is, it should be documented.
The unlink is not really needed so I'll remove it. The file permissions should be 0600 too, so I'll fix that as well.
Liam
-----Original Message----- From: Takashi Iwai [mailto:tiwai@suse.de] Sent: Tuesday, August 11, 2015 3:58 PM
On Mon, 10 Aug 2015 20:13:49 +0200, Liam Girdwood wrote:
+int tplg_add_bytes(snd_tplg_t *tplg, struct snd_tplg_bytes_template
*bytes_ctl,
- struct tplg_elem **e)
+{
- struct snd_soc_tplg_bytes_control *be;
- struct tplg_elem *elem;
- int ret;
- tplg_dbg(" Control Bytes: %s\n", bytes_ctl->hdr.name);
- if (bytes_ctl->hdr.type != SND_SOC_TPLG_TYPE_BYTES) {
SNDERR("error: invalid bytes type %d\n", bytes_ctl->hdr.type);
return -EINVAL;
- }
- elem = tplg_elem_new_common(tplg, NULL, bytes_ctl->hdr.name,
SND_TPLG_TYPE_BYTES);
- if (!elem)
return -ENOMEM;
- be = elem->bytes_ext;
- be->size = elem->size;
- ret = init_ctl_hdr(&be->hdr, &bytes_ctl->hdr);
- if (ret < 0) {
tplg_elem_free(elem);
return ret;
- }
- be->max = bytes_ctl->max;
- be->mask = bytes_ctl->mask;
- be->base = bytes_ctl->base;
- be->num_regs = bytes_ctl->num_regs;
- be->ext_ops.put = bytes_ctl->ext_ops.put;
- be->ext_ops.get = bytes_ctl->ext_ops.get;
- if (bytes_ctl->priv != NULL) {
be = realloc(be,
elem->size + bytes_ctl->priv->size);
if (!be) {
tplg_elem_free(elem);
return -ENOMEM;
}
elem->bytes_ext = be;
elem->size += bytes_ctl->priv->size;
memcpy(be->priv.data, bytes_ctl->priv->data,
bytes_ctl->priv->size);
be->priv.size = bytes_ctl->priv->size;
- }
- /* check on TLV bytes control */
- if (be->hdr.access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
if (be->hdr.access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE
!= SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) {
SNDERR("error: Invalid TLV bytes control access 0x%x\n",
be->hdr.access);
return -EINVAL;
Missing tplg_elem_free()?
tplg_elem_free() is not needed here. tplg_elem_new_common() has inserted the element into a specific list according to the element type. And snd_tplg_free() will be called at last even on error, and it will scan all lists and free the elements.
+struct tplg_elem* tplg_elem_new_route(snd_tplg_t *tplg) {
- struct tplg_elem *elem;
- struct snd_soc_tplg_dapm_graph_elem *line;
- elem = tplg_elem_new();
- if (!elem)
return NULL;
- list_add_tail(&elem->list, &tplg->route_list);
- strcpy(elem->id, "line");
- elem->type = SND_TPLG_TYPE_DAPM_GRAPH;
- elem->size = sizeof(*line);
- line = calloc(1, sizeof(*line));
- if (!line)
return NULL;
Missing free of elem in the error path. Also, tplg->route_list still contains the stray elem.
I guess this was a bug in the original code, so you can address it before this patch.
Same as above. snd_tplg_free() is expected to do the final cleanup.
+int tplg_add_widget_object(snd_tplg_t *tplg, snd_tplg_obj_template_t +*t) {
- struct snd_tplg_widget_template *wt = t->widget;
- struct snd_soc_tplg_dapm_widget *w;
- struct tplg_elem *elem;
- int i, ret = 0;
- tplg_dbg("Widget: %s\n", wt->name);
- elem = tplg_elem_new_common(tplg, NULL, wt->name,
SND_TPLG_TYPE_DAPM_WIDGET);
- if (!elem)
return -ENOMEM;
- /* init new widget */
- w = elem->widget;
- w->size = elem->size;
- w->id = wt->id;
- elem_copy_text(w->name, wt->name,
SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
- if (wt->sname)
elem_copy_text(w->sname, wt->sname,
SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Indentation problem.
- /* add controls to the widget's reference list */
- for (i = 0 ; i < wt->num_ctls; i++) {
struct snd_tplg_ctl_template *ct = wt->ctl[i];
struct tplg_elem *elem_ctl;
struct snd_tplg_mixer_template *mt;
struct snd_tplg_bytes_template *bt;
struct snd_tplg_enum_template *et;
if (!ct) {
tplg_elem_free(elem);
return -EINVAL;
}
switch (ct->type) {
case SND_SOC_TPLG_TYPE_MIXER:
mt = container_of(ct, struct snd_tplg_mixer_template, hdr);
ret = tplg_add_mixer(tplg, mt, &elem_ctl);
break;
case SND_SOC_TPLG_TYPE_BYTES:
bt = container_of(ct, struct snd_tplg_bytes_template, hdr);
ret = tplg_add_bytes(tplg, bt, &elem_ctl);
break;
case SND_SOC_TPLG_TYPE_ENUM:
et = container_of(ct, struct snd_tplg_enum_template, hdr);
ret = tplg_add_enum(tplg, bt, &elem_ctl);
et instead of bt?
Yes. It should be et here.
Thanks Mengdong
On Tue, 11 Aug 2015 17:37:51 +0200, Lin, Mengdong wrote:
-----Original Message----- From: Takashi Iwai [mailto:tiwai@suse.de] Sent: Tuesday, August 11, 2015 3:58 PM
On Mon, 10 Aug 2015 20:13:49 +0200, Liam Girdwood wrote:
+int tplg_add_bytes(snd_tplg_t *tplg, struct snd_tplg_bytes_template
*bytes_ctl,
- struct tplg_elem **e)
+{
- struct snd_soc_tplg_bytes_control *be;
- struct tplg_elem *elem;
- int ret;
- tplg_dbg(" Control Bytes: %s\n", bytes_ctl->hdr.name);
- if (bytes_ctl->hdr.type != SND_SOC_TPLG_TYPE_BYTES) {
SNDERR("error: invalid bytes type %d\n", bytes_ctl->hdr.type);
return -EINVAL;
- }
- elem = tplg_elem_new_common(tplg, NULL, bytes_ctl->hdr.name,
SND_TPLG_TYPE_BYTES);
- if (!elem)
return -ENOMEM;
- be = elem->bytes_ext;
- be->size = elem->size;
- ret = init_ctl_hdr(&be->hdr, &bytes_ctl->hdr);
- if (ret < 0) {
tplg_elem_free(elem);
return ret;
- }
- be->max = bytes_ctl->max;
- be->mask = bytes_ctl->mask;
- be->base = bytes_ctl->base;
- be->num_regs = bytes_ctl->num_regs;
- be->ext_ops.put = bytes_ctl->ext_ops.put;
- be->ext_ops.get = bytes_ctl->ext_ops.get;
- if (bytes_ctl->priv != NULL) {
be = realloc(be,
elem->size + bytes_ctl->priv->size);
if (!be) {
tplg_elem_free(elem);
return -ENOMEM;
}
elem->bytes_ext = be;
elem->size += bytes_ctl->priv->size;
memcpy(be->priv.data, bytes_ctl->priv->data,
bytes_ctl->priv->size);
be->priv.size = bytes_ctl->priv->size;
- }
- /* check on TLV bytes control */
- if (be->hdr.access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
if (be->hdr.access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE
!= SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) {
SNDERR("error: Invalid TLV bytes control access 0x%x\n",
be->hdr.access);
return -EINVAL;
Missing tplg_elem_free()?
tplg_elem_free() is not needed here. tplg_elem_new_common() has inserted the element into a specific list according to the element type. And snd_tplg_free() will be called at last even on error, and it will scan all lists and free the elements.
It's error-prone. You're calling tplg_elem_free() in other error cases but only this doesn't.
Takashi
participants (3)
-
Liam Girdwood
-
Lin, Mengdong
-
Takashi Iwai