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