]> git.alsa-project.org Git - alsa-lib.git/commitdiff
topology: Add support for parsing vendor tuples
authorMengdong Lin <mengdong.lin@linux.intel.com>
Thu, 7 Apr 2016 07:29:43 +0000 (15:29 +0800)
committerTakashi Iwai <tiwai@suse.de>
Thu, 7 Apr 2016 14:57:22 +0000 (16:57 +0200)
Vendor can define several tuple arrays in 'SectionVendorTuples', as
well as the reference to a vendor token list object.

A later patche will copy vendor tuples in ABI format to the private
buffer of its parent data object in the building phase.

Signed-off-by: Mengdong Lin <mengdong.lin@linux.intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
include/topology.h
src/topology/data.c
src/topology/elem.c
src/topology/parser.c
src/topology/tplg_local.h

index 0df112cc4a4d295866b6d185d3d3f75eaaa83f49..b47f422ddc90dae60cb5845ffce787666004053a 100644 (file)
@@ -579,6 +579,7 @@ enum snd_tplg_type {
        SND_TPLG_TYPE_CC,               /*!< Hostless codec <-> codec link */
        SND_TPLG_TYPE_MANIFEST,         /*!< Topology manifest */
        SND_TPLG_TYPE_TOKEN,            /*!< Vendor tokens */
+       SND_TPLG_TYPE_TUPLE,            /*!< Vendor tuples */
 };
 
 /**
index 8455c15abf095fdf9bd5c69edada69e01a7a31d9..606fcd3ef5e8d84a40ad368075fd18ec31e8120c 100644 (file)
@@ -253,6 +253,175 @@ static int tplg_parse_data_hex(snd_config_t *cfg, struct tplg_elem *elem,
        return ret;
 }
 
+static int parse_tuple_set(snd_tplg_t *tplg, snd_config_t *cfg,
+       struct tplg_tuple_set **s)
+{
+       snd_config_iterator_t i, next;
+       snd_config_t *n;
+       const char *id, *value;
+       struct tplg_tuple_set *set;
+       unsigned int type, num_tuples = 0;
+       struct tplg_tuple *tuple;
+       unsigned long int tuple_val;
+       int len;
+
+       snd_config_get_id(cfg, &id);
+
+       if (strcmp(id, "uuid") == 0)
+               type = SND_SOC_TPLG_TUPLE_TYPE_UUID;
+       else if (strcmp(id, "string") == 0)
+               type = SND_SOC_TPLG_TUPLE_TYPE_STRING;
+       else if (strcmp(id, "bool") == 0)
+               type = SND_SOC_TPLG_TUPLE_TYPE_BOOL;
+       else if (strcmp(id, "byte") == 0)
+               type = SND_SOC_TPLG_TUPLE_TYPE_BYTE;
+       else if (strcmp(id, "short") == 0)
+               type = SND_SOC_TPLG_TUPLE_TYPE_SHORT;
+       else if (strcmp(id, "word") == 0)
+               type = SND_SOC_TPLG_TUPLE_TYPE_WORD;
+       else {
+               SNDERR("error: invalid tuple type '%s'\n", id);
+               return -EINVAL;
+       }
+
+       snd_config_for_each(i, next, cfg)
+               num_tuples++;
+       if (!num_tuples)
+               return 0;
+
+       tplg_dbg("\t %d %s tuples:\n", num_tuples, id);
+       set = calloc(1, sizeof(*set) + num_tuples * sizeof(struct tplg_tuple));
+       if (!set)
+               return -ENOMEM;
+
+       set->type = type;
+
+       snd_config_for_each(i, next, cfg) {
+
+               n = snd_config_iterator_entry(i);
+
+               /* get id */
+               if (snd_config_get_id(n, &id) < 0)
+                       continue;
+
+               /* get value */
+               if (snd_config_get_string(n, &value) < 0)
+                       continue;
+
+               tuple = &set->tuple[set->num_tuples];
+               elem_copy_text(tuple->token, id,
+                               SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
+
+               switch (type) {
+               case SND_SOC_TPLG_TUPLE_TYPE_UUID:
+                       len = strlen(value);
+                       if (len > 16 || len == 0) {
+                               SNDERR("error: tuple %s: invalid uuid\n", id);
+                               goto err;
+                       }
+
+                       memcpy(tuple->uuid, value, len);
+                       tplg_dbg("\t\t%s = %s\n", tuple->token, tuple->uuid);
+                       break;
+
+               case SND_SOC_TPLG_TUPLE_TYPE_STRING:
+                       elem_copy_text(tuple->string, value,
+                               SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
+                       tplg_dbg("\t\t%s = %s\n", tuple->token, tuple->string);
+                       break;
+
+               case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
+                       if (strcmp(value, "true") == 0)
+                               tuple->value = 1;
+                       tplg_dbg("\t\t%s = %d\n", tuple->token, tuple->value);
+                       break;
+
+               case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
+               case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
+               case SND_SOC_TPLG_TUPLE_TYPE_WORD:
+                       errno = 0;
+                       /* no support for negative value */
+                       tuple_val = strtoul(value, NULL, 0);
+                       if ((errno == ERANGE && tuple_val == ULONG_MAX)
+                               || (errno != 0 && tuple_val == 0)) {
+                               SNDERR("error: tuple %s:strtoul fail\n", id);
+                               goto err;
+                       }
+
+                       if ((type == SND_SOC_TPLG_TUPLE_TYPE_WORD
+                                       && tuple_val > UINT_MAX)
+                               || (type == SND_SOC_TPLG_TUPLE_TYPE_SHORT
+                                       && tuple_val > USHRT_MAX)
+                               || (type == SND_SOC_TPLG_TUPLE_TYPE_BYTE
+                                       && tuple_val > UCHAR_MAX)) {
+                               SNDERR("error: tuple %s: invalid value\n", id);
+                               goto err;
+                       }
+
+                       tuple->value = (unsigned int) tuple_val;
+                       tplg_dbg("\t\t%s = 0x%x\n", tuple->token, tuple->value);
+                       break;
+
+               default:
+                       break;
+               }
+
+               set->num_tuples++;
+       }
+
+       *s = set;
+       return 0;
+
+err:
+       free(set);
+       return -EINVAL;
+}
+
+static int parse_tuple_sets(snd_tplg_t *tplg, snd_config_t *cfg,
+       struct tplg_vendor_tuples *tuples)
+{
+       snd_config_iterator_t i, next;
+       snd_config_t *n;
+       const char *id;
+       unsigned int num_tuple_sets = 0;
+       int err;
+
+       if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
+               SNDERR("error: compound type expected for %s", id);
+               return -EINVAL;
+       }
+
+       snd_config_for_each(i, next, cfg) {
+               num_tuple_sets++;
+       }
+
+       if (!num_tuple_sets)
+               return 0;
+
+       tuples->set = calloc(1, num_tuple_sets * sizeof(void *));
+       if (!tuples->set)
+               return -ENOMEM;
+
+       snd_config_for_each(i, next, cfg) {
+               n = snd_config_iterator_entry(i);
+               if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
+                       SNDERR("error: compound type expected for %s, is %d",
+                       id, snd_config_get_type(n));
+                       return -EINVAL;
+               }
+
+               err = parse_tuple_set(tplg, n, &tuples->set[tuples->num_sets]);
+               if (err < 0)
+                       return err;
+
+               /* overlook empty tuple sets */
+               if (tuples->set[tuples->num_sets])
+                       tuples->num_sets++;
+       }
+
+       return 0;
+}
+
 /* Parse vendor tokens
  */
 int tplg_parse_tokens(snd_tplg_t *tplg, snd_config_t *cfg,
@@ -304,10 +473,71 @@ int tplg_parse_tokens(snd_tplg_t *tplg, snd_config_t *cfg,
        return 0;
 }
 
+/* Parse vendor tuples.
+ */
+int tplg_parse_tuples(snd_tplg_t *tplg, snd_config_t *cfg,
+       void *private ATTRIBUTE_UNUSED)
+{
+       snd_config_iterator_t i, next;
+       snd_config_t *n;
+       const char *id, *value;
+       struct tplg_elem *elem;
+       struct tplg_vendor_tuples *tuples;
+       int err;
+
+       elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_TUPLE);
+       if (!elem)
+               return -ENOMEM;
+
+       tplg_dbg(" Vendor Tuples: %s\n", elem->id);
+
+       tuples = calloc(1, sizeof(*tuples));
+       if (!tuples)
+               return -ENOMEM;
+       elem->tuples = tuples;
+
+       snd_config_for_each(i, next, cfg) {
+
+               n = snd_config_iterator_entry(i);
+               if (snd_config_get_id(n, &id) < 0)
+                       continue;
+
+               if (strcmp(id, "tokens") == 0) {
+                       if (snd_config_get_string(n, &value) < 0)
+                               return -EINVAL;
+                       tplg_ref_add(elem, SND_TPLG_TYPE_TOKEN, value);
+                       tplg_dbg("\t refer to vendor tokens: %s\n", value);
+               }
+
+               if (strcmp(id, "tuples") == 0) {
+                       err = parse_tuple_sets(tplg, n, tuples);
+                       if (err < 0)
+                               return err;
+               }
+       }
+
+       return 0;
+}
+
+/* Free handler of tuples */
+void tplg_free_tuples(void *obj)
+{
+       struct tplg_vendor_tuples *tuples = (struct tplg_vendor_tuples *)obj;
+       int i;
+
+       if (!tuples || !tuples->set)
+               return;
+
+       for (i = 0; i < tuples->num_sets; i++)
+               free(tuples->set[i]);
+
+       free(tuples->set);
+}
+
 /* Parse Private data.
  *
  * Object private data can either be from file or defined as bytes, shorts,
- * words.
+ * words, tuples.
  */
 int tplg_parse_data(snd_tplg_t *tplg, snd_config_t *cfg,
        void *private ATTRIBUTE_UNUSED)
@@ -365,6 +595,14 @@ int tplg_parse_data(snd_tplg_t *tplg, snd_config_t *cfg,
                        continue;
                }
 
+               if (strcmp(id, "tuples") == 0) {
+                       if (snd_config_get_string(n, &val) < 0)
+                               return -EINVAL;
+                       tplg_dbg(" Data: %s\n", val);
+                       tplg_ref_add(elem, SND_TPLG_TYPE_TUPLE, val);
+                       continue;
+               }
+
                if (strcmp(id, "index") == 0) {
                        if (snd_config_get_string(n, &val) < 0)
                                return -EINVAL;
index 95e3fd44baf79cad5608a3d227e50c9ce207dd18..50414f0b6d1b6722f60961a62afa64cf7ea66c91 100644 (file)
@@ -196,6 +196,10 @@ struct tplg_elem* tplg_elem_new_common(snd_tplg_t *tplg,
        case SND_TPLG_TYPE_TOKEN:
                list_add_tail(&elem->list, &tplg->token_list);
                break;
+       case SND_TPLG_TYPE_TUPLE:
+               list_add_tail(&elem->list, &tplg->tuple_list);
+               elem->free = tplg_free_tuples;
+               break;
        default:
                free(elem);
                return NULL;
index 264abc81a792d0168a10fe845b1dd2c8b20bc945..0d967b4727234c5e00c242855b6d9a7e9118aeaf 100644 (file)
@@ -181,6 +181,14 @@ static int tplg_parse_config(snd_tplg_t *tplg, snd_config_t *cfg)
                        continue;
                }
 
+               if (strcmp(id, "SectionVendorTuples") == 0) {
+                       err = tplg_parse_compound(tplg, n, tplg_parse_tuples,
+                               NULL);
+                       if (err < 0)
+                               return err;
+                       continue;
+               }
+
                SNDERR("error: unknown section %s\n", id);
        }
        return 0;
@@ -416,6 +424,7 @@ snd_tplg_t *snd_tplg_new(void)
        INIT_LIST_HEAD(&tplg->enum_list);
        INIT_LIST_HEAD(&tplg->bytes_ext_list);
        INIT_LIST_HEAD(&tplg->token_list);
+       INIT_LIST_HEAD(&tplg->tuple_list);
 
        return tplg;
 }
@@ -436,6 +445,7 @@ void snd_tplg_free(snd_tplg_t *tplg)
        tplg_elem_free_list(&tplg->enum_list);
        tplg_elem_free_list(&tplg->bytes_ext_list);
        tplg_elem_free_list(&tplg->token_list);
+       tplg_elem_free_list(&tplg->tuple_list);
 
        free(tplg);
 }
index 679bfffdba780010fb58069e216b1246affd20dd..4d59a1ff6f0172801b83ed9906bf163510715c9c 100644 (file)
@@ -70,6 +70,7 @@ struct snd_tplg {
        struct list_head text_list;
        struct list_head pdata_list;
        struct list_head token_list;
+       struct list_head tuple_list;
        struct list_head pcm_config_list;
        struct list_head pcm_caps_list;
 
@@ -97,6 +98,28 @@ struct tplg_vendor_tokens {
        unsigned int num_tokens;
        struct tplg_token token[0];
 };
+
+/* element for vendor tuples */
+struct tplg_tuple {
+       char token[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       union {
+               char string[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+               char uuid[16];
+               unsigned int value;
+       };
+};
+
+struct tplg_tuple_set {
+       unsigned int  type; /* uuid, bool, byte, short, word, string*/
+       unsigned int  num_tuples;
+       struct tplg_tuple tuple[0];
+};
+
+struct tplg_vendor_tuples {
+       unsigned int  num_sets;
+       struct tplg_tuple_set **set;
+};
+
 /* topology element */
 struct tplg_elem {
 
@@ -130,6 +153,7 @@ struct tplg_elem {
                struct snd_soc_tplg_ctl_tlv *tlv;
                struct snd_soc_tplg_private *data;
                struct tplg_vendor_tokens *tokens;
+               struct tplg_vendor_tuples *tuples;
        };
 
        /* an element may refer to other elements:
@@ -166,6 +190,11 @@ int tplg_parse_data(snd_tplg_t *tplg, snd_config_t *cfg,
 int tplg_parse_tokens(snd_tplg_t *tplg, snd_config_t *cfg,
        void *private ATTRIBUTE_UNUSED);
 
+int tplg_parse_tuples(snd_tplg_t *tplg, snd_config_t *cfg,
+       void *private ATTRIBUTE_UNUSED);
+
+void tplg_free_tuples(void *obj);
+
 int tplg_parse_control_bytes(snd_tplg_t *tplg,
        snd_config_t *cfg, void *private ATTRIBUTE_UNUSED);