• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <assert.h>
21 #include <errno.h>
22 #include <stddef.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <alsa/asoundlib.h>
26 #include "gettext.h"
27 #include "topology.h"
28 #include "pre-processor.h"
29 
30 /* 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)31 int tplg_build_vendor_token_object(struct tplg_pre_processor *tplg_pp,
32 				   snd_config_t *obj_cfg, snd_config_t *parent)
33 {
34 	snd_config_iterator_t i, next;
35 	snd_config_t *vtop, *n, *obj;
36 	const char *name;
37 	int ret;
38 
39 	ret = tplg_build_object_from_template(tplg_pp, obj_cfg, &vtop, NULL, false);
40 	if (ret < 0)
41 		return ret;
42 
43 	ret = snd_config_get_id(vtop, &name);
44 	if (ret < 0)
45 		return ret;
46 
47 	/* add the tuples */
48 	obj = tplg_object_get_instance_config(tplg_pp, obj_cfg);
49 	snd_config_for_each(i, next, obj) {
50 		snd_config_t *dst;
51 		const char *id;
52 
53 		n = snd_config_iterator_entry(i);
54 
55 		if (snd_config_get_id(n, &id) < 0)
56 			continue;
57 
58 		if (!strcmp(id, "name"))
59 			continue;
60 
61 		ret = snd_config_copy(&dst, n);
62 		if (ret < 0) {
63 			SNDERR("Error copying config node %s for '%s'\n", id, name);
64 			return ret;
65 		}
66 
67 		ret = snd_config_add(vtop, dst);
68 		if (ret < 0) {
69 			snd_config_delete(dst);
70 			SNDERR("Error adding vendortoken %s for %s\n", id, name);
71 			return ret;
72 		}
73 	}
74 
75 	return ret;
76 }
77 
tplg_parent_update(struct tplg_pre_processor * tplg_pp,snd_config_t * parent,const char * section_name,const char * item_name)78 int tplg_parent_update(struct tplg_pre_processor *tplg_pp, snd_config_t *parent,
79 			  const char *section_name, const char *item_name)
80 {
81 	snd_config_iterator_t i, next;
82 	snd_config_t *child, *cfg, *top, *item_config, *n;
83 	const char *parent_name;
84 	char *item_id;
85 	int ret, id = 0;
86 
87 	/* Nothing to do if parent is NULL */
88 	if (!parent)
89 		return 0;
90 
91 	child = tplg_object_get_instance_config(tplg_pp, parent);
92 	ret = snd_config_search(child, "name", &cfg);
93 	if (ret < 0) {
94 		ret = snd_config_get_id(child, &parent_name);
95 		if (ret < 0) {
96 			SNDERR("No name config for parent\n");
97 			return ret;
98 		}
99 	} else {
100 		ret = snd_config_get_string(cfg, &parent_name);
101 		if (ret < 0) {
102 			SNDERR("Invalid name for parent\n");
103 			return ret;
104 		}
105 	}
106 
107 	top = tplg_object_get_section(tplg_pp, parent);
108 	if (!top)
109 		return -EINVAL;
110 
111 	/* get config with name */
112 	cfg = tplg_find_config(top, parent_name);
113 	if (!cfg)
114 		return ret;
115 
116 	/* get section config */
117 	if (!strcmp(section_name, "tlv")) {
118 		/* set tlv name if config exists already */
119 		ret = snd_config_search(cfg, section_name, &item_config);
120 			if (ret < 0) {
121 			ret = tplg_config_make_add(&item_config, section_name,
122 						  SND_CONFIG_TYPE_STRING, cfg);
123 			if (ret < 0) {
124 				SNDERR("Error creating section config widget %s for %s\n",
125 				       section_name, parent_name);
126 				return ret;
127 			}
128 		}
129 
130 		return snd_config_set_string(item_config, item_name);
131 	}
132 
133 	ret = snd_config_search(cfg, section_name, &item_config);
134 	if (ret < 0) {
135 		ret = tplg_config_make_add(&item_config, section_name,
136 					  SND_CONFIG_TYPE_COMPOUND, cfg);
137 		if (ret < 0) {
138 			SNDERR("Error creating section config widget %s for %s\n",
139 			       section_name, parent_name);
140 			return ret;
141 		}
142 	}
143 
144 	snd_config_for_each(i, next, item_config) {
145 		const char *name;
146 
147 		n = snd_config_iterator_entry(i);
148 		if (snd_config_get_string(n, &name) < 0)
149 			continue;
150 
151 		/* item already exists */
152 		if (!strcmp(name, item_name))
153 			return 0;
154 		id++;
155 	}
156 
157 	/* add new item */
158 	item_id = tplg_snprintf("%d", id);
159 	if (!item_id)
160 		return -ENOMEM;
161 
162 	ret = snd_config_make(&cfg, item_id, SND_CONFIG_TYPE_STRING);
163 	free(item_id);
164 	if (ret < 0)
165 		return ret;
166 
167 	ret = snd_config_set_string(cfg, item_name);
168 	if (ret < 0)
169 		return ret;
170 
171 	ret = snd_config_add(item_config, cfg);
172 	if (ret < 0)
173 		snd_config_delete(cfg);
174 
175 	return ret;
176 }
177 
178 /* 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)179 int tplg_build_data_object(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
180 			    snd_config_t *parent)
181 {
182 	snd_config_t *dtop;
183 	const char *name;
184 	int ret;
185 
186 	ret = tplg_build_object_from_template(tplg_pp, obj_cfg, &dtop, NULL, false);
187 	if (ret < 0)
188 		return ret;
189 
190 	ret = snd_config_get_id(dtop, &name);
191 	if (ret < 0)
192 		return ret;
193 
194 	return tplg_parent_update(tplg_pp, parent, "data", name);
195 }
196 
tplg_create_config_template(struct tplg_pre_processor * tplg_pp,snd_config_t ** template,const struct config_template_items * items)197 static int tplg_create_config_template(struct tplg_pre_processor *tplg_pp,
198 				       snd_config_t **template,
199 				       const struct config_template_items *items)
200 {
201 	snd_config_t *top, *child;
202 	int ret, i;
203 
204 	ret = snd_config_make(&top, "template", SND_CONFIG_TYPE_COMPOUND);
205 	if (ret < 0)
206 		return ret;
207 
208 	/* add integer configs */
209 	for (i = 0; i < MAX_CONFIGS_IN_TEMPLATE; i++)
210 		if (items->int_config_ids[i]) {
211 			ret = tplg_config_make_add(&child, items->int_config_ids[i],
212 						   SND_CONFIG_TYPE_INTEGER, top);
213 			if (ret < 0)
214 				goto err;
215 		}
216 
217 	/* add string configs */
218 	for (i = 0; i < MAX_CONFIGS_IN_TEMPLATE; i++)
219 		if (items->string_config_ids[i]) {
220 			ret = tplg_config_make_add(&child, items->string_config_ids[i],
221 						   SND_CONFIG_TYPE_STRING, top);
222 			if (ret < 0)
223 				goto err;
224 		}
225 
226 	/* add compound configs */
227 	for (i = 0; i < MAX_CONFIGS_IN_TEMPLATE; i++) {
228 		if (items->compound_config_ids[i]) {
229 			ret = tplg_config_make_add(&child, items->compound_config_ids[i],
230 						   SND_CONFIG_TYPE_COMPOUND, top);
231 			if (ret < 0)
232 				goto err;
233 		}
234 	}
235 
236 err:
237 	if (ret < 0) {
238 		snd_config_delete(top);
239 		return ret;
240 	}
241 
242 	*template = top;
243 	return ret;
244 }
245 
tplg_attribute_print_valid_values(snd_config_t * valid_values,const char * name)246 static void tplg_attribute_print_valid_values(snd_config_t *valid_values, const char *name)
247 {
248 	snd_config_iterator_t i, next;
249 	snd_config_t *n;
250 
251 	SNDERR("valid values for attribute %s are:\n", name);
252 
253 	snd_config_for_each(i, next, valid_values) {
254 		const char *s, *id;
255 
256 		n = snd_config_iterator_entry(i);
257 		if (snd_config_get_id(n, &id) < 0)
258 			continue;
259 
260 		if (snd_config_get_string(n, &s) < 0)
261 			continue;
262 
263 		SNDERR("%s", s);
264 	}
265 }
266 
267 /* check is attribute value belongs in the set of valid values */
tplg_is_attribute_valid_value(snd_config_t * valid_values,const char * value)268 static bool tplg_is_attribute_valid_value(snd_config_t *valid_values, const char *value)
269 {
270 	snd_config_iterator_t i, next;
271 	snd_config_t *n;
272 
273 	snd_config_for_each(i, next, valid_values) {
274 		const char *s, *id;
275 
276 		n = snd_config_iterator_entry(i);
277 		if (snd_config_get_id(n, &id) < 0)
278 			continue;
279 
280 		if (snd_config_get_string(n, &s) < 0)
281 			continue;
282 
283 		if (!strcmp(value, s))
284 			return true;
285 	}
286 
287 	return false;
288 }
289 
290 /* 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)291 static bool tplg_object_is_attribute_min_max_valid(snd_config_t *attr, snd_config_t *obj_attr,
292 						   bool min_check)
293 {
294 	snd_config_type_t type = snd_config_get_type(obj_attr);
295 	snd_config_t *valid;
296 	const char *attr_name;
297 	int ret;
298 
299 	if (snd_config_get_id(attr, &attr_name) < 0)
300 		return false;
301 
302 	if (min_check) {
303 		ret = snd_config_search(attr, "constraints.min", &valid);
304 		if (ret < 0)
305 			return true;
306 	} else {
307 		ret = snd_config_search(attr, "constraints.max", &valid);
308 		if (ret < 0)
309 			return true;
310 	}
311 
312 	switch(type) {
313 	case SND_CONFIG_TYPE_INTEGER:
314 	{
315 		long v, m;
316 
317 		if (snd_config_get_integer(valid, &m) < 0)
318 			return true;
319 
320 		if (snd_config_get_integer(obj_attr, &v) < 0)
321 			return false;
322 
323 		if (min_check) {
324 			if (v < m) {
325 				SNDERR("attribute '%s' value: %ld is less than min value: %d\n",
326 				       attr_name, v, m);
327 				return false;
328 			}
329 		} else {
330 			if (v > m) {
331 				SNDERR("attribute '%s' value: %ld is greater than max value: %d\n",
332 				       attr_name, v, m);
333 				return false;
334 			}
335 		}
336 
337 		return true;
338 	}
339 	case SND_CONFIG_TYPE_INTEGER64:
340 	{
341 		long long v;
342 		long m;
343 
344 		if (snd_config_get_integer(valid, &m) < 0)
345 			return true;
346 
347 		if (snd_config_get_integer64(obj_attr, &v) < 0)
348 			return false;
349 
350 		if (min_check) {
351 			if (v < m) {
352 				SNDERR("attribute '%s' value: %ld is less than min value: %d\n",
353 				       attr_name, v, m);
354 				return false;
355 			}
356 		} else {
357 			if (v > m) {
358 				SNDERR("attribute '%s' value: %ld is greater than max value: %d\n",
359 				       attr_name, v, m);
360 				return false;
361 			}
362 		}
363 
364 		return true;
365 	}
366 	default:
367 		break;
368 	}
369 
370 	return false;
371 }
372 
373 /* 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 * object)374 static bool tplg_object_is_attribute_valid(struct tplg_pre_processor *tplg_pp,
375 					   snd_config_t *attr, snd_config_t *object)
376 {
377 	snd_config_iterator_t i, next;
378 	snd_config_t *valid, *obj_attr, *n;
379 	snd_config_type_t type;
380 	const char *attr_name, *obj_value;
381 	int ret;
382 
383 	if (snd_config_get_id(attr, &attr_name) < 0)
384 		return false;
385 
386 	ret = snd_config_search(object, attr_name, &obj_attr);
387 	if (ret < 0) {
388 		SNDERR("attr %s not found \n", attr_name);
389 		return false;
390 	}
391 	type = snd_config_get_type(obj_attr);
392 
393 	/* check if attribute has valid values */
394 	ret = snd_config_search(attr, "constraints.valid_values", &valid);
395 	if (ret < 0)
396 		goto min_max_check;
397 
398 	switch(type) {
399 	case SND_CONFIG_TYPE_STRING:
400 		if (snd_config_get_string(obj_attr, &obj_value) < 0)
401 			return false;
402 		if (!tplg_is_attribute_valid_value(valid, obj_value)) {
403 			tplg_attribute_print_valid_values(valid, attr_name);
404 			return false;
405 		}
406 		return true;
407 	case SND_CONFIG_TYPE_COMPOUND:
408 		snd_config_for_each(i, next, obj_attr) {
409 			const char *s, *id;
410 
411 			n = snd_config_iterator_entry(i);
412 			if (snd_config_get_id(n, &id) < 0)
413 				continue;
414 
415 			if (snd_config_get_string(n, &s) < 0)
416 				continue;
417 
418 			if (!tplg_is_attribute_valid_value(valid, s)) {
419 				tplg_attribute_print_valid_values(valid, attr_name);
420 				return false;
421 			}
422 		}
423 		return true;
424 	default:
425 		break;
426 	}
427 
428 	return false;
429 
430 min_max_check:
431 	if (!tplg_object_is_attribute_min_max_valid(attr, obj_attr, true))
432 		return false;
433 
434 	return tplg_object_is_attribute_min_max_valid(attr, obj_attr, false);
435 }
436 
437 /* get object's name attribute value */
tplg_object_get_name(struct tplg_pre_processor * tplg_pp,snd_config_t * object)438 const char *tplg_object_get_name(struct tplg_pre_processor *tplg_pp,
439 				 snd_config_t *object)
440 {
441 	snd_config_t *cfg;
442 	const char *name;
443 	int ret;
444 
445 	ret = snd_config_search(object, "name", &cfg);
446 	if (ret < 0)
447 		return NULL;
448 
449 	ret = snd_config_get_string(cfg, &name);
450 	if (ret < 0)
451 		return NULL;
452 
453 	return name;
454 }
455 
456 /* look up the instance of object in a config */
tplg_object_lookup_in_config(struct tplg_pre_processor * tplg_pp,snd_config_t * class,const char * type,const char * class_name,const char * id)457 static snd_config_t *tplg_object_lookup_in_config(struct tplg_pre_processor *tplg_pp,
458 						  snd_config_t *class, const char *type,
459 						  const char *class_name, const char *id)
460 {
461 	snd_config_t *obj_cfg = NULL;
462 	char *config_id;
463 
464 	config_id = tplg_snprintf("Object.%s.%s.%s", type, class_name, id);
465 	if (!config_id)
466 		return NULL;
467 
468 	if (snd_config_search(class, config_id, &obj_cfg) < 0)
469 		return NULL;
470 	free(config_id);
471 	return obj_cfg;
472 }
473 
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)474 static int tplg_pp_add_object_tuple_section(struct tplg_pre_processor *tplg_pp,
475 					    snd_config_t *class_cfg,
476 					    snd_config_t *attr, char *data_name,
477 					    const char *token_ref, const char *array_name)
478 {
479 	snd_config_t *top, *tuple_cfg, *child, *cfg, *new;
480 	const char *id;
481 	char *token, *type, *str;
482 	long tuple_value;
483 	int ret;
484 
485 	tplg_pp_debug("Building vendor tuples section: '%s' ...", data_name);
486 
487 	ret = snd_config_search(tplg_pp->output_cfg, "SectionVendorTuples", &top);
488 	if (ret < 0) {
489 		ret = tplg_config_make_add(&top, "SectionVendorTuples",
490 					  SND_CONFIG_TYPE_COMPOUND, tplg_pp->output_cfg);
491 		if (ret < 0) {
492 			SNDERR("Error creating SectionVendorTuples config\n");
493 			return ret;
494 		}
495 	}
496 
497 	type = strchr(token_ref, '.');
498 	if(!type) {
499 		SNDERR("Error getting type for %s\n", token_ref);
500 		return -EINVAL;
501 	}
502 
503 	token = calloc(1, strlen(token_ref) - strlen(type) + 1);
504 	if (!token)
505 		return -ENOMEM;
506 	snprintf(token, strlen(token_ref) - strlen(type) + 1, "%s", token_ref);
507 
508 	if (!array_name)
509 		str = strdup(type + 1);
510 	else
511 		str = tplg_snprintf("%s.%s", type + 1, array_name);
512 	if (!str) {
513 		ret = -ENOMEM;
514 		goto free;
515 	}
516 
517 	tuple_cfg = tplg_find_config(top, data_name);
518 	if (!tuple_cfg) {
519 		/* add new SectionVendorTuples */
520 		ret = tplg_config_make_add(&tuple_cfg, data_name, SND_CONFIG_TYPE_COMPOUND, top);
521 		if (ret < 0) {
522 			SNDERR("Error creating new vendor tuples config %s\n", data_name);
523 			goto err;
524 		}
525 
526 		ret = tplg_config_make_add(&child, "tokens", SND_CONFIG_TYPE_STRING,
527 					  tuple_cfg);
528 		if (ret < 0) {
529 			SNDERR("Error creating tokens config for '%s'\n", data_name);
530 			goto err;
531 		}
532 
533 		ret = snd_config_set_string(child, token);
534 		if (ret < 0) {
535 			SNDERR("Error setting tokens config for '%s'\n", data_name);
536 			goto err;
537 		}
538 
539 		ret = tplg_config_make_add(&child, "tuples", SND_CONFIG_TYPE_COMPOUND,
540 					  tuple_cfg);
541 		if (ret < 0) {
542 			SNDERR("Error creating tuples config for '%s'\n", data_name);
543 			goto err;
544 		}
545 
546 		ret = tplg_config_make_add(&cfg, str, SND_CONFIG_TYPE_COMPOUND,
547 					  child);
548 		if (ret < 0) {
549 			SNDERR("Error creating tuples type config for '%s'\n", data_name);
550 			goto err;
551 		}
552 	} else {
553 		snd_config_t *tuples_cfg;
554 
555 		ret = snd_config_search(tuple_cfg, "tuples" , &tuples_cfg);
556 		if (ret < 0) {
557 			SNDERR("can't find tuples config in %s\n", data_name);
558 			goto err;
559 		}
560 
561 		cfg = tplg_find_config(tuples_cfg, str);
562 		if (!cfg) {
563 			ret = tplg_config_make_add(&cfg, str, SND_CONFIG_TYPE_COMPOUND,
564 						  tuples_cfg);
565 			if (ret < 0) {
566 				SNDERR("Error creating tuples config for '%s' and type name %s\n", data_name, str);
567 				goto err;
568 			}
569 		}
570 	}
571 
572 	ret = snd_config_get_id(attr, &id);
573 	if (ret < 0)
574 		goto err;
575 
576 	/* tuple exists already? */
577 	ret = snd_config_search(cfg, id, &child);
578 	if (ret >=0)
579 		goto err;
580 
581 	/* add attribute to tuples */
582 	tuple_value = tplg_class_attribute_valid_tuple_value(tplg_pp, class_cfg, attr);
583 	if (tuple_value < 0) {
584 		/* just copy attribute cfg as is */
585 		ret = snd_config_copy(&new, attr);
586 		if (ret < 0) {
587 			SNDERR("can't copy attribute for %s\n", data_name);
588 			goto err;
589 		}
590 	} else {
591 		ret = snd_config_make(&new, id, SND_CONFIG_TYPE_INTEGER);
592 		if (ret < 0)
593 			goto err;
594 
595 		ret = snd_config_set_integer(new, tuple_value);
596 		if (ret < 0)
597 			goto err;
598 	}
599 
600 	ret = snd_config_add(cfg, new);
601 err:
602 	free(str);
603 free:
604 	free(token);
605 	return ret;
606 }
607 
tplg_pp_add_object_data_section(struct tplg_pre_processor * tplg_pp,snd_config_t * obj_data,char * data_name)608 static int tplg_pp_add_object_data_section(struct tplg_pre_processor *tplg_pp,
609 					   snd_config_t *obj_data, char *data_name)
610 {
611 	snd_config_iterator_t i, next;
612 	snd_config_t *top, *data_cfg, *child;
613 	char *data_id;
614 	int ret, id = 0;
615 
616 	ret = snd_config_search(tplg_pp->output_cfg, "SectionData", &top);
617 	if (ret < 0) {
618 		ret = tplg_config_make_add(&top, "SectionData", SND_CONFIG_TYPE_COMPOUND,
619 					  tplg_pp->output_cfg);
620 		if (ret < 0) {
621 			SNDERR("Failed to add SectionData\n");
622 			return ret;
623 		}
624 	}
625 
626 	/* nothing to do if data section already exists */
627 	data_cfg = tplg_find_config(top, data_name);
628 	if (data_cfg)
629 		return 0;
630 
631 	tplg_pp_debug("Building data section %s ...", data_name);
632 
633 	/* add new SectionData */
634 	ret = tplg_config_make_add(&data_cfg, data_name, SND_CONFIG_TYPE_COMPOUND, top);
635 	if (ret < 0)
636 		return ret;
637 
638 	ret = tplg_config_make_add(&child, "tuples", SND_CONFIG_TYPE_STRING, data_cfg);
639 	if (ret < 0) {
640 		SNDERR("error adding data ref for %s\n", data_name);
641 		return ret;
642 	}
643 
644 	ret = snd_config_set_string(child, data_name);
645 	if (ret < 0) {
646 		SNDERR("error setting tuples ref for %s\n", data_name);
647 		return ret;
648 	}
649 
650 	/* add data item to object */
651 	snd_config_for_each(i, next, obj_data)
652 		id++;
653 
654 	data_id = tplg_snprintf("%d", id);
655 	if (!data_id)
656 		return -ENOMEM;
657 
658 	ret = tplg_config_make_add(&child, data_id, SND_CONFIG_TYPE_STRING, obj_data);
659 	free(data_id);
660 	if (ret < 0) {
661 		SNDERR("error adding data ref %s\n", data_name);
662 		return ret;
663 	}
664 
665 	return snd_config_set_string(child, data_name);
666 }
667 
tplg_add_object_data(struct tplg_pre_processor * tplg_pp,snd_config_t * obj_cfg,snd_config_t * top,const char * array_name)668 int tplg_add_object_data(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
669 			 snd_config_t *top, const char *array_name)
670 {
671 	snd_config_iterator_t i, next;
672 	snd_config_t *data_cfg, *class_cfg, *n, *obj;
673 	const char *object_id;
674 	int ret;
675 
676 	if (snd_config_get_id(top, &object_id) < 0)
677 		return 0;
678 
679 	obj = tplg_object_get_instance_config(tplg_pp, obj_cfg);
680 
681 	class_cfg = tplg_class_lookup(tplg_pp, obj_cfg);
682 	if (!class_cfg)
683 		return -EINVAL;
684 
685 	/* add data config to top */
686 	ret = snd_config_search(top, "data", &data_cfg);
687 	if (ret < 0) {
688 		ret = tplg_config_make_add(&data_cfg, "data", SND_CONFIG_TYPE_COMPOUND, top);
689 		if (ret < 0) {
690 			SNDERR("error creating data config for %s\n", object_id);
691 			return ret;
692 		}
693 	}
694 
695 	/* add data items to object's data section */
696 	snd_config_for_each(i, next, obj) {
697 		const char *id, *token;
698 		char *data_cfg_name;
699 
700 		n = snd_config_iterator_entry(i);
701 		if (snd_config_get_id(n, &id) < 0)
702 			continue;
703 
704 		token = tplg_class_get_attribute_token_ref(tplg_pp, class_cfg, id);
705 		if (!token)
706 			continue;
707 
708 		data_cfg_name = tplg_snprintf("%s.%s", object_id, token);
709 		if (!data_cfg_name)
710 			return -ENOMEM;
711 
712 		ret = tplg_pp_add_object_data_section(tplg_pp, data_cfg, data_cfg_name);
713 		if (ret < 0) {
714 			SNDERR("Failed to add data section %s\n", data_cfg_name);
715 			free(data_cfg_name);
716 			return ret;
717 		}
718 
719 		ret = tplg_pp_add_object_tuple_section(tplg_pp, class_cfg, n, data_cfg_name,
720 						       token, array_name);
721 		if (ret < 0) {
722 			SNDERR("Failed to add data section %s\n", data_cfg_name);
723 			free(data_cfg_name);
724 			return ret;
725 		}
726 		free(data_cfg_name);
727 	}
728 
729 	return 0;
730 }
731 
732 /* 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)733 static int tplg_object_add_attributes(snd_config_t *dst, snd_config_t *template,
734 				      snd_config_t *src)
735 {
736 	snd_config_iterator_t i, next;
737 	snd_config_t *n;
738 	int ret;
739 
740 	snd_config_for_each(i, next, template) {
741 		snd_config_t *attr, *new;
742 		const char *id;
743 
744 		n = snd_config_iterator_entry(i);
745 		if (snd_config_get_id(n, &id) < 0)
746 			continue;
747 
748 		ret = snd_config_search(src, id, &attr);
749 		if (ret < 0)
750 			continue;
751 
752 		/* skip if attribute is already set */
753 		ret = snd_config_search(dst, id, &new);
754 		if (ret >= 0)
755 			continue;
756 
757 		ret = snd_config_copy(&new, attr);
758 		if (ret < 0) {
759 			SNDERR("failed to copy attribute %s\n", id);
760 			return ret;
761 		}
762 
763 		ret = snd_config_add(dst, new);
764 		if (ret < 0) {
765 			snd_config_delete(new);
766 			SNDERR("failed to add attribute %s\n", id);
767 			return ret;
768 		}
769 	}
770 
771 	return 0;
772 }
773 
774 static const struct build_function_map *tplg_object_get_map(struct tplg_pre_processor *tplg_pp,
775 							    snd_config_t *obj);
776 
777 /* 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)778 static int tplg_build_parent_data(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
779 				  snd_config_t *parent)
780 {
781 	snd_config_t *obj, *parent_obj, *section_cfg, *top;
782 	const struct build_function_map *map;
783 	const char *id, *parent_id;
784 	int ret;
785 
786 	/* nothing to do if parent is NULL */
787 	if (!parent)
788 		return 0;
789 
790 	obj = tplg_object_get_instance_config(tplg_pp, obj_cfg);
791 	parent_obj = tplg_object_get_instance_config(tplg_pp, parent);
792 
793 	/* get object ID */
794 	if (snd_config_get_id(obj, &id) < 0) {
795 		SNDERR("Invalid ID for object\n");
796 		return -EINVAL;
797 	}
798 
799 	/* get parent object name or ID */
800 	parent_id = tplg_object_get_name(tplg_pp, parent_obj);
801 	if (!parent_id) {
802 		ret = snd_config_get_id(parent_obj, &parent_id);
803 		if (ret < 0) {
804 			SNDERR("Invalid ID for parent of object %s\n", id);
805 			return ret;
806 		}
807 	}
808 
809 	map = tplg_object_get_map(tplg_pp, parent);
810 	if (!map) {
811 		SNDERR("Parent object %s not supported\n", parent_id);
812 		return -EINVAL;
813 	}
814 
815 	/* find parent config with ID */
816 	ret = snd_config_search(tplg_pp->output_cfg, map->section_name, &section_cfg);
817 	if (ret < 0) {
818 		SNDERR("No SectionBE found\n");
819 		return ret;
820 	}
821 
822 	top = tplg_find_config(section_cfg, parent_id);
823 	if (!top) {
824 		SNDERR("SectionBE %s not found\n", parent_id);
825 		return -EINVAL;
826 	}
827 
828 	return tplg_add_object_data(tplg_pp, obj_cfg, top, id);
829 }
830 
831 /*
832  * Function to create a new "section" config based on the template. The new config will be
833  * added to the output_cfg or the top_config input parameter.
834  */
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)835 int tplg_build_object_from_template(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
836 				    snd_config_t **wtop, snd_config_t *top_config,
837 				    bool skip_name)
838 {
839 	snd_config_t *top, *template, *obj;
840 	const struct build_function_map *map;
841 	const char *object_name;
842 	int ret;
843 
844 	/* look up object map */
845 	map = tplg_object_get_map(tplg_pp, obj_cfg);
846 	if (!map) {
847 		SNDERR("unknown object type or class name\n");
848 		return -EINVAL;
849 	}
850 
851 	obj = tplg_object_get_instance_config(tplg_pp, obj_cfg);
852 
853 	/* look up or create the corresponding section config for object */
854 	if (!top_config)
855 		top_config = tplg_pp->output_cfg;
856 
857 	ret = snd_config_search(top_config, map->section_name, &top);
858 	if (ret < 0) {
859 		ret = tplg_config_make_add(&top, map->section_name, SND_CONFIG_TYPE_COMPOUND,
860 					   top_config);
861 		if (ret < 0) {
862 			SNDERR("Error creating %s config\n", map->section_name);
863 			return ret;
864 		}
865 	}
866 
867 	/* get object name */
868 	object_name = tplg_object_get_name(tplg_pp, obj);
869 	if (!object_name) {
870 		ret = snd_config_get_id(obj, &object_name);
871 		if (ret < 0) {
872 			SNDERR("Invalid ID for %s\n", map->section_name);
873 			return ret;
874 		}
875 	}
876 
877 	tplg_pp_debug("Building object: '%s' ...", object_name);
878 
879 	/* create and add new object config with name, if needed */
880 	if (skip_name) {
881 		*wtop = top;
882 	} else {
883 		*wtop = tplg_find_config(top, object_name);
884 		if (*wtop)
885 			goto template;
886 
887 		ret = tplg_config_make_add(wtop, object_name, SND_CONFIG_TYPE_COMPOUND,
888 					   top);
889 		if (ret < 0) {
890 			SNDERR("Error creating config for %s\n", object_name);
891 			return ret;
892 		}
893 	}
894 
895 template:
896 	/* create template config */
897 	if (!map->template_items)
898 		return 0;
899 
900 	ret = tplg_create_config_template(tplg_pp, &template, map->template_items);
901 	if (ret < 0) {
902 		SNDERR("Error creating template config for %s\n", object_name);
903 		return ret;
904 	}
905 
906 	/* update section config based on template and the attribute values in the object */
907 	ret = tplg_object_add_attributes(*wtop, template, obj);
908 	snd_config_delete(template);
909 	if (ret < 0)
910 		SNDERR("Error adding attributes for object '%s'\n", object_name);
911 
912 	return ret;
913 }
914 
tplg_build_generic_object(struct tplg_pre_processor * tplg_pp,snd_config_t * obj_cfg,snd_config_t * parent)915 static int tplg_build_generic_object(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
916 				     snd_config_t *parent)
917 {
918 	snd_config_t *wtop;
919 	const char *name;
920 	int ret;
921 
922 	ret = tplg_build_object_from_template(tplg_pp, obj_cfg, &wtop, NULL, false);
923 	if (ret < 0)
924 		return ret;
925 
926 	ret = snd_config_get_id(wtop, &name);
927 	if (ret < 0)
928 		return ret;
929 
930 	ret = tplg_add_object_data(tplg_pp, obj_cfg, wtop, NULL);
931 	if (ret < 0)
932 		SNDERR("Failed to add data section for %s\n", name);
933 
934 	return ret;
935 }
936 
937 const struct config_template_items pcm_caps_config = {
938 	.int_config_ids = {"rate_min", "rate_max", "channels_min", "channels_max", "periods_min",
939 			   "periods_max", "period_size_min", "period_size_max", "buffer_size_min",
940 			   "buffer_size_max", "sig_bits"},
941 	.string_config_ids = {"formats", "rates"},
942 };
943 
944 const struct config_template_items fe_dai_config = {
945 	.int_config_ids = {"id"},
946 };
947 
948 const struct config_template_items hwcfg_config = {
949 	.int_config_ids = {"id", "bclk_freq", "bclk_invert", "fsync_invert", "fsync_freq",
950 			   "mclk_freq", "pm_gate_clocks", "tdm_slots", "tdm_slot_width",
951 			   "tx_slots", "rx_slots", "tx_channels", "rx_channels"},
952 	.string_config_ids = {"format", "bclk", "fsync", "mclk"},
953 };
954 
955 const struct config_template_items be_dai_config = {
956 	.int_config_ids = {"id", "default_hw_conf_id", "symmertic_rates", "symmetric_channels",
957 			   "symmetric_sample_bits"},
958 	.string_config_ids = {"stream_name"},
959 };
960 
961 const struct config_template_items pcm_config = {
962 	.int_config_ids = {"id", "compress", "symmertic_rates", "symmetric_channels",
963 			   "symmetric_sample_bits"},
964 };
965 
966 const struct config_template_items mixer_control_config = {
967 	.int_config_ids = {"index", "max", "invert"},
968 	.compound_config_ids = {"access"}
969 };
970 
971 const struct config_template_items bytes_control_config = {
972 	.int_config_ids = {"index", "base", "num_regs", "max", "mask"},
973 	.compound_config_ids = {"access"}
974 };
975 
976 const struct config_template_items scale_config = {
977 	.int_config_ids = {"min", "step", "mute"},
978 };
979 
980 const struct config_template_items ops_config = {
981 	.int_config_ids = {"get", "put"},
982 	.string_config_ids = {"info"},
983 };
984 
985 const struct config_template_items channel_config = {
986 	.int_config_ids = {"reg", "shift"},
987 };
988 
989 const struct config_template_items widget_config = {
990 	.int_config_ids = {"index", "no_pm", "shift", "invert", "subseq", "event_type",
991 			    "event_flags"},
992 	.string_config_ids = {"type", "stream_name"},
993 };
994 
995 const struct config_template_items data_config = {
996 	.string_config_ids = {"bytes"}
997 };
998 
999 /*
1000  * Items without class name should be placed lower than those with one,
1001  * because they are much more generic.
1002  */
1003 const struct build_function_map object_build_map[] = {
1004 	{"Base", "manifest", "SectionManifest", &tplg_build_generic_object, NULL, NULL},
1005 	{"Base", "data", "SectionData", &tplg_build_data_object, NULL, &data_config},
1006 	{"Base", "tlv", "SectionTLV", &tplg_build_tlv_object, NULL, NULL},
1007 	{"Base", "scale", "scale", &tplg_build_scale_object, NULL, &scale_config},
1008 	{"Base", "ops", "ops" ,&tplg_build_ops_object, NULL, &ops_config},
1009 	{"Base", "extops", "extops" ,&tplg_build_ops_object, NULL, &ops_config},
1010 	{"Base", "channel", "channel", &tplg_build_channel_object, NULL, &channel_config},
1011 	{"Base", "VendorToken", "SectionVendorTokens", &tplg_build_vendor_token_object,
1012 	 NULL, NULL},
1013 	{"Base", "hw_config", "SectionHWConfig", &tplg_build_hw_cfg_object, NULL,
1014 	 &hwcfg_config},
1015 	{"Base", "fe_dai", "dai", &tplg_build_fe_dai_object, NULL, &fe_dai_config},
1016 	{"Base", "route", "SectionGraph", &tplg_build_dapm_route_object, NULL, NULL},
1017 	{"Widget", "buffer", "SectionWidget", &tplg_build_generic_object,
1018 	 tplg_update_buffer_auto_attr, &widget_config},
1019 	{"Widget", "", "SectionWidget", &tplg_build_generic_object, NULL, &widget_config},
1020 	{"Control", "mixer", "SectionControlMixer", &tplg_build_mixer_control, NULL,
1021 	 &mixer_control_config},
1022 	{"Control", "bytes", "SectionControlBytes", &tplg_build_bytes_control, NULL,
1023 	 &bytes_control_config},
1024 	{"Dai", "", "SectionBE", &tplg_build_generic_object, NULL, &be_dai_config},
1025 	{"PCM", "pcm", "SectionPCM", &tplg_build_generic_object, NULL, &pcm_config},
1026 	{"PCM", "pcm_caps", "SectionPCMCapabilities", &tplg_build_pcm_caps_object,
1027 	 NULL, &pcm_caps_config},
1028 };
1029 
tplg_object_get_map(struct tplg_pre_processor * tplg_pp,snd_config_t * obj)1030 static const struct build_function_map *tplg_object_get_map(struct tplg_pre_processor *tplg_pp,
1031 							    snd_config_t *obj)
1032 {
1033 	snd_config_iterator_t first;
1034 	snd_config_t *class;
1035 	const char *class_type, *class_name;
1036 	unsigned int i;
1037 
1038 	first = snd_config_iterator_first(obj);
1039 	class = snd_config_iterator_entry(first);
1040 
1041 	if (snd_config_get_id(class, &class_name) < 0)
1042 		return NULL;
1043 
1044 	if (snd_config_get_id(obj, &class_type) < 0)
1045 		return NULL;
1046 
1047 	for (i = 0; i < ARRAY_SIZE(object_build_map); i++) {
1048 		if (!strcmp(class_type, "Widget") &&
1049 		    !strcmp(object_build_map[i].class_type, "Widget") &&
1050 			!strcmp(object_build_map[i].class_name, ""))
1051 			return &object_build_map[i];
1052 
1053 		if (!strcmp(class_type, "Dai") &&
1054 		    !strcmp(object_build_map[i].class_type, "Dai"))
1055 			return &object_build_map[i];
1056 
1057 		/* for other type objects, also match the object class_name */
1058 		if (!strcmp(class_type, object_build_map[i].class_type) &&
1059 		    !strcmp(object_build_map[i].class_name, class_name))
1060 			return &object_build_map[i];
1061 	}
1062 
1063 	return NULL;
1064 }
1065 
1066 /* 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)1067 snd_config_t *tplg_object_get_section(struct tplg_pre_processor *tplg_pp, snd_config_t *class)
1068 {
1069 	const struct build_function_map *map;
1070 	snd_config_t *cfg = NULL;
1071 	int ret;
1072 
1073 	map = tplg_object_get_map(tplg_pp, class);
1074 	if (!map)
1075 		return NULL;
1076 
1077 	ret = snd_config_search(tplg_pp->output_cfg, map->section_name, &cfg);
1078 	if (ret < 0)
1079 		SNDERR("Section config for %s not found\n", map->section_name);
1080 
1081 	return cfg;
1082 }
1083 
1084 /* 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,snd_config_t * obj,snd_config_t * attr_cfg,snd_config_t * search_config)1085 static int tplg_object_copy_and_add_param(struct tplg_pre_processor *tplg_pp,
1086 					  snd_config_t *obj,
1087 					  snd_config_t *attr_cfg,
1088 					  snd_config_t *search_config)
1089 {
1090 	snd_config_t *attr, *new;
1091 	const char *id, *search_id;
1092 	int ret;
1093 
1094 	if (snd_config_get_id(attr_cfg, &id) < 0)
1095 		return 0;
1096 
1097 	if (snd_config_get_id(search_config, &search_id) < 0)
1098 		return 0;
1099 
1100 	/* copy object value */
1101 	ret = snd_config_search(search_config, id, &attr);
1102 	if (ret < 0)
1103 		return 1;
1104 
1105 	ret = snd_config_copy(&new, attr);
1106 	if (ret < 0) {
1107 		SNDERR("error copying attribute '%s' value from %s\n", id, search_id);
1108 		return ret;
1109 	}
1110 
1111 	ret = snd_config_add(obj, new);
1112 	if (ret < 0) {
1113 		snd_config_delete(new);
1114 		SNDERR("error adding attribute '%s' value to %s\n", id, search_id);
1115 	}
1116 
1117 	return ret;
1118 }
1119 
1120 /*
1121  * Attribute values for an object can be set in one of the following in order of
1122  * precedence:
1123  * 1. Value set in object instance
1124  * 2. Default value set in the object's class definition
1125  * 3. Inherited value from the parent object
1126  * 4. Value set in the object instance embedded in the parent object
1127  * 5. Value set in the object instance embedded in the parent class definition
1128  */
tplg_object_update(struct tplg_pre_processor * tplg_pp,snd_config_t * obj,snd_config_t * parent)1129 static int tplg_object_update(struct tplg_pre_processor *tplg_pp, snd_config_t *obj,
1130 			      snd_config_t *parent)
1131 {
1132 	snd_config_iterator_t i, next;
1133 	snd_config_t *n, *cfg, *args;
1134 	snd_config_t *obj_cfg, *class_cfg, *parent_obj;
1135 	const char *obj_id, *class_name, *class_type;
1136 	int ret;
1137 
1138 	class_cfg = tplg_class_lookup(tplg_pp, obj);
1139 	if (!class_cfg)
1140 		return -EINVAL;
1141 
1142 	/* find config for class attributes */
1143 	ret = snd_config_search(class_cfg, "DefineAttribute", &args);
1144 	if (ret < 0)
1145 		return 0;
1146 
1147 	if (snd_config_get_id(obj, &class_type) < 0)
1148 		return 0;
1149 
1150 	if (snd_config_get_id(class_cfg, &class_name) < 0)
1151 		return 0;
1152 
1153 	/* get obj cfg */
1154 	obj_cfg = tplg_object_get_instance_config(tplg_pp, obj);
1155 	if (snd_config_get_id(obj_cfg, &obj_id) < 0)
1156 		return 0;
1157 
1158 	/* copy and add attributes */
1159 	snd_config_for_each(i, next, args) {
1160 		snd_config_t *attr;
1161 		const char *id;
1162 
1163 		n = snd_config_iterator_entry(i);
1164 		if (snd_config_get_id(n, &id) < 0)
1165 			continue;
1166 
1167 		if (tplg_class_is_attribute_unique(id, class_cfg))
1168 			continue;
1169 
1170 		if (tplg_class_is_attribute_immutable(id, class_cfg))
1171 			goto class;
1172 
1173 		/* check if attribute value is set in the object */
1174 		ret = snd_config_search(obj_cfg, id, &attr);
1175 		if (ret < 0)
1176 			goto class;
1177 		goto validate;
1178 class:
1179 		/* search for attributes value in class */
1180 		ret = tplg_object_copy_and_add_param(tplg_pp, obj_cfg, n, class_cfg);
1181 		if (ret == 1) {
1182 			if (tplg_class_is_attribute_immutable(id, class_cfg)) {
1183 				SNDERR("Immutable attribute %s not set in class %s\n",
1184 				       id, class_name);
1185 				return -EINVAL;
1186 			}
1187 			goto parent;
1188 		}
1189 		else if (ret < 0)
1190 			return ret;
1191 		goto validate;
1192 parent:
1193 		/* search for attribute value in parent */
1194 		if (!parent)
1195 			goto parent_object;
1196 
1197 		/* get parent obj cfg */
1198 		parent_obj = tplg_object_get_instance_config(tplg_pp, parent);
1199 		if (!parent_obj)
1200 			goto parent_object;
1201 
1202 		ret = tplg_object_copy_and_add_param(tplg_pp, obj_cfg, n, parent_obj);
1203 		if (ret == 1)
1204 			goto parent_object;
1205 		else if (ret < 0)
1206 			return ret;
1207 		goto validate;
1208 parent_object:
1209 		if (!parent)
1210 			goto parent_class;
1211 
1212 		cfg = tplg_object_lookup_in_config(tplg_pp, parent_obj, class_type,
1213 						   class_name, obj_id);
1214 		if (!cfg)
1215 			goto parent_class;
1216 
1217 		ret = tplg_object_copy_and_add_param(tplg_pp, obj_cfg, n, cfg);
1218 		if (ret == 1)
1219 			goto parent_class;
1220 		else if (ret < 0)
1221 			return ret;
1222 		goto validate;
1223 parent_class:
1224 		if (!parent)
1225 			goto check;
1226 
1227 		cfg = tplg_class_lookup(tplg_pp, parent);
1228 		if (!cfg)
1229 			return -EINVAL;
1230 
1231 		cfg = tplg_object_lookup_in_config(tplg_pp, cfg, class_type,
1232 						   class_name, obj_id);
1233 		if (!cfg)
1234 			goto check;
1235 
1236 		ret = tplg_object_copy_and_add_param(tplg_pp, obj_cfg, n, cfg);
1237 		if (ret == 1)
1238 			goto check;
1239 		else if (ret < 0)
1240 			return ret;
1241 		goto validate;
1242 check:
1243 		if (tplg_class_is_attribute_mandatory(id, class_cfg)) {
1244 			SNDERR("Mandatory attribute %s not set for class %s\n", id, class_name);
1245 			return -EINVAL;
1246 		}
1247 		continue;
1248 validate:
1249 		if (!tplg_object_is_attribute_valid(tplg_pp, n, obj_cfg))
1250 			return -EINVAL;
1251 	}
1252 
1253 	return 0;
1254 }
1255 
tplg_object_pre_process_children(struct tplg_pre_processor * tplg_pp,snd_config_t * parent,snd_config_t * cfg)1256 static int tplg_object_pre_process_children(struct tplg_pre_processor *tplg_pp,
1257 					    snd_config_t *parent, snd_config_t *cfg)
1258 {
1259 	snd_config_iterator_t i, next;
1260 	snd_config_t *children, *n;
1261 	int ret;
1262 
1263 	ret = snd_config_search(cfg, "Object", &children);
1264 	if (ret < 0)
1265 		return 0;
1266 
1267 	/* create all embedded objects */
1268 	snd_config_for_each(i, next, children) {
1269 		const char *id;
1270 
1271 		n = snd_config_iterator_entry(i);
1272 		if (snd_config_get_id(n, &id) < 0)
1273 			continue;
1274 
1275 		ret = tplg_pre_process_objects(tplg_pp, n, parent);
1276 		if (ret < 0)
1277 			return ret;
1278 	}
1279 
1280 	return 0;
1281 }
1282 
tplg_construct_object_name(struct tplg_pre_processor * tplg_pp,snd_config_t * obj,snd_config_t * class_cfg)1283 static int tplg_construct_object_name(struct tplg_pre_processor *tplg_pp, snd_config_t *obj,
1284 				      snd_config_t *class_cfg)
1285 {
1286 	snd_config_iterator_t i, next;
1287 	snd_config_t *args, *n;
1288 	const char *id, *class_id, *obj_id, *s;
1289 	char *new_name;
1290 	int ret;
1291 
1292 	/* find config for class constructor attributes. Nothing to do if not defined */
1293 	ret = snd_config_search(class_cfg, "attributes.constructor", &args);
1294 	if (ret < 0)
1295 		return 0;
1296 
1297 	/* set class name as the name prefix for the object */
1298 	if (snd_config_get_id(obj, &obj_id) < 0)
1299 		return -EINVAL;
1300 	if (snd_config_get_id(class_cfg, &class_id) < 0)
1301 		return -EINVAL;
1302 	new_name = strdup(class_id);
1303 	if (!new_name)
1304 		return -ENOMEM;
1305 
1306 	/* iterate through all class arguments and set object name */
1307 	snd_config_for_each(i, next, args) {
1308 		snd_config_t *arg;
1309 		char *arg_value, *temp;
1310 
1311 		n = snd_config_iterator_entry(i);
1312 
1313 		if (snd_config_get_id(n, &id) < 0) {
1314 			SNDERR("Invalid ID for constructor argument\n");
1315 			ret = -EINVAL;
1316 			goto err;
1317 		}
1318 
1319 		if (snd_config_get_string(n, &s) < 0) {
1320 			SNDERR("Invalid value for constructor argument\n");
1321 			ret = -EINVAL;
1322 			goto err;
1323 		}
1324 
1325 		/* find and replace with value set in object */
1326 		ret = snd_config_search(obj, s, &arg);
1327 		if (ret < 0) {
1328 			SNDERR("Argument %s not set for object '%s.%s'\n", s, class_id, obj_id);
1329 			ret = -ENOENT;
1330 			goto err;
1331 		}
1332 
1333 		/* concat arg value to object name. arg types must be either integer or string */
1334 		switch (snd_config_get_type(arg)) {
1335 		case SND_CONFIG_TYPE_INTEGER:
1336 		{
1337 			long v;
1338 			ret = snd_config_get_integer(arg, &v);
1339 			assert(ret >= 0);
1340 
1341 			arg_value = tplg_snprintf("%ld", v);
1342 			if (!arg_value) {
1343 				ret = -ENOMEM;
1344 				goto err;
1345 			}
1346 			break;
1347 		}
1348 		case SND_CONFIG_TYPE_STRING:
1349 		{
1350 			const char *s;
1351 
1352 			ret = snd_config_get_string(arg, &s);
1353 			assert(ret >= 0);
1354 
1355 			arg_value = strdup(s);
1356 			if (!arg_value) {
1357 				ret = -ENOMEM;
1358 				goto err;
1359 			}
1360 			break;
1361 		}
1362 		default:
1363 			SNDERR("Argument '%s' in object '%s.%s' is not an integer or a string\n",
1364 			       s, class_id, obj_id);
1365 			ret = -EINVAL;
1366 			goto err;
1367 		}
1368 
1369 		/* alloc and concat arg value to the name */
1370 		temp = tplg_snprintf("%s.%s", new_name, arg_value);
1371 		free(arg_value);
1372 		if (!temp) {
1373 			ret = -ENOMEM;
1374 			goto err;
1375 		}
1376 		free(new_name);
1377 		new_name = temp;
1378 	}
1379 
1380 	ret = snd_config_set_id(obj, new_name);
1381 err:
1382 	free(new_name);
1383 	return ret;
1384 }
1385 
1386 /* set the attribute value by type */
tplg_set_attribute_value(snd_config_t * attr,const char * value)1387 static int tplg_set_attribute_value(snd_config_t *attr, const char *value)
1388 {
1389 	int err;
1390 	snd_config_type_t type = snd_config_get_type(attr);
1391 
1392 	switch (type) {
1393 	case SND_CONFIG_TYPE_INTEGER:
1394 	{
1395 		long v;
1396 
1397 		v = strtol(value, NULL, 10);
1398 		err = snd_config_set_integer(attr, v);
1399 		assert(err >= 0);
1400 		break;
1401 	}
1402 	case SND_CONFIG_TYPE_INTEGER64:
1403 	{
1404 		long long v;
1405 
1406 		v = strtoll(value, NULL, 10);
1407 		err = snd_config_set_integer64(attr, v);
1408 		assert(err >= 0);
1409 		break;
1410 	}
1411 	case SND_CONFIG_TYPE_STRING:
1412 	{
1413 		err = snd_config_set_string(attr, value);
1414 		assert(err >= 0);
1415 		break;
1416 	}
1417 	default:
1418 		return -EINVAL;
1419 	}
1420 
1421 	return 0;
1422 }
1423 
1424 
1425 /*
1426  * Find the unique attribute in the class definition and set its value and type.
1427  * Only string or integer types are allowed for unique values.
1428  */
tplg_object_set_unique_attribute(struct tplg_pre_processor * tplg_pp,snd_config_t * obj,snd_config_t * class_cfg,const char * id)1429 static int tplg_object_set_unique_attribute(struct tplg_pre_processor *tplg_pp,
1430 					    snd_config_t *obj, snd_config_t *class_cfg,
1431 					    const char *id)
1432 {
1433 	snd_config_t *unique_attr, *new;
1434 	const char *unique_name, *class_id;
1435 	int ret;
1436 
1437 	if (snd_config_get_id(class_cfg, &class_id) < 0)
1438 		return 0;
1439 
1440 	/* find config for class unique attribute */
1441 	unique_name = tplg_class_get_unique_attribute_name(tplg_pp, class_cfg);
1442 	if (!unique_name)
1443 		return -ENOENT;
1444 
1445 	/* find the unique attribute definition in the class */
1446 	unique_attr = tplg_class_find_attribute_by_name(tplg_pp, class_cfg, unique_name);
1447 	if (!unique_attr)
1448 		return -ENOENT;
1449 
1450 	/* override value if unique attribute is set in the object instance */
1451 	ret = snd_config_search(obj, unique_name, &new);
1452 	if (ret < 0) {
1453 		ret = snd_config_make(&new, unique_name,
1454 				      tplg_class_get_attribute_type(tplg_pp, unique_attr));
1455 		if (ret < 0) {
1456 			SNDERR("error creating new attribute cfg for object %s\n", id);
1457 			return ret;
1458 		}
1459 		ret = snd_config_add(obj, new);
1460 		if (ret < 0) {
1461 			SNDERR("error adding new attribute cfg for object %s\n", id);
1462 			return ret;
1463 		}
1464 	}
1465 
1466 	ret = tplg_set_attribute_value(new, id);
1467 	if (ret < 0) {
1468 		SNDERR("error setting unique attribute cfg for object %s\n", id);
1469 		return ret;
1470 	}
1471 
1472 	return ret;
1473 }
1474 
1475 /*
1476  * Helper function to get object instance config which is 2 nodes down from class_type config.
1477  * ex: Get the pointer to the config node with ID "0" from the input config Widget.pga.0 {}
1478  */
tplg_object_get_instance_config(struct tplg_pre_processor * tplg_pp,snd_config_t * class_type)1479 snd_config_t *tplg_object_get_instance_config(struct tplg_pre_processor *tplg_pp,
1480 					snd_config_t *class_type)
1481 {
1482 	snd_config_iterator_t first;
1483 	snd_config_t *cfg;
1484 
1485 	first = snd_config_iterator_first(class_type);
1486 	cfg = snd_config_iterator_entry(first);
1487 	first = snd_config_iterator_first(cfg);
1488 	return snd_config_iterator_entry(first);
1489 }
1490 
1491 /* 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)1492 static int tplg_build_object(struct tplg_pre_processor *tplg_pp, snd_config_t *new_obj,
1493 			      snd_config_t *parent)
1494 {
1495 	snd_config_t *obj_local, *class_cfg;
1496 	const struct build_function_map *map;
1497 	build_func builder;
1498 	update_auto_attr_func auto_attr_updater;
1499 	const char *id, *class_id;
1500 	int ret;
1501 
1502 	obj_local = tplg_object_get_instance_config(tplg_pp, new_obj);
1503 	if (!obj_local)
1504 		return -EINVAL;
1505 
1506 	class_cfg = tplg_class_lookup(tplg_pp, new_obj);
1507 	if (!class_cfg)
1508 		return -EINVAL;
1509 
1510 	if (snd_config_get_id(obj_local, &id) < 0)
1511 		return 0;
1512 
1513 	if (snd_config_get_id(class_cfg, &class_id) < 0)
1514 		return 0;
1515 
1516 	/* set unique attribute value */
1517 	ret = tplg_object_set_unique_attribute(tplg_pp, obj_local, class_cfg, id);
1518 	if (ret < 0) {
1519 		SNDERR("error setting unique attribute value for '%s.%s'\n", class_id, id);
1520 		return ret;
1521 	}
1522 
1523 	/* update object attributes and validate them */
1524 	ret = tplg_object_update(tplg_pp, new_obj, parent);
1525 	if (ret < 0) {
1526 		SNDERR("Failed to update attributes for object '%s.%s'\n", class_id, id);
1527 		return ret;
1528 	}
1529 
1530 	/* construct object name using class constructor */
1531 	ret = tplg_construct_object_name(tplg_pp, obj_local, class_cfg);
1532 	if (ret < 0) {
1533 		SNDERR("Failed to construct object name for %s\n", id);
1534 		return ret;
1535 	}
1536 
1537 	/*
1538 	 * Build objects if object type is supported.
1539 	 * If not, process object attributes and add to parent's data section
1540 	 */
1541 	map = tplg_object_get_map(tplg_pp, new_obj);
1542 	if (map) {
1543 		builder = map->builder;
1544 
1545 		/* update automatic attribute for current object */
1546 		auto_attr_updater = map->auto_attr_updater;
1547 		if(auto_attr_updater) {
1548 			ret = auto_attr_updater(tplg_pp, obj_local, parent);
1549 			if (ret < 0) {
1550 				SNDERR("Failed to update automatic attributes for %s\n", id);
1551 				return ret;
1552 			}
1553 		}
1554 	} else {
1555 		builder = &tplg_build_parent_data;
1556 	}
1557 
1558 	ret = builder(tplg_pp, new_obj, parent);
1559 	if (ret < 0)
1560 		return ret;
1561 
1562 	/* create child objects in the object instance */
1563 	ret = tplg_object_pre_process_children(tplg_pp, new_obj, obj_local);
1564 	if (ret < 0) {
1565 		SNDERR("error processing child objects in object %s\n", id);
1566 		return ret;
1567 	}
1568 
1569 	/* create child objects in the object's class definition */
1570 	ret = tplg_object_pre_process_children(tplg_pp, new_obj, class_cfg);
1571 	if (ret < 0)
1572 		SNDERR("error processing child objects in class %s\n", class_id);
1573 
1574 	return ret;
1575 }
1576 
1577 /* create top-level topology objects */
tplg_pre_process_objects(struct tplg_pre_processor * tplg_pp,snd_config_t * cfg,snd_config_t * parent)1578 int tplg_pre_process_objects(struct tplg_pre_processor *tplg_pp, snd_config_t *cfg,
1579 			     snd_config_t *parent)
1580 {
1581 	snd_config_iterator_t i, next, i2, next2;
1582 	snd_config_t *n, *n2, *_obj_type, *_obj_class, *_obj;
1583 	const char *id, *class_type, *class_name;
1584 	int ret;
1585 
1586 	if (snd_config_get_id(cfg, &class_type) < 0)
1587 		return 0;
1588 
1589 	/* create all objects of the same type and class */
1590 	snd_config_for_each(i, next, cfg) {
1591 		n = snd_config_iterator_entry(i);
1592 		if (snd_config_get_id(n, &class_name) < 0)
1593 			continue;
1594 		snd_config_for_each(i2, next2, n) {
1595 			snd_config_t *temp_n2;
1596 
1597 			n2 = snd_config_iterator_entry(i2);
1598 			if (snd_config_get_id(n2, &id) < 0) {
1599 				SNDERR("Invalid id for object\n");
1600 				return -EINVAL;
1601 			}
1602 
1603 			ret = snd_config_copy(&temp_n2, n2);
1604 			if (ret < 0)
1605 				return ret;
1606 
1607 			/*
1608 			 * An object declared within a class definition as follows:
1609 			 * Class.Pipeline.volume-playback {
1610 			 * 	Object.Widget.pga.0 {
1611 			 * 		ramp_step_ms 250
1612             		 * 	}
1613 			 * }
1614 			 *
1615 			 * While instantiating the volume-pipeline class, the pga object
1616 			 * could be modified as follows:
1617 			 * Object.Pipeline.volume-playback.0 {
1618 			 * 	Object.Widget.pga.0 {
1619 			 * 		format "s24le"
1620 			 * 	}
1621 			 * }
1622 			 * When building the pga.0 object in the class definition, merge
1623 			 * the attributes declared in the volume-playback.0 object to create
1624 			 * a new config as follows to make sure that all attributes are
1625 			 * set for the pga object.
1626 			 * Object.Widget.pga.0 {
1627 			 * 	ramp_step_ms 250
1628 			 * 	format "s24le"
1629 			 * }
1630 			 */
1631 
1632 			if (parent) {
1633 				snd_config_t *parent_instance, *parent_obj, *temp;
1634 				char *obj_cfg_name;
1635 
1636 				obj_cfg_name = tplg_snprintf("%s%s.%s.%s", "Object.",
1637 							     class_type, class_name, id);
1638 
1639 				/* search for object instance in the parent */
1640 				parent_instance = tplg_object_get_instance_config(tplg_pp, parent);
1641 				if (!parent_instance)
1642 					goto temp_cfg;
1643 
1644 				ret = snd_config_search(parent_instance, obj_cfg_name, &parent_obj);
1645 				free(obj_cfg_name);
1646 				if (ret < 0)
1647 					goto temp_cfg;
1648 
1649 				/* don't merge if the object configs are the same */
1650 				if (parent_obj == n2)
1651 					goto temp_cfg;
1652 
1653 				/* create a temp config copying the parent object config */
1654 				ret = snd_config_copy(&temp, parent_obj);
1655 				if (ret < 0) {
1656 					snd_config_delete(temp_n2);
1657 					return ret;
1658 				}
1659 
1660 				/*
1661 				 * Merge parent object with the current object instance.
1662 				 * temp will be deleted by merge
1663 				 */
1664 				ret = snd_config_merge(temp_n2, temp, false);
1665 				if (ret < 0) {
1666 					SNDERR("error merging parent object config for %s.%s.%s\n",
1667 					       class_type, class_name, id);
1668 					snd_config_delete(temp_n2);
1669 					return ret;
1670 				}
1671 			}
1672 temp_cfg:
1673 			/* create a temp config for object with class type as the root node */
1674 			ret = snd_config_make(&_obj_type, class_type, SND_CONFIG_TYPE_COMPOUND);
1675 			if (ret < 0) {
1676 				snd_config_delete(temp_n2);
1677 				return ret;
1678 			}
1679 
1680 			ret = snd_config_make(&_obj_class, class_name, SND_CONFIG_TYPE_COMPOUND);
1681 			if (ret < 0)
1682 				goto err;
1683 
1684 			ret = snd_config_add(_obj_type, _obj_class);
1685 			if (ret < 0) {
1686 				snd_config_delete(_obj_class);
1687 				goto err;
1688 			}
1689 
1690 			ret = snd_config_copy(&_obj, temp_n2);
1691 			if (ret < 0)
1692 				goto err;
1693 
1694 			ret = snd_config_add(_obj_class, _obj);
1695 			if (ret < 0) {
1696 				snd_config_delete(_obj);
1697 				goto err;
1698 			}
1699 
1700 			/* Build the object now */
1701 			ret = tplg_build_object(tplg_pp, _obj_type, parent);
1702 			if (ret < 0)
1703 				SNDERR("Error building object %s.%s.%s\n",
1704 				       class_type, class_name, id);
1705 err:
1706 			snd_config_delete(temp_n2);
1707 			snd_config_delete(_obj_type);
1708 			if (ret < 0)
1709 				return ret;
1710 		}
1711 	}
1712 
1713 	return 0;
1714 }
1715