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 4a16fb
static const struct ctl_access_elem ctl_access[] = {
Packit 4a16fb
	{"read", SNDRV_CTL_ELEM_ACCESS_READ},
Packit 4a16fb
	{"write", SNDRV_CTL_ELEM_ACCESS_WRITE},
Packit 4a16fb
	{"read_write", SNDRV_CTL_ELEM_ACCESS_READWRITE},
Packit 4a16fb
	{"volatile", SNDRV_CTL_ELEM_ACCESS_VOLATILE},
Packit 4a16fb
	{"timestamp", SNDRV_CTL_ELEM_ACCESS_TIMESTAMP},
Packit 4a16fb
	{"tlv_read", SNDRV_CTL_ELEM_ACCESS_TLV_READ},
Packit 4a16fb
	{"tlv_write", SNDRV_CTL_ELEM_ACCESS_TLV_WRITE},
Packit 4a16fb
	{"tlv_read_write", SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE},
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 4a16fb
	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 4a16fb
	tplg_dbg(" Access:\n");
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 4a16fb
				tplg_dbg("\t%s\n", 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 4a16fb
	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 4a16fb
				SNDERR("error: 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 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 4a16fb
	tplg_dbg("TLV '%s' used by '%s\n", 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 4a16fb
				struct tplg_elem *elem)
Packit 4a16fb
{
Packit 4a16fb
	struct tplg_ref *ref;
Packit 4a16fb
	struct list_head *base, *pos;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
Packit 4a16fb
	base = &elem->ref_list;
Packit 4a16fb
Packit 4a16fb
	/* 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 4a16fb
			SNDERR("error: cannot find '%s' referenced by"
Packit 4a16fb
				" control '%s'\n", 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 4a16fb
	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 4a16fb
				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 4a16fb
			SNDERR("error: cannot find '%s' referenced by"
Packit 4a16fb
				" control '%s'\n", 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 4a16fb
	struct snd_soc_tplg_ctl_tlv *tplg_tlv;
Packit 4a16fb
	struct snd_soc_tplg_tlv_dbscale *scale;
Packit 4a16fb
	const char *id = NULL, *value = NULL;
Packit 4a16fb
Packit 4a16fb
	tplg_dbg(" scale: %s\n", elem->id);
Packit 4a16fb
Packit 4a16fb
	tplg_tlv = calloc(1, sizeof(*tplg_tlv));
Packit 4a16fb
	if (!tplg_tlv)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
Packit 4a16fb
	elem->tlv = tplg_tlv;
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 4a16fb
		if (snd_config_get_id(n, &id) < 0) {
Packit 4a16fb
			SNDERR("error: cant get ID\n");
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		/* get value */
Packit 4a16fb
		if (snd_config_get_string(n, &value) < 0)
Packit 4a16fb
			continue;
Packit 4a16fb
Packit 4a16fb
		tplg_dbg("\t%s = %s\n", id, value);
Packit 4a16fb
Packit 4a16fb
		/* get TLV data */
Packit 4a16fb
		if (strcmp(id, "min") == 0)
Packit 4a16fb
			scale->min = atoi(value);
Packit 4a16fb
		else if (strcmp(id, "step") == 0)
Packit 4a16fb
			scale->step = atoi(value);
Packit 4a16fb
		else if (strcmp(id, "mute") == 0)
Packit 4a16fb
			scale->mute = atoi(value);
Packit 4a16fb
		else
Packit 4a16fb
			SNDERR("error: unknown key %s\n", 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 4a16fb
	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 4a16fb
				SNDERR("error: 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 4a16fb
/* Parse Control Bytes */
Packit 4a16fb
int tplg_parse_control_bytes(snd_tplg_t *tplg,
Packit 4a16fb
	snd_config_t *cfg, 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 4a16fb
	int err;
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 4a16fb
	tplg_dbg(" Control Bytes: %s\n", elem->id);
Packit 4a16fb
Packit 4a16fb
	snd_config_for_each(i, next, cfg) {
Packit 4a16fb
		n = snd_config_iterator_entry(i);
Packit 4a16fb
		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 4a16fb
			if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit 4a16fb
			be->base = atoi(val);
Packit 4a16fb
			tplg_dbg("\t%s: %d\n", id, be->base);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "num_regs") == 0) {
Packit 4a16fb
			if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit 4a16fb
			be->num_regs = atoi(val);
Packit 4a16fb
			tplg_dbg("\t%s: %d\n", id, be->num_regs);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "max") == 0) {
Packit 4a16fb
			if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit 4a16fb
			be->max = atoi(val);
Packit 4a16fb
			tplg_dbg("\t%s: %d\n", id, be->max);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "mask") == 0) {
Packit 4a16fb
			if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit 4a16fb
			be->mask = strtol(val, NULL, 16);
Packit 4a16fb
			tplg_dbg("\t%s: %d\n", id, be->mask);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "data") == 0) {
Packit 4a16fb
			err = tplg_parse_data_refs(n, elem);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		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 4a16fb
			tplg_dbg("\t%s: %s\n", 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 4a16fb
/* Parse Control Enums. */
Packit 4a16fb
int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg,
Packit 4a16fb
	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 4a16fb
	for (j = 0; j < SND_SOC_TPLG_MAX_CHAN; j++)
Packit 4a16fb
		ec->channel[j].reg = -1;
Packit 4a16fb
Packit 4a16fb
	tplg_dbg(" Control Enum: %s\n", 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 4a16fb
			tplg_dbg("\t%s: %s\n", 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 4a16fb
				SNDERR("error: too many channels %s\n",
Packit 4a16fb
					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 4a16fb
			err = tplg_parse_data_refs(n, elem);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		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 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 4a16fb
	snd_config_t *cfg, 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 4a16fb
	int err, j;
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 4a16fb
	tplg_dbg(" Control Mixer: %s\n", 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 4a16fb
				SNDERR("error: too many channels %s\n",
Packit 4a16fb
					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 4a16fb
			if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit 4a16fb
			mc->max = atoi(val);
Packit 4a16fb
			tplg_dbg("\t%s: %d\n", id, mc->max);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "invert") == 0) {
Packit 4a16fb
			if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit 4a16fb
			if (strcmp(val, "true") == 0)
Packit 4a16fb
				mc->invert = 1;
Packit 4a16fb
			else if (strcmp(val, "false") == 0)
Packit 4a16fb
				mc->invert = 0;
Packit 4a16fb
Packit 4a16fb
			tplg_dbg("\t%s: %d\n", 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 4a16fb
			tplg_dbg("\t%s: %s\n", id, val);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "data") == 0) {
Packit 4a16fb
			err = tplg_parse_data_refs(n, elem);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		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 4a16fb
static int init_ctl_hdr(struct snd_soc_tplg_ctl_hdr *hdr,
Packit 4a16fb
		struct snd_tplg_ctl_template *t)
Packit 4a16fb
{
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 4a16fb
		struct snd_soc_tplg_ctl_tlv *tlv = &hdr->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 4a16fb
			SNDERR("error: missing TLV data\n");
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		}
Packit 4a16fb
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 4a16fb
			SNDERR("error: unsupported TLV type %d\n", 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 4a16fb
	struct tplg_elem **e)
Packit 4a16fb
{
Packit 4a16fb
	struct snd_soc_tplg_private *priv = mixer->priv;
Packit 4a16fb
	struct snd_soc_tplg_mixer_control *mc;
Packit 4a16fb
	struct tplg_elem *elem;
Packit 4a16fb
	int ret, i, num_channels;
Packit 4a16fb
Packit 4a16fb
	tplg_dbg(" Control Mixer: %s\n", mixer->hdr.name);
Packit 4a16fb
Packit 4a16fb
	if (mixer->hdr.type != SND_SOC_TPLG_TYPE_MIXER) {
Packit 4a16fb
		SNDERR("error: invalid mixer type %d\n", 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 4a16fb
	ret =  init_ctl_hdr(&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 4a16fb
		mc->channel[i].size = channel->size;
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 4a16fb
	if (priv) {
Packit 4a16fb
		mc = realloc(mc, elem->size + priv->size);
Packit 4a16fb
		if (!mc) {
Packit 4a16fb
			tplg_elem_free(elem);
Packit 4a16fb
			return -ENOMEM;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		elem->mixer_ctrl = mc;
Packit 4a16fb
		elem->size += priv->size;
Packit 4a16fb
		mc->priv.size = priv->size;
Packit 4a16fb
		memcpy(mc->priv.data, priv->data,  priv->size);
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_enum(snd_tplg_t *tplg, struct snd_tplg_enum_template *enum_ctl,
Packit 4a16fb
	struct tplg_elem **e)
Packit 4a16fb
{
Packit 4a16fb
	struct snd_soc_tplg_enum_control *ec;
Packit 4a16fb
	struct tplg_elem *elem;
Packit 4a16fb
	int ret, i, num_items;
Packit 4a16fb
Packit 4a16fb
	tplg_dbg(" Control Enum: %s\n", enum_ctl->hdr.name);
Packit 4a16fb
Packit 4a16fb
	if (enum_ctl->hdr.type != SND_SOC_TPLG_TYPE_ENUM) {
Packit 4a16fb
		SNDERR("error: invalid enum type %d\n", 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 4a16fb
	ret = init_ctl_hdr(&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 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 4a16fb
	if (enum_ctl->priv != NULL) {
Packit 4a16fb
		ec = realloc(ec,
Packit 4a16fb
			elem->size + enum_ctl->priv->size);
Packit 4a16fb
		if (!ec) {
Packit 4a16fb
			tplg_elem_free(elem);
Packit 4a16fb
			return -ENOMEM;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		elem->enum_ctrl = ec;
Packit 4a16fb
		elem->size += enum_ctl->priv->size;
Packit 4a16fb
Packit 4a16fb
		memcpy(ec->priv.data, enum_ctl->priv->data,
Packit 4a16fb
			enum_ctl->priv->size);
Packit 4a16fb
Packit 4a16fb
		ec->priv.size = enum_ctl->priv->size;
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 4a16fb
	struct tplg_elem **e)
Packit 4a16fb
{
Packit 4a16fb
	struct snd_soc_tplg_bytes_control *be;
Packit 4a16fb
	struct tplg_elem *elem;
Packit 4a16fb
	int ret;
Packit 4a16fb
Packit 4a16fb
	tplg_dbg(" Control Bytes: %s\n", bytes_ctl->hdr.name);
Packit 4a16fb
Packit 4a16fb
	if (bytes_ctl->hdr.type != SND_SOC_TPLG_TYPE_BYTES) {
Packit 4a16fb
		SNDERR("error: invalid bytes type %d\n", 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 4a16fb
	ret = init_ctl_hdr(&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 4a16fb
	if (bytes_ctl->priv != NULL) {
Packit 4a16fb
		be = realloc(be,
Packit 4a16fb
			elem->size + bytes_ctl->priv->size);
Packit 4a16fb
		if (!be) {
Packit 4a16fb
			tplg_elem_free(elem);
Packit 4a16fb
			return -ENOMEM;
Packit 4a16fb
		}
Packit 4a16fb
		elem->bytes_ext = be;
Packit 4a16fb
		elem->size += bytes_ctl->priv->size;
Packit 4a16fb
Packit 4a16fb
		memcpy(be->priv.data, bytes_ctl->priv->data,
Packit 4a16fb
			bytes_ctl->priv->size);
Packit 4a16fb
Packit 4a16fb
		be->priv.size = bytes_ctl->priv->size;
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 4a16fb
			SNDERR("error: Invalid TLV bytes control access 0x%x\n",
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
}