1d5ac70f0Sopenharmony_ci/* 2d5ac70f0Sopenharmony_ci * This library is free software; you can redistribute it and/or 3d5ac70f0Sopenharmony_ci * modify it under the terms of the GNU Lesser General Public 4d5ac70f0Sopenharmony_ci * License as published by the Free Software Foundation; either 5d5ac70f0Sopenharmony_ci * version 2 of the License, or (at your option) any later version. 6d5ac70f0Sopenharmony_ci * 7d5ac70f0Sopenharmony_ci * This library is distributed in the hope that it will be useful, 8d5ac70f0Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 9d5ac70f0Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10d5ac70f0Sopenharmony_ci * Lesser General Public License for more details. 11d5ac70f0Sopenharmony_ci * 12d5ac70f0Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public 13d5ac70f0Sopenharmony_ci * License along with this library; if not, write to the Free Software 14d5ac70f0Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 15d5ac70f0Sopenharmony_ci * 16d5ac70f0Sopenharmony_ci * Support for the verb/device/modifier core logic and API, 17d5ac70f0Sopenharmony_ci * command line tool and file parser was kindly sponsored by 18d5ac70f0Sopenharmony_ci * Texas Instruments Inc. 19d5ac70f0Sopenharmony_ci * Support for multiple active modifiers and devices, 20d5ac70f0Sopenharmony_ci * transition sequences, multiple client access and user defined use 21d5ac70f0Sopenharmony_ci * cases was kindly sponsored by Wolfson Microelectronics PLC. 22d5ac70f0Sopenharmony_ci * 23d5ac70f0Sopenharmony_ci * Copyright (C) 2008-2010 SlimLogic Ltd 24d5ac70f0Sopenharmony_ci * Copyright (C) 2010 Wolfson Microelectronics PLC 25d5ac70f0Sopenharmony_ci * Copyright (C) 2010 Texas Instruments Inc. 26d5ac70f0Sopenharmony_ci * Copyright (C) 2010 Red Hat Inc. 27d5ac70f0Sopenharmony_ci * Authors: Liam Girdwood <lrg@slimlogic.co.uk> 28d5ac70f0Sopenharmony_ci * Stefan Schmidt <stefan@slimlogic.co.uk> 29d5ac70f0Sopenharmony_ci * Justin Xu <justinx@slimlogic.co.uk> 30d5ac70f0Sopenharmony_ci * Jaroslav Kysela <perex@perex.cz> 31d5ac70f0Sopenharmony_ci */ 32d5ac70f0Sopenharmony_ci 33d5ac70f0Sopenharmony_ci#include "ucm_local.h" 34d5ac70f0Sopenharmony_ci#include <sys/stat.h> 35d5ac70f0Sopenharmony_ci#include <stdbool.h> 36d5ac70f0Sopenharmony_ci#include <dirent.h> 37d5ac70f0Sopenharmony_ci#include <limits.h> 38d5ac70f0Sopenharmony_ci 39d5ac70f0Sopenharmony_cistatic int filename_filter(const struct dirent64 *dirent); 40d5ac70f0Sopenharmony_ci 41d5ac70f0Sopenharmony_cistatic int parse_sequence(snd_use_case_mgr_t *uc_mgr, 42d5ac70f0Sopenharmony_ci struct list_head *base, 43d5ac70f0Sopenharmony_ci snd_config_t *cfg); 44d5ac70f0Sopenharmony_ci 45d5ac70f0Sopenharmony_ci/* 46d5ac70f0Sopenharmony_ci * compose the absolute ucm filename 47d5ac70f0Sopenharmony_ci */ 48d5ac70f0Sopenharmony_cistatic void ucm_filename(char *fn, size_t fn_len, long version, 49d5ac70f0Sopenharmony_ci const char *dir, const char *file) 50d5ac70f0Sopenharmony_ci{ 51d5ac70f0Sopenharmony_ci const char *env = getenv(version > 1 ? ALSA_CONFIG_UCM2_VAR : ALSA_CONFIG_UCM_VAR); 52d5ac70f0Sopenharmony_ci 53d5ac70f0Sopenharmony_ci if (file[0] == '/') 54d5ac70f0Sopenharmony_ci file++; 55d5ac70f0Sopenharmony_ci if (env == NULL) 56d5ac70f0Sopenharmony_ci snprintf(fn, fn_len, "%s/%s/%s%s%s", 57d5ac70f0Sopenharmony_ci snd_config_topdir(), version > 1 ? "ucm2" : "ucm", 58d5ac70f0Sopenharmony_ci dir ?: "", dir ? "/" : "", file); 59d5ac70f0Sopenharmony_ci else 60d5ac70f0Sopenharmony_ci snprintf(fn, fn_len, "%s/%s%s%s", 61d5ac70f0Sopenharmony_ci env, dir ?: "", dir ? "/" : "", file); 62d5ac70f0Sopenharmony_ci} 63d5ac70f0Sopenharmony_ci 64d5ac70f0Sopenharmony_ci/* 65d5ac70f0Sopenharmony_ci * 66d5ac70f0Sopenharmony_ci */ 67d5ac70f0Sopenharmony_ciint uc_mgr_config_load_file(snd_use_case_mgr_t *uc_mgr, 68d5ac70f0Sopenharmony_ci const char *file, snd_config_t **cfg) 69d5ac70f0Sopenharmony_ci{ 70d5ac70f0Sopenharmony_ci char filename[PATH_MAX]; 71d5ac70f0Sopenharmony_ci int err; 72d5ac70f0Sopenharmony_ci 73d5ac70f0Sopenharmony_ci ucm_filename(filename, sizeof(filename), uc_mgr->conf_format, 74d5ac70f0Sopenharmony_ci file[0] == '/' ? NULL : uc_mgr->conf_dir_name, 75d5ac70f0Sopenharmony_ci file); 76d5ac70f0Sopenharmony_ci err = uc_mgr_config_load(uc_mgr->conf_format, filename, cfg); 77d5ac70f0Sopenharmony_ci if (err < 0) { 78d5ac70f0Sopenharmony_ci uc_error("error: failed to open file %s: %d", filename, err); 79d5ac70f0Sopenharmony_ci return err; 80d5ac70f0Sopenharmony_ci } 81d5ac70f0Sopenharmony_ci return 0; 82d5ac70f0Sopenharmony_ci} 83d5ac70f0Sopenharmony_ci 84d5ac70f0Sopenharmony_ci/* 85d5ac70f0Sopenharmony_ci * Replace mallocated string 86d5ac70f0Sopenharmony_ci */ 87d5ac70f0Sopenharmony_cistatic char *replace_string(char **dst, const char *value) 88d5ac70f0Sopenharmony_ci{ 89d5ac70f0Sopenharmony_ci free(*dst); 90d5ac70f0Sopenharmony_ci *dst = value ? strdup(value) : NULL; 91d5ac70f0Sopenharmony_ci return *dst; 92d5ac70f0Sopenharmony_ci} 93d5ac70f0Sopenharmony_ci 94d5ac70f0Sopenharmony_ci/* 95d5ac70f0Sopenharmony_ci * Parse string 96d5ac70f0Sopenharmony_ci */ 97d5ac70f0Sopenharmony_cistatic int parse_string(snd_config_t *n, char **res) 98d5ac70f0Sopenharmony_ci{ 99d5ac70f0Sopenharmony_ci int err; 100d5ac70f0Sopenharmony_ci 101d5ac70f0Sopenharmony_ci err = snd_config_get_string(n, (const char **)res); 102d5ac70f0Sopenharmony_ci if (err < 0) 103d5ac70f0Sopenharmony_ci return err; 104d5ac70f0Sopenharmony_ci *res = strdup(*res); 105d5ac70f0Sopenharmony_ci if (*res == NULL) 106d5ac70f0Sopenharmony_ci return -ENOMEM; 107d5ac70f0Sopenharmony_ci return 0; 108d5ac70f0Sopenharmony_ci} 109d5ac70f0Sopenharmony_ci 110d5ac70f0Sopenharmony_ci/* 111d5ac70f0Sopenharmony_ci * Parse string and substitute 112d5ac70f0Sopenharmony_ci */ 113d5ac70f0Sopenharmony_cistatic int parse_string_substitute(snd_use_case_mgr_t *uc_mgr, 114d5ac70f0Sopenharmony_ci snd_config_t *n, char **res) 115d5ac70f0Sopenharmony_ci{ 116d5ac70f0Sopenharmony_ci const char *str; 117d5ac70f0Sopenharmony_ci char *s; 118d5ac70f0Sopenharmony_ci int err; 119d5ac70f0Sopenharmony_ci 120d5ac70f0Sopenharmony_ci err = snd_config_get_string(n, &str); 121d5ac70f0Sopenharmony_ci if (err < 0) 122d5ac70f0Sopenharmony_ci return err; 123d5ac70f0Sopenharmony_ci err = uc_mgr_get_substituted_value(uc_mgr, &s, str); 124d5ac70f0Sopenharmony_ci if (err >= 0) 125d5ac70f0Sopenharmony_ci *res = s; 126d5ac70f0Sopenharmony_ci return err; 127d5ac70f0Sopenharmony_ci} 128d5ac70f0Sopenharmony_ci 129d5ac70f0Sopenharmony_ci/* 130d5ac70f0Sopenharmony_ci * Parse string and substitute 131d5ac70f0Sopenharmony_ci */ 132d5ac70f0Sopenharmony_cistatic int parse_string_substitute3(snd_use_case_mgr_t *uc_mgr, 133d5ac70f0Sopenharmony_ci snd_config_t *n, char **res) 134d5ac70f0Sopenharmony_ci{ 135d5ac70f0Sopenharmony_ci if (uc_mgr->conf_format < 3) 136d5ac70f0Sopenharmony_ci return parse_string(n, res); 137d5ac70f0Sopenharmony_ci return parse_string_substitute(uc_mgr, n, res); 138d5ac70f0Sopenharmony_ci} 139d5ac70f0Sopenharmony_ci 140d5ac70f0Sopenharmony_ci/* 141d5ac70f0Sopenharmony_ci * Parse integer with substitution 142d5ac70f0Sopenharmony_ci */ 143d5ac70f0Sopenharmony_cistatic int parse_integer_substitute(snd_use_case_mgr_t *uc_mgr, 144d5ac70f0Sopenharmony_ci snd_config_t *n, long *res) 145d5ac70f0Sopenharmony_ci{ 146d5ac70f0Sopenharmony_ci char *s1, *s2; 147d5ac70f0Sopenharmony_ci int err; 148d5ac70f0Sopenharmony_ci 149d5ac70f0Sopenharmony_ci err = snd_config_get_ascii(n, &s1); 150d5ac70f0Sopenharmony_ci if (err < 0) 151d5ac70f0Sopenharmony_ci return err; 152d5ac70f0Sopenharmony_ci err = uc_mgr_get_substituted_value(uc_mgr, &s2, s1); 153d5ac70f0Sopenharmony_ci if (err >= 0) 154d5ac70f0Sopenharmony_ci err = safe_strtol(s2, res); 155d5ac70f0Sopenharmony_ci free(s2); 156d5ac70f0Sopenharmony_ci free(s1); 157d5ac70f0Sopenharmony_ci return err; 158d5ac70f0Sopenharmony_ci} 159d5ac70f0Sopenharmony_ci 160d5ac70f0Sopenharmony_ci/* 161d5ac70f0Sopenharmony_ci * Parse integer with substitution 162d5ac70f0Sopenharmony_ci */ 163d5ac70f0Sopenharmony_cistatic int parse_integer_substitute3(snd_use_case_mgr_t *uc_mgr, 164d5ac70f0Sopenharmony_ci snd_config_t *n, long *res) 165d5ac70f0Sopenharmony_ci{ 166d5ac70f0Sopenharmony_ci char *s1, *s2; 167d5ac70f0Sopenharmony_ci int err; 168d5ac70f0Sopenharmony_ci 169d5ac70f0Sopenharmony_ci err = snd_config_get_ascii(n, &s1); 170d5ac70f0Sopenharmony_ci if (err < 0) 171d5ac70f0Sopenharmony_ci return err; 172d5ac70f0Sopenharmony_ci if (uc_mgr->conf_format < 3) 173d5ac70f0Sopenharmony_ci s2 = s1; 174d5ac70f0Sopenharmony_ci else 175d5ac70f0Sopenharmony_ci err = uc_mgr_get_substituted_value(uc_mgr, &s2, s1); 176d5ac70f0Sopenharmony_ci if (err >= 0) 177d5ac70f0Sopenharmony_ci err = safe_strtol(s2, res); 178d5ac70f0Sopenharmony_ci if (s1 != s2) 179d5ac70f0Sopenharmony_ci free(s2); 180d5ac70f0Sopenharmony_ci free(s1); 181d5ac70f0Sopenharmony_ci return err; 182d5ac70f0Sopenharmony_ci} 183d5ac70f0Sopenharmony_ci 184d5ac70f0Sopenharmony_ci/* 185d5ac70f0Sopenharmony_ci * Parse safe ID 186d5ac70f0Sopenharmony_ci */ 187d5ac70f0Sopenharmony_cistatic int parse_is_name_safe(const char *name) 188d5ac70f0Sopenharmony_ci{ 189d5ac70f0Sopenharmony_ci if (strchr(name, '.')) { 190d5ac70f0Sopenharmony_ci uc_error("char '.' not allowed in '%s'", name); 191d5ac70f0Sopenharmony_ci return 0; 192d5ac70f0Sopenharmony_ci } 193d5ac70f0Sopenharmony_ci return 1; 194d5ac70f0Sopenharmony_ci} 195d5ac70f0Sopenharmony_ci 196d5ac70f0Sopenharmony_cistatic int get_string3(snd_use_case_mgr_t *uc_mgr, const char *s1, char **s) 197d5ac70f0Sopenharmony_ci{ 198d5ac70f0Sopenharmony_ci if (uc_mgr->conf_format < 3) { 199d5ac70f0Sopenharmony_ci *s = strdup(s1); 200d5ac70f0Sopenharmony_ci if (*s == NULL) 201d5ac70f0Sopenharmony_ci return -ENOMEM; 202d5ac70f0Sopenharmony_ci return 0; 203d5ac70f0Sopenharmony_ci } 204d5ac70f0Sopenharmony_ci return uc_mgr_get_substituted_value(uc_mgr, s, s1); 205d5ac70f0Sopenharmony_ci} 206d5ac70f0Sopenharmony_ci 207d5ac70f0Sopenharmony_cistatic int parse_get_safe_name(snd_use_case_mgr_t *uc_mgr, snd_config_t *n, 208d5ac70f0Sopenharmony_ci const char *alt, char **name) 209d5ac70f0Sopenharmony_ci{ 210d5ac70f0Sopenharmony_ci const char *id; 211d5ac70f0Sopenharmony_ci int err; 212d5ac70f0Sopenharmony_ci 213d5ac70f0Sopenharmony_ci if (alt) { 214d5ac70f0Sopenharmony_ci id = alt; 215d5ac70f0Sopenharmony_ci } else { 216d5ac70f0Sopenharmony_ci err = snd_config_get_id(n, &id); 217d5ac70f0Sopenharmony_ci if (err < 0) 218d5ac70f0Sopenharmony_ci return err; 219d5ac70f0Sopenharmony_ci } 220d5ac70f0Sopenharmony_ci err = get_string3(uc_mgr, id, name); 221d5ac70f0Sopenharmony_ci if (err < 0) 222d5ac70f0Sopenharmony_ci return err; 223d5ac70f0Sopenharmony_ci if (!parse_is_name_safe(*name)) { 224d5ac70f0Sopenharmony_ci free(*name); 225d5ac70f0Sopenharmony_ci return -EINVAL; 226d5ac70f0Sopenharmony_ci } 227d5ac70f0Sopenharmony_ci return 0; 228d5ac70f0Sopenharmony_ci} 229d5ac70f0Sopenharmony_ci 230d5ac70f0Sopenharmony_ci/* 231d5ac70f0Sopenharmony_ci * Handle 'Error' configuration node. 232d5ac70f0Sopenharmony_ci */ 233d5ac70f0Sopenharmony_cistatic int error_node(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) 234d5ac70f0Sopenharmony_ci{ 235d5ac70f0Sopenharmony_ci int err; 236d5ac70f0Sopenharmony_ci char *s; 237d5ac70f0Sopenharmony_ci 238d5ac70f0Sopenharmony_ci err = parse_string_substitute3(uc_mgr, cfg, &s); 239d5ac70f0Sopenharmony_ci if (err < 0) { 240d5ac70f0Sopenharmony_ci uc_error("error: failed to get Error string"); 241d5ac70f0Sopenharmony_ci return err; 242d5ac70f0Sopenharmony_ci } 243d5ac70f0Sopenharmony_ci if (!uc_mgr->suppress_nodev_errors) 244d5ac70f0Sopenharmony_ci uc_error("%s", s); 245d5ac70f0Sopenharmony_ci free(s); 246d5ac70f0Sopenharmony_ci return -ENXIO; 247d5ac70f0Sopenharmony_ci} 248d5ac70f0Sopenharmony_ci 249d5ac70f0Sopenharmony_ci/* 250d5ac70f0Sopenharmony_ci * 251d5ac70f0Sopenharmony_ci */ 252d5ac70f0Sopenharmony_cistatic int parse_syntax_field(snd_use_case_mgr_t *uc_mgr, 253d5ac70f0Sopenharmony_ci snd_config_t *cfg, const char *filename) 254d5ac70f0Sopenharmony_ci{ 255d5ac70f0Sopenharmony_ci snd_config_t *n; 256d5ac70f0Sopenharmony_ci long l; 257d5ac70f0Sopenharmony_ci int err; 258d5ac70f0Sopenharmony_ci 259d5ac70f0Sopenharmony_ci err = snd_config_search(cfg, "Syntax", &n); 260d5ac70f0Sopenharmony_ci if (err < 0) { 261d5ac70f0Sopenharmony_ci uc_error("Syntax field not found in %s", filename); 262d5ac70f0Sopenharmony_ci return -EINVAL; 263d5ac70f0Sopenharmony_ci } 264d5ac70f0Sopenharmony_ci err = snd_config_get_integer(n, &l); 265d5ac70f0Sopenharmony_ci if (err < 0) { 266d5ac70f0Sopenharmony_ci uc_error("Syntax field is invalid in %s", filename); 267d5ac70f0Sopenharmony_ci return err; 268d5ac70f0Sopenharmony_ci } 269d5ac70f0Sopenharmony_ci if (l < 2 || l > SYNTAX_VERSION_MAX) { 270d5ac70f0Sopenharmony_ci uc_error("Incompatible syntax %ld in %s", l, filename); 271d5ac70f0Sopenharmony_ci return -EINVAL; 272d5ac70f0Sopenharmony_ci } 273d5ac70f0Sopenharmony_ci /* delete this field to optimize strcmp() call in the parsing loop */ 274d5ac70f0Sopenharmony_ci snd_config_delete(n); 275d5ac70f0Sopenharmony_ci uc_mgr->conf_format = l; 276d5ac70f0Sopenharmony_ci return l; 277d5ac70f0Sopenharmony_ci} 278d5ac70f0Sopenharmony_ci 279d5ac70f0Sopenharmony_ci/* 280d5ac70f0Sopenharmony_ci * Evaluate variable regex definitions (in-place delete) 281d5ac70f0Sopenharmony_ci */ 282d5ac70f0Sopenharmony_cistatic int evaluate_regex(snd_use_case_mgr_t *uc_mgr, 283d5ac70f0Sopenharmony_ci snd_config_t *cfg) 284d5ac70f0Sopenharmony_ci{ 285d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 286d5ac70f0Sopenharmony_ci snd_config_t *d, *n; 287d5ac70f0Sopenharmony_ci const char *id; 288d5ac70f0Sopenharmony_ci int err; 289d5ac70f0Sopenharmony_ci 290d5ac70f0Sopenharmony_ci err = snd_config_search(cfg, "DefineRegex", &d); 291d5ac70f0Sopenharmony_ci if (err == -ENOENT) 292d5ac70f0Sopenharmony_ci return 1; 293d5ac70f0Sopenharmony_ci if (err < 0) 294d5ac70f0Sopenharmony_ci return err; 295d5ac70f0Sopenharmony_ci 296d5ac70f0Sopenharmony_ci if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) { 297d5ac70f0Sopenharmony_ci uc_error("compound type expected for DefineRegex"); 298d5ac70f0Sopenharmony_ci return -EINVAL; 299d5ac70f0Sopenharmony_ci } 300d5ac70f0Sopenharmony_ci 301d5ac70f0Sopenharmony_ci if (uc_mgr->conf_format < 3) { 302d5ac70f0Sopenharmony_ci uc_error("DefineRegex is supported in v3+ syntax"); 303d5ac70f0Sopenharmony_ci return -EINVAL; 304d5ac70f0Sopenharmony_ci } 305d5ac70f0Sopenharmony_ci 306d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, d) { 307d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 308d5ac70f0Sopenharmony_ci err = snd_config_get_id(n, &id); 309d5ac70f0Sopenharmony_ci if (err < 0) 310d5ac70f0Sopenharmony_ci return err; 311d5ac70f0Sopenharmony_ci if (id[0] == '@') { 312d5ac70f0Sopenharmony_ci uc_error("error: value names starting with '@' are reserved for application variables"); 313d5ac70f0Sopenharmony_ci return -EINVAL; 314d5ac70f0Sopenharmony_ci } 315d5ac70f0Sopenharmony_ci err = uc_mgr_define_regex(uc_mgr, id, n); 316d5ac70f0Sopenharmony_ci if (err < 0) 317d5ac70f0Sopenharmony_ci return err; 318d5ac70f0Sopenharmony_ci } 319d5ac70f0Sopenharmony_ci 320d5ac70f0Sopenharmony_ci snd_config_delete(d); 321d5ac70f0Sopenharmony_ci return 0; 322d5ac70f0Sopenharmony_ci} 323d5ac70f0Sopenharmony_ci 324d5ac70f0Sopenharmony_ci/* 325d5ac70f0Sopenharmony_ci * Evaluate variable definitions (in-place delete) 326d5ac70f0Sopenharmony_ci */ 327d5ac70f0Sopenharmony_cistatic int evaluate_define(snd_use_case_mgr_t *uc_mgr, 328d5ac70f0Sopenharmony_ci snd_config_t *cfg) 329d5ac70f0Sopenharmony_ci{ 330d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 331d5ac70f0Sopenharmony_ci snd_config_t *d, *n; 332d5ac70f0Sopenharmony_ci const char *id; 333d5ac70f0Sopenharmony_ci char *var, *s; 334d5ac70f0Sopenharmony_ci int err; 335d5ac70f0Sopenharmony_ci 336d5ac70f0Sopenharmony_ci err = snd_config_search(cfg, "Define", &d); 337d5ac70f0Sopenharmony_ci if (err == -ENOENT) 338d5ac70f0Sopenharmony_ci return evaluate_regex(uc_mgr, cfg); 339d5ac70f0Sopenharmony_ci if (err < 0) 340d5ac70f0Sopenharmony_ci return err; 341d5ac70f0Sopenharmony_ci 342d5ac70f0Sopenharmony_ci if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) { 343d5ac70f0Sopenharmony_ci uc_error("compound type expected for Define"); 344d5ac70f0Sopenharmony_ci return -EINVAL; 345d5ac70f0Sopenharmony_ci } 346d5ac70f0Sopenharmony_ci 347d5ac70f0Sopenharmony_ci if (uc_mgr->conf_format < 3) { 348d5ac70f0Sopenharmony_ci uc_error("Define is supported in v3+ syntax"); 349d5ac70f0Sopenharmony_ci return -EINVAL; 350d5ac70f0Sopenharmony_ci } 351d5ac70f0Sopenharmony_ci 352d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, d) { 353d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 354d5ac70f0Sopenharmony_ci err = snd_config_get_id(n, &id); 355d5ac70f0Sopenharmony_ci if (err < 0) 356d5ac70f0Sopenharmony_ci return err; 357d5ac70f0Sopenharmony_ci err = snd_config_get_ascii(n, &var); 358d5ac70f0Sopenharmony_ci if (err < 0) 359d5ac70f0Sopenharmony_ci return err; 360d5ac70f0Sopenharmony_ci err = uc_mgr_get_substituted_value(uc_mgr, &s, var); 361d5ac70f0Sopenharmony_ci free(var); 362d5ac70f0Sopenharmony_ci if (err < 0) 363d5ac70f0Sopenharmony_ci return err; 364d5ac70f0Sopenharmony_ci if (id[0] == '@') { 365d5ac70f0Sopenharmony_ci free(s); 366d5ac70f0Sopenharmony_ci uc_error("error: value names starting with '@' are reserved for application variables"); 367d5ac70f0Sopenharmony_ci return -EINVAL; 368d5ac70f0Sopenharmony_ci } 369d5ac70f0Sopenharmony_ci err = uc_mgr_set_variable(uc_mgr, id, s); 370d5ac70f0Sopenharmony_ci free(s); 371d5ac70f0Sopenharmony_ci if (err < 0) 372d5ac70f0Sopenharmony_ci return err; 373d5ac70f0Sopenharmony_ci } 374d5ac70f0Sopenharmony_ci 375d5ac70f0Sopenharmony_ci snd_config_delete(d); 376d5ac70f0Sopenharmony_ci 377d5ac70f0Sopenharmony_ci return evaluate_regex(uc_mgr, cfg); 378d5ac70f0Sopenharmony_ci} 379d5ac70f0Sopenharmony_ci 380d5ac70f0Sopenharmony_ci/* 381d5ac70f0Sopenharmony_ci * Evaluate macro definitions (in-place delete) 382d5ac70f0Sopenharmony_ci */ 383d5ac70f0Sopenharmony_cistatic int evaluate_define_macro(snd_use_case_mgr_t *uc_mgr, 384d5ac70f0Sopenharmony_ci snd_config_t *cfg) 385d5ac70f0Sopenharmony_ci{ 386d5ac70f0Sopenharmony_ci snd_config_t *d; 387d5ac70f0Sopenharmony_ci int err; 388d5ac70f0Sopenharmony_ci 389d5ac70f0Sopenharmony_ci err = snd_config_search(cfg, "DefineMacro", &d); 390d5ac70f0Sopenharmony_ci if (err == -ENOENT) 391d5ac70f0Sopenharmony_ci return 1; 392d5ac70f0Sopenharmony_ci if (err < 0) 393d5ac70f0Sopenharmony_ci return err; 394d5ac70f0Sopenharmony_ci 395d5ac70f0Sopenharmony_ci if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) { 396d5ac70f0Sopenharmony_ci uc_error("compound type expected for DefineMacro"); 397d5ac70f0Sopenharmony_ci return -EINVAL; 398d5ac70f0Sopenharmony_ci } 399d5ac70f0Sopenharmony_ci 400d5ac70f0Sopenharmony_ci if (uc_mgr->conf_format < 6) { 401d5ac70f0Sopenharmony_ci uc_error("DefineMacro is supported in v6+ syntax"); 402d5ac70f0Sopenharmony_ci return -EINVAL; 403d5ac70f0Sopenharmony_ci } 404d5ac70f0Sopenharmony_ci 405d5ac70f0Sopenharmony_ci err = snd_config_merge(uc_mgr->macros, d, 0); 406d5ac70f0Sopenharmony_ci if (err < 0) 407d5ac70f0Sopenharmony_ci return err; 408d5ac70f0Sopenharmony_ci return 0; 409d5ac70f0Sopenharmony_ci} 410d5ac70f0Sopenharmony_ci 411d5ac70f0Sopenharmony_cistatic int evaluate_macro1(snd_use_case_mgr_t *uc_mgr, 412d5ac70f0Sopenharmony_ci snd_config_t *dst, 413d5ac70f0Sopenharmony_ci snd_config_t *args) 414d5ac70f0Sopenharmony_ci{ 415d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 416d5ac70f0Sopenharmony_ci snd_config_t *m, *mc, *a, *n; 417d5ac70f0Sopenharmony_ci const char *mid, *id; 418d5ac70f0Sopenharmony_ci char name[128], *var; 419d5ac70f0Sopenharmony_ci const char *s; 420d5ac70f0Sopenharmony_ci int err; 421d5ac70f0Sopenharmony_ci 422d5ac70f0Sopenharmony_ci err = snd_config_get_id(args, &mid); 423d5ac70f0Sopenharmony_ci if (err < 0) 424d5ac70f0Sopenharmony_ci return err; 425d5ac70f0Sopenharmony_ci err = snd_config_search(uc_mgr->macros, mid, &m); 426d5ac70f0Sopenharmony_ci if (err < 0) { 427d5ac70f0Sopenharmony_ci uc_error("Macro '%s' is not defined", mid); 428d5ac70f0Sopenharmony_ci return err; 429d5ac70f0Sopenharmony_ci } 430d5ac70f0Sopenharmony_ci 431d5ac70f0Sopenharmony_ci a = args; 432d5ac70f0Sopenharmony_ci if (snd_config_get_type(args) == SND_CONFIG_TYPE_STRING) { 433d5ac70f0Sopenharmony_ci err = snd_config_get_string(args, &s); 434d5ac70f0Sopenharmony_ci if (err < 0) 435d5ac70f0Sopenharmony_ci return err; 436d5ac70f0Sopenharmony_ci err = snd_config_load_string(&a, s, 0); 437d5ac70f0Sopenharmony_ci if (err < 0) 438d5ac70f0Sopenharmony_ci return err; 439d5ac70f0Sopenharmony_ci } else if (snd_config_get_type(args) != SND_CONFIG_TYPE_COMPOUND) { 440d5ac70f0Sopenharmony_ci return -EINVAL; 441d5ac70f0Sopenharmony_ci } 442d5ac70f0Sopenharmony_ci 443d5ac70f0Sopenharmony_ci /* set arguments */ 444d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, a) { 445d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 446d5ac70f0Sopenharmony_ci err = snd_config_get_id(n, &id); 447d5ac70f0Sopenharmony_ci if (err < 0) 448d5ac70f0Sopenharmony_ci goto __err_path; 449d5ac70f0Sopenharmony_ci err = snd_config_get_ascii(n, &var); 450d5ac70f0Sopenharmony_ci if (err < 0) 451d5ac70f0Sopenharmony_ci goto __err_path; 452d5ac70f0Sopenharmony_ci snprintf(name, sizeof(name), "__%s", id); 453d5ac70f0Sopenharmony_ci err = uc_mgr_set_variable(uc_mgr, name, var); 454d5ac70f0Sopenharmony_ci free(var); 455d5ac70f0Sopenharmony_ci if (err < 0) 456d5ac70f0Sopenharmony_ci goto __err_path; 457d5ac70f0Sopenharmony_ci } 458d5ac70f0Sopenharmony_ci 459d5ac70f0Sopenharmony_ci /* merge + substitute variables */ 460d5ac70f0Sopenharmony_ci err = snd_config_copy(&mc, m); 461d5ac70f0Sopenharmony_ci if (err < 0) 462d5ac70f0Sopenharmony_ci goto __err_path; 463d5ac70f0Sopenharmony_ci err = uc_mgr_evaluate_inplace(uc_mgr, mc); 464d5ac70f0Sopenharmony_ci if (err < 0) { 465d5ac70f0Sopenharmony_ci snd_config_delete(mc); 466d5ac70f0Sopenharmony_ci goto __err_path; 467d5ac70f0Sopenharmony_ci } 468d5ac70f0Sopenharmony_ci err = uc_mgr_config_tree_merge(uc_mgr, dst, mc, NULL, NULL); 469d5ac70f0Sopenharmony_ci snd_config_delete(mc); 470d5ac70f0Sopenharmony_ci 471d5ac70f0Sopenharmony_ci /* delete arguments */ 472d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, a) { 473d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 474d5ac70f0Sopenharmony_ci err = snd_config_get_id(n, &id); 475d5ac70f0Sopenharmony_ci if (err < 0) 476d5ac70f0Sopenharmony_ci goto __err_path; 477d5ac70f0Sopenharmony_ci snprintf(name, sizeof(name), "__%s", id); 478d5ac70f0Sopenharmony_ci err = uc_mgr_delete_variable(uc_mgr, name); 479d5ac70f0Sopenharmony_ci if (err < 0) 480d5ac70f0Sopenharmony_ci goto __err_path; 481d5ac70f0Sopenharmony_ci } 482d5ac70f0Sopenharmony_ci 483d5ac70f0Sopenharmony_ci__err_path: 484d5ac70f0Sopenharmony_ci if (a != args) 485d5ac70f0Sopenharmony_ci snd_config_delete(a); 486d5ac70f0Sopenharmony_ci return err; 487d5ac70f0Sopenharmony_ci} 488d5ac70f0Sopenharmony_ci 489d5ac70f0Sopenharmony_ci/* 490d5ac70f0Sopenharmony_ci * Evaluate macro definitions and instances (in-place delete) 491d5ac70f0Sopenharmony_ci */ 492d5ac70f0Sopenharmony_cistatic int evaluate_macro(snd_use_case_mgr_t *uc_mgr, 493d5ac70f0Sopenharmony_ci snd_config_t *cfg) 494d5ac70f0Sopenharmony_ci{ 495d5ac70f0Sopenharmony_ci snd_config_iterator_t i, i2, next, next2; 496d5ac70f0Sopenharmony_ci snd_config_t *d, *n, *n2; 497d5ac70f0Sopenharmony_ci int err, ret; 498d5ac70f0Sopenharmony_ci 499d5ac70f0Sopenharmony_ci ret = evaluate_define_macro(uc_mgr, cfg); 500d5ac70f0Sopenharmony_ci if (ret < 0) 501d5ac70f0Sopenharmony_ci return ret; 502d5ac70f0Sopenharmony_ci 503d5ac70f0Sopenharmony_ci err = snd_config_search(cfg, "Macro", &d); 504d5ac70f0Sopenharmony_ci if (err == -ENOENT) 505d5ac70f0Sopenharmony_ci return ret; 506d5ac70f0Sopenharmony_ci if (err < 0) 507d5ac70f0Sopenharmony_ci return err; 508d5ac70f0Sopenharmony_ci 509d5ac70f0Sopenharmony_ci if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) { 510d5ac70f0Sopenharmony_ci uc_error("compound type expected for DefineMacro"); 511d5ac70f0Sopenharmony_ci return -EINVAL; 512d5ac70f0Sopenharmony_ci } 513d5ac70f0Sopenharmony_ci 514d5ac70f0Sopenharmony_ci if (uc_mgr->conf_format < 6) { 515d5ac70f0Sopenharmony_ci uc_error("Macro is supported in v6+ syntax"); 516d5ac70f0Sopenharmony_ci return -EINVAL; 517d5ac70f0Sopenharmony_ci } 518d5ac70f0Sopenharmony_ci 519d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, d) { 520d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 521d5ac70f0Sopenharmony_ci if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { 522d5ac70f0Sopenharmony_ci const char *id; 523d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id)) 524d5ac70f0Sopenharmony_ci id = ""; 525d5ac70f0Sopenharmony_ci uc_error("compound type expected for Macro.%s", id); 526d5ac70f0Sopenharmony_ci return -EINVAL; 527d5ac70f0Sopenharmony_ci } 528d5ac70f0Sopenharmony_ci snd_config_for_each(i2, next2, n) { 529d5ac70f0Sopenharmony_ci n2 = snd_config_iterator_entry(i2); 530d5ac70f0Sopenharmony_ci err = evaluate_macro1(uc_mgr, cfg, n2); 531d5ac70f0Sopenharmony_ci if (err < 0) 532d5ac70f0Sopenharmony_ci return err; 533d5ac70f0Sopenharmony_ci } 534d5ac70f0Sopenharmony_ci } 535d5ac70f0Sopenharmony_ci 536d5ac70f0Sopenharmony_ci snd_config_delete(d); 537d5ac70f0Sopenharmony_ci 538d5ac70f0Sopenharmony_ci return 0; 539d5ac70f0Sopenharmony_ci} 540d5ac70f0Sopenharmony_ci 541d5ac70f0Sopenharmony_ci/* 542d5ac70f0Sopenharmony_ci * Evaluate include (in-place) 543d5ac70f0Sopenharmony_ci */ 544d5ac70f0Sopenharmony_cistatic int evaluate_include(snd_use_case_mgr_t *uc_mgr, 545d5ac70f0Sopenharmony_ci snd_config_t *cfg) 546d5ac70f0Sopenharmony_ci{ 547d5ac70f0Sopenharmony_ci snd_config_t *n; 548d5ac70f0Sopenharmony_ci int err; 549d5ac70f0Sopenharmony_ci 550d5ac70f0Sopenharmony_ci err = snd_config_search(cfg, "Include", &n); 551d5ac70f0Sopenharmony_ci if (err == -ENOENT) 552d5ac70f0Sopenharmony_ci return 1; 553d5ac70f0Sopenharmony_ci if (err < 0) 554d5ac70f0Sopenharmony_ci return err; 555d5ac70f0Sopenharmony_ci 556d5ac70f0Sopenharmony_ci err = uc_mgr_evaluate_include(uc_mgr, cfg, n); 557d5ac70f0Sopenharmony_ci snd_config_delete(n); 558d5ac70f0Sopenharmony_ci return err; 559d5ac70f0Sopenharmony_ci} 560d5ac70f0Sopenharmony_ci 561d5ac70f0Sopenharmony_ci/* 562d5ac70f0Sopenharmony_ci * Evaluate condition (in-place) 563d5ac70f0Sopenharmony_ci */ 564d5ac70f0Sopenharmony_cistatic int evaluate_condition(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) 565d5ac70f0Sopenharmony_ci{ 566d5ac70f0Sopenharmony_ci snd_config_t *n; 567d5ac70f0Sopenharmony_ci int err; 568d5ac70f0Sopenharmony_ci 569d5ac70f0Sopenharmony_ci err = snd_config_search(cfg, "If", &n); 570d5ac70f0Sopenharmony_ci if (err == -ENOENT) 571d5ac70f0Sopenharmony_ci return 1; 572d5ac70f0Sopenharmony_ci if (err < 0) 573d5ac70f0Sopenharmony_ci return err; 574d5ac70f0Sopenharmony_ci 575d5ac70f0Sopenharmony_ci err = uc_mgr_evaluate_condition(uc_mgr, cfg, n); 576d5ac70f0Sopenharmony_ci snd_config_delete(n); 577d5ac70f0Sopenharmony_ci return err; 578d5ac70f0Sopenharmony_ci} 579d5ac70f0Sopenharmony_ci 580d5ac70f0Sopenharmony_ci/* 581d5ac70f0Sopenharmony_ci * Evaluate variant (in-place) 582d5ac70f0Sopenharmony_ci */ 583d5ac70f0Sopenharmony_cistatic int evaluate_variant(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) 584d5ac70f0Sopenharmony_ci{ 585d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 586d5ac70f0Sopenharmony_ci snd_config_t *n, *c; 587d5ac70f0Sopenharmony_ci const char *id; 588d5ac70f0Sopenharmony_ci int err; 589d5ac70f0Sopenharmony_ci 590d5ac70f0Sopenharmony_ci err = snd_config_search(cfg, "Variant", &c); 591d5ac70f0Sopenharmony_ci if (err == -ENOENT) 592d5ac70f0Sopenharmony_ci return 1; 593d5ac70f0Sopenharmony_ci if (err < 0) 594d5ac70f0Sopenharmony_ci return err; 595d5ac70f0Sopenharmony_ci 596d5ac70f0Sopenharmony_ci if (uc_mgr->conf_format < 6) { 597d5ac70f0Sopenharmony_ci uc_error("Variant is supported in v6+ syntax"); 598d5ac70f0Sopenharmony_ci return -EINVAL; 599d5ac70f0Sopenharmony_ci } 600d5ac70f0Sopenharmony_ci 601d5ac70f0Sopenharmony_ci if (uc_mgr->parse_master_section) 602d5ac70f0Sopenharmony_ci return 1; 603d5ac70f0Sopenharmony_ci 604d5ac70f0Sopenharmony_ci if (uc_mgr->parse_variant == NULL) 605d5ac70f0Sopenharmony_ci goto __ret; 606d5ac70f0Sopenharmony_ci 607d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, c) { 608d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 609d5ac70f0Sopenharmony_ci 610d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 611d5ac70f0Sopenharmony_ci return -EINVAL; 612d5ac70f0Sopenharmony_ci 613d5ac70f0Sopenharmony_ci if (strcmp(id, uc_mgr->parse_variant)) 614d5ac70f0Sopenharmony_ci continue; 615d5ac70f0Sopenharmony_ci 616d5ac70f0Sopenharmony_ci err = uc_mgr_evaluate_inplace(uc_mgr, n); 617d5ac70f0Sopenharmony_ci if (err < 0) 618d5ac70f0Sopenharmony_ci return err; 619d5ac70f0Sopenharmony_ci 620d5ac70f0Sopenharmony_ci err = uc_mgr_config_tree_merge(uc_mgr, cfg, n, NULL, NULL); 621d5ac70f0Sopenharmony_ci if (err < 0) 622d5ac70f0Sopenharmony_ci return err; 623d5ac70f0Sopenharmony_ci snd_config_delete(c); 624d5ac70f0Sopenharmony_ci return 0; 625d5ac70f0Sopenharmony_ci } 626d5ac70f0Sopenharmony_ci 627d5ac70f0Sopenharmony_ci__ret: 628d5ac70f0Sopenharmony_ci snd_config_delete(c); 629d5ac70f0Sopenharmony_ci return 1; 630d5ac70f0Sopenharmony_ci} 631d5ac70f0Sopenharmony_ci 632d5ac70f0Sopenharmony_ci/* 633d5ac70f0Sopenharmony_ci * In-place evaluate 634d5ac70f0Sopenharmony_ci */ 635d5ac70f0Sopenharmony_ciint uc_mgr_evaluate_inplace(snd_use_case_mgr_t *uc_mgr, 636d5ac70f0Sopenharmony_ci snd_config_t *cfg) 637d5ac70f0Sopenharmony_ci{ 638d5ac70f0Sopenharmony_ci long iterations = 10000; 639d5ac70f0Sopenharmony_ci int err1 = 0, err2 = 0, err3 = 0, err4 = 0, err5 = 0; 640d5ac70f0Sopenharmony_ci 641d5ac70f0Sopenharmony_ci while (err1 == 0 || err2 == 0 || err3 == 0 || err4 == 0 || err5 == 0) { 642d5ac70f0Sopenharmony_ci if (iterations == 0) { 643d5ac70f0Sopenharmony_ci uc_error("Maximal inplace evaluation iterations number reached (recursive references?)"); 644d5ac70f0Sopenharmony_ci return -EINVAL; 645d5ac70f0Sopenharmony_ci } 646d5ac70f0Sopenharmony_ci iterations--; 647d5ac70f0Sopenharmony_ci /* variables at first */ 648d5ac70f0Sopenharmony_ci err1 = evaluate_define(uc_mgr, cfg); 649d5ac70f0Sopenharmony_ci if (err1 < 0) 650d5ac70f0Sopenharmony_ci return err1; 651d5ac70f0Sopenharmony_ci /* include at second */ 652d5ac70f0Sopenharmony_ci err2 = evaluate_include(uc_mgr, cfg); 653d5ac70f0Sopenharmony_ci if (err2 < 0) 654d5ac70f0Sopenharmony_ci return err2; 655d5ac70f0Sopenharmony_ci /* include or macro may define another variables */ 656d5ac70f0Sopenharmony_ci /* conditions may depend on them */ 657d5ac70f0Sopenharmony_ci if (err2 == 0) 658d5ac70f0Sopenharmony_ci continue; 659d5ac70f0Sopenharmony_ci err3 = evaluate_variant(uc_mgr, cfg); 660d5ac70f0Sopenharmony_ci if (err3 < 0) 661d5ac70f0Sopenharmony_ci return err3; 662d5ac70f0Sopenharmony_ci if (err3 == 0) 663d5ac70f0Sopenharmony_ci continue; 664d5ac70f0Sopenharmony_ci uc_mgr->macro_hops++; 665d5ac70f0Sopenharmony_ci if (uc_mgr->macro_hops > 100) { 666d5ac70f0Sopenharmony_ci uc_error("Maximal macro hops reached!"); 667d5ac70f0Sopenharmony_ci return -EINVAL; 668d5ac70f0Sopenharmony_ci } 669d5ac70f0Sopenharmony_ci err4 = evaluate_macro(uc_mgr, cfg); 670d5ac70f0Sopenharmony_ci uc_mgr->macro_hops--; 671d5ac70f0Sopenharmony_ci if (err4 < 0) 672d5ac70f0Sopenharmony_ci return err4; 673d5ac70f0Sopenharmony_ci if (err4 == 0) 674d5ac70f0Sopenharmony_ci continue; 675d5ac70f0Sopenharmony_ci err5 = evaluate_condition(uc_mgr, cfg); 676d5ac70f0Sopenharmony_ci if (err5 < 0) 677d5ac70f0Sopenharmony_ci return err5; 678d5ac70f0Sopenharmony_ci } 679d5ac70f0Sopenharmony_ci return 0; 680d5ac70f0Sopenharmony_ci} 681d5ac70f0Sopenharmony_ci 682d5ac70f0Sopenharmony_ci/* 683d5ac70f0Sopenharmony_ci * Parse one item for alsa-lib config 684d5ac70f0Sopenharmony_ci */ 685d5ac70f0Sopenharmony_cistatic int parse_libconfig1(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) 686d5ac70f0Sopenharmony_ci{ 687d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 688d5ac70f0Sopenharmony_ci snd_config_t *n, *config = NULL; 689d5ac70f0Sopenharmony_ci const char *id, *file = NULL; 690d5ac70f0Sopenharmony_ci bool substfile = false, substconfig = false; 691d5ac70f0Sopenharmony_ci int err; 692d5ac70f0Sopenharmony_ci 693d5ac70f0Sopenharmony_ci if (snd_config_get_id(cfg, &id) < 0) 694d5ac70f0Sopenharmony_ci return -EINVAL; 695d5ac70f0Sopenharmony_ci 696d5ac70f0Sopenharmony_ci if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 697d5ac70f0Sopenharmony_ci uc_error("compound type expected for %s", id); 698d5ac70f0Sopenharmony_ci return -EINVAL; 699d5ac70f0Sopenharmony_ci } 700d5ac70f0Sopenharmony_ci 701d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 702d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 703d5ac70f0Sopenharmony_ci 704d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 705d5ac70f0Sopenharmony_ci return -EINVAL; 706d5ac70f0Sopenharmony_ci 707d5ac70f0Sopenharmony_ci if (strcmp(id, "File") == 0 || 708d5ac70f0Sopenharmony_ci strcmp(id, "SubstiFile") == 0) { 709d5ac70f0Sopenharmony_ci substfile = id[0] == 'S'; 710d5ac70f0Sopenharmony_ci err = snd_config_get_string(n, &file); 711d5ac70f0Sopenharmony_ci if (err < 0) 712d5ac70f0Sopenharmony_ci return err; 713d5ac70f0Sopenharmony_ci continue; 714d5ac70f0Sopenharmony_ci } 715d5ac70f0Sopenharmony_ci 716d5ac70f0Sopenharmony_ci if (strcmp(id, "Config") == 0 || 717d5ac70f0Sopenharmony_ci strcmp(id, "SubstiConfig") == 0) { 718d5ac70f0Sopenharmony_ci substconfig = id[0] == 'S'; 719d5ac70f0Sopenharmony_ci if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) 720d5ac70f0Sopenharmony_ci return -EINVAL; 721d5ac70f0Sopenharmony_ci config = n; 722d5ac70f0Sopenharmony_ci continue; 723d5ac70f0Sopenharmony_ci } 724d5ac70f0Sopenharmony_ci 725d5ac70f0Sopenharmony_ci uc_error("unknown field %s", id); 726d5ac70f0Sopenharmony_ci return -EINVAL; 727d5ac70f0Sopenharmony_ci } 728d5ac70f0Sopenharmony_ci 729d5ac70f0Sopenharmony_ci if (file) { 730d5ac70f0Sopenharmony_ci if (substfile) { 731d5ac70f0Sopenharmony_ci snd_config_t *cfg; 732d5ac70f0Sopenharmony_ci err = uc_mgr_config_load(uc_mgr->conf_format, file, &cfg); 733d5ac70f0Sopenharmony_ci if (err < 0) 734d5ac70f0Sopenharmony_ci return err; 735d5ac70f0Sopenharmony_ci err = uc_mgr_substitute_tree(uc_mgr, cfg); 736d5ac70f0Sopenharmony_ci if (err < 0) { 737d5ac70f0Sopenharmony_ci snd_config_delete(cfg); 738d5ac70f0Sopenharmony_ci return err; 739d5ac70f0Sopenharmony_ci } 740d5ac70f0Sopenharmony_ci err = snd_config_merge(uc_mgr->local_config, cfg, 0); 741d5ac70f0Sopenharmony_ci if (err < 0) { 742d5ac70f0Sopenharmony_ci snd_config_delete(cfg); 743d5ac70f0Sopenharmony_ci return err; 744d5ac70f0Sopenharmony_ci } 745d5ac70f0Sopenharmony_ci } else { 746d5ac70f0Sopenharmony_ci char filename[PATH_MAX]; 747d5ac70f0Sopenharmony_ci 748d5ac70f0Sopenharmony_ci ucm_filename(filename, sizeof(filename), uc_mgr->conf_format, 749d5ac70f0Sopenharmony_ci file[0] == '/' ? NULL : uc_mgr->conf_dir_name, 750d5ac70f0Sopenharmony_ci file); 751d5ac70f0Sopenharmony_ci err = uc_mgr_config_load_into(uc_mgr->conf_format, filename, uc_mgr->local_config); 752d5ac70f0Sopenharmony_ci if (err < 0) 753d5ac70f0Sopenharmony_ci return err; 754d5ac70f0Sopenharmony_ci } 755d5ac70f0Sopenharmony_ci } 756d5ac70f0Sopenharmony_ci 757d5ac70f0Sopenharmony_ci if (config) { 758d5ac70f0Sopenharmony_ci if (substconfig) { 759d5ac70f0Sopenharmony_ci err = uc_mgr_substitute_tree(uc_mgr, config); 760d5ac70f0Sopenharmony_ci if (err < 0) 761d5ac70f0Sopenharmony_ci return err; 762d5ac70f0Sopenharmony_ci } 763d5ac70f0Sopenharmony_ci err = snd_config_merge(uc_mgr->local_config, config, 0); 764d5ac70f0Sopenharmony_ci if (err < 0) 765d5ac70f0Sopenharmony_ci return err; 766d5ac70f0Sopenharmony_ci } 767d5ac70f0Sopenharmony_ci 768d5ac70f0Sopenharmony_ci return 0; 769d5ac70f0Sopenharmony_ci} 770d5ac70f0Sopenharmony_ci 771d5ac70f0Sopenharmony_ci/* 772d5ac70f0Sopenharmony_ci * Parse alsa-lib config 773d5ac70f0Sopenharmony_ci */ 774d5ac70f0Sopenharmony_cistatic int parse_libconfig(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) 775d5ac70f0Sopenharmony_ci{ 776d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 777d5ac70f0Sopenharmony_ci snd_config_t *n; 778d5ac70f0Sopenharmony_ci const char *id; 779d5ac70f0Sopenharmony_ci int err; 780d5ac70f0Sopenharmony_ci 781d5ac70f0Sopenharmony_ci if (snd_config_get_id(cfg, &id) < 0) 782d5ac70f0Sopenharmony_ci return -EINVAL; 783d5ac70f0Sopenharmony_ci 784d5ac70f0Sopenharmony_ci if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 785d5ac70f0Sopenharmony_ci uc_error("compound type expected for %s", id); 786d5ac70f0Sopenharmony_ci return -EINVAL; 787d5ac70f0Sopenharmony_ci } 788d5ac70f0Sopenharmony_ci 789d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 790d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 791d5ac70f0Sopenharmony_ci 792d5ac70f0Sopenharmony_ci err = parse_libconfig1(uc_mgr, n); 793d5ac70f0Sopenharmony_ci if (err < 0) 794d5ac70f0Sopenharmony_ci return err; 795d5ac70f0Sopenharmony_ci } 796d5ac70f0Sopenharmony_ci 797d5ac70f0Sopenharmony_ci return 0; 798d5ac70f0Sopenharmony_ci} 799d5ac70f0Sopenharmony_ci 800d5ac70f0Sopenharmony_ci/* 801d5ac70f0Sopenharmony_ci * Parse transition 802d5ac70f0Sopenharmony_ci */ 803d5ac70f0Sopenharmony_cistatic int parse_transition(snd_use_case_mgr_t *uc_mgr, 804d5ac70f0Sopenharmony_ci struct list_head *tlist, 805d5ac70f0Sopenharmony_ci snd_config_t *cfg) 806d5ac70f0Sopenharmony_ci{ 807d5ac70f0Sopenharmony_ci struct transition_sequence *tseq; 808d5ac70f0Sopenharmony_ci const char *id; 809d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 810d5ac70f0Sopenharmony_ci snd_config_t *n; 811d5ac70f0Sopenharmony_ci int err; 812d5ac70f0Sopenharmony_ci 813d5ac70f0Sopenharmony_ci if (snd_config_get_id(cfg, &id) < 0) 814d5ac70f0Sopenharmony_ci return -EINVAL; 815d5ac70f0Sopenharmony_ci 816d5ac70f0Sopenharmony_ci if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 817d5ac70f0Sopenharmony_ci uc_error("compound type expected for %s", id); 818d5ac70f0Sopenharmony_ci return -EINVAL; 819d5ac70f0Sopenharmony_ci } 820d5ac70f0Sopenharmony_ci 821d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 822d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 823d5ac70f0Sopenharmony_ci 824d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 825d5ac70f0Sopenharmony_ci return -EINVAL; 826d5ac70f0Sopenharmony_ci 827d5ac70f0Sopenharmony_ci tseq = calloc(1, sizeof(*tseq)); 828d5ac70f0Sopenharmony_ci if (tseq == NULL) 829d5ac70f0Sopenharmony_ci return -ENOMEM; 830d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&tseq->transition_list); 831d5ac70f0Sopenharmony_ci 832d5ac70f0Sopenharmony_ci err = get_string3(uc_mgr, id, &tseq->name); 833d5ac70f0Sopenharmony_ci if (err < 0) { 834d5ac70f0Sopenharmony_ci free(tseq); 835d5ac70f0Sopenharmony_ci return err; 836d5ac70f0Sopenharmony_ci } 837d5ac70f0Sopenharmony_ci 838d5ac70f0Sopenharmony_ci err = parse_sequence(uc_mgr, &tseq->transition_list, n); 839d5ac70f0Sopenharmony_ci if (err < 0) { 840d5ac70f0Sopenharmony_ci uc_mgr_free_transition_element(tseq); 841d5ac70f0Sopenharmony_ci return err; 842d5ac70f0Sopenharmony_ci } 843d5ac70f0Sopenharmony_ci 844d5ac70f0Sopenharmony_ci list_add(&tseq->list, tlist); 845d5ac70f0Sopenharmony_ci } 846d5ac70f0Sopenharmony_ci return 0; 847d5ac70f0Sopenharmony_ci} 848d5ac70f0Sopenharmony_ci 849d5ac70f0Sopenharmony_ci/* 850d5ac70f0Sopenharmony_ci * Parse compound 851d5ac70f0Sopenharmony_ci */ 852d5ac70f0Sopenharmony_cistatic int parse_compound(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg, 853d5ac70f0Sopenharmony_ci int (*fcn)(snd_use_case_mgr_t *, snd_config_t *, void *, void *), 854d5ac70f0Sopenharmony_ci void *data1, void *data2) 855d5ac70f0Sopenharmony_ci{ 856d5ac70f0Sopenharmony_ci const char *id; 857d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 858d5ac70f0Sopenharmony_ci snd_config_t *n; 859d5ac70f0Sopenharmony_ci int err; 860d5ac70f0Sopenharmony_ci 861d5ac70f0Sopenharmony_ci if (snd_config_get_id(cfg, &id) < 0) 862d5ac70f0Sopenharmony_ci return -EINVAL; 863d5ac70f0Sopenharmony_ci 864d5ac70f0Sopenharmony_ci if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 865d5ac70f0Sopenharmony_ci uc_error("compound type expected for %s", id); 866d5ac70f0Sopenharmony_ci return -EINVAL; 867d5ac70f0Sopenharmony_ci } 868d5ac70f0Sopenharmony_ci /* parse compound */ 869d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 870d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 871d5ac70f0Sopenharmony_ci 872d5ac70f0Sopenharmony_ci if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 873d5ac70f0Sopenharmony_ci uc_error("compound type expected for %s, is %d", id, snd_config_get_type(cfg)); 874d5ac70f0Sopenharmony_ci return -EINVAL; 875d5ac70f0Sopenharmony_ci } 876d5ac70f0Sopenharmony_ci 877d5ac70f0Sopenharmony_ci err = fcn(uc_mgr, n, data1, data2); 878d5ac70f0Sopenharmony_ci if (err < 0) 879d5ac70f0Sopenharmony_ci return err; 880d5ac70f0Sopenharmony_ci } 881d5ac70f0Sopenharmony_ci 882d5ac70f0Sopenharmony_ci return 0; 883d5ac70f0Sopenharmony_ci} 884d5ac70f0Sopenharmony_ci 885d5ac70f0Sopenharmony_cistatic int strip_legacy_dev_index(char *name) 886d5ac70f0Sopenharmony_ci{ 887d5ac70f0Sopenharmony_ci char *dot = strchr(name, '.'); 888d5ac70f0Sopenharmony_ci if (!dot) 889d5ac70f0Sopenharmony_ci return 0; 890d5ac70f0Sopenharmony_ci if (dot[1] != '0' || dot[2] != '\0') { 891d5ac70f0Sopenharmony_ci uc_error("device name %s contains a '.'," 892d5ac70f0Sopenharmony_ci " and is not legacy foo.0 format", name); 893d5ac70f0Sopenharmony_ci return -EINVAL; 894d5ac70f0Sopenharmony_ci } 895d5ac70f0Sopenharmony_ci *dot = '\0'; 896d5ac70f0Sopenharmony_ci return 0; 897d5ac70f0Sopenharmony_ci} 898d5ac70f0Sopenharmony_ci 899d5ac70f0Sopenharmony_ci/* 900d5ac70f0Sopenharmony_ci * Parse device list 901d5ac70f0Sopenharmony_ci */ 902d5ac70f0Sopenharmony_cistatic int parse_device_list(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, 903d5ac70f0Sopenharmony_ci struct dev_list *dev_list, 904d5ac70f0Sopenharmony_ci enum dev_list_type type, 905d5ac70f0Sopenharmony_ci snd_config_t *cfg) 906d5ac70f0Sopenharmony_ci{ 907d5ac70f0Sopenharmony_ci struct dev_list_node *sdev; 908d5ac70f0Sopenharmony_ci const char *id; 909d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 910d5ac70f0Sopenharmony_ci snd_config_t *n; 911d5ac70f0Sopenharmony_ci int err; 912d5ac70f0Sopenharmony_ci 913d5ac70f0Sopenharmony_ci if (dev_list->type != DEVLIST_NONE) { 914d5ac70f0Sopenharmony_ci uc_error("error: multiple supported or" 915d5ac70f0Sopenharmony_ci " conflicting device lists"); 916d5ac70f0Sopenharmony_ci return -EEXIST; 917d5ac70f0Sopenharmony_ci } 918d5ac70f0Sopenharmony_ci 919d5ac70f0Sopenharmony_ci if (snd_config_get_id(cfg, &id) < 0) 920d5ac70f0Sopenharmony_ci return -EINVAL; 921d5ac70f0Sopenharmony_ci 922d5ac70f0Sopenharmony_ci if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 923d5ac70f0Sopenharmony_ci uc_error("compound type expected for %s", id); 924d5ac70f0Sopenharmony_ci return -EINVAL; 925d5ac70f0Sopenharmony_ci } 926d5ac70f0Sopenharmony_ci 927d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 928d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 929d5ac70f0Sopenharmony_ci 930d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 931d5ac70f0Sopenharmony_ci return -EINVAL; 932d5ac70f0Sopenharmony_ci 933d5ac70f0Sopenharmony_ci sdev = calloc(1, sizeof(struct dev_list_node)); 934d5ac70f0Sopenharmony_ci if (sdev == NULL) 935d5ac70f0Sopenharmony_ci return -ENOMEM; 936d5ac70f0Sopenharmony_ci err = parse_string_substitute3(uc_mgr, n, &sdev->name); 937d5ac70f0Sopenharmony_ci if (err < 0) { 938d5ac70f0Sopenharmony_ci free(sdev); 939d5ac70f0Sopenharmony_ci return err; 940d5ac70f0Sopenharmony_ci } 941d5ac70f0Sopenharmony_ci err = strip_legacy_dev_index(sdev->name); 942d5ac70f0Sopenharmony_ci if (err < 0) { 943d5ac70f0Sopenharmony_ci free(sdev->name); 944d5ac70f0Sopenharmony_ci free(sdev); 945d5ac70f0Sopenharmony_ci return err; 946d5ac70f0Sopenharmony_ci } 947d5ac70f0Sopenharmony_ci list_add(&sdev->list, &dev_list->list); 948d5ac70f0Sopenharmony_ci } 949d5ac70f0Sopenharmony_ci 950d5ac70f0Sopenharmony_ci dev_list->type = type; 951d5ac70f0Sopenharmony_ci 952d5ac70f0Sopenharmony_ci return 0; 953d5ac70f0Sopenharmony_ci} 954d5ac70f0Sopenharmony_ci 955d5ac70f0Sopenharmony_ci/* Find a component device by its name, and remove it from machine device 956d5ac70f0Sopenharmony_ci * list. 957d5ac70f0Sopenharmony_ci * 958d5ac70f0Sopenharmony_ci * Component devices are defined by machine components (usually off-soc 959d5ac70f0Sopenharmony_ci * codes or DSP embeded in SoC). Since alsaconf imports their configuration 960d5ac70f0Sopenharmony_ci * files automatically, we don't know which devices are component devices 961d5ac70f0Sopenharmony_ci * until they are referenced by a machine device sequence. So here when we 962d5ac70f0Sopenharmony_ci * find a referenced device, we move it from the machine device list to the 963d5ac70f0Sopenharmony_ci * component device list. Component devices will not be exposed to applications 964d5ac70f0Sopenharmony_ci * by the original API to list devices for backward compatibility. So sound 965d5ac70f0Sopenharmony_ci * servers can only see the machine devices. 966d5ac70f0Sopenharmony_ci */ 967d5ac70f0Sopenharmony_cistruct use_case_device *find_component_dev(snd_use_case_mgr_t *uc_mgr, 968d5ac70f0Sopenharmony_ci const char *name) 969d5ac70f0Sopenharmony_ci{ 970d5ac70f0Sopenharmony_ci struct list_head *pos, *posdev, *_posdev; 971d5ac70f0Sopenharmony_ci struct use_case_verb *verb; 972d5ac70f0Sopenharmony_ci struct use_case_device *dev; 973d5ac70f0Sopenharmony_ci 974d5ac70f0Sopenharmony_ci list_for_each(pos, &uc_mgr->verb_list) { 975d5ac70f0Sopenharmony_ci verb = list_entry(pos, struct use_case_verb, list); 976d5ac70f0Sopenharmony_ci 977d5ac70f0Sopenharmony_ci /* search in the component device list */ 978d5ac70f0Sopenharmony_ci list_for_each(posdev, &verb->cmpt_device_list) { 979d5ac70f0Sopenharmony_ci dev = list_entry(posdev, struct use_case_device, list); 980d5ac70f0Sopenharmony_ci if (!strcmp(dev->name, name)) 981d5ac70f0Sopenharmony_ci return dev; 982d5ac70f0Sopenharmony_ci } 983d5ac70f0Sopenharmony_ci 984d5ac70f0Sopenharmony_ci /* search the machine device list */ 985d5ac70f0Sopenharmony_ci list_for_each_safe(posdev, _posdev, &verb->device_list) { 986d5ac70f0Sopenharmony_ci dev = list_entry(posdev, struct use_case_device, list); 987d5ac70f0Sopenharmony_ci if (!strcmp(dev->name, name)) { 988d5ac70f0Sopenharmony_ci /* find the component device, move it from the 989d5ac70f0Sopenharmony_ci * machine device list to the component device 990d5ac70f0Sopenharmony_ci * list. 991d5ac70f0Sopenharmony_ci */ 992d5ac70f0Sopenharmony_ci list_del(&dev->list); 993d5ac70f0Sopenharmony_ci list_add_tail(&dev->list, 994d5ac70f0Sopenharmony_ci &verb->cmpt_device_list); 995d5ac70f0Sopenharmony_ci return dev; 996d5ac70f0Sopenharmony_ci } 997d5ac70f0Sopenharmony_ci } 998d5ac70f0Sopenharmony_ci } 999d5ac70f0Sopenharmony_ci 1000d5ac70f0Sopenharmony_ci return NULL; 1001d5ac70f0Sopenharmony_ci} 1002d5ac70f0Sopenharmony_ci 1003d5ac70f0Sopenharmony_ci/* parse sequence of a component device 1004d5ac70f0Sopenharmony_ci * 1005d5ac70f0Sopenharmony_ci * This function will find the component device and mark if its enable or 1006d5ac70f0Sopenharmony_ci * disable sequence is needed by its parenet device. 1007d5ac70f0Sopenharmony_ci */ 1008d5ac70f0Sopenharmony_cistatic int parse_component_seq(snd_use_case_mgr_t *uc_mgr, 1009d5ac70f0Sopenharmony_ci snd_config_t *n, int enable, 1010d5ac70f0Sopenharmony_ci struct component_sequence *cmpt_seq) 1011d5ac70f0Sopenharmony_ci{ 1012d5ac70f0Sopenharmony_ci char *val; 1013d5ac70f0Sopenharmony_ci int err; 1014d5ac70f0Sopenharmony_ci 1015d5ac70f0Sopenharmony_ci err = parse_string_substitute3(uc_mgr, n, &val); 1016d5ac70f0Sopenharmony_ci if (err < 0) 1017d5ac70f0Sopenharmony_ci return err; 1018d5ac70f0Sopenharmony_ci 1019d5ac70f0Sopenharmony_ci cmpt_seq->device = find_component_dev(uc_mgr, val); 1020d5ac70f0Sopenharmony_ci if (!cmpt_seq->device) { 1021d5ac70f0Sopenharmony_ci uc_error("error: Cannot find component device %s", val); 1022d5ac70f0Sopenharmony_ci free(val); 1023d5ac70f0Sopenharmony_ci return -EINVAL; 1024d5ac70f0Sopenharmony_ci } 1025d5ac70f0Sopenharmony_ci free(val); 1026d5ac70f0Sopenharmony_ci 1027d5ac70f0Sopenharmony_ci /* Parent needs its enable or disable sequence */ 1028d5ac70f0Sopenharmony_ci cmpt_seq->enable = enable; 1029d5ac70f0Sopenharmony_ci 1030d5ac70f0Sopenharmony_ci return 0; 1031d5ac70f0Sopenharmony_ci} 1032d5ac70f0Sopenharmony_ci 1033d5ac70f0Sopenharmony_ci/* 1034d5ac70f0Sopenharmony_ci * Parse sequences. 1035d5ac70f0Sopenharmony_ci * 1036d5ac70f0Sopenharmony_ci * Sequence controls elements are in the following form:- 1037d5ac70f0Sopenharmony_ci * 1038d5ac70f0Sopenharmony_ci * cdev "hw:0" 1039d5ac70f0Sopenharmony_ci * cset "element_id_syntax value_syntax" 1040d5ac70f0Sopenharmony_ci * usleep time 1041d5ac70f0Sopenharmony_ci * exec "any unix command with arguments" 1042d5ac70f0Sopenharmony_ci * enadev "component device name" 1043d5ac70f0Sopenharmony_ci * disdev "component device name" 1044d5ac70f0Sopenharmony_ci * 1045d5ac70f0Sopenharmony_ci * e.g. 1046d5ac70f0Sopenharmony_ci * cset "name='Master Playback Switch' 0,0" 1047d5ac70f0Sopenharmony_ci * cset "iface=PCM,name='Disable HDMI',index=1 0" 1048d5ac70f0Sopenharmony_ci * enadev "rt286:Headphones" 1049d5ac70f0Sopenharmony_ci * disdev "rt286:Speaker" 1050d5ac70f0Sopenharmony_ci */ 1051d5ac70f0Sopenharmony_cistatic int parse_sequence(snd_use_case_mgr_t *uc_mgr, 1052d5ac70f0Sopenharmony_ci struct list_head *base, 1053d5ac70f0Sopenharmony_ci snd_config_t *cfg) 1054d5ac70f0Sopenharmony_ci{ 1055d5ac70f0Sopenharmony_ci struct sequence_element *curr; 1056d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1057d5ac70f0Sopenharmony_ci snd_config_t *n; 1058d5ac70f0Sopenharmony_ci int err, idx = 0; 1059d5ac70f0Sopenharmony_ci const char *cmd = NULL; 1060d5ac70f0Sopenharmony_ci 1061d5ac70f0Sopenharmony_ci if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 1062d5ac70f0Sopenharmony_ci uc_error("error: compound is expected for sequence definition"); 1063d5ac70f0Sopenharmony_ci return -EINVAL; 1064d5ac70f0Sopenharmony_ci } 1065d5ac70f0Sopenharmony_ci 1066d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 1067d5ac70f0Sopenharmony_ci const char *id; 1068d5ac70f0Sopenharmony_ci idx ^= 1; 1069d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 1070d5ac70f0Sopenharmony_ci err = snd_config_get_id(n, &id); 1071d5ac70f0Sopenharmony_ci if (err < 0) 1072d5ac70f0Sopenharmony_ci continue; 1073d5ac70f0Sopenharmony_ci if (idx == 1) { 1074d5ac70f0Sopenharmony_ci if (snd_config_get_type(n) != SND_CONFIG_TYPE_STRING) { 1075d5ac70f0Sopenharmony_ci uc_error("error: string type is expected for sequence command"); 1076d5ac70f0Sopenharmony_ci return -EINVAL; 1077d5ac70f0Sopenharmony_ci } 1078d5ac70f0Sopenharmony_ci snd_config_get_string(n, &cmd); 1079d5ac70f0Sopenharmony_ci continue; 1080d5ac70f0Sopenharmony_ci } 1081d5ac70f0Sopenharmony_ci 1082d5ac70f0Sopenharmony_ci /* alloc new sequence element */ 1083d5ac70f0Sopenharmony_ci curr = calloc(1, sizeof(struct sequence_element)); 1084d5ac70f0Sopenharmony_ci if (curr == NULL) 1085d5ac70f0Sopenharmony_ci return -ENOMEM; 1086d5ac70f0Sopenharmony_ci list_add_tail(&curr->list, base); 1087d5ac70f0Sopenharmony_ci 1088d5ac70f0Sopenharmony_ci if (strcmp(cmd, "cdev") == 0) { 1089d5ac70f0Sopenharmony_ci curr->type = SEQUENCE_ELEMENT_TYPE_CDEV; 1090d5ac70f0Sopenharmony_ci err = parse_string_substitute3(uc_mgr, n, &curr->data.cdev); 1091d5ac70f0Sopenharmony_ci if (err < 0) { 1092d5ac70f0Sopenharmony_ci uc_error("error: cdev requires a string!"); 1093d5ac70f0Sopenharmony_ci return err; 1094d5ac70f0Sopenharmony_ci } 1095d5ac70f0Sopenharmony_ci continue; 1096d5ac70f0Sopenharmony_ci } 1097d5ac70f0Sopenharmony_ci 1098d5ac70f0Sopenharmony_ci if (strcmp(cmd, "cset") == 0) { 1099d5ac70f0Sopenharmony_ci curr->type = SEQUENCE_ELEMENT_TYPE_CSET; 1100d5ac70f0Sopenharmony_cicset: 1101d5ac70f0Sopenharmony_ci err = parse_string_substitute3(uc_mgr, n, &curr->data.cset); 1102d5ac70f0Sopenharmony_ci if (err < 0) { 1103d5ac70f0Sopenharmony_ci uc_error("error: %s requires a string!", cmd); 1104d5ac70f0Sopenharmony_ci return err; 1105d5ac70f0Sopenharmony_ci } 1106d5ac70f0Sopenharmony_ci continue; 1107d5ac70f0Sopenharmony_ci } 1108d5ac70f0Sopenharmony_ci 1109d5ac70f0Sopenharmony_ci if (strcmp(cmd, "enadev") == 0 || 1110d5ac70f0Sopenharmony_ci strcmp(cmd, "disdev") == 0) { 1111d5ac70f0Sopenharmony_ci /* need to enable or disable a component device */ 1112d5ac70f0Sopenharmony_ci curr->type = SEQUENCE_ELEMENT_TYPE_CMPT_SEQ; 1113d5ac70f0Sopenharmony_ci err = parse_component_seq(uc_mgr, n, 1114d5ac70f0Sopenharmony_ci strcmp(cmd, "enadev") == 0, 1115d5ac70f0Sopenharmony_ci &curr->data.cmpt_seq); 1116d5ac70f0Sopenharmony_ci if (err < 0) { 1117d5ac70f0Sopenharmony_ci uc_error("error: %s requires a valid device!", cmd); 1118d5ac70f0Sopenharmony_ci return err; 1119d5ac70f0Sopenharmony_ci } 1120d5ac70f0Sopenharmony_ci continue; 1121d5ac70f0Sopenharmony_ci } 1122d5ac70f0Sopenharmony_ci 1123d5ac70f0Sopenharmony_ci if (strcmp(cmd, "enadev2") == 0) { 1124d5ac70f0Sopenharmony_ci curr->type = SEQUENCE_ELEMENT_TYPE_DEV_ENABLE_SEQ; 1125d5ac70f0Sopenharmony_ci goto device; 1126d5ac70f0Sopenharmony_ci } 1127d5ac70f0Sopenharmony_ci 1128d5ac70f0Sopenharmony_ci if (strcmp(cmd, "disdev2") == 0) { 1129d5ac70f0Sopenharmony_ci curr->type = SEQUENCE_ELEMENT_TYPE_DEV_DISABLE_SEQ; 1130d5ac70f0Sopenharmony_cidevice: 1131d5ac70f0Sopenharmony_ci err = parse_string_substitute3(uc_mgr, n, &curr->data.device); 1132d5ac70f0Sopenharmony_ci if (err < 0) { 1133d5ac70f0Sopenharmony_ci uc_error("error: %s requires a valid device!", cmd); 1134d5ac70f0Sopenharmony_ci return err; 1135d5ac70f0Sopenharmony_ci } 1136d5ac70f0Sopenharmony_ci continue; 1137d5ac70f0Sopenharmony_ci } 1138d5ac70f0Sopenharmony_ci 1139d5ac70f0Sopenharmony_ci if (strcmp(cmd, "disdevall") == 0) { 1140d5ac70f0Sopenharmony_ci curr->type = SEQUENCE_ELEMENT_TYPE_DEV_DISABLE_ALL; 1141d5ac70f0Sopenharmony_ci continue; 1142d5ac70f0Sopenharmony_ci } 1143d5ac70f0Sopenharmony_ci 1144d5ac70f0Sopenharmony_ci if (strcmp(cmd, "cset-bin-file") == 0) { 1145d5ac70f0Sopenharmony_ci curr->type = SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE; 1146d5ac70f0Sopenharmony_ci goto cset; 1147d5ac70f0Sopenharmony_ci } 1148d5ac70f0Sopenharmony_ci 1149d5ac70f0Sopenharmony_ci if (strcmp(cmd, "cset-tlv") == 0) { 1150d5ac70f0Sopenharmony_ci curr->type = SEQUENCE_ELEMENT_TYPE_CSET_TLV; 1151d5ac70f0Sopenharmony_ci goto cset; 1152d5ac70f0Sopenharmony_ci } 1153d5ac70f0Sopenharmony_ci 1154d5ac70f0Sopenharmony_ci if (strcmp(cmd, "cset-new") == 0) { 1155d5ac70f0Sopenharmony_ci curr->type = SEQUENCE_ELEMENT_TYPE_CSET_NEW; 1156d5ac70f0Sopenharmony_ci goto cset; 1157d5ac70f0Sopenharmony_ci } 1158d5ac70f0Sopenharmony_ci 1159d5ac70f0Sopenharmony_ci if (strcmp(cmd, "ctl-remove") == 0) { 1160d5ac70f0Sopenharmony_ci curr->type = SEQUENCE_ELEMENT_TYPE_CTL_REMOVE; 1161d5ac70f0Sopenharmony_ci goto cset; 1162d5ac70f0Sopenharmony_ci } 1163d5ac70f0Sopenharmony_ci 1164d5ac70f0Sopenharmony_ci if (strcmp(cmd, "sysw") == 0) { 1165d5ac70f0Sopenharmony_ci curr->type = SEQUENCE_ELEMENT_TYPE_SYSSET; 1166d5ac70f0Sopenharmony_ci err = parse_string_substitute3(uc_mgr, n, &curr->data.sysw); 1167d5ac70f0Sopenharmony_ci if (err < 0) { 1168d5ac70f0Sopenharmony_ci uc_error("error: sysw requires a string!"); 1169d5ac70f0Sopenharmony_ci return err; 1170d5ac70f0Sopenharmony_ci } 1171d5ac70f0Sopenharmony_ci continue; 1172d5ac70f0Sopenharmony_ci } 1173d5ac70f0Sopenharmony_ci 1174d5ac70f0Sopenharmony_ci if (strcmp(cmd, "usleep") == 0) { 1175d5ac70f0Sopenharmony_ci curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP; 1176d5ac70f0Sopenharmony_ci err = parse_integer_substitute3(uc_mgr, n, &curr->data.sleep); 1177d5ac70f0Sopenharmony_ci if (err < 0) { 1178d5ac70f0Sopenharmony_ci uc_error("error: usleep requires integer!"); 1179d5ac70f0Sopenharmony_ci return err; 1180d5ac70f0Sopenharmony_ci } 1181d5ac70f0Sopenharmony_ci continue; 1182d5ac70f0Sopenharmony_ci } 1183d5ac70f0Sopenharmony_ci 1184d5ac70f0Sopenharmony_ci if (strcmp(cmd, "msleep") == 0) { 1185d5ac70f0Sopenharmony_ci curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP; 1186d5ac70f0Sopenharmony_ci err = parse_integer_substitute3(uc_mgr, n, &curr->data.sleep); 1187d5ac70f0Sopenharmony_ci if (err < 0) { 1188d5ac70f0Sopenharmony_ci uc_error("error: msleep requires integer!"); 1189d5ac70f0Sopenharmony_ci return err; 1190d5ac70f0Sopenharmony_ci } 1191d5ac70f0Sopenharmony_ci curr->data.sleep *= 1000L; 1192d5ac70f0Sopenharmony_ci continue; 1193d5ac70f0Sopenharmony_ci } 1194d5ac70f0Sopenharmony_ci 1195d5ac70f0Sopenharmony_ci if (strcmp(cmd, "exec") == 0) { 1196d5ac70f0Sopenharmony_ci curr->type = SEQUENCE_ELEMENT_TYPE_EXEC; 1197d5ac70f0Sopenharmony_ciexec: 1198d5ac70f0Sopenharmony_ci err = parse_string_substitute3(uc_mgr, n, &curr->data.exec); 1199d5ac70f0Sopenharmony_ci if (err < 0) { 1200d5ac70f0Sopenharmony_ci uc_error("error: exec requires a string!"); 1201d5ac70f0Sopenharmony_ci return err; 1202d5ac70f0Sopenharmony_ci } 1203d5ac70f0Sopenharmony_ci continue; 1204d5ac70f0Sopenharmony_ci } 1205d5ac70f0Sopenharmony_ci 1206d5ac70f0Sopenharmony_ci if (strcmp(cmd, "shell") == 0) { 1207d5ac70f0Sopenharmony_ci curr->type = SEQUENCE_ELEMENT_TYPE_SHELL; 1208d5ac70f0Sopenharmony_ci goto exec; 1209d5ac70f0Sopenharmony_ci } 1210d5ac70f0Sopenharmony_ci 1211d5ac70f0Sopenharmony_ci if (strcmp(cmd, "cfg-save") == 0) { 1212d5ac70f0Sopenharmony_ci curr->type = SEQUENCE_ELEMENT_TYPE_CFGSAVE; 1213d5ac70f0Sopenharmony_ci err = parse_string_substitute3(uc_mgr, n, &curr->data.cfgsave); 1214d5ac70f0Sopenharmony_ci if (err < 0) { 1215d5ac70f0Sopenharmony_ci uc_error("error: sysw requires a string!"); 1216d5ac70f0Sopenharmony_ci return err; 1217d5ac70f0Sopenharmony_ci } 1218d5ac70f0Sopenharmony_ci continue; 1219d5ac70f0Sopenharmony_ci } 1220d5ac70f0Sopenharmony_ci 1221d5ac70f0Sopenharmony_ci if (strcmp(cmd, "comment") == 0) 1222d5ac70f0Sopenharmony_ci goto skip; 1223d5ac70f0Sopenharmony_ci 1224d5ac70f0Sopenharmony_ci uc_error("error: sequence command '%s' is ignored", cmd); 1225d5ac70f0Sopenharmony_ci 1226d5ac70f0Sopenharmony_ciskip: 1227d5ac70f0Sopenharmony_ci list_del(&curr->list); 1228d5ac70f0Sopenharmony_ci uc_mgr_free_sequence_element(curr); 1229d5ac70f0Sopenharmony_ci } 1230d5ac70f0Sopenharmony_ci 1231d5ac70f0Sopenharmony_ci return 0; 1232d5ac70f0Sopenharmony_ci} 1233d5ac70f0Sopenharmony_ci 1234d5ac70f0Sopenharmony_ci/* 1235d5ac70f0Sopenharmony_ci * 1236d5ac70f0Sopenharmony_ci */ 1237d5ac70f0Sopenharmony_ciint uc_mgr_add_value(struct list_head *base, const char *key, char *val) 1238d5ac70f0Sopenharmony_ci{ 1239d5ac70f0Sopenharmony_ci struct ucm_value *curr; 1240d5ac70f0Sopenharmony_ci 1241d5ac70f0Sopenharmony_ci curr = calloc(1, sizeof(struct ucm_value)); 1242d5ac70f0Sopenharmony_ci if (curr == NULL) 1243d5ac70f0Sopenharmony_ci return -ENOMEM; 1244d5ac70f0Sopenharmony_ci curr->name = strdup(key); 1245d5ac70f0Sopenharmony_ci if (curr->name == NULL) { 1246d5ac70f0Sopenharmony_ci free(curr); 1247d5ac70f0Sopenharmony_ci return -ENOMEM; 1248d5ac70f0Sopenharmony_ci } 1249d5ac70f0Sopenharmony_ci list_add_tail(&curr->list, base); 1250d5ac70f0Sopenharmony_ci curr->data = val; 1251d5ac70f0Sopenharmony_ci return 0; 1252d5ac70f0Sopenharmony_ci} 1253d5ac70f0Sopenharmony_ci 1254d5ac70f0Sopenharmony_ci/* 1255d5ac70f0Sopenharmony_ci * Parse values. 1256d5ac70f0Sopenharmony_ci * 1257d5ac70f0Sopenharmony_ci * Parse values describing PCM, control/mixer settings and stream parameters. 1258d5ac70f0Sopenharmony_ci * 1259d5ac70f0Sopenharmony_ci * Value { 1260d5ac70f0Sopenharmony_ci * TQ Voice 1261d5ac70f0Sopenharmony_ci * CapturePCM "hw:1" 1262d5ac70f0Sopenharmony_ci * PlaybackVolume "name='Master Playback Volume',index=2" 1263d5ac70f0Sopenharmony_ci * PlaybackSwitch "name='Master Playback Switch',index=2" 1264d5ac70f0Sopenharmony_ci * } 1265d5ac70f0Sopenharmony_ci */ 1266d5ac70f0Sopenharmony_cistatic int parse_value(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, 1267d5ac70f0Sopenharmony_ci struct list_head *base, 1268d5ac70f0Sopenharmony_ci snd_config_t *cfg) 1269d5ac70f0Sopenharmony_ci{ 1270d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1271d5ac70f0Sopenharmony_ci snd_config_t *n; 1272d5ac70f0Sopenharmony_ci char *s; 1273d5ac70f0Sopenharmony_ci snd_config_type_t type; 1274d5ac70f0Sopenharmony_ci int err; 1275d5ac70f0Sopenharmony_ci 1276d5ac70f0Sopenharmony_ci if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 1277d5ac70f0Sopenharmony_ci uc_error("error: compound is expected for value definition"); 1278d5ac70f0Sopenharmony_ci return -EINVAL; 1279d5ac70f0Sopenharmony_ci } 1280d5ac70f0Sopenharmony_ci 1281d5ac70f0Sopenharmony_ci /* in-place evaluation */ 1282d5ac70f0Sopenharmony_ci err = uc_mgr_evaluate_inplace(uc_mgr, cfg); 1283d5ac70f0Sopenharmony_ci if (err < 0) 1284d5ac70f0Sopenharmony_ci return err; 1285d5ac70f0Sopenharmony_ci 1286d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 1287d5ac70f0Sopenharmony_ci const char *id; 1288d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 1289d5ac70f0Sopenharmony_ci err = snd_config_get_id(n, &id); 1290d5ac70f0Sopenharmony_ci if (err < 0) 1291d5ac70f0Sopenharmony_ci continue; 1292d5ac70f0Sopenharmony_ci 1293d5ac70f0Sopenharmony_ci type = snd_config_get_type(n); 1294d5ac70f0Sopenharmony_ci switch (type) { 1295d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_INTEGER: 1296d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_INTEGER64: 1297d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_REAL: 1298d5ac70f0Sopenharmony_ci err = snd_config_get_ascii(n, &s); 1299d5ac70f0Sopenharmony_ci if (err < 0) { 1300d5ac70f0Sopenharmony_ci uc_error("error: unable to parse value for id '%s': %s!", id, snd_strerror(err)); 1301d5ac70f0Sopenharmony_ci return err; 1302d5ac70f0Sopenharmony_ci } 1303d5ac70f0Sopenharmony_ci break; 1304d5ac70f0Sopenharmony_ci case SND_CONFIG_TYPE_STRING: 1305d5ac70f0Sopenharmony_ci err = parse_string_substitute(uc_mgr, n, &s); 1306d5ac70f0Sopenharmony_ci if (err < 0) { 1307d5ac70f0Sopenharmony_ci uc_error("error: unable to parse a string for id '%s'!", id); 1308d5ac70f0Sopenharmony_ci return err; 1309d5ac70f0Sopenharmony_ci } 1310d5ac70f0Sopenharmony_ci break; 1311d5ac70f0Sopenharmony_ci default: 1312d5ac70f0Sopenharmony_ci uc_error("error: invalid type %i in Value compound '%s'", type, id); 1313d5ac70f0Sopenharmony_ci return -EINVAL; 1314d5ac70f0Sopenharmony_ci } 1315d5ac70f0Sopenharmony_ci err = uc_mgr_add_value(base, id, s); 1316d5ac70f0Sopenharmony_ci if (err < 0) { 1317d5ac70f0Sopenharmony_ci free(s); 1318d5ac70f0Sopenharmony_ci return err; 1319d5ac70f0Sopenharmony_ci } 1320d5ac70f0Sopenharmony_ci } 1321d5ac70f0Sopenharmony_ci 1322d5ac70f0Sopenharmony_ci return 0; 1323d5ac70f0Sopenharmony_ci} 1324d5ac70f0Sopenharmony_ci 1325d5ac70f0Sopenharmony_ci/* 1326d5ac70f0Sopenharmony_ci * Parse Modifier Use cases 1327d5ac70f0Sopenharmony_ci * 1328d5ac70f0Sopenharmony_ci * # Each modifier is described in new section. N modifiers are allowed 1329d5ac70f0Sopenharmony_ci * SectionModifier."Capture Voice" { 1330d5ac70f0Sopenharmony_ci * 1331d5ac70f0Sopenharmony_ci * Comment "Record voice call" 1332d5ac70f0Sopenharmony_ci * 1333d5ac70f0Sopenharmony_ci * SupportedDevice [ 1334d5ac70f0Sopenharmony_ci * "x" 1335d5ac70f0Sopenharmony_ci * "y" 1336d5ac70f0Sopenharmony_ci * ] 1337d5ac70f0Sopenharmony_ci * 1338d5ac70f0Sopenharmony_ci * ConflictingDevice [ 1339d5ac70f0Sopenharmony_ci * "x" 1340d5ac70f0Sopenharmony_ci * "y" 1341d5ac70f0Sopenharmony_ci * ] 1342d5ac70f0Sopenharmony_ci * 1343d5ac70f0Sopenharmony_ci * EnableSequence [ 1344d5ac70f0Sopenharmony_ci * .... 1345d5ac70f0Sopenharmony_ci * ] 1346d5ac70f0Sopenharmony_ci * 1347d5ac70f0Sopenharmony_ci * DisableSequence [ 1348d5ac70f0Sopenharmony_ci * ... 1349d5ac70f0Sopenharmony_ci * ] 1350d5ac70f0Sopenharmony_ci * 1351d5ac70f0Sopenharmony_ci * TransitionSequence."ToModifierName" [ 1352d5ac70f0Sopenharmony_ci * ... 1353d5ac70f0Sopenharmony_ci * ] 1354d5ac70f0Sopenharmony_ci * 1355d5ac70f0Sopenharmony_ci * # Optional TQ and ALSA PCMs 1356d5ac70f0Sopenharmony_ci * Value { 1357d5ac70f0Sopenharmony_ci * TQ Voice 1358d5ac70f0Sopenharmony_ci * CapturePCM "hw:1" 1359d5ac70f0Sopenharmony_ci * PlaybackVolume "name='Master Playback Volume',index=2" 1360d5ac70f0Sopenharmony_ci * PlaybackSwitch "name='Master Playback Switch',index=2" 1361d5ac70f0Sopenharmony_ci * } 1362d5ac70f0Sopenharmony_ci * } 1363d5ac70f0Sopenharmony_ci * 1364d5ac70f0Sopenharmony_ci * SupportedDevice and ConflictingDevice cannot be specified together. 1365d5ac70f0Sopenharmony_ci * Both are optional. 1366d5ac70f0Sopenharmony_ci */ 1367d5ac70f0Sopenharmony_cistatic int parse_modifier(snd_use_case_mgr_t *uc_mgr, 1368d5ac70f0Sopenharmony_ci snd_config_t *cfg, 1369d5ac70f0Sopenharmony_ci void *data1, void *data2) 1370d5ac70f0Sopenharmony_ci{ 1371d5ac70f0Sopenharmony_ci struct use_case_verb *verb = data1; 1372d5ac70f0Sopenharmony_ci struct use_case_modifier *modifier; 1373d5ac70f0Sopenharmony_ci char *name; 1374d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1375d5ac70f0Sopenharmony_ci snd_config_t *n; 1376d5ac70f0Sopenharmony_ci int err; 1377d5ac70f0Sopenharmony_ci 1378d5ac70f0Sopenharmony_ci if (parse_get_safe_name(uc_mgr, cfg, data2, &name) < 0) 1379d5ac70f0Sopenharmony_ci return -EINVAL; 1380d5ac70f0Sopenharmony_ci 1381d5ac70f0Sopenharmony_ci /* allocate modifier */ 1382d5ac70f0Sopenharmony_ci modifier = calloc(1, sizeof(*modifier)); 1383d5ac70f0Sopenharmony_ci if (modifier == NULL) { 1384d5ac70f0Sopenharmony_ci free(name); 1385d5ac70f0Sopenharmony_ci return -ENOMEM; 1386d5ac70f0Sopenharmony_ci } 1387d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&modifier->enable_list); 1388d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&modifier->disable_list); 1389d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&modifier->transition_list); 1390d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&modifier->dev_list.list); 1391d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&modifier->value_list); 1392d5ac70f0Sopenharmony_ci list_add_tail(&modifier->list, &verb->modifier_list); 1393d5ac70f0Sopenharmony_ci modifier->name = name; 1394d5ac70f0Sopenharmony_ci 1395d5ac70f0Sopenharmony_ci /* in-place evaluation */ 1396d5ac70f0Sopenharmony_ci err = uc_mgr_evaluate_inplace(uc_mgr, cfg); 1397d5ac70f0Sopenharmony_ci if (err < 0) 1398d5ac70f0Sopenharmony_ci return err; 1399d5ac70f0Sopenharmony_ci 1400d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 1401d5ac70f0Sopenharmony_ci const char *id; 1402d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 1403d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 1404d5ac70f0Sopenharmony_ci continue; 1405d5ac70f0Sopenharmony_ci 1406d5ac70f0Sopenharmony_ci if (strcmp(id, "Comment") == 0) { 1407d5ac70f0Sopenharmony_ci err = parse_string_substitute3(uc_mgr, n, &modifier->comment); 1408d5ac70f0Sopenharmony_ci if (err < 0) { 1409d5ac70f0Sopenharmony_ci uc_error("error: failed to get modifier comment"); 1410d5ac70f0Sopenharmony_ci return err; 1411d5ac70f0Sopenharmony_ci } 1412d5ac70f0Sopenharmony_ci continue; 1413d5ac70f0Sopenharmony_ci } 1414d5ac70f0Sopenharmony_ci 1415d5ac70f0Sopenharmony_ci if (strcmp(id, "SupportedDevice") == 0) { 1416d5ac70f0Sopenharmony_ci err = parse_device_list(uc_mgr, &modifier->dev_list, 1417d5ac70f0Sopenharmony_ci DEVLIST_SUPPORTED, n); 1418d5ac70f0Sopenharmony_ci if (err < 0) { 1419d5ac70f0Sopenharmony_ci uc_error("error: failed to parse supported" 1420d5ac70f0Sopenharmony_ci " device list"); 1421d5ac70f0Sopenharmony_ci return err; 1422d5ac70f0Sopenharmony_ci } 1423d5ac70f0Sopenharmony_ci } 1424d5ac70f0Sopenharmony_ci 1425d5ac70f0Sopenharmony_ci if (strcmp(id, "ConflictingDevice") == 0) { 1426d5ac70f0Sopenharmony_ci err = parse_device_list(uc_mgr, &modifier->dev_list, 1427d5ac70f0Sopenharmony_ci DEVLIST_CONFLICTING, n); 1428d5ac70f0Sopenharmony_ci if (err < 0) { 1429d5ac70f0Sopenharmony_ci uc_error("error: failed to parse conflicting" 1430d5ac70f0Sopenharmony_ci " device list"); 1431d5ac70f0Sopenharmony_ci return err; 1432d5ac70f0Sopenharmony_ci } 1433d5ac70f0Sopenharmony_ci } 1434d5ac70f0Sopenharmony_ci 1435d5ac70f0Sopenharmony_ci if (strcmp(id, "EnableSequence") == 0) { 1436d5ac70f0Sopenharmony_ci err = parse_sequence(uc_mgr, &modifier->enable_list, n); 1437d5ac70f0Sopenharmony_ci if (err < 0) { 1438d5ac70f0Sopenharmony_ci uc_error("error: failed to parse modifier" 1439d5ac70f0Sopenharmony_ci " enable sequence"); 1440d5ac70f0Sopenharmony_ci return err; 1441d5ac70f0Sopenharmony_ci } 1442d5ac70f0Sopenharmony_ci continue; 1443d5ac70f0Sopenharmony_ci } 1444d5ac70f0Sopenharmony_ci 1445d5ac70f0Sopenharmony_ci if (strcmp(id, "DisableSequence") == 0) { 1446d5ac70f0Sopenharmony_ci err = parse_sequence(uc_mgr, &modifier->disable_list, n); 1447d5ac70f0Sopenharmony_ci if (err < 0) { 1448d5ac70f0Sopenharmony_ci uc_error("error: failed to parse modifier" 1449d5ac70f0Sopenharmony_ci " disable sequence"); 1450d5ac70f0Sopenharmony_ci return err; 1451d5ac70f0Sopenharmony_ci } 1452d5ac70f0Sopenharmony_ci continue; 1453d5ac70f0Sopenharmony_ci } 1454d5ac70f0Sopenharmony_ci 1455d5ac70f0Sopenharmony_ci if (strcmp(id, "TransitionSequence") == 0) { 1456d5ac70f0Sopenharmony_ci err = parse_transition(uc_mgr, &modifier->transition_list, n); 1457d5ac70f0Sopenharmony_ci if (err < 0) { 1458d5ac70f0Sopenharmony_ci uc_error("error: failed to parse transition" 1459d5ac70f0Sopenharmony_ci " modifier"); 1460d5ac70f0Sopenharmony_ci return err; 1461d5ac70f0Sopenharmony_ci } 1462d5ac70f0Sopenharmony_ci continue; 1463d5ac70f0Sopenharmony_ci } 1464d5ac70f0Sopenharmony_ci 1465d5ac70f0Sopenharmony_ci if (strcmp(id, "Value") == 0) { 1466d5ac70f0Sopenharmony_ci err = parse_value(uc_mgr, &modifier->value_list, n); 1467d5ac70f0Sopenharmony_ci if (err < 0) { 1468d5ac70f0Sopenharmony_ci uc_error("error: failed to parse Value"); 1469d5ac70f0Sopenharmony_ci return err; 1470d5ac70f0Sopenharmony_ci } 1471d5ac70f0Sopenharmony_ci continue; 1472d5ac70f0Sopenharmony_ci } 1473d5ac70f0Sopenharmony_ci } 1474d5ac70f0Sopenharmony_ci 1475d5ac70f0Sopenharmony_ci return 0; 1476d5ac70f0Sopenharmony_ci} 1477d5ac70f0Sopenharmony_ci 1478d5ac70f0Sopenharmony_ci/* 1479d5ac70f0Sopenharmony_ci * Parse Device Use Cases 1480d5ac70f0Sopenharmony_ci * 1481d5ac70f0Sopenharmony_ci * # Each device is described in new section. N devices are allowed 1482d5ac70f0Sopenharmony_ci * SectionDevice."Headphones" { 1483d5ac70f0Sopenharmony_ci * Comment "Headphones connected to 3.5mm jack" 1484d5ac70f0Sopenharmony_ci * 1485d5ac70f0Sopenharmony_ci * SupportedDevice [ 1486d5ac70f0Sopenharmony_ci * "x" 1487d5ac70f0Sopenharmony_ci * "y" 1488d5ac70f0Sopenharmony_ci * ] 1489d5ac70f0Sopenharmony_ci * 1490d5ac70f0Sopenharmony_ci * ConflictingDevice [ 1491d5ac70f0Sopenharmony_ci * "x" 1492d5ac70f0Sopenharmony_ci * "y" 1493d5ac70f0Sopenharmony_ci * ] 1494d5ac70f0Sopenharmony_ci * 1495d5ac70f0Sopenharmony_ci * EnableSequence [ 1496d5ac70f0Sopenharmony_ci * .... 1497d5ac70f0Sopenharmony_ci * ] 1498d5ac70f0Sopenharmony_ci * 1499d5ac70f0Sopenharmony_ci * DisableSequence [ 1500d5ac70f0Sopenharmony_ci * ... 1501d5ac70f0Sopenharmony_ci * ] 1502d5ac70f0Sopenharmony_ci * 1503d5ac70f0Sopenharmony_ci * TransitionSequence."ToDevice" [ 1504d5ac70f0Sopenharmony_ci * ... 1505d5ac70f0Sopenharmony_ci * ] 1506d5ac70f0Sopenharmony_ci * 1507d5ac70f0Sopenharmony_ci * Value { 1508d5ac70f0Sopenharmony_ci * PlaybackVolume "name='Master Playback Volume',index=2" 1509d5ac70f0Sopenharmony_ci * PlaybackSwitch "name='Master Playback Switch',index=2" 1510d5ac70f0Sopenharmony_ci * } 1511d5ac70f0Sopenharmony_ci * } 1512d5ac70f0Sopenharmony_ci */ 1513d5ac70f0Sopenharmony_cistatic int parse_device(snd_use_case_mgr_t *uc_mgr, 1514d5ac70f0Sopenharmony_ci snd_config_t *cfg, 1515d5ac70f0Sopenharmony_ci void *data1, void *data2) 1516d5ac70f0Sopenharmony_ci{ 1517d5ac70f0Sopenharmony_ci struct use_case_verb *verb = data1; 1518d5ac70f0Sopenharmony_ci char *name; 1519d5ac70f0Sopenharmony_ci struct use_case_device *device; 1520d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1521d5ac70f0Sopenharmony_ci snd_config_t *n; 1522d5ac70f0Sopenharmony_ci int err; 1523d5ac70f0Sopenharmony_ci 1524d5ac70f0Sopenharmony_ci if (parse_get_safe_name(uc_mgr, cfg, data2, &name) < 0) 1525d5ac70f0Sopenharmony_ci return -EINVAL; 1526d5ac70f0Sopenharmony_ci 1527d5ac70f0Sopenharmony_ci device = calloc(1, sizeof(*device)); 1528d5ac70f0Sopenharmony_ci if (device == NULL) { 1529d5ac70f0Sopenharmony_ci free(name); 1530d5ac70f0Sopenharmony_ci return -ENOMEM; 1531d5ac70f0Sopenharmony_ci } 1532d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&device->enable_list); 1533d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&device->disable_list); 1534d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&device->transition_list); 1535d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&device->dev_list.list); 1536d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&device->value_list); 1537d5ac70f0Sopenharmony_ci list_add_tail(&device->list, &verb->device_list); 1538d5ac70f0Sopenharmony_ci device->name = name; 1539d5ac70f0Sopenharmony_ci 1540d5ac70f0Sopenharmony_ci /* in-place evaluation */ 1541d5ac70f0Sopenharmony_ci err = uc_mgr_evaluate_inplace(uc_mgr, cfg); 1542d5ac70f0Sopenharmony_ci if (err < 0) 1543d5ac70f0Sopenharmony_ci return err; 1544d5ac70f0Sopenharmony_ci 1545d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 1546d5ac70f0Sopenharmony_ci const char *id; 1547d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 1548d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 1549d5ac70f0Sopenharmony_ci continue; 1550d5ac70f0Sopenharmony_ci 1551d5ac70f0Sopenharmony_ci if (strcmp(id, "Comment") == 0) { 1552d5ac70f0Sopenharmony_ci err = parse_string_substitute3(uc_mgr, n, &device->comment); 1553d5ac70f0Sopenharmony_ci if (err < 0) { 1554d5ac70f0Sopenharmony_ci uc_error("error: failed to get device comment"); 1555d5ac70f0Sopenharmony_ci return err; 1556d5ac70f0Sopenharmony_ci } 1557d5ac70f0Sopenharmony_ci continue; 1558d5ac70f0Sopenharmony_ci } 1559d5ac70f0Sopenharmony_ci 1560d5ac70f0Sopenharmony_ci if (strcmp(id, "SupportedDevice") == 0) { 1561d5ac70f0Sopenharmony_ci err = parse_device_list(uc_mgr, &device->dev_list, 1562d5ac70f0Sopenharmony_ci DEVLIST_SUPPORTED, n); 1563d5ac70f0Sopenharmony_ci if (err < 0) { 1564d5ac70f0Sopenharmony_ci uc_error("error: failed to parse supported" 1565d5ac70f0Sopenharmony_ci " device list"); 1566d5ac70f0Sopenharmony_ci return err; 1567d5ac70f0Sopenharmony_ci } 1568d5ac70f0Sopenharmony_ci } 1569d5ac70f0Sopenharmony_ci 1570d5ac70f0Sopenharmony_ci if (strcmp(id, "ConflictingDevice") == 0) { 1571d5ac70f0Sopenharmony_ci err = parse_device_list(uc_mgr, &device->dev_list, 1572d5ac70f0Sopenharmony_ci DEVLIST_CONFLICTING, n); 1573d5ac70f0Sopenharmony_ci if (err < 0) { 1574d5ac70f0Sopenharmony_ci uc_error("error: failed to parse conflicting" 1575d5ac70f0Sopenharmony_ci " device list"); 1576d5ac70f0Sopenharmony_ci return err; 1577d5ac70f0Sopenharmony_ci } 1578d5ac70f0Sopenharmony_ci } 1579d5ac70f0Sopenharmony_ci 1580d5ac70f0Sopenharmony_ci if (strcmp(id, "EnableSequence") == 0) { 1581d5ac70f0Sopenharmony_ci uc_dbg("EnableSequence"); 1582d5ac70f0Sopenharmony_ci err = parse_sequence(uc_mgr, &device->enable_list, n); 1583d5ac70f0Sopenharmony_ci if (err < 0) { 1584d5ac70f0Sopenharmony_ci uc_error("error: failed to parse device enable" 1585d5ac70f0Sopenharmony_ci " sequence"); 1586d5ac70f0Sopenharmony_ci return err; 1587d5ac70f0Sopenharmony_ci } 1588d5ac70f0Sopenharmony_ci continue; 1589d5ac70f0Sopenharmony_ci } 1590d5ac70f0Sopenharmony_ci 1591d5ac70f0Sopenharmony_ci if (strcmp(id, "DisableSequence") == 0) { 1592d5ac70f0Sopenharmony_ci uc_dbg("DisableSequence"); 1593d5ac70f0Sopenharmony_ci err = parse_sequence(uc_mgr, &device->disable_list, n); 1594d5ac70f0Sopenharmony_ci if (err < 0) { 1595d5ac70f0Sopenharmony_ci uc_error("error: failed to parse device disable" 1596d5ac70f0Sopenharmony_ci " sequence"); 1597d5ac70f0Sopenharmony_ci return err; 1598d5ac70f0Sopenharmony_ci } 1599d5ac70f0Sopenharmony_ci continue; 1600d5ac70f0Sopenharmony_ci } 1601d5ac70f0Sopenharmony_ci 1602d5ac70f0Sopenharmony_ci if (strcmp(id, "TransitionSequence") == 0) { 1603d5ac70f0Sopenharmony_ci uc_dbg("TransitionSequence"); 1604d5ac70f0Sopenharmony_ci err = parse_transition(uc_mgr, &device->transition_list, n); 1605d5ac70f0Sopenharmony_ci if (err < 0) { 1606d5ac70f0Sopenharmony_ci uc_error("error: failed to parse transition" 1607d5ac70f0Sopenharmony_ci " device"); 1608d5ac70f0Sopenharmony_ci return err; 1609d5ac70f0Sopenharmony_ci } 1610d5ac70f0Sopenharmony_ci continue; 1611d5ac70f0Sopenharmony_ci } 1612d5ac70f0Sopenharmony_ci 1613d5ac70f0Sopenharmony_ci if (strcmp(id, "Value") == 0) { 1614d5ac70f0Sopenharmony_ci err = parse_value(uc_mgr, &device->value_list, n); 1615d5ac70f0Sopenharmony_ci if (err < 0) { 1616d5ac70f0Sopenharmony_ci uc_error("error: failed to parse Value"); 1617d5ac70f0Sopenharmony_ci return err; 1618d5ac70f0Sopenharmony_ci } 1619d5ac70f0Sopenharmony_ci continue; 1620d5ac70f0Sopenharmony_ci } 1621d5ac70f0Sopenharmony_ci } 1622d5ac70f0Sopenharmony_ci return 0; 1623d5ac70f0Sopenharmony_ci} 1624d5ac70f0Sopenharmony_ci 1625d5ac70f0Sopenharmony_ci/* 1626d5ac70f0Sopenharmony_ci * Parse Device Rename/Delete Command 1627d5ac70f0Sopenharmony_ci * 1628d5ac70f0Sopenharmony_ci * # The devices might be renamed to allow the better conditional runtime 1629d5ac70f0Sopenharmony_ci * # evaluation. Bellow example renames Speaker1 device to Speaker and 1630d5ac70f0Sopenharmony_ci * # removes Speaker2 device. 1631d5ac70f0Sopenharmony_ci * RenameDevice."Speaker1" "Speaker" 1632d5ac70f0Sopenharmony_ci * RemoveDevice."Speaker2" "Speaker2" 1633d5ac70f0Sopenharmony_ci */ 1634d5ac70f0Sopenharmony_cistatic int parse_dev_name_list(snd_use_case_mgr_t *uc_mgr, 1635d5ac70f0Sopenharmony_ci snd_config_t *cfg, 1636d5ac70f0Sopenharmony_ci struct list_head *list) 1637d5ac70f0Sopenharmony_ci{ 1638d5ac70f0Sopenharmony_ci snd_config_t *n; 1639d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1640d5ac70f0Sopenharmony_ci const char *id, *name1; 1641d5ac70f0Sopenharmony_ci char *name1s, *name2; 1642d5ac70f0Sopenharmony_ci struct ucm_dev_name *dev; 1643d5ac70f0Sopenharmony_ci snd_config_iterator_t pos; 1644d5ac70f0Sopenharmony_ci int err; 1645d5ac70f0Sopenharmony_ci 1646d5ac70f0Sopenharmony_ci if (snd_config_get_id(cfg, &id) < 0) 1647d5ac70f0Sopenharmony_ci return -EINVAL; 1648d5ac70f0Sopenharmony_ci 1649d5ac70f0Sopenharmony_ci if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 1650d5ac70f0Sopenharmony_ci uc_error("compound type expected for %s", id); 1651d5ac70f0Sopenharmony_ci return -EINVAL; 1652d5ac70f0Sopenharmony_ci } 1653d5ac70f0Sopenharmony_ci 1654d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 1655d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 1656d5ac70f0Sopenharmony_ci 1657d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &name1) < 0) 1658d5ac70f0Sopenharmony_ci return -EINVAL; 1659d5ac70f0Sopenharmony_ci 1660d5ac70f0Sopenharmony_ci err = get_string3(uc_mgr, name1, &name1s); 1661d5ac70f0Sopenharmony_ci if (err < 0) 1662d5ac70f0Sopenharmony_ci return err; 1663d5ac70f0Sopenharmony_ci 1664d5ac70f0Sopenharmony_ci err = parse_string_substitute3(uc_mgr, n, &name2); 1665d5ac70f0Sopenharmony_ci if (err < 0) { 1666d5ac70f0Sopenharmony_ci free(name1s); 1667d5ac70f0Sopenharmony_ci uc_error("error: failed to get target device name for '%s'", name1); 1668d5ac70f0Sopenharmony_ci return err; 1669d5ac70f0Sopenharmony_ci } 1670d5ac70f0Sopenharmony_ci 1671d5ac70f0Sopenharmony_ci /* skip duplicates */ 1672d5ac70f0Sopenharmony_ci list_for_each(pos, list) { 1673d5ac70f0Sopenharmony_ci dev = list_entry(pos, struct ucm_dev_name, list); 1674d5ac70f0Sopenharmony_ci if (strcmp(dev->name1, name1s) == 0) { 1675d5ac70f0Sopenharmony_ci free(name2); 1676d5ac70f0Sopenharmony_ci free(name1s); 1677d5ac70f0Sopenharmony_ci return 0; 1678d5ac70f0Sopenharmony_ci } 1679d5ac70f0Sopenharmony_ci } 1680d5ac70f0Sopenharmony_ci 1681d5ac70f0Sopenharmony_ci free(name1s); 1682d5ac70f0Sopenharmony_ci 1683d5ac70f0Sopenharmony_ci dev = calloc(1, sizeof(*dev)); 1684d5ac70f0Sopenharmony_ci if (dev == NULL) { 1685d5ac70f0Sopenharmony_ci free(name2); 1686d5ac70f0Sopenharmony_ci return -ENOMEM; 1687d5ac70f0Sopenharmony_ci } 1688d5ac70f0Sopenharmony_ci dev->name1 = strdup(name1); 1689d5ac70f0Sopenharmony_ci if (dev->name1 == NULL) { 1690d5ac70f0Sopenharmony_ci free(dev); 1691d5ac70f0Sopenharmony_ci free(name2); 1692d5ac70f0Sopenharmony_ci return -ENOMEM; 1693d5ac70f0Sopenharmony_ci } 1694d5ac70f0Sopenharmony_ci dev->name2 = name2; 1695d5ac70f0Sopenharmony_ci list_add_tail(&dev->list, list); 1696d5ac70f0Sopenharmony_ci } 1697d5ac70f0Sopenharmony_ci 1698d5ac70f0Sopenharmony_ci return 0; 1699d5ac70f0Sopenharmony_ci} 1700d5ac70f0Sopenharmony_ci 1701d5ac70f0Sopenharmony_cistatic int parse_compound_check_legacy(snd_use_case_mgr_t *uc_mgr, 1702d5ac70f0Sopenharmony_ci snd_config_t *cfg, 1703d5ac70f0Sopenharmony_ci int (*fcn)(snd_use_case_mgr_t *, snd_config_t *, void *, void *), 1704d5ac70f0Sopenharmony_ci void *data1) 1705d5ac70f0Sopenharmony_ci{ 1706d5ac70f0Sopenharmony_ci const char *id, *idchild; 1707d5ac70f0Sopenharmony_ci int child_ctr = 0, legacy_format = 1; 1708d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1709d5ac70f0Sopenharmony_ci snd_config_t *child; 1710d5ac70f0Sopenharmony_ci int err; 1711d5ac70f0Sopenharmony_ci 1712d5ac70f0Sopenharmony_ci err = snd_config_get_id(cfg, &id); 1713d5ac70f0Sopenharmony_ci if (err < 0) 1714d5ac70f0Sopenharmony_ci return err; 1715d5ac70f0Sopenharmony_ci 1716d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 1717d5ac70f0Sopenharmony_ci child_ctr++; 1718d5ac70f0Sopenharmony_ci if (child_ctr > 1) { 1719d5ac70f0Sopenharmony_ci break; 1720d5ac70f0Sopenharmony_ci } 1721d5ac70f0Sopenharmony_ci 1722d5ac70f0Sopenharmony_ci child = snd_config_iterator_entry(i); 1723d5ac70f0Sopenharmony_ci 1724d5ac70f0Sopenharmony_ci if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 1725d5ac70f0Sopenharmony_ci legacy_format = 0; 1726d5ac70f0Sopenharmony_ci break; 1727d5ac70f0Sopenharmony_ci } 1728d5ac70f0Sopenharmony_ci 1729d5ac70f0Sopenharmony_ci if (snd_config_get_id(child, &idchild) < 0) 1730d5ac70f0Sopenharmony_ci return -EINVAL; 1731d5ac70f0Sopenharmony_ci 1732d5ac70f0Sopenharmony_ci if (strcmp(idchild, "0")) { 1733d5ac70f0Sopenharmony_ci legacy_format = 0; 1734d5ac70f0Sopenharmony_ci break; 1735d5ac70f0Sopenharmony_ci } 1736d5ac70f0Sopenharmony_ci } 1737d5ac70f0Sopenharmony_ci if (child_ctr != 1) { 1738d5ac70f0Sopenharmony_ci legacy_format = 0; 1739d5ac70f0Sopenharmony_ci } 1740d5ac70f0Sopenharmony_ci 1741d5ac70f0Sopenharmony_ci if (legacy_format) 1742d5ac70f0Sopenharmony_ci return parse_compound(uc_mgr, cfg, fcn, data1, (void *)id); 1743d5ac70f0Sopenharmony_ci else 1744d5ac70f0Sopenharmony_ci return fcn(uc_mgr, cfg, data1, NULL); 1745d5ac70f0Sopenharmony_ci} 1746d5ac70f0Sopenharmony_ci 1747d5ac70f0Sopenharmony_cistatic int parse_device_name(snd_use_case_mgr_t *uc_mgr, 1748d5ac70f0Sopenharmony_ci snd_config_t *cfg, 1749d5ac70f0Sopenharmony_ci void *data1, 1750d5ac70f0Sopenharmony_ci void *data2 ATTRIBUTE_UNUSED) 1751d5ac70f0Sopenharmony_ci{ 1752d5ac70f0Sopenharmony_ci return parse_compound_check_legacy(uc_mgr, cfg, parse_device, data1); 1753d5ac70f0Sopenharmony_ci} 1754d5ac70f0Sopenharmony_ci 1755d5ac70f0Sopenharmony_cistatic int parse_modifier_name(snd_use_case_mgr_t *uc_mgr, 1756d5ac70f0Sopenharmony_ci snd_config_t *cfg, 1757d5ac70f0Sopenharmony_ci void *data1, 1758d5ac70f0Sopenharmony_ci void *data2 ATTRIBUTE_UNUSED) 1759d5ac70f0Sopenharmony_ci{ 1760d5ac70f0Sopenharmony_ci return parse_compound_check_legacy(uc_mgr, cfg, parse_modifier, data1); 1761d5ac70f0Sopenharmony_ci} 1762d5ac70f0Sopenharmony_ci 1763d5ac70f0Sopenharmony_cistatic int verb_dev_list_add(struct use_case_verb *verb, 1764d5ac70f0Sopenharmony_ci enum dev_list_type dst_type, 1765d5ac70f0Sopenharmony_ci const char *dst, 1766d5ac70f0Sopenharmony_ci const char *src) 1767d5ac70f0Sopenharmony_ci{ 1768d5ac70f0Sopenharmony_ci struct use_case_device *device; 1769d5ac70f0Sopenharmony_ci struct list_head *pos; 1770d5ac70f0Sopenharmony_ci 1771d5ac70f0Sopenharmony_ci list_for_each(pos, &verb->device_list) { 1772d5ac70f0Sopenharmony_ci device = list_entry(pos, struct use_case_device, list); 1773d5ac70f0Sopenharmony_ci if (strcmp(device->name, dst) != 0) 1774d5ac70f0Sopenharmony_ci continue; 1775d5ac70f0Sopenharmony_ci if (device->dev_list.type != dst_type) { 1776d5ac70f0Sopenharmony_ci if (list_empty(&device->dev_list.list)) { 1777d5ac70f0Sopenharmony_ci device->dev_list.type = dst_type; 1778d5ac70f0Sopenharmony_ci } else { 1779d5ac70f0Sopenharmony_ci uc_error("error: incompatible device list type ('%s', '%s')", 1780d5ac70f0Sopenharmony_ci device->name, src); 1781d5ac70f0Sopenharmony_ci return -EINVAL; 1782d5ac70f0Sopenharmony_ci } 1783d5ac70f0Sopenharmony_ci } 1784d5ac70f0Sopenharmony_ci return uc_mgr_put_to_dev_list(&device->dev_list, src); 1785d5ac70f0Sopenharmony_ci } 1786d5ac70f0Sopenharmony_ci uc_error("error: unable to find device '%s'", dst); 1787d5ac70f0Sopenharmony_ci return -ENOENT; 1788d5ac70f0Sopenharmony_ci} 1789d5ac70f0Sopenharmony_ci 1790d5ac70f0Sopenharmony_cistatic int verb_dev_list_check(struct use_case_verb *verb) 1791d5ac70f0Sopenharmony_ci{ 1792d5ac70f0Sopenharmony_ci struct list_head *pos, *pos2; 1793d5ac70f0Sopenharmony_ci struct use_case_device *device; 1794d5ac70f0Sopenharmony_ci struct dev_list_node *dlist; 1795d5ac70f0Sopenharmony_ci int err; 1796d5ac70f0Sopenharmony_ci 1797d5ac70f0Sopenharmony_ci list_for_each(pos, &verb->device_list) { 1798d5ac70f0Sopenharmony_ci device = list_entry(pos, struct use_case_device, list); 1799d5ac70f0Sopenharmony_ci list_for_each(pos2, &device->dev_list.list) { 1800d5ac70f0Sopenharmony_ci dlist = list_entry(pos2, struct dev_list_node, list); 1801d5ac70f0Sopenharmony_ci err = verb_dev_list_add(verb, device->dev_list.type, 1802d5ac70f0Sopenharmony_ci dlist->name, device->name); 1803d5ac70f0Sopenharmony_ci if (err < 0) 1804d5ac70f0Sopenharmony_ci return err; 1805d5ac70f0Sopenharmony_ci } 1806d5ac70f0Sopenharmony_ci } 1807d5ac70f0Sopenharmony_ci return 0; 1808d5ac70f0Sopenharmony_ci} 1809d5ac70f0Sopenharmony_ci 1810d5ac70f0Sopenharmony_cistatic int verb_device_management(struct use_case_verb *verb) 1811d5ac70f0Sopenharmony_ci{ 1812d5ac70f0Sopenharmony_ci struct list_head *pos; 1813d5ac70f0Sopenharmony_ci struct ucm_dev_name *dev; 1814d5ac70f0Sopenharmony_ci int err; 1815d5ac70f0Sopenharmony_ci 1816d5ac70f0Sopenharmony_ci /* rename devices */ 1817d5ac70f0Sopenharmony_ci list_for_each(pos, &verb->rename_list) { 1818d5ac70f0Sopenharmony_ci dev = list_entry(pos, struct ucm_dev_name, list); 1819d5ac70f0Sopenharmony_ci err = uc_mgr_rename_device(verb, dev->name1, dev->name2); 1820d5ac70f0Sopenharmony_ci if (err < 0) { 1821d5ac70f0Sopenharmony_ci uc_error("error: cannot rename device '%s' to '%s'", dev->name1, dev->name2); 1822d5ac70f0Sopenharmony_ci return err; 1823d5ac70f0Sopenharmony_ci } 1824d5ac70f0Sopenharmony_ci } 1825d5ac70f0Sopenharmony_ci 1826d5ac70f0Sopenharmony_ci /* remove devices */ 1827d5ac70f0Sopenharmony_ci list_for_each(pos, &verb->remove_list) { 1828d5ac70f0Sopenharmony_ci dev = list_entry(pos, struct ucm_dev_name, list); 1829d5ac70f0Sopenharmony_ci err = uc_mgr_remove_device(verb, dev->name2); 1830d5ac70f0Sopenharmony_ci if (err < 0) { 1831d5ac70f0Sopenharmony_ci uc_error("error: cannot remove device '%s'", dev->name2); 1832d5ac70f0Sopenharmony_ci return err; 1833d5ac70f0Sopenharmony_ci } 1834d5ac70f0Sopenharmony_ci } 1835d5ac70f0Sopenharmony_ci 1836d5ac70f0Sopenharmony_ci /* those lists are no longer used */ 1837d5ac70f0Sopenharmony_ci uc_mgr_free_dev_name_list(&verb->rename_list); 1838d5ac70f0Sopenharmony_ci uc_mgr_free_dev_name_list(&verb->remove_list); 1839d5ac70f0Sopenharmony_ci 1840d5ac70f0Sopenharmony_ci /* handle conflicting/supported lists */ 1841d5ac70f0Sopenharmony_ci return verb_dev_list_check(verb); 1842d5ac70f0Sopenharmony_ci} 1843d5ac70f0Sopenharmony_ci 1844d5ac70f0Sopenharmony_ci/* 1845d5ac70f0Sopenharmony_ci * Parse Verb Section 1846d5ac70f0Sopenharmony_ci * 1847d5ac70f0Sopenharmony_ci * # Example Use case verb section for Voice call blah 1848d5ac70f0Sopenharmony_ci * # By Joe Blogs <joe@blogs.com> 1849d5ac70f0Sopenharmony_ci * 1850d5ac70f0Sopenharmony_ci * SectionVerb { 1851d5ac70f0Sopenharmony_ci * # enable and disable sequences are compulsory 1852d5ac70f0Sopenharmony_ci * EnableSequence [ 1853d5ac70f0Sopenharmony_ci * cset "name='Master Playback Switch',index=2 0,0" 1854d5ac70f0Sopenharmony_ci * cset "name='Master Playback Volume',index=2 25,25" 1855d5ac70f0Sopenharmony_ci * msleep 50 1856d5ac70f0Sopenharmony_ci * cset "name='Master Playback Switch',index=2 1,1" 1857d5ac70f0Sopenharmony_ci * cset "name='Master Playback Volume',index=2 50,50" 1858d5ac70f0Sopenharmony_ci * ] 1859d5ac70f0Sopenharmony_ci * 1860d5ac70f0Sopenharmony_ci * DisableSequence [ 1861d5ac70f0Sopenharmony_ci * cset "name='Master Playback Switch',index=2 0,0" 1862d5ac70f0Sopenharmony_ci * cset "name='Master Playback Volume',index=2 25,25" 1863d5ac70f0Sopenharmony_ci * msleep 50 1864d5ac70f0Sopenharmony_ci * cset "name='Master Playback Switch',index=2 1,1" 1865d5ac70f0Sopenharmony_ci * cset "name='Master Playback Volume',index=2 50,50" 1866d5ac70f0Sopenharmony_ci * ] 1867d5ac70f0Sopenharmony_ci * 1868d5ac70f0Sopenharmony_ci * # Optional transition verb 1869d5ac70f0Sopenharmony_ci * TransitionSequence."ToCaseName" [ 1870d5ac70f0Sopenharmony_ci * msleep 1 1871d5ac70f0Sopenharmony_ci * ] 1872d5ac70f0Sopenharmony_ci * 1873d5ac70f0Sopenharmony_ci * # Optional TQ and ALSA PCMs 1874d5ac70f0Sopenharmony_ci * Value { 1875d5ac70f0Sopenharmony_ci * TQ HiFi 1876d5ac70f0Sopenharmony_ci * CapturePCM "hw:0" 1877d5ac70f0Sopenharmony_ci * PlaybackPCM "hw:0" 1878d5ac70f0Sopenharmony_ci * } 1879d5ac70f0Sopenharmony_ci * } 1880d5ac70f0Sopenharmony_ci */ 1881d5ac70f0Sopenharmony_cistatic int parse_verb(snd_use_case_mgr_t *uc_mgr, 1882d5ac70f0Sopenharmony_ci struct use_case_verb *verb, 1883d5ac70f0Sopenharmony_ci snd_config_t *cfg) 1884d5ac70f0Sopenharmony_ci{ 1885d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1886d5ac70f0Sopenharmony_ci snd_config_t *n; 1887d5ac70f0Sopenharmony_ci int err; 1888d5ac70f0Sopenharmony_ci 1889d5ac70f0Sopenharmony_ci /* in-place evaluation */ 1890d5ac70f0Sopenharmony_ci err = uc_mgr_evaluate_inplace(uc_mgr, cfg); 1891d5ac70f0Sopenharmony_ci if (err < 0) 1892d5ac70f0Sopenharmony_ci return err; 1893d5ac70f0Sopenharmony_ci 1894d5ac70f0Sopenharmony_ci /* parse verb section */ 1895d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 1896d5ac70f0Sopenharmony_ci const char *id; 1897d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 1898d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 1899d5ac70f0Sopenharmony_ci continue; 1900d5ac70f0Sopenharmony_ci 1901d5ac70f0Sopenharmony_ci if (strcmp(id, "EnableSequence") == 0) { 1902d5ac70f0Sopenharmony_ci uc_dbg("Parse EnableSequence"); 1903d5ac70f0Sopenharmony_ci err = parse_sequence(uc_mgr, &verb->enable_list, n); 1904d5ac70f0Sopenharmony_ci if (err < 0) { 1905d5ac70f0Sopenharmony_ci uc_error("error: failed to parse verb enable sequence"); 1906d5ac70f0Sopenharmony_ci return err; 1907d5ac70f0Sopenharmony_ci } 1908d5ac70f0Sopenharmony_ci continue; 1909d5ac70f0Sopenharmony_ci } 1910d5ac70f0Sopenharmony_ci 1911d5ac70f0Sopenharmony_ci if (strcmp(id, "DisableSequence") == 0) { 1912d5ac70f0Sopenharmony_ci uc_dbg("Parse DisableSequence"); 1913d5ac70f0Sopenharmony_ci err = parse_sequence(uc_mgr, &verb->disable_list, n); 1914d5ac70f0Sopenharmony_ci if (err < 0) { 1915d5ac70f0Sopenharmony_ci uc_error("error: failed to parse verb disable sequence"); 1916d5ac70f0Sopenharmony_ci return err; 1917d5ac70f0Sopenharmony_ci } 1918d5ac70f0Sopenharmony_ci continue; 1919d5ac70f0Sopenharmony_ci } 1920d5ac70f0Sopenharmony_ci 1921d5ac70f0Sopenharmony_ci if (strcmp(id, "TransitionSequence") == 0) { 1922d5ac70f0Sopenharmony_ci uc_dbg("Parse TransitionSequence"); 1923d5ac70f0Sopenharmony_ci err = parse_transition(uc_mgr, &verb->transition_list, n); 1924d5ac70f0Sopenharmony_ci if (err < 0) { 1925d5ac70f0Sopenharmony_ci uc_error("error: failed to parse transition sequence"); 1926d5ac70f0Sopenharmony_ci return err; 1927d5ac70f0Sopenharmony_ci } 1928d5ac70f0Sopenharmony_ci continue; 1929d5ac70f0Sopenharmony_ci } 1930d5ac70f0Sopenharmony_ci 1931d5ac70f0Sopenharmony_ci if (strcmp(id, "Value") == 0) { 1932d5ac70f0Sopenharmony_ci uc_dbg("Parse Value"); 1933d5ac70f0Sopenharmony_ci err = parse_value(uc_mgr, &verb->value_list, n); 1934d5ac70f0Sopenharmony_ci if (err < 0) 1935d5ac70f0Sopenharmony_ci return err; 1936d5ac70f0Sopenharmony_ci continue; 1937d5ac70f0Sopenharmony_ci } 1938d5ac70f0Sopenharmony_ci } 1939d5ac70f0Sopenharmony_ci 1940d5ac70f0Sopenharmony_ci return 0; 1941d5ac70f0Sopenharmony_ci} 1942d5ac70f0Sopenharmony_ci 1943d5ac70f0Sopenharmony_ci/* 1944d5ac70f0Sopenharmony_ci * Parse a Use case verb file. 1945d5ac70f0Sopenharmony_ci * 1946d5ac70f0Sopenharmony_ci * This file contains the following :- 1947d5ac70f0Sopenharmony_ci * o Verb enable and disable sequences. 1948d5ac70f0Sopenharmony_ci * o Supported Device enable and disable sequences for verb. 1949d5ac70f0Sopenharmony_ci * o Supported Modifier enable and disable sequences for verb 1950d5ac70f0Sopenharmony_ci * o Optional QoS for the verb and modifiers. 1951d5ac70f0Sopenharmony_ci * o Optional PCM device ID for verb and modifiers 1952d5ac70f0Sopenharmony_ci * o Alias kcontrols IDs for master and volumes and mutes. 1953d5ac70f0Sopenharmony_ci */ 1954d5ac70f0Sopenharmony_cistatic int parse_verb_file(snd_use_case_mgr_t *uc_mgr, 1955d5ac70f0Sopenharmony_ci const char *use_case_name, 1956d5ac70f0Sopenharmony_ci const char *comment, 1957d5ac70f0Sopenharmony_ci const char *file) 1958d5ac70f0Sopenharmony_ci{ 1959d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1960d5ac70f0Sopenharmony_ci snd_config_t *n; 1961d5ac70f0Sopenharmony_ci struct use_case_verb *verb; 1962d5ac70f0Sopenharmony_ci snd_config_t *cfg; 1963d5ac70f0Sopenharmony_ci int err; 1964d5ac70f0Sopenharmony_ci 1965d5ac70f0Sopenharmony_ci /* allocate verb */ 1966d5ac70f0Sopenharmony_ci verb = calloc(1, sizeof(struct use_case_verb)); 1967d5ac70f0Sopenharmony_ci if (verb == NULL) 1968d5ac70f0Sopenharmony_ci return -ENOMEM; 1969d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&verb->enable_list); 1970d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&verb->disable_list); 1971d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&verb->transition_list); 1972d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&verb->device_list); 1973d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&verb->cmpt_device_list); 1974d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&verb->modifier_list); 1975d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&verb->value_list); 1976d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&verb->rename_list); 1977d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&verb->remove_list); 1978d5ac70f0Sopenharmony_ci list_add_tail(&verb->list, &uc_mgr->verb_list); 1979d5ac70f0Sopenharmony_ci if (use_case_name == NULL) 1980d5ac70f0Sopenharmony_ci return -EINVAL; 1981d5ac70f0Sopenharmony_ci verb->name = strdup(use_case_name); 1982d5ac70f0Sopenharmony_ci if (verb->name == NULL) 1983d5ac70f0Sopenharmony_ci return -ENOMEM; 1984d5ac70f0Sopenharmony_ci 1985d5ac70f0Sopenharmony_ci if (comment != NULL) { 1986d5ac70f0Sopenharmony_ci verb->comment = strdup(comment); 1987d5ac70f0Sopenharmony_ci if (verb->comment == NULL) 1988d5ac70f0Sopenharmony_ci return -ENOMEM; 1989d5ac70f0Sopenharmony_ci } 1990d5ac70f0Sopenharmony_ci 1991d5ac70f0Sopenharmony_ci /* open Verb file for reading */ 1992d5ac70f0Sopenharmony_ci err = uc_mgr_config_load_file(uc_mgr, file, &cfg); 1993d5ac70f0Sopenharmony_ci if (err < 0) 1994d5ac70f0Sopenharmony_ci return err; 1995d5ac70f0Sopenharmony_ci 1996d5ac70f0Sopenharmony_ci /* in-place evaluation */ 1997d5ac70f0Sopenharmony_ci err = uc_mgr_evaluate_inplace(uc_mgr, cfg); 1998d5ac70f0Sopenharmony_ci if (err < 0) 1999d5ac70f0Sopenharmony_ci goto _err; 2000d5ac70f0Sopenharmony_ci 2001d5ac70f0Sopenharmony_ci /* parse master config sections */ 2002d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 2003d5ac70f0Sopenharmony_ci const char *id; 2004d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 2005d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 2006d5ac70f0Sopenharmony_ci continue; 2007d5ac70f0Sopenharmony_ci 2008d5ac70f0Sopenharmony_ci /* find verb section and parse it */ 2009d5ac70f0Sopenharmony_ci if (strcmp(id, "SectionVerb") == 0) { 2010d5ac70f0Sopenharmony_ci err = parse_verb(uc_mgr, verb, n); 2011d5ac70f0Sopenharmony_ci if (err < 0) { 2012d5ac70f0Sopenharmony_ci uc_error("error: %s failed to parse verb", 2013d5ac70f0Sopenharmony_ci file); 2014d5ac70f0Sopenharmony_ci goto _err; 2015d5ac70f0Sopenharmony_ci } 2016d5ac70f0Sopenharmony_ci continue; 2017d5ac70f0Sopenharmony_ci } 2018d5ac70f0Sopenharmony_ci 2019d5ac70f0Sopenharmony_ci /* find device sections and parse them */ 2020d5ac70f0Sopenharmony_ci if (strcmp(id, "SectionDevice") == 0) { 2021d5ac70f0Sopenharmony_ci err = parse_compound(uc_mgr, n, 2022d5ac70f0Sopenharmony_ci parse_device_name, verb, NULL); 2023d5ac70f0Sopenharmony_ci if (err < 0) { 2024d5ac70f0Sopenharmony_ci uc_error("error: %s failed to parse device", 2025d5ac70f0Sopenharmony_ci file); 2026d5ac70f0Sopenharmony_ci goto _err; 2027d5ac70f0Sopenharmony_ci } 2028d5ac70f0Sopenharmony_ci continue; 2029d5ac70f0Sopenharmony_ci } 2030d5ac70f0Sopenharmony_ci 2031d5ac70f0Sopenharmony_ci /* find modifier sections and parse them */ 2032d5ac70f0Sopenharmony_ci if (strcmp(id, "SectionModifier") == 0) { 2033d5ac70f0Sopenharmony_ci err = parse_compound(uc_mgr, n, 2034d5ac70f0Sopenharmony_ci parse_modifier_name, verb, NULL); 2035d5ac70f0Sopenharmony_ci if (err < 0) { 2036d5ac70f0Sopenharmony_ci uc_error("error: %s failed to parse modifier", 2037d5ac70f0Sopenharmony_ci file); 2038d5ac70f0Sopenharmony_ci goto _err; 2039d5ac70f0Sopenharmony_ci } 2040d5ac70f0Sopenharmony_ci continue; 2041d5ac70f0Sopenharmony_ci } 2042d5ac70f0Sopenharmony_ci 2043d5ac70f0Sopenharmony_ci /* device renames */ 2044d5ac70f0Sopenharmony_ci if (strcmp(id, "RenameDevice") == 0) { 2045d5ac70f0Sopenharmony_ci err = parse_dev_name_list(uc_mgr, n, &verb->rename_list); 2046d5ac70f0Sopenharmony_ci if (err < 0) { 2047d5ac70f0Sopenharmony_ci uc_error("error: %s failed to parse device rename", 2048d5ac70f0Sopenharmony_ci file); 2049d5ac70f0Sopenharmony_ci goto _err; 2050d5ac70f0Sopenharmony_ci } 2051d5ac70f0Sopenharmony_ci continue; 2052d5ac70f0Sopenharmony_ci } 2053d5ac70f0Sopenharmony_ci 2054d5ac70f0Sopenharmony_ci /* device remove */ 2055d5ac70f0Sopenharmony_ci if (strcmp(id, "RemoveDevice") == 0) { 2056d5ac70f0Sopenharmony_ci err = parse_dev_name_list(uc_mgr, n, &verb->remove_list); 2057d5ac70f0Sopenharmony_ci if (err < 0) { 2058d5ac70f0Sopenharmony_ci uc_error("error: %s failed to parse device remove", 2059d5ac70f0Sopenharmony_ci file); 2060d5ac70f0Sopenharmony_ci goto _err; 2061d5ac70f0Sopenharmony_ci } 2062d5ac70f0Sopenharmony_ci continue; 2063d5ac70f0Sopenharmony_ci } 2064d5ac70f0Sopenharmony_ci 2065d5ac70f0Sopenharmony_ci /* alsa-lib configuration */ 2066d5ac70f0Sopenharmony_ci if (uc_mgr->conf_format > 3 && strcmp(id, "LibraryConfig") == 0) { 2067d5ac70f0Sopenharmony_ci err = parse_libconfig(uc_mgr, n); 2068d5ac70f0Sopenharmony_ci if (err < 0) { 2069d5ac70f0Sopenharmony_ci uc_error("error: failed to parse LibConfig"); 2070d5ac70f0Sopenharmony_ci goto _err; 2071d5ac70f0Sopenharmony_ci } 2072d5ac70f0Sopenharmony_ci continue; 2073d5ac70f0Sopenharmony_ci } 2074d5ac70f0Sopenharmony_ci } 2075d5ac70f0Sopenharmony_ci 2076d5ac70f0Sopenharmony_ci snd_config_delete(cfg); 2077d5ac70f0Sopenharmony_ci 2078d5ac70f0Sopenharmony_ci /* use case verb must have at least 1 device */ 2079d5ac70f0Sopenharmony_ci if (list_empty(&verb->device_list)) { 2080d5ac70f0Sopenharmony_ci uc_error("error: no use case device defined", file); 2081d5ac70f0Sopenharmony_ci return -EINVAL; 2082d5ac70f0Sopenharmony_ci } 2083d5ac70f0Sopenharmony_ci 2084d5ac70f0Sopenharmony_ci /* do device rename and delete */ 2085d5ac70f0Sopenharmony_ci err = verb_device_management(verb); 2086d5ac70f0Sopenharmony_ci if (err < 0) { 2087d5ac70f0Sopenharmony_ci uc_error("error: device management error in verb '%s'", verb->name); 2088d5ac70f0Sopenharmony_ci return err; 2089d5ac70f0Sopenharmony_ci } 2090d5ac70f0Sopenharmony_ci 2091d5ac70f0Sopenharmony_ci return 0; 2092d5ac70f0Sopenharmony_ci 2093d5ac70f0Sopenharmony_ci _err: 2094d5ac70f0Sopenharmony_ci snd_config_delete(cfg); 2095d5ac70f0Sopenharmony_ci return err; 2096d5ac70f0Sopenharmony_ci} 2097d5ac70f0Sopenharmony_ci 2098d5ac70f0Sopenharmony_ci/* 2099d5ac70f0Sopenharmony_ci * Parse variant information 2100d5ac70f0Sopenharmony_ci */ 2101d5ac70f0Sopenharmony_cistatic int parse_variant(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg, 2102d5ac70f0Sopenharmony_ci char **_vfile, char **_vcomment) 2103d5ac70f0Sopenharmony_ci{ 2104d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 2105d5ac70f0Sopenharmony_ci snd_config_t *n; 2106d5ac70f0Sopenharmony_ci char *file = NULL, *comment = NULL; 2107d5ac70f0Sopenharmony_ci int err; 2108d5ac70f0Sopenharmony_ci 2109d5ac70f0Sopenharmony_ci /* parse master config sections */ 2110d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 2111d5ac70f0Sopenharmony_ci const char *id; 2112d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 2113d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 2114d5ac70f0Sopenharmony_ci continue; 2115d5ac70f0Sopenharmony_ci 2116d5ac70f0Sopenharmony_ci /* get use case verb file name */ 2117d5ac70f0Sopenharmony_ci if (strcmp(id, "File") == 0) { 2118d5ac70f0Sopenharmony_ci if (_vfile) { 2119d5ac70f0Sopenharmony_ci err = parse_string_substitute3(uc_mgr, n, &file); 2120d5ac70f0Sopenharmony_ci if (err < 0) { 2121d5ac70f0Sopenharmony_ci uc_error("failed to get File"); 2122d5ac70f0Sopenharmony_ci goto __error; 2123d5ac70f0Sopenharmony_ci } 2124d5ac70f0Sopenharmony_ci } 2125d5ac70f0Sopenharmony_ci continue; 2126d5ac70f0Sopenharmony_ci } 2127d5ac70f0Sopenharmony_ci 2128d5ac70f0Sopenharmony_ci /* get optional use case comment */ 2129d5ac70f0Sopenharmony_ci if (strncmp(id, "Comment", 7) == 0) { 2130d5ac70f0Sopenharmony_ci if (_vcomment) { 2131d5ac70f0Sopenharmony_ci err = parse_string_substitute3(uc_mgr, n, &comment); 2132d5ac70f0Sopenharmony_ci if (err < 0) { 2133d5ac70f0Sopenharmony_ci uc_error("error: failed to get Comment"); 2134d5ac70f0Sopenharmony_ci goto __error; 2135d5ac70f0Sopenharmony_ci } 2136d5ac70f0Sopenharmony_ci } 2137d5ac70f0Sopenharmony_ci continue; 2138d5ac70f0Sopenharmony_ci } 2139d5ac70f0Sopenharmony_ci 2140d5ac70f0Sopenharmony_ci uc_error("unknown field '%s' in Variant section", id); 2141d5ac70f0Sopenharmony_ci err = -EINVAL; 2142d5ac70f0Sopenharmony_ci goto __error; 2143d5ac70f0Sopenharmony_ci } 2144d5ac70f0Sopenharmony_ci 2145d5ac70f0Sopenharmony_ci if (_vfile) 2146d5ac70f0Sopenharmony_ci *_vfile = file; 2147d5ac70f0Sopenharmony_ci if (_vcomment) 2148d5ac70f0Sopenharmony_ci *_vcomment = comment; 2149d5ac70f0Sopenharmony_ci return 0; 2150d5ac70f0Sopenharmony_ci 2151d5ac70f0Sopenharmony_ci__error: 2152d5ac70f0Sopenharmony_ci free(file); 2153d5ac70f0Sopenharmony_ci free(comment); 2154d5ac70f0Sopenharmony_ci return err; 2155d5ac70f0Sopenharmony_ci} 2156d5ac70f0Sopenharmony_ci 2157d5ac70f0Sopenharmony_ci/* 2158d5ac70f0Sopenharmony_ci * Parse master section for "Use Case" and "File" tags. 2159d5ac70f0Sopenharmony_ci */ 2160d5ac70f0Sopenharmony_cistatic int parse_master_section(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg, 2161d5ac70f0Sopenharmony_ci void *data1 ATTRIBUTE_UNUSED, 2162d5ac70f0Sopenharmony_ci void *data2 ATTRIBUTE_UNUSED) 2163d5ac70f0Sopenharmony_ci{ 2164d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 2165d5ac70f0Sopenharmony_ci snd_config_t *n, *variant = NULL; 2166d5ac70f0Sopenharmony_ci char *use_case_name, *file = NULL, *comment = NULL; 2167d5ac70f0Sopenharmony_ci bool variant_ok = false; 2168d5ac70f0Sopenharmony_ci int err; 2169d5ac70f0Sopenharmony_ci 2170d5ac70f0Sopenharmony_ci if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 2171d5ac70f0Sopenharmony_ci uc_error("compound type expected for use case section"); 2172d5ac70f0Sopenharmony_ci return -EINVAL; 2173d5ac70f0Sopenharmony_ci } 2174d5ac70f0Sopenharmony_ci 2175d5ac70f0Sopenharmony_ci err = parse_get_safe_name(uc_mgr, cfg, NULL, &use_case_name); 2176d5ac70f0Sopenharmony_ci if (err < 0) { 2177d5ac70f0Sopenharmony_ci uc_error("unable to get name for use case section"); 2178d5ac70f0Sopenharmony_ci return err; 2179d5ac70f0Sopenharmony_ci } 2180d5ac70f0Sopenharmony_ci 2181d5ac70f0Sopenharmony_ci /* in-place evaluation */ 2182d5ac70f0Sopenharmony_ci uc_mgr->parse_master_section = 1; 2183d5ac70f0Sopenharmony_ci err = uc_mgr_evaluate_inplace(uc_mgr, cfg); 2184d5ac70f0Sopenharmony_ci uc_mgr->parse_master_section = 0; 2185d5ac70f0Sopenharmony_ci if (err < 0) 2186d5ac70f0Sopenharmony_ci goto __error; 2187d5ac70f0Sopenharmony_ci 2188d5ac70f0Sopenharmony_ci /* parse master config sections */ 2189d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 2190d5ac70f0Sopenharmony_ci const char *id; 2191d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 2192d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 2193d5ac70f0Sopenharmony_ci continue; 2194d5ac70f0Sopenharmony_ci 2195d5ac70f0Sopenharmony_ci /* get use case verb file name */ 2196d5ac70f0Sopenharmony_ci if (strcmp(id, "File") == 0) { 2197d5ac70f0Sopenharmony_ci err = parse_string_substitute3(uc_mgr, n, &file); 2198d5ac70f0Sopenharmony_ci if (err < 0) { 2199d5ac70f0Sopenharmony_ci uc_error("failed to get File"); 2200d5ac70f0Sopenharmony_ci goto __error; 2201d5ac70f0Sopenharmony_ci } 2202d5ac70f0Sopenharmony_ci continue; 2203d5ac70f0Sopenharmony_ci } 2204d5ac70f0Sopenharmony_ci 2205d5ac70f0Sopenharmony_ci /* get optional use case comment */ 2206d5ac70f0Sopenharmony_ci if (strncmp(id, "Comment", 7) == 0) { 2207d5ac70f0Sopenharmony_ci err = parse_string_substitute3(uc_mgr, n, &comment); 2208d5ac70f0Sopenharmony_ci if (err < 0) { 2209d5ac70f0Sopenharmony_ci uc_error("error: failed to get Comment"); 2210d5ac70f0Sopenharmony_ci goto __error; 2211d5ac70f0Sopenharmony_ci } 2212d5ac70f0Sopenharmony_ci continue; 2213d5ac70f0Sopenharmony_ci } 2214d5ac70f0Sopenharmony_ci 2215d5ac70f0Sopenharmony_ci if (uc_mgr->conf_format >= 6 && strcmp(id, "Variant") == 0) { 2216d5ac70f0Sopenharmony_ci snd_config_iterator_t i2, next2; 2217d5ac70f0Sopenharmony_ci variant = n; 2218d5ac70f0Sopenharmony_ci snd_config_for_each(i2, next2, n) { 2219d5ac70f0Sopenharmony_ci const char *id2; 2220d5ac70f0Sopenharmony_ci snd_config_t *n2; 2221d5ac70f0Sopenharmony_ci n2 = snd_config_iterator_entry(i2); 2222d5ac70f0Sopenharmony_ci if (snd_config_get_id(n2, &id2) < 0) 2223d5ac70f0Sopenharmony_ci continue; 2224d5ac70f0Sopenharmony_ci err = uc_mgr_evaluate_inplace(uc_mgr, n2); 2225d5ac70f0Sopenharmony_ci if (err < 0) 2226d5ac70f0Sopenharmony_ci goto __error; 2227d5ac70f0Sopenharmony_ci if (strcmp(use_case_name, id2) == 0) 2228d5ac70f0Sopenharmony_ci variant_ok = true; 2229d5ac70f0Sopenharmony_ci } 2230d5ac70f0Sopenharmony_ci continue; 2231d5ac70f0Sopenharmony_ci } 2232d5ac70f0Sopenharmony_ci 2233d5ac70f0Sopenharmony_ci uc_error("unknown field '%s' in SectionUseCase", id); 2234d5ac70f0Sopenharmony_ci } 2235d5ac70f0Sopenharmony_ci 2236d5ac70f0Sopenharmony_ci if (variant && !variant_ok) { 2237d5ac70f0Sopenharmony_ci uc_error("error: undefined variant '%s'", use_case_name); 2238d5ac70f0Sopenharmony_ci err = -EINVAL; 2239d5ac70f0Sopenharmony_ci goto __error; 2240d5ac70f0Sopenharmony_ci } 2241d5ac70f0Sopenharmony_ci 2242d5ac70f0Sopenharmony_ci if (!variant) { 2243d5ac70f0Sopenharmony_ci uc_dbg("use_case_name %s file '%s'", use_case_name, file); 2244d5ac70f0Sopenharmony_ci 2245d5ac70f0Sopenharmony_ci /* do we have both use case name and file ? */ 2246d5ac70f0Sopenharmony_ci if (!file) { 2247d5ac70f0Sopenharmony_ci uc_error("error: use case missing file"); 2248d5ac70f0Sopenharmony_ci err = -EINVAL; 2249d5ac70f0Sopenharmony_ci goto __error; 2250d5ac70f0Sopenharmony_ci } 2251d5ac70f0Sopenharmony_ci 2252d5ac70f0Sopenharmony_ci /* parse verb file */ 2253d5ac70f0Sopenharmony_ci err = parse_verb_file(uc_mgr, use_case_name, comment, file); 2254d5ac70f0Sopenharmony_ci } else { 2255d5ac70f0Sopenharmony_ci /* parse variants */ 2256d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, variant) { 2257d5ac70f0Sopenharmony_ci char *vfile, *vcomment; 2258d5ac70f0Sopenharmony_ci const char *id; 2259d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 2260d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 2261d5ac70f0Sopenharmony_ci continue; 2262d5ac70f0Sopenharmony_ci if (!parse_is_name_safe(id)) { 2263d5ac70f0Sopenharmony_ci err = -EINVAL; 2264d5ac70f0Sopenharmony_ci goto __error; 2265d5ac70f0Sopenharmony_ci } 2266d5ac70f0Sopenharmony_ci err = parse_variant(uc_mgr, n, &vfile, &vcomment); 2267d5ac70f0Sopenharmony_ci if (err < 0) 2268d5ac70f0Sopenharmony_ci break; 2269d5ac70f0Sopenharmony_ci uc_mgr->parse_variant = id; 2270d5ac70f0Sopenharmony_ci err = parse_verb_file(uc_mgr, id, 2271d5ac70f0Sopenharmony_ci vcomment ? vcomment : comment, 2272d5ac70f0Sopenharmony_ci vfile ? vfile : file); 2273d5ac70f0Sopenharmony_ci uc_mgr->parse_variant = NULL; 2274d5ac70f0Sopenharmony_ci free(vfile); 2275d5ac70f0Sopenharmony_ci free(vcomment); 2276d5ac70f0Sopenharmony_ci } 2277d5ac70f0Sopenharmony_ci } 2278d5ac70f0Sopenharmony_ci 2279d5ac70f0Sopenharmony_ci__error: 2280d5ac70f0Sopenharmony_ci free(use_case_name); 2281d5ac70f0Sopenharmony_ci free(file); 2282d5ac70f0Sopenharmony_ci free(comment); 2283d5ac70f0Sopenharmony_ci return err; 2284d5ac70f0Sopenharmony_ci} 2285d5ac70f0Sopenharmony_ci 2286d5ac70f0Sopenharmony_ci/* 2287d5ac70f0Sopenharmony_ci * parse controls which should be run only at initial boot (forcefully) 2288d5ac70f0Sopenharmony_ci */ 2289d5ac70f0Sopenharmony_cistatic int parse_controls_fixedboot(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) 2290d5ac70f0Sopenharmony_ci{ 2291d5ac70f0Sopenharmony_ci int err; 2292d5ac70f0Sopenharmony_ci 2293d5ac70f0Sopenharmony_ci if (!list_empty(&uc_mgr->fixedboot_list)) { 2294d5ac70f0Sopenharmony_ci uc_error("FixedBoot list is not empty"); 2295d5ac70f0Sopenharmony_ci return -EINVAL; 2296d5ac70f0Sopenharmony_ci } 2297d5ac70f0Sopenharmony_ci err = parse_sequence(uc_mgr, &uc_mgr->fixedboot_list, cfg); 2298d5ac70f0Sopenharmony_ci if (err < 0) { 2299d5ac70f0Sopenharmony_ci uc_error("Unable to parse FixedBootSequence"); 2300d5ac70f0Sopenharmony_ci return err; 2301d5ac70f0Sopenharmony_ci } 2302d5ac70f0Sopenharmony_ci 2303d5ac70f0Sopenharmony_ci return 0; 2304d5ac70f0Sopenharmony_ci} 2305d5ac70f0Sopenharmony_ci 2306d5ac70f0Sopenharmony_ci/* 2307d5ac70f0Sopenharmony_ci * parse controls which should be run only at initial boot 2308d5ac70f0Sopenharmony_ci */ 2309d5ac70f0Sopenharmony_cistatic int parse_controls_boot(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) 2310d5ac70f0Sopenharmony_ci{ 2311d5ac70f0Sopenharmony_ci int err; 2312d5ac70f0Sopenharmony_ci 2313d5ac70f0Sopenharmony_ci if (!list_empty(&uc_mgr->boot_list)) { 2314d5ac70f0Sopenharmony_ci uc_error("Boot list is not empty"); 2315d5ac70f0Sopenharmony_ci return -EINVAL; 2316d5ac70f0Sopenharmony_ci } 2317d5ac70f0Sopenharmony_ci err = parse_sequence(uc_mgr, &uc_mgr->boot_list, cfg); 2318d5ac70f0Sopenharmony_ci if (err < 0) { 2319d5ac70f0Sopenharmony_ci uc_error("Unable to parse BootSequence"); 2320d5ac70f0Sopenharmony_ci return err; 2321d5ac70f0Sopenharmony_ci } 2322d5ac70f0Sopenharmony_ci 2323d5ac70f0Sopenharmony_ci return 0; 2324d5ac70f0Sopenharmony_ci} 2325d5ac70f0Sopenharmony_ci 2326d5ac70f0Sopenharmony_ci/* 2327d5ac70f0Sopenharmony_ci * parse controls 2328d5ac70f0Sopenharmony_ci */ 2329d5ac70f0Sopenharmony_cistatic int parse_controls(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) 2330d5ac70f0Sopenharmony_ci{ 2331d5ac70f0Sopenharmony_ci int err; 2332d5ac70f0Sopenharmony_ci 2333d5ac70f0Sopenharmony_ci if (!list_empty(&uc_mgr->default_list)) { 2334d5ac70f0Sopenharmony_ci uc_error("Default list is not empty"); 2335d5ac70f0Sopenharmony_ci return -EINVAL; 2336d5ac70f0Sopenharmony_ci } 2337d5ac70f0Sopenharmony_ci err = parse_sequence(uc_mgr, &uc_mgr->default_list, cfg); 2338d5ac70f0Sopenharmony_ci if (err < 0) { 2339d5ac70f0Sopenharmony_ci uc_error("Unable to parse SectionDefaults"); 2340d5ac70f0Sopenharmony_ci return err; 2341d5ac70f0Sopenharmony_ci } 2342d5ac70f0Sopenharmony_ci 2343d5ac70f0Sopenharmony_ci return 0; 2344d5ac70f0Sopenharmony_ci} 2345d5ac70f0Sopenharmony_ci 2346d5ac70f0Sopenharmony_ci/* 2347d5ac70f0Sopenharmony_ci * Each sound card has a master sound card file that lists all the supported 2348d5ac70f0Sopenharmony_ci * use case verbs for that sound card. i.e. 2349d5ac70f0Sopenharmony_ci * 2350d5ac70f0Sopenharmony_ci * #Example master file for blah sound card 2351d5ac70f0Sopenharmony_ci * #By Joe Blogs <joe@bloggs.org> 2352d5ac70f0Sopenharmony_ci * 2353d5ac70f0Sopenharmony_ci * Comment "Nice Abstracted Soundcard" 2354d5ac70f0Sopenharmony_ci * 2355d5ac70f0Sopenharmony_ci * # The file is divided into Use case sections. One section per use case verb. 2356d5ac70f0Sopenharmony_ci * 2357d5ac70f0Sopenharmony_ci * SectionUseCase."Voice Call" { 2358d5ac70f0Sopenharmony_ci * File "voice_call_blah" 2359d5ac70f0Sopenharmony_ci * Comment "Make a voice phone call." 2360d5ac70f0Sopenharmony_ci * } 2361d5ac70f0Sopenharmony_ci * 2362d5ac70f0Sopenharmony_ci * SectionUseCase."HiFi" { 2363d5ac70f0Sopenharmony_ci * File "hifi_blah" 2364d5ac70f0Sopenharmony_ci * Comment "Play and record HiFi quality Music." 2365d5ac70f0Sopenharmony_ci * } 2366d5ac70f0Sopenharmony_ci * 2367d5ac70f0Sopenharmony_ci * # Define Value defaults 2368d5ac70f0Sopenharmony_ci * 2369d5ac70f0Sopenharmony_ci * ValueDefaults { 2370d5ac70f0Sopenharmony_ci * PlaybackCTL "hw:CARD=0" 2371d5ac70f0Sopenharmony_ci * CaptureCTL "hw:CARD=0" 2372d5ac70f0Sopenharmony_ci * } 2373d5ac70f0Sopenharmony_ci * 2374d5ac70f0Sopenharmony_ci * # The initial boot (run once) configuration. 2375d5ac70f0Sopenharmony_ci * 2376d5ac70f0Sopenharmony_ci * BootSequence [ 2377d5ac70f0Sopenharmony_ci * cset "name='Master Playback Switch',index=2 1,1" 2378d5ac70f0Sopenharmony_ci * cset "name='Master Playback Volume',index=2 25,25" 2379d5ac70f0Sopenharmony_ci * ] 2380d5ac70f0Sopenharmony_ci * 2381d5ac70f0Sopenharmony_ci * # This file also stores the default sound card state. 2382d5ac70f0Sopenharmony_ci * 2383d5ac70f0Sopenharmony_ci * SectionDefaults [ 2384d5ac70f0Sopenharmony_ci * cset "name='Master Mono Playback',index=1 0" 2385d5ac70f0Sopenharmony_ci * cset "name='Master Mono Playback Volume',index=1 0" 2386d5ac70f0Sopenharmony_ci * cset "name='PCM Switch',index=2 1,1" 2387d5ac70f0Sopenharmony_ci * exec "some binary here" 2388d5ac70f0Sopenharmony_ci * msleep 50 2389d5ac70f0Sopenharmony_ci * ........ 2390d5ac70f0Sopenharmony_ci * ] 2391d5ac70f0Sopenharmony_ci * 2392d5ac70f0Sopenharmony_ci * # End of example file. 2393d5ac70f0Sopenharmony_ci */ 2394d5ac70f0Sopenharmony_cistatic int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg) 2395d5ac70f0Sopenharmony_ci{ 2396d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 2397d5ac70f0Sopenharmony_ci snd_config_t *n; 2398d5ac70f0Sopenharmony_ci const char *id; 2399d5ac70f0Sopenharmony_ci int err; 2400d5ac70f0Sopenharmony_ci 2401d5ac70f0Sopenharmony_ci if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 2402d5ac70f0Sopenharmony_ci uc_error("compound type expected for master file"); 2403d5ac70f0Sopenharmony_ci return -EINVAL; 2404d5ac70f0Sopenharmony_ci } 2405d5ac70f0Sopenharmony_ci 2406d5ac70f0Sopenharmony_ci if (uc_mgr->conf_format >= 2) { 2407d5ac70f0Sopenharmony_ci err = parse_syntax_field(uc_mgr, cfg, uc_mgr->conf_file_name); 2408d5ac70f0Sopenharmony_ci if (err < 0) 2409d5ac70f0Sopenharmony_ci return err; 2410d5ac70f0Sopenharmony_ci } 2411d5ac70f0Sopenharmony_ci 2412d5ac70f0Sopenharmony_ci /* in-place evaluation */ 2413d5ac70f0Sopenharmony_ci err = uc_mgr_evaluate_inplace(uc_mgr, cfg); 2414d5ac70f0Sopenharmony_ci if (err < 0) 2415d5ac70f0Sopenharmony_ci return err; 2416d5ac70f0Sopenharmony_ci 2417d5ac70f0Sopenharmony_ci /* parse master config sections */ 2418d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 2419d5ac70f0Sopenharmony_ci 2420d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 2421d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 2422d5ac70f0Sopenharmony_ci continue; 2423d5ac70f0Sopenharmony_ci 2424d5ac70f0Sopenharmony_ci if (strcmp(id, "Comment") == 0) { 2425d5ac70f0Sopenharmony_ci err = parse_string_substitute3(uc_mgr, n, &uc_mgr->comment); 2426d5ac70f0Sopenharmony_ci if (err < 0) { 2427d5ac70f0Sopenharmony_ci uc_error("error: failed to get master comment"); 2428d5ac70f0Sopenharmony_ci return err; 2429d5ac70f0Sopenharmony_ci } 2430d5ac70f0Sopenharmony_ci continue; 2431d5ac70f0Sopenharmony_ci } 2432d5ac70f0Sopenharmony_ci 2433d5ac70f0Sopenharmony_ci /* find use case section and parse it */ 2434d5ac70f0Sopenharmony_ci if (strcmp(id, "SectionUseCase") == 0) { 2435d5ac70f0Sopenharmony_ci err = parse_compound(uc_mgr, n, 2436d5ac70f0Sopenharmony_ci parse_master_section, 2437d5ac70f0Sopenharmony_ci NULL, NULL); 2438d5ac70f0Sopenharmony_ci if (err < 0) 2439d5ac70f0Sopenharmony_ci return err; 2440d5ac70f0Sopenharmony_ci continue; 2441d5ac70f0Sopenharmony_ci } 2442d5ac70f0Sopenharmony_ci 2443d5ac70f0Sopenharmony_ci /* find default control values section (force boot sequence only) */ 2444d5ac70f0Sopenharmony_ci if (strcmp(id, "FixedBootSequence") == 0) { 2445d5ac70f0Sopenharmony_ci err = parse_controls_fixedboot(uc_mgr, n); 2446d5ac70f0Sopenharmony_ci if (err < 0) 2447d5ac70f0Sopenharmony_ci return err; 2448d5ac70f0Sopenharmony_ci continue; 2449d5ac70f0Sopenharmony_ci } 2450d5ac70f0Sopenharmony_ci 2451d5ac70f0Sopenharmony_ci /* find default control values section (first boot only) */ 2452d5ac70f0Sopenharmony_ci if (strcmp(id, "BootSequence") == 0) { 2453d5ac70f0Sopenharmony_ci err = parse_controls_boot(uc_mgr, n); 2454d5ac70f0Sopenharmony_ci if (err < 0) 2455d5ac70f0Sopenharmony_ci return err; 2456d5ac70f0Sopenharmony_ci continue; 2457d5ac70f0Sopenharmony_ci } 2458d5ac70f0Sopenharmony_ci 2459d5ac70f0Sopenharmony_ci /* find default control values section and parse it */ 2460d5ac70f0Sopenharmony_ci if (strcmp(id, "SectionDefaults") == 0) { 2461d5ac70f0Sopenharmony_ci err = parse_controls(uc_mgr, n); 2462d5ac70f0Sopenharmony_ci if (err < 0) 2463d5ac70f0Sopenharmony_ci return err; 2464d5ac70f0Sopenharmony_ci continue; 2465d5ac70f0Sopenharmony_ci } 2466d5ac70f0Sopenharmony_ci 2467d5ac70f0Sopenharmony_ci /* get the default values */ 2468d5ac70f0Sopenharmony_ci if (strcmp(id, "ValueDefaults") == 0) { 2469d5ac70f0Sopenharmony_ci err = parse_value(uc_mgr, &uc_mgr->value_list, n); 2470d5ac70f0Sopenharmony_ci if (err < 0) { 2471d5ac70f0Sopenharmony_ci uc_error("error: failed to parse ValueDefaults"); 2472d5ac70f0Sopenharmony_ci return err; 2473d5ac70f0Sopenharmony_ci } 2474d5ac70f0Sopenharmony_ci continue; 2475d5ac70f0Sopenharmony_ci } 2476d5ac70f0Sopenharmony_ci 2477d5ac70f0Sopenharmony_ci /* alsa-lib configuration */ 2478d5ac70f0Sopenharmony_ci if (uc_mgr->conf_format > 3 && strcmp(id, "LibraryConfig") == 0) { 2479d5ac70f0Sopenharmony_ci err = parse_libconfig(uc_mgr, n); 2480d5ac70f0Sopenharmony_ci if (err < 0) { 2481d5ac70f0Sopenharmony_ci uc_error("error: failed to parse LibraryConfig"); 2482d5ac70f0Sopenharmony_ci return err; 2483d5ac70f0Sopenharmony_ci } 2484d5ac70f0Sopenharmony_ci continue; 2485d5ac70f0Sopenharmony_ci } 2486d5ac70f0Sopenharmony_ci 2487d5ac70f0Sopenharmony_ci /* error */ 2488d5ac70f0Sopenharmony_ci if (strcmp(id, "Error") == 0) 2489d5ac70f0Sopenharmony_ci return error_node(uc_mgr, n); 2490d5ac70f0Sopenharmony_ci 2491d5ac70f0Sopenharmony_ci /* skip further Syntax value updates (Include) */ 2492d5ac70f0Sopenharmony_ci if (strcmp(id, "Syntax") == 0) 2493d5ac70f0Sopenharmony_ci continue; 2494d5ac70f0Sopenharmony_ci 2495d5ac70f0Sopenharmony_ci uc_error("unknown master file field %s", id); 2496d5ac70f0Sopenharmony_ci } 2497d5ac70f0Sopenharmony_ci return 0; 2498d5ac70f0Sopenharmony_ci} 2499d5ac70f0Sopenharmony_ci 2500d5ac70f0Sopenharmony_ci/* get the card info */ 2501d5ac70f0Sopenharmony_cistatic int get_card_info(snd_use_case_mgr_t *mgr, 2502d5ac70f0Sopenharmony_ci const char *ctl_name, 2503d5ac70f0Sopenharmony_ci snd_ctl_card_info_t **info) 2504d5ac70f0Sopenharmony_ci{ 2505d5ac70f0Sopenharmony_ci struct ctl_list *ctl_list; 2506d5ac70f0Sopenharmony_ci int err; 2507d5ac70f0Sopenharmony_ci 2508d5ac70f0Sopenharmony_ci err = uc_mgr_open_ctl(mgr, &ctl_list, ctl_name, 0); 2509d5ac70f0Sopenharmony_ci if (err < 0) 2510d5ac70f0Sopenharmony_ci return err; 2511d5ac70f0Sopenharmony_ci 2512d5ac70f0Sopenharmony_ci if (info) 2513d5ac70f0Sopenharmony_ci *info = ctl_list->ctl_info; 2514d5ac70f0Sopenharmony_ci return err; 2515d5ac70f0Sopenharmony_ci} 2516d5ac70f0Sopenharmony_ci 2517d5ac70f0Sopenharmony_ci/* find the card in the local machine */ 2518d5ac70f0Sopenharmony_cistatic int get_by_card_name(snd_use_case_mgr_t *mgr, const char *card_name) 2519d5ac70f0Sopenharmony_ci{ 2520d5ac70f0Sopenharmony_ci int card, err; 2521d5ac70f0Sopenharmony_ci snd_ctl_card_info_t *info; 2522d5ac70f0Sopenharmony_ci const char *_driver, *_name, *_long_name; 2523d5ac70f0Sopenharmony_ci 2524d5ac70f0Sopenharmony_ci snd_ctl_card_info_alloca(&info); 2525d5ac70f0Sopenharmony_ci 2526d5ac70f0Sopenharmony_ci card = -1; 2527d5ac70f0Sopenharmony_ci if (snd_card_next(&card) < 0 || card < 0) { 2528d5ac70f0Sopenharmony_ci uc_error("no soundcards found..."); 2529d5ac70f0Sopenharmony_ci return -1; 2530d5ac70f0Sopenharmony_ci } 2531d5ac70f0Sopenharmony_ci 2532d5ac70f0Sopenharmony_ci while (card >= 0) { 2533d5ac70f0Sopenharmony_ci char name[32]; 2534d5ac70f0Sopenharmony_ci 2535d5ac70f0Sopenharmony_ci /* clear the list, keep the only one CTL device */ 2536d5ac70f0Sopenharmony_ci uc_mgr_free_ctl_list(mgr); 2537d5ac70f0Sopenharmony_ci 2538d5ac70f0Sopenharmony_ci sprintf(name, "hw:%d", card); 2539d5ac70f0Sopenharmony_ci err = get_card_info(mgr, name, &info); 2540d5ac70f0Sopenharmony_ci 2541d5ac70f0Sopenharmony_ci if (err == 0) { 2542d5ac70f0Sopenharmony_ci _driver = snd_ctl_card_info_get_driver(info); 2543d5ac70f0Sopenharmony_ci _name = snd_ctl_card_info_get_name(info); 2544d5ac70f0Sopenharmony_ci _long_name = snd_ctl_card_info_get_longname(info); 2545d5ac70f0Sopenharmony_ci if (!strcmp(card_name, _driver) || 2546d5ac70f0Sopenharmony_ci !strcmp(card_name, _name) || 2547d5ac70f0Sopenharmony_ci !strcmp(card_name, _long_name)) 2548d5ac70f0Sopenharmony_ci return 0; 2549d5ac70f0Sopenharmony_ci } 2550d5ac70f0Sopenharmony_ci 2551d5ac70f0Sopenharmony_ci if (snd_card_next(&card) < 0) { 2552d5ac70f0Sopenharmony_ci uc_error("snd_card_next"); 2553d5ac70f0Sopenharmony_ci break; 2554d5ac70f0Sopenharmony_ci } 2555d5ac70f0Sopenharmony_ci } 2556d5ac70f0Sopenharmony_ci 2557d5ac70f0Sopenharmony_ci uc_mgr_free_ctl_list(mgr); 2558d5ac70f0Sopenharmony_ci 2559d5ac70f0Sopenharmony_ci return -1; 2560d5ac70f0Sopenharmony_ci} 2561d5ac70f0Sopenharmony_ci 2562d5ac70f0Sopenharmony_ci/* set the driver name and long name by the card ctl name */ 2563d5ac70f0Sopenharmony_cistatic inline int get_by_card(snd_use_case_mgr_t *mgr, const char *ctl_name) 2564d5ac70f0Sopenharmony_ci{ 2565d5ac70f0Sopenharmony_ci return get_card_info(mgr, ctl_name, NULL); 2566d5ac70f0Sopenharmony_ci} 2567d5ac70f0Sopenharmony_ci 2568d5ac70f0Sopenharmony_cistatic int parse_toplevel_path(snd_use_case_mgr_t *uc_mgr, 2569d5ac70f0Sopenharmony_ci char *filename, 2570d5ac70f0Sopenharmony_ci snd_config_t *cfg) 2571d5ac70f0Sopenharmony_ci{ 2572d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next, i2, next2; 2573d5ac70f0Sopenharmony_ci snd_config_t *n, *n2; 2574d5ac70f0Sopenharmony_ci const char *id; 2575d5ac70f0Sopenharmony_ci char *dir = NULL, *file = NULL, fn[PATH_MAX]; 2576d5ac70f0Sopenharmony_ci struct stat64 st; 2577d5ac70f0Sopenharmony_ci long version; 2578d5ac70f0Sopenharmony_ci int err; 2579d5ac70f0Sopenharmony_ci 2580d5ac70f0Sopenharmony_ci if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 2581d5ac70f0Sopenharmony_ci uc_error("compound type expected for UseCasePath node"); 2582d5ac70f0Sopenharmony_ci return -EINVAL; 2583d5ac70f0Sopenharmony_ci } 2584d5ac70f0Sopenharmony_ci 2585d5ac70f0Sopenharmony_ci /* parse use case path config sections */ 2586d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 2587d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 2588d5ac70f0Sopenharmony_ci 2589d5ac70f0Sopenharmony_ci if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { 2590d5ac70f0Sopenharmony_ci uc_error("compound type expected for UseCasePath.something node"); 2591d5ac70f0Sopenharmony_ci return -EINVAL; 2592d5ac70f0Sopenharmony_ci } 2593d5ac70f0Sopenharmony_ci 2594d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 2595d5ac70f0Sopenharmony_ci continue; 2596d5ac70f0Sopenharmony_ci 2597d5ac70f0Sopenharmony_ci version = 2; 2598d5ac70f0Sopenharmony_ci 2599d5ac70f0Sopenharmony_ci /* parse use case path config sections */ 2600d5ac70f0Sopenharmony_ci snd_config_for_each(i2, next2, n) { 2601d5ac70f0Sopenharmony_ci 2602d5ac70f0Sopenharmony_ci n2 = snd_config_iterator_entry(i2); 2603d5ac70f0Sopenharmony_ci if (snd_config_get_id(n2, &id) < 0) 2604d5ac70f0Sopenharmony_ci continue; 2605d5ac70f0Sopenharmony_ci 2606d5ac70f0Sopenharmony_ci if (strcmp(id, "Version") == 0) { 2607d5ac70f0Sopenharmony_ci err = parse_integer_substitute(uc_mgr, n2, &version); 2608d5ac70f0Sopenharmony_ci if (err < 0) { 2609d5ac70f0Sopenharmony_ci uc_error("unable to parse UcmDirectory"); 2610d5ac70f0Sopenharmony_ci goto __error; 2611d5ac70f0Sopenharmony_ci } 2612d5ac70f0Sopenharmony_ci if (version < 1 || version > 2) { 2613d5ac70f0Sopenharmony_ci uc_error("Version must be 1 or 2"); 2614d5ac70f0Sopenharmony_ci err = -EINVAL; 2615d5ac70f0Sopenharmony_ci goto __error; 2616d5ac70f0Sopenharmony_ci } 2617d5ac70f0Sopenharmony_ci continue; 2618d5ac70f0Sopenharmony_ci } 2619d5ac70f0Sopenharmony_ci 2620d5ac70f0Sopenharmony_ci if (strcmp(id, "Directory") == 0) { 2621d5ac70f0Sopenharmony_ci err = parse_string_substitute(uc_mgr, n2, &dir); 2622d5ac70f0Sopenharmony_ci if (err < 0) { 2623d5ac70f0Sopenharmony_ci uc_error("unable to parse Directory"); 2624d5ac70f0Sopenharmony_ci goto __error; 2625d5ac70f0Sopenharmony_ci } 2626d5ac70f0Sopenharmony_ci continue; 2627d5ac70f0Sopenharmony_ci } 2628d5ac70f0Sopenharmony_ci 2629d5ac70f0Sopenharmony_ci if (strcmp(id, "File") == 0) { 2630d5ac70f0Sopenharmony_ci err = parse_string_substitute(uc_mgr, n2, &file); 2631d5ac70f0Sopenharmony_ci if (err < 0) { 2632d5ac70f0Sopenharmony_ci uc_error("unable to parse File"); 2633d5ac70f0Sopenharmony_ci goto __error; 2634d5ac70f0Sopenharmony_ci } 2635d5ac70f0Sopenharmony_ci continue; 2636d5ac70f0Sopenharmony_ci } 2637d5ac70f0Sopenharmony_ci 2638d5ac70f0Sopenharmony_ci uc_error("unknown UseCasePath field %s", id); 2639d5ac70f0Sopenharmony_ci } 2640d5ac70f0Sopenharmony_ci 2641d5ac70f0Sopenharmony_ci if (dir == NULL) { 2642d5ac70f0Sopenharmony_ci uc_error("Directory is not defined in %s!", filename); 2643d5ac70f0Sopenharmony_ci goto __next; 2644d5ac70f0Sopenharmony_ci } 2645d5ac70f0Sopenharmony_ci if (file == NULL) { 2646d5ac70f0Sopenharmony_ci uc_error("File is not defined in %s!", filename); 2647d5ac70f0Sopenharmony_ci goto __next; 2648d5ac70f0Sopenharmony_ci } 2649d5ac70f0Sopenharmony_ci 2650d5ac70f0Sopenharmony_ci ucm_filename(fn, sizeof(fn), version, dir, file); 2651d5ac70f0Sopenharmony_ci if (access(fn, R_OK) == 0 && lstat64(fn, &st) == 0) { 2652d5ac70f0Sopenharmony_ci if (S_ISLNK(st.st_mode)) { 2653d5ac70f0Sopenharmony_ci ssize_t r; 2654d5ac70f0Sopenharmony_ci char *link, *dir2, *p; 2655d5ac70f0Sopenharmony_ci 2656d5ac70f0Sopenharmony_ci link = malloc(PATH_MAX); 2657d5ac70f0Sopenharmony_ci if (link == NULL) 2658d5ac70f0Sopenharmony_ci goto __enomem; 2659d5ac70f0Sopenharmony_ci r = readlink(fn, link, PATH_MAX - 1); 2660d5ac70f0Sopenharmony_ci if (r <= 0) { 2661d5ac70f0Sopenharmony_ci free(link); 2662d5ac70f0Sopenharmony_ci goto __next; 2663d5ac70f0Sopenharmony_ci } 2664d5ac70f0Sopenharmony_ci link[r] = '\0'; 2665d5ac70f0Sopenharmony_ci p = strrchr(link, '/'); 2666d5ac70f0Sopenharmony_ci if (p) { 2667d5ac70f0Sopenharmony_ci *p = '\0'; 2668d5ac70f0Sopenharmony_ci dir2 = malloc(PATH_MAX); 2669d5ac70f0Sopenharmony_ci if (dir2 == NULL) { 2670d5ac70f0Sopenharmony_ci free(link); 2671d5ac70f0Sopenharmony_ci goto __enomem; 2672d5ac70f0Sopenharmony_ci } 2673d5ac70f0Sopenharmony_ci strncpy(dir2, dir, PATH_MAX - 1); 2674d5ac70f0Sopenharmony_ci strncat(dir2, "/", PATH_MAX - 1); 2675d5ac70f0Sopenharmony_ci strncat(dir2, link, PATH_MAX - 1); 2676d5ac70f0Sopenharmony_ci fn[PATH_MAX - 1] = '\0'; 2677d5ac70f0Sopenharmony_ci free(dir); 2678d5ac70f0Sopenharmony_ci dir = dir2; 2679d5ac70f0Sopenharmony_ci } 2680d5ac70f0Sopenharmony_ci free(link); 2681d5ac70f0Sopenharmony_ci } 2682d5ac70f0Sopenharmony_ci if (replace_string(&uc_mgr->conf_dir_name, dir) == NULL) 2683d5ac70f0Sopenharmony_ci goto __enomem; 2684d5ac70f0Sopenharmony_ci if (replace_string(&uc_mgr->conf_file_name, file) == NULL) 2685d5ac70f0Sopenharmony_ci goto __enomem; 2686d5ac70f0Sopenharmony_ci strncpy(filename, fn, PATH_MAX); 2687d5ac70f0Sopenharmony_ci filename[PATH_MAX - 1] = '\0'; 2688d5ac70f0Sopenharmony_ci uc_mgr->conf_format = version; 2689d5ac70f0Sopenharmony_ci goto __ok; 2690d5ac70f0Sopenharmony_ci } 2691d5ac70f0Sopenharmony_ci 2692d5ac70f0Sopenharmony_ci__next: 2693d5ac70f0Sopenharmony_ci free(file); 2694d5ac70f0Sopenharmony_ci if (dir != fn) 2695d5ac70f0Sopenharmony_ci free(dir); 2696d5ac70f0Sopenharmony_ci dir = NULL; 2697d5ac70f0Sopenharmony_ci file = NULL; 2698d5ac70f0Sopenharmony_ci } 2699d5ac70f0Sopenharmony_ci 2700d5ac70f0Sopenharmony_ci err = -ENOENT; 2701d5ac70f0Sopenharmony_ci goto __error; 2702d5ac70f0Sopenharmony_ci 2703d5ac70f0Sopenharmony_ci__enomem: 2704d5ac70f0Sopenharmony_ci err = -ENOMEM; 2705d5ac70f0Sopenharmony_ci goto __error; 2706d5ac70f0Sopenharmony_ci 2707d5ac70f0Sopenharmony_ci__ok: 2708d5ac70f0Sopenharmony_ci err = 0; 2709d5ac70f0Sopenharmony_ci__error: 2710d5ac70f0Sopenharmony_ci free(file); 2711d5ac70f0Sopenharmony_ci if (dir != fn) 2712d5ac70f0Sopenharmony_ci free(dir); 2713d5ac70f0Sopenharmony_ci return err; 2714d5ac70f0Sopenharmony_ci} 2715d5ac70f0Sopenharmony_ci 2716d5ac70f0Sopenharmony_cistatic int parse_toplevel_config(snd_use_case_mgr_t *uc_mgr, 2717d5ac70f0Sopenharmony_ci char *filename, 2718d5ac70f0Sopenharmony_ci snd_config_t *cfg) 2719d5ac70f0Sopenharmony_ci{ 2720d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 2721d5ac70f0Sopenharmony_ci snd_config_t *n; 2722d5ac70f0Sopenharmony_ci const char *id; 2723d5ac70f0Sopenharmony_ci int err; 2724d5ac70f0Sopenharmony_ci 2725d5ac70f0Sopenharmony_ci if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 2726d5ac70f0Sopenharmony_ci uc_error("compound type expected for toplevel file"); 2727d5ac70f0Sopenharmony_ci return -EINVAL; 2728d5ac70f0Sopenharmony_ci } 2729d5ac70f0Sopenharmony_ci 2730d5ac70f0Sopenharmony_ci err = parse_syntax_field(uc_mgr, cfg, filename); 2731d5ac70f0Sopenharmony_ci if (err < 0) 2732d5ac70f0Sopenharmony_ci return err; 2733d5ac70f0Sopenharmony_ci 2734d5ac70f0Sopenharmony_ci /* in-place evaluation */ 2735d5ac70f0Sopenharmony_ci err = uc_mgr_evaluate_inplace(uc_mgr, cfg); 2736d5ac70f0Sopenharmony_ci if (err < 0) 2737d5ac70f0Sopenharmony_ci return err; 2738d5ac70f0Sopenharmony_ci 2739d5ac70f0Sopenharmony_ci /* parse toplevel config sections */ 2740d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 2741d5ac70f0Sopenharmony_ci 2742d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 2743d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 2744d5ac70f0Sopenharmony_ci continue; 2745d5ac70f0Sopenharmony_ci 2746d5ac70f0Sopenharmony_ci if (strcmp(id, "UseCasePath") == 0) { 2747d5ac70f0Sopenharmony_ci err = parse_toplevel_path(uc_mgr, filename, n); 2748d5ac70f0Sopenharmony_ci if (err == 0) 2749d5ac70f0Sopenharmony_ci return err; 2750d5ac70f0Sopenharmony_ci continue; 2751d5ac70f0Sopenharmony_ci } 2752d5ac70f0Sopenharmony_ci 2753d5ac70f0Sopenharmony_ci /* alsa-lib configuration */ 2754d5ac70f0Sopenharmony_ci if (uc_mgr->conf_format > 3 && strcmp(id, "LibraryConfig") == 0) { 2755d5ac70f0Sopenharmony_ci err = parse_libconfig(uc_mgr, n); 2756d5ac70f0Sopenharmony_ci if (err < 0) { 2757d5ac70f0Sopenharmony_ci uc_error("error: failed to parse LibConfig"); 2758d5ac70f0Sopenharmony_ci return err; 2759d5ac70f0Sopenharmony_ci } 2760d5ac70f0Sopenharmony_ci continue; 2761d5ac70f0Sopenharmony_ci } 2762d5ac70f0Sopenharmony_ci 2763d5ac70f0Sopenharmony_ci /* skip further Syntax value updates (Include) */ 2764d5ac70f0Sopenharmony_ci if (strcmp(id, "Syntax") == 0) 2765d5ac70f0Sopenharmony_ci continue; 2766d5ac70f0Sopenharmony_ci 2767d5ac70f0Sopenharmony_ci uc_error("unknown toplevel field %s", id); 2768d5ac70f0Sopenharmony_ci } 2769d5ac70f0Sopenharmony_ci 2770d5ac70f0Sopenharmony_ci return -ENOENT; 2771d5ac70f0Sopenharmony_ci} 2772d5ac70f0Sopenharmony_ci 2773d5ac70f0Sopenharmony_cistatic int load_toplevel_config(snd_use_case_mgr_t *uc_mgr, 2774d5ac70f0Sopenharmony_ci snd_config_t **cfg) 2775d5ac70f0Sopenharmony_ci{ 2776d5ac70f0Sopenharmony_ci char filename[PATH_MAX]; 2777d5ac70f0Sopenharmony_ci snd_config_t *tcfg; 2778d5ac70f0Sopenharmony_ci int err; 2779d5ac70f0Sopenharmony_ci 2780d5ac70f0Sopenharmony_ci ucm_filename(filename, sizeof(filename), 2, NULL, "ucm.conf"); 2781d5ac70f0Sopenharmony_ci 2782d5ac70f0Sopenharmony_ci if (access(filename, R_OK) != 0) { 2783d5ac70f0Sopenharmony_ci uc_error("Unable to find the top-level configuration file '%s'.", filename); 2784d5ac70f0Sopenharmony_ci return -ENOENT; 2785d5ac70f0Sopenharmony_ci } 2786d5ac70f0Sopenharmony_ci 2787d5ac70f0Sopenharmony_ci err = uc_mgr_config_load(2, filename, &tcfg); 2788d5ac70f0Sopenharmony_ci if (err < 0) 2789d5ac70f0Sopenharmony_ci goto __error; 2790d5ac70f0Sopenharmony_ci 2791d5ac70f0Sopenharmony_ci /* filename is shared for function input and output! */ 2792d5ac70f0Sopenharmony_ci err = parse_toplevel_config(uc_mgr, filename, tcfg); 2793d5ac70f0Sopenharmony_ci snd_config_delete(tcfg); 2794d5ac70f0Sopenharmony_ci if (err < 0) 2795d5ac70f0Sopenharmony_ci goto __error; 2796d5ac70f0Sopenharmony_ci 2797d5ac70f0Sopenharmony_ci err = uc_mgr_config_load(uc_mgr->conf_format, filename, cfg); 2798d5ac70f0Sopenharmony_ci if (err < 0) { 2799d5ac70f0Sopenharmony_ci uc_error("error: could not parse configuration for card %s", 2800d5ac70f0Sopenharmony_ci uc_mgr->card_name); 2801d5ac70f0Sopenharmony_ci goto __error; 2802d5ac70f0Sopenharmony_ci } 2803d5ac70f0Sopenharmony_ci 2804d5ac70f0Sopenharmony_ci return 0; 2805d5ac70f0Sopenharmony_ci 2806d5ac70f0Sopenharmony_ci__error: 2807d5ac70f0Sopenharmony_ci return err; 2808d5ac70f0Sopenharmony_ci} 2809d5ac70f0Sopenharmony_ci 2810d5ac70f0Sopenharmony_ci/* load master use case file for sound card based on rules in ucm2/ucm.conf 2811d5ac70f0Sopenharmony_ci */ 2812d5ac70f0Sopenharmony_ciint uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr) 2813d5ac70f0Sopenharmony_ci{ 2814d5ac70f0Sopenharmony_ci snd_config_t *cfg; 2815d5ac70f0Sopenharmony_ci const char *name; 2816d5ac70f0Sopenharmony_ci int err; 2817d5ac70f0Sopenharmony_ci 2818d5ac70f0Sopenharmony_ci err = snd_config_top(&uc_mgr->local_config); 2819d5ac70f0Sopenharmony_ci if (err < 0) 2820d5ac70f0Sopenharmony_ci return err; 2821d5ac70f0Sopenharmony_ci 2822d5ac70f0Sopenharmony_ci err = snd_config_top(&uc_mgr->macros); 2823d5ac70f0Sopenharmony_ci if (err < 0) 2824d5ac70f0Sopenharmony_ci return err; 2825d5ac70f0Sopenharmony_ci 2826d5ac70f0Sopenharmony_ci name = uc_mgr->card_name; 2827d5ac70f0Sopenharmony_ci if (strncmp(name, "hw:", 3) == 0) { 2828d5ac70f0Sopenharmony_ci err = get_by_card(uc_mgr, name); 2829d5ac70f0Sopenharmony_ci if (err < 0) { 2830d5ac70f0Sopenharmony_ci uc_error("card '%s' is not valid", name); 2831d5ac70f0Sopenharmony_ci goto __error; 2832d5ac70f0Sopenharmony_ci } 2833d5ac70f0Sopenharmony_ci } else if (strncmp(name, "strict:", 7)) { 2834d5ac70f0Sopenharmony_ci /* do not handle the error here */ 2835d5ac70f0Sopenharmony_ci /* we can refer the virtual UCM config */ 2836d5ac70f0Sopenharmony_ci get_by_card_name(uc_mgr, name); 2837d5ac70f0Sopenharmony_ci } 2838d5ac70f0Sopenharmony_ci 2839d5ac70f0Sopenharmony_ci err = load_toplevel_config(uc_mgr, &cfg); 2840d5ac70f0Sopenharmony_ci if (err < 0) 2841d5ac70f0Sopenharmony_ci goto __error; 2842d5ac70f0Sopenharmony_ci 2843d5ac70f0Sopenharmony_ci err = parse_master_file(uc_mgr, cfg); 2844d5ac70f0Sopenharmony_ci if (uc_mgr->macros) { 2845d5ac70f0Sopenharmony_ci snd_config_delete(uc_mgr->macros); 2846d5ac70f0Sopenharmony_ci uc_mgr->macros = NULL; 2847d5ac70f0Sopenharmony_ci } 2848d5ac70f0Sopenharmony_ci snd_config_delete(cfg); 2849d5ac70f0Sopenharmony_ci if (err < 0) { 2850d5ac70f0Sopenharmony_ci uc_mgr_free_ctl_list(uc_mgr); 2851d5ac70f0Sopenharmony_ci uc_mgr_free_verb(uc_mgr); 2852d5ac70f0Sopenharmony_ci } 2853d5ac70f0Sopenharmony_ci 2854d5ac70f0Sopenharmony_ci return err; 2855d5ac70f0Sopenharmony_ci 2856d5ac70f0Sopenharmony_ci__error: 2857d5ac70f0Sopenharmony_ci uc_mgr_free_ctl_list(uc_mgr); 2858d5ac70f0Sopenharmony_ci replace_string(&uc_mgr->conf_dir_name, NULL); 2859d5ac70f0Sopenharmony_ci return err; 2860d5ac70f0Sopenharmony_ci} 2861d5ac70f0Sopenharmony_ci 2862d5ac70f0Sopenharmony_cistatic int filename_filter(const struct dirent64 *dirent) 2863d5ac70f0Sopenharmony_ci{ 2864d5ac70f0Sopenharmony_ci if (dirent == NULL) 2865d5ac70f0Sopenharmony_ci return 0; 2866d5ac70f0Sopenharmony_ci if (dirent->d_type == DT_DIR) { 2867d5ac70f0Sopenharmony_ci if (dirent->d_name[0] == '.') { 2868d5ac70f0Sopenharmony_ci if (dirent->d_name[1] == '\0') 2869d5ac70f0Sopenharmony_ci return 0; 2870d5ac70f0Sopenharmony_ci if (dirent->d_name[1] == '.' && 2871d5ac70f0Sopenharmony_ci dirent->d_name[2] == '\0') 2872d5ac70f0Sopenharmony_ci return 0; 2873d5ac70f0Sopenharmony_ci } 2874d5ac70f0Sopenharmony_ci return 1; 2875d5ac70f0Sopenharmony_ci } 2876d5ac70f0Sopenharmony_ci return 0; 2877d5ac70f0Sopenharmony_ci} 2878d5ac70f0Sopenharmony_ci 2879d5ac70f0Sopenharmony_ci/* scan all cards and comments 2880d5ac70f0Sopenharmony_ci * 2881d5ac70f0Sopenharmony_ci * Cards are defined by machines. Each card/machine installs its UCM 2882d5ac70f0Sopenharmony_ci * configuration files in a subdirectory with the same name as the sound 2883d5ac70f0Sopenharmony_ci * card under /usr/share/alsa/ucm2. This function will scan all the card 2884d5ac70f0Sopenharmony_ci * directories and skip the component directories defined in the array 2885d5ac70f0Sopenharmony_ci * component_dir. 2886d5ac70f0Sopenharmony_ci */ 2887d5ac70f0Sopenharmony_ciint uc_mgr_scan_master_configs(const char **_list[]) 2888d5ac70f0Sopenharmony_ci{ 2889d5ac70f0Sopenharmony_ci char filename[PATH_MAX], dfl[PATH_MAX], fn[FILENAME_MAX]; 2890d5ac70f0Sopenharmony_ci char *env = getenv(ALSA_CONFIG_UCM2_VAR); 2891d5ac70f0Sopenharmony_ci snd_use_case_mgr_t *uc_mgr; 2892d5ac70f0Sopenharmony_ci const char **list, *d_name; 2893d5ac70f0Sopenharmony_ci char *s; 2894d5ac70f0Sopenharmony_ci snd_config_t *cfg, *c; 2895d5ac70f0Sopenharmony_ci int i, j, cnt, err, cards; 2896d5ac70f0Sopenharmony_ci long l; 2897d5ac70f0Sopenharmony_ci ssize_t ss; 2898d5ac70f0Sopenharmony_ci struct dirent64 **namelist; 2899d5ac70f0Sopenharmony_ci 2900d5ac70f0Sopenharmony_ci i = -1; 2901d5ac70f0Sopenharmony_ci cards = 0; 2902d5ac70f0Sopenharmony_ci while (1) { 2903d5ac70f0Sopenharmony_ci err = snd_card_next(&i); 2904d5ac70f0Sopenharmony_ci if (err < 0) 2905d5ac70f0Sopenharmony_ci return err; 2906d5ac70f0Sopenharmony_ci if (i < 0) 2907d5ac70f0Sopenharmony_ci break; 2908d5ac70f0Sopenharmony_ci cards++; 2909d5ac70f0Sopenharmony_ci } 2910d5ac70f0Sopenharmony_ci cards += 4; /* plug-and-play */ 2911d5ac70f0Sopenharmony_ci 2912d5ac70f0Sopenharmony_ci if (env) 2913d5ac70f0Sopenharmony_ci snprintf(filename, sizeof(filename), "%s/conf.virt.d", env); 2914d5ac70f0Sopenharmony_ci else 2915d5ac70f0Sopenharmony_ci snprintf(filename, sizeof(filename), "%s/ucm2/conf.virt.d", 2916d5ac70f0Sopenharmony_ci snd_config_topdir()); 2917d5ac70f0Sopenharmony_ci 2918d5ac70f0Sopenharmony_ci#if defined(_GNU_SOURCE) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) && !defined(__sun) && !defined(__ANDROID__) 2919d5ac70f0Sopenharmony_ci#define SORTFUNC versionsort64 2920d5ac70f0Sopenharmony_ci#else 2921d5ac70f0Sopenharmony_ci#define SORTFUNC alphasort64 2922d5ac70f0Sopenharmony_ci#endif 2923d5ac70f0Sopenharmony_ci err = scandir64(filename, &namelist, filename_filter, SORTFUNC); 2924d5ac70f0Sopenharmony_ci if (err < 0) { 2925d5ac70f0Sopenharmony_ci err = -errno; 2926d5ac70f0Sopenharmony_ci uc_error("error: could not scan directory %s: %s", 2927d5ac70f0Sopenharmony_ci filename, strerror(-err)); 2928d5ac70f0Sopenharmony_ci return err; 2929d5ac70f0Sopenharmony_ci } 2930d5ac70f0Sopenharmony_ci cnt = err; 2931d5ac70f0Sopenharmony_ci 2932d5ac70f0Sopenharmony_ci dfl[0] = '\0'; 2933d5ac70f0Sopenharmony_ci if (strlen(filename) + 8 < sizeof(filename)) { 2934d5ac70f0Sopenharmony_ci strcat(filename, "/default"); 2935d5ac70f0Sopenharmony_ci ss = readlink(filename, dfl, sizeof(dfl)-1); 2936d5ac70f0Sopenharmony_ci if (ss >= 0) { 2937d5ac70f0Sopenharmony_ci dfl[ss] = '\0'; 2938d5ac70f0Sopenharmony_ci dfl[sizeof(dfl)-1] = '\0'; 2939d5ac70f0Sopenharmony_ci if (dfl[0] && dfl[strlen(dfl)-1] == '/') 2940d5ac70f0Sopenharmony_ci dfl[strlen(dfl)-1] = '\0'; 2941d5ac70f0Sopenharmony_ci } else { 2942d5ac70f0Sopenharmony_ci dfl[0] = '\0'; 2943d5ac70f0Sopenharmony_ci } 2944d5ac70f0Sopenharmony_ci } 2945d5ac70f0Sopenharmony_ci 2946d5ac70f0Sopenharmony_ci j = 0; 2947d5ac70f0Sopenharmony_ci list = calloc(1, (cards + cnt) * 2 * sizeof(char *)); 2948d5ac70f0Sopenharmony_ci if (list == NULL) { 2949d5ac70f0Sopenharmony_ci err = -ENOMEM; 2950d5ac70f0Sopenharmony_ci goto __err; 2951d5ac70f0Sopenharmony_ci } 2952d5ac70f0Sopenharmony_ci 2953d5ac70f0Sopenharmony_ci i = -1; 2954d5ac70f0Sopenharmony_ci while (j / 2 < cards) { 2955d5ac70f0Sopenharmony_ci err = snd_card_next(&i); 2956d5ac70f0Sopenharmony_ci if (err < 0) 2957d5ac70f0Sopenharmony_ci goto __err; 2958d5ac70f0Sopenharmony_ci if (i < 0) 2959d5ac70f0Sopenharmony_ci break; 2960d5ac70f0Sopenharmony_ci snprintf(fn, sizeof(fn), "-hw:%d", i); 2961d5ac70f0Sopenharmony_ci err = snd_use_case_mgr_open(&uc_mgr, fn); 2962d5ac70f0Sopenharmony_ci if (err == -ENOENT || err == -ENXIO) 2963d5ac70f0Sopenharmony_ci continue; 2964d5ac70f0Sopenharmony_ci if (err < 0) { 2965d5ac70f0Sopenharmony_ci uc_error("Unable to open '%s': %s", fn, snd_strerror(err)); 2966d5ac70f0Sopenharmony_ci goto __err; 2967d5ac70f0Sopenharmony_ci } 2968d5ac70f0Sopenharmony_ci err = snd_use_case_get(uc_mgr, "comment", (const char **)&s); 2969d5ac70f0Sopenharmony_ci if (err < 0) { 2970d5ac70f0Sopenharmony_ci err = snd_card_get_longname(i, &s); 2971d5ac70f0Sopenharmony_ci if (err < 0) 2972d5ac70f0Sopenharmony_ci goto __err; 2973d5ac70f0Sopenharmony_ci } 2974d5ac70f0Sopenharmony_ci snd_use_case_mgr_close(uc_mgr); 2975d5ac70f0Sopenharmony_ci list[j] = strdup(fn + 1); 2976d5ac70f0Sopenharmony_ci if (list[j] == NULL) { 2977d5ac70f0Sopenharmony_ci free(s); 2978d5ac70f0Sopenharmony_ci err = -ENOMEM; 2979d5ac70f0Sopenharmony_ci goto __err; 2980d5ac70f0Sopenharmony_ci } 2981d5ac70f0Sopenharmony_ci list[j + 1] = s; 2982d5ac70f0Sopenharmony_ci j += 2; 2983d5ac70f0Sopenharmony_ci } 2984d5ac70f0Sopenharmony_ci 2985d5ac70f0Sopenharmony_ci for (i = 0; i < cnt; i++) { 2986d5ac70f0Sopenharmony_ci 2987d5ac70f0Sopenharmony_ci d_name = namelist[i]->d_name; 2988d5ac70f0Sopenharmony_ci 2989d5ac70f0Sopenharmony_ci snprintf(fn, sizeof(fn), "%s.conf", d_name); 2990d5ac70f0Sopenharmony_ci ucm_filename(filename, sizeof(filename), 2, d_name, fn); 2991d5ac70f0Sopenharmony_ci#ifdef HAVE_EACCESS 2992d5ac70f0Sopenharmony_ci if (eaccess(filename, R_OK)) 2993d5ac70f0Sopenharmony_ci#else 2994d5ac70f0Sopenharmony_ci if (access(filename, R_OK)) 2995d5ac70f0Sopenharmony_ci#endif 2996d5ac70f0Sopenharmony_ci continue; 2997d5ac70f0Sopenharmony_ci 2998d5ac70f0Sopenharmony_ci err = uc_mgr_config_load(2, filename, &cfg); 2999d5ac70f0Sopenharmony_ci if (err < 0) 3000d5ac70f0Sopenharmony_ci goto __err; 3001d5ac70f0Sopenharmony_ci err = snd_config_search(cfg, "Syntax", &c); 3002d5ac70f0Sopenharmony_ci if (err < 0) { 3003d5ac70f0Sopenharmony_ci uc_error("Syntax field not found in %s", d_name); 3004d5ac70f0Sopenharmony_ci snd_config_delete(cfg); 3005d5ac70f0Sopenharmony_ci continue; 3006d5ac70f0Sopenharmony_ci } 3007d5ac70f0Sopenharmony_ci err = snd_config_get_integer(c, &l); 3008d5ac70f0Sopenharmony_ci if (err < 0) { 3009d5ac70f0Sopenharmony_ci uc_error("Syntax field is invalid in %s", d_name); 3010d5ac70f0Sopenharmony_ci snd_config_delete(cfg); 3011d5ac70f0Sopenharmony_ci goto __err; 3012d5ac70f0Sopenharmony_ci } 3013d5ac70f0Sopenharmony_ci if (l < 2 || l > SYNTAX_VERSION_MAX) { 3014d5ac70f0Sopenharmony_ci uc_error("Incompatible syntax %d in %s", l, d_name); 3015d5ac70f0Sopenharmony_ci snd_config_delete(cfg); 3016d5ac70f0Sopenharmony_ci goto __err; 3017d5ac70f0Sopenharmony_ci } 3018d5ac70f0Sopenharmony_ci err = snd_config_search(cfg, "Comment", &c); 3019d5ac70f0Sopenharmony_ci if (err >= 0) { 3020d5ac70f0Sopenharmony_ci err = parse_string(c, (char **)&list[j+1]); 3021d5ac70f0Sopenharmony_ci if (err < 0) { 3022d5ac70f0Sopenharmony_ci snd_config_delete(cfg); 3023d5ac70f0Sopenharmony_ci goto __err; 3024d5ac70f0Sopenharmony_ci } 3025d5ac70f0Sopenharmony_ci } 3026d5ac70f0Sopenharmony_ci snd_config_delete(cfg); 3027d5ac70f0Sopenharmony_ci list[j] = strdup(d_name); 3028d5ac70f0Sopenharmony_ci if (list[j] == NULL) { 3029d5ac70f0Sopenharmony_ci err = -ENOMEM; 3030d5ac70f0Sopenharmony_ci goto __err; 3031d5ac70f0Sopenharmony_ci } 3032d5ac70f0Sopenharmony_ci if (strcmp(dfl, list[j]) == 0) { 3033d5ac70f0Sopenharmony_ci /* default to top */ 3034d5ac70f0Sopenharmony_ci const char *save1 = list[j]; 3035d5ac70f0Sopenharmony_ci const char *save2 = list[j + 1]; 3036d5ac70f0Sopenharmony_ci memmove(list + 2, list, j * sizeof(char *)); 3037d5ac70f0Sopenharmony_ci list[0] = save1; 3038d5ac70f0Sopenharmony_ci list[1] = save2; 3039d5ac70f0Sopenharmony_ci } 3040d5ac70f0Sopenharmony_ci j += 2; 3041d5ac70f0Sopenharmony_ci } 3042d5ac70f0Sopenharmony_ci err = 0; 3043d5ac70f0Sopenharmony_ci 3044d5ac70f0Sopenharmony_ci __err: 3045d5ac70f0Sopenharmony_ci for (i = 0; i < cnt; i++) 3046d5ac70f0Sopenharmony_ci free(namelist[i]); 3047d5ac70f0Sopenharmony_ci free(namelist); 3048d5ac70f0Sopenharmony_ci if (err < 0) { 3049d5ac70f0Sopenharmony_ci for (i = 0; i < j; i++) { 3050d5ac70f0Sopenharmony_ci free((void *)list[i * 2]); 3051d5ac70f0Sopenharmony_ci free((void *)list[i * 2 + 1]); 3052d5ac70f0Sopenharmony_ci } 3053d5ac70f0Sopenharmony_ci free(list); 3054d5ac70f0Sopenharmony_ci return err; 3055d5ac70f0Sopenharmony_ci } 3056d5ac70f0Sopenharmony_ci 3057d5ac70f0Sopenharmony_ci *_list = list; 3058d5ac70f0Sopenharmony_ci return j; 3059d5ac70f0Sopenharmony_ci} 3060