1c72fcc34Sopenharmony_ci/*
2c72fcc34Sopenharmony_ci  Copyright(c) 2021 Intel Corporation
3c72fcc34Sopenharmony_ci  All rights reserved.
4c72fcc34Sopenharmony_ci
5c72fcc34Sopenharmony_ci  This program is free software; you can redistribute it and/or modify
6c72fcc34Sopenharmony_ci  it under the terms of version 2 of the GNU General Public License as
7c72fcc34Sopenharmony_ci  published by the Free Software Foundation.
8c72fcc34Sopenharmony_ci
9c72fcc34Sopenharmony_ci  This program is distributed in the hope that it will be useful, but
10c72fcc34Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
11c72fcc34Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12c72fcc34Sopenharmony_ci  General Public License for more details.
13c72fcc34Sopenharmony_ci
14c72fcc34Sopenharmony_ci  You should have received a copy of the GNU General Public License
15c72fcc34Sopenharmony_ci  along with this program; if not, write to the Free Software
16c72fcc34Sopenharmony_ci  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17c72fcc34Sopenharmony_ci  The full GNU General Public License is included in this distribution
18c72fcc34Sopenharmony_ci  in the file called LICENSE.GPL.
19c72fcc34Sopenharmony_ci*/
20c72fcc34Sopenharmony_ci#include <errno.h>
21c72fcc34Sopenharmony_ci#include <stdio.h>
22c72fcc34Sopenharmony_ci#include <alsa/asoundlib.h>
23c72fcc34Sopenharmony_ci#include "topology.h"
24c72fcc34Sopenharmony_ci#include "pre-processor.h"
25c72fcc34Sopenharmony_ci
26c72fcc34Sopenharmony_ciint tplg_build_base_object(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
27c72fcc34Sopenharmony_ci			   snd_config_t *parent, bool skip_name)
28c72fcc34Sopenharmony_ci{
29c72fcc34Sopenharmony_ci	snd_config_t *top, *parent_obj, *cfg, *dest;
30c72fcc34Sopenharmony_ci	const char *parent_name;
31c72fcc34Sopenharmony_ci
32c72fcc34Sopenharmony_ci	/* find parent section config */
33c72fcc34Sopenharmony_ci	top = tplg_object_get_section(tplg_pp, parent);
34c72fcc34Sopenharmony_ci	if (!top)
35c72fcc34Sopenharmony_ci		return -EINVAL;
36c72fcc34Sopenharmony_ci
37c72fcc34Sopenharmony_ci	parent_obj = tplg_object_get_instance_config(tplg_pp, parent);
38c72fcc34Sopenharmony_ci
39c72fcc34Sopenharmony_ci	/* get parent name */
40c72fcc34Sopenharmony_ci	parent_name = tplg_object_get_name(tplg_pp, parent_obj);
41c72fcc34Sopenharmony_ci	if (!parent_name)
42c72fcc34Sopenharmony_ci		return 0;
43c72fcc34Sopenharmony_ci
44c72fcc34Sopenharmony_ci	/* find parent config with name */
45c72fcc34Sopenharmony_ci	dest = tplg_find_config(top, parent_name);
46c72fcc34Sopenharmony_ci	if (!dest) {
47c72fcc34Sopenharmony_ci		SNDERR("Cannot find parent config %s\n", parent_name);
48c72fcc34Sopenharmony_ci		return -EINVAL;
49c72fcc34Sopenharmony_ci	}
50c72fcc34Sopenharmony_ci
51c72fcc34Sopenharmony_ci	/* build config from template and add to parent */
52c72fcc34Sopenharmony_ci	return tplg_build_object_from_template(tplg_pp, obj_cfg, &cfg, dest, skip_name);
53c72fcc34Sopenharmony_ci}
54c72fcc34Sopenharmony_ci
55c72fcc34Sopenharmony_ciint tplg_build_scale_object(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
56c72fcc34Sopenharmony_ci			      snd_config_t *parent)
57c72fcc34Sopenharmony_ci{
58c72fcc34Sopenharmony_ci	return tplg_build_base_object(tplg_pp, obj_cfg, parent, true);
59c72fcc34Sopenharmony_ci}
60c72fcc34Sopenharmony_ci
61c72fcc34Sopenharmony_ciint tplg_build_ops_object(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
62c72fcc34Sopenharmony_ci			      snd_config_t *parent)
63c72fcc34Sopenharmony_ci{
64c72fcc34Sopenharmony_ci	return tplg_build_base_object(tplg_pp, obj_cfg, parent, false);
65c72fcc34Sopenharmony_ci}
66c72fcc34Sopenharmony_ci
67c72fcc34Sopenharmony_ciint tplg_build_channel_object(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
68c72fcc34Sopenharmony_ci			      snd_config_t *parent)
69c72fcc34Sopenharmony_ci{
70c72fcc34Sopenharmony_ci	return tplg_build_base_object(tplg_pp, obj_cfg, parent, false);
71c72fcc34Sopenharmony_ci}
72c72fcc34Sopenharmony_ci
73c72fcc34Sopenharmony_ciint tplg_build_text_object(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
74c72fcc34Sopenharmony_ci			   snd_config_t *parent)
75c72fcc34Sopenharmony_ci{
76c72fcc34Sopenharmony_ci	snd_config_t *cfg;
77c72fcc34Sopenharmony_ci	const char *name;
78c72fcc34Sopenharmony_ci	int ret;
79c72fcc34Sopenharmony_ci
80c72fcc34Sopenharmony_ci	cfg = tplg_object_get_instance_config(tplg_pp, obj_cfg);
81c72fcc34Sopenharmony_ci
82c72fcc34Sopenharmony_ci	name = tplg_object_get_name(tplg_pp, cfg);
83c72fcc34Sopenharmony_ci	if (!name)
84c72fcc34Sopenharmony_ci		return -EINVAL;
85c72fcc34Sopenharmony_ci
86c72fcc34Sopenharmony_ci	ret = tplg_build_object_from_template(tplg_pp, obj_cfg, &cfg, NULL, false);
87c72fcc34Sopenharmony_ci	if (ret < 0)
88c72fcc34Sopenharmony_ci		return ret;
89c72fcc34Sopenharmony_ci
90c72fcc34Sopenharmony_ci	return tplg_parent_update(tplg_pp, parent, "texts", name);
91c72fcc34Sopenharmony_ci}
92c72fcc34Sopenharmony_ci
93c72fcc34Sopenharmony_ciint tplg_build_tlv_object(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
94c72fcc34Sopenharmony_ci			      snd_config_t *parent)
95c72fcc34Sopenharmony_ci{
96c72fcc34Sopenharmony_ci	snd_config_t *cfg;
97c72fcc34Sopenharmony_ci	const char *name;
98c72fcc34Sopenharmony_ci	int ret;
99c72fcc34Sopenharmony_ci
100c72fcc34Sopenharmony_ci	cfg = tplg_object_get_instance_config(tplg_pp, obj_cfg);
101c72fcc34Sopenharmony_ci
102c72fcc34Sopenharmony_ci	name = tplg_object_get_name(tplg_pp, cfg);
103c72fcc34Sopenharmony_ci	if (!name)
104c72fcc34Sopenharmony_ci		return -EINVAL;
105c72fcc34Sopenharmony_ci
106c72fcc34Sopenharmony_ci	ret = tplg_build_object_from_template(tplg_pp, obj_cfg, &cfg, NULL, false);
107c72fcc34Sopenharmony_ci	if (ret < 0)
108c72fcc34Sopenharmony_ci		return ret;
109c72fcc34Sopenharmony_ci
110c72fcc34Sopenharmony_ci	return tplg_parent_update(tplg_pp, parent, "tlv", name);
111c72fcc34Sopenharmony_ci}
112c72fcc34Sopenharmony_ci
113c72fcc34Sopenharmony_cistatic int tplg_build_control(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
114c72fcc34Sopenharmony_ci			      snd_config_t *parent, char *type)
115c72fcc34Sopenharmony_ci{
116c72fcc34Sopenharmony_ci	snd_config_t *cfg, *obj;
117c72fcc34Sopenharmony_ci	const char *name;
118c72fcc34Sopenharmony_ci	int ret;
119c72fcc34Sopenharmony_ci
120c72fcc34Sopenharmony_ci	obj = tplg_object_get_instance_config(tplg_pp, obj_cfg);
121c72fcc34Sopenharmony_ci
122c72fcc34Sopenharmony_ci	/* get control name */
123c72fcc34Sopenharmony_ci	ret = snd_config_search(obj, "name", &cfg);
124c72fcc34Sopenharmony_ci	if (ret < 0)
125c72fcc34Sopenharmony_ci		return 0;
126c72fcc34Sopenharmony_ci
127c72fcc34Sopenharmony_ci	ret = snd_config_get_string(cfg, &name);
128c72fcc34Sopenharmony_ci	if (ret < 0)
129c72fcc34Sopenharmony_ci		return ret;
130c72fcc34Sopenharmony_ci
131c72fcc34Sopenharmony_ci	ret = tplg_build_object_from_template(tplg_pp, obj_cfg, &cfg, NULL, false);
132c72fcc34Sopenharmony_ci	if (ret < 0)
133c72fcc34Sopenharmony_ci		return ret;
134c72fcc34Sopenharmony_ci
135c72fcc34Sopenharmony_ci	ret = tplg_add_object_data(tplg_pp, obj_cfg, cfg, NULL);
136c72fcc34Sopenharmony_ci	if (ret < 0)
137c72fcc34Sopenharmony_ci		SNDERR("Failed to add data section for %s\n", name);
138c72fcc34Sopenharmony_ci
139c72fcc34Sopenharmony_ci	return tplg_parent_update(tplg_pp, parent, type, name);
140c72fcc34Sopenharmony_ci}
141c72fcc34Sopenharmony_ci
142c72fcc34Sopenharmony_ciint tplg_build_mixer_control(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
143c72fcc34Sopenharmony_ci			      snd_config_t *parent)
144c72fcc34Sopenharmony_ci{
145c72fcc34Sopenharmony_ci	return tplg_build_control(tplg_pp, obj_cfg, parent, "mixer");
146c72fcc34Sopenharmony_ci}
147c72fcc34Sopenharmony_ci
148c72fcc34Sopenharmony_ciint tplg_build_bytes_control(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
149c72fcc34Sopenharmony_ci			      snd_config_t *parent)
150c72fcc34Sopenharmony_ci{
151c72fcc34Sopenharmony_ci	return tplg_build_control(tplg_pp, obj_cfg, parent, "bytes");
152c72fcc34Sopenharmony_ci}
153c72fcc34Sopenharmony_ci
154c72fcc34Sopenharmony_ciint tplg_build_enum_control(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
155c72fcc34Sopenharmony_ci			     snd_config_t *parent)
156c72fcc34Sopenharmony_ci{
157c72fcc34Sopenharmony_ci	return tplg_build_control(tplg_pp, obj_cfg, parent, "enum");
158c72fcc34Sopenharmony_ci}
159c72fcc34Sopenharmony_ci
160c72fcc34Sopenharmony_ci/*
161c72fcc34Sopenharmony_ci * Widget names for pipeline endpoints can be of the following type:
162c72fcc34Sopenharmony_ci * "class.<constructor args separated by .> ex: pga.0.1, buffer.1.1 etc
163c72fcc34Sopenharmony_ci * Optionally, the index argument for a widget can be omitted and will be substituted with
164c72fcc34Sopenharmony_ci * the index from the route: ex: pga..0, host..playback etc
165c72fcc34Sopenharmony_ci */
166c72fcc34Sopenharmony_cistatic int tplg_pp_get_widget_name(struct tplg_pre_processor *tplg_pp,
167c72fcc34Sopenharmony_ci				      const char *string, long index, char **widget)
168c72fcc34Sopenharmony_ci{
169c72fcc34Sopenharmony_ci	snd_config_iterator_t i, next;
170c72fcc34Sopenharmony_ci	snd_config_t *temp_cfg, *child, *class_cfg, *n;
171c72fcc34Sopenharmony_ci	char *class_name, *args, *widget_name;
172c72fcc34Sopenharmony_ci	int ret;
173c72fcc34Sopenharmony_ci
174c72fcc34Sopenharmony_ci	/* get class name */
175c72fcc34Sopenharmony_ci	args = strchr(string, '.');
176c72fcc34Sopenharmony_ci	if (!args) {
177c72fcc34Sopenharmony_ci		SNDERR("Error getting class name for %s\n", string);
178c72fcc34Sopenharmony_ci		return -EINVAL;
179c72fcc34Sopenharmony_ci	}
180c72fcc34Sopenharmony_ci
181c72fcc34Sopenharmony_ci	class_name = calloc(1, strlen(string) - strlen(args) + 1);
182c72fcc34Sopenharmony_ci	if (!class_name)
183c72fcc34Sopenharmony_ci		return -ENOMEM;
184c72fcc34Sopenharmony_ci
185c72fcc34Sopenharmony_ci	snprintf(class_name, strlen(string) - strlen(args) + 1, "%s", string);
186c72fcc34Sopenharmony_ci
187c72fcc34Sopenharmony_ci	/* create config with Widget class type */
188c72fcc34Sopenharmony_ci	ret = snd_config_make(&temp_cfg, "Widget", SND_CONFIG_TYPE_COMPOUND);
189c72fcc34Sopenharmony_ci	if (ret < 0) {
190c72fcc34Sopenharmony_ci		free(class_name);
191c72fcc34Sopenharmony_ci		return ret;
192c72fcc34Sopenharmony_ci	}
193c72fcc34Sopenharmony_ci
194c72fcc34Sopenharmony_ci	/* create config with class name and add it to the Widget config */
195c72fcc34Sopenharmony_ci	ret = tplg_config_make_add(&child, class_name, SND_CONFIG_TYPE_COMPOUND, temp_cfg);
196c72fcc34Sopenharmony_ci	if (ret < 0) {
197c72fcc34Sopenharmony_ci		free(class_name);
198c72fcc34Sopenharmony_ci		return ret;
199c72fcc34Sopenharmony_ci	}
200c72fcc34Sopenharmony_ci
201c72fcc34Sopenharmony_ci	/* get class definition for widget */
202c72fcc34Sopenharmony_ci	class_cfg = tplg_class_lookup(tplg_pp, temp_cfg);
203c72fcc34Sopenharmony_ci	snd_config_delete(temp_cfg);
204c72fcc34Sopenharmony_ci	if (!class_cfg) {
205c72fcc34Sopenharmony_ci		free(class_name);
206c72fcc34Sopenharmony_ci		return -EINVAL;
207c72fcc34Sopenharmony_ci	}
208c72fcc34Sopenharmony_ci
209c72fcc34Sopenharmony_ci	/* get constructor for class */
210c72fcc34Sopenharmony_ci	ret = snd_config_search(class_cfg, "attributes.constructor", &temp_cfg);
211c72fcc34Sopenharmony_ci	if (ret < 0) {
212c72fcc34Sopenharmony_ci		SNDERR("No arguments in class for widget %s\n", string);
213c72fcc34Sopenharmony_ci		free(class_name);
214c72fcc34Sopenharmony_ci		return ret;
215c72fcc34Sopenharmony_ci	}
216c72fcc34Sopenharmony_ci
217c72fcc34Sopenharmony_ci	widget_name = strdup(class_name);
218c72fcc34Sopenharmony_ci	free(class_name);
219c72fcc34Sopenharmony_ci	if (!widget_name)
220c72fcc34Sopenharmony_ci		return -ENOMEM;
221c72fcc34Sopenharmony_ci
222c72fcc34Sopenharmony_ci	/* construct widget name using the constructor argument values */
223c72fcc34Sopenharmony_ci	snd_config_for_each(i, next, temp_cfg) {
224c72fcc34Sopenharmony_ci		const char *id;
225c72fcc34Sopenharmony_ci		char *arg, *remaining, *temp;
226c72fcc34Sopenharmony_ci
227c72fcc34Sopenharmony_ci		n = snd_config_iterator_entry(i);
228c72fcc34Sopenharmony_ci		if (snd_config_get_string(n, &id) < 0)
229c72fcc34Sopenharmony_ci			continue;
230c72fcc34Sopenharmony_ci
231c72fcc34Sopenharmony_ci		if (!args) {
232c72fcc34Sopenharmony_ci			SNDERR("insufficient arugments for widget %s\n", string);
233c72fcc34Sopenharmony_ci			ret = -EINVAL;
234c72fcc34Sopenharmony_ci			goto err;
235c72fcc34Sopenharmony_ci		}
236c72fcc34Sopenharmony_ci
237c72fcc34Sopenharmony_ci		remaining = strchr(args + 1, '.');
238c72fcc34Sopenharmony_ci		if (remaining) {
239c72fcc34Sopenharmony_ci			arg = calloc(1, strlen(args + 1) - strlen(remaining) + 1);
240c72fcc34Sopenharmony_ci			if (!arg) {
241c72fcc34Sopenharmony_ci				ret = -ENOMEM;
242c72fcc34Sopenharmony_ci				goto err;
243c72fcc34Sopenharmony_ci			}
244c72fcc34Sopenharmony_ci			snprintf(arg, strlen(args + 1) - strlen(remaining) + 1, "%s", args + 1);
245c72fcc34Sopenharmony_ci		} else {
246c72fcc34Sopenharmony_ci			arg = calloc(1, strlen(args + 1) + 1);
247c72fcc34Sopenharmony_ci			if (!arg) {
248c72fcc34Sopenharmony_ci				ret = -ENOMEM;
249c72fcc34Sopenharmony_ci				goto err;
250c72fcc34Sopenharmony_ci			}
251c72fcc34Sopenharmony_ci
252c72fcc34Sopenharmony_ci			snprintf(arg, strlen(args + 1) + 1, "%s", args + 1);
253c72fcc34Sopenharmony_ci		}
254c72fcc34Sopenharmony_ci
255c72fcc34Sopenharmony_ci		/* if no index provided, substitue with route index */
256c72fcc34Sopenharmony_ci		if (!strcmp(arg, "") && !strcmp(id, "index")) {
257c72fcc34Sopenharmony_ci			free(arg);
258c72fcc34Sopenharmony_ci			arg = tplg_snprintf("%ld", index);
259c72fcc34Sopenharmony_ci			if (!arg) {
260c72fcc34Sopenharmony_ci				ret = -ENOMEM;
261c72fcc34Sopenharmony_ci				free(arg);
262c72fcc34Sopenharmony_ci				goto err;
263c72fcc34Sopenharmony_ci			}
264c72fcc34Sopenharmony_ci		}
265c72fcc34Sopenharmony_ci
266c72fcc34Sopenharmony_ci		temp = tplg_snprintf("%s.%s", widget_name, arg);
267c72fcc34Sopenharmony_ci		if (!temp) {
268c72fcc34Sopenharmony_ci			ret = -ENOMEM;
269c72fcc34Sopenharmony_ci			free(arg);
270c72fcc34Sopenharmony_ci			goto err;
271c72fcc34Sopenharmony_ci		}
272c72fcc34Sopenharmony_ci
273c72fcc34Sopenharmony_ci		free(widget_name);
274c72fcc34Sopenharmony_ci		widget_name = temp;
275c72fcc34Sopenharmony_ci		free(arg);
276c72fcc34Sopenharmony_ci		if (remaining)
277c72fcc34Sopenharmony_ci			args = remaining;
278c72fcc34Sopenharmony_ci		else
279c72fcc34Sopenharmony_ci			args = NULL;
280c72fcc34Sopenharmony_ci	}
281c72fcc34Sopenharmony_ci
282c72fcc34Sopenharmony_ci	*widget = widget_name;
283c72fcc34Sopenharmony_ci	return 0;
284c72fcc34Sopenharmony_ci
285c72fcc34Sopenharmony_cierr:
286c72fcc34Sopenharmony_ci	free(widget_name);
287c72fcc34Sopenharmony_ci	return ret;
288c72fcc34Sopenharmony_ci}
289c72fcc34Sopenharmony_ci
290c72fcc34Sopenharmony_ciint tplg_build_dapm_route_object(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
291c72fcc34Sopenharmony_ci			      snd_config_t *parent)
292c72fcc34Sopenharmony_ci{
293c72fcc34Sopenharmony_ci	snd_config_t *top, *obj, *cfg, *route, *child, *parent_obj;
294c72fcc34Sopenharmony_ci	const char *name, *wname;
295c72fcc34Sopenharmony_ci	const char *parent_name = "Endpoint";
296c72fcc34Sopenharmony_ci	char *src_widget_name, *sink_widget_name, *line_str, *route_name;
297c72fcc34Sopenharmony_ci	const char *control = "";
298c72fcc34Sopenharmony_ci	long index = 0;
299c72fcc34Sopenharmony_ci	int ret;
300c72fcc34Sopenharmony_ci
301c72fcc34Sopenharmony_ci	obj = tplg_object_get_instance_config(tplg_pp, obj_cfg);
302c72fcc34Sopenharmony_ci
303c72fcc34Sopenharmony_ci	ret = snd_config_get_id(obj, &name);
304c72fcc34Sopenharmony_ci	if (ret < 0)
305c72fcc34Sopenharmony_ci		return -EINVAL;
306c72fcc34Sopenharmony_ci
307c72fcc34Sopenharmony_ci	/* endpoint connections at the top-level conf have no parent */
308c72fcc34Sopenharmony_ci	if (parent) {
309c72fcc34Sopenharmony_ci		parent_obj = tplg_object_get_instance_config(tplg_pp, parent);
310c72fcc34Sopenharmony_ci
311c72fcc34Sopenharmony_ci		ret = snd_config_get_id(parent_obj, &parent_name);
312c72fcc34Sopenharmony_ci		if (ret < 0)
313c72fcc34Sopenharmony_ci			return -EINVAL;
314c72fcc34Sopenharmony_ci	}
315c72fcc34Sopenharmony_ci
316c72fcc34Sopenharmony_ci	tplg_pp_debug("Building DAPM route object: '%s' ...", name);
317c72fcc34Sopenharmony_ci
318c72fcc34Sopenharmony_ci	ret = snd_config_search(tplg_pp->output_cfg, "SectionGraph", &top);
319c72fcc34Sopenharmony_ci	if (ret < 0) {
320c72fcc34Sopenharmony_ci		ret = tplg_config_make_add(&top, "SectionGraph",
321c72fcc34Sopenharmony_ci					  SND_CONFIG_TYPE_COMPOUND, tplg_pp->output_cfg);
322c72fcc34Sopenharmony_ci		if (ret < 0) {
323c72fcc34Sopenharmony_ci			SNDERR("Error creating 'SectionGraph' config\n");
324c72fcc34Sopenharmony_ci			return ret;
325c72fcc34Sopenharmony_ci		}
326c72fcc34Sopenharmony_ci	}
327c72fcc34Sopenharmony_ci
328c72fcc34Sopenharmony_ci	/* get route index */
329c72fcc34Sopenharmony_ci	ret = snd_config_search(obj, "index", &cfg);
330c72fcc34Sopenharmony_ci	if (ret >= 0) {
331c72fcc34Sopenharmony_ci		ret = snd_config_get_integer(cfg, &index);
332c72fcc34Sopenharmony_ci		if (ret < 0) {
333c72fcc34Sopenharmony_ci			SNDERR("Invalid index route %s\n", name);
334c72fcc34Sopenharmony_ci			return ret;
335c72fcc34Sopenharmony_ci		}
336c72fcc34Sopenharmony_ci	}
337c72fcc34Sopenharmony_ci
338c72fcc34Sopenharmony_ci	/* get source widget name */
339c72fcc34Sopenharmony_ci	ret = snd_config_search(obj, "source", &cfg);
340c72fcc34Sopenharmony_ci	if (ret < 0) {
341c72fcc34Sopenharmony_ci		SNDERR("No source for route %s\n", name);
342c72fcc34Sopenharmony_ci		return ret;
343c72fcc34Sopenharmony_ci	}
344c72fcc34Sopenharmony_ci
345c72fcc34Sopenharmony_ci	ret = snd_config_get_string(cfg, &wname);
346c72fcc34Sopenharmony_ci	if (ret < 0) {
347c72fcc34Sopenharmony_ci		SNDERR("Invalid name for source in route %s\n", name);
348c72fcc34Sopenharmony_ci		return ret;
349c72fcc34Sopenharmony_ci	}
350c72fcc34Sopenharmony_ci
351c72fcc34Sopenharmony_ci	ret = tplg_pp_get_widget_name(tplg_pp, wname, index, &src_widget_name);
352c72fcc34Sopenharmony_ci	if (ret < 0) {
353c72fcc34Sopenharmony_ci		SNDERR("error getting widget name for %s\n", wname);
354c72fcc34Sopenharmony_ci		return ret;
355c72fcc34Sopenharmony_ci	}
356c72fcc34Sopenharmony_ci
357c72fcc34Sopenharmony_ci	/* get sink widget name */
358c72fcc34Sopenharmony_ci	ret = snd_config_search(obj, "sink", &cfg);
359c72fcc34Sopenharmony_ci	if (ret < 0) {
360c72fcc34Sopenharmony_ci		SNDERR("No sink for route %s\n", name);
361c72fcc34Sopenharmony_ci		free(src_widget_name);
362c72fcc34Sopenharmony_ci		return ret;
363c72fcc34Sopenharmony_ci	}
364c72fcc34Sopenharmony_ci
365c72fcc34Sopenharmony_ci	ret = snd_config_get_string(cfg, &wname);
366c72fcc34Sopenharmony_ci	if (ret < 0) {
367c72fcc34Sopenharmony_ci		SNDERR("Invalid name for sink in route %s\n", name);
368c72fcc34Sopenharmony_ci		free(src_widget_name);
369c72fcc34Sopenharmony_ci		return ret;
370c72fcc34Sopenharmony_ci	}
371c72fcc34Sopenharmony_ci
372c72fcc34Sopenharmony_ci	ret = tplg_pp_get_widget_name(tplg_pp, wname, index, &sink_widget_name);
373c72fcc34Sopenharmony_ci	if (ret < 0) {
374c72fcc34Sopenharmony_ci		SNDERR("error getting widget name for %s\n", wname);
375c72fcc34Sopenharmony_ci		free(src_widget_name);
376c72fcc34Sopenharmony_ci		return ret;
377c72fcc34Sopenharmony_ci	}
378c72fcc34Sopenharmony_ci
379c72fcc34Sopenharmony_ci	/* get control name */
380c72fcc34Sopenharmony_ci	ret = snd_config_search(obj, "control", &cfg);
381c72fcc34Sopenharmony_ci	if (ret >= 0) {
382c72fcc34Sopenharmony_ci		ret = snd_config_get_string(cfg, &control);
383c72fcc34Sopenharmony_ci		if (ret < 0) {
384c72fcc34Sopenharmony_ci			SNDERR("Invalid control name for route %s\n", name);
385c72fcc34Sopenharmony_ci			goto err;
386c72fcc34Sopenharmony_ci		}
387c72fcc34Sopenharmony_ci	}
388c72fcc34Sopenharmony_ci
389c72fcc34Sopenharmony_ci	/* add route */
390c72fcc34Sopenharmony_ci	route_name = tplg_snprintf("%s.%s", parent_name, name);
391c72fcc34Sopenharmony_ci	if (!route_name) {
392c72fcc34Sopenharmony_ci		ret = -ENOMEM;
393c72fcc34Sopenharmony_ci		goto err;
394c72fcc34Sopenharmony_ci	}
395c72fcc34Sopenharmony_ci
396c72fcc34Sopenharmony_ci	ret = snd_config_make(&route, route_name, SND_CONFIG_TYPE_COMPOUND);
397c72fcc34Sopenharmony_ci	free(route_name);
398c72fcc34Sopenharmony_ci	if (ret < 0) {
399c72fcc34Sopenharmony_ci		SNDERR("Error creating route config for %s %d\n", name, ret);
400c72fcc34Sopenharmony_ci		goto err;
401c72fcc34Sopenharmony_ci	}
402c72fcc34Sopenharmony_ci
403c72fcc34Sopenharmony_ci	ret = snd_config_add(top, route);
404c72fcc34Sopenharmony_ci	if (ret < 0) {
405c72fcc34Sopenharmony_ci		SNDERR("Error adding route config for %s %d\n", name, ret);
406c72fcc34Sopenharmony_ci		goto err;
407c72fcc34Sopenharmony_ci	}
408c72fcc34Sopenharmony_ci
409c72fcc34Sopenharmony_ci	/* add index */
410c72fcc34Sopenharmony_ci	ret = tplg_config_make_add(&child, "index", SND_CONFIG_TYPE_INTEGER, route);
411c72fcc34Sopenharmony_ci	if (ret < 0) {
412c72fcc34Sopenharmony_ci		SNDERR("Error creating index config for %s\n", name);
413c72fcc34Sopenharmony_ci		goto err;
414c72fcc34Sopenharmony_ci	}
415c72fcc34Sopenharmony_ci
416c72fcc34Sopenharmony_ci	ret = snd_config_set_integer(child, index);
417c72fcc34Sopenharmony_ci	if (ret < 0) {
418c72fcc34Sopenharmony_ci		SNDERR("Error setting index config for %s\n", name);
419c72fcc34Sopenharmony_ci		goto err;
420c72fcc34Sopenharmony_ci	}
421c72fcc34Sopenharmony_ci
422c72fcc34Sopenharmony_ci	/* add lines */
423c72fcc34Sopenharmony_ci	ret = tplg_config_make_add(&cfg, "lines", SND_CONFIG_TYPE_COMPOUND, route);
424c72fcc34Sopenharmony_ci	if (ret < 0) {
425c72fcc34Sopenharmony_ci		SNDERR("Error creating lines config for %s\n", name);
426c72fcc34Sopenharmony_ci		goto err;
427c72fcc34Sopenharmony_ci	}
428c72fcc34Sopenharmony_ci
429c72fcc34Sopenharmony_ci	/* add route string */
430c72fcc34Sopenharmony_ci	ret = tplg_config_make_add(&child, "0", SND_CONFIG_TYPE_STRING, cfg);
431c72fcc34Sopenharmony_ci	if (ret < 0) {
432c72fcc34Sopenharmony_ci		SNDERR("Error creating lines config for %s\n", name);
433c72fcc34Sopenharmony_ci		goto err;
434c72fcc34Sopenharmony_ci	}
435c72fcc34Sopenharmony_ci
436c72fcc34Sopenharmony_ci	line_str = tplg_snprintf("%s, %s, %s", sink_widget_name, control, src_widget_name);
437c72fcc34Sopenharmony_ci	if (!line_str) {
438c72fcc34Sopenharmony_ci		ret = -ENOMEM;
439c72fcc34Sopenharmony_ci		goto err;
440c72fcc34Sopenharmony_ci	}
441c72fcc34Sopenharmony_ci
442c72fcc34Sopenharmony_ci	/* set the line string */
443c72fcc34Sopenharmony_ci	ret = snd_config_set_string(child, line_str);
444c72fcc34Sopenharmony_ci	free(line_str);
445c72fcc34Sopenharmony_ci	if (ret < 0)
446c72fcc34Sopenharmony_ci		SNDERR("Error creating lines config for %s\n", name);
447c72fcc34Sopenharmony_cierr:
448c72fcc34Sopenharmony_ci	free(src_widget_name);
449c72fcc34Sopenharmony_ci	free(sink_widget_name);
450c72fcc34Sopenharmony_ci	return ret;
451c72fcc34Sopenharmony_ci}
452