Blame src/topology/elem.c

Packit Service db8eaa
/*
Packit Service db8eaa
  Copyright(c) 2014-2015 Intel Corporation
Packit Service db8eaa
  All rights reserved.
Packit Service db8eaa
Packit Service db8eaa
  This library is free software; you can redistribute it and/or modify
Packit Service db8eaa
  it under the terms of the GNU Lesser General Public License as
Packit Service db8eaa
  published by the Free Software Foundation; either version 2.1 of
Packit Service db8eaa
  the License, or (at your option) any later version.
Packit Service db8eaa
Packit Service db8eaa
  This program is distributed in the hope that it will be useful,
Packit Service db8eaa
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service db8eaa
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service db8eaa
  GNU Lesser General Public License for more details.
Packit Service db8eaa
Packit Service db8eaa
  Authors: Mengdong Lin <mengdong.lin@intel.com>
Packit Service db8eaa
           Yao Jin <yao.jin@intel.com>
Packit Service db8eaa
           Liam Girdwood <liam.r.girdwood@linux.intel.com>
Packit Service db8eaa
*/
Packit Service db8eaa
Packit Service db8eaa
#include "list.h"
Packit Service db8eaa
#include "tplg_local.h"
Packit Service db8eaa
Packit Service db8eaa
struct tplg_table tplg_table[] = {
Packit Service db8eaa
	{
Packit Service db8eaa
		.name  = "manifest",
Packit Service db8eaa
		.id    = "SectionManifest",
Packit Service db8eaa
		.loff  = offsetof(snd_tplg_t, manifest_list),
Packit Service db8eaa
		.type  = SND_TPLG_TYPE_MANIFEST,
Packit Service db8eaa
		.tsoc  = SND_SOC_TPLG_TYPE_MANIFEST,
Packit Service db8eaa
		.size  = sizeof(struct snd_soc_tplg_manifest),
Packit Service db8eaa
		.enew  = 1,
Packit Service db8eaa
		.parse = tplg_parse_manifest_data,
Packit Service db8eaa
		.save  = tplg_save_manifest_data,
Packit Service db8eaa
		.decod = tplg_decode_manifest_data,
Packit Service db8eaa
	},
Packit Service db8eaa
	{
Packit Service db8eaa
		.name  = "control mixer",
Packit Service db8eaa
		.id    = "SectionControlMixer",
Packit Service db8eaa
		.loff  = offsetof(snd_tplg_t, mixer_list),
Packit Service db8eaa
		.type  = SND_TPLG_TYPE_MIXER,
Packit Service db8eaa
		.tsoc  = SND_SOC_TPLG_TYPE_MIXER,
Packit Service db8eaa
		.size  = sizeof(struct snd_soc_tplg_mixer_control),
Packit Service db8eaa
		.build = 1,
Packit Service db8eaa
		.enew  = 1,
Packit Service db8eaa
		.parse = tplg_parse_control_mixer,
Packit Service db8eaa
		.save  = tplg_save_control_mixer,
Packit Service db8eaa
		.decod = tplg_decode_control_mixer,
Packit Service db8eaa
	},
Packit Service db8eaa
	{
Packit Service db8eaa
		.name  = "control enum",
Packit Service db8eaa
		.id    = "SectionControlEnum",
Packit Service db8eaa
		.loff  = offsetof(snd_tplg_t, enum_list),
Packit Service db8eaa
		.type  = SND_TPLG_TYPE_ENUM,
Packit Service db8eaa
		.tsoc  = SND_SOC_TPLG_TYPE_ENUM,
Packit Service db8eaa
		.size  = sizeof(struct snd_soc_tplg_enum_control),
Packit Service db8eaa
		.build = 1,
Packit Service db8eaa
		.enew  = 1,
Packit Service db8eaa
		.parse = tplg_parse_control_enum,
Packit Service db8eaa
		.save  = tplg_save_control_enum,
Packit Service db8eaa
		.decod = tplg_decode_control_enum,
Packit Service db8eaa
	},
Packit Service db8eaa
	{
Packit Service db8eaa
		.name  = "control extended (bytes)",
Packit Service db8eaa
		.id    = "SectionControlBytes",
Packit Service db8eaa
		.loff  = offsetof(snd_tplg_t, bytes_ext_list),
Packit Service db8eaa
		.type  = SND_TPLG_TYPE_BYTES,
Packit Service db8eaa
		.tsoc  = SND_SOC_TPLG_TYPE_BYTES,
Packit Service db8eaa
		.size  = sizeof(struct snd_soc_tplg_bytes_control),
Packit Service db8eaa
		.build = 1,
Packit Service db8eaa
		.enew  = 1,
Packit Service db8eaa
		.parse = tplg_parse_control_bytes,
Packit Service db8eaa
		.save  = tplg_save_control_bytes,
Packit Service db8eaa
		.decod = tplg_decode_control_bytes,
Packit Service db8eaa
	},
Packit Service db8eaa
	{
Packit Service db8eaa
		.name  = "dapm widget",
Packit Service db8eaa
		.id    = "SectionWidget",
Packit Service db8eaa
		.loff  = offsetof(snd_tplg_t, widget_list),
Packit Service db8eaa
		.type  = SND_TPLG_TYPE_DAPM_WIDGET,
Packit Service db8eaa
		.tsoc  = SND_SOC_TPLG_TYPE_DAPM_WIDGET,
Packit Service db8eaa
		.size  = sizeof(struct snd_soc_tplg_dapm_widget),
Packit Service db8eaa
		.build = 1,
Packit Service db8eaa
		.enew  = 1,
Packit Service db8eaa
		.parse = tplg_parse_dapm_widget,
Packit Service db8eaa
		.save  = tplg_save_dapm_widget,
Packit Service db8eaa
		.decod = tplg_decode_dapm_widget,
Packit Service db8eaa
	},
Packit Service db8eaa
	{
Packit Service db8eaa
		.name  = "pcm",
Packit Service db8eaa
		.id    = "SectionPCM",
Packit Service db8eaa
		.loff  = offsetof(snd_tplg_t, pcm_list),
Packit Service db8eaa
		.type  = SND_TPLG_TYPE_PCM,
Packit Service db8eaa
		.tsoc  = SND_SOC_TPLG_TYPE_PCM,
Packit Service db8eaa
		.size  = sizeof(struct snd_soc_tplg_pcm),
Packit Service db8eaa
		.build = 1,
Packit Service db8eaa
		.enew  = 1,
Packit Service db8eaa
		.parse = tplg_parse_pcm,
Packit Service db8eaa
		.save  = tplg_save_pcm,
Packit Service db8eaa
		.decod = tplg_decode_pcm,
Packit Service db8eaa
	},
Packit Service db8eaa
	{
Packit Service db8eaa
		.name  = "physical dai",
Packit Service db8eaa
		.id    = "SectionDAI",
Packit Service db8eaa
		.loff  = offsetof(snd_tplg_t, dai_list),
Packit Service db8eaa
		.type  = SND_TPLG_TYPE_DAI,
Packit Service db8eaa
		.tsoc  = SND_SOC_TPLG_TYPE_DAI,
Packit Service db8eaa
		.size  = sizeof(struct snd_soc_tplg_dai),
Packit Service db8eaa
		.build = 1,
Packit Service db8eaa
		.enew  = 1,
Packit Service db8eaa
		.parse = tplg_parse_dai,
Packit Service db8eaa
		.save  = tplg_save_dai,
Packit Service db8eaa
		.decod = tplg_decode_dai,
Packit Service db8eaa
	},
Packit Service db8eaa
	{
Packit Service db8eaa
		.name  = "be",
Packit Service db8eaa
		.id    = "SectionBE",
Packit Service db8eaa
		.id2   = "SectionLink",
Packit Service db8eaa
		.loff  = offsetof(snd_tplg_t, be_list),
Packit Service db8eaa
		.type  = SND_TPLG_TYPE_BE,
Packit Service db8eaa
		.tsoc  = SND_SOC_TPLG_TYPE_BACKEND_LINK,
Packit Service db8eaa
		.size  = sizeof(struct snd_soc_tplg_link_config),
Packit Service db8eaa
		.build = 1,
Packit Service db8eaa
		.enew  = 1,
Packit Service db8eaa
		.parse = tplg_parse_link,
Packit Service db8eaa
		.save  = tplg_save_link,
Packit Service db8eaa
		.decod = tplg_decode_link,
Packit Service db8eaa
	},
Packit Service db8eaa
	{
Packit Service db8eaa
		.name  = "cc",
Packit Service db8eaa
		.id    = "SectionCC",
Packit Service db8eaa
		.loff  = offsetof(snd_tplg_t, cc_list),
Packit Service db8eaa
		.type  = SND_TPLG_TYPE_CC,
Packit Service db8eaa
		.tsoc  = SND_SOC_TPLG_TYPE_CODEC_LINK,
Packit Service db8eaa
		.size  = sizeof(struct snd_soc_tplg_link_config),
Packit Service db8eaa
		.build = 1,
Packit Service db8eaa
		.enew  = 1,
Packit Service db8eaa
		.parse = tplg_parse_cc,
Packit Service db8eaa
		.save  = tplg_save_cc,
Packit Service db8eaa
		.decod = tplg_decode_cc,
Packit Service db8eaa
	},
Packit Service db8eaa
	{
Packit Service db8eaa
		.name  = "route (dapm graph)",
Packit Service db8eaa
		.id = "SectionGraph",
Packit Service db8eaa
		.loff  = offsetof(snd_tplg_t, route_list),
Packit Service db8eaa
		.type  = SND_TPLG_TYPE_DAPM_GRAPH,
Packit Service db8eaa
		.tsoc  = SND_SOC_TPLG_TYPE_DAPM_GRAPH,
Packit Service db8eaa
		.build = 1,
Packit Service db8eaa
		.parse = tplg_parse_dapm_graph,
Packit Service db8eaa
		.gsave = tplg_save_dapm_graph,
Packit Service db8eaa
		.decod = tplg_decode_dapm_graph,
Packit Service db8eaa
	},
Packit Service db8eaa
	{
Packit Service db8eaa
		.name  = "private data",
Packit Service db8eaa
		.id    = "SectionData",
Packit Service db8eaa
		.loff  = offsetof(snd_tplg_t, pdata_list),
Packit Service db8eaa
		.type  = SND_TPLG_TYPE_DATA,
Packit Service db8eaa
		.tsoc  = SND_SOC_TPLG_TYPE_PDATA,
Packit Service db8eaa
		.build = 1,
Packit Service db8eaa
		.enew  = 1,
Packit Service db8eaa
		.parse = tplg_parse_data,
Packit Service db8eaa
		.save  = tplg_save_data,
Packit Service db8eaa
		.decod = tplg_decode_data,
Packit Service db8eaa
	},
Packit Service db8eaa
	{
Packit Service db8eaa
		.name  = "text",
Packit Service db8eaa
		.id    = "SectionText",
Packit Service db8eaa
		.loff  = offsetof(snd_tplg_t, text_list),
Packit Service db8eaa
		.type  = SND_TPLG_TYPE_TEXT,
Packit Service db8eaa
		.size  = sizeof(struct tplg_texts),
Packit Service db8eaa
		.enew  = 1,
Packit Service db8eaa
		.parse = tplg_parse_text,
Packit Service db8eaa
		.save  = tplg_save_text,
Packit Service db8eaa
	},
Packit Service db8eaa
	{
Packit Service db8eaa
		.name  = "tlv",
Packit Service db8eaa
		.id    = "SectionTLV",
Packit Service db8eaa
		.loff  = offsetof(snd_tplg_t, tlv_list),
Packit Service db8eaa
		.type  = SND_TPLG_TYPE_TLV,
Packit Service db8eaa
		.size  = sizeof(struct snd_soc_tplg_ctl_tlv),
Packit Service db8eaa
		.enew  = 1,
Packit Service db8eaa
		.parse = tplg_parse_tlv,
Packit Service db8eaa
		.save  = tplg_save_tlv,
Packit Service db8eaa
	},
Packit Service db8eaa
	{
Packit Service db8eaa
		.name  = "stream config",
Packit Service db8eaa
		.loff  = offsetof(snd_tplg_t, pcm_config_list),
Packit Service db8eaa
		.type  = SND_TPLG_TYPE_STREAM_CONFIG,
Packit Service db8eaa
		.size  = sizeof(struct snd_soc_tplg_stream),
Packit Service db8eaa
		.enew  = 1,
Packit Service db8eaa
	},
Packit Service db8eaa
	{
Packit Service db8eaa
		.name  = "stream capabilities",
Packit Service db8eaa
		.id    = "SectionPCMCapabilities",
Packit Service db8eaa
		.loff  = offsetof(snd_tplg_t, pcm_caps_list),
Packit Service db8eaa
		.type  = SND_TPLG_TYPE_STREAM_CAPS,
Packit Service db8eaa
		.size  = sizeof(struct snd_soc_tplg_stream_caps),
Packit Service db8eaa
		.enew  = 1,
Packit Service db8eaa
		.parse = tplg_parse_stream_caps,
Packit Service db8eaa
		.save  = tplg_save_stream_caps,
Packit Service db8eaa
	},
Packit Service db8eaa
	{
Packit Service db8eaa
		.name  = "token",
Packit Service db8eaa
		.id    = "SectionVendorTokens",
Packit Service db8eaa
		.loff  = offsetof(snd_tplg_t, token_list),
Packit Service db8eaa
		.type  = SND_TPLG_TYPE_TOKEN,
Packit Service db8eaa
		.enew  = 1,
Packit Service db8eaa
		.parse = tplg_parse_tokens,
Packit Service db8eaa
		.save  = tplg_save_tokens,
Packit Service db8eaa
	},
Packit Service db8eaa
	{
Packit Service db8eaa
		.name  = "tuple",
Packit Service db8eaa
		.id    = "SectionVendorTuples",
Packit Service db8eaa
		.loff  = offsetof(snd_tplg_t, tuple_list),
Packit Service db8eaa
		.type  = SND_TPLG_TYPE_TUPLE,
Packit Service db8eaa
		.free  = tplg_free_tuples,
Packit Service db8eaa
		.enew  = 1,
Packit Service db8eaa
		.parse = tplg_parse_tuples,
Packit Service db8eaa
		.save  = tplg_save_tuples,
Packit Service db8eaa
	},
Packit Service db8eaa
	{
Packit Service db8eaa
		.name  = "hw config",
Packit Service db8eaa
		.id    = "SectionHWConfig",
Packit Service db8eaa
		.loff  = offsetof(snd_tplg_t, hw_cfg_list),
Packit Service db8eaa
		.type  = SND_TPLG_TYPE_HW_CONFIG,
Packit Service db8eaa
		.size  = sizeof(struct snd_soc_tplg_hw_config),
Packit Service db8eaa
		.enew  = 1,
Packit Service db8eaa
		.parse = tplg_parse_hw_config,
Packit Service db8eaa
		.save  = tplg_save_hw_config,
Packit Service db8eaa
	}
Packit Service db8eaa
};
Packit Service db8eaa
Packit Service db8eaa
unsigned int tplg_table_items = ARRAY_SIZE(tplg_table);
Packit Service db8eaa
Packit Service db8eaa
int tplg_get_type(int asoc_type)
Packit Service db8eaa
{
Packit Service db8eaa
	unsigned int index;
Packit Service db8eaa
Packit Service db8eaa
	for (index = 0; index < tplg_table_items; index++)
Packit Service db8eaa
		if (tplg_table[index].tsoc == asoc_type)
Packit Service db8eaa
			return tplg_table[index].type;
Packit Service db8eaa
	SNDERR("uknown asoc type %d", asoc_type);
Packit Service db8eaa
	return -EINVAL;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
int tplg_ref_add(struct tplg_elem *elem, int type, const char* id)
Packit Service db8eaa
{
Packit Service db8eaa
	struct tplg_ref *ref;
Packit Service db8eaa
Packit Service db8eaa
	ref = calloc(1, sizeof(*ref));
Packit Service db8eaa
	if (!ref)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
	strncpy(ref->id, id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit Service db8eaa
	ref->id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN - 1] = 0;
Packit Service db8eaa
	ref->type = type;
Packit Service db8eaa
Packit Service db8eaa
	list_add_tail(&ref->list, &elem->ref_list);
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* directly add a reference elem */
Packit Service db8eaa
int tplg_ref_add_elem(struct tplg_elem *elem, struct tplg_elem *elem_ref)
Packit Service db8eaa
{
Packit Service db8eaa
	struct tplg_ref *ref;
Packit Service db8eaa
Packit Service db8eaa
	ref = calloc(1, sizeof(*ref));
Packit Service db8eaa
	if (!ref)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
Packit Service db8eaa
	ref->type = elem_ref->type;
Packit Service db8eaa
	ref->elem = elem_ref;
Packit Service db8eaa
	snd_strlcpy(ref->id, elem_ref->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit Service db8eaa
Packit Service db8eaa
	list_add_tail(&ref->list, &elem->ref_list);
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
void tplg_ref_free_list(struct list_head *base)
Packit Service db8eaa
{
Packit Service db8eaa
	struct list_head *pos, *npos;
Packit Service db8eaa
	struct tplg_ref *ref;
Packit Service db8eaa
Packit Service db8eaa
	list_for_each_safe(pos, npos, base) {
Packit Service db8eaa
		ref = list_entry(pos, struct tplg_ref, list);
Packit Service db8eaa
		list_del(&ref->list);
Packit Service db8eaa
		free(ref);
Packit Service db8eaa
	}
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
struct tplg_elem *tplg_elem_new(void)
Packit Service db8eaa
{
Packit Service db8eaa
	struct tplg_elem *elem;
Packit Service db8eaa
Packit Service db8eaa
	elem = calloc(1, sizeof(*elem));
Packit Service db8eaa
	if (!elem)
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
Packit Service db8eaa
	INIT_LIST_HEAD(&elem->ref_list);
Packit Service db8eaa
	return elem;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
void tplg_elem_free(struct tplg_elem *elem)
Packit Service db8eaa
{
Packit Service db8eaa
	list_del(&elem->list);
Packit Service db8eaa
Packit Service db8eaa
	tplg_ref_free_list(&elem->ref_list);
Packit Service db8eaa
Packit Service db8eaa
	/* free struct snd_tplg_ object,
Packit Service db8eaa
	 * the union pointers share the same address
Packit Service db8eaa
	 */
Packit Service db8eaa
	if (elem->obj) {
Packit Service db8eaa
		if (elem->free)
Packit Service db8eaa
			elem->free(elem->obj);
Packit Service db8eaa
Packit Service db8eaa
		free(elem->obj);
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	free(elem);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
void tplg_elem_free_list(struct list_head *base)
Packit Service db8eaa
{
Packit Service db8eaa
	struct list_head *pos, *npos;
Packit Service db8eaa
	struct tplg_elem *elem;
Packit Service db8eaa
Packit Service db8eaa
	list_for_each_safe(pos, npos, base) {
Packit Service db8eaa
		elem = list_entry(pos, struct tplg_elem, list);
Packit Service db8eaa
		tplg_elem_free(elem);
Packit Service db8eaa
	}
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
struct tplg_elem *tplg_elem_lookup(struct list_head *base, const char* id,
Packit Service db8eaa
				   unsigned int type, int index)
Packit Service db8eaa
{
Packit Service db8eaa
	struct list_head *pos;
Packit Service db8eaa
	struct tplg_elem *elem;
Packit Service db8eaa
Packit Service db8eaa
	if (!base || !id)
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
Packit Service db8eaa
	list_for_each(pos, base) {
Packit Service db8eaa
Packit Service db8eaa
		elem = list_entry(pos, struct tplg_elem, list);
Packit Service db8eaa
Packit Service db8eaa
		if (!strcmp(elem->id, id) && elem->type == type)
Packit Service db8eaa
			return elem;
Packit Service db8eaa
		/* SND_TPLG_INDEX_ALL is the default value "0" and applicable
Packit Service db8eaa
		   for all use cases */
Packit Service db8eaa
		if ((index != SND_TPLG_INDEX_ALL)
Packit Service db8eaa
			&& (elem->index > index))
Packit Service db8eaa
			break;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return NULL;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* find an element by type */
Packit Service db8eaa
struct tplg_elem *tplg_elem_type_lookup(snd_tplg_t *tplg,
Packit Service db8eaa
					enum snd_tplg_type type)
Packit Service db8eaa
{
Packit Service db8eaa
	struct tplg_table *tptr;
Packit Service db8eaa
	struct list_head *pos, *list;
Packit Service db8eaa
	struct tplg_elem *elem;
Packit Service db8eaa
	unsigned int index;
Packit Service db8eaa
Packit Service db8eaa
	for (index = 0; index < tplg_table_items; index++) {
Packit Service db8eaa
		tptr = &tplg_table[index];
Packit Service db8eaa
		if (!tptr->enew)
Packit Service db8eaa
			continue;
Packit Service db8eaa
		if ((int)type != tptr->type)
Packit Service db8eaa
			continue;
Packit Service db8eaa
		break;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (index >= tplg_table_items)
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
Packit Service db8eaa
	list = (struct list_head *)((void *)tplg + tptr->loff);
Packit Service db8eaa
Packit Service db8eaa
	/* return only first element */
Packit Service db8eaa
	list_for_each(pos, list) {
Packit Service db8eaa
		elem = list_entry(pos, struct tplg_elem, list);
Packit Service db8eaa
		return elem;
Packit Service db8eaa
	}
Packit Service db8eaa
	return NULL;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* insert a new element into list in the ascending order of index value */
Packit Service db8eaa
void tplg_elem_insert(struct tplg_elem *elem_p, struct list_head *list)
Packit Service db8eaa
{
Packit Service db8eaa
	struct list_head *pos, *p = &(elem_p->list);
Packit Service db8eaa
	struct tplg_elem *elem;
Packit Service db8eaa
Packit Service db8eaa
	list_for_each(pos, list) {
Packit Service db8eaa
		elem = list_entry(pos, struct tplg_elem, list);
Packit Service db8eaa
		if (elem_p->index < elem->index)
Packit Service db8eaa
			break;
Packit Service db8eaa
	}
Packit Service db8eaa
	/* insert item before pos */
Packit Service db8eaa
	list_insert(p, pos->prev, pos);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* create a new common element and object */
Packit Service db8eaa
struct tplg_elem* tplg_elem_new_common(snd_tplg_t *tplg,
Packit Service db8eaa
				       snd_config_t *cfg,
Packit Service db8eaa
				       const char *name,
Packit Service db8eaa
				       enum snd_tplg_type type)
Packit Service db8eaa
{
Packit Service db8eaa
	struct tplg_table *tptr;
Packit Service db8eaa
	struct tplg_elem *elem;
Packit Service db8eaa
	struct list_head *list;
Packit Service db8eaa
	const char *id;
Packit Service db8eaa
	int obj_size = 0;
Packit Service db8eaa
	unsigned index;
Packit Service db8eaa
	void *obj;
Packit Service db8eaa
	snd_config_iterator_t i, next;
Packit Service db8eaa
	snd_config_t *n;
Packit Service db8eaa
Packit Service db8eaa
	if (!cfg && !name)
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
Packit Service db8eaa
	elem = tplg_elem_new();
Packit Service db8eaa
	if (!elem)
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
Packit Service db8eaa
	/* do we get name from cfg */
Packit Service db8eaa
	if (cfg) {
Packit Service db8eaa
		snd_config_get_id(cfg, &id;;
Packit Service db8eaa
		snd_strlcpy(elem->id, id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit Service db8eaa
		elem->id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN - 1] = 0;
Packit Service db8eaa
		/* as we insert new elem based on the index value, move index
Packit Service db8eaa
		   parsing here */
Packit Service db8eaa
		snd_config_for_each(i, next, cfg) {
Packit Service db8eaa
			n = snd_config_iterator_entry(i);
Packit Service db8eaa
			if (snd_config_get_id(n, &id))
Packit Service db8eaa
				continue;
Packit Service db8eaa
			if (strcmp(id, "index") == 0) {
Packit Service db8eaa
				if (tplg_get_integer(n, &elem->index, 0)) {
Packit Service db8eaa
					free(elem);
Packit Service db8eaa
					return NULL;
Packit Service db8eaa
				}
Packit Service db8eaa
				if (elem->index < 0) {
Packit Service db8eaa
					free(elem);
Packit Service db8eaa
					return NULL;
Packit Service db8eaa
				}
Packit Service db8eaa
			}
Packit Service db8eaa
		}
Packit Service db8eaa
	} else if (name != NULL)
Packit Service db8eaa
		snd_strlcpy(elem->id, name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
Packit Service db8eaa
Packit Service db8eaa
	for (index = 0; index < tplg_table_items; index++) {
Packit Service db8eaa
		tptr = &tplg_table[index];
Packit Service db8eaa
		if (!tptr->enew)
Packit Service db8eaa
			continue;
Packit Service db8eaa
		if ((int)type != tptr->type)
Packit Service db8eaa
			continue;
Packit Service db8eaa
		break;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (index >= tplg_table_items) {
Packit Service db8eaa
		free(elem);
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	list = (struct list_head *)((void *)tplg + tptr->loff);
Packit Service db8eaa
	tplg_elem_insert(elem, list);
Packit Service db8eaa
	obj_size = tptr->size;
Packit Service db8eaa
	elem->free = tptr->free;
Packit Service db8eaa
	elem->table = tptr;
Packit Service db8eaa
Packit Service db8eaa
	/* create new object too if required */
Packit Service db8eaa
	if (obj_size > 0) {
Packit Service db8eaa
		obj = calloc(1, obj_size);
Packit Service db8eaa
		if (obj == NULL) {
Packit Service db8eaa
			free(elem);
Packit Service db8eaa
			return NULL;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		elem->obj = obj;
Packit Service db8eaa
		elem->size = obj_size;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	elem->type = type;
Packit Service db8eaa
	return elem;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
struct tplg_alloc {
Packit Service db8eaa
	struct list_head list;
Packit Service db8eaa
	void *data[0];
Packit Service db8eaa
};
Packit Service db8eaa
Packit Service db8eaa
void *tplg_calloc(struct list_head *heap, size_t size)
Packit Service db8eaa
{
Packit Service db8eaa
	struct tplg_alloc *a;
Packit Service db8eaa
Packit Service db8eaa
	a = calloc(1, sizeof(*a) + size);
Packit Service db8eaa
	if (a == NULL)
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
	list_add_tail(&a->list, heap);
Packit Service db8eaa
	return a->data;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
void tplg_free(struct list_head *heap)
Packit Service db8eaa
{
Packit Service db8eaa
	struct list_head *pos, *npos;
Packit Service db8eaa
	struct tplg_alloc *a;
Packit Service db8eaa
Packit Service db8eaa
	list_for_each_safe(pos, npos, heap) {
Packit Service db8eaa
		a = list_entry(pos, struct tplg_alloc, list);
Packit Service db8eaa
		list_del(&a->list);
Packit Service db8eaa
		free(a);
Packit Service db8eaa
	}
Packit Service db8eaa
}