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 Service f36a15
static const char *get_widget_name(unsigned int type)
Packit 4a16fb
{
Packit Service f36a15
	unsigned int i;
Packit 4a16fb
Packit Service f36a15
	for (i = 0; i < ARRAY_SIZE(widget_map); i++) {
Packit Service f36a15
		if ((unsigned int)widget_map[i].id == type)
Packit Service f36a15
			return widget_map[i].name;
Packit 4a16fb
	}
Packit 4a16fb
Packit Service f36a15
	return NULL;
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 Service f36a15
	tplg_dbg("Control '%s' used by '%s'", ref->id, elem->id);
Packit Service f36a15
	tplg_dbg("\tparent size: %d + %d -> %d, priv size -> %d",
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 Service f36a15
static int tplg_build_widget(snd_tplg_t *tplg, 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 Service f36a15
	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 Service f36a15
			SNDERR("cannot find '%s' referenced by widget '%s'",
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 Service f36a15
			SNDERR("invalid widget '%s'", 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 Service f36a15
			SNDERR("invalid route '%s'", elem->id);
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		route = elem->route;
Packit Service f36a15
		tplg_dbg("Check route: sink '%s', control '%s', source '%s'",
Packit Service f36a15
			 route->sink, route->control, route->source);
Packit 4a16fb
Packit 4a16fb
		/* validate sink */
Packit 4a16fb
		if (strlen(route->sink) <= 0) {
Packit Service f36a15
			SNDERR("no sink");
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 Service f36a15
			SNDERR("undefined sink widget/stream '%s'", 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 Service f36a15
				SNDERR("undefined mixer/enum control '%s'",
Packit Service f36a15
				       route->control);
Packit 4a16fb
			}
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		/* validate source */
Packit 4a16fb
		if (strlen(route->source) <= 0) {
Packit Service f36a15
			SNDERR("no source");
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 Service f36a15
			SNDERR("undefined source widget/stream '%s'",
Packit Service f36a15
			       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 Service f36a15
struct tplg_elem *tplg_elem_new_route(snd_tplg_t *tplg, int index)
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 Service f36a15
	elem->index = index;
Packit Service f36a15
	if (tplg->dapm_sort)
Packit Service f36a15
		tplg_elem_insert(elem, &tplg->route_list);
Packit Service f36a15
	else
Packit Service f36a15
		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 Service f36a15
/* line is defined as '"sink, control, source"' */
Packit 4a16fb
static int tplg_parse_line(const char *text,
Packit Service f36a15
			   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 Service f36a15
		SNDERR("invalid route \"%s\"", 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 Service f36a15
	SNDERR("invalid route \"%s\"", 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 Service f36a15
	SNDERR("invalid route \"%s\"", 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 Service f36a15
		elem = tplg_elem_new_route(tplg, index);
Packit 4a16fb
		if (!elem)
Packit 4a16fb
			return -ENOMEM;
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 Service f36a15
		tplg_dbg("route: sink '%s', control '%s', source '%s'",
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 Service f36a15
			  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 Service f36a15
	const char *graph_id;
Packit 4a16fb
	int index = -1;
Packit 4a16fb
Packit 4a16fb
	if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
Packit Service f36a15
		SNDERR("compound is expected for dapm graph definition");
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 Service f36a15
			if (tplg_get_integer(n, &index, 0))
Packit Service f36a15
				return -EINVAL;
Packit Service f36a15
			if (index < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "lines") == 0) {
Packit 4a16fb
			if (index < 0) {
Packit Service f36a15
				SNDERR("failed to parse dapm graph %s, missing index",
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 Service f36a15
				SNDERR("failed to parse dapm graph %s",
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 Service f36a15
/* save DAPM graph */
Packit Service f36a15
int tplg_save_dapm_graph(snd_tplg_t *tplg, int index, char **dst, const char *pfx)
Packit Service f36a15
{
Packit Service f36a15
	struct snd_soc_tplg_dapm_graph_elem *route;
Packit Service f36a15
	struct list_head *pos;
Packit Service f36a15
	struct tplg_elem *elem;
Packit Service f36a15
	int err, first, old_index;
Packit Service f36a15
	unsigned block, count;
Packit Service f36a15
	const char *fmt;
Packit Service f36a15
Packit Service f36a15
	old_index = -1;
Packit Service f36a15
	block = 0;
Packit Service f36a15
	count = 0;
Packit Service f36a15
	list_for_each(pos, &tplg->route_list) {
Packit Service f36a15
		elem = list_entry(pos, struct tplg_elem, list);
Packit Service f36a15
		if (!elem->route || elem->type != SND_TPLG_TYPE_DAPM_GRAPH)
Packit Service f36a15
			continue;
Packit Service f36a15
		if (index >= 0 && elem->index != index)
Packit Service f36a15
			continue;
Packit Service f36a15
		if (old_index != elem->index) {
Packit Service f36a15
			block++;
Packit Service f36a15
			old_index = elem->index;
Packit Service f36a15
		}
Packit Service f36a15
		count++;
Packit Service f36a15
	}
Packit Service f36a15
	if (count == 0)
Packit Service f36a15
		return 0;
Packit Service f36a15
	if (block < 10) {
Packit Service f36a15
		fmt = "\tset%u {\n";
Packit Service f36a15
	} else if (block < 100) {
Packit Service f36a15
		fmt = "\tset%02u {\n";
Packit Service f36a15
	} else if (block < 1000) {
Packit Service f36a15
		fmt = "\tset%03u {\n";
Packit Service f36a15
	} else {
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	}
Packit Service f36a15
	old_index = -1;
Packit Service f36a15
	block = -1;
Packit Service f36a15
	first = 1;
Packit Service f36a15
	err = tplg_save_printf(dst, pfx, "SectionGraph {\n");
Packit Service f36a15
	list_for_each(pos, &tplg->route_list) {
Packit Service f36a15
		elem = list_entry(pos, struct tplg_elem, list);
Packit Service f36a15
		if (!elem->route || elem->type != SND_TPLG_TYPE_DAPM_GRAPH)
Packit Service f36a15
			continue;
Packit Service f36a15
		if (index >= 0 && elem->index != index)
Packit Service f36a15
			continue;
Packit Service f36a15
		if (old_index != elem->index) {
Packit Service f36a15
			if (old_index >= 0) {
Packit Service f36a15
				err = tplg_save_printf(dst, pfx, "\t\t]\n");
Packit Service f36a15
				if (err < 0)
Packit Service f36a15
					return err;
Packit Service f36a15
				err = tplg_save_printf(dst, pfx, "\t}\n");
Packit Service f36a15
				if (err < 0)
Packit Service f36a15
					return err;
Packit Service f36a15
			}
Packit Service f36a15
			old_index = elem->index;
Packit Service f36a15
			block++;
Packit Service f36a15
			first = 1;
Packit Service f36a15
			err = tplg_save_printf(dst, pfx, fmt, block);
Packit Service f36a15
			if (err >= 0)
Packit Service f36a15
				err = tplg_save_printf(dst, pfx, "\t\tindex %u\n",
Packit Service f36a15
						       elem->index);
Packit Service f36a15
			if (err < 0)
Packit Service f36a15
				return err;
Packit Service f36a15
		}
Packit Service f36a15
		if (first) {
Packit Service f36a15
			first = 0;
Packit Service f36a15
			err = tplg_save_printf(dst, pfx, "\t\tlines [\n", elem->index);
Packit Service f36a15
			if (err < 0)
Packit Service f36a15
				return err;
Packit Service f36a15
		}
Packit Service f36a15
		route = elem->route;
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\t\t\t'%s, %s, %s'\n",
Packit Service f36a15
					route->sink, route->control,
Packit Service f36a15
					route->source);
Packit Service f36a15
		if (err < 0)
Packit Service f36a15
			return err;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	if (!first) {
Packit Service f36a15
		if (err >= 0)
Packit Service f36a15
			err = tplg_save_printf(dst, pfx, "\t\t]\n");
Packit Service f36a15
		if (err >= 0)
Packit Service f36a15
			err = tplg_save_printf(dst, pfx, "\t}\n");
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	if (err >= 0)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "}\n");
Packit Service f36a15
	return err;
Packit Service f36a15
}
Packit Service f36a15
Packit 4a16fb
/* DAPM Widget */
Packit 4a16fb
int tplg_parse_dapm_widget(snd_tplg_t *tplg,
Packit Service f36a15
			   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 Service f36a15
	int widget_type, err, ival;
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 Service f36a15
	tplg_dbg(" Widget: %s", 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 Service f36a15
				SNDERR("widget '%s': Unsupported widget type %s",
Packit 4a16fb
					elem->id, val);
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
			}
Packit 4a16fb
Packit 4a16fb
			widget->id = widget_type;
Packit Service f36a15
			tplg_dbg("\t%s: %s", 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 Service f36a15
			tplg_dbg("\t%s: %s", id, val);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "no_pm") == 0) {
Packit Service f36a15
			ival = snd_config_get_bool(n);
Packit Service f36a15
			if (ival < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit Service f36a15
			widget->reg = ival ? -1 : 0;
Packit 4a16fb
Packit Service f36a15
			tplg_dbg("\t%s: %s", id, val);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "shift") == 0) {
Packit Service f36a15
			if (tplg_get_integer(n, &ival, 0))
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit Service f36a15
			widget->shift = ival;
Packit Service f36a15
			tplg_dbg("\t%s: %d", id, widget->shift);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "reg") == 0) {
Packit Service f36a15
			if (tplg_get_integer(n, &ival, 0))
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit Service f36a15
			widget->reg = ival;
Packit Service f36a15
			tplg_dbg("\t%s: %d", id, widget->reg);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "invert") == 0) {
Packit Service f36a15
			ival = snd_config_get_bool(n);
Packit Service f36a15
			if (ival < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit Service f36a15
			widget->invert = ival;
Packit Service f36a15
			tplg_dbg("\t%s: %d", id, widget->invert);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "subseq") == 0) {
Packit Service f36a15
			if (tplg_get_integer(n, &ival, 0))
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit Service f36a15
			widget->subseq = ival;
Packit Service f36a15
			tplg_dbg("\t%s: %d", id, widget->subseq);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "event_type") == 0) {
Packit Service f36a15
			if (tplg_get_integer(n, &ival, 0))
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit Service f36a15
			widget->event_type = ival;
Packit Service f36a15
			tplg_dbg("\t%s: %d", id, widget->event_type);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "event_flags") == 0) {
Packit Service f36a15
			if (tplg_get_integer(n, &ival, 0))
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit Service f36a15
			widget->event_flags = ival;
Packit Service f36a15
			tplg_dbg("\t%s: %d", id, widget->event_flags);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "enum") == 0) {
Packit Service f36a15
			err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_ENUM);
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 Service f36a15
			err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_MIXER);
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 Service f36a15
			err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_BYTES);
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 Service f36a15
			err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_DATA);
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 Service f36a15
/* save DAPM widget */
Packit Service f36a15
int tplg_save_dapm_widget(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
Packit Service f36a15
			  struct tplg_elem *elem,
Packit Service f36a15
			  char **dst, const char *pfx)
Packit Service f36a15
{
Packit Service f36a15
	struct snd_soc_tplg_dapm_widget *widget = elem->widget;
Packit Service f36a15
	const char *s;
Packit Service f36a15
	char pfx2[16];
Packit Service f36a15
	int err;
Packit Service f36a15
Packit Service f36a15
	err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
Packit Service f36a15
	if (err >= 0 && elem->index)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\tindex %u\n",
Packit Service f36a15
				       elem->index);
Packit Service f36a15
	if (err >= 0) {
Packit Service f36a15
		s = get_widget_name(widget->id);
Packit Service f36a15
		if (s)
Packit Service f36a15
			err = tplg_save_printf(dst, pfx, "\ttype %s\n", s);
Packit Service f36a15
		else
Packit Service f36a15
			err = tplg_save_printf(dst, pfx, "\ttype %u\n",
Packit Service f36a15
					       widget->id);
Packit Service f36a15
	}
Packit Service f36a15
	if (err >= 0 && widget->sname[0])
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\tstream_name '%s'\n",
Packit Service f36a15
				       widget->sname);
Packit Service f36a15
	if (err >= 0 && widget->reg)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\tno_pm 1\n");
Packit Service f36a15
	if (err >= 0 && widget->shift)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\tshift %u\n",
Packit Service f36a15
				       widget->shift);
Packit Service f36a15
	if (err >= 0 && widget->invert)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\tinvert %u\n",
Packit Service f36a15
				       widget->invert);
Packit Service f36a15
	if (err >= 0 && widget->subseq)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\tsubseq %u\n",
Packit Service f36a15
				       widget->subseq);
Packit Service f36a15
	if (err >= 0 && widget->event_type)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\tevent_type %u\n",
Packit Service f36a15
				       widget->event_type);
Packit Service f36a15
	if (err >= 0 && widget->event_flags)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\tevent_flags %u\n",
Packit Service f36a15
				       widget->event_flags);
Packit Service f36a15
	snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
Packit Service f36a15
	if (err >= 0)
Packit Service f36a15
		err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_ENUM,
Packit Service f36a15
				     "enum", dst, pfx2);
Packit Service f36a15
	if (err >= 0)
Packit Service f36a15
		err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_MIXER,
Packit Service f36a15
				     "mixer", dst, pfx2);
Packit Service f36a15
	if (err >= 0)
Packit Service f36a15
		err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_BYTES,
Packit Service f36a15
				     "bytes", dst, pfx2);
Packit Service f36a15
	if (err >= 0)
Packit Service f36a15
		err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_DATA,
Packit Service f36a15
				     "data", dst, pfx2);
Packit Service f36a15
	if (err >= 0)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "}\n");
Packit Service f36a15
	return err;
Packit Service f36a15
}
Packit Service f36a15
Packit Service f36a15
int tplg_add_route(snd_tplg_t *tplg, struct snd_tplg_graph_elem *t, int index)
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 Service f36a15
	elem = tplg_elem_new_route(tplg, index);
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 Service f36a15
				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 Service f36a15
		ret = tplg_add_route(tplg, gt->elem + i, t->index);
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 Service f36a15
	tplg_dbg("Widget: %s", 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 Service f36a15
	/* add private data */
Packit Service f36a15
	if (wt->priv != NULL && wt->priv->size > 0) {
Packit Service f36a15
		ret = tplg_add_data(tplg, elem, wt->priv,
Packit Service f36a15
				    sizeof(*wt->priv) + wt->priv->size);
Packit Service f36a15
		if (ret < 0) {
Packit 4a16fb
			tplg_elem_free(elem);
Packit Service f36a15
			return ret;
Packit 4a16fb
		}
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 Service f36a15
			SNDERR("widget %s: invalid type %d for ctl %d",
Packit 4a16fb
				wt->name, ct->type, i);
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
}
Packit Service f36a15
Packit Service f36a15
/* decode dapm widget from the binary input */
Packit Service f36a15
int tplg_decode_dapm_widget(snd_tplg_t *tplg,
Packit Service f36a15
			    size_t pos,
Packit Service f36a15
			    struct snd_soc_tplg_hdr *hdr,
Packit Service f36a15
			    void *bin, size_t size)
Packit Service f36a15
{
Packit Service f36a15
	struct list_head heap;
Packit Service f36a15
	struct snd_soc_tplg_dapm_widget *w;
Packit Service f36a15
	snd_tplg_obj_template_t t;
Packit Service f36a15
	struct snd_tplg_widget_template *wt;
Packit Service f36a15
	struct snd_tplg_mixer_template *mt;
Packit Service f36a15
	struct snd_tplg_enum_template *et;
Packit Service f36a15
	struct snd_tplg_bytes_template *bt;
Packit Service f36a15
	struct snd_soc_tplg_ctl_hdr *chdr;
Packit Service f36a15
	struct snd_soc_tplg_mixer_control *mc;
Packit Service f36a15
	struct snd_soc_tplg_enum_control *ec;
Packit Service f36a15
	struct snd_soc_tplg_bytes_control *bc;
Packit Service f36a15
	size_t size2;
Packit Service f36a15
	unsigned int index;
Packit Service f36a15
	int err;
Packit Service f36a15
Packit Service f36a15
	err = tplg_decode_template(tplg, pos, hdr, &t);
Packit Service f36a15
	if (err < 0)
Packit Service f36a15
		return err;
Packit Service f36a15
Packit Service f36a15
next:
Packit Service f36a15
	INIT_LIST_HEAD(&heap;;
Packit Service f36a15
	w = bin;
Packit Service f36a15
Packit Service f36a15
	if (size < sizeof(*w)) {
Packit Service f36a15
		SNDERR("dapm widget: small size %d", size);
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	}
Packit Service f36a15
	if (sizeof(*w) != w->size) {
Packit Service f36a15
		SNDERR("dapm widget: unknown element size %d (expected %zd)",
Packit Service f36a15
		       w->size, sizeof(*w));
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	}
Packit Service f36a15
	if (w->num_kcontrols > 16) {
Packit Service f36a15
		SNDERR("dapm widget: too many kcontrols %d",
Packit Service f36a15
		       w->num_kcontrols);
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	tplg_log(tplg, 'D', pos, "dapm widget: size %d private size %d kcontrols %d",
Packit Service f36a15
		 w->size, w->priv.size, w->num_kcontrols);
Packit Service f36a15
Packit Service f36a15
	wt = tplg_calloc(&heap, sizeof(*wt) + sizeof(void *) * w->num_kcontrols);
Packit Service f36a15
	if (wt == NULL)
Packit Service f36a15
		return -ENOMEM;
Packit Service f36a15
	wt->id = w->id;
Packit Service f36a15
	wt->name = w->name;
Packit Service f36a15
	wt->sname = w->sname;
Packit Service f36a15
	wt->reg = w->reg;
Packit Service f36a15
	wt->shift = w->shift;
Packit Service f36a15
	wt->mask = w->mask;
Packit Service f36a15
	wt->subseq = w->subseq;
Packit Service f36a15
	wt->invert = w->invert;
Packit Service f36a15
	wt->ignore_suspend = w->ignore_suspend;
Packit Service f36a15
	wt->event_flags = w->event_flags;
Packit Service f36a15
	wt->event_type = w->event_type;
Packit Service f36a15
Packit Service f36a15
	tplg_log(tplg, 'D', pos, "dapm widget: name '%s' sname '%s'",
Packit Service f36a15
		 wt->name, wt->sname);
Packit Service f36a15
Packit Service f36a15
	if (sizeof(*w) + w->priv.size > size) {
Packit Service f36a15
		SNDERR("dapm widget: wrong private data size %d",
Packit Service f36a15
		       w->priv.size);
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	tplg_log(tplg, 'D', pos + offsetof(struct snd_soc_tplg_dapm_widget, priv),
Packit Service f36a15
		 "dapm widget: private start");
Packit Service f36a15
Packit Service f36a15
	wt->priv = &w->priv;
Packit Service f36a15
	bin += sizeof(*w) + w->priv.size;
Packit Service f36a15
	size -= sizeof(*w) + w->priv.size;
Packit Service f36a15
	pos += sizeof(*w) + w->priv.size;
Packit Service f36a15
Packit Service f36a15
	for (index = 0; index < w->num_kcontrols; index++) {
Packit Service f36a15
		chdr = bin;
Packit Service f36a15
		switch (chdr->type) {
Packit Service f36a15
		case SND_SOC_TPLG_TYPE_MIXER:
Packit Service f36a15
			mt = tplg_calloc(&heap, sizeof(*mt));
Packit Service f36a15
			if (mt == NULL) {
Packit Service f36a15
				err = -ENOMEM;
Packit Service f36a15
				goto retval;
Packit Service f36a15
			}
Packit Service f36a15
			wt->ctl[index] = (void *)mt;
Packit Service f36a15
			wt->num_ctls++;
Packit Service f36a15
			mc = bin;
Packit Service f36a15
			size2 = mc->size + mc->priv.size;
Packit Service f36a15
			tplg_log(tplg, 'D', pos, "kcontrol mixer size %zd", size2);
Packit Service f36a15
			if (size2 > size) {
Packit Service f36a15
				SNDERR("dapm widget: small mixer size %d",
Packit Service f36a15
				       size2);
Packit Service f36a15
				err = -EINVAL;
Packit Service f36a15
				goto retval;
Packit Service f36a15
			}
Packit Service f36a15
			err = tplg_decode_control_mixer1(tplg, &heap, mt, pos,
Packit Service f36a15
							 bin, size2);
Packit Service f36a15
			break;
Packit Service f36a15
		case SND_SOC_TPLG_TYPE_ENUM:
Packit Service f36a15
			et = tplg_calloc(&heap, sizeof(*mt));
Packit Service f36a15
			if (et == NULL) {
Packit Service f36a15
				err = -ENOMEM;
Packit Service f36a15
				goto retval;
Packit Service f36a15
			}
Packit Service f36a15
			wt->ctl[index] = (void *)et;
Packit Service f36a15
			wt->num_ctls++;
Packit Service f36a15
			ec = bin;
Packit Service f36a15
			size2 = ec->size + ec->priv.size;
Packit Service f36a15
			tplg_log(tplg, 'D', pos, "kcontrol enum size %zd", size2);
Packit Service f36a15
			if (size2 > size) {
Packit Service f36a15
				SNDERR("dapm widget: small enum size %d",
Packit Service f36a15
				       size2);
Packit Service f36a15
				err = -EINVAL;
Packit Service f36a15
				goto retval;
Packit Service f36a15
			}
Packit Service f36a15
			err = tplg_decode_control_enum1(tplg, &heap, et, pos,
Packit Service f36a15
							bin, size2);
Packit Service f36a15
			break;
Packit Service f36a15
		case SND_SOC_TPLG_TYPE_BYTES:
Packit Service f36a15
			bt = tplg_calloc(&heap, sizeof(*bt));
Packit Service f36a15
			if (bt == NULL) {
Packit Service f36a15
				err = -ENOMEM;
Packit Service f36a15
				goto retval;
Packit Service f36a15
			}
Packit Service f36a15
			wt->ctl[index] = (void *)bt;
Packit Service f36a15
			wt->num_ctls++;
Packit Service f36a15
			bc = bin;
Packit Service f36a15
			size2 = bc->size + bc->priv.size;
Packit Service f36a15
			tplg_log(tplg, 'D', pos, "kcontrol bytes size %zd", size2);
Packit Service f36a15
			if (size2 > size) {
Packit Service f36a15
				SNDERR("dapm widget: small bytes size %d",
Packit Service f36a15
				       size2);
Packit Service f36a15
				err = -EINVAL;
Packit Service f36a15
				goto retval;
Packit Service f36a15
			}
Packit Service f36a15
			err = tplg_decode_control_bytes1(tplg, bt, pos,
Packit Service f36a15
							 bin, size2);
Packit Service f36a15
			break;
Packit Service f36a15
		default:
Packit Service f36a15
			SNDERR("dapm widget: wrong control type %d",
Packit Service f36a15
			       chdr->type);
Packit Service f36a15
			err = -EINVAL;
Packit Service f36a15
			goto retval;
Packit Service f36a15
		}
Packit Service f36a15
		if (err < 0)
Packit Service f36a15
			goto retval;
Packit Service f36a15
		bin += size2;
Packit Service f36a15
		size -= size2;
Packit Service f36a15
		pos += size2;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	t.widget = wt;
Packit Service f36a15
	err = snd_tplg_add_object(tplg, &t);
Packit Service f36a15
	tplg_free(&heap;;
Packit Service f36a15
	if (err < 0)
Packit Service f36a15
		return err;
Packit Service f36a15
	if (size > 0)
Packit Service f36a15
		goto next;
Packit Service f36a15
	return 0;
Packit Service f36a15
Packit Service f36a15
retval:
Packit Service f36a15
	tplg_free(&heap;;
Packit Service f36a15
	return err;
Packit Service f36a15
}
Packit Service f36a15
Packit Service f36a15
/* decode dapm link from the binary input */
Packit Service f36a15
int tplg_decode_dapm_graph(snd_tplg_t *tplg,
Packit Service f36a15
			   size_t pos,
Packit Service f36a15
			   struct snd_soc_tplg_hdr *hdr,
Packit Service f36a15
			   void *bin, size_t size)
Packit Service f36a15
{
Packit Service f36a15
	struct snd_soc_tplg_dapm_graph_elem *g;
Packit Service f36a15
	snd_tplg_obj_template_t t;
Packit Service f36a15
	struct snd_tplg_graph_template *gt;
Packit Service f36a15
	struct snd_tplg_graph_elem *ge;
Packit Service f36a15
	size_t asize;
Packit Service f36a15
	int err;
Packit Service f36a15
Packit Service f36a15
	err = tplg_decode_template(tplg, pos, hdr, &t);
Packit Service f36a15
	if (err < 0)
Packit Service f36a15
		return err;
Packit Service f36a15
Packit Service f36a15
	asize = sizeof(*gt) + (size / sizeof(*g)) * sizeof(*ge);
Packit Service f36a15
	gt = alloca(asize);
Packit Service f36a15
	memset(gt, 0, asize);
Packit Service f36a15
	for (ge = gt->elem; size > 0; ge++) {
Packit Service f36a15
		g = bin;
Packit Service f36a15
		if (size < sizeof(*g)) {
Packit Service f36a15
			SNDERR("dapm graph: small size %d", size);
Packit Service f36a15
			return -EINVAL;
Packit Service f36a15
		}
Packit Service f36a15
		ge->src = g->source;
Packit Service f36a15
		ge->ctl = g->control;
Packit Service f36a15
		ge->sink = g->sink;
Packit Service f36a15
		gt->count++;
Packit Service f36a15
		tplg_log(tplg, 'D', pos, "dapm graph: src='%s' ctl='%s' sink='%s'",
Packit Service f36a15
			ge->src, ge->ctl, ge->sink);
Packit Service f36a15
		bin += sizeof(*g);
Packit Service f36a15
		size -= sizeof(*g);
Packit Service f36a15
		pos += sizeof(*g);
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	t.graph = gt;
Packit Service f36a15
	return snd_tplg_add_object(tplg, &t);
Packit Service f36a15
}