1d5ac70f0Sopenharmony_ci/*
2d5ac70f0Sopenharmony_ci  Copyright(c) 2014-2015 Intel Corporation
3d5ac70f0Sopenharmony_ci  All rights reserved.
4d5ac70f0Sopenharmony_ci
5d5ac70f0Sopenharmony_ci  This library is free software; you can redistribute it and/or modify
6d5ac70f0Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as
7d5ac70f0Sopenharmony_ci  published by the Free Software Foundation; either version 2.1 of
8d5ac70f0Sopenharmony_ci  the License, or (at your option) any later version.
9d5ac70f0Sopenharmony_ci
10d5ac70f0Sopenharmony_ci  This program is distributed in the hope that it will be useful,
11d5ac70f0Sopenharmony_ci  but WITHOUT ANY WARRANTY; without even the implied warranty of
12d5ac70f0Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13d5ac70f0Sopenharmony_ci  GNU Lesser General Public License for more details.
14d5ac70f0Sopenharmony_ci
15d5ac70f0Sopenharmony_ci  Authors: Mengdong Lin <mengdong.lin@intel.com>
16d5ac70f0Sopenharmony_ci           Yao Jin <yao.jin@intel.com>
17d5ac70f0Sopenharmony_ci           Liam Girdwood <liam.r.girdwood@linux.intel.com>
18d5ac70f0Sopenharmony_ci*/
19d5ac70f0Sopenharmony_ci
20d5ac70f0Sopenharmony_ci#include "tplg_local.h"
21d5ac70f0Sopenharmony_ci#include <ctype.h>
22d5ac70f0Sopenharmony_ci
23d5ac70f0Sopenharmony_ci#define UUID_FORMAT "\
24d5ac70f0Sopenharmony_ci%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:\
25d5ac70f0Sopenharmony_ci%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
26d5ac70f0Sopenharmony_ci
27d5ac70f0Sopenharmony_ci/* Get private data buffer of an element */
28d5ac70f0Sopenharmony_cistruct snd_soc_tplg_private *get_priv_data(struct tplg_elem *elem)
29d5ac70f0Sopenharmony_ci{
30d5ac70f0Sopenharmony_ci	struct snd_soc_tplg_private *priv = NULL;
31d5ac70f0Sopenharmony_ci
32d5ac70f0Sopenharmony_ci	switch (elem->type) {
33d5ac70f0Sopenharmony_ci	case SND_TPLG_TYPE_MANIFEST:
34d5ac70f0Sopenharmony_ci		priv = &elem->manifest->priv;
35d5ac70f0Sopenharmony_ci		break;
36d5ac70f0Sopenharmony_ci
37d5ac70f0Sopenharmony_ci	case SND_TPLG_TYPE_MIXER:
38d5ac70f0Sopenharmony_ci		priv = &elem->mixer_ctrl->priv;
39d5ac70f0Sopenharmony_ci		break;
40d5ac70f0Sopenharmony_ci
41d5ac70f0Sopenharmony_ci	case SND_TPLG_TYPE_ENUM:
42d5ac70f0Sopenharmony_ci		priv = &elem->enum_ctrl->priv;
43d5ac70f0Sopenharmony_ci		break;
44d5ac70f0Sopenharmony_ci
45d5ac70f0Sopenharmony_ci	case SND_TPLG_TYPE_BYTES:
46d5ac70f0Sopenharmony_ci		priv = &elem->bytes_ext->priv;
47d5ac70f0Sopenharmony_ci		break;
48d5ac70f0Sopenharmony_ci
49d5ac70f0Sopenharmony_ci	case SND_TPLG_TYPE_DAPM_WIDGET:
50d5ac70f0Sopenharmony_ci		priv = &elem->widget->priv;
51d5ac70f0Sopenharmony_ci		break;
52d5ac70f0Sopenharmony_ci
53d5ac70f0Sopenharmony_ci	case SND_TPLG_TYPE_DAI:
54d5ac70f0Sopenharmony_ci		priv = &elem->dai->priv;
55d5ac70f0Sopenharmony_ci		break;
56d5ac70f0Sopenharmony_ci	case SND_TPLG_TYPE_BE:
57d5ac70f0Sopenharmony_ci		priv = &elem->link->priv;
58d5ac70f0Sopenharmony_ci		break;
59d5ac70f0Sopenharmony_ci	case SND_TPLG_TYPE_PCM:
60d5ac70f0Sopenharmony_ci		priv = &elem->pcm->priv;
61d5ac70f0Sopenharmony_ci		break;
62d5ac70f0Sopenharmony_ci	default:
63d5ac70f0Sopenharmony_ci		SNDERR("'%s': no support for private data for type %d",
64d5ac70f0Sopenharmony_ci			elem->id, elem->type);
65d5ac70f0Sopenharmony_ci	}
66d5ac70f0Sopenharmony_ci
67d5ac70f0Sopenharmony_ci	return priv;
68d5ac70f0Sopenharmony_ci}
69d5ac70f0Sopenharmony_ci
70d5ac70f0Sopenharmony_ci/* Parse references for the element, either a single data section
71d5ac70f0Sopenharmony_ci * or a list of data sections.
72d5ac70f0Sopenharmony_ci */
73d5ac70f0Sopenharmony_ciint tplg_parse_refs(snd_config_t *cfg, struct tplg_elem *elem,
74d5ac70f0Sopenharmony_ci		    unsigned int type)
75d5ac70f0Sopenharmony_ci{
76d5ac70f0Sopenharmony_ci	snd_config_type_t cfg_type;
77d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
78d5ac70f0Sopenharmony_ci	snd_config_t *n;
79d5ac70f0Sopenharmony_ci	const char *val = NULL;
80d5ac70f0Sopenharmony_ci	int err, count;
81d5ac70f0Sopenharmony_ci
82d5ac70f0Sopenharmony_ci	cfg_type = snd_config_get_type(cfg);
83d5ac70f0Sopenharmony_ci
84d5ac70f0Sopenharmony_ci	/* refer to a single data section */
85d5ac70f0Sopenharmony_ci	if (cfg_type == SND_CONFIG_TYPE_STRING) {
86d5ac70f0Sopenharmony_ci		if (snd_config_get_string(cfg, &val) < 0)
87d5ac70f0Sopenharmony_ci			return -EINVAL;
88d5ac70f0Sopenharmony_ci
89d5ac70f0Sopenharmony_ci		tplg_dbg("\tref data: %s", val);
90d5ac70f0Sopenharmony_ci		err = tplg_ref_add(elem, type, val);
91d5ac70f0Sopenharmony_ci		if (err < 0)
92d5ac70f0Sopenharmony_ci			return err;
93d5ac70f0Sopenharmony_ci		return 1;
94d5ac70f0Sopenharmony_ci	}
95d5ac70f0Sopenharmony_ci
96d5ac70f0Sopenharmony_ci	if (cfg_type != SND_CONFIG_TYPE_COMPOUND) {
97d5ac70f0Sopenharmony_ci		SNDERR("compound type expected for %s", elem->id);
98d5ac70f0Sopenharmony_ci		return -EINVAL;
99d5ac70f0Sopenharmony_ci	}
100d5ac70f0Sopenharmony_ci
101d5ac70f0Sopenharmony_ci	/* refer to a list of data sections */
102d5ac70f0Sopenharmony_ci	count = 0;
103d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
104d5ac70f0Sopenharmony_ci		const char *val;
105d5ac70f0Sopenharmony_ci
106d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
107d5ac70f0Sopenharmony_ci		if (snd_config_get_string(n, &val) < 0)
108d5ac70f0Sopenharmony_ci			continue;
109d5ac70f0Sopenharmony_ci
110d5ac70f0Sopenharmony_ci		tplg_dbg("\tref data: %s", val);
111d5ac70f0Sopenharmony_ci		err = tplg_ref_add(elem, type, val);
112d5ac70f0Sopenharmony_ci		if (err < 0)
113d5ac70f0Sopenharmony_ci			return err;
114d5ac70f0Sopenharmony_ci		count++;
115d5ac70f0Sopenharmony_ci	}
116d5ac70f0Sopenharmony_ci
117d5ac70f0Sopenharmony_ci	return count;
118d5ac70f0Sopenharmony_ci}
119d5ac70f0Sopenharmony_ci
120d5ac70f0Sopenharmony_ci/* save references */
121d5ac70f0Sopenharmony_ciint tplg_save_refs(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
122d5ac70f0Sopenharmony_ci		   struct tplg_elem *elem, unsigned int type,
123d5ac70f0Sopenharmony_ci		   const char *id, struct tplg_buf *dst,
124d5ac70f0Sopenharmony_ci		   const char *pfx)
125d5ac70f0Sopenharmony_ci{
126d5ac70f0Sopenharmony_ci	struct tplg_ref *ref, *last;
127d5ac70f0Sopenharmony_ci	struct list_head *pos;
128d5ac70f0Sopenharmony_ci	int err, count;
129d5ac70f0Sopenharmony_ci
130d5ac70f0Sopenharmony_ci	count = 0;
131d5ac70f0Sopenharmony_ci	last = NULL;
132d5ac70f0Sopenharmony_ci	list_for_each(pos, &elem->ref_list) {
133d5ac70f0Sopenharmony_ci		ref = list_entry(pos, struct tplg_ref, list);
134d5ac70f0Sopenharmony_ci		if (ref->type == type) {
135d5ac70f0Sopenharmony_ci			last = ref;
136d5ac70f0Sopenharmony_ci			count++;
137d5ac70f0Sopenharmony_ci		}
138d5ac70f0Sopenharmony_ci	}
139d5ac70f0Sopenharmony_ci
140d5ac70f0Sopenharmony_ci	if (count == 0)
141d5ac70f0Sopenharmony_ci		return 0;
142d5ac70f0Sopenharmony_ci
143d5ac70f0Sopenharmony_ci	if (count == 1)
144d5ac70f0Sopenharmony_ci		return tplg_save_printf(dst, pfx, "%s '%s'\n", id, last->id);
145d5ac70f0Sopenharmony_ci
146d5ac70f0Sopenharmony_ci	err = tplg_save_printf(dst, pfx, "%s [\n", id);
147d5ac70f0Sopenharmony_ci	if (err < 0)
148d5ac70f0Sopenharmony_ci		return err;
149d5ac70f0Sopenharmony_ci	list_for_each(pos, &elem->ref_list) {
150d5ac70f0Sopenharmony_ci		ref = list_entry(pos, struct tplg_ref, list);
151d5ac70f0Sopenharmony_ci		if (ref->type == type) {
152d5ac70f0Sopenharmony_ci			err = tplg_save_printf(dst, pfx, "\t'%s'\n", ref->id);
153d5ac70f0Sopenharmony_ci			if (err < 0)
154d5ac70f0Sopenharmony_ci				return err;
155d5ac70f0Sopenharmony_ci		}
156d5ac70f0Sopenharmony_ci	}
157d5ac70f0Sopenharmony_ci
158d5ac70f0Sopenharmony_ci	return tplg_save_printf(dst, pfx, "]\n");
159d5ac70f0Sopenharmony_ci}
160d5ac70f0Sopenharmony_ci
161d5ac70f0Sopenharmony_ci/* Get Private data from a file. */
162d5ac70f0Sopenharmony_cistatic int tplg_parse_data_file(snd_config_t *cfg, struct tplg_elem *elem)
163d5ac70f0Sopenharmony_ci{
164d5ac70f0Sopenharmony_ci	struct snd_soc_tplg_private *priv = NULL;
165d5ac70f0Sopenharmony_ci	const char *value = NULL;
166d5ac70f0Sopenharmony_ci	char filename[PATH_MAX];
167d5ac70f0Sopenharmony_ci	char *env = getenv(ALSA_CONFIG_TPLG_VAR);
168d5ac70f0Sopenharmony_ci	FILE *fp;
169d5ac70f0Sopenharmony_ci	size_t size, bytes_read;
170d5ac70f0Sopenharmony_ci	int ret = 0;
171d5ac70f0Sopenharmony_ci
172d5ac70f0Sopenharmony_ci	tplg_dbg("data DataFile: %s", elem->id);
173d5ac70f0Sopenharmony_ci
174d5ac70f0Sopenharmony_ci	if (snd_config_get_string(cfg, &value) < 0)
175d5ac70f0Sopenharmony_ci		return -EINVAL;
176d5ac70f0Sopenharmony_ci
177d5ac70f0Sopenharmony_ci	/* prepend alsa config directory to path */
178d5ac70f0Sopenharmony_ci	if (env)
179d5ac70f0Sopenharmony_ci		snprintf(filename, sizeof(filename), "%s/%s", env, value);
180d5ac70f0Sopenharmony_ci	else
181d5ac70f0Sopenharmony_ci		snprintf(filename, sizeof(filename), "%s/topology/%s",
182d5ac70f0Sopenharmony_ci			 snd_config_topdir(), value);
183d5ac70f0Sopenharmony_ci
184d5ac70f0Sopenharmony_ci	fp = fopen(filename, "r");
185d5ac70f0Sopenharmony_ci	if (fp == NULL) {
186d5ac70f0Sopenharmony_ci		SNDERR("invalid data file path '%s'", filename);
187d5ac70f0Sopenharmony_ci		return -errno;
188d5ac70f0Sopenharmony_ci	}
189d5ac70f0Sopenharmony_ci
190d5ac70f0Sopenharmony_ci	fseek(fp, 0L, SEEK_END);
191d5ac70f0Sopenharmony_ci	size = ftell(fp);
192d5ac70f0Sopenharmony_ci	fseek(fp, 0L, SEEK_SET);
193d5ac70f0Sopenharmony_ci	if (size <= 0) {
194d5ac70f0Sopenharmony_ci		SNDERR("invalid data file size %zu", size);
195d5ac70f0Sopenharmony_ci		ret = -EINVAL;
196d5ac70f0Sopenharmony_ci		goto err;
197d5ac70f0Sopenharmony_ci	}
198d5ac70f0Sopenharmony_ci	if (size > TPLG_MAX_PRIV_SIZE) {
199d5ac70f0Sopenharmony_ci		SNDERR("data file too big %zu", size);
200d5ac70f0Sopenharmony_ci		ret = -EINVAL;
201d5ac70f0Sopenharmony_ci		goto err;
202d5ac70f0Sopenharmony_ci	}
203d5ac70f0Sopenharmony_ci
204d5ac70f0Sopenharmony_ci	priv = calloc(1, sizeof(*priv) + size);
205d5ac70f0Sopenharmony_ci	if (!priv) {
206d5ac70f0Sopenharmony_ci		ret = -ENOMEM;
207d5ac70f0Sopenharmony_ci		goto err;
208d5ac70f0Sopenharmony_ci	}
209d5ac70f0Sopenharmony_ci
210d5ac70f0Sopenharmony_ci	bytes_read = fread(&priv->data, 1, size, fp);
211d5ac70f0Sopenharmony_ci	if (bytes_read != size) {
212d5ac70f0Sopenharmony_ci		ret = -errno;
213d5ac70f0Sopenharmony_ci		goto err;
214d5ac70f0Sopenharmony_ci	}
215d5ac70f0Sopenharmony_ci
216d5ac70f0Sopenharmony_ci	elem->data = priv;
217d5ac70f0Sopenharmony_ci	priv->size = size;
218d5ac70f0Sopenharmony_ci	elem->size = sizeof(*priv) + size;
219d5ac70f0Sopenharmony_ci
220d5ac70f0Sopenharmony_ci	if (fclose(fp) == EOF) {
221d5ac70f0Sopenharmony_ci		SNDERR("Cannot close data file.");
222d5ac70f0Sopenharmony_ci		return -errno;
223d5ac70f0Sopenharmony_ci	}
224d5ac70f0Sopenharmony_ci	return 0;
225d5ac70f0Sopenharmony_ci
226d5ac70f0Sopenharmony_cierr:
227d5ac70f0Sopenharmony_ci	fclose(fp);
228d5ac70f0Sopenharmony_ci	if (priv)
229d5ac70f0Sopenharmony_ci		free(priv);
230d5ac70f0Sopenharmony_ci	return ret;
231d5ac70f0Sopenharmony_ci}
232d5ac70f0Sopenharmony_ci
233d5ac70f0Sopenharmony_cistatic void dump_priv_data(struct tplg_elem *elem ATTRIBUTE_UNUSED)
234d5ac70f0Sopenharmony_ci{
235d5ac70f0Sopenharmony_ci#ifdef TPLG_DEBUG
236d5ac70f0Sopenharmony_ci	struct snd_soc_tplg_private *priv = elem->data;
237d5ac70f0Sopenharmony_ci	unsigned char *p = (unsigned char *)priv->data;
238d5ac70f0Sopenharmony_ci	char buf[128], buf2[8];
239d5ac70f0Sopenharmony_ci	unsigned int i;
240d5ac70f0Sopenharmony_ci
241d5ac70f0Sopenharmony_ci	tplg_dbg(" elem size = %d, priv data size = %d",
242d5ac70f0Sopenharmony_ci		elem->size, priv->size);
243d5ac70f0Sopenharmony_ci
244d5ac70f0Sopenharmony_ci	buf[0] = '\0';
245d5ac70f0Sopenharmony_ci	for (i = 0; i < priv->size; i++) {
246d5ac70f0Sopenharmony_ci		if (i > 0 && (i % 16) == 0) {
247d5ac70f0Sopenharmony_ci			tplg_dbg("%s", buf);
248d5ac70f0Sopenharmony_ci			buf[0] = '\0';
249d5ac70f0Sopenharmony_ci		}
250d5ac70f0Sopenharmony_ci
251d5ac70f0Sopenharmony_ci		snprintf(buf2, sizeof(buf2), " %02x", *p++);
252d5ac70f0Sopenharmony_ci		strcat(buf, buf2);
253d5ac70f0Sopenharmony_ci	}
254d5ac70f0Sopenharmony_ci
255d5ac70f0Sopenharmony_ci	if (buf[0])
256d5ac70f0Sopenharmony_ci		tplg_dbg("%s", buf);
257d5ac70f0Sopenharmony_ci#endif
258d5ac70f0Sopenharmony_ci}
259d5ac70f0Sopenharmony_ci
260d5ac70f0Sopenharmony_cistatic inline int check_nibble(unsigned char c)
261d5ac70f0Sopenharmony_ci{
262d5ac70f0Sopenharmony_ci	return (c >= '0' && c <= '9') ||
263d5ac70f0Sopenharmony_ci	       (c >= 'a' && c <= 'f') ||
264d5ac70f0Sopenharmony_ci	       (c >= 'A' && c <= 'F');
265d5ac70f0Sopenharmony_ci}
266d5ac70f0Sopenharmony_ci
267d5ac70f0Sopenharmony_ci/* get number of hex value elements in CSV list */
268d5ac70f0Sopenharmony_cistatic int get_hex_num(const char *str)
269d5ac70f0Sopenharmony_ci{
270d5ac70f0Sopenharmony_ci	int delims, values, len = strlen(str);
271d5ac70f0Sopenharmony_ci	const char *s, *end = str + len;
272d5ac70f0Sopenharmony_ci
273d5ac70f0Sopenharmony_ci	/* check "aa:bb:00" syntax */
274d5ac70f0Sopenharmony_ci	s = str;
275d5ac70f0Sopenharmony_ci	delims = values = 0;
276d5ac70f0Sopenharmony_ci	while (s < end) {
277d5ac70f0Sopenharmony_ci		/* skip white space */
278d5ac70f0Sopenharmony_ci		if (isspace(*s)) {
279d5ac70f0Sopenharmony_ci			s++;
280d5ac70f0Sopenharmony_ci			continue;
281d5ac70f0Sopenharmony_ci		}
282d5ac70f0Sopenharmony_ci		/* find delimeters */
283d5ac70f0Sopenharmony_ci		if (*s == ':') {
284d5ac70f0Sopenharmony_ci			delims++;
285d5ac70f0Sopenharmony_ci			s++;
286d5ac70f0Sopenharmony_ci			continue;
287d5ac70f0Sopenharmony_ci		}
288d5ac70f0Sopenharmony_ci		/* check 00 hexadecimal value */
289d5ac70f0Sopenharmony_ci		if (s + 1 <= end) {
290d5ac70f0Sopenharmony_ci			if (check_nibble(s[0]) && check_nibble(s[1])) {
291d5ac70f0Sopenharmony_ci				values++;
292d5ac70f0Sopenharmony_ci			} else {
293d5ac70f0Sopenharmony_ci				goto format2;
294d5ac70f0Sopenharmony_ci			}
295d5ac70f0Sopenharmony_ci			s++;
296d5ac70f0Sopenharmony_ci		}
297d5ac70f0Sopenharmony_ci		s++;
298d5ac70f0Sopenharmony_ci	}
299d5ac70f0Sopenharmony_ci	goto end;
300d5ac70f0Sopenharmony_ci
301d5ac70f0Sopenharmony_ciformat2:
302d5ac70f0Sopenharmony_ci	/* we expect "0x0, 0x0, 0x0" */
303d5ac70f0Sopenharmony_ci	s = str;
304d5ac70f0Sopenharmony_ci	delims = values = 0;
305d5ac70f0Sopenharmony_ci	while (s < end) {
306d5ac70f0Sopenharmony_ci
307d5ac70f0Sopenharmony_ci		/* skip white space */
308d5ac70f0Sopenharmony_ci		if (isspace(*s)) {
309d5ac70f0Sopenharmony_ci			s++;
310d5ac70f0Sopenharmony_ci			continue;
311d5ac70f0Sopenharmony_ci		}
312d5ac70f0Sopenharmony_ci
313d5ac70f0Sopenharmony_ci		/* find delimeters */
314d5ac70f0Sopenharmony_ci		if (*s == ',') {
315d5ac70f0Sopenharmony_ci			delims++;
316d5ac70f0Sopenharmony_ci			s++;
317d5ac70f0Sopenharmony_ci			continue;
318d5ac70f0Sopenharmony_ci		}
319d5ac70f0Sopenharmony_ci
320d5ac70f0Sopenharmony_ci		/* find 0x[0-9] values */
321d5ac70f0Sopenharmony_ci		if (*s == '0' && s + 2 <= end) {
322d5ac70f0Sopenharmony_ci			if (s[1] == 'x' && check_nibble(s[2])) {
323d5ac70f0Sopenharmony_ci				if (check_nibble(s[3]))
324d5ac70f0Sopenharmony_ci					s++;
325d5ac70f0Sopenharmony_ci				values++;
326d5ac70f0Sopenharmony_ci				s += 2;
327d5ac70f0Sopenharmony_ci			}
328d5ac70f0Sopenharmony_ci		}
329d5ac70f0Sopenharmony_ci
330d5ac70f0Sopenharmony_ci		s++;
331d5ac70f0Sopenharmony_ci	}
332d5ac70f0Sopenharmony_ci
333d5ac70f0Sopenharmony_ciend:
334d5ac70f0Sopenharmony_ci	/* there should always be one less comma than value */
335d5ac70f0Sopenharmony_ci	if (values - 1 != delims)
336d5ac70f0Sopenharmony_ci		return -EINVAL;
337d5ac70f0Sopenharmony_ci
338d5ac70f0Sopenharmony_ci	return values;
339d5ac70f0Sopenharmony_ci}
340d5ac70f0Sopenharmony_ci
341d5ac70f0Sopenharmony_ci/* get uuid from a string made by 16 characters separated by commas */
342d5ac70f0Sopenharmony_cistatic int get_uuid(const char *str, unsigned char *uuid_le)
343d5ac70f0Sopenharmony_ci{
344d5ac70f0Sopenharmony_ci	unsigned long int  val;
345d5ac70f0Sopenharmony_ci	char *tmp, *s = NULL;
346d5ac70f0Sopenharmony_ci	int values = 0, ret = 0;
347d5ac70f0Sopenharmony_ci
348d5ac70f0Sopenharmony_ci	tmp = strdup(str);
349d5ac70f0Sopenharmony_ci	if (tmp == NULL)
350d5ac70f0Sopenharmony_ci		return -ENOMEM;
351d5ac70f0Sopenharmony_ci
352d5ac70f0Sopenharmony_ci	if (strchr(tmp, ':') == NULL)
353d5ac70f0Sopenharmony_ci		goto data2;
354d5ac70f0Sopenharmony_ci
355d5ac70f0Sopenharmony_ci	s = strtok(tmp, ":");
356d5ac70f0Sopenharmony_ci	while (s != NULL) {
357d5ac70f0Sopenharmony_ci		errno = 0;
358d5ac70f0Sopenharmony_ci		val = strtoul(s, NULL, 16);
359d5ac70f0Sopenharmony_ci		if ((errno == ERANGE && val == ULONG_MAX)
360d5ac70f0Sopenharmony_ci			|| (errno != 0 && val == 0)
361d5ac70f0Sopenharmony_ci			|| (val > UCHAR_MAX)) {
362d5ac70f0Sopenharmony_ci			SNDERR("invalid value for uuid");
363d5ac70f0Sopenharmony_ci			ret = -EINVAL;
364d5ac70f0Sopenharmony_ci			goto out;
365d5ac70f0Sopenharmony_ci		}
366d5ac70f0Sopenharmony_ci
367d5ac70f0Sopenharmony_ci		*(uuid_le + values) = (unsigned char)val;
368d5ac70f0Sopenharmony_ci
369d5ac70f0Sopenharmony_ci		values++;
370d5ac70f0Sopenharmony_ci		if (values >= 16)
371d5ac70f0Sopenharmony_ci			break;
372d5ac70f0Sopenharmony_ci
373d5ac70f0Sopenharmony_ci		s = strtok(NULL, ":");
374d5ac70f0Sopenharmony_ci	}
375d5ac70f0Sopenharmony_ci	goto out;
376d5ac70f0Sopenharmony_ci
377d5ac70f0Sopenharmony_cidata2:
378d5ac70f0Sopenharmony_ci	s = strtok(tmp, ",");
379d5ac70f0Sopenharmony_ci
380d5ac70f0Sopenharmony_ci	while (s != NULL) {
381d5ac70f0Sopenharmony_ci		errno = 0;
382d5ac70f0Sopenharmony_ci		val = strtoul(s, NULL, 0);
383d5ac70f0Sopenharmony_ci		if ((errno == ERANGE && val == ULONG_MAX)
384d5ac70f0Sopenharmony_ci			|| (errno != 0 && val == 0)
385d5ac70f0Sopenharmony_ci			|| (val > UCHAR_MAX)) {
386d5ac70f0Sopenharmony_ci			SNDERR("invalid value for uuid");
387d5ac70f0Sopenharmony_ci			ret = -EINVAL;
388d5ac70f0Sopenharmony_ci			goto out;
389d5ac70f0Sopenharmony_ci		}
390d5ac70f0Sopenharmony_ci
391d5ac70f0Sopenharmony_ci		*(uuid_le + values) = (unsigned char)val;
392d5ac70f0Sopenharmony_ci
393d5ac70f0Sopenharmony_ci		values++;
394d5ac70f0Sopenharmony_ci		if (values >= 16)
395d5ac70f0Sopenharmony_ci			break;
396d5ac70f0Sopenharmony_ci
397d5ac70f0Sopenharmony_ci		s = strtok(NULL, ",");
398d5ac70f0Sopenharmony_ci	}
399d5ac70f0Sopenharmony_ci
400d5ac70f0Sopenharmony_ci	if (values < 16) {
401d5ac70f0Sopenharmony_ci		SNDERR("less than 16 integers for uuid");
402d5ac70f0Sopenharmony_ci		ret = -EINVAL;
403d5ac70f0Sopenharmony_ci	}
404d5ac70f0Sopenharmony_ci
405d5ac70f0Sopenharmony_ciout:
406d5ac70f0Sopenharmony_ci	free(tmp);
407d5ac70f0Sopenharmony_ci	return ret;
408d5ac70f0Sopenharmony_ci}
409d5ac70f0Sopenharmony_ci
410d5ac70f0Sopenharmony_cistatic int write_hex(char *buf, char *str, int width)
411d5ac70f0Sopenharmony_ci{
412d5ac70f0Sopenharmony_ci	long val;
413d5ac70f0Sopenharmony_ci	void *p = &val;
414d5ac70f0Sopenharmony_ci
415d5ac70f0Sopenharmony_ci        errno = 0;
416d5ac70f0Sopenharmony_ci	if (safe_strtol_base(str, &val, 16) < 0)
417d5ac70f0Sopenharmony_ci		return -EINVAL;
418d5ac70f0Sopenharmony_ci
419d5ac70f0Sopenharmony_ci	switch (width) {
420d5ac70f0Sopenharmony_ci	case 1:
421d5ac70f0Sopenharmony_ci		*(unsigned char *)buf = *(unsigned char *)p;
422d5ac70f0Sopenharmony_ci		break;
423d5ac70f0Sopenharmony_ci	case 2:
424d5ac70f0Sopenharmony_ci		*(unsigned short *)buf = *(unsigned short *)p;
425d5ac70f0Sopenharmony_ci		break;
426d5ac70f0Sopenharmony_ci	case 4:
427d5ac70f0Sopenharmony_ci		*(unsigned int *)buf = *(unsigned int *)p;
428d5ac70f0Sopenharmony_ci		break;
429d5ac70f0Sopenharmony_ci	default:
430d5ac70f0Sopenharmony_ci		return -EINVAL;
431d5ac70f0Sopenharmony_ci	}
432d5ac70f0Sopenharmony_ci
433d5ac70f0Sopenharmony_ci	return 0;
434d5ac70f0Sopenharmony_ci}
435d5ac70f0Sopenharmony_ci
436d5ac70f0Sopenharmony_cistatic int copy_data_hex(char *data, int off, const char *str, int width)
437d5ac70f0Sopenharmony_ci{
438d5ac70f0Sopenharmony_ci	char *tmp, *s = NULL, *p = data;
439d5ac70f0Sopenharmony_ci	int ret;
440d5ac70f0Sopenharmony_ci
441d5ac70f0Sopenharmony_ci	tmp = strdup(str);
442d5ac70f0Sopenharmony_ci	if (tmp == NULL)
443d5ac70f0Sopenharmony_ci		return -ENOMEM;
444d5ac70f0Sopenharmony_ci
445d5ac70f0Sopenharmony_ci	p += off;
446d5ac70f0Sopenharmony_ci	s = strtok(tmp, ",:");
447d5ac70f0Sopenharmony_ci
448d5ac70f0Sopenharmony_ci	while (s != NULL) {
449d5ac70f0Sopenharmony_ci		ret = write_hex(p, s, width);
450d5ac70f0Sopenharmony_ci		if (ret < 0) {
451d5ac70f0Sopenharmony_ci			free(tmp);
452d5ac70f0Sopenharmony_ci			return ret;
453d5ac70f0Sopenharmony_ci		}
454d5ac70f0Sopenharmony_ci
455d5ac70f0Sopenharmony_ci		s = strtok(NULL, ",:");
456d5ac70f0Sopenharmony_ci		p += width;
457d5ac70f0Sopenharmony_ci	}
458d5ac70f0Sopenharmony_ci
459d5ac70f0Sopenharmony_ci	free(tmp);
460d5ac70f0Sopenharmony_ci	return 0;
461d5ac70f0Sopenharmony_ci}
462d5ac70f0Sopenharmony_ci
463d5ac70f0Sopenharmony_cistatic int tplg_parse_data_hex(snd_config_t *cfg, struct tplg_elem *elem,
464d5ac70f0Sopenharmony_ci	int width)
465d5ac70f0Sopenharmony_ci{
466d5ac70f0Sopenharmony_ci	struct snd_soc_tplg_private *priv;
467d5ac70f0Sopenharmony_ci	const char *value = NULL;
468d5ac70f0Sopenharmony_ci	int size, esize, off, num;
469d5ac70f0Sopenharmony_ci	int ret;
470d5ac70f0Sopenharmony_ci
471d5ac70f0Sopenharmony_ci	tplg_dbg(" data: %s", elem->id);
472d5ac70f0Sopenharmony_ci
473d5ac70f0Sopenharmony_ci	if (snd_config_get_string(cfg, &value) < 0)
474d5ac70f0Sopenharmony_ci		return -EINVAL;
475d5ac70f0Sopenharmony_ci
476d5ac70f0Sopenharmony_ci	num = get_hex_num(value);
477d5ac70f0Sopenharmony_ci	if (num <= 0) {
478d5ac70f0Sopenharmony_ci		SNDERR("malformed hex variable list %s", value);
479d5ac70f0Sopenharmony_ci		return -EINVAL;
480d5ac70f0Sopenharmony_ci	}
481d5ac70f0Sopenharmony_ci
482d5ac70f0Sopenharmony_ci	size = num * width;
483d5ac70f0Sopenharmony_ci	priv = elem->data;
484d5ac70f0Sopenharmony_ci
485d5ac70f0Sopenharmony_ci	if (size > TPLG_MAX_PRIV_SIZE) {
486d5ac70f0Sopenharmony_ci		SNDERR("data too big %d", size);
487d5ac70f0Sopenharmony_ci		return -EINVAL;
488d5ac70f0Sopenharmony_ci	}
489d5ac70f0Sopenharmony_ci
490d5ac70f0Sopenharmony_ci	if (priv != NULL) {
491d5ac70f0Sopenharmony_ci		off = priv->size;
492d5ac70f0Sopenharmony_ci		esize = elem->size + size;
493d5ac70f0Sopenharmony_ci		priv = realloc(priv, esize);
494d5ac70f0Sopenharmony_ci	} else {
495d5ac70f0Sopenharmony_ci		off = 0;
496d5ac70f0Sopenharmony_ci		esize = sizeof(*priv) + size;
497d5ac70f0Sopenharmony_ci		priv = calloc(1, esize);
498d5ac70f0Sopenharmony_ci	}
499d5ac70f0Sopenharmony_ci
500d5ac70f0Sopenharmony_ci	if (!priv)
501d5ac70f0Sopenharmony_ci		return -ENOMEM;
502d5ac70f0Sopenharmony_ci
503d5ac70f0Sopenharmony_ci	elem->data = priv;
504d5ac70f0Sopenharmony_ci	priv->size += size;
505d5ac70f0Sopenharmony_ci	elem->size = esize;
506d5ac70f0Sopenharmony_ci
507d5ac70f0Sopenharmony_ci	ret = copy_data_hex(priv->data, off, value, width);
508d5ac70f0Sopenharmony_ci
509d5ac70f0Sopenharmony_ci	dump_priv_data(elem);
510d5ac70f0Sopenharmony_ci	return ret;
511d5ac70f0Sopenharmony_ci}
512d5ac70f0Sopenharmony_ci
513d5ac70f0Sopenharmony_ci/* get the token integer value from its id */
514d5ac70f0Sopenharmony_cistatic int get_token_value(const char *token_id,
515d5ac70f0Sopenharmony_ci			   struct tplg_vendor_tokens *tokens)
516d5ac70f0Sopenharmony_ci{
517d5ac70f0Sopenharmony_ci	unsigned int i;
518d5ac70f0Sopenharmony_ci
519d5ac70f0Sopenharmony_ci	for (i = 0; i < tokens->num_tokens; i++) {
520d5ac70f0Sopenharmony_ci		if (strcmp(token_id, tokens->token[i].id) == 0)
521d5ac70f0Sopenharmony_ci			return tokens->token[i].value;
522d5ac70f0Sopenharmony_ci	}
523d5ac70f0Sopenharmony_ci
524d5ac70f0Sopenharmony_ci	SNDERR("cannot find token id '%s'", token_id);
525d5ac70f0Sopenharmony_ci	return -1;
526d5ac70f0Sopenharmony_ci}
527d5ac70f0Sopenharmony_ci
528d5ac70f0Sopenharmony_ci/* get the vendor tokens referred by the vendor tuples */
529d5ac70f0Sopenharmony_cistatic struct tplg_elem *get_tokens(snd_tplg_t *tplg, struct tplg_elem *elem)
530d5ac70f0Sopenharmony_ci{
531d5ac70f0Sopenharmony_ci	struct tplg_ref *ref;
532d5ac70f0Sopenharmony_ci	struct list_head *base, *pos;
533d5ac70f0Sopenharmony_ci
534d5ac70f0Sopenharmony_ci	base = &elem->ref_list;
535d5ac70f0Sopenharmony_ci	list_for_each(pos, base) {
536d5ac70f0Sopenharmony_ci
537d5ac70f0Sopenharmony_ci		ref = list_entry(pos, struct tplg_ref, list);
538d5ac70f0Sopenharmony_ci
539d5ac70f0Sopenharmony_ci		if (ref->type != SND_TPLG_TYPE_TOKEN)
540d5ac70f0Sopenharmony_ci			continue;
541d5ac70f0Sopenharmony_ci
542d5ac70f0Sopenharmony_ci		if (!ref->elem) {
543d5ac70f0Sopenharmony_ci			ref->elem = tplg_elem_lookup(&tplg->token_list,
544d5ac70f0Sopenharmony_ci				ref->id, SND_TPLG_TYPE_TOKEN, elem->index);
545d5ac70f0Sopenharmony_ci		}
546d5ac70f0Sopenharmony_ci
547d5ac70f0Sopenharmony_ci		return ref->elem;
548d5ac70f0Sopenharmony_ci	}
549d5ac70f0Sopenharmony_ci
550d5ac70f0Sopenharmony_ci	return NULL;
551d5ac70f0Sopenharmony_ci}
552d5ac70f0Sopenharmony_ci
553d5ac70f0Sopenharmony_ci/* check if a data element has tuples */
554d5ac70f0Sopenharmony_cistatic bool has_tuples(struct tplg_elem *elem)
555d5ac70f0Sopenharmony_ci{
556d5ac70f0Sopenharmony_ci	struct tplg_ref *ref;
557d5ac70f0Sopenharmony_ci	struct list_head *base, *pos;
558d5ac70f0Sopenharmony_ci
559d5ac70f0Sopenharmony_ci	base = &elem->ref_list;
560d5ac70f0Sopenharmony_ci	list_for_each(pos, base) {
561d5ac70f0Sopenharmony_ci
562d5ac70f0Sopenharmony_ci		ref = list_entry(pos, struct tplg_ref, list);
563d5ac70f0Sopenharmony_ci		if (ref->type == SND_TPLG_TYPE_TUPLE)
564d5ac70f0Sopenharmony_ci			return true;
565d5ac70f0Sopenharmony_ci	}
566d5ac70f0Sopenharmony_ci
567d5ac70f0Sopenharmony_ci	return false;
568d5ac70f0Sopenharmony_ci}
569d5ac70f0Sopenharmony_ci
570d5ac70f0Sopenharmony_ci/* get size of a tuple element from its type */
571d5ac70f0Sopenharmony_ciunsigned int tplg_get_tuple_size(int type)
572d5ac70f0Sopenharmony_ci{
573d5ac70f0Sopenharmony_ci	switch (type) {
574d5ac70f0Sopenharmony_ci
575d5ac70f0Sopenharmony_ci	case SND_SOC_TPLG_TUPLE_TYPE_UUID:
576d5ac70f0Sopenharmony_ci		return sizeof(struct snd_soc_tplg_vendor_uuid_elem);
577d5ac70f0Sopenharmony_ci
578d5ac70f0Sopenharmony_ci	case SND_SOC_TPLG_TUPLE_TYPE_STRING:
579d5ac70f0Sopenharmony_ci		return sizeof(struct snd_soc_tplg_vendor_string_elem);
580d5ac70f0Sopenharmony_ci
581d5ac70f0Sopenharmony_ci	default:
582d5ac70f0Sopenharmony_ci		return sizeof(struct snd_soc_tplg_vendor_value_elem);
583d5ac70f0Sopenharmony_ci	}
584d5ac70f0Sopenharmony_ci}
585d5ac70f0Sopenharmony_ci
586d5ac70f0Sopenharmony_ci/* Add a tuples object to the private buffer of its parent data element */
587d5ac70f0Sopenharmony_cistatic int copy_tuples(struct tplg_elem *elem,
588d5ac70f0Sopenharmony_ci		       struct tplg_vendor_tuples *tuples,
589d5ac70f0Sopenharmony_ci		       struct tplg_vendor_tokens *tokens)
590d5ac70f0Sopenharmony_ci{
591d5ac70f0Sopenharmony_ci	struct snd_soc_tplg_private *priv = elem->data, *priv2;
592d5ac70f0Sopenharmony_ci	struct tplg_tuple_set *tuple_set;
593d5ac70f0Sopenharmony_ci	struct tplg_tuple *tuple;
594d5ac70f0Sopenharmony_ci	struct snd_soc_tplg_vendor_array *array;
595d5ac70f0Sopenharmony_ci	struct snd_soc_tplg_vendor_uuid_elem *uuid;
596d5ac70f0Sopenharmony_ci	struct snd_soc_tplg_vendor_string_elem *string;
597d5ac70f0Sopenharmony_ci	struct snd_soc_tplg_vendor_value_elem *value;
598d5ac70f0Sopenharmony_ci	int set_size, size, off;
599d5ac70f0Sopenharmony_ci	unsigned int i, j;
600d5ac70f0Sopenharmony_ci	int token_val;
601d5ac70f0Sopenharmony_ci
602d5ac70f0Sopenharmony_ci	size = priv ? priv->size : 0; /* original private data size */
603d5ac70f0Sopenharmony_ci
604d5ac70f0Sopenharmony_ci	/* scan each tuples set (one set per type) */
605d5ac70f0Sopenharmony_ci	for (i = 0; i < tuples->num_sets ; i++) {
606d5ac70f0Sopenharmony_ci		tuple_set = tuples->set[i];
607d5ac70f0Sopenharmony_ci		set_size = sizeof(struct snd_soc_tplg_vendor_array)
608d5ac70f0Sopenharmony_ci			+ tplg_get_tuple_size(tuple_set->type)
609d5ac70f0Sopenharmony_ci			* tuple_set->num_tuples;
610d5ac70f0Sopenharmony_ci		size += set_size;
611d5ac70f0Sopenharmony_ci		if (size > TPLG_MAX_PRIV_SIZE) {
612d5ac70f0Sopenharmony_ci			SNDERR("data too big %d", size);
613d5ac70f0Sopenharmony_ci			return -EINVAL;
614d5ac70f0Sopenharmony_ci		}
615d5ac70f0Sopenharmony_ci
616d5ac70f0Sopenharmony_ci		if (priv != NULL) {
617d5ac70f0Sopenharmony_ci			priv2 = realloc(priv, sizeof(*priv) + size);
618d5ac70f0Sopenharmony_ci			if (priv2 == NULL) {
619d5ac70f0Sopenharmony_ci				free(priv);
620d5ac70f0Sopenharmony_ci				priv = NULL;
621d5ac70f0Sopenharmony_ci			} else {
622d5ac70f0Sopenharmony_ci				priv = priv2;
623d5ac70f0Sopenharmony_ci			}
624d5ac70f0Sopenharmony_ci		} else {
625d5ac70f0Sopenharmony_ci			priv = calloc(1, sizeof(*priv) + size);
626d5ac70f0Sopenharmony_ci		}
627d5ac70f0Sopenharmony_ci		if (!priv)
628d5ac70f0Sopenharmony_ci			return -ENOMEM;
629d5ac70f0Sopenharmony_ci
630d5ac70f0Sopenharmony_ci		off = priv->size;
631d5ac70f0Sopenharmony_ci		priv->size = size; /* update private data size */
632d5ac70f0Sopenharmony_ci		elem->data = priv;
633d5ac70f0Sopenharmony_ci
634d5ac70f0Sopenharmony_ci		array = (struct snd_soc_tplg_vendor_array *)(priv->data + off);
635d5ac70f0Sopenharmony_ci		memset(array, 0, set_size);
636d5ac70f0Sopenharmony_ci		array->size = set_size;
637d5ac70f0Sopenharmony_ci		array->type = tuple_set->type;
638d5ac70f0Sopenharmony_ci		array->num_elems = tuple_set->num_tuples;
639d5ac70f0Sopenharmony_ci
640d5ac70f0Sopenharmony_ci		/* fill the private data buffer */
641d5ac70f0Sopenharmony_ci		for (j = 0; j < tuple_set->num_tuples; j++) {
642d5ac70f0Sopenharmony_ci			tuple = &tuple_set->tuple[j];
643d5ac70f0Sopenharmony_ci			token_val = get_token_value(tuple->token, tokens);
644d5ac70f0Sopenharmony_ci			if (token_val  < 0)
645d5ac70f0Sopenharmony_ci				return -EINVAL;
646d5ac70f0Sopenharmony_ci
647d5ac70f0Sopenharmony_ci			switch (tuple_set->type) {
648d5ac70f0Sopenharmony_ci			case SND_SOC_TPLG_TUPLE_TYPE_UUID:
649d5ac70f0Sopenharmony_ci				uuid = &array->uuid[j];
650d5ac70f0Sopenharmony_ci				uuid->token = token_val;
651d5ac70f0Sopenharmony_ci				memcpy(uuid->uuid, tuple->uuid, 16);
652d5ac70f0Sopenharmony_ci				break;
653d5ac70f0Sopenharmony_ci
654d5ac70f0Sopenharmony_ci			case SND_SOC_TPLG_TUPLE_TYPE_STRING:
655d5ac70f0Sopenharmony_ci				string = &array->string[j];
656d5ac70f0Sopenharmony_ci				string->token = token_val;
657d5ac70f0Sopenharmony_ci				snd_strlcpy(string->string, tuple->string,
658d5ac70f0Sopenharmony_ci					SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
659d5ac70f0Sopenharmony_ci				break;
660d5ac70f0Sopenharmony_ci
661d5ac70f0Sopenharmony_ci			default:
662d5ac70f0Sopenharmony_ci				value = &array->value[j];
663d5ac70f0Sopenharmony_ci				value->token = token_val;
664d5ac70f0Sopenharmony_ci				value->value = tuple->value;
665d5ac70f0Sopenharmony_ci				break;
666d5ac70f0Sopenharmony_ci			}
667d5ac70f0Sopenharmony_ci		}
668d5ac70f0Sopenharmony_ci	}
669d5ac70f0Sopenharmony_ci
670d5ac70f0Sopenharmony_ci	return 0;
671d5ac70f0Sopenharmony_ci}
672d5ac70f0Sopenharmony_ci
673d5ac70f0Sopenharmony_ci/* build a data element from its tuples */
674d5ac70f0Sopenharmony_cistatic int build_tuples(snd_tplg_t *tplg, struct tplg_elem *elem)
675d5ac70f0Sopenharmony_ci{
676d5ac70f0Sopenharmony_ci	struct tplg_ref *ref;
677d5ac70f0Sopenharmony_ci	struct list_head *base, *pos;
678d5ac70f0Sopenharmony_ci	struct tplg_elem *tuples, *tokens;
679d5ac70f0Sopenharmony_ci	int err;
680d5ac70f0Sopenharmony_ci
681d5ac70f0Sopenharmony_ci	base = &elem->ref_list;
682d5ac70f0Sopenharmony_ci	list_for_each(pos, base) {
683d5ac70f0Sopenharmony_ci
684d5ac70f0Sopenharmony_ci		ref = list_entry(pos, struct tplg_ref, list);
685d5ac70f0Sopenharmony_ci
686d5ac70f0Sopenharmony_ci		if (ref->type != SND_TPLG_TYPE_TUPLE)
687d5ac70f0Sopenharmony_ci			continue;
688d5ac70f0Sopenharmony_ci
689d5ac70f0Sopenharmony_ci		tplg_dbg("tuples '%s' used by data '%s'", ref->id, elem->id);
690d5ac70f0Sopenharmony_ci
691d5ac70f0Sopenharmony_ci		if (!ref->elem)
692d5ac70f0Sopenharmony_ci			ref->elem = tplg_elem_lookup(&tplg->tuple_list,
693d5ac70f0Sopenharmony_ci				ref->id, SND_TPLG_TYPE_TUPLE, elem->index);
694d5ac70f0Sopenharmony_ci		tuples = ref->elem;
695d5ac70f0Sopenharmony_ci		if (!tuples) {
696d5ac70f0Sopenharmony_ci			SNDERR("cannot find tuples %s", ref->id);
697d5ac70f0Sopenharmony_ci			return -EINVAL;
698d5ac70f0Sopenharmony_ci		}
699d5ac70f0Sopenharmony_ci
700d5ac70f0Sopenharmony_ci		tokens = get_tokens(tplg, tuples);
701d5ac70f0Sopenharmony_ci		if (!tokens) {
702d5ac70f0Sopenharmony_ci			SNDERR("cannot find token for %s", ref->id);
703d5ac70f0Sopenharmony_ci			return -EINVAL;
704d5ac70f0Sopenharmony_ci		}
705d5ac70f0Sopenharmony_ci
706d5ac70f0Sopenharmony_ci		/* a data object can have multiple tuples objects */
707d5ac70f0Sopenharmony_ci		err = copy_tuples(elem, tuples->tuples, tokens->tokens);
708d5ac70f0Sopenharmony_ci		if (err < 0)
709d5ac70f0Sopenharmony_ci			return err;
710d5ac70f0Sopenharmony_ci	}
711d5ac70f0Sopenharmony_ci
712d5ac70f0Sopenharmony_ci	return 0;
713d5ac70f0Sopenharmony_ci}
714d5ac70f0Sopenharmony_ci
715d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN
716d5ac70f0Sopenharmony_cistruct tuple_type {
717d5ac70f0Sopenharmony_ci	unsigned int type;
718d5ac70f0Sopenharmony_ci	const char *name;
719d5ac70f0Sopenharmony_ci	unsigned int size;
720d5ac70f0Sopenharmony_ci};
721d5ac70f0Sopenharmony_ci#endif /* DOC_HIDDEN */
722d5ac70f0Sopenharmony_ci
723d5ac70f0Sopenharmony_cistatic struct tuple_type tuple_types[] = {
724d5ac70f0Sopenharmony_ci	{
725d5ac70f0Sopenharmony_ci		.type = SND_SOC_TPLG_TUPLE_TYPE_UUID,
726d5ac70f0Sopenharmony_ci		.name = "uuid",
727d5ac70f0Sopenharmony_ci		.size = 4,
728d5ac70f0Sopenharmony_ci	},
729d5ac70f0Sopenharmony_ci	{
730d5ac70f0Sopenharmony_ci		.type = SND_SOC_TPLG_TUPLE_TYPE_STRING,
731d5ac70f0Sopenharmony_ci		.name = "string",
732d5ac70f0Sopenharmony_ci		.size = 6,
733d5ac70f0Sopenharmony_ci	},
734d5ac70f0Sopenharmony_ci	{
735d5ac70f0Sopenharmony_ci		.type = SND_SOC_TPLG_TUPLE_TYPE_BOOL,
736d5ac70f0Sopenharmony_ci		.name = "bool",
737d5ac70f0Sopenharmony_ci		.size = 4,
738d5ac70f0Sopenharmony_ci	},
739d5ac70f0Sopenharmony_ci	{
740d5ac70f0Sopenharmony_ci		.type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
741d5ac70f0Sopenharmony_ci		.name = "byte",
742d5ac70f0Sopenharmony_ci		.size = 4,
743d5ac70f0Sopenharmony_ci	},
744d5ac70f0Sopenharmony_ci	{
745d5ac70f0Sopenharmony_ci		.type = SND_SOC_TPLG_TUPLE_TYPE_SHORT,
746d5ac70f0Sopenharmony_ci		.name = "short",
747d5ac70f0Sopenharmony_ci		.size = 5,
748d5ac70f0Sopenharmony_ci	},
749d5ac70f0Sopenharmony_ci	{
750d5ac70f0Sopenharmony_ci		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
751d5ac70f0Sopenharmony_ci		.name = "word",
752d5ac70f0Sopenharmony_ci		.size = 4
753d5ac70f0Sopenharmony_ci	},
754d5ac70f0Sopenharmony_ci};
755d5ac70f0Sopenharmony_ci
756d5ac70f0Sopenharmony_cistatic int get_tuple_type(const char *name)
757d5ac70f0Sopenharmony_ci{
758d5ac70f0Sopenharmony_ci	struct tuple_type *t;
759d5ac70f0Sopenharmony_ci	unsigned int i;
760d5ac70f0Sopenharmony_ci
761d5ac70f0Sopenharmony_ci	/* skip initial index for sorting */
762d5ac70f0Sopenharmony_ci	while ((*name >= '0' && *name <= '9') || *name == '_')
763d5ac70f0Sopenharmony_ci		name++;
764d5ac70f0Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(tuple_types); i++) {
765d5ac70f0Sopenharmony_ci		t = &tuple_types[i];
766d5ac70f0Sopenharmony_ci		if (strncasecmp(t->name, name, t->size) == 0)
767d5ac70f0Sopenharmony_ci			return t->type;
768d5ac70f0Sopenharmony_ci	}
769d5ac70f0Sopenharmony_ci	return -EINVAL;
770d5ac70f0Sopenharmony_ci}
771d5ac70f0Sopenharmony_ci
772d5ac70f0Sopenharmony_cistatic const char *get_tuple_type_name(unsigned int type)
773d5ac70f0Sopenharmony_ci{
774d5ac70f0Sopenharmony_ci	unsigned int i;
775d5ac70f0Sopenharmony_ci
776d5ac70f0Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(tuple_types); i++)
777d5ac70f0Sopenharmony_ci		if (tuple_types[i].type == type)
778d5ac70f0Sopenharmony_ci			return tuple_types[i].name;
779d5ac70f0Sopenharmony_ci	return NULL;
780d5ac70f0Sopenharmony_ci}
781d5ac70f0Sopenharmony_ci
782d5ac70f0Sopenharmony_cistatic int parse_tuple_set(snd_config_t *cfg,
783d5ac70f0Sopenharmony_ci			   struct tplg_tuple_set **s)
784d5ac70f0Sopenharmony_ci{
785d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
786d5ac70f0Sopenharmony_ci	snd_config_t *n;
787d5ac70f0Sopenharmony_ci	const char *id, *value;
788d5ac70f0Sopenharmony_ci	struct tplg_tuple_set *set;
789d5ac70f0Sopenharmony_ci	unsigned int num_tuples = 0;
790d5ac70f0Sopenharmony_ci	struct tplg_tuple *tuple;
791d5ac70f0Sopenharmony_ci	unsigned int tuple_val;
792d5ac70f0Sopenharmony_ci	int type, ival;
793d5ac70f0Sopenharmony_ci
794d5ac70f0Sopenharmony_ci	snd_config_get_id(cfg, &id);
795d5ac70f0Sopenharmony_ci
796d5ac70f0Sopenharmony_ci	type = get_tuple_type(id);
797d5ac70f0Sopenharmony_ci	if (type < 0) {
798d5ac70f0Sopenharmony_ci		SNDERR("invalid tuple type '%s'", id);
799d5ac70f0Sopenharmony_ci		return type;
800d5ac70f0Sopenharmony_ci	}
801d5ac70f0Sopenharmony_ci
802d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg)
803d5ac70f0Sopenharmony_ci		num_tuples++;
804d5ac70f0Sopenharmony_ci	if (!num_tuples)
805d5ac70f0Sopenharmony_ci		return 0;
806d5ac70f0Sopenharmony_ci
807d5ac70f0Sopenharmony_ci	tplg_dbg("\t %d %s tuples:", num_tuples, id);
808d5ac70f0Sopenharmony_ci	set = calloc(1, sizeof(*set) + num_tuples * sizeof(struct tplg_tuple));
809d5ac70f0Sopenharmony_ci	if (!set)
810d5ac70f0Sopenharmony_ci		return -ENOMEM;
811d5ac70f0Sopenharmony_ci
812d5ac70f0Sopenharmony_ci	set->type = type;
813d5ac70f0Sopenharmony_ci
814d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
815d5ac70f0Sopenharmony_ci
816d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
817d5ac70f0Sopenharmony_ci
818d5ac70f0Sopenharmony_ci		/* get id */
819d5ac70f0Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
820d5ac70f0Sopenharmony_ci			continue;
821d5ac70f0Sopenharmony_ci
822d5ac70f0Sopenharmony_ci		tuple = &set->tuple[set->num_tuples];
823d5ac70f0Sopenharmony_ci		snd_strlcpy(tuple->token, id,
824d5ac70f0Sopenharmony_ci				SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
825d5ac70f0Sopenharmony_ci
826d5ac70f0Sopenharmony_ci		switch (type) {
827d5ac70f0Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
828d5ac70f0Sopenharmony_ci			if (snd_config_get_string(n, &value) < 0)
829d5ac70f0Sopenharmony_ci				continue;
830d5ac70f0Sopenharmony_ci			if (get_uuid(value, tuple->uuid) < 0)
831d5ac70f0Sopenharmony_ci				goto err;
832d5ac70f0Sopenharmony_ci			break;
833d5ac70f0Sopenharmony_ci
834d5ac70f0Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
835d5ac70f0Sopenharmony_ci			if (snd_config_get_string(n, &value) < 0)
836d5ac70f0Sopenharmony_ci				continue;
837d5ac70f0Sopenharmony_ci			snd_strlcpy(tuple->string, value,
838d5ac70f0Sopenharmony_ci				SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
839d5ac70f0Sopenharmony_ci			tplg_dbg("\t\t%s = %s", tuple->token, tuple->string);
840d5ac70f0Sopenharmony_ci			break;
841d5ac70f0Sopenharmony_ci
842d5ac70f0Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
843d5ac70f0Sopenharmony_ci			ival = snd_config_get_bool(n);
844d5ac70f0Sopenharmony_ci			if (ival < 0)
845d5ac70f0Sopenharmony_ci				continue;
846d5ac70f0Sopenharmony_ci			tuple->value = ival;
847d5ac70f0Sopenharmony_ci			tplg_dbg("\t\t%s = %d", tuple->token, tuple->value);
848d5ac70f0Sopenharmony_ci			break;
849d5ac70f0Sopenharmony_ci
850d5ac70f0Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
851d5ac70f0Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
852d5ac70f0Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_WORD:
853d5ac70f0Sopenharmony_ci			ival = tplg_get_unsigned(n, &tuple_val, 0);
854d5ac70f0Sopenharmony_ci			if (ival < 0) {
855d5ac70f0Sopenharmony_ci				SNDERR("tuple %s: %s", id, snd_strerror(ival));
856d5ac70f0Sopenharmony_ci				goto err;
857d5ac70f0Sopenharmony_ci			}
858d5ac70f0Sopenharmony_ci
859d5ac70f0Sopenharmony_ci			if (/* (type == SND_SOC_TPLG_TUPLE_TYPE_WORD
860d5ac70f0Sopenharmony_ci					&& tuple_val > UINT_MAX) || */
861d5ac70f0Sopenharmony_ci				(type == SND_SOC_TPLG_TUPLE_TYPE_SHORT
862d5ac70f0Sopenharmony_ci					&& tuple_val > USHRT_MAX) ||
863d5ac70f0Sopenharmony_ci				(type == SND_SOC_TPLG_TUPLE_TYPE_BYTE
864d5ac70f0Sopenharmony_ci					&& tuple_val > UCHAR_MAX)) {
865d5ac70f0Sopenharmony_ci				SNDERR("tuple %s: invalid value", id);
866d5ac70f0Sopenharmony_ci				goto err;
867d5ac70f0Sopenharmony_ci			}
868d5ac70f0Sopenharmony_ci
869d5ac70f0Sopenharmony_ci			tuple->value = tuple_val;
870d5ac70f0Sopenharmony_ci			tplg_dbg("\t\t%s = 0x%x", tuple->token, tuple->value);
871d5ac70f0Sopenharmony_ci			break;
872d5ac70f0Sopenharmony_ci
873d5ac70f0Sopenharmony_ci		default:
874d5ac70f0Sopenharmony_ci			break;
875d5ac70f0Sopenharmony_ci		}
876d5ac70f0Sopenharmony_ci
877d5ac70f0Sopenharmony_ci		set->num_tuples++;
878d5ac70f0Sopenharmony_ci	}
879d5ac70f0Sopenharmony_ci
880d5ac70f0Sopenharmony_ci	*s = set;
881d5ac70f0Sopenharmony_ci	return 0;
882d5ac70f0Sopenharmony_ci
883d5ac70f0Sopenharmony_cierr:
884d5ac70f0Sopenharmony_ci	free(set);
885d5ac70f0Sopenharmony_ci	return -EINVAL;
886d5ac70f0Sopenharmony_ci}
887d5ac70f0Sopenharmony_ci
888d5ac70f0Sopenharmony_ci/* save tuple set */
889d5ac70f0Sopenharmony_cistatic int tplg_save_tuple_set(struct tplg_vendor_tuples *tuples,
890d5ac70f0Sopenharmony_ci			       unsigned int set_index,
891d5ac70f0Sopenharmony_ci			       struct tplg_buf *dst, const char *pfx)
892d5ac70f0Sopenharmony_ci{
893d5ac70f0Sopenharmony_ci	struct tplg_tuple_set *set;
894d5ac70f0Sopenharmony_ci	struct tplg_tuple *tuple;
895d5ac70f0Sopenharmony_ci	const char *s, *fmt;
896d5ac70f0Sopenharmony_ci	char buf[32];
897d5ac70f0Sopenharmony_ci	unsigned int i;
898d5ac70f0Sopenharmony_ci	int err;
899d5ac70f0Sopenharmony_ci
900d5ac70f0Sopenharmony_ci	set = tuples->set[set_index];
901d5ac70f0Sopenharmony_ci	if (set->num_tuples == 0)
902d5ac70f0Sopenharmony_ci		return 0;
903d5ac70f0Sopenharmony_ci	s = get_tuple_type_name(set->type);
904d5ac70f0Sopenharmony_ci	if (s == NULL)
905d5ac70f0Sopenharmony_ci		return -EINVAL;
906d5ac70f0Sopenharmony_ci	if (tuples->num_sets < 10)
907d5ac70f0Sopenharmony_ci		fmt = "%u_";
908d5ac70f0Sopenharmony_ci	else if (tuples->num_sets < 100)
909d5ac70f0Sopenharmony_ci		fmt = "%02u_";
910d5ac70f0Sopenharmony_ci	else if (tuples->num_sets < 1000)
911d5ac70f0Sopenharmony_ci		fmt = "%03u_";
912d5ac70f0Sopenharmony_ci	else
913d5ac70f0Sopenharmony_ci		return -EINVAL;
914d5ac70f0Sopenharmony_ci	if (set->num_tuples > 1) {
915d5ac70f0Sopenharmony_ci		snprintf(buf, sizeof(buf), "tuples.%s%%s {\n", fmt);
916d5ac70f0Sopenharmony_ci		err = tplg_save_printf(dst, NULL, buf, set_index, s);
917d5ac70f0Sopenharmony_ci		if (err < 0)
918d5ac70f0Sopenharmony_ci			return err;
919d5ac70f0Sopenharmony_ci	}
920d5ac70f0Sopenharmony_ci	for (i = 0; i < set->num_tuples; i++) {
921d5ac70f0Sopenharmony_ci		tuple = &set->tuple[i];
922d5ac70f0Sopenharmony_ci		if (set->num_tuples == 1) {
923d5ac70f0Sopenharmony_ci			snprintf(buf, sizeof(buf), "tuples.%s%%s.'%%s' ", fmt);
924d5ac70f0Sopenharmony_ci			err = tplg_save_printf(dst, NULL, buf,
925d5ac70f0Sopenharmony_ci					       set_index, s, tuple->token);
926d5ac70f0Sopenharmony_ci		} else {
927d5ac70f0Sopenharmony_ci			err = tplg_save_printf(dst, pfx, "\t'%s' ",
928d5ac70f0Sopenharmony_ci					       tuple->token);
929d5ac70f0Sopenharmony_ci		}
930d5ac70f0Sopenharmony_ci		if (err < 0)
931d5ac70f0Sopenharmony_ci			return err;
932d5ac70f0Sopenharmony_ci		switch (set->type) {
933d5ac70f0Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
934d5ac70f0Sopenharmony_ci			err = tplg_save_printf(dst, NULL, "'" UUID_FORMAT "'\n",
935d5ac70f0Sopenharmony_ci					       tuple->uuid[0], tuple->uuid[1],
936d5ac70f0Sopenharmony_ci					       tuple->uuid[2], tuple->uuid[3],
937d5ac70f0Sopenharmony_ci					       tuple->uuid[4], tuple->uuid[5],
938d5ac70f0Sopenharmony_ci					       tuple->uuid[6], tuple->uuid[7],
939d5ac70f0Sopenharmony_ci					       tuple->uuid[8], tuple->uuid[9],
940d5ac70f0Sopenharmony_ci					       tuple->uuid[10], tuple->uuid[11],
941d5ac70f0Sopenharmony_ci					       tuple->uuid[12], tuple->uuid[13],
942d5ac70f0Sopenharmony_ci					       tuple->uuid[14], tuple->uuid[15]);
943d5ac70f0Sopenharmony_ci			break;
944d5ac70f0Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
945d5ac70f0Sopenharmony_ci			err = tplg_save_printf(dst, NULL, "'%s'\n",
946d5ac70f0Sopenharmony_ci					       tuple->string);
947d5ac70f0Sopenharmony_ci			break;
948d5ac70f0Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
949d5ac70f0Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
950d5ac70f0Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
951d5ac70f0Sopenharmony_ci			err = tplg_save_printf(dst, NULL, "%u\n", tuple->value);
952d5ac70f0Sopenharmony_ci			break;
953d5ac70f0Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_WORD:
954d5ac70f0Sopenharmony_ci			tplg_nice_value_format(buf, sizeof(buf), tuple->value);
955d5ac70f0Sopenharmony_ci			err = tplg_save_printf(dst, NULL, "%s\n", buf);
956d5ac70f0Sopenharmony_ci			break;
957d5ac70f0Sopenharmony_ci		default:
958d5ac70f0Sopenharmony_ci			return -EINVAL;
959d5ac70f0Sopenharmony_ci		}
960d5ac70f0Sopenharmony_ci		if (err < 0)
961d5ac70f0Sopenharmony_ci			return err;
962d5ac70f0Sopenharmony_ci	}
963d5ac70f0Sopenharmony_ci	if (set->num_tuples > 1)
964d5ac70f0Sopenharmony_ci		return tplg_save_printf(dst, pfx, "}\n");
965d5ac70f0Sopenharmony_ci	return 0;
966d5ac70f0Sopenharmony_ci}
967d5ac70f0Sopenharmony_ci
968d5ac70f0Sopenharmony_cistatic int parse_tuple_sets(snd_config_t *cfg,
969d5ac70f0Sopenharmony_ci			    struct tplg_vendor_tuples *tuples)
970d5ac70f0Sopenharmony_ci{
971d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
972d5ac70f0Sopenharmony_ci	snd_config_t *n;
973d5ac70f0Sopenharmony_ci	const char *id;
974d5ac70f0Sopenharmony_ci	unsigned int num_tuple_sets = 0;
975d5ac70f0Sopenharmony_ci	int err;
976d5ac70f0Sopenharmony_ci
977d5ac70f0Sopenharmony_ci	if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
978d5ac70f0Sopenharmony_ci		if (snd_config_get_id(cfg, &id) >= 0)
979d5ac70f0Sopenharmony_ci			SNDERR("compound type expected for %s", id);
980d5ac70f0Sopenharmony_ci		return -EINVAL;
981d5ac70f0Sopenharmony_ci	}
982d5ac70f0Sopenharmony_ci
983d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
984d5ac70f0Sopenharmony_ci		num_tuple_sets++;
985d5ac70f0Sopenharmony_ci	}
986d5ac70f0Sopenharmony_ci
987d5ac70f0Sopenharmony_ci	if (!num_tuple_sets)
988d5ac70f0Sopenharmony_ci		return 0;
989d5ac70f0Sopenharmony_ci
990d5ac70f0Sopenharmony_ci	tuples->set = calloc(1, num_tuple_sets * sizeof(void *));
991d5ac70f0Sopenharmony_ci	if (!tuples->set)
992d5ac70f0Sopenharmony_ci		return -ENOMEM;
993d5ac70f0Sopenharmony_ci
994d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
995d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
996d5ac70f0Sopenharmony_ci		if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
997d5ac70f0Sopenharmony_ci			SNDERR("compound type expected for %s, is %d",
998d5ac70f0Sopenharmony_ci			       id, snd_config_get_type(n));
999d5ac70f0Sopenharmony_ci			return -EINVAL;
1000d5ac70f0Sopenharmony_ci		}
1001d5ac70f0Sopenharmony_ci
1002d5ac70f0Sopenharmony_ci		err = parse_tuple_set(n, &tuples->set[tuples->num_sets]);
1003d5ac70f0Sopenharmony_ci		if (err < 0)
1004d5ac70f0Sopenharmony_ci			return err;
1005d5ac70f0Sopenharmony_ci
1006d5ac70f0Sopenharmony_ci		/* overlook empty tuple sets */
1007d5ac70f0Sopenharmony_ci		if (tuples->set[tuples->num_sets])
1008d5ac70f0Sopenharmony_ci			tuples->num_sets++;
1009d5ac70f0Sopenharmony_ci	}
1010d5ac70f0Sopenharmony_ci
1011d5ac70f0Sopenharmony_ci	return 0;
1012d5ac70f0Sopenharmony_ci}
1013d5ac70f0Sopenharmony_ci
1014d5ac70f0Sopenharmony_ci/* save tuple sets */
1015d5ac70f0Sopenharmony_ciint tplg_save_tuple_sets(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
1016d5ac70f0Sopenharmony_ci			 struct tplg_elem *elem,
1017d5ac70f0Sopenharmony_ci			 struct tplg_buf *dst, const char *pfx)
1018d5ac70f0Sopenharmony_ci{
1019d5ac70f0Sopenharmony_ci	struct tplg_vendor_tuples *tuples = elem->tuples;
1020d5ac70f0Sopenharmony_ci	unsigned int i;
1021d5ac70f0Sopenharmony_ci	int err = 0;
1022d5ac70f0Sopenharmony_ci
1023d5ac70f0Sopenharmony_ci	for (i = 0; i < tuples->num_sets; i++) {
1024d5ac70f0Sopenharmony_ci		err = tplg_save_printf(dst, pfx, "");
1025d5ac70f0Sopenharmony_ci		if (err < 0)
1026d5ac70f0Sopenharmony_ci			break;
1027d5ac70f0Sopenharmony_ci		err = tplg_save_tuple_set(tuples, i, dst, pfx);
1028d5ac70f0Sopenharmony_ci		if (err < 0)
1029d5ac70f0Sopenharmony_ci			break;
1030d5ac70f0Sopenharmony_ci	}
1031d5ac70f0Sopenharmony_ci	return err;
1032d5ac70f0Sopenharmony_ci}
1033d5ac70f0Sopenharmony_ci
1034d5ac70f0Sopenharmony_ci/* Parse vendor tokens
1035d5ac70f0Sopenharmony_ci */
1036d5ac70f0Sopenharmony_ciint tplg_parse_tokens(snd_tplg_t *tplg, snd_config_t *cfg,
1037d5ac70f0Sopenharmony_ci		      void *private ATTRIBUTE_UNUSED)
1038d5ac70f0Sopenharmony_ci{
1039d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
1040d5ac70f0Sopenharmony_ci	snd_config_t *n;
1041d5ac70f0Sopenharmony_ci	const char *id;
1042d5ac70f0Sopenharmony_ci	struct tplg_elem *elem;
1043d5ac70f0Sopenharmony_ci	struct tplg_vendor_tokens *tokens;
1044d5ac70f0Sopenharmony_ci	int num_tokens = 0, value;
1045d5ac70f0Sopenharmony_ci
1046d5ac70f0Sopenharmony_ci	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_TOKEN);
1047d5ac70f0Sopenharmony_ci	if (!elem)
1048d5ac70f0Sopenharmony_ci		return -ENOMEM;
1049d5ac70f0Sopenharmony_ci
1050d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
1051d5ac70f0Sopenharmony_ci		num_tokens++;
1052d5ac70f0Sopenharmony_ci	}
1053d5ac70f0Sopenharmony_ci
1054d5ac70f0Sopenharmony_ci	if (!num_tokens)
1055d5ac70f0Sopenharmony_ci		return 0;
1056d5ac70f0Sopenharmony_ci
1057d5ac70f0Sopenharmony_ci	tplg_dbg(" Vendor tokens: %s, %d tokens", elem->id, num_tokens);
1058d5ac70f0Sopenharmony_ci
1059d5ac70f0Sopenharmony_ci	tokens = calloc(1, sizeof(*tokens)
1060d5ac70f0Sopenharmony_ci			+ num_tokens * sizeof(struct tplg_token));
1061d5ac70f0Sopenharmony_ci	if (!tokens)
1062d5ac70f0Sopenharmony_ci		return -ENOMEM;
1063d5ac70f0Sopenharmony_ci	elem->tokens = tokens;
1064d5ac70f0Sopenharmony_ci
1065d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
1066d5ac70f0Sopenharmony_ci
1067d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
1068d5ac70f0Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
1069d5ac70f0Sopenharmony_ci			continue;
1070d5ac70f0Sopenharmony_ci
1071d5ac70f0Sopenharmony_ci		if (tplg_get_integer(n, &value, 0))
1072d5ac70f0Sopenharmony_ci			continue;
1073d5ac70f0Sopenharmony_ci
1074d5ac70f0Sopenharmony_ci		snd_strlcpy(tokens->token[tokens->num_tokens].id, id,
1075d5ac70f0Sopenharmony_ci				SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
1076d5ac70f0Sopenharmony_ci		tokens->token[tokens->num_tokens].value = value;
1077d5ac70f0Sopenharmony_ci		tplg_dbg("\t\t %s : %d", tokens->token[tokens->num_tokens].id,
1078d5ac70f0Sopenharmony_ci			tokens->token[tokens->num_tokens].value);
1079d5ac70f0Sopenharmony_ci		tokens->num_tokens++;
1080d5ac70f0Sopenharmony_ci	}
1081d5ac70f0Sopenharmony_ci
1082d5ac70f0Sopenharmony_ci	return 0;
1083d5ac70f0Sopenharmony_ci}
1084d5ac70f0Sopenharmony_ci
1085d5ac70f0Sopenharmony_ci/* save vendor tokens */
1086d5ac70f0Sopenharmony_ciint tplg_save_tokens(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
1087d5ac70f0Sopenharmony_ci		     struct tplg_elem *elem,
1088d5ac70f0Sopenharmony_ci		     struct tplg_buf *dst, const char *pfx)
1089d5ac70f0Sopenharmony_ci{
1090d5ac70f0Sopenharmony_ci	struct tplg_vendor_tokens *tokens = elem->tokens;
1091d5ac70f0Sopenharmony_ci	unsigned int i;
1092d5ac70f0Sopenharmony_ci	int err;
1093d5ac70f0Sopenharmony_ci
1094d5ac70f0Sopenharmony_ci	if (!tokens || tokens->num_tokens == 0)
1095d5ac70f0Sopenharmony_ci		return 0;
1096d5ac70f0Sopenharmony_ci
1097d5ac70f0Sopenharmony_ci	err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
1098d5ac70f0Sopenharmony_ci	if (err < 0)
1099d5ac70f0Sopenharmony_ci		return err;
1100d5ac70f0Sopenharmony_ci	for (i = 0; err >= 0 && i < tokens->num_tokens; i++)
1101d5ac70f0Sopenharmony_ci		err = tplg_save_printf(dst, pfx, "\t'%s' %u\n",
1102d5ac70f0Sopenharmony_ci				       tokens->token[i].id,
1103d5ac70f0Sopenharmony_ci				       tokens->token[i].value);
1104d5ac70f0Sopenharmony_ci	err = tplg_save_printf(dst, pfx, "}\n");
1105d5ac70f0Sopenharmony_ci	if (err < 0)
1106d5ac70f0Sopenharmony_ci		return err;
1107d5ac70f0Sopenharmony_ci	return 0;
1108d5ac70f0Sopenharmony_ci}
1109d5ac70f0Sopenharmony_ci
1110d5ac70f0Sopenharmony_ci/* Parse vendor tuples.
1111d5ac70f0Sopenharmony_ci */
1112d5ac70f0Sopenharmony_ciint tplg_parse_tuples(snd_tplg_t *tplg, snd_config_t *cfg,
1113d5ac70f0Sopenharmony_ci		      void *private ATTRIBUTE_UNUSED)
1114d5ac70f0Sopenharmony_ci{
1115d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
1116d5ac70f0Sopenharmony_ci	snd_config_t *n;
1117d5ac70f0Sopenharmony_ci	const char *id, *value;
1118d5ac70f0Sopenharmony_ci	struct tplg_elem *elem;
1119d5ac70f0Sopenharmony_ci	struct tplg_vendor_tuples *tuples;
1120d5ac70f0Sopenharmony_ci	int err;
1121d5ac70f0Sopenharmony_ci
1122d5ac70f0Sopenharmony_ci	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_TUPLE);
1123d5ac70f0Sopenharmony_ci	if (!elem)
1124d5ac70f0Sopenharmony_ci		return -ENOMEM;
1125d5ac70f0Sopenharmony_ci
1126d5ac70f0Sopenharmony_ci	tplg_dbg(" Vendor Tuples: %s", elem->id);
1127d5ac70f0Sopenharmony_ci
1128d5ac70f0Sopenharmony_ci	tuples = calloc(1, sizeof(*tuples));
1129d5ac70f0Sopenharmony_ci	if (!tuples)
1130d5ac70f0Sopenharmony_ci		return -ENOMEM;
1131d5ac70f0Sopenharmony_ci	elem->tuples = tuples;
1132d5ac70f0Sopenharmony_ci
1133d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
1134d5ac70f0Sopenharmony_ci
1135d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
1136d5ac70f0Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
1137d5ac70f0Sopenharmony_ci			continue;
1138d5ac70f0Sopenharmony_ci
1139d5ac70f0Sopenharmony_ci		if (strcmp(id, "tokens") == 0) {
1140d5ac70f0Sopenharmony_ci			if (snd_config_get_string(n, &value) < 0)
1141d5ac70f0Sopenharmony_ci				return -EINVAL;
1142d5ac70f0Sopenharmony_ci			tplg_ref_add(elem, SND_TPLG_TYPE_TOKEN, value);
1143d5ac70f0Sopenharmony_ci			tplg_dbg("\t refer to vendor tokens: %s", value);
1144d5ac70f0Sopenharmony_ci		}
1145d5ac70f0Sopenharmony_ci
1146d5ac70f0Sopenharmony_ci		if (strcmp(id, "tuples") == 0) {
1147d5ac70f0Sopenharmony_ci			err = parse_tuple_sets(n, tuples);
1148d5ac70f0Sopenharmony_ci			if (err < 0)
1149d5ac70f0Sopenharmony_ci				return err;
1150d5ac70f0Sopenharmony_ci		}
1151d5ac70f0Sopenharmony_ci	}
1152d5ac70f0Sopenharmony_ci
1153d5ac70f0Sopenharmony_ci	return 0;
1154d5ac70f0Sopenharmony_ci}
1155d5ac70f0Sopenharmony_ci
1156d5ac70f0Sopenharmony_ci/* save vendor tuples */
1157d5ac70f0Sopenharmony_ciint tplg_save_tuples(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
1158d5ac70f0Sopenharmony_ci		     struct tplg_elem *elem,
1159d5ac70f0Sopenharmony_ci		     struct tplg_buf *dst, const char *pfx)
1160d5ac70f0Sopenharmony_ci{
1161d5ac70f0Sopenharmony_ci	char pfx2[16];
1162d5ac70f0Sopenharmony_ci	int err;
1163d5ac70f0Sopenharmony_ci
1164d5ac70f0Sopenharmony_ci	if (!elem->tuples)
1165d5ac70f0Sopenharmony_ci		return 0;
1166d5ac70f0Sopenharmony_ci
1167d5ac70f0Sopenharmony_ci	err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
1168d5ac70f0Sopenharmony_ci	snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
1169d5ac70f0Sopenharmony_ci	if (err >= 0)
1170d5ac70f0Sopenharmony_ci		err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_TOKEN,
1171d5ac70f0Sopenharmony_ci				     "tokens", dst, pfx2);
1172d5ac70f0Sopenharmony_ci	if (err >= 0)
1173d5ac70f0Sopenharmony_ci		err = tplg_save_tuple_sets(tplg, elem, dst, pfx2);
1174d5ac70f0Sopenharmony_ci	if (err >= 0)
1175d5ac70f0Sopenharmony_ci		err = tplg_save_printf(dst, pfx, "}\n");
1176d5ac70f0Sopenharmony_ci	return 0;
1177d5ac70f0Sopenharmony_ci}
1178d5ac70f0Sopenharmony_ci
1179d5ac70f0Sopenharmony_ci/* Free handler of tuples */
1180d5ac70f0Sopenharmony_civoid tplg_free_tuples(void *obj)
1181d5ac70f0Sopenharmony_ci{
1182d5ac70f0Sopenharmony_ci	struct tplg_vendor_tuples *tuples = (struct tplg_vendor_tuples *)obj;
1183d5ac70f0Sopenharmony_ci	unsigned int i;
1184d5ac70f0Sopenharmony_ci
1185d5ac70f0Sopenharmony_ci	if (!tuples || !tuples->set)
1186d5ac70f0Sopenharmony_ci		return;
1187d5ac70f0Sopenharmony_ci
1188d5ac70f0Sopenharmony_ci	for (i = 0; i < tuples->num_sets; i++)
1189d5ac70f0Sopenharmony_ci		free(tuples->set[i]);
1190d5ac70f0Sopenharmony_ci
1191d5ac70f0Sopenharmony_ci	free(tuples->set);
1192d5ac70f0Sopenharmony_ci}
1193d5ac70f0Sopenharmony_ci
1194d5ac70f0Sopenharmony_ci/* Parse manifest's data references
1195d5ac70f0Sopenharmony_ci */
1196d5ac70f0Sopenharmony_ciint tplg_parse_manifest_data(snd_tplg_t *tplg, snd_config_t *cfg,
1197d5ac70f0Sopenharmony_ci			     void *private ATTRIBUTE_UNUSED)
1198d5ac70f0Sopenharmony_ci{
1199d5ac70f0Sopenharmony_ci	struct snd_soc_tplg_manifest *manifest;
1200d5ac70f0Sopenharmony_ci	struct tplg_elem *elem;
1201d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
1202d5ac70f0Sopenharmony_ci	snd_config_t *n;
1203d5ac70f0Sopenharmony_ci	const char *id;
1204d5ac70f0Sopenharmony_ci	int err;
1205d5ac70f0Sopenharmony_ci
1206d5ac70f0Sopenharmony_ci	if (!list_empty(&tplg->manifest_list)) {
1207d5ac70f0Sopenharmony_ci		SNDERR("already has manifest data");
1208d5ac70f0Sopenharmony_ci		return -EINVAL;
1209d5ac70f0Sopenharmony_ci	}
1210d5ac70f0Sopenharmony_ci
1211d5ac70f0Sopenharmony_ci	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_MANIFEST);
1212d5ac70f0Sopenharmony_ci	if (!elem)
1213d5ac70f0Sopenharmony_ci		return -ENOMEM;
1214d5ac70f0Sopenharmony_ci
1215d5ac70f0Sopenharmony_ci	manifest = elem->manifest;
1216d5ac70f0Sopenharmony_ci	manifest->size = elem->size;
1217d5ac70f0Sopenharmony_ci
1218d5ac70f0Sopenharmony_ci	tplg_dbg(" Manifest: %s", elem->id);
1219d5ac70f0Sopenharmony_ci
1220d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
1221d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
1222d5ac70f0Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
1223d5ac70f0Sopenharmony_ci			continue;
1224d5ac70f0Sopenharmony_ci
1225d5ac70f0Sopenharmony_ci		/* skip comments */
1226d5ac70f0Sopenharmony_ci		if (strcmp(id, "comment") == 0)
1227d5ac70f0Sopenharmony_ci			continue;
1228d5ac70f0Sopenharmony_ci		if (id[0] == '#')
1229d5ac70f0Sopenharmony_ci			continue;
1230d5ac70f0Sopenharmony_ci
1231d5ac70f0Sopenharmony_ci
1232d5ac70f0Sopenharmony_ci		if (strcmp(id, "data") == 0) {
1233d5ac70f0Sopenharmony_ci			err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_DATA);
1234d5ac70f0Sopenharmony_ci			if (err < 0)
1235d5ac70f0Sopenharmony_ci				return err;
1236d5ac70f0Sopenharmony_ci			continue;
1237d5ac70f0Sopenharmony_ci		}
1238d5ac70f0Sopenharmony_ci	}
1239d5ac70f0Sopenharmony_ci
1240d5ac70f0Sopenharmony_ci	return 0;
1241d5ac70f0Sopenharmony_ci}
1242d5ac70f0Sopenharmony_ci
1243d5ac70f0Sopenharmony_ci/* save manifest data */
1244d5ac70f0Sopenharmony_ciint tplg_save_manifest_data(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
1245d5ac70f0Sopenharmony_ci			    struct tplg_elem *elem, struct tplg_buf *dst,
1246d5ac70f0Sopenharmony_ci			    const char *pfx)
1247d5ac70f0Sopenharmony_ci{
1248d5ac70f0Sopenharmony_ci	struct list_head *pos;
1249d5ac70f0Sopenharmony_ci	struct tplg_ref *ref;
1250d5ac70f0Sopenharmony_ci	int err, index, count;
1251d5ac70f0Sopenharmony_ci
1252d5ac70f0Sopenharmony_ci	/* for each ref in this manifest elem */
1253d5ac70f0Sopenharmony_ci	count = 0;
1254d5ac70f0Sopenharmony_ci	list_for_each(pos, &elem->ref_list) {
1255d5ac70f0Sopenharmony_ci		ref = list_entry(pos, struct tplg_ref, list);
1256d5ac70f0Sopenharmony_ci		if (ref->type != SND_TPLG_TYPE_DATA)
1257d5ac70f0Sopenharmony_ci			continue;
1258d5ac70f0Sopenharmony_ci		count++;
1259d5ac70f0Sopenharmony_ci	}
1260d5ac70f0Sopenharmony_ci	if (count == 0)
1261d5ac70f0Sopenharmony_ci		return tplg_save_printf(dst, NULL,
1262d5ac70f0Sopenharmony_ci					"'%s'.comment 'empty'\n", elem->id);
1263d5ac70f0Sopenharmony_ci	if (count > 1) {
1264d5ac70f0Sopenharmony_ci		err = tplg_save_printf(dst, NULL, "'%s'.data [\n", elem->id);
1265d5ac70f0Sopenharmony_ci		if (err < 0)
1266d5ac70f0Sopenharmony_ci			return err;
1267d5ac70f0Sopenharmony_ci	}
1268d5ac70f0Sopenharmony_ci	index = 0;
1269d5ac70f0Sopenharmony_ci	list_for_each(pos, &elem->ref_list) {
1270d5ac70f0Sopenharmony_ci		ref = list_entry(pos, struct tplg_ref, list);
1271d5ac70f0Sopenharmony_ci		if (ref->type != SND_TPLG_TYPE_DATA)
1272d5ac70f0Sopenharmony_ci			continue;
1273d5ac70f0Sopenharmony_ci		if (count == 1) {
1274d5ac70f0Sopenharmony_ci			err = tplg_save_printf(dst, NULL, "'%s'.data.%u '%s'\n",
1275d5ac70f0Sopenharmony_ci					       elem->id, index, ref->id);
1276d5ac70f0Sopenharmony_ci		} else {
1277d5ac70f0Sopenharmony_ci			err = tplg_save_printf(dst, pfx, "\t'%s'\n", ref->id);
1278d5ac70f0Sopenharmony_ci		}
1279d5ac70f0Sopenharmony_ci		if (err < 0)
1280d5ac70f0Sopenharmony_ci			return err;
1281d5ac70f0Sopenharmony_ci		index++;
1282d5ac70f0Sopenharmony_ci	}
1283d5ac70f0Sopenharmony_ci	if (count > 1) {
1284d5ac70f0Sopenharmony_ci		err = tplg_save_printf(dst, pfx, "]\n");
1285d5ac70f0Sopenharmony_ci		if (err < 0)
1286d5ac70f0Sopenharmony_ci			return err;
1287d5ac70f0Sopenharmony_ci	}
1288d5ac70f0Sopenharmony_ci	return 0;
1289d5ac70f0Sopenharmony_ci}
1290d5ac70f0Sopenharmony_ci
1291d5ac70f0Sopenharmony_ci/* merge private data of manifest */
1292d5ac70f0Sopenharmony_ciint tplg_build_manifest_data(snd_tplg_t *tplg)
1293d5ac70f0Sopenharmony_ci{
1294d5ac70f0Sopenharmony_ci	struct list_head *base, *pos;
1295d5ac70f0Sopenharmony_ci	struct tplg_elem *elem = NULL;
1296d5ac70f0Sopenharmony_ci	struct tplg_ref *ref;
1297d5ac70f0Sopenharmony_ci	struct snd_soc_tplg_manifest *manifest;
1298d5ac70f0Sopenharmony_ci	int err = 0;
1299d5ac70f0Sopenharmony_ci
1300d5ac70f0Sopenharmony_ci	base = &tplg->manifest_list;
1301d5ac70f0Sopenharmony_ci	list_for_each(pos, base) {
1302d5ac70f0Sopenharmony_ci
1303d5ac70f0Sopenharmony_ci		elem = list_entry(pos, struct tplg_elem, list);
1304d5ac70f0Sopenharmony_ci		break;
1305d5ac70f0Sopenharmony_ci	}
1306d5ac70f0Sopenharmony_ci
1307d5ac70f0Sopenharmony_ci	if (!elem) /* no manifest data */
1308d5ac70f0Sopenharmony_ci		return 0;
1309d5ac70f0Sopenharmony_ci
1310d5ac70f0Sopenharmony_ci	base = &elem->ref_list;
1311d5ac70f0Sopenharmony_ci
1312d5ac70f0Sopenharmony_ci	/* for each ref in this manifest elem */
1313d5ac70f0Sopenharmony_ci	list_for_each(pos, base) {
1314d5ac70f0Sopenharmony_ci
1315d5ac70f0Sopenharmony_ci		ref = list_entry(pos, struct tplg_ref, list);
1316d5ac70f0Sopenharmony_ci		if (ref->elem)
1317d5ac70f0Sopenharmony_ci			continue;
1318d5ac70f0Sopenharmony_ci
1319d5ac70f0Sopenharmony_ci		if (ref->type == SND_TPLG_TYPE_DATA) {
1320d5ac70f0Sopenharmony_ci			err = tplg_copy_data(tplg, elem, ref);
1321d5ac70f0Sopenharmony_ci			if (err < 0)
1322d5ac70f0Sopenharmony_ci				return err;
1323d5ac70f0Sopenharmony_ci		}
1324d5ac70f0Sopenharmony_ci	}
1325d5ac70f0Sopenharmony_ci
1326d5ac70f0Sopenharmony_ci	manifest = elem->manifest;
1327d5ac70f0Sopenharmony_ci	if (!manifest->priv.size) /* no manifest data */
1328d5ac70f0Sopenharmony_ci		return 0;
1329d5ac70f0Sopenharmony_ci
1330d5ac70f0Sopenharmony_ci	tplg->manifest_pdata = malloc(manifest->priv.size);
1331d5ac70f0Sopenharmony_ci	if (!tplg->manifest_pdata)
1332d5ac70f0Sopenharmony_ci		return -ENOMEM;
1333d5ac70f0Sopenharmony_ci
1334d5ac70f0Sopenharmony_ci	tplg->manifest.priv.size = manifest->priv.size;
1335d5ac70f0Sopenharmony_ci	memcpy(tplg->manifest_pdata, manifest->priv.data, manifest->priv.size);
1336d5ac70f0Sopenharmony_ci	return 0;
1337d5ac70f0Sopenharmony_ci}
1338d5ac70f0Sopenharmony_ci
1339d5ac70f0Sopenharmony_ci/* Parse Private data.
1340d5ac70f0Sopenharmony_ci *
1341d5ac70f0Sopenharmony_ci * Object private data can either be from file or defined as bytes, shorts,
1342d5ac70f0Sopenharmony_ci * words, tuples.
1343d5ac70f0Sopenharmony_ci */
1344d5ac70f0Sopenharmony_ciint tplg_parse_data(snd_tplg_t *tplg, snd_config_t *cfg,
1345d5ac70f0Sopenharmony_ci		    void *private ATTRIBUTE_UNUSED)
1346d5ac70f0Sopenharmony_ci{
1347d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
1348d5ac70f0Sopenharmony_ci	snd_config_t *n;
1349d5ac70f0Sopenharmony_ci	const char *id;
1350d5ac70f0Sopenharmony_ci	int err = 0, ival;
1351d5ac70f0Sopenharmony_ci	struct tplg_elem *elem;
1352d5ac70f0Sopenharmony_ci
1353d5ac70f0Sopenharmony_ci	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_DATA);
1354d5ac70f0Sopenharmony_ci	if (!elem)
1355d5ac70f0Sopenharmony_ci		return -ENOMEM;
1356d5ac70f0Sopenharmony_ci
1357d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
1358d5ac70f0Sopenharmony_ci
1359d5ac70f0Sopenharmony_ci		n = snd_config_iterator_entry(i);
1360d5ac70f0Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0) {
1361d5ac70f0Sopenharmony_ci			continue;
1362d5ac70f0Sopenharmony_ci		}
1363d5ac70f0Sopenharmony_ci
1364d5ac70f0Sopenharmony_ci		if (strcmp(id, "file") == 0) {
1365d5ac70f0Sopenharmony_ci			err = tplg_parse_data_file(n, elem);
1366d5ac70f0Sopenharmony_ci			if (err < 0) {
1367d5ac70f0Sopenharmony_ci				SNDERR("failed to parse data file");
1368d5ac70f0Sopenharmony_ci				return err;
1369d5ac70f0Sopenharmony_ci			}
1370d5ac70f0Sopenharmony_ci			continue;
1371d5ac70f0Sopenharmony_ci		}
1372d5ac70f0Sopenharmony_ci
1373d5ac70f0Sopenharmony_ci		if (strcmp(id, "bytes") == 0) {
1374d5ac70f0Sopenharmony_ci			err = tplg_parse_data_hex(n, elem, 1);
1375d5ac70f0Sopenharmony_ci			if (err < 0) {
1376d5ac70f0Sopenharmony_ci				SNDERR("failed to parse data bytes");
1377d5ac70f0Sopenharmony_ci				return err;
1378d5ac70f0Sopenharmony_ci			}
1379d5ac70f0Sopenharmony_ci			continue;
1380d5ac70f0Sopenharmony_ci		}
1381d5ac70f0Sopenharmony_ci
1382d5ac70f0Sopenharmony_ci		if (strcmp(id, "shorts") == 0) {
1383d5ac70f0Sopenharmony_ci			err = tplg_parse_data_hex(n, elem, 2);
1384d5ac70f0Sopenharmony_ci			if (err < 0) {
1385d5ac70f0Sopenharmony_ci				SNDERR("failed to parse data shorts");
1386d5ac70f0Sopenharmony_ci				return err;
1387d5ac70f0Sopenharmony_ci			}
1388d5ac70f0Sopenharmony_ci			continue;
1389d5ac70f0Sopenharmony_ci		}
1390d5ac70f0Sopenharmony_ci
1391d5ac70f0Sopenharmony_ci		if (strcmp(id, "words") == 0) {
1392d5ac70f0Sopenharmony_ci			err = tplg_parse_data_hex(n, elem, 4);
1393d5ac70f0Sopenharmony_ci			if (err < 0) {
1394d5ac70f0Sopenharmony_ci				SNDERR("failed to parse data words");
1395d5ac70f0Sopenharmony_ci				return err;
1396d5ac70f0Sopenharmony_ci			}
1397d5ac70f0Sopenharmony_ci			continue;
1398d5ac70f0Sopenharmony_ci		}
1399d5ac70f0Sopenharmony_ci
1400d5ac70f0Sopenharmony_ci		if (strcmp(id, "tuples") == 0) {
1401d5ac70f0Sopenharmony_ci			err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_TUPLE);
1402d5ac70f0Sopenharmony_ci			if (err < 0)
1403d5ac70f0Sopenharmony_ci				return err;
1404d5ac70f0Sopenharmony_ci			continue;
1405d5ac70f0Sopenharmony_ci		}
1406d5ac70f0Sopenharmony_ci
1407d5ac70f0Sopenharmony_ci		if (strcmp(id, "type") == 0) {
1408d5ac70f0Sopenharmony_ci			if (tplg_get_integer(n, &ival, 0))
1409d5ac70f0Sopenharmony_ci				return -EINVAL;
1410d5ac70f0Sopenharmony_ci
1411d5ac70f0Sopenharmony_ci			elem->vendor_type = ival;
1412d5ac70f0Sopenharmony_ci			tplg_dbg("\t%s: %d", id, elem->index);
1413d5ac70f0Sopenharmony_ci			continue;
1414d5ac70f0Sopenharmony_ci		}
1415d5ac70f0Sopenharmony_ci	}
1416d5ac70f0Sopenharmony_ci
1417d5ac70f0Sopenharmony_ci	return err;
1418d5ac70f0Sopenharmony_ci}
1419d5ac70f0Sopenharmony_ci
1420d5ac70f0Sopenharmony_ci/* save data element */
1421d5ac70f0Sopenharmony_ciint tplg_save_data(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
1422d5ac70f0Sopenharmony_ci		   struct tplg_elem *elem,
1423d5ac70f0Sopenharmony_ci		   struct tplg_buf *dst, const char *pfx)
1424d5ac70f0Sopenharmony_ci{
1425d5ac70f0Sopenharmony_ci	struct snd_soc_tplg_private *priv = elem->data;
1426d5ac70f0Sopenharmony_ci	struct list_head *pos;
1427d5ac70f0Sopenharmony_ci	struct tplg_ref *ref;
1428d5ac70f0Sopenharmony_ci	char pfx2[16];
1429d5ac70f0Sopenharmony_ci	unsigned int i, count;
1430d5ac70f0Sopenharmony_ci	int err;
1431d5ac70f0Sopenharmony_ci
1432d5ac70f0Sopenharmony_ci	count = 0;
1433d5ac70f0Sopenharmony_ci	if (priv && priv->size > 0)
1434d5ac70f0Sopenharmony_ci		count++;
1435d5ac70f0Sopenharmony_ci	list_for_each(pos, &elem->ref_list) {
1436d5ac70f0Sopenharmony_ci		ref = list_entry(pos, struct tplg_ref, list);
1437d5ac70f0Sopenharmony_ci		if (ref->type == SND_TPLG_TYPE_TUPLE)
1438d5ac70f0Sopenharmony_ci			count++;
1439d5ac70f0Sopenharmony_ci	}
1440d5ac70f0Sopenharmony_ci	if (elem->vendor_type > 0)
1441d5ac70f0Sopenharmony_ci		count++;
1442d5ac70f0Sopenharmony_ci
1443d5ac70f0Sopenharmony_ci	if (count > 1) {
1444d5ac70f0Sopenharmony_ci		err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
1445d5ac70f0Sopenharmony_ci		if (err >= 0)
1446d5ac70f0Sopenharmony_ci			err = tplg_save_printf(dst, NULL, "");
1447d5ac70f0Sopenharmony_ci	} else {
1448d5ac70f0Sopenharmony_ci		err = tplg_save_printf(dst, NULL, "'%s'.", elem->id);
1449d5ac70f0Sopenharmony_ci	}
1450d5ac70f0Sopenharmony_ci	if (err >= 0 && priv && priv->size > 0) {
1451d5ac70f0Sopenharmony_ci		if (count > 1) {
1452d5ac70f0Sopenharmony_ci			err = tplg_save_printf(dst, pfx, "");
1453d5ac70f0Sopenharmony_ci			if (err < 0)
1454d5ac70f0Sopenharmony_ci				return err;
1455d5ac70f0Sopenharmony_ci		}
1456d5ac70f0Sopenharmony_ci		if (priv->size > 8) {
1457d5ac70f0Sopenharmony_ci			err = tplg_save_printf(dst, NULL, "bytes\n");
1458d5ac70f0Sopenharmony_ci			if (err >= 0)
1459d5ac70f0Sopenharmony_ci				err = tplg_save_printf(dst, pfx, "\t'");
1460d5ac70f0Sopenharmony_ci		} else {
1461d5ac70f0Sopenharmony_ci			err = tplg_save_printf(dst, NULL, "bytes '");
1462d5ac70f0Sopenharmony_ci		}
1463d5ac70f0Sopenharmony_ci		if (err < 0)
1464d5ac70f0Sopenharmony_ci			return err;
1465d5ac70f0Sopenharmony_ci		for (i = 0; i < priv->size; i++) {
1466d5ac70f0Sopenharmony_ci			if (i > 0 && (i % 8) == 0) {
1467d5ac70f0Sopenharmony_ci				err = tplg_save_printf(dst, NULL, ":\n");
1468d5ac70f0Sopenharmony_ci				if (err < 0)
1469d5ac70f0Sopenharmony_ci					return err;
1470d5ac70f0Sopenharmony_ci				err = tplg_save_printf(dst, pfx, "\t ");
1471d5ac70f0Sopenharmony_ci				if (err < 0)
1472d5ac70f0Sopenharmony_ci					return err;
1473d5ac70f0Sopenharmony_ci			}
1474d5ac70f0Sopenharmony_ci			err = tplg_save_printf(dst, NULL, "%s%02x",
1475d5ac70f0Sopenharmony_ci					       (i % 8) == 0 ? "" : ":",
1476d5ac70f0Sopenharmony_ci					       (unsigned char)priv->data[i]);
1477d5ac70f0Sopenharmony_ci			if (err < 0)
1478d5ac70f0Sopenharmony_ci				return err;
1479d5ac70f0Sopenharmony_ci		}
1480d5ac70f0Sopenharmony_ci		err = tplg_save_printf(dst, NULL, "'\n");
1481d5ac70f0Sopenharmony_ci	}
1482d5ac70f0Sopenharmony_ci	snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
1483d5ac70f0Sopenharmony_ci	if (err >= 0)
1484d5ac70f0Sopenharmony_ci		err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_TUPLE,
1485d5ac70f0Sopenharmony_ci				     "tuples", dst,
1486d5ac70f0Sopenharmony_ci				     count > 1 ? pfx2 : NULL);
1487d5ac70f0Sopenharmony_ci	if (err >= 0 && elem->vendor_type > 0)
1488d5ac70f0Sopenharmony_ci		err = tplg_save_printf(dst, pfx, "type %u",
1489d5ac70f0Sopenharmony_ci				       elem->vendor_type);
1490d5ac70f0Sopenharmony_ci	if (err >= 0 && count > 1)
1491d5ac70f0Sopenharmony_ci		err = tplg_save_printf(dst, pfx, "}\n");
1492d5ac70f0Sopenharmony_ci	return err;
1493d5ac70f0Sopenharmony_ci}
1494d5ac70f0Sopenharmony_ci
1495d5ac70f0Sopenharmony_ci/* Find a referenced data element and copy its data to the parent
1496d5ac70f0Sopenharmony_ci * element's private data buffer.
1497d5ac70f0Sopenharmony_ci * An element can refer to multiple data sections. Data of these sections
1498d5ac70f0Sopenharmony_ci * will be merged in the their reference order.
1499d5ac70f0Sopenharmony_ci */
1500d5ac70f0Sopenharmony_ciint tplg_copy_data(snd_tplg_t *tplg, struct tplg_elem *elem,
1501d5ac70f0Sopenharmony_ci		   struct tplg_ref *ref)
1502d5ac70f0Sopenharmony_ci{
1503d5ac70f0Sopenharmony_ci	struct tplg_elem *ref_elem;
1504d5ac70f0Sopenharmony_ci	struct snd_soc_tplg_private *priv, *old_priv;
1505d5ac70f0Sopenharmony_ci	int priv_data_size, old_priv_data_size;
1506d5ac70f0Sopenharmony_ci	void *obj;
1507d5ac70f0Sopenharmony_ci
1508d5ac70f0Sopenharmony_ci	ref_elem = tplg_elem_lookup(&tplg->pdata_list,
1509d5ac70f0Sopenharmony_ci				     ref->id, SND_TPLG_TYPE_DATA, elem->index);
1510d5ac70f0Sopenharmony_ci	if (!ref_elem) {
1511d5ac70f0Sopenharmony_ci		SNDERR("cannot find data '%s' referenced by"
1512d5ac70f0Sopenharmony_ci		       " element '%s'", ref->id, elem->id);
1513d5ac70f0Sopenharmony_ci		return -EINVAL;
1514d5ac70f0Sopenharmony_ci	}
1515d5ac70f0Sopenharmony_ci
1516d5ac70f0Sopenharmony_ci	tplg_dbg("Data '%s' used by '%s'", ref->id, elem->id);
1517d5ac70f0Sopenharmony_ci	/* overlook empty private data */
1518d5ac70f0Sopenharmony_ci	if (!ref_elem->data || !ref_elem->data->size) {
1519d5ac70f0Sopenharmony_ci		ref->elem = ref_elem;
1520d5ac70f0Sopenharmony_ci		return 0;
1521d5ac70f0Sopenharmony_ci	}
1522d5ac70f0Sopenharmony_ci
1523d5ac70f0Sopenharmony_ci	old_priv = get_priv_data(elem);
1524d5ac70f0Sopenharmony_ci	if (!old_priv)
1525d5ac70f0Sopenharmony_ci		return -EINVAL;
1526d5ac70f0Sopenharmony_ci	old_priv_data_size = old_priv->size;
1527d5ac70f0Sopenharmony_ci
1528d5ac70f0Sopenharmony_ci	priv_data_size = ref_elem->data->size;
1529d5ac70f0Sopenharmony_ci	obj = realloc(elem->obj,
1530d5ac70f0Sopenharmony_ci			elem->size + priv_data_size);
1531d5ac70f0Sopenharmony_ci	if (!obj)
1532d5ac70f0Sopenharmony_ci		return -ENOMEM;
1533d5ac70f0Sopenharmony_ci	elem->obj = obj;
1534d5ac70f0Sopenharmony_ci
1535d5ac70f0Sopenharmony_ci	priv = get_priv_data(elem);
1536d5ac70f0Sopenharmony_ci	if (!priv)
1537d5ac70f0Sopenharmony_ci		return -EINVAL;
1538d5ac70f0Sopenharmony_ci
1539d5ac70f0Sopenharmony_ci	/* merge the new data block */
1540d5ac70f0Sopenharmony_ci	elem->size += priv_data_size;
1541d5ac70f0Sopenharmony_ci	priv->size = priv_data_size + old_priv_data_size;
1542d5ac70f0Sopenharmony_ci	ref_elem->compound_elem = 1;
1543d5ac70f0Sopenharmony_ci	memcpy(priv->data + old_priv_data_size,
1544d5ac70f0Sopenharmony_ci	       ref_elem->data->data, priv_data_size);
1545d5ac70f0Sopenharmony_ci
1546d5ac70f0Sopenharmony_ci	ref->elem = ref_elem;
1547d5ac70f0Sopenharmony_ci	return 0;
1548d5ac70f0Sopenharmony_ci}
1549d5ac70f0Sopenharmony_ci
1550d5ac70f0Sopenharmony_ci/* check data objects and build those with tuples */
1551d5ac70f0Sopenharmony_ciint tplg_build_data(snd_tplg_t *tplg)
1552d5ac70f0Sopenharmony_ci{
1553d5ac70f0Sopenharmony_ci	struct list_head *base, *pos;
1554d5ac70f0Sopenharmony_ci	struct tplg_elem *elem;
1555d5ac70f0Sopenharmony_ci	int err = 0;
1556d5ac70f0Sopenharmony_ci
1557d5ac70f0Sopenharmony_ci	base = &tplg->pdata_list;
1558d5ac70f0Sopenharmony_ci	list_for_each(pos, base) {
1559d5ac70f0Sopenharmony_ci
1560d5ac70f0Sopenharmony_ci		elem = list_entry(pos, struct tplg_elem, list);
1561d5ac70f0Sopenharmony_ci		if (has_tuples(elem)) {
1562d5ac70f0Sopenharmony_ci			err = build_tuples(tplg, elem);
1563d5ac70f0Sopenharmony_ci			if (err < 0)
1564d5ac70f0Sopenharmony_ci				return err;
1565d5ac70f0Sopenharmony_ci		}
1566d5ac70f0Sopenharmony_ci	}
1567d5ac70f0Sopenharmony_ci
1568d5ac70f0Sopenharmony_ci	return 0;
1569d5ac70f0Sopenharmony_ci}
1570d5ac70f0Sopenharmony_ci
1571d5ac70f0Sopenharmony_ci/* decode manifest data */
1572d5ac70f0Sopenharmony_ciint tplg_decode_manifest_data(snd_tplg_t *tplg,
1573d5ac70f0Sopenharmony_ci			      size_t pos,
1574d5ac70f0Sopenharmony_ci			      struct snd_soc_tplg_hdr *hdr,
1575d5ac70f0Sopenharmony_ci			      void *bin, size_t size)
1576d5ac70f0Sopenharmony_ci{
1577d5ac70f0Sopenharmony_ci	struct snd_soc_tplg_manifest *m = bin;
1578d5ac70f0Sopenharmony_ci	struct tplg_elem *elem;
1579d5ac70f0Sopenharmony_ci	size_t off;
1580d5ac70f0Sopenharmony_ci
1581d5ac70f0Sopenharmony_ci	if (hdr->index != 0) {
1582d5ac70f0Sopenharmony_ci		SNDERR("manifest - wrong index %d", hdr->index);
1583d5ac70f0Sopenharmony_ci		return -EINVAL;
1584d5ac70f0Sopenharmony_ci	}
1585d5ac70f0Sopenharmony_ci
1586d5ac70f0Sopenharmony_ci	if (sizeof(*m) > size) {
1587d5ac70f0Sopenharmony_ci		SNDERR("manifest - wrong size %zd (minimal %zd)",
1588d5ac70f0Sopenharmony_ci		       size, sizeof(*m));
1589d5ac70f0Sopenharmony_ci		return -EINVAL;
1590d5ac70f0Sopenharmony_ci	}
1591d5ac70f0Sopenharmony_ci
1592d5ac70f0Sopenharmony_ci	if (m->size != sizeof(*m)) {
1593d5ac70f0Sopenharmony_ci		SNDERR("manifest - wrong sructure size %d", m->size);
1594d5ac70f0Sopenharmony_ci		return -EINVAL;
1595d5ac70f0Sopenharmony_ci	}
1596d5ac70f0Sopenharmony_ci
1597d5ac70f0Sopenharmony_ci	off = offsetof(struct snd_soc_tplg_manifest, priv);
1598d5ac70f0Sopenharmony_ci	if (off + m->priv.size > size) {
1599d5ac70f0Sopenharmony_ci		SNDERR("manifest - wrong private size %d", m->priv.size);
1600d5ac70f0Sopenharmony_ci		return -EINVAL;
1601d5ac70f0Sopenharmony_ci	}
1602d5ac70f0Sopenharmony_ci
1603d5ac70f0Sopenharmony_ci	tplg->manifest = *m;
1604d5ac70f0Sopenharmony_ci
1605d5ac70f0Sopenharmony_ci	bin += off;
1606d5ac70f0Sopenharmony_ci	size -= off;
1607d5ac70f0Sopenharmony_ci	pos += off;
1608d5ac70f0Sopenharmony_ci
1609d5ac70f0Sopenharmony_ci	elem = tplg_elem_new_common(tplg, NULL, "manifest",
1610d5ac70f0Sopenharmony_ci				    SND_TPLG_TYPE_MANIFEST);
1611d5ac70f0Sopenharmony_ci	if (!elem)
1612d5ac70f0Sopenharmony_ci		return -ENOMEM;
1613d5ac70f0Sopenharmony_ci
1614d5ac70f0Sopenharmony_ci	tplg_log(tplg, 'D', pos, "manifest: private size %zd", size);
1615d5ac70f0Sopenharmony_ci	return tplg_add_data(tplg, elem, bin, size);
1616d5ac70f0Sopenharmony_ci}
1617d5ac70f0Sopenharmony_ci
1618d5ac70f0Sopenharmony_ciint tplg_add_token(snd_tplg_t *tplg, struct tplg_elem *parent,
1619d5ac70f0Sopenharmony_ci		   unsigned int token,
1620d5ac70f0Sopenharmony_ci		   char str_ref[SNDRV_CTL_ELEM_ID_NAME_MAXLEN])
1621d5ac70f0Sopenharmony_ci{
1622d5ac70f0Sopenharmony_ci	struct tplg_elem *elem;
1623d5ac70f0Sopenharmony_ci	struct tplg_token *t;
1624d5ac70f0Sopenharmony_ci	struct tplg_vendor_tokens *tokens;
1625d5ac70f0Sopenharmony_ci	unsigned int i;
1626d5ac70f0Sopenharmony_ci	size_t size;
1627d5ac70f0Sopenharmony_ci
1628d5ac70f0Sopenharmony_ci	elem = tplg_elem_lookup(&tplg->token_list, parent->id,
1629d5ac70f0Sopenharmony_ci				SND_TPLG_TYPE_TOKEN, parent->index);
1630d5ac70f0Sopenharmony_ci	if (elem == NULL) {
1631d5ac70f0Sopenharmony_ci		elem = tplg_elem_new_common(tplg, NULL, parent->id,
1632d5ac70f0Sopenharmony_ci					    SND_TPLG_TYPE_TOKEN);
1633d5ac70f0Sopenharmony_ci		if (!elem)
1634d5ac70f0Sopenharmony_ci			return -ENOMEM;
1635d5ac70f0Sopenharmony_ci	}
1636d5ac70f0Sopenharmony_ci
1637d5ac70f0Sopenharmony_ci	tokens = elem->tokens;
1638d5ac70f0Sopenharmony_ci	if (tokens) {
1639d5ac70f0Sopenharmony_ci		for (i = 0; i < tokens->num_tokens; i++) {
1640d5ac70f0Sopenharmony_ci			t = &tokens->token[i];
1641d5ac70f0Sopenharmony_ci			if (t->value == token)
1642d5ac70f0Sopenharmony_ci				goto found;
1643d5ac70f0Sopenharmony_ci		}
1644d5ac70f0Sopenharmony_ci		size = sizeof(*tokens) +
1645d5ac70f0Sopenharmony_ci		       (tokens->num_tokens + 1) * sizeof(struct tplg_token);
1646d5ac70f0Sopenharmony_ci		tokens = realloc(tokens, size);
1647d5ac70f0Sopenharmony_ci	} else {
1648d5ac70f0Sopenharmony_ci		size = sizeof(*tokens) + 1 * sizeof(struct tplg_token);
1649d5ac70f0Sopenharmony_ci		tokens = calloc(1, size);
1650d5ac70f0Sopenharmony_ci	}
1651d5ac70f0Sopenharmony_ci
1652d5ac70f0Sopenharmony_ci	if (!tokens)
1653d5ac70f0Sopenharmony_ci		return -ENOMEM;
1654d5ac70f0Sopenharmony_ci
1655d5ac70f0Sopenharmony_ci	memset(&tokens->token[tokens->num_tokens], 0, sizeof(struct tplg_token));
1656d5ac70f0Sopenharmony_ci	elem->tokens = tokens;
1657d5ac70f0Sopenharmony_ci	t = &tokens->token[tokens->num_tokens];
1658d5ac70f0Sopenharmony_ci	tokens->num_tokens++;
1659d5ac70f0Sopenharmony_ci	snprintf(t->id, sizeof(t->id), "token%u", token);
1660d5ac70f0Sopenharmony_ci	t->value = token;
1661d5ac70f0Sopenharmony_cifound:
1662d5ac70f0Sopenharmony_ci	snd_strlcpy(str_ref, t->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
1663d5ac70f0Sopenharmony_ci	return 0;
1664d5ac70f0Sopenharmony_ci}
1665d5ac70f0Sopenharmony_ci
1666d5ac70f0Sopenharmony_cistatic int tplg_verify_tuple_set(snd_tplg_t *tplg, size_t pos,
1667d5ac70f0Sopenharmony_ci				 const void *bin, size_t size)
1668d5ac70f0Sopenharmony_ci{
1669d5ac70f0Sopenharmony_ci	const struct snd_soc_tplg_vendor_array *va;
1670d5ac70f0Sopenharmony_ci	unsigned int j;
1671d5ac70f0Sopenharmony_ci
1672d5ac70f0Sopenharmony_ci	va = bin;
1673d5ac70f0Sopenharmony_ci	if (size < sizeof(*va) || size < va->size) {
1674d5ac70f0Sopenharmony_ci		tplg_log(tplg, 'A', pos, "tuple set verify: wrong size %zd", size);
1675d5ac70f0Sopenharmony_ci		return -EINVAL;
1676d5ac70f0Sopenharmony_ci	}
1677d5ac70f0Sopenharmony_ci
1678d5ac70f0Sopenharmony_ci	switch (va->type) {
1679d5ac70f0Sopenharmony_ci	case SND_SOC_TPLG_TUPLE_TYPE_UUID:
1680d5ac70f0Sopenharmony_ci	case SND_SOC_TPLG_TUPLE_TYPE_STRING:
1681d5ac70f0Sopenharmony_ci	case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
1682d5ac70f0Sopenharmony_ci	case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
1683d5ac70f0Sopenharmony_ci	case SND_SOC_TPLG_TUPLE_TYPE_WORD:
1684d5ac70f0Sopenharmony_ci	case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
1685d5ac70f0Sopenharmony_ci		break;
1686d5ac70f0Sopenharmony_ci	default:
1687d5ac70f0Sopenharmony_ci		tplg_log(tplg, 'A', pos, "tuple set verify: unknown array type %d", va->type);
1688d5ac70f0Sopenharmony_ci		return -EINVAL;
1689d5ac70f0Sopenharmony_ci	}
1690d5ac70f0Sopenharmony_ci
1691d5ac70f0Sopenharmony_ci	j = tplg_get_tuple_size(va->type) * va->num_elems;
1692d5ac70f0Sopenharmony_ci	if (j + sizeof(*va) != va->size) {
1693d5ac70f0Sopenharmony_ci		tplg_log(tplg, 'A', pos, "tuple set verify: wrong vendor array size %d "
1694d5ac70f0Sopenharmony_ci			 "(expected %d for %d count %d)",
1695d5ac70f0Sopenharmony_ci			 va->size, j + sizeof(*va), va->type, va->num_elems);
1696d5ac70f0Sopenharmony_ci		return -EINVAL;
1697d5ac70f0Sopenharmony_ci	}
1698d5ac70f0Sopenharmony_ci
1699d5ac70f0Sopenharmony_ci	if (va->num_elems > 4096) {
1700d5ac70f0Sopenharmony_ci		tplg_log(tplg, 'A', pos, "tuple set verify: tuples overflow %d", va->num_elems);
1701d5ac70f0Sopenharmony_ci		return -EINVAL;
1702d5ac70f0Sopenharmony_ci	}
1703d5ac70f0Sopenharmony_ci
1704d5ac70f0Sopenharmony_ci	return 0;
1705d5ac70f0Sopenharmony_ci}
1706d5ac70f0Sopenharmony_ci
1707d5ac70f0Sopenharmony_cistatic int tplg_decode_tuple_set(snd_tplg_t *tplg,
1708d5ac70f0Sopenharmony_ci				 size_t pos,
1709d5ac70f0Sopenharmony_ci				 struct tplg_elem *parent,
1710d5ac70f0Sopenharmony_ci				 struct tplg_tuple_set **_set,
1711d5ac70f0Sopenharmony_ci				 const void *bin, size_t size)
1712d5ac70f0Sopenharmony_ci{
1713d5ac70f0Sopenharmony_ci	const struct snd_soc_tplg_vendor_array *va;
1714d5ac70f0Sopenharmony_ci	struct tplg_tuple_set *set;
1715d5ac70f0Sopenharmony_ci	struct tplg_tuple *tuple;
1716d5ac70f0Sopenharmony_ci	unsigned int j;
1717d5ac70f0Sopenharmony_ci	int err;
1718d5ac70f0Sopenharmony_ci
1719d5ac70f0Sopenharmony_ci	va = bin;
1720d5ac70f0Sopenharmony_ci	if (size < sizeof(*va) || size < va->size) {
1721d5ac70f0Sopenharmony_ci		SNDERR("tuples: wrong size %zd", size);
1722d5ac70f0Sopenharmony_ci		return -EINVAL;
1723d5ac70f0Sopenharmony_ci	}
1724d5ac70f0Sopenharmony_ci
1725d5ac70f0Sopenharmony_ci	switch (va->type) {
1726d5ac70f0Sopenharmony_ci	case SND_SOC_TPLG_TUPLE_TYPE_UUID:
1727d5ac70f0Sopenharmony_ci	case SND_SOC_TPLG_TUPLE_TYPE_STRING:
1728d5ac70f0Sopenharmony_ci	case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
1729d5ac70f0Sopenharmony_ci	case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
1730d5ac70f0Sopenharmony_ci	case SND_SOC_TPLG_TUPLE_TYPE_WORD:
1731d5ac70f0Sopenharmony_ci	case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
1732d5ac70f0Sopenharmony_ci		break;
1733d5ac70f0Sopenharmony_ci	default:
1734d5ac70f0Sopenharmony_ci		SNDERR("tuples: unknown array type %d", va->type);
1735d5ac70f0Sopenharmony_ci		return -EINVAL;
1736d5ac70f0Sopenharmony_ci	}
1737d5ac70f0Sopenharmony_ci
1738d5ac70f0Sopenharmony_ci	j = tplg_get_tuple_size(va->type) * va->num_elems;
1739d5ac70f0Sopenharmony_ci	if (j + sizeof(*va) != va->size) {
1740d5ac70f0Sopenharmony_ci		SNDERR("tuples: wrong vendor array size %d "
1741d5ac70f0Sopenharmony_ci		       "(expected %d for %d count %d)",
1742d5ac70f0Sopenharmony_ci		       va->size, j + sizeof(*va), va->type, va->num_elems);
1743d5ac70f0Sopenharmony_ci		return -EINVAL;
1744d5ac70f0Sopenharmony_ci	}
1745d5ac70f0Sopenharmony_ci
1746d5ac70f0Sopenharmony_ci	if (va->num_elems > 4096) {
1747d5ac70f0Sopenharmony_ci		SNDERR("tuples: tuples overflow %d", va->num_elems);
1748d5ac70f0Sopenharmony_ci		return -EINVAL;
1749d5ac70f0Sopenharmony_ci	}
1750d5ac70f0Sopenharmony_ci
1751d5ac70f0Sopenharmony_ci	set = calloc(1, sizeof(*set) + va->num_elems * sizeof(struct tplg_tuple));
1752d5ac70f0Sopenharmony_ci	if (!set)
1753d5ac70f0Sopenharmony_ci		return -ENOMEM;
1754d5ac70f0Sopenharmony_ci
1755d5ac70f0Sopenharmony_ci	set->type = va->type;
1756d5ac70f0Sopenharmony_ci	set->num_tuples = va->num_elems;
1757d5ac70f0Sopenharmony_ci
1758d5ac70f0Sopenharmony_ci	tplg_log(tplg, 'A', pos, "tuple set: type %d (%s) tuples %d size %d", set->type,
1759d5ac70f0Sopenharmony_ci		 get_tuple_type_name(set->type), set->num_tuples, va->size);
1760d5ac70f0Sopenharmony_ci	for (j = 0; j < set->num_tuples; j++) {
1761d5ac70f0Sopenharmony_ci		tuple = &set->tuple[j];
1762d5ac70f0Sopenharmony_ci		switch (va->type) {
1763d5ac70f0Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
1764d5ac70f0Sopenharmony_ci			err = tplg_add_token(tplg, parent, va->uuid[j].token,
1765d5ac70f0Sopenharmony_ci					     tuple->token);
1766d5ac70f0Sopenharmony_ci			if (err < 0)
1767d5ac70f0Sopenharmony_ci				goto retval;
1768d5ac70f0Sopenharmony_ci			memcpy(tuple->uuid, va->uuid[j].uuid,
1769d5ac70f0Sopenharmony_ci			       sizeof(va->uuid[j].uuid));
1770d5ac70f0Sopenharmony_ci			break;
1771d5ac70f0Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
1772d5ac70f0Sopenharmony_ci			err = tplg_add_token(tplg, parent, va->string[j].token,
1773d5ac70f0Sopenharmony_ci					     tuple->token);
1774d5ac70f0Sopenharmony_ci			if (err < 0)
1775d5ac70f0Sopenharmony_ci				goto retval;
1776d5ac70f0Sopenharmony_ci			snd_strlcpy(tuple->string, va->string[j].string,
1777d5ac70f0Sopenharmony_ci				    sizeof(tuple->string));
1778d5ac70f0Sopenharmony_ci			break;
1779d5ac70f0Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
1780d5ac70f0Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
1781d5ac70f0Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_WORD:
1782d5ac70f0Sopenharmony_ci		case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
1783d5ac70f0Sopenharmony_ci			err = tplg_add_token(tplg, parent, va->value[j].token,
1784d5ac70f0Sopenharmony_ci					     tuple->token);
1785d5ac70f0Sopenharmony_ci			if (err < 0)
1786d5ac70f0Sopenharmony_ci				goto retval;
1787d5ac70f0Sopenharmony_ci			tuple->value = va->value[j].value;
1788d5ac70f0Sopenharmony_ci			break;
1789d5ac70f0Sopenharmony_ci		}
1790d5ac70f0Sopenharmony_ci	}
1791d5ac70f0Sopenharmony_ci
1792d5ac70f0Sopenharmony_ci	*_set = set;
1793d5ac70f0Sopenharmony_ci	return 0;
1794d5ac70f0Sopenharmony_ci
1795d5ac70f0Sopenharmony_ciretval:
1796d5ac70f0Sopenharmony_ci	free(set);
1797d5ac70f0Sopenharmony_ci	return err;
1798d5ac70f0Sopenharmony_ci}
1799d5ac70f0Sopenharmony_ci
1800d5ac70f0Sopenharmony_ci/* verify tuples from the binary input */
1801d5ac70f0Sopenharmony_cistatic int tplg_verify_tuples(snd_tplg_t *tplg, size_t pos,
1802d5ac70f0Sopenharmony_ci			      const void *bin, size_t size)
1803d5ac70f0Sopenharmony_ci{
1804d5ac70f0Sopenharmony_ci	const struct snd_soc_tplg_vendor_array *va;
1805d5ac70f0Sopenharmony_ci	int err;
1806d5ac70f0Sopenharmony_ci
1807d5ac70f0Sopenharmony_ci	if (size < sizeof(*va)) {
1808d5ac70f0Sopenharmony_ci		tplg_log(tplg, 'A', pos, "tuples: small size %zd", size);
1809d5ac70f0Sopenharmony_ci		return -EINVAL;
1810d5ac70f0Sopenharmony_ci	}
1811d5ac70f0Sopenharmony_ci
1812d5ac70f0Sopenharmony_cinext:
1813d5ac70f0Sopenharmony_ci	va = bin;
1814d5ac70f0Sopenharmony_ci	if (size < sizeof(*va)) {
1815d5ac70f0Sopenharmony_ci		tplg_log(tplg, 'A', pos, "tuples: unexpected vendor arry size %zd", size);
1816d5ac70f0Sopenharmony_ci		return -EINVAL;
1817d5ac70f0Sopenharmony_ci	}
1818d5ac70f0Sopenharmony_ci
1819d5ac70f0Sopenharmony_ci	err = tplg_verify_tuple_set(tplg, pos, va, va->size);
1820d5ac70f0Sopenharmony_ci	if (err < 0)
1821d5ac70f0Sopenharmony_ci		return err;
1822d5ac70f0Sopenharmony_ci
1823d5ac70f0Sopenharmony_ci	bin += va->size;
1824d5ac70f0Sopenharmony_ci	size -= va->size;
1825d5ac70f0Sopenharmony_ci	pos += va->size;
1826d5ac70f0Sopenharmony_ci	if (size > 0)
1827d5ac70f0Sopenharmony_ci		goto next;
1828d5ac70f0Sopenharmony_ci
1829d5ac70f0Sopenharmony_ci	return 0;
1830d5ac70f0Sopenharmony_ci}
1831d5ac70f0Sopenharmony_ci
1832d5ac70f0Sopenharmony_ci/* add tuples from the binary input */
1833d5ac70f0Sopenharmony_cistatic int tplg_decode_tuples(snd_tplg_t *tplg,
1834d5ac70f0Sopenharmony_ci			      size_t pos,
1835d5ac70f0Sopenharmony_ci			      struct tplg_elem *parent,
1836d5ac70f0Sopenharmony_ci			      struct tplg_vendor_tuples *tuples,
1837d5ac70f0Sopenharmony_ci			      const void *bin, size_t size)
1838d5ac70f0Sopenharmony_ci{
1839d5ac70f0Sopenharmony_ci	const struct snd_soc_tplg_vendor_array *va;
1840d5ac70f0Sopenharmony_ci	struct tplg_tuple_set *set;
1841d5ac70f0Sopenharmony_ci	int err;
1842d5ac70f0Sopenharmony_ci
1843d5ac70f0Sopenharmony_ci	if (size < sizeof(*va)) {
1844d5ac70f0Sopenharmony_ci		SNDERR("tuples: small size %zd", size);
1845d5ac70f0Sopenharmony_ci		return -EINVAL;
1846d5ac70f0Sopenharmony_ci	}
1847d5ac70f0Sopenharmony_ci
1848d5ac70f0Sopenharmony_cinext:
1849d5ac70f0Sopenharmony_ci	va = bin;
1850d5ac70f0Sopenharmony_ci	if (size < sizeof(*va)) {
1851d5ac70f0Sopenharmony_ci		SNDERR("tuples: unexpected vendor arry size %zd", size);
1852d5ac70f0Sopenharmony_ci		return -EINVAL;
1853d5ac70f0Sopenharmony_ci	}
1854d5ac70f0Sopenharmony_ci
1855d5ac70f0Sopenharmony_ci	if (tuples->num_sets >= tuples->alloc_sets) {
1856d5ac70f0Sopenharmony_ci		SNDERR("tuples: index overflow (%d)", tuples->num_sets);
1857d5ac70f0Sopenharmony_ci		return -EINVAL;
1858d5ac70f0Sopenharmony_ci	}
1859d5ac70f0Sopenharmony_ci
1860d5ac70f0Sopenharmony_ci	err = tplg_decode_tuple_set(tplg, pos, parent, &set, va, va->size);
1861d5ac70f0Sopenharmony_ci	if (err < 0)
1862d5ac70f0Sopenharmony_ci		return err;
1863d5ac70f0Sopenharmony_ci	tuples->set[tuples->num_sets++] = set;
1864d5ac70f0Sopenharmony_ci
1865d5ac70f0Sopenharmony_ci	bin += va->size;
1866d5ac70f0Sopenharmony_ci	size -= va->size;
1867d5ac70f0Sopenharmony_ci	pos += va->size;
1868d5ac70f0Sopenharmony_ci	if (size > 0)
1869d5ac70f0Sopenharmony_ci		goto next;
1870d5ac70f0Sopenharmony_ci
1871d5ac70f0Sopenharmony_ci	return 0;
1872d5ac70f0Sopenharmony_ci}
1873d5ac70f0Sopenharmony_ci
1874d5ac70f0Sopenharmony_ci/* decode private data */
1875d5ac70f0Sopenharmony_ciint tplg_add_data(snd_tplg_t *tplg,
1876d5ac70f0Sopenharmony_ci		  struct tplg_elem *parent,
1877d5ac70f0Sopenharmony_ci		  const void *bin, size_t size)
1878d5ac70f0Sopenharmony_ci{
1879d5ac70f0Sopenharmony_ci	const struct snd_soc_tplg_private *tp;
1880d5ac70f0Sopenharmony_ci	const struct snd_soc_tplg_vendor_array *va;
1881d5ac70f0Sopenharmony_ci	struct tplg_elem *elem = NULL, *elem2 = NULL;
1882d5ac70f0Sopenharmony_ci	struct tplg_vendor_tuples *tuples = NULL;
1883d5ac70f0Sopenharmony_ci	char id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
1884d5ac70f0Sopenharmony_ci	char suffix[16];
1885d5ac70f0Sopenharmony_ci	size_t pos = 0, off;
1886d5ac70f0Sopenharmony_ci	int err, num_tuples = 0, block = 0;
1887d5ac70f0Sopenharmony_ci
1888d5ac70f0Sopenharmony_ci	if (size == 0)
1889d5ac70f0Sopenharmony_ci		return 0;
1890d5ac70f0Sopenharmony_ci
1891d5ac70f0Sopenharmony_ci	off = offsetof(struct snd_soc_tplg_private, array);
1892d5ac70f0Sopenharmony_ci
1893d5ac70f0Sopenharmony_cinext:
1894d5ac70f0Sopenharmony_ci	tp = bin;
1895d5ac70f0Sopenharmony_ci	if (off + size < tp->size) {
1896d5ac70f0Sopenharmony_ci		SNDERR("data: unexpected element size %zd", size);
1897d5ac70f0Sopenharmony_ci		return -EINVAL;
1898d5ac70f0Sopenharmony_ci	}
1899d5ac70f0Sopenharmony_ci
1900d5ac70f0Sopenharmony_ci	if (tplg_verify_tuples(tplg, pos, tp->array, tp->size) < 0) {
1901d5ac70f0Sopenharmony_ci		if (tuples) {
1902d5ac70f0Sopenharmony_ci			err = tplg_ref_add(elem, SND_TPLG_TYPE_TOKEN, parent->id);
1903d5ac70f0Sopenharmony_ci			if (err < 0)
1904d5ac70f0Sopenharmony_ci				return err;
1905d5ac70f0Sopenharmony_ci			err = tplg_ref_add(elem2, SND_TPLG_TYPE_TUPLE, id);
1906d5ac70f0Sopenharmony_ci			if (err < 0)
1907d5ac70f0Sopenharmony_ci				return err;
1908d5ac70f0Sopenharmony_ci			err = tplg_ref_add(parent, SND_TPLG_TYPE_DATA, id);
1909d5ac70f0Sopenharmony_ci			if (err < 0)
1910d5ac70f0Sopenharmony_ci				return err;
1911d5ac70f0Sopenharmony_ci			tuples = NULL;
1912d5ac70f0Sopenharmony_ci		}
1913d5ac70f0Sopenharmony_ci		tplg_log(tplg, 'A', pos, "add bytes: size %d", tp->size);
1914d5ac70f0Sopenharmony_ci		snprintf(suffix, sizeof(suffix), "data%u", block++);
1915d5ac70f0Sopenharmony_ci		err = tplg_add_data_bytes(tplg, parent, suffix, tp->array, tp->size);
1916d5ac70f0Sopenharmony_ci	} else {
1917d5ac70f0Sopenharmony_ci		if (!tuples) {
1918d5ac70f0Sopenharmony_ci			snprintf(id, sizeof(id), "%.30s:tuple%d", parent->id, (block++) & 0xffff);
1919d5ac70f0Sopenharmony_ci			elem = tplg_elem_new_common(tplg, NULL, id, SND_TPLG_TYPE_TUPLE);
1920d5ac70f0Sopenharmony_ci			if (!elem)
1921d5ac70f0Sopenharmony_ci				return -ENOMEM;
1922d5ac70f0Sopenharmony_ci
1923d5ac70f0Sopenharmony_ci			elem2 = tplg_elem_new_common(tplg, NULL, id, SND_TPLG_TYPE_DATA);
1924d5ac70f0Sopenharmony_ci			if (!elem2)
1925d5ac70f0Sopenharmony_ci				return -ENOMEM;
1926d5ac70f0Sopenharmony_ci
1927d5ac70f0Sopenharmony_ci			tuples = calloc(1, sizeof(*tuples));
1928d5ac70f0Sopenharmony_ci			if (!tuples)
1929d5ac70f0Sopenharmony_ci				return -ENOMEM;
1930d5ac70f0Sopenharmony_ci			elem->tuples = tuples;
1931d5ac70f0Sopenharmony_ci
1932d5ac70f0Sopenharmony_ci			tuples->alloc_sets = (size / sizeof(*va)) + 1;
1933d5ac70f0Sopenharmony_ci			tuples->set = calloc(1, tuples->alloc_sets * sizeof(void *));
1934d5ac70f0Sopenharmony_ci			if (!tuples->set) {
1935d5ac70f0Sopenharmony_ci				tuples->alloc_sets = 0;
1936d5ac70f0Sopenharmony_ci				return -ENOMEM;
1937d5ac70f0Sopenharmony_ci			}
1938d5ac70f0Sopenharmony_ci		}
1939d5ac70f0Sopenharmony_ci		tplg_log(tplg, 'A', pos, "decode tuples: size %d", tp->size);
1940d5ac70f0Sopenharmony_ci		err = tplg_decode_tuples(tplg, pos, parent, tuples, tp->array, tp->size);
1941d5ac70f0Sopenharmony_ci		num_tuples++;
1942d5ac70f0Sopenharmony_ci	}
1943d5ac70f0Sopenharmony_ci	if (err < 0)
1944d5ac70f0Sopenharmony_ci		return err;
1945d5ac70f0Sopenharmony_ci
1946d5ac70f0Sopenharmony_ci	bin += off + tp->size;
1947d5ac70f0Sopenharmony_ci	size -= off + tp->size;
1948d5ac70f0Sopenharmony_ci	pos += off + tp->size;
1949d5ac70f0Sopenharmony_ci	if (size > 0)
1950d5ac70f0Sopenharmony_ci		goto next;
1951d5ac70f0Sopenharmony_ci
1952d5ac70f0Sopenharmony_ci	if (tuples && elem && elem2) {
1953d5ac70f0Sopenharmony_ci		err = tplg_ref_add(elem, SND_TPLG_TYPE_TOKEN, parent->id);
1954d5ac70f0Sopenharmony_ci		if (err < 0)
1955d5ac70f0Sopenharmony_ci			return err;
1956d5ac70f0Sopenharmony_ci		err = tplg_ref_add(elem2, SND_TPLG_TYPE_TUPLE, id);
1957d5ac70f0Sopenharmony_ci		if (err < 0)
1958d5ac70f0Sopenharmony_ci			return err;
1959d5ac70f0Sopenharmony_ci		err = tplg_ref_add(parent, SND_TPLG_TYPE_DATA, id);
1960d5ac70f0Sopenharmony_ci		if (err < 0)
1961d5ac70f0Sopenharmony_ci			return err;
1962d5ac70f0Sopenharmony_ci	}
1963d5ac70f0Sopenharmony_ci
1964d5ac70f0Sopenharmony_ci	return 0;
1965d5ac70f0Sopenharmony_ci}
1966d5ac70f0Sopenharmony_ci
1967d5ac70f0Sopenharmony_ci/* add private data - bytes */
1968d5ac70f0Sopenharmony_ciint tplg_add_data_bytes(snd_tplg_t *tplg, struct tplg_elem *parent,
1969d5ac70f0Sopenharmony_ci			const char *suffix, const void *bin, size_t size)
1970d5ac70f0Sopenharmony_ci{
1971d5ac70f0Sopenharmony_ci	struct snd_soc_tplg_private *priv;
1972d5ac70f0Sopenharmony_ci	struct tplg_elem *elem;
1973d5ac70f0Sopenharmony_ci	char id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
1974d5ac70f0Sopenharmony_ci
1975d5ac70f0Sopenharmony_ci	if (suffix)
1976d5ac70f0Sopenharmony_ci		snprintf(id, sizeof(id), "%.30s:%.12s", parent->id, suffix);
1977d5ac70f0Sopenharmony_ci	else
1978d5ac70f0Sopenharmony_ci		snd_strlcpy(id, parent->id, sizeof(id));
1979d5ac70f0Sopenharmony_ci	elem = tplg_elem_new_common(tplg, NULL, id, SND_TPLG_TYPE_DATA);
1980d5ac70f0Sopenharmony_ci	if (!elem)
1981d5ac70f0Sopenharmony_ci		return -ENOMEM;
1982d5ac70f0Sopenharmony_ci
1983d5ac70f0Sopenharmony_ci	priv = malloc(sizeof(*priv) + size);
1984d5ac70f0Sopenharmony_ci	if (!priv)
1985d5ac70f0Sopenharmony_ci		return -ENOMEM;
1986d5ac70f0Sopenharmony_ci	memcpy(priv->data, bin, size);
1987d5ac70f0Sopenharmony_ci	priv->size = size;
1988d5ac70f0Sopenharmony_ci	elem->data = priv;
1989d5ac70f0Sopenharmony_ci
1990d5ac70f0Sopenharmony_ci	return tplg_ref_add(parent, SND_TPLG_TYPE_DATA, id);
1991d5ac70f0Sopenharmony_ci}
1992d5ac70f0Sopenharmony_ci
1993d5ac70f0Sopenharmony_ci/* decode data from the binary input */
1994d5ac70f0Sopenharmony_ciint tplg_decode_data(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
1995d5ac70f0Sopenharmony_ci		     size_t pos ATTRIBUTE_UNUSED,
1996d5ac70f0Sopenharmony_ci		     struct snd_soc_tplg_hdr *hdr ATTRIBUTE_UNUSED,
1997d5ac70f0Sopenharmony_ci		     void *bin ATTRIBUTE_UNUSED,
1998d5ac70f0Sopenharmony_ci		     size_t size ATTRIBUTE_UNUSED)
1999d5ac70f0Sopenharmony_ci{
2000d5ac70f0Sopenharmony_ci	SNDERR("data type not expected");
2001d5ac70f0Sopenharmony_ci	return -EINVAL;
2002d5ac70f0Sopenharmony_ci}
2003