• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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