1 /*
2 Copyright (c) 2019 Red Hat Inc.
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: Jaroslav Kysela <perex@perex.cz>
16 */
17
18 #include "tplg_local.h"
19
tplg_decode_template(snd_tplg_t *tplg, size_t pos, struct snd_soc_tplg_hdr *hdr, snd_tplg_obj_template_t *t)20 int tplg_decode_template(snd_tplg_t *tplg,
21 size_t pos,
22 struct snd_soc_tplg_hdr *hdr,
23 snd_tplg_obj_template_t *t)
24 {
25 int type;
26
27 type = tplg_get_type(hdr->type);
28 tplg_log(tplg, 'D', pos, "template: asoc type %d library type %d",
29 hdr->type, type);
30 if (type < 0)
31 return type;
32
33 memset(t, 0, sizeof(*t));
34 t->type = type;
35 t->index = hdr->index;
36 t->version = hdr->version;
37 t->vendor_type = hdr->vendor_type;
38 tplg_log(tplg, 'D', pos, "template: index %d version %d vendor_type %d",
39 hdr->index, hdr->version, hdr->vendor_type);
40 return 0;
41 }
42
snd_tplg_decode(snd_tplg_t *tplg, void *bin, size_t size, int dflags)43 int snd_tplg_decode(snd_tplg_t *tplg, void *bin, size_t size, int dflags)
44 {
45 struct snd_soc_tplg_hdr *hdr;
46 struct tplg_table *tptr;
47 size_t pos;
48 void *b = bin;
49 unsigned int index;
50 int err;
51
52 if (dflags != 0)
53 return -EINVAL;
54 if (tplg == NULL || bin == NULL)
55 return -EINVAL;
56 while (1) {
57 pos = b - bin;
58 if (size == pos) {
59 tplg_log(tplg, 'D', pos, "block: success (total %zd)", size);
60 return 0;
61 }
62 if (size - pos < sizeof(*hdr)) {
63 tplg_log(tplg, 'D', pos, "block: small size");
64 SNDERR("incomplete header data to decode");
65 return -EINVAL;
66 }
67 hdr = b;
68 if (hdr->magic != SND_SOC_TPLG_MAGIC) {
69 SNDERR("bad block magic %08x", hdr->magic);
70 return -EINVAL;
71 }
72
73 tplg_log(tplg, 'D', pos, "block: abi %d size %d payload size %d",
74 hdr->abi, hdr->size, hdr->payload_size);
75 if (hdr->abi != SND_SOC_TPLG_ABI_VERSION) {
76 SNDERR("unsupported ABI version %d", hdr->abi);
77 return -EINVAL;
78 }
79 if (hdr->size != sizeof(*hdr)) {
80 SNDERR("header size mismatch");
81 return -EINVAL;
82 }
83
84 if (size - pos < hdr->size + hdr->payload_size) {
85 SNDERR("incomplete payload data to decode");
86 return -EINVAL;
87 }
88
89 if (hdr->payload_size < 8) {
90 SNDERR("wrong payload size %d", hdr->payload_size);
91 return -EINVAL;
92 }
93
94 /* first block must be manifest */
95 if (b == bin) {
96 if (hdr->type != SND_SOC_TPLG_TYPE_MANIFEST) {
97 SNDERR("first block must be manifest (value %d)", hdr->type);
98 return -EINVAL;
99 }
100 err = snd_tplg_set_version(tplg, hdr->version);
101 if (err < 0)
102 return err;
103 }
104
105 pos += hdr->size;
106 for (index = 0; index < tplg_table_items; index++) {
107 tptr = &tplg_table[index];
108 if (tptr->tsoc == (int)hdr->type)
109 break;
110 }
111 if (index >= tplg_table_items || tptr->decod == NULL) {
112 SNDERR("unknown block type %d", hdr->type);
113 return -EINVAL;
114 }
115 tplg_log(tplg, 'D', pos, "block: type %d - %s", hdr->type, tptr->name);
116 err = tptr->decod(tplg, pos, hdr, b + hdr->size, hdr->payload_size);
117 if (err < 0)
118 return err;
119 b += hdr->size + hdr->payload_size;
120 }
121 }
122