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