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#include <ctype.h> 22d5ac70f0Sopenharmony_ci 23d5ac70f0Sopenharmony_ci#define UUID_FORMAT "\ 24d5ac70f0Sopenharmony_ci%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:\ 25d5ac70f0Sopenharmony_ci%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x" 26d5ac70f0Sopenharmony_ci 27d5ac70f0Sopenharmony_ci/* Get private data buffer of an element */ 28d5ac70f0Sopenharmony_cistruct snd_soc_tplg_private *get_priv_data(struct tplg_elem *elem) 29d5ac70f0Sopenharmony_ci{ 30d5ac70f0Sopenharmony_ci struct snd_soc_tplg_private *priv = NULL; 31d5ac70f0Sopenharmony_ci 32d5ac70f0Sopenharmony_ci switch (elem->type) { 33d5ac70f0Sopenharmony_ci case SND_TPLG_TYPE_MANIFEST: 34d5ac70f0Sopenharmony_ci priv = &elem->manifest->priv; 35d5ac70f0Sopenharmony_ci break; 36d5ac70f0Sopenharmony_ci 37d5ac70f0Sopenharmony_ci case SND_TPLG_TYPE_MIXER: 38d5ac70f0Sopenharmony_ci priv = &elem->mixer_ctrl->priv; 39d5ac70f0Sopenharmony_ci break; 40d5ac70f0Sopenharmony_ci 41d5ac70f0Sopenharmony_ci case SND_TPLG_TYPE_ENUM: 42d5ac70f0Sopenharmony_ci priv = &elem->enum_ctrl->priv; 43d5ac70f0Sopenharmony_ci break; 44d5ac70f0Sopenharmony_ci 45d5ac70f0Sopenharmony_ci case SND_TPLG_TYPE_BYTES: 46d5ac70f0Sopenharmony_ci priv = &elem->bytes_ext->priv; 47d5ac70f0Sopenharmony_ci break; 48d5ac70f0Sopenharmony_ci 49d5ac70f0Sopenharmony_ci case SND_TPLG_TYPE_DAPM_WIDGET: 50d5ac70f0Sopenharmony_ci priv = &elem->widget->priv; 51d5ac70f0Sopenharmony_ci break; 52d5ac70f0Sopenharmony_ci 53d5ac70f0Sopenharmony_ci case SND_TPLG_TYPE_DAI: 54d5ac70f0Sopenharmony_ci priv = &elem->dai->priv; 55d5ac70f0Sopenharmony_ci break; 56d5ac70f0Sopenharmony_ci case SND_TPLG_TYPE_BE: 57d5ac70f0Sopenharmony_ci priv = &elem->link->priv; 58d5ac70f0Sopenharmony_ci break; 59d5ac70f0Sopenharmony_ci case SND_TPLG_TYPE_PCM: 60d5ac70f0Sopenharmony_ci priv = &elem->pcm->priv; 61d5ac70f0Sopenharmony_ci break; 62d5ac70f0Sopenharmony_ci default: 63d5ac70f0Sopenharmony_ci SNDERR("'%s': no support for private data for type %d", 64d5ac70f0Sopenharmony_ci elem->id, elem->type); 65d5ac70f0Sopenharmony_ci } 66d5ac70f0Sopenharmony_ci 67d5ac70f0Sopenharmony_ci return priv; 68d5ac70f0Sopenharmony_ci} 69d5ac70f0Sopenharmony_ci 70d5ac70f0Sopenharmony_ci/* Parse references for the element, either a single data section 71d5ac70f0Sopenharmony_ci * or a list of data sections. 72d5ac70f0Sopenharmony_ci */ 73d5ac70f0Sopenharmony_ciint tplg_parse_refs(snd_config_t *cfg, struct tplg_elem *elem, 74d5ac70f0Sopenharmony_ci unsigned int type) 75d5ac70f0Sopenharmony_ci{ 76d5ac70f0Sopenharmony_ci snd_config_type_t cfg_type; 77d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 78d5ac70f0Sopenharmony_ci snd_config_t *n; 79d5ac70f0Sopenharmony_ci const char *val = NULL; 80d5ac70f0Sopenharmony_ci int err, count; 81d5ac70f0Sopenharmony_ci 82d5ac70f0Sopenharmony_ci cfg_type = snd_config_get_type(cfg); 83d5ac70f0Sopenharmony_ci 84d5ac70f0Sopenharmony_ci /* refer to a single data section */ 85d5ac70f0Sopenharmony_ci if (cfg_type == SND_CONFIG_TYPE_STRING) { 86d5ac70f0Sopenharmony_ci if (snd_config_get_string(cfg, &val) < 0) 87d5ac70f0Sopenharmony_ci return -EINVAL; 88d5ac70f0Sopenharmony_ci 89d5ac70f0Sopenharmony_ci tplg_dbg("\tref data: %s", val); 90d5ac70f0Sopenharmony_ci err = tplg_ref_add(elem, type, val); 91d5ac70f0Sopenharmony_ci if (err < 0) 92d5ac70f0Sopenharmony_ci return err; 93d5ac70f0Sopenharmony_ci return 1; 94d5ac70f0Sopenharmony_ci } 95d5ac70f0Sopenharmony_ci 96d5ac70f0Sopenharmony_ci if (cfg_type != SND_CONFIG_TYPE_COMPOUND) { 97d5ac70f0Sopenharmony_ci SNDERR("compound type expected for %s", elem->id); 98d5ac70f0Sopenharmony_ci return -EINVAL; 99d5ac70f0Sopenharmony_ci } 100d5ac70f0Sopenharmony_ci 101d5ac70f0Sopenharmony_ci /* refer to a list of data sections */ 102d5ac70f0Sopenharmony_ci count = 0; 103d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 104d5ac70f0Sopenharmony_ci const char *val; 105d5ac70f0Sopenharmony_ci 106d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 107d5ac70f0Sopenharmony_ci if (snd_config_get_string(n, &val) < 0) 108d5ac70f0Sopenharmony_ci continue; 109d5ac70f0Sopenharmony_ci 110d5ac70f0Sopenharmony_ci tplg_dbg("\tref data: %s", val); 111d5ac70f0Sopenharmony_ci err = tplg_ref_add(elem, type, val); 112d5ac70f0Sopenharmony_ci if (err < 0) 113d5ac70f0Sopenharmony_ci return err; 114d5ac70f0Sopenharmony_ci count++; 115d5ac70f0Sopenharmony_ci } 116d5ac70f0Sopenharmony_ci 117d5ac70f0Sopenharmony_ci return count; 118d5ac70f0Sopenharmony_ci} 119d5ac70f0Sopenharmony_ci 120d5ac70f0Sopenharmony_ci/* save references */ 121d5ac70f0Sopenharmony_ciint tplg_save_refs(snd_tplg_t *tplg ATTRIBUTE_UNUSED, 122d5ac70f0Sopenharmony_ci struct tplg_elem *elem, unsigned int type, 123d5ac70f0Sopenharmony_ci const char *id, struct tplg_buf *dst, 124d5ac70f0Sopenharmony_ci const char *pfx) 125d5ac70f0Sopenharmony_ci{ 126d5ac70f0Sopenharmony_ci struct tplg_ref *ref, *last; 127d5ac70f0Sopenharmony_ci struct list_head *pos; 128d5ac70f0Sopenharmony_ci int err, count; 129d5ac70f0Sopenharmony_ci 130d5ac70f0Sopenharmony_ci count = 0; 131d5ac70f0Sopenharmony_ci last = NULL; 132d5ac70f0Sopenharmony_ci list_for_each(pos, &elem->ref_list) { 133d5ac70f0Sopenharmony_ci ref = list_entry(pos, struct tplg_ref, list); 134d5ac70f0Sopenharmony_ci if (ref->type == type) { 135d5ac70f0Sopenharmony_ci last = ref; 136d5ac70f0Sopenharmony_ci count++; 137d5ac70f0Sopenharmony_ci } 138d5ac70f0Sopenharmony_ci } 139d5ac70f0Sopenharmony_ci 140d5ac70f0Sopenharmony_ci if (count == 0) 141d5ac70f0Sopenharmony_ci return 0; 142d5ac70f0Sopenharmony_ci 143d5ac70f0Sopenharmony_ci if (count == 1) 144d5ac70f0Sopenharmony_ci return tplg_save_printf(dst, pfx, "%s '%s'\n", id, last->id); 145d5ac70f0Sopenharmony_ci 146d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "%s [\n", id); 147d5ac70f0Sopenharmony_ci if (err < 0) 148d5ac70f0Sopenharmony_ci return err; 149d5ac70f0Sopenharmony_ci list_for_each(pos, &elem->ref_list) { 150d5ac70f0Sopenharmony_ci ref = list_entry(pos, struct tplg_ref, list); 151d5ac70f0Sopenharmony_ci if (ref->type == type) { 152d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "\t'%s'\n", ref->id); 153d5ac70f0Sopenharmony_ci if (err < 0) 154d5ac70f0Sopenharmony_ci return err; 155d5ac70f0Sopenharmony_ci } 156d5ac70f0Sopenharmony_ci } 157d5ac70f0Sopenharmony_ci 158d5ac70f0Sopenharmony_ci return tplg_save_printf(dst, pfx, "]\n"); 159d5ac70f0Sopenharmony_ci} 160d5ac70f0Sopenharmony_ci 161d5ac70f0Sopenharmony_ci/* Get Private data from a file. */ 162d5ac70f0Sopenharmony_cistatic int tplg_parse_data_file(snd_config_t *cfg, struct tplg_elem *elem) 163d5ac70f0Sopenharmony_ci{ 164d5ac70f0Sopenharmony_ci struct snd_soc_tplg_private *priv = NULL; 165d5ac70f0Sopenharmony_ci const char *value = NULL; 166d5ac70f0Sopenharmony_ci char filename[PATH_MAX]; 167d5ac70f0Sopenharmony_ci char *env = getenv(ALSA_CONFIG_TPLG_VAR); 168d5ac70f0Sopenharmony_ci FILE *fp; 169d5ac70f0Sopenharmony_ci size_t size, bytes_read; 170d5ac70f0Sopenharmony_ci int ret = 0; 171d5ac70f0Sopenharmony_ci 172d5ac70f0Sopenharmony_ci tplg_dbg("data DataFile: %s", elem->id); 173d5ac70f0Sopenharmony_ci 174d5ac70f0Sopenharmony_ci if (snd_config_get_string(cfg, &value) < 0) 175d5ac70f0Sopenharmony_ci return -EINVAL; 176d5ac70f0Sopenharmony_ci 177d5ac70f0Sopenharmony_ci /* prepend alsa config directory to path */ 178d5ac70f0Sopenharmony_ci if (env) 179d5ac70f0Sopenharmony_ci snprintf(filename, sizeof(filename), "%s/%s", env, value); 180d5ac70f0Sopenharmony_ci else 181d5ac70f0Sopenharmony_ci snprintf(filename, sizeof(filename), "%s/topology/%s", 182d5ac70f0Sopenharmony_ci snd_config_topdir(), value); 183d5ac70f0Sopenharmony_ci 184d5ac70f0Sopenharmony_ci fp = fopen(filename, "r"); 185d5ac70f0Sopenharmony_ci if (fp == NULL) { 186d5ac70f0Sopenharmony_ci SNDERR("invalid data file path '%s'", filename); 187d5ac70f0Sopenharmony_ci return -errno; 188d5ac70f0Sopenharmony_ci } 189d5ac70f0Sopenharmony_ci 190d5ac70f0Sopenharmony_ci fseek(fp, 0L, SEEK_END); 191d5ac70f0Sopenharmony_ci size = ftell(fp); 192d5ac70f0Sopenharmony_ci fseek(fp, 0L, SEEK_SET); 193d5ac70f0Sopenharmony_ci if (size <= 0) { 194d5ac70f0Sopenharmony_ci SNDERR("invalid data file size %zu", size); 195d5ac70f0Sopenharmony_ci ret = -EINVAL; 196d5ac70f0Sopenharmony_ci goto err; 197d5ac70f0Sopenharmony_ci } 198d5ac70f0Sopenharmony_ci if (size > TPLG_MAX_PRIV_SIZE) { 199d5ac70f0Sopenharmony_ci SNDERR("data file too big %zu", size); 200d5ac70f0Sopenharmony_ci ret = -EINVAL; 201d5ac70f0Sopenharmony_ci goto err; 202d5ac70f0Sopenharmony_ci } 203d5ac70f0Sopenharmony_ci 204d5ac70f0Sopenharmony_ci priv = calloc(1, sizeof(*priv) + size); 205d5ac70f0Sopenharmony_ci if (!priv) { 206d5ac70f0Sopenharmony_ci ret = -ENOMEM; 207d5ac70f0Sopenharmony_ci goto err; 208d5ac70f0Sopenharmony_ci } 209d5ac70f0Sopenharmony_ci 210d5ac70f0Sopenharmony_ci bytes_read = fread(&priv->data, 1, size, fp); 211d5ac70f0Sopenharmony_ci if (bytes_read != size) { 212d5ac70f0Sopenharmony_ci ret = -errno; 213d5ac70f0Sopenharmony_ci goto err; 214d5ac70f0Sopenharmony_ci } 215d5ac70f0Sopenharmony_ci 216d5ac70f0Sopenharmony_ci elem->data = priv; 217d5ac70f0Sopenharmony_ci priv->size = size; 218d5ac70f0Sopenharmony_ci elem->size = sizeof(*priv) + size; 219d5ac70f0Sopenharmony_ci 220d5ac70f0Sopenharmony_ci if (fclose(fp) == EOF) { 221d5ac70f0Sopenharmony_ci SNDERR("Cannot close data file."); 222d5ac70f0Sopenharmony_ci return -errno; 223d5ac70f0Sopenharmony_ci } 224d5ac70f0Sopenharmony_ci return 0; 225d5ac70f0Sopenharmony_ci 226d5ac70f0Sopenharmony_cierr: 227d5ac70f0Sopenharmony_ci fclose(fp); 228d5ac70f0Sopenharmony_ci if (priv) 229d5ac70f0Sopenharmony_ci free(priv); 230d5ac70f0Sopenharmony_ci return ret; 231d5ac70f0Sopenharmony_ci} 232d5ac70f0Sopenharmony_ci 233d5ac70f0Sopenharmony_cistatic void dump_priv_data(struct tplg_elem *elem ATTRIBUTE_UNUSED) 234d5ac70f0Sopenharmony_ci{ 235d5ac70f0Sopenharmony_ci#ifdef TPLG_DEBUG 236d5ac70f0Sopenharmony_ci struct snd_soc_tplg_private *priv = elem->data; 237d5ac70f0Sopenharmony_ci unsigned char *p = (unsigned char *)priv->data; 238d5ac70f0Sopenharmony_ci char buf[128], buf2[8]; 239d5ac70f0Sopenharmony_ci unsigned int i; 240d5ac70f0Sopenharmony_ci 241d5ac70f0Sopenharmony_ci tplg_dbg(" elem size = %d, priv data size = %d", 242d5ac70f0Sopenharmony_ci elem->size, priv->size); 243d5ac70f0Sopenharmony_ci 244d5ac70f0Sopenharmony_ci buf[0] = '\0'; 245d5ac70f0Sopenharmony_ci for (i = 0; i < priv->size; i++) { 246d5ac70f0Sopenharmony_ci if (i > 0 && (i % 16) == 0) { 247d5ac70f0Sopenharmony_ci tplg_dbg("%s", buf); 248d5ac70f0Sopenharmony_ci buf[0] = '\0'; 249d5ac70f0Sopenharmony_ci } 250d5ac70f0Sopenharmony_ci 251d5ac70f0Sopenharmony_ci snprintf(buf2, sizeof(buf2), " %02x", *p++); 252d5ac70f0Sopenharmony_ci strcat(buf, buf2); 253d5ac70f0Sopenharmony_ci } 254d5ac70f0Sopenharmony_ci 255d5ac70f0Sopenharmony_ci if (buf[0]) 256d5ac70f0Sopenharmony_ci tplg_dbg("%s", buf); 257d5ac70f0Sopenharmony_ci#endif 258d5ac70f0Sopenharmony_ci} 259d5ac70f0Sopenharmony_ci 260d5ac70f0Sopenharmony_cistatic inline int check_nibble(unsigned char c) 261d5ac70f0Sopenharmony_ci{ 262d5ac70f0Sopenharmony_ci return (c >= '0' && c <= '9') || 263d5ac70f0Sopenharmony_ci (c >= 'a' && c <= 'f') || 264d5ac70f0Sopenharmony_ci (c >= 'A' && c <= 'F'); 265d5ac70f0Sopenharmony_ci} 266d5ac70f0Sopenharmony_ci 267d5ac70f0Sopenharmony_ci/* get number of hex value elements in CSV list */ 268d5ac70f0Sopenharmony_cistatic int get_hex_num(const char *str) 269d5ac70f0Sopenharmony_ci{ 270d5ac70f0Sopenharmony_ci int delims, values, len = strlen(str); 271d5ac70f0Sopenharmony_ci const char *s, *end = str + len; 272d5ac70f0Sopenharmony_ci 273d5ac70f0Sopenharmony_ci /* check "aa:bb:00" syntax */ 274d5ac70f0Sopenharmony_ci s = str; 275d5ac70f0Sopenharmony_ci delims = values = 0; 276d5ac70f0Sopenharmony_ci while (s < end) { 277d5ac70f0Sopenharmony_ci /* skip white space */ 278d5ac70f0Sopenharmony_ci if (isspace(*s)) { 279d5ac70f0Sopenharmony_ci s++; 280d5ac70f0Sopenharmony_ci continue; 281d5ac70f0Sopenharmony_ci } 282d5ac70f0Sopenharmony_ci /* find delimeters */ 283d5ac70f0Sopenharmony_ci if (*s == ':') { 284d5ac70f0Sopenharmony_ci delims++; 285d5ac70f0Sopenharmony_ci s++; 286d5ac70f0Sopenharmony_ci continue; 287d5ac70f0Sopenharmony_ci } 288d5ac70f0Sopenharmony_ci /* check 00 hexadecimal value */ 289d5ac70f0Sopenharmony_ci if (s + 1 <= end) { 290d5ac70f0Sopenharmony_ci if (check_nibble(s[0]) && check_nibble(s[1])) { 291d5ac70f0Sopenharmony_ci values++; 292d5ac70f0Sopenharmony_ci } else { 293d5ac70f0Sopenharmony_ci goto format2; 294d5ac70f0Sopenharmony_ci } 295d5ac70f0Sopenharmony_ci s++; 296d5ac70f0Sopenharmony_ci } 297d5ac70f0Sopenharmony_ci s++; 298d5ac70f0Sopenharmony_ci } 299d5ac70f0Sopenharmony_ci goto end; 300d5ac70f0Sopenharmony_ci 301d5ac70f0Sopenharmony_ciformat2: 302d5ac70f0Sopenharmony_ci /* we expect "0x0, 0x0, 0x0" */ 303d5ac70f0Sopenharmony_ci s = str; 304d5ac70f0Sopenharmony_ci delims = values = 0; 305d5ac70f0Sopenharmony_ci while (s < end) { 306d5ac70f0Sopenharmony_ci 307d5ac70f0Sopenharmony_ci /* skip white space */ 308d5ac70f0Sopenharmony_ci if (isspace(*s)) { 309d5ac70f0Sopenharmony_ci s++; 310d5ac70f0Sopenharmony_ci continue; 311d5ac70f0Sopenharmony_ci } 312d5ac70f0Sopenharmony_ci 313d5ac70f0Sopenharmony_ci /* find delimeters */ 314d5ac70f0Sopenharmony_ci if (*s == ',') { 315d5ac70f0Sopenharmony_ci delims++; 316d5ac70f0Sopenharmony_ci s++; 317d5ac70f0Sopenharmony_ci continue; 318d5ac70f0Sopenharmony_ci } 319d5ac70f0Sopenharmony_ci 320d5ac70f0Sopenharmony_ci /* find 0x[0-9] values */ 321d5ac70f0Sopenharmony_ci if (*s == '0' && s + 2 <= end) { 322d5ac70f0Sopenharmony_ci if (s[1] == 'x' && check_nibble(s[2])) { 323d5ac70f0Sopenharmony_ci if (check_nibble(s[3])) 324d5ac70f0Sopenharmony_ci s++; 325d5ac70f0Sopenharmony_ci values++; 326d5ac70f0Sopenharmony_ci s += 2; 327d5ac70f0Sopenharmony_ci } 328d5ac70f0Sopenharmony_ci } 329d5ac70f0Sopenharmony_ci 330d5ac70f0Sopenharmony_ci s++; 331d5ac70f0Sopenharmony_ci } 332d5ac70f0Sopenharmony_ci 333d5ac70f0Sopenharmony_ciend: 334d5ac70f0Sopenharmony_ci /* there should always be one less comma than value */ 335d5ac70f0Sopenharmony_ci if (values - 1 != delims) 336d5ac70f0Sopenharmony_ci return -EINVAL; 337d5ac70f0Sopenharmony_ci 338d5ac70f0Sopenharmony_ci return values; 339d5ac70f0Sopenharmony_ci} 340d5ac70f0Sopenharmony_ci 341d5ac70f0Sopenharmony_ci/* get uuid from a string made by 16 characters separated by commas */ 342d5ac70f0Sopenharmony_cistatic int get_uuid(const char *str, unsigned char *uuid_le) 343d5ac70f0Sopenharmony_ci{ 344d5ac70f0Sopenharmony_ci unsigned long int val; 345d5ac70f0Sopenharmony_ci char *tmp, *s = NULL; 346d5ac70f0Sopenharmony_ci int values = 0, ret = 0; 347d5ac70f0Sopenharmony_ci 348d5ac70f0Sopenharmony_ci tmp = strdup(str); 349d5ac70f0Sopenharmony_ci if (tmp == NULL) 350d5ac70f0Sopenharmony_ci return -ENOMEM; 351d5ac70f0Sopenharmony_ci 352d5ac70f0Sopenharmony_ci if (strchr(tmp, ':') == NULL) 353d5ac70f0Sopenharmony_ci goto data2; 354d5ac70f0Sopenharmony_ci 355d5ac70f0Sopenharmony_ci s = strtok(tmp, ":"); 356d5ac70f0Sopenharmony_ci while (s != NULL) { 357d5ac70f0Sopenharmony_ci errno = 0; 358d5ac70f0Sopenharmony_ci val = strtoul(s, NULL, 16); 359d5ac70f0Sopenharmony_ci if ((errno == ERANGE && val == ULONG_MAX) 360d5ac70f0Sopenharmony_ci || (errno != 0 && val == 0) 361d5ac70f0Sopenharmony_ci || (val > UCHAR_MAX)) { 362d5ac70f0Sopenharmony_ci SNDERR("invalid value for uuid"); 363d5ac70f0Sopenharmony_ci ret = -EINVAL; 364d5ac70f0Sopenharmony_ci goto out; 365d5ac70f0Sopenharmony_ci } 366d5ac70f0Sopenharmony_ci 367d5ac70f0Sopenharmony_ci *(uuid_le + values) = (unsigned char)val; 368d5ac70f0Sopenharmony_ci 369d5ac70f0Sopenharmony_ci values++; 370d5ac70f0Sopenharmony_ci if (values >= 16) 371d5ac70f0Sopenharmony_ci break; 372d5ac70f0Sopenharmony_ci 373d5ac70f0Sopenharmony_ci s = strtok(NULL, ":"); 374d5ac70f0Sopenharmony_ci } 375d5ac70f0Sopenharmony_ci goto out; 376d5ac70f0Sopenharmony_ci 377d5ac70f0Sopenharmony_cidata2: 378d5ac70f0Sopenharmony_ci s = strtok(tmp, ","); 379d5ac70f0Sopenharmony_ci 380d5ac70f0Sopenharmony_ci while (s != NULL) { 381d5ac70f0Sopenharmony_ci errno = 0; 382d5ac70f0Sopenharmony_ci val = strtoul(s, NULL, 0); 383d5ac70f0Sopenharmony_ci if ((errno == ERANGE && val == ULONG_MAX) 384d5ac70f0Sopenharmony_ci || (errno != 0 && val == 0) 385d5ac70f0Sopenharmony_ci || (val > UCHAR_MAX)) { 386d5ac70f0Sopenharmony_ci SNDERR("invalid value for uuid"); 387d5ac70f0Sopenharmony_ci ret = -EINVAL; 388d5ac70f0Sopenharmony_ci goto out; 389d5ac70f0Sopenharmony_ci } 390d5ac70f0Sopenharmony_ci 391d5ac70f0Sopenharmony_ci *(uuid_le + values) = (unsigned char)val; 392d5ac70f0Sopenharmony_ci 393d5ac70f0Sopenharmony_ci values++; 394d5ac70f0Sopenharmony_ci if (values >= 16) 395d5ac70f0Sopenharmony_ci break; 396d5ac70f0Sopenharmony_ci 397d5ac70f0Sopenharmony_ci s = strtok(NULL, ","); 398d5ac70f0Sopenharmony_ci } 399d5ac70f0Sopenharmony_ci 400d5ac70f0Sopenharmony_ci if (values < 16) { 401d5ac70f0Sopenharmony_ci SNDERR("less than 16 integers for uuid"); 402d5ac70f0Sopenharmony_ci ret = -EINVAL; 403d5ac70f0Sopenharmony_ci } 404d5ac70f0Sopenharmony_ci 405d5ac70f0Sopenharmony_ciout: 406d5ac70f0Sopenharmony_ci free(tmp); 407d5ac70f0Sopenharmony_ci return ret; 408d5ac70f0Sopenharmony_ci} 409d5ac70f0Sopenharmony_ci 410d5ac70f0Sopenharmony_cistatic int write_hex(char *buf, char *str, int width) 411d5ac70f0Sopenharmony_ci{ 412d5ac70f0Sopenharmony_ci long val; 413d5ac70f0Sopenharmony_ci void *p = &val; 414d5ac70f0Sopenharmony_ci 415d5ac70f0Sopenharmony_ci errno = 0; 416d5ac70f0Sopenharmony_ci if (safe_strtol_base(str, &val, 16) < 0) 417d5ac70f0Sopenharmony_ci return -EINVAL; 418d5ac70f0Sopenharmony_ci 419d5ac70f0Sopenharmony_ci switch (width) { 420d5ac70f0Sopenharmony_ci case 1: 421d5ac70f0Sopenharmony_ci *(unsigned char *)buf = *(unsigned char *)p; 422d5ac70f0Sopenharmony_ci break; 423d5ac70f0Sopenharmony_ci case 2: 424d5ac70f0Sopenharmony_ci *(unsigned short *)buf = *(unsigned short *)p; 425d5ac70f0Sopenharmony_ci break; 426d5ac70f0Sopenharmony_ci case 4: 427d5ac70f0Sopenharmony_ci *(unsigned int *)buf = *(unsigned int *)p; 428d5ac70f0Sopenharmony_ci break; 429d5ac70f0Sopenharmony_ci default: 430d5ac70f0Sopenharmony_ci return -EINVAL; 431d5ac70f0Sopenharmony_ci } 432d5ac70f0Sopenharmony_ci 433d5ac70f0Sopenharmony_ci return 0; 434d5ac70f0Sopenharmony_ci} 435d5ac70f0Sopenharmony_ci 436d5ac70f0Sopenharmony_cistatic int copy_data_hex(char *data, int off, const char *str, int width) 437d5ac70f0Sopenharmony_ci{ 438d5ac70f0Sopenharmony_ci char *tmp, *s = NULL, *p = data; 439d5ac70f0Sopenharmony_ci int ret; 440d5ac70f0Sopenharmony_ci 441d5ac70f0Sopenharmony_ci tmp = strdup(str); 442d5ac70f0Sopenharmony_ci if (tmp == NULL) 443d5ac70f0Sopenharmony_ci return -ENOMEM; 444d5ac70f0Sopenharmony_ci 445d5ac70f0Sopenharmony_ci p += off; 446d5ac70f0Sopenharmony_ci s = strtok(tmp, ",:"); 447d5ac70f0Sopenharmony_ci 448d5ac70f0Sopenharmony_ci while (s != NULL) { 449d5ac70f0Sopenharmony_ci ret = write_hex(p, s, width); 450d5ac70f0Sopenharmony_ci if (ret < 0) { 451d5ac70f0Sopenharmony_ci free(tmp); 452d5ac70f0Sopenharmony_ci return ret; 453d5ac70f0Sopenharmony_ci } 454d5ac70f0Sopenharmony_ci 455d5ac70f0Sopenharmony_ci s = strtok(NULL, ",:"); 456d5ac70f0Sopenharmony_ci p += width; 457d5ac70f0Sopenharmony_ci } 458d5ac70f0Sopenharmony_ci 459d5ac70f0Sopenharmony_ci free(tmp); 460d5ac70f0Sopenharmony_ci return 0; 461d5ac70f0Sopenharmony_ci} 462d5ac70f0Sopenharmony_ci 463d5ac70f0Sopenharmony_cistatic int tplg_parse_data_hex(snd_config_t *cfg, struct tplg_elem *elem, 464d5ac70f0Sopenharmony_ci int width) 465d5ac70f0Sopenharmony_ci{ 466d5ac70f0Sopenharmony_ci struct snd_soc_tplg_private *priv; 467d5ac70f0Sopenharmony_ci const char *value = NULL; 468d5ac70f0Sopenharmony_ci int size, esize, off, num; 469d5ac70f0Sopenharmony_ci int ret; 470d5ac70f0Sopenharmony_ci 471d5ac70f0Sopenharmony_ci tplg_dbg(" data: %s", elem->id); 472d5ac70f0Sopenharmony_ci 473d5ac70f0Sopenharmony_ci if (snd_config_get_string(cfg, &value) < 0) 474d5ac70f0Sopenharmony_ci return -EINVAL; 475d5ac70f0Sopenharmony_ci 476d5ac70f0Sopenharmony_ci num = get_hex_num(value); 477d5ac70f0Sopenharmony_ci if (num <= 0) { 478d5ac70f0Sopenharmony_ci SNDERR("malformed hex variable list %s", value); 479d5ac70f0Sopenharmony_ci return -EINVAL; 480d5ac70f0Sopenharmony_ci } 481d5ac70f0Sopenharmony_ci 482d5ac70f0Sopenharmony_ci size = num * width; 483d5ac70f0Sopenharmony_ci priv = elem->data; 484d5ac70f0Sopenharmony_ci 485d5ac70f0Sopenharmony_ci if (size > TPLG_MAX_PRIV_SIZE) { 486d5ac70f0Sopenharmony_ci SNDERR("data too big %d", size); 487d5ac70f0Sopenharmony_ci return -EINVAL; 488d5ac70f0Sopenharmony_ci } 489d5ac70f0Sopenharmony_ci 490d5ac70f0Sopenharmony_ci if (priv != NULL) { 491d5ac70f0Sopenharmony_ci off = priv->size; 492d5ac70f0Sopenharmony_ci esize = elem->size + size; 493d5ac70f0Sopenharmony_ci priv = realloc(priv, esize); 494d5ac70f0Sopenharmony_ci } else { 495d5ac70f0Sopenharmony_ci off = 0; 496d5ac70f0Sopenharmony_ci esize = sizeof(*priv) + size; 497d5ac70f0Sopenharmony_ci priv = calloc(1, esize); 498d5ac70f0Sopenharmony_ci } 499d5ac70f0Sopenharmony_ci 500d5ac70f0Sopenharmony_ci if (!priv) 501d5ac70f0Sopenharmony_ci return -ENOMEM; 502d5ac70f0Sopenharmony_ci 503d5ac70f0Sopenharmony_ci elem->data = priv; 504d5ac70f0Sopenharmony_ci priv->size += size; 505d5ac70f0Sopenharmony_ci elem->size = esize; 506d5ac70f0Sopenharmony_ci 507d5ac70f0Sopenharmony_ci ret = copy_data_hex(priv->data, off, value, width); 508d5ac70f0Sopenharmony_ci 509d5ac70f0Sopenharmony_ci dump_priv_data(elem); 510d5ac70f0Sopenharmony_ci return ret; 511d5ac70f0Sopenharmony_ci} 512d5ac70f0Sopenharmony_ci 513d5ac70f0Sopenharmony_ci/* get the token integer value from its id */ 514d5ac70f0Sopenharmony_cistatic int get_token_value(const char *token_id, 515d5ac70f0Sopenharmony_ci struct tplg_vendor_tokens *tokens) 516d5ac70f0Sopenharmony_ci{ 517d5ac70f0Sopenharmony_ci unsigned int i; 518d5ac70f0Sopenharmony_ci 519d5ac70f0Sopenharmony_ci for (i = 0; i < tokens->num_tokens; i++) { 520d5ac70f0Sopenharmony_ci if (strcmp(token_id, tokens->token[i].id) == 0) 521d5ac70f0Sopenharmony_ci return tokens->token[i].value; 522d5ac70f0Sopenharmony_ci } 523d5ac70f0Sopenharmony_ci 524d5ac70f0Sopenharmony_ci SNDERR("cannot find token id '%s'", token_id); 525d5ac70f0Sopenharmony_ci return -1; 526d5ac70f0Sopenharmony_ci} 527d5ac70f0Sopenharmony_ci 528d5ac70f0Sopenharmony_ci/* get the vendor tokens referred by the vendor tuples */ 529d5ac70f0Sopenharmony_cistatic struct tplg_elem *get_tokens(snd_tplg_t *tplg, struct tplg_elem *elem) 530d5ac70f0Sopenharmony_ci{ 531d5ac70f0Sopenharmony_ci struct tplg_ref *ref; 532d5ac70f0Sopenharmony_ci struct list_head *base, *pos; 533d5ac70f0Sopenharmony_ci 534d5ac70f0Sopenharmony_ci base = &elem->ref_list; 535d5ac70f0Sopenharmony_ci list_for_each(pos, base) { 536d5ac70f0Sopenharmony_ci 537d5ac70f0Sopenharmony_ci ref = list_entry(pos, struct tplg_ref, list); 538d5ac70f0Sopenharmony_ci 539d5ac70f0Sopenharmony_ci if (ref->type != SND_TPLG_TYPE_TOKEN) 540d5ac70f0Sopenharmony_ci continue; 541d5ac70f0Sopenharmony_ci 542d5ac70f0Sopenharmony_ci if (!ref->elem) { 543d5ac70f0Sopenharmony_ci ref->elem = tplg_elem_lookup(&tplg->token_list, 544d5ac70f0Sopenharmony_ci ref->id, SND_TPLG_TYPE_TOKEN, elem->index); 545d5ac70f0Sopenharmony_ci } 546d5ac70f0Sopenharmony_ci 547d5ac70f0Sopenharmony_ci return ref->elem; 548d5ac70f0Sopenharmony_ci } 549d5ac70f0Sopenharmony_ci 550d5ac70f0Sopenharmony_ci return NULL; 551d5ac70f0Sopenharmony_ci} 552d5ac70f0Sopenharmony_ci 553d5ac70f0Sopenharmony_ci/* check if a data element has tuples */ 554d5ac70f0Sopenharmony_cistatic bool has_tuples(struct tplg_elem *elem) 555d5ac70f0Sopenharmony_ci{ 556d5ac70f0Sopenharmony_ci struct tplg_ref *ref; 557d5ac70f0Sopenharmony_ci struct list_head *base, *pos; 558d5ac70f0Sopenharmony_ci 559d5ac70f0Sopenharmony_ci base = &elem->ref_list; 560d5ac70f0Sopenharmony_ci list_for_each(pos, base) { 561d5ac70f0Sopenharmony_ci 562d5ac70f0Sopenharmony_ci ref = list_entry(pos, struct tplg_ref, list); 563d5ac70f0Sopenharmony_ci if (ref->type == SND_TPLG_TYPE_TUPLE) 564d5ac70f0Sopenharmony_ci return true; 565d5ac70f0Sopenharmony_ci } 566d5ac70f0Sopenharmony_ci 567d5ac70f0Sopenharmony_ci return false; 568d5ac70f0Sopenharmony_ci} 569d5ac70f0Sopenharmony_ci 570d5ac70f0Sopenharmony_ci/* get size of a tuple element from its type */ 571d5ac70f0Sopenharmony_ciunsigned int tplg_get_tuple_size(int type) 572d5ac70f0Sopenharmony_ci{ 573d5ac70f0Sopenharmony_ci switch (type) { 574d5ac70f0Sopenharmony_ci 575d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_UUID: 576d5ac70f0Sopenharmony_ci return sizeof(struct snd_soc_tplg_vendor_uuid_elem); 577d5ac70f0Sopenharmony_ci 578d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_STRING: 579d5ac70f0Sopenharmony_ci return sizeof(struct snd_soc_tplg_vendor_string_elem); 580d5ac70f0Sopenharmony_ci 581d5ac70f0Sopenharmony_ci default: 582d5ac70f0Sopenharmony_ci return sizeof(struct snd_soc_tplg_vendor_value_elem); 583d5ac70f0Sopenharmony_ci } 584d5ac70f0Sopenharmony_ci} 585d5ac70f0Sopenharmony_ci 586d5ac70f0Sopenharmony_ci/* Add a tuples object to the private buffer of its parent data element */ 587d5ac70f0Sopenharmony_cistatic int copy_tuples(struct tplg_elem *elem, 588d5ac70f0Sopenharmony_ci struct tplg_vendor_tuples *tuples, 589d5ac70f0Sopenharmony_ci struct tplg_vendor_tokens *tokens) 590d5ac70f0Sopenharmony_ci{ 591d5ac70f0Sopenharmony_ci struct snd_soc_tplg_private *priv = elem->data, *priv2; 592d5ac70f0Sopenharmony_ci struct tplg_tuple_set *tuple_set; 593d5ac70f0Sopenharmony_ci struct tplg_tuple *tuple; 594d5ac70f0Sopenharmony_ci struct snd_soc_tplg_vendor_array *array; 595d5ac70f0Sopenharmony_ci struct snd_soc_tplg_vendor_uuid_elem *uuid; 596d5ac70f0Sopenharmony_ci struct snd_soc_tplg_vendor_string_elem *string; 597d5ac70f0Sopenharmony_ci struct snd_soc_tplg_vendor_value_elem *value; 598d5ac70f0Sopenharmony_ci int set_size, size, off; 599d5ac70f0Sopenharmony_ci unsigned int i, j; 600d5ac70f0Sopenharmony_ci int token_val; 601d5ac70f0Sopenharmony_ci 602d5ac70f0Sopenharmony_ci size = priv ? priv->size : 0; /* original private data size */ 603d5ac70f0Sopenharmony_ci 604d5ac70f0Sopenharmony_ci /* scan each tuples set (one set per type) */ 605d5ac70f0Sopenharmony_ci for (i = 0; i < tuples->num_sets ; i++) { 606d5ac70f0Sopenharmony_ci tuple_set = tuples->set[i]; 607d5ac70f0Sopenharmony_ci set_size = sizeof(struct snd_soc_tplg_vendor_array) 608d5ac70f0Sopenharmony_ci + tplg_get_tuple_size(tuple_set->type) 609d5ac70f0Sopenharmony_ci * tuple_set->num_tuples; 610d5ac70f0Sopenharmony_ci size += set_size; 611d5ac70f0Sopenharmony_ci if (size > TPLG_MAX_PRIV_SIZE) { 612d5ac70f0Sopenharmony_ci SNDERR("data too big %d", size); 613d5ac70f0Sopenharmony_ci return -EINVAL; 614d5ac70f0Sopenharmony_ci } 615d5ac70f0Sopenharmony_ci 616d5ac70f0Sopenharmony_ci if (priv != NULL) { 617d5ac70f0Sopenharmony_ci priv2 = realloc(priv, sizeof(*priv) + size); 618d5ac70f0Sopenharmony_ci if (priv2 == NULL) { 619d5ac70f0Sopenharmony_ci free(priv); 620d5ac70f0Sopenharmony_ci priv = NULL; 621d5ac70f0Sopenharmony_ci } else { 622d5ac70f0Sopenharmony_ci priv = priv2; 623d5ac70f0Sopenharmony_ci } 624d5ac70f0Sopenharmony_ci } else { 625d5ac70f0Sopenharmony_ci priv = calloc(1, sizeof(*priv) + size); 626d5ac70f0Sopenharmony_ci } 627d5ac70f0Sopenharmony_ci if (!priv) 628d5ac70f0Sopenharmony_ci return -ENOMEM; 629d5ac70f0Sopenharmony_ci 630d5ac70f0Sopenharmony_ci off = priv->size; 631d5ac70f0Sopenharmony_ci priv->size = size; /* update private data size */ 632d5ac70f0Sopenharmony_ci elem->data = priv; 633d5ac70f0Sopenharmony_ci 634d5ac70f0Sopenharmony_ci array = (struct snd_soc_tplg_vendor_array *)(priv->data + off); 635d5ac70f0Sopenharmony_ci memset(array, 0, set_size); 636d5ac70f0Sopenharmony_ci array->size = set_size; 637d5ac70f0Sopenharmony_ci array->type = tuple_set->type; 638d5ac70f0Sopenharmony_ci array->num_elems = tuple_set->num_tuples; 639d5ac70f0Sopenharmony_ci 640d5ac70f0Sopenharmony_ci /* fill the private data buffer */ 641d5ac70f0Sopenharmony_ci for (j = 0; j < tuple_set->num_tuples; j++) { 642d5ac70f0Sopenharmony_ci tuple = &tuple_set->tuple[j]; 643d5ac70f0Sopenharmony_ci token_val = get_token_value(tuple->token, tokens); 644d5ac70f0Sopenharmony_ci if (token_val < 0) 645d5ac70f0Sopenharmony_ci return -EINVAL; 646d5ac70f0Sopenharmony_ci 647d5ac70f0Sopenharmony_ci switch (tuple_set->type) { 648d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_UUID: 649d5ac70f0Sopenharmony_ci uuid = &array->uuid[j]; 650d5ac70f0Sopenharmony_ci uuid->token = token_val; 651d5ac70f0Sopenharmony_ci memcpy(uuid->uuid, tuple->uuid, 16); 652d5ac70f0Sopenharmony_ci break; 653d5ac70f0Sopenharmony_ci 654d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_STRING: 655d5ac70f0Sopenharmony_ci string = &array->string[j]; 656d5ac70f0Sopenharmony_ci string->token = token_val; 657d5ac70f0Sopenharmony_ci snd_strlcpy(string->string, tuple->string, 658d5ac70f0Sopenharmony_ci SNDRV_CTL_ELEM_ID_NAME_MAXLEN); 659d5ac70f0Sopenharmony_ci break; 660d5ac70f0Sopenharmony_ci 661d5ac70f0Sopenharmony_ci default: 662d5ac70f0Sopenharmony_ci value = &array->value[j]; 663d5ac70f0Sopenharmony_ci value->token = token_val; 664d5ac70f0Sopenharmony_ci value->value = tuple->value; 665d5ac70f0Sopenharmony_ci break; 666d5ac70f0Sopenharmony_ci } 667d5ac70f0Sopenharmony_ci } 668d5ac70f0Sopenharmony_ci } 669d5ac70f0Sopenharmony_ci 670d5ac70f0Sopenharmony_ci return 0; 671d5ac70f0Sopenharmony_ci} 672d5ac70f0Sopenharmony_ci 673d5ac70f0Sopenharmony_ci/* build a data element from its tuples */ 674d5ac70f0Sopenharmony_cistatic int build_tuples(snd_tplg_t *tplg, struct tplg_elem *elem) 675d5ac70f0Sopenharmony_ci{ 676d5ac70f0Sopenharmony_ci struct tplg_ref *ref; 677d5ac70f0Sopenharmony_ci struct list_head *base, *pos; 678d5ac70f0Sopenharmony_ci struct tplg_elem *tuples, *tokens; 679d5ac70f0Sopenharmony_ci int err; 680d5ac70f0Sopenharmony_ci 681d5ac70f0Sopenharmony_ci base = &elem->ref_list; 682d5ac70f0Sopenharmony_ci list_for_each(pos, base) { 683d5ac70f0Sopenharmony_ci 684d5ac70f0Sopenharmony_ci ref = list_entry(pos, struct tplg_ref, list); 685d5ac70f0Sopenharmony_ci 686d5ac70f0Sopenharmony_ci if (ref->type != SND_TPLG_TYPE_TUPLE) 687d5ac70f0Sopenharmony_ci continue; 688d5ac70f0Sopenharmony_ci 689d5ac70f0Sopenharmony_ci tplg_dbg("tuples '%s' used by data '%s'", ref->id, elem->id); 690d5ac70f0Sopenharmony_ci 691d5ac70f0Sopenharmony_ci if (!ref->elem) 692d5ac70f0Sopenharmony_ci ref->elem = tplg_elem_lookup(&tplg->tuple_list, 693d5ac70f0Sopenharmony_ci ref->id, SND_TPLG_TYPE_TUPLE, elem->index); 694d5ac70f0Sopenharmony_ci tuples = ref->elem; 695d5ac70f0Sopenharmony_ci if (!tuples) { 696d5ac70f0Sopenharmony_ci SNDERR("cannot find tuples %s", ref->id); 697d5ac70f0Sopenharmony_ci return -EINVAL; 698d5ac70f0Sopenharmony_ci } 699d5ac70f0Sopenharmony_ci 700d5ac70f0Sopenharmony_ci tokens = get_tokens(tplg, tuples); 701d5ac70f0Sopenharmony_ci if (!tokens) { 702d5ac70f0Sopenharmony_ci SNDERR("cannot find token for %s", ref->id); 703d5ac70f0Sopenharmony_ci return -EINVAL; 704d5ac70f0Sopenharmony_ci } 705d5ac70f0Sopenharmony_ci 706d5ac70f0Sopenharmony_ci /* a data object can have multiple tuples objects */ 707d5ac70f0Sopenharmony_ci err = copy_tuples(elem, tuples->tuples, tokens->tokens); 708d5ac70f0Sopenharmony_ci if (err < 0) 709d5ac70f0Sopenharmony_ci return err; 710d5ac70f0Sopenharmony_ci } 711d5ac70f0Sopenharmony_ci 712d5ac70f0Sopenharmony_ci return 0; 713d5ac70f0Sopenharmony_ci} 714d5ac70f0Sopenharmony_ci 715d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 716d5ac70f0Sopenharmony_cistruct tuple_type { 717d5ac70f0Sopenharmony_ci unsigned int type; 718d5ac70f0Sopenharmony_ci const char *name; 719d5ac70f0Sopenharmony_ci unsigned int size; 720d5ac70f0Sopenharmony_ci}; 721d5ac70f0Sopenharmony_ci#endif /* DOC_HIDDEN */ 722d5ac70f0Sopenharmony_ci 723d5ac70f0Sopenharmony_cistatic struct tuple_type tuple_types[] = { 724d5ac70f0Sopenharmony_ci { 725d5ac70f0Sopenharmony_ci .type = SND_SOC_TPLG_TUPLE_TYPE_UUID, 726d5ac70f0Sopenharmony_ci .name = "uuid", 727d5ac70f0Sopenharmony_ci .size = 4, 728d5ac70f0Sopenharmony_ci }, 729d5ac70f0Sopenharmony_ci { 730d5ac70f0Sopenharmony_ci .type = SND_SOC_TPLG_TUPLE_TYPE_STRING, 731d5ac70f0Sopenharmony_ci .name = "string", 732d5ac70f0Sopenharmony_ci .size = 6, 733d5ac70f0Sopenharmony_ci }, 734d5ac70f0Sopenharmony_ci { 735d5ac70f0Sopenharmony_ci .type = SND_SOC_TPLG_TUPLE_TYPE_BOOL, 736d5ac70f0Sopenharmony_ci .name = "bool", 737d5ac70f0Sopenharmony_ci .size = 4, 738d5ac70f0Sopenharmony_ci }, 739d5ac70f0Sopenharmony_ci { 740d5ac70f0Sopenharmony_ci .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE, 741d5ac70f0Sopenharmony_ci .name = "byte", 742d5ac70f0Sopenharmony_ci .size = 4, 743d5ac70f0Sopenharmony_ci }, 744d5ac70f0Sopenharmony_ci { 745d5ac70f0Sopenharmony_ci .type = SND_SOC_TPLG_TUPLE_TYPE_SHORT, 746d5ac70f0Sopenharmony_ci .name = "short", 747d5ac70f0Sopenharmony_ci .size = 5, 748d5ac70f0Sopenharmony_ci }, 749d5ac70f0Sopenharmony_ci { 750d5ac70f0Sopenharmony_ci .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, 751d5ac70f0Sopenharmony_ci .name = "word", 752d5ac70f0Sopenharmony_ci .size = 4 753d5ac70f0Sopenharmony_ci }, 754d5ac70f0Sopenharmony_ci}; 755d5ac70f0Sopenharmony_ci 756d5ac70f0Sopenharmony_cistatic int get_tuple_type(const char *name) 757d5ac70f0Sopenharmony_ci{ 758d5ac70f0Sopenharmony_ci struct tuple_type *t; 759d5ac70f0Sopenharmony_ci unsigned int i; 760d5ac70f0Sopenharmony_ci 761d5ac70f0Sopenharmony_ci /* skip initial index for sorting */ 762d5ac70f0Sopenharmony_ci while ((*name >= '0' && *name <= '9') || *name == '_') 763d5ac70f0Sopenharmony_ci name++; 764d5ac70f0Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(tuple_types); i++) { 765d5ac70f0Sopenharmony_ci t = &tuple_types[i]; 766d5ac70f0Sopenharmony_ci if (strncasecmp(t->name, name, t->size) == 0) 767d5ac70f0Sopenharmony_ci return t->type; 768d5ac70f0Sopenharmony_ci } 769d5ac70f0Sopenharmony_ci return -EINVAL; 770d5ac70f0Sopenharmony_ci} 771d5ac70f0Sopenharmony_ci 772d5ac70f0Sopenharmony_cistatic const char *get_tuple_type_name(unsigned int type) 773d5ac70f0Sopenharmony_ci{ 774d5ac70f0Sopenharmony_ci unsigned int i; 775d5ac70f0Sopenharmony_ci 776d5ac70f0Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(tuple_types); i++) 777d5ac70f0Sopenharmony_ci if (tuple_types[i].type == type) 778d5ac70f0Sopenharmony_ci return tuple_types[i].name; 779d5ac70f0Sopenharmony_ci return NULL; 780d5ac70f0Sopenharmony_ci} 781d5ac70f0Sopenharmony_ci 782d5ac70f0Sopenharmony_cistatic int parse_tuple_set(snd_config_t *cfg, 783d5ac70f0Sopenharmony_ci struct tplg_tuple_set **s) 784d5ac70f0Sopenharmony_ci{ 785d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 786d5ac70f0Sopenharmony_ci snd_config_t *n; 787d5ac70f0Sopenharmony_ci const char *id, *value; 788d5ac70f0Sopenharmony_ci struct tplg_tuple_set *set; 789d5ac70f0Sopenharmony_ci unsigned int num_tuples = 0; 790d5ac70f0Sopenharmony_ci struct tplg_tuple *tuple; 791d5ac70f0Sopenharmony_ci unsigned int tuple_val; 792d5ac70f0Sopenharmony_ci int type, ival; 793d5ac70f0Sopenharmony_ci 794d5ac70f0Sopenharmony_ci snd_config_get_id(cfg, &id); 795d5ac70f0Sopenharmony_ci 796d5ac70f0Sopenharmony_ci type = get_tuple_type(id); 797d5ac70f0Sopenharmony_ci if (type < 0) { 798d5ac70f0Sopenharmony_ci SNDERR("invalid tuple type '%s'", id); 799d5ac70f0Sopenharmony_ci return type; 800d5ac70f0Sopenharmony_ci } 801d5ac70f0Sopenharmony_ci 802d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) 803d5ac70f0Sopenharmony_ci num_tuples++; 804d5ac70f0Sopenharmony_ci if (!num_tuples) 805d5ac70f0Sopenharmony_ci return 0; 806d5ac70f0Sopenharmony_ci 807d5ac70f0Sopenharmony_ci tplg_dbg("\t %d %s tuples:", num_tuples, id); 808d5ac70f0Sopenharmony_ci set = calloc(1, sizeof(*set) + num_tuples * sizeof(struct tplg_tuple)); 809d5ac70f0Sopenharmony_ci if (!set) 810d5ac70f0Sopenharmony_ci return -ENOMEM; 811d5ac70f0Sopenharmony_ci 812d5ac70f0Sopenharmony_ci set->type = type; 813d5ac70f0Sopenharmony_ci 814d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 815d5ac70f0Sopenharmony_ci 816d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 817d5ac70f0Sopenharmony_ci 818d5ac70f0Sopenharmony_ci /* get id */ 819d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 820d5ac70f0Sopenharmony_ci continue; 821d5ac70f0Sopenharmony_ci 822d5ac70f0Sopenharmony_ci tuple = &set->tuple[set->num_tuples]; 823d5ac70f0Sopenharmony_ci snd_strlcpy(tuple->token, id, 824d5ac70f0Sopenharmony_ci SNDRV_CTL_ELEM_ID_NAME_MAXLEN); 825d5ac70f0Sopenharmony_ci 826d5ac70f0Sopenharmony_ci switch (type) { 827d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_UUID: 828d5ac70f0Sopenharmony_ci if (snd_config_get_string(n, &value) < 0) 829d5ac70f0Sopenharmony_ci continue; 830d5ac70f0Sopenharmony_ci if (get_uuid(value, tuple->uuid) < 0) 831d5ac70f0Sopenharmony_ci goto err; 832d5ac70f0Sopenharmony_ci break; 833d5ac70f0Sopenharmony_ci 834d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_STRING: 835d5ac70f0Sopenharmony_ci if (snd_config_get_string(n, &value) < 0) 836d5ac70f0Sopenharmony_ci continue; 837d5ac70f0Sopenharmony_ci snd_strlcpy(tuple->string, value, 838d5ac70f0Sopenharmony_ci SNDRV_CTL_ELEM_ID_NAME_MAXLEN); 839d5ac70f0Sopenharmony_ci tplg_dbg("\t\t%s = %s", tuple->token, tuple->string); 840d5ac70f0Sopenharmony_ci break; 841d5ac70f0Sopenharmony_ci 842d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_BOOL: 843d5ac70f0Sopenharmony_ci ival = snd_config_get_bool(n); 844d5ac70f0Sopenharmony_ci if (ival < 0) 845d5ac70f0Sopenharmony_ci continue; 846d5ac70f0Sopenharmony_ci tuple->value = ival; 847d5ac70f0Sopenharmony_ci tplg_dbg("\t\t%s = %d", tuple->token, tuple->value); 848d5ac70f0Sopenharmony_ci break; 849d5ac70f0Sopenharmony_ci 850d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_BYTE: 851d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_SHORT: 852d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_WORD: 853d5ac70f0Sopenharmony_ci ival = tplg_get_unsigned(n, &tuple_val, 0); 854d5ac70f0Sopenharmony_ci if (ival < 0) { 855d5ac70f0Sopenharmony_ci SNDERR("tuple %s: %s", id, snd_strerror(ival)); 856d5ac70f0Sopenharmony_ci goto err; 857d5ac70f0Sopenharmony_ci } 858d5ac70f0Sopenharmony_ci 859d5ac70f0Sopenharmony_ci if (/* (type == SND_SOC_TPLG_TUPLE_TYPE_WORD 860d5ac70f0Sopenharmony_ci && tuple_val > UINT_MAX) || */ 861d5ac70f0Sopenharmony_ci (type == SND_SOC_TPLG_TUPLE_TYPE_SHORT 862d5ac70f0Sopenharmony_ci && tuple_val > USHRT_MAX) || 863d5ac70f0Sopenharmony_ci (type == SND_SOC_TPLG_TUPLE_TYPE_BYTE 864d5ac70f0Sopenharmony_ci && tuple_val > UCHAR_MAX)) { 865d5ac70f0Sopenharmony_ci SNDERR("tuple %s: invalid value", id); 866d5ac70f0Sopenharmony_ci goto err; 867d5ac70f0Sopenharmony_ci } 868d5ac70f0Sopenharmony_ci 869d5ac70f0Sopenharmony_ci tuple->value = tuple_val; 870d5ac70f0Sopenharmony_ci tplg_dbg("\t\t%s = 0x%x", tuple->token, tuple->value); 871d5ac70f0Sopenharmony_ci break; 872d5ac70f0Sopenharmony_ci 873d5ac70f0Sopenharmony_ci default: 874d5ac70f0Sopenharmony_ci break; 875d5ac70f0Sopenharmony_ci } 876d5ac70f0Sopenharmony_ci 877d5ac70f0Sopenharmony_ci set->num_tuples++; 878d5ac70f0Sopenharmony_ci } 879d5ac70f0Sopenharmony_ci 880d5ac70f0Sopenharmony_ci *s = set; 881d5ac70f0Sopenharmony_ci return 0; 882d5ac70f0Sopenharmony_ci 883d5ac70f0Sopenharmony_cierr: 884d5ac70f0Sopenharmony_ci free(set); 885d5ac70f0Sopenharmony_ci return -EINVAL; 886d5ac70f0Sopenharmony_ci} 887d5ac70f0Sopenharmony_ci 888d5ac70f0Sopenharmony_ci/* save tuple set */ 889d5ac70f0Sopenharmony_cistatic int tplg_save_tuple_set(struct tplg_vendor_tuples *tuples, 890d5ac70f0Sopenharmony_ci unsigned int set_index, 891d5ac70f0Sopenharmony_ci struct tplg_buf *dst, const char *pfx) 892d5ac70f0Sopenharmony_ci{ 893d5ac70f0Sopenharmony_ci struct tplg_tuple_set *set; 894d5ac70f0Sopenharmony_ci struct tplg_tuple *tuple; 895d5ac70f0Sopenharmony_ci const char *s, *fmt; 896d5ac70f0Sopenharmony_ci char buf[32]; 897d5ac70f0Sopenharmony_ci unsigned int i; 898d5ac70f0Sopenharmony_ci int err; 899d5ac70f0Sopenharmony_ci 900d5ac70f0Sopenharmony_ci set = tuples->set[set_index]; 901d5ac70f0Sopenharmony_ci if (set->num_tuples == 0) 902d5ac70f0Sopenharmony_ci return 0; 903d5ac70f0Sopenharmony_ci s = get_tuple_type_name(set->type); 904d5ac70f0Sopenharmony_ci if (s == NULL) 905d5ac70f0Sopenharmony_ci return -EINVAL; 906d5ac70f0Sopenharmony_ci if (tuples->num_sets < 10) 907d5ac70f0Sopenharmony_ci fmt = "%u_"; 908d5ac70f0Sopenharmony_ci else if (tuples->num_sets < 100) 909d5ac70f0Sopenharmony_ci fmt = "%02u_"; 910d5ac70f0Sopenharmony_ci else if (tuples->num_sets < 1000) 911d5ac70f0Sopenharmony_ci fmt = "%03u_"; 912d5ac70f0Sopenharmony_ci else 913d5ac70f0Sopenharmony_ci return -EINVAL; 914d5ac70f0Sopenharmony_ci if (set->num_tuples > 1) { 915d5ac70f0Sopenharmony_ci snprintf(buf, sizeof(buf), "tuples.%s%%s {\n", fmt); 916d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, buf, set_index, s); 917d5ac70f0Sopenharmony_ci if (err < 0) 918d5ac70f0Sopenharmony_ci return err; 919d5ac70f0Sopenharmony_ci } 920d5ac70f0Sopenharmony_ci for (i = 0; i < set->num_tuples; i++) { 921d5ac70f0Sopenharmony_ci tuple = &set->tuple[i]; 922d5ac70f0Sopenharmony_ci if (set->num_tuples == 1) { 923d5ac70f0Sopenharmony_ci snprintf(buf, sizeof(buf), "tuples.%s%%s.'%%s' ", fmt); 924d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, buf, 925d5ac70f0Sopenharmony_ci set_index, s, tuple->token); 926d5ac70f0Sopenharmony_ci } else { 927d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "\t'%s' ", 928d5ac70f0Sopenharmony_ci tuple->token); 929d5ac70f0Sopenharmony_ci } 930d5ac70f0Sopenharmony_ci if (err < 0) 931d5ac70f0Sopenharmony_ci return err; 932d5ac70f0Sopenharmony_ci switch (set->type) { 933d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_UUID: 934d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, "'" UUID_FORMAT "'\n", 935d5ac70f0Sopenharmony_ci tuple->uuid[0], tuple->uuid[1], 936d5ac70f0Sopenharmony_ci tuple->uuid[2], tuple->uuid[3], 937d5ac70f0Sopenharmony_ci tuple->uuid[4], tuple->uuid[5], 938d5ac70f0Sopenharmony_ci tuple->uuid[6], tuple->uuid[7], 939d5ac70f0Sopenharmony_ci tuple->uuid[8], tuple->uuid[9], 940d5ac70f0Sopenharmony_ci tuple->uuid[10], tuple->uuid[11], 941d5ac70f0Sopenharmony_ci tuple->uuid[12], tuple->uuid[13], 942d5ac70f0Sopenharmony_ci tuple->uuid[14], tuple->uuid[15]); 943d5ac70f0Sopenharmony_ci break; 944d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_STRING: 945d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, "'%s'\n", 946d5ac70f0Sopenharmony_ci tuple->string); 947d5ac70f0Sopenharmony_ci break; 948d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_BOOL: 949d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_BYTE: 950d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_SHORT: 951d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, "%u\n", tuple->value); 952d5ac70f0Sopenharmony_ci break; 953d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_WORD: 954d5ac70f0Sopenharmony_ci tplg_nice_value_format(buf, sizeof(buf), tuple->value); 955d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, "%s\n", buf); 956d5ac70f0Sopenharmony_ci break; 957d5ac70f0Sopenharmony_ci default: 958d5ac70f0Sopenharmony_ci return -EINVAL; 959d5ac70f0Sopenharmony_ci } 960d5ac70f0Sopenharmony_ci if (err < 0) 961d5ac70f0Sopenharmony_ci return err; 962d5ac70f0Sopenharmony_ci } 963d5ac70f0Sopenharmony_ci if (set->num_tuples > 1) 964d5ac70f0Sopenharmony_ci return tplg_save_printf(dst, pfx, "}\n"); 965d5ac70f0Sopenharmony_ci return 0; 966d5ac70f0Sopenharmony_ci} 967d5ac70f0Sopenharmony_ci 968d5ac70f0Sopenharmony_cistatic int parse_tuple_sets(snd_config_t *cfg, 969d5ac70f0Sopenharmony_ci struct tplg_vendor_tuples *tuples) 970d5ac70f0Sopenharmony_ci{ 971d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 972d5ac70f0Sopenharmony_ci snd_config_t *n; 973d5ac70f0Sopenharmony_ci const char *id; 974d5ac70f0Sopenharmony_ci unsigned int num_tuple_sets = 0; 975d5ac70f0Sopenharmony_ci int err; 976d5ac70f0Sopenharmony_ci 977d5ac70f0Sopenharmony_ci if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 978d5ac70f0Sopenharmony_ci if (snd_config_get_id(cfg, &id) >= 0) 979d5ac70f0Sopenharmony_ci SNDERR("compound type expected for %s", id); 980d5ac70f0Sopenharmony_ci return -EINVAL; 981d5ac70f0Sopenharmony_ci } 982d5ac70f0Sopenharmony_ci 983d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 984d5ac70f0Sopenharmony_ci num_tuple_sets++; 985d5ac70f0Sopenharmony_ci } 986d5ac70f0Sopenharmony_ci 987d5ac70f0Sopenharmony_ci if (!num_tuple_sets) 988d5ac70f0Sopenharmony_ci return 0; 989d5ac70f0Sopenharmony_ci 990d5ac70f0Sopenharmony_ci tuples->set = calloc(1, num_tuple_sets * sizeof(void *)); 991d5ac70f0Sopenharmony_ci if (!tuples->set) 992d5ac70f0Sopenharmony_ci return -ENOMEM; 993d5ac70f0Sopenharmony_ci 994d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 995d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 996d5ac70f0Sopenharmony_ci if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { 997d5ac70f0Sopenharmony_ci SNDERR("compound type expected for %s, is %d", 998d5ac70f0Sopenharmony_ci id, snd_config_get_type(n)); 999d5ac70f0Sopenharmony_ci return -EINVAL; 1000d5ac70f0Sopenharmony_ci } 1001d5ac70f0Sopenharmony_ci 1002d5ac70f0Sopenharmony_ci err = parse_tuple_set(n, &tuples->set[tuples->num_sets]); 1003d5ac70f0Sopenharmony_ci if (err < 0) 1004d5ac70f0Sopenharmony_ci return err; 1005d5ac70f0Sopenharmony_ci 1006d5ac70f0Sopenharmony_ci /* overlook empty tuple sets */ 1007d5ac70f0Sopenharmony_ci if (tuples->set[tuples->num_sets]) 1008d5ac70f0Sopenharmony_ci tuples->num_sets++; 1009d5ac70f0Sopenharmony_ci } 1010d5ac70f0Sopenharmony_ci 1011d5ac70f0Sopenharmony_ci return 0; 1012d5ac70f0Sopenharmony_ci} 1013d5ac70f0Sopenharmony_ci 1014d5ac70f0Sopenharmony_ci/* save tuple sets */ 1015d5ac70f0Sopenharmony_ciint tplg_save_tuple_sets(snd_tplg_t *tplg ATTRIBUTE_UNUSED, 1016d5ac70f0Sopenharmony_ci struct tplg_elem *elem, 1017d5ac70f0Sopenharmony_ci struct tplg_buf *dst, const char *pfx) 1018d5ac70f0Sopenharmony_ci{ 1019d5ac70f0Sopenharmony_ci struct tplg_vendor_tuples *tuples = elem->tuples; 1020d5ac70f0Sopenharmony_ci unsigned int i; 1021d5ac70f0Sopenharmony_ci int err = 0; 1022d5ac70f0Sopenharmony_ci 1023d5ac70f0Sopenharmony_ci for (i = 0; i < tuples->num_sets; i++) { 1024d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, ""); 1025d5ac70f0Sopenharmony_ci if (err < 0) 1026d5ac70f0Sopenharmony_ci break; 1027d5ac70f0Sopenharmony_ci err = tplg_save_tuple_set(tuples, i, dst, pfx); 1028d5ac70f0Sopenharmony_ci if (err < 0) 1029d5ac70f0Sopenharmony_ci break; 1030d5ac70f0Sopenharmony_ci } 1031d5ac70f0Sopenharmony_ci return err; 1032d5ac70f0Sopenharmony_ci} 1033d5ac70f0Sopenharmony_ci 1034d5ac70f0Sopenharmony_ci/* Parse vendor tokens 1035d5ac70f0Sopenharmony_ci */ 1036d5ac70f0Sopenharmony_ciint tplg_parse_tokens(snd_tplg_t *tplg, snd_config_t *cfg, 1037d5ac70f0Sopenharmony_ci void *private ATTRIBUTE_UNUSED) 1038d5ac70f0Sopenharmony_ci{ 1039d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1040d5ac70f0Sopenharmony_ci snd_config_t *n; 1041d5ac70f0Sopenharmony_ci const char *id; 1042d5ac70f0Sopenharmony_ci struct tplg_elem *elem; 1043d5ac70f0Sopenharmony_ci struct tplg_vendor_tokens *tokens; 1044d5ac70f0Sopenharmony_ci int num_tokens = 0, value; 1045d5ac70f0Sopenharmony_ci 1046d5ac70f0Sopenharmony_ci elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_TOKEN); 1047d5ac70f0Sopenharmony_ci if (!elem) 1048d5ac70f0Sopenharmony_ci return -ENOMEM; 1049d5ac70f0Sopenharmony_ci 1050d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 1051d5ac70f0Sopenharmony_ci num_tokens++; 1052d5ac70f0Sopenharmony_ci } 1053d5ac70f0Sopenharmony_ci 1054d5ac70f0Sopenharmony_ci if (!num_tokens) 1055d5ac70f0Sopenharmony_ci return 0; 1056d5ac70f0Sopenharmony_ci 1057d5ac70f0Sopenharmony_ci tplg_dbg(" Vendor tokens: %s, %d tokens", elem->id, num_tokens); 1058d5ac70f0Sopenharmony_ci 1059d5ac70f0Sopenharmony_ci tokens = calloc(1, sizeof(*tokens) 1060d5ac70f0Sopenharmony_ci + num_tokens * sizeof(struct tplg_token)); 1061d5ac70f0Sopenharmony_ci if (!tokens) 1062d5ac70f0Sopenharmony_ci return -ENOMEM; 1063d5ac70f0Sopenharmony_ci elem->tokens = tokens; 1064d5ac70f0Sopenharmony_ci 1065d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 1066d5ac70f0Sopenharmony_ci 1067d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 1068d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 1069d5ac70f0Sopenharmony_ci continue; 1070d5ac70f0Sopenharmony_ci 1071d5ac70f0Sopenharmony_ci if (tplg_get_integer(n, &value, 0)) 1072d5ac70f0Sopenharmony_ci continue; 1073d5ac70f0Sopenharmony_ci 1074d5ac70f0Sopenharmony_ci snd_strlcpy(tokens->token[tokens->num_tokens].id, id, 1075d5ac70f0Sopenharmony_ci SNDRV_CTL_ELEM_ID_NAME_MAXLEN); 1076d5ac70f0Sopenharmony_ci tokens->token[tokens->num_tokens].value = value; 1077d5ac70f0Sopenharmony_ci tplg_dbg("\t\t %s : %d", tokens->token[tokens->num_tokens].id, 1078d5ac70f0Sopenharmony_ci tokens->token[tokens->num_tokens].value); 1079d5ac70f0Sopenharmony_ci tokens->num_tokens++; 1080d5ac70f0Sopenharmony_ci } 1081d5ac70f0Sopenharmony_ci 1082d5ac70f0Sopenharmony_ci return 0; 1083d5ac70f0Sopenharmony_ci} 1084d5ac70f0Sopenharmony_ci 1085d5ac70f0Sopenharmony_ci/* save vendor tokens */ 1086d5ac70f0Sopenharmony_ciint tplg_save_tokens(snd_tplg_t *tplg ATTRIBUTE_UNUSED, 1087d5ac70f0Sopenharmony_ci struct tplg_elem *elem, 1088d5ac70f0Sopenharmony_ci struct tplg_buf *dst, const char *pfx) 1089d5ac70f0Sopenharmony_ci{ 1090d5ac70f0Sopenharmony_ci struct tplg_vendor_tokens *tokens = elem->tokens; 1091d5ac70f0Sopenharmony_ci unsigned int i; 1092d5ac70f0Sopenharmony_ci int err; 1093d5ac70f0Sopenharmony_ci 1094d5ac70f0Sopenharmony_ci if (!tokens || tokens->num_tokens == 0) 1095d5ac70f0Sopenharmony_ci return 0; 1096d5ac70f0Sopenharmony_ci 1097d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id); 1098d5ac70f0Sopenharmony_ci if (err < 0) 1099d5ac70f0Sopenharmony_ci return err; 1100d5ac70f0Sopenharmony_ci for (i = 0; err >= 0 && i < tokens->num_tokens; i++) 1101d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "\t'%s' %u\n", 1102d5ac70f0Sopenharmony_ci tokens->token[i].id, 1103d5ac70f0Sopenharmony_ci tokens->token[i].value); 1104d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "}\n"); 1105d5ac70f0Sopenharmony_ci if (err < 0) 1106d5ac70f0Sopenharmony_ci return err; 1107d5ac70f0Sopenharmony_ci return 0; 1108d5ac70f0Sopenharmony_ci} 1109d5ac70f0Sopenharmony_ci 1110d5ac70f0Sopenharmony_ci/* Parse vendor tuples. 1111d5ac70f0Sopenharmony_ci */ 1112d5ac70f0Sopenharmony_ciint tplg_parse_tuples(snd_tplg_t *tplg, snd_config_t *cfg, 1113d5ac70f0Sopenharmony_ci void *private ATTRIBUTE_UNUSED) 1114d5ac70f0Sopenharmony_ci{ 1115d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1116d5ac70f0Sopenharmony_ci snd_config_t *n; 1117d5ac70f0Sopenharmony_ci const char *id, *value; 1118d5ac70f0Sopenharmony_ci struct tplg_elem *elem; 1119d5ac70f0Sopenharmony_ci struct tplg_vendor_tuples *tuples; 1120d5ac70f0Sopenharmony_ci int err; 1121d5ac70f0Sopenharmony_ci 1122d5ac70f0Sopenharmony_ci elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_TUPLE); 1123d5ac70f0Sopenharmony_ci if (!elem) 1124d5ac70f0Sopenharmony_ci return -ENOMEM; 1125d5ac70f0Sopenharmony_ci 1126d5ac70f0Sopenharmony_ci tplg_dbg(" Vendor Tuples: %s", elem->id); 1127d5ac70f0Sopenharmony_ci 1128d5ac70f0Sopenharmony_ci tuples = calloc(1, sizeof(*tuples)); 1129d5ac70f0Sopenharmony_ci if (!tuples) 1130d5ac70f0Sopenharmony_ci return -ENOMEM; 1131d5ac70f0Sopenharmony_ci elem->tuples = tuples; 1132d5ac70f0Sopenharmony_ci 1133d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 1134d5ac70f0Sopenharmony_ci 1135d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 1136d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 1137d5ac70f0Sopenharmony_ci continue; 1138d5ac70f0Sopenharmony_ci 1139d5ac70f0Sopenharmony_ci if (strcmp(id, "tokens") == 0) { 1140d5ac70f0Sopenharmony_ci if (snd_config_get_string(n, &value) < 0) 1141d5ac70f0Sopenharmony_ci return -EINVAL; 1142d5ac70f0Sopenharmony_ci tplg_ref_add(elem, SND_TPLG_TYPE_TOKEN, value); 1143d5ac70f0Sopenharmony_ci tplg_dbg("\t refer to vendor tokens: %s", value); 1144d5ac70f0Sopenharmony_ci } 1145d5ac70f0Sopenharmony_ci 1146d5ac70f0Sopenharmony_ci if (strcmp(id, "tuples") == 0) { 1147d5ac70f0Sopenharmony_ci err = parse_tuple_sets(n, tuples); 1148d5ac70f0Sopenharmony_ci if (err < 0) 1149d5ac70f0Sopenharmony_ci return err; 1150d5ac70f0Sopenharmony_ci } 1151d5ac70f0Sopenharmony_ci } 1152d5ac70f0Sopenharmony_ci 1153d5ac70f0Sopenharmony_ci return 0; 1154d5ac70f0Sopenharmony_ci} 1155d5ac70f0Sopenharmony_ci 1156d5ac70f0Sopenharmony_ci/* save vendor tuples */ 1157d5ac70f0Sopenharmony_ciint tplg_save_tuples(snd_tplg_t *tplg ATTRIBUTE_UNUSED, 1158d5ac70f0Sopenharmony_ci struct tplg_elem *elem, 1159d5ac70f0Sopenharmony_ci struct tplg_buf *dst, const char *pfx) 1160d5ac70f0Sopenharmony_ci{ 1161d5ac70f0Sopenharmony_ci char pfx2[16]; 1162d5ac70f0Sopenharmony_ci int err; 1163d5ac70f0Sopenharmony_ci 1164d5ac70f0Sopenharmony_ci if (!elem->tuples) 1165d5ac70f0Sopenharmony_ci return 0; 1166d5ac70f0Sopenharmony_ci 1167d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id); 1168d5ac70f0Sopenharmony_ci snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: ""); 1169d5ac70f0Sopenharmony_ci if (err >= 0) 1170d5ac70f0Sopenharmony_ci err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_TOKEN, 1171d5ac70f0Sopenharmony_ci "tokens", dst, pfx2); 1172d5ac70f0Sopenharmony_ci if (err >= 0) 1173d5ac70f0Sopenharmony_ci err = tplg_save_tuple_sets(tplg, elem, dst, pfx2); 1174d5ac70f0Sopenharmony_ci if (err >= 0) 1175d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "}\n"); 1176d5ac70f0Sopenharmony_ci return 0; 1177d5ac70f0Sopenharmony_ci} 1178d5ac70f0Sopenharmony_ci 1179d5ac70f0Sopenharmony_ci/* Free handler of tuples */ 1180d5ac70f0Sopenharmony_civoid tplg_free_tuples(void *obj) 1181d5ac70f0Sopenharmony_ci{ 1182d5ac70f0Sopenharmony_ci struct tplg_vendor_tuples *tuples = (struct tplg_vendor_tuples *)obj; 1183d5ac70f0Sopenharmony_ci unsigned int i; 1184d5ac70f0Sopenharmony_ci 1185d5ac70f0Sopenharmony_ci if (!tuples || !tuples->set) 1186d5ac70f0Sopenharmony_ci return; 1187d5ac70f0Sopenharmony_ci 1188d5ac70f0Sopenharmony_ci for (i = 0; i < tuples->num_sets; i++) 1189d5ac70f0Sopenharmony_ci free(tuples->set[i]); 1190d5ac70f0Sopenharmony_ci 1191d5ac70f0Sopenharmony_ci free(tuples->set); 1192d5ac70f0Sopenharmony_ci} 1193d5ac70f0Sopenharmony_ci 1194d5ac70f0Sopenharmony_ci/* Parse manifest's data references 1195d5ac70f0Sopenharmony_ci */ 1196d5ac70f0Sopenharmony_ciint tplg_parse_manifest_data(snd_tplg_t *tplg, snd_config_t *cfg, 1197d5ac70f0Sopenharmony_ci void *private ATTRIBUTE_UNUSED) 1198d5ac70f0Sopenharmony_ci{ 1199d5ac70f0Sopenharmony_ci struct snd_soc_tplg_manifest *manifest; 1200d5ac70f0Sopenharmony_ci struct tplg_elem *elem; 1201d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1202d5ac70f0Sopenharmony_ci snd_config_t *n; 1203d5ac70f0Sopenharmony_ci const char *id; 1204d5ac70f0Sopenharmony_ci int err; 1205d5ac70f0Sopenharmony_ci 1206d5ac70f0Sopenharmony_ci if (!list_empty(&tplg->manifest_list)) { 1207d5ac70f0Sopenharmony_ci SNDERR("already has manifest data"); 1208d5ac70f0Sopenharmony_ci return -EINVAL; 1209d5ac70f0Sopenharmony_ci } 1210d5ac70f0Sopenharmony_ci 1211d5ac70f0Sopenharmony_ci elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_MANIFEST); 1212d5ac70f0Sopenharmony_ci if (!elem) 1213d5ac70f0Sopenharmony_ci return -ENOMEM; 1214d5ac70f0Sopenharmony_ci 1215d5ac70f0Sopenharmony_ci manifest = elem->manifest; 1216d5ac70f0Sopenharmony_ci manifest->size = elem->size; 1217d5ac70f0Sopenharmony_ci 1218d5ac70f0Sopenharmony_ci tplg_dbg(" Manifest: %s", elem->id); 1219d5ac70f0Sopenharmony_ci 1220d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 1221d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 1222d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 1223d5ac70f0Sopenharmony_ci continue; 1224d5ac70f0Sopenharmony_ci 1225d5ac70f0Sopenharmony_ci /* skip comments */ 1226d5ac70f0Sopenharmony_ci if (strcmp(id, "comment") == 0) 1227d5ac70f0Sopenharmony_ci continue; 1228d5ac70f0Sopenharmony_ci if (id[0] == '#') 1229d5ac70f0Sopenharmony_ci continue; 1230d5ac70f0Sopenharmony_ci 1231d5ac70f0Sopenharmony_ci 1232d5ac70f0Sopenharmony_ci if (strcmp(id, "data") == 0) { 1233d5ac70f0Sopenharmony_ci err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_DATA); 1234d5ac70f0Sopenharmony_ci if (err < 0) 1235d5ac70f0Sopenharmony_ci return err; 1236d5ac70f0Sopenharmony_ci continue; 1237d5ac70f0Sopenharmony_ci } 1238d5ac70f0Sopenharmony_ci } 1239d5ac70f0Sopenharmony_ci 1240d5ac70f0Sopenharmony_ci return 0; 1241d5ac70f0Sopenharmony_ci} 1242d5ac70f0Sopenharmony_ci 1243d5ac70f0Sopenharmony_ci/* save manifest data */ 1244d5ac70f0Sopenharmony_ciint tplg_save_manifest_data(snd_tplg_t *tplg ATTRIBUTE_UNUSED, 1245d5ac70f0Sopenharmony_ci struct tplg_elem *elem, struct tplg_buf *dst, 1246d5ac70f0Sopenharmony_ci const char *pfx) 1247d5ac70f0Sopenharmony_ci{ 1248d5ac70f0Sopenharmony_ci struct list_head *pos; 1249d5ac70f0Sopenharmony_ci struct tplg_ref *ref; 1250d5ac70f0Sopenharmony_ci int err, index, count; 1251d5ac70f0Sopenharmony_ci 1252d5ac70f0Sopenharmony_ci /* for each ref in this manifest elem */ 1253d5ac70f0Sopenharmony_ci count = 0; 1254d5ac70f0Sopenharmony_ci list_for_each(pos, &elem->ref_list) { 1255d5ac70f0Sopenharmony_ci ref = list_entry(pos, struct tplg_ref, list); 1256d5ac70f0Sopenharmony_ci if (ref->type != SND_TPLG_TYPE_DATA) 1257d5ac70f0Sopenharmony_ci continue; 1258d5ac70f0Sopenharmony_ci count++; 1259d5ac70f0Sopenharmony_ci } 1260d5ac70f0Sopenharmony_ci if (count == 0) 1261d5ac70f0Sopenharmony_ci return tplg_save_printf(dst, NULL, 1262d5ac70f0Sopenharmony_ci "'%s'.comment 'empty'\n", elem->id); 1263d5ac70f0Sopenharmony_ci if (count > 1) { 1264d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, "'%s'.data [\n", elem->id); 1265d5ac70f0Sopenharmony_ci if (err < 0) 1266d5ac70f0Sopenharmony_ci return err; 1267d5ac70f0Sopenharmony_ci } 1268d5ac70f0Sopenharmony_ci index = 0; 1269d5ac70f0Sopenharmony_ci list_for_each(pos, &elem->ref_list) { 1270d5ac70f0Sopenharmony_ci ref = list_entry(pos, struct tplg_ref, list); 1271d5ac70f0Sopenharmony_ci if (ref->type != SND_TPLG_TYPE_DATA) 1272d5ac70f0Sopenharmony_ci continue; 1273d5ac70f0Sopenharmony_ci if (count == 1) { 1274d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, "'%s'.data.%u '%s'\n", 1275d5ac70f0Sopenharmony_ci elem->id, index, ref->id); 1276d5ac70f0Sopenharmony_ci } else { 1277d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "\t'%s'\n", ref->id); 1278d5ac70f0Sopenharmony_ci } 1279d5ac70f0Sopenharmony_ci if (err < 0) 1280d5ac70f0Sopenharmony_ci return err; 1281d5ac70f0Sopenharmony_ci index++; 1282d5ac70f0Sopenharmony_ci } 1283d5ac70f0Sopenharmony_ci if (count > 1) { 1284d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "]\n"); 1285d5ac70f0Sopenharmony_ci if (err < 0) 1286d5ac70f0Sopenharmony_ci return err; 1287d5ac70f0Sopenharmony_ci } 1288d5ac70f0Sopenharmony_ci return 0; 1289d5ac70f0Sopenharmony_ci} 1290d5ac70f0Sopenharmony_ci 1291d5ac70f0Sopenharmony_ci/* merge private data of manifest */ 1292d5ac70f0Sopenharmony_ciint tplg_build_manifest_data(snd_tplg_t *tplg) 1293d5ac70f0Sopenharmony_ci{ 1294d5ac70f0Sopenharmony_ci struct list_head *base, *pos; 1295d5ac70f0Sopenharmony_ci struct tplg_elem *elem = NULL; 1296d5ac70f0Sopenharmony_ci struct tplg_ref *ref; 1297d5ac70f0Sopenharmony_ci struct snd_soc_tplg_manifest *manifest; 1298d5ac70f0Sopenharmony_ci int err = 0; 1299d5ac70f0Sopenharmony_ci 1300d5ac70f0Sopenharmony_ci base = &tplg->manifest_list; 1301d5ac70f0Sopenharmony_ci list_for_each(pos, base) { 1302d5ac70f0Sopenharmony_ci 1303d5ac70f0Sopenharmony_ci elem = list_entry(pos, struct tplg_elem, list); 1304d5ac70f0Sopenharmony_ci break; 1305d5ac70f0Sopenharmony_ci } 1306d5ac70f0Sopenharmony_ci 1307d5ac70f0Sopenharmony_ci if (!elem) /* no manifest data */ 1308d5ac70f0Sopenharmony_ci return 0; 1309d5ac70f0Sopenharmony_ci 1310d5ac70f0Sopenharmony_ci base = &elem->ref_list; 1311d5ac70f0Sopenharmony_ci 1312d5ac70f0Sopenharmony_ci /* for each ref in this manifest elem */ 1313d5ac70f0Sopenharmony_ci list_for_each(pos, base) { 1314d5ac70f0Sopenharmony_ci 1315d5ac70f0Sopenharmony_ci ref = list_entry(pos, struct tplg_ref, list); 1316d5ac70f0Sopenharmony_ci if (ref->elem) 1317d5ac70f0Sopenharmony_ci continue; 1318d5ac70f0Sopenharmony_ci 1319d5ac70f0Sopenharmony_ci if (ref->type == SND_TPLG_TYPE_DATA) { 1320d5ac70f0Sopenharmony_ci err = tplg_copy_data(tplg, elem, ref); 1321d5ac70f0Sopenharmony_ci if (err < 0) 1322d5ac70f0Sopenharmony_ci return err; 1323d5ac70f0Sopenharmony_ci } 1324d5ac70f0Sopenharmony_ci } 1325d5ac70f0Sopenharmony_ci 1326d5ac70f0Sopenharmony_ci manifest = elem->manifest; 1327d5ac70f0Sopenharmony_ci if (!manifest->priv.size) /* no manifest data */ 1328d5ac70f0Sopenharmony_ci return 0; 1329d5ac70f0Sopenharmony_ci 1330d5ac70f0Sopenharmony_ci tplg->manifest_pdata = malloc(manifest->priv.size); 1331d5ac70f0Sopenharmony_ci if (!tplg->manifest_pdata) 1332d5ac70f0Sopenharmony_ci return -ENOMEM; 1333d5ac70f0Sopenharmony_ci 1334d5ac70f0Sopenharmony_ci tplg->manifest.priv.size = manifest->priv.size; 1335d5ac70f0Sopenharmony_ci memcpy(tplg->manifest_pdata, manifest->priv.data, manifest->priv.size); 1336d5ac70f0Sopenharmony_ci return 0; 1337d5ac70f0Sopenharmony_ci} 1338d5ac70f0Sopenharmony_ci 1339d5ac70f0Sopenharmony_ci/* Parse Private data. 1340d5ac70f0Sopenharmony_ci * 1341d5ac70f0Sopenharmony_ci * Object private data can either be from file or defined as bytes, shorts, 1342d5ac70f0Sopenharmony_ci * words, tuples. 1343d5ac70f0Sopenharmony_ci */ 1344d5ac70f0Sopenharmony_ciint tplg_parse_data(snd_tplg_t *tplg, snd_config_t *cfg, 1345d5ac70f0Sopenharmony_ci void *private ATTRIBUTE_UNUSED) 1346d5ac70f0Sopenharmony_ci{ 1347d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1348d5ac70f0Sopenharmony_ci snd_config_t *n; 1349d5ac70f0Sopenharmony_ci const char *id; 1350d5ac70f0Sopenharmony_ci int err = 0, ival; 1351d5ac70f0Sopenharmony_ci struct tplg_elem *elem; 1352d5ac70f0Sopenharmony_ci 1353d5ac70f0Sopenharmony_ci elem = tplg_elem_new_common(tplg, cfg, NULL, SND_TPLG_TYPE_DATA); 1354d5ac70f0Sopenharmony_ci if (!elem) 1355d5ac70f0Sopenharmony_ci return -ENOMEM; 1356d5ac70f0Sopenharmony_ci 1357d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 1358d5ac70f0Sopenharmony_ci 1359d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 1360d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) { 1361d5ac70f0Sopenharmony_ci continue; 1362d5ac70f0Sopenharmony_ci } 1363d5ac70f0Sopenharmony_ci 1364d5ac70f0Sopenharmony_ci if (strcmp(id, "file") == 0) { 1365d5ac70f0Sopenharmony_ci err = tplg_parse_data_file(n, elem); 1366d5ac70f0Sopenharmony_ci if (err < 0) { 1367d5ac70f0Sopenharmony_ci SNDERR("failed to parse data file"); 1368d5ac70f0Sopenharmony_ci return err; 1369d5ac70f0Sopenharmony_ci } 1370d5ac70f0Sopenharmony_ci continue; 1371d5ac70f0Sopenharmony_ci } 1372d5ac70f0Sopenharmony_ci 1373d5ac70f0Sopenharmony_ci if (strcmp(id, "bytes") == 0) { 1374d5ac70f0Sopenharmony_ci err = tplg_parse_data_hex(n, elem, 1); 1375d5ac70f0Sopenharmony_ci if (err < 0) { 1376d5ac70f0Sopenharmony_ci SNDERR("failed to parse data bytes"); 1377d5ac70f0Sopenharmony_ci return err; 1378d5ac70f0Sopenharmony_ci } 1379d5ac70f0Sopenharmony_ci continue; 1380d5ac70f0Sopenharmony_ci } 1381d5ac70f0Sopenharmony_ci 1382d5ac70f0Sopenharmony_ci if (strcmp(id, "shorts") == 0) { 1383d5ac70f0Sopenharmony_ci err = tplg_parse_data_hex(n, elem, 2); 1384d5ac70f0Sopenharmony_ci if (err < 0) { 1385d5ac70f0Sopenharmony_ci SNDERR("failed to parse data shorts"); 1386d5ac70f0Sopenharmony_ci return err; 1387d5ac70f0Sopenharmony_ci } 1388d5ac70f0Sopenharmony_ci continue; 1389d5ac70f0Sopenharmony_ci } 1390d5ac70f0Sopenharmony_ci 1391d5ac70f0Sopenharmony_ci if (strcmp(id, "words") == 0) { 1392d5ac70f0Sopenharmony_ci err = tplg_parse_data_hex(n, elem, 4); 1393d5ac70f0Sopenharmony_ci if (err < 0) { 1394d5ac70f0Sopenharmony_ci SNDERR("failed to parse data words"); 1395d5ac70f0Sopenharmony_ci return err; 1396d5ac70f0Sopenharmony_ci } 1397d5ac70f0Sopenharmony_ci continue; 1398d5ac70f0Sopenharmony_ci } 1399d5ac70f0Sopenharmony_ci 1400d5ac70f0Sopenharmony_ci if (strcmp(id, "tuples") == 0) { 1401d5ac70f0Sopenharmony_ci err = tplg_parse_refs(n, elem, SND_TPLG_TYPE_TUPLE); 1402d5ac70f0Sopenharmony_ci if (err < 0) 1403d5ac70f0Sopenharmony_ci return err; 1404d5ac70f0Sopenharmony_ci continue; 1405d5ac70f0Sopenharmony_ci } 1406d5ac70f0Sopenharmony_ci 1407d5ac70f0Sopenharmony_ci if (strcmp(id, "type") == 0) { 1408d5ac70f0Sopenharmony_ci if (tplg_get_integer(n, &ival, 0)) 1409d5ac70f0Sopenharmony_ci return -EINVAL; 1410d5ac70f0Sopenharmony_ci 1411d5ac70f0Sopenharmony_ci elem->vendor_type = ival; 1412d5ac70f0Sopenharmony_ci tplg_dbg("\t%s: %d", id, elem->index); 1413d5ac70f0Sopenharmony_ci continue; 1414d5ac70f0Sopenharmony_ci } 1415d5ac70f0Sopenharmony_ci } 1416d5ac70f0Sopenharmony_ci 1417d5ac70f0Sopenharmony_ci return err; 1418d5ac70f0Sopenharmony_ci} 1419d5ac70f0Sopenharmony_ci 1420d5ac70f0Sopenharmony_ci/* save data element */ 1421d5ac70f0Sopenharmony_ciint tplg_save_data(snd_tplg_t *tplg ATTRIBUTE_UNUSED, 1422d5ac70f0Sopenharmony_ci struct tplg_elem *elem, 1423d5ac70f0Sopenharmony_ci struct tplg_buf *dst, const char *pfx) 1424d5ac70f0Sopenharmony_ci{ 1425d5ac70f0Sopenharmony_ci struct snd_soc_tplg_private *priv = elem->data; 1426d5ac70f0Sopenharmony_ci struct list_head *pos; 1427d5ac70f0Sopenharmony_ci struct tplg_ref *ref; 1428d5ac70f0Sopenharmony_ci char pfx2[16]; 1429d5ac70f0Sopenharmony_ci unsigned int i, count; 1430d5ac70f0Sopenharmony_ci int err; 1431d5ac70f0Sopenharmony_ci 1432d5ac70f0Sopenharmony_ci count = 0; 1433d5ac70f0Sopenharmony_ci if (priv && priv->size > 0) 1434d5ac70f0Sopenharmony_ci count++; 1435d5ac70f0Sopenharmony_ci list_for_each(pos, &elem->ref_list) { 1436d5ac70f0Sopenharmony_ci ref = list_entry(pos, struct tplg_ref, list); 1437d5ac70f0Sopenharmony_ci if (ref->type == SND_TPLG_TYPE_TUPLE) 1438d5ac70f0Sopenharmony_ci count++; 1439d5ac70f0Sopenharmony_ci } 1440d5ac70f0Sopenharmony_ci if (elem->vendor_type > 0) 1441d5ac70f0Sopenharmony_ci count++; 1442d5ac70f0Sopenharmony_ci 1443d5ac70f0Sopenharmony_ci if (count > 1) { 1444d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, "'%s' {\n", elem->id); 1445d5ac70f0Sopenharmony_ci if (err >= 0) 1446d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, ""); 1447d5ac70f0Sopenharmony_ci } else { 1448d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, "'%s'.", elem->id); 1449d5ac70f0Sopenharmony_ci } 1450d5ac70f0Sopenharmony_ci if (err >= 0 && priv && priv->size > 0) { 1451d5ac70f0Sopenharmony_ci if (count > 1) { 1452d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, ""); 1453d5ac70f0Sopenharmony_ci if (err < 0) 1454d5ac70f0Sopenharmony_ci return err; 1455d5ac70f0Sopenharmony_ci } 1456d5ac70f0Sopenharmony_ci if (priv->size > 8) { 1457d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, "bytes\n"); 1458d5ac70f0Sopenharmony_ci if (err >= 0) 1459d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "\t'"); 1460d5ac70f0Sopenharmony_ci } else { 1461d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, "bytes '"); 1462d5ac70f0Sopenharmony_ci } 1463d5ac70f0Sopenharmony_ci if (err < 0) 1464d5ac70f0Sopenharmony_ci return err; 1465d5ac70f0Sopenharmony_ci for (i = 0; i < priv->size; i++) { 1466d5ac70f0Sopenharmony_ci if (i > 0 && (i % 8) == 0) { 1467d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, ":\n"); 1468d5ac70f0Sopenharmony_ci if (err < 0) 1469d5ac70f0Sopenharmony_ci return err; 1470d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "\t "); 1471d5ac70f0Sopenharmony_ci if (err < 0) 1472d5ac70f0Sopenharmony_ci return err; 1473d5ac70f0Sopenharmony_ci } 1474d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, "%s%02x", 1475d5ac70f0Sopenharmony_ci (i % 8) == 0 ? "" : ":", 1476d5ac70f0Sopenharmony_ci (unsigned char)priv->data[i]); 1477d5ac70f0Sopenharmony_ci if (err < 0) 1478d5ac70f0Sopenharmony_ci return err; 1479d5ac70f0Sopenharmony_ci } 1480d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, NULL, "'\n"); 1481d5ac70f0Sopenharmony_ci } 1482d5ac70f0Sopenharmony_ci snprintf(pfx2, sizeof(pfx2), "%s\t", pfx ?: ""); 1483d5ac70f0Sopenharmony_ci if (err >= 0) 1484d5ac70f0Sopenharmony_ci err = tplg_save_refs(tplg, elem, SND_TPLG_TYPE_TUPLE, 1485d5ac70f0Sopenharmony_ci "tuples", dst, 1486d5ac70f0Sopenharmony_ci count > 1 ? pfx2 : NULL); 1487d5ac70f0Sopenharmony_ci if (err >= 0 && elem->vendor_type > 0) 1488d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "type %u", 1489d5ac70f0Sopenharmony_ci elem->vendor_type); 1490d5ac70f0Sopenharmony_ci if (err >= 0 && count > 1) 1491d5ac70f0Sopenharmony_ci err = tplg_save_printf(dst, pfx, "}\n"); 1492d5ac70f0Sopenharmony_ci return err; 1493d5ac70f0Sopenharmony_ci} 1494d5ac70f0Sopenharmony_ci 1495d5ac70f0Sopenharmony_ci/* Find a referenced data element and copy its data to the parent 1496d5ac70f0Sopenharmony_ci * element's private data buffer. 1497d5ac70f0Sopenharmony_ci * An element can refer to multiple data sections. Data of these sections 1498d5ac70f0Sopenharmony_ci * will be merged in the their reference order. 1499d5ac70f0Sopenharmony_ci */ 1500d5ac70f0Sopenharmony_ciint tplg_copy_data(snd_tplg_t *tplg, struct tplg_elem *elem, 1501d5ac70f0Sopenharmony_ci struct tplg_ref *ref) 1502d5ac70f0Sopenharmony_ci{ 1503d5ac70f0Sopenharmony_ci struct tplg_elem *ref_elem; 1504d5ac70f0Sopenharmony_ci struct snd_soc_tplg_private *priv, *old_priv; 1505d5ac70f0Sopenharmony_ci int priv_data_size, old_priv_data_size; 1506d5ac70f0Sopenharmony_ci void *obj; 1507d5ac70f0Sopenharmony_ci 1508d5ac70f0Sopenharmony_ci ref_elem = tplg_elem_lookup(&tplg->pdata_list, 1509d5ac70f0Sopenharmony_ci ref->id, SND_TPLG_TYPE_DATA, elem->index); 1510d5ac70f0Sopenharmony_ci if (!ref_elem) { 1511d5ac70f0Sopenharmony_ci SNDERR("cannot find data '%s' referenced by" 1512d5ac70f0Sopenharmony_ci " element '%s'", ref->id, elem->id); 1513d5ac70f0Sopenharmony_ci return -EINVAL; 1514d5ac70f0Sopenharmony_ci } 1515d5ac70f0Sopenharmony_ci 1516d5ac70f0Sopenharmony_ci tplg_dbg("Data '%s' used by '%s'", ref->id, elem->id); 1517d5ac70f0Sopenharmony_ci /* overlook empty private data */ 1518d5ac70f0Sopenharmony_ci if (!ref_elem->data || !ref_elem->data->size) { 1519d5ac70f0Sopenharmony_ci ref->elem = ref_elem; 1520d5ac70f0Sopenharmony_ci return 0; 1521d5ac70f0Sopenharmony_ci } 1522d5ac70f0Sopenharmony_ci 1523d5ac70f0Sopenharmony_ci old_priv = get_priv_data(elem); 1524d5ac70f0Sopenharmony_ci if (!old_priv) 1525d5ac70f0Sopenharmony_ci return -EINVAL; 1526d5ac70f0Sopenharmony_ci old_priv_data_size = old_priv->size; 1527d5ac70f0Sopenharmony_ci 1528d5ac70f0Sopenharmony_ci priv_data_size = ref_elem->data->size; 1529d5ac70f0Sopenharmony_ci obj = realloc(elem->obj, 1530d5ac70f0Sopenharmony_ci elem->size + priv_data_size); 1531d5ac70f0Sopenharmony_ci if (!obj) 1532d5ac70f0Sopenharmony_ci return -ENOMEM; 1533d5ac70f0Sopenharmony_ci elem->obj = obj; 1534d5ac70f0Sopenharmony_ci 1535d5ac70f0Sopenharmony_ci priv = get_priv_data(elem); 1536d5ac70f0Sopenharmony_ci if (!priv) 1537d5ac70f0Sopenharmony_ci return -EINVAL; 1538d5ac70f0Sopenharmony_ci 1539d5ac70f0Sopenharmony_ci /* merge the new data block */ 1540d5ac70f0Sopenharmony_ci elem->size += priv_data_size; 1541d5ac70f0Sopenharmony_ci priv->size = priv_data_size + old_priv_data_size; 1542d5ac70f0Sopenharmony_ci ref_elem->compound_elem = 1; 1543d5ac70f0Sopenharmony_ci memcpy(priv->data + old_priv_data_size, 1544d5ac70f0Sopenharmony_ci ref_elem->data->data, priv_data_size); 1545d5ac70f0Sopenharmony_ci 1546d5ac70f0Sopenharmony_ci ref->elem = ref_elem; 1547d5ac70f0Sopenharmony_ci return 0; 1548d5ac70f0Sopenharmony_ci} 1549d5ac70f0Sopenharmony_ci 1550d5ac70f0Sopenharmony_ci/* check data objects and build those with tuples */ 1551d5ac70f0Sopenharmony_ciint tplg_build_data(snd_tplg_t *tplg) 1552d5ac70f0Sopenharmony_ci{ 1553d5ac70f0Sopenharmony_ci struct list_head *base, *pos; 1554d5ac70f0Sopenharmony_ci struct tplg_elem *elem; 1555d5ac70f0Sopenharmony_ci int err = 0; 1556d5ac70f0Sopenharmony_ci 1557d5ac70f0Sopenharmony_ci base = &tplg->pdata_list; 1558d5ac70f0Sopenharmony_ci list_for_each(pos, base) { 1559d5ac70f0Sopenharmony_ci 1560d5ac70f0Sopenharmony_ci elem = list_entry(pos, struct tplg_elem, list); 1561d5ac70f0Sopenharmony_ci if (has_tuples(elem)) { 1562d5ac70f0Sopenharmony_ci err = build_tuples(tplg, elem); 1563d5ac70f0Sopenharmony_ci if (err < 0) 1564d5ac70f0Sopenharmony_ci return err; 1565d5ac70f0Sopenharmony_ci } 1566d5ac70f0Sopenharmony_ci } 1567d5ac70f0Sopenharmony_ci 1568d5ac70f0Sopenharmony_ci return 0; 1569d5ac70f0Sopenharmony_ci} 1570d5ac70f0Sopenharmony_ci 1571d5ac70f0Sopenharmony_ci/* decode manifest data */ 1572d5ac70f0Sopenharmony_ciint tplg_decode_manifest_data(snd_tplg_t *tplg, 1573d5ac70f0Sopenharmony_ci size_t pos, 1574d5ac70f0Sopenharmony_ci struct snd_soc_tplg_hdr *hdr, 1575d5ac70f0Sopenharmony_ci void *bin, size_t size) 1576d5ac70f0Sopenharmony_ci{ 1577d5ac70f0Sopenharmony_ci struct snd_soc_tplg_manifest *m = bin; 1578d5ac70f0Sopenharmony_ci struct tplg_elem *elem; 1579d5ac70f0Sopenharmony_ci size_t off; 1580d5ac70f0Sopenharmony_ci 1581d5ac70f0Sopenharmony_ci if (hdr->index != 0) { 1582d5ac70f0Sopenharmony_ci SNDERR("manifest - wrong index %d", hdr->index); 1583d5ac70f0Sopenharmony_ci return -EINVAL; 1584d5ac70f0Sopenharmony_ci } 1585d5ac70f0Sopenharmony_ci 1586d5ac70f0Sopenharmony_ci if (sizeof(*m) > size) { 1587d5ac70f0Sopenharmony_ci SNDERR("manifest - wrong size %zd (minimal %zd)", 1588d5ac70f0Sopenharmony_ci size, sizeof(*m)); 1589d5ac70f0Sopenharmony_ci return -EINVAL; 1590d5ac70f0Sopenharmony_ci } 1591d5ac70f0Sopenharmony_ci 1592d5ac70f0Sopenharmony_ci if (m->size != sizeof(*m)) { 1593d5ac70f0Sopenharmony_ci SNDERR("manifest - wrong sructure size %d", m->size); 1594d5ac70f0Sopenharmony_ci return -EINVAL; 1595d5ac70f0Sopenharmony_ci } 1596d5ac70f0Sopenharmony_ci 1597d5ac70f0Sopenharmony_ci off = offsetof(struct snd_soc_tplg_manifest, priv); 1598d5ac70f0Sopenharmony_ci if (off + m->priv.size > size) { 1599d5ac70f0Sopenharmony_ci SNDERR("manifest - wrong private size %d", m->priv.size); 1600d5ac70f0Sopenharmony_ci return -EINVAL; 1601d5ac70f0Sopenharmony_ci } 1602d5ac70f0Sopenharmony_ci 1603d5ac70f0Sopenharmony_ci tplg->manifest = *m; 1604d5ac70f0Sopenharmony_ci 1605d5ac70f0Sopenharmony_ci bin += off; 1606d5ac70f0Sopenharmony_ci size -= off; 1607d5ac70f0Sopenharmony_ci pos += off; 1608d5ac70f0Sopenharmony_ci 1609d5ac70f0Sopenharmony_ci elem = tplg_elem_new_common(tplg, NULL, "manifest", 1610d5ac70f0Sopenharmony_ci SND_TPLG_TYPE_MANIFEST); 1611d5ac70f0Sopenharmony_ci if (!elem) 1612d5ac70f0Sopenharmony_ci return -ENOMEM; 1613d5ac70f0Sopenharmony_ci 1614d5ac70f0Sopenharmony_ci tplg_log(tplg, 'D', pos, "manifest: private size %zd", size); 1615d5ac70f0Sopenharmony_ci return tplg_add_data(tplg, elem, bin, size); 1616d5ac70f0Sopenharmony_ci} 1617d5ac70f0Sopenharmony_ci 1618d5ac70f0Sopenharmony_ciint tplg_add_token(snd_tplg_t *tplg, struct tplg_elem *parent, 1619d5ac70f0Sopenharmony_ci unsigned int token, 1620d5ac70f0Sopenharmony_ci char str_ref[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]) 1621d5ac70f0Sopenharmony_ci{ 1622d5ac70f0Sopenharmony_ci struct tplg_elem *elem; 1623d5ac70f0Sopenharmony_ci struct tplg_token *t; 1624d5ac70f0Sopenharmony_ci struct tplg_vendor_tokens *tokens; 1625d5ac70f0Sopenharmony_ci unsigned int i; 1626d5ac70f0Sopenharmony_ci size_t size; 1627d5ac70f0Sopenharmony_ci 1628d5ac70f0Sopenharmony_ci elem = tplg_elem_lookup(&tplg->token_list, parent->id, 1629d5ac70f0Sopenharmony_ci SND_TPLG_TYPE_TOKEN, parent->index); 1630d5ac70f0Sopenharmony_ci if (elem == NULL) { 1631d5ac70f0Sopenharmony_ci elem = tplg_elem_new_common(tplg, NULL, parent->id, 1632d5ac70f0Sopenharmony_ci SND_TPLG_TYPE_TOKEN); 1633d5ac70f0Sopenharmony_ci if (!elem) 1634d5ac70f0Sopenharmony_ci return -ENOMEM; 1635d5ac70f0Sopenharmony_ci } 1636d5ac70f0Sopenharmony_ci 1637d5ac70f0Sopenharmony_ci tokens = elem->tokens; 1638d5ac70f0Sopenharmony_ci if (tokens) { 1639d5ac70f0Sopenharmony_ci for (i = 0; i < tokens->num_tokens; i++) { 1640d5ac70f0Sopenharmony_ci t = &tokens->token[i]; 1641d5ac70f0Sopenharmony_ci if (t->value == token) 1642d5ac70f0Sopenharmony_ci goto found; 1643d5ac70f0Sopenharmony_ci } 1644d5ac70f0Sopenharmony_ci size = sizeof(*tokens) + 1645d5ac70f0Sopenharmony_ci (tokens->num_tokens + 1) * sizeof(struct tplg_token); 1646d5ac70f0Sopenharmony_ci tokens = realloc(tokens, size); 1647d5ac70f0Sopenharmony_ci } else { 1648d5ac70f0Sopenharmony_ci size = sizeof(*tokens) + 1 * sizeof(struct tplg_token); 1649d5ac70f0Sopenharmony_ci tokens = calloc(1, size); 1650d5ac70f0Sopenharmony_ci } 1651d5ac70f0Sopenharmony_ci 1652d5ac70f0Sopenharmony_ci if (!tokens) 1653d5ac70f0Sopenharmony_ci return -ENOMEM; 1654d5ac70f0Sopenharmony_ci 1655d5ac70f0Sopenharmony_ci memset(&tokens->token[tokens->num_tokens], 0, sizeof(struct tplg_token)); 1656d5ac70f0Sopenharmony_ci elem->tokens = tokens; 1657d5ac70f0Sopenharmony_ci t = &tokens->token[tokens->num_tokens]; 1658d5ac70f0Sopenharmony_ci tokens->num_tokens++; 1659d5ac70f0Sopenharmony_ci snprintf(t->id, sizeof(t->id), "token%u", token); 1660d5ac70f0Sopenharmony_ci t->value = token; 1661d5ac70f0Sopenharmony_cifound: 1662d5ac70f0Sopenharmony_ci snd_strlcpy(str_ref, t->id, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); 1663d5ac70f0Sopenharmony_ci return 0; 1664d5ac70f0Sopenharmony_ci} 1665d5ac70f0Sopenharmony_ci 1666d5ac70f0Sopenharmony_cistatic int tplg_verify_tuple_set(snd_tplg_t *tplg, size_t pos, 1667d5ac70f0Sopenharmony_ci const void *bin, size_t size) 1668d5ac70f0Sopenharmony_ci{ 1669d5ac70f0Sopenharmony_ci const struct snd_soc_tplg_vendor_array *va; 1670d5ac70f0Sopenharmony_ci unsigned int j; 1671d5ac70f0Sopenharmony_ci 1672d5ac70f0Sopenharmony_ci va = bin; 1673d5ac70f0Sopenharmony_ci if (size < sizeof(*va) || size < va->size) { 1674d5ac70f0Sopenharmony_ci tplg_log(tplg, 'A', pos, "tuple set verify: wrong size %zd", size); 1675d5ac70f0Sopenharmony_ci return -EINVAL; 1676d5ac70f0Sopenharmony_ci } 1677d5ac70f0Sopenharmony_ci 1678d5ac70f0Sopenharmony_ci switch (va->type) { 1679d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_UUID: 1680d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_STRING: 1681d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_BOOL: 1682d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_BYTE: 1683d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_WORD: 1684d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_SHORT: 1685d5ac70f0Sopenharmony_ci break; 1686d5ac70f0Sopenharmony_ci default: 1687d5ac70f0Sopenharmony_ci tplg_log(tplg, 'A', pos, "tuple set verify: unknown array type %d", va->type); 1688d5ac70f0Sopenharmony_ci return -EINVAL; 1689d5ac70f0Sopenharmony_ci } 1690d5ac70f0Sopenharmony_ci 1691d5ac70f0Sopenharmony_ci j = tplg_get_tuple_size(va->type) * va->num_elems; 1692d5ac70f0Sopenharmony_ci if (j + sizeof(*va) != va->size) { 1693d5ac70f0Sopenharmony_ci tplg_log(tplg, 'A', pos, "tuple set verify: wrong vendor array size %d " 1694d5ac70f0Sopenharmony_ci "(expected %d for %d count %d)", 1695d5ac70f0Sopenharmony_ci va->size, j + sizeof(*va), va->type, va->num_elems); 1696d5ac70f0Sopenharmony_ci return -EINVAL; 1697d5ac70f0Sopenharmony_ci } 1698d5ac70f0Sopenharmony_ci 1699d5ac70f0Sopenharmony_ci if (va->num_elems > 4096) { 1700d5ac70f0Sopenharmony_ci tplg_log(tplg, 'A', pos, "tuple set verify: tuples overflow %d", va->num_elems); 1701d5ac70f0Sopenharmony_ci return -EINVAL; 1702d5ac70f0Sopenharmony_ci } 1703d5ac70f0Sopenharmony_ci 1704d5ac70f0Sopenharmony_ci return 0; 1705d5ac70f0Sopenharmony_ci} 1706d5ac70f0Sopenharmony_ci 1707d5ac70f0Sopenharmony_cistatic int tplg_decode_tuple_set(snd_tplg_t *tplg, 1708d5ac70f0Sopenharmony_ci size_t pos, 1709d5ac70f0Sopenharmony_ci struct tplg_elem *parent, 1710d5ac70f0Sopenharmony_ci struct tplg_tuple_set **_set, 1711d5ac70f0Sopenharmony_ci const void *bin, size_t size) 1712d5ac70f0Sopenharmony_ci{ 1713d5ac70f0Sopenharmony_ci const struct snd_soc_tplg_vendor_array *va; 1714d5ac70f0Sopenharmony_ci struct tplg_tuple_set *set; 1715d5ac70f0Sopenharmony_ci struct tplg_tuple *tuple; 1716d5ac70f0Sopenharmony_ci unsigned int j; 1717d5ac70f0Sopenharmony_ci int err; 1718d5ac70f0Sopenharmony_ci 1719d5ac70f0Sopenharmony_ci va = bin; 1720d5ac70f0Sopenharmony_ci if (size < sizeof(*va) || size < va->size) { 1721d5ac70f0Sopenharmony_ci SNDERR("tuples: wrong size %zd", size); 1722d5ac70f0Sopenharmony_ci return -EINVAL; 1723d5ac70f0Sopenharmony_ci } 1724d5ac70f0Sopenharmony_ci 1725d5ac70f0Sopenharmony_ci switch (va->type) { 1726d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_UUID: 1727d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_STRING: 1728d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_BOOL: 1729d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_BYTE: 1730d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_WORD: 1731d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_SHORT: 1732d5ac70f0Sopenharmony_ci break; 1733d5ac70f0Sopenharmony_ci default: 1734d5ac70f0Sopenharmony_ci SNDERR("tuples: unknown array type %d", va->type); 1735d5ac70f0Sopenharmony_ci return -EINVAL; 1736d5ac70f0Sopenharmony_ci } 1737d5ac70f0Sopenharmony_ci 1738d5ac70f0Sopenharmony_ci j = tplg_get_tuple_size(va->type) * va->num_elems; 1739d5ac70f0Sopenharmony_ci if (j + sizeof(*va) != va->size) { 1740d5ac70f0Sopenharmony_ci SNDERR("tuples: wrong vendor array size %d " 1741d5ac70f0Sopenharmony_ci "(expected %d for %d count %d)", 1742d5ac70f0Sopenharmony_ci va->size, j + sizeof(*va), va->type, va->num_elems); 1743d5ac70f0Sopenharmony_ci return -EINVAL; 1744d5ac70f0Sopenharmony_ci } 1745d5ac70f0Sopenharmony_ci 1746d5ac70f0Sopenharmony_ci if (va->num_elems > 4096) { 1747d5ac70f0Sopenharmony_ci SNDERR("tuples: tuples overflow %d", va->num_elems); 1748d5ac70f0Sopenharmony_ci return -EINVAL; 1749d5ac70f0Sopenharmony_ci } 1750d5ac70f0Sopenharmony_ci 1751d5ac70f0Sopenharmony_ci set = calloc(1, sizeof(*set) + va->num_elems * sizeof(struct tplg_tuple)); 1752d5ac70f0Sopenharmony_ci if (!set) 1753d5ac70f0Sopenharmony_ci return -ENOMEM; 1754d5ac70f0Sopenharmony_ci 1755d5ac70f0Sopenharmony_ci set->type = va->type; 1756d5ac70f0Sopenharmony_ci set->num_tuples = va->num_elems; 1757d5ac70f0Sopenharmony_ci 1758d5ac70f0Sopenharmony_ci tplg_log(tplg, 'A', pos, "tuple set: type %d (%s) tuples %d size %d", set->type, 1759d5ac70f0Sopenharmony_ci get_tuple_type_name(set->type), set->num_tuples, va->size); 1760d5ac70f0Sopenharmony_ci for (j = 0; j < set->num_tuples; j++) { 1761d5ac70f0Sopenharmony_ci tuple = &set->tuple[j]; 1762d5ac70f0Sopenharmony_ci switch (va->type) { 1763d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_UUID: 1764d5ac70f0Sopenharmony_ci err = tplg_add_token(tplg, parent, va->uuid[j].token, 1765d5ac70f0Sopenharmony_ci tuple->token); 1766d5ac70f0Sopenharmony_ci if (err < 0) 1767d5ac70f0Sopenharmony_ci goto retval; 1768d5ac70f0Sopenharmony_ci memcpy(tuple->uuid, va->uuid[j].uuid, 1769d5ac70f0Sopenharmony_ci sizeof(va->uuid[j].uuid)); 1770d5ac70f0Sopenharmony_ci break; 1771d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_STRING: 1772d5ac70f0Sopenharmony_ci err = tplg_add_token(tplg, parent, va->string[j].token, 1773d5ac70f0Sopenharmony_ci tuple->token); 1774d5ac70f0Sopenharmony_ci if (err < 0) 1775d5ac70f0Sopenharmony_ci goto retval; 1776d5ac70f0Sopenharmony_ci snd_strlcpy(tuple->string, va->string[j].string, 1777d5ac70f0Sopenharmony_ci sizeof(tuple->string)); 1778d5ac70f0Sopenharmony_ci break; 1779d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_BOOL: 1780d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_BYTE: 1781d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_WORD: 1782d5ac70f0Sopenharmony_ci case SND_SOC_TPLG_TUPLE_TYPE_SHORT: 1783d5ac70f0Sopenharmony_ci err = tplg_add_token(tplg, parent, va->value[j].token, 1784d5ac70f0Sopenharmony_ci tuple->token); 1785d5ac70f0Sopenharmony_ci if (err < 0) 1786d5ac70f0Sopenharmony_ci goto retval; 1787d5ac70f0Sopenharmony_ci tuple->value = va->value[j].value; 1788d5ac70f0Sopenharmony_ci break; 1789d5ac70f0Sopenharmony_ci } 1790d5ac70f0Sopenharmony_ci } 1791d5ac70f0Sopenharmony_ci 1792d5ac70f0Sopenharmony_ci *_set = set; 1793d5ac70f0Sopenharmony_ci return 0; 1794d5ac70f0Sopenharmony_ci 1795d5ac70f0Sopenharmony_ciretval: 1796d5ac70f0Sopenharmony_ci free(set); 1797d5ac70f0Sopenharmony_ci return err; 1798d5ac70f0Sopenharmony_ci} 1799d5ac70f0Sopenharmony_ci 1800d5ac70f0Sopenharmony_ci/* verify tuples from the binary input */ 1801d5ac70f0Sopenharmony_cistatic int tplg_verify_tuples(snd_tplg_t *tplg, size_t pos, 1802d5ac70f0Sopenharmony_ci const void *bin, size_t size) 1803d5ac70f0Sopenharmony_ci{ 1804d5ac70f0Sopenharmony_ci const struct snd_soc_tplg_vendor_array *va; 1805d5ac70f0Sopenharmony_ci int err; 1806d5ac70f0Sopenharmony_ci 1807d5ac70f0Sopenharmony_ci if (size < sizeof(*va)) { 1808d5ac70f0Sopenharmony_ci tplg_log(tplg, 'A', pos, "tuples: small size %zd", size); 1809d5ac70f0Sopenharmony_ci return -EINVAL; 1810d5ac70f0Sopenharmony_ci } 1811d5ac70f0Sopenharmony_ci 1812d5ac70f0Sopenharmony_cinext: 1813d5ac70f0Sopenharmony_ci va = bin; 1814d5ac70f0Sopenharmony_ci if (size < sizeof(*va)) { 1815d5ac70f0Sopenharmony_ci tplg_log(tplg, 'A', pos, "tuples: unexpected vendor arry size %zd", size); 1816d5ac70f0Sopenharmony_ci return -EINVAL; 1817d5ac70f0Sopenharmony_ci } 1818d5ac70f0Sopenharmony_ci 1819d5ac70f0Sopenharmony_ci err = tplg_verify_tuple_set(tplg, pos, va, va->size); 1820d5ac70f0Sopenharmony_ci if (err < 0) 1821d5ac70f0Sopenharmony_ci return err; 1822d5ac70f0Sopenharmony_ci 1823d5ac70f0Sopenharmony_ci bin += va->size; 1824d5ac70f0Sopenharmony_ci size -= va->size; 1825d5ac70f0Sopenharmony_ci pos += va->size; 1826d5ac70f0Sopenharmony_ci if (size > 0) 1827d5ac70f0Sopenharmony_ci goto next; 1828d5ac70f0Sopenharmony_ci 1829d5ac70f0Sopenharmony_ci return 0; 1830d5ac70f0Sopenharmony_ci} 1831d5ac70f0Sopenharmony_ci 1832d5ac70f0Sopenharmony_ci/* add tuples from the binary input */ 1833d5ac70f0Sopenharmony_cistatic int tplg_decode_tuples(snd_tplg_t *tplg, 1834d5ac70f0Sopenharmony_ci size_t pos, 1835d5ac70f0Sopenharmony_ci struct tplg_elem *parent, 1836d5ac70f0Sopenharmony_ci struct tplg_vendor_tuples *tuples, 1837d5ac70f0Sopenharmony_ci const void *bin, size_t size) 1838d5ac70f0Sopenharmony_ci{ 1839d5ac70f0Sopenharmony_ci const struct snd_soc_tplg_vendor_array *va; 1840d5ac70f0Sopenharmony_ci struct tplg_tuple_set *set; 1841d5ac70f0Sopenharmony_ci int err; 1842d5ac70f0Sopenharmony_ci 1843d5ac70f0Sopenharmony_ci if (size < sizeof(*va)) { 1844d5ac70f0Sopenharmony_ci SNDERR("tuples: small size %zd", size); 1845d5ac70f0Sopenharmony_ci return -EINVAL; 1846d5ac70f0Sopenharmony_ci } 1847d5ac70f0Sopenharmony_ci 1848d5ac70f0Sopenharmony_cinext: 1849d5ac70f0Sopenharmony_ci va = bin; 1850d5ac70f0Sopenharmony_ci if (size < sizeof(*va)) { 1851d5ac70f0Sopenharmony_ci SNDERR("tuples: unexpected vendor arry size %zd", size); 1852d5ac70f0Sopenharmony_ci return -EINVAL; 1853d5ac70f0Sopenharmony_ci } 1854d5ac70f0Sopenharmony_ci 1855d5ac70f0Sopenharmony_ci if (tuples->num_sets >= tuples->alloc_sets) { 1856d5ac70f0Sopenharmony_ci SNDERR("tuples: index overflow (%d)", tuples->num_sets); 1857d5ac70f0Sopenharmony_ci return -EINVAL; 1858d5ac70f0Sopenharmony_ci } 1859d5ac70f0Sopenharmony_ci 1860d5ac70f0Sopenharmony_ci err = tplg_decode_tuple_set(tplg, pos, parent, &set, va, va->size); 1861d5ac70f0Sopenharmony_ci if (err < 0) 1862d5ac70f0Sopenharmony_ci return err; 1863d5ac70f0Sopenharmony_ci tuples->set[tuples->num_sets++] = set; 1864d5ac70f0Sopenharmony_ci 1865d5ac70f0Sopenharmony_ci bin += va->size; 1866d5ac70f0Sopenharmony_ci size -= va->size; 1867d5ac70f0Sopenharmony_ci pos += va->size; 1868d5ac70f0Sopenharmony_ci if (size > 0) 1869d5ac70f0Sopenharmony_ci goto next; 1870d5ac70f0Sopenharmony_ci 1871d5ac70f0Sopenharmony_ci return 0; 1872d5ac70f0Sopenharmony_ci} 1873d5ac70f0Sopenharmony_ci 1874d5ac70f0Sopenharmony_ci/* decode private data */ 1875d5ac70f0Sopenharmony_ciint tplg_add_data(snd_tplg_t *tplg, 1876d5ac70f0Sopenharmony_ci struct tplg_elem *parent, 1877d5ac70f0Sopenharmony_ci const void *bin, size_t size) 1878d5ac70f0Sopenharmony_ci{ 1879d5ac70f0Sopenharmony_ci const struct snd_soc_tplg_private *tp; 1880d5ac70f0Sopenharmony_ci const struct snd_soc_tplg_vendor_array *va; 1881d5ac70f0Sopenharmony_ci struct tplg_elem *elem = NULL, *elem2 = NULL; 1882d5ac70f0Sopenharmony_ci struct tplg_vendor_tuples *tuples = NULL; 1883d5ac70f0Sopenharmony_ci char id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 1884d5ac70f0Sopenharmony_ci char suffix[16]; 1885d5ac70f0Sopenharmony_ci size_t pos = 0, off; 1886d5ac70f0Sopenharmony_ci int err, num_tuples = 0, block = 0; 1887d5ac70f0Sopenharmony_ci 1888d5ac70f0Sopenharmony_ci if (size == 0) 1889d5ac70f0Sopenharmony_ci return 0; 1890d5ac70f0Sopenharmony_ci 1891d5ac70f0Sopenharmony_ci off = offsetof(struct snd_soc_tplg_private, array); 1892d5ac70f0Sopenharmony_ci 1893d5ac70f0Sopenharmony_cinext: 1894d5ac70f0Sopenharmony_ci tp = bin; 1895d5ac70f0Sopenharmony_ci if (off + size < tp->size) { 1896d5ac70f0Sopenharmony_ci SNDERR("data: unexpected element size %zd", size); 1897d5ac70f0Sopenharmony_ci return -EINVAL; 1898d5ac70f0Sopenharmony_ci } 1899d5ac70f0Sopenharmony_ci 1900d5ac70f0Sopenharmony_ci if (tplg_verify_tuples(tplg, pos, tp->array, tp->size) < 0) { 1901d5ac70f0Sopenharmony_ci if (tuples) { 1902d5ac70f0Sopenharmony_ci err = tplg_ref_add(elem, SND_TPLG_TYPE_TOKEN, parent->id); 1903d5ac70f0Sopenharmony_ci if (err < 0) 1904d5ac70f0Sopenharmony_ci return err; 1905d5ac70f0Sopenharmony_ci err = tplg_ref_add(elem2, SND_TPLG_TYPE_TUPLE, id); 1906d5ac70f0Sopenharmony_ci if (err < 0) 1907d5ac70f0Sopenharmony_ci return err; 1908d5ac70f0Sopenharmony_ci err = tplg_ref_add(parent, SND_TPLG_TYPE_DATA, id); 1909d5ac70f0Sopenharmony_ci if (err < 0) 1910d5ac70f0Sopenharmony_ci return err; 1911d5ac70f0Sopenharmony_ci tuples = NULL; 1912d5ac70f0Sopenharmony_ci } 1913d5ac70f0Sopenharmony_ci tplg_log(tplg, 'A', pos, "add bytes: size %d", tp->size); 1914d5ac70f0Sopenharmony_ci snprintf(suffix, sizeof(suffix), "data%u", block++); 1915d5ac70f0Sopenharmony_ci err = tplg_add_data_bytes(tplg, parent, suffix, tp->array, tp->size); 1916d5ac70f0Sopenharmony_ci } else { 1917d5ac70f0Sopenharmony_ci if (!tuples) { 1918d5ac70f0Sopenharmony_ci snprintf(id, sizeof(id), "%.30s:tuple%d", parent->id, (block++) & 0xffff); 1919d5ac70f0Sopenharmony_ci elem = tplg_elem_new_common(tplg, NULL, id, SND_TPLG_TYPE_TUPLE); 1920d5ac70f0Sopenharmony_ci if (!elem) 1921d5ac70f0Sopenharmony_ci return -ENOMEM; 1922d5ac70f0Sopenharmony_ci 1923d5ac70f0Sopenharmony_ci elem2 = tplg_elem_new_common(tplg, NULL, id, SND_TPLG_TYPE_DATA); 1924d5ac70f0Sopenharmony_ci if (!elem2) 1925d5ac70f0Sopenharmony_ci return -ENOMEM; 1926d5ac70f0Sopenharmony_ci 1927d5ac70f0Sopenharmony_ci tuples = calloc(1, sizeof(*tuples)); 1928d5ac70f0Sopenharmony_ci if (!tuples) 1929d5ac70f0Sopenharmony_ci return -ENOMEM; 1930d5ac70f0Sopenharmony_ci elem->tuples = tuples; 1931d5ac70f0Sopenharmony_ci 1932d5ac70f0Sopenharmony_ci tuples->alloc_sets = (size / sizeof(*va)) + 1; 1933d5ac70f0Sopenharmony_ci tuples->set = calloc(1, tuples->alloc_sets * sizeof(void *)); 1934d5ac70f0Sopenharmony_ci if (!tuples->set) { 1935d5ac70f0Sopenharmony_ci tuples->alloc_sets = 0; 1936d5ac70f0Sopenharmony_ci return -ENOMEM; 1937d5ac70f0Sopenharmony_ci } 1938d5ac70f0Sopenharmony_ci } 1939d5ac70f0Sopenharmony_ci tplg_log(tplg, 'A', pos, "decode tuples: size %d", tp->size); 1940d5ac70f0Sopenharmony_ci err = tplg_decode_tuples(tplg, pos, parent, tuples, tp->array, tp->size); 1941d5ac70f0Sopenharmony_ci num_tuples++; 1942d5ac70f0Sopenharmony_ci } 1943d5ac70f0Sopenharmony_ci if (err < 0) 1944d5ac70f0Sopenharmony_ci return err; 1945d5ac70f0Sopenharmony_ci 1946d5ac70f0Sopenharmony_ci bin += off + tp->size; 1947d5ac70f0Sopenharmony_ci size -= off + tp->size; 1948d5ac70f0Sopenharmony_ci pos += off + tp->size; 1949d5ac70f0Sopenharmony_ci if (size > 0) 1950d5ac70f0Sopenharmony_ci goto next; 1951d5ac70f0Sopenharmony_ci 1952d5ac70f0Sopenharmony_ci if (tuples && elem && elem2) { 1953d5ac70f0Sopenharmony_ci err = tplg_ref_add(elem, SND_TPLG_TYPE_TOKEN, parent->id); 1954d5ac70f0Sopenharmony_ci if (err < 0) 1955d5ac70f0Sopenharmony_ci return err; 1956d5ac70f0Sopenharmony_ci err = tplg_ref_add(elem2, SND_TPLG_TYPE_TUPLE, id); 1957d5ac70f0Sopenharmony_ci if (err < 0) 1958d5ac70f0Sopenharmony_ci return err; 1959d5ac70f0Sopenharmony_ci err = tplg_ref_add(parent, SND_TPLG_TYPE_DATA, id); 1960d5ac70f0Sopenharmony_ci if (err < 0) 1961d5ac70f0Sopenharmony_ci return err; 1962d5ac70f0Sopenharmony_ci } 1963d5ac70f0Sopenharmony_ci 1964d5ac70f0Sopenharmony_ci return 0; 1965d5ac70f0Sopenharmony_ci} 1966d5ac70f0Sopenharmony_ci 1967d5ac70f0Sopenharmony_ci/* add private data - bytes */ 1968d5ac70f0Sopenharmony_ciint tplg_add_data_bytes(snd_tplg_t *tplg, struct tplg_elem *parent, 1969d5ac70f0Sopenharmony_ci const char *suffix, const void *bin, size_t size) 1970d5ac70f0Sopenharmony_ci{ 1971d5ac70f0Sopenharmony_ci struct snd_soc_tplg_private *priv; 1972d5ac70f0Sopenharmony_ci struct tplg_elem *elem; 1973d5ac70f0Sopenharmony_ci char id[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; 1974d5ac70f0Sopenharmony_ci 1975d5ac70f0Sopenharmony_ci if (suffix) 1976d5ac70f0Sopenharmony_ci snprintf(id, sizeof(id), "%.30s:%.12s", parent->id, suffix); 1977d5ac70f0Sopenharmony_ci else 1978d5ac70f0Sopenharmony_ci snd_strlcpy(id, parent->id, sizeof(id)); 1979d5ac70f0Sopenharmony_ci elem = tplg_elem_new_common(tplg, NULL, id, SND_TPLG_TYPE_DATA); 1980d5ac70f0Sopenharmony_ci if (!elem) 1981d5ac70f0Sopenharmony_ci return -ENOMEM; 1982d5ac70f0Sopenharmony_ci 1983d5ac70f0Sopenharmony_ci priv = malloc(sizeof(*priv) + size); 1984d5ac70f0Sopenharmony_ci if (!priv) 1985d5ac70f0Sopenharmony_ci return -ENOMEM; 1986d5ac70f0Sopenharmony_ci memcpy(priv->data, bin, size); 1987d5ac70f0Sopenharmony_ci priv->size = size; 1988d5ac70f0Sopenharmony_ci elem->data = priv; 1989d5ac70f0Sopenharmony_ci 1990d5ac70f0Sopenharmony_ci return tplg_ref_add(parent, SND_TPLG_TYPE_DATA, id); 1991d5ac70f0Sopenharmony_ci} 1992d5ac70f0Sopenharmony_ci 1993d5ac70f0Sopenharmony_ci/* decode data from the binary input */ 1994d5ac70f0Sopenharmony_ciint tplg_decode_data(snd_tplg_t *tplg ATTRIBUTE_UNUSED, 1995d5ac70f0Sopenharmony_ci size_t pos ATTRIBUTE_UNUSED, 1996d5ac70f0Sopenharmony_ci struct snd_soc_tplg_hdr *hdr ATTRIBUTE_UNUSED, 1997d5ac70f0Sopenharmony_ci void *bin ATTRIBUTE_UNUSED, 1998d5ac70f0Sopenharmony_ci size_t size ATTRIBUTE_UNUSED) 1999d5ac70f0Sopenharmony_ci{ 2000d5ac70f0Sopenharmony_ci SNDERR("data type not expected"); 2001d5ac70f0Sopenharmony_ci return -EINVAL; 2002d5ac70f0Sopenharmony_ci} 2003