1 /*
2 Copyright(c) 2014-2015 Intel Corporation
3 All rights reserved.
4
5 This library is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of
8 the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
14
15 Authors: Mengdong Lin <mengdong.lin@intel.com>
16 Yao Jin <yao.jin@intel.com>
17 Liam Girdwood <liam.r.girdwood@linux.intel.com>
18 */
19
20 #include "list.h"
21 #include "tplg_local.h"
22 #include <ctype.h>
23
24 #define UUID_FORMAT "\
25 %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:\
26 %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
27
28 /* Get private data buffer of an element */
get_priv_data(struct tplg_elem * elem)29 struct snd_soc_tplg_private *get_priv_data(struct tplg_elem *elem)
30 {
31 struct snd_soc_tplg_private *priv = NULL;
32
33 switch (elem->type) {
34 case SND_TPLG_TYPE_MANIFEST:
35 priv = &elem->manifest->priv;
36 break;
37
38 case SND_TPLG_TYPE_MIXER:
39 priv = &elem->mixer_ctrl->priv;
40 break;
41
42 case SND_TPLG_TYPE_ENUM:
43 priv = &elem->enum_ctrl->priv;
44 break;
45
46 case SND_TPLG_TYPE_BYTES:
47 priv = &elem->bytes_ext->priv;
48 break;
49
50 case SND_TPLG_TYPE_DAPM_WIDGET:
51 priv = &elem->widget->priv;
52 break;
53
54 case SND_TPLG_TYPE_DAI:
55 priv = &elem->dai->priv;
56 break;
57 case SND_TPLG_TYPE_BE:
58 priv = &elem->link->priv;
59 break;
60 case SND_TPLG_TYPE_PCM:
61 priv = &elem->pcm->priv;
62 break;
63 default:
64 SNDERR("'%s': no support for private data for type %d",
65 elem->id, elem->type);
66 }
67
68 return priv;
69 }
70
71 /* Parse references for the element, either a single data section
72 * or a list of data sections.
73 */
tplg_parse_refs(snd_config_t * cfg,struct tplg_elem * elem,unsigned int type)74 int tplg_parse_refs(snd_config_t *cfg, struct tplg_elem *elem,
75 unsigned int type)
76 {
77 snd_config_type_t cfg_type;
78 snd_config_iterator_t i, next;
79 snd_config_t *n;
80 const char *val = NULL;
81 int err, count;
82
83 cfg_type = snd_config_get_type(cfg);
84
85 /* refer to a single data section */
86 if (cfg_type == SND_CONFIG_TYPE_STRING) {
87 if (snd_config_get_string(cfg, &val) < 0)
88 return -EINVAL;
89
90 tplg_dbg("\tref data: %s", val);
91 err = tplg_ref_add(elem, type, val);
92 if (err < 0)
93 return err;
94 return 1;
95 }
96
97 if (cfg_type != SND_CONFIG_TYPE_COMPOUND) {
98 SNDERR("compound type expected for %s", elem->id);
99 return -EINVAL;
100 }
101
102 /* refer to a list of data sections */
103 count = 0;
104 snd_config_for_each(i, next, cfg) {
105 const char *val;
106
107 n = snd_config_iterator_entry(i);
108 if (snd_config_get_string(n, &val) < 0)
109 continue;
110
111 tplg_dbg("\tref data: %s", val);
112 err = tplg_ref_add(elem, type, val);
113 if (err < 0)
114 return err;
115 count++;
116 }
117
118 return count;
119 }
120
121 /* save references */
tplg_save_refs(snd_tplg_t * tplg ATTRIBUTE_UNUSED,struct tplg_elem * elem,unsigned int type,const char * id,struct tplg_buf * dst,const char * pfx)122 int tplg_save_refs(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
123 struct tplg_elem *elem, unsigned int type,
124 const char *id, struct tplg_buf *dst,
125 const char *pfx)
126 {
127 struct tplg_ref *ref, *last;
128 struct list_head *pos;
129 int err, count;
130
131 count = 0;
132 last = NULL;
133 list_for_each(pos, &elem->ref_list) {
134 ref = list_entry(pos, struct tplg_ref, list);
135 if (ref->type == type) {
136 last = ref;
137 count++;
138 }
139 }
140
141 if (count == 0)
142 return 0;
143
144 if (count == 1)
145 return tplg_save_printf(dst, pfx, "%s '%s'\n", id, last->id);
146
147 err = tplg_save_printf(dst, pfx, "%s [\n", id);
148 if (err < 0)
149 return err;
150 list_for_each(pos, &elem->ref_list) {
151 ref = list_entry(pos, struct tplg_ref, list);
152 if (ref->type == type) {
153 err = tplg_save_printf(dst, pfx, "\t'%s'\n", ref->id);
154 if (err < 0)
155 return err;
156 }
157 }
158
159 return tplg_save_printf(dst, pfx, "]\n");
160 }
161
162 /* Get Private data from a file. */
tplg_parse_data_file(snd_config_t * cfg,struct tplg_elem * elem)163 static int tplg_parse_data_file(snd_config_t *cfg, struct tplg_elem *elem)
164 {
165 struct snd_soc_tplg_private *priv = NULL;
166 const char *value = NULL;
167 char filename[PATH_MAX];
168 char *env = getenv(ALSA_CONFIG_TPLG_VAR);
169 FILE *fp;
170 size_t size, bytes_read;
171 int ret = 0;
172
173 tplg_dbg("data DataFile: %s", elem->id);
174
175 if (snd_config_get_string(cfg, &value) < 0)
176 return -EINVAL;
177
178 /* prepend alsa config directory to path */
179 if (env)
180 snprintf(filename, sizeof(filename), "%s/%s", env, value);
181 else
182 snprintf(filename, sizeof(filename), "%s/topology/%s",
183 snd_config_topdir(), value);
184
185 fp = fopen(filename, "r");
186 if (fp == NULL) {
187 SNDERR("invalid data file path '%s'", filename);
188 return -errno;
189 }
190
191 fseek(fp, 0L, SEEK_END);
192 size = ftell(fp);
193 fseek(fp, 0L, SEEK_SET);
194 if (size <= 0) {
195 SNDERR("invalid data file size %zu", size);
196 ret = -EINVAL;
197 goto err;
198 }
199 if (size > TPLG_MAX_PRIV_SIZE) {
200 SNDERR("data file too big %zu", size);
201 ret = -EINVAL;
202 goto err;
203 }
204
205 priv = calloc(1, sizeof(*priv) + size);
206 if (!priv) {
207 ret = -ENOMEM;
208 goto err;
209 }
210
211 bytes_read = fread(&priv->data, 1, size, fp);
212 if (bytes_read != size) {
213 ret = -errno;
214 goto err;
215 }
216
217 elem->data = priv;
218 priv->size = size;
219 elem->size = sizeof(*priv) + size;
220
221 if (fclose(fp) == EOF) {
222 SNDERR("Cannot close data file.");
223 return -errno;
224 }
225 return 0;
226
227 err:
228 fclose(fp);
229 if (priv)
230 free(priv);
231 return ret;
232 }
233
dump_priv_data(struct tplg_elem * elem ATTRIBUTE_UNUSED)234 static void dump_priv_data(struct tplg_elem *elem ATTRIBUTE_UNUSED)
235 {
236 #ifdef TPLG_DEBUG
237 struct snd_soc_tplg_private *priv = elem->data;
238 unsigned char *p = (unsigned char *)priv->data;
239 char buf[128], buf2[8];
240 unsigned int i;
241
242 tplg_dbg(" elem size = %d, priv data size = %d",
243 elem->size, priv->size);
244
245 buf[0] = '\0';
246 for (i = 0; i < priv->size; i++) {
247 if (i > 0 && (i % 16) == 0) {
248 tplg_dbg("%s", buf);
249 buf[0] = '\0';
250 }
251
252 snprintf(buf2, sizeof(buf2), " %02x", *p++);
253 strcat(buf, buf2);
254 }
255
256 if (buf[0])
257 tplg_dbg("%s", buf);
258 #endif
259 }
260
check_nibble(unsigned char c)261 static inline int check_nibble(unsigned char c)
262 {
263 return (c >= '0' && c <= '9') ||
264 (c >= 'a' && c <= 'f') ||
265 (c >= 'A' && c <= 'F');
266 }
267
268 /* get number of hex value elements in CSV list */
get_hex_num(const char * str)269 static int get_hex_num(const char *str)
270 {
271 int delims, values, len = strlen(str);
272 const char *s, *end = str + len;
273
274 /* check "aa:bb:00" syntax */
275 s = str;
276 delims = values = 0;
277 while (s < end) {
278 /* skip white space */
279 if (isspace(*s)) {
280 s++;
281 continue;
282 }
283 /* find delimeters */
284 if (*s == ':') {
285 delims++;
286 s++;
287 continue;
288 }
289 /* check 00 hexadecimal value */
290 if (s + 1 <= end) {
291 if (check_nibble(s[0]) && check_nibble(s[1])) {
292 values++;
293 } else {
294 goto format2;
295 }
296 s++;
297 }
298 s++;
299 }
300 goto end;
301
302 format2:
303 /* we expect "0x0, 0x0, 0x0" */
304 s = str;
305 delims = values = 0;
306 while (s < end) {
307
308 /* skip white space */
309 if (isspace(*s)) {
310 s++;
311 continue;
312 }
313
314 /* find delimeters */
315 if (*s == ',') {
316 delims++;
317 s++;
318 continue;
319 }
320
321 /* find 0x[0-9] values */
322 if (*s == '0' && s + 2 <= end) {
323 if (s[1] == 'x' && check_nibble(s[2])) {
324 if (check_nibble(s[3]))
325 s++;
326 values++;
327 s += 2;
328 }
329 }
330
331 s++;
332 }
333
334 end:
335 /* there should always be one less comma than value */
336 if (values - 1 != delims)
337 return -EINVAL;
338
339 return values;
340 }
341
342 /* get uuid from a string made by 16 characters separated by commas */
get_uuid(const char * str,unsigned char * uuid_le)343 static int get_uuid(const char *str, unsigned char *uuid_le)
344 {
345 unsigned long int val;
346 char *tmp, *s = NULL;
347 int values = 0, ret = 0;
348
349 tmp = strdup(str);
350 if (tmp == NULL)
351 return -ENOMEM;
352
353 if (strchr(tmp, ':') == NULL)
354 goto data2;
355
356 s = strtok(tmp, ":");
357 while (s != NULL) {
358 errno = 0;
359 val = strtoul(s, NULL, 16);
360 if ((errno == ERANGE && val == ULONG_MAX)
361 || (errno != 0 && val == 0)
362 || (val > UCHAR_MAX)) {
363 SNDERR("invalid value for uuid");
364 ret = -EINVAL;
365 goto out;
366 }
367
368 *(uuid_le + values) = (unsigned char)val;
369
370 values++;
371 if (values >= 16)
372 break;
373
374 s = strtok(NULL, ":");
375 }
376 goto out;
377
378 data2:
379 s = strtok(tmp, ",");
380
381 while (s != NULL) {
382 errno = 0;
383 val = strtoul(s, NULL, 0);
384 if ((errno == ERANGE && val == ULONG_MAX)
385 || (errno != 0 && val == 0)
386 || (val > UCHAR_MAX)) {
387 SNDERR("invalid value for uuid");
388 ret = -EINVAL;
389 goto out;
390 }
391
392 *(uuid_le + values) = (unsigned char)val;
393
394 values++;
395 if (values >= 16)
396 break;
397
398 s = strtok(NULL, ",");
399 }
400
401 if (values < 16) {
402 SNDERR("less than 16 integers for uuid");
403 ret = -EINVAL;
404 }
405
406 out:
407 free(tmp);
408 return ret;
409 }
410
write_hex(char * buf,char * str,int width)411 static int write_hex(char *buf, char *str, int width)
412 {
413 long val;
414 void *p = &val;
415
416 errno = 0;
417 if (safe_strtol_base(str, &val, 16) < 0)
418 return -EINVAL;
419
420 switch (width) {
421 case 1:
422 *(unsigned char *)buf = *(unsigned char *)p;
423 break;
424 case 2:
425 *(unsigned short *)buf = *(unsigned short *)p;
426 break;
427 case 4:
428 *(unsigned int *)buf = *(unsigned int *)p;
429 break;
430 default:
431 return -EINVAL;
432 }
433
434 return 0;
435 }
436
copy_data_hex(char * data,int off,const char * str,int width)437 static int copy_data_hex(char *data, int off, const char *str, int width)
438 {
439 char *tmp, *s = NULL, *p = data;
440 int ret;
441
442 tmp = strdup(str);
443 if (tmp == NULL)
444 return -ENOMEM;
445
446 p += off;
447 s = strtok(tmp, ",:");
448
449 while (s != NULL) {
450 ret = write_hex(p, s, width);
451 if (ret < 0) {
452 free(tmp);
453 return ret;
454 }
455
456 s = strtok(NULL, ",:");
457 p += width;
458 }
459
460 free(tmp);
461 return 0;
462 }
463
tplg_parse_data_hex(snd_config_t * cfg,struct tplg_elem * elem,int width)464 static int tplg_parse_data_hex(snd_config_t *cfg, struct tplg_elem *elem,
465 int width)
466 {
467 struct snd_soc_tplg_private *priv;
468 const char *value = NULL;
469 int size, esize, off, num;
470 int ret;
471
472 tplg_dbg(" data: %s", elem->id);
473
474 if (snd_config_get_string(cfg, &value) < 0)
475 return -EINVAL;
476
477 num = get_hex_num(value);
478 if (num <= 0) {
479 SNDERR("malformed hex variable list %s", value);
480 return -EINVAL;
481 }
482
483 size = num * width;
484 priv = elem->data;
485
486 if (size > TPLG_MAX_PRIV_SIZE) {
487 SNDERR("data too big %d", size);
488 return -EINVAL;
489 }
490
491 if (priv != NULL) {
492 off = priv->size;
493 esize = elem->size + size;
494 priv = realloc(priv, esize);
495 } else {
496 off = 0;
497 esize = sizeof(*priv) + size;
498 priv = calloc(1, esize);
499 }
500
501 if (!priv)
502 return -ENOMEM;
503
504 elem->data = priv;
505 priv->size += size;
506 elem->size = esize;
507
508 ret = copy_data_hex(priv->data, off, value, width);
509
510 dump_priv_data(elem);
511 return ret;
512 }
513
514 /* get the token integer value from its id */
get_token_value(const char * token_id,struct tplg_vendor_tokens * tokens)515 static int get_token_value(const char *token_id,
516 struct tplg_vendor_tokens *tokens)
517 {
518 unsigned int i;
519
520 for (i = 0; i < tokens->num_tokens; i++) {
521 if (strcmp(token_id, tokens->token[i].id) == 0)
522 return tokens->token[i].value;
523 }
524
525 SNDERR("cannot find token id '%s'", token_id);
526 return -1;
527 }
528
529 /* get the vendor tokens referred by the vendor tuples */
get_tokens(snd_tplg_t * tplg,struct tplg_elem * elem)530 static struct tplg_elem *get_tokens(snd_tplg_t *tplg, struct tplg_elem *elem)
531 {
532 struct tplg_ref *ref;
533 struct list_head *base, *pos;
534
535 base = &elem->ref_list;
536 list_for_each(pos, base) {
537
538 ref = list_entry(pos, struct tplg_ref, list);
539
540 if (ref->type != SND_TPLG_TYPE_TOKEN)
541 continue;
542
543 if (!ref->elem) {
544 ref->elem = tplg_elem_lookup(&tplg->token_list,
545 ref->id, SND_TPLG_TYPE_TOKEN, elem->index);
546 }
547
548 return ref->elem;
549 }
550
551 return NULL;
552 }
553
554 /* check if a data element has tuples */
has_tuples(struct tplg_elem * elem)555 static bool has_tuples(struct tplg_elem *elem)
556 {
557 struct tplg_ref *ref;
558 struct list_head *base, *pos;
559
560 base = &elem->ref_list;
561 list_for_each(pos, base) {
562
563 ref = list_entry(pos, struct tplg_ref, list);
564 if (ref->type == SND_TPLG_TYPE_TUPLE)
565 return true;
566 }
567
568 return false;
569 }
570
571 /* get size of a tuple element from its type */
tplg_get_tuple_size(int type)572 unsigned int tplg_get_tuple_size(int type)
573 {
574 switch (type) {
575
576 case SND_SOC_TPLG_TUPLE_TYPE_UUID:
577 return sizeof(struct snd_soc_tplg_vendor_uuid_elem);
578
579 case SND_SOC_TPLG_TUPLE_TYPE_STRING:
580 return sizeof(struct snd_soc_tplg_vendor_string_elem);
581
582 default:
583 return sizeof(struct snd_soc_tplg_vendor_value_elem);
584 }
585 }
586
587 /* Add a tuples object to the private buffer of its parent data element */
copy_tuples(struct tplg_elem * elem,struct tplg_vendor_tuples * tuples,struct tplg_vendor_tokens * tokens)588 static int copy_tuples(struct tplg_elem *elem,
589 struct tplg_vendor_tuples *tuples,
590 struct tplg_vendor_tokens *tokens)
591 {
592 struct snd_soc_tplg_private *priv = elem->data, *priv2;
593 struct tplg_tuple_set *tuple_set;
594 struct tplg_tuple *tuple;
595 struct snd_soc_tplg_vendor_array *array;
596 struct snd_soc_tplg_vendor_uuid_elem *uuid;
597 struct snd_soc_tplg_vendor_string_elem *string;
598 struct snd_soc_tplg_vendor_value_elem *value;
599 int set_size, size, off;
600 unsigned int i, j;
601 int token_val;
602
603 size = priv ? priv->size : 0; /* original private data size */
604
605 /* scan each tuples set (one set per type) */
606 for (i = 0; i < tuples->num_sets ; i++) {
607 tuple_set = tuples->set[i];
608 set_size = sizeof(struct snd_soc_tplg_vendor_array)
609 + tplg_get_tuple_size(tuple_set->type)
610 * tuple_set->num_tuples;
611 size += set_size;
612 if (size > TPLG_MAX_PRIV_SIZE) {
613 SNDERR("data too big %d", size);
614 return -EINVAL;
615 }
616
617 if (priv != NULL) {
618 priv2 = realloc(priv, sizeof(*priv) + size);
619 if (priv2 == NULL) {
620 free(priv);
621 priv = NULL;
622 } else {
623 priv = priv2;
624 }
625 } else {
626 priv = calloc(1, sizeof(*priv) + size);
627 }
628 if (!priv)
629 return -ENOMEM;
630
631 off = priv->size;
632 priv->size = size; /* update private data size */
633 elem->data = priv;
634
635 array = (struct snd_soc_tplg_vendor_array *)(priv->data + off);
636 memset(array, 0, set_size);
637 array->size = set_size;
638 array->type = tuple_set->type;
639 array->num_elems = tuple_set->num_tuples;
640
641 /* fill the private data buffer */
642 for (j = 0; j < tuple_set->num_tuples; j++) {
643 tuple = &tuple_set->tuple[j];
644 token_val = get_token_value(tuple->token, tokens);
645 if (token_val < 0)
646 return -EINVAL;
647
648 switch (tuple_set->type) {
649 case SND_SOC_TPLG_TUPLE_TYPE_UUID:
650 uuid = &array->uuid[j];
651 uuid->token = token_val;
652 memcpy(uuid->uuid, tuple->uuid, 16);
653 break;
654
655 case SND_SOC_TPLG_TUPLE_TYPE_STRING:
656 string = &array->string[j];
657 string->token = token_val;
658 snd_strlcpy(string->string, tuple->string,
659 SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
660 break;
661
662 default:
663 value = &array->value[j];
664 value->token = token_val;
665 value->value = tuple->value;
666 break;
667 }
668 }
669 }
670
671 return 0;
672 }
673
674 /* build a data element from its tuples */
build_tuples(snd_tplg_t * tplg,struct tplg_elem * elem)675 static int build_tuples(snd_tplg_t *tplg, struct tplg_elem *elem)
676 {
677 struct tplg_ref *ref;
678 struct list_head *base, *pos;
679 struct tplg_elem *tuples, *tokens;
680 int err;
681
682 base = &elem->ref_list;
683 list_for_each(pos, base) {
684
685 ref = list_entry(pos, struct tplg_ref, list);
686
687 if (ref->type != SND_TPLG_TYPE_TUPLE)
688 continue;
689
690 tplg_dbg("tuples '%s' used by data '%s'", ref->id, elem->id);
691
692 if (!ref->elem)
693 ref->elem = tplg_elem_lookup(&tplg->tuple_list,
694 ref->id, SND_TPLG_TYPE_TUPLE, elem->index);
695 tuples = ref->elem;
696 if (!tuples) {
697 SNDERR("cannot find tuples %s", ref->id);
698 return -EINVAL;
699 }
700
701 tokens = get_tokens(tplg, tuples);
702 if (!tokens) {
703 SNDERR("cannot find token for %s", ref->id);
704 return -EINVAL;
705 }
706
707 /* a data object can have multiple tuples objects */
708 err = copy_tuples(elem, tuples->tuples, tokens->tokens);
709 if (err < 0)
710 return err;
711 }
712
713 return 0;
714 }
715
716 struct tuple_type {
717 unsigned int type;
718 const char *name;
719 unsigned int size;
720 };
721
722 static struct tuple_type tuple_types[] = {
723 {
724 .type = SND_SOC_TPLG_TUPLE_TYPE_UUID,
725 .name = "uuid",
726 .size = 4,
727 },
728 {
729 .type = SND_SOC_TPLG_TUPLE_TYPE_STRING,
730 .name = "string",
731 .size = 6,
732 },
733 {
734 .type = SND_SOC_TPLG_TUPLE_TYPE_BOOL,
735 .name = "bool",
736 .size = 4,
737 },
738 {
739 .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
740 .name = "byte",
741 .size = 4,
742 },
743 {
744 .type = SND_SOC_TPLG_TUPLE_TYPE_SHORT,
745 .name = "short",
746 .size = 5,
747 },
748 {
749 .type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
750 .name = "word",
751 .size = 4
752 },
753 };
754
get_tuple_type(const char * name)755 static int get_tuple_type(const char *name)
756 {
757 struct tuple_type *t;
758 unsigned int i;
759
760 /* skip initial index for sorting */
761 while ((*name >= '0' && *name <= '9') || *name == '_')
762 name++;
763 for (i = 0; i < ARRAY_SIZE(tuple_types); i++) {
764 t = &tuple_types[i];
765 if (strncasecmp(t->name, name, t->size) == 0)
766 return t->type;
767 }
768 return -EINVAL;
769 }
770
get_tuple_type_name(unsigned int type)771 static const char *get_tuple_type_name(unsigned int type)
772 {
773 unsigned int i;
774
775 for (i = 0; i < ARRAY_SIZE(tuple_types); i++)
776 if (tuple_types[i].type == type)
777 return tuple_types[i].name;
778 return NULL;
779 }
780
parse_tuple_set(snd_config_t * cfg,struct tplg_tuple_set ** s)781 static int parse_tuple_set(snd_config_t *cfg,
782 struct tplg_tuple_set **s)
783 {
784 snd_config_iterator_t i, next;
785 snd_config_t *n;
786 const char *id, *value;
787 struct tplg_tuple_set *set;
788 unsigned int num_tuples = 0;
789 struct tplg_tuple *tuple;
790 unsigned int tuple_val;
791 int type, ival;
792
793 snd_config_get_id(cfg, &id);
794
795 type = get_tuple_type(id);
796 if (type < 0) {
797 SNDERR("invalid tuple type '%s'", id);
798 return type;
799 }
800
801 snd_config_for_each(i, next, cfg)
802 num_tuples++;
803 if (!num_tuples)
804 return 0;
805
806 tplg_dbg("\t %d %s tuples:", num_tuples, id);
807 set = calloc(1, sizeof(*set) + num_tuples * sizeof(struct tplg_tuple));
808 if (!set)
809 return -ENOMEM;
810
811 set->type = type;
812
813 snd_config_for_each(i, next, cfg) {
814
815 n = snd_config_iterator_entry(i);
816
817 /* get id */
818 if (snd_config_get_id(n, &id) < 0)
819 continue;
820
821 tuple = &set->tuple[set->num_tuples];
822 snd_strlcpy(tuple->token, id,
823 SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
824
825 switch (type) {
826 case SND_SOC_TPLG_TUPLE_TYPE_UUID:
827 if (snd_config_get_string(n, &value) < 0)
828 continue;
829 if (get_uuid(value, tuple->uuid) < 0)
830 goto err;
831 break;
832
833 case SND_SOC_TPLG_TUPLE_TYPE_STRING:
834 if (snd_config_get_string(n, &value) < 0)
835 continue;
836 snd_strlcpy(tuple->string, value,
837 SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
838 tplg_dbg("\t\t%s = %s", tuple->token, tuple->string);
839 break;
840
841 case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
842 ival = snd_config_get_bool(n);
843 if (ival < 0)
844 continue;
845 tuple->value = ival;
846 tplg_dbg("\t\t%s = %d", tuple->token, tuple->value);
847 break;
848
849 case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
850 case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
851 case SND_SOC_TPLG_TUPLE_TYPE_WORD:
852 ival = tplg_get_unsigned(n, &tuple_val, 0);
853 if (ival < 0) {
854 SNDERR("tuple %s: %s", id, snd_strerror(ival));
855 goto err;
856 }
857
858 if (/* (type == SND_SOC_TPLG_TUPLE_TYPE_WORD
859 && tuple_val > UINT_MAX) || */
860 (type == SND_SOC_TPLG_TUPLE_TYPE_SHORT
861 && tuple_val > USHRT_MAX) ||
862 (type == SND_SOC_TPLG_TUPLE_TYPE_BYTE
863 && tuple_val > UCHAR_MAX)) {
864 SNDERR("tuple %s: invalid value", id);
865 goto err;
866 }
867
868 tuple->value = tuple_val;
869 tplg_dbg("\t\t%s = 0x%x", tuple->token, tuple->value);
870 break;
871
872 default:
873 break;
874 }
875
876 set->num_tuples++;
877 }
878
879 *s = set;
880 return 0;
881
882 err:
883 free(set);
884 return -EINVAL;
885 }
886
887 /* save tuple set */
tplg_save_tuple_set(struct tplg_vendor_tuples * tuples,unsigned int set_index,struct tplg_buf * dst,const char * pfx)888 static int tplg_save_tuple_set(struct tplg_vendor_tuples *tuples,
889 unsigned int set_index,
890 struct tplg_buf *dst, const char *pfx)
891 {
892 struct tplg_tuple_set *set;
893 struct tplg_tuple *tuple;
894 const char *s, *fmt;
895 char buf[32];
896 unsigned int i;
897 int err;
898
899 set = tuples->set[set_index];
900 if (set->num_tuples == 0)
901 return 0;
902 s = get_tuple_type_name(set->type);
903 if (s == NULL)
904 return -EINVAL;
905 if (tuples->num_sets < 10)
906 fmt = "%u_";
907 else if (tuples->num_sets < 100)
908 fmt = "%02u_";
909 else if (tuples->num_sets < 1000)
910 fmt = "%03u_";
911 else
912 return -EINVAL;
913 if (set->num_tuples > 1) {
914 snprintf(buf, sizeof(buf), "tuples.%s%%s {\n", fmt);
915 err = tplg_save_printf(dst, NULL, buf, set_index, s);
916 if (err < 0)
917 return err;
918 }
919 for (i = 0; i < set->num_tuples; i++) {
920 tuple = &set->tuple[i];
921 if (set->num_tuples == 1) {
922 snprintf(buf, sizeof(buf), "tuples.%s%%s.'%%s' ", fmt);
923 err = tplg_save_printf(dst, NULL, buf,
924 set_index, s, tuple->token);
925 } else {
926 err = tplg_save_printf(dst, pfx, "\t'%s' ",
927 tuple->token);
928 }
929 if (err < 0)
930 return err;
931 switch (set->type) {
932 case SND_SOC_TPLG_TUPLE_TYPE_UUID:
933 err = tplg_save_printf(dst, NULL, "'" UUID_FORMAT "'\n",
934 tuple->uuid[0], tuple->uuid[1],
935 tuple->uuid[2], tuple->uuid[3],
936 tuple->uuid[4], tuple->uuid[5],
937 tuple->uuid[6], tuple->uuid[7],
938 tuple->uuid[8], tuple->uuid[9],
939 tuple->uuid[10], tuple->uuid[11],
940 tuple->uuid[12], tuple->uuid[13],
941 tuple->uuid[14], tuple->uuid[15]);
942 break;
943 case SND_SOC_TPLG_TUPLE_TYPE_STRING:
944 err = tplg_save_printf(dst, NULL, "'%s'\n",
945 tuple->string);
946 break;
947 case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
948 case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
949 case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
950 err = tplg_save_printf(dst, NULL, "%u\n", tuple->value);
951 break;
952 case SND_SOC_TPLG_TUPLE_TYPE_WORD:
953 tplg_nice_value_format(buf, sizeof(buf), tuple->value);
954 err = tplg_save_printf(dst, NULL, "%s\n", buf);
955 break;
956 default:
957 return -EINVAL;
958 }
959 if (err < 0)
960 return err;
961 }
962 if (set->num_tuples > 1)
963 return tplg_save_printf(dst, pfx, "}\n");
964 return 0;
965 }
966
parse_tuple_sets(snd_config_t * cfg,struct tplg_vendor_tuples * tuples)967 static int parse_tuple_sets(snd_config_t *cfg,
968 struct tplg_vendor_tuples *tuples)
969 {
970 snd_config_iterator_t i, next;
971 snd_config_t *n;
972 const char *id;
973 unsigned int num_tuple_sets = 0;
974 int err;
975
976 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
977 if (snd_config_get_id(cfg, &id) >= 0)
978 SNDERR("compound type expected for %s", id);
979 return -EINVAL;
980 }
981
982 snd_config_for_each(i, next, cfg) {
983 num_tuple_sets++;
984 }
985
986 if (!num_tuple_sets)
987 return 0;
988
989 tuples->set = calloc(1, num_tuple_sets * sizeof(void *));
990 if (!tuples->set)
991 return -ENOMEM;
992
993 snd_config_for_each(i, next, cfg) {
994 n = snd_config_iterator_entry(i);
995 if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
996 SNDERR("compound type expected for %s, is %d",
997 id, snd_config_get_type(n));
998 return -EINVAL;
999 }
1000
1001 err = parse_tuple_set(n, &tuples->set[tuples->num_sets]);
1002 if (err < 0)
1003 return err;
1004
1005 /* overlook empty tuple sets */
1006 if (tuples->set[tuples->num_sets])
1007 tuples->num_sets++;
1008 }
1009
1010 return 0;
1011 }
1012
1013 /* save tuple sets */
tplg_save_tuple_sets(snd_tplg_t * tplg ATTRIBUTE_UNUSED,struct tplg_elem * elem,struct tplg_buf * dst,const char * pfx)1014 int tplg_save_tuple_sets(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
1015 struct tplg_elem *elem,
1016 struct tplg_buf *dst, const char *pfx)
1017 {
1018 struct tplg_vendor_tuples *tuples = elem->tuples;
1019 unsigned int i;
1020 int err = 0;
1021
1022 for (i = 0; i < tuples->num_sets; i++) {
1023 err = tplg_save_printf(dst, pfx, "");
1024 if (err < 0)
1025 break;
1026 err = tplg_save_tuple_set(tuples, i, dst, pfx);
1027 if (err < 0)
1028 break;
1029 }
1030 return err;
1031 }
1032
1033 /* Parse vendor tokens
1034 */
tplg_parse_tokens(snd_tplg_t * tplg,snd_config_t * cfg,void * private ATTRIBUTE_UNUSED)1035 int tplg_parse_tokens(snd_tplg_t *tplg, snd_config_t *cfg,
1036 void *private ATTRIBUTE_UNUSED)
1037 {
1038 snd_config_iterator_t i, next;
1039 snd_config_t *n;
1040 const char *id;
1041 struct tplg_elem *elem;
1042 struct tplg_vendor_tokens *tokens;
1043 int num_tokens = 0, value;
1044
1045 elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_TOKEN);
1046 if (!elem)
1047 return -ENOMEM;
1048
1049 snd_config_for_each(i, next, cfg) {
1050 num_tokens++;
1051 }
1052
1053 if (!num_tokens)
1054 return 0;
1055
1056 tplg_dbg(" Vendor tokens: %s, %d tokens", elem->id, num_tokens);
1057
1058 tokens = calloc(1, sizeof(*tokens)
1059 + num_tokens * sizeof(struct tplg_token));
1060 if (!tokens)
1061 return -ENOMEM;
1062 elem->tokens = tokens;
1063
1064 snd_config_for_each(i, next, cfg) {
1065
1066 n = snd_config_iterator_entry(i);
1067 if (snd_config_get_id(n, &id) < 0)
1068 continue;
1069
1070 if (tplg_get_integer(n, &value, 0))
1071 continue;
1072
1073 snd_strlcpy(tokens->token[tokens->num_tokens].id, id,
1074 SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
1075 tokens->token[tokens->num_tokens].value = value;
1076 tplg_dbg("\t\t %s : %d", tokens->token[tokens->num_tokens].id,
1077 tokens->token[tokens->num_tokens].value);
1078 tokens->num_tokens++;
1079 }
1080
1081 return 0;
1082 }
1083
1084 /* save vendor tokens */
tplg_save_tokens(snd_tplg_t * tplg ATTRIBUTE_UNUSED,struct tplg_elem * elem,struct tplg_buf * dst,const char * pfx)1085 int tplg_save_tokens(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
1086 struct tplg_elem *elem,
1087 struct tplg_buf *dst, const char *pfx)
1088 {
1089 struct tplg_vendor_tokens *tokens = elem->tokens;
1090 unsigned int i;
1091 int err;
1092
1093 if (!tokens || tokens->num_tokens == 0)
1094 return 0;
1095
1096 err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
1097 if (err < 0)
1098 return err;
1099 for (i = 0; err >= 0 && i < tokens->num_tokens; i++)
1100 err = tplg_save_printf(dst, pfx, "\t'%s' %u\n",
1101 tokens->token[i].id,
1102 tokens->token[i].value);
1103 err = tplg_save_printf(dst, pfx, "}\n");
1104 if (err < 0)
1105 return err;
1106 return 0;
1107 }
1108
1109 /* Parse vendor tuples.
1110 */
tplg_parse_tuples(snd_tplg_t * tplg,snd_config_t * cfg,void * private ATTRIBUTE_UNUSED)1111 int tplg_parse_tuples(snd_tplg_t *tplg, snd_config_t *cfg,
1112 void *private ATTRIBUTE_UNUSED)
1113 {
1114 snd_config_iterator_t i, next;
1115 snd_config_t *n;
1116 const char *id, *value;
1117 struct tplg_elem *elem;
1118 struct tplg_vendor_tuples *tuples;
1119 int err;
1120
1121 elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_TUPLE);
1122 if (!elem)
1123 return -ENOMEM;
1124
1125 tplg_dbg(" Vendor Tuples: %s", elem->id);
1126
1127 tuples = calloc(1, sizeof(*tuples));
1128 if (!tuples)
1129 return -ENOMEM;
1130 elem->tuples = tuples;
1131
1132 snd_config_for_each(i, next, cfg) {
1133
1134 n = snd_config_iterator_entry(i);
1135 if (snd_config_get_id(n, &id) < 0)
1136 continue;
1137
1138 if (strcmp(id, "tokens") == 0) {
1139 if (snd_config_get_string(n, &value) < 0)
1140 return -EINVAL;
1141 tplg_ref_add(elem, SND_TPLG_TYPE_TOKEN, value);
1142 tplg_dbg("\t refer to vendor tokens: %s", value);
1143 }
1144
1145 if (strcmp(id, "tuples") == 0) {
1146 err = parse_tuple_sets(n, tuples);
1147 if (err < 0)
1148 return err;
1149 }
1150 }
1151
1152 return 0;
1153 }
1154
1155 /* save vendor tuples */
tplg_save_tuples(snd_tplg_t * tplg ATTRIBUTE_UNUSED,struct tplg_elem * elem,struct tplg_buf * dst,const char * pfx)1156 int tplg_save_tuples(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
1157 struct tplg_elem *elem,
1158 struct tplg_buf *dst, const char *pfx)
1159 {
1160 char pfx2[16];
1161 int err;
1162
1163 if (!elem->tuples)
1164 return 0;
1165
1166 err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
1167 snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
1168 if (err >= 0)
1169 err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_TOKEN,
1170 "tokens", dst, pfx2);
1171 if (err >= 0)
1172 err = tplg_save_tuple_sets(tplg, elem, dst, pfx2);
1173 if (err >= 0)
1174 err = tplg_save_printf(dst, pfx, "}\n");
1175 return 0;
1176 }
1177
1178 /* Free handler of tuples */
tplg_free_tuples(void * obj)1179 void tplg_free_tuples(void *obj)
1180 {
1181 struct tplg_vendor_tuples *tuples = (struct tplg_vendor_tuples *)obj;
1182 unsigned int i;
1183
1184 if (!tuples || !tuples->set)
1185 return;
1186
1187 for (i = 0; i < tuples->num_sets; i++)
1188 free(tuples->set[i]);
1189
1190 free(tuples->set);
1191 }
1192
1193 /* Parse manifest's data references
1194 */
tplg_parse_manifest_data(snd_tplg_t * tplg,snd_config_t * cfg,void * private ATTRIBUTE_UNUSED)1195 int tplg_parse_manifest_data(snd_tplg_t *tplg, snd_config_t *cfg,
1196 void *private ATTRIBUTE_UNUSED)
1197 {
1198 struct snd_soc_tplg_manifest *manifest;
1199 struct tplg_elem *elem;
1200 snd_config_iterator_t i, next;
1201 snd_config_t *n;
1202 const char *id;
1203 int err;
1204
1205 if (!list_empty(&tplg->manifest_list)) {
1206 SNDERR("already has manifest data");
1207 return -EINVAL;
1208 }
1209
1210 elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_MANIFEST);
1211 if (!elem)
1212 return -ENOMEM;
1213
1214 manifest = elem->manifest;
1215 manifest->size = elem->size;
1216
1217 tplg_dbg(" Manifest: %s", elem->id);
1218
1219 snd_config_for_each(i, next, cfg) {
1220 n = snd_config_iterator_entry(i);
1221 if (snd_config_get_id(n, &id) < 0)
1222 continue;
1223
1224 /* skip comments */
1225 if (strcmp(id, "comment") == 0)
1226 continue;
1227 if (id[0] == '#')
1228 continue;
1229
1230
1231 if (strcmp(id, "data") == 0) {
1232 err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_DATA);
1233 if (err < 0)
1234 return err;
1235 continue;
1236 }
1237 }
1238
1239 return 0;
1240 }
1241
1242 /* save manifest data */
tplg_save_manifest_data(snd_tplg_t * tplg ATTRIBUTE_UNUSED,struct tplg_elem * elem,struct tplg_buf * dst,const char * pfx)1243 int tplg_save_manifest_data(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
1244 struct tplg_elem *elem, struct tplg_buf *dst,
1245 const char *pfx)
1246 {
1247 struct list_head *pos;
1248 struct tplg_ref *ref;
1249 int err, index, count;
1250
1251 /* for each ref in this manifest elem */
1252 count = 0;
1253 list_for_each(pos, &elem->ref_list) {
1254 ref = list_entry(pos, struct tplg_ref, list);
1255 if (ref->type != SND_TPLG_TYPE_DATA)
1256 continue;
1257 count++;
1258 }
1259 if (count == 0)
1260 return tplg_save_printf(dst, NULL,
1261 "'%s'.comment 'empty'\n", elem->id);
1262 if (count > 1) {
1263 err = tplg_save_printf(dst, NULL, "'%s'.data [\n", elem->id);
1264 if (err < 0)
1265 return err;
1266 }
1267 index = 0;
1268 list_for_each(pos, &elem->ref_list) {
1269 ref = list_entry(pos, struct tplg_ref, list);
1270 if (ref->type != SND_TPLG_TYPE_DATA)
1271 continue;
1272 if (count == 1) {
1273 err = tplg_save_printf(dst, NULL, "'%s'.data.%u '%s'\n",
1274 elem->id, index, ref->id);
1275 } else {
1276 err = tplg_save_printf(dst, pfx, "\t'%s'\n", ref->id);
1277 }
1278 if (err < 0)
1279 return err;
1280 index++;
1281 }
1282 if (count > 1) {
1283 err = tplg_save_printf(dst, pfx, "]\n");
1284 if (err < 0)
1285 return err;
1286 }
1287 return 0;
1288 }
1289
1290 /* merge private data of manifest */
tplg_build_manifest_data(snd_tplg_t * tplg)1291 int tplg_build_manifest_data(snd_tplg_t *tplg)
1292 {
1293 struct list_head *base, *pos;
1294 struct tplg_elem *elem = NULL;
1295 struct tplg_ref *ref;
1296 struct snd_soc_tplg_manifest *manifest;
1297 int err = 0;
1298
1299 base = &tplg->manifest_list;
1300 list_for_each(pos, base) {
1301
1302 elem = list_entry(pos, struct tplg_elem, list);
1303 break;
1304 }
1305
1306 if (!elem) /* no manifest data */
1307 return 0;
1308
1309 base = &elem->ref_list;
1310
1311 /* for each ref in this manifest elem */
1312 list_for_each(pos, base) {
1313
1314 ref = list_entry(pos, struct tplg_ref, list);
1315 if (ref->elem)
1316 continue;
1317
1318 if (ref->type == SND_TPLG_TYPE_DATA) {
1319 err = tplg_copy_data(tplg, elem, ref);
1320 if (err < 0)
1321 return err;
1322 }
1323 }
1324
1325 manifest = elem->manifest;
1326 if (!manifest->priv.size) /* no manifest data */
1327 return 0;
1328
1329 tplg->manifest_pdata = malloc(manifest->priv.size);
1330 if (!tplg->manifest_pdata)
1331 return -ENOMEM;
1332
1333 tplg->manifest.priv.size = manifest->priv.size;
1334 memcpy(tplg->manifest_pdata, manifest->priv.data, manifest->priv.size);
1335 return 0;
1336 }
1337
1338 /* Parse Private data.
1339 *
1340 * Object private data can either be from file or defined as bytes, shorts,
1341 * words, tuples.
1342 */
tplg_parse_data(snd_tplg_t * tplg,snd_config_t * cfg,void * private ATTRIBUTE_UNUSED)1343 int tplg_parse_data(snd_tplg_t *tplg, snd_config_t *cfg,
1344 void *private ATTRIBUTE_UNUSED)
1345 {
1346 snd_config_iterator_t i, next;
1347 snd_config_t *n;
1348 const char *id;
1349 int err = 0, ival;
1350 struct tplg_elem *elem;
1351
1352 elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_DATA);
1353 if (!elem)
1354 return -ENOMEM;
1355
1356 snd_config_for_each(i, next, cfg) {
1357
1358 n = snd_config_iterator_entry(i);
1359 if (snd_config_get_id(n, &id) < 0) {
1360 continue;
1361 }
1362
1363 if (strcmp(id, "file") == 0) {
1364 err = tplg_parse_data_file(n, elem);
1365 if (err < 0) {
1366 SNDERR("failed to parse data file");
1367 return err;
1368 }
1369 continue;
1370 }
1371
1372 if (strcmp(id, "bytes") == 0) {
1373 err = tplg_parse_data_hex(n, elem, 1);
1374 if (err < 0) {
1375 SNDERR("failed to parse data bytes");
1376 return err;
1377 }
1378 continue;
1379 }
1380
1381 if (strcmp(id, "shorts") == 0) {
1382 err = tplg_parse_data_hex(n, elem, 2);
1383 if (err < 0) {
1384 SNDERR("failed to parse data shorts");
1385 return err;
1386 }
1387 continue;
1388 }
1389
1390 if (strcmp(id, "words") == 0) {
1391 err = tplg_parse_data_hex(n, elem, 4);
1392 if (err < 0) {
1393 SNDERR("failed to parse data words");
1394 return err;
1395 }
1396 continue;
1397 }
1398
1399 if (strcmp(id, "tuples") == 0) {
1400 err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_TUPLE);
1401 if (err < 0)
1402 return err;
1403 continue;
1404 }
1405
1406 if (strcmp(id, "type") == 0) {
1407 if (tplg_get_integer(n, &ival, 0))
1408 return -EINVAL;
1409
1410 elem->vendor_type = ival;
1411 tplg_dbg("\t%s: %d", id, elem->index);
1412 continue;
1413 }
1414 }
1415
1416 return err;
1417 }
1418
1419 /* save data element */
tplg_save_data(snd_tplg_t * tplg ATTRIBUTE_UNUSED,struct tplg_elem * elem,struct tplg_buf * dst,const char * pfx)1420 int tplg_save_data(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
1421 struct tplg_elem *elem,
1422 struct tplg_buf *dst, const char *pfx)
1423 {
1424 struct snd_soc_tplg_private *priv = elem->data;
1425 struct list_head *pos;
1426 struct tplg_ref *ref;
1427 char pfx2[16];
1428 unsigned int i, count;
1429 int err;
1430
1431 count = 0;
1432 if (priv && priv->size > 0)
1433 count++;
1434 list_for_each(pos, &elem->ref_list) {
1435 ref = list_entry(pos, struct tplg_ref, list);
1436 if (ref->type == SND_TPLG_TYPE_TUPLE)
1437 count++;
1438 }
1439 if (elem->vendor_type > 0)
1440 count++;
1441
1442 if (count > 1) {
1443 err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
1444 if (err >= 0)
1445 err = tplg_save_printf(dst, NULL, "");
1446 } else {
1447 err = tplg_save_printf(dst, NULL, "'%s'.", elem->id);
1448 }
1449 if (err >= 0 && priv && priv->size > 0) {
1450 if (count > 1) {
1451 err = tplg_save_printf(dst, pfx, "");
1452 if (err < 0)
1453 return err;
1454 }
1455 if (priv->size > 8) {
1456 err = tplg_save_printf(dst, NULL, "bytes\n");
1457 if (err >= 0)
1458 err = tplg_save_printf(dst, pfx, "\t'");
1459 } else {
1460 err = tplg_save_printf(dst, NULL, "bytes '");
1461 }
1462 if (err < 0)
1463 return err;
1464 for (i = 0; i < priv->size; i++) {
1465 if (i > 0 && (i % 8) == 0) {
1466 err = tplg_save_printf(dst, NULL, ":\n");
1467 if (err < 0)
1468 return err;
1469 err = tplg_save_printf(dst, pfx, "\t ");
1470 if (err < 0)
1471 return err;
1472 }
1473 err = tplg_save_printf(dst, NULL, "%s%02x",
1474 (i % 8) == 0 ? "" : ":",
1475 (unsigned char)priv->data[i]);
1476 if (err < 0)
1477 return err;
1478 }
1479 err = tplg_save_printf(dst, NULL, "'\n");
1480 }
1481 snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
1482 if (err >= 0)
1483 err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_TUPLE,
1484 "tuples", dst,
1485 count > 1 ? pfx2 : NULL);
1486 if (err >= 0 && elem->vendor_type > 0)
1487 err = tplg_save_printf(dst, pfx, "type %u",
1488 elem->vendor_type);
1489 if (err >= 0 && count > 1)
1490 err = tplg_save_printf(dst, pfx, "}\n");
1491 return err;
1492 }
1493
1494 /* Find a referenced data element and copy its data to the parent
1495 * element's private data buffer.
1496 * An element can refer to multiple data sections. Data of these sections
1497 * will be merged in the their reference order.
1498 */
tplg_copy_data(snd_tplg_t * tplg,struct tplg_elem * elem,struct tplg_ref * ref)1499 int tplg_copy_data(snd_tplg_t *tplg, struct tplg_elem *elem,
1500 struct tplg_ref *ref)
1501 {
1502 struct tplg_elem *ref_elem;
1503 struct snd_soc_tplg_private *priv, *old_priv;
1504 int priv_data_size, old_priv_data_size;
1505 void *obj;
1506
1507 ref_elem = tplg_elem_lookup(&tplg->pdata_list,
1508 ref->id, SND_TPLG_TYPE_DATA, elem->index);
1509 if (!ref_elem) {
1510 SNDERR("cannot find data '%s' referenced by"
1511 " element '%s'", ref->id, elem->id);
1512 return -EINVAL;
1513 }
1514
1515 tplg_dbg("Data '%s' used by '%s'", ref->id, elem->id);
1516 /* overlook empty private data */
1517 if (!ref_elem->data || !ref_elem->data->size) {
1518 ref->elem = ref_elem;
1519 return 0;
1520 }
1521
1522 old_priv = get_priv_data(elem);
1523 if (!old_priv)
1524 return -EINVAL;
1525 old_priv_data_size = old_priv->size;
1526
1527 priv_data_size = ref_elem->data->size;
1528 obj = realloc(elem->obj,
1529 elem->size + priv_data_size);
1530 if (!obj)
1531 return -ENOMEM;
1532 elem->obj = obj;
1533
1534 priv = get_priv_data(elem);
1535 if (!priv)
1536 return -EINVAL;
1537
1538 /* merge the new data block */
1539 elem->size += priv_data_size;
1540 priv->size = priv_data_size + old_priv_data_size;
1541 ref_elem->compound_elem = 1;
1542 memcpy(priv->data + old_priv_data_size,
1543 ref_elem->data->data, priv_data_size);
1544
1545 ref->elem = ref_elem;
1546 return 0;
1547 }
1548
1549 /* check data objects and build those with tuples */
tplg_build_data(snd_tplg_t * tplg)1550 int tplg_build_data(snd_tplg_t *tplg)
1551 {
1552 struct list_head *base, *pos;
1553 struct tplg_elem *elem;
1554 int err = 0;
1555
1556 base = &tplg->pdata_list;
1557 list_for_each(pos, base) {
1558
1559 elem = list_entry(pos, struct tplg_elem, list);
1560 if (has_tuples(elem)) {
1561 err = build_tuples(tplg, elem);
1562 if (err < 0)
1563 return err;
1564 }
1565 }
1566
1567 return 0;
1568 }
1569
1570 /* decode manifest data */
tplg_decode_manifest_data(snd_tplg_t * tplg,size_t pos,struct snd_soc_tplg_hdr * hdr,void * bin,size_t size)1571 int tplg_decode_manifest_data(snd_tplg_t *tplg,
1572 size_t pos,
1573 struct snd_soc_tplg_hdr *hdr,
1574 void *bin, size_t size)
1575 {
1576 struct snd_soc_tplg_manifest *m = bin;
1577 struct tplg_elem *elem;
1578 size_t off;
1579
1580 if (hdr->index != 0) {
1581 SNDERR("manifest - wrong index %d", hdr->index);
1582 return -EINVAL;
1583 }
1584
1585 if (sizeof(*m) > size) {
1586 SNDERR("manifest - wrong size %zd (minimal %zd)",
1587 size, sizeof(*m));
1588 return -EINVAL;
1589 }
1590
1591 if (m->size != sizeof(*m)) {
1592 SNDERR("manifest - wrong sructure size %d", m->size);
1593 return -EINVAL;
1594 }
1595
1596 off = offsetof(struct snd_soc_tplg_manifest, priv);
1597 if (off + m->priv.size > size) {
1598 SNDERR("manifest - wrong private size %d", m->priv.size);
1599 return -EINVAL;
1600 }
1601
1602 tplg->manifest = *m;
1603
1604 bin += off;
1605 size -= off;
1606 pos += off;
1607
1608 elem = tplg_elem_new_common(tplg, NULL, "manifest",
1609 SND_TPLG_TYPE_MANIFEST);
1610 if (!elem)
1611 return -ENOMEM;
1612
1613 tplg_log(tplg, 'D', pos, "manifest: private size %zd", size);
1614 return tplg_add_data(tplg, elem, bin, size);
1615 }
1616
tplg_add_token(snd_tplg_t * tplg,struct tplg_elem * parent,unsigned int token,char str_ref[SNDRV_CTL_ELEM_ID_NAME_MAXLEN])1617 int tplg_add_token(snd_tplg_t *tplg, struct tplg_elem *parent,
1618 unsigned int token,
1619 char str_ref[SNDRV_CTL_ELEM_ID_NAME_MAXLEN])
1620 {
1621 struct tplg_elem *elem;
1622 struct tplg_token *t;
1623 struct tplg_vendor_tokens *tokens;
1624 unsigned int i;
1625 size_t size;
1626
1627 elem = tplg_elem_lookup(&tplg->token_list, parent->id,
1628 SND_TPLG_TYPE_TOKEN, parent->index);
1629 if (elem == NULL) {
1630 elem = tplg_elem_new_common(tplg, NULL, parent->id,
1631 SND_TPLG_TYPE_TOKEN);
1632 if (!elem)
1633 return -ENOMEM;
1634 }
1635
1636 tokens = elem->tokens;
1637 if (tokens) {
1638 for (i = 0; i < tokens->num_tokens; i++) {
1639 t = &tokens->token[i];
1640 if (t->value == token)
1641 goto found;
1642 }
1643 size = sizeof(*tokens) +
1644 (tokens->num_tokens + 1) * sizeof(struct tplg_token);
1645 tokens = realloc(tokens, size);
1646 } else {
1647 size = sizeof(*tokens) + 1 * sizeof(struct tplg_token);
1648 tokens = calloc(1, size);
1649 }
1650
1651 if (!tokens)
1652 return -ENOMEM;
1653
1654 memset(&tokens->token[tokens->num_tokens], 0, sizeof(struct tplg_token));
1655 elem->tokens = tokens;
1656 t = &tokens->token[tokens->num_tokens];
1657 tokens->num_tokens++;
1658 snprintf(t->id, sizeof(t->id), "token%u", token);
1659 t->value = token;
1660 found:
1661 snd_strlcpy(str_ref, t->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
1662 return 0;
1663 }
1664
tplg_verify_tuple_set(snd_tplg_t * tplg,size_t pos,const void * bin,size_t size)1665 static int tplg_verify_tuple_set(snd_tplg_t *tplg, size_t pos,
1666 const void *bin, size_t size)
1667 {
1668 const struct snd_soc_tplg_vendor_array *va;
1669 unsigned int j;
1670
1671 va = bin;
1672 if (size < sizeof(*va) || size < va->size) {
1673 tplg_log(tplg, 'A', pos, "tuple set verify: wrong size %zd", size);
1674 return -EINVAL;
1675 }
1676
1677 switch (va->type) {
1678 case SND_SOC_TPLG_TUPLE_TYPE_UUID:
1679 case SND_SOC_TPLG_TUPLE_TYPE_STRING:
1680 case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
1681 case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
1682 case SND_SOC_TPLG_TUPLE_TYPE_WORD:
1683 case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
1684 break;
1685 default:
1686 tplg_log(tplg, 'A', pos, "tuple set verify: unknown array type %d", va->type);
1687 return -EINVAL;
1688 }
1689
1690 j = tplg_get_tuple_size(va->type) * va->num_elems;
1691 if (j + sizeof(*va) != va->size) {
1692 tplg_log(tplg, 'A', pos, "tuple set verify: wrong vendor array size %d "
1693 "(expected %d for %d count %d)",
1694 va->size, j + sizeof(*va), va->type, va->num_elems);
1695 return -EINVAL;
1696 }
1697
1698 if (va->num_elems > 4096) {
1699 tplg_log(tplg, 'A', pos, "tuple set verify: tuples overflow %d", va->num_elems);
1700 return -EINVAL;
1701 }
1702
1703 return 0;
1704 }
1705
tplg_decode_tuple_set(snd_tplg_t * tplg,size_t pos,struct tplg_elem * parent,struct tplg_tuple_set ** _set,const void * bin,size_t size)1706 static int tplg_decode_tuple_set(snd_tplg_t *tplg,
1707 size_t pos,
1708 struct tplg_elem *parent,
1709 struct tplg_tuple_set **_set,
1710 const void *bin, size_t size)
1711 {
1712 const struct snd_soc_tplg_vendor_array *va;
1713 struct tplg_tuple_set *set;
1714 struct tplg_tuple *tuple;
1715 unsigned int j;
1716 int err;
1717
1718 va = bin;
1719 if (size < sizeof(*va) || size < va->size) {
1720 SNDERR("tuples: wrong size %zd", size);
1721 return -EINVAL;
1722 }
1723
1724 switch (va->type) {
1725 case SND_SOC_TPLG_TUPLE_TYPE_UUID:
1726 case SND_SOC_TPLG_TUPLE_TYPE_STRING:
1727 case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
1728 case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
1729 case SND_SOC_TPLG_TUPLE_TYPE_WORD:
1730 case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
1731 break;
1732 default:
1733 SNDERR("tuples: unknown array type %d", va->type);
1734 return -EINVAL;
1735 }
1736
1737 j = tplg_get_tuple_size(va->type) * va->num_elems;
1738 if (j + sizeof(*va) != va->size) {
1739 SNDERR("tuples: wrong vendor array size %d "
1740 "(expected %d for %d count %d)",
1741 va->size, j + sizeof(*va), va->type, va->num_elems);
1742 return -EINVAL;
1743 }
1744
1745 if (va->num_elems > 4096) {
1746 SNDERR("tuples: tuples overflow %d", va->num_elems);
1747 return -EINVAL;
1748 }
1749
1750 set = calloc(1, sizeof(*set) + va->num_elems * sizeof(struct tplg_tuple));
1751 if (!set)
1752 return -ENOMEM;
1753
1754 set->type = va->type;
1755 set->num_tuples = va->num_elems;
1756
1757 tplg_log(tplg, 'A', pos, "tuple set: type %d (%s) tuples %d size %d", set->type,
1758 get_tuple_type_name(set->type), set->num_tuples, va->size);
1759 for (j = 0; j < set->num_tuples; j++) {
1760 tuple = &set->tuple[j];
1761 switch (va->type) {
1762 case SND_SOC_TPLG_TUPLE_TYPE_UUID:
1763 err = tplg_add_token(tplg, parent, va->uuid[j].token,
1764 tuple->token);
1765 if (err < 0)
1766 goto retval;
1767 memcpy(tuple->uuid, va->uuid[j].uuid,
1768 sizeof(va->uuid[j].uuid));
1769 break;
1770 case SND_SOC_TPLG_TUPLE_TYPE_STRING:
1771 err = tplg_add_token(tplg, parent, va->string[j].token,
1772 tuple->token);
1773 if (err < 0)
1774 goto retval;
1775 snd_strlcpy(tuple->string, va->string[j].string,
1776 sizeof(tuple->string));
1777 break;
1778 case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
1779 case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
1780 case SND_SOC_TPLG_TUPLE_TYPE_WORD:
1781 case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
1782 err = tplg_add_token(tplg, parent, va->value[j].token,
1783 tuple->token);
1784 if (err < 0)
1785 goto retval;
1786 tuple->value = va->value[j].value;
1787 break;
1788 }
1789 }
1790
1791 *_set = set;
1792 return 0;
1793
1794 retval:
1795 free(set);
1796 return err;
1797 }
1798
1799 /* verify tuples from the binary input */
tplg_verify_tuples(snd_tplg_t * tplg,size_t pos,const void * bin,size_t size)1800 static int tplg_verify_tuples(snd_tplg_t *tplg, size_t pos,
1801 const void *bin, size_t size)
1802 {
1803 const struct snd_soc_tplg_vendor_array *va;
1804 int err;
1805
1806 if (size < sizeof(*va)) {
1807 tplg_log(tplg, 'A', pos, "tuples: small size %zd", size);
1808 return -EINVAL;
1809 }
1810
1811 next:
1812 va = bin;
1813 if (size < sizeof(*va)) {
1814 tplg_log(tplg, 'A', pos, "tuples: unexpected vendor arry size %zd", size);
1815 return -EINVAL;
1816 }
1817
1818 err = tplg_verify_tuple_set(tplg, pos, va, va->size);
1819 if (err < 0)
1820 return err;
1821
1822 bin += va->size;
1823 size -= va->size;
1824 pos += va->size;
1825 if (size > 0)
1826 goto next;
1827
1828 return 0;
1829 }
1830
1831 /* add tuples from the binary input */
tplg_decode_tuples(snd_tplg_t * tplg,size_t pos,struct tplg_elem * parent,struct tplg_vendor_tuples * tuples,const void * bin,size_t size)1832 static int tplg_decode_tuples(snd_tplg_t *tplg,
1833 size_t pos,
1834 struct tplg_elem *parent,
1835 struct tplg_vendor_tuples *tuples,
1836 const void *bin, size_t size)
1837 {
1838 const struct snd_soc_tplg_vendor_array *va;
1839 struct tplg_tuple_set *set;
1840 int err;
1841
1842 if (size < sizeof(*va)) {
1843 SNDERR("tuples: small size %zd", size);
1844 return -EINVAL;
1845 }
1846
1847 next:
1848 va = bin;
1849 if (size < sizeof(*va)) {
1850 SNDERR("tuples: unexpected vendor arry size %zd", size);
1851 return -EINVAL;
1852 }
1853
1854 if (tuples->num_sets >= tuples->alloc_sets) {
1855 SNDERR("tuples: index overflow (%d)", tuples->num_sets);
1856 return -EINVAL;
1857 }
1858
1859 err = tplg_decode_tuple_set(tplg, pos, parent, &set, va, va->size);
1860 if (err < 0)
1861 return err;
1862 tuples->set[tuples->num_sets++] = set;
1863
1864 bin += va->size;
1865 size -= va->size;
1866 pos += va->size;
1867 if (size > 0)
1868 goto next;
1869
1870 return 0;
1871 }
1872
1873 /* decode private data */
tplg_add_data(snd_tplg_t * tplg,struct tplg_elem * parent,const void * bin,size_t size)1874 int tplg_add_data(snd_tplg_t *tplg,
1875 struct tplg_elem *parent,
1876 const void *bin, size_t size)
1877 {
1878 const struct snd_soc_tplg_private *tp;
1879 const struct snd_soc_tplg_vendor_array *va;
1880 struct tplg_elem *elem = NULL, *elem2 = NULL;
1881 struct tplg_vendor_tuples *tuples = NULL;
1882 char id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
1883 char suffix[16];
1884 size_t pos = 0, off;
1885 int err, num_tuples = 0, block = 0;
1886
1887 if (size == 0)
1888 return 0;
1889
1890 off = offsetof(struct snd_soc_tplg_private, array);
1891
1892 next:
1893 tp = bin;
1894 if (off + size < tp->size) {
1895 SNDERR("data: unexpected element size %zd", size);
1896 return -EINVAL;
1897 }
1898
1899 if (tplg_verify_tuples(tplg, pos, tp->array, tp->size) < 0) {
1900 if (tuples) {
1901 err = tplg_ref_add(elem, SND_TPLG_TYPE_TOKEN, parent->id);
1902 if (err < 0)
1903 return err;
1904 err = tplg_ref_add(elem2, SND_TPLG_TYPE_TUPLE, id);
1905 if (err < 0)
1906 return err;
1907 err = tplg_ref_add(parent, SND_TPLG_TYPE_DATA, id);
1908 if (err < 0)
1909 return err;
1910 tuples = NULL;
1911 }
1912 tplg_log(tplg, 'A', pos, "add bytes: size %d", tp->size);
1913 snprintf(suffix, sizeof(suffix), "data%u", block++);
1914 err = tplg_add_data_bytes(tplg, parent, suffix, tp->array, tp->size);
1915 } else {
1916 if (!tuples) {
1917 snprintf(id, sizeof(id), "%.30s:tuple%d", parent->id, (block++) & 0xffff);
1918 elem = tplg_elem_new_common(tplg, NULL, id, SND_TPLG_TYPE_TUPLE);
1919 if (!elem)
1920 return -ENOMEM;
1921
1922 elem2 = tplg_elem_new_common(tplg, NULL, id, SND_TPLG_TYPE_DATA);
1923 if (!elem2)
1924 return -ENOMEM;
1925
1926 tuples = calloc(1, sizeof(*tuples));
1927 if (!tuples)
1928 return -ENOMEM;
1929 elem->tuples = tuples;
1930
1931 tuples->alloc_sets = (size / sizeof(*va)) + 1;
1932 tuples->set = calloc(1, tuples->alloc_sets * sizeof(void *));
1933 if (!tuples->set) {
1934 tuples->alloc_sets = 0;
1935 return -ENOMEM;
1936 }
1937 }
1938 tplg_log(tplg, 'A', pos, "decode tuples: size %d", tp->size);
1939 err = tplg_decode_tuples(tplg, pos, parent, tuples, tp->array, tp->size);
1940 num_tuples++;
1941 }
1942 if (err < 0)
1943 return err;
1944
1945 bin += off + tp->size;
1946 size -= off + tp->size;
1947 pos += off + tp->size;
1948 if (size > 0)
1949 goto next;
1950
1951 if (tuples && elem && elem2) {
1952 err = tplg_ref_add(elem, SND_TPLG_TYPE_TOKEN, parent->id);
1953 if (err < 0)
1954 return err;
1955 err = tplg_ref_add(elem2, SND_TPLG_TYPE_TUPLE, id);
1956 if (err < 0)
1957 return err;
1958 err = tplg_ref_add(parent, SND_TPLG_TYPE_DATA, id);
1959 if (err < 0)
1960 return err;
1961 }
1962
1963 return 0;
1964 }
1965
1966 /* add private data - bytes */
tplg_add_data_bytes(snd_tplg_t * tplg,struct tplg_elem * parent,const char * suffix,const void * bin,size_t size)1967 int tplg_add_data_bytes(snd_tplg_t *tplg, struct tplg_elem *parent,
1968 const char *suffix, const void *bin, size_t size)
1969 {
1970 struct snd_soc_tplg_private *priv;
1971 struct tplg_elem *elem;
1972 char id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
1973
1974 if (suffix)
1975 snprintf(id, sizeof(id), "%.30s:%.12s", parent->id, suffix);
1976 else
1977 snd_strlcpy(id, parent->id, sizeof(id));
1978 elem = tplg_elem_new_common(tplg, NULL, id, SND_TPLG_TYPE_DATA);
1979 if (!elem)
1980 return -ENOMEM;
1981
1982 priv = malloc(sizeof(*priv) + size);
1983 if (!priv)
1984 return -ENOMEM;
1985 memcpy(priv->data, bin, size);
1986 priv->size = size;
1987 elem->data = priv;
1988
1989 return tplg_ref_add(parent, SND_TPLG_TYPE_DATA, id);
1990 }
1991
1992 /* decode data from the binary input */
tplg_decode_data(snd_tplg_t * tplg ATTRIBUTE_UNUSED,size_t pos ATTRIBUTE_UNUSED,struct snd_soc_tplg_hdr * hdr ATTRIBUTE_UNUSED,void * bin ATTRIBUTE_UNUSED,size_t size ATTRIBUTE_UNUSED)1993 int tplg_decode_data(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
1994 size_t pos ATTRIBUTE_UNUSED,
1995 struct snd_soc_tplg_hdr *hdr ATTRIBUTE_UNUSED,
1996 void *bin ATTRIBUTE_UNUSED,
1997 size_t size ATTRIBUTE_UNUSED)
1998 {
1999 SNDERR("data type not expected");
2000 return -EINVAL;
2001 }
2002