Blame src/topology/data.c

Packit Service db8eaa
/*
Packit Service db8eaa
  Copyright(c) 2014-2015 Intel Corporation
Packit Service db8eaa
  All rights reserved.
Packit Service db8eaa
Packit Service db8eaa
  This library is free software; you can redistribute it and/or modify
Packit Service db8eaa
  it under the terms of the GNU Lesser General Public License as
Packit Service db8eaa
  published by the Free Software Foundation; either version 2.1 of
Packit Service db8eaa
  the License, or (at your option) any later version.
Packit Service db8eaa
Packit Service db8eaa
  This program is distributed in the hope that it will be useful,
Packit Service db8eaa
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service db8eaa
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service db8eaa
  GNU Lesser General Public License for more details.
Packit Service db8eaa
Packit Service db8eaa
  Authors: Mengdong Lin <mengdong.lin@intel.com>
Packit Service db8eaa
           Yao Jin <yao.jin@intel.com>
Packit Service db8eaa
           Liam Girdwood <liam.r.girdwood@linux.intel.com>
Packit Service db8eaa
*/
Packit Service db8eaa
Packit Service db8eaa
#include "list.h"
Packit Service db8eaa
#include "tplg_local.h"
Packit Service db8eaa
#include <ctype.h>
Packit Service db8eaa
Packit Service db8eaa
#define UUID_FORMAT "\
Packit Service db8eaa
%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:\
Packit Service db8eaa
%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
Packit Service db8eaa
Packit Service db8eaa
/* Get private data buffer of an element */
Packit Service db8eaa
struct snd_soc_tplg_private *get_priv_data(struct tplg_elem *elem)
Packit Service db8eaa
{
Packit Service db8eaa
	struct snd_soc_tplg_private *priv = NULL;
Packit Service db8eaa
Packit Service db8eaa
	switch (elem->type) {
Packit Service db8eaa
	case SND_TPLG_TYPE_MANIFEST:
Packit Service db8eaa
		priv = &elem->manifest->priv;
Packit Service db8eaa
		break;
Packit Service db8eaa
Packit Service db8eaa
	case SND_TPLG_TYPE_MIXER:
Packit Service db8eaa
		priv = &elem->mixer_ctrl->priv;
Packit Service db8eaa
		break;
Packit Service db8eaa
Packit Service db8eaa
	case SND_TPLG_TYPE_ENUM:
Packit Service db8eaa
		priv = &elem->enum_ctrl->priv;
Packit Service db8eaa
		break;
Packit Service db8eaa
Packit Service db8eaa
	case SND_TPLG_TYPE_BYTES:
Packit Service db8eaa
		priv = &elem->bytes_ext->priv;
Packit Service db8eaa
		break;
Packit Service db8eaa
Packit Service db8eaa
	case SND_TPLG_TYPE_DAPM_WIDGET:
Packit Service db8eaa
		priv = &elem->widget->priv;
Packit Service db8eaa
		break;
Packit Service db8eaa
Packit Service db8eaa
	case SND_TPLG_TYPE_DAI:
Packit Service db8eaa
		priv = &elem->dai->priv;
Packit Service db8eaa
		break;
Packit Service db8eaa
	case SND_TPLG_TYPE_BE:
Packit Service db8eaa
		priv = &elem->link->priv;
Packit Service db8eaa
		break;
Packit Service db8eaa
	case SND_TPLG_TYPE_PCM:
Packit Service db8eaa
		priv = &elem->pcm->priv;
Packit Service db8eaa
		break;
Packit Service db8eaa
	default:
Packit Service db8eaa
		SNDERR("'%s': no support for private data for type %d",
Packit Service db8eaa
			elem->id, elem->type);
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return priv;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* Parse references for the element, either a single data section
Packit Service db8eaa
 * or a list of data sections.
Packit Service db8eaa
 */
Packit Service db8eaa
int tplg_parse_refs(snd_config_t *cfg, struct tplg_elem *elem,
Packit Service db8eaa
		    unsigned int type)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_config_type_t cfg_type;
Packit Service db8eaa
	snd_config_iterator_t i, next;
Packit Service db8eaa
	snd_config_t *n;
Packit Service db8eaa
	const char *val = NULL;
Packit Service db8eaa
	int err, count;
Packit Service db8eaa
Packit Service db8eaa
	cfg_type = snd_config_get_type(cfg);
Packit Service db8eaa
Packit Service db8eaa
	/* refer to a single data section */
Packit Service db8eaa
	if (cfg_type == SND_CONFIG_TYPE_STRING) {
Packit Service db8eaa
		if (snd_config_get_string(cfg, &val) < 0)
Packit Service db8eaa
			return -EINVAL;
Packit Service db8eaa
Packit Service db8eaa
		tplg_dbg("\tref data: %s", val);
Packit Service db8eaa
		err = tplg_ref_add(elem, type, val);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		return 1;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (cfg_type != SND_CONFIG_TYPE_COMPOUND) {
Packit Service db8eaa
		SNDERR("compound type expected for %s", elem->id);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	/* refer to a list of data sections */
Packit Service db8eaa
	count = 0;
Packit Service db8eaa
	snd_config_for_each(i, next, cfg) {
Packit Service db8eaa
		const char *val;
Packit Service db8eaa
Packit Service db8eaa
		n = snd_config_iterator_entry(i);
Packit Service db8eaa
		if (snd_config_get_string(n, &val) < 0)
Packit Service db8eaa
			continue;
Packit Service db8eaa
Packit Service db8eaa
		tplg_dbg("\tref data: %s", val);
Packit Service db8eaa
		err = tplg_ref_add(elem, type, val);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		count++;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return count;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* save references */
Packit Service db8eaa
int tplg_save_refs(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
Packit Service db8eaa
		   struct tplg_elem *elem, unsigned int type,
Packit Service db8eaa
		   const char *id, struct tplg_buf *dst,
Packit Service db8eaa
		   const char *pfx)
Packit Service db8eaa
{
Packit Service db8eaa
	struct tplg_ref *ref, *last;
Packit Service db8eaa
	struct list_head *pos;
Packit Service db8eaa
	int err, count;
Packit Service db8eaa
Packit Service db8eaa
	count = 0;
Packit Service db8eaa
	last = NULL;
Packit Service db8eaa
	list_for_each(pos, &elem->ref_list) {
Packit Service db8eaa
		ref = list_entry(pos, struct tplg_ref, list);
Packit Service db8eaa
		if (ref->type == type) {
Packit Service db8eaa
			last = ref;
Packit Service db8eaa
			count++;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (count == 0)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
Packit Service db8eaa
	if (count == 1)
Packit Service db8eaa
		return tplg_save_printf(dst, pfx, "%s '%s'\n", id, last->id);
Packit Service db8eaa
Packit Service db8eaa
	err = tplg_save_printf(dst, pfx, "%s [\n", id);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
	list_for_each(pos, &elem->ref_list) {
Packit Service db8eaa
		ref = list_entry(pos, struct tplg_ref, list);
Packit Service db8eaa
		if (ref->type == type) {
Packit Service db8eaa
			err = tplg_save_printf(dst, pfx, "\t'%s'\n", ref->id);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return err;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return tplg_save_printf(dst, pfx, "]\n");
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* Get Private data from a file. */
Packit Service db8eaa
static int tplg_parse_data_file(snd_config_t *cfg, struct tplg_elem *elem)
Packit Service db8eaa
{
Packit Service db8eaa
	struct snd_soc_tplg_private *priv = NULL;
Packit Service db8eaa
	const char *value = NULL;
Packit Service db8eaa
	char filename[PATH_MAX];
Packit Service db8eaa
	char *env = getenv(ALSA_CONFIG_TPLG_VAR);
Packit Service db8eaa
	FILE *fp;
Packit Service db8eaa
	size_t size, bytes_read;
Packit Service db8eaa
	int ret = 0;
Packit Service db8eaa
Packit Service db8eaa
	tplg_dbg("data DataFile: %s", elem->id);
Packit Service db8eaa
Packit Service db8eaa
	if (snd_config_get_string(cfg, &value) < 0)
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
Packit Service db8eaa
	/* prepend alsa config directory to path */
Packit Service db8eaa
	if (env)
Packit Service db8eaa
		snprintf(filename, sizeof(filename), "%s/%s", env, value);
Packit Service db8eaa
	else
Packit Service db8eaa
		snprintf(filename, sizeof(filename), "%s/topology/%s",
Packit Service db8eaa
			 snd_config_topdir(), value);
Packit Service db8eaa
Packit Service db8eaa
	fp = fopen(filename, "r");
Packit Service db8eaa
	if (fp == NULL) {
Packit Service db8eaa
		SNDERR("invalid data file path '%s'", filename);
Packit Service db8eaa
		return -errno;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	fseek(fp, 0L, SEEK_END);
Packit Service db8eaa
	size = ftell(fp);
Packit Service db8eaa
	fseek(fp, 0L, SEEK_SET);
Packit Service db8eaa
	if (size <= 0) {
Packit Service db8eaa
		SNDERR("invalid data file size %zu", size);
Packit Service db8eaa
		ret = -EINVAL;
Packit Service db8eaa
		goto err;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (size > TPLG_MAX_PRIV_SIZE) {
Packit Service db8eaa
		SNDERR("data file too big %zu", size);
Packit Service db8eaa
		ret = -EINVAL;
Packit Service db8eaa
		goto err;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	priv = calloc(1, sizeof(*priv) + size);
Packit Service db8eaa
	if (!priv) {
Packit Service db8eaa
		ret = -ENOMEM;
Packit Service db8eaa
		goto err;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	bytes_read = fread(&priv->data, 1, size, fp);
Packit Service db8eaa
	if (bytes_read != size) {
Packit Service db8eaa
		ret = -errno;
Packit Service db8eaa
		goto err;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	elem->data = priv;
Packit Service db8eaa
	priv->size = size;
Packit Service db8eaa
	elem->size = sizeof(*priv) + size;
Packit Service db8eaa
Packit Service db8eaa
	if (fclose(fp) == EOF) {
Packit Service db8eaa
		SNDERR("Cannot close data file.");
Packit Service db8eaa
		return -errno;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
Packit Service db8eaa
err:
Packit Service db8eaa
	fclose(fp);
Packit Service db8eaa
	if (priv)
Packit Service db8eaa
		free(priv);
Packit Service db8eaa
	return ret;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static void dump_priv_data(struct tplg_elem *elem ATTRIBUTE_UNUSED)
Packit Service db8eaa
{
Packit Service db8eaa
#ifdef TPLG_DEBUG
Packit Service db8eaa
	struct snd_soc_tplg_private *priv = elem->data;
Packit Service db8eaa
	unsigned char *p = (unsigned char *)priv->data;
Packit Service db8eaa
	char buf[128], buf2[8];
Packit Service db8eaa
	unsigned int i;
Packit Service db8eaa
Packit Service db8eaa
	tplg_dbg(" elem size = %d, priv data size = %d",
Packit Service db8eaa
		elem->size, priv->size);
Packit Service db8eaa
Packit Service db8eaa
	buf[0] = '\0';
Packit Service db8eaa
	for (i = 0; i < priv->size; i++) {
Packit Service db8eaa
		if (i > 0 && (i % 16) == 0) {
Packit Service db8eaa
			tplg_dbg("%s", buf);
Packit Service db8eaa
			buf[0] = '\0';
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		snprintf(buf2, sizeof(buf2), " %02x", *p++);
Packit Service db8eaa
		strcat(buf, buf2);
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (buf[0])
Packit Service db8eaa
		tplg_dbg("%s", buf);
Packit Service db8eaa
#endif
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static inline int check_nibble(unsigned char c)
Packit Service db8eaa
{
Packit Service db8eaa
	return (c >= '0' && c <= '9') ||
Packit Service db8eaa
	       (c >= 'a' && c <= 'f') ||
Packit Service db8eaa
	       (c >= 'A' && c <= 'F');
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* get number of hex value elements in CSV list */
Packit Service db8eaa
static int get_hex_num(const char *str)
Packit Service db8eaa
{
Packit Service db8eaa
	int delims, values, len = strlen(str);
Packit Service db8eaa
	const char *s, *end = str + len;
Packit Service db8eaa
Packit Service db8eaa
	/* check "aa:bb:00" syntax */
Packit Service db8eaa
	s = str;
Packit Service db8eaa
	delims = values = 0;
Packit Service db8eaa
	while (s < end) {
Packit Service db8eaa
		/* skip white space */
Packit Service db8eaa
		if (isspace(*s)) {
Packit Service db8eaa
			s++;
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
		/* find delimeters */
Packit Service db8eaa
		if (*s == ':') {
Packit Service db8eaa
			delims++;
Packit Service db8eaa
			s++;
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
		/* check 00 hexadecimal value */
Packit Service db8eaa
		if (s + 1 <= end) {
Packit Service db8eaa
			if (check_nibble(s[0]) && check_nibble(s[1])) {
Packit Service db8eaa
				values++;
Packit Service db8eaa
			} else {
Packit Service db8eaa
				goto format2;
Packit Service db8eaa
			}
Packit Service db8eaa
			s++;
Packit Service db8eaa
		}
Packit Service db8eaa
		s++;
Packit Service db8eaa
	}
Packit Service db8eaa
	goto end;
Packit Service db8eaa
Packit Service db8eaa
format2:
Packit Service db8eaa
	/* we expect "0x0, 0x0, 0x0" */
Packit Service db8eaa
	s = str;
Packit Service db8eaa
	delims = values = 0;
Packit Service db8eaa
	while (s < end) {
Packit Service db8eaa
Packit Service db8eaa
		/* skip white space */
Packit Service db8eaa
		if (isspace(*s)) {
Packit Service db8eaa
			s++;
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		/* find delimeters */
Packit Service db8eaa
		if (*s == ',') {
Packit Service db8eaa
			delims++;
Packit Service db8eaa
			s++;
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		/* find 0x[0-9] values */
Packit Service db8eaa
		if (*s == '0' && s + 2 <= end) {
Packit Service db8eaa
			if (s[1] == 'x' && check_nibble(s[2])) {
Packit Service db8eaa
				if (check_nibble(s[3]))
Packit Service db8eaa
					s++;
Packit Service db8eaa
				values++;
Packit Service db8eaa
				s += 2;
Packit Service db8eaa
			}
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		s++;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
end:
Packit Service db8eaa
	/* there should always be one less comma than value */
Packit Service db8eaa
	if (values - 1 != delims)
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
Packit Service db8eaa
	return values;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* get uuid from a string made by 16 characters separated by commas */
Packit Service db8eaa
static int get_uuid(const char *str, unsigned char *uuid_le)
Packit Service db8eaa
{
Packit Service db8eaa
	unsigned long int  val;
Packit Service db8eaa
	char *tmp, *s = NULL;
Packit Service db8eaa
	int values = 0, ret = 0;
Packit Service db8eaa
Packit Service db8eaa
	tmp = strdup(str);
Packit Service db8eaa
	if (tmp == NULL)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
	if (strchr(tmp, ':') == NULL)
Packit Service db8eaa
		goto data2;
Packit Service db8eaa
Packit Service db8eaa
	s = strtok(tmp, ":");
Packit Service db8eaa
	while (s != NULL) {
Packit Service db8eaa
		errno = 0;
Packit Service db8eaa
		val = strtoul(s, NULL, 16);
Packit Service db8eaa
		if ((errno == ERANGE && val == ULONG_MAX)
Packit Service db8eaa
			|| (errno != 0 && val == 0)
Packit Service db8eaa
			|| (val > UCHAR_MAX)) {
Packit Service db8eaa
			SNDERR("invalid value for uuid");
Packit Service db8eaa
			ret = -EINVAL;
Packit Service db8eaa
			goto out;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		*(uuid_le + values) = (unsigned char)val;
Packit Service db8eaa
Packit Service db8eaa
		values++;
Packit Service db8eaa
		if (values >= 16)
Packit Service db8eaa
			break;
Packit Service db8eaa
Packit Service db8eaa
		s = strtok(NULL, ":");
Packit Service db8eaa
	}
Packit Service db8eaa
	goto out;
Packit Service db8eaa
Packit Service db8eaa
data2:
Packit Service db8eaa
	s = strtok(tmp, ",");
Packit Service db8eaa
Packit Service db8eaa
	while (s != NULL) {
Packit Service db8eaa
		errno = 0;
Packit Service db8eaa
		val = strtoul(s, NULL, 0);
Packit Service db8eaa
		if ((errno == ERANGE && val == ULONG_MAX)
Packit Service db8eaa
			|| (errno != 0 && val == 0)
Packit Service db8eaa
			|| (val > UCHAR_MAX)) {
Packit Service db8eaa
			SNDERR("invalid value for uuid");
Packit Service db8eaa
			ret = -EINVAL;
Packit Service db8eaa
			goto out;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		*(uuid_le + values) = (unsigned char)val;
Packit Service db8eaa
Packit Service db8eaa
		values++;
Packit Service db8eaa
		if (values >= 16)
Packit Service db8eaa
			break;
Packit Service db8eaa
Packit Service db8eaa
		s = strtok(NULL, ",");
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (values < 16) {
Packit Service db8eaa
		SNDERR("less than 16 integers for uuid");
Packit Service db8eaa
		ret = -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
out:
Packit Service db8eaa
	free(tmp);
Packit Service db8eaa
	return ret;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int write_hex(char *buf, char *str, int width)
Packit Service db8eaa
{
Packit Service db8eaa
	long val;
Packit Service db8eaa
	void *p = &val;
Packit Service db8eaa
Packit Service db8eaa
        errno = 0;
Packit Service db8eaa
	val = strtol(str, NULL, 16);
Packit Service db8eaa
Packit Service db8eaa
	if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
Packit Service db8eaa
		|| (errno != 0 && val == 0)) {
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
        }
Packit Service db8eaa
Packit Service db8eaa
	switch (width) {
Packit Service db8eaa
	case 1:
Packit Service db8eaa
		*(unsigned char *)buf = *(unsigned char *)p;
Packit Service db8eaa
		break;
Packit Service db8eaa
	case 2:
Packit Service db8eaa
		*(unsigned short *)buf = *(unsigned short *)p;
Packit Service db8eaa
		break;
Packit Service db8eaa
	case 4:
Packit Service db8eaa
		*(unsigned int *)buf = *(unsigned int *)p;
Packit Service db8eaa
		break;
Packit Service db8eaa
	default:
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int copy_data_hex(char *data, int off, const char *str, int width)
Packit Service db8eaa
{
Packit Service db8eaa
	char *tmp, *s = NULL, *p = data;
Packit Service db8eaa
	int ret;
Packit Service db8eaa
Packit Service db8eaa
	tmp = strdup(str);
Packit Service db8eaa
	if (tmp == NULL)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
	p += off;
Packit Service db8eaa
	s = strtok(tmp, ",:");
Packit Service db8eaa
Packit Service db8eaa
	while (s != NULL) {
Packit Service db8eaa
		ret = write_hex(p, s, width);
Packit Service db8eaa
		if (ret < 0) {
Packit Service db8eaa
			free(tmp);
Packit Service db8eaa
			return ret;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		s = strtok(NULL, ",:");
Packit Service db8eaa
		p += width;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	free(tmp);
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int tplg_parse_data_hex(snd_config_t *cfg, struct tplg_elem *elem,
Packit Service db8eaa
	int width)
Packit Service db8eaa
{
Packit Service db8eaa
	struct snd_soc_tplg_private *priv;
Packit Service db8eaa
	const char *value = NULL;
Packit Service db8eaa
	int size, esize, off, num;
Packit Service db8eaa
	int ret;
Packit Service db8eaa
Packit Service db8eaa
	tplg_dbg(" data: %s", elem->id);
Packit Service db8eaa
Packit Service db8eaa
	if (snd_config_get_string(cfg, &value) < 0)
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
Packit Service db8eaa
	num = get_hex_num(value);
Packit Service db8eaa
	if (num <= 0) {
Packit Service db8eaa
		SNDERR("malformed hex variable list %s", value);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	size = num * width;
Packit Service db8eaa
	priv = elem->data;
Packit Service db8eaa
Packit Service db8eaa
	if (size > TPLG_MAX_PRIV_SIZE) {
Packit Service db8eaa
		SNDERR("data too big %d", size);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (priv != NULL) {
Packit Service db8eaa
		off = priv->size;
Packit Service db8eaa
		esize = elem->size + size;
Packit Service db8eaa
		priv = realloc(priv, esize);
Packit Service db8eaa
	} else {
Packit Service db8eaa
		off = 0;
Packit Service db8eaa
		esize = sizeof(*priv) + size;
Packit Service db8eaa
		priv = calloc(1, esize);
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (!priv)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
	elem->data = priv;
Packit Service db8eaa
	priv->size += size;
Packit Service db8eaa
	elem->size = esize;
Packit Service db8eaa
Packit Service db8eaa
	ret = copy_data_hex(priv->data, off, value, width);
Packit Service db8eaa
Packit Service db8eaa
	dump_priv_data(elem);
Packit Service db8eaa
	return ret;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* get the token integer value from its id */
Packit Service db8eaa
static int get_token_value(const char *token_id,
Packit Service db8eaa
			   struct tplg_vendor_tokens *tokens)
Packit Service db8eaa
{
Packit Service db8eaa
	unsigned int i;
Packit Service db8eaa
Packit Service db8eaa
	for (i = 0; i < tokens->num_tokens; i++) {
Packit Service db8eaa
		if (strcmp(token_id, tokens->token[i].id) == 0)
Packit Service db8eaa
			return tokens->token[i].value;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	SNDERR("cannot find token id '%s'", token_id);
Packit Service db8eaa
	return -1;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* get the vendor tokens referred by the vendor tuples */
Packit Service db8eaa
static struct tplg_elem *get_tokens(snd_tplg_t *tplg, struct tplg_elem *elem)
Packit Service db8eaa
{
Packit Service db8eaa
	struct tplg_ref *ref;
Packit Service db8eaa
	struct list_head *base, *pos;
Packit Service db8eaa
Packit Service db8eaa
	base = &elem->ref_list;
Packit Service db8eaa
	list_for_each(pos, base) {
Packit Service db8eaa
Packit Service db8eaa
		ref = list_entry(pos, struct tplg_ref, list);
Packit Service db8eaa
Packit Service db8eaa
		if (ref->type != SND_TPLG_TYPE_TOKEN)
Packit Service db8eaa
			continue;
Packit Service db8eaa
Packit Service db8eaa
		if (!ref->elem) {
Packit Service db8eaa
			ref->elem = tplg_elem_lookup(&tplg->token_list,
Packit Service db8eaa
				ref->id, SND_TPLG_TYPE_TOKEN, elem->index);
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		return ref->elem;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return NULL;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* check if a data element has tuples */
Packit Service db8eaa
static bool has_tuples(struct tplg_elem *elem)
Packit Service db8eaa
{
Packit Service db8eaa
	struct tplg_ref *ref;
Packit Service db8eaa
	struct list_head *base, *pos;
Packit Service db8eaa
Packit Service db8eaa
	base = &elem->ref_list;
Packit Service db8eaa
	list_for_each(pos, base) {
Packit Service db8eaa
Packit Service db8eaa
		ref = list_entry(pos, struct tplg_ref, list);
Packit Service db8eaa
		if (ref->type == SND_TPLG_TYPE_TUPLE)
Packit Service db8eaa
			return true;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return false;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* get size of a tuple element from its type */
Packit Service db8eaa
unsigned int tplg_get_tuple_size(int type)
Packit Service db8eaa
{
Packit Service db8eaa
	switch (type) {
Packit Service db8eaa
Packit Service db8eaa
	case SND_SOC_TPLG_TUPLE_TYPE_UUID:
Packit Service db8eaa
		return sizeof(struct snd_soc_tplg_vendor_uuid_elem);
Packit Service db8eaa
Packit Service db8eaa
	case SND_SOC_TPLG_TUPLE_TYPE_STRING:
Packit Service db8eaa
		return sizeof(struct snd_soc_tplg_vendor_string_elem);
Packit Service db8eaa
Packit Service db8eaa
	default:
Packit Service db8eaa
		return sizeof(struct snd_soc_tplg_vendor_value_elem);
Packit Service db8eaa
	}
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* Add a tuples object to the private buffer of its parent data element */
Packit Service db8eaa
static int copy_tuples(struct tplg_elem *elem,
Packit Service db8eaa
		       struct tplg_vendor_tuples *tuples,
Packit Service db8eaa
		       struct tplg_vendor_tokens *tokens)
Packit Service db8eaa
{
Packit Service db8eaa
	struct snd_soc_tplg_private *priv = elem->data, *priv2;
Packit Service db8eaa
	struct tplg_tuple_set *tuple_set;
Packit Service db8eaa
	struct tplg_tuple *tuple;
Packit Service db8eaa
	struct snd_soc_tplg_vendor_array *array;
Packit Service db8eaa
	struct snd_soc_tplg_vendor_uuid_elem *uuid;
Packit Service db8eaa
	struct snd_soc_tplg_vendor_string_elem *string;
Packit Service db8eaa
	struct snd_soc_tplg_vendor_value_elem *value;
Packit Service db8eaa
	int set_size, size, off;
Packit Service db8eaa
	unsigned int i, j;
Packit Service db8eaa
	int token_val;
Packit Service db8eaa
Packit Service db8eaa
	size = priv ? priv->size : 0; /* original private data size */
Packit Service db8eaa
Packit Service db8eaa
	/* scan each tuples set (one set per type) */
Packit Service db8eaa
	for (i = 0; i < tuples->num_sets ; i++) {
Packit Service db8eaa
		tuple_set = tuples->set[i];
Packit Service db8eaa
		set_size = sizeof(struct snd_soc_tplg_vendor_array)
Packit Service db8eaa
			+ tplg_get_tuple_size(tuple_set->type)
Packit Service db8eaa
			* tuple_set->num_tuples;
Packit Service db8eaa
		size += set_size;
Packit Service db8eaa
		if (size > TPLG_MAX_PRIV_SIZE) {
Packit Service db8eaa
			SNDERR("data too big %d", size);
Packit Service db8eaa
			return -EINVAL;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (priv != NULL) {
Packit Service db8eaa
			priv2 = realloc(priv, sizeof(*priv) + size);
Packit Service db8eaa
			if (priv2 == NULL) {
Packit Service db8eaa
				free(priv);
Packit Service db8eaa
				priv = NULL;
Packit Service db8eaa
			} else {
Packit Service db8eaa
				priv = priv2;
Packit Service db8eaa
			}
Packit Service db8eaa
		} else {
Packit Service db8eaa
			priv = calloc(1, sizeof(*priv) + size);
Packit Service db8eaa
		}
Packit Service db8eaa
		if (!priv)
Packit Service db8eaa
			return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
		off = priv->size;
Packit Service db8eaa
		priv->size = size; /* update private data size */
Packit Service db8eaa
		elem->data = priv;
Packit Service db8eaa
Packit Service db8eaa
		array = (struct snd_soc_tplg_vendor_array *)(priv->data + off);
Packit Service db8eaa
		memset(array, 0, set_size);
Packit Service db8eaa
		array->size = set_size;
Packit Service db8eaa
		array->type = tuple_set->type;
Packit Service db8eaa
		array->num_elems = tuple_set->num_tuples;
Packit Service db8eaa
Packit Service db8eaa
		/* fill the private data buffer */
Packit Service db8eaa
		for (j = 0; j < tuple_set->num_tuples; j++) {
Packit Service db8eaa
			tuple = &tuple_set->tuple[j];
Packit Service db8eaa
			token_val = get_token_value(tuple->token, tokens);
Packit Service db8eaa
			if (token_val  < 0)
Packit Service db8eaa
				return -EINVAL;
Packit Service db8eaa
Packit Service db8eaa
			switch (tuple_set->type) {
Packit Service db8eaa
			case SND_SOC_TPLG_TUPLE_TYPE_UUID:
Packit Service db8eaa
				uuid = &array->uuid[j];
Packit Service db8eaa
				uuid->token = token_val;
Packit Service db8eaa
				memcpy(uuid->uuid, tuple->uuid, 16);
Packit Service db8eaa
				break;
Packit Service db8eaa
Packit Service db8eaa
			case SND_SOC_TPLG_TUPLE_TYPE_STRING:
Packit Service db8eaa
				string = &array->string[j];
Packit Service db8eaa
				string->token = token_val;
Packit Service db8eaa
				snd_strlcpy(string->string, tuple->string,
Packit Service db8eaa
					SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit Service db8eaa
				break;
Packit Service db8eaa
Packit Service db8eaa
			default:
Packit Service db8eaa
				value = &array->value[j];
Packit Service db8eaa
				value->token = token_val;
Packit Service db8eaa
				value->value = tuple->value;
Packit Service db8eaa
				break;
Packit Service db8eaa
			}
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* build a data element from its tuples */
Packit Service db8eaa
static int build_tuples(snd_tplg_t *tplg, struct tplg_elem *elem)
Packit Service db8eaa
{
Packit Service db8eaa
	struct tplg_ref *ref;
Packit Service db8eaa
	struct list_head *base, *pos;
Packit Service db8eaa
	struct tplg_elem *tuples, *tokens;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	base = &elem->ref_list;
Packit Service db8eaa
	list_for_each(pos, base) {
Packit Service db8eaa
Packit Service db8eaa
		ref = list_entry(pos, struct tplg_ref, list);
Packit Service db8eaa
Packit Service db8eaa
		if (ref->type != SND_TPLG_TYPE_TUPLE)
Packit Service db8eaa
			continue;
Packit Service db8eaa
Packit Service db8eaa
		tplg_dbg("tuples '%s' used by data '%s'", ref->id, elem->id);
Packit Service db8eaa
Packit Service db8eaa
		if (!ref->elem)
Packit Service db8eaa
			ref->elem = tplg_elem_lookup(&tplg->tuple_list,
Packit Service db8eaa
				ref->id, SND_TPLG_TYPE_TUPLE, elem->index);
Packit Service db8eaa
		tuples = ref->elem;
Packit Service db8eaa
		if (!tuples) {
Packit Service db8eaa
			SNDERR("cannot find tuples %s", ref->id);
Packit Service db8eaa
			return -EINVAL;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		tokens = get_tokens(tplg, tuples);
Packit Service db8eaa
		if (!tokens) {
Packit Service db8eaa
			SNDERR("cannot find token for %s", ref->id);
Packit Service db8eaa
			return -EINVAL;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		/* a data object can have multiple tuples objects */
Packit Service db8eaa
		err = copy_tuples(elem, tuples->tuples, tokens->tokens);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
struct tuple_type {
Packit Service db8eaa
	unsigned int type;
Packit Service db8eaa
	const char *name;
Packit Service db8eaa
	unsigned int size;
Packit Service db8eaa
};
Packit Service db8eaa
Packit Service db8eaa
static struct tuple_type tuple_types[] = {
Packit Service db8eaa
	{
Packit Service db8eaa
		.type = SND_SOC_TPLG_TUPLE_TYPE_UUID,
Packit Service db8eaa
		.name = "uuid",
Packit Service db8eaa
		.size = 4,
Packit Service db8eaa
	},
Packit Service db8eaa
	{
Packit Service db8eaa
		.type = SND_SOC_TPLG_TUPLE_TYPE_STRING,
Packit Service db8eaa
		.name = "string",
Packit Service db8eaa
		.size = 6,
Packit Service db8eaa
	},
Packit Service db8eaa
	{
Packit Service db8eaa
		.type = SND_SOC_TPLG_TUPLE_TYPE_BOOL,
Packit Service db8eaa
		.name = "bool",
Packit Service db8eaa
		.size = 4,
Packit Service db8eaa
	},
Packit Service db8eaa
	{
Packit Service db8eaa
		.type = SND_SOC_TPLG_TUPLE_TYPE_BYTE,
Packit Service db8eaa
		.name = "byte",
Packit Service db8eaa
		.size = 4,
Packit Service db8eaa
	},
Packit Service db8eaa
	{
Packit Service db8eaa
		.type = SND_SOC_TPLG_TUPLE_TYPE_SHORT,
Packit Service db8eaa
		.name = "short",
Packit Service db8eaa
		.size = 5,
Packit Service db8eaa
	},
Packit Service db8eaa
	{
Packit Service db8eaa
		.type = SND_SOC_TPLG_TUPLE_TYPE_WORD,
Packit Service db8eaa
		.name = "word",
Packit Service db8eaa
		.size = 4
Packit Service db8eaa
	},
Packit Service db8eaa
};
Packit Service db8eaa
Packit Service db8eaa
static int get_tuple_type(const char *name)
Packit Service db8eaa
{
Packit Service db8eaa
	struct tuple_type *t;
Packit Service db8eaa
	unsigned int i;
Packit Service db8eaa
Packit Service db8eaa
	/* skip initial index for sorting */
Packit Service db8eaa
	while ((*name >= '0' && *name <= '9') || *name == '_')
Packit Service db8eaa
		name++;
Packit Service db8eaa
	for (i = 0; i < ARRAY_SIZE(tuple_types); i++) {
Packit Service db8eaa
		t = &tuple_types[i];
Packit Service db8eaa
		if (strncasecmp(t->name, name, t->size) == 0)
Packit Service db8eaa
			return t->type;
Packit Service db8eaa
	}
Packit Service db8eaa
	return -EINVAL;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static const char *get_tuple_type_name(unsigned int type)
Packit Service db8eaa
{
Packit Service db8eaa
	unsigned int i;
Packit Service db8eaa
Packit Service db8eaa
	for (i = 0; i < ARRAY_SIZE(tuple_types); i++)
Packit Service db8eaa
		if (tuple_types[i].type == type)
Packit Service db8eaa
			return tuple_types[i].name;
Packit Service db8eaa
	return NULL;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int parse_tuple_set(snd_config_t *cfg,
Packit Service db8eaa
			   struct tplg_tuple_set **s)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_config_iterator_t i, next;
Packit Service db8eaa
	snd_config_t *n;
Packit Service db8eaa
	const char *id, *value;
Packit Service db8eaa
	struct tplg_tuple_set *set;
Packit Service db8eaa
	unsigned int num_tuples = 0;
Packit Service db8eaa
	struct tplg_tuple *tuple;
Packit Service db8eaa
	unsigned int tuple_val;
Packit Service db8eaa
	int type, ival;
Packit Service db8eaa
Packit Service db8eaa
	snd_config_get_id(cfg, &id;;
Packit Service db8eaa
Packit Service db8eaa
	type = get_tuple_type(id);
Packit Service db8eaa
	if (type < 0) {
Packit Service db8eaa
		SNDERR("invalid tuple type '%s'", id);
Packit Service db8eaa
		return type;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	snd_config_for_each(i, next, cfg)
Packit Service db8eaa
		num_tuples++;
Packit Service db8eaa
	if (!num_tuples)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
Packit Service db8eaa
	tplg_dbg("\t %d %s tuples:", num_tuples, id);
Packit Service db8eaa
	set = calloc(1, sizeof(*set) + num_tuples * sizeof(struct tplg_tuple));
Packit Service db8eaa
	if (!set)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
	set->type = type;
Packit Service db8eaa
Packit Service db8eaa
	snd_config_for_each(i, next, cfg) {
Packit Service db8eaa
Packit Service db8eaa
		n = snd_config_iterator_entry(i);
Packit Service db8eaa
Packit Service db8eaa
		/* get id */
Packit Service db8eaa
		if (snd_config_get_id(n, &id) < 0)
Packit Service db8eaa
			continue;
Packit Service db8eaa
Packit Service db8eaa
		tuple = &set->tuple[set->num_tuples];
Packit Service db8eaa
		snd_strlcpy(tuple->token, id,
Packit Service db8eaa
				SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit Service db8eaa
Packit Service db8eaa
		switch (type) {
Packit Service db8eaa
		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
Packit Service db8eaa
			if (snd_config_get_string(n, &value) < 0)
Packit Service db8eaa
				continue;
Packit Service db8eaa
			if (get_uuid(value, tuple->uuid) < 0)
Packit Service db8eaa
				goto err;
Packit Service db8eaa
			break;
Packit Service db8eaa
Packit Service db8eaa
		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
Packit Service db8eaa
			if (snd_config_get_string(n, &value) < 0)
Packit Service db8eaa
				continue;
Packit Service db8eaa
			snd_strlcpy(tuple->string, value,
Packit Service db8eaa
				SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit Service db8eaa
			tplg_dbg("\t\t%s = %s", tuple->token, tuple->string);
Packit Service db8eaa
			break;
Packit Service db8eaa
Packit Service db8eaa
		case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
Packit Service db8eaa
			ival = snd_config_get_bool(n);
Packit Service db8eaa
			if (ival < 0)
Packit Service db8eaa
				continue;
Packit Service db8eaa
			tuple->value = ival;
Packit Service db8eaa
			tplg_dbg("\t\t%s = %d", tuple->token, tuple->value);
Packit Service db8eaa
			break;
Packit Service db8eaa
Packit Service db8eaa
		case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
Packit Service db8eaa
		case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
Packit Service db8eaa
		case SND_SOC_TPLG_TUPLE_TYPE_WORD:
Packit Service db8eaa
			ival = tplg_get_unsigned(n, &tuple_val, 0);
Packit Service db8eaa
			if (ival < 0) {
Packit Service db8eaa
				SNDERR("tuple %s: %s", id, snd_strerror(ival));
Packit Service db8eaa
				goto err;
Packit Service db8eaa
			}
Packit Service db8eaa
Packit Service 01c0b7
			if (/* (type == SND_SOC_TPLG_TUPLE_TYPE_WORD
Packit Service 01c0b7
					&& tuple_val > UINT_MAX) || */
Packit Service 01c0b7
				(type == SND_SOC_TPLG_TUPLE_TYPE_SHORT
Packit Service 01c0b7
					&& tuple_val > USHRT_MAX) ||
Packit Service 01c0b7
				(type == SND_SOC_TPLG_TUPLE_TYPE_BYTE
Packit Service db8eaa
					&& tuple_val > UCHAR_MAX)) {
Packit Service db8eaa
				SNDERR("tuple %s: invalid value", id);
Packit Service db8eaa
				goto err;
Packit Service db8eaa
			}
Packit Service db8eaa
Packit Service db8eaa
			tuple->value = tuple_val;
Packit Service db8eaa
			tplg_dbg("\t\t%s = 0x%x", tuple->token, tuple->value);
Packit Service db8eaa
			break;
Packit Service db8eaa
Packit Service db8eaa
		default:
Packit Service db8eaa
			break;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		set->num_tuples++;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	*s = set;
Packit Service db8eaa
	return 0;
Packit Service db8eaa
Packit Service db8eaa
err:
Packit Service db8eaa
	free(set);
Packit Service db8eaa
	return -EINVAL;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* save tuple set */
Packit Service db8eaa
static int tplg_save_tuple_set(struct tplg_vendor_tuples *tuples,
Packit Service db8eaa
			       unsigned int set_index,
Packit Service db8eaa
			       struct tplg_buf *dst, const char *pfx)
Packit Service db8eaa
{
Packit Service db8eaa
	struct tplg_tuple_set *set;
Packit Service db8eaa
	struct tplg_tuple *tuple;
Packit Service db8eaa
	const char *s, *fmt;
Packit Service db8eaa
	char buf[32];
Packit Service db8eaa
	unsigned int i;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	set = tuples->set[set_index];
Packit Service db8eaa
	if (set->num_tuples == 0)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
	s = get_tuple_type_name(set->type);
Packit Service db8eaa
	if (s == NULL)
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	if (tuples->num_sets < 10)
Packit Service db8eaa
		fmt = "%u_";
Packit Service db8eaa
	else if (tuples->num_sets < 100)
Packit Service db8eaa
		fmt = "%02u_";
Packit Service db8eaa
	else if (tuples->num_sets < 1000)
Packit Service db8eaa
		fmt = "%03u_";
Packit Service db8eaa
	else
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	if (set->num_tuples > 1) {
Packit Service db8eaa
		snprintf(buf, sizeof(buf), "tuples.%s%%s {\n", fmt);
Packit Service db8eaa
		err = tplg_save_printf(dst, NULL, buf, set_index, s);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	for (i = 0; i < set->num_tuples; i++) {
Packit Service db8eaa
		tuple = &set->tuple[i];
Packit Service db8eaa
		if (set->num_tuples == 1) {
Packit Service db8eaa
			snprintf(buf, sizeof(buf), "tuples.%s%%s.'%%s' ", fmt);
Packit Service db8eaa
			err = tplg_save_printf(dst, NULL, buf,
Packit Service db8eaa
					       set_index, s, tuple->token);
Packit Service db8eaa
		} else {
Packit Service db8eaa
			err = tplg_save_printf(dst, pfx, "\t'%s' ",
Packit Service db8eaa
					       tuple->token);
Packit Service db8eaa
		}
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		switch (set->type) {
Packit Service db8eaa
		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
Packit Service db8eaa
			err = tplg_save_printf(dst, NULL, "'" UUID_FORMAT "'\n",
Packit Service db8eaa
					       tuple->uuid[0], tuple->uuid[1],
Packit Service db8eaa
					       tuple->uuid[2], tuple->uuid[3],
Packit Service db8eaa
					       tuple->uuid[4], tuple->uuid[5],
Packit Service db8eaa
					       tuple->uuid[6], tuple->uuid[7],
Packit Service db8eaa
					       tuple->uuid[8], tuple->uuid[9],
Packit Service db8eaa
					       tuple->uuid[10], tuple->uuid[11],
Packit Service db8eaa
					       tuple->uuid[12], tuple->uuid[13],
Packit Service db8eaa
					       tuple->uuid[14], tuple->uuid[15]);
Packit Service db8eaa
			break;
Packit Service db8eaa
		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
Packit Service db8eaa
			err = tplg_save_printf(dst, NULL, "'%s'\n",
Packit Service db8eaa
					       tuple->string);
Packit Service db8eaa
			break;
Packit Service db8eaa
		case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
Packit Service db8eaa
		case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
Packit Service db8eaa
		case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
Packit Service db8eaa
			err = tplg_save_printf(dst, NULL, "%u\n", tuple->value);
Packit Service db8eaa
			break;
Packit Service db8eaa
		case SND_SOC_TPLG_TUPLE_TYPE_WORD:
Packit Service db8eaa
			tplg_nice_value_format(buf, sizeof(buf), tuple->value);
Packit Service db8eaa
			err = tplg_save_printf(dst, NULL, "%s\n", buf);
Packit Service db8eaa
			break;
Packit Service db8eaa
		default:
Packit Service db8eaa
			return -EINVAL;
Packit Service db8eaa
		}
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (set->num_tuples > 1)
Packit Service db8eaa
		return tplg_save_printf(dst, pfx, "}\n");
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int parse_tuple_sets(snd_config_t *cfg,
Packit Service db8eaa
			    struct tplg_vendor_tuples *tuples)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_config_iterator_t i, next;
Packit Service db8eaa
	snd_config_t *n;
Packit Service db8eaa
	const char *id;
Packit Service db8eaa
	unsigned int num_tuple_sets = 0;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
Packit Service db8eaa
		if (snd_config_get_id(cfg, &id) >= 0)
Packit Service db8eaa
			SNDERR("compound type expected for %s", id);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	snd_config_for_each(i, next, cfg) {
Packit Service db8eaa
		num_tuple_sets++;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (!num_tuple_sets)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
Packit Service db8eaa
	tuples->set = calloc(1, num_tuple_sets * sizeof(void *));
Packit Service db8eaa
	if (!tuples->set)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
	snd_config_for_each(i, next, cfg) {
Packit Service db8eaa
		n = snd_config_iterator_entry(i);
Packit Service db8eaa
		if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
Packit Service db8eaa
			SNDERR("compound type expected for %s, is %d",
Packit Service db8eaa
			       id, snd_config_get_type(n));
Packit Service db8eaa
			return -EINVAL;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		err = parse_tuple_set(n, &tuples->set[tuples->num_sets]);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
Packit Service db8eaa
		/* overlook empty tuple sets */
Packit Service db8eaa
		if (tuples->set[tuples->num_sets])
Packit Service db8eaa
			tuples->num_sets++;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* save tuple sets */
Packit Service db8eaa
int tplg_save_tuple_sets(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
Packit Service db8eaa
			 struct tplg_elem *elem,
Packit Service db8eaa
			 struct tplg_buf *dst, const char *pfx)
Packit Service db8eaa
{
Packit Service db8eaa
	struct tplg_vendor_tuples *tuples = elem->tuples;
Packit Service db8eaa
	unsigned int i;
Packit Service db8eaa
	int err = 0;
Packit Service db8eaa
Packit Service db8eaa
	for (i = 0; i < tuples->num_sets; i++) {
Packit Service db8eaa
		err = tplg_save_printf(dst, pfx, "");
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			break;
Packit Service db8eaa
		err = tplg_save_tuple_set(tuples, i, dst, pfx);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			break;
Packit Service db8eaa
	}
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* Parse vendor tokens
Packit Service db8eaa
 */
Packit Service db8eaa
int tplg_parse_tokens(snd_tplg_t *tplg, snd_config_t *cfg,
Packit Service db8eaa
		      void *private ATTRIBUTE_UNUSED)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_config_iterator_t i, next;
Packit Service db8eaa
	snd_config_t *n;
Packit Service db8eaa
	const char *id;
Packit Service db8eaa
	struct tplg_elem *elem;
Packit Service db8eaa
	struct tplg_vendor_tokens *tokens;
Packit Service db8eaa
	int num_tokens = 0, value;
Packit Service db8eaa
Packit Service db8eaa
	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_TOKEN);
Packit Service db8eaa
	if (!elem)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
	snd_config_for_each(i, next, cfg) {
Packit Service db8eaa
		num_tokens++;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (!num_tokens)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
Packit Service db8eaa
	tplg_dbg(" Vendor tokens: %s, %d tokens", elem->id, num_tokens);
Packit Service db8eaa
Packit Service db8eaa
	tokens = calloc(1, sizeof(*tokens)
Packit Service db8eaa
			+ num_tokens * sizeof(struct tplg_token));
Packit Service db8eaa
	if (!tokens)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
	elem->tokens = tokens;
Packit Service db8eaa
Packit Service db8eaa
	snd_config_for_each(i, next, cfg) {
Packit Service db8eaa
Packit Service db8eaa
		n = snd_config_iterator_entry(i);
Packit Service db8eaa
		if (snd_config_get_id(n, &id) < 0)
Packit Service db8eaa
			continue;
Packit Service db8eaa
Packit Service db8eaa
		if (tplg_get_integer(n, &value, 0))
Packit Service db8eaa
			continue;
Packit Service db8eaa
Packit Service db8eaa
		snd_strlcpy(tokens->token[tokens->num_tokens].id, id,
Packit Service db8eaa
				SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit Service db8eaa
		tokens->token[tokens->num_tokens].value = value;
Packit Service db8eaa
		tplg_dbg("\t\t %s : %d", tokens->token[tokens->num_tokens].id,
Packit Service db8eaa
			tokens->token[tokens->num_tokens].value);
Packit Service db8eaa
		tokens->num_tokens++;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* save vendor tokens */
Packit Service db8eaa
int tplg_save_tokens(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
Packit Service db8eaa
		     struct tplg_elem *elem,
Packit Service db8eaa
		     struct tplg_buf *dst, const char *pfx)
Packit Service db8eaa
{
Packit Service db8eaa
	struct tplg_vendor_tokens *tokens = elem->tokens;
Packit Service db8eaa
	unsigned int i;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	if (!tokens || tokens->num_tokens == 0)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
Packit Service db8eaa
	err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
	for (i = 0; err >= 0 && i < tokens->num_tokens; i++)
Packit Service db8eaa
		err = tplg_save_printf(dst, pfx, "\t'%s' %u\n",
Packit Service db8eaa
				       tokens->token[i].id,
Packit Service db8eaa
				       tokens->token[i].value);
Packit Service db8eaa
	err = tplg_save_printf(dst, pfx, "}\n");
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* Parse vendor tuples.
Packit Service db8eaa
 */
Packit Service db8eaa
int tplg_parse_tuples(snd_tplg_t *tplg, snd_config_t *cfg,
Packit Service db8eaa
		      void *private ATTRIBUTE_UNUSED)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_config_iterator_t i, next;
Packit Service db8eaa
	snd_config_t *n;
Packit Service db8eaa
	const char *id, *value;
Packit Service db8eaa
	struct tplg_elem *elem;
Packit Service db8eaa
	struct tplg_vendor_tuples *tuples;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_TUPLE);
Packit Service db8eaa
	if (!elem)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
	tplg_dbg(" Vendor Tuples: %s", elem->id);
Packit Service db8eaa
Packit Service db8eaa
	tuples = calloc(1, sizeof(*tuples));
Packit Service db8eaa
	if (!tuples)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
	elem->tuples = tuples;
Packit Service db8eaa
Packit Service db8eaa
	snd_config_for_each(i, next, cfg) {
Packit Service db8eaa
Packit Service db8eaa
		n = snd_config_iterator_entry(i);
Packit Service db8eaa
		if (snd_config_get_id(n, &id) < 0)
Packit Service db8eaa
			continue;
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "tokens") == 0) {
Packit Service db8eaa
			if (snd_config_get_string(n, &value) < 0)
Packit Service db8eaa
				return -EINVAL;
Packit Service db8eaa
			tplg_ref_add(elem, SND_TPLG_TYPE_TOKEN, value);
Packit Service db8eaa
			tplg_dbg("\t refer to vendor tokens: %s", value);
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "tuples") == 0) {
Packit Service db8eaa
			err = parse_tuple_sets(n, tuples);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return err;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* save vendor tuples */
Packit Service db8eaa
int tplg_save_tuples(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
Packit Service db8eaa
		     struct tplg_elem *elem,
Packit Service db8eaa
		     struct tplg_buf *dst, const char *pfx)
Packit Service db8eaa
{
Packit Service db8eaa
	char pfx2[16];
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	if (!elem->tuples)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
Packit Service db8eaa
	err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
Packit Service db8eaa
	snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
Packit Service db8eaa
	if (err >= 0)
Packit Service db8eaa
		err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_TOKEN,
Packit Service db8eaa
				     "tokens", dst, pfx2);
Packit Service db8eaa
	if (err >= 0)
Packit Service db8eaa
		err = tplg_save_tuple_sets(tplg, elem, dst, pfx2);
Packit Service db8eaa
	if (err >= 0)
Packit Service db8eaa
		err = tplg_save_printf(dst, pfx, "}\n");
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* Free handler of tuples */
Packit Service db8eaa
void tplg_free_tuples(void *obj)
Packit Service db8eaa
{
Packit Service db8eaa
	struct tplg_vendor_tuples *tuples = (struct tplg_vendor_tuples *)obj;
Packit Service db8eaa
	unsigned int i;
Packit Service db8eaa
Packit Service db8eaa
	if (!tuples || !tuples->set)
Packit Service db8eaa
		return;
Packit Service db8eaa
Packit Service db8eaa
	for (i = 0; i < tuples->num_sets; i++)
Packit Service db8eaa
		free(tuples->set[i]);
Packit Service db8eaa
Packit Service db8eaa
	free(tuples->set);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* Parse manifest's data references
Packit Service db8eaa
 */
Packit Service db8eaa
int tplg_parse_manifest_data(snd_tplg_t *tplg, snd_config_t *cfg,
Packit Service db8eaa
			     void *private ATTRIBUTE_UNUSED)
Packit Service db8eaa
{
Packit Service db8eaa
	struct snd_soc_tplg_manifest *manifest;
Packit Service db8eaa
	struct tplg_elem *elem;
Packit Service db8eaa
	snd_config_iterator_t i, next;
Packit Service db8eaa
	snd_config_t *n;
Packit Service db8eaa
	const char *id;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	if (!list_empty(&tplg->manifest_list)) {
Packit Service db8eaa
		SNDERR("already has manifest data");
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_MANIFEST);
Packit Service db8eaa
	if (!elem)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
	manifest = elem->manifest;
Packit Service db8eaa
	manifest->size = elem->size;
Packit Service db8eaa
Packit Service db8eaa
	tplg_dbg(" Manifest: %s", elem->id);
Packit Service db8eaa
Packit Service db8eaa
	snd_config_for_each(i, next, cfg) {
Packit Service db8eaa
		n = snd_config_iterator_entry(i);
Packit Service db8eaa
		if (snd_config_get_id(n, &id) < 0)
Packit Service db8eaa
			continue;
Packit Service db8eaa
Packit Service db8eaa
		/* skip comments */
Packit Service db8eaa
		if (strcmp(id, "comment") == 0)
Packit Service db8eaa
			continue;
Packit Service db8eaa
		if (id[0] == '#')
Packit Service db8eaa
			continue;
Packit Service db8eaa
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "data") == 0) {
Packit Service db8eaa
			err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_DATA);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return err;
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* save manifest data */
Packit Service db8eaa
int tplg_save_manifest_data(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
Packit Service db8eaa
			    struct tplg_elem *elem, struct tplg_buf *dst,
Packit Service db8eaa
			    const char *pfx)
Packit Service db8eaa
{
Packit Service db8eaa
	struct list_head *pos;
Packit Service db8eaa
	struct tplg_ref *ref;
Packit Service db8eaa
	int err, index, count;
Packit Service db8eaa
Packit Service db8eaa
	/* for each ref in this manifest elem */
Packit Service db8eaa
	count = 0;
Packit Service db8eaa
	list_for_each(pos, &elem->ref_list) {
Packit Service db8eaa
		ref = list_entry(pos, struct tplg_ref, list);
Packit Service db8eaa
		if (ref->type != SND_TPLG_TYPE_DATA)
Packit Service db8eaa
			continue;
Packit Service db8eaa
		count++;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (count == 0)
Packit Service db8eaa
		return tplg_save_printf(dst, NULL,
Packit Service db8eaa
					"'%s'.comment 'empty'\n", elem->id);
Packit Service db8eaa
	if (count > 1) {
Packit Service db8eaa
		err = tplg_save_printf(dst, NULL, "'%s'.data [\n", elem->id);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	index = 0;
Packit Service db8eaa
	list_for_each(pos, &elem->ref_list) {
Packit Service db8eaa
		ref = list_entry(pos, struct tplg_ref, list);
Packit Service db8eaa
		if (ref->type != SND_TPLG_TYPE_DATA)
Packit Service db8eaa
			continue;
Packit Service db8eaa
		if (count == 1) {
Packit Service db8eaa
			err = tplg_save_printf(dst, NULL, "'%s'.data.%u '%s'\n",
Packit Service db8eaa
					       elem->id, index, ref->id);
Packit Service db8eaa
		} else {
Packit Service db8eaa
			err = tplg_save_printf(dst, pfx, "\t'%s'\n", ref->id);
Packit Service db8eaa
		}
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		index++;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (count > 1) {
Packit Service db8eaa
		err = tplg_save_printf(dst, pfx, "]\n");
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* merge private data of manifest */
Packit Service db8eaa
int tplg_build_manifest_data(snd_tplg_t *tplg)
Packit Service db8eaa
{
Packit Service db8eaa
	struct list_head *base, *pos;
Packit Service db8eaa
	struct tplg_elem *elem = NULL;
Packit Service db8eaa
	struct tplg_ref *ref;
Packit Service db8eaa
	struct snd_soc_tplg_manifest *manifest;
Packit Service db8eaa
	int err = 0;
Packit Service db8eaa
Packit Service db8eaa
	base = &tplg->manifest_list;
Packit Service db8eaa
	list_for_each(pos, base) {
Packit Service db8eaa
Packit Service db8eaa
		elem = list_entry(pos, struct tplg_elem, list);
Packit Service db8eaa
		break;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (!elem) /* no manifest data */
Packit Service db8eaa
		return 0;
Packit Service db8eaa
Packit Service db8eaa
	base = &elem->ref_list;
Packit Service db8eaa
Packit Service db8eaa
	/* for each ref in this manifest elem */
Packit Service db8eaa
	list_for_each(pos, base) {
Packit Service db8eaa
Packit Service db8eaa
		ref = list_entry(pos, struct tplg_ref, list);
Packit Service db8eaa
		if (ref->elem)
Packit Service db8eaa
			continue;
Packit Service db8eaa
Packit Service db8eaa
		if (ref->type == SND_TPLG_TYPE_DATA) {
Packit Service db8eaa
			err = tplg_copy_data(tplg, elem, ref);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return err;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	manifest = elem->manifest;
Packit Service db8eaa
	if (!manifest->priv.size) /* no manifest data */
Packit Service db8eaa
		return 0;
Packit Service db8eaa
Packit Service db8eaa
	tplg->manifest_pdata = malloc(manifest->priv.size);
Packit Service db8eaa
	if (!tplg->manifest_pdata)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
	tplg->manifest.priv.size = manifest->priv.size;
Packit Service db8eaa
	memcpy(tplg->manifest_pdata, manifest->priv.data, manifest->priv.size);
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* Parse Private data.
Packit Service db8eaa
 *
Packit Service db8eaa
 * Object private data can either be from file or defined as bytes, shorts,
Packit Service db8eaa
 * words, tuples.
Packit Service db8eaa
 */
Packit Service db8eaa
int tplg_parse_data(snd_tplg_t *tplg, snd_config_t *cfg,
Packit Service db8eaa
		    void *private ATTRIBUTE_UNUSED)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_config_iterator_t i, next;
Packit Service db8eaa
	snd_config_t *n;
Packit Service db8eaa
	const char *id;
Packit Service db8eaa
	int err = 0, ival;
Packit Service db8eaa
	struct tplg_elem *elem;
Packit Service db8eaa
Packit Service db8eaa
	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_DATA);
Packit Service db8eaa
	if (!elem)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
	snd_config_for_each(i, next, cfg) {
Packit Service db8eaa
Packit Service db8eaa
		n = snd_config_iterator_entry(i);
Packit Service db8eaa
		if (snd_config_get_id(n, &id) < 0) {
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "file") == 0) {
Packit Service db8eaa
			err = tplg_parse_data_file(n, elem);
Packit Service db8eaa
			if (err < 0) {
Packit Service db8eaa
				SNDERR("failed to parse data file");
Packit Service db8eaa
				return err;
Packit Service db8eaa
			}
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "bytes") == 0) {
Packit Service db8eaa
			err = tplg_parse_data_hex(n, elem, 1);
Packit Service db8eaa
			if (err < 0) {
Packit Service db8eaa
				SNDERR("failed to parse data bytes");
Packit Service db8eaa
				return err;
Packit Service db8eaa
			}
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "shorts") == 0) {
Packit Service db8eaa
			err = tplg_parse_data_hex(n, elem, 2);
Packit Service db8eaa
			if (err < 0) {
Packit Service db8eaa
				SNDERR("failed to parse data shorts");
Packit Service db8eaa
				return err;
Packit Service db8eaa
			}
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "words") == 0) {
Packit Service db8eaa
			err = tplg_parse_data_hex(n, elem, 4);
Packit Service db8eaa
			if (err < 0) {
Packit Service db8eaa
				SNDERR("failed to parse data words");
Packit Service db8eaa
				return err;
Packit Service db8eaa
			}
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "tuples") == 0) {
Packit Service db8eaa
			err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_TUPLE);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return err;
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(id, "type") == 0) {
Packit Service db8eaa
			if (tplg_get_integer(n, &ival, 0))
Packit Service db8eaa
				return -EINVAL;
Packit Service db8eaa
Packit Service db8eaa
			elem->vendor_type = ival;
Packit Service db8eaa
			tplg_dbg("\t%s: %d", id, elem->index);
Packit Service db8eaa
			continue;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* save data element */
Packit Service db8eaa
int tplg_save_data(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
Packit Service db8eaa
		   struct tplg_elem *elem,
Packit Service db8eaa
		   struct tplg_buf *dst, const char *pfx)
Packit Service db8eaa
{
Packit Service db8eaa
	struct snd_soc_tplg_private *priv = elem->data;
Packit Service db8eaa
	struct list_head *pos;
Packit Service db8eaa
	struct tplg_ref *ref;
Packit Service db8eaa
	char pfx2[16];
Packit Service db8eaa
	unsigned int i, count;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	count = 0;
Packit Service db8eaa
	if (priv && priv->size > 0)
Packit Service db8eaa
		count++;
Packit Service db8eaa
	list_for_each(pos, &elem->ref_list) {
Packit Service db8eaa
		ref = list_entry(pos, struct tplg_ref, list);
Packit Service db8eaa
		if (ref->type == SND_TPLG_TYPE_TUPLE)
Packit Service db8eaa
			count++;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (elem->vendor_type > 0)
Packit Service db8eaa
		count++;
Packit Service db8eaa
Packit Service db8eaa
	if (count > 1) {
Packit Service db8eaa
		err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id);
Packit Service db8eaa
		if (err >= 0)
Packit Service db8eaa
			err = tplg_save_printf(dst, NULL, "");
Packit Service db8eaa
	} else {
Packit Service db8eaa
		err = tplg_save_printf(dst, NULL, "'%s'.", elem->id);
Packit Service db8eaa
	}
Packit Service db8eaa
	if (err >= 0 && priv && priv->size > 0) {
Packit Service db8eaa
		if (count > 1) {
Packit Service db8eaa
			err = tplg_save_printf(dst, pfx, "");
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return err;
Packit Service db8eaa
		}
Packit Service db8eaa
		if (priv->size > 8) {
Packit Service db8eaa
			err = tplg_save_printf(dst, NULL, "bytes\n");
Packit Service db8eaa
			if (err >= 0)
Packit Service db8eaa
				err = tplg_save_printf(dst, pfx, "\t'");
Packit Service db8eaa
		} else {
Packit Service db8eaa
			err = tplg_save_printf(dst, NULL, "bytes '");
Packit Service db8eaa
		}
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		for (i = 0; i < priv->size; i++) {
Packit Service db8eaa
			if (i > 0 && (i % 8) == 0) {
Packit Service db8eaa
				err = tplg_save_printf(dst, NULL, ":\n");
Packit Service db8eaa
				if (err < 0)
Packit Service db8eaa
					return err;
Packit Service db8eaa
				err = tplg_save_printf(dst, pfx, "\t ");
Packit Service db8eaa
				if (err < 0)
Packit Service db8eaa
					return err;
Packit Service db8eaa
			}
Packit Service db8eaa
			err = tplg_save_printf(dst, NULL, "%s%02x",
Packit Service db8eaa
					       (i % 8) == 0 ? "" : ":",
Packit Service db8eaa
					       (unsigned char)priv->data[i]);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return err;
Packit Service db8eaa
		}
Packit Service db8eaa
		err = tplg_save_printf(dst, NULL, "'\n");
Packit Service db8eaa
	}
Packit Service db8eaa
	snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: "");
Packit Service db8eaa
	if (err >= 0)
Packit Service db8eaa
		err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_TUPLE,
Packit Service db8eaa
				     "tuples", dst,
Packit Service db8eaa
				     count > 1 ? pfx2 : NULL);
Packit Service db8eaa
	if (err >= 0 && elem->vendor_type > 0)
Packit Service db8eaa
		err = tplg_save_printf(dst, pfx, "type %u",
Packit Service db8eaa
				       elem->vendor_type);
Packit Service db8eaa
	if (err >= 0 && count > 1)
Packit Service db8eaa
		err = tplg_save_printf(dst, pfx, "}\n");
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* Find a referenced data element and copy its data to the parent
Packit Service db8eaa
 * element's private data buffer.
Packit Service db8eaa
 * An element can refer to multiple data sections. Data of these sections
Packit Service db8eaa
 * will be merged in the their reference order.
Packit Service db8eaa
 */
Packit Service db8eaa
int tplg_copy_data(snd_tplg_t *tplg, struct tplg_elem *elem,
Packit Service db8eaa
		   struct tplg_ref *ref)
Packit Service db8eaa
{
Packit Service db8eaa
	struct tplg_elem *ref_elem;
Packit Service db8eaa
	struct snd_soc_tplg_private *priv, *old_priv;
Packit Service db8eaa
	int priv_data_size, old_priv_data_size;
Packit Service db8eaa
	void *obj;
Packit Service db8eaa
Packit Service db8eaa
	ref_elem = tplg_elem_lookup(&tplg->pdata_list,
Packit Service db8eaa
				     ref->id, SND_TPLG_TYPE_DATA, elem->index);
Packit Service db8eaa
	if (!ref_elem) {
Packit Service db8eaa
		SNDERR("cannot find data '%s' referenced by"
Packit Service db8eaa
		       " element '%s'", ref->id, elem->id);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	tplg_dbg("Data '%s' used by '%s'", ref->id, elem->id);
Packit Service db8eaa
	/* overlook empty private data */
Packit Service db8eaa
	if (!ref_elem->data || !ref_elem->data->size) {
Packit Service db8eaa
		ref->elem = ref_elem;
Packit Service db8eaa
		return 0;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	old_priv = get_priv_data(elem);
Packit Service db8eaa
	if (!old_priv)
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	old_priv_data_size = old_priv->size;
Packit Service db8eaa
Packit Service db8eaa
	priv_data_size = ref_elem->data->size;
Packit Service db8eaa
	obj = realloc(elem->obj,
Packit Service db8eaa
			elem->size + priv_data_size);
Packit Service db8eaa
	if (!obj)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
	elem->obj = obj;
Packit Service db8eaa
Packit Service db8eaa
	priv = get_priv_data(elem);
Packit Service db8eaa
	if (!priv)
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
Packit Service db8eaa
	/* merge the new data block */
Packit Service db8eaa
	elem->size += priv_data_size;
Packit Service db8eaa
	priv->size = priv_data_size + old_priv_data_size;
Packit Service db8eaa
	ref_elem->compound_elem = 1;
Packit Service db8eaa
	memcpy(priv->data + old_priv_data_size,
Packit Service db8eaa
	       ref_elem->data->data, priv_data_size);
Packit Service db8eaa
Packit Service db8eaa
	ref->elem = ref_elem;
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* check data objects and build those with tuples */
Packit Service db8eaa
int tplg_build_data(snd_tplg_t *tplg)
Packit Service db8eaa
{
Packit Service db8eaa
	struct list_head *base, *pos;
Packit Service db8eaa
	struct tplg_elem *elem;
Packit Service db8eaa
	int err = 0;
Packit Service db8eaa
Packit Service db8eaa
	base = &tplg->pdata_list;
Packit Service db8eaa
	list_for_each(pos, base) {
Packit Service db8eaa
Packit Service db8eaa
		elem = list_entry(pos, struct tplg_elem, list);
Packit Service db8eaa
		if (has_tuples(elem)) {
Packit Service db8eaa
			err = build_tuples(tplg, elem);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return err;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* decode manifest data */
Packit Service db8eaa
int tplg_decode_manifest_data(snd_tplg_t *tplg,
Packit Service db8eaa
			      size_t pos,
Packit Service db8eaa
			      struct snd_soc_tplg_hdr *hdr,
Packit Service db8eaa
			      void *bin, size_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	struct snd_soc_tplg_manifest *m = bin;
Packit Service db8eaa
	struct tplg_elem *elem;
Packit Service db8eaa
	size_t off;
Packit Service db8eaa
Packit Service db8eaa
	if (hdr->index != 0) {
Packit Service db8eaa
		SNDERR("manifest - wrong index %d", hdr->index);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (sizeof(*m) > size) {
Packit Service db8eaa
		SNDERR("manifest - wrong size %zd (minimal %zd)",
Packit Service db8eaa
		       size, sizeof(*m));
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (m->size != sizeof(*m)) {
Packit Service db8eaa
		SNDERR("manifest - wrong sructure size %d", m->size);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	off = offsetof(struct snd_soc_tplg_manifest, priv);
Packit Service db8eaa
	if (off + m->priv.size > size) {
Packit Service db8eaa
		SNDERR("manifest - wrong private size %d", m->priv.size);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	tplg->manifest = *m;
Packit Service db8eaa
Packit Service db8eaa
	bin += off;
Packit Service db8eaa
	size -= off;
Packit Service db8eaa
	pos += off;
Packit Service db8eaa
Packit Service db8eaa
	elem = tplg_elem_new_common(tplg, NULL, "manifest",
Packit Service db8eaa
				    SND_TPLG_TYPE_MANIFEST);
Packit Service db8eaa
	if (!elem)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
	tplg_log(tplg, 'D', pos, "manifest: private size %zd", size);
Packit Service db8eaa
	return tplg_add_data(tplg, elem, bin, size);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
int tplg_add_token(snd_tplg_t *tplg, struct tplg_elem *parent,
Packit Service db8eaa
		   unsigned int token,
Packit Service db8eaa
		   char str_ref[SNDRV_CTL_ELEM_ID_NAME_MAXLEN])
Packit Service db8eaa
{
Packit Service db8eaa
	struct tplg_elem *elem;
Packit Service db8eaa
	struct tplg_token *t;
Packit Service db8eaa
	struct tplg_vendor_tokens *tokens;
Packit Service db8eaa
	unsigned int i;
Packit Service db8eaa
	size_t size;
Packit Service db8eaa
Packit Service db8eaa
	elem = tplg_elem_lookup(&tplg->token_list, parent->id,
Packit Service db8eaa
				SND_TPLG_TYPE_TOKEN, parent->index);
Packit Service db8eaa
	if (elem == NULL) {
Packit Service db8eaa
		elem = tplg_elem_new_common(tplg, NULL, parent->id,
Packit Service db8eaa
					    SND_TPLG_TYPE_TOKEN);
Packit Service db8eaa
		if (!elem)
Packit Service db8eaa
			return -ENOMEM;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	tokens = elem->tokens;
Packit Service db8eaa
	if (tokens) {
Packit Service db8eaa
		for (i = 0; i < tokens->num_tokens; i++) {
Packit Service db8eaa
			t = &tokens->token[i];
Packit Service db8eaa
			if (t->value == token)
Packit Service db8eaa
				goto found;
Packit Service db8eaa
		}
Packit Service db8eaa
		size = sizeof(*tokens) +
Packit Service db8eaa
		       (tokens->num_tokens + 1) * sizeof(struct tplg_token);
Packit Service db8eaa
		tokens = realloc(tokens, size);
Packit Service db8eaa
	} else {
Packit Service db8eaa
		size = sizeof(*tokens) + 1 * sizeof(struct tplg_token);
Packit Service db8eaa
		tokens = calloc(1, size);
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (!tokens)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
	memset(&tokens->token[tokens->num_tokens], 0, sizeof(struct tplg_token));
Packit Service db8eaa
	elem->tokens = tokens;
Packit Service db8eaa
	t = &tokens->token[tokens->num_tokens];
Packit Service db8eaa
	tokens->num_tokens++;
Packit Service db8eaa
	snprintf(t->id, sizeof(t->id), "token%u", token);
Packit Service db8eaa
	t->value = token;
Packit Service db8eaa
found:
Packit Service db8eaa
	snd_strlcpy(str_ref, t->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int tplg_verify_tuple_set(snd_tplg_t *tplg, size_t pos,
Packit Service db8eaa
				 const void *bin, size_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	const struct snd_soc_tplg_vendor_array *va;
Packit Service db8eaa
	unsigned int j;
Packit Service db8eaa
Packit Service db8eaa
	va = bin;
Packit Service db8eaa
	if (size < sizeof(*va) || size < va->size) {
Packit Service db8eaa
		tplg_log(tplg, 'A', pos, "tuple set verify: wrong size %zd", size);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	switch (va->type) {
Packit Service db8eaa
	case SND_SOC_TPLG_TUPLE_TYPE_UUID:
Packit Service db8eaa
	case SND_SOC_TPLG_TUPLE_TYPE_STRING:
Packit Service db8eaa
	case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
Packit Service db8eaa
	case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
Packit Service db8eaa
	case SND_SOC_TPLG_TUPLE_TYPE_WORD:
Packit Service db8eaa
	case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
Packit Service db8eaa
		break;
Packit Service db8eaa
	default:
Packit Service db8eaa
		tplg_log(tplg, 'A', pos, "tuple set verify: unknown array type %d", va->type);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	j = tplg_get_tuple_size(va->type) * va->num_elems;
Packit Service db8eaa
	if (j + sizeof(*va) != va->size) {
Packit Service db8eaa
		tplg_log(tplg, 'A', pos, "tuple set verify: wrong vendor array size %d "
Packit Service db8eaa
			 "(expected %d for %d count %d)",
Packit Service db8eaa
			 va->size, j + sizeof(*va), va->type, va->num_elems);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (va->num_elems > 4096) {
Packit Service db8eaa
		tplg_log(tplg, 'A', pos, "tuple set verify: tuples overflow %d", va->num_elems);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int tplg_decode_tuple_set(snd_tplg_t *tplg,
Packit Service db8eaa
				 size_t pos,
Packit Service db8eaa
				 struct tplg_elem *parent,
Packit Service db8eaa
				 struct tplg_tuple_set **_set,
Packit Service db8eaa
				 const void *bin, size_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	const struct snd_soc_tplg_vendor_array *va;
Packit Service db8eaa
	struct tplg_tuple_set *set;
Packit Service db8eaa
	struct tplg_tuple *tuple;
Packit Service db8eaa
	unsigned int j;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	va = bin;
Packit Service db8eaa
	if (size < sizeof(*va) || size < va->size) {
Packit Service db8eaa
		SNDERR("tuples: wrong size %zd", size);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	switch (va->type) {
Packit Service db8eaa
	case SND_SOC_TPLG_TUPLE_TYPE_UUID:
Packit Service db8eaa
	case SND_SOC_TPLG_TUPLE_TYPE_STRING:
Packit Service db8eaa
	case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
Packit Service db8eaa
	case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
Packit Service db8eaa
	case SND_SOC_TPLG_TUPLE_TYPE_WORD:
Packit Service db8eaa
	case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
Packit Service db8eaa
		break;
Packit Service db8eaa
	default:
Packit Service db8eaa
		SNDERR("tuples: unknown array type %d", va->type);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	j = tplg_get_tuple_size(va->type) * va->num_elems;
Packit Service db8eaa
	if (j + sizeof(*va) != va->size) {
Packit Service db8eaa
		SNDERR("tuples: wrong vendor array size %d "
Packit Service db8eaa
		       "(expected %d for %d count %d)",
Packit Service db8eaa
		       va->size, j + sizeof(*va), va->type, va->num_elems);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (va->num_elems > 4096) {
Packit Service db8eaa
		SNDERR("tuples: tuples overflow %d", va->num_elems);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	set = calloc(1, sizeof(*set) + va->num_elems * sizeof(struct tplg_tuple));
Packit Service db8eaa
	if (!set)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
	set->type = va->type;
Packit Service db8eaa
	set->num_tuples = va->num_elems;
Packit Service db8eaa
Packit Service db8eaa
	tplg_log(tplg, 'A', pos, "tuple set: type %d (%s) tuples %d size %d", set->type,
Packit Service db8eaa
		 get_tuple_type_name(set->type), set->num_tuples, va->size);
Packit Service db8eaa
	for (j = 0; j < set->num_tuples; j++) {
Packit Service db8eaa
		tuple = &set->tuple[j];
Packit Service db8eaa
		switch (va->type) {
Packit Service db8eaa
		case SND_SOC_TPLG_TUPLE_TYPE_UUID:
Packit Service db8eaa
			err = tplg_add_token(tplg, parent, va->uuid[j].token,
Packit Service db8eaa
					     tuple->token);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				goto retval;
Packit Service db8eaa
			memcpy(tuple->uuid, va->uuid[j].uuid,
Packit Service db8eaa
			       sizeof(va->uuid[j].uuid));
Packit Service db8eaa
			break;
Packit Service db8eaa
		case SND_SOC_TPLG_TUPLE_TYPE_STRING:
Packit Service db8eaa
			err = tplg_add_token(tplg, parent, va->string[j].token,
Packit Service db8eaa
					     tuple->token);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				goto retval;
Packit Service db8eaa
			snd_strlcpy(tuple->string, va->string[j].string,
Packit Service db8eaa
				    sizeof(tuple->string));
Packit Service db8eaa
			break;
Packit Service db8eaa
		case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
Packit Service db8eaa
		case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
Packit Service db8eaa
		case SND_SOC_TPLG_TUPLE_TYPE_WORD:
Packit Service db8eaa
		case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
Packit Service db8eaa
			err = tplg_add_token(tplg, parent, va->value[j].token,
Packit Service db8eaa
					     tuple->token);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				goto retval;
Packit Service db8eaa
			tuple->value = va->value[j].value;
Packit Service db8eaa
			break;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	*_set = set;
Packit Service db8eaa
	return 0;
Packit Service db8eaa
Packit Service db8eaa
retval:
Packit Service db8eaa
	free(set);
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* verify tuples from the binary input */
Packit Service db8eaa
static int tplg_verify_tuples(snd_tplg_t *tplg, size_t pos,
Packit Service db8eaa
			      const void *bin, size_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	const struct snd_soc_tplg_vendor_array *va;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	if (size < sizeof(*va)) {
Packit Service db8eaa
		tplg_log(tplg, 'A', pos, "tuples: small size %zd", size);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
next:
Packit Service db8eaa
	va = bin;
Packit Service db8eaa
	if (size < sizeof(*va)) {
Packit Service db8eaa
		tplg_log(tplg, 'A', pos, "tuples: unexpected vendor arry size %zd", size);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	err = tplg_verify_tuple_set(tplg, pos, va, va->size);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
Packit Service db8eaa
	bin += va->size;
Packit Service db8eaa
	size -= va->size;
Packit Service db8eaa
	pos += va->size;
Packit Service db8eaa
	if (size > 0)
Packit Service db8eaa
		goto next;
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* add tuples from the binary input */
Packit Service db8eaa
static int tplg_decode_tuples(snd_tplg_t *tplg,
Packit Service db8eaa
			      size_t pos,
Packit Service db8eaa
			      struct tplg_elem *parent,
Packit Service db8eaa
			      struct tplg_vendor_tuples *tuples,
Packit Service db8eaa
			      const void *bin, size_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	const struct snd_soc_tplg_vendor_array *va;
Packit Service db8eaa
	struct tplg_tuple_set *set;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	if (size < sizeof(*va)) {
Packit Service db8eaa
		SNDERR("tuples: small size %zd", size);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
next:
Packit Service db8eaa
	va = bin;
Packit Service db8eaa
	if (size < sizeof(*va)) {
Packit Service db8eaa
		SNDERR("tuples: unexpected vendor arry size %zd", size);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (tuples->num_sets >= tuples->alloc_sets) {
Packit Service db8eaa
		SNDERR("tuples: index overflow (%d)", tuples->num_sets);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	err = tplg_decode_tuple_set(tplg, pos, parent, &set, va, va->size);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
	tuples->set[tuples->num_sets++] = set;
Packit Service db8eaa
Packit Service db8eaa
	bin += va->size;
Packit Service db8eaa
	size -= va->size;
Packit Service db8eaa
	pos += va->size;
Packit Service db8eaa
	if (size > 0)
Packit Service db8eaa
		goto next;
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* decode private data */
Packit Service db8eaa
int tplg_add_data(snd_tplg_t *tplg,
Packit Service db8eaa
		  struct tplg_elem *parent,
Packit Service db8eaa
		  const void *bin, size_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	const struct snd_soc_tplg_private *tp;
Packit Service db8eaa
	const struct snd_soc_tplg_vendor_array *va;
Packit Service db8eaa
	struct tplg_elem *elem = NULL, *elem2 = NULL;
Packit Service db8eaa
	struct tplg_vendor_tuples *tuples = NULL;
Packit Service db8eaa
	char id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
Packit Service db8eaa
	char suffix[16];
Packit Service db8eaa
	size_t pos = 0, off;
Packit Service db8eaa
	int err, num_tuples = 0, block = 0;
Packit Service db8eaa
Packit Service db8eaa
	if (size == 0)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
Packit Service db8eaa
	off = offsetof(struct snd_soc_tplg_private, array);
Packit Service db8eaa
Packit Service db8eaa
next:
Packit Service db8eaa
	tp = bin;
Packit Service db8eaa
	if (off + size < tp->size) {
Packit Service db8eaa
		SNDERR("data: unexpected element size %zd", size);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (tplg_verify_tuples(tplg, pos, tp->array, tp->size) < 0) {
Packit Service db8eaa
		if (tuples) {
Packit Service db8eaa
			err = tplg_ref_add(elem, SND_TPLG_TYPE_TOKEN, parent->id);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return err;
Packit Service db8eaa
			err = tplg_ref_add(elem2, SND_TPLG_TYPE_TUPLE, id);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return err;
Packit Service db8eaa
			err = tplg_ref_add(parent, SND_TPLG_TYPE_DATA, id);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return err;
Packit Service db8eaa
			tuples = NULL;
Packit Service db8eaa
		}
Packit Service db8eaa
		tplg_log(tplg, 'A', pos, "add bytes: size %d", tp->size);
Packit Service db8eaa
		snprintf(suffix, sizeof(suffix), "data%u", block++);
Packit Service db8eaa
		err = tplg_add_data_bytes(tplg, parent, suffix, tp->array, tp->size);
Packit Service db8eaa
	} else {
Packit Service db8eaa
		if (!tuples) {
Packit Service db8eaa
			snprintf(id, sizeof(id), "%.30s:tuple%d", parent->id, (block++) & 0xffff);
Packit Service db8eaa
			elem = tplg_elem_new_common(tplg, NULL, id, SND_TPLG_TYPE_TUPLE);
Packit Service db8eaa
			if (!elem)
Packit Service db8eaa
				return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
			elem2 = tplg_elem_new_common(tplg, NULL, id, SND_TPLG_TYPE_DATA);
Packit Service db8eaa
			if (!elem2)
Packit Service db8eaa
				return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
			tuples = calloc(1, sizeof(*tuples));
Packit Service db8eaa
			if (!tuples)
Packit Service db8eaa
				return -ENOMEM;
Packit Service db8eaa
			elem->tuples = tuples;
Packit Service db8eaa
Packit Service db8eaa
			tuples->alloc_sets = (size / sizeof(*va)) + 1;
Packit Service db8eaa
			tuples->set = calloc(1, tuples->alloc_sets * sizeof(void *));
Packit Service db8eaa
			if (!tuples->set) {
Packit Service db8eaa
				tuples->alloc_sets = 0;
Packit Service db8eaa
				return -ENOMEM;
Packit Service db8eaa
			}
Packit Service db8eaa
		}
Packit Service db8eaa
		tplg_log(tplg, 'A', pos, "decode tuples: size %d", tp->size);
Packit Service db8eaa
		err = tplg_decode_tuples(tplg, pos, parent, tuples, tp->array, tp->size);
Packit Service db8eaa
		num_tuples++;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
Packit Service db8eaa
	bin += off + tp->size;
Packit Service db8eaa
	size -= off + tp->size;
Packit Service db8eaa
	pos += off + tp->size;
Packit Service db8eaa
	if (size > 0)
Packit Service db8eaa
		goto next;
Packit Service db8eaa
Packit Service db8eaa
	if (tuples && elem && elem2) {
Packit Service db8eaa
		err = tplg_ref_add(elem, SND_TPLG_TYPE_TOKEN, parent->id);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		err = tplg_ref_add(elem2, SND_TPLG_TYPE_TUPLE, id);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		err = tplg_ref_add(parent, SND_TPLG_TYPE_DATA, id);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* add private data - bytes */
Packit Service db8eaa
int tplg_add_data_bytes(snd_tplg_t *tplg, struct tplg_elem *parent,
Packit Service db8eaa
			const char *suffix, const void *bin, size_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	struct snd_soc_tplg_private *priv;
Packit Service db8eaa
	struct tplg_elem *elem;
Packit Service db8eaa
	char id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
Packit Service db8eaa
Packit Service db8eaa
	if (suffix)
Packit Service db8eaa
		snprintf(id, sizeof(id), "%.30s:%.12s", parent->id, suffix);
Packit Service db8eaa
	else
Packit Service db8eaa
		snd_strlcpy(id, parent->id, sizeof(id));
Packit Service db8eaa
	elem = tplg_elem_new_common(tplg, NULL, id, SND_TPLG_TYPE_DATA);
Packit Service db8eaa
	if (!elem)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
	priv = malloc(sizeof(*priv) + size);
Packit Service db8eaa
	if (!priv)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
	memcpy(priv->data, bin, size);
Packit Service db8eaa
	priv->size = size;
Packit Service db8eaa
	elem->data = priv;
Packit Service db8eaa
Packit Service db8eaa
	return tplg_ref_add(parent, SND_TPLG_TYPE_DATA, id);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* decode data from the binary input */
Packit Service db8eaa
int tplg_decode_data(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
Packit Service db8eaa
		     size_t pos ATTRIBUTE_UNUSED,
Packit Service db8eaa
		     struct snd_soc_tplg_hdr *hdr ATTRIBUTE_UNUSED,
Packit Service db8eaa
		     void *bin ATTRIBUTE_UNUSED,
Packit Service db8eaa
		     size_t size ATTRIBUTE_UNUSED)
Packit Service db8eaa
{
Packit Service db8eaa
	SNDERR("data type not expected");
Packit Service db8eaa
	return -EINVAL;
Packit Service db8eaa
}