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, §ion_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