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