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 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 4a16fb
		SNDERR("error: '%s': no support for private data for type %d\n",
Packit 4a16fb
			elem->id, elem->type);
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return priv;
Packit 4a16fb
}
Packit 4a16fb
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 4a16fb
	char filename[MAX_FILE];
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 4a16fb
	tplg_dbg("data DataFile: %s\n", 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 4a16fb
		SNDERR("error: invalid data file path '%s'\n",
Packit 4a16fb
			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 4a16fb
		SNDERR("error: invalid data file size %zu\n", size);
Packit 4a16fb
		ret = -EINVAL;
Packit 4a16fb
		goto err;
Packit 4a16fb
	}
Packit 4a16fb
	if (size > TPLG_MAX_PRIV_SIZE) {
Packit 4a16fb
		SNDERR("error: data file too big %zu\n", 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 4a16fb
static void dump_priv_data(struct tplg_elem *elem)
Packit 4a16fb
{
Packit 4a16fb
	struct snd_soc_tplg_private *priv = elem->data;
Packit 4a16fb
	unsigned int i, j = 0;
Packit 4a16fb
Packit 4a16fb
	tplg_dbg(" elem size = %d, priv data size = %d\n",
Packit 4a16fb
		elem->size, priv->size);
Packit 4a16fb
Packit 4a16fb
	for (i = 0; i < priv->size; i++) {
Packit 4a16fb
		if (j++ % 8 == 0)
Packit 4a16fb
			tplg_dbg("\n");
Packit 4a16fb
Packit 4a16fb
		tplg_dbg(" 0x%x", *p++);
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	tplg_dbg("\n\n");
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 4a16fb
	int commas = 0, values = 0, len = strlen(str);
Packit 4a16fb
	const char *end = str + len;
Packit 4a16fb
Packit 4a16fb
	/* we expect "0x0, 0x0, 0x0" */
Packit 4a16fb
	while (str < end) {
Packit 4a16fb
Packit 4a16fb
		/* skip white space */
Packit 4a16fb
		if (isspace(*str)) {
Packit 4a16fb
			str++;
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		/* find delimeters */
Packit 4a16fb
		if (*str == ',') {
Packit 4a16fb
			commas++;
Packit 4a16fb
			str++;
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		/* find 0x[0-9] values */
Packit 4a16fb
		if (*str == '0' && str + 2 <= end) {
Packit 4a16fb
			if (str[1] == 'x' && str[2] >= '0' && str[2] <= 'f') {
Packit 4a16fb
				values++;
Packit 4a16fb
				str += 3;
Packit 4a16fb
			} else {
Packit 4a16fb
				str++;
Packit 4a16fb
			}
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		str++;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	/* there should always be one less comma than value */
Packit 4a16fb
	if (values -1 != commas)
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 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 4a16fb
			SNDERR("error: invalid value for uuid\n");
Packit 4a16fb
			ret = -EINVAL;
Packit 4a16fb
			goto out;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		 *(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 4a16fb
		SNDERR("error: less than 16 integers for uuid\n");
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 4a16fb
	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 4a16fb
		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 4a16fb
	tplg_dbg(" data: %s\n", 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 4a16fb
		SNDERR("error: malformed hex variable list %s\n", 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 4a16fb
		SNDERR("error: data too big %d\n", 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 4a16fb
	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 4a16fb
	SNDERR("error: cannot find token id '%s'\n", 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 4a16fb
static unsigned int 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 4a16fb
	struct tplg_vendor_tuples *tuples, 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 4a16fb
			+ 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 4a16fb
			SNDERR("error: data too big %d\n", 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 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 4a16fb
		tplg_dbg("tuples '%s' used by data '%s'\n", 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 4a16fb
			SNDERR("error: cannot find tuples %s\n", ref->id);
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		tokens = get_tokens(tplg, tuples);
Packit 4a16fb
		if (!tokens) {
Packit 4a16fb
			SNDERR("error: cannot find token for %s\n", 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 4a16fb
static int parse_tuple_set(snd_config_t *cfg,
Packit 4a16fb
	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 4a16fb
	unsigned int type, num_tuples = 0;
Packit 4a16fb
	struct tplg_tuple *tuple;
Packit 4a16fb
	unsigned long int tuple_val;
Packit 4a16fb
Packit 4a16fb
	snd_config_get_id(cfg, &id;;
Packit 4a16fb
Packit 4a16fb
	if (strncmp(id, "uuid", 4) == 0)
Packit 4a16fb
		type = SND_SOC_TPLG_TUPLE_TYPE_UUID;
Packit 4a16fb
	else if (strncmp(id, "string", 5) == 0)
Packit 4a16fb
		type = SND_SOC_TPLG_TUPLE_TYPE_STRING;
Packit 4a16fb
	else if (strncmp(id, "bool", 4) == 0)
Packit 4a16fb
		type = SND_SOC_TPLG_TUPLE_TYPE_BOOL;
Packit 4a16fb
	else if (strncmp(id, "byte", 4) == 0)
Packit 4a16fb
		type = SND_SOC_TPLG_TUPLE_TYPE_BYTE;
Packit 4a16fb
	else if (strncmp(id, "short", 5) == 0)
Packit 4a16fb
		type = SND_SOC_TPLG_TUPLE_TYPE_SHORT;
Packit 4a16fb
	else if (strncmp(id, "word", 4) == 0)
Packit 4a16fb
		type = SND_SOC_TPLG_TUPLE_TYPE_WORD;
Packit 4a16fb
	else {
Packit 4a16fb
		SNDERR("error: invalid tuple type '%s'\n", id);
Packit 4a16fb
		return -EINVAL;
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 4a16fb
	tplg_dbg("\t %d %s tuples:\n", 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
		/* get value */
Packit 4a16fb
		if (snd_config_get_string(n, &value) < 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 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 4a16fb
			snd_strlcpy(tuple->string, value,
Packit 4a16fb
				SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit 4a16fb
			tplg_dbg("\t\t%s = %s\n", tuple->token, tuple->string);
Packit 4a16fb
			break;
Packit 4a16fb
Packit 4a16fb
		case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
Packit 4a16fb
			if (strcmp(value, "true") == 0)
Packit 4a16fb
				tuple->value = 1;
Packit 4a16fb
			tplg_dbg("\t\t%s = %d\n", 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 4a16fb
			errno = 0;
Packit 4a16fb
			/* no support for negative value */
Packit 4a16fb
			tuple_val = strtoul(value, NULL, 0);
Packit 4a16fb
			if ((errno == ERANGE && tuple_val == ULONG_MAX)
Packit 4a16fb
				|| (errno != 0 && tuple_val == 0)) {
Packit 4a16fb
				SNDERR("error: tuple %s:strtoul fail\n", id);
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 4a16fb
				SNDERR("error: tuple %s: invalid value\n", id);
Packit 4a16fb
				goto err;
Packit 4a16fb
			}
Packit 4a16fb
Packit 4a16fb
			tuple->value = (unsigned int) tuple_val;
Packit 4a16fb
			tplg_dbg("\t\t%s = 0x%x\n", 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 4a16fb
static int parse_tuple_sets(snd_config_t *cfg,
Packit 4a16fb
	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 4a16fb
			SNDERR("error: 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 4a16fb
			SNDERR("error: compound type expected for %s, is %d",
Packit 4a16fb
			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 4a16fb
/* Parse tuples references for a data element, either a single tuples section
Packit 4a16fb
 * or a list of tuples sections.
Packit 4a16fb
 */
Packit 4a16fb
static int parse_tuples_refs(snd_config_t *cfg,
Packit 4a16fb
	struct tplg_elem *elem)
Packit 4a16fb
{
Packit 4a16fb
	snd_config_type_t  type;
Packit 4a16fb
	snd_config_iterator_t i, next;
Packit 4a16fb
	snd_config_t *n;
Packit 4a16fb
	const char *val = NULL;
Packit 4a16fb
Packit 4a16fb
	type = snd_config_get_type(cfg);
Packit 4a16fb
Packit 4a16fb
	/* refer to a single tuples section */
Packit 4a16fb
	if (type == SND_CONFIG_TYPE_STRING) {
Packit 4a16fb
		if (snd_config_get_string(cfg, &val) < 0)
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
		tplg_dbg("\ttuples: %s\n", val);
Packit 4a16fb
		return tplg_ref_add(elem, SND_TPLG_TYPE_TUPLE, val);
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	if (type != SND_CONFIG_TYPE_COMPOUND) {
Packit 4a16fb
		SNDERR("error: compound type expected for %s", elem->id);
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	/* refer to a list of data sections */
Packit 4a16fb
	snd_config_for_each(i, next, cfg) {
Packit 4a16fb
		const char *val;
Packit 4a16fb
Packit 4a16fb
		n = snd_config_iterator_entry(i);
Packit 4a16fb
		if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
			continue;
Packit 4a16fb
Packit 4a16fb
		tplg_dbg("\ttuples: %s\n", val);
Packit 4a16fb
		tplg_ref_add(elem, SND_TPLG_TYPE_TUPLE, val);
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/* Parse private data references for the element, either a single data section
Packit 4a16fb
 * or a list of data sections.
Packit 4a16fb
 */
Packit 4a16fb
int tplg_parse_data_refs(snd_config_t *cfg,
Packit 4a16fb
	struct tplg_elem *elem)
Packit 4a16fb
{
Packit 4a16fb
	snd_config_type_t  type;
Packit 4a16fb
	snd_config_iterator_t i, next;
Packit 4a16fb
	snd_config_t *n;
Packit 4a16fb
	const char *val = NULL;
Packit 4a16fb
Packit 4a16fb
	type = snd_config_get_type(cfg);
Packit 4a16fb
Packit 4a16fb
	/* refer to a single data section */
Packit 4a16fb
	if (type == SND_CONFIG_TYPE_STRING) {
Packit 4a16fb
		if (snd_config_get_string(cfg, &val) < 0)
Packit 4a16fb
			return -EINVAL;
Packit 4a16fb
Packit 4a16fb
		tplg_dbg("\tdata: %s\n", val);
Packit 4a16fb
		return tplg_ref_add(elem, SND_TPLG_TYPE_DATA, val);
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	if (type != SND_CONFIG_TYPE_COMPOUND) {
Packit 4a16fb
		SNDERR("error: compound type expected for %s", elem->id);
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	/* refer to a list of data sections */
Packit 4a16fb
	snd_config_for_each(i, next, cfg) {
Packit 4a16fb
		const char *val;
Packit 4a16fb
Packit 4a16fb
		n = snd_config_iterator_entry(i);
Packit 4a16fb
		if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
			continue;
Packit 4a16fb
Packit 4a16fb
		tplg_dbg("\tdata: %s\n", val);
Packit 4a16fb
		tplg_ref_add(elem, SND_TPLG_TYPE_DATA, val);
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
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 4a16fb
	void *private ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	snd_config_iterator_t i, next;
Packit 4a16fb
	snd_config_t *n;
Packit 4a16fb
	const char *id, *value;
Packit 4a16fb
	struct tplg_elem *elem;
Packit 4a16fb
	struct tplg_vendor_tokens *tokens;
Packit 4a16fb
	int num_tokens = 0;
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 4a16fb
	tplg_dbg(" Vendor tokens: %s, %d tokens\n", 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 4a16fb
		if (snd_config_get_string(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 4a16fb
		tokens->token[tokens->num_tokens].value = atoi(value);
Packit 4a16fb
		tplg_dbg("\t\t %s : %d\n", 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 4a16fb
/* Parse vendor tuples.
Packit 4a16fb
 */
Packit 4a16fb
int tplg_parse_tuples(snd_tplg_t *tplg, snd_config_t *cfg,
Packit 4a16fb
	void *private ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	snd_config_iterator_t i, next;
Packit 4a16fb
	snd_config_t *n;
Packit 4a16fb
	const char *id, *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 4a16fb
	tplg_dbg(" Vendor Tuples: %s\n", 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 4a16fb
			tplg_dbg("\t refer to vendor tokens: %s\n", 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 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 4a16fb
	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 4a16fb
		SNDERR("error: already has manifest data\n");
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 4a16fb
	tplg_dbg(" Manifest: %s\n", elem->id);
Packit 4a16fb
Packit 4a16fb
	snd_config_for_each(i, next, cfg) {
Packit 4a16fb
		n = snd_config_iterator_entry(i);
Packit 4a16fb
		if (snd_config_get_id(n, &id) < 0)
Packit 4a16fb
			continue;
Packit 4a16fb
Packit 4a16fb
		/* skip comments */
Packit 4a16fb
		if (strcmp(id, "comment") == 0)
Packit 4a16fb
			continue;
Packit 4a16fb
		if (id[0] == '#')
Packit 4a16fb
			continue;
Packit 4a16fb
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "data") == 0) {
Packit 4a16fb
			err = tplg_parse_data_refs(n, elem);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
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 4a16fb
	void *private ATTRIBUTE_UNUSED)
Packit 4a16fb
{
Packit 4a16fb
	snd_config_iterator_t i, next;
Packit 4a16fb
	snd_config_t *n;
Packit 4a16fb
	const char *id, *val = NULL;
Packit 4a16fb
	int err = 0;
Packit 4a16fb
	struct tplg_elem *elem;
Packit 4a16fb
Packit 4a16fb
	elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_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 4a16fb
				SNDERR("error: failed to parse data file\n");
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 4a16fb
				SNDERR("error: failed to parse data bytes\n");
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 4a16fb
				SNDERR("error: failed to parse data shorts\n");
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 4a16fb
				SNDERR("error: failed to parse data words\n");
Packit 4a16fb
				return err;
Packit 4a16fb
			}
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "tuples") == 0) {
Packit 4a16fb
			err = parse_tuples_refs(n, elem);
Packit 4a16fb
			if (err < 0)
Packit 4a16fb
				return err;
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
Packit 4a16fb
		if (strcmp(id, "type") == 0) {
Packit 4a16fb
			if (snd_config_get_string(n, &val) < 0)
Packit 4a16fb
				return -EINVAL;
Packit 4a16fb
Packit 4a16fb
			elem->vendor_type = atoi(val);
Packit 4a16fb
			tplg_dbg("\t%s: %d\n", id, elem->index);
Packit 4a16fb
			continue;
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	return err;
Packit 4a16fb
}
Packit 4a16fb
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 4a16fb
		SNDERR("error: cannot find data '%s' referenced by"
Packit 4a16fb
		" element '%s'\n", ref->id, elem->id);
Packit 4a16fb
		return -EINVAL;
Packit 4a16fb
	}
Packit 4a16fb
Packit 4a16fb
	tplg_dbg("Data '%s' used by '%s'\n", 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
}