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