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 "../control/control_local.h" 35d5ac70f0Sopenharmony_ci#include <stdbool.h> 36d5ac70f0Sopenharmony_ci#include <ctype.h> 37d5ac70f0Sopenharmony_ci#include <stdarg.h> 38d5ac70f0Sopenharmony_ci#include <pthread.h> 39d5ac70f0Sopenharmony_ci#include <sys/stat.h> 40d5ac70f0Sopenharmony_ci#include <sys/wait.h> 41d5ac70f0Sopenharmony_ci#include <limits.h> 42d5ac70f0Sopenharmony_ci 43d5ac70f0Sopenharmony_ci/* 44d5ac70f0Sopenharmony_ci * misc 45d5ac70f0Sopenharmony_ci */ 46d5ac70f0Sopenharmony_ci 47d5ac70f0Sopenharmony_cistatic int get_value(snd_use_case_mgr_t *uc_mgr, 48d5ac70f0Sopenharmony_ci const char *identifier, 49d5ac70f0Sopenharmony_ci char **value, 50d5ac70f0Sopenharmony_ci const char *mod_dev_name, 51d5ac70f0Sopenharmony_ci const char *verb_name, 52d5ac70f0Sopenharmony_ci int exact); 53d5ac70f0Sopenharmony_cistatic int get_value1(snd_use_case_mgr_t *uc_mgr, char **value, 54d5ac70f0Sopenharmony_ci struct list_head *value_list, const char *identifier); 55d5ac70f0Sopenharmony_cistatic int get_value3(snd_use_case_mgr_t *uc_mgr, 56d5ac70f0Sopenharmony_ci char **value, 57d5ac70f0Sopenharmony_ci const char *identifier, 58d5ac70f0Sopenharmony_ci struct list_head *value_list1, 59d5ac70f0Sopenharmony_ci struct list_head *value_list2, 60d5ac70f0Sopenharmony_ci struct list_head *value_list3); 61d5ac70f0Sopenharmony_ci 62d5ac70f0Sopenharmony_cistatic int execute_sequence(snd_use_case_mgr_t *uc_mgr, 63d5ac70f0Sopenharmony_ci struct use_case_verb *verb, 64d5ac70f0Sopenharmony_ci struct list_head *seq, 65d5ac70f0Sopenharmony_ci struct list_head *value_list1, 66d5ac70f0Sopenharmony_ci struct list_head *value_list2, 67d5ac70f0Sopenharmony_ci struct list_head *value_list3); 68d5ac70f0Sopenharmony_ci 69d5ac70f0Sopenharmony_cistatic int execute_component_seq(snd_use_case_mgr_t *uc_mgr, 70d5ac70f0Sopenharmony_ci struct component_sequence *cmpt_seq, 71d5ac70f0Sopenharmony_ci struct list_head *value_list1, 72d5ac70f0Sopenharmony_ci struct list_head *value_list2, 73d5ac70f0Sopenharmony_ci struct list_head *value_list3, 74d5ac70f0Sopenharmony_ci char *cdev); 75d5ac70f0Sopenharmony_ci 76d5ac70f0Sopenharmony_cistatic inline struct use_case_device * 77d5ac70f0Sopenharmony_ci find_device(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb, 78d5ac70f0Sopenharmony_ci const char *device_name, int check_supported); 79d5ac70f0Sopenharmony_ci 80d5ac70f0Sopenharmony_cistatic int check_identifier(const char *identifier, const char *prefix) 81d5ac70f0Sopenharmony_ci{ 82d5ac70f0Sopenharmony_ci int len; 83d5ac70f0Sopenharmony_ci 84d5ac70f0Sopenharmony_ci len = strlen(prefix); 85d5ac70f0Sopenharmony_ci if (strncmp(identifier, prefix, len) != 0) 86d5ac70f0Sopenharmony_ci return 0; 87d5ac70f0Sopenharmony_ci 88d5ac70f0Sopenharmony_ci if (identifier[len] == 0 || identifier[len] == '/') 89d5ac70f0Sopenharmony_ci return 1; 90d5ac70f0Sopenharmony_ci 91d5ac70f0Sopenharmony_ci return 0; 92d5ac70f0Sopenharmony_ci} 93d5ac70f0Sopenharmony_ci 94d5ac70f0Sopenharmony_cistatic int list_count(struct list_head *list) 95d5ac70f0Sopenharmony_ci{ 96d5ac70f0Sopenharmony_ci struct list_head *pos; 97d5ac70f0Sopenharmony_ci int count = 0; 98d5ac70f0Sopenharmony_ci 99d5ac70f0Sopenharmony_ci list_for_each(pos, list) { 100d5ac70f0Sopenharmony_ci count += 1; 101d5ac70f0Sopenharmony_ci } 102d5ac70f0Sopenharmony_ci return count; 103d5ac70f0Sopenharmony_ci} 104d5ac70f0Sopenharmony_ci 105d5ac70f0Sopenharmony_cistatic int alloc_str_list(struct list_head *list, int mult, char **result[]) 106d5ac70f0Sopenharmony_ci{ 107d5ac70f0Sopenharmony_ci char **res; 108d5ac70f0Sopenharmony_ci int cnt; 109d5ac70f0Sopenharmony_ci 110d5ac70f0Sopenharmony_ci cnt = list_count(list) * mult; 111d5ac70f0Sopenharmony_ci if (cnt == 0) { 112d5ac70f0Sopenharmony_ci *result = NULL; 113d5ac70f0Sopenharmony_ci return cnt; 114d5ac70f0Sopenharmony_ci } 115d5ac70f0Sopenharmony_ci res = calloc(mult, cnt * sizeof(char *)); 116d5ac70f0Sopenharmony_ci if (res == NULL) 117d5ac70f0Sopenharmony_ci return -ENOMEM; 118d5ac70f0Sopenharmony_ci *result = res; 119d5ac70f0Sopenharmony_ci return cnt; 120d5ac70f0Sopenharmony_ci} 121d5ac70f0Sopenharmony_ci 122d5ac70f0Sopenharmony_ci/** 123d5ac70f0Sopenharmony_ci * \brief Create an identifier 124d5ac70f0Sopenharmony_ci * \param fmt Format (sprintf like) 125d5ac70f0Sopenharmony_ci * \param ... Optional arguments for sprintf like format 126d5ac70f0Sopenharmony_ci * \return Allocated string identifier or NULL on error 127d5ac70f0Sopenharmony_ci */ 128d5ac70f0Sopenharmony_cichar *snd_use_case_identifier(const char *fmt, ...) 129d5ac70f0Sopenharmony_ci{ 130d5ac70f0Sopenharmony_ci char *str, *res; 131d5ac70f0Sopenharmony_ci int size = strlen(fmt) + 512; 132d5ac70f0Sopenharmony_ci va_list args; 133d5ac70f0Sopenharmony_ci 134d5ac70f0Sopenharmony_ci str = malloc(size); 135d5ac70f0Sopenharmony_ci if (str == NULL) 136d5ac70f0Sopenharmony_ci return NULL; 137d5ac70f0Sopenharmony_ci va_start(args, fmt); 138d5ac70f0Sopenharmony_ci vsnprintf(str, size, fmt, args); 139d5ac70f0Sopenharmony_ci va_end(args); 140d5ac70f0Sopenharmony_ci str[size-1] = '\0'; 141d5ac70f0Sopenharmony_ci res = realloc(str, strlen(str) + 1); 142d5ac70f0Sopenharmony_ci if (res) 143d5ac70f0Sopenharmony_ci return res; 144d5ac70f0Sopenharmony_ci return str; 145d5ac70f0Sopenharmony_ci} 146d5ac70f0Sopenharmony_ci 147d5ac70f0Sopenharmony_ci/** 148d5ac70f0Sopenharmony_ci * \brief Free a string list 149d5ac70f0Sopenharmony_ci * \param list The string list to free 150d5ac70f0Sopenharmony_ci * \param items Count of strings 151d5ac70f0Sopenharmony_ci * \return Zero if success, otherwise a negative error code 152d5ac70f0Sopenharmony_ci */ 153d5ac70f0Sopenharmony_ciint snd_use_case_free_list(const char *list[], int items) 154d5ac70f0Sopenharmony_ci{ 155d5ac70f0Sopenharmony_ci int i; 156d5ac70f0Sopenharmony_ci if (list == NULL) 157d5ac70f0Sopenharmony_ci return 0; 158d5ac70f0Sopenharmony_ci for (i = 0; i < items; i++) 159d5ac70f0Sopenharmony_ci free((void *)list[i]); 160d5ac70f0Sopenharmony_ci free(list); 161d5ac70f0Sopenharmony_ci return 0; 162d5ac70f0Sopenharmony_ci} 163d5ac70f0Sopenharmony_ci 164d5ac70f0Sopenharmony_cistatic int read_tlv_file(unsigned int **res, 165d5ac70f0Sopenharmony_ci const char *filepath) 166d5ac70f0Sopenharmony_ci{ 167d5ac70f0Sopenharmony_ci int err = 0; 168d5ac70f0Sopenharmony_ci int fd; 169d5ac70f0Sopenharmony_ci struct stat64 st; 170d5ac70f0Sopenharmony_ci size_t sz; 171d5ac70f0Sopenharmony_ci ssize_t sz_read; 172d5ac70f0Sopenharmony_ci struct snd_ctl_tlv *tlv; 173d5ac70f0Sopenharmony_ci 174d5ac70f0Sopenharmony_ci fd = open(filepath, O_RDONLY); 175d5ac70f0Sopenharmony_ci if (fd < 0) { 176d5ac70f0Sopenharmony_ci err = -errno; 177d5ac70f0Sopenharmony_ci return err; 178d5ac70f0Sopenharmony_ci } 179d5ac70f0Sopenharmony_ci if (fstat64(fd, &st) == -1) { 180d5ac70f0Sopenharmony_ci err = -errno; 181d5ac70f0Sopenharmony_ci goto __fail; 182d5ac70f0Sopenharmony_ci } 183d5ac70f0Sopenharmony_ci sz = st.st_size; 184d5ac70f0Sopenharmony_ci if (sz > 16 * 1024 * 1024 || sz < 8 || sz % 4) { 185d5ac70f0Sopenharmony_ci uc_error("File size should be less than 16 MB " 186d5ac70f0Sopenharmony_ci "and multiple of 4"); 187d5ac70f0Sopenharmony_ci err = -EINVAL; 188d5ac70f0Sopenharmony_ci goto __fail; 189d5ac70f0Sopenharmony_ci } 190d5ac70f0Sopenharmony_ci *res = malloc(sz); 191d5ac70f0Sopenharmony_ci if (res == NULL) { 192d5ac70f0Sopenharmony_ci err = -ENOMEM; 193d5ac70f0Sopenharmony_ci goto __fail; 194d5ac70f0Sopenharmony_ci } 195d5ac70f0Sopenharmony_ci sz_read = read(fd, *res, sz); 196d5ac70f0Sopenharmony_ci if (sz_read < 0 || (size_t)sz_read != sz) { 197d5ac70f0Sopenharmony_ci err = -EIO; 198d5ac70f0Sopenharmony_ci free(*res); 199d5ac70f0Sopenharmony_ci *res = NULL; 200d5ac70f0Sopenharmony_ci } 201d5ac70f0Sopenharmony_ci /* Check if the tlv file specifies valid size. */ 202d5ac70f0Sopenharmony_ci tlv = (struct snd_ctl_tlv *)(*res); 203d5ac70f0Sopenharmony_ci if (tlv->length + 2 * sizeof(unsigned int) != sz) { 204d5ac70f0Sopenharmony_ci uc_error("Invalid tlv size: %d", tlv->length); 205d5ac70f0Sopenharmony_ci err = -EINVAL; 206d5ac70f0Sopenharmony_ci free(*res); 207d5ac70f0Sopenharmony_ci *res = NULL; 208d5ac70f0Sopenharmony_ci } 209d5ac70f0Sopenharmony_ci 210d5ac70f0Sopenharmony_ci__fail: 211d5ac70f0Sopenharmony_ci close(fd); 212d5ac70f0Sopenharmony_ci return err; 213d5ac70f0Sopenharmony_ci} 214d5ac70f0Sopenharmony_ci 215d5ac70f0Sopenharmony_cistatic int binary_file_parse(snd_ctl_elem_value_t *dst, 216d5ac70f0Sopenharmony_ci snd_ctl_elem_info_t *info, 217d5ac70f0Sopenharmony_ci const char *filepath) 218d5ac70f0Sopenharmony_ci{ 219d5ac70f0Sopenharmony_ci int err = 0; 220d5ac70f0Sopenharmony_ci int fd; 221d5ac70f0Sopenharmony_ci struct stat64 st; 222d5ac70f0Sopenharmony_ci size_t sz; 223d5ac70f0Sopenharmony_ci ssize_t sz_read; 224d5ac70f0Sopenharmony_ci char *res; 225d5ac70f0Sopenharmony_ci snd_ctl_elem_type_t type; 226d5ac70f0Sopenharmony_ci unsigned int idx, count; 227d5ac70f0Sopenharmony_ci 228d5ac70f0Sopenharmony_ci type = snd_ctl_elem_info_get_type(info); 229d5ac70f0Sopenharmony_ci if (type != SND_CTL_ELEM_TYPE_BYTES) { 230d5ac70f0Sopenharmony_ci uc_error("only support byte type!"); 231d5ac70f0Sopenharmony_ci err = -EINVAL; 232d5ac70f0Sopenharmony_ci return err; 233d5ac70f0Sopenharmony_ci } 234d5ac70f0Sopenharmony_ci fd = open(filepath, O_RDONLY); 235d5ac70f0Sopenharmony_ci if (fd < 0) { 236d5ac70f0Sopenharmony_ci err = -errno; 237d5ac70f0Sopenharmony_ci return err; 238d5ac70f0Sopenharmony_ci } 239d5ac70f0Sopenharmony_ci if (stat64(filepath, &st) == -1) { 240d5ac70f0Sopenharmony_ci err = -errno; 241d5ac70f0Sopenharmony_ci goto __fail; 242d5ac70f0Sopenharmony_ci } 243d5ac70f0Sopenharmony_ci sz = st.st_size; 244d5ac70f0Sopenharmony_ci count = snd_ctl_elem_info_get_count(info); 245d5ac70f0Sopenharmony_ci if (sz != count || sz > sizeof(dst->value.bytes)) { 246d5ac70f0Sopenharmony_ci uc_error("invalid parameter size %d!", sz); 247d5ac70f0Sopenharmony_ci err = -EINVAL; 248d5ac70f0Sopenharmony_ci goto __fail; 249d5ac70f0Sopenharmony_ci } 250d5ac70f0Sopenharmony_ci res = malloc(sz); 251d5ac70f0Sopenharmony_ci if (res == NULL) { 252d5ac70f0Sopenharmony_ci err = -ENOMEM; 253d5ac70f0Sopenharmony_ci goto __fail; 254d5ac70f0Sopenharmony_ci } 255d5ac70f0Sopenharmony_ci sz_read = read(fd, res, sz); 256d5ac70f0Sopenharmony_ci if (sz_read < 0 || (size_t)sz_read != sz) { 257d5ac70f0Sopenharmony_ci err = -errno; 258d5ac70f0Sopenharmony_ci goto __fail_read; 259d5ac70f0Sopenharmony_ci } 260d5ac70f0Sopenharmony_ci for (idx = 0; idx < sz; idx++) 261d5ac70f0Sopenharmony_ci snd_ctl_elem_value_set_byte(dst, idx, *(res + idx)); 262d5ac70f0Sopenharmony_ci __fail_read: 263d5ac70f0Sopenharmony_ci free(res); 264d5ac70f0Sopenharmony_ci __fail: 265d5ac70f0Sopenharmony_ci close(fd); 266d5ac70f0Sopenharmony_ci return err; 267d5ac70f0Sopenharmony_ci} 268d5ac70f0Sopenharmony_ci 269d5ac70f0Sopenharmony_cistatic const char *parse_type(const char *p, const char *prefix, size_t len, 270d5ac70f0Sopenharmony_ci snd_ctl_elem_info_t *info) 271d5ac70f0Sopenharmony_ci{ 272d5ac70f0Sopenharmony_ci if (strncasecmp(p, prefix, len)) 273d5ac70f0Sopenharmony_ci return p; 274d5ac70f0Sopenharmony_ci p += len; 275d5ac70f0Sopenharmony_ci if (info->type != SND_CTL_ELEM_TYPE_NONE) 276d5ac70f0Sopenharmony_ci return NULL; 277d5ac70f0Sopenharmony_ci if (strncasecmp(p, "bool", sizeof("bool") - 1) == 0) 278d5ac70f0Sopenharmony_ci info->type = SND_CTL_ELEM_TYPE_BOOLEAN; 279d5ac70f0Sopenharmony_ci else if (strncasecmp(p, "integer64", sizeof("integer64") - 1) == 0) 280d5ac70f0Sopenharmony_ci info->type = SND_CTL_ELEM_TYPE_INTEGER64; 281d5ac70f0Sopenharmony_ci else if (strncasecmp(p, "int64", sizeof("int64") - 1) == 0) 282d5ac70f0Sopenharmony_ci info->type = SND_CTL_ELEM_TYPE_INTEGER64; 283d5ac70f0Sopenharmony_ci else if (strncasecmp(p, "int", sizeof("int") - 1) == 0) 284d5ac70f0Sopenharmony_ci info->type = SND_CTL_ELEM_TYPE_INTEGER; 285d5ac70f0Sopenharmony_ci else if (strncasecmp(p, "enum", sizeof("enum") - 1) == 0) 286d5ac70f0Sopenharmony_ci info->type = SND_CTL_ELEM_TYPE_ENUMERATED; 287d5ac70f0Sopenharmony_ci else if (strncasecmp(p, "bytes", sizeof("bytes") - 1) == 0) 288d5ac70f0Sopenharmony_ci info->type = SND_CTL_ELEM_TYPE_BYTES; 289d5ac70f0Sopenharmony_ci else 290d5ac70f0Sopenharmony_ci return NULL; 291d5ac70f0Sopenharmony_ci while (isalpha(*p)) 292d5ac70f0Sopenharmony_ci p++; 293d5ac70f0Sopenharmony_ci return p; 294d5ac70f0Sopenharmony_ci} 295d5ac70f0Sopenharmony_ci 296d5ac70f0Sopenharmony_cistatic const char *parse_uint(const char *p, const char *prefix, size_t len, 297d5ac70f0Sopenharmony_ci unsigned int min, unsigned int max, unsigned int *rval) 298d5ac70f0Sopenharmony_ci{ 299d5ac70f0Sopenharmony_ci long v; 300d5ac70f0Sopenharmony_ci char *end; 301d5ac70f0Sopenharmony_ci 302d5ac70f0Sopenharmony_ci if (strncasecmp(p, prefix, len)) 303d5ac70f0Sopenharmony_ci return p; 304d5ac70f0Sopenharmony_ci p += len; 305d5ac70f0Sopenharmony_ci v = strtol(p, &end, 0); 306d5ac70f0Sopenharmony_ci if (*end != '\0' && *end != ' ' && *end != ',') { 307d5ac70f0Sopenharmony_ci uc_error("unable to parse '%s'", prefix); 308d5ac70f0Sopenharmony_ci return NULL; 309d5ac70f0Sopenharmony_ci } 310d5ac70f0Sopenharmony_ci if ((unsigned int)v < min || (unsigned int)v > max) { 311d5ac70f0Sopenharmony_ci uc_error("value '%s' out of range %u-%u %(%ld)", min, max, v); 312d5ac70f0Sopenharmony_ci return NULL; 313d5ac70f0Sopenharmony_ci } 314d5ac70f0Sopenharmony_ci *rval = v; 315d5ac70f0Sopenharmony_ci return end; 316d5ac70f0Sopenharmony_ci} 317d5ac70f0Sopenharmony_ci 318d5ac70f0Sopenharmony_cistatic const char *parse_labels(const char *p, const char *prefix, size_t len, 319d5ac70f0Sopenharmony_ci snd_ctl_elem_info_t *info) 320d5ac70f0Sopenharmony_ci{ 321d5ac70f0Sopenharmony_ci const char *s; 322d5ac70f0Sopenharmony_ci char *buf, *bp; 323d5ac70f0Sopenharmony_ci size_t l; 324d5ac70f0Sopenharmony_ci int c; 325d5ac70f0Sopenharmony_ci 326d5ac70f0Sopenharmony_ci if (info->type != SND_CTL_ELEM_TYPE_ENUMERATED) 327d5ac70f0Sopenharmony_ci return NULL; 328d5ac70f0Sopenharmony_ci if (strncasecmp(p, prefix, len)) 329d5ac70f0Sopenharmony_ci return p; 330d5ac70f0Sopenharmony_ci p += len; 331d5ac70f0Sopenharmony_ci s = p; 332d5ac70f0Sopenharmony_ci c = *s; 333d5ac70f0Sopenharmony_ci l = 0; 334d5ac70f0Sopenharmony_ci if (c == '\'' || c == '\"') { 335d5ac70f0Sopenharmony_ci s++; 336d5ac70f0Sopenharmony_ci while (*s && *s != c) { 337d5ac70f0Sopenharmony_ci s++, l++; 338d5ac70f0Sopenharmony_ci } 339d5ac70f0Sopenharmony_ci if (*s == c) 340d5ac70f0Sopenharmony_ci s++; 341d5ac70f0Sopenharmony_ci } else { 342d5ac70f0Sopenharmony_ci while (*s && *s != ',') 343d5ac70f0Sopenharmony_ci l++; 344d5ac70f0Sopenharmony_ci } 345d5ac70f0Sopenharmony_ci if (l == 0) 346d5ac70f0Sopenharmony_ci return NULL; 347d5ac70f0Sopenharmony_ci buf = malloc(l + 1); 348d5ac70f0Sopenharmony_ci if (buf == NULL) 349d5ac70f0Sopenharmony_ci return NULL; 350d5ac70f0Sopenharmony_ci memcpy(buf, p + ((c == '\'' || c == '\"') ? 1 : 0), l); 351d5ac70f0Sopenharmony_ci buf[l] = '\0'; 352d5ac70f0Sopenharmony_ci info->value.enumerated.items = 1; 353d5ac70f0Sopenharmony_ci for (bp = buf; *bp; bp++) { 354d5ac70f0Sopenharmony_ci if (*bp == ';') { 355d5ac70f0Sopenharmony_ci if (bp == buf || bp[1] == ';') { 356d5ac70f0Sopenharmony_ci free(buf); 357d5ac70f0Sopenharmony_ci return NULL; 358d5ac70f0Sopenharmony_ci } 359d5ac70f0Sopenharmony_ci info->value.enumerated.items++; 360d5ac70f0Sopenharmony_ci *bp = '\0'; 361d5ac70f0Sopenharmony_ci } 362d5ac70f0Sopenharmony_ci } 363d5ac70f0Sopenharmony_ci info->value.enumerated.names_ptr = (uintptr_t)buf; 364d5ac70f0Sopenharmony_ci info->value.enumerated.names_length = l + 1; 365d5ac70f0Sopenharmony_ci return s; 366d5ac70f0Sopenharmony_ci} 367d5ac70f0Sopenharmony_ci 368d5ac70f0Sopenharmony_cistatic int parse_cset_new_info(snd_ctl_elem_info_t *info, const char *s, const char **pos) 369d5ac70f0Sopenharmony_ci{ 370d5ac70f0Sopenharmony_ci const char *p = s, *op; 371d5ac70f0Sopenharmony_ci 372d5ac70f0Sopenharmony_ci info->count = 1; 373d5ac70f0Sopenharmony_ci while (*s) { 374d5ac70f0Sopenharmony_ci op = p; 375d5ac70f0Sopenharmony_ci p = parse_type(p, "type=", sizeof("type=") - 1, info); 376d5ac70f0Sopenharmony_ci if (p != op) 377d5ac70f0Sopenharmony_ci goto next; 378d5ac70f0Sopenharmony_ci p = parse_uint(p, "elements=", sizeof("elements=") - 1, 1, 128, (unsigned int *)&info->owner); 379d5ac70f0Sopenharmony_ci if (p != op) 380d5ac70f0Sopenharmony_ci goto next; 381d5ac70f0Sopenharmony_ci p = parse_uint(p, "count=", sizeof("count=") - 1, 1, 128, &info->count); 382d5ac70f0Sopenharmony_ci if (p != op) 383d5ac70f0Sopenharmony_ci goto next; 384d5ac70f0Sopenharmony_ci p = parse_labels(p, "labels=", sizeof("labels=") - 1, info); 385d5ac70f0Sopenharmony_cinext: 386d5ac70f0Sopenharmony_ci if (p == NULL) 387d5ac70f0Sopenharmony_ci goto er; 388d5ac70f0Sopenharmony_ci if (*p == ',') 389d5ac70f0Sopenharmony_ci p++; 390d5ac70f0Sopenharmony_ci if (isspace(*p)) 391d5ac70f0Sopenharmony_ci break; 392d5ac70f0Sopenharmony_ci if (op == p) 393d5ac70f0Sopenharmony_ci goto er; 394d5ac70f0Sopenharmony_ci } 395d5ac70f0Sopenharmony_ci *pos = p; 396d5ac70f0Sopenharmony_ci return 0; 397d5ac70f0Sopenharmony_cier: 398d5ac70f0Sopenharmony_ci uc_error("unknown syntax '%s'", p); 399d5ac70f0Sopenharmony_ci return -EINVAL; 400d5ac70f0Sopenharmony_ci} 401d5ac70f0Sopenharmony_ci 402d5ac70f0Sopenharmony_cistatic int execute_cset(snd_ctl_t *ctl, const char *cset, unsigned int type) 403d5ac70f0Sopenharmony_ci{ 404d5ac70f0Sopenharmony_ci const char *pos; 405d5ac70f0Sopenharmony_ci int err; 406d5ac70f0Sopenharmony_ci snd_ctl_elem_id_t *id; 407d5ac70f0Sopenharmony_ci snd_ctl_elem_value_t *value; 408d5ac70f0Sopenharmony_ci snd_ctl_elem_info_t *info, *info2 = NULL; 409d5ac70f0Sopenharmony_ci unsigned int *res = NULL; 410d5ac70f0Sopenharmony_ci 411d5ac70f0Sopenharmony_ci snd_ctl_elem_id_malloc(&id); 412d5ac70f0Sopenharmony_ci snd_ctl_elem_value_malloc(&value); 413d5ac70f0Sopenharmony_ci snd_ctl_elem_info_malloc(&info); 414d5ac70f0Sopenharmony_ci 415d5ac70f0Sopenharmony_ci err = __snd_ctl_ascii_elem_id_parse(id, cset, &pos); 416d5ac70f0Sopenharmony_ci if (err < 0) 417d5ac70f0Sopenharmony_ci goto __fail; 418d5ac70f0Sopenharmony_ci while (*pos && isspace(*pos)) 419d5ac70f0Sopenharmony_ci pos++; 420d5ac70f0Sopenharmony_ci if (type == SEQUENCE_ELEMENT_TYPE_CSET_NEW) { 421d5ac70f0Sopenharmony_ci snd_ctl_elem_info_malloc(&info2); 422d5ac70f0Sopenharmony_ci snd_ctl_elem_info_set_id(info2, id); 423d5ac70f0Sopenharmony_ci err = parse_cset_new_info(info2, pos, &pos); 424d5ac70f0Sopenharmony_ci if (err < 0 || !*pos) { 425d5ac70f0Sopenharmony_ci uc_error("undefined or wrong id config for cset-new", cset); 426d5ac70f0Sopenharmony_ci err = -EINVAL; 427d5ac70f0Sopenharmony_ci goto __fail; 428d5ac70f0Sopenharmony_ci } 429d5ac70f0Sopenharmony_ci while (*pos && isspace(*pos)) 430d5ac70f0Sopenharmony_ci pos++; 431d5ac70f0Sopenharmony_ci } 432d5ac70f0Sopenharmony_ci if (!*pos) { 433d5ac70f0Sopenharmony_ci if (type != SEQUENCE_ELEMENT_TYPE_CTL_REMOVE) { 434d5ac70f0Sopenharmony_ci uc_error("undefined value for cset >%s<", cset); 435d5ac70f0Sopenharmony_ci err = -EINVAL; 436d5ac70f0Sopenharmony_ci goto __fail; 437d5ac70f0Sopenharmony_ci } 438d5ac70f0Sopenharmony_ci } else if (type == SEQUENCE_ELEMENT_TYPE_CTL_REMOVE) { 439d5ac70f0Sopenharmony_ci uc_error("extra value for ctl-remove >%s<", cset); 440d5ac70f0Sopenharmony_ci err = -EINVAL; 441d5ac70f0Sopenharmony_ci goto __fail; 442d5ac70f0Sopenharmony_ci } 443d5ac70f0Sopenharmony_ci 444d5ac70f0Sopenharmony_ci snd_ctl_elem_info_set_id(info, id); 445d5ac70f0Sopenharmony_ci err = snd_ctl_elem_info(ctl, info); 446d5ac70f0Sopenharmony_ci if (type == SEQUENCE_ELEMENT_TYPE_CSET_NEW || 447d5ac70f0Sopenharmony_ci type == SEQUENCE_ELEMENT_TYPE_CTL_REMOVE) { 448d5ac70f0Sopenharmony_ci if (err >= 0) { 449d5ac70f0Sopenharmony_ci err = snd_ctl_elem_remove(ctl, id); 450d5ac70f0Sopenharmony_ci if (err < 0) { 451d5ac70f0Sopenharmony_ci uc_error("unable to remove control"); 452d5ac70f0Sopenharmony_ci err = -EINVAL; 453d5ac70f0Sopenharmony_ci goto __fail; 454d5ac70f0Sopenharmony_ci } 455d5ac70f0Sopenharmony_ci } 456d5ac70f0Sopenharmony_ci if (type == SEQUENCE_ELEMENT_TYPE_CTL_REMOVE) 457d5ac70f0Sopenharmony_ci goto __ok; 458d5ac70f0Sopenharmony_ci err = __snd_ctl_add_elem_set(ctl, info2, info2->owner, info2->count); 459d5ac70f0Sopenharmony_ci if (err < 0) { 460d5ac70f0Sopenharmony_ci uc_error("unable to create new control"); 461d5ac70f0Sopenharmony_ci goto __fail; 462d5ac70f0Sopenharmony_ci } 463d5ac70f0Sopenharmony_ci /* new id copy */ 464d5ac70f0Sopenharmony_ci snd_ctl_elem_info_get_id(info2, id); 465d5ac70f0Sopenharmony_ci snd_ctl_elem_info_set_id(info, id); 466d5ac70f0Sopenharmony_ci } else if (err < 0) 467d5ac70f0Sopenharmony_ci goto __fail; 468d5ac70f0Sopenharmony_ci if (type == SEQUENCE_ELEMENT_TYPE_CSET_TLV) { 469d5ac70f0Sopenharmony_ci if (!snd_ctl_elem_info_is_tlv_writable(info)) { 470d5ac70f0Sopenharmony_ci err = -EINVAL; 471d5ac70f0Sopenharmony_ci goto __fail; 472d5ac70f0Sopenharmony_ci } 473d5ac70f0Sopenharmony_ci err = read_tlv_file(&res, pos); 474d5ac70f0Sopenharmony_ci if (err < 0) 475d5ac70f0Sopenharmony_ci goto __fail; 476d5ac70f0Sopenharmony_ci err = snd_ctl_elem_tlv_write(ctl, id, res); 477d5ac70f0Sopenharmony_ci if (err < 0) 478d5ac70f0Sopenharmony_ci goto __fail; 479d5ac70f0Sopenharmony_ci } else { 480d5ac70f0Sopenharmony_ci snd_ctl_elem_value_set_id(value, id); 481d5ac70f0Sopenharmony_ci err = snd_ctl_elem_read(ctl, value); 482d5ac70f0Sopenharmony_ci if (err < 0) 483d5ac70f0Sopenharmony_ci goto __fail; 484d5ac70f0Sopenharmony_ci if (type == SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE) 485d5ac70f0Sopenharmony_ci err = binary_file_parse(value, info, pos); 486d5ac70f0Sopenharmony_ci else 487d5ac70f0Sopenharmony_ci err = snd_ctl_ascii_value_parse(ctl, value, info, pos); 488d5ac70f0Sopenharmony_ci if (err < 0) 489d5ac70f0Sopenharmony_ci goto __fail; 490d5ac70f0Sopenharmony_ci err = snd_ctl_elem_write(ctl, value); 491d5ac70f0Sopenharmony_ci if (err < 0) 492d5ac70f0Sopenharmony_ci goto __fail; 493d5ac70f0Sopenharmony_ci if (type == SEQUENCE_ELEMENT_TYPE_CSET_NEW) { 494d5ac70f0Sopenharmony_ci unsigned int idx; 495d5ac70f0Sopenharmony_ci for (idx = 1; idx < (unsigned int)info2->owner; idx++) { 496d5ac70f0Sopenharmony_ci value->id.numid += 1; 497d5ac70f0Sopenharmony_ci err = snd_ctl_elem_write(ctl, value); 498d5ac70f0Sopenharmony_ci if (err < 0) 499d5ac70f0Sopenharmony_ci goto __fail; 500d5ac70f0Sopenharmony_ci } 501d5ac70f0Sopenharmony_ci } 502d5ac70f0Sopenharmony_ci } 503d5ac70f0Sopenharmony_ci __ok: 504d5ac70f0Sopenharmony_ci err = 0; 505d5ac70f0Sopenharmony_ci __fail: 506d5ac70f0Sopenharmony_ci free(id); 507d5ac70f0Sopenharmony_ci free(value); 508d5ac70f0Sopenharmony_ci if (info2) { 509d5ac70f0Sopenharmony_ci if (info2->type == SND_CTL_ELEM_TYPE_ENUMERATED) 510d5ac70f0Sopenharmony_ci free((void *)(size_t)info2->value.enumerated.names_ptr); 511d5ac70f0Sopenharmony_ci free(info2); 512d5ac70f0Sopenharmony_ci } 513d5ac70f0Sopenharmony_ci free(info); 514d5ac70f0Sopenharmony_ci free(res); 515d5ac70f0Sopenharmony_ci 516d5ac70f0Sopenharmony_ci return err; 517d5ac70f0Sopenharmony_ci} 518d5ac70f0Sopenharmony_ci 519d5ac70f0Sopenharmony_cistatic int execute_sysw(const char *sysw) 520d5ac70f0Sopenharmony_ci{ 521d5ac70f0Sopenharmony_ci char path[PATH_MAX]; 522d5ac70f0Sopenharmony_ci const char *e; 523d5ac70f0Sopenharmony_ci char *s, *value; 524d5ac70f0Sopenharmony_ci ssize_t wlen; 525d5ac70f0Sopenharmony_ci size_t len; 526d5ac70f0Sopenharmony_ci int fd, myerrno; 527d5ac70f0Sopenharmony_ci bool ignore_error = false; 528d5ac70f0Sopenharmony_ci 529d5ac70f0Sopenharmony_ci if (sysw == NULL || *sysw == '\0') 530d5ac70f0Sopenharmony_ci return 0; 531d5ac70f0Sopenharmony_ci 532d5ac70f0Sopenharmony_ci if (sysw[0] == '-') { 533d5ac70f0Sopenharmony_ci ignore_error = true; 534d5ac70f0Sopenharmony_ci sysw++; 535d5ac70f0Sopenharmony_ci } 536d5ac70f0Sopenharmony_ci 537d5ac70f0Sopenharmony_ci if (sysw[0] == ':') 538d5ac70f0Sopenharmony_ci return -EINVAL; 539d5ac70f0Sopenharmony_ci 540d5ac70f0Sopenharmony_ci s = strdup(sysw[0] != '/' ? sysw : sysw + 1); 541d5ac70f0Sopenharmony_ci if (s == NULL) 542d5ac70f0Sopenharmony_ci return -ENOMEM; 543d5ac70f0Sopenharmony_ci 544d5ac70f0Sopenharmony_ci value = strchr(s, ':'); 545d5ac70f0Sopenharmony_ci if (!value) { 546d5ac70f0Sopenharmony_ci free(s); 547d5ac70f0Sopenharmony_ci return -EINVAL; 548d5ac70f0Sopenharmony_ci } 549d5ac70f0Sopenharmony_ci *value = '\0'; 550d5ac70f0Sopenharmony_ci value++; 551d5ac70f0Sopenharmony_ci len = strlen(value); 552d5ac70f0Sopenharmony_ci if (len < 1) { 553d5ac70f0Sopenharmony_ci free(s); 554d5ac70f0Sopenharmony_ci return -EINVAL; 555d5ac70f0Sopenharmony_ci } 556d5ac70f0Sopenharmony_ci 557d5ac70f0Sopenharmony_ci e = uc_mgr_sysfs_root(); 558d5ac70f0Sopenharmony_ci if (e == NULL) { 559d5ac70f0Sopenharmony_ci free(s); 560d5ac70f0Sopenharmony_ci return -EINVAL; 561d5ac70f0Sopenharmony_ci } 562d5ac70f0Sopenharmony_ci snprintf(path, sizeof(path), "%s/%s", e, s); 563d5ac70f0Sopenharmony_ci 564d5ac70f0Sopenharmony_ci fd = open(path, O_WRONLY|O_CLOEXEC); 565d5ac70f0Sopenharmony_ci if (fd < 0) { 566d5ac70f0Sopenharmony_ci free(s); 567d5ac70f0Sopenharmony_ci if (ignore_error) 568d5ac70f0Sopenharmony_ci return 0; 569d5ac70f0Sopenharmony_ci uc_error("unable to open '%s' for write", path); 570d5ac70f0Sopenharmony_ci return -EINVAL; 571d5ac70f0Sopenharmony_ci } 572d5ac70f0Sopenharmony_ci wlen = write(fd, value, len); 573d5ac70f0Sopenharmony_ci myerrno = errno; 574d5ac70f0Sopenharmony_ci close(fd); 575d5ac70f0Sopenharmony_ci 576d5ac70f0Sopenharmony_ci if (ignore_error) 577d5ac70f0Sopenharmony_ci goto __end; 578d5ac70f0Sopenharmony_ci 579d5ac70f0Sopenharmony_ci if (wlen != (ssize_t)len) { 580d5ac70f0Sopenharmony_ci uc_error("unable to write '%s' to '%s': %s", value, path, strerror(myerrno)); 581d5ac70f0Sopenharmony_ci free(s); 582d5ac70f0Sopenharmony_ci return -EINVAL; 583d5ac70f0Sopenharmony_ci } 584d5ac70f0Sopenharmony_ci 585d5ac70f0Sopenharmony_ci__end: 586d5ac70f0Sopenharmony_ci free(s); 587d5ac70f0Sopenharmony_ci return 0; 588d5ac70f0Sopenharmony_ci} 589d5ac70f0Sopenharmony_ci 590d5ac70f0Sopenharmony_ciint _snd_config_save_node_value(snd_config_t *n, snd_output_t *out, unsigned int level); 591d5ac70f0Sopenharmony_ci 592d5ac70f0Sopenharmony_cistatic int execute_cfgsave(snd_use_case_mgr_t *uc_mgr, const char *filename) 593d5ac70f0Sopenharmony_ci{ 594d5ac70f0Sopenharmony_ci snd_config_t *config = uc_mgr->local_config; 595d5ac70f0Sopenharmony_ci char *file, *root; 596d5ac70f0Sopenharmony_ci snd_output_t *out; 597d5ac70f0Sopenharmony_ci bool with_root = false; 598d5ac70f0Sopenharmony_ci int err = 0; 599d5ac70f0Sopenharmony_ci 600d5ac70f0Sopenharmony_ci file = strdup(filename); 601d5ac70f0Sopenharmony_ci if (!file) 602d5ac70f0Sopenharmony_ci return -ENOMEM; 603d5ac70f0Sopenharmony_ci root = strchr(file, ':'); 604d5ac70f0Sopenharmony_ci if (config && root) { 605d5ac70f0Sopenharmony_ci *root++ = '\0'; 606d5ac70f0Sopenharmony_ci if (*root == '+') { 607d5ac70f0Sopenharmony_ci with_root = true; 608d5ac70f0Sopenharmony_ci root++; 609d5ac70f0Sopenharmony_ci } 610d5ac70f0Sopenharmony_ci err = snd_config_search(config, root, &config); 611d5ac70f0Sopenharmony_ci if (err < 0) { 612d5ac70f0Sopenharmony_ci uc_error("Unable to find subtree '%s'", root); 613d5ac70f0Sopenharmony_ci goto _err; 614d5ac70f0Sopenharmony_ci } 615d5ac70f0Sopenharmony_ci } 616d5ac70f0Sopenharmony_ci 617d5ac70f0Sopenharmony_ci err = snd_output_stdio_open(&out, file, "w+"); 618d5ac70f0Sopenharmony_ci if (err < 0) { 619d5ac70f0Sopenharmony_ci uc_error("unable to open file '%s': %s", file, snd_strerror(err)); 620d5ac70f0Sopenharmony_ci goto _err; 621d5ac70f0Sopenharmony_ci } 622d5ac70f0Sopenharmony_ci if (!config || snd_config_is_empty(config)) { 623d5ac70f0Sopenharmony_ci snd_output_close(out); 624d5ac70f0Sopenharmony_ci goto _err; 625d5ac70f0Sopenharmony_ci } 626d5ac70f0Sopenharmony_ci if (with_root) { 627d5ac70f0Sopenharmony_ci snd_output_printf(out, "%s ", root); 628d5ac70f0Sopenharmony_ci err = _snd_config_save_node_value(config, out, 0); 629d5ac70f0Sopenharmony_ci } else { 630d5ac70f0Sopenharmony_ci err = snd_config_save(config, out); 631d5ac70f0Sopenharmony_ci } 632d5ac70f0Sopenharmony_ci snd_output_close(out); 633d5ac70f0Sopenharmony_ci if (err < 0) { 634d5ac70f0Sopenharmony_ci uc_error("unable to save configuration: %s", snd_strerror(err)); 635d5ac70f0Sopenharmony_ci goto _err; 636d5ac70f0Sopenharmony_ci } 637d5ac70f0Sopenharmony_ci_err: 638d5ac70f0Sopenharmony_ci free(file); 639d5ac70f0Sopenharmony_ci return err; 640d5ac70f0Sopenharmony_ci} 641d5ac70f0Sopenharmony_ci 642d5ac70f0Sopenharmony_cistatic int rewrite_device_value(snd_use_case_mgr_t *uc_mgr, const char *name, char **value) 643d5ac70f0Sopenharmony_ci{ 644d5ac70f0Sopenharmony_ci char *sval; 645d5ac70f0Sopenharmony_ci size_t l; 646d5ac70f0Sopenharmony_ci static const char **s, *_prefix[] = { 647d5ac70f0Sopenharmony_ci "PlaybackCTL", 648d5ac70f0Sopenharmony_ci "CaptureCTL", 649d5ac70f0Sopenharmony_ci "PlaybackMixer", 650d5ac70f0Sopenharmony_ci "CaptureMixer", 651d5ac70f0Sopenharmony_ci "PlaybackPCM", 652d5ac70f0Sopenharmony_ci "CapturePCM", 653d5ac70f0Sopenharmony_ci NULL 654d5ac70f0Sopenharmony_ci }; 655d5ac70f0Sopenharmony_ci 656d5ac70f0Sopenharmony_ci if (!uc_mgr_has_local_config(uc_mgr)) 657d5ac70f0Sopenharmony_ci return 0; 658d5ac70f0Sopenharmony_ci for (s = _prefix; *s && *value; s++) { 659d5ac70f0Sopenharmony_ci if (strcmp(*s, name) != 0) 660d5ac70f0Sopenharmony_ci continue; 661d5ac70f0Sopenharmony_ci l = strlen(*value) + 9 + 1; 662d5ac70f0Sopenharmony_ci sval = malloc(l); 663d5ac70f0Sopenharmony_ci if (sval == NULL) { 664d5ac70f0Sopenharmony_ci free(*value); 665d5ac70f0Sopenharmony_ci *value = NULL; 666d5ac70f0Sopenharmony_ci return -ENOMEM; 667d5ac70f0Sopenharmony_ci } 668d5ac70f0Sopenharmony_ci snprintf(sval, l, "_ucm%04X.%s", uc_mgr->ucm_card_number, *value); 669d5ac70f0Sopenharmony_ci free(*value); 670d5ac70f0Sopenharmony_ci *value = sval; 671d5ac70f0Sopenharmony_ci break; 672d5ac70f0Sopenharmony_ci } 673d5ac70f0Sopenharmony_ci return 0; 674d5ac70f0Sopenharmony_ci} 675d5ac70f0Sopenharmony_ci 676d5ac70f0Sopenharmony_cistatic int run_device_sequence(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb, 677d5ac70f0Sopenharmony_ci const char *name, bool enable) 678d5ac70f0Sopenharmony_ci{ 679d5ac70f0Sopenharmony_ci struct use_case_device *device; 680d5ac70f0Sopenharmony_ci 681d5ac70f0Sopenharmony_ci if (verb == NULL) { 682d5ac70f0Sopenharmony_ci uc_error("error: enadev2 / disdev2 must be executed inside the verb context"); 683d5ac70f0Sopenharmony_ci return -ENOENT; 684d5ac70f0Sopenharmony_ci } 685d5ac70f0Sopenharmony_ci 686d5ac70f0Sopenharmony_ci device = find_device(uc_mgr, verb, name, 0); 687d5ac70f0Sopenharmony_ci if (device == NULL) { 688d5ac70f0Sopenharmony_ci uc_error("error: unable to find device '%s'\n", name); 689d5ac70f0Sopenharmony_ci return -ENOENT; 690d5ac70f0Sopenharmony_ci } 691d5ac70f0Sopenharmony_ci 692d5ac70f0Sopenharmony_ci return execute_sequence(uc_mgr, verb, 693d5ac70f0Sopenharmony_ci enable ? &device->enable_list : &device->disable_list, 694d5ac70f0Sopenharmony_ci &device->value_list, 695d5ac70f0Sopenharmony_ci &verb->value_list, 696d5ac70f0Sopenharmony_ci &uc_mgr->value_list); 697d5ac70f0Sopenharmony_ci} 698d5ac70f0Sopenharmony_ci 699d5ac70f0Sopenharmony_cistatic int run_device_all_sequence(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb) 700d5ac70f0Sopenharmony_ci{ 701d5ac70f0Sopenharmony_ci struct use_case_device *device; 702d5ac70f0Sopenharmony_ci struct list_head *pos; 703d5ac70f0Sopenharmony_ci int err; 704d5ac70f0Sopenharmony_ci 705d5ac70f0Sopenharmony_ci if (verb == NULL) { 706d5ac70f0Sopenharmony_ci uc_error("error: disdevall must be executed inside the verb context"); 707d5ac70f0Sopenharmony_ci return -ENOENT; 708d5ac70f0Sopenharmony_ci } 709d5ac70f0Sopenharmony_ci 710d5ac70f0Sopenharmony_ci list_for_each(pos, &verb->device_list) { 711d5ac70f0Sopenharmony_ci device = list_entry(pos, struct use_case_device, list); 712d5ac70f0Sopenharmony_ci 713d5ac70f0Sopenharmony_ci err = execute_sequence(uc_mgr, verb, 714d5ac70f0Sopenharmony_ci &device->disable_list, 715d5ac70f0Sopenharmony_ci &device->value_list, 716d5ac70f0Sopenharmony_ci &verb->value_list, 717d5ac70f0Sopenharmony_ci &uc_mgr->value_list); 718d5ac70f0Sopenharmony_ci if (err < 0) 719d5ac70f0Sopenharmony_ci return err; 720d5ac70f0Sopenharmony_ci } 721d5ac70f0Sopenharmony_ci return 0; 722d5ac70f0Sopenharmony_ci} 723d5ac70f0Sopenharmony_ci 724d5ac70f0Sopenharmony_ci/** 725d5ac70f0Sopenharmony_ci * \brief Execute the sequence 726d5ac70f0Sopenharmony_ci * \param uc_mgr Use case manager 727d5ac70f0Sopenharmony_ci * \param seq Sequence 728d5ac70f0Sopenharmony_ci * \return zero on success, otherwise a negative error code 729d5ac70f0Sopenharmony_ci */ 730d5ac70f0Sopenharmony_cistatic int execute_sequence(snd_use_case_mgr_t *uc_mgr, 731d5ac70f0Sopenharmony_ci struct use_case_verb *verb, 732d5ac70f0Sopenharmony_ci struct list_head *seq, 733d5ac70f0Sopenharmony_ci struct list_head *value_list1, 734d5ac70f0Sopenharmony_ci struct list_head *value_list2, 735d5ac70f0Sopenharmony_ci struct list_head *value_list3) 736d5ac70f0Sopenharmony_ci{ 737d5ac70f0Sopenharmony_ci struct list_head *pos; 738d5ac70f0Sopenharmony_ci struct sequence_element *s; 739d5ac70f0Sopenharmony_ci char *cdev = NULL; 740d5ac70f0Sopenharmony_ci snd_ctl_t *ctl = NULL; 741d5ac70f0Sopenharmony_ci struct ctl_list *ctl_list; 742d5ac70f0Sopenharmony_ci bool ignore_error; 743d5ac70f0Sopenharmony_ci int err = 0; 744d5ac70f0Sopenharmony_ci 745d5ac70f0Sopenharmony_ci if (uc_mgr->sequence_hops > 100) { 746d5ac70f0Sopenharmony_ci uc_error("error: too many inner sequences!"); 747d5ac70f0Sopenharmony_ci return -EINVAL; 748d5ac70f0Sopenharmony_ci } 749d5ac70f0Sopenharmony_ci uc_mgr->sequence_hops++; 750d5ac70f0Sopenharmony_ci list_for_each(pos, seq) { 751d5ac70f0Sopenharmony_ci s = list_entry(pos, struct sequence_element, list); 752d5ac70f0Sopenharmony_ci switch (s->type) { 753d5ac70f0Sopenharmony_ci case SEQUENCE_ELEMENT_TYPE_CDEV: 754d5ac70f0Sopenharmony_ci cdev = strdup(s->data.cdev); 755d5ac70f0Sopenharmony_ci if (cdev == NULL) 756d5ac70f0Sopenharmony_ci goto __fail_nomem; 757d5ac70f0Sopenharmony_ci if (rewrite_device_value(uc_mgr, "PlaybackCTL", &cdev)) 758d5ac70f0Sopenharmony_ci goto __fail_nomem; 759d5ac70f0Sopenharmony_ci break; 760d5ac70f0Sopenharmony_ci case SEQUENCE_ELEMENT_TYPE_CSET: 761d5ac70f0Sopenharmony_ci case SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE: 762d5ac70f0Sopenharmony_ci case SEQUENCE_ELEMENT_TYPE_CSET_TLV: 763d5ac70f0Sopenharmony_ci case SEQUENCE_ELEMENT_TYPE_CSET_NEW: 764d5ac70f0Sopenharmony_ci case SEQUENCE_ELEMENT_TYPE_CTL_REMOVE: 765d5ac70f0Sopenharmony_ci if (cdev == NULL && uc_mgr->in_component_domain) { 766d5ac70f0Sopenharmony_ci /* For sequence of a component device, use 767d5ac70f0Sopenharmony_ci * its parent's cdev stored by ucm manager. 768d5ac70f0Sopenharmony_ci */ 769d5ac70f0Sopenharmony_ci if (uc_mgr->cdev == NULL) { 770d5ac70f0Sopenharmony_ci uc_error("cdev is not defined!"); 771d5ac70f0Sopenharmony_ci return err; 772d5ac70f0Sopenharmony_ci } 773d5ac70f0Sopenharmony_ci 774d5ac70f0Sopenharmony_ci cdev = strndup(uc_mgr->cdev, PATH_MAX); 775d5ac70f0Sopenharmony_ci if (!cdev) 776d5ac70f0Sopenharmony_ci return -ENOMEM; 777d5ac70f0Sopenharmony_ci } else if (cdev == NULL) { 778d5ac70f0Sopenharmony_ci char *playback_ctl = NULL; 779d5ac70f0Sopenharmony_ci char *capture_ctl = NULL; 780d5ac70f0Sopenharmony_ci 781d5ac70f0Sopenharmony_ci err = get_value3(uc_mgr, &playback_ctl, "PlaybackCTL", 782d5ac70f0Sopenharmony_ci value_list1, 783d5ac70f0Sopenharmony_ci value_list2, 784d5ac70f0Sopenharmony_ci value_list3); 785d5ac70f0Sopenharmony_ci if (err < 0 && err != -ENOENT) { 786d5ac70f0Sopenharmony_ci uc_error("cdev is not defined!"); 787d5ac70f0Sopenharmony_ci return err; 788d5ac70f0Sopenharmony_ci } 789d5ac70f0Sopenharmony_ci err = get_value3(uc_mgr, &capture_ctl, "CaptureCTL", 790d5ac70f0Sopenharmony_ci value_list1, 791d5ac70f0Sopenharmony_ci value_list2, 792d5ac70f0Sopenharmony_ci value_list3); 793d5ac70f0Sopenharmony_ci if (err < 0 && err != -ENOENT) { 794d5ac70f0Sopenharmony_ci free(playback_ctl); 795d5ac70f0Sopenharmony_ci uc_error("cdev is not defined!"); 796d5ac70f0Sopenharmony_ci return err; 797d5ac70f0Sopenharmony_ci } 798d5ac70f0Sopenharmony_ci if (playback_ctl == NULL && 799d5ac70f0Sopenharmony_ci capture_ctl == NULL) { 800d5ac70f0Sopenharmony_ci uc_error("cdev is not defined!"); 801d5ac70f0Sopenharmony_ci return -EINVAL; 802d5ac70f0Sopenharmony_ci } 803d5ac70f0Sopenharmony_ci if (playback_ctl != NULL && 804d5ac70f0Sopenharmony_ci capture_ctl != NULL && 805d5ac70f0Sopenharmony_ci strcmp(playback_ctl, capture_ctl) != 0) { 806d5ac70f0Sopenharmony_ci free(playback_ctl); 807d5ac70f0Sopenharmony_ci free(capture_ctl); 808d5ac70f0Sopenharmony_ci uc_error("cdev is not equal for playback and capture!"); 809d5ac70f0Sopenharmony_ci return -EINVAL; 810d5ac70f0Sopenharmony_ci } 811d5ac70f0Sopenharmony_ci if (playback_ctl != NULL) { 812d5ac70f0Sopenharmony_ci cdev = playback_ctl; 813d5ac70f0Sopenharmony_ci free(capture_ctl); 814d5ac70f0Sopenharmony_ci } else { 815d5ac70f0Sopenharmony_ci cdev = capture_ctl; 816d5ac70f0Sopenharmony_ci } 817d5ac70f0Sopenharmony_ci } 818d5ac70f0Sopenharmony_ci if (ctl == NULL) { 819d5ac70f0Sopenharmony_ci err = uc_mgr_open_ctl(uc_mgr, &ctl_list, cdev, 1); 820d5ac70f0Sopenharmony_ci if (err < 0) { 821d5ac70f0Sopenharmony_ci uc_error("unable to open ctl device '%s'", cdev); 822d5ac70f0Sopenharmony_ci goto __fail; 823d5ac70f0Sopenharmony_ci } 824d5ac70f0Sopenharmony_ci ctl = ctl_list->ctl; 825d5ac70f0Sopenharmony_ci } 826d5ac70f0Sopenharmony_ci err = execute_cset(ctl, s->data.cset, s->type); 827d5ac70f0Sopenharmony_ci if (err < 0) { 828d5ac70f0Sopenharmony_ci uc_error("unable to execute cset '%s'", s->data.cset); 829d5ac70f0Sopenharmony_ci goto __fail; 830d5ac70f0Sopenharmony_ci } 831d5ac70f0Sopenharmony_ci break; 832d5ac70f0Sopenharmony_ci case SEQUENCE_ELEMENT_TYPE_SYSSET: 833d5ac70f0Sopenharmony_ci err = execute_sysw(s->data.sysw); 834d5ac70f0Sopenharmony_ci if (err < 0) 835d5ac70f0Sopenharmony_ci goto __fail; 836d5ac70f0Sopenharmony_ci break; 837d5ac70f0Sopenharmony_ci case SEQUENCE_ELEMENT_TYPE_SLEEP: 838d5ac70f0Sopenharmony_ci usleep(s->data.sleep); 839d5ac70f0Sopenharmony_ci break; 840d5ac70f0Sopenharmony_ci case SEQUENCE_ELEMENT_TYPE_EXEC: 841d5ac70f0Sopenharmony_ci if (s->data.exec == NULL) 842d5ac70f0Sopenharmony_ci break; 843d5ac70f0Sopenharmony_ci ignore_error = s->data.exec[0] == '-'; 844d5ac70f0Sopenharmony_ci err = uc_mgr_exec(s->data.exec + (ignore_error ? 1 : 0)); 845d5ac70f0Sopenharmony_ci if (ignore_error == false && err != 0) { 846d5ac70f0Sopenharmony_ci uc_error("exec '%s' failed (exit code %d)", s->data.exec, err); 847d5ac70f0Sopenharmony_ci goto __fail; 848d5ac70f0Sopenharmony_ci } 849d5ac70f0Sopenharmony_ci break; 850d5ac70f0Sopenharmony_ci case SEQUENCE_ELEMENT_TYPE_SHELL: 851d5ac70f0Sopenharmony_ci if (s->data.exec == NULL) 852d5ac70f0Sopenharmony_ci break; 853d5ac70f0Sopenharmony_ci ignore_error = s->data.exec[0] == '-'; 854d5ac70f0Sopenharmony_cishell_retry: 855d5ac70f0Sopenharmony_ci err = system(s->data.exec + (ignore_error ? 1 : 0)); 856d5ac70f0Sopenharmony_ci if (WIFSIGNALED(err)) { 857d5ac70f0Sopenharmony_ci err = -EINTR; 858d5ac70f0Sopenharmony_ci } if (WIFEXITED(err)) { 859d5ac70f0Sopenharmony_ci if (ignore_error == false && WEXITSTATUS(err) != 0) { 860d5ac70f0Sopenharmony_ci uc_error("command '%s' failed (exit code %d)", s->data.exec, WEXITSTATUS(err)); 861d5ac70f0Sopenharmony_ci err = -EINVAL; 862d5ac70f0Sopenharmony_ci goto __fail; 863d5ac70f0Sopenharmony_ci } 864d5ac70f0Sopenharmony_ci } else if (err < 0) { 865d5ac70f0Sopenharmony_ci if (errno == EAGAIN) 866d5ac70f0Sopenharmony_ci goto shell_retry; 867d5ac70f0Sopenharmony_ci err = -errno; 868d5ac70f0Sopenharmony_ci goto __fail; 869d5ac70f0Sopenharmony_ci } 870d5ac70f0Sopenharmony_ci break; 871d5ac70f0Sopenharmony_ci case SEQUENCE_ELEMENT_TYPE_CMPT_SEQ: 872d5ac70f0Sopenharmony_ci /* Execute enable or disable sequence of a component 873d5ac70f0Sopenharmony_ci * device. Pass the cdev defined by the machine device. 874d5ac70f0Sopenharmony_ci */ 875d5ac70f0Sopenharmony_ci err = execute_component_seq(uc_mgr, 876d5ac70f0Sopenharmony_ci &s->data.cmpt_seq, 877d5ac70f0Sopenharmony_ci value_list1, 878d5ac70f0Sopenharmony_ci value_list2, 879d5ac70f0Sopenharmony_ci value_list3, 880d5ac70f0Sopenharmony_ci cdev); 881d5ac70f0Sopenharmony_ci if (err < 0) 882d5ac70f0Sopenharmony_ci goto __fail; 883d5ac70f0Sopenharmony_ci break; 884d5ac70f0Sopenharmony_ci case SEQUENCE_ELEMENT_TYPE_CFGSAVE: 885d5ac70f0Sopenharmony_ci err = execute_cfgsave(uc_mgr, s->data.cfgsave); 886d5ac70f0Sopenharmony_ci if (err < 0) 887d5ac70f0Sopenharmony_ci goto __fail; 888d5ac70f0Sopenharmony_ci break; 889d5ac70f0Sopenharmony_ci case SEQUENCE_ELEMENT_TYPE_DEV_ENABLE_SEQ: 890d5ac70f0Sopenharmony_ci case SEQUENCE_ELEMENT_TYPE_DEV_DISABLE_SEQ: 891d5ac70f0Sopenharmony_ci err = run_device_sequence(uc_mgr, verb, s->data.device, 892d5ac70f0Sopenharmony_ci s->type == SEQUENCE_ELEMENT_TYPE_DEV_ENABLE_SEQ); 893d5ac70f0Sopenharmony_ci if (err < 0) 894d5ac70f0Sopenharmony_ci goto __fail; 895d5ac70f0Sopenharmony_ci break; 896d5ac70f0Sopenharmony_ci case SEQUENCE_ELEMENT_TYPE_DEV_DISABLE_ALL: 897d5ac70f0Sopenharmony_ci err = run_device_all_sequence(uc_mgr, verb); 898d5ac70f0Sopenharmony_ci if (err < 0) 899d5ac70f0Sopenharmony_ci goto __fail; 900d5ac70f0Sopenharmony_ci break; 901d5ac70f0Sopenharmony_ci default: 902d5ac70f0Sopenharmony_ci uc_error("unknown sequence command %i", s->type); 903d5ac70f0Sopenharmony_ci break; 904d5ac70f0Sopenharmony_ci } 905d5ac70f0Sopenharmony_ci } 906d5ac70f0Sopenharmony_ci free(cdev); 907d5ac70f0Sopenharmony_ci uc_mgr->sequence_hops--; 908d5ac70f0Sopenharmony_ci return 0; 909d5ac70f0Sopenharmony_ci __fail_nomem: 910d5ac70f0Sopenharmony_ci err = -ENOMEM; 911d5ac70f0Sopenharmony_ci __fail: 912d5ac70f0Sopenharmony_ci free(cdev); 913d5ac70f0Sopenharmony_ci uc_mgr->sequence_hops--; 914d5ac70f0Sopenharmony_ci return err; 915d5ac70f0Sopenharmony_ci 916d5ac70f0Sopenharmony_ci} 917d5ac70f0Sopenharmony_ci 918d5ac70f0Sopenharmony_ci/* Execute enable or disable sequence of a component device. 919d5ac70f0Sopenharmony_ci * 920d5ac70f0Sopenharmony_ci * For a component device (a codec or embedded DSP), its sequence doesn't 921d5ac70f0Sopenharmony_ci * specify the sound card device 'cdev', because a component can be reused 922d5ac70f0Sopenharmony_ci * by different sound cards (machines). So when executing its sequence, a 923d5ac70f0Sopenharmony_ci * parameter 'cdev' is used to pass cdev defined by the sequence of its 924d5ac70f0Sopenharmony_ci * parent, the machine device. UCM manger will store the cdev when entering 925d5ac70f0Sopenharmony_ci * the component domain. 926d5ac70f0Sopenharmony_ci */ 927d5ac70f0Sopenharmony_cistatic int execute_component_seq(snd_use_case_mgr_t *uc_mgr, 928d5ac70f0Sopenharmony_ci struct component_sequence *cmpt_seq, 929d5ac70f0Sopenharmony_ci struct list_head *value_list1 ATTRIBUTE_UNUSED, 930d5ac70f0Sopenharmony_ci struct list_head *value_list2 ATTRIBUTE_UNUSED, 931d5ac70f0Sopenharmony_ci struct list_head *value_list3 ATTRIBUTE_UNUSED, 932d5ac70f0Sopenharmony_ci char *cdev) 933d5ac70f0Sopenharmony_ci{ 934d5ac70f0Sopenharmony_ci struct use_case_device *device = cmpt_seq->device; 935d5ac70f0Sopenharmony_ci struct list_head *seq; 936d5ac70f0Sopenharmony_ci int err; 937d5ac70f0Sopenharmony_ci 938d5ac70f0Sopenharmony_ci /* enter component domain and store cdev for the component */ 939d5ac70f0Sopenharmony_ci uc_mgr->in_component_domain = 1; 940d5ac70f0Sopenharmony_ci uc_mgr->cdev = cdev; 941d5ac70f0Sopenharmony_ci 942d5ac70f0Sopenharmony_ci /* choose enable or disable sequence of the component device */ 943d5ac70f0Sopenharmony_ci if (cmpt_seq->enable) 944d5ac70f0Sopenharmony_ci seq = &device->enable_list; 945d5ac70f0Sopenharmony_ci else 946d5ac70f0Sopenharmony_ci seq = &device->disable_list; 947d5ac70f0Sopenharmony_ci 948d5ac70f0Sopenharmony_ci /* excecute the sequence of the component dev */ 949d5ac70f0Sopenharmony_ci err = execute_sequence(uc_mgr, uc_mgr->active_verb, seq, 950d5ac70f0Sopenharmony_ci &device->value_list, 951d5ac70f0Sopenharmony_ci &uc_mgr->active_verb->value_list, 952d5ac70f0Sopenharmony_ci &uc_mgr->value_list); 953d5ac70f0Sopenharmony_ci 954d5ac70f0Sopenharmony_ci /* exit component domain and clear cdev */ 955d5ac70f0Sopenharmony_ci uc_mgr->in_component_domain = 0; 956d5ac70f0Sopenharmony_ci uc_mgr->cdev = NULL; 957d5ac70f0Sopenharmony_ci 958d5ac70f0Sopenharmony_ci return err; 959d5ac70f0Sopenharmony_ci} 960d5ac70f0Sopenharmony_ci 961d5ac70f0Sopenharmony_cistatic int add_auto_value(snd_use_case_mgr_t *uc_mgr, const char *key, char *value) 962d5ac70f0Sopenharmony_ci{ 963d5ac70f0Sopenharmony_ci char *s; 964d5ac70f0Sopenharmony_ci int err; 965d5ac70f0Sopenharmony_ci 966d5ac70f0Sopenharmony_ci err = get_value1(uc_mgr, &value, &uc_mgr->value_list, key); 967d5ac70f0Sopenharmony_ci if (err == -ENOENT) { 968d5ac70f0Sopenharmony_ci s = strdup(value); 969d5ac70f0Sopenharmony_ci if (s == NULL) 970d5ac70f0Sopenharmony_ci return -ENOMEM; 971d5ac70f0Sopenharmony_ci return uc_mgr_add_value(&uc_mgr->value_list, key, s); 972d5ac70f0Sopenharmony_ci } else if (err < 0) { 973d5ac70f0Sopenharmony_ci return err; 974d5ac70f0Sopenharmony_ci } 975d5ac70f0Sopenharmony_ci free(value); 976d5ac70f0Sopenharmony_ci return 0; 977d5ac70f0Sopenharmony_ci} 978d5ac70f0Sopenharmony_ci 979d5ac70f0Sopenharmony_cistatic int add_auto_values(snd_use_case_mgr_t *uc_mgr) 980d5ac70f0Sopenharmony_ci{ 981d5ac70f0Sopenharmony_ci struct ctl_list *ctl_list; 982d5ac70f0Sopenharmony_ci const char *id; 983d5ac70f0Sopenharmony_ci char buf[40]; 984d5ac70f0Sopenharmony_ci int err; 985d5ac70f0Sopenharmony_ci 986d5ac70f0Sopenharmony_ci ctl_list = uc_mgr_get_master_ctl(uc_mgr); 987d5ac70f0Sopenharmony_ci if (ctl_list) { 988d5ac70f0Sopenharmony_ci id = snd_ctl_card_info_get_id(ctl_list->ctl_info); 989d5ac70f0Sopenharmony_ci snprintf(buf, sizeof(buf), "hw:%s", id); 990d5ac70f0Sopenharmony_ci err = add_auto_value(uc_mgr, "PlaybackCTL", buf); 991d5ac70f0Sopenharmony_ci if (err < 0) 992d5ac70f0Sopenharmony_ci return err; 993d5ac70f0Sopenharmony_ci err = add_auto_value(uc_mgr, "CaptureCTL", buf); 994d5ac70f0Sopenharmony_ci if (err < 0) 995d5ac70f0Sopenharmony_ci return err; 996d5ac70f0Sopenharmony_ci } 997d5ac70f0Sopenharmony_ci return 0; 998d5ac70f0Sopenharmony_ci} 999d5ac70f0Sopenharmony_ci 1000d5ac70f0Sopenharmony_ci/** 1001d5ac70f0Sopenharmony_ci * \brief execute default commands 1002d5ac70f0Sopenharmony_ci * \param uc_mgr Use case manager 1003d5ac70f0Sopenharmony_ci * \param force Force run 1004d5ac70f0Sopenharmony_ci * \return zero on success, otherwise a negative error code 1005d5ac70f0Sopenharmony_ci */ 1006d5ac70f0Sopenharmony_cistatic int set_defaults(snd_use_case_mgr_t *uc_mgr, bool force) 1007d5ac70f0Sopenharmony_ci{ 1008d5ac70f0Sopenharmony_ci int err; 1009d5ac70f0Sopenharmony_ci 1010d5ac70f0Sopenharmony_ci if (!force && uc_mgr->default_list_executed) 1011d5ac70f0Sopenharmony_ci return 0; 1012d5ac70f0Sopenharmony_ci err = execute_sequence(uc_mgr, NULL, &uc_mgr->default_list, 1013d5ac70f0Sopenharmony_ci &uc_mgr->value_list, NULL, NULL); 1014d5ac70f0Sopenharmony_ci if (err < 0) { 1015d5ac70f0Sopenharmony_ci uc_error("Unable to execute default sequence"); 1016d5ac70f0Sopenharmony_ci return err; 1017d5ac70f0Sopenharmony_ci } 1018d5ac70f0Sopenharmony_ci uc_mgr->default_list_executed = 1; 1019d5ac70f0Sopenharmony_ci return 0; 1020d5ac70f0Sopenharmony_ci} 1021d5ac70f0Sopenharmony_ci 1022d5ac70f0Sopenharmony_ci/** 1023d5ac70f0Sopenharmony_ci * \brief Import master config and execute the default sequence 1024d5ac70f0Sopenharmony_ci * \param uc_mgr Use case manager 1025d5ac70f0Sopenharmony_ci * \return zero on success, otherwise a negative error code 1026d5ac70f0Sopenharmony_ci */ 1027d5ac70f0Sopenharmony_cistatic int import_master_config(snd_use_case_mgr_t *uc_mgr) 1028d5ac70f0Sopenharmony_ci{ 1029d5ac70f0Sopenharmony_ci int err; 1030d5ac70f0Sopenharmony_ci 1031d5ac70f0Sopenharmony_ci err = uc_mgr_import_master_config(uc_mgr); 1032d5ac70f0Sopenharmony_ci if (err < 0) 1033d5ac70f0Sopenharmony_ci return err; 1034d5ac70f0Sopenharmony_ci return add_auto_values(uc_mgr); 1035d5ac70f0Sopenharmony_ci} 1036d5ac70f0Sopenharmony_ci 1037d5ac70f0Sopenharmony_ci/** 1038d5ac70f0Sopenharmony_ci * \brief Check, if the UCM configuration is empty 1039d5ac70f0Sopenharmony_ci * \param uc_mgr Use case Manager 1040d5ac70f0Sopenharmony_ci * \return zero on success, otherwise a negative error code 1041d5ac70f0Sopenharmony_ci */ 1042d5ac70f0Sopenharmony_cistatic int check_empty_configuration(snd_use_case_mgr_t *uc_mgr) 1043d5ac70f0Sopenharmony_ci{ 1044d5ac70f0Sopenharmony_ci int err; 1045d5ac70f0Sopenharmony_ci char *value; 1046d5ac70f0Sopenharmony_ci 1047d5ac70f0Sopenharmony_ci err = get_value(uc_mgr, "Linked", &value, NULL, NULL, 1); 1048d5ac70f0Sopenharmony_ci if (err >= 0) { 1049d5ac70f0Sopenharmony_ci err = strcasecmp(value, "true") == 0 || 1050d5ac70f0Sopenharmony_ci strcmp(value, "1") == 0; 1051d5ac70f0Sopenharmony_ci free(value); 1052d5ac70f0Sopenharmony_ci if (err) 1053d5ac70f0Sopenharmony_ci return 0; 1054d5ac70f0Sopenharmony_ci } 1055d5ac70f0Sopenharmony_ci if (!list_empty(&uc_mgr->verb_list)) 1056d5ac70f0Sopenharmony_ci return 0; 1057d5ac70f0Sopenharmony_ci if (!list_empty(&uc_mgr->fixedboot_list)) 1058d5ac70f0Sopenharmony_ci return 0; 1059d5ac70f0Sopenharmony_ci if (!list_empty(&uc_mgr->boot_list)) 1060d5ac70f0Sopenharmony_ci return 0; 1061d5ac70f0Sopenharmony_ci return -ENXIO; 1062d5ac70f0Sopenharmony_ci} 1063d5ac70f0Sopenharmony_ci 1064d5ac70f0Sopenharmony_ci/** 1065d5ac70f0Sopenharmony_ci * \brief Universal find - string in a list 1066d5ac70f0Sopenharmony_ci * \param list List of structures 1067d5ac70f0Sopenharmony_ci * \param offset Offset of list structure 1068d5ac70f0Sopenharmony_ci * \param soffset Offset of string structure 1069d5ac70f0Sopenharmony_ci * \param match String to match 1070d5ac70f0Sopenharmony_ci * \return structure on success, otherwise a NULL (not found) 1071d5ac70f0Sopenharmony_ci */ 1072d5ac70f0Sopenharmony_cistatic void *find0(struct list_head *list, 1073d5ac70f0Sopenharmony_ci unsigned long offset, 1074d5ac70f0Sopenharmony_ci unsigned long soffset, 1075d5ac70f0Sopenharmony_ci const char *match) 1076d5ac70f0Sopenharmony_ci{ 1077d5ac70f0Sopenharmony_ci struct list_head *pos; 1078d5ac70f0Sopenharmony_ci char *ptr, *str; 1079d5ac70f0Sopenharmony_ci 1080d5ac70f0Sopenharmony_ci list_for_each(pos, list) { 1081d5ac70f0Sopenharmony_ci ptr = list_entry_offset(pos, char, offset); 1082d5ac70f0Sopenharmony_ci str = *((char **)(ptr + soffset)); 1083d5ac70f0Sopenharmony_ci if (strcmp(str, match) == 0) 1084d5ac70f0Sopenharmony_ci return ptr; 1085d5ac70f0Sopenharmony_ci } 1086d5ac70f0Sopenharmony_ci return NULL; 1087d5ac70f0Sopenharmony_ci} 1088d5ac70f0Sopenharmony_ci 1089d5ac70f0Sopenharmony_ci#define find(list, type, member, value, match) \ 1090d5ac70f0Sopenharmony_ci find0(list, (unsigned long)(&((type *)0)->member), \ 1091d5ac70f0Sopenharmony_ci (unsigned long)(&((type *)0)->value), match) 1092d5ac70f0Sopenharmony_ci 1093d5ac70f0Sopenharmony_ci/** 1094d5ac70f0Sopenharmony_ci * \brief Universal string list 1095d5ac70f0Sopenharmony_ci * \param list List of structures 1096d5ac70f0Sopenharmony_ci * \param result Result list 1097d5ac70f0Sopenharmony_ci * \param offset Offset of list structure 1098d5ac70f0Sopenharmony_ci * \param s1offset Offset of string structure 1099d5ac70f0Sopenharmony_ci * \return count of items on success, otherwise a negative error code 1100d5ac70f0Sopenharmony_ci */ 1101d5ac70f0Sopenharmony_cistatic int get_list0(struct list_head *list, 1102d5ac70f0Sopenharmony_ci const char **result[], 1103d5ac70f0Sopenharmony_ci unsigned long offset, 1104d5ac70f0Sopenharmony_ci unsigned long s1offset) 1105d5ac70f0Sopenharmony_ci{ 1106d5ac70f0Sopenharmony_ci char **res; 1107d5ac70f0Sopenharmony_ci int cnt; 1108d5ac70f0Sopenharmony_ci struct list_head *pos; 1109d5ac70f0Sopenharmony_ci char *ptr, *str1; 1110d5ac70f0Sopenharmony_ci 1111d5ac70f0Sopenharmony_ci cnt = alloc_str_list(list, 1, &res); 1112d5ac70f0Sopenharmony_ci if (cnt <= 0) { 1113d5ac70f0Sopenharmony_ci *result = NULL; 1114d5ac70f0Sopenharmony_ci return cnt; 1115d5ac70f0Sopenharmony_ci } 1116d5ac70f0Sopenharmony_ci *result = (const char **)res; 1117d5ac70f0Sopenharmony_ci list_for_each(pos, list) { 1118d5ac70f0Sopenharmony_ci ptr = list_entry_offset(pos, char, offset); 1119d5ac70f0Sopenharmony_ci str1 = *((char **)(ptr + s1offset)); 1120d5ac70f0Sopenharmony_ci if (str1 != NULL) { 1121d5ac70f0Sopenharmony_ci *res = strdup(str1); 1122d5ac70f0Sopenharmony_ci if (*res == NULL) 1123d5ac70f0Sopenharmony_ci goto __fail; 1124d5ac70f0Sopenharmony_ci } else { 1125d5ac70f0Sopenharmony_ci *res = NULL; 1126d5ac70f0Sopenharmony_ci } 1127d5ac70f0Sopenharmony_ci res++; 1128d5ac70f0Sopenharmony_ci } 1129d5ac70f0Sopenharmony_ci return cnt; 1130d5ac70f0Sopenharmony_ci __fail: 1131d5ac70f0Sopenharmony_ci snd_use_case_free_list(*result, cnt); 1132d5ac70f0Sopenharmony_ci return -ENOMEM; 1133d5ac70f0Sopenharmony_ci} 1134d5ac70f0Sopenharmony_ci 1135d5ac70f0Sopenharmony_ci#define get_list(list, result, type, member, s1) \ 1136d5ac70f0Sopenharmony_ci get_list0(list, result, \ 1137d5ac70f0Sopenharmony_ci (unsigned long)(&((type *)0)->member), \ 1138d5ac70f0Sopenharmony_ci (unsigned long)(&((type *)0)->s1)) 1139d5ac70f0Sopenharmony_ci 1140d5ac70f0Sopenharmony_ci/** 1141d5ac70f0Sopenharmony_ci * \brief Universal string list - pair of strings 1142d5ac70f0Sopenharmony_ci * \param list List of structures 1143d5ac70f0Sopenharmony_ci * \param result Result list 1144d5ac70f0Sopenharmony_ci * \param offset Offset of list structure 1145d5ac70f0Sopenharmony_ci * \param s1offset Offset of string structure 1146d5ac70f0Sopenharmony_ci * \param s1offset Offset of string structure 1147d5ac70f0Sopenharmony_ci * \return count of items on success, otherwise a negative error code 1148d5ac70f0Sopenharmony_ci */ 1149d5ac70f0Sopenharmony_cistatic int get_list20(struct list_head *list, 1150d5ac70f0Sopenharmony_ci const char **result[], 1151d5ac70f0Sopenharmony_ci unsigned long offset, 1152d5ac70f0Sopenharmony_ci unsigned long s1offset, 1153d5ac70f0Sopenharmony_ci unsigned long s2offset) 1154d5ac70f0Sopenharmony_ci{ 1155d5ac70f0Sopenharmony_ci char **res; 1156d5ac70f0Sopenharmony_ci int cnt; 1157d5ac70f0Sopenharmony_ci struct list_head *pos; 1158d5ac70f0Sopenharmony_ci char *ptr, *str1, *str2; 1159d5ac70f0Sopenharmony_ci 1160d5ac70f0Sopenharmony_ci cnt = alloc_str_list(list, 2, &res); 1161d5ac70f0Sopenharmony_ci if (cnt <= 0) { 1162d5ac70f0Sopenharmony_ci *result = NULL; 1163d5ac70f0Sopenharmony_ci return cnt; 1164d5ac70f0Sopenharmony_ci } 1165d5ac70f0Sopenharmony_ci *result = (const char **)res; 1166d5ac70f0Sopenharmony_ci list_for_each(pos, list) { 1167d5ac70f0Sopenharmony_ci ptr = list_entry_offset(pos, char, offset); 1168d5ac70f0Sopenharmony_ci str1 = *((char **)(ptr + s1offset)); 1169d5ac70f0Sopenharmony_ci if (str1 != NULL) { 1170d5ac70f0Sopenharmony_ci *res = strdup(str1); 1171d5ac70f0Sopenharmony_ci if (*res == NULL) 1172d5ac70f0Sopenharmony_ci goto __fail; 1173d5ac70f0Sopenharmony_ci } else { 1174d5ac70f0Sopenharmony_ci *res = NULL; 1175d5ac70f0Sopenharmony_ci } 1176d5ac70f0Sopenharmony_ci res++; 1177d5ac70f0Sopenharmony_ci str2 = *((char **)(ptr + s2offset)); 1178d5ac70f0Sopenharmony_ci if (str2 != NULL) { 1179d5ac70f0Sopenharmony_ci *res = strdup(str2); 1180d5ac70f0Sopenharmony_ci if (*res == NULL) 1181d5ac70f0Sopenharmony_ci goto __fail; 1182d5ac70f0Sopenharmony_ci } else { 1183d5ac70f0Sopenharmony_ci *res = NULL; 1184d5ac70f0Sopenharmony_ci } 1185d5ac70f0Sopenharmony_ci res++; 1186d5ac70f0Sopenharmony_ci } 1187d5ac70f0Sopenharmony_ci return cnt; 1188d5ac70f0Sopenharmony_ci __fail: 1189d5ac70f0Sopenharmony_ci snd_use_case_free_list(*result, cnt); 1190d5ac70f0Sopenharmony_ci return -ENOMEM; 1191d5ac70f0Sopenharmony_ci} 1192d5ac70f0Sopenharmony_ci 1193d5ac70f0Sopenharmony_ci#define get_list2(list, result, type, member, s1, s2) \ 1194d5ac70f0Sopenharmony_ci get_list20(list, result, \ 1195d5ac70f0Sopenharmony_ci (unsigned long)(&((type *)0)->member), \ 1196d5ac70f0Sopenharmony_ci (unsigned long)(&((type *)0)->s1), \ 1197d5ac70f0Sopenharmony_ci (unsigned long)(&((type *)0)->s2)) 1198d5ac70f0Sopenharmony_ci 1199d5ac70f0Sopenharmony_ci/** 1200d5ac70f0Sopenharmony_ci * \brief Find verb 1201d5ac70f0Sopenharmony_ci * \param uc_mgr Use case manager 1202d5ac70f0Sopenharmony_ci * \param verb_name verb to find 1203d5ac70f0Sopenharmony_ci * \return structure on success, otherwise a NULL (not found) 1204d5ac70f0Sopenharmony_ci */ 1205d5ac70f0Sopenharmony_cistatic inline struct use_case_verb *find_verb(snd_use_case_mgr_t *uc_mgr, 1206d5ac70f0Sopenharmony_ci const char *verb_name) 1207d5ac70f0Sopenharmony_ci{ 1208d5ac70f0Sopenharmony_ci return find(&uc_mgr->verb_list, 1209d5ac70f0Sopenharmony_ci struct use_case_verb, list, name, 1210d5ac70f0Sopenharmony_ci verb_name); 1211d5ac70f0Sopenharmony_ci} 1212d5ac70f0Sopenharmony_ci 1213d5ac70f0Sopenharmony_cistatic int is_devlist_supported(snd_use_case_mgr_t *uc_mgr, 1214d5ac70f0Sopenharmony_ci struct dev_list *dev_list) 1215d5ac70f0Sopenharmony_ci{ 1216d5ac70f0Sopenharmony_ci struct dev_list_node *device; 1217d5ac70f0Sopenharmony_ci struct use_case_device *adev; 1218d5ac70f0Sopenharmony_ci struct list_head *pos, *pos1; 1219d5ac70f0Sopenharmony_ci int found_ret; 1220d5ac70f0Sopenharmony_ci 1221d5ac70f0Sopenharmony_ci switch (dev_list->type) { 1222d5ac70f0Sopenharmony_ci case DEVLIST_NONE: 1223d5ac70f0Sopenharmony_ci default: 1224d5ac70f0Sopenharmony_ci return 1; 1225d5ac70f0Sopenharmony_ci case DEVLIST_SUPPORTED: 1226d5ac70f0Sopenharmony_ci found_ret = 1; 1227d5ac70f0Sopenharmony_ci break; 1228d5ac70f0Sopenharmony_ci case DEVLIST_CONFLICTING: 1229d5ac70f0Sopenharmony_ci found_ret = 0; 1230d5ac70f0Sopenharmony_ci break; 1231d5ac70f0Sopenharmony_ci } 1232d5ac70f0Sopenharmony_ci 1233d5ac70f0Sopenharmony_ci list_for_each(pos, &dev_list->list) { 1234d5ac70f0Sopenharmony_ci device = list_entry(pos, struct dev_list_node, list); 1235d5ac70f0Sopenharmony_ci 1236d5ac70f0Sopenharmony_ci list_for_each(pos1, &uc_mgr->active_devices) { 1237d5ac70f0Sopenharmony_ci adev = list_entry(pos1, struct use_case_device, 1238d5ac70f0Sopenharmony_ci active_list); 1239d5ac70f0Sopenharmony_ci if (!strcmp(device->name, adev->name)) 1240d5ac70f0Sopenharmony_ci return found_ret; 1241d5ac70f0Sopenharmony_ci } 1242d5ac70f0Sopenharmony_ci } 1243d5ac70f0Sopenharmony_ci return 1 - found_ret; 1244d5ac70f0Sopenharmony_ci} 1245d5ac70f0Sopenharmony_ci 1246d5ac70f0Sopenharmony_cistatic inline int is_modifier_supported(snd_use_case_mgr_t *uc_mgr, 1247d5ac70f0Sopenharmony_ci struct use_case_modifier *modifier) 1248d5ac70f0Sopenharmony_ci{ 1249d5ac70f0Sopenharmony_ci return is_devlist_supported(uc_mgr, &modifier->dev_list); 1250d5ac70f0Sopenharmony_ci} 1251d5ac70f0Sopenharmony_ci 1252d5ac70f0Sopenharmony_cistatic inline int is_device_supported(snd_use_case_mgr_t *uc_mgr, 1253d5ac70f0Sopenharmony_ci struct use_case_device *device) 1254d5ac70f0Sopenharmony_ci{ 1255d5ac70f0Sopenharmony_ci return is_devlist_supported(uc_mgr, &device->dev_list); 1256d5ac70f0Sopenharmony_ci} 1257d5ac70f0Sopenharmony_ci 1258d5ac70f0Sopenharmony_ci/** 1259d5ac70f0Sopenharmony_ci * \brief Find device 1260d5ac70f0Sopenharmony_ci * \param verb Use case verb 1261d5ac70f0Sopenharmony_ci * \param device_name device to find 1262d5ac70f0Sopenharmony_ci * \return structure on success, otherwise a NULL (not found) 1263d5ac70f0Sopenharmony_ci */ 1264d5ac70f0Sopenharmony_cistatic inline struct use_case_device * 1265d5ac70f0Sopenharmony_ci find_device(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb, 1266d5ac70f0Sopenharmony_ci const char *device_name, int check_supported) 1267d5ac70f0Sopenharmony_ci{ 1268d5ac70f0Sopenharmony_ci struct use_case_device *device; 1269d5ac70f0Sopenharmony_ci struct list_head *pos; 1270d5ac70f0Sopenharmony_ci 1271d5ac70f0Sopenharmony_ci list_for_each(pos, &verb->device_list) { 1272d5ac70f0Sopenharmony_ci device = list_entry(pos, struct use_case_device, list); 1273d5ac70f0Sopenharmony_ci 1274d5ac70f0Sopenharmony_ci if (strcmp(device_name, device->name)) 1275d5ac70f0Sopenharmony_ci continue; 1276d5ac70f0Sopenharmony_ci 1277d5ac70f0Sopenharmony_ci if (check_supported && 1278d5ac70f0Sopenharmony_ci !is_device_supported(uc_mgr, device)) 1279d5ac70f0Sopenharmony_ci continue; 1280d5ac70f0Sopenharmony_ci 1281d5ac70f0Sopenharmony_ci return device; 1282d5ac70f0Sopenharmony_ci } 1283d5ac70f0Sopenharmony_ci return NULL; 1284d5ac70f0Sopenharmony_ci} 1285d5ac70f0Sopenharmony_ci 1286d5ac70f0Sopenharmony_ci/** 1287d5ac70f0Sopenharmony_ci * \brief Find modifier 1288d5ac70f0Sopenharmony_ci * \param verb Use case verb 1289d5ac70f0Sopenharmony_ci * \param modifier_name modifier to find 1290d5ac70f0Sopenharmony_ci * \return structure on success, otherwise a NULL (not found) 1291d5ac70f0Sopenharmony_ci */ 1292d5ac70f0Sopenharmony_cistatic struct use_case_modifier * 1293d5ac70f0Sopenharmony_ci find_modifier(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb, 1294d5ac70f0Sopenharmony_ci const char *modifier_name, int check_supported) 1295d5ac70f0Sopenharmony_ci{ 1296d5ac70f0Sopenharmony_ci struct use_case_modifier *modifier; 1297d5ac70f0Sopenharmony_ci struct list_head *pos; 1298d5ac70f0Sopenharmony_ci 1299d5ac70f0Sopenharmony_ci list_for_each(pos, &verb->modifier_list) { 1300d5ac70f0Sopenharmony_ci modifier = list_entry(pos, struct use_case_modifier, list); 1301d5ac70f0Sopenharmony_ci 1302d5ac70f0Sopenharmony_ci if (strcmp(modifier->name, modifier_name)) 1303d5ac70f0Sopenharmony_ci continue; 1304d5ac70f0Sopenharmony_ci 1305d5ac70f0Sopenharmony_ci if (check_supported && 1306d5ac70f0Sopenharmony_ci !is_modifier_supported(uc_mgr, modifier)) 1307d5ac70f0Sopenharmony_ci continue; 1308d5ac70f0Sopenharmony_ci 1309d5ac70f0Sopenharmony_ci return modifier; 1310d5ac70f0Sopenharmony_ci } 1311d5ac70f0Sopenharmony_ci return NULL; 1312d5ac70f0Sopenharmony_ci} 1313d5ac70f0Sopenharmony_ci 1314d5ac70f0Sopenharmony_cilong device_status(snd_use_case_mgr_t *uc_mgr, 1315d5ac70f0Sopenharmony_ci const char *device_name) 1316d5ac70f0Sopenharmony_ci{ 1317d5ac70f0Sopenharmony_ci struct use_case_device *dev; 1318d5ac70f0Sopenharmony_ci struct list_head *pos; 1319d5ac70f0Sopenharmony_ci 1320d5ac70f0Sopenharmony_ci list_for_each(pos, &uc_mgr->active_devices) { 1321d5ac70f0Sopenharmony_ci dev = list_entry(pos, struct use_case_device, active_list); 1322d5ac70f0Sopenharmony_ci if (strcmp(dev->name, device_name) == 0) 1323d5ac70f0Sopenharmony_ci return 1; 1324d5ac70f0Sopenharmony_ci } 1325d5ac70f0Sopenharmony_ci return 0; 1326d5ac70f0Sopenharmony_ci} 1327d5ac70f0Sopenharmony_ci 1328d5ac70f0Sopenharmony_cilong modifier_status(snd_use_case_mgr_t *uc_mgr, 1329d5ac70f0Sopenharmony_ci const char *modifier_name) 1330d5ac70f0Sopenharmony_ci{ 1331d5ac70f0Sopenharmony_ci struct use_case_modifier *mod; 1332d5ac70f0Sopenharmony_ci struct list_head *pos; 1333d5ac70f0Sopenharmony_ci 1334d5ac70f0Sopenharmony_ci list_for_each(pos, &uc_mgr->active_modifiers) { 1335d5ac70f0Sopenharmony_ci mod = list_entry(pos, struct use_case_modifier, active_list); 1336d5ac70f0Sopenharmony_ci if (strcmp(mod->name, modifier_name) == 0) 1337d5ac70f0Sopenharmony_ci return 1; 1338d5ac70f0Sopenharmony_ci } 1339d5ac70f0Sopenharmony_ci return 0; 1340d5ac70f0Sopenharmony_ci} 1341d5ac70f0Sopenharmony_ci 1342d5ac70f0Sopenharmony_ci/** 1343d5ac70f0Sopenharmony_ci * \brief Set verb 1344d5ac70f0Sopenharmony_ci * \param uc_mgr Use case manager 1345d5ac70f0Sopenharmony_ci * \param verb verb to set 1346d5ac70f0Sopenharmony_ci * \param enable nonzero = enable, zero = disable 1347d5ac70f0Sopenharmony_ci * \return zero on success, otherwise a negative error code 1348d5ac70f0Sopenharmony_ci */ 1349d5ac70f0Sopenharmony_cistatic int set_verb(snd_use_case_mgr_t *uc_mgr, 1350d5ac70f0Sopenharmony_ci struct use_case_verb *verb, 1351d5ac70f0Sopenharmony_ci int enable) 1352d5ac70f0Sopenharmony_ci{ 1353d5ac70f0Sopenharmony_ci struct list_head *seq; 1354d5ac70f0Sopenharmony_ci int err; 1355d5ac70f0Sopenharmony_ci 1356d5ac70f0Sopenharmony_ci if (enable) { 1357d5ac70f0Sopenharmony_ci err = set_defaults(uc_mgr, false); 1358d5ac70f0Sopenharmony_ci if (err < 0) 1359d5ac70f0Sopenharmony_ci return err; 1360d5ac70f0Sopenharmony_ci seq = &verb->enable_list; 1361d5ac70f0Sopenharmony_ci } else { 1362d5ac70f0Sopenharmony_ci seq = &verb->disable_list; 1363d5ac70f0Sopenharmony_ci } 1364d5ac70f0Sopenharmony_ci err = execute_sequence(uc_mgr, verb, seq, 1365d5ac70f0Sopenharmony_ci &verb->value_list, 1366d5ac70f0Sopenharmony_ci &uc_mgr->value_list, 1367d5ac70f0Sopenharmony_ci NULL); 1368d5ac70f0Sopenharmony_ci if (enable && err >= 0) 1369d5ac70f0Sopenharmony_ci uc_mgr->active_verb = verb; 1370d5ac70f0Sopenharmony_ci return err; 1371d5ac70f0Sopenharmony_ci} 1372d5ac70f0Sopenharmony_ci 1373d5ac70f0Sopenharmony_ci/** 1374d5ac70f0Sopenharmony_ci * \brief Set modifier 1375d5ac70f0Sopenharmony_ci * \param uc_mgr Use case manager 1376d5ac70f0Sopenharmony_ci * \param modifier modifier to set 1377d5ac70f0Sopenharmony_ci * \param enable nonzero = enable, zero = disable 1378d5ac70f0Sopenharmony_ci * \return zero on success, otherwise a negative error code 1379d5ac70f0Sopenharmony_ci */ 1380d5ac70f0Sopenharmony_cistatic int set_modifier(snd_use_case_mgr_t *uc_mgr, 1381d5ac70f0Sopenharmony_ci struct use_case_modifier *modifier, 1382d5ac70f0Sopenharmony_ci int enable) 1383d5ac70f0Sopenharmony_ci{ 1384d5ac70f0Sopenharmony_ci struct list_head *seq; 1385d5ac70f0Sopenharmony_ci int err; 1386d5ac70f0Sopenharmony_ci 1387d5ac70f0Sopenharmony_ci if (modifier_status(uc_mgr, modifier->name) == enable) 1388d5ac70f0Sopenharmony_ci return 0; 1389d5ac70f0Sopenharmony_ci 1390d5ac70f0Sopenharmony_ci if (enable) { 1391d5ac70f0Sopenharmony_ci seq = &modifier->enable_list; 1392d5ac70f0Sopenharmony_ci } else { 1393d5ac70f0Sopenharmony_ci seq = &modifier->disable_list; 1394d5ac70f0Sopenharmony_ci } 1395d5ac70f0Sopenharmony_ci err = execute_sequence(uc_mgr, uc_mgr->active_verb, seq, 1396d5ac70f0Sopenharmony_ci &modifier->value_list, 1397d5ac70f0Sopenharmony_ci &uc_mgr->active_verb->value_list, 1398d5ac70f0Sopenharmony_ci &uc_mgr->value_list); 1399d5ac70f0Sopenharmony_ci if (enable && err >= 0) { 1400d5ac70f0Sopenharmony_ci list_add_tail(&modifier->active_list, &uc_mgr->active_modifiers); 1401d5ac70f0Sopenharmony_ci } else if (!enable) { 1402d5ac70f0Sopenharmony_ci list_del(&modifier->active_list); 1403d5ac70f0Sopenharmony_ci } 1404d5ac70f0Sopenharmony_ci return err; 1405d5ac70f0Sopenharmony_ci} 1406d5ac70f0Sopenharmony_ci 1407d5ac70f0Sopenharmony_ci/** 1408d5ac70f0Sopenharmony_ci * \brief Set device 1409d5ac70f0Sopenharmony_ci * \param uc_mgr Use case manager 1410d5ac70f0Sopenharmony_ci * \param device device to set 1411d5ac70f0Sopenharmony_ci * \param enable nonzero = enable, zero = disable 1412d5ac70f0Sopenharmony_ci * \return zero on success, otherwise a negative error code 1413d5ac70f0Sopenharmony_ci */ 1414d5ac70f0Sopenharmony_cistatic int set_device(snd_use_case_mgr_t *uc_mgr, 1415d5ac70f0Sopenharmony_ci struct use_case_device *device, 1416d5ac70f0Sopenharmony_ci int enable) 1417d5ac70f0Sopenharmony_ci{ 1418d5ac70f0Sopenharmony_ci struct list_head *seq; 1419d5ac70f0Sopenharmony_ci int err; 1420d5ac70f0Sopenharmony_ci 1421d5ac70f0Sopenharmony_ci if (device_status(uc_mgr, device->name) == enable) 1422d5ac70f0Sopenharmony_ci return 0; 1423d5ac70f0Sopenharmony_ci 1424d5ac70f0Sopenharmony_ci if (enable) { 1425d5ac70f0Sopenharmony_ci seq = &device->enable_list; 1426d5ac70f0Sopenharmony_ci } else { 1427d5ac70f0Sopenharmony_ci seq = &device->disable_list; 1428d5ac70f0Sopenharmony_ci } 1429d5ac70f0Sopenharmony_ci err = execute_sequence(uc_mgr, uc_mgr->active_verb, seq, 1430d5ac70f0Sopenharmony_ci &device->value_list, 1431d5ac70f0Sopenharmony_ci &uc_mgr->active_verb->value_list, 1432d5ac70f0Sopenharmony_ci &uc_mgr->value_list); 1433d5ac70f0Sopenharmony_ci if (enable && err >= 0) { 1434d5ac70f0Sopenharmony_ci list_add_tail(&device->active_list, &uc_mgr->active_devices); 1435d5ac70f0Sopenharmony_ci } else if (!enable) { 1436d5ac70f0Sopenharmony_ci list_del(&device->active_list); 1437d5ac70f0Sopenharmony_ci } 1438d5ac70f0Sopenharmony_ci return err; 1439d5ac70f0Sopenharmony_ci} 1440d5ac70f0Sopenharmony_ci 1441d5ac70f0Sopenharmony_ci/** 1442d5ac70f0Sopenharmony_ci * \brief Do the full reset 1443d5ac70f0Sopenharmony_ci * \param uc_mgr Use case manager 1444d5ac70f0Sopenharmony_ci * \return zero on success, otherwise a negative error code 1445d5ac70f0Sopenharmony_ci */ 1446d5ac70f0Sopenharmony_cistatic int do_reset(snd_use_case_mgr_t *uc_mgr) 1447d5ac70f0Sopenharmony_ci{ 1448d5ac70f0Sopenharmony_ci int err; 1449d5ac70f0Sopenharmony_ci 1450d5ac70f0Sopenharmony_ci err = set_defaults(uc_mgr, true); 1451d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&uc_mgr->active_modifiers); 1452d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&uc_mgr->active_devices); 1453d5ac70f0Sopenharmony_ci uc_mgr->active_verb = NULL; 1454d5ac70f0Sopenharmony_ci return err; 1455d5ac70f0Sopenharmony_ci} 1456d5ac70f0Sopenharmony_ci 1457d5ac70f0Sopenharmony_ci/** 1458d5ac70f0Sopenharmony_ci * \brief Parse open arguments 1459d5ac70f0Sopenharmony_ci * \param uc_mgr Use case manager 1460d5ac70f0Sopenharmony_ci * \param name name of card to open 1461d5ac70f0Sopenharmony_ci * \return the rest of the card name to open 1462d5ac70f0Sopenharmony_ci */ 1463d5ac70f0Sopenharmony_ciconst char *parse_open_variables(snd_use_case_mgr_t *uc_mgr, const char *name) 1464d5ac70f0Sopenharmony_ci{ 1465d5ac70f0Sopenharmony_ci const char *end, *id; 1466d5ac70f0Sopenharmony_ci char *args, *var; 1467d5ac70f0Sopenharmony_ci snd_config_t *cfg, *n; 1468d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1469d5ac70f0Sopenharmony_ci char vname[128]; 1470d5ac70f0Sopenharmony_ci size_t l; 1471d5ac70f0Sopenharmony_ci int err; 1472d5ac70f0Sopenharmony_ci 1473d5ac70f0Sopenharmony_ci end = strstr(name, ">>>"); 1474d5ac70f0Sopenharmony_ci if (end == NULL) 1475d5ac70f0Sopenharmony_ci return name; 1476d5ac70f0Sopenharmony_ci l = end - name - 3; 1477d5ac70f0Sopenharmony_ci args = alloca(l + 1); 1478d5ac70f0Sopenharmony_ci strncpy(args, name + 3, l); 1479d5ac70f0Sopenharmony_ci args[l] = '\0'; 1480d5ac70f0Sopenharmony_ci 1481d5ac70f0Sopenharmony_ci err = snd_config_load_string(&cfg, args, 0); 1482d5ac70f0Sopenharmony_ci if (err < 0) { 1483d5ac70f0Sopenharmony_ci uc_error("error: open arguments are not valid (%s)", args); 1484d5ac70f0Sopenharmony_ci goto skip; 1485d5ac70f0Sopenharmony_ci } 1486d5ac70f0Sopenharmony_ci 1487d5ac70f0Sopenharmony_ci /* set arguments */ 1488d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 1489d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 1490d5ac70f0Sopenharmony_ci err = snd_config_get_id(n, &id); 1491d5ac70f0Sopenharmony_ci if (err < 0) 1492d5ac70f0Sopenharmony_ci goto skip; 1493d5ac70f0Sopenharmony_ci err = snd_config_get_ascii(n, &var); 1494d5ac70f0Sopenharmony_ci if (err < 0) 1495d5ac70f0Sopenharmony_ci goto skip; 1496d5ac70f0Sopenharmony_ci snprintf(vname, sizeof(vname), "@%s", id); 1497d5ac70f0Sopenharmony_ci err = uc_mgr_set_variable(uc_mgr, vname, var); 1498d5ac70f0Sopenharmony_ci free(var); 1499d5ac70f0Sopenharmony_ci if (err < 0) 1500d5ac70f0Sopenharmony_ci goto skip; 1501d5ac70f0Sopenharmony_ci } 1502d5ac70f0Sopenharmony_ci 1503d5ac70f0Sopenharmony_ciskip: 1504d5ac70f0Sopenharmony_ci snd_config_delete(cfg); 1505d5ac70f0Sopenharmony_ci return end + 3; 1506d5ac70f0Sopenharmony_ci} 1507d5ac70f0Sopenharmony_ci 1508d5ac70f0Sopenharmony_ciint snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr, 1509d5ac70f0Sopenharmony_ci const char *card_name) 1510d5ac70f0Sopenharmony_ci{ 1511d5ac70f0Sopenharmony_ci snd_use_case_mgr_t *mgr; 1512d5ac70f0Sopenharmony_ci int err; 1513d5ac70f0Sopenharmony_ci 1514d5ac70f0Sopenharmony_ci /* create a new UCM */ 1515d5ac70f0Sopenharmony_ci mgr = calloc(1, sizeof(snd_use_case_mgr_t)); 1516d5ac70f0Sopenharmony_ci if (mgr == NULL) 1517d5ac70f0Sopenharmony_ci return -ENOMEM; 1518d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&mgr->verb_list); 1519d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&mgr->fixedboot_list); 1520d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&mgr->boot_list); 1521d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&mgr->default_list); 1522d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&mgr->value_list); 1523d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&mgr->active_modifiers); 1524d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&mgr->active_devices); 1525d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&mgr->ctl_list); 1526d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&mgr->variable_list); 1527d5ac70f0Sopenharmony_ci pthread_mutex_init(&mgr->mutex, NULL); 1528d5ac70f0Sopenharmony_ci 1529d5ac70f0Sopenharmony_ci if (card_name && *card_name == '-') { 1530d5ac70f0Sopenharmony_ci card_name++; 1531d5ac70f0Sopenharmony_ci mgr->suppress_nodev_errors = 1; 1532d5ac70f0Sopenharmony_ci } 1533d5ac70f0Sopenharmony_ci 1534d5ac70f0Sopenharmony_ci if (card_name && card_name[0] == '<' && card_name[1] == '<' && card_name[2] == '<') 1535d5ac70f0Sopenharmony_ci card_name = parse_open_variables(mgr, card_name); 1536d5ac70f0Sopenharmony_ci 1537d5ac70f0Sopenharmony_ci err = uc_mgr_card_open(mgr); 1538d5ac70f0Sopenharmony_ci if (err < 0) { 1539d5ac70f0Sopenharmony_ci uc_mgr_free(mgr); 1540d5ac70f0Sopenharmony_ci return err; 1541d5ac70f0Sopenharmony_ci } 1542d5ac70f0Sopenharmony_ci 1543d5ac70f0Sopenharmony_ci mgr->card_name = strdup(card_name); 1544d5ac70f0Sopenharmony_ci if (mgr->card_name == NULL) { 1545d5ac70f0Sopenharmony_ci err = -ENOMEM; 1546d5ac70f0Sopenharmony_ci goto _err; 1547d5ac70f0Sopenharmony_ci } 1548d5ac70f0Sopenharmony_ci 1549d5ac70f0Sopenharmony_ci /* get info on use_cases and verify against card */ 1550d5ac70f0Sopenharmony_ci err = import_master_config(mgr); 1551d5ac70f0Sopenharmony_ci if (err < 0) { 1552d5ac70f0Sopenharmony_ci if (err == -ENXIO && mgr->suppress_nodev_errors) 1553d5ac70f0Sopenharmony_ci goto _err; 1554d5ac70f0Sopenharmony_ci uc_error("error: failed to import %s use case configuration %d", 1555d5ac70f0Sopenharmony_ci card_name, err); 1556d5ac70f0Sopenharmony_ci goto _err; 1557d5ac70f0Sopenharmony_ci } 1558d5ac70f0Sopenharmony_ci 1559d5ac70f0Sopenharmony_ci err = check_empty_configuration(mgr); 1560d5ac70f0Sopenharmony_ci if (err < 0) { 1561d5ac70f0Sopenharmony_ci uc_error("error: failed to import %s (empty configuration)", card_name); 1562d5ac70f0Sopenharmony_ci goto _err; 1563d5ac70f0Sopenharmony_ci } 1564d5ac70f0Sopenharmony_ci 1565d5ac70f0Sopenharmony_ci *uc_mgr = mgr; 1566d5ac70f0Sopenharmony_ci return 0; 1567d5ac70f0Sopenharmony_ci 1568d5ac70f0Sopenharmony_ci_err: 1569d5ac70f0Sopenharmony_ci uc_mgr_card_close(mgr); 1570d5ac70f0Sopenharmony_ci uc_mgr_free(mgr); 1571d5ac70f0Sopenharmony_ci return err; 1572d5ac70f0Sopenharmony_ci} 1573d5ac70f0Sopenharmony_ci 1574d5ac70f0Sopenharmony_ciint snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr) 1575d5ac70f0Sopenharmony_ci{ 1576d5ac70f0Sopenharmony_ci int err; 1577d5ac70f0Sopenharmony_ci 1578d5ac70f0Sopenharmony_ci pthread_mutex_lock(&uc_mgr->mutex); 1579d5ac70f0Sopenharmony_ci 1580d5ac70f0Sopenharmony_ci do_reset(uc_mgr); 1581d5ac70f0Sopenharmony_ci 1582d5ac70f0Sopenharmony_ci uc_mgr_free_verb(uc_mgr); 1583d5ac70f0Sopenharmony_ci 1584d5ac70f0Sopenharmony_ci uc_mgr->default_list_executed = 0; 1585d5ac70f0Sopenharmony_ci 1586d5ac70f0Sopenharmony_ci /* reload all use cases */ 1587d5ac70f0Sopenharmony_ci err = import_master_config(uc_mgr); 1588d5ac70f0Sopenharmony_ci if (err < 0) { 1589d5ac70f0Sopenharmony_ci uc_error("error: failed to reload use cases"); 1590d5ac70f0Sopenharmony_ci pthread_mutex_unlock(&uc_mgr->mutex); 1591d5ac70f0Sopenharmony_ci return -EINVAL; 1592d5ac70f0Sopenharmony_ci } 1593d5ac70f0Sopenharmony_ci 1594d5ac70f0Sopenharmony_ci pthread_mutex_unlock(&uc_mgr->mutex); 1595d5ac70f0Sopenharmony_ci return err; 1596d5ac70f0Sopenharmony_ci} 1597d5ac70f0Sopenharmony_ci 1598d5ac70f0Sopenharmony_ciint snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr) 1599d5ac70f0Sopenharmony_ci{ 1600d5ac70f0Sopenharmony_ci uc_mgr_card_close(uc_mgr); 1601d5ac70f0Sopenharmony_ci uc_mgr_free(uc_mgr); 1602d5ac70f0Sopenharmony_ci 1603d5ac70f0Sopenharmony_ci return 0; 1604d5ac70f0Sopenharmony_ci} 1605d5ac70f0Sopenharmony_ci 1606d5ac70f0Sopenharmony_ci/* 1607d5ac70f0Sopenharmony_ci * Tear down current use case verb, device and modifier. 1608d5ac70f0Sopenharmony_ci */ 1609d5ac70f0Sopenharmony_cistatic int dismantle_use_case(snd_use_case_mgr_t *uc_mgr) 1610d5ac70f0Sopenharmony_ci{ 1611d5ac70f0Sopenharmony_ci struct list_head *pos, *npos; 1612d5ac70f0Sopenharmony_ci struct use_case_modifier *modifier; 1613d5ac70f0Sopenharmony_ci struct use_case_device *device; 1614d5ac70f0Sopenharmony_ci int err; 1615d5ac70f0Sopenharmony_ci 1616d5ac70f0Sopenharmony_ci list_for_each_safe(pos, npos, &uc_mgr->active_modifiers) { 1617d5ac70f0Sopenharmony_ci modifier = list_entry(pos, struct use_case_modifier, 1618d5ac70f0Sopenharmony_ci active_list); 1619d5ac70f0Sopenharmony_ci err = set_modifier(uc_mgr, modifier, 0); 1620d5ac70f0Sopenharmony_ci if (err < 0) 1621d5ac70f0Sopenharmony_ci uc_error("Unable to disable modifier %s", modifier->name); 1622d5ac70f0Sopenharmony_ci } 1623d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&uc_mgr->active_modifiers); 1624d5ac70f0Sopenharmony_ci 1625d5ac70f0Sopenharmony_ci list_for_each_safe(pos, npos, &uc_mgr->active_devices) { 1626d5ac70f0Sopenharmony_ci device = list_entry(pos, struct use_case_device, 1627d5ac70f0Sopenharmony_ci active_list); 1628d5ac70f0Sopenharmony_ci err = set_device(uc_mgr, device, 0); 1629d5ac70f0Sopenharmony_ci if (err < 0) 1630d5ac70f0Sopenharmony_ci uc_error("Unable to disable device %s", device->name); 1631d5ac70f0Sopenharmony_ci } 1632d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&uc_mgr->active_devices); 1633d5ac70f0Sopenharmony_ci 1634d5ac70f0Sopenharmony_ci err = set_verb(uc_mgr, uc_mgr->active_verb, 0); 1635d5ac70f0Sopenharmony_ci if (err < 0) { 1636d5ac70f0Sopenharmony_ci uc_error("Unable to disable verb %s", uc_mgr->active_verb->name); 1637d5ac70f0Sopenharmony_ci return err; 1638d5ac70f0Sopenharmony_ci } 1639d5ac70f0Sopenharmony_ci uc_mgr->active_verb = NULL; 1640d5ac70f0Sopenharmony_ci 1641d5ac70f0Sopenharmony_ci err = set_defaults(uc_mgr, true); 1642d5ac70f0Sopenharmony_ci 1643d5ac70f0Sopenharmony_ci return err; 1644d5ac70f0Sopenharmony_ci} 1645d5ac70f0Sopenharmony_ci 1646d5ac70f0Sopenharmony_ciint snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr) 1647d5ac70f0Sopenharmony_ci{ 1648d5ac70f0Sopenharmony_ci int err; 1649d5ac70f0Sopenharmony_ci 1650d5ac70f0Sopenharmony_ci pthread_mutex_lock(&uc_mgr->mutex); 1651d5ac70f0Sopenharmony_ci err = do_reset(uc_mgr); 1652d5ac70f0Sopenharmony_ci pthread_mutex_unlock(&uc_mgr->mutex); 1653d5ac70f0Sopenharmony_ci return err; 1654d5ac70f0Sopenharmony_ci} 1655d5ac70f0Sopenharmony_ci 1656d5ac70f0Sopenharmony_ci/** 1657d5ac70f0Sopenharmony_ci * \brief Get list of verbs in pair verbname+comment 1658d5ac70f0Sopenharmony_ci * \param list Returned list 1659d5ac70f0Sopenharmony_ci * \return Number of list entries if success, otherwise a negative error code 1660d5ac70f0Sopenharmony_ci */ 1661d5ac70f0Sopenharmony_cistatic int get_verb_list(snd_use_case_mgr_t *uc_mgr, const char **list[]) 1662d5ac70f0Sopenharmony_ci{ 1663d5ac70f0Sopenharmony_ci return get_list2(&uc_mgr->verb_list, list, 1664d5ac70f0Sopenharmony_ci struct use_case_verb, list, 1665d5ac70f0Sopenharmony_ci name, comment); 1666d5ac70f0Sopenharmony_ci} 1667d5ac70f0Sopenharmony_ci 1668d5ac70f0Sopenharmony_ci/** 1669d5ac70f0Sopenharmony_ci * \brief Get list of devices in pair devicename+comment 1670d5ac70f0Sopenharmony_ci * \param list Returned list 1671d5ac70f0Sopenharmony_ci * \param verbname For verb (NULL = current) 1672d5ac70f0Sopenharmony_ci * \return Number of list entries if success, otherwise a negative error code 1673d5ac70f0Sopenharmony_ci */ 1674d5ac70f0Sopenharmony_cistatic int get_device_list(snd_use_case_mgr_t *uc_mgr, const char **list[], 1675d5ac70f0Sopenharmony_ci char *verbname) 1676d5ac70f0Sopenharmony_ci{ 1677d5ac70f0Sopenharmony_ci struct use_case_verb *verb; 1678d5ac70f0Sopenharmony_ci 1679d5ac70f0Sopenharmony_ci if (verbname) { 1680d5ac70f0Sopenharmony_ci verb = find_verb(uc_mgr, verbname); 1681d5ac70f0Sopenharmony_ci } else { 1682d5ac70f0Sopenharmony_ci verb = uc_mgr->active_verb; 1683d5ac70f0Sopenharmony_ci } 1684d5ac70f0Sopenharmony_ci if (verb == NULL) 1685d5ac70f0Sopenharmony_ci return -ENOENT; 1686d5ac70f0Sopenharmony_ci return get_list2(&verb->device_list, list, 1687d5ac70f0Sopenharmony_ci struct use_case_device, list, 1688d5ac70f0Sopenharmony_ci name, comment); 1689d5ac70f0Sopenharmony_ci} 1690d5ac70f0Sopenharmony_ci 1691d5ac70f0Sopenharmony_ci/** 1692d5ac70f0Sopenharmony_ci * \brief Get list of modifiers in pair devicename+comment 1693d5ac70f0Sopenharmony_ci * \param list Returned list 1694d5ac70f0Sopenharmony_ci * \param verbname For verb (NULL = current) 1695d5ac70f0Sopenharmony_ci * \return Number of list entries if success, otherwise a negative error code 1696d5ac70f0Sopenharmony_ci */ 1697d5ac70f0Sopenharmony_cistatic int get_modifier_list(snd_use_case_mgr_t *uc_mgr, const char **list[], 1698d5ac70f0Sopenharmony_ci char *verbname) 1699d5ac70f0Sopenharmony_ci{ 1700d5ac70f0Sopenharmony_ci struct use_case_verb *verb; 1701d5ac70f0Sopenharmony_ci if (verbname) { 1702d5ac70f0Sopenharmony_ci verb = find_verb(uc_mgr, verbname); 1703d5ac70f0Sopenharmony_ci } else { 1704d5ac70f0Sopenharmony_ci verb = uc_mgr->active_verb; 1705d5ac70f0Sopenharmony_ci } 1706d5ac70f0Sopenharmony_ci if (verb == NULL) 1707d5ac70f0Sopenharmony_ci return -ENOENT; 1708d5ac70f0Sopenharmony_ci return get_list2(&verb->modifier_list, list, 1709d5ac70f0Sopenharmony_ci struct use_case_modifier, list, 1710d5ac70f0Sopenharmony_ci name, comment); 1711d5ac70f0Sopenharmony_ci} 1712d5ac70f0Sopenharmony_ci 1713d5ac70f0Sopenharmony_ci/** 1714d5ac70f0Sopenharmony_ci * \brief Get list of supported/conflicting devices 1715d5ac70f0Sopenharmony_ci * \param list Returned list 1716d5ac70f0Sopenharmony_ci * \param name Name of modifier or verb to query 1717d5ac70f0Sopenharmony_ci * \param type Type of device list entries to return 1718d5ac70f0Sopenharmony_ci * \return Number of list entries if success, otherwise a negative error code 1719d5ac70f0Sopenharmony_ci */ 1720d5ac70f0Sopenharmony_cistatic int get_supcon_device_list(snd_use_case_mgr_t *uc_mgr, 1721d5ac70f0Sopenharmony_ci const char **list[], char *name, 1722d5ac70f0Sopenharmony_ci enum dev_list_type type) 1723d5ac70f0Sopenharmony_ci{ 1724d5ac70f0Sopenharmony_ci char *str; 1725d5ac70f0Sopenharmony_ci struct use_case_verb *verb; 1726d5ac70f0Sopenharmony_ci struct use_case_modifier *modifier; 1727d5ac70f0Sopenharmony_ci struct use_case_device *device; 1728d5ac70f0Sopenharmony_ci 1729d5ac70f0Sopenharmony_ci if (!name) 1730d5ac70f0Sopenharmony_ci return -ENOENT; 1731d5ac70f0Sopenharmony_ci 1732d5ac70f0Sopenharmony_ci str = strchr(name, '/'); 1733d5ac70f0Sopenharmony_ci if (str) { 1734d5ac70f0Sopenharmony_ci *str = '\0'; 1735d5ac70f0Sopenharmony_ci verb = find_verb(uc_mgr, str + 1); 1736d5ac70f0Sopenharmony_ci } 1737d5ac70f0Sopenharmony_ci else { 1738d5ac70f0Sopenharmony_ci verb = uc_mgr->active_verb; 1739d5ac70f0Sopenharmony_ci } 1740d5ac70f0Sopenharmony_ci if (!verb) 1741d5ac70f0Sopenharmony_ci return -ENOENT; 1742d5ac70f0Sopenharmony_ci 1743d5ac70f0Sopenharmony_ci modifier = find_modifier(uc_mgr, verb, name, 0); 1744d5ac70f0Sopenharmony_ci if (modifier) { 1745d5ac70f0Sopenharmony_ci if (modifier->dev_list.type != type) { 1746d5ac70f0Sopenharmony_ci *list = NULL; 1747d5ac70f0Sopenharmony_ci return 0; 1748d5ac70f0Sopenharmony_ci } 1749d5ac70f0Sopenharmony_ci return get_list(&modifier->dev_list.list, list, 1750d5ac70f0Sopenharmony_ci struct dev_list_node, list, 1751d5ac70f0Sopenharmony_ci name); 1752d5ac70f0Sopenharmony_ci } 1753d5ac70f0Sopenharmony_ci 1754d5ac70f0Sopenharmony_ci device = find_device(uc_mgr, verb, name, 0); 1755d5ac70f0Sopenharmony_ci if (device) { 1756d5ac70f0Sopenharmony_ci if (device->dev_list.type != type) { 1757d5ac70f0Sopenharmony_ci *list = NULL; 1758d5ac70f0Sopenharmony_ci return 0; 1759d5ac70f0Sopenharmony_ci } 1760d5ac70f0Sopenharmony_ci return get_list(&device->dev_list.list, list, 1761d5ac70f0Sopenharmony_ci struct dev_list_node, list, 1762d5ac70f0Sopenharmony_ci name); 1763d5ac70f0Sopenharmony_ci } 1764d5ac70f0Sopenharmony_ci 1765d5ac70f0Sopenharmony_ci return -ENOENT; 1766d5ac70f0Sopenharmony_ci} 1767d5ac70f0Sopenharmony_ci 1768d5ac70f0Sopenharmony_ci/** 1769d5ac70f0Sopenharmony_ci * \brief Get list of supported devices 1770d5ac70f0Sopenharmony_ci * \param list Returned list 1771d5ac70f0Sopenharmony_ci * \param name Name of verb or modifier to query 1772d5ac70f0Sopenharmony_ci * \return Number of list entries if success, otherwise a negative error code 1773d5ac70f0Sopenharmony_ci */ 1774d5ac70f0Sopenharmony_cistatic int get_supported_device_list(snd_use_case_mgr_t *uc_mgr, 1775d5ac70f0Sopenharmony_ci const char **list[], char *name) 1776d5ac70f0Sopenharmony_ci{ 1777d5ac70f0Sopenharmony_ci return get_supcon_device_list(uc_mgr, list, name, DEVLIST_SUPPORTED); 1778d5ac70f0Sopenharmony_ci} 1779d5ac70f0Sopenharmony_ci 1780d5ac70f0Sopenharmony_ci/** 1781d5ac70f0Sopenharmony_ci * \brief Get list of conflicting devices 1782d5ac70f0Sopenharmony_ci * \param list Returned list 1783d5ac70f0Sopenharmony_ci * \param name Name of verb or modifier to query 1784d5ac70f0Sopenharmony_ci * \return Number of list entries if success, otherwise a negative error code 1785d5ac70f0Sopenharmony_ci */ 1786d5ac70f0Sopenharmony_cistatic int get_conflicting_device_list(snd_use_case_mgr_t *uc_mgr, 1787d5ac70f0Sopenharmony_ci const char **list[], char *name) 1788d5ac70f0Sopenharmony_ci{ 1789d5ac70f0Sopenharmony_ci return get_supcon_device_list(uc_mgr, list, name, DEVLIST_CONFLICTING); 1790d5ac70f0Sopenharmony_ci} 1791d5ac70f0Sopenharmony_ci 1792d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 1793d5ac70f0Sopenharmony_cistruct myvalue { 1794d5ac70f0Sopenharmony_ci struct list_head list; 1795d5ac70f0Sopenharmony_ci const char *text; 1796d5ac70f0Sopenharmony_ci}; 1797d5ac70f0Sopenharmony_ci#endif 1798d5ac70f0Sopenharmony_ci 1799d5ac70f0Sopenharmony_ci/** 1800d5ac70f0Sopenharmony_ci * \brief Convert myvalue list string list 1801d5ac70f0Sopenharmony_ci * \param list myvalue list 1802d5ac70f0Sopenharmony_ci * \param res string list 1803d5ac70f0Sopenharmony_ci * \retval Number of list entries if success, otherwise a negativer error code 1804d5ac70f0Sopenharmony_ci */ 1805d5ac70f0Sopenharmony_cistatic int myvalue_to_str_list(struct list_head *list, char ***res) 1806d5ac70f0Sopenharmony_ci{ 1807d5ac70f0Sopenharmony_ci struct list_head *pos; 1808d5ac70f0Sopenharmony_ci struct myvalue *value; 1809d5ac70f0Sopenharmony_ci char **p; 1810d5ac70f0Sopenharmony_ci int cnt; 1811d5ac70f0Sopenharmony_ci 1812d5ac70f0Sopenharmony_ci cnt = alloc_str_list(list, 1, res); 1813d5ac70f0Sopenharmony_ci if (cnt < 0) 1814d5ac70f0Sopenharmony_ci return cnt; 1815d5ac70f0Sopenharmony_ci p = *res; 1816d5ac70f0Sopenharmony_ci list_for_each(pos, list) { 1817d5ac70f0Sopenharmony_ci value = list_entry(pos, struct myvalue, list); 1818d5ac70f0Sopenharmony_ci *p = strdup(value->text); 1819d5ac70f0Sopenharmony_ci if (*p == NULL) { 1820d5ac70f0Sopenharmony_ci snd_use_case_free_list((const char **)p, cnt); 1821d5ac70f0Sopenharmony_ci return -ENOMEM; 1822d5ac70f0Sopenharmony_ci } 1823d5ac70f0Sopenharmony_ci p++; 1824d5ac70f0Sopenharmony_ci } 1825d5ac70f0Sopenharmony_ci return cnt; 1826d5ac70f0Sopenharmony_ci} 1827d5ac70f0Sopenharmony_ci 1828d5ac70f0Sopenharmony_ci/** 1829d5ac70f0Sopenharmony_ci * \brief Free myvalue list 1830d5ac70f0Sopenharmony_ci * \param list myvalue list 1831d5ac70f0Sopenharmony_ci */ 1832d5ac70f0Sopenharmony_cistatic void myvalue_list_free(struct list_head *list) 1833d5ac70f0Sopenharmony_ci{ 1834d5ac70f0Sopenharmony_ci struct list_head *pos, *npos; 1835d5ac70f0Sopenharmony_ci struct myvalue *value; 1836d5ac70f0Sopenharmony_ci 1837d5ac70f0Sopenharmony_ci list_for_each_safe(pos, npos, list) { 1838d5ac70f0Sopenharmony_ci value = list_entry(pos, struct myvalue, list); 1839d5ac70f0Sopenharmony_ci list_del(&value->list); 1840d5ac70f0Sopenharmony_ci free(value); 1841d5ac70f0Sopenharmony_ci } 1842d5ac70f0Sopenharmony_ci} 1843d5ac70f0Sopenharmony_ci 1844d5ac70f0Sopenharmony_ci/** 1845d5ac70f0Sopenharmony_ci * \brief Merge one value to the myvalue list 1846d5ac70f0Sopenharmony_ci * \param list The list with values 1847d5ac70f0Sopenharmony_ci * \param value The value to be merged (without duplicates) 1848d5ac70f0Sopenharmony_ci * \return 1 if dup, 0 if success, otherwise a negative error code 1849d5ac70f0Sopenharmony_ci */ 1850d5ac70f0Sopenharmony_cistatic int merge_value(struct list_head *list, const char *text) 1851d5ac70f0Sopenharmony_ci{ 1852d5ac70f0Sopenharmony_ci struct list_head *pos; 1853d5ac70f0Sopenharmony_ci struct myvalue *value; 1854d5ac70f0Sopenharmony_ci 1855d5ac70f0Sopenharmony_ci list_for_each(pos, list) { 1856d5ac70f0Sopenharmony_ci value = list_entry(pos, struct myvalue, list); 1857d5ac70f0Sopenharmony_ci if (strcmp(value->text, text) == 0) 1858d5ac70f0Sopenharmony_ci return 1; 1859d5ac70f0Sopenharmony_ci } 1860d5ac70f0Sopenharmony_ci value = malloc(sizeof(*value)); 1861d5ac70f0Sopenharmony_ci if (value == NULL) 1862d5ac70f0Sopenharmony_ci return -ENOMEM; 1863d5ac70f0Sopenharmony_ci value->text = text; 1864d5ac70f0Sopenharmony_ci list_add_tail(&value->list, list); 1865d5ac70f0Sopenharmony_ci return 0; 1866d5ac70f0Sopenharmony_ci} 1867d5ac70f0Sopenharmony_ci 1868d5ac70f0Sopenharmony_ci/** 1869d5ac70f0Sopenharmony_ci * \brief Find all values for given identifier 1870d5ac70f0Sopenharmony_ci * \param list Returned list 1871d5ac70f0Sopenharmony_ci * \param source Source list with ucm_value structures 1872d5ac70f0Sopenharmony_ci * \return Zero if success, otherwise a negative error code 1873d5ac70f0Sopenharmony_ci */ 1874d5ac70f0Sopenharmony_cistatic int add_identifiers(struct list_head *list, 1875d5ac70f0Sopenharmony_ci struct list_head *source) 1876d5ac70f0Sopenharmony_ci{ 1877d5ac70f0Sopenharmony_ci struct ucm_value *v; 1878d5ac70f0Sopenharmony_ci struct list_head *pos; 1879d5ac70f0Sopenharmony_ci int err; 1880d5ac70f0Sopenharmony_ci 1881d5ac70f0Sopenharmony_ci list_for_each(pos, source) { 1882d5ac70f0Sopenharmony_ci v = list_entry(pos, struct ucm_value, list); 1883d5ac70f0Sopenharmony_ci err = merge_value(list, v->name); 1884d5ac70f0Sopenharmony_ci if (err < 0) 1885d5ac70f0Sopenharmony_ci return err; 1886d5ac70f0Sopenharmony_ci } 1887d5ac70f0Sopenharmony_ci return 0; 1888d5ac70f0Sopenharmony_ci} 1889d5ac70f0Sopenharmony_ci 1890d5ac70f0Sopenharmony_ci/** 1891d5ac70f0Sopenharmony_ci * \brief Find all values for given identifier 1892d5ac70f0Sopenharmony_ci * \param list Returned list 1893d5ac70f0Sopenharmony_ci * \param identifier Identifier 1894d5ac70f0Sopenharmony_ci * \param source Source list with ucm_value structures 1895d5ac70f0Sopenharmony_ci */ 1896d5ac70f0Sopenharmony_cistatic int add_values(struct list_head *list, 1897d5ac70f0Sopenharmony_ci const char *identifier, 1898d5ac70f0Sopenharmony_ci struct list_head *source) 1899d5ac70f0Sopenharmony_ci{ 1900d5ac70f0Sopenharmony_ci struct ucm_value *v; 1901d5ac70f0Sopenharmony_ci struct list_head *pos; 1902d5ac70f0Sopenharmony_ci int err; 1903d5ac70f0Sopenharmony_ci 1904d5ac70f0Sopenharmony_ci list_for_each(pos, source) { 1905d5ac70f0Sopenharmony_ci v = list_entry(pos, struct ucm_value, list); 1906d5ac70f0Sopenharmony_ci if (check_identifier(identifier, v->name)) { 1907d5ac70f0Sopenharmony_ci err = merge_value(list, v->data); 1908d5ac70f0Sopenharmony_ci if (err < 0) 1909d5ac70f0Sopenharmony_ci return err; 1910d5ac70f0Sopenharmony_ci } 1911d5ac70f0Sopenharmony_ci } 1912d5ac70f0Sopenharmony_ci return 0; 1913d5ac70f0Sopenharmony_ci} 1914d5ac70f0Sopenharmony_ci 1915d5ac70f0Sopenharmony_ci/** 1916d5ac70f0Sopenharmony_ci * \brief compare two identifiers 1917d5ac70f0Sopenharmony_ci */ 1918d5ac70f0Sopenharmony_cistatic int identifier_cmp(const void *_a, const void *_b) 1919d5ac70f0Sopenharmony_ci{ 1920d5ac70f0Sopenharmony_ci const char * const *a = _a; 1921d5ac70f0Sopenharmony_ci const char * const *b = _b; 1922d5ac70f0Sopenharmony_ci return strcmp(*a, *b); 1923d5ac70f0Sopenharmony_ci} 1924d5ac70f0Sopenharmony_ci 1925d5ac70f0Sopenharmony_ci/** 1926d5ac70f0Sopenharmony_ci * \brief Get list of available identifiers 1927d5ac70f0Sopenharmony_ci * \param list Returned list 1928d5ac70f0Sopenharmony_ci * \param name Name of verb or modifier to query 1929d5ac70f0Sopenharmony_ci * \return Number of list entries if success, otherwise a negative error code 1930d5ac70f0Sopenharmony_ci */ 1931d5ac70f0Sopenharmony_cistatic int get_identifiers_list(snd_use_case_mgr_t *uc_mgr, 1932d5ac70f0Sopenharmony_ci const char **list[], char *name) 1933d5ac70f0Sopenharmony_ci{ 1934d5ac70f0Sopenharmony_ci struct use_case_verb *verb; 1935d5ac70f0Sopenharmony_ci struct use_case_modifier *modifier; 1936d5ac70f0Sopenharmony_ci struct use_case_device *device; 1937d5ac70f0Sopenharmony_ci struct list_head mylist; 1938d5ac70f0Sopenharmony_ci struct list_head *value_list; 1939d5ac70f0Sopenharmony_ci char *str, **res; 1940d5ac70f0Sopenharmony_ci int err; 1941d5ac70f0Sopenharmony_ci 1942d5ac70f0Sopenharmony_ci if (!name) 1943d5ac70f0Sopenharmony_ci return -ENOENT; 1944d5ac70f0Sopenharmony_ci 1945d5ac70f0Sopenharmony_ci str = strchr(name, '/'); 1946d5ac70f0Sopenharmony_ci if (str) { 1947d5ac70f0Sopenharmony_ci *str = '\0'; 1948d5ac70f0Sopenharmony_ci verb = find_verb(uc_mgr, str + 1); 1949d5ac70f0Sopenharmony_ci } 1950d5ac70f0Sopenharmony_ci else { 1951d5ac70f0Sopenharmony_ci verb = uc_mgr->active_verb; 1952d5ac70f0Sopenharmony_ci } 1953d5ac70f0Sopenharmony_ci if (!verb) 1954d5ac70f0Sopenharmony_ci return -ENOENT; 1955d5ac70f0Sopenharmony_ci 1956d5ac70f0Sopenharmony_ci value_list = NULL; 1957d5ac70f0Sopenharmony_ci modifier = find_modifier(uc_mgr, verb, name, 0); 1958d5ac70f0Sopenharmony_ci if (modifier) { 1959d5ac70f0Sopenharmony_ci value_list = &modifier->value_list; 1960d5ac70f0Sopenharmony_ci } else { 1961d5ac70f0Sopenharmony_ci device = find_device(uc_mgr, verb, name, 0); 1962d5ac70f0Sopenharmony_ci if (device) 1963d5ac70f0Sopenharmony_ci value_list = &device->value_list; 1964d5ac70f0Sopenharmony_ci } 1965d5ac70f0Sopenharmony_ci if (value_list == NULL) 1966d5ac70f0Sopenharmony_ci return -ENOENT; 1967d5ac70f0Sopenharmony_ci 1968d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&mylist); 1969d5ac70f0Sopenharmony_ci err = add_identifiers(&mylist, &uc_mgr->value_list); 1970d5ac70f0Sopenharmony_ci if (err < 0) 1971d5ac70f0Sopenharmony_ci goto __fail; 1972d5ac70f0Sopenharmony_ci err = add_identifiers(&mylist, &verb->value_list); 1973d5ac70f0Sopenharmony_ci if (err < 0) 1974d5ac70f0Sopenharmony_ci goto __fail; 1975d5ac70f0Sopenharmony_ci err = add_identifiers(&mylist, value_list); 1976d5ac70f0Sopenharmony_ci if (err < 0) 1977d5ac70f0Sopenharmony_ci goto __fail; 1978d5ac70f0Sopenharmony_ci err = myvalue_to_str_list(&mylist, &res); 1979d5ac70f0Sopenharmony_ci if (err > 0) 1980d5ac70f0Sopenharmony_ci *list = (const char **)res; 1981d5ac70f0Sopenharmony_ci else if (err == 0) 1982d5ac70f0Sopenharmony_ci *list = NULL; 1983d5ac70f0Sopenharmony_ci__fail: 1984d5ac70f0Sopenharmony_ci myvalue_list_free(&mylist); 1985d5ac70f0Sopenharmony_ci if (err <= 0) 1986d5ac70f0Sopenharmony_ci return err; 1987d5ac70f0Sopenharmony_ci qsort(*list, err, sizeof(char *), identifier_cmp); 1988d5ac70f0Sopenharmony_ci return err; 1989d5ac70f0Sopenharmony_ci} 1990d5ac70f0Sopenharmony_ci 1991d5ac70f0Sopenharmony_ci/** 1992d5ac70f0Sopenharmony_ci * \brief Get list of values 1993d5ac70f0Sopenharmony_ci * \param list Returned list 1994d5ac70f0Sopenharmony_ci * \param verbname For verb (NULL = current) 1995d5ac70f0Sopenharmony_ci * \return Number of list entries if success, otherwise a negative error code 1996d5ac70f0Sopenharmony_ci */ 1997d5ac70f0Sopenharmony_cistatic int get_value_list(snd_use_case_mgr_t *uc_mgr, 1998d5ac70f0Sopenharmony_ci const char *identifier, 1999d5ac70f0Sopenharmony_ci const char **list[], 2000d5ac70f0Sopenharmony_ci char *verbname) 2001d5ac70f0Sopenharmony_ci{ 2002d5ac70f0Sopenharmony_ci struct list_head mylist, *pos; 2003d5ac70f0Sopenharmony_ci struct use_case_verb *verb; 2004d5ac70f0Sopenharmony_ci struct use_case_device *dev; 2005d5ac70f0Sopenharmony_ci struct use_case_modifier *mod; 2006d5ac70f0Sopenharmony_ci char **res; 2007d5ac70f0Sopenharmony_ci int err; 2008d5ac70f0Sopenharmony_ci 2009d5ac70f0Sopenharmony_ci if (verbname) { 2010d5ac70f0Sopenharmony_ci verb = find_verb(uc_mgr, verbname); 2011d5ac70f0Sopenharmony_ci } else { 2012d5ac70f0Sopenharmony_ci verb = uc_mgr->active_verb; 2013d5ac70f0Sopenharmony_ci } 2014d5ac70f0Sopenharmony_ci if (verb == NULL) 2015d5ac70f0Sopenharmony_ci return -ENOENT; 2016d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&mylist); 2017d5ac70f0Sopenharmony_ci err = add_values(&mylist, identifier, &uc_mgr->value_list); 2018d5ac70f0Sopenharmony_ci if (err < 0) 2019d5ac70f0Sopenharmony_ci goto __fail; 2020d5ac70f0Sopenharmony_ci err = add_values(&mylist, identifier, &verb->value_list); 2021d5ac70f0Sopenharmony_ci if (err < 0) 2022d5ac70f0Sopenharmony_ci goto __fail; 2023d5ac70f0Sopenharmony_ci list_for_each(pos, &verb->device_list) { 2024d5ac70f0Sopenharmony_ci dev = list_entry(pos, struct use_case_device, list); 2025d5ac70f0Sopenharmony_ci err = add_values(&mylist, identifier, &dev->value_list); 2026d5ac70f0Sopenharmony_ci if (err < 0) 2027d5ac70f0Sopenharmony_ci goto __fail; 2028d5ac70f0Sopenharmony_ci } 2029d5ac70f0Sopenharmony_ci list_for_each(pos, &verb->modifier_list) { 2030d5ac70f0Sopenharmony_ci mod = list_entry(pos, struct use_case_modifier, list); 2031d5ac70f0Sopenharmony_ci err = add_values(&mylist, identifier, &mod->value_list); 2032d5ac70f0Sopenharmony_ci if (err < 0) 2033d5ac70f0Sopenharmony_ci goto __fail; 2034d5ac70f0Sopenharmony_ci } 2035d5ac70f0Sopenharmony_ci err = myvalue_to_str_list(&mylist, &res); 2036d5ac70f0Sopenharmony_ci if (err > 0) 2037d5ac70f0Sopenharmony_ci *list = (const char **)res; 2038d5ac70f0Sopenharmony_ci else if (err == 0) 2039d5ac70f0Sopenharmony_ci *list = NULL; 2040d5ac70f0Sopenharmony_ci __fail: 2041d5ac70f0Sopenharmony_ci myvalue_list_free(&mylist); 2042d5ac70f0Sopenharmony_ci return err; 2043d5ac70f0Sopenharmony_ci} 2044d5ac70f0Sopenharmony_ci 2045d5ac70f0Sopenharmony_ci/** 2046d5ac70f0Sopenharmony_ci * \brief Get list of enabled devices 2047d5ac70f0Sopenharmony_ci * \param list Returned list 2048d5ac70f0Sopenharmony_ci * \param verbname For verb (NULL = current) 2049d5ac70f0Sopenharmony_ci * \return Number of list entries if success, otherwise a negative error code 2050d5ac70f0Sopenharmony_ci */ 2051d5ac70f0Sopenharmony_cistatic int get_enabled_device_list(snd_use_case_mgr_t *uc_mgr, 2052d5ac70f0Sopenharmony_ci const char **list[]) 2053d5ac70f0Sopenharmony_ci{ 2054d5ac70f0Sopenharmony_ci if (uc_mgr->active_verb == NULL) 2055d5ac70f0Sopenharmony_ci return -EINVAL; 2056d5ac70f0Sopenharmony_ci return get_list(&uc_mgr->active_devices, list, 2057d5ac70f0Sopenharmony_ci struct use_case_device, active_list, 2058d5ac70f0Sopenharmony_ci name); 2059d5ac70f0Sopenharmony_ci} 2060d5ac70f0Sopenharmony_ci 2061d5ac70f0Sopenharmony_ci/** 2062d5ac70f0Sopenharmony_ci * \brief Get list of enabled modifiers 2063d5ac70f0Sopenharmony_ci * \param list Returned list 2064d5ac70f0Sopenharmony_ci * \param verbname For verb (NULL = current) 2065d5ac70f0Sopenharmony_ci * \return Number of list entries if success, otherwise a negative error code 2066d5ac70f0Sopenharmony_ci */ 2067d5ac70f0Sopenharmony_cistatic int get_enabled_modifier_list(snd_use_case_mgr_t *uc_mgr, 2068d5ac70f0Sopenharmony_ci const char **list[]) 2069d5ac70f0Sopenharmony_ci{ 2070d5ac70f0Sopenharmony_ci if (uc_mgr->active_verb == NULL) 2071d5ac70f0Sopenharmony_ci return -EINVAL; 2072d5ac70f0Sopenharmony_ci return get_list(&uc_mgr->active_modifiers, list, 2073d5ac70f0Sopenharmony_ci struct use_case_modifier, active_list, 2074d5ac70f0Sopenharmony_ci name); 2075d5ac70f0Sopenharmony_ci} 2076d5ac70f0Sopenharmony_ci 2077d5ac70f0Sopenharmony_ciint snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr, 2078d5ac70f0Sopenharmony_ci const char *identifier, 2079d5ac70f0Sopenharmony_ci const char **list[]) 2080d5ac70f0Sopenharmony_ci{ 2081d5ac70f0Sopenharmony_ci char *str, *str1; 2082d5ac70f0Sopenharmony_ci int err; 2083d5ac70f0Sopenharmony_ci 2084d5ac70f0Sopenharmony_ci if (uc_mgr == NULL || identifier == NULL) 2085d5ac70f0Sopenharmony_ci return uc_mgr_scan_master_configs(list); 2086d5ac70f0Sopenharmony_ci pthread_mutex_lock(&uc_mgr->mutex); 2087d5ac70f0Sopenharmony_ci if (strcmp(identifier, "_verbs") == 0) 2088d5ac70f0Sopenharmony_ci err = get_verb_list(uc_mgr, list); 2089d5ac70f0Sopenharmony_ci else if (strcmp(identifier, "_enadevs") == 0) 2090d5ac70f0Sopenharmony_ci err = get_enabled_device_list(uc_mgr, list); 2091d5ac70f0Sopenharmony_ci else if (strcmp(identifier, "_enamods") == 0) 2092d5ac70f0Sopenharmony_ci err = get_enabled_modifier_list(uc_mgr, list); 2093d5ac70f0Sopenharmony_ci else { 2094d5ac70f0Sopenharmony_ci str1 = strchr(identifier, '/'); 2095d5ac70f0Sopenharmony_ci if (str1) { 2096d5ac70f0Sopenharmony_ci str = strdup(str1 + 1); 2097d5ac70f0Sopenharmony_ci if (str == NULL) { 2098d5ac70f0Sopenharmony_ci err = -ENOMEM; 2099d5ac70f0Sopenharmony_ci goto __end; 2100d5ac70f0Sopenharmony_ci } 2101d5ac70f0Sopenharmony_ci } else { 2102d5ac70f0Sopenharmony_ci str = NULL; 2103d5ac70f0Sopenharmony_ci } 2104d5ac70f0Sopenharmony_ci if (check_identifier(identifier, "_devices")) 2105d5ac70f0Sopenharmony_ci err = get_device_list(uc_mgr, list, str); 2106d5ac70f0Sopenharmony_ci else if (check_identifier(identifier, "_modifiers")) 2107d5ac70f0Sopenharmony_ci err = get_modifier_list(uc_mgr, list, str); 2108d5ac70f0Sopenharmony_ci else if (check_identifier(identifier, "_identifiers")) 2109d5ac70f0Sopenharmony_ci err = get_identifiers_list(uc_mgr, list, str); 2110d5ac70f0Sopenharmony_ci else if (check_identifier(identifier, "_supporteddevs")) 2111d5ac70f0Sopenharmony_ci err = get_supported_device_list(uc_mgr, list, str); 2112d5ac70f0Sopenharmony_ci else if (check_identifier(identifier, "_conflictingdevs")) 2113d5ac70f0Sopenharmony_ci err = get_conflicting_device_list(uc_mgr, list, str); 2114d5ac70f0Sopenharmony_ci else if (identifier[0] == '_') 2115d5ac70f0Sopenharmony_ci err = -ENOENT; 2116d5ac70f0Sopenharmony_ci else 2117d5ac70f0Sopenharmony_ci err = get_value_list(uc_mgr, identifier, list, str); 2118d5ac70f0Sopenharmony_ci if (str) 2119d5ac70f0Sopenharmony_ci free(str); 2120d5ac70f0Sopenharmony_ci } 2121d5ac70f0Sopenharmony_ci __end: 2122d5ac70f0Sopenharmony_ci pthread_mutex_unlock(&uc_mgr->mutex); 2123d5ac70f0Sopenharmony_ci return err; 2124d5ac70f0Sopenharmony_ci} 2125d5ac70f0Sopenharmony_ci 2126d5ac70f0Sopenharmony_cistatic int get_value1(snd_use_case_mgr_t *uc_mgr, char **value, 2127d5ac70f0Sopenharmony_ci struct list_head *value_list, const char *identifier) 2128d5ac70f0Sopenharmony_ci{ 2129d5ac70f0Sopenharmony_ci struct ucm_value *val; 2130d5ac70f0Sopenharmony_ci struct list_head *pos; 2131d5ac70f0Sopenharmony_ci int err; 2132d5ac70f0Sopenharmony_ci 2133d5ac70f0Sopenharmony_ci if (!value_list) 2134d5ac70f0Sopenharmony_ci return -ENOENT; 2135d5ac70f0Sopenharmony_ci 2136d5ac70f0Sopenharmony_ci list_for_each(pos, value_list) { 2137d5ac70f0Sopenharmony_ci val = list_entry(pos, struct ucm_value, list); 2138d5ac70f0Sopenharmony_ci if (check_identifier(identifier, val->name)) { 2139d5ac70f0Sopenharmony_ci if (uc_mgr->conf_format < 2) { 2140d5ac70f0Sopenharmony_ci *value = strdup(val->data); 2141d5ac70f0Sopenharmony_ci if (*value == NULL) 2142d5ac70f0Sopenharmony_ci return -ENOMEM; 2143d5ac70f0Sopenharmony_ci return 0; 2144d5ac70f0Sopenharmony_ci } 2145d5ac70f0Sopenharmony_ci err = uc_mgr_get_substituted_value(uc_mgr, value, val->data); 2146d5ac70f0Sopenharmony_ci if (err < 0) 2147d5ac70f0Sopenharmony_ci return err; 2148d5ac70f0Sopenharmony_ci return rewrite_device_value(uc_mgr, val->name, value); 2149d5ac70f0Sopenharmony_ci } 2150d5ac70f0Sopenharmony_ci } 2151d5ac70f0Sopenharmony_ci return -ENOENT; 2152d5ac70f0Sopenharmony_ci} 2153d5ac70f0Sopenharmony_ci 2154d5ac70f0Sopenharmony_cistatic int get_value3(snd_use_case_mgr_t *uc_mgr, 2155d5ac70f0Sopenharmony_ci char **value, 2156d5ac70f0Sopenharmony_ci const char *identifier, 2157d5ac70f0Sopenharmony_ci struct list_head *value_list1, 2158d5ac70f0Sopenharmony_ci struct list_head *value_list2, 2159d5ac70f0Sopenharmony_ci struct list_head *value_list3) 2160d5ac70f0Sopenharmony_ci{ 2161d5ac70f0Sopenharmony_ci int err; 2162d5ac70f0Sopenharmony_ci 2163d5ac70f0Sopenharmony_ci err = get_value1(uc_mgr, value, value_list1, identifier); 2164d5ac70f0Sopenharmony_ci if (err >= 0 || err != -ENOENT) 2165d5ac70f0Sopenharmony_ci return err; 2166d5ac70f0Sopenharmony_ci err = get_value1(uc_mgr, value, value_list2, identifier); 2167d5ac70f0Sopenharmony_ci if (err >= 0 || err != -ENOENT) 2168d5ac70f0Sopenharmony_ci return err; 2169d5ac70f0Sopenharmony_ci err = get_value1(uc_mgr, value, value_list3, identifier); 2170d5ac70f0Sopenharmony_ci if (err >= 0 || err != -ENOENT) 2171d5ac70f0Sopenharmony_ci return err; 2172d5ac70f0Sopenharmony_ci return -ENOENT; 2173d5ac70f0Sopenharmony_ci} 2174d5ac70f0Sopenharmony_ci 2175d5ac70f0Sopenharmony_ci/** 2176d5ac70f0Sopenharmony_ci * \brief Get value 2177d5ac70f0Sopenharmony_ci * \param uc_mgr Use case manager 2178d5ac70f0Sopenharmony_ci * \param identifier Value identifier (string) 2179d5ac70f0Sopenharmony_ci * \param value Returned value string 2180d5ac70f0Sopenharmony_ci * \param item Modifier or Device name (string) 2181d5ac70f0Sopenharmony_ci * \return Zero on success (value is filled), otherwise a negative error code 2182d5ac70f0Sopenharmony_ci */ 2183d5ac70f0Sopenharmony_cistatic int get_value(snd_use_case_mgr_t *uc_mgr, 2184d5ac70f0Sopenharmony_ci const char *identifier, 2185d5ac70f0Sopenharmony_ci char **value, 2186d5ac70f0Sopenharmony_ci const char *mod_dev_name, 2187d5ac70f0Sopenharmony_ci const char *verb_name, 2188d5ac70f0Sopenharmony_ci int exact) 2189d5ac70f0Sopenharmony_ci{ 2190d5ac70f0Sopenharmony_ci struct use_case_verb *verb; 2191d5ac70f0Sopenharmony_ci struct use_case_modifier *mod; 2192d5ac70f0Sopenharmony_ci struct use_case_device *dev; 2193d5ac70f0Sopenharmony_ci int err; 2194d5ac70f0Sopenharmony_ci 2195d5ac70f0Sopenharmony_ci if (mod_dev_name || verb_name || !exact) { 2196d5ac70f0Sopenharmony_ci if (verb_name && strlen(verb_name)) { 2197d5ac70f0Sopenharmony_ci verb = find_verb(uc_mgr, verb_name); 2198d5ac70f0Sopenharmony_ci } else { 2199d5ac70f0Sopenharmony_ci verb = uc_mgr->active_verb; 2200d5ac70f0Sopenharmony_ci } 2201d5ac70f0Sopenharmony_ci if (verb) { 2202d5ac70f0Sopenharmony_ci if (mod_dev_name) { 2203d5ac70f0Sopenharmony_ci mod = find_modifier(uc_mgr, verb, 2204d5ac70f0Sopenharmony_ci mod_dev_name, 0); 2205d5ac70f0Sopenharmony_ci if (mod) { 2206d5ac70f0Sopenharmony_ci err = get_value1(uc_mgr, value, 2207d5ac70f0Sopenharmony_ci &mod->value_list, 2208d5ac70f0Sopenharmony_ci identifier); 2209d5ac70f0Sopenharmony_ci if (err >= 0 || err != -ENOENT) 2210d5ac70f0Sopenharmony_ci return err; 2211d5ac70f0Sopenharmony_ci } 2212d5ac70f0Sopenharmony_ci 2213d5ac70f0Sopenharmony_ci dev = find_device(uc_mgr, verb, 2214d5ac70f0Sopenharmony_ci mod_dev_name, 0); 2215d5ac70f0Sopenharmony_ci if (dev) { 2216d5ac70f0Sopenharmony_ci err = get_value1(uc_mgr, value, 2217d5ac70f0Sopenharmony_ci &dev->value_list, 2218d5ac70f0Sopenharmony_ci identifier); 2219d5ac70f0Sopenharmony_ci if (err >= 0 || err != -ENOENT) 2220d5ac70f0Sopenharmony_ci return err; 2221d5ac70f0Sopenharmony_ci } 2222d5ac70f0Sopenharmony_ci 2223d5ac70f0Sopenharmony_ci if (exact) 2224d5ac70f0Sopenharmony_ci return -ENOENT; 2225d5ac70f0Sopenharmony_ci } 2226d5ac70f0Sopenharmony_ci 2227d5ac70f0Sopenharmony_ci err = get_value1(uc_mgr, value, &verb->value_list, identifier); 2228d5ac70f0Sopenharmony_ci if (err >= 0 || err != -ENOENT) 2229d5ac70f0Sopenharmony_ci return err; 2230d5ac70f0Sopenharmony_ci } 2231d5ac70f0Sopenharmony_ci 2232d5ac70f0Sopenharmony_ci if (exact) 2233d5ac70f0Sopenharmony_ci return -ENOENT; 2234d5ac70f0Sopenharmony_ci } 2235d5ac70f0Sopenharmony_ci 2236d5ac70f0Sopenharmony_ci err = get_value1(uc_mgr, value, &uc_mgr->value_list, identifier); 2237d5ac70f0Sopenharmony_ci if (err >= 0 || err != -ENOENT) 2238d5ac70f0Sopenharmony_ci return err; 2239d5ac70f0Sopenharmony_ci 2240d5ac70f0Sopenharmony_ci return -ENOENT; 2241d5ac70f0Sopenharmony_ci} 2242d5ac70f0Sopenharmony_ci 2243d5ac70f0Sopenharmony_ci/** 2244d5ac70f0Sopenharmony_ci * \brief Get private alsa-lib configuration (ASCII) 2245d5ac70f0Sopenharmony_ci * \param uc_mgr Use case manager 2246d5ac70f0Sopenharmony_ci * \param str Returned value string 2247d5ac70f0Sopenharmony_ci * \return Zero on success (value is filled), otherwise a negative error code 2248d5ac70f0Sopenharmony_ci */ 2249d5ac70f0Sopenharmony_cistatic int get_alibcfg(snd_use_case_mgr_t *uc_mgr, char **str) 2250d5ac70f0Sopenharmony_ci{ 2251d5ac70f0Sopenharmony_ci snd_output_t *out; 2252d5ac70f0Sopenharmony_ci size_t size; 2253d5ac70f0Sopenharmony_ci int err; 2254d5ac70f0Sopenharmony_ci 2255d5ac70f0Sopenharmony_ci err = snd_output_buffer_open(&out); 2256d5ac70f0Sopenharmony_ci if (err < 0) 2257d5ac70f0Sopenharmony_ci return err; 2258d5ac70f0Sopenharmony_ci err = snd_config_save(uc_mgr->local_config, out); 2259d5ac70f0Sopenharmony_ci if (err >= 0) { 2260d5ac70f0Sopenharmony_ci size = snd_output_buffer_steal(out, str); 2261d5ac70f0Sopenharmony_ci if (*str) 2262d5ac70f0Sopenharmony_ci (*str)[size] = '\0'; 2263d5ac70f0Sopenharmony_ci } 2264d5ac70f0Sopenharmony_ci snd_output_close(out); 2265d5ac70f0Sopenharmony_ci return 0; 2266d5ac70f0Sopenharmony_ci} 2267d5ac70f0Sopenharmony_ci 2268d5ac70f0Sopenharmony_ci/** 2269d5ac70f0Sopenharmony_ci * \brief Get device prefix for private alsa-lib configuration 2270d5ac70f0Sopenharmony_ci * \param uc_mgr Use case manager 2271d5ac70f0Sopenharmony_ci * \param str Returned value string 2272d5ac70f0Sopenharmony_ci * \return Zero on success (value is filled), otherwise a negative error code 2273d5ac70f0Sopenharmony_ci */ 2274d5ac70f0Sopenharmony_cistatic int get_alibpref(snd_use_case_mgr_t *uc_mgr, char **str) 2275d5ac70f0Sopenharmony_ci{ 2276d5ac70f0Sopenharmony_ci const size_t l = 10; 2277d5ac70f0Sopenharmony_ci char *s; 2278d5ac70f0Sopenharmony_ci 2279d5ac70f0Sopenharmony_ci s = malloc(l); 2280d5ac70f0Sopenharmony_ci if (s == NULL) 2281d5ac70f0Sopenharmony_ci return -ENOMEM; 2282d5ac70f0Sopenharmony_ci snprintf(s, l, "_ucm%04X.", uc_mgr->ucm_card_number); 2283d5ac70f0Sopenharmony_ci *str = s; 2284d5ac70f0Sopenharmony_ci return 0; 2285d5ac70f0Sopenharmony_ci} 2286d5ac70f0Sopenharmony_ci 2287d5ac70f0Sopenharmony_ciint snd_use_case_get(snd_use_case_mgr_t *uc_mgr, 2288d5ac70f0Sopenharmony_ci const char *identifier, 2289d5ac70f0Sopenharmony_ci const char **value) 2290d5ac70f0Sopenharmony_ci{ 2291d5ac70f0Sopenharmony_ci const char *slash1, *slash2, *mod_dev_after; 2292d5ac70f0Sopenharmony_ci const char *ident, *mod_dev, *verb; 2293d5ac70f0Sopenharmony_ci int exact = 0; 2294d5ac70f0Sopenharmony_ci int err; 2295d5ac70f0Sopenharmony_ci 2296d5ac70f0Sopenharmony_ci pthread_mutex_lock(&uc_mgr->mutex); 2297d5ac70f0Sopenharmony_ci if (identifier == NULL) { 2298d5ac70f0Sopenharmony_ci *value = strdup(uc_mgr->card_name); 2299d5ac70f0Sopenharmony_ci if (*value == NULL) { 2300d5ac70f0Sopenharmony_ci err = -ENOMEM; 2301d5ac70f0Sopenharmony_ci goto __end; 2302d5ac70f0Sopenharmony_ci } 2303d5ac70f0Sopenharmony_ci err = 0; 2304d5ac70f0Sopenharmony_ci } else if (strcmp(identifier, "_verb") == 0) { 2305d5ac70f0Sopenharmony_ci if (uc_mgr->active_verb == NULL) { 2306d5ac70f0Sopenharmony_ci err = -ENOENT; 2307d5ac70f0Sopenharmony_ci goto __end; 2308d5ac70f0Sopenharmony_ci } 2309d5ac70f0Sopenharmony_ci *value = strdup(uc_mgr->active_verb->name); 2310d5ac70f0Sopenharmony_ci if (*value == NULL) { 2311d5ac70f0Sopenharmony_ci err = -ENOMEM; 2312d5ac70f0Sopenharmony_ci goto __end; 2313d5ac70f0Sopenharmony_ci } 2314d5ac70f0Sopenharmony_ci err = 0; 2315d5ac70f0Sopenharmony_ci } else if (strcmp(identifier, "_file") == 0) { 2316d5ac70f0Sopenharmony_ci /* get the conf file name of the opened card */ 2317d5ac70f0Sopenharmony_ci if ((uc_mgr->card_name == NULL) || 2318d5ac70f0Sopenharmony_ci (uc_mgr->conf_file_name == NULL) || 2319d5ac70f0Sopenharmony_ci (uc_mgr->conf_file_name[0] == '\0')) { 2320d5ac70f0Sopenharmony_ci err = -ENOENT; 2321d5ac70f0Sopenharmony_ci goto __end; 2322d5ac70f0Sopenharmony_ci } 2323d5ac70f0Sopenharmony_ci *value = strdup(uc_mgr->conf_file_name); 2324d5ac70f0Sopenharmony_ci if (*value == NULL) { 2325d5ac70f0Sopenharmony_ci err = -ENOMEM; 2326d5ac70f0Sopenharmony_ci goto __end; 2327d5ac70f0Sopenharmony_ci } 2328d5ac70f0Sopenharmony_ci err = 0; 2329d5ac70f0Sopenharmony_ci 2330d5ac70f0Sopenharmony_ci } else if (strcmp(identifier, "_alibcfg") == 0) { 2331d5ac70f0Sopenharmony_ci err = get_alibcfg(uc_mgr, (char **)value); 2332d5ac70f0Sopenharmony_ci } else if (strcmp(identifier, "_alibpref") == 0) { 2333d5ac70f0Sopenharmony_ci err = get_alibpref(uc_mgr, (char **)value); 2334d5ac70f0Sopenharmony_ci } else if (identifier[0] == '_') { 2335d5ac70f0Sopenharmony_ci err = -ENOENT; 2336d5ac70f0Sopenharmony_ci } else { 2337d5ac70f0Sopenharmony_ci if (identifier[0] == '=') { 2338d5ac70f0Sopenharmony_ci exact = 1; 2339d5ac70f0Sopenharmony_ci identifier++; 2340d5ac70f0Sopenharmony_ci } 2341d5ac70f0Sopenharmony_ci 2342d5ac70f0Sopenharmony_ci slash1 = strchr(identifier, '/'); 2343d5ac70f0Sopenharmony_ci if (slash1) { 2344d5ac70f0Sopenharmony_ci ident = strndup(identifier, slash1 - identifier); 2345d5ac70f0Sopenharmony_ci 2346d5ac70f0Sopenharmony_ci slash2 = strchr(slash1 + 1, '/'); 2347d5ac70f0Sopenharmony_ci if (slash2) { 2348d5ac70f0Sopenharmony_ci mod_dev_after = slash2; 2349d5ac70f0Sopenharmony_ci verb = slash2 + 1; 2350d5ac70f0Sopenharmony_ci } 2351d5ac70f0Sopenharmony_ci else { 2352d5ac70f0Sopenharmony_ci mod_dev_after = slash1 + strlen(slash1); 2353d5ac70f0Sopenharmony_ci verb = NULL; 2354d5ac70f0Sopenharmony_ci } 2355d5ac70f0Sopenharmony_ci 2356d5ac70f0Sopenharmony_ci if (mod_dev_after == slash1 + 1) 2357d5ac70f0Sopenharmony_ci mod_dev = NULL; 2358d5ac70f0Sopenharmony_ci else 2359d5ac70f0Sopenharmony_ci mod_dev = strndup(slash1 + 1, 2360d5ac70f0Sopenharmony_ci mod_dev_after - (slash1 + 1)); 2361d5ac70f0Sopenharmony_ci } 2362d5ac70f0Sopenharmony_ci else { 2363d5ac70f0Sopenharmony_ci ident = identifier; 2364d5ac70f0Sopenharmony_ci mod_dev = NULL; 2365d5ac70f0Sopenharmony_ci verb = NULL; 2366d5ac70f0Sopenharmony_ci } 2367d5ac70f0Sopenharmony_ci 2368d5ac70f0Sopenharmony_ci err = get_value(uc_mgr, ident, (char **)value, mod_dev, verb, 2369d5ac70f0Sopenharmony_ci exact); 2370d5ac70f0Sopenharmony_ci if (ident != identifier) 2371d5ac70f0Sopenharmony_ci free((void *)ident); 2372d5ac70f0Sopenharmony_ci if (mod_dev) 2373d5ac70f0Sopenharmony_ci free((void *)mod_dev); 2374d5ac70f0Sopenharmony_ci } 2375d5ac70f0Sopenharmony_ci __end: 2376d5ac70f0Sopenharmony_ci pthread_mutex_unlock(&uc_mgr->mutex); 2377d5ac70f0Sopenharmony_ci return err; 2378d5ac70f0Sopenharmony_ci} 2379d5ac70f0Sopenharmony_ci 2380d5ac70f0Sopenharmony_ci/* 2381d5ac70f0Sopenharmony_ci * a helper macro to obtain status and existence 2382d5ac70f0Sopenharmony_ci */ 2383d5ac70f0Sopenharmony_ci#define geti(uc_mgr, status, ifind, str, value) ({ \ 2384d5ac70f0Sopenharmony_ci long val = -EINVAL; \ 2385d5ac70f0Sopenharmony_ci if (str) { \ 2386d5ac70f0Sopenharmony_ci val = (status)((uc_mgr), (str)); \ 2387d5ac70f0Sopenharmony_ci if (val >= 0) { \ 2388d5ac70f0Sopenharmony_ci if ((ifind)((uc_mgr), (uc_mgr)->active_verb, (str), 0)) { \ 2389d5ac70f0Sopenharmony_ci *(value) = val; \ 2390d5ac70f0Sopenharmony_ci val = 0; \ 2391d5ac70f0Sopenharmony_ci } else { \ 2392d5ac70f0Sopenharmony_ci val = -ENOENT; \ 2393d5ac70f0Sopenharmony_ci } \ 2394d5ac70f0Sopenharmony_ci } \ 2395d5ac70f0Sopenharmony_ci } \ 2396d5ac70f0Sopenharmony_ci ; val; /* return value */ \ 2397d5ac70f0Sopenharmony_ci}) 2398d5ac70f0Sopenharmony_ci 2399d5ac70f0Sopenharmony_ciint snd_use_case_geti(snd_use_case_mgr_t *uc_mgr, 2400d5ac70f0Sopenharmony_ci const char *identifier, 2401d5ac70f0Sopenharmony_ci long *value) 2402d5ac70f0Sopenharmony_ci{ 2403d5ac70f0Sopenharmony_ci char *str, *str1; 2404d5ac70f0Sopenharmony_ci int err; 2405d5ac70f0Sopenharmony_ci 2406d5ac70f0Sopenharmony_ci pthread_mutex_lock(&uc_mgr->mutex); 2407d5ac70f0Sopenharmony_ci if (0) { 2408d5ac70f0Sopenharmony_ci /* nothing here - prepared for fixed identifiers */ 2409d5ac70f0Sopenharmony_ci } else { 2410d5ac70f0Sopenharmony_ci str1 = strchr(identifier, '/'); 2411d5ac70f0Sopenharmony_ci if (str1) { 2412d5ac70f0Sopenharmony_ci str = strdup(str1 + 1); 2413d5ac70f0Sopenharmony_ci if (str == NULL) { 2414d5ac70f0Sopenharmony_ci err = -ENOMEM; 2415d5ac70f0Sopenharmony_ci goto __end; 2416d5ac70f0Sopenharmony_ci } 2417d5ac70f0Sopenharmony_ci } else { 2418d5ac70f0Sopenharmony_ci str = NULL; 2419d5ac70f0Sopenharmony_ci } 2420d5ac70f0Sopenharmony_ci if (check_identifier(identifier, "_devstatus")) { 2421d5ac70f0Sopenharmony_ci err = geti(uc_mgr, device_status, find_device, str, value); 2422d5ac70f0Sopenharmony_ci } else if (check_identifier(identifier, "_modstatus")) { 2423d5ac70f0Sopenharmony_ci err = geti(uc_mgr, modifier_status, find_modifier, str, value); 2424d5ac70f0Sopenharmony_ci#if 0 2425d5ac70f0Sopenharmony_ci /* 2426d5ac70f0Sopenharmony_ci * enable this block if the else clause below is expanded to query 2427d5ac70f0Sopenharmony_ci * user-supplied values 2428d5ac70f0Sopenharmony_ci */ 2429d5ac70f0Sopenharmony_ci } else if (identifier[0] == '_') { 2430d5ac70f0Sopenharmony_ci err = -ENOENT; 2431d5ac70f0Sopenharmony_ci#endif 2432d5ac70f0Sopenharmony_ci } else 2433d5ac70f0Sopenharmony_ci err = -ENOENT; 2434d5ac70f0Sopenharmony_ci if (str) 2435d5ac70f0Sopenharmony_ci free(str); 2436d5ac70f0Sopenharmony_ci } 2437d5ac70f0Sopenharmony_ci __end: 2438d5ac70f0Sopenharmony_ci pthread_mutex_unlock(&uc_mgr->mutex); 2439d5ac70f0Sopenharmony_ci return err; 2440d5ac70f0Sopenharmony_ci} 2441d5ac70f0Sopenharmony_ci 2442d5ac70f0Sopenharmony_cistatic int set_fixedboot_user(snd_use_case_mgr_t *uc_mgr, 2443d5ac70f0Sopenharmony_ci const char *value) 2444d5ac70f0Sopenharmony_ci{ 2445d5ac70f0Sopenharmony_ci int err; 2446d5ac70f0Sopenharmony_ci 2447d5ac70f0Sopenharmony_ci if (value != NULL && *value) { 2448d5ac70f0Sopenharmony_ci uc_error("error: wrong value for _fboot (%s)", value); 2449d5ac70f0Sopenharmony_ci return -EINVAL; 2450d5ac70f0Sopenharmony_ci } 2451d5ac70f0Sopenharmony_ci if (list_empty(&uc_mgr->fixedboot_list)) 2452d5ac70f0Sopenharmony_ci return -ENOENT; 2453d5ac70f0Sopenharmony_ci err = execute_sequence(uc_mgr, NULL, &uc_mgr->fixedboot_list, 2454d5ac70f0Sopenharmony_ci &uc_mgr->value_list, NULL, NULL); 2455d5ac70f0Sopenharmony_ci if (err < 0) { 2456d5ac70f0Sopenharmony_ci uc_error("Unable to execute force boot sequence"); 2457d5ac70f0Sopenharmony_ci return err; 2458d5ac70f0Sopenharmony_ci } 2459d5ac70f0Sopenharmony_ci return err; 2460d5ac70f0Sopenharmony_ci} 2461d5ac70f0Sopenharmony_ci 2462d5ac70f0Sopenharmony_cistatic int set_boot_user(snd_use_case_mgr_t *uc_mgr, 2463d5ac70f0Sopenharmony_ci const char *value) 2464d5ac70f0Sopenharmony_ci{ 2465d5ac70f0Sopenharmony_ci int err; 2466d5ac70f0Sopenharmony_ci 2467d5ac70f0Sopenharmony_ci if (value != NULL && *value) { 2468d5ac70f0Sopenharmony_ci uc_error("error: wrong value for _boot (%s)", value); 2469d5ac70f0Sopenharmony_ci return -EINVAL; 2470d5ac70f0Sopenharmony_ci } 2471d5ac70f0Sopenharmony_ci if (list_empty(&uc_mgr->boot_list)) 2472d5ac70f0Sopenharmony_ci return -ENOENT; 2473d5ac70f0Sopenharmony_ci err = execute_sequence(uc_mgr, NULL, &uc_mgr->boot_list, 2474d5ac70f0Sopenharmony_ci &uc_mgr->value_list, NULL, NULL); 2475d5ac70f0Sopenharmony_ci if (err < 0) { 2476d5ac70f0Sopenharmony_ci uc_error("Unable to execute boot sequence"); 2477d5ac70f0Sopenharmony_ci return err; 2478d5ac70f0Sopenharmony_ci } 2479d5ac70f0Sopenharmony_ci return err; 2480d5ac70f0Sopenharmony_ci} 2481d5ac70f0Sopenharmony_ci 2482d5ac70f0Sopenharmony_cistatic int set_defaults_user(snd_use_case_mgr_t *uc_mgr, 2483d5ac70f0Sopenharmony_ci const char *value) 2484d5ac70f0Sopenharmony_ci{ 2485d5ac70f0Sopenharmony_ci if (value != NULL && *value) { 2486d5ac70f0Sopenharmony_ci uc_error("error: wrong value for _defaults (%s)", value); 2487d5ac70f0Sopenharmony_ci return -EINVAL; 2488d5ac70f0Sopenharmony_ci } 2489d5ac70f0Sopenharmony_ci return set_defaults(uc_mgr, false); 2490d5ac70f0Sopenharmony_ci} 2491d5ac70f0Sopenharmony_ci 2492d5ac70f0Sopenharmony_cistatic int handle_transition_verb(snd_use_case_mgr_t *uc_mgr, 2493d5ac70f0Sopenharmony_ci struct use_case_verb *new_verb) 2494d5ac70f0Sopenharmony_ci{ 2495d5ac70f0Sopenharmony_ci struct list_head *pos; 2496d5ac70f0Sopenharmony_ci struct transition_sequence *trans; 2497d5ac70f0Sopenharmony_ci int err; 2498d5ac70f0Sopenharmony_ci 2499d5ac70f0Sopenharmony_ci list_for_each(pos, &uc_mgr->active_verb->transition_list) { 2500d5ac70f0Sopenharmony_ci trans = list_entry(pos, struct transition_sequence, list); 2501d5ac70f0Sopenharmony_ci if (strcmp(trans->name, new_verb->name) == 0) { 2502d5ac70f0Sopenharmony_ci err = execute_sequence(uc_mgr, uc_mgr->active_verb, 2503d5ac70f0Sopenharmony_ci &trans->transition_list, 2504d5ac70f0Sopenharmony_ci &uc_mgr->active_verb->value_list, 2505d5ac70f0Sopenharmony_ci &uc_mgr->value_list, 2506d5ac70f0Sopenharmony_ci NULL); 2507d5ac70f0Sopenharmony_ci if (err >= 0) 2508d5ac70f0Sopenharmony_ci return 1; 2509d5ac70f0Sopenharmony_ci return err; 2510d5ac70f0Sopenharmony_ci } 2511d5ac70f0Sopenharmony_ci } 2512d5ac70f0Sopenharmony_ci return 0; 2513d5ac70f0Sopenharmony_ci} 2514d5ac70f0Sopenharmony_ci 2515d5ac70f0Sopenharmony_cistatic int set_verb_user(snd_use_case_mgr_t *uc_mgr, 2516d5ac70f0Sopenharmony_ci const char *verb_name) 2517d5ac70f0Sopenharmony_ci{ 2518d5ac70f0Sopenharmony_ci struct use_case_verb *verb; 2519d5ac70f0Sopenharmony_ci int err = 0; 2520d5ac70f0Sopenharmony_ci 2521d5ac70f0Sopenharmony_ci if (uc_mgr->active_verb && 2522d5ac70f0Sopenharmony_ci strcmp(uc_mgr->active_verb->name, verb_name) == 0) 2523d5ac70f0Sopenharmony_ci return 0; 2524d5ac70f0Sopenharmony_ci if (strcmp(verb_name, SND_USE_CASE_VERB_INACTIVE) != 0) { 2525d5ac70f0Sopenharmony_ci verb = find_verb(uc_mgr, verb_name); 2526d5ac70f0Sopenharmony_ci if (verb == NULL) 2527d5ac70f0Sopenharmony_ci return -ENOENT; 2528d5ac70f0Sopenharmony_ci } else { 2529d5ac70f0Sopenharmony_ci verb = NULL; 2530d5ac70f0Sopenharmony_ci } 2531d5ac70f0Sopenharmony_ci if (uc_mgr->active_verb) { 2532d5ac70f0Sopenharmony_ci err = handle_transition_verb(uc_mgr, verb); 2533d5ac70f0Sopenharmony_ci if (err == 0) { 2534d5ac70f0Sopenharmony_ci err = dismantle_use_case(uc_mgr); 2535d5ac70f0Sopenharmony_ci if (err < 0) 2536d5ac70f0Sopenharmony_ci return err; 2537d5ac70f0Sopenharmony_ci } else if (err == 1) { 2538d5ac70f0Sopenharmony_ci uc_mgr->active_verb = verb; 2539d5ac70f0Sopenharmony_ci verb = NULL; 2540d5ac70f0Sopenharmony_ci } else { 2541d5ac70f0Sopenharmony_ci verb = NULL; /* show error */ 2542d5ac70f0Sopenharmony_ci } 2543d5ac70f0Sopenharmony_ci } 2544d5ac70f0Sopenharmony_ci if (verb) { 2545d5ac70f0Sopenharmony_ci err = set_verb(uc_mgr, verb, 1); 2546d5ac70f0Sopenharmony_ci if (err < 0) 2547d5ac70f0Sopenharmony_ci uc_error("error: failed to initialize new use case: %s", 2548d5ac70f0Sopenharmony_ci verb_name); 2549d5ac70f0Sopenharmony_ci } 2550d5ac70f0Sopenharmony_ci return err; 2551d5ac70f0Sopenharmony_ci} 2552d5ac70f0Sopenharmony_ci 2553d5ac70f0Sopenharmony_ci 2554d5ac70f0Sopenharmony_cistatic int set_device_user(snd_use_case_mgr_t *uc_mgr, 2555d5ac70f0Sopenharmony_ci const char *device_name, 2556d5ac70f0Sopenharmony_ci int enable) 2557d5ac70f0Sopenharmony_ci{ 2558d5ac70f0Sopenharmony_ci struct use_case_device *device; 2559d5ac70f0Sopenharmony_ci 2560d5ac70f0Sopenharmony_ci if (uc_mgr->active_verb == NULL) 2561d5ac70f0Sopenharmony_ci return -ENOENT; 2562d5ac70f0Sopenharmony_ci device = find_device(uc_mgr, uc_mgr->active_verb, device_name, 1); 2563d5ac70f0Sopenharmony_ci if (device == NULL) 2564d5ac70f0Sopenharmony_ci return -ENOENT; 2565d5ac70f0Sopenharmony_ci return set_device(uc_mgr, device, enable); 2566d5ac70f0Sopenharmony_ci} 2567d5ac70f0Sopenharmony_ci 2568d5ac70f0Sopenharmony_cistatic int set_modifier_user(snd_use_case_mgr_t *uc_mgr, 2569d5ac70f0Sopenharmony_ci const char *modifier_name, 2570d5ac70f0Sopenharmony_ci int enable) 2571d5ac70f0Sopenharmony_ci{ 2572d5ac70f0Sopenharmony_ci struct use_case_modifier *modifier; 2573d5ac70f0Sopenharmony_ci 2574d5ac70f0Sopenharmony_ci if (uc_mgr->active_verb == NULL) 2575d5ac70f0Sopenharmony_ci return -ENOENT; 2576d5ac70f0Sopenharmony_ci 2577d5ac70f0Sopenharmony_ci modifier = find_modifier(uc_mgr, uc_mgr->active_verb, modifier_name, 1); 2578d5ac70f0Sopenharmony_ci if (modifier == NULL) 2579d5ac70f0Sopenharmony_ci return -ENOENT; 2580d5ac70f0Sopenharmony_ci return set_modifier(uc_mgr, modifier, enable); 2581d5ac70f0Sopenharmony_ci} 2582d5ac70f0Sopenharmony_ci 2583d5ac70f0Sopenharmony_cistatic int switch_device(snd_use_case_mgr_t *uc_mgr, 2584d5ac70f0Sopenharmony_ci const char *old_device, 2585d5ac70f0Sopenharmony_ci const char *new_device) 2586d5ac70f0Sopenharmony_ci{ 2587d5ac70f0Sopenharmony_ci struct use_case_device *xold, *xnew; 2588d5ac70f0Sopenharmony_ci struct transition_sequence *trans; 2589d5ac70f0Sopenharmony_ci struct list_head *pos; 2590d5ac70f0Sopenharmony_ci int err, seq_found = 0; 2591d5ac70f0Sopenharmony_ci 2592d5ac70f0Sopenharmony_ci if (uc_mgr->active_verb == NULL) 2593d5ac70f0Sopenharmony_ci return -ENOENT; 2594d5ac70f0Sopenharmony_ci if (device_status(uc_mgr, old_device) == 0) { 2595d5ac70f0Sopenharmony_ci uc_error("error: device %s not enabled", old_device); 2596d5ac70f0Sopenharmony_ci return -EINVAL; 2597d5ac70f0Sopenharmony_ci } 2598d5ac70f0Sopenharmony_ci if (device_status(uc_mgr, new_device) != 0) { 2599d5ac70f0Sopenharmony_ci uc_error("error: device %s already enabled", new_device); 2600d5ac70f0Sopenharmony_ci return -EINVAL; 2601d5ac70f0Sopenharmony_ci } 2602d5ac70f0Sopenharmony_ci xold = find_device(uc_mgr, uc_mgr->active_verb, old_device, 1); 2603d5ac70f0Sopenharmony_ci if (xold == NULL) 2604d5ac70f0Sopenharmony_ci return -ENOENT; 2605d5ac70f0Sopenharmony_ci list_del(&xold->active_list); 2606d5ac70f0Sopenharmony_ci xnew = find_device(uc_mgr, uc_mgr->active_verb, new_device, 1); 2607d5ac70f0Sopenharmony_ci list_add_tail(&xold->active_list, &uc_mgr->active_devices); 2608d5ac70f0Sopenharmony_ci if (xnew == NULL) 2609d5ac70f0Sopenharmony_ci return -ENOENT; 2610d5ac70f0Sopenharmony_ci err = 0; 2611d5ac70f0Sopenharmony_ci list_for_each(pos, &xold->transition_list) { 2612d5ac70f0Sopenharmony_ci trans = list_entry(pos, struct transition_sequence, list); 2613d5ac70f0Sopenharmony_ci if (strcmp(trans->name, new_device) == 0) { 2614d5ac70f0Sopenharmony_ci err = execute_sequence(uc_mgr, uc_mgr->active_verb, 2615d5ac70f0Sopenharmony_ci &trans->transition_list, 2616d5ac70f0Sopenharmony_ci &xold->value_list, 2617d5ac70f0Sopenharmony_ci &uc_mgr->active_verb->value_list, 2618d5ac70f0Sopenharmony_ci &uc_mgr->value_list); 2619d5ac70f0Sopenharmony_ci if (err >= 0) { 2620d5ac70f0Sopenharmony_ci list_del(&xold->active_list); 2621d5ac70f0Sopenharmony_ci list_add_tail(&xnew->active_list, &uc_mgr->active_devices); 2622d5ac70f0Sopenharmony_ci } 2623d5ac70f0Sopenharmony_ci seq_found = 1; 2624d5ac70f0Sopenharmony_ci break; 2625d5ac70f0Sopenharmony_ci } 2626d5ac70f0Sopenharmony_ci } 2627d5ac70f0Sopenharmony_ci if (!seq_found) { 2628d5ac70f0Sopenharmony_ci err = set_device(uc_mgr, xold, 0); 2629d5ac70f0Sopenharmony_ci if (err < 0) 2630d5ac70f0Sopenharmony_ci return err; 2631d5ac70f0Sopenharmony_ci err = set_device(uc_mgr, xnew, 1); 2632d5ac70f0Sopenharmony_ci if (err < 0) 2633d5ac70f0Sopenharmony_ci return err; 2634d5ac70f0Sopenharmony_ci } 2635d5ac70f0Sopenharmony_ci return err; 2636d5ac70f0Sopenharmony_ci} 2637d5ac70f0Sopenharmony_ci 2638d5ac70f0Sopenharmony_cistatic int switch_modifier(snd_use_case_mgr_t *uc_mgr, 2639d5ac70f0Sopenharmony_ci const char *old_modifier, 2640d5ac70f0Sopenharmony_ci const char *new_modifier) 2641d5ac70f0Sopenharmony_ci{ 2642d5ac70f0Sopenharmony_ci struct use_case_modifier *xold, *xnew; 2643d5ac70f0Sopenharmony_ci struct transition_sequence *trans; 2644d5ac70f0Sopenharmony_ci struct list_head *pos; 2645d5ac70f0Sopenharmony_ci int err, seq_found = 0; 2646d5ac70f0Sopenharmony_ci 2647d5ac70f0Sopenharmony_ci if (uc_mgr->active_verb == NULL) 2648d5ac70f0Sopenharmony_ci return -ENOENT; 2649d5ac70f0Sopenharmony_ci if (modifier_status(uc_mgr, old_modifier) == 0) { 2650d5ac70f0Sopenharmony_ci uc_error("error: modifier %s not enabled", old_modifier); 2651d5ac70f0Sopenharmony_ci return -EINVAL; 2652d5ac70f0Sopenharmony_ci } 2653d5ac70f0Sopenharmony_ci if (modifier_status(uc_mgr, new_modifier) != 0) { 2654d5ac70f0Sopenharmony_ci uc_error("error: modifier %s already enabled", new_modifier); 2655d5ac70f0Sopenharmony_ci return -EINVAL; 2656d5ac70f0Sopenharmony_ci } 2657d5ac70f0Sopenharmony_ci xold = find_modifier(uc_mgr, uc_mgr->active_verb, old_modifier, 1); 2658d5ac70f0Sopenharmony_ci if (xold == NULL) 2659d5ac70f0Sopenharmony_ci return -ENOENT; 2660d5ac70f0Sopenharmony_ci xnew = find_modifier(uc_mgr, uc_mgr->active_verb, new_modifier, 1); 2661d5ac70f0Sopenharmony_ci if (xnew == NULL) 2662d5ac70f0Sopenharmony_ci return -ENOENT; 2663d5ac70f0Sopenharmony_ci err = 0; 2664d5ac70f0Sopenharmony_ci list_for_each(pos, &xold->transition_list) { 2665d5ac70f0Sopenharmony_ci trans = list_entry(pos, struct transition_sequence, list); 2666d5ac70f0Sopenharmony_ci if (strcmp(trans->name, new_modifier) == 0) { 2667d5ac70f0Sopenharmony_ci err = execute_sequence(uc_mgr, uc_mgr->active_verb, 2668d5ac70f0Sopenharmony_ci &trans->transition_list, 2669d5ac70f0Sopenharmony_ci &xold->value_list, 2670d5ac70f0Sopenharmony_ci &uc_mgr->active_verb->value_list, 2671d5ac70f0Sopenharmony_ci &uc_mgr->value_list); 2672d5ac70f0Sopenharmony_ci if (err >= 0) { 2673d5ac70f0Sopenharmony_ci list_del(&xold->active_list); 2674d5ac70f0Sopenharmony_ci list_add_tail(&xnew->active_list, &uc_mgr->active_modifiers); 2675d5ac70f0Sopenharmony_ci } 2676d5ac70f0Sopenharmony_ci seq_found = 1; 2677d5ac70f0Sopenharmony_ci break; 2678d5ac70f0Sopenharmony_ci } 2679d5ac70f0Sopenharmony_ci } 2680d5ac70f0Sopenharmony_ci if (!seq_found) { 2681d5ac70f0Sopenharmony_ci err = set_modifier(uc_mgr, xold, 0); 2682d5ac70f0Sopenharmony_ci if (err < 0) 2683d5ac70f0Sopenharmony_ci return err; 2684d5ac70f0Sopenharmony_ci err = set_modifier(uc_mgr, xnew, 1); 2685d5ac70f0Sopenharmony_ci if (err < 0) 2686d5ac70f0Sopenharmony_ci return err; 2687d5ac70f0Sopenharmony_ci } 2688d5ac70f0Sopenharmony_ci return err; 2689d5ac70f0Sopenharmony_ci} 2690d5ac70f0Sopenharmony_ci 2691d5ac70f0Sopenharmony_ciint snd_use_case_set(snd_use_case_mgr_t *uc_mgr, 2692d5ac70f0Sopenharmony_ci const char *identifier, 2693d5ac70f0Sopenharmony_ci const char *value) 2694d5ac70f0Sopenharmony_ci{ 2695d5ac70f0Sopenharmony_ci char *str, *str1; 2696d5ac70f0Sopenharmony_ci int err = 0; 2697d5ac70f0Sopenharmony_ci 2698d5ac70f0Sopenharmony_ci pthread_mutex_lock(&uc_mgr->mutex); 2699d5ac70f0Sopenharmony_ci if (strcmp(identifier, "_fboot") == 0) 2700d5ac70f0Sopenharmony_ci err = set_fixedboot_user(uc_mgr, value); 2701d5ac70f0Sopenharmony_ci else if (strcmp(identifier, "_boot") == 0) 2702d5ac70f0Sopenharmony_ci err = set_boot_user(uc_mgr, value); 2703d5ac70f0Sopenharmony_ci else if (strcmp(identifier, "_defaults") == 0) 2704d5ac70f0Sopenharmony_ci err = set_defaults_user(uc_mgr, value); 2705d5ac70f0Sopenharmony_ci else if (strcmp(identifier, "_verb") == 0) 2706d5ac70f0Sopenharmony_ci err = set_verb_user(uc_mgr, value); 2707d5ac70f0Sopenharmony_ci else if (strcmp(identifier, "_enadev") == 0) 2708d5ac70f0Sopenharmony_ci err = set_device_user(uc_mgr, value, 1); 2709d5ac70f0Sopenharmony_ci else if (strcmp(identifier, "_disdev") == 0) 2710d5ac70f0Sopenharmony_ci err = set_device_user(uc_mgr, value, 0); 2711d5ac70f0Sopenharmony_ci else if (strcmp(identifier, "_enamod") == 0) 2712d5ac70f0Sopenharmony_ci err = set_modifier_user(uc_mgr, value, 1); 2713d5ac70f0Sopenharmony_ci else if (strcmp(identifier, "_dismod") == 0) 2714d5ac70f0Sopenharmony_ci err = set_modifier_user(uc_mgr, value, 0); 2715d5ac70f0Sopenharmony_ci else { 2716d5ac70f0Sopenharmony_ci str1 = strchr(identifier, '/'); 2717d5ac70f0Sopenharmony_ci if (str1) { 2718d5ac70f0Sopenharmony_ci str = strdup(str1 + 1); 2719d5ac70f0Sopenharmony_ci if (str == NULL) { 2720d5ac70f0Sopenharmony_ci err = -ENOMEM; 2721d5ac70f0Sopenharmony_ci goto __end; 2722d5ac70f0Sopenharmony_ci } 2723d5ac70f0Sopenharmony_ci } else { 2724d5ac70f0Sopenharmony_ci err = -EINVAL; 2725d5ac70f0Sopenharmony_ci goto __end; 2726d5ac70f0Sopenharmony_ci } 2727d5ac70f0Sopenharmony_ci if (check_identifier(identifier, "_swdev")) 2728d5ac70f0Sopenharmony_ci err = switch_device(uc_mgr, str, value); 2729d5ac70f0Sopenharmony_ci else if (check_identifier(identifier, "_swmod")) 2730d5ac70f0Sopenharmony_ci err = switch_modifier(uc_mgr, str, value); 2731d5ac70f0Sopenharmony_ci else 2732d5ac70f0Sopenharmony_ci err = -EINVAL; 2733d5ac70f0Sopenharmony_ci if (str) 2734d5ac70f0Sopenharmony_ci free(str); 2735d5ac70f0Sopenharmony_ci } 2736d5ac70f0Sopenharmony_ci __end: 2737d5ac70f0Sopenharmony_ci pthread_mutex_unlock(&uc_mgr->mutex); 2738d5ac70f0Sopenharmony_ci return err; 2739d5ac70f0Sopenharmony_ci} 2740d5ac70f0Sopenharmony_ci 2741d5ac70f0Sopenharmony_ci/** 2742d5ac70f0Sopenharmony_ci * \brief Parse control element identifier 2743d5ac70f0Sopenharmony_ci * \param dst Element identifier 2744d5ac70f0Sopenharmony_ci * \param ucm_id Use case identifier 2745d5ac70f0Sopenharmony_ci * \param value String value to be parsed 2746d5ac70f0Sopenharmony_ci * \return Zero if success, otherwise a negative error code 2747d5ac70f0Sopenharmony_ci */ 2748d5ac70f0Sopenharmony_ciint snd_use_case_parse_ctl_elem_id(snd_ctl_elem_id_t *dst, 2749d5ac70f0Sopenharmony_ci const char *ucm_id, 2750d5ac70f0Sopenharmony_ci const char *value) 2751d5ac70f0Sopenharmony_ci{ 2752d5ac70f0Sopenharmony_ci snd_ctl_elem_iface_t iface; 2753d5ac70f0Sopenharmony_ci int jack_control; 2754d5ac70f0Sopenharmony_ci 2755d5ac70f0Sopenharmony_ci jack_control = strcmp(ucm_id, "JackControl") == 0; 2756d5ac70f0Sopenharmony_ci if (!jack_control && 2757d5ac70f0Sopenharmony_ci strcmp(ucm_id, "PlaybackVolume") && 2758d5ac70f0Sopenharmony_ci strcmp(ucm_id, "PlaybackSwitch") && 2759d5ac70f0Sopenharmony_ci strcmp(ucm_id, "CaptureVolume") && 2760d5ac70f0Sopenharmony_ci strcmp(ucm_id, "CaptureSwitch")) 2761d5ac70f0Sopenharmony_ci return -EINVAL; 2762d5ac70f0Sopenharmony_ci snd_ctl_elem_id_clear(dst); 2763d5ac70f0Sopenharmony_ci if (strcasestr(value, "name=")) 2764d5ac70f0Sopenharmony_ci return __snd_ctl_ascii_elem_id_parse(dst, value, NULL); 2765d5ac70f0Sopenharmony_ci iface = SND_CTL_ELEM_IFACE_MIXER; 2766d5ac70f0Sopenharmony_ci if (jack_control) 2767d5ac70f0Sopenharmony_ci iface = SND_CTL_ELEM_IFACE_CARD; 2768d5ac70f0Sopenharmony_ci snd_ctl_elem_id_set_interface(dst, iface); 2769d5ac70f0Sopenharmony_ci snd_ctl_elem_id_set_name(dst, value); 2770d5ac70f0Sopenharmony_ci return 0; 2771d5ac70f0Sopenharmony_ci} 2772d5ac70f0Sopenharmony_ci 2773d5ac70f0Sopenharmony_ci/** 2774d5ac70f0Sopenharmony_ci * \brief Parse mixer element identifier 2775d5ac70f0Sopenharmony_ci * \param dst Simple mixer element identifier 2776d5ac70f0Sopenharmony_ci * \param ucm_id Use case identifier 2777d5ac70f0Sopenharmony_ci * \param value String value to be parsed 2778d5ac70f0Sopenharmony_ci * \return Zero if success, otherwise a negative error code 2779d5ac70f0Sopenharmony_ci */ 2780d5ac70f0Sopenharmony_ciint snd_use_case_parse_selem_id(snd_mixer_selem_id_t *dst, 2781d5ac70f0Sopenharmony_ci const char *ucm_id, 2782d5ac70f0Sopenharmony_ci const char *value) 2783d5ac70f0Sopenharmony_ci{ 2784d5ac70f0Sopenharmony_ci#ifdef BUILD_MIXER 2785d5ac70f0Sopenharmony_ci if (strcmp(ucm_id, "PlaybackMixerId") == 0 || 2786d5ac70f0Sopenharmony_ci strcmp(ucm_id, "CaptureMixerId") == 0) 2787d5ac70f0Sopenharmony_ci return snd_mixer_selem_id_parse(dst, value); 2788d5ac70f0Sopenharmony_ci#endif 2789d5ac70f0Sopenharmony_ci return -EINVAL; 2790d5ac70f0Sopenharmony_ci} 2791