]> git.alsa-project.org Git - alsa-lib.git/commitdiff
topology: An element can refer to multipe data sections in text conf file
authorMengdong Lin <mengdong.lin@linux.intel.com>
Fri, 15 Jul 2016 12:17:43 +0000 (20:17 +0800)
committerTakashi Iwai <tiwai@suse.de>
Sun, 17 Jul 2016 07:59:21 +0000 (09:59 +0200)
Previously in text conf file, an element can only refer to one data
section (SectionData). Now it can also refer to a list of data sections.
Thus users can split groups of firmware parameters to multiple data
sections, and put them all in the reference list.

Finally, data of these data sections will be merged, in the same order as
they are in the reference list, as the element's private data for kernel.

We still support the original syntax of reference to a single data
section. The doc is updated for the syntax extension.

Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com>
Reviewed-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
include/topology.h
src/topology/ctl.c
src/topology/dapm.c
src/topology/data.c
src/topology/tplg_local.h

index 9d57ce3b7b68aca12ba0827f053b0284fecfd5a2..d666505f17c5118c46ba393230961491a959cbf8 100644 (file)
@@ -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
index b948ac021ceecc116bc1087075743243e4b14055..7ded0a42ec1d63bda5a990e905eadc1adac58cbd 100644 (file)
@@ -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;
                }
 
index 278d6056ead70dcc45809fd402072028afd0fb9e..d8eb10c1196cac3cee1f7667528666c2231cbc72 100644 (file)
@@ -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;
                }
        }
index c0a098cd3b13b58b812d08d6faf7ea42b4559c58..0c5469a873183b76769a2e806564cb37b8ba6bb2 100644 (file)
 #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;
 }
 
index 9239aef8fa30025ba054e9f0a5b29c7c4fbbd5b6..4daa540775201d5cd6f11e12df866457a9270107 100644 (file)
@@ -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);