summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/topology.h28
-rw-r--r--src/topology/ctl.c24
-rw-r--r--src/topology/dapm.c8
-rw-r--r--src/topology/data.c116
-rw-r--r--src/topology/tplg_local.h1
5 files changed, 131 insertions, 46 deletions
diff --git a/include/topology.h b/include/topology.h
index 9d57ce3b..d666505f 100644
--- a/include/topology.h
+++ b/include/topology.h
@@ -213,6 +213,34 @@ extern "C" {
* The keyword tuples is to define vendor specific tuples. Please refer to
* section Vendor Tokens and Vendor tuples.
*
+ * <h5>How to define an element with private data</h5>
+ * An element can refer to a single data section or multiple data
+ * sections.
+ *
+ * <h6>To refer to a single data section:</h6>
+ * <pre>
+ * Sectionxxx."element name" {
+ * ...
+ * data "name of data section" # optional private data
+ * }
+ * </pre>
+ *
+ * <h6>To refer to multiple data sections:</h6>
+ * <pre>
+ * Sectionxxx."element name" {
+ * ...
+ * data [ # optional private data
+ * "name of 1st data section"
+ * "name of 2nd data section"
+ * ...
+ * ]
+ * }
+ * </pre>
+ * And data of these sections will be merged in the same order as they are
+ * in the list, as the element's private data for kernel.
+ *
+ * </pre>
+ *
* <h6>Vendor Tokens</h6>
* A vendor token list is defined as a new section. Each token element is
* a pair of string ID and integer value. And both the ID and value are
diff --git a/src/topology/ctl.c b/src/topology/ctl.c
index b948ac02..7ded0a42 100644
--- a/src/topology/ctl.c
+++ b/src/topology/ctl.c
@@ -447,11 +447,9 @@ int tplg_parse_control_bytes(snd_tplg_t *tplg,
}
if (strcmp(id, "data") == 0) {
- if (snd_config_get_string(n, &val) < 0)
- return -EINVAL;
-
- tplg_ref_add(elem, SND_TPLG_TYPE_DATA, val);
- tplg_dbg("\t%s: %s\n", id, val);
+ err = tplg_parse_data_refs(n, elem);
+ if (err < 0)
+ return err;
continue;
}
@@ -587,11 +585,9 @@ int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg,
}
if (strcmp(id, "data") == 0) {
- if (snd_config_get_string(n, &val) < 0)
- return -EINVAL;
-
- tplg_ref_add(elem, SND_TPLG_TYPE_DATA, val);
- tplg_dbg("\t%s: %s\n", id, val);
+ err = tplg_parse_data_refs(n, elem);
+ if (err < 0)
+ return err;
continue;
}
@@ -725,11 +721,9 @@ int tplg_parse_control_mixer(snd_tplg_t *tplg,
}
if (strcmp(id, "data") == 0) {
- if (snd_config_get_string(n, &val) < 0)
- return -EINVAL;
-
- tplg_ref_add(elem, SND_TPLG_TYPE_DATA, val);
- tplg_dbg("\t%s: %s\n", id, val);
+ err = tplg_parse_data_refs(n, elem);
+ if (err < 0)
+ return err;
continue;
}
diff --git a/src/topology/dapm.c b/src/topology/dapm.c
index 278d6056..d8eb10c1 100644
--- a/src/topology/dapm.c
+++ b/src/topology/dapm.c
@@ -598,11 +598,9 @@ int tplg_parse_dapm_widget(snd_tplg_t *tplg,
}
if (strcmp(id, "data") == 0) {
- if (snd_config_get_string(n, &val) < 0)
- return -EINVAL;
-
- tplg_ref_add(elem, SND_TPLG_TYPE_DATA, val);
- tplg_dbg("\t%s: %s\n", id, val);
+ err = tplg_parse_data_refs(n, elem);
+ if (err < 0)
+ return err;
continue;
}
}
diff --git a/src/topology/data.c b/src/topology/data.c
index c0a098cd..0c5469a8 100644
--- a/src/topology/data.c
+++ b/src/topology/data.c
@@ -20,6 +20,36 @@
#include "tplg_local.h"
#include <ctype.h>
+/* Get private data buffer of an element */
+struct snd_soc_tplg_private *get_priv_data(struct tplg_elem *elem)
+{
+ struct snd_soc_tplg_private *priv = NULL;
+
+ switch (elem->type) {
+ case SND_TPLG_TYPE_MIXER:
+ priv = &elem->mixer_ctrl->priv;
+ break;
+
+ case SND_TPLG_TYPE_ENUM:
+ priv = &elem->enum_ctrl->priv;
+ break;
+
+ case SND_TPLG_TYPE_BYTES:
+ priv = &elem->bytes_ext->priv;
+ break;
+
+ case SND_TPLG_TYPE_DAPM_WIDGET:
+ priv = &elem->widget->priv;
+ break;
+
+ default:
+ SNDERR("error: '%s': no support for private data for type %d\n",
+ elem->id, elem->type);
+ }
+
+ return priv;
+}
+
/* Get Private data from a file. */
static int tplg_parse_data_file(snd_config_t *cfg, struct tplg_elem *elem)
{
@@ -614,6 +644,48 @@ static int parse_tuple_sets(snd_tplg_t *tplg, snd_config_t *cfg,
return 0;
}
+/* Parse private data references for the element, either a single data section
+ * or a list of data sections.
+ */
+int tplg_parse_data_refs(snd_config_t *cfg,
+ struct tplg_elem *elem)
+{
+ snd_config_type_t type;
+ snd_config_iterator_t i, next;
+ snd_config_t *n;
+ const char *val = NULL;
+
+ type = snd_config_get_type(cfg);
+
+ /* refer to a single data section */
+ if (type == SND_CONFIG_TYPE_STRING) {
+ if (snd_config_get_string(cfg, &val) < 0)
+ return -EINVAL;
+
+ tplg_dbg("\tdata: %s\n", val);
+ return tplg_ref_add(elem, SND_TPLG_TYPE_DATA, val);
+ }
+
+ if (type != SND_CONFIG_TYPE_COMPOUND) {
+ SNDERR("error: compound type expected for %s", elem->id);
+ return -EINVAL;
+ }
+
+ /* refer to a list of data sections */
+ snd_config_for_each(i, next, cfg) {
+ const char *val;
+
+ n = snd_config_iterator_entry(i);
+ if (snd_config_get_string(n, &val) < 0)
+ continue;
+
+ tplg_dbg("\tdata: %s\n", val);
+ tplg_ref_add(elem, SND_TPLG_TYPE_DATA, val);
+ }
+
+ return 0;
+}
+
/* Parse vendor tokens
*/
int tplg_parse_tokens(snd_tplg_t *tplg, snd_config_t *cfg,
@@ -817,11 +889,15 @@ int tplg_parse_data(snd_tplg_t *tplg, snd_config_t *cfg,
return err;
}
-/* copy private data into the bytes extended control */
+/* Merge data from a referenced data element to the parent element's
+ * private data buffer.
+ * An element can refer to multiple data sections. Data of these sections
+ * will be merged in the their reference order.
+ */
int tplg_copy_data(struct tplg_elem *elem, struct tplg_elem *ref)
{
- struct snd_soc_tplg_private *priv;
- int priv_data_size;
+ struct snd_soc_tplg_private *priv, *old_priv;
+ int priv_data_size, old_priv_data_size;
void *obj;
if (!ref)
@@ -831,6 +907,11 @@ int tplg_copy_data(struct tplg_elem *elem, struct tplg_elem *ref)
if (!ref->data || !ref->data->size) /* overlook empty private data */
return 0;
+ old_priv = get_priv_data(elem);
+ if (!old_priv)
+ return -EINVAL;
+ old_priv_data_size = old_priv->size;
+
priv_data_size = ref->data->size;
obj = realloc(elem->obj,
elem->size + priv_data_size);
@@ -838,33 +919,16 @@ int tplg_copy_data(struct tplg_elem *elem, struct tplg_elem *ref)
return -ENOMEM;
elem->obj = obj;
- switch (elem->type) {
- case SND_TPLG_TYPE_MIXER:
- priv = &elem->mixer_ctrl->priv;
- break;
-
- case SND_TPLG_TYPE_ENUM:
- priv = &elem->enum_ctrl->priv;
- break;
-
- case SND_TPLG_TYPE_BYTES:
- priv = &elem->bytes_ext->priv;
- break;
-
- case SND_TPLG_TYPE_DAPM_WIDGET:
- priv = &elem->widget->priv;
- break;
-
- default:
- SNDERR("error: elem '%s': type %d private data not supported \n",
- elem->id, elem->type);
+ priv = get_priv_data(elem);
+ if (!priv)
return -EINVAL;
- }
+ /* merge the new data block */
elem->size += priv_data_size;
- priv->size = priv_data_size;
+ priv->size = priv_data_size + old_priv_data_size;
ref->compound_elem = 1;
- memcpy(priv->data, ref->data->data, priv_data_size);
+ memcpy(priv->data + old_priv_data_size,
+ ref->data->data, priv_data_size);
return 0;
}
diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h
index 9239aef8..4daa5407 100644
--- a/src/topology/tplg_local.h
+++ b/src/topology/tplg_local.h
@@ -229,6 +229,7 @@ int tplg_build_routes(snd_tplg_t *tplg);
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_parse_data_refs(snd_config_t *cfg, struct tplg_elem *elem);
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);