Blame src/topology/dapm.c

Packit Service db8eaa
/*
Packit Service db8eaa
  Copyright(c) 2014-2015 Intel Corporation
Packit Service db8eaa
  All rights reserved.
Packit Service db8eaa
Packit Service db8eaa
  This library is free software; you can redistribute it and/or modify
Packit Service db8eaa
  it under the terms of the GNU Lesser General Public License as
Packit Service db8eaa
  published by the Free Software Foundation; either version 2.1 of
Packit Service db8eaa
  the License, or (at your option) any later version.
Packit Service db8eaa
Packit Service db8eaa
  This program is distributed in the hope that it will be useful,
Packit Service db8eaa
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service db8eaa
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service db8eaa
  GNU Lesser General Public License for more details.
Packit Service db8eaa
Packit Service db8eaa
  Authors: Mengdong Lin <mengdong.lin@intel.com>
Packit Service db8eaa
           Yao Jin <yao.jin@intel.com>
Packit Service db8eaa
           Liam Girdwood <liam.r.girdwood@linux.intel.com>
Packit Service db8eaa
*/
Packit Service db8eaa
Packit Service db8eaa
#include "list.h"
Packit Service db8eaa
#include "tplg_local.h"
Packit Service db8eaa
Packit Service db8eaa
/* mapping of widget text names to types */
Packit Service db8eaa
static const struct map_elem widget_map[] = {
Packit Service db8eaa
	{"input", SND_SOC_TPLG_DAPM_INPUT},
Packit Service db8eaa
	{"output", SND_SOC_TPLG_DAPM_OUTPUT},
Packit Service db8eaa
	{"mux", SND_SOC_TPLG_DAPM_MUX},
Packit Service db8eaa
	{"mixer", SND_SOC_TPLG_DAPM_MIXER},
Packit Service db8eaa
	{"pga", SND_SOC_TPLG_DAPM_PGA},
Packit Service db8eaa
	{"out_drv", SND_SOC_TPLG_DAPM_OUT_DRV},
Packit Service db8eaa
	{"adc", SND_SOC_TPLG_DAPM_ADC},
Packit Service db8eaa
	{"dac", SND_SOC_TPLG_DAPM_DAC},
Packit Service db8eaa
	{"switch", SND_SOC_TPLG_DAPM_SWITCH},
Packit Service db8eaa
	{"pre", SND_SOC_TPLG_DAPM_PRE},
Packit Service db8eaa
	{"post", SND_SOC_TPLG_DAPM_POST},
Packit Service db8eaa
	{"aif_in", SND_SOC_TPLG_DAPM_AIF_IN},
Packit Service db8eaa
	{"aif_out", SND_SOC_TPLG_DAPM_AIF_OUT},
Packit Service db8eaa
	{"dai_in", SND_SOC_TPLG_DAPM_DAI_IN},
Packit Service db8eaa
	{"dai_out", SND_SOC_TPLG_DAPM_DAI_OUT},
Packit Service db8eaa
	{"dai_link", SND_SOC_TPLG_DAPM_DAI_LINK},
Packit Service db8eaa
	{"buffer", SND_SOC_TPLG_DAPM_BUFFER},
Packit Service db8eaa
	{"scheduler", SND_SOC_TPLG_DAPM_SCHEDULER},
Packit Service db8eaa
	{"effect", SND_SOC_TPLG_DAPM_EFFECT},
Packit Service db8eaa
	{"siggen", SND_SOC_TPLG_DAPM_SIGGEN},
Packit Service db8eaa
	{"src", SND_SOC_TPLG_DAPM_SRC},
Packit Service db8eaa
	{"asrc", SND_SOC_TPLG_DAPM_ASRC},
Packit Service db8eaa
	{"encoder", SND_SOC_TPLG_DAPM_ENCODER},
Packit Service db8eaa
	{"decoder", SND_SOC_TPLG_DAPM_DECODER},
Packit Service db8eaa
};
Packit Service db8eaa
Packit Service db8eaa
static int lookup_widget(const char *w)
Packit Service db8eaa
{
Packit Service db8eaa
	unsigned int i;
Packit Service db8eaa
Packit Service db8eaa
	for (i = 0; i < ARRAY_SIZE(widget_map); i++) {
Packit Service db8eaa
		if (strcmp(widget_map[i].name, w) == 0)
Packit Service db8eaa
			return widget_map[i].id;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return -EINVAL;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static const char *get_widget_name(unsigned int type)
Packit Service db8eaa
{
Packit Service db8eaa
	unsigned int i;
Packit Service db8eaa
Packit Service db8eaa
	for (i = 0; i < ARRAY_SIZE(widget_map); i++) {
Packit Service db8eaa
		if ((unsigned int)widget_map[i].id == type)
Packit Service db8eaa
			return widget_map[i].name;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return NULL;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* move referenced controls to the widget */
Packit Service db8eaa
static int copy_dapm_control(struct tplg_elem *elem, struct tplg_elem *ref)
Packit Service db8eaa
{
Packit Service db8eaa
	struct snd_soc_tplg_dapm_widget *widget = elem->widget;
Packit Service db8eaa
Packit Service db8eaa
	tplg_dbg("Control '%s' used by '%s'", ref->id, elem->id);
Packit Service db8eaa
	tplg_dbg("\tparent size: %d + %d -> %d, priv size -> %d",
Packit Service db8eaa
		elem->size, ref->size, elem->size + ref->size,
Packit Service db8eaa
		widget->priv.size);
Packit Service db8eaa
Packit Service db8eaa
	widget = realloc(widget, elem->size + ref->size);
Packit Service db8eaa
	if (!widget)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
	elem->widget = widget;
Packit Service db8eaa
Packit Service db8eaa
	/* append the control to the end of the widget */
Packit Service db8eaa
	memcpy((void*)widget + elem->size, ref->obj, ref->size);
Packit Service db8eaa
	elem->size += ref->size;
Packit Service db8eaa
Packit Service db8eaa
	widget->num_kcontrols++;
Packit Service db8eaa
	ref->compound_elem = 1;
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* check referenced controls for a widget */
Packit Service db8eaa
static int tplg_build_widget(snd_tplg_t *tplg, struct tplg_elem *elem)
Packit Service db8eaa
{
Packit Service db8eaa
	struct tplg_ref *ref;
Packit Service db8eaa
	struct list_head *base, *pos;
Packit Service db8eaa
	int err = 0;
Packit Service db8eaa
Packit Service db8eaa
	base = &elem->ref_list;
Packit Service db8eaa
Packit Service db8eaa
	/* A widget's private data sits before the embedded controls.
Packit Service db8eaa
	 * So merge the private data blocks at first
Packit Service db8eaa
	 */
Packit Service db8eaa
	list_for_each(pos, base) {
Packit Service db8eaa
		ref = list_entry(pos, struct tplg_ref, list);
Packit Service db8eaa
Packit Service db8eaa
		if (ref->type != SND_TPLG_TYPE_DATA)
Packit Service db8eaa
			continue;
Packit Service db8eaa
Packit Service db8eaa
		err = tplg_copy_data(tplg, elem, ref);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	/* Merge the embedded controls */
Packit Service db8eaa
	list_for_each(pos, base) {
Packit Service db8eaa
Packit Service db8eaa
		ref = list_entry(pos, struct tplg_ref, list);
Packit Service db8eaa
Packit Service db8eaa
		switch (ref->type) {
Packit Service db8eaa
		case SND_TPLG_TYPE_MIXER:
Packit Service db8eaa
			if (!ref->elem)
Packit Service db8eaa
				ref->elem = tplg_elem_lookup(&tplg->mixer_list,
Packit Service db8eaa
				ref->id, SND_TPLG_TYPE_MIXER, elem->index);
Packit Service db8eaa
			if (ref->elem)
Packit Service db8eaa
				err = copy_dapm_control(elem, ref->elem);
Packit Service db8eaa
			break;
Packit Service db8eaa
Packit Service db8eaa
		case SND_TPLG_TYPE_ENUM:
Packit Service db8eaa
			if (!ref->elem)
Packit Service db8eaa
				ref->elem = tplg_elem_lookup(&tplg->enum_list,
Packit Service db8eaa
				ref->id, SND_TPLG_TYPE_ENUM, elem->index);
Packit Service db8eaa
			if (ref->elem)
Packit Service db8eaa
				err = copy_dapm_control(elem, ref->elem);
Packit Service db8eaa
			break;
Packit Service db8eaa
Packit Service db8eaa
		case SND_TPLG_TYPE_BYTES:
Packit Service db8eaa
			if (!ref->elem)
Packit Service db8eaa
				ref->elem = tplg_elem_lookup(&tplg->bytes_ext_list,
Packit Service db8eaa
				ref->id, SND_TPLG_TYPE_BYTES, elem->index);
Packit Service db8eaa
			if (ref->elem)
Packit Service db8eaa
				err = copy_dapm_control(elem, ref->elem);
Packit Service db8eaa
			break;
Packit Service db8eaa
Packit Service db8eaa
		default:
Packit Service db8eaa
			break;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (!ref->elem) {
Packit Service db8eaa
			SNDERR("cannot find '%s' referenced by widget '%s'",
Packit Service db8eaa
				ref->id, elem->id);
Packit Service db8eaa
			return -EINVAL;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
int tplg_build_widgets(snd_tplg_t *tplg)
Packit Service db8eaa
{
Packit Service db8eaa
Packit Service db8eaa
	struct list_head *base, *pos;
Packit Service db8eaa
	struct tplg_elem *elem;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	base = &tplg->widget_list;
Packit Service db8eaa
	list_for_each(pos, base) {
Packit Service db8eaa
Packit Service db8eaa
		elem = list_entry(pos, struct tplg_elem, list);
Packit Service db8eaa
		if (!elem->widget || elem->type != SND_TPLG_TYPE_DAPM_WIDGET) {
Packit Service db8eaa
			SNDERR("invalid widget '%s'", elem->id);
Packit Service db8eaa
			return -EINVAL;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		err = tplg_build_widget(tplg, elem);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
Packit Service db8eaa
		/* add widget to manifest */
Packit Service db8eaa
		tplg->manifest.widget_elems++;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
int tplg_build_routes(snd_tplg_t *tplg)
Packit Service db8eaa
{
Packit Service db8eaa
	struct list_head *base, *pos;
Packit Service db8eaa
	struct tplg_elem *elem;
Packit Service db8eaa
	struct snd_soc_tplg_dapm_graph_elem *route;
Packit Service db8eaa
Packit Service db8eaa
	base = &tplg->route_list;
Packit Service db8eaa
Packit Service db8eaa
	list_for_each(pos, base) {
Packit Service db8eaa
		elem = list_entry(pos, struct tplg_elem, list);
Packit Service db8eaa
Packit Service db8eaa
		if (!elem->route || elem->type != SND_TPLG_TYPE_DAPM_GRAPH) {
Packit Service db8eaa
			SNDERR("invalid route '%s'", elem->id);
Packit Service db8eaa
			return -EINVAL;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		route = elem->route;
Packit Service db8eaa
		tplg_dbg("Check route: sink '%s', control '%s', source '%s'",
Packit Service db8eaa
			 route->sink, route->control, route->source);
Packit Service db8eaa
Packit Service db8eaa
		/* validate sink */
Packit Service db8eaa
		if (strlen(route->sink) <= 0) {
Packit Service db8eaa
			SNDERR("no sink");
Packit Service db8eaa
			return -EINVAL;
Packit Service db8eaa
Packit Service db8eaa
		}
Packit Service db8eaa
		if (!tplg_elem_lookup(&tplg->widget_list, route->sink,
Packit Service db8eaa
			SND_TPLG_TYPE_DAPM_WIDGET, SND_TPLG_INDEX_ALL)) {
Packit Service db8eaa
			SNDERR("undefined sink widget/stream '%s'", route->sink);
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		/* validate control name */
Packit Service db8eaa
		if (strlen(route->control)) {
Packit Service db8eaa
			if (!tplg_elem_lookup(&tplg->mixer_list, route->control,
Packit Service db8eaa
					SND_TPLG_TYPE_MIXER, elem->index) &&
Packit Service db8eaa
			!tplg_elem_lookup(&tplg->enum_list, route->control,
Packit Service db8eaa
					SND_TPLG_TYPE_ENUM, elem->index)) {
Packit Service db8eaa
				SNDERR("undefined mixer/enum control '%s'",
Packit Service db8eaa
				       route->control);
Packit Service db8eaa
			}
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		/* validate source */
Packit Service db8eaa
		if (strlen(route->source) <= 0) {
Packit Service db8eaa
			SNDERR("no source");
Packit Service db8eaa
			return -EINVAL;
Packit Service db8eaa
Packit Service db8eaa
		}
Packit Service db8eaa
		if (!tplg_elem_lookup(&tplg->widget_list, route->source,
Packit Service db8eaa
			SND_TPLG_TYPE_DAPM_WIDGET, SND_TPLG_INDEX_ALL)) {
Packit Service db8eaa
			SNDERR("undefined source widget/stream '%s'",
Packit Service db8eaa
			       route->source);
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		/* add graph to manifest */
Packit Service db8eaa
		tplg->manifest.graph_elems++;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
struct tplg_elem *tplg_elem_new_route(snd_tplg_t *tplg, int index)
Packit Service db8eaa
{
Packit Service db8eaa
	struct tplg_elem *elem;
Packit Service db8eaa
	struct snd_soc_tplg_dapm_graph_elem *line;
Packit Service db8eaa
Packit Service db8eaa
	elem = tplg_elem_new();
Packit Service db8eaa
	if (!elem)
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
Packit Service db8eaa
	elem->index = index;
Packit Service db8eaa
	if (tplg->dapm_sort)
Packit Service db8eaa
		tplg_elem_insert(elem, &tplg->route_list);
Packit Service db8eaa
	else
Packit Service db8eaa
		list_add_tail(&elem->list, &tplg->route_list);
Packit Service db8eaa
	strcpy(elem->id, "line");
Packit Service db8eaa
	elem->type = SND_TPLG_TYPE_DAPM_GRAPH;
Packit Service db8eaa
	elem->size = sizeof(*line);
Packit Service db8eaa
Packit Service db8eaa
	line = calloc(1, sizeof(*line));
Packit Service db8eaa
	if (!line) {
Packit Service db8eaa
		tplg_elem_free(elem);
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
	}
Packit Service db8eaa
	elem->route = line;
Packit Service db8eaa
Packit Service db8eaa
	return elem;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
#define LINE_SIZE	1024
Packit Service db8eaa
Packit Service db8eaa
/* line is defined as '"sink, control, source"' */
Packit Service db8eaa
static int tplg_parse_line(const char *text,
Packit Service db8eaa
			   struct snd_soc_tplg_dapm_graph_elem *line)
Packit Service db8eaa
{
Packit Service db8eaa
	char buf[LINE_SIZE];
Packit Service db8eaa
	unsigned int len, i;
Packit Service db8eaa
	const char *source = NULL, *sink = NULL, *control = NULL;
Packit Service db8eaa
Packit Service db8eaa
	snd_strlcpy(buf, text, LINE_SIZE);
Packit Service db8eaa
Packit Service db8eaa
	len = strlen(buf);
Packit Service db8eaa
	if (len <= 2) {
Packit Service db8eaa
		SNDERR("invalid route \"%s\"", buf);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	/* find first , */
Packit Service db8eaa
	for (i = 1; i < len; i++) {
Packit Service db8eaa
		if (buf[i] == ',')
Packit Service db8eaa
			goto second;
Packit Service db8eaa
	}
Packit Service db8eaa
	SNDERR("invalid route \"%s\"", buf);
Packit Service db8eaa
	return -EINVAL;
Packit Service db8eaa
Packit Service db8eaa
second:
Packit Service db8eaa
	/* find second , */
Packit Service db8eaa
	sink = buf;
Packit Service db8eaa
	control = &buf[i + 2];
Packit Service db8eaa
	buf[i] = 0;
Packit Service db8eaa
Packit Service db8eaa
	for (; i < len; i++) {
Packit Service db8eaa
		if (buf[i] == ',')
Packit Service db8eaa
			goto done;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	SNDERR("invalid route \"%s\"", buf);
Packit Service db8eaa
	return -EINVAL;
Packit Service db8eaa
Packit Service db8eaa
done:
Packit Service db8eaa
	buf[i] = 0;
Packit Service db8eaa
	source = &buf[i + 2];
Packit Service db8eaa
Packit Service db8eaa
	strcpy(line->source, source);
Packit Service db8eaa
	strcpy(line->control, control);
Packit Service db8eaa
	strcpy(line->sink, sink);
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
Packit Service db8eaa
static int tplg_parse_routes(snd_tplg_t *tplg, snd_config_t *cfg, int index)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_config_iterator_t i, next;
Packit Service db8eaa
	snd_config_t *n;
Packit Service db8eaa
	struct tplg_elem *elem;
Packit Service db8eaa
	struct snd_soc_tplg_dapm_graph_elem *line;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	snd_config_for_each(i, next, cfg) {
Packit Service db8eaa
		const char *val;
Packit Service db8eaa
Packit Service db8eaa
		n = snd_config_iterator_entry(i);
Packit Service db8eaa
		if (snd_config_get_string(n, &val) < 0)
Packit Service db8eaa
			continue;
Packit Service db8eaa
Packit Service db8eaa
		elem = tplg_elem_new_route(tplg, index);
Packit Service db8eaa
		if (!elem)
Packit Service db8eaa
			return -ENOMEM;
Packit Service db8eaa
		line = elem->route;
Packit Service db8eaa
Packit Service db8eaa
		err = tplg_parse_line(val, line);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
Packit Service db8eaa
		tplg_dbg("route: sink '%s', control '%s', source '%s'",
Packit Service db8eaa
				line->sink, line->control, line->source);
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
int tplg_parse_dapm_graph(snd_tplg_t *tplg, snd_config_t *cfg,
Packit Service db8eaa
			  void *private ATTRIBUTE_UNUSED)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_config_iterator_t i, next;
Packit Service db8eaa
	snd_config_t *n;
Packit Service db8eaa
	int err;
Packit Service db8eaa
	const char *graph_id;
Packit Service db8eaa
	int index = -1;
Packit Service db8eaa
Packit Service db8eaa
	if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
Packit Service db8eaa
		SNDERR("compound is expected for dapm graph definition");
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	snd_config_get_id(cfg, &graph_id);
Packit Service db8eaa
Packit Service db8eaa
	snd_config_for_each(i, next, cfg) {
Packit Service db8eaa
		const char *id;
Packit Service db8eaa
Packit Service db8eaa
		n = snd_config_iterator_entry(i);
Packit Service db8eaa
		if (snd_config_get_id(n, &id) < 0) {
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "index") == 0) {
Packit Service db8eaa
			if (tplg_get_integer(n, &index, 0))
Packit Service db8eaa
				return -EINVAL;
Packit Service db8eaa
			if (index < 0)
Packit Service db8eaa
				return -EINVAL;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "lines") == 0) {
Packit Service db8eaa
			if (index < 0) {
Packit Service db8eaa
				SNDERR("failed to parse dapm graph %s, missing index",
Packit Service db8eaa
					graph_id);
Packit Service db8eaa
				return -EINVAL;
Packit Service db8eaa
			}
Packit Service db8eaa
			err = tplg_parse_routes(tplg, n, index);
Packit Service db8eaa
			if (err < 0) {
Packit Service db8eaa
				SNDERR("failed to parse dapm graph %s",
Packit Service db8eaa
					graph_id);
Packit Service db8eaa
				return err;
Packit Service db8eaa
			}
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* save DAPM graph */
Packit Service db8eaa
int tplg_save_dapm_graph(snd_tplg_t *tplg, int index,
Packit Service db8eaa
			 struct tplg_buf *dst, const char *pfx)
Packit Service db8eaa
{
Packit Service db8eaa
	struct snd_soc_tplg_dapm_graph_elem *route;
Packit Service db8eaa
	struct list_head *pos;
Packit Service db8eaa
	struct tplg_elem *elem;
Packit Service db8eaa
	int err, first, old_index;
Packit Service db8eaa
	unsigned block, count;
Packit Service db8eaa
	const char *fmt;
Packit Service db8eaa
Packit Service db8eaa
	old_index = -1;
Packit Service db8eaa
	block = 0;
Packit Service db8eaa
	count = 0;
Packit Service db8eaa
	list_for_each(pos, &tplg->route_list) {
Packit Service db8eaa
		elem = list_entry(pos, struct tplg_elem, list);
Packit Service db8eaa
		if (!elem->route || elem->type != SND_TPLG_TYPE_DAPM_GRAPH)
Packit Service db8eaa
			continue;
Packit Service db8eaa
		if (index >= 0 && elem->index != index)
Packit Service db8eaa
			continue;
Packit Service db8eaa
		if (old_index != elem->index) {
Packit Service db8eaa
			block++;
Packit Service db8eaa
			old_index = elem->index;
Packit Service db8eaa
		}
Packit Service db8eaa
		count++;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (count == 0)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
	if (block < 10) {
Packit Service db8eaa
		fmt = "\tset%u {\n";
Packit Service db8eaa
	} else if (block < 100) {
Packit Service db8eaa
		fmt = "\tset%02u {\n";
Packit Service db8eaa
	} else if (block < 1000) {
Packit Service db8eaa
		fmt = "\tset%03u {\n";
Packit Service db8eaa
	} else {
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
	old_index = -1;
Packit Service db8eaa
	block = -1;
Packit Service db8eaa
	first = 1;
Packit Service db8eaa
	err = tplg_save_printf(dst, pfx, "SectionGraph {\n");
Packit Service db8eaa
	list_for_each(pos, &tplg->route_list) {
Packit Service db8eaa
		elem = list_entry(pos, struct tplg_elem, list);
Packit Service db8eaa
		if (!elem->route || elem->type != SND_TPLG_TYPE_DAPM_GRAPH)
Packit Service db8eaa
			continue;
Packit Service db8eaa
		if (index >= 0 && elem->index != index)
Packit Service db8eaa
			continue;
Packit Service db8eaa
		if (old_index != elem->index) {
Packit Service db8eaa
			if (old_index >= 0) {
Packit Service db8eaa
				err = tplg_save_printf(dst, pfx, "\t\t]\n");
Packit Service db8eaa
				if (err < 0)
Packit Service db8eaa
					return err;
Packit Service db8eaa
				err = tplg_save_printf(dst, pfx, "\t}\n");
Packit Service db8eaa
				if (err < 0)
Packit Service db8eaa
					return err;
Packit Service db8eaa
			}
Packit Service db8eaa
			old_index = elem->index;
Packit Service db8eaa
			block++;
Packit Service db8eaa
			first = 1;
Packit Service db8eaa
			err = tplg_save_printf(dst, pfx, fmt, block);
Packit Service db8eaa
			if (err >= 0)
Packit Service db8eaa
				err = tplg_save_printf(dst, pfx, "\t\tindex %u\n",
Packit Service db8eaa
						       elem->index);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return err;
Packit Service db8eaa
		}
Packit Service db8eaa
		if (first) {
Packit Service db8eaa
			first = 0;
Packit Service db8eaa
			err = tplg_save_printf(dst, pfx, "\t\tlines [\n");
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return err;
Packit Service db8eaa
		}
Packit Service db8eaa
		route = elem->route;
Packit Service db8eaa
		err = tplg_save_printf(dst, pfx, "\t\t\t'%s, %s, %s'\n",
Packit Service db8eaa
					route->sink, route->control,
Packit Service db8eaa
					route->source);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (!first) {
Packit Service db8eaa
		if (err >= 0)
Packit Service db8eaa
			err = tplg_save_printf(dst, pfx, "\t\t]\n");
Packit Service db8eaa
		if (err >= 0)
Packit Service db8eaa
			err = tplg_save_printf(dst, pfx, "\t}\n");
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (err >= 0)
Packit Service db8eaa
		err = tplg_save_printf(dst, pfx, "}\n");
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* DAPM Widget */
Packit Service db8eaa
int tplg_parse_dapm_widget(snd_tplg_t *tplg,
Packit Service db8eaa
			   snd_config_t *cfg, void *private ATTRIBUTE_UNUSED)
Packit Service db8eaa
{
Packit Service db8eaa
	struct snd_soc_tplg_dapm_widget *widget;
Packit Service db8eaa
	struct tplg_elem *elem;
Packit Service db8eaa
	snd_config_iterator_t i, next;
Packit Service db8eaa
	snd_config_t *n;
Packit Service db8eaa
	const char *id, *val = NULL;
Packit Service db8eaa
	int widget_type, err, ival;
Packit Service db8eaa
Packit Service db8eaa
	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_DAPM_WIDGET);
Packit Service db8eaa
	if (!elem)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
	tplg_dbg(" Widget: %s", elem->id);
Packit Service db8eaa
Packit Service db8eaa
	widget = elem->widget;
Packit Service db8eaa
	snd_strlcpy(widget->name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit Service db8eaa
	widget->size = elem->size;
Packit Service db8eaa
Packit Service db8eaa
	snd_config_for_each(i, next, cfg) {
Packit Service db8eaa
Packit Service db8eaa
		n = snd_config_iterator_entry(i);
Packit Service db8eaa
		if (snd_config_get_id(n, &id) < 0)
Packit Service db8eaa
			continue;
Packit Service db8eaa
Packit Service db8eaa
		/* skip comments */
Packit Service db8eaa
		if (strcmp(id, "comment") == 0)
Packit Service db8eaa
			continue;
Packit Service db8eaa
		if (id[0] == '#')
Packit Service db8eaa
			continue;
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "type") == 0) {
Packit Service db8eaa
			if (snd_config_get_string(n, &val) < 0)
Packit Service db8eaa
				return -EINVAL;
Packit Service db8eaa
Packit Service db8eaa
			widget_type = lookup_widget(val);
Packit Service db8eaa
			if (widget_type < 0){
Packit Service db8eaa
				SNDERR("widget '%s': Unsupported widget type %s",
Packit Service db8eaa
					elem->id, val);
Packit Service db8eaa
				return -EINVAL;
Packit Service db8eaa
			}
Packit Service db8eaa
Packit Service db8eaa
			widget->id = widget_type;
Packit Service db8eaa
			tplg_dbg("\t%s: %s", id, val);
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "stream_name") == 0) {
Packit Service db8eaa
			if (snd_config_get_string(n, &val) < 0)
Packit Service db8eaa
				return -EINVAL;
Packit Service db8eaa
Packit Service db8eaa
			snd_strlcpy(widget->sname, val,
Packit Service db8eaa
				       SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit Service db8eaa
			tplg_dbg("\t%s: %s", id, val);
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "no_pm") == 0) {
Packit Service db8eaa
			ival = snd_config_get_bool(n);
Packit Service db8eaa
			if (ival < 0)
Packit Service db8eaa
				return -EINVAL;
Packit Service db8eaa
Packit Service db8eaa
			widget->reg = ival ? -1 : 0;
Packit Service db8eaa
Packit Service db8eaa
			tplg_dbg("\t%s: %s", id, val);
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "shift") == 0) {
Packit Service db8eaa
			if (tplg_get_integer(n, &ival, 0))
Packit Service db8eaa
				return -EINVAL;
Packit Service db8eaa
Packit Service db8eaa
			widget->shift = ival;
Packit Service db8eaa
			tplg_dbg("\t%s: %d", id, widget->shift);
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "reg") == 0) {
Packit Service db8eaa
			if (tplg_get_integer(n, &ival, 0))
Packit Service db8eaa
				return -EINVAL;
Packit Service db8eaa
Packit Service db8eaa
			widget->reg = ival;
Packit Service db8eaa
			tplg_dbg("\t%s: %d", id, widget->reg);
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "invert") == 0) {
Packit Service db8eaa
			ival = snd_config_get_bool(n);
Packit Service db8eaa
			if (ival < 0)
Packit Service db8eaa
				return -EINVAL;
Packit Service db8eaa
Packit Service db8eaa
			widget->invert = ival;
Packit Service db8eaa
			tplg_dbg("\t%s: %d", id, widget->invert);
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "subseq") == 0) {
Packit Service db8eaa
			if (tplg_get_integer(n, &ival, 0))
Packit Service db8eaa
				return -EINVAL;
Packit Service db8eaa
Packit Service db8eaa
			widget->subseq = ival;
Packit Service db8eaa
			tplg_dbg("\t%s: %d", id, widget->subseq);
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "event_type") == 0) {
Packit Service db8eaa
			if (tplg_get_integer(n, &ival, 0))
Packit Service db8eaa
				return -EINVAL;
Packit Service db8eaa
Packit Service db8eaa
			widget->event_type = ival;
Packit Service db8eaa
			tplg_dbg("\t%s: %d", id, widget->event_type);
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "event_flags") == 0) {
Packit Service db8eaa
			if (tplg_get_integer(n, &ival, 0))
Packit Service db8eaa
				return -EINVAL;
Packit Service db8eaa
Packit Service db8eaa
			widget->event_flags = ival;
Packit Service db8eaa
			tplg_dbg("\t%s: %d", id, widget->event_flags);
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "enum") == 0) {
Packit Service db8eaa
			err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_ENUM);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return err;
Packit Service db8eaa
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "mixer") == 0) {
Packit Service db8eaa
			err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_MIXER);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return err;
Packit Service db8eaa
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "bytes") == 0) {
Packit Service db8eaa
			err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_BYTES);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return err;
Packit Service db8eaa
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "data") == 0) {
Packit Service db8eaa
			err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_DATA);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return err;
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* save DAPM widget */
Packit Service db8eaa
int tplg_save_dapm_widget(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
Packit Service db8eaa
			  struct tplg_elem *elem,
Packit Service db8eaa
			  struct tplg_buf *dst, const char *pfx)
Packit Service db8eaa
{
Packit Service db8eaa
	struct snd_soc_tplg_dapm_widget *widget = elem->widget;
Packit Service db8eaa
	const char *s;
Packit Service db8eaa
	char pfx2[16];
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
Packit Service db8eaa
	if (err >= 0 && elem->index)
Packit Service db8eaa
		err = tplg_save_printf(dst, pfx, "\tindex %u\n",
Packit Service db8eaa
				       elem->index);
Packit Service db8eaa
	if (err >= 0) {
Packit Service db8eaa
		s = get_widget_name(widget->id);
Packit Service db8eaa
		if (s)
Packit Service db8eaa
			err = tplg_save_printf(dst, pfx, "\ttype %s\n", s);
Packit Service db8eaa
		else
Packit Service db8eaa
			err = tplg_save_printf(dst, pfx, "\ttype %u\n",
Packit Service db8eaa
					       widget->id);
Packit Service db8eaa
	}
Packit Service db8eaa
	if (err >= 0 && widget->sname[0])
Packit Service db8eaa
		err = tplg_save_printf(dst, pfx, "\tstream_name '%s'\n",
Packit Service db8eaa
				       widget->sname);
Packit Service db8eaa
	if (err >= 0 && widget->reg)
Packit Service db8eaa
		err = tplg_save_printf(dst, pfx, "\tno_pm 1\n");
Packit Service db8eaa
	if (err >= 0 && widget->shift)
Packit Service db8eaa
		err = tplg_save_printf(dst, pfx, "\tshift %u\n",
Packit Service db8eaa
				       widget->shift);
Packit Service db8eaa
	if (err >= 0 && widget->invert)
Packit Service db8eaa
		err = tplg_save_printf(dst, pfx, "\tinvert %u\n",
Packit Service db8eaa
				       widget->invert);
Packit Service db8eaa
	if (err >= 0 && widget->subseq)
Packit Service db8eaa
		err = tplg_save_printf(dst, pfx, "\tsubseq %u\n",
Packit Service db8eaa
				       widget->subseq);
Packit Service db8eaa
	if (err >= 0 && widget->event_type)
Packit Service db8eaa
		err = tplg_save_printf(dst, pfx, "\tevent_type %u\n",
Packit Service db8eaa
				       widget->event_type);
Packit Service db8eaa
	if (err >= 0 && widget->event_flags)
Packit Service db8eaa
		err = tplg_save_printf(dst, pfx, "\tevent_flags %u\n",
Packit Service db8eaa
				       widget->event_flags);
Packit Service db8eaa
	snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
Packit Service db8eaa
	if (err >= 0)
Packit Service db8eaa
		err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_ENUM,
Packit Service db8eaa
				     "enum", dst, pfx2);
Packit Service db8eaa
	if (err >= 0)
Packit Service db8eaa
		err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_MIXER,
Packit Service db8eaa
				     "mixer", dst, pfx2);
Packit Service db8eaa
	if (err >= 0)
Packit Service db8eaa
		err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_BYTES,
Packit Service db8eaa
				     "bytes", dst, pfx2);
Packit Service db8eaa
	if (err >= 0)
Packit Service db8eaa
		err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_DATA,
Packit Service db8eaa
				     "data", dst, pfx2);
Packit Service db8eaa
	if (err >= 0)
Packit Service db8eaa
		err = tplg_save_printf(dst, pfx, "}\n");
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
int tplg_add_route(snd_tplg_t *tplg, struct snd_tplg_graph_elem *t, int index)
Packit Service db8eaa
{
Packit Service db8eaa
	struct tplg_elem *elem;
Packit Service db8eaa
	struct snd_soc_tplg_dapm_graph_elem *line;
Packit Service db8eaa
Packit Service db8eaa
	if (!t->src || !t->sink)
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
Packit Service db8eaa
	elem = tplg_elem_new_route(tplg, index);
Packit Service db8eaa
	if (!elem)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
	line = elem->route;
Packit Service db8eaa
	snd_strlcpy(line->source, t->src, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit Service db8eaa
	if (t->ctl)
Packit Service db8eaa
		snd_strlcpy(line->control, t->ctl,
Packit Service db8eaa
				SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit Service db8eaa
	snd_strlcpy(line->sink, t->sink, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
int tplg_add_graph_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
Packit Service db8eaa
{
Packit Service db8eaa
	struct snd_tplg_graph_template *gt =  t->graph;
Packit Service db8eaa
	int i, ret;
Packit Service db8eaa
Packit Service db8eaa
	for (i = 0; i < gt->count; i++) {
Packit Service db8eaa
		ret = tplg_add_route(tplg, gt->elem + i, t->index);
Packit Service db8eaa
		if (ret < 0)
Packit Service db8eaa
			return ret;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
int tplg_add_widget_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
Packit Service db8eaa
{
Packit Service db8eaa
	struct snd_tplg_widget_template *wt = t->widget;
Packit Service db8eaa
	struct snd_soc_tplg_dapm_widget *w;
Packit Service db8eaa
	struct tplg_elem *elem;
Packit Service db8eaa
	int i, ret = 0;
Packit Service db8eaa
Packit Service db8eaa
	tplg_dbg("Widget: %s", wt->name);
Packit Service db8eaa
Packit Service db8eaa
	elem = tplg_elem_new_common(tplg, NULL, wt->name,
Packit Service db8eaa
		SND_TPLG_TYPE_DAPM_WIDGET);
Packit Service db8eaa
	if (!elem)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
	/* init new widget */
Packit Service db8eaa
	w = elem->widget;
Packit Service db8eaa
	w->size = elem->size;
Packit Service db8eaa
Packit Service db8eaa
	w->id = wt->id;
Packit Service db8eaa
	snd_strlcpy(w->name, wt->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit Service db8eaa
	if (wt->sname)
Packit Service db8eaa
		snd_strlcpy(w->sname, wt->sname, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit Service db8eaa
	w->reg = wt->reg;
Packit Service db8eaa
	w->shift = wt->shift;
Packit Service db8eaa
	w->mask = wt->mask;
Packit Service db8eaa
	w->subseq = wt->subseq;
Packit Service db8eaa
	w->invert = wt->invert;
Packit Service db8eaa
	w->ignore_suspend = wt->ignore_suspend;
Packit Service db8eaa
	w->event_flags = wt->event_flags;
Packit Service db8eaa
	w->event_type = wt->event_type;
Packit Service db8eaa
Packit Service db8eaa
	/* add private data */
Packit Service db8eaa
	if (wt->priv != NULL && wt->priv->size > 0) {
Packit Service db8eaa
		ret = tplg_add_data(tplg, elem, wt->priv,
Packit Service db8eaa
				    sizeof(*wt->priv) + wt->priv->size);
Packit Service db8eaa
		if (ret < 0) {
Packit Service db8eaa
			tplg_elem_free(elem);
Packit Service db8eaa
			return ret;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	/* add controls to the widget's reference list */
Packit Service db8eaa
	for (i = 0 ; i < wt->num_ctls; i++) {
Packit Service db8eaa
		struct snd_tplg_ctl_template *ct = wt->ctl[i];
Packit Service db8eaa
		struct tplg_elem *elem_ctl;
Packit Service db8eaa
		struct snd_tplg_mixer_template *mt;
Packit Service db8eaa
		struct snd_tplg_bytes_template *bt;
Packit Service db8eaa
		struct snd_tplg_enum_template *et;
Packit Service db8eaa
Packit Service db8eaa
		if (!ct) {
Packit Service db8eaa
			tplg_elem_free(elem);
Packit Service db8eaa
			return -EINVAL;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		switch (ct->type) {
Packit Service db8eaa
		case SND_SOC_TPLG_TYPE_MIXER:
Packit Service db8eaa
			mt = container_of(ct, struct snd_tplg_mixer_template, hdr);
Packit Service db8eaa
			ret = tplg_add_mixer(tplg, mt, &elem_ctl);
Packit Service db8eaa
			break;
Packit Service db8eaa
Packit Service db8eaa
		case SND_SOC_TPLG_TYPE_BYTES:
Packit Service db8eaa
			bt = container_of(ct, struct snd_tplg_bytes_template, hdr);
Packit Service db8eaa
			ret = tplg_add_bytes(tplg, bt, &elem_ctl);
Packit Service db8eaa
			break;
Packit Service db8eaa
Packit Service db8eaa
		case SND_SOC_TPLG_TYPE_ENUM:
Packit Service db8eaa
			et = container_of(ct, struct snd_tplg_enum_template, hdr);
Packit Service db8eaa
			ret = tplg_add_enum(tplg, et, &elem_ctl);
Packit Service db8eaa
			break;
Packit Service db8eaa
Packit Service db8eaa
		default:
Packit Service db8eaa
			SNDERR("widget %s: invalid type %d for ctl %d",
Packit Service db8eaa
				wt->name, ct->type, i);
Packit Service 01c0b7
			ret = -EINVAL;
Packit Service db8eaa
			break;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (ret < 0) {
Packit Service db8eaa
			tplg_elem_free(elem);
Packit Service db8eaa
			return ret;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		ret = tplg_ref_add_elem(elem, elem_ctl);
Packit Service db8eaa
		if (ret < 0) {
Packit Service db8eaa
			tplg_elem_free(elem);
Packit Service db8eaa
			return ret;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* decode dapm widget from the binary input */
Packit Service db8eaa
int tplg_decode_dapm_widget(snd_tplg_t *tplg,
Packit Service db8eaa
			    size_t pos,
Packit Service db8eaa
			    struct snd_soc_tplg_hdr *hdr,
Packit Service db8eaa
			    void *bin, size_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	struct list_head heap;
Packit Service db8eaa
	struct snd_soc_tplg_dapm_widget *w;
Packit Service db8eaa
	snd_tplg_obj_template_t t;
Packit Service db8eaa
	struct snd_tplg_widget_template *wt;
Packit Service db8eaa
	struct snd_tplg_mixer_template *mt;
Packit Service db8eaa
	struct snd_tplg_enum_template *et;
Packit Service db8eaa
	struct snd_tplg_bytes_template *bt;
Packit Service db8eaa
	struct snd_soc_tplg_ctl_hdr *chdr;
Packit Service db8eaa
	struct snd_soc_tplg_mixer_control *mc;
Packit Service db8eaa
	struct snd_soc_tplg_enum_control *ec;
Packit Service db8eaa
	struct snd_soc_tplg_bytes_control *bc;
Packit Service db8eaa
	size_t size2;
Packit Service db8eaa
	unsigned int index;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	err = tplg_decode_template(tplg, pos, hdr, &t);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
Packit Service db8eaa
next:
Packit Service db8eaa
	INIT_LIST_HEAD(&heap;;
Packit Service db8eaa
	w = bin;
Packit Service db8eaa
Packit Service db8eaa
	if (size < sizeof(*w)) {
Packit Service db8eaa
		SNDERR("dapm widget: small size %d", size);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (sizeof(*w) != w->size) {
Packit Service db8eaa
		SNDERR("dapm widget: unknown element size %d (expected %zd)",
Packit Service db8eaa
		       w->size, sizeof(*w));
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (w->num_kcontrols > 16) {
Packit Service db8eaa
		SNDERR("dapm widget: too many kcontrols %d",
Packit Service db8eaa
		       w->num_kcontrols);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	tplg_log(tplg, 'D', pos, "dapm widget: size %d private size %d kcontrols %d",
Packit Service db8eaa
		 w->size, w->priv.size, w->num_kcontrols);
Packit Service db8eaa
Packit Service db8eaa
	wt = tplg_calloc(&heap, sizeof(*wt) + sizeof(void *) * w->num_kcontrols);
Packit Service db8eaa
	if (wt == NULL)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
	wt->id = w->id;
Packit Service db8eaa
	wt->name = w->name;
Packit Service db8eaa
	wt->sname = w->sname;
Packit Service db8eaa
	wt->reg = w->reg;
Packit Service db8eaa
	wt->shift = w->shift;
Packit Service db8eaa
	wt->mask = w->mask;
Packit Service db8eaa
	wt->subseq = w->subseq;
Packit Service db8eaa
	wt->invert = w->invert;
Packit Service db8eaa
	wt->ignore_suspend = w->ignore_suspend;
Packit Service db8eaa
	wt->event_flags = w->event_flags;
Packit Service db8eaa
	wt->event_type = w->event_type;
Packit Service db8eaa
Packit Service db8eaa
	tplg_log(tplg, 'D', pos, "dapm widget: name '%s' sname '%s'",
Packit Service db8eaa
		 wt->name, wt->sname);
Packit Service db8eaa
Packit Service db8eaa
	if (sizeof(*w) + w->priv.size > size) {
Packit Service db8eaa
		SNDERR("dapm widget: wrong private data size %d",
Packit Service db8eaa
		       w->priv.size);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	tplg_log(tplg, 'D', pos + offsetof(struct snd_soc_tplg_dapm_widget, priv),
Packit Service db8eaa
		 "dapm widget: private start");
Packit Service db8eaa
Packit Service db8eaa
	wt->priv = &w->priv;
Packit Service db8eaa
	bin += sizeof(*w) + w->priv.size;
Packit Service db8eaa
	size -= sizeof(*w) + w->priv.size;
Packit Service db8eaa
	pos += sizeof(*w) + w->priv.size;
Packit Service db8eaa
Packit Service db8eaa
	for (index = 0; index < w->num_kcontrols; index++) {
Packit Service db8eaa
		chdr = bin;
Packit Service db8eaa
		switch (chdr->type) {
Packit Service db8eaa
		case SND_SOC_TPLG_TYPE_MIXER:
Packit Service db8eaa
			mt = tplg_calloc(&heap, sizeof(*mt));
Packit Service db8eaa
			if (mt == NULL) {
Packit Service db8eaa
				err = -ENOMEM;
Packit Service db8eaa
				goto retval;
Packit Service db8eaa
			}
Packit Service db8eaa
			wt->ctl[index] = (void *)mt;
Packit Service db8eaa
			wt->num_ctls++;
Packit Service db8eaa
			mc = bin;
Packit Service db8eaa
			size2 = mc->size + mc->priv.size;
Packit Service db8eaa
			tplg_log(tplg, 'D', pos, "kcontrol mixer size %zd", size2);
Packit Service db8eaa
			if (size2 > size) {
Packit Service db8eaa
				SNDERR("dapm widget: small mixer size %d",
Packit Service db8eaa
				       size2);
Packit Service db8eaa
				err = -EINVAL;
Packit Service db8eaa
				goto retval;
Packit Service db8eaa
			}
Packit Service db8eaa
			err = tplg_decode_control_mixer1(tplg, &heap, mt, pos,
Packit Service db8eaa
							 bin, size2);
Packit Service db8eaa
			break;
Packit Service db8eaa
		case SND_SOC_TPLG_TYPE_ENUM:
Packit Service db8eaa
			et = tplg_calloc(&heap, sizeof(*mt));
Packit Service db8eaa
			if (et == NULL) {
Packit Service db8eaa
				err = -ENOMEM;
Packit Service db8eaa
				goto retval;
Packit Service db8eaa
			}
Packit Service db8eaa
			wt->ctl[index] = (void *)et;
Packit Service db8eaa
			wt->num_ctls++;
Packit Service db8eaa
			ec = bin;
Packit Service db8eaa
			size2 = ec->size + ec->priv.size;
Packit Service db8eaa
			tplg_log(tplg, 'D', pos, "kcontrol enum size %zd", size2);
Packit Service db8eaa
			if (size2 > size) {
Packit Service db8eaa
				SNDERR("dapm widget: small enum size %d",
Packit Service db8eaa
				       size2);
Packit Service db8eaa
				err = -EINVAL;
Packit Service db8eaa
				goto retval;
Packit Service db8eaa
			}
Packit Service db8eaa
			err = tplg_decode_control_enum1(tplg, &heap, et, pos, ec);
Packit Service db8eaa
			break;
Packit Service db8eaa
		case SND_SOC_TPLG_TYPE_BYTES:
Packit Service db8eaa
			bt = tplg_calloc(&heap, sizeof(*bt));
Packit Service db8eaa
			if (bt == NULL) {
Packit Service db8eaa
				err = -ENOMEM;
Packit Service db8eaa
				goto retval;
Packit Service db8eaa
			}
Packit Service db8eaa
			wt->ctl[index] = (void *)bt;
Packit Service db8eaa
			wt->num_ctls++;
Packit Service db8eaa
			bc = bin;
Packit Service db8eaa
			size2 = bc->size + bc->priv.size;
Packit Service db8eaa
			tplg_log(tplg, 'D', pos, "kcontrol bytes size %zd", size2);
Packit Service db8eaa
			if (size2 > size) {
Packit Service db8eaa
				SNDERR("dapm widget: small bytes size %d",
Packit Service db8eaa
				       size2);
Packit Service db8eaa
				err = -EINVAL;
Packit Service db8eaa
				goto retval;
Packit Service db8eaa
			}
Packit Service db8eaa
			err = tplg_decode_control_bytes1(tplg, bt, pos,
Packit Service db8eaa
							 bin, size2);
Packit Service db8eaa
			break;
Packit Service db8eaa
		default:
Packit Service db8eaa
			SNDERR("dapm widget: wrong control type %d",
Packit Service db8eaa
			       chdr->type);
Packit Service db8eaa
			err = -EINVAL;
Packit Service db8eaa
			goto retval;
Packit Service db8eaa
		}
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			goto retval;
Packit Service db8eaa
		bin += size2;
Packit Service db8eaa
		size -= size2;
Packit Service db8eaa
		pos += size2;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	t.widget = wt;
Packit Service db8eaa
	err = snd_tplg_add_object(tplg, &t);
Packit Service db8eaa
	tplg_free(&heap;;
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
	if (size > 0)
Packit Service db8eaa
		goto next;
Packit Service db8eaa
	return 0;
Packit Service db8eaa
Packit Service db8eaa
retval:
Packit Service db8eaa
	tplg_free(&heap;;
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* decode dapm link from the binary input */
Packit Service db8eaa
int tplg_decode_dapm_graph(snd_tplg_t *tplg,
Packit Service db8eaa
			   size_t pos,
Packit Service db8eaa
			   struct snd_soc_tplg_hdr *hdr,
Packit Service db8eaa
			   void *bin, size_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	struct snd_soc_tplg_dapm_graph_elem *g;
Packit Service db8eaa
	snd_tplg_obj_template_t t;
Packit Service db8eaa
	struct snd_tplg_graph_template *gt;
Packit Service db8eaa
	struct snd_tplg_graph_elem *ge;
Packit Service db8eaa
	size_t asize;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	err = tplg_decode_template(tplg, pos, hdr, &t);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
Packit Service db8eaa
	asize = sizeof(*gt) + (size / sizeof(*g)) * sizeof(*ge);
Packit Service db8eaa
	gt = alloca(asize);
Packit Service db8eaa
	memset(gt, 0, asize);
Packit Service db8eaa
	for (ge = gt->elem; size > 0; ge++) {
Packit Service db8eaa
		g = bin;
Packit Service db8eaa
		if (size < sizeof(*g)) {
Packit Service db8eaa
			SNDERR("dapm graph: small size %d", size);
Packit Service db8eaa
			return -EINVAL;
Packit Service db8eaa
		}
Packit Service db8eaa
		ge->src = g->source;
Packit Service db8eaa
		ge->ctl = g->control;
Packit Service db8eaa
		ge->sink = g->sink;
Packit Service db8eaa
		gt->count++;
Packit Service db8eaa
		tplg_log(tplg, 'D', pos, "dapm graph: src='%s' ctl='%s' sink='%s'",
Packit Service db8eaa
			ge->src, ge->ctl, ge->sink);
Packit Service db8eaa
		bin += sizeof(*g);
Packit Service db8eaa
		size -= sizeof(*g);
Packit Service db8eaa
		pos += sizeof(*g);
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	t.graph = gt;
Packit Service db8eaa
	return snd_tplg_add_object(tplg, &t);
Packit Service db8eaa
}