return ret;
}
+/* get the token integer value from its id */
+static int get_token_value(const char *token_id,
+ struct tplg_vendor_tokens *tokens)
+{
+ int i;
+
+ for (i = 0; i < tokens->num_tokens; i++) {
+ if (strcmp(token_id, tokens->token[i].id) == 0)
+ return tokens->token[i].value;
+ }
+
+ SNDERR("error: cannot find token id '%s'\n", token_id);
+ return -1;
+}
+
+/* get the vendor tokens referred by the vendor tuples */
+static struct tplg_elem *get_tokens(snd_tplg_t *tplg, struct tplg_elem *elem)
+{
+ struct tplg_ref *ref;
+ struct list_head *base, *pos;
+ int err = 0;
+
+ base = &elem->ref_list;
+ list_for_each(pos, base) {
+
+ ref = list_entry(pos, struct tplg_ref, list);
+
+ if (!ref->id || ref->type != SND_TPLG_TYPE_TOKEN)
+ continue;
+
+ if (!ref->elem) {
+ ref->elem = tplg_elem_lookup(&tplg->token_list,
+ ref->id, SND_TPLG_TYPE_TOKEN);
+ }
+
+ return ref->elem;
+ }
+
+ return NULL;
+}
+
+/* check if a data element has tuples */
+static bool has_tuples(struct tplg_elem *elem)
+{
+ struct tplg_ref *ref;
+ struct list_head *base, *pos;
+ int err = 0;
+
+ base = &elem->ref_list;
+ list_for_each(pos, base) {
+
+ ref = list_entry(pos, struct tplg_ref, list);
+ if (ref->id && ref->type == SND_TPLG_TYPE_TUPLE)
+ return true;
+ }
+
+ return false;
+}
+
+/* get size of a tuple element from its type */
+static unsigned int get_tuple_size(int type)
+{
+ switch (type) {
+
+ case SND_SOC_TPLG_TUPLE_TYPE_UUID:
+ return sizeof(struct snd_soc_tplg_vendor_uuid_elem);
+
+ case SND_SOC_TPLG_TUPLE_TYPE_STRING:
+ return sizeof(struct snd_soc_tplg_vendor_string_elem);
+
+ default:
+ return sizeof(struct snd_soc_tplg_vendor_value_elem);
+ }
+}
+
+/* fill a data element's private buffer with its tuples */
+static int copy_tuples(struct tplg_elem *elem,
+ struct tplg_vendor_tuples *tuples, struct tplg_vendor_tokens *tokens)
+{
+ struct snd_soc_tplg_private *priv = elem->data;
+ struct tplg_tuple_set *tuple_set;
+ struct tplg_tuple *tuple;
+ struct snd_soc_tplg_vendor_array *array;
+ struct snd_soc_tplg_vendor_uuid_elem *uuid;
+ struct snd_soc_tplg_vendor_string_elem *string;
+ struct snd_soc_tplg_vendor_value_elem *value;
+ int set_size, size, off;
+ int i, j, token_val;
+
+ if (priv) {
+ SNDERR("error: %s has more data than tuples\n", elem->id);
+ return -EINVAL;
+ }
+
+ size = 0;
+ for (i = 0; i < tuples->num_sets ; i++) {
+ tuple_set = tuples->set[i];
+ set_size = sizeof(struct snd_soc_tplg_vendor_array)
+ + get_tuple_size(tuple_set->type)
+ * tuple_set->num_tuples;
+ size += set_size;
+ if (size > TPLG_MAX_PRIV_SIZE) {
+ SNDERR("error: data too big %d\n", size);
+ return -EINVAL;
+ }
+
+ if (priv != NULL)
+ priv = realloc(priv, sizeof(*priv) + size);
+ else
+ priv = calloc(1, sizeof(*priv) + size);
+ if (!priv)
+ return -ENOMEM;
+
+ off = priv->size;
+ priv->size = size;
+
+ array = (struct snd_soc_tplg_vendor_array *)(priv->data + off);
+ array->size = set_size;
+ array->type = tuple_set->type;
+ array->num_elems = tuple_set->num_tuples;
+
+ /* fill the private data buffer */
+ for (j = 0; j < tuple_set->num_tuples; j++) {
+ tuple = &tuple_set->tuple[j];
+ token_val = get_token_value(tuple->token, tokens);
+ if (token_val < 0)
+ return -EINVAL;
+
+ switch (tuple_set->type) {
+ case SND_SOC_TPLG_TUPLE_TYPE_UUID:
+ uuid = &array->uuid[j];
+ uuid->token = token_val;
+ memcpy(uuid->uuid, tuple->uuid, 16);
+ break;
+
+ case SND_SOC_TPLG_TUPLE_TYPE_STRING:
+ string = &array->string[j];
+ string->token = token_val;
+ elem_copy_text(string->string, tuple->string,
+ SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
+ break;
+
+ default:
+ value = &array->value[j];
+ value->token = token_val;
+ value->value = tuple->value;
+ break;
+ }
+ }
+ }
+
+ elem->data = priv;
+ return 0;
+}
+
+/* build a data element from its tuples */
+static int build_tuples(snd_tplg_t *tplg, struct tplg_elem *elem)
+{
+ struct tplg_ref *ref;
+ struct list_head *base, *pos;
+ struct tplg_elem *tuples, *tokens;
+
+ base = &elem->ref_list;
+ list_for_each(pos, base) {
+
+ ref = list_entry(pos, struct tplg_ref, list);
+
+ if (!ref->id || ref->type != SND_TPLG_TYPE_TUPLE)
+ continue;
+
+ tplg_dbg("look up tuples %s\n", ref->id);
+
+ if (!ref->elem)
+ ref->elem = tplg_elem_lookup(&tplg->tuple_list,
+ ref->id, SND_TPLG_TYPE_TUPLE);
+ tuples = ref->elem;
+ if (!tuples)
+ return -EINVAL;
+
+ tplg_dbg("found tuples %s\n", tuples->id);
+ tokens = get_tokens(tplg, tuples);
+ if (!tokens)
+ return -EINVAL;
+
+ tplg_dbg("found tokens %s\n", tokens->id);
+ /* a data object can only have one tuples object */
+ return copy_tuples(elem, tuples->tuples, tokens->tokens);
+ }
+
+ return 0;
+}
+
static int parse_tuple_set(snd_tplg_t *tplg, snd_config_t *cfg,
struct tplg_tuple_set **s)
{
memcpy(priv->data, ref->data->data, priv_data_size);
return 0;
}
+
+/* check data objects and build those with tuples */
+int tplg_build_data(snd_tplg_t *tplg)
+{
+ struct list_head *base, *pos;
+ struct tplg_elem *elem;
+ int err = 0;
+
+ base = &tplg->pdata_list;
+ list_for_each(pos, base) {
+
+ elem = list_entry(pos, struct tplg_elem, list);
+ if (has_tuples(elem)) {
+ err = build_tuples(tplg, elem);
+ if (err < 0)
+ return err;
+ }
+ }
+
+ return 0;
+}