xref: /third_party/alsa-lib/src/topology/elem.c (revision d5ac70f0)
1d5ac70f0Sopenharmony_ci/*
2d5ac70f0Sopenharmony_ci  Copyright(c) 2014-2015 Intel Corporation
3d5ac70f0Sopenharmony_ci  All rights reserved.
4d5ac70f0Sopenharmony_ci
5d5ac70f0Sopenharmony_ci  This library is free software; you can redistribute it and/or modify
6d5ac70f0Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as
7d5ac70f0Sopenharmony_ci  published by the Free Software Foundation; either version 2.1 of
8d5ac70f0Sopenharmony_ci  the License, or (at your option) any later version.
9d5ac70f0Sopenharmony_ci
10d5ac70f0Sopenharmony_ci  This program is distributed in the hope that it will be useful,
11d5ac70f0Sopenharmony_ci  but WITHOUT ANY WARRANTY; without even the implied warranty of
12d5ac70f0Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13d5ac70f0Sopenharmony_ci  GNU Lesser General Public License for more details.
14d5ac70f0Sopenharmony_ci
15d5ac70f0Sopenharmony_ci  Authors: Mengdong Lin <mengdong.lin@intel.com>
16d5ac70f0Sopenharmony_ci           Yao Jin <yao.jin@intel.com>
17d5ac70f0Sopenharmony_ci           Liam Girdwood <liam.r.girdwood@linux.intel.com>
18d5ac70f0Sopenharmony_ci*/
19d5ac70f0Sopenharmony_ci
20d5ac70f0Sopenharmony_ci#include "tplg_local.h"
21d5ac70f0Sopenharmony_ci
22d5ac70f0Sopenharmony_cistruct tplg_table tplg_table[] = {
23d5ac70f0Sopenharmony_ci	{
24d5ac70f0Sopenharmony_ci		.name  = "manifest",
25d5ac70f0Sopenharmony_ci		.id    = "SectionManifest",
26d5ac70f0Sopenharmony_ci		.loff  = offsetof(snd_tplg_t, manifest_list),
27d5ac70f0Sopenharmony_ci		.type  = SND_TPLG_TYPE_MANIFEST,
28d5ac70f0Sopenharmony_ci		.tsoc  = SND_SOC_TPLG_TYPE_MANIFEST,
29d5ac70f0Sopenharmony_ci		.size  = sizeof(struct snd_soc_tplg_manifest),
30d5ac70f0Sopenharmony_ci		.enew  = 1,
31d5ac70f0Sopenharmony_ci		.parse = tplg_parse_manifest_data,
32d5ac70f0Sopenharmony_ci		.save  = tplg_save_manifest_data,
33d5ac70f0Sopenharmony_ci		.decod = tplg_decode_manifest_data,
34d5ac70f0Sopenharmony_ci	},
35d5ac70f0Sopenharmony_ci	{
36d5ac70f0Sopenharmony_ci		.name  = "control mixer",
37d5ac70f0Sopenharmony_ci		.id    = "SectionControlMixer",
38d5ac70f0Sopenharmony_ci		.loff  = offsetof(snd_tplg_t, mixer_list),
39d5ac70f0Sopenharmony_ci		.type  = SND_TPLG_TYPE_MIXER,
40d5ac70f0Sopenharmony_ci		.tsoc  = SND_SOC_TPLG_TYPE_MIXER,
41d5ac70f0Sopenharmony_ci		.size  = sizeof(struct snd_soc_tplg_mixer_control),
42d5ac70f0Sopenharmony_ci		.build = 1,
43d5ac70f0Sopenharmony_ci		.enew  = 1,
44d5ac70f0Sopenharmony_ci		.parse = tplg_parse_control_mixer,
45d5ac70f0Sopenharmony_ci		.save  = tplg_save_control_mixer,
46d5ac70f0Sopenharmony_ci		.decod = tplg_decode_control_mixer,
47d5ac70f0Sopenharmony_ci	},
48d5ac70f0Sopenharmony_ci	{
49d5ac70f0Sopenharmony_ci		.name  = "control enum",
50d5ac70f0Sopenharmony_ci		.id    = "SectionControlEnum",
51d5ac70f0Sopenharmony_ci		.loff  = offsetof(snd_tplg_t, enum_list),
52d5ac70f0Sopenharmony_ci		.type  = SND_TPLG_TYPE_ENUM,
53d5ac70f0Sopenharmony_ci		.tsoc  = SND_SOC_TPLG_TYPE_ENUM,
54d5ac70f0Sopenharmony_ci		.size  = sizeof(struct snd_soc_tplg_enum_control),
55d5ac70f0Sopenharmony_ci		.build = 1,
56d5ac70f0Sopenharmony_ci		.enew  = 1,
57d5ac70f0Sopenharmony_ci		.parse = tplg_parse_control_enum,
58d5ac70f0Sopenharmony_ci		.save  = tplg_save_control_enum,
59d5ac70f0Sopenharmony_ci		.decod = tplg_decode_control_enum,
60d5ac70f0Sopenharmony_ci	},
61d5ac70f0Sopenharmony_ci	{
62d5ac70f0Sopenharmony_ci		.name  = "control extended (bytes)",
63d5ac70f0Sopenharmony_ci		.id    = "SectionControlBytes",
64d5ac70f0Sopenharmony_ci		.loff  = offsetof(snd_tplg_t, bytes_ext_list),
65d5ac70f0Sopenharmony_ci		.type  = SND_TPLG_TYPE_BYTES,
66d5ac70f0Sopenharmony_ci		.tsoc  = SND_SOC_TPLG_TYPE_BYTES,
67d5ac70f0Sopenharmony_ci		.size  = sizeof(struct snd_soc_tplg_bytes_control),
68d5ac70f0Sopenharmony_ci		.build = 1,
69d5ac70f0Sopenharmony_ci		.enew  = 1,
70d5ac70f0Sopenharmony_ci		.parse = tplg_parse_control_bytes,
71d5ac70f0Sopenharmony_ci		.save  = tplg_save_control_bytes,
72d5ac70f0Sopenharmony_ci		.decod = tplg_decode_control_bytes,
73d5ac70f0Sopenharmony_ci	},
74d5ac70f0Sopenharmony_ci	{
75d5ac70f0Sopenharmony_ci		.name  = "dapm widget",
76d5ac70f0Sopenharmony_ci		.id    = "SectionWidget",
77d5ac70f0Sopenharmony_ci		.loff  = offsetof(snd_tplg_t, widget_list),
78d5ac70f0Sopenharmony_ci		.type  = SND_TPLG_TYPE_DAPM_WIDGET,
79d5ac70f0Sopenharmony_ci		.tsoc  = SND_SOC_TPLG_TYPE_DAPM_WIDGET,
80d5ac70f0Sopenharmony_ci		.size  = sizeof(struct snd_soc_tplg_dapm_widget),
81d5ac70f0Sopenharmony_ci		.build = 1,
82d5ac70f0Sopenharmony_ci		.enew  = 1,
83d5ac70f0Sopenharmony_ci		.parse = tplg_parse_dapm_widget,
84d5ac70f0Sopenharmony_ci		.save  = tplg_save_dapm_widget,
85d5ac70f0Sopenharmony_ci		.decod = tplg_decode_dapm_widget,
86d5ac70f0Sopenharmony_ci	},
87d5ac70f0Sopenharmony_ci	{
88d5ac70f0Sopenharmony_ci		.name  = "pcm",
89d5ac70f0Sopenharmony_ci		.id    = "SectionPCM",
90d5ac70f0Sopenharmony_ci		.loff  = offsetof(snd_tplg_t, pcm_list),
91d5ac70f0Sopenharmony_ci		.type  = SND_TPLG_TYPE_PCM,
92d5ac70f0Sopenharmony_ci		.tsoc  = SND_SOC_TPLG_TYPE_PCM,
93d5ac70f0Sopenharmony_ci		.size  = sizeof(struct snd_soc_tplg_pcm),
94d5ac70f0Sopenharmony_ci		.build = 1,
95d5ac70f0Sopenharmony_ci		.enew  = 1,
96d5ac70f0Sopenharmony_ci		.parse = tplg_parse_pcm,
97d5ac70f0Sopenharmony_ci		.save  = tplg_save_pcm,
98d5ac70f0Sopenharmony_ci		.decod = tplg_decode_pcm,
99d5ac70f0Sopenharmony_ci	},
100d5ac70f0Sopenharmony_ci	{
101d5ac70f0Sopenharmony_ci		.name  = "physical dai",
102d5ac70f0Sopenharmony_ci		.id    = "SectionDAI",
103d5ac70f0Sopenharmony_ci		.loff  = offsetof(snd_tplg_t, dai_list),
104d5ac70f0Sopenharmony_ci		.type  = SND_TPLG_TYPE_DAI,
105d5ac70f0Sopenharmony_ci		.tsoc  = SND_SOC_TPLG_TYPE_DAI,
106d5ac70f0Sopenharmony_ci		.size  = sizeof(struct snd_soc_tplg_dai),
107d5ac70f0Sopenharmony_ci		.build = 1,
108d5ac70f0Sopenharmony_ci		.enew  = 1,
109d5ac70f0Sopenharmony_ci		.parse = tplg_parse_dai,
110d5ac70f0Sopenharmony_ci		.save  = tplg_save_dai,
111d5ac70f0Sopenharmony_ci		.decod = tplg_decode_dai,
112d5ac70f0Sopenharmony_ci	},
113d5ac70f0Sopenharmony_ci	{
114d5ac70f0Sopenharmony_ci		.name  = "be",
115d5ac70f0Sopenharmony_ci		.id    = "SectionBE",
116d5ac70f0Sopenharmony_ci		.id2   = "SectionLink",
117d5ac70f0Sopenharmony_ci		.loff  = offsetof(snd_tplg_t, be_list),
118d5ac70f0Sopenharmony_ci		.type  = SND_TPLG_TYPE_BE,
119d5ac70f0Sopenharmony_ci		.tsoc  = SND_SOC_TPLG_TYPE_BACKEND_LINK,
120d5ac70f0Sopenharmony_ci		.size  = sizeof(struct snd_soc_tplg_link_config),
121d5ac70f0Sopenharmony_ci		.build = 1,
122d5ac70f0Sopenharmony_ci		.enew  = 1,
123d5ac70f0Sopenharmony_ci		.parse = tplg_parse_link,
124d5ac70f0Sopenharmony_ci		.save  = tplg_save_link,
125d5ac70f0Sopenharmony_ci		.decod = tplg_decode_link,
126d5ac70f0Sopenharmony_ci	},
127d5ac70f0Sopenharmony_ci	{
128d5ac70f0Sopenharmony_ci		.name  = "cc",
129d5ac70f0Sopenharmony_ci		.id    = "SectionCC",
130d5ac70f0Sopenharmony_ci		.loff  = offsetof(snd_tplg_t, cc_list),
131d5ac70f0Sopenharmony_ci		.type  = SND_TPLG_TYPE_CC,
132d5ac70f0Sopenharmony_ci		.tsoc  = SND_SOC_TPLG_TYPE_CODEC_LINK,
133d5ac70f0Sopenharmony_ci		.size  = sizeof(struct snd_soc_tplg_link_config),
134d5ac70f0Sopenharmony_ci		.build = 1,
135d5ac70f0Sopenharmony_ci		.enew  = 1,
136d5ac70f0Sopenharmony_ci		.parse = tplg_parse_cc,
137d5ac70f0Sopenharmony_ci		.save  = tplg_save_cc,
138d5ac70f0Sopenharmony_ci		.decod = tplg_decode_cc,
139d5ac70f0Sopenharmony_ci	},
140d5ac70f0Sopenharmony_ci	{
141d5ac70f0Sopenharmony_ci		.name  = "route (dapm graph)",
142d5ac70f0Sopenharmony_ci		.id = "SectionGraph",
143d5ac70f0Sopenharmony_ci		.loff  = offsetof(snd_tplg_t, route_list),
144d5ac70f0Sopenharmony_ci		.type  = SND_TPLG_TYPE_DAPM_GRAPH,
145d5ac70f0Sopenharmony_ci		.tsoc  = SND_SOC_TPLG_TYPE_DAPM_GRAPH,
146d5ac70f0Sopenharmony_ci		.build = 1,
147d5ac70f0Sopenharmony_ci		.parse = tplg_parse_dapm_graph,
148d5ac70f0Sopenharmony_ci		.gsave = tplg_save_dapm_graph,
149d5ac70f0Sopenharmony_ci		.decod = tplg_decode_dapm_graph,
150d5ac70f0Sopenharmony_ci	},
151d5ac70f0Sopenharmony_ci	{
152d5ac70f0Sopenharmony_ci		.name  = "private data",
153d5ac70f0Sopenharmony_ci		.id    = "SectionData",
154d5ac70f0Sopenharmony_ci		.loff  = offsetof(snd_tplg_t, pdata_list),
155d5ac70f0Sopenharmony_ci		.type  = SND_TPLG_TYPE_DATA,
156d5ac70f0Sopenharmony_ci		.tsoc  = SND_SOC_TPLG_TYPE_PDATA,
157d5ac70f0Sopenharmony_ci		.build = 1,
158d5ac70f0Sopenharmony_ci		.enew  = 1,
159d5ac70f0Sopenharmony_ci		.parse = tplg_parse_data,
160d5ac70f0Sopenharmony_ci		.save  = tplg_save_data,
161d5ac70f0Sopenharmony_ci		.decod = tplg_decode_data,
162d5ac70f0Sopenharmony_ci	},
163d5ac70f0Sopenharmony_ci	{
164d5ac70f0Sopenharmony_ci		.name  = "text",
165d5ac70f0Sopenharmony_ci		.id    = "SectionText",
166d5ac70f0Sopenharmony_ci		.loff  = offsetof(snd_tplg_t, text_list),
167d5ac70f0Sopenharmony_ci		.type  = SND_TPLG_TYPE_TEXT,
168d5ac70f0Sopenharmony_ci		.size  = sizeof(struct tplg_texts),
169d5ac70f0Sopenharmony_ci		.enew  = 1,
170d5ac70f0Sopenharmony_ci		.parse = tplg_parse_text,
171d5ac70f0Sopenharmony_ci		.save  = tplg_save_text,
172d5ac70f0Sopenharmony_ci	},
173d5ac70f0Sopenharmony_ci	{
174d5ac70f0Sopenharmony_ci		.name  = "tlv",
175d5ac70f0Sopenharmony_ci		.id    = "SectionTLV",
176d5ac70f0Sopenharmony_ci		.loff  = offsetof(snd_tplg_t, tlv_list),
177d5ac70f0Sopenharmony_ci		.type  = SND_TPLG_TYPE_TLV,
178d5ac70f0Sopenharmony_ci		.size  = sizeof(struct snd_soc_tplg_ctl_tlv),
179d5ac70f0Sopenharmony_ci		.enew  = 1,
180d5ac70f0Sopenharmony_ci		.parse = tplg_parse_tlv,
181d5ac70f0Sopenharmony_ci		.save  = tplg_save_tlv,
182d5ac70f0Sopenharmony_ci	},
183d5ac70f0Sopenharmony_ci	{
184d5ac70f0Sopenharmony_ci		.name  = "stream config",
185d5ac70f0Sopenharmony_ci		.loff  = offsetof(snd_tplg_t, pcm_config_list),
186d5ac70f0Sopenharmony_ci		.type  = SND_TPLG_TYPE_STREAM_CONFIG,
187d5ac70f0Sopenharmony_ci		.size  = sizeof(struct snd_soc_tplg_stream),
188d5ac70f0Sopenharmony_ci		.enew  = 1,
189d5ac70f0Sopenharmony_ci	},
190d5ac70f0Sopenharmony_ci	{
191d5ac70f0Sopenharmony_ci		.name  = "stream capabilities",
192d5ac70f0Sopenharmony_ci		.id    = "SectionPCMCapabilities",
193d5ac70f0Sopenharmony_ci		.loff  = offsetof(snd_tplg_t, pcm_caps_list),
194d5ac70f0Sopenharmony_ci		.type  = SND_TPLG_TYPE_STREAM_CAPS,
195d5ac70f0Sopenharmony_ci		.size  = sizeof(struct snd_soc_tplg_stream_caps),
196d5ac70f0Sopenharmony_ci		.enew  = 1,
197d5ac70f0Sopenharmony_ci		.parse = tplg_parse_stream_caps,
198d5ac70f0Sopenharmony_ci		.save  = tplg_save_stream_caps,
199d5ac70f0Sopenharmony_ci	},
200d5ac70f0Sopenharmony_ci	{
201d5ac70f0Sopenharmony_ci		.name  = "token",
202d5ac70f0Sopenharmony_ci		.id    = "SectionVendorTokens",
203d5ac70f0Sopenharmony_ci		.loff  = offsetof(snd_tplg_t, token_list),
204d5ac70f0Sopenharmony_ci		.type  = SND_TPLG_TYPE_TOKEN,
205d5ac70f0Sopenharmony_ci		.enew  = 1,
206d5ac70f0Sopenharmony_ci		.parse = tplg_parse_tokens,
207d5ac70f0Sopenharmony_ci		.save  = tplg_save_tokens,
208d5ac70f0Sopenharmony_ci	},
209d5ac70f0Sopenharmony_ci	{
210d5ac70f0Sopenharmony_ci		.name  = "tuple",
211d5ac70f0Sopenharmony_ci		.id    = "SectionVendorTuples",
212d5ac70f0Sopenharmony_ci		.loff  = offsetof(snd_tplg_t, tuple_list),
213d5ac70f0Sopenharmony_ci		.type  = SND_TPLG_TYPE_TUPLE,
214d5ac70f0Sopenharmony_ci		.free  = tplg_free_tuples,
215d5ac70f0Sopenharmony_ci		.enew  = 1,
216d5ac70f0Sopenharmony_ci		.parse = tplg_parse_tuples,
217d5ac70f0Sopenharmony_ci		.save  = tplg_save_tuples,
218d5ac70f0Sopenharmony_ci	},
219d5ac70f0Sopenharmony_ci	{
220d5ac70f0Sopenharmony_ci		.name  = "hw config",
221d5ac70f0Sopenharmony_ci		.id    = "SectionHWConfig",
222d5ac70f0Sopenharmony_ci		.loff  = offsetof(snd_tplg_t, hw_cfg_list),
223d5ac70f0Sopenharmony_ci		.type  = SND_TPLG_TYPE_HW_CONFIG,
224d5ac70f0Sopenharmony_ci		.size  = sizeof(struct snd_soc_tplg_hw_config),
225d5ac70f0Sopenharmony_ci		.enew  = 1,
226d5ac70f0Sopenharmony_ci		.parse = tplg_parse_hw_config,
227d5ac70f0Sopenharmony_ci		.save  = tplg_save_hw_config,
228d5ac70f0Sopenharmony_ci	}
229d5ac70f0Sopenharmony_ci};
230d5ac70f0Sopenharmony_ci
231d5ac70f0Sopenharmony_ciunsigned int tplg_table_items = ARRAY_SIZE(tplg_table);
232d5ac70f0Sopenharmony_ci
233d5ac70f0Sopenharmony_ciint tplg_get_type(int asoc_type)
234d5ac70f0Sopenharmony_ci{
235d5ac70f0Sopenharmony_ci	unsigned int index;
236d5ac70f0Sopenharmony_ci
237d5ac70f0Sopenharmony_ci	for (index = 0; index < tplg_table_items; index++)
238d5ac70f0Sopenharmony_ci		if (tplg_table[index].tsoc == asoc_type)
239d5ac70f0Sopenharmony_ci			return tplg_table[index].type;
240d5ac70f0Sopenharmony_ci	SNDERR("uknown asoc type %d", asoc_type);
241d5ac70f0Sopenharmony_ci	return -EINVAL;
242d5ac70f0Sopenharmony_ci}
243d5ac70f0Sopenharmony_ci
244d5ac70f0Sopenharmony_ciint tplg_ref_add(struct tplg_elem *elem, int type, const char* id)
245d5ac70f0Sopenharmony_ci{
246d5ac70f0Sopenharmony_ci	struct tplg_ref *ref;
247d5ac70f0Sopenharmony_ci
248d5ac70f0Sopenharmony_ci	ref = calloc(1, sizeof(*ref));
249d5ac70f0Sopenharmony_ci	if (!ref)
250d5ac70f0Sopenharmony_ci		return -ENOMEM;
251d5ac70f0Sopenharmony_ci
252d5ac70f0Sopenharmony_ci	strncpy(ref->id, id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
253d5ac70f0Sopenharmony_ci	ref->id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN - 1] = 0;
254d5ac70f0Sopenharmony_ci	ref->type = type;
255d5ac70f0Sopenharmony_ci
256d5ac70f0Sopenharmony_ci	list_add_tail(&ref->list, &elem->ref_list);
257d5ac70f0Sopenharmony_ci	return 0;
258d5ac70f0Sopenharmony_ci}
259d5ac70f0Sopenharmony_ci
260d5ac70f0Sopenharmony_ci/* directly add a reference elem */
261d5ac70f0Sopenharmony_ciint tplg_ref_add_elem(struct tplg_elem *elem, struct tplg_elem *elem_ref)
262d5ac70f0Sopenharmony_ci{
263d5ac70f0Sopenharmony_ci	struct tplg_ref *ref;
264d5ac70f0Sopenharmony_ci
265d5ac70f0Sopenharmony_ci	ref = calloc(1, sizeof(*ref));
266d5ac70f0Sopenharmony_ci	if (!ref)
267d5ac70f0Sopenharmony_ci		return -ENOMEM;
268d5ac70f0Sopenharmony_ci
269d5ac70f0Sopenharmony_ci	ref->type = elem_ref->type;
270d5ac70f0Sopenharmony_ci	ref->elem = elem_ref;
271d5ac70f0Sopenharmony_ci	snd_strlcpy(ref->id, elem_ref->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
272d5ac70f0Sopenharmony_ci
273d5ac70f0Sopenharmony_ci	list_add_tail(&ref->list, &elem->ref_list);
274d5ac70f0Sopenharmony_ci	return 0;
275d5ac70f0Sopenharmony_ci}
276d5ac70f0Sopenharmony_ci
277d5ac70f0Sopenharmony_civoid tplg_ref_free_list(struct list_head *base)
278d5ac70f0Sopenharmony_ci{
279d5ac70f0Sopenharmony_ci	struct list_head *pos, *npos;
280d5ac70f0Sopenharmony_ci	struct tplg_ref *ref;
281d5ac70f0Sopenharmony_ci
282d5ac70f0Sopenharmony_ci	list_for_each_safe(pos, npos, base) {
283d5ac70f0Sopenharmony_ci		ref = list_entry(pos, struct tplg_ref, list);
284d5ac70f0Sopenharmony_ci		list_del(&ref->list);
285d5ac70f0Sopenharmony_ci		free(ref);
286d5ac70f0Sopenharmony_ci	}
287d5ac70f0Sopenharmony_ci}
288d5ac70f0Sopenharmony_ci
289d5ac70f0Sopenharmony_cistruct tplg_elem *tplg_elem_new(void)
290d5ac70f0Sopenharmony_ci{
291d5ac70f0Sopenharmony_ci	struct tplg_elem *elem;
292d5ac70f0Sopenharmony_ci
293d5ac70f0Sopenharmony_ci	elem = calloc(1, sizeof(*elem));
294d5ac70f0Sopenharmony_ci	if (!elem)
295d5ac70f0Sopenharmony_ci		return NULL;
296d5ac70f0Sopenharmony_ci
297d5ac70f0Sopenharmony_ci	INIT_LIST_HEAD(&elem->ref_list);
298d5ac70f0Sopenharmony_ci	return elem;
299d5ac70f0Sopenharmony_ci}
300d5ac70f0Sopenharmony_ci
301d5ac70f0Sopenharmony_civoid tplg_elem_free(struct tplg_elem *elem)
302d5ac70f0Sopenharmony_ci{
303d5ac70f0Sopenharmony_ci	list_del(&elem->list);
304d5ac70f0Sopenharmony_ci
305d5ac70f0Sopenharmony_ci	tplg_ref_free_list(&elem->ref_list);
306d5ac70f0Sopenharmony_ci
307d5ac70f0Sopenharmony_ci	/* free struct snd_tplg_ object,
308d5ac70f0Sopenharmony_ci	 * the union pointers share the same address
309d5ac70f0Sopenharmony_ci	 */
310d5ac70f0Sopenharmony_ci	if (elem->obj) {
311d5ac70f0Sopenharmony_ci		if (elem->free)
312d5ac70f0Sopenharmony_ci			elem->free(elem->obj);
313d5ac70f0Sopenharmony_ci
314d5ac70f0Sopenharmony_ci		free(elem->obj);
315d5ac70f0Sopenharmony_ci	}
316d5ac70f0Sopenharmony_ci
317d5ac70f0Sopenharmony_ci	free(elem);
318d5ac70f0Sopenharmony_ci}
319d5ac70f0Sopenharmony_ci
320d5ac70f0Sopenharmony_civoid tplg_elem_free_list(struct list_head *base)
321d5ac70f0Sopenharmony_ci{
322d5ac70f0Sopenharmony_ci	struct list_head *pos, *npos;
323d5ac70f0Sopenharmony_ci	struct tplg_elem *elem;
324d5ac70f0Sopenharmony_ci
325d5ac70f0Sopenharmony_ci	list_for_each_safe(pos, npos, base) {
326d5ac70f0Sopenharmony_ci		elem = list_entry(pos, struct tplg_elem, list);
327d5ac70f0Sopenharmony_ci		tplg_elem_free(elem);
328d5ac70f0Sopenharmony_ci	}
329d5ac70f0Sopenharmony_ci}
330d5ac70f0Sopenharmony_ci
331d5ac70f0Sopenharmony_cistruct tplg_elem *tplg_elem_lookup(struct list_head *base, const char* id,
332d5ac70f0Sopenharmony_ci				   unsigned int type, int index)
333d5ac70f0Sopenharmony_ci{
334d5ac70f0Sopenharmony_ci	struct list_head *pos;
335d5ac70f0Sopenharmony_ci	struct tplg_elem *elem;
336d5ac70f0Sopenharmony_ci
337d5ac70f0Sopenharmony_ci	if (!base || !id)
338d5ac70f0Sopenharmony_ci		return NULL;
339d5ac70f0Sopenharmony_ci
340d5ac70f0Sopenharmony_ci	list_for_each(pos, base) {
341d5ac70f0Sopenharmony_ci
342d5ac70f0Sopenharmony_ci		elem = list_entry(pos, struct tplg_elem, list);
343d5ac70f0Sopenharmony_ci
344d5ac70f0Sopenharmony_ci		if (!strcmp(elem->id, id) && elem->type == type)
345d5ac70f0Sopenharmony_ci			return elem;
346d5ac70f0Sopenharmony_ci		/* SND_TPLG_INDEX_ALL is the default value "0" and applicable
347d5ac70f0Sopenharmony_ci		   for all use cases */
348d5ac70f0Sopenharmony_ci		if ((index != SND_TPLG_INDEX_ALL)
349d5ac70f0Sopenharmony_ci			&& (elem->index > index))
350d5ac70f0Sopenharmony_ci			break;
351d5ac70f0Sopenharmony_ci	}
352d5ac70f0Sopenharmony_ci
353d5ac70f0Sopenharmony_ci	return NULL;
354d5ac70f0Sopenharmony_ci}
355d5ac70f0Sopenharmony_ci
356d5ac70f0Sopenharmony_ci/* find an element by type */
357d5ac70f0Sopenharmony_cistruct tplg_elem *tplg_elem_type_lookup(snd_tplg_t *tplg,
358d5ac70f0Sopenharmony_ci					enum snd_tplg_type type)
359d5ac70f0Sopenharmony_ci{
360d5ac70f0Sopenharmony_ci	struct tplg_table *tptr;
361d5ac70f0Sopenharmony_ci	struct list_head *pos, *list;
362d5ac70f0Sopenharmony_ci	struct tplg_elem *elem;
363d5ac70f0Sopenharmony_ci	unsigned int index;
364d5ac70f0Sopenharmony_ci
365d5ac70f0Sopenharmony_ci	for (index = 0; index < tplg_table_items; index++) {
366d5ac70f0Sopenharmony_ci		tptr = &tplg_table[index];
367d5ac70f0Sopenharmony_ci		if (!tptr->enew)
368d5ac70f0Sopenharmony_ci			continue;
369d5ac70f0Sopenharmony_ci		if ((int)type != tptr->type)
370d5ac70f0Sopenharmony_ci			continue;
371d5ac70f0Sopenharmony_ci		break;
372d5ac70f0Sopenharmony_ci	}
373d5ac70f0Sopenharmony_ci	if (index >= tplg_table_items)
374d5ac70f0Sopenharmony_ci		return NULL;
375d5ac70f0Sopenharmony_ci
376d5ac70f0Sopenharmony_ci	list = (struct list_head *)((void *)tplg + tptr->loff);
377d5ac70f0Sopenharmony_ci
378d5ac70f0Sopenharmony_ci	/* return only first element */
379d5ac70f0Sopenharmony_ci	list_for_each(pos, list) {
380d5ac70f0Sopenharmony_ci		elem = list_entry(pos, struct tplg_elem, list);
381d5ac70f0Sopenharmony_ci		return elem;
382d5ac70f0Sopenharmony_ci	}
383d5ac70f0Sopenharmony_ci	return NULL;
384d5ac70f0Sopenharmony_ci}
385d5ac70f0Sopenharmony_ci
386d5ac70f0Sopenharmony_ci/* insert a new element into list in the ascending order of index value */
387d5ac70f0Sopenharmony_civoid tplg_elem_insert(struct tplg_elem *elem_p, struct list_head *list)
388d5ac70f0Sopenharmony_ci{
389d5ac70f0Sopenharmony_ci	struct list_head *pos, *p = &(elem_p->list);
390d5ac70f0Sopenharmony_ci	struct tplg_elem *elem;
391d5ac70f0Sopenharmony_ci
392d5ac70f0Sopenharmony_ci	list_for_each(pos, list) {
393d5ac70f0Sopenharmony_ci		elem = list_entry(pos, struct tplg_elem, list);
394d5ac70f0Sopenharmony_ci		if (elem_p->index < elem->index)
395d5ac70f0Sopenharmony_ci			break;
396d5ac70f0Sopenharmony_ci	}
397d5ac70f0Sopenharmony_ci	/* insert item before pos */
398d5ac70f0Sopenharmony_ci	list_insert(p, pos->prev, pos);
399d5ac70f0Sopenharmony_ci}
400d5ac70f0Sopenharmony_ci
401d5ac70f0Sopenharmony_ci/* create a new common element and object */
402d5ac70f0Sopenharmony_cistruct tplg_elem* tplg_elem_new_common(snd_tplg_t *tplg,
403d5ac70f0Sopenharmony_ci				       snd_config_t *cfg,
404d5ac70f0Sopenharmony_ci				       const char *name,
405d5ac70f0Sopenharmony_ci				       enum snd_tplg_type type)
406d5ac70f0Sopenharmony_ci{
407d5ac70f0Sopenharmony_ci	struct tplg_table *tptr;
408d5ac70f0Sopenharmony_ci	struct tplg_elem *elem;
409d5ac70f0Sopenharmony_ci	struct list_head *list;
410d5ac70f0Sopenharmony_ci	const char *id;
411d5ac70f0Sopenharmony_ci	int obj_size = 0;
412d5ac70f0Sopenharmony_ci	unsigned index;
413d5ac70f0Sopenharmony_ci	void *obj;
414d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
415d5ac70f0Sopenharmony_ci	snd_config_t *n;
416d5ac70f0Sopenharmony_ci
417d5ac70f0Sopenharmony_ci	if (!cfg && !name)
418d5ac70f0Sopenharmony_ci		return NULL;
419d5ac70f0Sopenharmony_ci
420d5ac70f0Sopenharmony_ci	elem = tplg_elem_new();
421d5ac70f0Sopenharmony_ci	if (!elem)
422d5ac70f0Sopenharmony_ci		return NULL;
423d5ac70f0Sopenharmony_ci
424d5ac70f0Sopenharmony_ci	/* do we get name from cfg */
425d5ac70f0Sopenharmony_ci	if (cfg) {
426d5ac70f0Sopenharmony_ci		snd_config_get_id(cfg, &id);
427d5ac70f0Sopenharmony_ci		snd_strlcpy(elem->id, id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
428d5ac70f0Sopenharmony_ci		elem->id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN - 1] = 0;
429d5ac70f0Sopenharmony_ci		/* as we insert new elem based on the index value, move index
430d5ac70f0Sopenharmony_ci		   parsing here */
431d5ac70f0Sopenharmony_ci		snd_config_for_each(i, next, cfg) {
432d5ac70f0Sopenharmony_ci			n = snd_config_iterator_entry(i);
433d5ac70f0Sopenharmony_ci			if (snd_config_get_id(n, &id))
434d5ac70f0Sopenharmony_ci				continue;
435d5ac70f0Sopenharmony_ci			if (strcmp(id, "index") == 0) {
436d5ac70f0Sopenharmony_ci				if (tplg_get_integer(n, &elem->index, 0)) {
437d5ac70f0Sopenharmony_ci					free(elem);
438d5ac70f0Sopenharmony_ci					return NULL;
439d5ac70f0Sopenharmony_ci				}
440d5ac70f0Sopenharmony_ci				if (elem->index < 0) {
441d5ac70f0Sopenharmony_ci					free(elem);
442d5ac70f0Sopenharmony_ci					return NULL;
443d5ac70f0Sopenharmony_ci				}
444d5ac70f0Sopenharmony_ci			}
445d5ac70f0Sopenharmony_ci		}
446d5ac70f0Sopenharmony_ci	} else if (name != NULL)
447d5ac70f0Sopenharmony_ci		snd_strlcpy(elem->id, name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN);
448d5ac70f0Sopenharmony_ci
449d5ac70f0Sopenharmony_ci	for (index = 0; index < tplg_table_items; index++) {
450d5ac70f0Sopenharmony_ci		tptr = &tplg_table[index];
451d5ac70f0Sopenharmony_ci		if (!tptr->enew)
452d5ac70f0Sopenharmony_ci			continue;
453d5ac70f0Sopenharmony_ci		if ((int)type != tptr->type)
454d5ac70f0Sopenharmony_ci			continue;
455d5ac70f0Sopenharmony_ci		break;
456d5ac70f0Sopenharmony_ci	}
457d5ac70f0Sopenharmony_ci	if (index >= tplg_table_items) {
458d5ac70f0Sopenharmony_ci		free(elem);
459d5ac70f0Sopenharmony_ci		return NULL;
460d5ac70f0Sopenharmony_ci	}
461d5ac70f0Sopenharmony_ci
462d5ac70f0Sopenharmony_ci	list = (struct list_head *)((void *)tplg + tptr->loff);
463d5ac70f0Sopenharmony_ci	tplg_elem_insert(elem, list);
464d5ac70f0Sopenharmony_ci	obj_size = tptr->size;
465d5ac70f0Sopenharmony_ci	elem->free = tptr->free;
466d5ac70f0Sopenharmony_ci	elem->table = tptr;
467d5ac70f0Sopenharmony_ci
468d5ac70f0Sopenharmony_ci	/* create new object too if required */
469d5ac70f0Sopenharmony_ci	if (obj_size > 0) {
470d5ac70f0Sopenharmony_ci		obj = calloc(1, obj_size);
471d5ac70f0Sopenharmony_ci		if (obj == NULL) {
472d5ac70f0Sopenharmony_ci			free(elem);
473d5ac70f0Sopenharmony_ci			return NULL;
474d5ac70f0Sopenharmony_ci		}
475d5ac70f0Sopenharmony_ci
476d5ac70f0Sopenharmony_ci		elem->obj = obj;
477d5ac70f0Sopenharmony_ci		elem->size = obj_size;
478d5ac70f0Sopenharmony_ci	}
479d5ac70f0Sopenharmony_ci
480d5ac70f0Sopenharmony_ci	elem->type = type;
481d5ac70f0Sopenharmony_ci	return elem;
482d5ac70f0Sopenharmony_ci}
483d5ac70f0Sopenharmony_ci
484d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN
485d5ac70f0Sopenharmony_cistruct tplg_alloc {
486d5ac70f0Sopenharmony_ci	struct list_head list;
487d5ac70f0Sopenharmony_ci	void *data[0];
488d5ac70f0Sopenharmony_ci};
489d5ac70f0Sopenharmony_ci#endif /* DOC_HIDDEN */
490d5ac70f0Sopenharmony_ci
491d5ac70f0Sopenharmony_civoid *tplg_calloc(struct list_head *heap, size_t size)
492d5ac70f0Sopenharmony_ci{
493d5ac70f0Sopenharmony_ci	struct tplg_alloc *a;
494d5ac70f0Sopenharmony_ci
495d5ac70f0Sopenharmony_ci	a = calloc(1, sizeof(*a) + size);
496d5ac70f0Sopenharmony_ci	if (a == NULL)
497d5ac70f0Sopenharmony_ci		return NULL;
498d5ac70f0Sopenharmony_ci	list_add_tail(&a->list, heap);
499d5ac70f0Sopenharmony_ci	return a->data;
500d5ac70f0Sopenharmony_ci}
501d5ac70f0Sopenharmony_ci
502d5ac70f0Sopenharmony_civoid tplg_free(struct list_head *heap)
503d5ac70f0Sopenharmony_ci{
504d5ac70f0Sopenharmony_ci	struct list_head *pos, *npos;
505d5ac70f0Sopenharmony_ci	struct tplg_alloc *a;
506d5ac70f0Sopenharmony_ci
507d5ac70f0Sopenharmony_ci	list_for_each_safe(pos, npos, heap) {
508d5ac70f0Sopenharmony_ci		a = list_entry(pos, struct tplg_alloc, list);
509d5ac70f0Sopenharmony_ci		list_del(&a->list);
510d5ac70f0Sopenharmony_ci		free(a);
511d5ac70f0Sopenharmony_ci	}
512d5ac70f0Sopenharmony_ci}
513