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