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