1c72fcc34Sopenharmony_ci/*
2c72fcc34Sopenharmony_ci  Copyright(c) 2021 Intel Corporation
3c72fcc34Sopenharmony_ci  All rights reserved.
4c72fcc34Sopenharmony_ci
5c72fcc34Sopenharmony_ci  This program is free software; you can redistribute it and/or modify
6c72fcc34Sopenharmony_ci  it under the terms of version 2 of the GNU General Public License as
7c72fcc34Sopenharmony_ci  published by the Free Software Foundation.
8c72fcc34Sopenharmony_ci
9c72fcc34Sopenharmony_ci  This program is distributed in the hope that it will be useful, but
10c72fcc34Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
11c72fcc34Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12c72fcc34Sopenharmony_ci  General Public License for more details.
13c72fcc34Sopenharmony_ci
14c72fcc34Sopenharmony_ci  You should have received a copy of the GNU General Public License
15c72fcc34Sopenharmony_ci  along with this program; if not, write to the Free Software
16c72fcc34Sopenharmony_ci  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17c72fcc34Sopenharmony_ci  The full GNU General Public License is included in this distribution
18c72fcc34Sopenharmony_ci  in the file called LICENSE.GPL.
19c72fcc34Sopenharmony_ci*/
20c72fcc34Sopenharmony_ci#include "aconfig.h"
21c72fcc34Sopenharmony_ci#include <assert.h>
22c72fcc34Sopenharmony_ci#include <errno.h>
23c72fcc34Sopenharmony_ci#include <stddef.h>
24c72fcc34Sopenharmony_ci#include <stdio.h>
25c72fcc34Sopenharmony_ci#include <string.h>
26c72fcc34Sopenharmony_ci#include <ctype.h>
27c72fcc34Sopenharmony_ci#include <alsa/asoundlib.h>
28c72fcc34Sopenharmony_ci#include "gettext.h"
29c72fcc34Sopenharmony_ci#include "topology.h"
30c72fcc34Sopenharmony_ci#include "pre-processor.h"
31c72fcc34Sopenharmony_ci
32c72fcc34Sopenharmony_ci/* Parse VendorToken object, create the "SectionVendorToken" and save it */
33c72fcc34Sopenharmony_ciint tplg_build_vendor_token_object(struct tplg_pre_processor *tplg_pp,
34c72fcc34Sopenharmony_ci				   snd_config_t *obj_cfg,
35c72fcc34Sopenharmony_ci				   snd_config_t *parent ATTRIBUTE_UNUSED)
36c72fcc34Sopenharmony_ci{
37c72fcc34Sopenharmony_ci	snd_config_iterator_t i, next;
38c72fcc34Sopenharmony_ci	snd_config_t *vtop, *n, *obj;
39c72fcc34Sopenharmony_ci	const char *name;
40c72fcc34Sopenharmony_ci	int ret;
41c72fcc34Sopenharmony_ci
42c72fcc34Sopenharmony_ci	ret = tplg_build_object_from_template(tplg_pp, obj_cfg, &vtop, NULL, false);
43c72fcc34Sopenharmony_ci	if (ret < 0)
44c72fcc34Sopenharmony_ci		return ret;
45c72fcc34Sopenharmony_ci
46c72fcc34Sopenharmony_ci	ret = snd_config_get_id(vtop, &name);
47c72fcc34Sopenharmony_ci	if (ret < 0)
48c72fcc34Sopenharmony_ci		return ret;
49c72fcc34Sopenharmony_ci
50c72fcc34Sopenharmony_ci	/* add the tuples */
51c72fcc34Sopenharmony_ci	obj = tplg_object_get_instance_config(tplg_pp, obj_cfg);
52c72fcc34Sopenharmony_ci	snd_config_for_each(i, next, obj) {
53c72fcc34Sopenharmony_ci		snd_config_t *dst;
54c72fcc34Sopenharmony_ci		const char *id;
55c72fcc34Sopenharmony_ci
56c72fcc34Sopenharmony_ci		n = snd_config_iterator_entry(i);
57c72fcc34Sopenharmony_ci
58c72fcc34Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
59c72fcc34Sopenharmony_ci			continue;
60c72fcc34Sopenharmony_ci
61c72fcc34Sopenharmony_ci		if (!strcmp(id, "name"))
62c72fcc34Sopenharmony_ci			continue;
63c72fcc34Sopenharmony_ci
64c72fcc34Sopenharmony_ci		ret = snd_config_copy(&dst, n);
65c72fcc34Sopenharmony_ci		if (ret < 0) {
66c72fcc34Sopenharmony_ci			SNDERR("Error copying config node %s for '%s'\n", id, name);
67c72fcc34Sopenharmony_ci			return ret;
68c72fcc34Sopenharmony_ci		}
69c72fcc34Sopenharmony_ci
70c72fcc34Sopenharmony_ci		ret = snd_config_add(vtop, dst);
71c72fcc34Sopenharmony_ci		if (ret < 0) {
72c72fcc34Sopenharmony_ci			snd_config_delete(dst);
73c72fcc34Sopenharmony_ci			SNDERR("Error adding vendortoken %s for %s\n", id, name);
74c72fcc34Sopenharmony_ci			return ret;
75c72fcc34Sopenharmony_ci		}
76c72fcc34Sopenharmony_ci	}
77c72fcc34Sopenharmony_ci
78c72fcc34Sopenharmony_ci	return ret;
79c72fcc34Sopenharmony_ci}
80c72fcc34Sopenharmony_ci
81c72fcc34Sopenharmony_ciint tplg_parent_update(struct tplg_pre_processor *tplg_pp, snd_config_t *parent,
82c72fcc34Sopenharmony_ci			  const char *section_name, const char *item_name)
83c72fcc34Sopenharmony_ci{
84c72fcc34Sopenharmony_ci	snd_config_iterator_t i, next;
85c72fcc34Sopenharmony_ci	snd_config_t *child, *cfg, *top, *item_config, *n;
86c72fcc34Sopenharmony_ci	const char *parent_name;
87c72fcc34Sopenharmony_ci	char *item_id;
88c72fcc34Sopenharmony_ci	int ret, id = 0;
89c72fcc34Sopenharmony_ci
90c72fcc34Sopenharmony_ci	/* Nothing to do if parent is NULL */
91c72fcc34Sopenharmony_ci	if (!parent)
92c72fcc34Sopenharmony_ci		return 0;
93c72fcc34Sopenharmony_ci
94c72fcc34Sopenharmony_ci	child = tplg_object_get_instance_config(tplg_pp, parent);
95c72fcc34Sopenharmony_ci	ret = snd_config_search(child, "name", &cfg);
96c72fcc34Sopenharmony_ci	if (ret < 0) {
97c72fcc34Sopenharmony_ci		ret = snd_config_get_id(child, &parent_name);
98c72fcc34Sopenharmony_ci		if (ret < 0) {
99c72fcc34Sopenharmony_ci			SNDERR("No name config for parent\n");
100c72fcc34Sopenharmony_ci			return ret;
101c72fcc34Sopenharmony_ci		}
102c72fcc34Sopenharmony_ci	} else {
103c72fcc34Sopenharmony_ci		ret = snd_config_get_string(cfg, &parent_name);
104c72fcc34Sopenharmony_ci		if (ret < 0) {
105c72fcc34Sopenharmony_ci			SNDERR("Invalid name for parent\n");
106c72fcc34Sopenharmony_ci			return ret;
107c72fcc34Sopenharmony_ci		}
108c72fcc34Sopenharmony_ci	}
109c72fcc34Sopenharmony_ci
110c72fcc34Sopenharmony_ci	top = tplg_object_get_section(tplg_pp, parent);
111c72fcc34Sopenharmony_ci	if (!top)
112c72fcc34Sopenharmony_ci		return -EINVAL;
113c72fcc34Sopenharmony_ci
114c72fcc34Sopenharmony_ci	/* get config with name */
115c72fcc34Sopenharmony_ci	cfg = tplg_find_config(top, parent_name);
116c72fcc34Sopenharmony_ci	if (!cfg)
117c72fcc34Sopenharmony_ci		return ret;
118c72fcc34Sopenharmony_ci
119c72fcc34Sopenharmony_ci	/* get section config */
120c72fcc34Sopenharmony_ci	if (!strcmp(section_name, "tlv") || !strcmp(section_name, "texts")) {
121c72fcc34Sopenharmony_ci		/* set tlv name if config exists already */
122c72fcc34Sopenharmony_ci		ret = snd_config_search(cfg, section_name, &item_config);
123c72fcc34Sopenharmony_ci			if (ret < 0) {
124c72fcc34Sopenharmony_ci			ret = tplg_config_make_add(&item_config, section_name,
125c72fcc34Sopenharmony_ci						  SND_CONFIG_TYPE_STRING, cfg);
126c72fcc34Sopenharmony_ci			if (ret < 0) {
127c72fcc34Sopenharmony_ci				SNDERR("Error creating section config widget %s for %s\n",
128c72fcc34Sopenharmony_ci				       section_name, parent_name);
129c72fcc34Sopenharmony_ci				return ret;
130c72fcc34Sopenharmony_ci			}
131c72fcc34Sopenharmony_ci		}
132c72fcc34Sopenharmony_ci
133c72fcc34Sopenharmony_ci		return snd_config_set_string(item_config, item_name);
134c72fcc34Sopenharmony_ci	}
135c72fcc34Sopenharmony_ci
136c72fcc34Sopenharmony_ci	ret = snd_config_search(cfg, section_name, &item_config);
137c72fcc34Sopenharmony_ci	if (ret < 0) {
138c72fcc34Sopenharmony_ci		ret = tplg_config_make_add(&item_config, section_name,
139c72fcc34Sopenharmony_ci					  SND_CONFIG_TYPE_COMPOUND, cfg);
140c72fcc34Sopenharmony_ci		if (ret < 0) {
141c72fcc34Sopenharmony_ci			SNDERR("Error creating section config widget %s for %s\n",
142c72fcc34Sopenharmony_ci			       section_name, parent_name);
143c72fcc34Sopenharmony_ci			return ret;
144c72fcc34Sopenharmony_ci		}
145c72fcc34Sopenharmony_ci	}
146c72fcc34Sopenharmony_ci
147c72fcc34Sopenharmony_ci	snd_config_for_each(i, next, item_config) {
148c72fcc34Sopenharmony_ci		const char *name;
149c72fcc34Sopenharmony_ci
150c72fcc34Sopenharmony_ci		n = snd_config_iterator_entry(i);
151c72fcc34Sopenharmony_ci		if (snd_config_get_string(n, &name) < 0)
152c72fcc34Sopenharmony_ci			continue;
153c72fcc34Sopenharmony_ci
154c72fcc34Sopenharmony_ci		/* item already exists */
155c72fcc34Sopenharmony_ci		if (!strcmp(name, item_name))
156c72fcc34Sopenharmony_ci			return 0;
157c72fcc34Sopenharmony_ci		id++;
158c72fcc34Sopenharmony_ci	}
159c72fcc34Sopenharmony_ci
160c72fcc34Sopenharmony_ci	/* add new item */
161c72fcc34Sopenharmony_ci	item_id = tplg_snprintf("%d", id);
162c72fcc34Sopenharmony_ci	if (!item_id)
163c72fcc34Sopenharmony_ci		return -ENOMEM;
164c72fcc34Sopenharmony_ci
165c72fcc34Sopenharmony_ci	ret = snd_config_make(&cfg, item_id, SND_CONFIG_TYPE_STRING);
166c72fcc34Sopenharmony_ci	free(item_id);
167c72fcc34Sopenharmony_ci	if (ret < 0)
168c72fcc34Sopenharmony_ci		return ret;
169c72fcc34Sopenharmony_ci
170c72fcc34Sopenharmony_ci	ret = snd_config_set_string(cfg, item_name);
171c72fcc34Sopenharmony_ci	if (ret < 0)
172c72fcc34Sopenharmony_ci		return ret;
173c72fcc34Sopenharmony_ci
174c72fcc34Sopenharmony_ci	ret = snd_config_add(item_config, cfg);
175c72fcc34Sopenharmony_ci	if (ret < 0)
176c72fcc34Sopenharmony_ci		snd_config_delete(cfg);
177c72fcc34Sopenharmony_ci
178c72fcc34Sopenharmony_ci	return ret;
179c72fcc34Sopenharmony_ci}
180c72fcc34Sopenharmony_ci
181c72fcc34Sopenharmony_ci/* Parse data object, create the "SectionData" and save it. Only "bytes" data supported for now */
182c72fcc34Sopenharmony_ciint tplg_build_data_object(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
183c72fcc34Sopenharmony_ci			    snd_config_t *parent)
184c72fcc34Sopenharmony_ci{
185c72fcc34Sopenharmony_ci	snd_config_t *dtop;
186c72fcc34Sopenharmony_ci	const char *name;
187c72fcc34Sopenharmony_ci	int ret;
188c72fcc34Sopenharmony_ci
189c72fcc34Sopenharmony_ci	ret = tplg_build_object_from_template(tplg_pp, obj_cfg, &dtop, NULL, false);
190c72fcc34Sopenharmony_ci	if (ret < 0)
191c72fcc34Sopenharmony_ci		return ret;
192c72fcc34Sopenharmony_ci
193c72fcc34Sopenharmony_ci	ret = snd_config_get_id(dtop, &name);
194c72fcc34Sopenharmony_ci	if (ret < 0)
195c72fcc34Sopenharmony_ci		return ret;
196c72fcc34Sopenharmony_ci
197c72fcc34Sopenharmony_ci	return tplg_parent_update(tplg_pp, parent, "data", name);
198c72fcc34Sopenharmony_ci}
199c72fcc34Sopenharmony_ci
200c72fcc34Sopenharmony_cistatic int tplg_create_config_template(struct tplg_pre_processor *tplg_pp ATTRIBUTE_UNUSED,
201c72fcc34Sopenharmony_ci				       snd_config_t **template,
202c72fcc34Sopenharmony_ci				       const struct config_template_items *items)
203c72fcc34Sopenharmony_ci{
204c72fcc34Sopenharmony_ci	snd_config_t *top, *child;
205c72fcc34Sopenharmony_ci	int ret, i;
206c72fcc34Sopenharmony_ci
207c72fcc34Sopenharmony_ci	ret = snd_config_make(&top, "template", SND_CONFIG_TYPE_COMPOUND);
208c72fcc34Sopenharmony_ci	if (ret < 0)
209c72fcc34Sopenharmony_ci		return ret;
210c72fcc34Sopenharmony_ci
211c72fcc34Sopenharmony_ci	/* add integer configs */
212c72fcc34Sopenharmony_ci	for (i = 0; i < MAX_CONFIGS_IN_TEMPLATE; i++)
213c72fcc34Sopenharmony_ci		if (items->int_config_ids[i]) {
214c72fcc34Sopenharmony_ci			ret = tplg_config_make_add(&child, items->int_config_ids[i],
215c72fcc34Sopenharmony_ci						   SND_CONFIG_TYPE_INTEGER, top);
216c72fcc34Sopenharmony_ci			if (ret < 0)
217c72fcc34Sopenharmony_ci				goto err;
218c72fcc34Sopenharmony_ci		}
219c72fcc34Sopenharmony_ci
220c72fcc34Sopenharmony_ci	/* add string configs */
221c72fcc34Sopenharmony_ci	for (i = 0; i < MAX_CONFIGS_IN_TEMPLATE; i++)
222c72fcc34Sopenharmony_ci		if (items->string_config_ids[i]) {
223c72fcc34Sopenharmony_ci			ret = tplg_config_make_add(&child, items->string_config_ids[i],
224c72fcc34Sopenharmony_ci						   SND_CONFIG_TYPE_STRING, top);
225c72fcc34Sopenharmony_ci			if (ret < 0)
226c72fcc34Sopenharmony_ci				goto err;
227c72fcc34Sopenharmony_ci		}
228c72fcc34Sopenharmony_ci
229c72fcc34Sopenharmony_ci	/* add compound configs */
230c72fcc34Sopenharmony_ci	for (i = 0; i < MAX_CONFIGS_IN_TEMPLATE; i++) {
231c72fcc34Sopenharmony_ci		if (items->compound_config_ids[i]) {
232c72fcc34Sopenharmony_ci			ret = tplg_config_make_add(&child, items->compound_config_ids[i],
233c72fcc34Sopenharmony_ci						   SND_CONFIG_TYPE_COMPOUND, top);
234c72fcc34Sopenharmony_ci			if (ret < 0)
235c72fcc34Sopenharmony_ci				goto err;
236c72fcc34Sopenharmony_ci		}
237c72fcc34Sopenharmony_ci	}
238c72fcc34Sopenharmony_ci
239c72fcc34Sopenharmony_cierr:
240c72fcc34Sopenharmony_ci	if (ret < 0) {
241c72fcc34Sopenharmony_ci		snd_config_delete(top);
242c72fcc34Sopenharmony_ci		return ret;
243c72fcc34Sopenharmony_ci	}
244c72fcc34Sopenharmony_ci
245c72fcc34Sopenharmony_ci	*template = top;
246c72fcc34Sopenharmony_ci	return ret;
247c72fcc34Sopenharmony_ci}
248c72fcc34Sopenharmony_ci
249c72fcc34Sopenharmony_cistatic void tplg_attribute_print_valid_values(snd_config_t *valid_values, const char *name)
250c72fcc34Sopenharmony_ci{
251c72fcc34Sopenharmony_ci	snd_config_iterator_t i, next;
252c72fcc34Sopenharmony_ci	snd_config_t *n;
253c72fcc34Sopenharmony_ci
254c72fcc34Sopenharmony_ci	SNDERR("valid values for attribute %s are:\n", name);
255c72fcc34Sopenharmony_ci
256c72fcc34Sopenharmony_ci	snd_config_for_each(i, next, valid_values) {
257c72fcc34Sopenharmony_ci		const char *s, *id;
258c72fcc34Sopenharmony_ci
259c72fcc34Sopenharmony_ci		n = snd_config_iterator_entry(i);
260c72fcc34Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
261c72fcc34Sopenharmony_ci			continue;
262c72fcc34Sopenharmony_ci
263c72fcc34Sopenharmony_ci		if (snd_config_get_string(n, &s) < 0)
264c72fcc34Sopenharmony_ci			continue;
265c72fcc34Sopenharmony_ci
266c72fcc34Sopenharmony_ci		SNDERR("%s", s);
267c72fcc34Sopenharmony_ci	}
268c72fcc34Sopenharmony_ci}
269c72fcc34Sopenharmony_ci
270c72fcc34Sopenharmony_ci/* check is attribute value belongs in the set of valid values */
271c72fcc34Sopenharmony_cistatic bool tplg_is_attribute_valid_value(snd_config_t *valid_values, const char *value)
272c72fcc34Sopenharmony_ci{
273c72fcc34Sopenharmony_ci	snd_config_iterator_t i, next;
274c72fcc34Sopenharmony_ci	snd_config_t *n;
275c72fcc34Sopenharmony_ci
276c72fcc34Sopenharmony_ci	snd_config_for_each(i, next, valid_values) {
277c72fcc34Sopenharmony_ci		const char *s, *id;
278c72fcc34Sopenharmony_ci
279c72fcc34Sopenharmony_ci		n = snd_config_iterator_entry(i);
280c72fcc34Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
281c72fcc34Sopenharmony_ci			continue;
282c72fcc34Sopenharmony_ci
283c72fcc34Sopenharmony_ci		if (snd_config_get_string(n, &s) < 0)
284c72fcc34Sopenharmony_ci			continue;
285c72fcc34Sopenharmony_ci
286c72fcc34Sopenharmony_ci		if (!strcmp(value, s))
287c72fcc34Sopenharmony_ci			return true;
288c72fcc34Sopenharmony_ci	}
289c72fcc34Sopenharmony_ci
290c72fcc34Sopenharmony_ci	return false;
291c72fcc34Sopenharmony_ci}
292c72fcc34Sopenharmony_ci
293c72fcc34Sopenharmony_ci#if SND_LIB_VER(1, 2, 5) < SND_LIB_VERSION
294c72fcc34Sopenharmony_cistatic int pre_process_find_variable(snd_config_t **dst, const char *str, snd_config_t *config);
295c72fcc34Sopenharmony_ci
296c72fcc34Sopenharmony_ci/* check is attribute value belongs in the set of valid values after expanding the valid values */
297c72fcc34Sopenharmony_cistatic bool tplg_is_attribute_valid_expanded_value(struct tplg_pre_processor *tplg_pp,
298c72fcc34Sopenharmony_ci						   snd_config_t *valid_values, int value)
299c72fcc34Sopenharmony_ci{
300c72fcc34Sopenharmony_ci	snd_config_iterator_t i, next;
301c72fcc34Sopenharmony_ci	snd_config_t *n, *var, *conf_defines;
302c72fcc34Sopenharmony_ci	int ret;
303c72fcc34Sopenharmony_ci
304c72fcc34Sopenharmony_ci	ret = snd_config_search(tplg_pp->input_cfg, "Define", &conf_defines);
305c72fcc34Sopenharmony_ci	if (ret < 0)
306c72fcc34Sopenharmony_ci		return false;
307c72fcc34Sopenharmony_ci
308c72fcc34Sopenharmony_ci	snd_config_for_each(i, next, valid_values) {
309c72fcc34Sopenharmony_ci		const char *s, *id;
310c72fcc34Sopenharmony_ci		long v;
311c72fcc34Sopenharmony_ci
312c72fcc34Sopenharmony_ci		n = snd_config_iterator_entry(i);
313c72fcc34Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
314c72fcc34Sopenharmony_ci			continue;
315c72fcc34Sopenharmony_ci
316c72fcc34Sopenharmony_ci		if (snd_config_get_string(n, &s) < 0)
317c72fcc34Sopenharmony_ci			continue;
318c72fcc34Sopenharmony_ci
319c72fcc34Sopenharmony_ci		if (s[0] != '$')
320c72fcc34Sopenharmony_ci			continue;
321c72fcc34Sopenharmony_ci
322c72fcc34Sopenharmony_ci		/* find the variable definition */
323c72fcc34Sopenharmony_ci		ret = pre_process_find_variable(&var, s + 1, conf_defines);
324c72fcc34Sopenharmony_ci		if (ret < 0) {
325c72fcc34Sopenharmony_ci			SNDERR("No definition for variable %s\n", s + 1);
326c72fcc34Sopenharmony_ci			return false;
327c72fcc34Sopenharmony_ci		}
328c72fcc34Sopenharmony_ci
329c72fcc34Sopenharmony_ci		if (snd_config_get_integer(var, &v) < 0) {
330c72fcc34Sopenharmony_ci			SNDERR("Invalid definition for %s\n", s);
331c72fcc34Sopenharmony_ci			snd_config_delete(var);
332c72fcc34Sopenharmony_ci			return false;
333c72fcc34Sopenharmony_ci		}
334c72fcc34Sopenharmony_ci
335c72fcc34Sopenharmony_ci		snd_config_delete(var);
336c72fcc34Sopenharmony_ci
337c72fcc34Sopenharmony_ci		if (value == v)
338c72fcc34Sopenharmony_ci			return true;
339c72fcc34Sopenharmony_ci	}
340c72fcc34Sopenharmony_ci
341c72fcc34Sopenharmony_ci	return false;
342c72fcc34Sopenharmony_ci}
343c72fcc34Sopenharmony_ci#endif
344c72fcc34Sopenharmony_ci
345c72fcc34Sopenharmony_ci/* check if attribute value passes the min/max value constraints */
346c72fcc34Sopenharmony_cistatic bool tplg_object_is_attribute_min_max_valid(snd_config_t *attr, snd_config_t *obj_attr,
347c72fcc34Sopenharmony_ci						   bool min_check)
348c72fcc34Sopenharmony_ci{
349c72fcc34Sopenharmony_ci	snd_config_type_t type = snd_config_get_type(obj_attr);
350c72fcc34Sopenharmony_ci	snd_config_t *valid;
351c72fcc34Sopenharmony_ci	const char *attr_name;
352c72fcc34Sopenharmony_ci	int ret;
353c72fcc34Sopenharmony_ci
354c72fcc34Sopenharmony_ci	if (snd_config_get_id(attr, &attr_name) < 0)
355c72fcc34Sopenharmony_ci		return false;
356c72fcc34Sopenharmony_ci
357c72fcc34Sopenharmony_ci	if (min_check) {
358c72fcc34Sopenharmony_ci		ret = snd_config_search(attr, "constraints.min", &valid);
359c72fcc34Sopenharmony_ci		if (ret < 0)
360c72fcc34Sopenharmony_ci			return true;
361c72fcc34Sopenharmony_ci	} else {
362c72fcc34Sopenharmony_ci		ret = snd_config_search(attr, "constraints.max", &valid);
363c72fcc34Sopenharmony_ci		if (ret < 0)
364c72fcc34Sopenharmony_ci			return true;
365c72fcc34Sopenharmony_ci	}
366c72fcc34Sopenharmony_ci
367c72fcc34Sopenharmony_ci	switch(type) {
368c72fcc34Sopenharmony_ci	case SND_CONFIG_TYPE_INTEGER:
369c72fcc34Sopenharmony_ci	{
370c72fcc34Sopenharmony_ci		long v, m;
371c72fcc34Sopenharmony_ci
372c72fcc34Sopenharmony_ci		if (snd_config_get_integer(valid, &m) < 0)
373c72fcc34Sopenharmony_ci			return true;
374c72fcc34Sopenharmony_ci
375c72fcc34Sopenharmony_ci		if (snd_config_get_integer(obj_attr, &v) < 0)
376c72fcc34Sopenharmony_ci			return false;
377c72fcc34Sopenharmony_ci
378c72fcc34Sopenharmony_ci		if (min_check) {
379c72fcc34Sopenharmony_ci			if (v < m) {
380c72fcc34Sopenharmony_ci				SNDERR("attribute '%s' value: %ld is less than min value: %d\n",
381c72fcc34Sopenharmony_ci				       attr_name, v, m);
382c72fcc34Sopenharmony_ci				return false;
383c72fcc34Sopenharmony_ci			}
384c72fcc34Sopenharmony_ci		} else {
385c72fcc34Sopenharmony_ci			if (v > m) {
386c72fcc34Sopenharmony_ci				SNDERR("attribute '%s' value: %ld is greater than max value: %d\n",
387c72fcc34Sopenharmony_ci				       attr_name, v, m);
388c72fcc34Sopenharmony_ci				return false;
389c72fcc34Sopenharmony_ci			}
390c72fcc34Sopenharmony_ci		}
391c72fcc34Sopenharmony_ci
392c72fcc34Sopenharmony_ci		return true;
393c72fcc34Sopenharmony_ci	}
394c72fcc34Sopenharmony_ci	case SND_CONFIG_TYPE_INTEGER64:
395c72fcc34Sopenharmony_ci	{
396c72fcc34Sopenharmony_ci		long long v;
397c72fcc34Sopenharmony_ci		long m;
398c72fcc34Sopenharmony_ci
399c72fcc34Sopenharmony_ci		if (snd_config_get_integer(valid, &m) < 0)
400c72fcc34Sopenharmony_ci			return true;
401c72fcc34Sopenharmony_ci
402c72fcc34Sopenharmony_ci		if (snd_config_get_integer64(obj_attr, &v) < 0)
403c72fcc34Sopenharmony_ci			return false;
404c72fcc34Sopenharmony_ci
405c72fcc34Sopenharmony_ci		if (min_check) {
406c72fcc34Sopenharmony_ci			if (v < m) {
407c72fcc34Sopenharmony_ci				SNDERR("attribute '%s' value: %ld is less than min value: %d\n",
408c72fcc34Sopenharmony_ci				       attr_name, v, m);
409c72fcc34Sopenharmony_ci				return false;
410c72fcc34Sopenharmony_ci			}
411c72fcc34Sopenharmony_ci		} else {
412c72fcc34Sopenharmony_ci			if (v > m) {
413c72fcc34Sopenharmony_ci				SNDERR("attribute '%s' value: %ld is greater than max value: %d\n",
414c72fcc34Sopenharmony_ci				       attr_name, v, m);
415c72fcc34Sopenharmony_ci				return false;
416c72fcc34Sopenharmony_ci			}
417c72fcc34Sopenharmony_ci		}
418c72fcc34Sopenharmony_ci
419c72fcc34Sopenharmony_ci		return true;
420c72fcc34Sopenharmony_ci	}
421c72fcc34Sopenharmony_ci	default:
422c72fcc34Sopenharmony_ci		break;
423c72fcc34Sopenharmony_ci	}
424c72fcc34Sopenharmony_ci
425c72fcc34Sopenharmony_ci	return false;
426c72fcc34Sopenharmony_ci}
427c72fcc34Sopenharmony_ci
428c72fcc34Sopenharmony_ci/* check for min/max and valid value constraints */
429c72fcc34Sopenharmony_cistatic bool tplg_object_is_attribute_valid(struct tplg_pre_processor *tplg_pp,
430c72fcc34Sopenharmony_ci					   snd_config_t *attr, snd_config_t *obj_attr)
431c72fcc34Sopenharmony_ci{
432c72fcc34Sopenharmony_ci	snd_config_iterator_t i, next;
433c72fcc34Sopenharmony_ci	snd_config_t *valid, *n;
434c72fcc34Sopenharmony_ci	snd_config_type_t type;
435c72fcc34Sopenharmony_ci	const char *attr_name, *obj_value;
436c72fcc34Sopenharmony_ci	int ret;
437c72fcc34Sopenharmony_ci
438c72fcc34Sopenharmony_ci	if (snd_config_get_id(attr, &attr_name) < 0)
439c72fcc34Sopenharmony_ci		return false;
440c72fcc34Sopenharmony_ci
441c72fcc34Sopenharmony_ci	type = snd_config_get_type(obj_attr);
442c72fcc34Sopenharmony_ci
443c72fcc34Sopenharmony_ci	/* check if attribute has valid values */
444c72fcc34Sopenharmony_ci	ret = snd_config_search(attr, "constraints.valid_values", &valid);
445c72fcc34Sopenharmony_ci	if (ret < 0)
446c72fcc34Sopenharmony_ci		goto min_max_check;
447c72fcc34Sopenharmony_ci
448c72fcc34Sopenharmony_ci	switch(type) {
449c72fcc34Sopenharmony_ci	case SND_CONFIG_TYPE_STRING:
450c72fcc34Sopenharmony_ci		if (snd_config_get_string(obj_attr, &obj_value) < 0)
451c72fcc34Sopenharmony_ci			return false;
452c72fcc34Sopenharmony_ci		if (!tplg_is_attribute_valid_value(valid, obj_value)) {
453c72fcc34Sopenharmony_ci			tplg_attribute_print_valid_values(valid, attr_name);
454c72fcc34Sopenharmony_ci			return false;
455c72fcc34Sopenharmony_ci		}
456c72fcc34Sopenharmony_ci		return true;
457c72fcc34Sopenharmony_ci	case SND_CONFIG_TYPE_COMPOUND:
458c72fcc34Sopenharmony_ci		snd_config_for_each(i, next, obj_attr) {
459c72fcc34Sopenharmony_ci			const char *s, *id;
460c72fcc34Sopenharmony_ci
461c72fcc34Sopenharmony_ci			n = snd_config_iterator_entry(i);
462c72fcc34Sopenharmony_ci			if (snd_config_get_id(n, &id) < 0)
463c72fcc34Sopenharmony_ci				continue;
464c72fcc34Sopenharmony_ci
465c72fcc34Sopenharmony_ci			if (snd_config_get_string(n, &s) < 0)
466c72fcc34Sopenharmony_ci				continue;
467c72fcc34Sopenharmony_ci
468c72fcc34Sopenharmony_ci			if (!tplg_is_attribute_valid_value(valid, s)) {
469c72fcc34Sopenharmony_ci				tplg_attribute_print_valid_values(valid, attr_name);
470c72fcc34Sopenharmony_ci				return false;
471c72fcc34Sopenharmony_ci			}
472c72fcc34Sopenharmony_ci		}
473c72fcc34Sopenharmony_ci		return true;
474c72fcc34Sopenharmony_ci#if SND_LIB_VER(1, 2, 5) < SND_LIB_VERSION
475c72fcc34Sopenharmony_ci	case SND_CONFIG_TYPE_INTEGER:
476c72fcc34Sopenharmony_ci	{
477c72fcc34Sopenharmony_ci		long v;
478c72fcc34Sopenharmony_ci
479c72fcc34Sopenharmony_ci		if (snd_config_get_integer(obj_attr, &v) < 0)
480c72fcc34Sopenharmony_ci			return false;
481c72fcc34Sopenharmony_ci
482c72fcc34Sopenharmony_ci		if (!tplg_is_attribute_valid_expanded_value(tplg_pp, valid, v)) {
483c72fcc34Sopenharmony_ci			tplg_attribute_print_valid_values(valid, attr_name);
484c72fcc34Sopenharmony_ci			return false;
485c72fcc34Sopenharmony_ci		}
486c72fcc34Sopenharmony_ci		return true;
487c72fcc34Sopenharmony_ci	}
488c72fcc34Sopenharmony_ci#endif
489c72fcc34Sopenharmony_ci	default:
490c72fcc34Sopenharmony_ci		break;
491c72fcc34Sopenharmony_ci	}
492c72fcc34Sopenharmony_ci
493c72fcc34Sopenharmony_ci	return false;
494c72fcc34Sopenharmony_ci
495c72fcc34Sopenharmony_cimin_max_check:
496c72fcc34Sopenharmony_ci	if (!tplg_object_is_attribute_min_max_valid(attr, obj_attr, true))
497c72fcc34Sopenharmony_ci		return false;
498c72fcc34Sopenharmony_ci
499c72fcc34Sopenharmony_ci	return tplg_object_is_attribute_min_max_valid(attr, obj_attr, false);
500c72fcc34Sopenharmony_ci}
501c72fcc34Sopenharmony_ci
502c72fcc34Sopenharmony_ci/* get object's name attribute value */
503c72fcc34Sopenharmony_ciconst char *tplg_object_get_name(struct tplg_pre_processor *tplg_pp ATTRIBUTE_UNUSED,
504c72fcc34Sopenharmony_ci				 snd_config_t *object)
505c72fcc34Sopenharmony_ci{
506c72fcc34Sopenharmony_ci	snd_config_t *cfg;
507c72fcc34Sopenharmony_ci	const char *name;
508c72fcc34Sopenharmony_ci	int ret;
509c72fcc34Sopenharmony_ci
510c72fcc34Sopenharmony_ci	ret = snd_config_search(object, "name", &cfg);
511c72fcc34Sopenharmony_ci	if (ret < 0)
512c72fcc34Sopenharmony_ci		return NULL;
513c72fcc34Sopenharmony_ci
514c72fcc34Sopenharmony_ci	ret = snd_config_get_string(cfg, &name);
515c72fcc34Sopenharmony_ci	if (ret < 0)
516c72fcc34Sopenharmony_ci		return NULL;
517c72fcc34Sopenharmony_ci
518c72fcc34Sopenharmony_ci	return name;
519c72fcc34Sopenharmony_ci}
520c72fcc34Sopenharmony_ci
521c72fcc34Sopenharmony_ci/* look up the instance of object in a config */
522c72fcc34Sopenharmony_cistatic snd_config_t *tplg_object_lookup_in_config(struct tplg_pre_processor *tplg_pp ATTRIBUTE_UNUSED,
523c72fcc34Sopenharmony_ci						  snd_config_t *class, const char *type,
524c72fcc34Sopenharmony_ci						  const char *class_name, const char *id)
525c72fcc34Sopenharmony_ci{
526c72fcc34Sopenharmony_ci	snd_config_t *obj_cfg = NULL;
527c72fcc34Sopenharmony_ci	char *config_id;
528c72fcc34Sopenharmony_ci
529c72fcc34Sopenharmony_ci	config_id = tplg_snprintf("Object.%s.%s.%s", type, class_name, id);
530c72fcc34Sopenharmony_ci	if (!config_id)
531c72fcc34Sopenharmony_ci		return NULL;
532c72fcc34Sopenharmony_ci
533c72fcc34Sopenharmony_ci	if (snd_config_search(class, config_id, &obj_cfg) < 0)
534c72fcc34Sopenharmony_ci		return NULL;
535c72fcc34Sopenharmony_ci	free(config_id);
536c72fcc34Sopenharmony_ci	return obj_cfg;
537c72fcc34Sopenharmony_ci}
538c72fcc34Sopenharmony_ci
539c72fcc34Sopenharmony_cistatic int tplg_pp_add_object_tuple_section(struct tplg_pre_processor *tplg_pp,
540c72fcc34Sopenharmony_ci					    snd_config_t *class_cfg,
541c72fcc34Sopenharmony_ci					    snd_config_t *attr, char *data_name,
542c72fcc34Sopenharmony_ci					    const char *token_ref, const char *array_name)
543c72fcc34Sopenharmony_ci{
544c72fcc34Sopenharmony_ci	snd_config_t *top, *tuple_cfg, *child, *cfg, *new;
545c72fcc34Sopenharmony_ci	const char *id;
546c72fcc34Sopenharmony_ci	char *token, *type, *str;
547c72fcc34Sopenharmony_ci	long tuple_value;
548c72fcc34Sopenharmony_ci	int ret;
549c72fcc34Sopenharmony_ci
550c72fcc34Sopenharmony_ci	tplg_pp_debug("Building vendor tuples section: '%s' ...", data_name);
551c72fcc34Sopenharmony_ci
552c72fcc34Sopenharmony_ci	ret = snd_config_search(tplg_pp->output_cfg, "SectionVendorTuples", &top);
553c72fcc34Sopenharmony_ci	if (ret < 0) {
554c72fcc34Sopenharmony_ci		ret = tplg_config_make_add(&top, "SectionVendorTuples",
555c72fcc34Sopenharmony_ci					  SND_CONFIG_TYPE_COMPOUND, tplg_pp->output_cfg);
556c72fcc34Sopenharmony_ci		if (ret < 0) {
557c72fcc34Sopenharmony_ci			SNDERR("Error creating SectionVendorTuples config\n");
558c72fcc34Sopenharmony_ci			return ret;
559c72fcc34Sopenharmony_ci		}
560c72fcc34Sopenharmony_ci	}
561c72fcc34Sopenharmony_ci
562c72fcc34Sopenharmony_ci	type = strchr(token_ref, '.');
563c72fcc34Sopenharmony_ci	if(!type) {
564c72fcc34Sopenharmony_ci		SNDERR("Error getting type for %s\n", token_ref);
565c72fcc34Sopenharmony_ci		return -EINVAL;
566c72fcc34Sopenharmony_ci	}
567c72fcc34Sopenharmony_ci
568c72fcc34Sopenharmony_ci	token = calloc(1, strlen(token_ref) - strlen(type) + 1);
569c72fcc34Sopenharmony_ci	if (!token)
570c72fcc34Sopenharmony_ci		return -ENOMEM;
571c72fcc34Sopenharmony_ci	snprintf(token, strlen(token_ref) - strlen(type) + 1, "%s", token_ref);
572c72fcc34Sopenharmony_ci
573c72fcc34Sopenharmony_ci	if (!array_name)
574c72fcc34Sopenharmony_ci		str = strdup(type + 1);
575c72fcc34Sopenharmony_ci	else
576c72fcc34Sopenharmony_ci		str = tplg_snprintf("%s.%s", type + 1, array_name);
577c72fcc34Sopenharmony_ci	if (!str) {
578c72fcc34Sopenharmony_ci		ret = -ENOMEM;
579c72fcc34Sopenharmony_ci		goto free;
580c72fcc34Sopenharmony_ci	}
581c72fcc34Sopenharmony_ci
582c72fcc34Sopenharmony_ci	tuple_cfg = tplg_find_config(top, data_name);
583c72fcc34Sopenharmony_ci	if (!tuple_cfg) {
584c72fcc34Sopenharmony_ci		/* add new SectionVendorTuples */
585c72fcc34Sopenharmony_ci		ret = tplg_config_make_add(&tuple_cfg, data_name, SND_CONFIG_TYPE_COMPOUND, top);
586c72fcc34Sopenharmony_ci		if (ret < 0) {
587c72fcc34Sopenharmony_ci			SNDERR("Error creating new vendor tuples config %s\n", data_name);
588c72fcc34Sopenharmony_ci			goto err;
589c72fcc34Sopenharmony_ci		}
590c72fcc34Sopenharmony_ci
591c72fcc34Sopenharmony_ci		ret = tplg_config_make_add(&child, "tokens", SND_CONFIG_TYPE_STRING,
592c72fcc34Sopenharmony_ci					  tuple_cfg);
593c72fcc34Sopenharmony_ci		if (ret < 0) {
594c72fcc34Sopenharmony_ci			SNDERR("Error creating tokens config for '%s'\n", data_name);
595c72fcc34Sopenharmony_ci			goto err;
596c72fcc34Sopenharmony_ci		}
597c72fcc34Sopenharmony_ci
598c72fcc34Sopenharmony_ci		ret = snd_config_set_string(child, token);
599c72fcc34Sopenharmony_ci		if (ret < 0) {
600c72fcc34Sopenharmony_ci			SNDERR("Error setting tokens config for '%s'\n", data_name);
601c72fcc34Sopenharmony_ci			goto err;
602c72fcc34Sopenharmony_ci		}
603c72fcc34Sopenharmony_ci
604c72fcc34Sopenharmony_ci		ret = tplg_config_make_add(&child, "tuples", SND_CONFIG_TYPE_COMPOUND,
605c72fcc34Sopenharmony_ci					  tuple_cfg);
606c72fcc34Sopenharmony_ci		if (ret < 0) {
607c72fcc34Sopenharmony_ci			SNDERR("Error creating tuples config for '%s'\n", data_name);
608c72fcc34Sopenharmony_ci			goto err;
609c72fcc34Sopenharmony_ci		}
610c72fcc34Sopenharmony_ci
611c72fcc34Sopenharmony_ci		ret = tplg_config_make_add(&cfg, str, SND_CONFIG_TYPE_COMPOUND,
612c72fcc34Sopenharmony_ci					  child);
613c72fcc34Sopenharmony_ci		if (ret < 0) {
614c72fcc34Sopenharmony_ci			SNDERR("Error creating tuples type config for '%s'\n", data_name);
615c72fcc34Sopenharmony_ci			goto err;
616c72fcc34Sopenharmony_ci		}
617c72fcc34Sopenharmony_ci	} else {
618c72fcc34Sopenharmony_ci		snd_config_t *tuples_cfg;
619c72fcc34Sopenharmony_ci
620c72fcc34Sopenharmony_ci		ret = snd_config_search(tuple_cfg, "tuples" , &tuples_cfg);
621c72fcc34Sopenharmony_ci		if (ret < 0) {
622c72fcc34Sopenharmony_ci			SNDERR("can't find tuples config in %s\n", data_name);
623c72fcc34Sopenharmony_ci			goto err;
624c72fcc34Sopenharmony_ci		}
625c72fcc34Sopenharmony_ci
626c72fcc34Sopenharmony_ci		cfg = tplg_find_config(tuples_cfg, str);
627c72fcc34Sopenharmony_ci		if (!cfg) {
628c72fcc34Sopenharmony_ci			ret = tplg_config_make_add(&cfg, str, SND_CONFIG_TYPE_COMPOUND,
629c72fcc34Sopenharmony_ci						  tuples_cfg);
630c72fcc34Sopenharmony_ci			if (ret < 0) {
631c72fcc34Sopenharmony_ci				SNDERR("Error creating tuples config for '%s' and type name %s\n", data_name, str);
632c72fcc34Sopenharmony_ci				goto err;
633c72fcc34Sopenharmony_ci			}
634c72fcc34Sopenharmony_ci		}
635c72fcc34Sopenharmony_ci	}
636c72fcc34Sopenharmony_ci
637c72fcc34Sopenharmony_ci	ret = snd_config_get_id(attr, &id);
638c72fcc34Sopenharmony_ci	if (ret < 0)
639c72fcc34Sopenharmony_ci		goto err;
640c72fcc34Sopenharmony_ci
641c72fcc34Sopenharmony_ci	/* tuple exists already? */
642c72fcc34Sopenharmony_ci	ret = snd_config_search(cfg, id, &child);
643c72fcc34Sopenharmony_ci	if (ret >=0)
644c72fcc34Sopenharmony_ci		goto err;
645c72fcc34Sopenharmony_ci
646c72fcc34Sopenharmony_ci	/* add attribute to tuples */
647c72fcc34Sopenharmony_ci	tuple_value = tplg_class_attribute_valid_tuple_value(tplg_pp, class_cfg, attr);
648c72fcc34Sopenharmony_ci	if (tuple_value < 0) {
649c72fcc34Sopenharmony_ci		/* just copy attribute cfg as is */
650c72fcc34Sopenharmony_ci		ret = snd_config_copy(&new, attr);
651c72fcc34Sopenharmony_ci		if (ret < 0) {
652c72fcc34Sopenharmony_ci			SNDERR("can't copy attribute for %s\n", data_name);
653c72fcc34Sopenharmony_ci			goto err;
654c72fcc34Sopenharmony_ci		}
655c72fcc34Sopenharmony_ci	} else {
656c72fcc34Sopenharmony_ci		ret = snd_config_make(&new, id, SND_CONFIG_TYPE_INTEGER);
657c72fcc34Sopenharmony_ci		if (ret < 0)
658c72fcc34Sopenharmony_ci			goto err;
659c72fcc34Sopenharmony_ci
660c72fcc34Sopenharmony_ci		ret = snd_config_set_integer(new, tuple_value);
661c72fcc34Sopenharmony_ci		if (ret < 0)
662c72fcc34Sopenharmony_ci			goto err;
663c72fcc34Sopenharmony_ci	}
664c72fcc34Sopenharmony_ci
665c72fcc34Sopenharmony_ci	ret = snd_config_add(cfg, new);
666c72fcc34Sopenharmony_cierr:
667c72fcc34Sopenharmony_ci	free(str);
668c72fcc34Sopenharmony_cifree:
669c72fcc34Sopenharmony_ci	free(token);
670c72fcc34Sopenharmony_ci	return ret;
671c72fcc34Sopenharmony_ci}
672c72fcc34Sopenharmony_ci
673c72fcc34Sopenharmony_cistatic int tplg_pp_add_object_data_section(struct tplg_pre_processor *tplg_pp,
674c72fcc34Sopenharmony_ci					   snd_config_t *obj_data, char *data_name)
675c72fcc34Sopenharmony_ci{
676c72fcc34Sopenharmony_ci	snd_config_iterator_t i, next;
677c72fcc34Sopenharmony_ci	snd_config_t *top, *data_cfg, *child;
678c72fcc34Sopenharmony_ci	char *data_id;
679c72fcc34Sopenharmony_ci	int ret, id = 0;
680c72fcc34Sopenharmony_ci
681c72fcc34Sopenharmony_ci	ret = snd_config_search(tplg_pp->output_cfg, "SectionData", &top);
682c72fcc34Sopenharmony_ci	if (ret < 0) {
683c72fcc34Sopenharmony_ci		ret = tplg_config_make_add(&top, "SectionData", SND_CONFIG_TYPE_COMPOUND,
684c72fcc34Sopenharmony_ci					  tplg_pp->output_cfg);
685c72fcc34Sopenharmony_ci		if (ret < 0) {
686c72fcc34Sopenharmony_ci			SNDERR("Failed to add SectionData\n");
687c72fcc34Sopenharmony_ci			return ret;
688c72fcc34Sopenharmony_ci		}
689c72fcc34Sopenharmony_ci	}
690c72fcc34Sopenharmony_ci
691c72fcc34Sopenharmony_ci	/* nothing to do if data section already exists */
692c72fcc34Sopenharmony_ci	data_cfg = tplg_find_config(top, data_name);
693c72fcc34Sopenharmony_ci	if (data_cfg)
694c72fcc34Sopenharmony_ci		return 0;
695c72fcc34Sopenharmony_ci
696c72fcc34Sopenharmony_ci	tplg_pp_debug("Building data section %s ...", data_name);
697c72fcc34Sopenharmony_ci
698c72fcc34Sopenharmony_ci	/* add new SectionData */
699c72fcc34Sopenharmony_ci	ret = tplg_config_make_add(&data_cfg, data_name, SND_CONFIG_TYPE_COMPOUND, top);
700c72fcc34Sopenharmony_ci	if (ret < 0)
701c72fcc34Sopenharmony_ci		return ret;
702c72fcc34Sopenharmony_ci
703c72fcc34Sopenharmony_ci	ret = tplg_config_make_add(&child, "tuples", SND_CONFIG_TYPE_STRING, data_cfg);
704c72fcc34Sopenharmony_ci	if (ret < 0) {
705c72fcc34Sopenharmony_ci		SNDERR("error adding data ref for %s\n", data_name);
706c72fcc34Sopenharmony_ci		return ret;
707c72fcc34Sopenharmony_ci	}
708c72fcc34Sopenharmony_ci
709c72fcc34Sopenharmony_ci	ret = snd_config_set_string(child, data_name);
710c72fcc34Sopenharmony_ci	if (ret < 0) {
711c72fcc34Sopenharmony_ci		SNDERR("error setting tuples ref for %s\n", data_name);
712c72fcc34Sopenharmony_ci		return ret;
713c72fcc34Sopenharmony_ci	}
714c72fcc34Sopenharmony_ci
715c72fcc34Sopenharmony_ci	/* add data item to object */
716c72fcc34Sopenharmony_ci	snd_config_for_each(i, next, obj_data)
717c72fcc34Sopenharmony_ci		id++;
718c72fcc34Sopenharmony_ci
719c72fcc34Sopenharmony_ci	data_id = tplg_snprintf("%d", id);
720c72fcc34Sopenharmony_ci	if (!data_id)
721c72fcc34Sopenharmony_ci		return -ENOMEM;
722c72fcc34Sopenharmony_ci
723c72fcc34Sopenharmony_ci	ret = tplg_config_make_add(&child, data_id, SND_CONFIG_TYPE_STRING, obj_data);
724c72fcc34Sopenharmony_ci	free(data_id);
725c72fcc34Sopenharmony_ci	if (ret < 0) {
726c72fcc34Sopenharmony_ci		SNDERR("error adding data ref %s\n", data_name);
727c72fcc34Sopenharmony_ci		return ret;
728c72fcc34Sopenharmony_ci	}
729c72fcc34Sopenharmony_ci
730c72fcc34Sopenharmony_ci	return snd_config_set_string(child, data_name);
731c72fcc34Sopenharmony_ci}
732c72fcc34Sopenharmony_ci
733c72fcc34Sopenharmony_ciint tplg_add_object_data(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
734c72fcc34Sopenharmony_ci			 snd_config_t *top, const char *array_name)
735c72fcc34Sopenharmony_ci{
736c72fcc34Sopenharmony_ci	snd_config_iterator_t i, next;
737c72fcc34Sopenharmony_ci	snd_config_t *data_cfg, *class_cfg, *n, *obj;
738c72fcc34Sopenharmony_ci	const char *object_id;
739c72fcc34Sopenharmony_ci	int ret;
740c72fcc34Sopenharmony_ci
741c72fcc34Sopenharmony_ci	if (snd_config_get_id(top, &object_id) < 0)
742c72fcc34Sopenharmony_ci		return 0;
743c72fcc34Sopenharmony_ci
744c72fcc34Sopenharmony_ci	obj = tplg_object_get_instance_config(tplg_pp, obj_cfg);
745c72fcc34Sopenharmony_ci
746c72fcc34Sopenharmony_ci	class_cfg = tplg_class_lookup(tplg_pp, obj_cfg);
747c72fcc34Sopenharmony_ci	if (!class_cfg)
748c72fcc34Sopenharmony_ci		return -EINVAL;
749c72fcc34Sopenharmony_ci
750c72fcc34Sopenharmony_ci	/* add data config to top */
751c72fcc34Sopenharmony_ci	ret = snd_config_search(top, "data", &data_cfg);
752c72fcc34Sopenharmony_ci	if (ret < 0) {
753c72fcc34Sopenharmony_ci		ret = tplg_config_make_add(&data_cfg, "data", SND_CONFIG_TYPE_COMPOUND, top);
754c72fcc34Sopenharmony_ci		if (ret < 0) {
755c72fcc34Sopenharmony_ci			SNDERR("error creating data config for %s\n", object_id);
756c72fcc34Sopenharmony_ci			return ret;
757c72fcc34Sopenharmony_ci		}
758c72fcc34Sopenharmony_ci	}
759c72fcc34Sopenharmony_ci
760c72fcc34Sopenharmony_ci	/* add data items to object's data section */
761c72fcc34Sopenharmony_ci	snd_config_for_each(i, next, obj) {
762c72fcc34Sopenharmony_ci		const char *id, *token;
763c72fcc34Sopenharmony_ci		char *data_cfg_name;
764c72fcc34Sopenharmony_ci
765c72fcc34Sopenharmony_ci		n = snd_config_iterator_entry(i);
766c72fcc34Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
767c72fcc34Sopenharmony_ci			continue;
768c72fcc34Sopenharmony_ci
769c72fcc34Sopenharmony_ci		token = tplg_class_get_attribute_token_ref(tplg_pp, class_cfg, id);
770c72fcc34Sopenharmony_ci		if (!token)
771c72fcc34Sopenharmony_ci			continue;
772c72fcc34Sopenharmony_ci
773c72fcc34Sopenharmony_ci		data_cfg_name = tplg_snprintf("%s.%s", object_id, token);
774c72fcc34Sopenharmony_ci		if (!data_cfg_name)
775c72fcc34Sopenharmony_ci			return -ENOMEM;
776c72fcc34Sopenharmony_ci
777c72fcc34Sopenharmony_ci		ret = tplg_pp_add_object_data_section(tplg_pp, data_cfg, data_cfg_name);
778c72fcc34Sopenharmony_ci		if (ret < 0) {
779c72fcc34Sopenharmony_ci			SNDERR("Failed to add data section %s\n", data_cfg_name);
780c72fcc34Sopenharmony_ci			free(data_cfg_name);
781c72fcc34Sopenharmony_ci			return ret;
782c72fcc34Sopenharmony_ci		}
783c72fcc34Sopenharmony_ci
784c72fcc34Sopenharmony_ci		ret = tplg_pp_add_object_tuple_section(tplg_pp, class_cfg, n, data_cfg_name,
785c72fcc34Sopenharmony_ci						       token, array_name);
786c72fcc34Sopenharmony_ci		if (ret < 0) {
787c72fcc34Sopenharmony_ci			SNDERR("Failed to add data section %s\n", data_cfg_name);
788c72fcc34Sopenharmony_ci			free(data_cfg_name);
789c72fcc34Sopenharmony_ci			return ret;
790c72fcc34Sopenharmony_ci		}
791c72fcc34Sopenharmony_ci		free(data_cfg_name);
792c72fcc34Sopenharmony_ci	}
793c72fcc34Sopenharmony_ci
794c72fcc34Sopenharmony_ci	return 0;
795c72fcc34Sopenharmony_ci}
796c72fcc34Sopenharmony_ci
797c72fcc34Sopenharmony_ci/* search for all template configs in the source config and copy them to the destination */
798c72fcc34Sopenharmony_cistatic int tplg_object_add_attributes(snd_config_t *dst, snd_config_t *template,
799c72fcc34Sopenharmony_ci				      snd_config_t *src)
800c72fcc34Sopenharmony_ci{
801c72fcc34Sopenharmony_ci	snd_config_iterator_t i, next;
802c72fcc34Sopenharmony_ci	snd_config_t *n;
803c72fcc34Sopenharmony_ci	int ret;
804c72fcc34Sopenharmony_ci
805c72fcc34Sopenharmony_ci	snd_config_for_each(i, next, template) {
806c72fcc34Sopenharmony_ci		snd_config_t *attr, *new;
807c72fcc34Sopenharmony_ci		const char *id;
808c72fcc34Sopenharmony_ci
809c72fcc34Sopenharmony_ci		n = snd_config_iterator_entry(i);
810c72fcc34Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
811c72fcc34Sopenharmony_ci			continue;
812c72fcc34Sopenharmony_ci
813c72fcc34Sopenharmony_ci		ret = snd_config_search(src, id, &attr);
814c72fcc34Sopenharmony_ci		if (ret < 0)
815c72fcc34Sopenharmony_ci			continue;
816c72fcc34Sopenharmony_ci
817c72fcc34Sopenharmony_ci		/* skip if attribute is already set */
818c72fcc34Sopenharmony_ci		ret = snd_config_search(dst, id, &new);
819c72fcc34Sopenharmony_ci		if (ret >= 0)
820c72fcc34Sopenharmony_ci			continue;
821c72fcc34Sopenharmony_ci
822c72fcc34Sopenharmony_ci		ret = snd_config_copy(&new, attr);
823c72fcc34Sopenharmony_ci		if (ret < 0) {
824c72fcc34Sopenharmony_ci			SNDERR("failed to copy attribute %s\n", id);
825c72fcc34Sopenharmony_ci			return ret;
826c72fcc34Sopenharmony_ci		}
827c72fcc34Sopenharmony_ci
828c72fcc34Sopenharmony_ci		ret = snd_config_add(dst, new);
829c72fcc34Sopenharmony_ci		if (ret < 0) {
830c72fcc34Sopenharmony_ci			snd_config_delete(new);
831c72fcc34Sopenharmony_ci			SNDERR("failed to add attribute %s\n", id);
832c72fcc34Sopenharmony_ci			return ret;
833c72fcc34Sopenharmony_ci		}
834c72fcc34Sopenharmony_ci	}
835c72fcc34Sopenharmony_ci
836c72fcc34Sopenharmony_ci	return 0;
837c72fcc34Sopenharmony_ci}
838c72fcc34Sopenharmony_ci
839c72fcc34Sopenharmony_cistatic const struct build_function_map *tplg_object_get_map(struct tplg_pre_processor *tplg_pp,
840c72fcc34Sopenharmony_ci							    snd_config_t *obj);
841c72fcc34Sopenharmony_ci
842c72fcc34Sopenharmony_ci/* Add object attributes to the private data of the parent object config */
843c72fcc34Sopenharmony_cistatic int tplg_build_parent_data(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
844c72fcc34Sopenharmony_ci				  snd_config_t *parent)
845c72fcc34Sopenharmony_ci{
846c72fcc34Sopenharmony_ci	snd_config_t *obj, *parent_obj, *section_cfg, *top;
847c72fcc34Sopenharmony_ci	const struct build_function_map *map;
848c72fcc34Sopenharmony_ci	const char *id, *parent_id;
849c72fcc34Sopenharmony_ci	int ret;
850c72fcc34Sopenharmony_ci
851c72fcc34Sopenharmony_ci	/* nothing to do if parent is NULL */
852c72fcc34Sopenharmony_ci	if (!parent)
853c72fcc34Sopenharmony_ci		return 0;
854c72fcc34Sopenharmony_ci
855c72fcc34Sopenharmony_ci	obj = tplg_object_get_instance_config(tplg_pp, obj_cfg);
856c72fcc34Sopenharmony_ci	parent_obj = tplg_object_get_instance_config(tplg_pp, parent);
857c72fcc34Sopenharmony_ci
858c72fcc34Sopenharmony_ci	/* get object ID */
859c72fcc34Sopenharmony_ci	if (snd_config_get_id(obj, &id) < 0) {
860c72fcc34Sopenharmony_ci		SNDERR("Invalid ID for object\n");
861c72fcc34Sopenharmony_ci		return -EINVAL;
862c72fcc34Sopenharmony_ci	}
863c72fcc34Sopenharmony_ci
864c72fcc34Sopenharmony_ci	/* get parent object name or ID */
865c72fcc34Sopenharmony_ci	parent_id = tplg_object_get_name(tplg_pp, parent_obj);
866c72fcc34Sopenharmony_ci	if (!parent_id) {
867c72fcc34Sopenharmony_ci		ret = snd_config_get_id(parent_obj, &parent_id);
868c72fcc34Sopenharmony_ci		if (ret < 0) {
869c72fcc34Sopenharmony_ci			SNDERR("Invalid ID for parent of object %s\n", id);
870c72fcc34Sopenharmony_ci			return ret;
871c72fcc34Sopenharmony_ci		}
872c72fcc34Sopenharmony_ci	}
873c72fcc34Sopenharmony_ci
874c72fcc34Sopenharmony_ci	map = tplg_object_get_map(tplg_pp, parent);
875c72fcc34Sopenharmony_ci	if (!map) {
876c72fcc34Sopenharmony_ci		SNDERR("Parent object %s not supported\n", parent_id);
877c72fcc34Sopenharmony_ci		return -EINVAL;
878c72fcc34Sopenharmony_ci	}
879c72fcc34Sopenharmony_ci
880c72fcc34Sopenharmony_ci	/* find parent config with ID */
881c72fcc34Sopenharmony_ci	ret = snd_config_search(tplg_pp->output_cfg, map->section_name, &section_cfg);
882c72fcc34Sopenharmony_ci	if (ret < 0) {
883c72fcc34Sopenharmony_ci		SNDERR("No SectionBE found\n");
884c72fcc34Sopenharmony_ci		return ret;
885c72fcc34Sopenharmony_ci	}
886c72fcc34Sopenharmony_ci
887c72fcc34Sopenharmony_ci	top = tplg_find_config(section_cfg, parent_id);
888c72fcc34Sopenharmony_ci	if (!top) {
889c72fcc34Sopenharmony_ci		SNDERR("SectionBE %s not found\n", parent_id);
890c72fcc34Sopenharmony_ci		return -EINVAL;
891c72fcc34Sopenharmony_ci	}
892c72fcc34Sopenharmony_ci
893c72fcc34Sopenharmony_ci	return tplg_add_object_data(tplg_pp, obj_cfg, top, id);
894c72fcc34Sopenharmony_ci}
895c72fcc34Sopenharmony_ci
896c72fcc34Sopenharmony_ci/*
897c72fcc34Sopenharmony_ci * Function to create a new "section" config based on the template. The new config will be
898c72fcc34Sopenharmony_ci * added to the output_cfg or the top_config input parameter.
899c72fcc34Sopenharmony_ci */
900c72fcc34Sopenharmony_ciint tplg_build_object_from_template(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
901c72fcc34Sopenharmony_ci				    snd_config_t **wtop, snd_config_t *top_config,
902c72fcc34Sopenharmony_ci				    bool skip_name)
903c72fcc34Sopenharmony_ci{
904c72fcc34Sopenharmony_ci	snd_config_t *top, *template, *obj;
905c72fcc34Sopenharmony_ci	const struct build_function_map *map;
906c72fcc34Sopenharmony_ci	const char *object_name;
907c72fcc34Sopenharmony_ci	int ret;
908c72fcc34Sopenharmony_ci
909c72fcc34Sopenharmony_ci	/* look up object map */
910c72fcc34Sopenharmony_ci	map = tplg_object_get_map(tplg_pp, obj_cfg);
911c72fcc34Sopenharmony_ci	if (!map) {
912c72fcc34Sopenharmony_ci		SNDERR("unknown object type or class name\n");
913c72fcc34Sopenharmony_ci		return -EINVAL;
914c72fcc34Sopenharmony_ci	}
915c72fcc34Sopenharmony_ci
916c72fcc34Sopenharmony_ci	obj = tplg_object_get_instance_config(tplg_pp, obj_cfg);
917c72fcc34Sopenharmony_ci
918c72fcc34Sopenharmony_ci	/* look up or create the corresponding section config for object */
919c72fcc34Sopenharmony_ci	if (!top_config)
920c72fcc34Sopenharmony_ci		top_config = tplg_pp->output_cfg;
921c72fcc34Sopenharmony_ci
922c72fcc34Sopenharmony_ci	ret = snd_config_search(top_config, map->section_name, &top);
923c72fcc34Sopenharmony_ci	if (ret < 0) {
924c72fcc34Sopenharmony_ci		ret = tplg_config_make_add(&top, map->section_name, SND_CONFIG_TYPE_COMPOUND,
925c72fcc34Sopenharmony_ci					   top_config);
926c72fcc34Sopenharmony_ci		if (ret < 0) {
927c72fcc34Sopenharmony_ci			SNDERR("Error creating %s config\n", map->section_name);
928c72fcc34Sopenharmony_ci			return ret;
929c72fcc34Sopenharmony_ci		}
930c72fcc34Sopenharmony_ci	}
931c72fcc34Sopenharmony_ci
932c72fcc34Sopenharmony_ci	/* get object name */
933c72fcc34Sopenharmony_ci	object_name = tplg_object_get_name(tplg_pp, obj);
934c72fcc34Sopenharmony_ci	if (!object_name) {
935c72fcc34Sopenharmony_ci		ret = snd_config_get_id(obj, &object_name);
936c72fcc34Sopenharmony_ci		if (ret < 0) {
937c72fcc34Sopenharmony_ci			SNDERR("Invalid ID for %s\n", map->section_name);
938c72fcc34Sopenharmony_ci			return ret;
939c72fcc34Sopenharmony_ci		}
940c72fcc34Sopenharmony_ci	}
941c72fcc34Sopenharmony_ci
942c72fcc34Sopenharmony_ci	tplg_pp_debug("Building object: '%s' ...", object_name);
943c72fcc34Sopenharmony_ci
944c72fcc34Sopenharmony_ci	/* create and add new object config with name, if needed */
945c72fcc34Sopenharmony_ci	if (skip_name) {
946c72fcc34Sopenharmony_ci		*wtop = top;
947c72fcc34Sopenharmony_ci	} else {
948c72fcc34Sopenharmony_ci		*wtop = tplg_find_config(top, object_name);
949c72fcc34Sopenharmony_ci		if (*wtop)
950c72fcc34Sopenharmony_ci			goto template;
951c72fcc34Sopenharmony_ci
952c72fcc34Sopenharmony_ci		ret = tplg_config_make_add(wtop, object_name, SND_CONFIG_TYPE_COMPOUND,
953c72fcc34Sopenharmony_ci					   top);
954c72fcc34Sopenharmony_ci		if (ret < 0) {
955c72fcc34Sopenharmony_ci			SNDERR("Error creating config for %s\n", object_name);
956c72fcc34Sopenharmony_ci			return ret;
957c72fcc34Sopenharmony_ci		}
958c72fcc34Sopenharmony_ci	}
959c72fcc34Sopenharmony_ci
960c72fcc34Sopenharmony_citemplate:
961c72fcc34Sopenharmony_ci	/* create template config */
962c72fcc34Sopenharmony_ci	if (!map->template_items)
963c72fcc34Sopenharmony_ci		return 0;
964c72fcc34Sopenharmony_ci
965c72fcc34Sopenharmony_ci	ret = tplg_create_config_template(tplg_pp, &template, map->template_items);
966c72fcc34Sopenharmony_ci	if (ret < 0) {
967c72fcc34Sopenharmony_ci		SNDERR("Error creating template config for %s\n", object_name);
968c72fcc34Sopenharmony_ci		return ret;
969c72fcc34Sopenharmony_ci	}
970c72fcc34Sopenharmony_ci
971c72fcc34Sopenharmony_ci	/* update section config based on template and the attribute values in the object */
972c72fcc34Sopenharmony_ci	ret = tplg_object_add_attributes(*wtop, template, obj);
973c72fcc34Sopenharmony_ci	snd_config_delete(template);
974c72fcc34Sopenharmony_ci	if (ret < 0)
975c72fcc34Sopenharmony_ci		SNDERR("Error adding attributes for object '%s'\n", object_name);
976c72fcc34Sopenharmony_ci
977c72fcc34Sopenharmony_ci	return ret;
978c72fcc34Sopenharmony_ci}
979c72fcc34Sopenharmony_ci
980c72fcc34Sopenharmony_cistatic int tplg_build_generic_object(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
981c72fcc34Sopenharmony_ci				     snd_config_t *parent ATTRIBUTE_UNUSED)
982c72fcc34Sopenharmony_ci{
983c72fcc34Sopenharmony_ci	snd_config_t *wtop;
984c72fcc34Sopenharmony_ci	const char *name;
985c72fcc34Sopenharmony_ci	int ret;
986c72fcc34Sopenharmony_ci
987c72fcc34Sopenharmony_ci	ret = tplg_build_object_from_template(tplg_pp, obj_cfg, &wtop, NULL, false);
988c72fcc34Sopenharmony_ci	if (ret < 0)
989c72fcc34Sopenharmony_ci		return ret;
990c72fcc34Sopenharmony_ci
991c72fcc34Sopenharmony_ci	ret = snd_config_get_id(wtop, &name);
992c72fcc34Sopenharmony_ci	if (ret < 0)
993c72fcc34Sopenharmony_ci		return ret;
994c72fcc34Sopenharmony_ci
995c72fcc34Sopenharmony_ci	ret = tplg_add_object_data(tplg_pp, obj_cfg, wtop, NULL);
996c72fcc34Sopenharmony_ci	if (ret < 0)
997c72fcc34Sopenharmony_ci		SNDERR("Failed to add data section for %s\n", name);
998c72fcc34Sopenharmony_ci
999c72fcc34Sopenharmony_ci	return ret;
1000c72fcc34Sopenharmony_ci}
1001c72fcc34Sopenharmony_ci
1002c72fcc34Sopenharmony_ciconst struct config_template_items pcm_caps_config = {
1003c72fcc34Sopenharmony_ci	.int_config_ids = {"rate_min", "rate_max", "channels_min", "channels_max", "periods_min",
1004c72fcc34Sopenharmony_ci			   "periods_max", "period_size_min", "period_size_max", "buffer_size_min",
1005c72fcc34Sopenharmony_ci			   "buffer_size_max", "sig_bits"},
1006c72fcc34Sopenharmony_ci	.string_config_ids = {"formats", "rates"},
1007c72fcc34Sopenharmony_ci};
1008c72fcc34Sopenharmony_ci
1009c72fcc34Sopenharmony_ciconst struct config_template_items fe_dai_config = {
1010c72fcc34Sopenharmony_ci	.int_config_ids = {"id"},
1011c72fcc34Sopenharmony_ci};
1012c72fcc34Sopenharmony_ci
1013c72fcc34Sopenharmony_ciconst struct config_template_items hwcfg_config = {
1014c72fcc34Sopenharmony_ci	.int_config_ids = {"id", "bclk_freq", "bclk_invert", "fsync_invert", "fsync_freq",
1015c72fcc34Sopenharmony_ci			   "mclk_freq", "pm_gate_clocks", "tdm_slots", "tdm_slot_width",
1016c72fcc34Sopenharmony_ci			   "tx_slots", "rx_slots", "tx_channels", "rx_channels"},
1017c72fcc34Sopenharmony_ci	.string_config_ids = {"format", "bclk", "fsync", "mclk"},
1018c72fcc34Sopenharmony_ci};
1019c72fcc34Sopenharmony_ci
1020c72fcc34Sopenharmony_ciconst struct config_template_items be_dai_config = {
1021c72fcc34Sopenharmony_ci	.int_config_ids = {"id", "default_hw_conf_id", "symmertic_rates", "symmetric_channels",
1022c72fcc34Sopenharmony_ci			   "symmetric_sample_bits"},
1023c72fcc34Sopenharmony_ci	.string_config_ids = {"stream_name"},
1024c72fcc34Sopenharmony_ci};
1025c72fcc34Sopenharmony_ci
1026c72fcc34Sopenharmony_ciconst struct config_template_items pcm_config = {
1027c72fcc34Sopenharmony_ci	.int_config_ids = {"id", "compress", "symmertic_rates", "symmetric_channels",
1028c72fcc34Sopenharmony_ci			   "symmetric_sample_bits"},
1029c72fcc34Sopenharmony_ci};
1030c72fcc34Sopenharmony_ci
1031c72fcc34Sopenharmony_ciconst struct config_template_items mixer_control_config = {
1032c72fcc34Sopenharmony_ci	.int_config_ids = {"index", "max", "invert"},
1033c72fcc34Sopenharmony_ci	.compound_config_ids = {"access"}
1034c72fcc34Sopenharmony_ci};
1035c72fcc34Sopenharmony_ci
1036c72fcc34Sopenharmony_ciconst struct config_template_items bytes_control_config = {
1037c72fcc34Sopenharmony_ci	.int_config_ids = {"index", "base", "num_regs", "max", "mask"},
1038c72fcc34Sopenharmony_ci	.compound_config_ids = {"access"}
1039c72fcc34Sopenharmony_ci};
1040c72fcc34Sopenharmony_ci
1041c72fcc34Sopenharmony_ciconst struct config_template_items enum_control_config = {
1042c72fcc34Sopenharmony_ci	.int_config_ids = {"index"},
1043c72fcc34Sopenharmony_ci	.compound_config_ids = {"access"}
1044c72fcc34Sopenharmony_ci};
1045c72fcc34Sopenharmony_ci
1046c72fcc34Sopenharmony_ciconst struct config_template_items text_config = {
1047c72fcc34Sopenharmony_ci	.compound_config_ids = {"values"}
1048c72fcc34Sopenharmony_ci};
1049c72fcc34Sopenharmony_ci
1050c72fcc34Sopenharmony_ciconst struct config_template_items scale_config = {
1051c72fcc34Sopenharmony_ci	.int_config_ids = {"min", "step", "mute"},
1052c72fcc34Sopenharmony_ci};
1053c72fcc34Sopenharmony_ci
1054c72fcc34Sopenharmony_ciconst struct config_template_items ops_config = {
1055c72fcc34Sopenharmony_ci	.int_config_ids = {"get", "put"},
1056c72fcc34Sopenharmony_ci	.string_config_ids = {"info"},
1057c72fcc34Sopenharmony_ci};
1058c72fcc34Sopenharmony_ci
1059c72fcc34Sopenharmony_ciconst struct config_template_items channel_config = {
1060c72fcc34Sopenharmony_ci	.int_config_ids = {"reg", "shift"},
1061c72fcc34Sopenharmony_ci};
1062c72fcc34Sopenharmony_ci
1063c72fcc34Sopenharmony_ciconst struct config_template_items widget_config = {
1064c72fcc34Sopenharmony_ci	.int_config_ids = {"index", "no_pm", "shift", "invert", "subseq", "event_type",
1065c72fcc34Sopenharmony_ci			    "event_flags"},
1066c72fcc34Sopenharmony_ci	.string_config_ids = {"type", "stream_name"},
1067c72fcc34Sopenharmony_ci};
1068c72fcc34Sopenharmony_ci
1069c72fcc34Sopenharmony_ciconst struct config_template_items data_config = {
1070c72fcc34Sopenharmony_ci	.string_config_ids = {"bytes"}
1071c72fcc34Sopenharmony_ci};
1072c72fcc34Sopenharmony_ci
1073c72fcc34Sopenharmony_ci/*
1074c72fcc34Sopenharmony_ci * Items without class name should be placed lower than those with one,
1075c72fcc34Sopenharmony_ci * because they are much more generic.
1076c72fcc34Sopenharmony_ci */
1077c72fcc34Sopenharmony_ciconst struct build_function_map object_build_map[] = {
1078c72fcc34Sopenharmony_ci	{"Base", "manifest", "SectionManifest", &tplg_build_generic_object, NULL, NULL},
1079c72fcc34Sopenharmony_ci	{"Base", "data", "SectionData", &tplg_build_data_object, NULL, &data_config},
1080c72fcc34Sopenharmony_ci	{"Base", "tlv", "SectionTLV", &tplg_build_tlv_object, NULL, NULL},
1081c72fcc34Sopenharmony_ci	{"Base", "scale", "scale", &tplg_build_scale_object, NULL, &scale_config},
1082c72fcc34Sopenharmony_ci	{"Base", "ops", "ops" ,&tplg_build_ops_object, NULL, &ops_config},
1083c72fcc34Sopenharmony_ci	{"Base", "extops", "extops" ,&tplg_build_ops_object, NULL, &ops_config},
1084c72fcc34Sopenharmony_ci	{"Base", "channel", "channel", &tplg_build_channel_object, NULL, &channel_config},
1085c72fcc34Sopenharmony_ci	{"Base", "text", "SectionText", &tplg_build_text_object, NULL, &text_config},
1086c72fcc34Sopenharmony_ci	{"Base", "VendorToken", "SectionVendorTokens", &tplg_build_vendor_token_object,
1087c72fcc34Sopenharmony_ci	 NULL, NULL},
1088c72fcc34Sopenharmony_ci	{"Base", "hw_config", "SectionHWConfig", &tplg_build_hw_cfg_object, NULL,
1089c72fcc34Sopenharmony_ci	 &hwcfg_config},
1090c72fcc34Sopenharmony_ci	{"Base", "fe_dai", "dai", &tplg_build_fe_dai_object, NULL, &fe_dai_config},
1091c72fcc34Sopenharmony_ci	{"Base", "route", "SectionGraph", &tplg_build_dapm_route_object, NULL, NULL},
1092c72fcc34Sopenharmony_ci	{"Widget", "buffer", "SectionWidget", &tplg_build_generic_object, NULL, &widget_config},
1093c72fcc34Sopenharmony_ci	{"Widget", "", "SectionWidget", &tplg_build_generic_object, NULL, &widget_config},
1094c72fcc34Sopenharmony_ci	{"Control", "mixer", "SectionControlMixer", &tplg_build_mixer_control, NULL,
1095c72fcc34Sopenharmony_ci	 &mixer_control_config},
1096c72fcc34Sopenharmony_ci	{"Control", "bytes", "SectionControlBytes", &tplg_build_bytes_control, NULL,
1097c72fcc34Sopenharmony_ci	 &bytes_control_config},
1098c72fcc34Sopenharmony_ci	 {"Control", "enum", "SectionControlEnum", &tplg_build_enum_control, NULL,
1099c72fcc34Sopenharmony_ci	 &enum_control_config},
1100c72fcc34Sopenharmony_ci	{"Dai", "", "SectionBE", &tplg_build_generic_object, NULL, &be_dai_config},
1101c72fcc34Sopenharmony_ci	{"PCM", "pcm", "SectionPCM", &tplg_build_generic_object, NULL, &pcm_config},
1102c72fcc34Sopenharmony_ci	{"PCM", "pcm_caps", "SectionPCMCapabilities", &tplg_build_pcm_caps_object,
1103c72fcc34Sopenharmony_ci	 NULL, &pcm_caps_config},
1104c72fcc34Sopenharmony_ci};
1105c72fcc34Sopenharmony_ci
1106c72fcc34Sopenharmony_cistatic const struct build_function_map *tplg_object_get_map(struct tplg_pre_processor *tplg_pp ATTRIBUTE_UNUSED,
1107c72fcc34Sopenharmony_ci							    snd_config_t *obj)
1108c72fcc34Sopenharmony_ci{
1109c72fcc34Sopenharmony_ci	snd_config_iterator_t first;
1110c72fcc34Sopenharmony_ci	snd_config_t *class;
1111c72fcc34Sopenharmony_ci	const char *class_type, *class_name;
1112c72fcc34Sopenharmony_ci	unsigned int i;
1113c72fcc34Sopenharmony_ci
1114c72fcc34Sopenharmony_ci	first = snd_config_iterator_first(obj);
1115c72fcc34Sopenharmony_ci	class = snd_config_iterator_entry(first);
1116c72fcc34Sopenharmony_ci
1117c72fcc34Sopenharmony_ci	if (snd_config_get_id(class, &class_name) < 0)
1118c72fcc34Sopenharmony_ci		return NULL;
1119c72fcc34Sopenharmony_ci
1120c72fcc34Sopenharmony_ci	if (snd_config_get_id(obj, &class_type) < 0)
1121c72fcc34Sopenharmony_ci		return NULL;
1122c72fcc34Sopenharmony_ci
1123c72fcc34Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(object_build_map); i++) {
1124c72fcc34Sopenharmony_ci		if (!strcmp(class_type, "Widget") &&
1125c72fcc34Sopenharmony_ci		    !strcmp(object_build_map[i].class_type, "Widget") &&
1126c72fcc34Sopenharmony_ci			!strcmp(object_build_map[i].class_name, ""))
1127c72fcc34Sopenharmony_ci			return &object_build_map[i];
1128c72fcc34Sopenharmony_ci
1129c72fcc34Sopenharmony_ci		if (!strcmp(class_type, "Dai") &&
1130c72fcc34Sopenharmony_ci		    !strcmp(object_build_map[i].class_type, "Dai"))
1131c72fcc34Sopenharmony_ci			return &object_build_map[i];
1132c72fcc34Sopenharmony_ci
1133c72fcc34Sopenharmony_ci		/* for other type objects, also match the object class_name */
1134c72fcc34Sopenharmony_ci		if (!strcmp(class_type, object_build_map[i].class_type) &&
1135c72fcc34Sopenharmony_ci		    !strcmp(object_build_map[i].class_name, class_name))
1136c72fcc34Sopenharmony_ci			return &object_build_map[i];
1137c72fcc34Sopenharmony_ci	}
1138c72fcc34Sopenharmony_ci
1139c72fcc34Sopenharmony_ci	return NULL;
1140c72fcc34Sopenharmony_ci}
1141c72fcc34Sopenharmony_ci
1142c72fcc34Sopenharmony_ci/* search for section name based on class type and name and return the config in output_cfg */
1143c72fcc34Sopenharmony_cisnd_config_t *tplg_object_get_section(struct tplg_pre_processor *tplg_pp, snd_config_t *class)
1144c72fcc34Sopenharmony_ci{
1145c72fcc34Sopenharmony_ci	const struct build_function_map *map;
1146c72fcc34Sopenharmony_ci	snd_config_t *cfg = NULL;
1147c72fcc34Sopenharmony_ci	int ret;
1148c72fcc34Sopenharmony_ci
1149c72fcc34Sopenharmony_ci	map = tplg_object_get_map(tplg_pp, class);
1150c72fcc34Sopenharmony_ci	if (!map)
1151c72fcc34Sopenharmony_ci		return NULL;
1152c72fcc34Sopenharmony_ci
1153c72fcc34Sopenharmony_ci	ret = snd_config_search(tplg_pp->output_cfg, map->section_name, &cfg);
1154c72fcc34Sopenharmony_ci	if (ret < 0)
1155c72fcc34Sopenharmony_ci		SNDERR("Section config for %s not found\n", map->section_name);
1156c72fcc34Sopenharmony_ci
1157c72fcc34Sopenharmony_ci	return cfg;
1158c72fcc34Sopenharmony_ci}
1159c72fcc34Sopenharmony_ci
1160c72fcc34Sopenharmony_ci/* return 1 if attribute not found in search_config, 0 on success and negative value on error */
1161c72fcc34Sopenharmony_cistatic int tplg_object_copy_and_add_param(struct tplg_pre_processor *tplg_pp ATTRIBUTE_UNUSED,
1162c72fcc34Sopenharmony_ci					  snd_config_t *obj,
1163c72fcc34Sopenharmony_ci					  snd_config_t *attr_cfg,
1164c72fcc34Sopenharmony_ci					  snd_config_t *search_config)
1165c72fcc34Sopenharmony_ci{
1166c72fcc34Sopenharmony_ci	snd_config_iterator_t first = snd_config_iterator_first(obj);
1167c72fcc34Sopenharmony_ci	snd_config_t *attr, *new, *first_cfg;
1168c72fcc34Sopenharmony_ci	const char *id, *search_id;
1169c72fcc34Sopenharmony_ci	int ret;
1170c72fcc34Sopenharmony_ci
1171c72fcc34Sopenharmony_ci	first_cfg = snd_config_iterator_entry(first);
1172c72fcc34Sopenharmony_ci
1173c72fcc34Sopenharmony_ci	if (snd_config_get_id(attr_cfg, &id) < 0)
1174c72fcc34Sopenharmony_ci		return 0;
1175c72fcc34Sopenharmony_ci
1176c72fcc34Sopenharmony_ci	if (snd_config_get_id(search_config, &search_id) < 0)
1177c72fcc34Sopenharmony_ci		return 0;
1178c72fcc34Sopenharmony_ci
1179c72fcc34Sopenharmony_ci	/* copy object value */
1180c72fcc34Sopenharmony_ci	ret = snd_config_search(search_config, id, &attr);
1181c72fcc34Sopenharmony_ci	if (ret < 0)
1182c72fcc34Sopenharmony_ci		return 1;
1183c72fcc34Sopenharmony_ci
1184c72fcc34Sopenharmony_ci	ret = snd_config_copy(&new, attr);
1185c72fcc34Sopenharmony_ci	if (ret < 0) {
1186c72fcc34Sopenharmony_ci		SNDERR("error copying attribute '%s' value from %s\n", id, search_id);
1187c72fcc34Sopenharmony_ci		return ret;
1188c72fcc34Sopenharmony_ci	}
1189c72fcc34Sopenharmony_ci
1190c72fcc34Sopenharmony_ci	if (first_cfg) {
1191c72fcc34Sopenharmony_ci		/* prepend the new config */
1192c72fcc34Sopenharmony_ci		ret = snd_config_add_before(first_cfg, new);
1193c72fcc34Sopenharmony_ci		if (ret < 0) {
1194c72fcc34Sopenharmony_ci			snd_config_delete(new);
1195c72fcc34Sopenharmony_ci			SNDERR("error prepending attribute '%s' value to %s\n", id, search_id);
1196c72fcc34Sopenharmony_ci		}
1197c72fcc34Sopenharmony_ci	} else {
1198c72fcc34Sopenharmony_ci		ret = snd_config_add(obj, new);
1199c72fcc34Sopenharmony_ci		if (ret < 0) {
1200c72fcc34Sopenharmony_ci			snd_config_delete(new);
1201c72fcc34Sopenharmony_ci			SNDERR("error adding attribute '%s' value to %s\n", id, search_id);
1202c72fcc34Sopenharmony_ci		}
1203c72fcc34Sopenharmony_ci	}
1204c72fcc34Sopenharmony_ci
1205c72fcc34Sopenharmony_ci	return ret;
1206c72fcc34Sopenharmony_ci}
1207c72fcc34Sopenharmony_ci
1208c72fcc34Sopenharmony_ci/*
1209c72fcc34Sopenharmony_ci * Attribute values for an object can be set in one of the following in order of
1210c72fcc34Sopenharmony_ci * precedence:
1211c72fcc34Sopenharmony_ci * 1. Value set in object instance
1212c72fcc34Sopenharmony_ci * 2. Default value set in the object's class definition
1213c72fcc34Sopenharmony_ci * 3. Inherited value from the parent object
1214c72fcc34Sopenharmony_ci * 4. Value set in the object instance embedded in the parent object
1215c72fcc34Sopenharmony_ci * 5. Value set in the object instance embedded in the parent class definition
1216c72fcc34Sopenharmony_ci */
1217c72fcc34Sopenharmony_cistatic int tplg_object_update(struct tplg_pre_processor *tplg_pp, snd_config_t *obj,
1218c72fcc34Sopenharmony_ci			      snd_config_t *parent)
1219c72fcc34Sopenharmony_ci{
1220c72fcc34Sopenharmony_ci	snd_config_iterator_t i, next;
1221c72fcc34Sopenharmony_ci	snd_config_t *n, *cfg, *args;
1222c72fcc34Sopenharmony_ci	snd_config_t *obj_cfg, *class_cfg, *parent_obj;
1223c72fcc34Sopenharmony_ci	const char *obj_id, *class_name, *class_type;
1224c72fcc34Sopenharmony_ci	int ret;
1225c72fcc34Sopenharmony_ci
1226c72fcc34Sopenharmony_ci	class_cfg = tplg_class_lookup(tplg_pp, obj);
1227c72fcc34Sopenharmony_ci	if (!class_cfg)
1228c72fcc34Sopenharmony_ci		return -EINVAL;
1229c72fcc34Sopenharmony_ci
1230c72fcc34Sopenharmony_ci	/* find config for class attributes */
1231c72fcc34Sopenharmony_ci	ret = snd_config_search(class_cfg, "DefineAttribute", &args);
1232c72fcc34Sopenharmony_ci	if (ret < 0)
1233c72fcc34Sopenharmony_ci		return 0;
1234c72fcc34Sopenharmony_ci
1235c72fcc34Sopenharmony_ci	if (snd_config_get_id(obj, &class_type) < 0)
1236c72fcc34Sopenharmony_ci		return 0;
1237c72fcc34Sopenharmony_ci
1238c72fcc34Sopenharmony_ci	if (snd_config_get_id(class_cfg, &class_name) < 0)
1239c72fcc34Sopenharmony_ci		return 0;
1240c72fcc34Sopenharmony_ci
1241c72fcc34Sopenharmony_ci	/* get obj cfg */
1242c72fcc34Sopenharmony_ci	obj_cfg = tplg_object_get_instance_config(tplg_pp, obj);
1243c72fcc34Sopenharmony_ci	if (snd_config_get_id(obj_cfg, &obj_id) < 0)
1244c72fcc34Sopenharmony_ci		return 0;
1245c72fcc34Sopenharmony_ci
1246c72fcc34Sopenharmony_ci	/* copy and add attributes */
1247c72fcc34Sopenharmony_ci	snd_config_for_each(i, next, args) {
1248c72fcc34Sopenharmony_ci		snd_config_t *attr;
1249c72fcc34Sopenharmony_ci		const char *id;
1250c72fcc34Sopenharmony_ci
1251c72fcc34Sopenharmony_ci		n = snd_config_iterator_entry(i);
1252c72fcc34Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
1253c72fcc34Sopenharmony_ci			continue;
1254c72fcc34Sopenharmony_ci
1255c72fcc34Sopenharmony_ci		if (tplg_class_is_attribute_unique(id, class_cfg))
1256c72fcc34Sopenharmony_ci			continue;
1257c72fcc34Sopenharmony_ci
1258c72fcc34Sopenharmony_ci		if (tplg_class_is_attribute_immutable(id, class_cfg))
1259c72fcc34Sopenharmony_ci			goto class;
1260c72fcc34Sopenharmony_ci
1261c72fcc34Sopenharmony_ci		/* check if attribute value is set in the object */
1262c72fcc34Sopenharmony_ci		ret = snd_config_search(obj_cfg, id, &attr);
1263c72fcc34Sopenharmony_ci		if (ret < 0)
1264c72fcc34Sopenharmony_ci			goto class;
1265c72fcc34Sopenharmony_ci		continue;
1266c72fcc34Sopenharmony_ciclass:
1267c72fcc34Sopenharmony_ci		/* search for attributes value in class */
1268c72fcc34Sopenharmony_ci		ret = tplg_object_copy_and_add_param(tplg_pp, obj_cfg, n, class_cfg);
1269c72fcc34Sopenharmony_ci		if (ret == 1) {
1270c72fcc34Sopenharmony_ci			if (tplg_class_is_attribute_immutable(id, class_cfg)) {
1271c72fcc34Sopenharmony_ci				SNDERR("Immutable attribute %s not set in class %s\n",
1272c72fcc34Sopenharmony_ci				       id, class_name);
1273c72fcc34Sopenharmony_ci				return -EINVAL;
1274c72fcc34Sopenharmony_ci			}
1275c72fcc34Sopenharmony_ci			goto parent;
1276c72fcc34Sopenharmony_ci		}
1277c72fcc34Sopenharmony_ci		else if (ret < 0)
1278c72fcc34Sopenharmony_ci			return ret;
1279c72fcc34Sopenharmony_ci		continue;
1280c72fcc34Sopenharmony_ciparent:
1281c72fcc34Sopenharmony_ci		/* search for attribute value in parent */
1282c72fcc34Sopenharmony_ci		if (!parent)
1283c72fcc34Sopenharmony_ci			goto parent_object;
1284c72fcc34Sopenharmony_ci
1285c72fcc34Sopenharmony_ci		/* get parent obj cfg */
1286c72fcc34Sopenharmony_ci		parent_obj = tplg_object_get_instance_config(tplg_pp, parent);
1287c72fcc34Sopenharmony_ci		if (!parent_obj)
1288c72fcc34Sopenharmony_ci			goto parent_object;
1289c72fcc34Sopenharmony_ci
1290c72fcc34Sopenharmony_ci		ret = tplg_object_copy_and_add_param(tplg_pp, obj_cfg, n, parent_obj);
1291c72fcc34Sopenharmony_ci		if (ret == 1)
1292c72fcc34Sopenharmony_ci			goto parent_object;
1293c72fcc34Sopenharmony_ci		else if (ret < 0)
1294c72fcc34Sopenharmony_ci			return ret;
1295c72fcc34Sopenharmony_ci		continue;
1296c72fcc34Sopenharmony_ciparent_object:
1297c72fcc34Sopenharmony_ci		if (!parent)
1298c72fcc34Sopenharmony_ci			goto parent_class;
1299c72fcc34Sopenharmony_ci
1300c72fcc34Sopenharmony_ci		cfg = tplg_object_lookup_in_config(tplg_pp, parent_obj, class_type,
1301c72fcc34Sopenharmony_ci						   class_name, obj_id);
1302c72fcc34Sopenharmony_ci		if (!cfg)
1303c72fcc34Sopenharmony_ci			goto parent_class;
1304c72fcc34Sopenharmony_ci
1305c72fcc34Sopenharmony_ci		ret = tplg_object_copy_and_add_param(tplg_pp, obj_cfg, n, cfg);
1306c72fcc34Sopenharmony_ci		if (ret == 1)
1307c72fcc34Sopenharmony_ci			goto parent_class;
1308c72fcc34Sopenharmony_ci		else if (ret < 0)
1309c72fcc34Sopenharmony_ci			return ret;
1310c72fcc34Sopenharmony_ci		continue;
1311c72fcc34Sopenharmony_ciparent_class:
1312c72fcc34Sopenharmony_ci		if (!parent)
1313c72fcc34Sopenharmony_ci			goto check;
1314c72fcc34Sopenharmony_ci
1315c72fcc34Sopenharmony_ci		cfg = tplg_class_lookup(tplg_pp, parent);
1316c72fcc34Sopenharmony_ci		if (!cfg)
1317c72fcc34Sopenharmony_ci			return -EINVAL;
1318c72fcc34Sopenharmony_ci
1319c72fcc34Sopenharmony_ci		cfg = tplg_object_lookup_in_config(tplg_pp, cfg, class_type,
1320c72fcc34Sopenharmony_ci						   class_name, obj_id);
1321c72fcc34Sopenharmony_ci		if (!cfg)
1322c72fcc34Sopenharmony_ci			goto check;
1323c72fcc34Sopenharmony_ci
1324c72fcc34Sopenharmony_ci		ret = tplg_object_copy_and_add_param(tplg_pp, obj_cfg, n, cfg);
1325c72fcc34Sopenharmony_ci		if (ret == 1)
1326c72fcc34Sopenharmony_ci			goto check;
1327c72fcc34Sopenharmony_ci		else if (ret < 0)
1328c72fcc34Sopenharmony_ci			return ret;
1329c72fcc34Sopenharmony_ci		continue;
1330c72fcc34Sopenharmony_cicheck:
1331c72fcc34Sopenharmony_ci		if (tplg_class_is_attribute_mandatory(id, class_cfg)) {
1332c72fcc34Sopenharmony_ci			SNDERR("Mandatory attribute %s not set for class %s\n", id, class_name);
1333c72fcc34Sopenharmony_ci			return -EINVAL;
1334c72fcc34Sopenharmony_ci		}
1335c72fcc34Sopenharmony_ci	}
1336c72fcc34Sopenharmony_ci
1337c72fcc34Sopenharmony_ci	return 0;
1338c72fcc34Sopenharmony_ci}
1339c72fcc34Sopenharmony_ci
1340c72fcc34Sopenharmony_cistatic int tplg_object_pre_process_children(struct tplg_pre_processor *tplg_pp,
1341c72fcc34Sopenharmony_ci					    snd_config_t *parent, snd_config_t *cfg)
1342c72fcc34Sopenharmony_ci{
1343c72fcc34Sopenharmony_ci	snd_config_iterator_t i, next;
1344c72fcc34Sopenharmony_ci	snd_config_t *children, *n;
1345c72fcc34Sopenharmony_ci	int ret;
1346c72fcc34Sopenharmony_ci
1347c72fcc34Sopenharmony_ci	ret = snd_config_search(cfg, "Object", &children);
1348c72fcc34Sopenharmony_ci	if (ret < 0)
1349c72fcc34Sopenharmony_ci		return 0;
1350c72fcc34Sopenharmony_ci
1351c72fcc34Sopenharmony_ci	/* create all embedded objects */
1352c72fcc34Sopenharmony_ci	snd_config_for_each(i, next, children) {
1353c72fcc34Sopenharmony_ci		const char *id;
1354c72fcc34Sopenharmony_ci
1355c72fcc34Sopenharmony_ci		n = snd_config_iterator_entry(i);
1356c72fcc34Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
1357c72fcc34Sopenharmony_ci			continue;
1358c72fcc34Sopenharmony_ci
1359c72fcc34Sopenharmony_ci		ret = tplg_pre_process_objects(tplg_pp, n, parent);
1360c72fcc34Sopenharmony_ci		if (ret < 0)
1361c72fcc34Sopenharmony_ci			return ret;
1362c72fcc34Sopenharmony_ci	}
1363c72fcc34Sopenharmony_ci
1364c72fcc34Sopenharmony_ci	return 0;
1365c72fcc34Sopenharmony_ci}
1366c72fcc34Sopenharmony_ci
1367c72fcc34Sopenharmony_cistatic int tplg_construct_object_name(struct tplg_pre_processor *tplg_pp ATTRIBUTE_UNUSED,
1368c72fcc34Sopenharmony_ci				      snd_config_t *obj, snd_config_t *class_cfg)
1369c72fcc34Sopenharmony_ci{
1370c72fcc34Sopenharmony_ci	snd_config_iterator_t i, next;
1371c72fcc34Sopenharmony_ci	snd_config_t *args, *n;
1372c72fcc34Sopenharmony_ci	const char *id, *class_id, *obj_id, *s;
1373c72fcc34Sopenharmony_ci	char *new_name;
1374c72fcc34Sopenharmony_ci	int ret;
1375c72fcc34Sopenharmony_ci
1376c72fcc34Sopenharmony_ci	/* find config for class constructor attributes. Nothing to do if not defined */
1377c72fcc34Sopenharmony_ci	ret = snd_config_search(class_cfg, "attributes.constructor", &args);
1378c72fcc34Sopenharmony_ci	if (ret < 0)
1379c72fcc34Sopenharmony_ci		return 0;
1380c72fcc34Sopenharmony_ci
1381c72fcc34Sopenharmony_ci	/* set class name as the name prefix for the object */
1382c72fcc34Sopenharmony_ci	if (snd_config_get_id(obj, &obj_id) < 0)
1383c72fcc34Sopenharmony_ci		return -EINVAL;
1384c72fcc34Sopenharmony_ci	if (snd_config_get_id(class_cfg, &class_id) < 0)
1385c72fcc34Sopenharmony_ci		return -EINVAL;
1386c72fcc34Sopenharmony_ci	new_name = strdup(class_id);
1387c72fcc34Sopenharmony_ci	if (!new_name)
1388c72fcc34Sopenharmony_ci		return -ENOMEM;
1389c72fcc34Sopenharmony_ci
1390c72fcc34Sopenharmony_ci	/* iterate through all class arguments and set object name */
1391c72fcc34Sopenharmony_ci	snd_config_for_each(i, next, args) {
1392c72fcc34Sopenharmony_ci		snd_config_t *arg;
1393c72fcc34Sopenharmony_ci		char *arg_value, *temp;
1394c72fcc34Sopenharmony_ci
1395c72fcc34Sopenharmony_ci		n = snd_config_iterator_entry(i);
1396c72fcc34Sopenharmony_ci
1397c72fcc34Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0) {
1398c72fcc34Sopenharmony_ci			SNDERR("Invalid ID for constructor argument\n");
1399c72fcc34Sopenharmony_ci			ret = -EINVAL;
1400c72fcc34Sopenharmony_ci			goto err;
1401c72fcc34Sopenharmony_ci		}
1402c72fcc34Sopenharmony_ci
1403c72fcc34Sopenharmony_ci		if (snd_config_get_string(n, &s) < 0) {
1404c72fcc34Sopenharmony_ci			SNDERR("Invalid value for constructor argument\n");
1405c72fcc34Sopenharmony_ci			ret = -EINVAL;
1406c72fcc34Sopenharmony_ci			goto err;
1407c72fcc34Sopenharmony_ci		}
1408c72fcc34Sopenharmony_ci
1409c72fcc34Sopenharmony_ci		/* find and replace with value set in object */
1410c72fcc34Sopenharmony_ci		ret = snd_config_search(obj, s, &arg);
1411c72fcc34Sopenharmony_ci		if (ret < 0) {
1412c72fcc34Sopenharmony_ci			SNDERR("Argument %s not set for object '%s.%s'\n", s, class_id, obj_id);
1413c72fcc34Sopenharmony_ci			ret = -ENOENT;
1414c72fcc34Sopenharmony_ci			goto err;
1415c72fcc34Sopenharmony_ci		}
1416c72fcc34Sopenharmony_ci
1417c72fcc34Sopenharmony_ci		/* concat arg value to object name. arg types must be either integer or string */
1418c72fcc34Sopenharmony_ci		switch (snd_config_get_type(arg)) {
1419c72fcc34Sopenharmony_ci		case SND_CONFIG_TYPE_INTEGER:
1420c72fcc34Sopenharmony_ci		{
1421c72fcc34Sopenharmony_ci			long v;
1422c72fcc34Sopenharmony_ci			ret = snd_config_get_integer(arg, &v);
1423c72fcc34Sopenharmony_ci			assert(ret >= 0);
1424c72fcc34Sopenharmony_ci
1425c72fcc34Sopenharmony_ci			arg_value = tplg_snprintf("%ld", v);
1426c72fcc34Sopenharmony_ci			if (!arg_value) {
1427c72fcc34Sopenharmony_ci				ret = -ENOMEM;
1428c72fcc34Sopenharmony_ci				goto err;
1429c72fcc34Sopenharmony_ci			}
1430c72fcc34Sopenharmony_ci			break;
1431c72fcc34Sopenharmony_ci		}
1432c72fcc34Sopenharmony_ci		case SND_CONFIG_TYPE_STRING:
1433c72fcc34Sopenharmony_ci		{
1434c72fcc34Sopenharmony_ci			const char *s;
1435c72fcc34Sopenharmony_ci
1436c72fcc34Sopenharmony_ci			ret = snd_config_get_string(arg, &s);
1437c72fcc34Sopenharmony_ci			assert(ret >= 0);
1438c72fcc34Sopenharmony_ci
1439c72fcc34Sopenharmony_ci			arg_value = strdup(s);
1440c72fcc34Sopenharmony_ci			if (!arg_value) {
1441c72fcc34Sopenharmony_ci				ret = -ENOMEM;
1442c72fcc34Sopenharmony_ci				goto err;
1443c72fcc34Sopenharmony_ci			}
1444c72fcc34Sopenharmony_ci			break;
1445c72fcc34Sopenharmony_ci		}
1446c72fcc34Sopenharmony_ci		default:
1447c72fcc34Sopenharmony_ci			SNDERR("Argument '%s' in object '%s.%s' is not an integer or a string\n",
1448c72fcc34Sopenharmony_ci			       s, class_id, obj_id);
1449c72fcc34Sopenharmony_ci			ret = -EINVAL;
1450c72fcc34Sopenharmony_ci			goto err;
1451c72fcc34Sopenharmony_ci		}
1452c72fcc34Sopenharmony_ci
1453c72fcc34Sopenharmony_ci		/* alloc and concat arg value to the name */
1454c72fcc34Sopenharmony_ci		temp = tplg_snprintf("%s.%s", new_name, arg_value);
1455c72fcc34Sopenharmony_ci		free(arg_value);
1456c72fcc34Sopenharmony_ci		if (!temp) {
1457c72fcc34Sopenharmony_ci			ret = -ENOMEM;
1458c72fcc34Sopenharmony_ci			goto err;
1459c72fcc34Sopenharmony_ci		}
1460c72fcc34Sopenharmony_ci		free(new_name);
1461c72fcc34Sopenharmony_ci		new_name = temp;
1462c72fcc34Sopenharmony_ci	}
1463c72fcc34Sopenharmony_ci
1464c72fcc34Sopenharmony_ci	ret = snd_config_set_id(obj, new_name);
1465c72fcc34Sopenharmony_cierr:
1466c72fcc34Sopenharmony_ci	free(new_name);
1467c72fcc34Sopenharmony_ci	return ret;
1468c72fcc34Sopenharmony_ci}
1469c72fcc34Sopenharmony_ci
1470c72fcc34Sopenharmony_ci/* set the attribute value by type */
1471c72fcc34Sopenharmony_cistatic int tplg_set_attribute_value(snd_config_t *attr, const char *value)
1472c72fcc34Sopenharmony_ci{
1473c72fcc34Sopenharmony_ci	int err;
1474c72fcc34Sopenharmony_ci	snd_config_type_t type = snd_config_get_type(attr);
1475c72fcc34Sopenharmony_ci
1476c72fcc34Sopenharmony_ci	switch (type) {
1477c72fcc34Sopenharmony_ci	case SND_CONFIG_TYPE_INTEGER:
1478c72fcc34Sopenharmony_ci	{
1479c72fcc34Sopenharmony_ci		long v;
1480c72fcc34Sopenharmony_ci
1481c72fcc34Sopenharmony_ci		v = strtol(value, NULL, 10);
1482c72fcc34Sopenharmony_ci		err = snd_config_set_integer(attr, v);
1483c72fcc34Sopenharmony_ci		assert(err >= 0);
1484c72fcc34Sopenharmony_ci		break;
1485c72fcc34Sopenharmony_ci	}
1486c72fcc34Sopenharmony_ci	case SND_CONFIG_TYPE_INTEGER64:
1487c72fcc34Sopenharmony_ci	{
1488c72fcc34Sopenharmony_ci		long long v;
1489c72fcc34Sopenharmony_ci
1490c72fcc34Sopenharmony_ci		v = strtoll(value, NULL, 10);
1491c72fcc34Sopenharmony_ci		err = snd_config_set_integer64(attr, v);
1492c72fcc34Sopenharmony_ci		assert(err >= 0);
1493c72fcc34Sopenharmony_ci		break;
1494c72fcc34Sopenharmony_ci	}
1495c72fcc34Sopenharmony_ci	case SND_CONFIG_TYPE_STRING:
1496c72fcc34Sopenharmony_ci	{
1497c72fcc34Sopenharmony_ci		err = snd_config_set_string(attr, value);
1498c72fcc34Sopenharmony_ci		assert(err >= 0);
1499c72fcc34Sopenharmony_ci		break;
1500c72fcc34Sopenharmony_ci	}
1501c72fcc34Sopenharmony_ci	default:
1502c72fcc34Sopenharmony_ci		return -EINVAL;
1503c72fcc34Sopenharmony_ci	}
1504c72fcc34Sopenharmony_ci
1505c72fcc34Sopenharmony_ci	return 0;
1506c72fcc34Sopenharmony_ci}
1507c72fcc34Sopenharmony_ci
1508c72fcc34Sopenharmony_ci
1509c72fcc34Sopenharmony_ci/*
1510c72fcc34Sopenharmony_ci * Find the unique attribute in the class definition and set its value and type.
1511c72fcc34Sopenharmony_ci * Only string or integer types are allowed for unique values.
1512c72fcc34Sopenharmony_ci */
1513c72fcc34Sopenharmony_cistatic int tplg_object_set_unique_attribute(struct tplg_pre_processor *tplg_pp,
1514c72fcc34Sopenharmony_ci					    snd_config_t *obj, snd_config_t *class_cfg,
1515c72fcc34Sopenharmony_ci					    const char *id)
1516c72fcc34Sopenharmony_ci{
1517c72fcc34Sopenharmony_ci	snd_config_t *unique_attr, *new;
1518c72fcc34Sopenharmony_ci	const char *unique_name, *class_id;
1519c72fcc34Sopenharmony_ci	int ret;
1520c72fcc34Sopenharmony_ci
1521c72fcc34Sopenharmony_ci	if (snd_config_get_id(class_cfg, &class_id) < 0)
1522c72fcc34Sopenharmony_ci		return 0;
1523c72fcc34Sopenharmony_ci
1524c72fcc34Sopenharmony_ci	/* find config for class unique attribute */
1525c72fcc34Sopenharmony_ci	unique_name = tplg_class_get_unique_attribute_name(tplg_pp, class_cfg);
1526c72fcc34Sopenharmony_ci	if (!unique_name)
1527c72fcc34Sopenharmony_ci		return -ENOENT;
1528c72fcc34Sopenharmony_ci
1529c72fcc34Sopenharmony_ci	/* find the unique attribute definition in the class */
1530c72fcc34Sopenharmony_ci	unique_attr = tplg_class_find_attribute_by_name(tplg_pp, class_cfg, unique_name);
1531c72fcc34Sopenharmony_ci	if (!unique_attr)
1532c72fcc34Sopenharmony_ci		return -ENOENT;
1533c72fcc34Sopenharmony_ci
1534c72fcc34Sopenharmony_ci	/* override value if unique attribute is set in the object instance */
1535c72fcc34Sopenharmony_ci	ret = snd_config_search(obj, unique_name, &new);
1536c72fcc34Sopenharmony_ci	if (ret < 0) {
1537c72fcc34Sopenharmony_ci		ret = snd_config_make(&new, unique_name,
1538c72fcc34Sopenharmony_ci				      tplg_class_get_attribute_type(tplg_pp, unique_attr));
1539c72fcc34Sopenharmony_ci		if (ret < 0) {
1540c72fcc34Sopenharmony_ci			SNDERR("error creating new attribute cfg for object %s\n", id);
1541c72fcc34Sopenharmony_ci			return ret;
1542c72fcc34Sopenharmony_ci		}
1543c72fcc34Sopenharmony_ci		ret = snd_config_add(obj, new);
1544c72fcc34Sopenharmony_ci		if (ret < 0) {
1545c72fcc34Sopenharmony_ci			SNDERR("error adding new attribute cfg for object %s\n", id);
1546c72fcc34Sopenharmony_ci			return ret;
1547c72fcc34Sopenharmony_ci		}
1548c72fcc34Sopenharmony_ci	}
1549c72fcc34Sopenharmony_ci
1550c72fcc34Sopenharmony_ci	ret = tplg_set_attribute_value(new, id);
1551c72fcc34Sopenharmony_ci	if (ret < 0) {
1552c72fcc34Sopenharmony_ci		SNDERR("error setting unique attribute cfg for object %s\n", id);
1553c72fcc34Sopenharmony_ci		return ret;
1554c72fcc34Sopenharmony_ci	}
1555c72fcc34Sopenharmony_ci
1556c72fcc34Sopenharmony_ci	return ret;
1557c72fcc34Sopenharmony_ci}
1558c72fcc34Sopenharmony_ci
1559c72fcc34Sopenharmony_ci/*
1560c72fcc34Sopenharmony_ci * Helper function to get object instance config which is 2 nodes down from class_type config.
1561c72fcc34Sopenharmony_ci * ex: Get the pointer to the config node with ID "0" from the input config Widget.pga.0 {}
1562c72fcc34Sopenharmony_ci */
1563c72fcc34Sopenharmony_cisnd_config_t *tplg_object_get_instance_config(struct tplg_pre_processor *tplg_pp ATTRIBUTE_UNUSED,
1564c72fcc34Sopenharmony_ci					snd_config_t *class_type)
1565c72fcc34Sopenharmony_ci{
1566c72fcc34Sopenharmony_ci	snd_config_iterator_t first;
1567c72fcc34Sopenharmony_ci	snd_config_t *cfg;
1568c72fcc34Sopenharmony_ci
1569c72fcc34Sopenharmony_ci	first = snd_config_iterator_first(class_type);
1570c72fcc34Sopenharmony_ci	cfg = snd_config_iterator_entry(first);
1571c72fcc34Sopenharmony_ci	first = snd_config_iterator_first(cfg);
1572c72fcc34Sopenharmony_ci	return snd_config_iterator_entry(first);
1573c72fcc34Sopenharmony_ci}
1574c72fcc34Sopenharmony_ci
1575c72fcc34Sopenharmony_ci#if SND_LIB_VER(1, 2, 5) < SND_LIB_VERSION
1576c72fcc34Sopenharmony_cistatic int pre_process_find_variable(snd_config_t **dst, const char *str, snd_config_t *config)
1577c72fcc34Sopenharmony_ci{
1578c72fcc34Sopenharmony_ci	snd_config_iterator_t i, next;
1579c72fcc34Sopenharmony_ci
1580c72fcc34Sopenharmony_ci	snd_config_for_each(i, next, config) {
1581c72fcc34Sopenharmony_ci		snd_config_t *n;
1582c72fcc34Sopenharmony_ci		const char *id;
1583c72fcc34Sopenharmony_ci
1584c72fcc34Sopenharmony_ci		n = snd_config_iterator_entry(i);
1585c72fcc34Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
1586c72fcc34Sopenharmony_ci			continue;
1587c72fcc34Sopenharmony_ci
1588c72fcc34Sopenharmony_ci		if (strcmp(id, str))
1589c72fcc34Sopenharmony_ci			continue;
1590c72fcc34Sopenharmony_ci
1591c72fcc34Sopenharmony_ci		/* found definition, copy config */
1592c72fcc34Sopenharmony_ci		return snd_config_copy(dst, n);
1593c72fcc34Sopenharmony_ci	}
1594c72fcc34Sopenharmony_ci
1595c72fcc34Sopenharmony_ci	return -EINVAL;
1596c72fcc34Sopenharmony_ci}
1597c72fcc34Sopenharmony_ci
1598c72fcc34Sopenharmony_cistatic int
1599c72fcc34Sopenharmony_cipre_process_object_variables_expand_fcn(snd_config_t **dst, const char *str, void *private_data)
1600c72fcc34Sopenharmony_ci{
1601c72fcc34Sopenharmony_ci
1602c72fcc34Sopenharmony_ci	struct tplg_pre_processor *tplg_pp = private_data;
1603c72fcc34Sopenharmony_ci	snd_config_t *object_cfg = tplg_pp->current_obj_cfg;
1604c72fcc34Sopenharmony_ci	snd_config_t *conf_defines;
1605c72fcc34Sopenharmony_ci	const char *object_id;
1606c72fcc34Sopenharmony_ci	const char *val;
1607c72fcc34Sopenharmony_ci	int ret;
1608c72fcc34Sopenharmony_ci
1609c72fcc34Sopenharmony_ci	ret = snd_config_search(tplg_pp->input_cfg, "Define", &conf_defines);
1610c72fcc34Sopenharmony_ci	if (ret < 0)
1611c72fcc34Sopenharmony_ci		return 0;
1612c72fcc34Sopenharmony_ci
1613c72fcc34Sopenharmony_ci	/* find variable from global definitions first */
1614c72fcc34Sopenharmony_ci	ret = pre_process_find_variable(dst, str, conf_defines);
1615c72fcc34Sopenharmony_ci	if (ret >= 0)
1616c72fcc34Sopenharmony_ci		return ret;
1617c72fcc34Sopenharmony_ci
1618c72fcc34Sopenharmony_ci	/* No global define found, proceeed to object attribute search */
1619c72fcc34Sopenharmony_ci	if (snd_config_get_id(object_cfg, &object_id) < 0)
1620c72fcc34Sopenharmony_ci		return -EINVAL;
1621c72fcc34Sopenharmony_ci
1622c72fcc34Sopenharmony_ci	/* find variable from object attribute values if not found in global definitions */
1623c72fcc34Sopenharmony_ci	ret = pre_process_find_variable(dst, str, object_cfg);
1624c72fcc34Sopenharmony_ci	if (ret < 0) {
1625c72fcc34Sopenharmony_ci		SNDERR("Failed to find definition for attribute %s in '%s' object\n",
1626c72fcc34Sopenharmony_ci		       str, object_id);
1627c72fcc34Sopenharmony_ci		return ret;
1628c72fcc34Sopenharmony_ci	}
1629c72fcc34Sopenharmony_ci
1630c72fcc34Sopenharmony_ci	/* the extracted value may contain a nested $-expression */
1631c72fcc34Sopenharmony_ci	if (snd_config_get_string(*dst, &val) >= 0) {
1632c72fcc34Sopenharmony_ci		if (val[0] == '$') {
1633c72fcc34Sopenharmony_ci			char *var = strdup(val);
1634c72fcc34Sopenharmony_ci
1635c72fcc34Sopenharmony_ci			snd_config_delete(*dst);
1636c72fcc34Sopenharmony_ci			ret = snd_config_evaluate_string(dst, var,
1637c72fcc34Sopenharmony_ci							 pre_process_object_variables_expand_fcn,
1638c72fcc34Sopenharmony_ci							 tplg_pp);
1639c72fcc34Sopenharmony_ci			free(var);
1640c72fcc34Sopenharmony_ci		}
1641c72fcc34Sopenharmony_ci	}
1642c72fcc34Sopenharmony_ci
1643c72fcc34Sopenharmony_ci	return ret;
1644c72fcc34Sopenharmony_ci}
1645c72fcc34Sopenharmony_ci
1646c72fcc34Sopenharmony_ci/*
1647c72fcc34Sopenharmony_ci * Searches for the first '$VAR_NAME' or '$[<contents>]' occurrence in
1648c72fcc34Sopenharmony_ci * *stringp. Allocates memory for it and copies it there. The
1649c72fcc34Sopenharmony_ci * allocated string is returned in '*varname'. If there was a prefix
1650c72fcc34Sopenharmony_ci * before $VAR_NAME, it is returned in '*prefix'. The *stringp is
1651c72fcc34Sopenharmony_ci * moved forward to the char after the $VAR_NAME.
1652c72fcc34Sopenharmony_ci *
1653c72fcc34Sopenharmony_ci * The end of $VAR_NAME is the first char that is not alpha numeric, '_',
1654c72fcc34Sopenharmony_ci * or '\0'.
1655c72fcc34Sopenharmony_ci *
1656c72fcc34Sopenharmony_ci * In '$[<contents>]' case all letters but '[' and ']' are allow in
1657c72fcc34Sopenharmony_ci * any sequence. Nested '[]' is also allowed if the number of '[' and
1658c72fcc34Sopenharmony_ci * ']' match.
1659c72fcc34Sopenharmony_ci *
1660c72fcc34Sopenharmony_ci * The function modifies *stringp, and *prefix - if not NULL - points
1661c72fcc34Sopenharmony_ci * to the original *stringp, *varname - if not NULL - is malloced and
1662c72fcc34Sopenharmony_ci * should be freed by the caller.
1663c72fcc34Sopenharmony_ci *
1664c72fcc34Sopenharmony_ci * Returns 0		if the *stringp was an empty string.
1665c72fcc34Sopenharmony_ci *         1		if *prefix or *varname was set
1666c72fcc34Sopenharmony_ci *         -ENOMEM	if malloc failed
1667c72fcc34Sopenharmony_ci */
1668c72fcc34Sopenharmony_cistatic int tplg_get_varname(char **stringp, char **prefix, char **varname)
1669c72fcc34Sopenharmony_ci{
1670c72fcc34Sopenharmony_ci	size_t prefix_len, varname_len = 0;
1671c72fcc34Sopenharmony_ci
1672c72fcc34Sopenharmony_ci	*prefix = NULL;
1673c72fcc34Sopenharmony_ci	*varname = NULL;
1674c72fcc34Sopenharmony_ci
1675c72fcc34Sopenharmony_ci	prefix_len = strcspn(*stringp, "$");
1676c72fcc34Sopenharmony_ci	*prefix = *stringp;
1677c72fcc34Sopenharmony_ci	(*stringp) += prefix_len;
1678c72fcc34Sopenharmony_ci	if (**stringp == '$') {
1679c72fcc34Sopenharmony_ci		if ((*stringp)[1] == '[') {
1680c72fcc34Sopenharmony_ci			int brackets = 1;
1681c72fcc34Sopenharmony_ci			varname_len = 1;
1682c72fcc34Sopenharmony_ci
1683c72fcc34Sopenharmony_ci			do {
1684c72fcc34Sopenharmony_ci				varname_len += strcspn((*stringp) + varname_len + 1, "[]") + 1;
1685c72fcc34Sopenharmony_ci				if ((*stringp)[varname_len] == '[')
1686c72fcc34Sopenharmony_ci					brackets++;
1687c72fcc34Sopenharmony_ci				else if ((*stringp)[varname_len] == ']')
1688c72fcc34Sopenharmony_ci					brackets--;
1689c72fcc34Sopenharmony_ci				else
1690c72fcc34Sopenharmony_ci					break;
1691c72fcc34Sopenharmony_ci			}  while (brackets > 0);
1692c72fcc34Sopenharmony_ci			if (brackets != 0)
1693c72fcc34Sopenharmony_ci				return -EINVAL;
1694c72fcc34Sopenharmony_ci			varname_len++;
1695c72fcc34Sopenharmony_ci		} else {
1696c72fcc34Sopenharmony_ci			varname_len = 1;
1697c72fcc34Sopenharmony_ci			while (isalnum((*stringp)[varname_len]) || (*stringp)[varname_len] == '_')
1698c72fcc34Sopenharmony_ci				varname_len++;
1699c72fcc34Sopenharmony_ci		}
1700c72fcc34Sopenharmony_ci	}
1701c72fcc34Sopenharmony_ci
1702c72fcc34Sopenharmony_ci	if (varname_len == 0 && prefix_len == 0)
1703c72fcc34Sopenharmony_ci		return 0;
1704c72fcc34Sopenharmony_ci
1705c72fcc34Sopenharmony_ci	if (varname_len) {
1706c72fcc34Sopenharmony_ci		*varname = malloc(varname_len + 1);
1707c72fcc34Sopenharmony_ci		if (*varname == NULL)
1708c72fcc34Sopenharmony_ci			return -ENOMEM;
1709c72fcc34Sopenharmony_ci		strncpy(*varname, *stringp, varname_len);
1710c72fcc34Sopenharmony_ci		(*varname)[varname_len] = '\0';
1711c72fcc34Sopenharmony_ci		(*stringp) += varname_len;
1712c72fcc34Sopenharmony_ci	}
1713c72fcc34Sopenharmony_ci
1714c72fcc34Sopenharmony_ci	if (prefix_len)
1715c72fcc34Sopenharmony_ci		(*prefix)[prefix_len] = '\0';
1716c72fcc34Sopenharmony_ci	else
1717c72fcc34Sopenharmony_ci		*prefix = NULL;
1718c72fcc34Sopenharmony_ci
1719c72fcc34Sopenharmony_ci	return 1;
1720c72fcc34Sopenharmony_ci}
1721c72fcc34Sopenharmony_ci
1722c72fcc34Sopenharmony_cistatic int tplg_evaluate_config_string(struct tplg_pre_processor *tplg_pp,
1723c72fcc34Sopenharmony_ci				    snd_config_t **dst, const char *s, const char *id)
1724c72fcc34Sopenharmony_ci{
1725c72fcc34Sopenharmony_ci	char *str = strdup(s);
1726c72fcc34Sopenharmony_ci	char *varname, *prefix, *freep = str;
1727c72fcc34Sopenharmony_ci	int ret;
1728c72fcc34Sopenharmony_ci
1729c72fcc34Sopenharmony_ci	if (!str)
1730c72fcc34Sopenharmony_ci		return -ENOMEM;
1731c72fcc34Sopenharmony_ci
1732c72fcc34Sopenharmony_ci	*dst = NULL;
1733c72fcc34Sopenharmony_ci
1734c72fcc34Sopenharmony_ci	/* split the string and expand global definitions or object attribute values */
1735c72fcc34Sopenharmony_ci	while (tplg_get_varname(&str, &prefix, &varname) == 1) {
1736c72fcc34Sopenharmony_ci		const char *current_str;
1737c72fcc34Sopenharmony_ci		char *temp;
1738c72fcc34Sopenharmony_ci
1739c72fcc34Sopenharmony_ci		if (prefix) {
1740c72fcc34Sopenharmony_ci			if (*dst == NULL) {
1741c72fcc34Sopenharmony_ci				ret = snd_config_make(dst, id, SND_CONFIG_TYPE_STRING);
1742c72fcc34Sopenharmony_ci				if (ret < 0)
1743c72fcc34Sopenharmony_ci					goto out;
1744c72fcc34Sopenharmony_ci				ret = snd_config_set_string(*dst, prefix);
1745c72fcc34Sopenharmony_ci				if (ret < 0)
1746c72fcc34Sopenharmony_ci					goto out;
1747c72fcc34Sopenharmony_ci			} else {
1748c72fcc34Sopenharmony_ci				/* concat the prefix */
1749c72fcc34Sopenharmony_ci				snd_config_get_string(*dst, &current_str);
1750c72fcc34Sopenharmony_ci				temp = tplg_snprintf("%s%s", current_str, prefix);
1751c72fcc34Sopenharmony_ci				if (!temp) {
1752c72fcc34Sopenharmony_ci					ret = -ENOMEM;
1753c72fcc34Sopenharmony_ci					goto out;
1754c72fcc34Sopenharmony_ci				}
1755c72fcc34Sopenharmony_ci
1756c72fcc34Sopenharmony_ci				ret = snd_config_set_string(*dst, temp);
1757c72fcc34Sopenharmony_ci				free(temp);
1758c72fcc34Sopenharmony_ci				if (ret < 0)
1759c72fcc34Sopenharmony_ci					goto out;
1760c72fcc34Sopenharmony_ci			}
1761c72fcc34Sopenharmony_ci		}
1762c72fcc34Sopenharmony_ci
1763c72fcc34Sopenharmony_ci		if (varname) {
1764c72fcc34Sopenharmony_ci			snd_config_t *tmp_config;
1765c72fcc34Sopenharmony_ci
1766c72fcc34Sopenharmony_ci			ret = snd_config_evaluate_string(&tmp_config, varname,
1767c72fcc34Sopenharmony_ci							 pre_process_object_variables_expand_fcn,
1768c72fcc34Sopenharmony_ci							 tplg_pp);
1769c72fcc34Sopenharmony_ci			if (ret < 0)
1770c72fcc34Sopenharmony_ci				goto out;
1771c72fcc34Sopenharmony_ci
1772c72fcc34Sopenharmony_ci			if (*dst == NULL) {
1773c72fcc34Sopenharmony_ci				*dst = tmp_config;
1774c72fcc34Sopenharmony_ci			} else {
1775c72fcc34Sopenharmony_ci				char *ascii;
1776c72fcc34Sopenharmony_ci
1777c72fcc34Sopenharmony_ci				snd_config_get_string(*dst, &current_str);
1778c72fcc34Sopenharmony_ci
1779c72fcc34Sopenharmony_ci				ret = snd_config_get_ascii(tmp_config, &ascii);
1780c72fcc34Sopenharmony_ci				if (ret)
1781c72fcc34Sopenharmony_ci					goto out;
1782c72fcc34Sopenharmony_ci
1783c72fcc34Sopenharmony_ci				temp = tplg_snprintf("%s%s", current_str, ascii);
1784c72fcc34Sopenharmony_ci				free(ascii);
1785c72fcc34Sopenharmony_ci
1786c72fcc34Sopenharmony_ci				if (!temp) {
1787c72fcc34Sopenharmony_ci					ret = -ENOMEM;
1788c72fcc34Sopenharmony_ci					goto out;
1789c72fcc34Sopenharmony_ci				}
1790c72fcc34Sopenharmony_ci
1791c72fcc34Sopenharmony_ci				ret = snd_config_set_string(*dst, temp);
1792c72fcc34Sopenharmony_ci				free(temp);
1793c72fcc34Sopenharmony_ci				snd_config_delete(tmp_config);
1794c72fcc34Sopenharmony_ci				if (ret < 0)
1795c72fcc34Sopenharmony_ci					goto out;
1796c72fcc34Sopenharmony_ci			}
1797c72fcc34Sopenharmony_ci			free(varname);
1798c72fcc34Sopenharmony_ci		}
1799c72fcc34Sopenharmony_ci	}
1800c72fcc34Sopenharmony_ci
1801c72fcc34Sopenharmony_ci	free(freep);
1802c72fcc34Sopenharmony_ci	snd_config_set_id(*dst, id);
1803c72fcc34Sopenharmony_ci
1804c72fcc34Sopenharmony_ci	return 0;
1805c72fcc34Sopenharmony_ciout:
1806c72fcc34Sopenharmony_ci	if (*dst)
1807c72fcc34Sopenharmony_ci		snd_config_delete(*dst);
1808c72fcc34Sopenharmony_ci	free(varname);
1809c72fcc34Sopenharmony_ci	free(freep);
1810c72fcc34Sopenharmony_ci	return ret;
1811c72fcc34Sopenharmony_ci}
1812c72fcc34Sopenharmony_ci
1813c72fcc34Sopenharmony_ci#endif
1814c72fcc34Sopenharmony_ci
1815c72fcc34Sopenharmony_ci/* build object config and its child objects recursively */
1816c72fcc34Sopenharmony_cistatic int tplg_build_object(struct tplg_pre_processor *tplg_pp, snd_config_t *new_obj,
1817c72fcc34Sopenharmony_ci			      snd_config_t *parent)
1818c72fcc34Sopenharmony_ci{
1819c72fcc34Sopenharmony_ci	snd_config_t *obj_local, *class_cfg;
1820c72fcc34Sopenharmony_ci	const struct build_function_map *map;
1821c72fcc34Sopenharmony_ci	snd_config_iterator_t i, next;
1822c72fcc34Sopenharmony_ci	build_func builder;
1823c72fcc34Sopenharmony_ci	update_auto_attr_func auto_attr_updater;
1824c72fcc34Sopenharmony_ci	const char *id, *class_id;
1825c72fcc34Sopenharmony_ci	int ret;
1826c72fcc34Sopenharmony_ci
1827c72fcc34Sopenharmony_ci	obj_local = tplg_object_get_instance_config(tplg_pp, new_obj);
1828c72fcc34Sopenharmony_ci	if (!obj_local)
1829c72fcc34Sopenharmony_ci		return -EINVAL;
1830c72fcc34Sopenharmony_ci
1831c72fcc34Sopenharmony_ci	class_cfg = tplg_class_lookup(tplg_pp, new_obj);
1832c72fcc34Sopenharmony_ci	if (!class_cfg)
1833c72fcc34Sopenharmony_ci		return -EINVAL;
1834c72fcc34Sopenharmony_ci
1835c72fcc34Sopenharmony_ci	if (snd_config_get_id(obj_local, &id) < 0)
1836c72fcc34Sopenharmony_ci		return 0;
1837c72fcc34Sopenharmony_ci
1838c72fcc34Sopenharmony_ci	if (snd_config_get_id(class_cfg, &class_id) < 0)
1839c72fcc34Sopenharmony_ci		return 0;
1840c72fcc34Sopenharmony_ci
1841c72fcc34Sopenharmony_ci	/* set unique attribute value */
1842c72fcc34Sopenharmony_ci	ret = tplg_object_set_unique_attribute(tplg_pp, obj_local, class_cfg, id);
1843c72fcc34Sopenharmony_ci	if (ret < 0) {
1844c72fcc34Sopenharmony_ci		SNDERR("error setting unique attribute value for '%s.%s'\n", class_id, id);
1845c72fcc34Sopenharmony_ci		return ret;
1846c72fcc34Sopenharmony_ci	}
1847c72fcc34Sopenharmony_ci
1848c72fcc34Sopenharmony_ci	/* update object attributes and validate them */
1849c72fcc34Sopenharmony_ci	ret = tplg_object_update(tplg_pp, new_obj, parent);
1850c72fcc34Sopenharmony_ci	if (ret < 0) {
1851c72fcc34Sopenharmony_ci		SNDERR("Failed to update attributes for object '%s.%s'\n", class_id, id);
1852c72fcc34Sopenharmony_ci		return ret;
1853c72fcc34Sopenharmony_ci	}
1854c72fcc34Sopenharmony_ci
1855c72fcc34Sopenharmony_ci#if SND_LIB_VER(1, 2, 5) < SND_LIB_VERSION
1856c72fcc34Sopenharmony_ci	tplg_pp_config_debug(tplg_pp, obj_local);
1857c72fcc34Sopenharmony_ci
1858c72fcc34Sopenharmony_ci	/* expand all non-compound type child configs in object */
1859c72fcc34Sopenharmony_ci	snd_config_for_each(i, next, obj_local) {
1860c72fcc34Sopenharmony_ci		snd_config_t *n, *new, *class_attr;
1861c72fcc34Sopenharmony_ci		const char *id, *s;
1862c72fcc34Sopenharmony_ci		char *attr_config_name;
1863c72fcc34Sopenharmony_ci
1864c72fcc34Sopenharmony_ci		n = snd_config_iterator_entry(i);
1865c72fcc34Sopenharmony_ci
1866c72fcc34Sopenharmony_ci		if (snd_config_get_type(n) == SND_CONFIG_TYPE_COMPOUND)
1867c72fcc34Sopenharmony_ci			continue;
1868c72fcc34Sopenharmony_ci
1869c72fcc34Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
1870c72fcc34Sopenharmony_ci			continue;
1871c72fcc34Sopenharmony_ci
1872c72fcc34Sopenharmony_ci		if (snd_config_get_string(n, &s) < 0)
1873c72fcc34Sopenharmony_ci			continue;
1874c72fcc34Sopenharmony_ci
1875c72fcc34Sopenharmony_ci		if (!strstr(s, "$"))
1876c72fcc34Sopenharmony_ci			goto validate;
1877c72fcc34Sopenharmony_ci
1878c72fcc34Sopenharmony_ci		tplg_pp->current_obj_cfg = obj_local;
1879c72fcc34Sopenharmony_ci
1880c72fcc34Sopenharmony_ci		/* Expand definitions and object attribute references. */
1881c72fcc34Sopenharmony_ci		ret = tplg_evaluate_config_string(tplg_pp, &new, s, id);
1882c72fcc34Sopenharmony_ci		if (ret < 0) {
1883c72fcc34Sopenharmony_ci			SNDERR("Failed to evaluate attributes %s in %s, from '%s'\n",
1884c72fcc34Sopenharmony_ci			       id, class_id, s);
1885c72fcc34Sopenharmony_ci			return ret;
1886c72fcc34Sopenharmony_ci		}
1887c72fcc34Sopenharmony_ci
1888c72fcc34Sopenharmony_ci		ret = snd_config_merge(n, new, true);
1889c72fcc34Sopenharmony_ci		if (ret < 0)
1890c72fcc34Sopenharmony_ci			return ret;
1891c72fcc34Sopenharmony_civalidate:
1892c72fcc34Sopenharmony_ci		/* validate attribute value */
1893c72fcc34Sopenharmony_ci		snd_config_get_id(n, &id);
1894c72fcc34Sopenharmony_ci		attr_config_name = tplg_snprintf("DefineAttribute.%s", id);
1895c72fcc34Sopenharmony_ci		if (!attr_config_name)
1896c72fcc34Sopenharmony_ci			return -ENOMEM;
1897c72fcc34Sopenharmony_ci
1898c72fcc34Sopenharmony_ci		ret = snd_config_search(class_cfg, attr_config_name, &class_attr);
1899c72fcc34Sopenharmony_ci		free(attr_config_name);
1900c72fcc34Sopenharmony_ci		if (ret < 0)
1901c72fcc34Sopenharmony_ci			continue;
1902c72fcc34Sopenharmony_ci
1903c72fcc34Sopenharmony_ci		if (!tplg_object_is_attribute_valid(tplg_pp, class_attr, n)) {
1904c72fcc34Sopenharmony_ci			SNDERR("Failed to validate attribute %s in %s\n", id, class_id);
1905c72fcc34Sopenharmony_ci			return -EINVAL;
1906c72fcc34Sopenharmony_ci		}
1907c72fcc34Sopenharmony_ci	}
1908c72fcc34Sopenharmony_ci#endif
1909c72fcc34Sopenharmony_ci
1910c72fcc34Sopenharmony_ci	/* construct object name using class constructor */
1911c72fcc34Sopenharmony_ci	ret = tplg_construct_object_name(tplg_pp, obj_local, class_cfg);
1912c72fcc34Sopenharmony_ci	if (ret < 0) {
1913c72fcc34Sopenharmony_ci		SNDERR("Failed to construct object name for %s\n", id);
1914c72fcc34Sopenharmony_ci		return ret;
1915c72fcc34Sopenharmony_ci	}
1916c72fcc34Sopenharmony_ci
1917c72fcc34Sopenharmony_ci	/*
1918c72fcc34Sopenharmony_ci	 * Build objects if object type is supported.
1919c72fcc34Sopenharmony_ci	 * If not, process object attributes and add to parent's data section
1920c72fcc34Sopenharmony_ci	 */
1921c72fcc34Sopenharmony_ci	map = tplg_object_get_map(tplg_pp, new_obj);
1922c72fcc34Sopenharmony_ci	if (map) {
1923c72fcc34Sopenharmony_ci		builder = map->builder;
1924c72fcc34Sopenharmony_ci
1925c72fcc34Sopenharmony_ci		/* update automatic attribute for current object */
1926c72fcc34Sopenharmony_ci		auto_attr_updater = map->auto_attr_updater;
1927c72fcc34Sopenharmony_ci		if(auto_attr_updater) {
1928c72fcc34Sopenharmony_ci			ret = auto_attr_updater(tplg_pp, obj_local, parent);
1929c72fcc34Sopenharmony_ci			if (ret < 0) {
1930c72fcc34Sopenharmony_ci				SNDERR("Failed to update automatic attributes for %s\n", id);
1931c72fcc34Sopenharmony_ci				return ret;
1932c72fcc34Sopenharmony_ci			}
1933c72fcc34Sopenharmony_ci		}
1934c72fcc34Sopenharmony_ci	} else {
1935c72fcc34Sopenharmony_ci		builder = &tplg_build_parent_data;
1936c72fcc34Sopenharmony_ci	}
1937c72fcc34Sopenharmony_ci
1938c72fcc34Sopenharmony_ci	ret = builder(tplg_pp, new_obj, parent);
1939c72fcc34Sopenharmony_ci	if (ret < 0)
1940c72fcc34Sopenharmony_ci		return ret;
1941c72fcc34Sopenharmony_ci
1942c72fcc34Sopenharmony_ci	/* create child objects in the object instance */
1943c72fcc34Sopenharmony_ci	ret = tplg_object_pre_process_children(tplg_pp, new_obj, obj_local);
1944c72fcc34Sopenharmony_ci	if (ret < 0) {
1945c72fcc34Sopenharmony_ci		SNDERR("error processing child objects in object %s\n", id);
1946c72fcc34Sopenharmony_ci		return ret;
1947c72fcc34Sopenharmony_ci	}
1948c72fcc34Sopenharmony_ci
1949c72fcc34Sopenharmony_ci	/* create child objects in the object's class definition */
1950c72fcc34Sopenharmony_ci	ret = tplg_object_pre_process_children(tplg_pp, new_obj, class_cfg);
1951c72fcc34Sopenharmony_ci	if (ret < 0)
1952c72fcc34Sopenharmony_ci		SNDERR("error processing child objects in class %s\n", class_id);
1953c72fcc34Sopenharmony_ci
1954c72fcc34Sopenharmony_ci	return ret;
1955c72fcc34Sopenharmony_ci}
1956c72fcc34Sopenharmony_ci
1957c72fcc34Sopenharmony_ci/* create top-level topology objects */
1958c72fcc34Sopenharmony_ciint tplg_pre_process_objects(struct tplg_pre_processor *tplg_pp, snd_config_t *cfg,
1959c72fcc34Sopenharmony_ci			     snd_config_t *parent)
1960c72fcc34Sopenharmony_ci{
1961c72fcc34Sopenharmony_ci	snd_config_iterator_t i, next, i2, next2;
1962c72fcc34Sopenharmony_ci	snd_config_t *n, *n2, *_obj_type, *_obj_class, *_obj;
1963c72fcc34Sopenharmony_ci	const char *id, *class_type, *class_name;
1964c72fcc34Sopenharmony_ci	int ret;
1965c72fcc34Sopenharmony_ci
1966c72fcc34Sopenharmony_ci	if (snd_config_get_id(cfg, &class_type) < 0)
1967c72fcc34Sopenharmony_ci		return 0;
1968c72fcc34Sopenharmony_ci
1969c72fcc34Sopenharmony_ci	/* create all objects of the same type and class */
1970c72fcc34Sopenharmony_ci	snd_config_for_each(i, next, cfg) {
1971c72fcc34Sopenharmony_ci		n = snd_config_iterator_entry(i);
1972c72fcc34Sopenharmony_ci		if (snd_config_get_id(n, &class_name) < 0)
1973c72fcc34Sopenharmony_ci			continue;
1974c72fcc34Sopenharmony_ci		snd_config_for_each(i2, next2, n) {
1975c72fcc34Sopenharmony_ci			snd_config_t *temp_n2;
1976c72fcc34Sopenharmony_ci
1977c72fcc34Sopenharmony_ci			n2 = snd_config_iterator_entry(i2);
1978c72fcc34Sopenharmony_ci			if (snd_config_get_id(n2, &id) < 0) {
1979c72fcc34Sopenharmony_ci				SNDERR("Invalid id for object\n");
1980c72fcc34Sopenharmony_ci				return -EINVAL;
1981c72fcc34Sopenharmony_ci			}
1982c72fcc34Sopenharmony_ci
1983c72fcc34Sopenharmony_ci			ret = snd_config_copy(&temp_n2, n2);
1984c72fcc34Sopenharmony_ci			if (ret < 0)
1985c72fcc34Sopenharmony_ci				return ret;
1986c72fcc34Sopenharmony_ci
1987c72fcc34Sopenharmony_ci			/*
1988c72fcc34Sopenharmony_ci			 * An object declared within a class definition as follows:
1989c72fcc34Sopenharmony_ci			 * Class.Pipeline.volume-playback {
1990c72fcc34Sopenharmony_ci			 * 	Object.Widget.pga.0 {
1991c72fcc34Sopenharmony_ci			 * 		ramp_step_ms 250
1992c72fcc34Sopenharmony_ci            		 * 	}
1993c72fcc34Sopenharmony_ci			 * }
1994c72fcc34Sopenharmony_ci			 *
1995c72fcc34Sopenharmony_ci			 * While instantiating the volume-pipeline class, the pga object
1996c72fcc34Sopenharmony_ci			 * could be modified as follows:
1997c72fcc34Sopenharmony_ci			 * Object.Pipeline.volume-playback.0 {
1998c72fcc34Sopenharmony_ci			 * 	Object.Widget.pga.0 {
1999c72fcc34Sopenharmony_ci			 * 		format "s24le"
2000c72fcc34Sopenharmony_ci			 * 	}
2001c72fcc34Sopenharmony_ci			 * }
2002c72fcc34Sopenharmony_ci			 * When building the pga.0 object in the class definition, merge
2003c72fcc34Sopenharmony_ci			 * the attributes declared in the volume-playback.0 object to create
2004c72fcc34Sopenharmony_ci			 * a new config as follows to make sure that all attributes are
2005c72fcc34Sopenharmony_ci			 * set for the pga object.
2006c72fcc34Sopenharmony_ci			 * Object.Widget.pga.0 {
2007c72fcc34Sopenharmony_ci			 * 	ramp_step_ms 250
2008c72fcc34Sopenharmony_ci			 * 	format "s24le"
2009c72fcc34Sopenharmony_ci			 * }
2010c72fcc34Sopenharmony_ci			 */
2011c72fcc34Sopenharmony_ci
2012c72fcc34Sopenharmony_ci			if (parent) {
2013c72fcc34Sopenharmony_ci				snd_config_t *parent_instance, *parent_obj, *temp;
2014c72fcc34Sopenharmony_ci				char *obj_cfg_name;
2015c72fcc34Sopenharmony_ci
2016c72fcc34Sopenharmony_ci				obj_cfg_name = tplg_snprintf("%s%s.%s.%s", "Object.",
2017c72fcc34Sopenharmony_ci							     class_type, class_name, id);
2018c72fcc34Sopenharmony_ci
2019c72fcc34Sopenharmony_ci				/* search for object instance in the parent */
2020c72fcc34Sopenharmony_ci				parent_instance = tplg_object_get_instance_config(tplg_pp, parent);
2021c72fcc34Sopenharmony_ci				if (!parent_instance)
2022c72fcc34Sopenharmony_ci					goto temp_cfg;
2023c72fcc34Sopenharmony_ci
2024c72fcc34Sopenharmony_ci				ret = snd_config_search(parent_instance, obj_cfg_name, &parent_obj);
2025c72fcc34Sopenharmony_ci				free(obj_cfg_name);
2026c72fcc34Sopenharmony_ci				if (ret < 0)
2027c72fcc34Sopenharmony_ci					goto temp_cfg;
2028c72fcc34Sopenharmony_ci
2029c72fcc34Sopenharmony_ci				/* don't merge if the object configs are the same */
2030c72fcc34Sopenharmony_ci				if (parent_obj == n2)
2031c72fcc34Sopenharmony_ci					goto temp_cfg;
2032c72fcc34Sopenharmony_ci
2033c72fcc34Sopenharmony_ci				/* create a temp config copying the parent object config */
2034c72fcc34Sopenharmony_ci				ret = snd_config_copy(&temp, parent_obj);
2035c72fcc34Sopenharmony_ci				if (ret < 0) {
2036c72fcc34Sopenharmony_ci					snd_config_delete(temp_n2);
2037c72fcc34Sopenharmony_ci					return ret;
2038c72fcc34Sopenharmony_ci				}
2039c72fcc34Sopenharmony_ci
2040c72fcc34Sopenharmony_ci				/*
2041c72fcc34Sopenharmony_ci				 * Merge parent object with the current object instance.
2042c72fcc34Sopenharmony_ci				 * temp will be deleted by merge
2043c72fcc34Sopenharmony_ci				 */
2044c72fcc34Sopenharmony_ci				ret = snd_config_merge(temp_n2, temp, false);
2045c72fcc34Sopenharmony_ci				if (ret < 0) {
2046c72fcc34Sopenharmony_ci					SNDERR("error merging parent object config for %s.%s.%s\n",
2047c72fcc34Sopenharmony_ci					       class_type, class_name, id);
2048c72fcc34Sopenharmony_ci					snd_config_delete(temp_n2);
2049c72fcc34Sopenharmony_ci					return ret;
2050c72fcc34Sopenharmony_ci				}
2051c72fcc34Sopenharmony_ci			}
2052c72fcc34Sopenharmony_citemp_cfg:
2053c72fcc34Sopenharmony_ci			/* create a temp config for object with class type as the root node */
2054c72fcc34Sopenharmony_ci			ret = snd_config_make(&_obj_type, class_type, SND_CONFIG_TYPE_COMPOUND);
2055c72fcc34Sopenharmony_ci			if (ret < 0) {
2056c72fcc34Sopenharmony_ci				snd_config_delete(temp_n2);
2057c72fcc34Sopenharmony_ci				return ret;
2058c72fcc34Sopenharmony_ci			}
2059c72fcc34Sopenharmony_ci
2060c72fcc34Sopenharmony_ci			ret = snd_config_make(&_obj_class, class_name, SND_CONFIG_TYPE_COMPOUND);
2061c72fcc34Sopenharmony_ci			if (ret < 0)
2062c72fcc34Sopenharmony_ci				goto err;
2063c72fcc34Sopenharmony_ci
2064c72fcc34Sopenharmony_ci			ret = snd_config_add(_obj_type, _obj_class);
2065c72fcc34Sopenharmony_ci			if (ret < 0) {
2066c72fcc34Sopenharmony_ci				snd_config_delete(_obj_class);
2067c72fcc34Sopenharmony_ci				goto err;
2068c72fcc34Sopenharmony_ci			}
2069c72fcc34Sopenharmony_ci
2070c72fcc34Sopenharmony_ci			ret = snd_config_copy(&_obj, temp_n2);
2071c72fcc34Sopenharmony_ci			if (ret < 0)
2072c72fcc34Sopenharmony_ci				goto err;
2073c72fcc34Sopenharmony_ci
2074c72fcc34Sopenharmony_ci			ret = snd_config_add(_obj_class, _obj);
2075c72fcc34Sopenharmony_ci			if (ret < 0) {
2076c72fcc34Sopenharmony_ci				snd_config_delete(_obj);
2077c72fcc34Sopenharmony_ci				goto err;
2078c72fcc34Sopenharmony_ci			}
2079c72fcc34Sopenharmony_ci
2080c72fcc34Sopenharmony_ci			/* Build the object now */
2081c72fcc34Sopenharmony_ci			ret = tplg_build_object(tplg_pp, _obj_type, parent);
2082c72fcc34Sopenharmony_ci			if (ret < 0)
2083c72fcc34Sopenharmony_ci				SNDERR("Error building object %s.%s.%s\n",
2084c72fcc34Sopenharmony_ci				       class_type, class_name, id);
2085c72fcc34Sopenharmony_cierr:
2086c72fcc34Sopenharmony_ci			snd_config_delete(temp_n2);
2087c72fcc34Sopenharmony_ci			snd_config_delete(_obj_type);
2088c72fcc34Sopenharmony_ci			if (ret < 0)
2089c72fcc34Sopenharmony_ci				return ret;
2090c72fcc34Sopenharmony_ci		}
2091c72fcc34Sopenharmony_ci	}
2092c72fcc34Sopenharmony_ci
2093c72fcc34Sopenharmony_ci	return 0;
2094c72fcc34Sopenharmony_ci}
2095