Blame src/topology/ctl.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
#define ENUM_VAL_SIZE 	(SNDRV_CTL_ELEM_ID_NAME_MAXLEN >> 2)
Packit 4a16fb
Packit 4a16fb
struct ctl_access_elem {
Packit 4a16fb
	const char *name;
Packit 4a16fb
	unsigned int value;
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
/* CTL access strings and codes */
Packit Service f36a15
/* place the multi-bit values on top - like read_write - for save */
Packit 4a16fb
static const struct ctl_access_elem ctl_access[] = {
Packit Service f36a15
	{"read_write", SNDRV_CTL_ELEM_ACCESS_READWRITE},
Packit Service f36a15
	{"tlv_read_write", SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE},
Packit 4a16fb
	{"read", SNDRV_CTL_ELEM_ACCESS_READ},
Packit 4a16fb
	{"write", SNDRV_CTL_ELEM_ACCESS_WRITE},
Packit 4a16fb
	{"volatile", SNDRV_CTL_ELEM_ACCESS_VOLATILE},
Packit 4a16fb
	{"tlv_read", SNDRV_CTL_ELEM_ACCESS_TLV_READ},
Packit 4a16fb
	{"tlv_write", SNDRV_CTL_ELEM_ACCESS_TLV_WRITE},
Packit 4a16fb
	{"tlv_command", SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND},
Packit 4a16fb
	{"inactive", SNDRV_CTL_ELEM_ACCESS_INACTIVE},
Packit 4a16fb
	{"lock", SNDRV_CTL_ELEM_ACCESS_LOCK},
Packit 4a16fb
	{"owner", SNDRV_CTL_ELEM_ACCESS_OWNER},
Packit 4a16fb
	{"tlv_callback", SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK},
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
/* find CTL access strings and conver to values */
Packit 4a16fb
static int parse_access_values(snd_config_t *cfg,
Packit Service f36a15
			       struct snd_soc_tplg_ctl_hdr *hdr)
Packit 4a16fb
{
Packit 4a16fb
	snd_config_iterator_t i, next;
Packit 4a16fb
	snd_config_t *n;
Packit 4a16fb
	const char *value = NULL;
Packit 4a16fb
	unsigned int j;
Packit 4a16fb
Packit Service f36a15
	tplg_dbg(" Access:");
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
		/* match access value and set flags */
Packit 4a16fb
		for (j = 0; j < ARRAY_SIZE(ctl_access); j++) {
Packit 4a16fb
			if (strcmp(value, ctl_access[j].name) == 0) {
Packit 4a16fb
				hdr->access |= ctl_access[j].value;
Packit Service f36a15
				tplg_dbg("\t%s", value);
Packit 4a16fb
				break;
Packit 4a16fb
			}
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* Parse Access */
Packit 4a16fb
int parse_access(snd_config_t *cfg,
Packit Service f36a15
		 struct snd_soc_tplg_ctl_hdr *hdr)
Packit 4a16fb
{
Packit 4a16fb
	snd_config_iterator_t i, next;
Packit 4a16fb
	snd_config_t *n;
Packit 4a16fb
	const char *id;
Packit 4a16fb
	int err = 0;
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
		if (strcmp(id, "access") == 0) {
Packit 4a16fb
			err = parse_access_values(n, hdr);
Packit 4a16fb
			if (err < 0) {
Packit Service f36a15
				SNDERR("failed to parse access");
Packit 4a16fb
				return err;
Packit 4a16fb
			}
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit Service f36a15
/* Save Access */
Packit Service f36a15
static int tplg_save_access(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
Packit Service f36a15
			    struct snd_soc_tplg_ctl_hdr *hdr, char **dst,
Packit Service f36a15
			    const char *pfx)
Packit Service f36a15
{
Packit Service f36a15
	const char *last;
Packit Service f36a15
	unsigned int j, count, access, cval;
Packit Service f36a15
	int err;
Packit Service f36a15
Packit Service f36a15
	if (hdr->access == 0)
Packit Service f36a15
		return 0;
Packit Service f36a15
Packit Service f36a15
	access = hdr->access;
Packit Service f36a15
	for (j = 0, count = 0, last = NULL; j < ARRAY_SIZE(ctl_access); j++) {
Packit Service f36a15
		cval = ctl_access[j].value;
Packit Service f36a15
		if ((access & cval) == cval) {
Packit Service f36a15
			access &= ~cval;
Packit Service f36a15
			last = ctl_access[j].name;
Packit Service f36a15
			count++;
Packit Service f36a15
		}
Packit Service f36a15
	}
Packit Service f36a15
	if (count == 1)
Packit Service f36a15
		return tplg_save_printf(dst, pfx, "access.0 %s\n", last);
Packit Service f36a15
	err = tplg_save_printf(dst, pfx, "access [\n");
Packit Service f36a15
	if (err < 0)
Packit Service f36a15
		return err;
Packit Service f36a15
	access = hdr->access;
Packit Service f36a15
	for (j = 0; j < ARRAY_SIZE(ctl_access); j++) {
Packit Service f36a15
		cval = ctl_access[j].value;
Packit Service f36a15
		if ((access & cval) == cval) {
Packit Service f36a15
			err = tplg_save_printf(dst, pfx, "\t%s\n",
Packit Service f36a15
					       ctl_access[j].name);
Packit Service f36a15
			if (err < 0)
Packit Service f36a15
				return err;
Packit Service f36a15
			access &= ~cval;
Packit Service f36a15
		}
Packit Service f36a15
	}
Packit Service f36a15
	return tplg_save_printf(dst, pfx, "]\n");
Packit Service f36a15
}
Packit Service f36a15
Packit 4a16fb
/* copy referenced TLV to the mixer control */
Packit 4a16fb
static int copy_tlv(struct tplg_elem *elem, struct tplg_elem *ref)
Packit 4a16fb
{
Packit 4a16fb
	struct snd_soc_tplg_mixer_control *mixer_ctrl =  elem->mixer_ctrl;
Packit 4a16fb
	struct snd_soc_tplg_ctl_tlv *tlv = ref->tlv;
Packit 4a16fb
Packit Service f36a15
	tplg_dbg("TLV '%s' used by '%s", ref->id, elem->id);
Packit 4a16fb
Packit 4a16fb
	/* TLV has a fixed size */
Packit 4a16fb
	mixer_ctrl->hdr.tlv = *tlv;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* check referenced TLV for a mixer control */
Packit 4a16fb
static int tplg_build_mixer_control(snd_tplg_t *tplg,
Packit Service f36a15
				    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
	/* for each ref in this control elem */
Packit 4a16fb
	list_for_each(pos, base) {
Packit 4a16fb
Packit 4a16fb
		ref = list_entry(pos, struct tplg_ref, list);
Packit 4a16fb
		if (ref->elem)
Packit 4a16fb
			continue;
Packit 4a16fb
Packit 4a16fb
		if (ref->type == SND_TPLG_TYPE_TLV) {
Packit 4a16fb
			ref->elem = tplg_elem_lookup(&tplg->tlv_list,
Packit 4a16fb
				ref->id, SND_TPLG_TYPE_TLV, elem->index);
Packit 4a16fb
			if (ref->elem)
Packit 4a16fb
				 err = copy_tlv(elem, ref->elem);
Packit 4a16fb
Packit 4a16fb
		} else if (ref->type == SND_TPLG_TYPE_DATA) {
Packit 4a16fb
			err = tplg_copy_data(tplg, elem, ref);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (!ref->elem) {
Packit Service f36a15
			SNDERR("cannot find '%s' referenced by"
Packit Service f36a15
				" control '%s'", ref->id, elem->id);
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		} else if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static void copy_enum_texts(struct tplg_elem *enum_elem,
Packit Service f36a15
			    struct tplg_elem *ref_elem)
Packit 4a16fb
{
Packit 4a16fb
	struct snd_soc_tplg_enum_control *ec = enum_elem->enum_ctrl;
Packit 4a16fb
	struct tplg_texts *texts = ref_elem->texts;
Packit 4a16fb
Packit 4a16fb
	memcpy(ec->texts, texts->items,
Packit 4a16fb
		SND_SOC_TPLG_NUM_TEXTS * SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit 4a16fb
	ec->items += texts->num_items;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* check referenced text for a enum control */
Packit 4a16fb
static int tplg_build_enum_control(snd_tplg_t *tplg,
Packit Service f36a15
				   struct tplg_elem *elem)
Packit 4a16fb
{
Packit 4a16fb
	struct tplg_ref *ref;
Packit 4a16fb
	struct list_head *base, *pos;
Packit 4a16fb
	int err;
Packit 4a16fb
Packit 4a16fb
	base = &elem->ref_list;
Packit 4a16fb
Packit 4a16fb
	list_for_each(pos, base) {
Packit 4a16fb
Packit 4a16fb
		ref = list_entry(pos, struct tplg_ref, list);
Packit 4a16fb
		if (ref->elem)
Packit 4a16fb
			continue;
Packit 4a16fb
Packit 4a16fb
		if (ref->type == SND_TPLG_TYPE_TEXT) {
Packit 4a16fb
			ref->elem = tplg_elem_lookup(&tplg->text_list,
Packit 4a16fb
				ref->id, SND_TPLG_TYPE_TEXT, elem->index);
Packit 4a16fb
			if (ref->elem)
Packit 4a16fb
				copy_enum_texts(elem, ref->elem);
Packit 4a16fb
Packit 4a16fb
		} else if (ref->type == SND_TPLG_TYPE_DATA) {
Packit 4a16fb
			err = tplg_copy_data(tplg, elem, ref);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
		}
Packit 4a16fb
		if (!ref->elem) {
Packit Service f36a15
			SNDERR("cannot find '%s' referenced by"
Packit Service f36a15
				" control '%s'", ref->id, elem->id);
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* check referenced private data for a byte control */
Packit 4a16fb
static int tplg_build_bytes_control(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;
Packit 4a16fb
Packit 4a16fb
	base = &elem->ref_list;
Packit 4a16fb
Packit 4a16fb
	list_for_each(pos, base) {
Packit 4a16fb
Packit 4a16fb
		ref = list_entry(pos, struct tplg_ref, list);
Packit 4a16fb
		if (ref->elem)
Packit 4a16fb
			continue;
Packit 4a16fb
Packit 4a16fb
		 if (ref->type == SND_TPLG_TYPE_DATA) {
Packit 4a16fb
			err = tplg_copy_data(tplg, elem, ref);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
int tplg_build_controls(snd_tplg_t *tplg)
Packit 4a16fb
{
Packit 4a16fb
	struct list_head *base, *pos;
Packit 4a16fb
	struct tplg_elem *elem;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
Packit 4a16fb
	base = &tplg->mixer_list;
Packit 4a16fb
	list_for_each(pos, base) {
Packit 4a16fb
Packit 4a16fb
		elem = list_entry(pos, struct tplg_elem, list);
Packit 4a16fb
		err = tplg_build_mixer_control(tplg, elem);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
Packit 4a16fb
		/* add control to manifest */
Packit 4a16fb
		tplg->manifest.control_elems++;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	base = &tplg->enum_list;
Packit 4a16fb
	list_for_each(pos, base) {
Packit 4a16fb
Packit 4a16fb
		elem = list_entry(pos, struct tplg_elem, list);
Packit 4a16fb
		err = tplg_build_enum_control(tplg, elem);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
Packit 4a16fb
		/* add control to manifest */
Packit 4a16fb
		tplg->manifest.control_elems++;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	base = &tplg->bytes_ext_list;
Packit 4a16fb
	list_for_each(pos, base) {
Packit 4a16fb
Packit 4a16fb
		elem = list_entry(pos, struct tplg_elem, list);
Packit 4a16fb
		err = tplg_build_bytes_control(tplg, elem);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
Packit 4a16fb
		/* add control to manifest */
Packit 4a16fb
		tplg->manifest.control_elems++;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
Packit 4a16fb
/*
Packit 4a16fb
 * Parse TLV of DBScale type.
Packit 4a16fb
 *
Packit 4a16fb
 * Parse DBScale describing min, step, mute in DB.
Packit 4a16fb
 */
Packit 4a16fb
static int tplg_parse_tlv_dbscale(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 Service f36a15
	struct snd_soc_tplg_ctl_tlv *tplg_tlv = elem->tlv;
Packit 4a16fb
	struct snd_soc_tplg_tlv_dbscale *scale;
Packit Service f36a15
	const char *id = NULL;
Packit Service f36a15
	int val;
Packit 4a16fb
Packit Service f36a15
	tplg_dbg(" scale: %s", elem->id);
Packit 4a16fb
Packit 4a16fb
	tplg_tlv->size = sizeof(struct snd_soc_tplg_ctl_tlv);
Packit 4a16fb
	tplg_tlv->type = SNDRV_CTL_TLVT_DB_SCALE;
Packit 4a16fb
	scale = &tplg_tlv->scale;
Packit 4a16fb
Packit 4a16fb
	snd_config_for_each(i, next, cfg) {
Packit 4a16fb
Packit 4a16fb
		n = snd_config_iterator_entry(i);
Packit 4a16fb
Packit 4a16fb
		/* get ID */
Packit Service f36a15
		if (snd_config_get_id(n, &id) < 0)
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
Packit 4a16fb
		/* get value */
Packit Service f36a15
		if (tplg_get_integer(n, &val, 0))
Packit 4a16fb
			continue;
Packit 4a16fb
Packit Service f36a15
		tplg_dbg("\t%s = %i", id, val);
Packit 4a16fb
Packit 4a16fb
		/* get TLV data */
Packit 4a16fb
		if (strcmp(id, "min") == 0)
Packit Service f36a15
			scale->min = val;
Packit 4a16fb
		else if (strcmp(id, "step") == 0)
Packit Service f36a15
			scale->step = val;
Packit 4a16fb
		else if (strcmp(id, "mute") == 0)
Packit Service f36a15
			scale->mute = val;
Packit 4a16fb
		else
Packit Service f36a15
			SNDERR("unknown id '%s'", id);
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* Parse TLV */
Packit 4a16fb
int tplg_parse_tlv(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
	const char *id;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
	struct tplg_elem *elem;
Packit 4a16fb
Packit 4a16fb
	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_TLV);
Packit 4a16fb
	if (!elem)
Packit 4a16fb
		return -ENOMEM;
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
		if (strcmp(id, "scale") == 0) {
Packit 4a16fb
			err = tplg_parse_tlv_dbscale(n, elem);
Packit 4a16fb
			if (err < 0) {
Packit Service f36a15
				SNDERR("failed to DBScale");
Packit 4a16fb
				return err;
Packit 4a16fb
			}
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
Packit Service f36a15
/* save TLV data */
Packit Service f36a15
int tplg_save_tlv(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_ctl_tlv *tlv = elem->tlv;
Packit Service f36a15
	struct snd_soc_tplg_tlv_dbscale *scale;
Packit Service f36a15
	int err;
Packit Service f36a15
Packit Service f36a15
	if (tlv->type != SNDRV_CTL_TLVT_DB_SCALE) {
Packit Service f36a15
		SNDERR("unknown TLV type");
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	scale = &tlv->scale;
Packit Service f36a15
	err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
Packit Service f36a15
	if (err >= 0)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\tscale {\n");
Packit Service f36a15
	if (err >= 0 && scale->min)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\t\tmin %i\n", scale->min);
Packit Service f36a15
	if (err >= 0 && scale->step > 0)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\t\tstep %i\n", scale->step);
Packit Service f36a15
	if (err >= 0 && scale->mute > 0)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\t\tmute %i\n", scale->mute);
Packit Service f36a15
	if (err >= 0)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\t}\n");
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
/* Parse Control Bytes */
Packit 4a16fb
int tplg_parse_control_bytes(snd_tplg_t *tplg,
Packit Service f36a15
			     snd_config_t *cfg,
Packit Service f36a15
			     void *private ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	struct snd_soc_tplg_bytes_control *be;
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 err, ival;
Packit 4a16fb
	bool access_set = false, tlv_set = false;
Packit 4a16fb
Packit 4a16fb
	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_BYTES);
Packit 4a16fb
	if (!elem)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
Packit 4a16fb
	be = elem->bytes_ext;
Packit 4a16fb
	be->size = elem->size;
Packit 4a16fb
	snd_strlcpy(be->hdr.name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit 4a16fb
	be->hdr.type = SND_SOC_TPLG_TYPE_BYTES;
Packit 4a16fb
Packit Service f36a15
	tplg_dbg(" Control Bytes: %s", elem->id);
Packit 4a16fb
Packit 4a16fb
	snd_config_for_each(i, next, cfg) {
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, "base") == 0) {
Packit Service f36a15
			if (tplg_get_integer(n, &ival, 0))
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit Service f36a15
			be->base = ival;
Packit Service f36a15
			tplg_dbg("\t%s: %d", id, be->base);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "num_regs") == 0) {
Packit Service f36a15
			if (tplg_get_integer(n, &ival, 0))
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit Service f36a15
			be->num_regs = ival;
Packit Service f36a15
			tplg_dbg("\t%s: %d", id, be->num_regs);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "max") == 0) {
Packit Service f36a15
			if (tplg_get_integer(n, &ival, 0))
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit Service f36a15
			be->max = ival;
Packit Service f36a15
			tplg_dbg("\t%s: %d", id, be->max);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "mask") == 0) {
Packit Service f36a15
			if (tplg_get_integer(n, &ival, 16))
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit Service f36a15
			be->mask = ival;
Packit Service f36a15
			tplg_dbg("\t%s: %d", id, be->mask);
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
		if (strcmp(id, "tlv") == 0) {
Packit 4a16fb
			if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit 4a16fb
			err = tplg_ref_add(elem, SND_TPLG_TYPE_TLV, val);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
Packit 4a16fb
			tlv_set = true;
Packit Service f36a15
			tplg_dbg("\t%s: %s", id, val);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "ops") == 0) {
Packit 4a16fb
			err = tplg_parse_compound(tplg, n, tplg_parse_ops,
Packit 4a16fb
				&be->hdr);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "extops") == 0) {
Packit 4a16fb
			err = tplg_parse_compound(tplg, n, tplg_parse_ext_ops,
Packit 4a16fb
				be);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "access") == 0) {
Packit 4a16fb
			err = parse_access(cfg, &be->hdr);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
			access_set = true;
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	/* set CTL access to default values if none are provided */
Packit 4a16fb
	if (!access_set) {
Packit 4a16fb
Packit 4a16fb
		be->hdr.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
Packit 4a16fb
		if (tlv_set)
Packit 4a16fb
			be->hdr.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit Service f36a15
/* save control bytes */
Packit Service f36a15
int tplg_save_control_bytes(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_bytes_control *be = elem->bytes_ext;
Packit Service f36a15
	char pfx2[16];
Packit Service f36a15
	int err;
Packit Service f36a15
Packit Service f36a15
	if (!be)
Packit Service f36a15
		return 0;
Packit Service f36a15
Packit Service f36a15
	snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
Packit Service f36a15
	err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
Packit Service f36a15
	if (err < 0)
Packit Service f36a15
		return err;
Packit Service f36a15
	if (err >= 0 && elem->index > 0)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\tindex %u\n", elem->index);
Packit Service f36a15
	if (err >= 0 && be->base > 0)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\tbase %u\n", be->base);
Packit Service f36a15
	if (err >= 0 && be->num_regs > 0)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\tnum_regs %u\n", be->num_regs);
Packit Service f36a15
	if (err >= 0 && be->max > 0)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\tmax %u\n", be->max);
Packit Service f36a15
	if (err >= 0 && be->mask > 0)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\tmask %u\n", be->mask);
Packit Service f36a15
	if (err >= 0)
Packit Service f36a15
		err = tplg_save_ops(tplg, &be->hdr, dst, pfx2);
Packit Service f36a15
	if (err >= 0)
Packit Service f36a15
		err = tplg_save_ext_ops(tplg, be, dst, pfx2);
Packit Service f36a15
	if (err >= 0)
Packit Service f36a15
		err = tplg_save_access(tplg, &be->hdr, dst, pfx2);
Packit Service f36a15
	if (err >= 0)
Packit Service f36a15
		err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_TLV,
Packit Service f36a15
				     "tlv", 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 4a16fb
/* Parse Control Enums. */
Packit 4a16fb
int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg,
Packit Service f36a15
			    void *private ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	struct snd_soc_tplg_enum_control *ec;
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 err, j;
Packit 4a16fb
	bool access_set = false;
Packit 4a16fb
Packit 4a16fb
	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_ENUM);
Packit 4a16fb
	if (!elem)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
Packit 4a16fb
	ec = elem->enum_ctrl;
Packit 4a16fb
	snd_strlcpy(ec->hdr.name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit 4a16fb
	ec->hdr.type = SND_SOC_TPLG_TYPE_ENUM;
Packit 4a16fb
	ec->size = elem->size;
Packit 4a16fb
	tplg->channel_idx = 0;
Packit 4a16fb
Packit 4a16fb
	/* set channel reg to default state */
Packit Service f36a15
	for (j = 0; j < SND_SOC_TPLG_MAX_CHAN; j++) {
Packit 4a16fb
		ec->channel[j].reg = -1;
Packit Service f36a15
	}
Packit 4a16fb
Packit Service f36a15
	tplg_dbg(" Control Enum: %s", elem->id);
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, "texts") == 0) {
Packit 4a16fb
			if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit 4a16fb
			tplg_ref_add(elem, SND_TPLG_TYPE_TEXT, val);
Packit Service f36a15
			tplg_dbg("\t%s: %s", id, val);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "channel") == 0) {
Packit 4a16fb
			if (ec->num_channels >= SND_SOC_TPLG_MAX_CHAN) {
Packit Service f36a15
				SNDERR("too many channels %s", elem->id);
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
			}
Packit 4a16fb
Packit 4a16fb
			err = tplg_parse_compound(tplg, n, tplg_parse_channel,
Packit 4a16fb
				ec->channel);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
Packit 4a16fb
			ec->num_channels = tplg->channel_idx;
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "ops") == 0) {
Packit 4a16fb
			err = tplg_parse_compound(tplg, n, tplg_parse_ops,
Packit 4a16fb
				&ec->hdr);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
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
		if (strcmp(id, "access") == 0) {
Packit 4a16fb
			err = parse_access(cfg, &ec->hdr);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
			access_set = true;
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	/* set CTL access to default values if none are provided */
Packit 4a16fb
	if (!access_set) {
Packit 4a16fb
		ec->hdr.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit Service f36a15
/* save control eunm */
Packit Service f36a15
int tplg_save_control_enum(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_enum_control *ec = elem->enum_ctrl;
Packit Service f36a15
	char pfx2[16];
Packit Service f36a15
	int err;
Packit Service f36a15
Packit Service f36a15
	if (!ec)
Packit Service f36a15
		return 0;
Packit Service f36a15
Packit Service f36a15
	snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
Packit Service f36a15
	err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
Packit Service f36a15
	if (err < 0)
Packit Service f36a15
		return err;
Packit Service f36a15
	if (err >= 0 && elem->index > 0)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\tindex %u\n", elem->index);
Packit Service f36a15
	if (err >= 0)
Packit Service f36a15
		err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_TEXT,
Packit Service f36a15
				     "texts", dst, pfx2);
Packit Service f36a15
	if (err >= 0)
Packit Service f36a15
		err = tplg_save_channels(tplg, ec->channel, ec->num_channels,
Packit Service f36a15
					 dst, pfx2);
Packit Service f36a15
	if (err >= 0)
Packit Service f36a15
		err = tplg_save_ops(tplg, &ec->hdr, dst, pfx2);
Packit Service f36a15
	if (err >= 0)
Packit Service f36a15
		err = tplg_save_access(tplg, &ec->hdr, 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 4a16fb
/* Parse Controls.
Packit 4a16fb
 *
Packit 4a16fb
 * Mixer control. Supports multiple channels.
Packit 4a16fb
 */
Packit 4a16fb
int tplg_parse_control_mixer(snd_tplg_t *tplg,
Packit Service f36a15
			     snd_config_t *cfg,
Packit Service f36a15
			     void *private ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	struct snd_soc_tplg_mixer_control *mc;
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 err, j, ival;
Packit 4a16fb
	bool access_set = false, tlv_set = false;
Packit 4a16fb
Packit 4a16fb
	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_MIXER);
Packit 4a16fb
	if (!elem)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
Packit 4a16fb
	/* init new mixer */
Packit 4a16fb
	mc = elem->mixer_ctrl;
Packit 4a16fb
	snd_strlcpy(mc->hdr.name, elem->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit 4a16fb
	mc->hdr.type = SND_SOC_TPLG_TYPE_MIXER;
Packit 4a16fb
	mc->size = elem->size;
Packit 4a16fb
	tplg->channel_idx = 0;
Packit 4a16fb
Packit 4a16fb
	/* set channel reg to default state */
Packit 4a16fb
	for (j = 0; j < SND_SOC_TPLG_MAX_CHAN; j++)
Packit 4a16fb
		mc->channel[j].reg = -1;
Packit 4a16fb
Packit Service f36a15
	tplg_dbg(" Control Mixer: %s", elem->id);
Packit 4a16fb
Packit 4a16fb
	/* giterate trough each mixer elment */
Packit 4a16fb
	snd_config_for_each(i, next, cfg) {
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, "channel") == 0) {
Packit 4a16fb
			if (mc->num_channels >= SND_SOC_TPLG_MAX_CHAN) {
Packit Service f36a15
				SNDERR("too many channels %s", elem->id);
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
			}
Packit 4a16fb
Packit 4a16fb
			err = tplg_parse_compound(tplg, n, tplg_parse_channel,
Packit 4a16fb
				mc->channel);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
Packit 4a16fb
			mc->num_channels = tplg->channel_idx;
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "max") == 0) {
Packit Service f36a15
			if (tplg_get_integer(n, &ival, 0))
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit Service f36a15
			mc->max = ival;
Packit Service f36a15
			tplg_dbg("\t%s: %d", id, mc->max);
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 Service f36a15
			mc->invert = ival;
Packit 4a16fb
Packit Service f36a15
			tplg_dbg("\t%s: %d", id, mc->invert);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "ops") == 0) {
Packit 4a16fb
			err = tplg_parse_compound(tplg, n, tplg_parse_ops,
Packit 4a16fb
				&mc->hdr);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "tlv") == 0) {
Packit 4a16fb
			if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit 4a16fb
			err = tplg_ref_add(elem, SND_TPLG_TYPE_TLV, val);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
Packit 4a16fb
			tlv_set = true;
Packit Service f36a15
			tplg_dbg("\t%s: %s", id, val);
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
		if (strcmp(id, "access") == 0) {
Packit 4a16fb
			err = parse_access(cfg, &mc->hdr);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
			access_set = true;
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	/* set CTL access to default values if none are provided */
Packit 4a16fb
	if (!access_set) {
Packit 4a16fb
Packit 4a16fb
		mc->hdr.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
Packit 4a16fb
		if (tlv_set)
Packit 4a16fb
			mc->hdr.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit Service f36a15
int tplg_save_control_mixer(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
Packit Service f36a15
			    struct tplg_elem *elem, char **dst,
Packit Service f36a15
			    const char *pfx)
Packit 4a16fb
{
Packit Service f36a15
	struct snd_soc_tplg_mixer_control *mc = elem->mixer_ctrl;
Packit Service f36a15
	char pfx2[16];
Packit Service f36a15
	int err;
Packit Service f36a15
Packit Service f36a15
	if (!mc)
Packit Service f36a15
		return 0;
Packit Service f36a15
	err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
Packit Service f36a15
	if (err < 0)
Packit Service f36a15
		return err;
Packit Service f36a15
	snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
Packit Service f36a15
	if (err >= 0 && elem->index > 0)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\tindex %u\n", elem->index);
Packit Service f36a15
	if (err >= 0)
Packit Service f36a15
		err = tplg_save_channels(tplg, mc->channel, mc->num_channels,
Packit Service f36a15
					 dst, pfx2);
Packit Service f36a15
	if (err >= 0 && mc->max > 0)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\tmax %u\n", mc->max);
Packit Service f36a15
	if (err >= 0 && mc->invert > 0)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\tinvert 1\n", mc->max);
Packit Service f36a15
	if (err >= 0 && mc->invert > 0)
Packit Service f36a15
		err = tplg_save_printf(dst, pfx, "\tinvert 1\n", mc->max);
Packit Service f36a15
	if (err >= 0)
Packit Service f36a15
		err = tplg_save_ops(tplg, &mc->hdr, dst, pfx2);
Packit Service f36a15
	if (err >= 0)
Packit Service f36a15
		err = tplg_save_access(tplg, &mc->hdr, dst, pfx2);
Packit Service f36a15
	if (err >= 0)
Packit Service f36a15
		err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_TLV,
Packit Service f36a15
				     "tlv", 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
static int init_ctl_hdr(snd_tplg_t *tplg,
Packit Service f36a15
			struct tplg_elem *parent,
Packit Service f36a15
			struct snd_soc_tplg_ctl_hdr *hdr,
Packit Service f36a15
			struct snd_tplg_ctl_template *t)
Packit Service f36a15
{
Packit Service f36a15
	struct tplg_elem *elem;
Packit Service f36a15
	int err;
Packit Service f36a15
Packit 4a16fb
	hdr->size = sizeof(struct snd_soc_tplg_ctl_hdr);
Packit 4a16fb
	hdr->type = t->type;
Packit 4a16fb
Packit 4a16fb
	snd_strlcpy(hdr->name, t->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit 4a16fb
Packit 4a16fb
	/* clean up access flag */
Packit 4a16fb
	if (t->access == 0)
Packit 4a16fb
		t->access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
Packit 4a16fb
	t->access &= (SNDRV_CTL_ELEM_ACCESS_READWRITE |
Packit 4a16fb
		SNDRV_CTL_ELEM_ACCESS_VOLATILE |
Packit 4a16fb
		SNDRV_CTL_ELEM_ACCESS_INACTIVE |
Packit 4a16fb
		SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE |
Packit 4a16fb
		SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND |
Packit 4a16fb
		SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK);
Packit 4a16fb
Packit 4a16fb
	hdr->access = t->access;
Packit 4a16fb
	hdr->ops.get = t->ops.get;
Packit 4a16fb
	hdr->ops.put = t->ops.put;
Packit 4a16fb
	hdr->ops.info = t->ops.info;
Packit 4a16fb
Packit 4a16fb
	/* TLV */
Packit 4a16fb
	if (hdr->access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE
Packit 4a16fb
		&& !(hdr->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)) {
Packit 4a16fb
Packit 4a16fb
		struct snd_tplg_tlv_template *tlvt = t->tlv;
Packit Service f36a15
		struct snd_soc_tplg_ctl_tlv *tlv;
Packit 4a16fb
		struct snd_tplg_tlv_dbscale_template *scalet;
Packit 4a16fb
		struct snd_soc_tplg_tlv_dbscale *scale;
Packit 4a16fb
Packit 4a16fb
		if (!tlvt) {
Packit Service f36a15
			SNDERR("missing TLV data");
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		}
Packit 4a16fb
Packit Service f36a15
		elem = tplg_elem_new_common(tplg, NULL, parent->id,
Packit Service f36a15
					    SND_TPLG_TYPE_TLV);
Packit Service f36a15
		if (!elem)
Packit Service f36a15
			return -ENOMEM;
Packit Service f36a15
Packit Service f36a15
		tlv = elem->tlv;
Packit Service f36a15
Packit Service f36a15
		err = tplg_ref_add(parent, SND_TPLG_TYPE_TLV, parent->id);
Packit Service f36a15
		if (err < 0)
Packit Service f36a15
			return err;
Packit Service f36a15
Packit 4a16fb
		tlv->size = sizeof(struct snd_soc_tplg_ctl_tlv);
Packit 4a16fb
		tlv->type = tlvt->type;
Packit 4a16fb
Packit 4a16fb
		switch (tlvt->type) {
Packit 4a16fb
		case SNDRV_CTL_TLVT_DB_SCALE:
Packit 4a16fb
			scalet = container_of(tlvt,
Packit 4a16fb
				struct snd_tplg_tlv_dbscale_template, hdr);
Packit 4a16fb
			scale = &tlv->scale;
Packit 4a16fb
			scale->min = scalet->min;
Packit 4a16fb
			scale->step = scalet->step;
Packit 4a16fb
			scale->mute = scalet->mute;
Packit 4a16fb
			break;
Packit 4a16fb
Packit 4a16fb
		/* TODO: add support for other TLV types */
Packit 4a16fb
		default:
Packit Service f36a15
			SNDERR("unsupported TLV type %d", tlv->type);
Packit 4a16fb
			break;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
int tplg_add_mixer(snd_tplg_t *tplg, struct snd_tplg_mixer_template *mixer,
Packit Service f36a15
		   struct tplg_elem **e)
Packit 4a16fb
{
Packit 4a16fb
	struct snd_soc_tplg_mixer_control *mc;
Packit Service f36a15
	struct snd_soc_tplg_private *priv;
Packit 4a16fb
	struct tplg_elem *elem;
Packit 4a16fb
	int ret, i, num_channels;
Packit 4a16fb
Packit Service f36a15
	tplg_dbg(" Control Mixer: %s", mixer->hdr.name);
Packit 4a16fb
Packit 4a16fb
	if (mixer->hdr.type != SND_SOC_TPLG_TYPE_MIXER) {
Packit Service f36a15
		SNDERR("invalid mixer type %d", mixer->hdr.type);
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	elem = tplg_elem_new_common(tplg, NULL, mixer->hdr.name,
Packit 4a16fb
		SND_TPLG_TYPE_MIXER);
Packit 4a16fb
	if (!elem)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
Packit 4a16fb
	/* init new mixer */
Packit 4a16fb
	mc = elem->mixer_ctrl;
Packit 4a16fb
	mc->size = elem->size;
Packit Service f36a15
	ret = init_ctl_hdr(tplg, elem, &mc->hdr, &mixer->hdr);
Packit 4a16fb
	if (ret < 0) {
Packit 4a16fb
		tplg_elem_free(elem);
Packit 4a16fb
		return ret;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	mc->min = mixer->min;
Packit 4a16fb
	mc->max = mixer->max;
Packit 4a16fb
	mc->platform_max = mixer->platform_max;
Packit 4a16fb
	mc->invert = mixer->invert;
Packit 4a16fb
Packit 4a16fb
	/* set channel reg to default state */
Packit 4a16fb
	for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++)
Packit 4a16fb
		mc->channel[i].reg = -1;
Packit 4a16fb
Packit 4a16fb
	num_channels = mixer->map ? mixer->map->num_channels : 0;
Packit 4a16fb
	mc->num_channels = num_channels;
Packit 4a16fb
Packit 4a16fb
	for (i = 0; i < num_channels; i++) {
Packit 4a16fb
		struct snd_tplg_channel_elem *channel = &mixer->map->channel[i];
Packit 4a16fb
Packit Service f36a15
		mc->channel[i].size = sizeof(mc->channel[0]);
Packit 4a16fb
		mc->channel[i].reg = channel->reg;
Packit 4a16fb
		mc->channel[i].shift = channel->shift;
Packit 4a16fb
		mc->channel[i].id = channel->id;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	/* priv data */
Packit Service f36a15
	priv = mixer->priv;
Packit Service f36a15
	if (priv && priv->size > 0) {
Packit Service f36a15
		ret = tplg_add_data(tplg, elem, priv,
Packit Service f36a15
				    sizeof(*priv) + priv->size);
Packit Service f36a15
		if (ret < 0)
Packit Service f36a15
			return ret;
Packit Service f36a15
	}
Packit 4a16fb
Packit 4a16fb
	if (e)
Packit 4a16fb
		*e = elem;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
int tplg_add_enum(snd_tplg_t *tplg, struct snd_tplg_enum_template *enum_ctl,
Packit Service f36a15
		  struct tplg_elem **e)
Packit 4a16fb
{
Packit 4a16fb
	struct snd_soc_tplg_enum_control *ec;
Packit Service f36a15
	struct snd_soc_tplg_private *priv;
Packit 4a16fb
	struct tplg_elem *elem;
Packit Service f36a15
	int ret, i, num_items, num_channels;
Packit 4a16fb
Packit Service f36a15
	tplg_dbg(" Control Enum: %s", enum_ctl->hdr.name);
Packit 4a16fb
Packit 4a16fb
	if (enum_ctl->hdr.type != SND_SOC_TPLG_TYPE_ENUM) {
Packit Service f36a15
		SNDERR("invalid enum type %d", enum_ctl->hdr.type);
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	elem = tplg_elem_new_common(tplg, NULL, enum_ctl->hdr.name,
Packit 4a16fb
		SND_TPLG_TYPE_ENUM);
Packit 4a16fb
	if (!elem)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
Packit 4a16fb
	ec = elem->enum_ctrl;
Packit 4a16fb
	ec->size = elem->size;
Packit Service f36a15
	ret = init_ctl_hdr(tplg, elem, &ec->hdr, &enum_ctl->hdr);
Packit 4a16fb
	if (ret < 0) {
Packit 4a16fb
		tplg_elem_free(elem);
Packit 4a16fb
		return ret;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	num_items =  enum_ctl->items < SND_SOC_TPLG_NUM_TEXTS ?
Packit 4a16fb
		enum_ctl->items : SND_SOC_TPLG_NUM_TEXTS;
Packit 4a16fb
	ec->items = num_items;
Packit 4a16fb
	ec->mask = enum_ctl->mask;
Packit 4a16fb
	ec->count = enum_ctl->items;
Packit 4a16fb
Packit Service f36a15
	/* set channel reg to default state */
Packit Service f36a15
	for (i = 0; i < SND_SOC_TPLG_MAX_CHAN; i++)
Packit Service f36a15
		ec->channel[i].reg = -1;
Packit Service f36a15
Packit Service f36a15
	num_channels = enum_ctl->map ? enum_ctl->map->num_channels : 0;
Packit Service f36a15
	ec->num_channels = num_channels;
Packit Service f36a15
Packit Service f36a15
	for (i = 0; i < num_channels; i++) {
Packit Service f36a15
		struct snd_tplg_channel_elem *channel = &enum_ctl->map->channel[i];
Packit Service f36a15
Packit Service f36a15
		ec->channel[i].size = sizeof(ec->channel[0]);
Packit Service f36a15
		ec->channel[i].reg = channel->reg;
Packit Service f36a15
		ec->channel[i].shift = channel->shift;
Packit Service f36a15
		ec->channel[i].id = channel->id;
Packit Service f36a15
	}
Packit Service f36a15
Packit 4a16fb
	if (enum_ctl->texts != NULL) {
Packit 4a16fb
		for (i = 0; i < num_items; i++) {
Packit 4a16fb
			if (enum_ctl->texts[i] != NULL)
Packit 4a16fb
				snd_strlcpy(ec->texts[i], enum_ctl->texts[i],
Packit 4a16fb
					    SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	if (enum_ctl->values != NULL) {
Packit 4a16fb
		for (i = 0; i < num_items; i++) {
Packit 4a16fb
			if (enum_ctl->values[i] == NULL)
Packit 4a16fb
				continue;
Packit 4a16fb
Packit 4a16fb
			memcpy(&ec->values[i * sizeof(int) * ENUM_VAL_SIZE],
Packit 4a16fb
				enum_ctl->values[i],
Packit 4a16fb
				sizeof(int) * ENUM_VAL_SIZE);
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
Packit Service f36a15
	/* priv data */
Packit Service f36a15
	priv = enum_ctl->priv;
Packit Service f36a15
	if (priv && priv->size > 0) {
Packit Service f36a15
		ret = tplg_add_data(tplg, elem, priv,
Packit Service f36a15
				    sizeof(*priv) + priv->size);
Packit Service f36a15
		if (ret < 0)
Packit Service f36a15
			return ret;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	if (e)
Packit 4a16fb
		*e = elem;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
int tplg_add_bytes(snd_tplg_t *tplg, struct snd_tplg_bytes_template *bytes_ctl,
Packit Service f36a15
		   struct tplg_elem **e)
Packit 4a16fb
{
Packit 4a16fb
	struct snd_soc_tplg_bytes_control *be;
Packit Service f36a15
	struct snd_soc_tplg_private *priv;
Packit 4a16fb
	struct tplg_elem *elem;
Packit 4a16fb
	int ret;
Packit 4a16fb
Packit Service f36a15
	tplg_dbg(" Control Bytes: %s", bytes_ctl->hdr.name);
Packit 4a16fb
Packit 4a16fb
	if (bytes_ctl->hdr.type != SND_SOC_TPLG_TYPE_BYTES) {
Packit Service f36a15
		SNDERR("invalid bytes type %d", bytes_ctl->hdr.type);
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	elem = tplg_elem_new_common(tplg, NULL, bytes_ctl->hdr.name,
Packit 4a16fb
		SND_TPLG_TYPE_BYTES);
Packit 4a16fb
	if (!elem)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
Packit 4a16fb
	be = elem->bytes_ext;
Packit 4a16fb
	be->size = elem->size;
Packit Service f36a15
	ret = init_ctl_hdr(tplg, elem, &be->hdr, &bytes_ctl->hdr);
Packit 4a16fb
	if (ret < 0) {
Packit 4a16fb
		tplg_elem_free(elem);
Packit 4a16fb
		return ret;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	be->max = bytes_ctl->max;
Packit 4a16fb
	be->mask = bytes_ctl->mask;
Packit 4a16fb
	be->base = bytes_ctl->base;
Packit 4a16fb
	be->num_regs = bytes_ctl->num_regs;
Packit 4a16fb
	be->ext_ops.put = bytes_ctl->ext_ops.put;
Packit 4a16fb
	be->ext_ops.get = bytes_ctl->ext_ops.get;
Packit 4a16fb
Packit Service f36a15
	/* priv data */
Packit Service f36a15
	priv = bytes_ctl->priv;
Packit Service f36a15
	if (priv && priv->size > 0) {
Packit Service f36a15
		ret = tplg_add_data(tplg, elem, priv,
Packit Service f36a15
				    sizeof(*priv) + priv->size);
Packit Service f36a15
		if (ret < 0)
Packit Service f36a15
			return ret;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	/* check on TLV bytes control */
Packit 4a16fb
	if (be->hdr.access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
Packit 4a16fb
		if ((be->hdr.access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)
Packit 4a16fb
			!= SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) {
Packit Service f36a15
			SNDERR("Invalid TLV bytes control access 0x%x",
Packit 4a16fb
				be->hdr.access);
Packit 4a16fb
			tplg_elem_free(elem);
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (!be->max) {
Packit 4a16fb
			tplg_elem_free(elem);
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	if (e)
Packit 4a16fb
		*e = elem;
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
int tplg_add_mixer_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
Packit 4a16fb
{
Packit 4a16fb
	return tplg_add_mixer(tplg, t->mixer, NULL);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
int tplg_add_enum_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
Packit 4a16fb
{
Packit 4a16fb
	return tplg_add_enum(tplg, t->enum_ctl, NULL);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
int tplg_add_bytes_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t)
Packit 4a16fb
{
Packit 4a16fb
	return tplg_add_bytes(tplg, t->bytes_ctl, NULL);
Packit 4a16fb
}
Packit Service f36a15
Packit Service f36a15
int tplg_decode_control_mixer1(snd_tplg_t *tplg,
Packit Service f36a15
			       struct list_head *heap,
Packit Service f36a15
			       struct snd_tplg_mixer_template *mt,
Packit Service f36a15
			       size_t pos,
Packit Service f36a15
			       void *bin, size_t size)
Packit Service f36a15
{
Packit Service f36a15
	struct snd_soc_tplg_mixer_control *mc = bin;
Packit Service f36a15
	struct snd_tplg_channel_map_template *map;
Packit Service f36a15
	struct snd_tplg_tlv_dbscale_template *db;
Packit Service f36a15
	int i;
Packit Service f36a15
Packit Service f36a15
	if (size < sizeof(*mc)) {
Packit Service f36a15
		SNDERR("mixer: small size %d", size);
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	tplg_log(tplg, 'D', pos, "mixer: size %d TLV size %d private size %d",
Packit Service f36a15
		 mc->size, mc->hdr.tlv.size, mc->priv.size);
Packit Service f36a15
	if (size != mc->size + mc->priv.size) {
Packit Service f36a15
		SNDERR("mixer: unexpected element size %d", size);
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	memset(mt, 0, sizeof(*mt));
Packit Service f36a15
	mt->hdr.type = mc->hdr.type;
Packit Service f36a15
	mt->hdr.name = mc->hdr.name;
Packit Service f36a15
	mt->hdr.access = mc->hdr.access;
Packit Service f36a15
	mt->hdr.ops.get = mc->hdr.ops.get;
Packit Service f36a15
	mt->hdr.ops.put = mc->hdr.ops.put;
Packit Service f36a15
	mt->hdr.ops.info = mc->hdr.ops.info;
Packit Service f36a15
	mt->min = mc->min;
Packit Service f36a15
	mt->max = mc->max;
Packit Service f36a15
	mt->platform_max = mc->platform_max;
Packit Service f36a15
	tplg_log(tplg, 'D', pos, "mixer: name '%s' access 0x%x",
Packit Service f36a15
		mt->hdr.name, mt->hdr.access);
Packit Service f36a15
	if (mc->num_channels > 0) {
Packit Service f36a15
		map = tplg_calloc(heap, sizeof(*map));
Packit Service f36a15
		map->num_channels = mc->num_channels;
Packit Service f36a15
		for (i = 0; i < map->num_channels; i++) {
Packit Service f36a15
			map->channel[i].reg = mc->channel[i].reg;
Packit Service f36a15
			map->channel[i].shift = mc->channel[i].shift;
Packit Service f36a15
			map->channel[i].id = mc->channel[i].id;
Packit Service f36a15
		}
Packit Service f36a15
		mt->map = map;
Packit Service f36a15
	}
Packit Service f36a15
	if (mc->hdr.tlv.size == 0) {
Packit Service f36a15
		/* nothing */
Packit Service f36a15
	} else if (mc->hdr.tlv.size == sizeof(struct snd_soc_tplg_ctl_tlv)) {
Packit Service f36a15
		if (mc->hdr.tlv.type != SNDRV_CTL_TLVT_DB_SCALE) {
Packit Service f36a15
			SNDERR("mixer: unknown TLV type %d",
Packit Service f36a15
			       mc->hdr.tlv.type);
Packit Service f36a15
			return -EINVAL;
Packit Service f36a15
		}
Packit Service f36a15
		db = tplg_calloc(heap, sizeof(*db));
Packit Service f36a15
		if (db == NULL)
Packit Service f36a15
			return -ENOMEM;
Packit Service f36a15
		mt->hdr.tlv_scale = db;
Packit Service f36a15
		db->hdr.type = mc->hdr.tlv.type;
Packit Service f36a15
		db->min = mc->hdr.tlv.scale.min;
Packit Service f36a15
		db->step = mc->hdr.tlv.scale.step;
Packit Service f36a15
		db->mute = mc->hdr.tlv.scale.mute;
Packit Service f36a15
		tplg_log(tplg, 'D', pos, "mixer: dB scale TLV: min %d step %d mute %d",
Packit Service f36a15
			 db->min, db->step, db->mute);
Packit Service f36a15
	} else {
Packit Service f36a15
		SNDERR("mixer: wrong TLV size %d", mc->hdr.tlv.size);
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	mt->priv = &mc->priv;
Packit Service f36a15
	tplg_log(tplg, 'D', pos + offsetof(struct snd_soc_tplg_mixer_control, priv),
Packit Service f36a15
		 "mixer: private start");
Packit Service f36a15
	return 0;
Packit Service f36a15
}
Packit Service f36a15
Packit Service f36a15
int tplg_decode_control_mixer(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
	snd_tplg_obj_template_t t;
Packit Service f36a15
	struct snd_tplg_mixer_template mt;
Packit Service f36a15
	struct snd_soc_tplg_mixer_control *mc;
Packit Service f36a15
	size_t size2;
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
	if (size < sizeof(*mc)) {
Packit Service f36a15
		SNDERR("mixer: small size %d", size);
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	}
Packit Service f36a15
	INIT_LIST_HEAD(&heap;;
Packit Service f36a15
	mc = bin;
Packit Service f36a15
	size2 = mc->size + mc->priv.size;
Packit Service f36a15
	if (size2 > size) {
Packit Service f36a15
		SNDERR("mixer: wrong element size (%d, priv %d)",
Packit Service f36a15
		       mc->size, mc->priv.size);
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	err = tplg_decode_control_mixer1(tplg, &heap, &mt, pos, bin, size2);
Packit Service f36a15
	if (err >= 0) {
Packit Service f36a15
		t.mixer = &mt;
Packit Service f36a15
		err = snd_tplg_add_object(tplg, &t);
Packit Service f36a15
	}
Packit Service f36a15
	tplg_free(&heap;;
Packit Service f36a15
	if (err < 0)
Packit Service f36a15
		return err;
Packit Service f36a15
Packit Service f36a15
	bin += size2;
Packit Service f36a15
	size -= size2;
Packit Service f36a15
	pos += size2;
Packit Service f36a15
Packit Service f36a15
	if (size > 0)
Packit Service f36a15
		goto next;
Packit Service f36a15
Packit Service f36a15
	return 0;
Packit Service f36a15
}
Packit Service f36a15
Packit Service f36a15
int tplg_decode_control_enum1(snd_tplg_t *tplg,
Packit Service f36a15
			      struct list_head *heap,
Packit Service f36a15
			      struct snd_tplg_enum_template *et,
Packit Service f36a15
			      size_t pos,
Packit Service f36a15
			      void *bin, size_t size)
Packit Service f36a15
{
Packit Service f36a15
	struct snd_soc_tplg_enum_control *ec = bin;
Packit Service f36a15
	struct snd_tplg_channel_map_template cmt;
Packit Service f36a15
	int i;
Packit Service f36a15
Packit Service f36a15
	if (size < sizeof(*ec)) {
Packit Service f36a15
		SNDERR("enum: small size %d", size);
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	tplg_log(tplg, 'D', pos, "enum: size %d private size %d",
Packit Service f36a15
		 ec->size, ec->priv.size);
Packit Service f36a15
	if (size != ec->size + ec->priv.size) {
Packit Service f36a15
		SNDERR("enum: unexpected element size %d", size);
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	}
Packit Service f36a15
	if (ec->num_channels > SND_TPLG_MAX_CHAN ||
Packit Service f36a15
	    ec->num_channels > SND_SOC_TPLG_MAX_CHAN) {
Packit Service f36a15
		SNDERR("enum: unexpected channel count %d", ec->num_channels);
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	}
Packit Service f36a15
	if (ec->items > SND_SOC_TPLG_NUM_TEXTS) {
Packit Service f36a15
		SNDERR("enum: unexpected texts count %d", ec->items);
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	memset(et, 0, sizeof(*et));
Packit Service f36a15
	et->hdr.type = ec->hdr.type;
Packit Service f36a15
	et->hdr.name = ec->hdr.name;
Packit Service f36a15
	et->hdr.access = ec->hdr.access;
Packit Service f36a15
	et->hdr.ops.get = ec->hdr.ops.get;
Packit Service f36a15
	et->hdr.ops.put = ec->hdr.ops.put;
Packit Service f36a15
	et->hdr.ops.info = ec->hdr.ops.info;
Packit Service f36a15
	et->mask = ec->mask;
Packit Service f36a15
Packit Service f36a15
	if (ec->items > 0) {
Packit Service f36a15
		et->items = ec->items;
Packit Service f36a15
		et->texts = tplg_calloc(heap, sizeof(char *) * ec->items);
Packit Service f36a15
		if (!et->texts)
Packit Service f36a15
			return -ENOMEM;
Packit Service f36a15
		for (i = 0; ec->items; i++) {
Packit Service f36a15
			unsigned int j = i * sizeof(int) * ENUM_VAL_SIZE;
Packit Service f36a15
			et->texts[i] = ec->texts[i];
Packit Service f36a15
			et->values[i] = (int *)&ec->values[j];
Packit Service f36a15
		}
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	et->map = &cm;;
Packit Service f36a15
	memset(&cmt, 0, sizeof(cmt));
Packit Service f36a15
	cmt.num_channels = ec->num_channels;
Packit Service f36a15
	for (i = 0; i < cmt.num_channels; i++) {
Packit Service f36a15
		struct snd_tplg_channel_elem *channel = &cmt.channel[i];
Packit Service f36a15
		tplg_log(tplg, 'D', pos + ((void *)&ec->channel[i] - (void *)ec),
Packit Service f36a15
			 "enum: channel size %d", ec->channel[i].size);
Packit Service f36a15
		channel->reg = ec->channel[i].reg;
Packit Service f36a15
		channel->shift = ec->channel[i].shift;
Packit Service f36a15
		channel->id = ec->channel[i].id;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	et->priv = &ec->priv;
Packit Service f36a15
	return 0;
Packit Service f36a15
}
Packit Service f36a15
Packit Service f36a15
int tplg_decode_control_enum(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
	snd_tplg_obj_template_t t;
Packit Service f36a15
	struct snd_tplg_enum_template et;
Packit Service f36a15
	struct snd_soc_tplg_enum_control *ec;
Packit Service f36a15
	size_t size2;
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
	if (size < sizeof(*ec)) {
Packit Service f36a15
		SNDERR("enum: small size %d", size);
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	}
Packit Service f36a15
	INIT_LIST_HEAD(&heap;;
Packit Service f36a15
	ec = bin;
Packit Service f36a15
	size2 = ec->size + ec->priv.size;
Packit Service f36a15
	if (size2 > size) {
Packit Service f36a15
		SNDERR("enum: wrong element size (%d, priv %d)",
Packit Service f36a15
		       ec->size, ec->priv.size);
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	err = tplg_decode_control_enum1(tplg, &heap, &et, pos, bin, size);
Packit Service f36a15
	if (err >= 0) {
Packit Service f36a15
		t.enum_ctl = &et;
Packit Service f36a15
		err = snd_tplg_add_object(tplg, &t);
Packit Service f36a15
	}
Packit Service f36a15
	tplg_free(&heap;;
Packit Service f36a15
	if (err < 0)
Packit Service f36a15
		return err;
Packit Service f36a15
Packit Service f36a15
	bin += size2;
Packit Service f36a15
	size -= size2;
Packit Service f36a15
	pos += size2;
Packit Service f36a15
Packit Service f36a15
	if (size > 0)
Packit Service f36a15
		goto next;
Packit Service f36a15
Packit Service f36a15
	return 0;
Packit Service f36a15
}
Packit Service f36a15
Packit Service f36a15
int tplg_decode_control_bytes1(snd_tplg_t *tplg,
Packit Service f36a15
			       struct snd_tplg_bytes_template *bt,
Packit Service f36a15
			       size_t pos,
Packit Service f36a15
			       void *bin, size_t size)
Packit Service f36a15
{
Packit Service f36a15
	struct snd_soc_tplg_bytes_control *bc = bin;
Packit Service f36a15
Packit Service f36a15
	if (size < sizeof(*bc)) {
Packit Service f36a15
		SNDERR("bytes: small size %d", size);
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	tplg_log(tplg, 'D', pos, "control bytes: size %d private size %d",
Packit Service f36a15
		 bc->size, bc->priv.size);
Packit Service f36a15
	if (size != bc->size + bc->priv.size) {
Packit Service f36a15
		SNDERR("bytes: unexpected element size %d", size);
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	memset(bt, 0, sizeof(*bt));
Packit Service f36a15
	bt->hdr.type = bc->hdr.type;
Packit Service f36a15
	bt->hdr.name = bc->hdr.name;
Packit Service f36a15
	bt->hdr.access = bc->hdr.access;
Packit Service f36a15
	bt->hdr.ops.get = bc->hdr.ops.get;
Packit Service f36a15
	bt->hdr.ops.put = bc->hdr.ops.put;
Packit Service f36a15
	bt->hdr.ops.info = bc->hdr.ops.info;
Packit Service f36a15
	bt->max = bc->max;
Packit Service f36a15
	bt->mask = bc->mask;
Packit Service f36a15
	bt->base = bc->base;
Packit Service f36a15
	bt->num_regs = bc->num_regs;
Packit Service f36a15
	bt->ext_ops.get = bc->ext_ops.get;
Packit Service f36a15
	bt->ext_ops.put = bc->ext_ops.put;
Packit Service f36a15
	bt->ext_ops.info = bc->ext_ops.info;
Packit Service f36a15
	tplg_log(tplg, 'D', pos, "control bytes: name '%s' access 0x%x",
Packit Service f36a15
		 bt->hdr.name, bt->hdr.access);
Packit Service f36a15
Packit Service f36a15
	bt->priv = &bc->priv;
Packit Service f36a15
	return 0;
Packit Service f36a15
}
Packit Service f36a15
Packit Service f36a15
int tplg_decode_control_bytes(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
	snd_tplg_obj_template_t t;
Packit Service f36a15
	struct snd_tplg_bytes_template bt;
Packit Service f36a15
	struct snd_soc_tplg_bytes_control *bc;
Packit Service f36a15
	size_t size2;
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
	if (size < sizeof(*bc)) {
Packit Service f36a15
		SNDERR("bytes: small size %d", size);
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	}
Packit Service f36a15
	bc = bin;
Packit Service f36a15
	size2 = bc->size + bc->priv.size;
Packit Service f36a15
	if (size2 > size) {
Packit Service f36a15
		SNDERR("bytes: wrong element size (%d, priv %d)",
Packit Service f36a15
		       bc->size, bc->priv.size);
Packit Service f36a15
		return -EINVAL;
Packit Service f36a15
	}
Packit Service f36a15
Packit Service f36a15
	err = tplg_decode_control_bytes1(tplg, &bt, pos, bin, size);
Packit Service f36a15
	if (err < 0)
Packit Service f36a15
		return err;
Packit Service f36a15
Packit Service f36a15
	t.bytes_ctl = &bt;
Packit Service f36a15
	err = snd_tplg_add_object(tplg, &t);
Packit Service f36a15
	if (err < 0)
Packit Service f36a15
		return err;
Packit Service f36a15
Packit Service f36a15
	bin += size2;
Packit Service f36a15
	size -= size2;
Packit Service f36a15
	pos += size2;
Packit Service f36a15
Packit Service f36a15
	if (size > 0)
Packit Service f36a15
		goto next;
Packit Service f36a15
Packit Service f36a15
	return 0;
Packit Service f36a15
}