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 <sys/stat.h>
21 #include "list.h"
22 #include "tplg_local.h"
23 
24 /*
25  * Get integer value
26  */
tplg_get_integer(snd_config_t * n,int * val,int base)27 int tplg_get_integer(snd_config_t *n, int *val, int base)
28 {
29 	const char *str;
30 	long lval;
31 	int err;
32 
33 	switch (snd_config_get_type(n)) {
34 	case SND_CONFIG_TYPE_INTEGER:
35 		err = snd_config_get_integer(n, &lval);
36 		if (err < 0)
37 			return err;
38 		if (lval < INT_MIN || lval > INT_MAX)
39 			return -ERANGE;
40 		*val = lval;
41 		return err;
42 	case SND_CONFIG_TYPE_STRING:
43 		err = snd_config_get_string(n, &str);
44 		if (err < 0)
45 			return err;
46 		errno = 0;
47 		*val = strtol(str, NULL, base);
48 		if (errno == ERANGE)
49 			return -ERANGE;
50 		if (errno && *val == 0)
51 			return -EINVAL;
52 		return 0;
53 	default:
54 		return -EINVAL;
55 	}
56 }
57 
58 /*
59  * Get unsigned integer value
60  */
tplg_get_unsigned(snd_config_t * n,unsigned * val,int base)61 int tplg_get_unsigned(snd_config_t *n, unsigned *val, int base)
62 {
63 	const char *str;
64 	long lval;
65 	long long llval;
66 	unsigned long uval;
67 	int err;
68 
69 	switch (snd_config_get_type(n)) {
70 	case SND_CONFIG_TYPE_INTEGER:
71 		err = snd_config_get_integer(n, &lval);
72 		if (err < 0)
73 			return err;
74 		if (lval < 0 && lval >= INT_MIN)
75 			lval = UINT_MAX + lval + 1;
76 		if (lval < 0 || lval > UINT_MAX)
77 			return -ERANGE;
78 		*val = lval;
79 		return err;
80 	case SND_CONFIG_TYPE_INTEGER64:
81 		err = snd_config_get_integer64(n, &llval);
82 		if (err < 0)
83 			return err;
84 		if (llval < 0 && llval >= INT_MIN)
85 			llval = UINT_MAX + llval + 1;
86 		if (llval < 0 || llval > UINT_MAX)
87 			return -ERANGE;
88 		*val = llval;
89 		return err;
90 	case SND_CONFIG_TYPE_STRING:
91 		err = snd_config_get_string(n, &str);
92 		if (err < 0)
93 			return err;
94 		errno = 0;
95 		uval = strtoul(str, NULL, base);
96 		if (errno == ERANGE && uval == ULONG_MAX)
97 			return -ERANGE;
98 		if (errno && uval == 0)
99 			return -EINVAL;
100 		if (uval > UINT_MAX)
101 			return -ERANGE;
102 		*val = uval;
103 		return 0;
104 	default:
105 		return -EINVAL;
106 	}
107 }
108 
109 /*
110  * Parse compound
111  */
tplg_parse_compound(snd_tplg_t * tplg,snd_config_t * cfg,int (* fcn)(snd_tplg_t *,snd_config_t *,void *),void * private)112 int tplg_parse_compound(snd_tplg_t *tplg, snd_config_t *cfg,
113 			int (*fcn)(snd_tplg_t *, snd_config_t *, void *),
114 			void *private)
115 {
116 	const char *id;
117 	snd_config_iterator_t i, next;
118 	snd_config_t *n;
119 	int err = -EINVAL;
120 
121 	if (snd_config_get_id(cfg, &id) < 0)
122 		return -EINVAL;
123 
124 	if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
125 		SNDERR("compound type expected for %s", id);
126 		return -EINVAL;
127 	}
128 
129 	/* parse compound */
130 	snd_config_for_each(i, next, cfg) {
131 		n = snd_config_iterator_entry(i);
132 
133 		if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
134 			SNDERR("compound type expected for %s, is %d",
135 				id, snd_config_get_type(cfg));
136 			return -EINVAL;
137 		}
138 
139 		err = fcn(tplg, n, private);
140 		if (err < 0)
141 			return err;
142 	}
143 
144 	return err;
145 }
146 
tplg_parse_config(snd_tplg_t * tplg,snd_config_t * cfg)147 static int tplg_parse_config(snd_tplg_t *tplg, snd_config_t *cfg)
148 {
149 	int (*parser)(snd_tplg_t *tplg, snd_config_t *cfg, void *priv);
150 	snd_config_iterator_t i, next;
151 	snd_config_t *n;
152 	const char *id;
153 	struct tplg_table *p;
154 	unsigned int idx;
155 	int err;
156 
157 	if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
158 		SNDERR("compound type expected at top level");
159 		return -EINVAL;
160 	}
161 
162 	/* parse topology config sections */
163 	snd_config_for_each(i, next, cfg) {
164 
165 		n = snd_config_iterator_entry(i);
166 		if (snd_config_get_id(n, &id) < 0)
167 			continue;
168 
169 		parser = NULL;
170 		for (idx = 0; idx < tplg_table_items; idx++) {
171 			p = &tplg_table[idx];
172 			if (p->id && strcmp(id, p->id) == 0) {
173 				parser = p->parse;
174 				break;
175 			}
176 			if (p->id2 && strcmp(id, p->id2) == 0) {
177 				parser = p->parse;
178 				break;
179 			}
180 		}
181 
182 		if (parser == NULL) {
183 			SNDERR("unknown section %s", id);
184 			continue;
185 		}
186 
187 		err = tplg_parse_compound(tplg, n, parser, NULL);
188 		if (err < 0)
189 			return err;
190 	}
191 	return 0;
192 }
193 
tplg_load_config(snd_tplg_t * tplg,snd_input_t * in)194 static int tplg_load_config(snd_tplg_t *tplg, snd_input_t *in)
195 {
196 	snd_config_t *top;
197 	int ret;
198 
199 	ret = snd_config_top(&top);
200 	if (ret < 0)
201 		return ret;
202 
203 	ret = snd_config_load(top, in);
204 	if (ret < 0) {
205 		SNDERR("could not load configuration");
206 		snd_config_delete(top);
207 		return ret;
208 	}
209 
210 	ret = tplg_parse_config(tplg, top);
211 	snd_config_delete(top);
212 	if (ret < 0) {
213 		SNDERR("failed to parse topology");
214 		return ret;
215 	}
216 
217 	return 0;
218 }
219 
tplg_build_integ(snd_tplg_t * tplg)220 static int tplg_build_integ(snd_tplg_t *tplg)
221 {
222 	int err;
223 
224 	err = tplg_build_data(tplg);
225 	if (err <  0)
226 		return err;
227 
228 	err = tplg_build_manifest_data(tplg);
229 	if (err <  0)
230 		return err;
231 
232 	err = tplg_build_controls(tplg);
233 	if (err <  0)
234 		return err;
235 
236 	err = tplg_build_widgets(tplg);
237 	if (err <  0)
238 		return err;
239 
240 	err = tplg_build_pcms(tplg, SND_TPLG_TYPE_PCM);
241 	if (err <  0)
242 		return err;
243 
244 	err = tplg_build_dais(tplg, SND_TPLG_TYPE_DAI);
245 	if (err <  0)
246 		return err;
247 
248 	err = tplg_build_links(tplg, SND_TPLG_TYPE_BE);
249 	if (err <  0)
250 		return err;
251 
252 	err = tplg_build_links(tplg, SND_TPLG_TYPE_CC);
253 	if (err <  0)
254 		return err;
255 
256 	err = tplg_build_routes(tplg);
257 	if (err <  0)
258 		return err;
259 
260 	return err;
261 }
262 
snd_tplg_load(snd_tplg_t * tplg,const char * buf,size_t size)263 int snd_tplg_load(snd_tplg_t *tplg, const char *buf, size_t size)
264 {
265 	snd_input_t *in;
266 	int err;
267 
268 	err = snd_input_buffer_open(&in, buf, size);
269 	if (err < 0) {
270 		SNDERR("could not create input buffer");
271 		return err;
272 	}
273 
274 	err = tplg_load_config(tplg, in);
275 	snd_input_close(in);
276 	return err;
277 }
278 
tplg_build(snd_tplg_t * tplg)279 static int tplg_build(snd_tplg_t *tplg)
280 {
281 	int err;
282 
283 	err = tplg_build_integ(tplg);
284 	if (err < 0) {
285 		SNDERR("failed to check topology integrity");
286 		return err;
287 	}
288 
289 	err = tplg_write_data(tplg);
290 	if (err < 0) {
291 		SNDERR("failed to write data %d", err);
292 		return err;
293 	}
294 	return 0;
295 }
296 
snd_tplg_build_file(snd_tplg_t * tplg,const char * infile,const char * outfile)297 int snd_tplg_build_file(snd_tplg_t *tplg,
298 			const char *infile,
299 			const char *outfile)
300 {
301 	FILE *fp;
302 	snd_input_t *in;
303 	int err;
304 
305 	fp = fopen(infile, "r");
306 	if (fp == NULL) {
307 		SNDERR("could not open configuration file %s", infile);
308 		return -errno;
309 	}
310 
311 	err = snd_input_stdio_attach(&in, fp, 1);
312 	if (err < 0) {
313 		fclose(fp);
314 		SNDERR("could not attach stdio %s", infile);
315 		return err;
316 	}
317 
318 	err = tplg_load_config(tplg, in);
319 	snd_input_close(in);
320 	if (err < 0)
321 		return err;
322 
323 	return snd_tplg_build(tplg, outfile);
324 }
325 
snd_tplg_add_object(snd_tplg_t * tplg,snd_tplg_obj_template_t * t)326 int snd_tplg_add_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
327 {
328 	switch (t->type) {
329 	case SND_TPLG_TYPE_MIXER:
330 		return tplg_add_mixer_object(tplg, t);
331 	case SND_TPLG_TYPE_ENUM:
332 		return tplg_add_enum_object(tplg, t);
333 	case SND_TPLG_TYPE_BYTES:
334 		return tplg_add_bytes_object(tplg, t);
335 	case SND_TPLG_TYPE_DAPM_WIDGET:
336 		return tplg_add_widget_object(tplg, t);
337 	case SND_TPLG_TYPE_DAPM_GRAPH:
338 		return tplg_add_graph_object(tplg, t);
339 	case SND_TPLG_TYPE_PCM:
340 		return tplg_add_pcm_object(tplg, t);
341 	case SND_TPLG_TYPE_DAI:
342 		return tplg_add_dai_object(tplg, t);
343 	case SND_TPLG_TYPE_LINK:
344 	case SND_TPLG_TYPE_BE:
345 	case SND_TPLG_TYPE_CC:
346 		return tplg_add_link_object(tplg, t);
347 	default:
348 		SNDERR("invalid object type %d", t->type);
349 		return -EINVAL;
350 	};
351 }
352 
snd_tplg_build(snd_tplg_t * tplg,const char * outfile)353 int snd_tplg_build(snd_tplg_t *tplg, const char *outfile)
354 {
355 	int fd, err;
356 	ssize_t r;
357 
358 	err = tplg_build(tplg);
359 	if (err < 0)
360 		return err;
361 
362 	fd = open(outfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
363 	if (fd < 0) {
364 		SNDERR("failed to open %s err %d", outfile, -errno);
365 		return -errno;
366 	}
367 	r = write(fd, tplg->bin, tplg->bin_size);
368 	close(fd);
369 	if (r < 0) {
370 		err = -errno;
371 		SNDERR("write error: %s", strerror(errno));
372 		return err;
373 	}
374 	if ((size_t)r != tplg->bin_size) {
375 		SNDERR("partial write (%zd != %zd)", r, tplg->bin_size);
376 		return -EIO;
377 	}
378 	return 0;
379 }
380 
snd_tplg_build_bin(snd_tplg_t * tplg,void ** bin,size_t * size)381 int snd_tplg_build_bin(snd_tplg_t *tplg,
382 		       void **bin, size_t *size)
383 {
384 	int err;
385 
386 	err = tplg_build(tplg);
387 	if (err < 0)
388 		return err;
389 
390 	*bin = tplg->bin;
391 	*size = tplg->bin_size;
392 	tplg->bin = NULL;
393 	tplg->bin_size = tplg->bin_pos = 0;
394 	return 0;
395 }
396 
snd_tplg_set_manifest_data(snd_tplg_t * tplg,const void * data,int len)397 int snd_tplg_set_manifest_data(snd_tplg_t *tplg, const void *data, int len)
398 {
399 	struct tplg_elem *elem;
400 
401 	elem = tplg_elem_type_lookup(tplg, SND_TPLG_TYPE_MANIFEST);
402 	if (elem == NULL) {
403 		elem = tplg_elem_new_common(tplg, NULL, "manifest",
404 					    SND_TPLG_TYPE_MANIFEST);
405 		if (!elem)
406 			return -ENOMEM;
407 		tplg->manifest.size = elem->size;
408 	}
409 
410 	if (len <= 0)
411 		return 0;
412 
413 	return tplg_add_data_bytes(tplg, elem, NULL, data, len);
414 }
415 
snd_tplg_set_version(snd_tplg_t * tplg,unsigned int version)416 int snd_tplg_set_version(snd_tplg_t *tplg, unsigned int version)
417 {
418 	tplg->version = version;
419 
420 	return 0;
421 }
422 
snd_tplg_verbose(snd_tplg_t * tplg,int verbose)423 void snd_tplg_verbose(snd_tplg_t *tplg, int verbose)
424 {
425 	tplg->verbose = verbose;
426 }
427 
is_little_endian(void)428 static bool is_little_endian(void)
429 {
430 #ifdef __BYTE_ORDER
431 	#if __BYTE_ORDER == __LITTLE_ENDIAN
432 		return true;
433 	#endif
434 #endif
435 	return false;
436 }
437 
snd_tplg_create(int flags)438 snd_tplg_t *snd_tplg_create(int flags)
439 {
440 	snd_tplg_t *tplg;
441 
442 	if (!is_little_endian()) {
443 		SNDERR("cannot support big-endian machines");
444 		return NULL;
445 	}
446 
447 	tplg = calloc(1, sizeof(snd_tplg_t));
448 	if (!tplg)
449 		return NULL;
450 
451 	tplg->verbose = !!(flags & SND_TPLG_CREATE_VERBOSE);
452 	tplg->dapm_sort = (flags & SND_TPLG_CREATE_DAPM_NOSORT) == 0;
453 
454 	tplg->manifest.size = sizeof(struct snd_soc_tplg_manifest);
455 
456 	INIT_LIST_HEAD(&tplg->tlv_list);
457 	INIT_LIST_HEAD(&tplg->widget_list);
458 	INIT_LIST_HEAD(&tplg->pcm_list);
459 	INIT_LIST_HEAD(&tplg->dai_list);
460 	INIT_LIST_HEAD(&tplg->be_list);
461 	INIT_LIST_HEAD(&tplg->cc_list);
462 	INIT_LIST_HEAD(&tplg->route_list);
463 	INIT_LIST_HEAD(&tplg->pdata_list);
464 	INIT_LIST_HEAD(&tplg->manifest_list);
465 	INIT_LIST_HEAD(&tplg->text_list);
466 	INIT_LIST_HEAD(&tplg->pcm_config_list);
467 	INIT_LIST_HEAD(&tplg->pcm_caps_list);
468 	INIT_LIST_HEAD(&tplg->mixer_list);
469 	INIT_LIST_HEAD(&tplg->enum_list);
470 	INIT_LIST_HEAD(&tplg->bytes_ext_list);
471 	INIT_LIST_HEAD(&tplg->token_list);
472 	INIT_LIST_HEAD(&tplg->tuple_list);
473 	INIT_LIST_HEAD(&tplg->hw_cfg_list);
474 
475 	return tplg;
476 }
477 
snd_tplg_new(void)478 snd_tplg_t *snd_tplg_new(void)
479 {
480 	return snd_tplg_create(0);
481 }
482 
snd_tplg_free(snd_tplg_t * tplg)483 void snd_tplg_free(snd_tplg_t *tplg)
484 {
485 	free(tplg->bin);
486 	free(tplg->manifest_pdata);
487 
488 	tplg_elem_free_list(&tplg->tlv_list);
489 	tplg_elem_free_list(&tplg->widget_list);
490 	tplg_elem_free_list(&tplg->pcm_list);
491 	tplg_elem_free_list(&tplg->dai_list);
492 	tplg_elem_free_list(&tplg->be_list);
493 	tplg_elem_free_list(&tplg->cc_list);
494 	tplg_elem_free_list(&tplg->route_list);
495 	tplg_elem_free_list(&tplg->pdata_list);
496 	tplg_elem_free_list(&tplg->manifest_list);
497 	tplg_elem_free_list(&tplg->text_list);
498 	tplg_elem_free_list(&tplg->pcm_config_list);
499 	tplg_elem_free_list(&tplg->pcm_caps_list);
500 	tplg_elem_free_list(&tplg->mixer_list);
501 	tplg_elem_free_list(&tplg->enum_list);
502 	tplg_elem_free_list(&tplg->bytes_ext_list);
503 	tplg_elem_free_list(&tplg->token_list);
504 	tplg_elem_free_list(&tplg->tuple_list);
505 	tplg_elem_free_list(&tplg->hw_cfg_list);
506 
507 	free(tplg);
508 }
509 
snd_tplg_version(void)510 const char *snd_tplg_version(void)
511 {
512 	return SND_LIB_VERSION_STR;
513 }
514