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