Blame src/topology/dapm.c

Packit 4a16fb
/*
Packit 4a16fb
  Copyright(c) 2014-2015 Intel Corporation
Packit 4a16fb
  All rights reserved.
Packit 4a16fb
Packit 4a16fb
  This library is free software; you can redistribute it and/or modify
Packit 4a16fb
  it under the terms of the GNU Lesser General Public License as
Packit 4a16fb
  published by the Free Software Foundation; either version 2.1 of
Packit 4a16fb
  the License, or (at your option) any later version.
Packit 4a16fb
Packit 4a16fb
  This program is distributed in the hope that it will be useful,
Packit 4a16fb
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 4a16fb
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 4a16fb
  GNU Lesser General Public License for more details.
Packit 4a16fb
Packit 4a16fb
  Authors: Mengdong Lin <mengdong.lin@intel.com>
Packit 4a16fb
           Yao Jin <yao.jin@intel.com>
Packit 4a16fb
           Liam Girdwood <liam.r.girdwood@linux.intel.com>
Packit 4a16fb
*/
Packit 4a16fb
Packit 4a16fb
#include "list.h"
Packit 4a16fb
#include "tplg_local.h"
Packit 4a16fb
Packit 4a16fb
/* mapping of widget text names to types */
Packit 4a16fb
static const struct map_elem widget_map[] = {
Packit 4a16fb
	{"input", SND_SOC_TPLG_DAPM_INPUT},
Packit 4a16fb
	{"output", SND_SOC_TPLG_DAPM_OUTPUT},
Packit 4a16fb
	{"mux", SND_SOC_TPLG_DAPM_MUX},
Packit 4a16fb
	{"mixer", SND_SOC_TPLG_DAPM_MIXER},
Packit 4a16fb
	{"pga", SND_SOC_TPLG_DAPM_PGA},
Packit 4a16fb
	{"out_drv", SND_SOC_TPLG_DAPM_OUT_DRV},
Packit 4a16fb
	{"adc", SND_SOC_TPLG_DAPM_ADC},
Packit 4a16fb
	{"dac", SND_SOC_TPLG_DAPM_DAC},
Packit 4a16fb
	{"switch", SND_SOC_TPLG_DAPM_SWITCH},
Packit 4a16fb
	{"pre", SND_SOC_TPLG_DAPM_PRE},
Packit 4a16fb
	{"post", SND_SOC_TPLG_DAPM_POST},
Packit 4a16fb
	{"aif_in", SND_SOC_TPLG_DAPM_AIF_IN},
Packit 4a16fb
	{"aif_out", SND_SOC_TPLG_DAPM_AIF_OUT},
Packit 4a16fb
	{"dai_in", SND_SOC_TPLG_DAPM_DAI_IN},
Packit 4a16fb
	{"dai_out", SND_SOC_TPLG_DAPM_DAI_OUT},
Packit 4a16fb
	{"dai_link", SND_SOC_TPLG_DAPM_DAI_LINK},
Packit 4a16fb
	{"buffer", SND_SOC_TPLG_DAPM_BUFFER},
Packit 4a16fb
	{"scheduler", SND_SOC_TPLG_DAPM_SCHEDULER},
Packit 4a16fb
	{"effect", SND_SOC_TPLG_DAPM_EFFECT},
Packit 4a16fb
	{"siggen", SND_SOC_TPLG_DAPM_SIGGEN},
Packit 4a16fb
	{"src", SND_SOC_TPLG_DAPM_SRC},
Packit 4a16fb
	{"asrc", SND_SOC_TPLG_DAPM_ASRC},
Packit 4a16fb
	{"encoder", SND_SOC_TPLG_DAPM_ENCODER},
Packit 4a16fb
	{"decoder", SND_SOC_TPLG_DAPM_DECODER},
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
static int lookup_widget(const char *w)
Packit 4a16fb
{
Packit 4a16fb
	unsigned int i;
Packit 4a16fb
Packit 4a16fb
	for (i = 0; i < ARRAY_SIZE(widget_map); i++) {
Packit 4a16fb
		if (strcmp(widget_map[i].name, w) == 0)
Packit 4a16fb
			return widget_map[i].id;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return -EINVAL;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int tplg_parse_dapm_mixers(snd_config_t *cfg, struct tplg_elem *elem)
Packit 4a16fb
{
Packit 4a16fb
	snd_config_iterator_t i, next;
Packit 4a16fb
	snd_config_t *n;
Packit 4a16fb
	const char *value = NULL;
Packit 4a16fb
Packit 4a16fb
	tplg_dbg(" DAPM Mixer Controls: %s\n", elem->id);
Packit 4a16fb
Packit 4a16fb
	snd_config_for_each(i, next, cfg) {
Packit 4a16fb
		n = snd_config_iterator_entry(i);
Packit 4a16fb
Packit 4a16fb
		/* get value */
Packit 4a16fb
		if (snd_config_get_string(n, &value) < 0)
Packit 4a16fb
			continue;
Packit 4a16fb
Packit 4a16fb
		tplg_ref_add(elem, SND_TPLG_TYPE_MIXER, value);
Packit 4a16fb
		tplg_dbg("\t\t %s\n", value);
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int tplg_parse_dapm_enums(snd_config_t *cfg, struct tplg_elem *elem)
Packit 4a16fb
{
Packit 4a16fb
	snd_config_iterator_t i, next;
Packit 4a16fb
	snd_config_t *n;
Packit 4a16fb
	const char *value = NULL;
Packit 4a16fb
Packit 4a16fb
	tplg_dbg(" DAPM Enum Controls: %s\n", elem->id);
Packit 4a16fb
Packit 4a16fb
	snd_config_for_each(i, next, cfg) {
Packit 4a16fb
		n = snd_config_iterator_entry(i);
Packit 4a16fb
Packit 4a16fb
		/* get value */
Packit 4a16fb
		if (snd_config_get_string(n, &value) < 0)
Packit 4a16fb
			continue;
Packit 4a16fb
Packit 4a16fb
		tplg_ref_add(elem, SND_TPLG_TYPE_ENUM, value);
Packit 4a16fb
		tplg_dbg("\t\t %s\n", value);
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int tplg_parse_dapm_bytes(snd_config_t *cfg, struct tplg_elem *elem)
Packit 4a16fb
{
Packit 4a16fb
	snd_config_iterator_t i, next;
Packit 4a16fb
	snd_config_t *n;
Packit 4a16fb
	const char *value = NULL;
Packit 4a16fb
Packit 4a16fb
	tplg_dbg(" DAPM Bytes Controls: %s\n", elem->id);
Packit 4a16fb
Packit 4a16fb
	snd_config_for_each(i, next, cfg) {
Packit 4a16fb
		n = snd_config_iterator_entry(i);
Packit 4a16fb
Packit 4a16fb
		/* get value */
Packit 4a16fb
		if (snd_config_get_string(n, &value) < 0)
Packit 4a16fb
			continue;
Packit 4a16fb
Packit 4a16fb
		tplg_ref_add(elem, SND_TPLG_TYPE_BYTES, value);
Packit 4a16fb
		tplg_dbg("\t\t %s\n", value);
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* move referenced controls to the widget */
Packit 4a16fb
static int copy_dapm_control(struct tplg_elem *elem, struct tplg_elem *ref)
Packit 4a16fb
{
Packit 4a16fb
	struct snd_soc_tplg_dapm_widget *widget = elem->widget;
Packit 4a16fb
Packit 4a16fb
	tplg_dbg("Control '%s' used by '%s'\n", ref->id, elem->id);
Packit 4a16fb
	tplg_dbg("\tparent size: %d + %d -> %d, priv size -> %d\n",
Packit 4a16fb
		elem->size, ref->size, elem->size + ref->size,
Packit 4a16fb
		widget->priv.size);
Packit 4a16fb
Packit 4a16fb
	widget = realloc(widget, elem->size + ref->size);
Packit 4a16fb
	if (!widget)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
Packit 4a16fb
	elem->widget = widget;
Packit 4a16fb
Packit 4a16fb
	/* append the control to the end of the widget */
Packit 4a16fb
	memcpy((void*)widget + elem->size, ref->obj, ref->size);
Packit 4a16fb
	elem->size += ref->size;
Packit 4a16fb
Packit 4a16fb
	widget->num_kcontrols++;
Packit 4a16fb
	ref->compound_elem = 1;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* check referenced controls for a widget */
Packit 4a16fb
static int tplg_build_widget(snd_tplg_t *tplg,
Packit 4a16fb
	struct tplg_elem *elem)
Packit 4a16fb
{
Packit 4a16fb
	struct tplg_ref *ref;
Packit 4a16fb
	struct list_head *base, *pos;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
Packit 4a16fb
	base = &elem->ref_list;
Packit 4a16fb
Packit 4a16fb
	/* A widget's private data sits before the embedded controls.
Packit 4a16fb
	 * So merge the private data blocks at first
Packit 4a16fb
	 */
Packit 4a16fb
	 list_for_each(pos, base) {
Packit 4a16fb
		ref = list_entry(pos, struct tplg_ref, list);
Packit 4a16fb
Packit 4a16fb
		if (ref->type != SND_TPLG_TYPE_DATA)
Packit 4a16fb
			continue;
Packit 4a16fb
Packit 4a16fb
		err = tplg_copy_data(tplg, elem, ref);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	/* Merge the embedded controls */
Packit 4a16fb
	list_for_each(pos, base) {
Packit 4a16fb
Packit 4a16fb
		ref = list_entry(pos, struct tplg_ref, list);
Packit 4a16fb
Packit 4a16fb
		switch (ref->type) {
Packit 4a16fb
		case SND_TPLG_TYPE_MIXER:
Packit 4a16fb
			if (!ref->elem)
Packit 4a16fb
				ref->elem = tplg_elem_lookup(&tplg->mixer_list,
Packit 4a16fb
				ref->id, SND_TPLG_TYPE_MIXER, elem->index);
Packit 4a16fb
			if (ref->elem)
Packit 4a16fb
				err = copy_dapm_control(elem, ref->elem);
Packit 4a16fb
			break;
Packit 4a16fb
Packit 4a16fb
		case SND_TPLG_TYPE_ENUM:
Packit 4a16fb
			if (!ref->elem)
Packit 4a16fb
				ref->elem = tplg_elem_lookup(&tplg->enum_list,
Packit 4a16fb
				ref->id, SND_TPLG_TYPE_ENUM, elem->index);
Packit 4a16fb
			if (ref->elem)
Packit 4a16fb
				err = copy_dapm_control(elem, ref->elem);
Packit 4a16fb
			break;
Packit 4a16fb
Packit 4a16fb
		case SND_TPLG_TYPE_BYTES:
Packit 4a16fb
			if (!ref->elem)
Packit 4a16fb
				ref->elem = tplg_elem_lookup(&tplg->bytes_ext_list,
Packit 4a16fb
				ref->id, SND_TPLG_TYPE_BYTES, elem->index);
Packit 4a16fb
			if (ref->elem)
Packit 4a16fb
				err = copy_dapm_control(elem, ref->elem);
Packit 4a16fb
			break;
Packit 4a16fb
Packit 4a16fb
		default:
Packit 4a16fb
			break;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (!ref->elem) {
Packit 4a16fb
			SNDERR("error: cannot find '%s'"
Packit 4a16fb
				" referenced by widget '%s'\n",
Packit 4a16fb
				ref->id, elem->id);
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
int tplg_build_widgets(snd_tplg_t *tplg)
Packit 4a16fb
{
Packit 4a16fb
Packit 4a16fb
	struct list_head *base, *pos;
Packit 4a16fb
	struct tplg_elem *elem;
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	base = &tplg->widget_list;
Packit 4a16fb
	list_for_each(pos, base) {
Packit 4a16fb
Packit 4a16fb
		elem = list_entry(pos, struct tplg_elem, list);
Packit 4a16fb
		if (!elem->widget || elem->type != SND_TPLG_TYPE_DAPM_WIDGET) {
Packit 4a16fb
			SNDERR("error: invalid widget '%s'\n",
Packit 4a16fb
				elem->id);
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		err = tplg_build_widget(tplg, elem);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
Packit 4a16fb
		/* add widget to manifest */
Packit 4a16fb
		tplg->manifest.widget_elems++;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
int tplg_build_routes(snd_tplg_t *tplg)
Packit 4a16fb
{
Packit 4a16fb
	struct list_head *base, *pos;
Packit 4a16fb
	struct tplg_elem *elem;
Packit 4a16fb
	struct snd_soc_tplg_dapm_graph_elem *route;
Packit 4a16fb
Packit 4a16fb
	base = &tplg->route_list;
Packit 4a16fb
Packit 4a16fb
	list_for_each(pos, base) {
Packit 4a16fb
		elem = list_entry(pos, struct tplg_elem, list);
Packit 4a16fb
Packit 4a16fb
		if (!elem->route || elem->type != SND_TPLG_TYPE_DAPM_GRAPH) {
Packit 4a16fb
			SNDERR("error: invalid route '%s'\n",
Packit 4a16fb
				elem->id);
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		route = elem->route;
Packit 4a16fb
		tplg_dbg("\nCheck route: sink '%s', control '%s', source '%s'\n",
Packit 4a16fb
			route->sink, route->control, route->source);
Packit 4a16fb
Packit 4a16fb
		/* validate sink */
Packit 4a16fb
		if (strlen(route->sink) <= 0) {
Packit 4a16fb
			SNDERR("error: no sink\n");
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
Packit 4a16fb
		}
Packit 4a16fb
		if (!tplg_elem_lookup(&tplg->widget_list, route->sink,
Packit 4a16fb
			SND_TPLG_TYPE_DAPM_WIDGET, SND_TPLG_INDEX_ALL)) {
Packit 4a16fb
			SNDERR("warning: undefined sink widget/stream '%s'\n",
Packit 4a16fb
				route->sink);
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		/* validate control name */
Packit 4a16fb
		if (strlen(route->control)) {
Packit 4a16fb
			if (!tplg_elem_lookup(&tplg->mixer_list, route->control,
Packit 4a16fb
					SND_TPLG_TYPE_MIXER, elem->index) &&
Packit 4a16fb
			!tplg_elem_lookup(&tplg->enum_list, route->control,
Packit 4a16fb
					SND_TPLG_TYPE_ENUM, elem->index)) {
Packit 4a16fb
				SNDERR("warning: Undefined mixer/enum control '%s'\n",
Packit 4a16fb
					route->control);
Packit 4a16fb
			}
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		/* validate source */
Packit 4a16fb
		if (strlen(route->source) <= 0) {
Packit 4a16fb
			SNDERR("error: no source\n");
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
Packit 4a16fb
		}
Packit 4a16fb
		if (!tplg_elem_lookup(&tplg->widget_list, route->source,
Packit 4a16fb
			SND_TPLG_TYPE_DAPM_WIDGET, SND_TPLG_INDEX_ALL)) {
Packit 4a16fb
			SNDERR("warning: Undefined source widget/stream '%s'\n",
Packit 4a16fb
				route->source);
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		/* add graph to manifest */
Packit 4a16fb
		tplg->manifest.graph_elems++;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
struct tplg_elem* tplg_elem_new_route(snd_tplg_t *tplg)
Packit 4a16fb
{
Packit 4a16fb
	struct tplg_elem *elem;
Packit 4a16fb
	struct snd_soc_tplg_dapm_graph_elem *line;
Packit 4a16fb
Packit 4a16fb
	elem = tplg_elem_new();
Packit 4a16fb
	if (!elem)
Packit 4a16fb
		return NULL;
Packit 4a16fb
Packit 4a16fb
	list_add_tail(&elem->list, &tplg->route_list);
Packit 4a16fb
	strcpy(elem->id, "line");
Packit 4a16fb
	elem->type = SND_TPLG_TYPE_DAPM_GRAPH;
Packit 4a16fb
	elem->size = sizeof(*line);
Packit 4a16fb
Packit 4a16fb
	line = calloc(1, sizeof(*line));
Packit 4a16fb
	if (!line) {
Packit 4a16fb
		tplg_elem_free(elem);
Packit 4a16fb
		return NULL;
Packit 4a16fb
	}
Packit 4a16fb
	elem->route = line;
Packit 4a16fb
Packit 4a16fb
	return elem;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
#define LINE_SIZE	1024
Packit 4a16fb
Packit 4a16fb
/* line is defined as '"source, control, sink"' */
Packit 4a16fb
static int tplg_parse_line(const char *text,
Packit 4a16fb
	struct snd_soc_tplg_dapm_graph_elem *line)
Packit 4a16fb
{
Packit 4a16fb
	char buf[LINE_SIZE];
Packit 4a16fb
	unsigned int len, i;
Packit 4a16fb
	const char *source = NULL, *sink = NULL, *control = NULL;
Packit 4a16fb
Packit 4a16fb
	snd_strlcpy(buf, text, LINE_SIZE);
Packit 4a16fb
Packit 4a16fb
	len = strlen(buf);
Packit 4a16fb
	if (len <= 2) {
Packit 4a16fb
		SNDERR("error: invalid route \"%s\"\n", buf);
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	/* find first , */
Packit 4a16fb
	for (i = 1; i < len; i++) {
Packit 4a16fb
		if (buf[i] == ',')
Packit 4a16fb
			goto second;
Packit 4a16fb
	}
Packit 4a16fb
	SNDERR("error: invalid route \"%s\"\n", buf);
Packit 4a16fb
	return -EINVAL;
Packit 4a16fb
Packit 4a16fb
second:
Packit 4a16fb
	/* find second , */
Packit 4a16fb
	sink = buf;
Packit 4a16fb
	control = &buf[i + 2];
Packit 4a16fb
	buf[i] = 0;
Packit 4a16fb
Packit 4a16fb
	for (; i < len; i++) {
Packit 4a16fb
		if (buf[i] == ',')
Packit 4a16fb
			goto done;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	SNDERR("error: invalid route \"%s\"\n", buf);
Packit 4a16fb
	return -EINVAL;
Packit 4a16fb
Packit 4a16fb
done:
Packit 4a16fb
	buf[i] = 0;
Packit 4a16fb
	source = &buf[i + 2];
Packit 4a16fb
Packit 4a16fb
	strcpy(line->source, source);
Packit 4a16fb
	strcpy(line->control, control);
Packit 4a16fb
	strcpy(line->sink, sink);
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
Packit 4a16fb
static int tplg_parse_routes(snd_tplg_t *tplg, snd_config_t *cfg, int index)
Packit 4a16fb
{
Packit 4a16fb
	snd_config_iterator_t i, next;
Packit 4a16fb
	snd_config_t *n;
Packit 4a16fb
	struct tplg_elem *elem;
Packit 4a16fb
	struct snd_soc_tplg_dapm_graph_elem *line;
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	snd_config_for_each(i, next, cfg) {
Packit 4a16fb
		const char *val;
Packit 4a16fb
Packit 4a16fb
		n = snd_config_iterator_entry(i);
Packit 4a16fb
		if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
			continue;
Packit 4a16fb
Packit 4a16fb
		elem = tplg_elem_new_route(tplg);
Packit 4a16fb
		if (!elem)
Packit 4a16fb
			return -ENOMEM;
Packit 4a16fb
		elem->index = index;
Packit 4a16fb
		line = elem->route;
Packit 4a16fb
Packit 4a16fb
		err = tplg_parse_line(val, line);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
Packit 4a16fb
		tplg_dbg("route: sink '%s', control '%s', source '%s'\n",
Packit 4a16fb
				line->sink, line->control, line->source);
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
int tplg_parse_dapm_graph(snd_tplg_t *tplg, snd_config_t *cfg,
Packit 4a16fb
	void *private ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	snd_config_iterator_t i, next;
Packit 4a16fb
	snd_config_t *n;
Packit 4a16fb
	int err;
Packit 4a16fb
	const char *graph_id, *val = NULL;
Packit 4a16fb
	int index = -1;
Packit 4a16fb
Packit 4a16fb
	if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
Packit 4a16fb
		SNDERR("error: compound is expected for dapm graph definition\n");
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	snd_config_get_id(cfg, &graph_id);
Packit 4a16fb
Packit 4a16fb
	snd_config_for_each(i, next, cfg) {
Packit 4a16fb
		const char *id;
Packit 4a16fb
Packit 4a16fb
		n = snd_config_iterator_entry(i);
Packit 4a16fb
		if (snd_config_get_id(n, &id) < 0) {
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "index") == 0) {
Packit 4a16fb
			if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
			index = atoi(val);
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "lines") == 0) {
Packit 4a16fb
			if (index < 0) {
Packit 4a16fb
				SNDERR("error: failed to parse dapm graph %s, missing index\n",
Packit 4a16fb
					graph_id);
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
			}
Packit 4a16fb
			err = tplg_parse_routes(tplg, n, index);
Packit 4a16fb
			if (err < 0) {
Packit 4a16fb
				SNDERR("error: failed to parse dapm graph %s\n",
Packit 4a16fb
					graph_id);
Packit 4a16fb
				return err;
Packit 4a16fb
			}
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* DAPM Widget */
Packit 4a16fb
int tplg_parse_dapm_widget(snd_tplg_t *tplg,
Packit 4a16fb
	snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	struct snd_soc_tplg_dapm_widget *widget;
Packit 4a16fb
	struct tplg_elem *elem;
Packit 4a16fb
	snd_config_iterator_t i, next;
Packit 4a16fb
	snd_config_t *n;
Packit 4a16fb
	const char *id, *val = NULL;
Packit 4a16fb
	int widget_type, err;
Packit 4a16fb
Packit 4a16fb
	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_DAPM_WIDGET);
Packit 4a16fb
	if (!elem)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
Packit 4a16fb
	tplg_dbg(" Widget: %s\n", elem->id);
Packit 4a16fb
Packit 4a16fb
	widget = elem->widget;
Packit 4a16fb
	snd_strlcpy(widget->name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit 4a16fb
	widget->size = elem->size;
Packit 4a16fb
Packit 4a16fb
	snd_config_for_each(i, next, cfg) {
Packit 4a16fb
Packit 4a16fb
		n = snd_config_iterator_entry(i);
Packit 4a16fb
		if (snd_config_get_id(n, &id) < 0)
Packit 4a16fb
			continue;
Packit 4a16fb
Packit 4a16fb
		/* skip comments */
Packit 4a16fb
		if (strcmp(id, "comment") == 0)
Packit 4a16fb
			continue;
Packit 4a16fb
		if (id[0] == '#')
Packit 4a16fb
			continue;
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "type") == 0) {
Packit 4a16fb
			if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit 4a16fb
			widget_type = lookup_widget(val);
Packit 4a16fb
			if (widget_type < 0){
Packit 4a16fb
				SNDERR("Widget '%s': Unsupported widget type %s\n",
Packit 4a16fb
					elem->id, val);
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
			}
Packit 4a16fb
Packit 4a16fb
			widget->id = widget_type;
Packit 4a16fb
			tplg_dbg("\t%s: %s\n", id, val);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "stream_name") == 0) {
Packit 4a16fb
			if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit 4a16fb
			snd_strlcpy(widget->sname, val,
Packit 4a16fb
				       SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit 4a16fb
			tplg_dbg("\t%s: %s\n", id, val);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "no_pm") == 0) {
Packit 4a16fb
			if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit 4a16fb
			if (strcmp(val, "true") == 0)
Packit 4a16fb
				widget->reg = -1;
Packit 4a16fb
Packit 4a16fb
			tplg_dbg("\t%s: %s\n", id, val);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "shift") == 0) {
Packit 4a16fb
			if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit 4a16fb
			widget->shift = atoi(val);
Packit 4a16fb
			tplg_dbg("\t%s: %d\n", id, widget->shift);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "reg") == 0) {
Packit 4a16fb
			if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit 4a16fb
			widget->reg = atoi(val);
Packit 4a16fb
			tplg_dbg("\t%s: %d\n", id, widget->reg);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "invert") == 0) {
Packit 4a16fb
			if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit 4a16fb
			widget->invert = atoi(val);
Packit 4a16fb
			tplg_dbg("\t%s: %d\n", id, widget->invert);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "subseq") == 0) {
Packit 4a16fb
			if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit 4a16fb
			widget->subseq= atoi(val);
Packit 4a16fb
			tplg_dbg("\t%s: %d\n", id, widget->subseq);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "event_type") == 0) {
Packit 4a16fb
			if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit 4a16fb
			widget->event_type = atoi(val);
Packit 4a16fb
			tplg_dbg("\t%s: %d\n", id, widget->event_type);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "event_flags") == 0) {
Packit 4a16fb
			if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit 4a16fb
			widget->event_flags = atoi(val);
Packit 4a16fb
			tplg_dbg("\t%s: %d\n", id, widget->event_flags);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "enum") == 0) {
Packit 4a16fb
			err = tplg_parse_dapm_enums(n, elem);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "mixer") == 0) {
Packit 4a16fb
			err = tplg_parse_dapm_mixers(n, elem);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "bytes") == 0) {
Packit 4a16fb
			err = tplg_parse_dapm_bytes(n, elem);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "data") == 0) {
Packit 4a16fb
			err = tplg_parse_data_refs(n, elem);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
int tplg_add_route(snd_tplg_t *tplg, struct snd_tplg_graph_elem *t)
Packit 4a16fb
{
Packit 4a16fb
	struct tplg_elem *elem;
Packit 4a16fb
	struct snd_soc_tplg_dapm_graph_elem *line;
Packit 4a16fb
Packit 4a16fb
	if (!t->src || !t->sink)
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
Packit 4a16fb
	elem = tplg_elem_new_route(tplg);
Packit 4a16fb
	if (!elem)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
Packit 4a16fb
	line = elem->route;
Packit 4a16fb
	snd_strlcpy(line->source, t->src, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit 4a16fb
	if (t->ctl)
Packit 4a16fb
		snd_strlcpy(line->control, t->ctl,
Packit 4a16fb
			SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit 4a16fb
	snd_strlcpy(line->sink, t->sink, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
int tplg_add_graph_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
Packit 4a16fb
{
Packit 4a16fb
	struct snd_tplg_graph_template *gt =  t->graph;
Packit 4a16fb
	int i, ret;
Packit 4a16fb
Packit 4a16fb
	for (i = 0; i < gt->count; i++) {
Packit 4a16fb
		ret = tplg_add_route(tplg, gt->elem + i);
Packit 4a16fb
		if (ret < 0)
Packit 4a16fb
			return ret;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
int tplg_add_widget_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
Packit 4a16fb
{
Packit 4a16fb
	struct snd_tplg_widget_template *wt = t->widget;
Packit 4a16fb
	struct snd_soc_tplg_dapm_widget *w;
Packit 4a16fb
	struct tplg_elem *elem;
Packit 4a16fb
	int i, ret = 0;
Packit 4a16fb
Packit 4a16fb
	tplg_dbg("Widget: %s\n", wt->name);
Packit 4a16fb
Packit 4a16fb
	elem = tplg_elem_new_common(tplg, NULL, wt->name,
Packit 4a16fb
		SND_TPLG_TYPE_DAPM_WIDGET);
Packit 4a16fb
	if (!elem)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
Packit 4a16fb
	/* init new widget */
Packit 4a16fb
	w = elem->widget;
Packit 4a16fb
	w->size = elem->size;
Packit 4a16fb
Packit 4a16fb
	w->id = wt->id;
Packit 4a16fb
	snd_strlcpy(w->name, wt->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit 4a16fb
	if (wt->sname)
Packit 4a16fb
		snd_strlcpy(w->sname, wt->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit 4a16fb
	w->reg = wt->reg;
Packit 4a16fb
	w->shift = wt->shift;
Packit 4a16fb
	w->mask = wt->mask;
Packit 4a16fb
	w->subseq = wt->subseq;
Packit 4a16fb
	w->invert = wt->invert;
Packit 4a16fb
	w->ignore_suspend = wt->ignore_suspend;
Packit 4a16fb
	w->event_flags = wt->event_flags;
Packit 4a16fb
	w->event_type = wt->event_type;
Packit 4a16fb
Packit 4a16fb
	if (wt->priv != NULL) {
Packit 4a16fb
		w = realloc(w,
Packit 4a16fb
			elem->size + wt->priv->size);
Packit 4a16fb
		if (!w) {
Packit 4a16fb
			tplg_elem_free(elem);
Packit 4a16fb
			return -ENOMEM;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		elem->widget = w;
Packit 4a16fb
		elem->size += wt->priv->size;
Packit 4a16fb
Packit 4a16fb
		memcpy(w->priv.data, wt->priv->data,
Packit 4a16fb
			wt->priv->size);
Packit 4a16fb
		w->priv.size = wt->priv->size;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	/* add controls to the widget's reference list */
Packit 4a16fb
	for (i = 0 ; i < wt->num_ctls; i++) {
Packit 4a16fb
		struct snd_tplg_ctl_template *ct = wt->ctl[i];
Packit 4a16fb
		struct tplg_elem *elem_ctl;
Packit 4a16fb
		struct snd_tplg_mixer_template *mt;
Packit 4a16fb
		struct snd_tplg_bytes_template *bt;
Packit 4a16fb
		struct snd_tplg_enum_template *et;
Packit 4a16fb
Packit 4a16fb
		if (!ct) {
Packit 4a16fb
			tplg_elem_free(elem);
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		switch (ct->type) {
Packit 4a16fb
		case SND_SOC_TPLG_TYPE_MIXER:
Packit 4a16fb
			mt = container_of(ct, struct snd_tplg_mixer_template, hdr);
Packit 4a16fb
			ret = tplg_add_mixer(tplg, mt, &elem_ctl);
Packit 4a16fb
			break;
Packit 4a16fb
Packit 4a16fb
		case SND_SOC_TPLG_TYPE_BYTES:
Packit 4a16fb
			bt = container_of(ct, struct snd_tplg_bytes_template, hdr);
Packit 4a16fb
			ret = tplg_add_bytes(tplg, bt, &elem_ctl);
Packit 4a16fb
			break;
Packit 4a16fb
Packit 4a16fb
		case SND_SOC_TPLG_TYPE_ENUM:
Packit 4a16fb
			et = container_of(ct, struct snd_tplg_enum_template, hdr);
Packit 4a16fb
			ret = tplg_add_enum(tplg, et, &elem_ctl);
Packit 4a16fb
			break;
Packit 4a16fb
Packit 4a16fb
		default:
Packit 4a16fb
			SNDERR("error: widget %s: invalid type %d for ctl %d\n",
Packit 4a16fb
				wt->name, ct->type, i);
Packit 4a16fb
			ret = -EINVAL;
Packit 4a16fb
			break;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (ret < 0) {
Packit 4a16fb
			tplg_elem_free(elem);
Packit 4a16fb
			return ret;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		ret = tplg_ref_add_elem(elem, elem_ctl);
Packit 4a16fb
		if (ret < 0) {
Packit 4a16fb
			tplg_elem_free(elem);
Packit 4a16fb
			return ret;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}