1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file control/namehint.c 3d5ac70f0Sopenharmony_ci * \ingroup Configuration 4d5ac70f0Sopenharmony_ci * \brief Give device name hints 5d5ac70f0Sopenharmony_ci * \author Jaroslav Kysela <perex@perex.cz> 6d5ac70f0Sopenharmony_ci * \date 2006 7d5ac70f0Sopenharmony_ci */ 8d5ac70f0Sopenharmony_ci/* 9d5ac70f0Sopenharmony_ci * Give device name hints - main file 10d5ac70f0Sopenharmony_ci * Copyright (c) 2006 by Jaroslav Kysela <perex@perex.cz> 11d5ac70f0Sopenharmony_ci * 12d5ac70f0Sopenharmony_ci * 13d5ac70f0Sopenharmony_ci * This library is free software; you can redistribute it and/or modify 14d5ac70f0Sopenharmony_ci * it under the terms of the GNU Lesser General Public License as 15d5ac70f0Sopenharmony_ci * published by the Free Software Foundation; either version 2.1 of 16d5ac70f0Sopenharmony_ci * the License, or (at your option) any later version. 17d5ac70f0Sopenharmony_ci * 18d5ac70f0Sopenharmony_ci * This program is distributed in the hope that it will be useful, 19d5ac70f0Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 20d5ac70f0Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21d5ac70f0Sopenharmony_ci * GNU Lesser General Public License for more details. 22d5ac70f0Sopenharmony_ci * 23d5ac70f0Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public 24d5ac70f0Sopenharmony_ci * License along with this library; if not, write to the Free Software 25d5ac70f0Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 26d5ac70f0Sopenharmony_ci * 27d5ac70f0Sopenharmony_ci */ 28d5ac70f0Sopenharmony_ci 29d5ac70f0Sopenharmony_ci#include "local.h" 30d5ac70f0Sopenharmony_ci 31d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 32d5ac70f0Sopenharmony_ci#define DEV_SKIP 9999 /* some non-existing device number */ 33d5ac70f0Sopenharmony_cistruct hint_list { 34d5ac70f0Sopenharmony_ci char **list; 35d5ac70f0Sopenharmony_ci unsigned int count; 36d5ac70f0Sopenharmony_ci unsigned int allocated; 37d5ac70f0Sopenharmony_ci const char *siface; 38d5ac70f0Sopenharmony_ci snd_ctl_elem_iface_t iface; 39d5ac70f0Sopenharmony_ci snd_ctl_t *ctl; 40d5ac70f0Sopenharmony_ci snd_ctl_card_info_t *info; 41d5ac70f0Sopenharmony_ci int card; 42d5ac70f0Sopenharmony_ci int device; 43d5ac70f0Sopenharmony_ci long device_input; 44d5ac70f0Sopenharmony_ci long device_output; 45d5ac70f0Sopenharmony_ci int stream; 46d5ac70f0Sopenharmony_ci int show_all; 47d5ac70f0Sopenharmony_ci char *cardname; 48d5ac70f0Sopenharmony_ci}; 49d5ac70f0Sopenharmony_ci#endif 50d5ac70f0Sopenharmony_ci 51d5ac70f0Sopenharmony_cistatic int hint_list_add(struct hint_list *list, 52d5ac70f0Sopenharmony_ci const char *name, 53d5ac70f0Sopenharmony_ci const char *description) 54d5ac70f0Sopenharmony_ci{ 55d5ac70f0Sopenharmony_ci char *x; 56d5ac70f0Sopenharmony_ci 57d5ac70f0Sopenharmony_ci if (list->count + 1 >= list->allocated) { 58d5ac70f0Sopenharmony_ci char **n = realloc(list->list, (list->allocated + 10) * sizeof(char *)); 59d5ac70f0Sopenharmony_ci if (n == NULL) 60d5ac70f0Sopenharmony_ci return -ENOMEM; 61d5ac70f0Sopenharmony_ci memset(n + list->allocated, 0, 10 * sizeof(*n)); 62d5ac70f0Sopenharmony_ci list->allocated += 10; 63d5ac70f0Sopenharmony_ci list->list = n; 64d5ac70f0Sopenharmony_ci } 65d5ac70f0Sopenharmony_ci if (name == NULL) { 66d5ac70f0Sopenharmony_ci x = NULL; 67d5ac70f0Sopenharmony_ci } else { 68d5ac70f0Sopenharmony_ci x = malloc(4 + strlen(name) + (description != NULL ? (4 + strlen(description) + 1) : 0) + 1); 69d5ac70f0Sopenharmony_ci if (x == NULL) 70d5ac70f0Sopenharmony_ci return -ENOMEM; 71d5ac70f0Sopenharmony_ci memcpy(x, "NAME", 4); 72d5ac70f0Sopenharmony_ci strcpy(x + 4, name); 73d5ac70f0Sopenharmony_ci if (description != NULL) { 74d5ac70f0Sopenharmony_ci strcat(x, "|DESC"); 75d5ac70f0Sopenharmony_ci strcat(x, description); 76d5ac70f0Sopenharmony_ci } 77d5ac70f0Sopenharmony_ci } 78d5ac70f0Sopenharmony_ci list->list[list->count++] = x; 79d5ac70f0Sopenharmony_ci return 0; 80d5ac70f0Sopenharmony_ci} 81d5ac70f0Sopenharmony_ci 82d5ac70f0Sopenharmony_ci/** 83d5ac70f0Sopenharmony_ci * Add a namehint from string given in a user configuration file 84d5ac70f0Sopenharmony_ci */ 85d5ac70f0Sopenharmony_cistatic int hint_list_add_custom(struct hint_list *list, 86d5ac70f0Sopenharmony_ci const char *entry) 87d5ac70f0Sopenharmony_ci{ 88d5ac70f0Sopenharmony_ci int err; 89d5ac70f0Sopenharmony_ci const char *sep; 90d5ac70f0Sopenharmony_ci char *name; 91d5ac70f0Sopenharmony_ci 92d5ac70f0Sopenharmony_ci assert(entry); 93d5ac70f0Sopenharmony_ci 94d5ac70f0Sopenharmony_ci sep = strchr(entry, '|'); 95d5ac70f0Sopenharmony_ci if (sep == NULL) 96d5ac70f0Sopenharmony_ci return hint_list_add(list, entry, NULL); 97d5ac70f0Sopenharmony_ci 98d5ac70f0Sopenharmony_ci name = strndup(entry, sep - entry); 99d5ac70f0Sopenharmony_ci if (name == NULL) 100d5ac70f0Sopenharmony_ci return -ENOMEM; 101d5ac70f0Sopenharmony_ci 102d5ac70f0Sopenharmony_ci err = hint_list_add(list, name, sep + 1); 103d5ac70f0Sopenharmony_ci free(name); 104d5ac70f0Sopenharmony_ci return err; 105d5ac70f0Sopenharmony_ci} 106d5ac70f0Sopenharmony_ci 107d5ac70f0Sopenharmony_cistatic void zero_handler(const char *file ATTRIBUTE_UNUSED, 108d5ac70f0Sopenharmony_ci int line ATTRIBUTE_UNUSED, 109d5ac70f0Sopenharmony_ci const char *function ATTRIBUTE_UNUSED, 110d5ac70f0Sopenharmony_ci int err ATTRIBUTE_UNUSED, 111d5ac70f0Sopenharmony_ci const char *fmt ATTRIBUTE_UNUSED, 112d5ac70f0Sopenharmony_ci va_list arg ATTRIBUTE_UNUSED) 113d5ac70f0Sopenharmony_ci{ 114d5ac70f0Sopenharmony_ci} 115d5ac70f0Sopenharmony_ci 116d5ac70f0Sopenharmony_cistatic int get_dev_name1(struct hint_list *list, char **res, int device, 117d5ac70f0Sopenharmony_ci int stream) 118d5ac70f0Sopenharmony_ci{ 119d5ac70f0Sopenharmony_ci *res = NULL; 120d5ac70f0Sopenharmony_ci if (device < 0 || device == DEV_SKIP) 121d5ac70f0Sopenharmony_ci return 0; 122d5ac70f0Sopenharmony_ci switch (list->iface) { 123d5ac70f0Sopenharmony_ci#ifdef BUILD_HWDEP 124d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_IFACE_HWDEP: 125d5ac70f0Sopenharmony_ci { 126d5ac70f0Sopenharmony_ci snd_hwdep_info_t info = {0}; 127d5ac70f0Sopenharmony_ci snd_hwdep_info_set_device(&info, device); 128d5ac70f0Sopenharmony_ci if (snd_ctl_hwdep_info(list->ctl, &info) < 0) 129d5ac70f0Sopenharmony_ci return 0; 130d5ac70f0Sopenharmony_ci *res = strdup(snd_hwdep_info_get_name(&info)); 131d5ac70f0Sopenharmony_ci return 0; 132d5ac70f0Sopenharmony_ci } 133d5ac70f0Sopenharmony_ci#endif 134d5ac70f0Sopenharmony_ci#ifdef BUILD_PCM 135d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_IFACE_PCM: 136d5ac70f0Sopenharmony_ci { 137d5ac70f0Sopenharmony_ci snd_pcm_info_t info = {0}; 138d5ac70f0Sopenharmony_ci snd_pcm_info_set_device(&info, device); 139d5ac70f0Sopenharmony_ci snd_pcm_info_set_stream(&info, stream ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK); 140d5ac70f0Sopenharmony_ci if (snd_ctl_pcm_info(list->ctl, &info) < 0) 141d5ac70f0Sopenharmony_ci return 0; 142d5ac70f0Sopenharmony_ci switch (snd_pcm_info_get_class(&info)) { 143d5ac70f0Sopenharmony_ci case SND_PCM_CLASS_MODEM: 144d5ac70f0Sopenharmony_ci case SND_PCM_CLASS_DIGITIZER: 145d5ac70f0Sopenharmony_ci return -ENODEV; 146d5ac70f0Sopenharmony_ci default: 147d5ac70f0Sopenharmony_ci break; 148d5ac70f0Sopenharmony_ci } 149d5ac70f0Sopenharmony_ci *res = strdup(snd_pcm_info_get_name(&info)); 150d5ac70f0Sopenharmony_ci return 0; 151d5ac70f0Sopenharmony_ci } 152d5ac70f0Sopenharmony_ci#endif 153d5ac70f0Sopenharmony_ci#ifdef BUILD_RAWMIDI 154d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_IFACE_RAWMIDI: 155d5ac70f0Sopenharmony_ci { 156d5ac70f0Sopenharmony_ci snd_rawmidi_info_t info = {0}; 157d5ac70f0Sopenharmony_ci snd_rawmidi_info_set_device(&info, device); 158d5ac70f0Sopenharmony_ci snd_rawmidi_info_set_stream(&info, stream ? SND_RAWMIDI_STREAM_INPUT : SND_RAWMIDI_STREAM_OUTPUT); 159d5ac70f0Sopenharmony_ci if (snd_ctl_rawmidi_info(list->ctl, &info) < 0) 160d5ac70f0Sopenharmony_ci return 0; 161d5ac70f0Sopenharmony_ci *res = strdup(snd_rawmidi_info_get_name(&info)); 162d5ac70f0Sopenharmony_ci return 0; 163d5ac70f0Sopenharmony_ci } 164d5ac70f0Sopenharmony_ci#endif 165d5ac70f0Sopenharmony_ci default: 166d5ac70f0Sopenharmony_ci return 0; 167d5ac70f0Sopenharmony_ci } 168d5ac70f0Sopenharmony_ci} 169d5ac70f0Sopenharmony_ci 170d5ac70f0Sopenharmony_cistatic char *get_dev_name(struct hint_list *list) 171d5ac70f0Sopenharmony_ci{ 172d5ac70f0Sopenharmony_ci char *str1, *str2, *res; 173d5ac70f0Sopenharmony_ci int device; 174d5ac70f0Sopenharmony_ci 175d5ac70f0Sopenharmony_ci device = list->device_input >= 0 ? list->device_input : list->device; 176d5ac70f0Sopenharmony_ci if (get_dev_name1(list, &str1, device, 1) < 0) 177d5ac70f0Sopenharmony_ci return NULL; 178d5ac70f0Sopenharmony_ci device = list->device_output >= 0 ? list->device_output : list->device; 179d5ac70f0Sopenharmony_ci if (get_dev_name1(list, &str2, device, 0) < 0) { 180d5ac70f0Sopenharmony_ci if (str1) 181d5ac70f0Sopenharmony_ci free(str1); 182d5ac70f0Sopenharmony_ci return NULL; 183d5ac70f0Sopenharmony_ci } 184d5ac70f0Sopenharmony_ci if (str1 != NULL || str2 != NULL) { 185d5ac70f0Sopenharmony_ci if (str1 != NULL && str2 != NULL) { 186d5ac70f0Sopenharmony_ci if (strcmp(str1, str2) == 0) { 187d5ac70f0Sopenharmony_ci res = malloc(strlen(list->cardname) + strlen(str2) + 3); 188d5ac70f0Sopenharmony_ci if (res != NULL) { 189d5ac70f0Sopenharmony_ci strcpy(res, list->cardname); 190d5ac70f0Sopenharmony_ci strcat(res, ", "); 191d5ac70f0Sopenharmony_ci strcat(res, str2); 192d5ac70f0Sopenharmony_ci } 193d5ac70f0Sopenharmony_ci } else { 194d5ac70f0Sopenharmony_ci res = malloc(strlen(list->cardname) + strlen(str2) + strlen(str1) + 6); 195d5ac70f0Sopenharmony_ci if (res != NULL) { 196d5ac70f0Sopenharmony_ci strcpy(res, list->cardname); 197d5ac70f0Sopenharmony_ci strcat(res, ", "); 198d5ac70f0Sopenharmony_ci strcat(res, str2); 199d5ac70f0Sopenharmony_ci strcat(res, " / "); 200d5ac70f0Sopenharmony_ci strcat(res, str1); 201d5ac70f0Sopenharmony_ci } 202d5ac70f0Sopenharmony_ci } 203d5ac70f0Sopenharmony_ci free(str2); 204d5ac70f0Sopenharmony_ci free(str1); 205d5ac70f0Sopenharmony_ci return res; 206d5ac70f0Sopenharmony_ci } else { 207d5ac70f0Sopenharmony_ci if (str1 != NULL) { 208d5ac70f0Sopenharmony_ci str2 = "Input"; 209d5ac70f0Sopenharmony_ci } else { 210d5ac70f0Sopenharmony_ci str1 = str2; 211d5ac70f0Sopenharmony_ci str2 = "Output"; 212d5ac70f0Sopenharmony_ci } 213d5ac70f0Sopenharmony_ci res = malloc(strlen(list->cardname) + strlen(str1) + 19); 214d5ac70f0Sopenharmony_ci if (res == NULL) { 215d5ac70f0Sopenharmony_ci free(str1); 216d5ac70f0Sopenharmony_ci return NULL; 217d5ac70f0Sopenharmony_ci } 218d5ac70f0Sopenharmony_ci strcpy(res, list->cardname); 219d5ac70f0Sopenharmony_ci strcat(res, ", "); 220d5ac70f0Sopenharmony_ci strcat(res, str1); 221d5ac70f0Sopenharmony_ci strcat(res, "|IOID"); 222d5ac70f0Sopenharmony_ci strcat(res, str2); 223d5ac70f0Sopenharmony_ci free(str1); 224d5ac70f0Sopenharmony_ci return res; 225d5ac70f0Sopenharmony_ci } 226d5ac70f0Sopenharmony_ci } 227d5ac70f0Sopenharmony_ci /* if the specified device doesn't exist, skip this entry */ 228d5ac70f0Sopenharmony_ci if (list->device >= 0 || list->device_input >= 0 || list->device_output >= 0) 229d5ac70f0Sopenharmony_ci return NULL; 230d5ac70f0Sopenharmony_ci return strdup(list->cardname); 231d5ac70f0Sopenharmony_ci} 232d5ac70f0Sopenharmony_ci 233d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 234d5ac70f0Sopenharmony_ci#define BUF_SIZE 128 235d5ac70f0Sopenharmony_ci#endif 236d5ac70f0Sopenharmony_ci 237d5ac70f0Sopenharmony_cistatic int try_config(snd_config_t *config, 238d5ac70f0Sopenharmony_ci struct hint_list *list, 239d5ac70f0Sopenharmony_ci const char *base, 240d5ac70f0Sopenharmony_ci const char *name) 241d5ac70f0Sopenharmony_ci{ 242d5ac70f0Sopenharmony_ci snd_local_error_handler_t eh; 243d5ac70f0Sopenharmony_ci snd_config_t *res = NULL, *cfg, *cfg1, *n; 244d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 245d5ac70f0Sopenharmony_ci char *buf, *buf1 = NULL, *buf2; 246d5ac70f0Sopenharmony_ci const char *str; 247d5ac70f0Sopenharmony_ci int err = 0, level; 248d5ac70f0Sopenharmony_ci long dev = list->device; 249d5ac70f0Sopenharmony_ci int cleanup_res = 0; 250d5ac70f0Sopenharmony_ci 251d5ac70f0Sopenharmony_ci list->device_input = -1; 252d5ac70f0Sopenharmony_ci list->device_output = -1; 253d5ac70f0Sopenharmony_ci buf = malloc(BUF_SIZE); 254d5ac70f0Sopenharmony_ci if (buf == NULL) 255d5ac70f0Sopenharmony_ci return -ENOMEM; 256d5ac70f0Sopenharmony_ci sprintf(buf, "%s.%s", base, name); 257d5ac70f0Sopenharmony_ci /* look for redirection */ 258d5ac70f0Sopenharmony_ci if (snd_config_search(config, buf, &cfg) >= 0 && 259d5ac70f0Sopenharmony_ci snd_config_get_string(cfg, &str) >= 0 && 260d5ac70f0Sopenharmony_ci ((strncmp(base, str, strlen(base)) == 0 && 261d5ac70f0Sopenharmony_ci str[strlen(base)] == '.') || strchr(str, '.') == NULL)) 262d5ac70f0Sopenharmony_ci goto __skip_add; 263d5ac70f0Sopenharmony_ci if (list->card >= 0 && list->device >= 0) 264d5ac70f0Sopenharmony_ci sprintf(buf, "%s:CARD=%s,DEV=%i", name, snd_ctl_card_info_get_id(list->info), list->device); 265d5ac70f0Sopenharmony_ci else if (list->card >= 0) 266d5ac70f0Sopenharmony_ci sprintf(buf, "%s:CARD=%s", name, snd_ctl_card_info_get_id(list->info)); 267d5ac70f0Sopenharmony_ci else 268d5ac70f0Sopenharmony_ci strcpy(buf, name); 269d5ac70f0Sopenharmony_ci eh = snd_lib_error_set_local(&zero_handler); 270d5ac70f0Sopenharmony_ci err = snd_config_search_definition(config, base, buf, &res); 271d5ac70f0Sopenharmony_ci snd_lib_error_set_local(eh); 272d5ac70f0Sopenharmony_ci if (err < 0) 273d5ac70f0Sopenharmony_ci goto __skip_add; 274d5ac70f0Sopenharmony_ci cleanup_res = 1; 275d5ac70f0Sopenharmony_ci err = -EINVAL; 276d5ac70f0Sopenharmony_ci if (snd_config_get_type(res) != SND_CONFIG_TYPE_COMPOUND) 277d5ac70f0Sopenharmony_ci goto __cleanup; 278d5ac70f0Sopenharmony_ci if (snd_config_search(res, "type", NULL) < 0) 279d5ac70f0Sopenharmony_ci goto __cleanup; 280d5ac70f0Sopenharmony_ci 281d5ac70f0Sopenharmony_ci#if 0 /* for debug purposes */ 282d5ac70f0Sopenharmony_ci { 283d5ac70f0Sopenharmony_ci snd_output_t *out; 284d5ac70f0Sopenharmony_ci fprintf(stderr, "********* PCM '%s':\n", buf); 285d5ac70f0Sopenharmony_ci snd_output_stdio_attach(&out, stderr, 0); 286d5ac70f0Sopenharmony_ci snd_config_save(res, out); 287d5ac70f0Sopenharmony_ci snd_output_close(out); 288d5ac70f0Sopenharmony_ci fprintf(stderr, "\n"); 289d5ac70f0Sopenharmony_ci } 290d5ac70f0Sopenharmony_ci#endif 291d5ac70f0Sopenharmony_ci 292d5ac70f0Sopenharmony_ci cfg1 = res; 293d5ac70f0Sopenharmony_ci level = 0; 294d5ac70f0Sopenharmony_ci __hint: 295d5ac70f0Sopenharmony_ci level++; 296d5ac70f0Sopenharmony_ci if (snd_config_search(cfg1, "type", &cfg) >= 0 && 297d5ac70f0Sopenharmony_ci snd_config_get_string(cfg, &str) >= 0 && 298d5ac70f0Sopenharmony_ci strcmp(str, "hw") == 0) { 299d5ac70f0Sopenharmony_ci if (snd_config_search(cfg1, "device", &cfg) >= 0) { 300d5ac70f0Sopenharmony_ci if (snd_config_get_integer(cfg, &dev) < 0) { 301d5ac70f0Sopenharmony_ci SNDERR("(%s) device must be an integer", buf); 302d5ac70f0Sopenharmony_ci err = -EINVAL; 303d5ac70f0Sopenharmony_ci goto __cleanup; 304d5ac70f0Sopenharmony_ci } 305d5ac70f0Sopenharmony_ci } 306d5ac70f0Sopenharmony_ci } 307d5ac70f0Sopenharmony_ci 308d5ac70f0Sopenharmony_ci if (snd_config_search(cfg1, "hint", &cfg) >= 0) { 309d5ac70f0Sopenharmony_ci if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) { 310d5ac70f0Sopenharmony_ci SNDERR("hint (%s) must be a compound", buf); 311d5ac70f0Sopenharmony_ci err = -EINVAL; 312d5ac70f0Sopenharmony_ci goto __cleanup; 313d5ac70f0Sopenharmony_ci } 314d5ac70f0Sopenharmony_ci if (list->card < 0 && 315d5ac70f0Sopenharmony_ci snd_config_search(cfg, "omit_noargs", &n) >= 0 && 316d5ac70f0Sopenharmony_ci snd_config_get_bool(n) > 0) 317d5ac70f0Sopenharmony_ci goto __skip_add; 318d5ac70f0Sopenharmony_ci if (level == 1 && 319d5ac70f0Sopenharmony_ci snd_config_search(cfg, "show", &n) >= 0 && 320d5ac70f0Sopenharmony_ci snd_config_get_bool(n) <= 0) 321d5ac70f0Sopenharmony_ci goto __skip_add; 322d5ac70f0Sopenharmony_ci if (buf1 == NULL && 323d5ac70f0Sopenharmony_ci snd_config_search(cfg, "description", &n) >= 0 && 324d5ac70f0Sopenharmony_ci snd_config_get_string(n, &str) >= 0) { 325d5ac70f0Sopenharmony_ci buf1 = strdup(str); 326d5ac70f0Sopenharmony_ci if (buf1 == NULL) { 327d5ac70f0Sopenharmony_ci err = -ENOMEM; 328d5ac70f0Sopenharmony_ci goto __cleanup; 329d5ac70f0Sopenharmony_ci } 330d5ac70f0Sopenharmony_ci } 331d5ac70f0Sopenharmony_ci if (snd_config_search(cfg, "device", &n) >= 0) { 332d5ac70f0Sopenharmony_ci if (snd_config_get_integer(n, &dev) < 0) { 333d5ac70f0Sopenharmony_ci SNDERR("(%s) device must be an integer", buf); 334d5ac70f0Sopenharmony_ci err = -EINVAL; 335d5ac70f0Sopenharmony_ci goto __cleanup; 336d5ac70f0Sopenharmony_ci } 337d5ac70f0Sopenharmony_ci list->device_input = dev; 338d5ac70f0Sopenharmony_ci list->device_output = dev; 339d5ac70f0Sopenharmony_ci } 340d5ac70f0Sopenharmony_ci if (snd_config_search(cfg, "device_input", &n) >= 0) { 341d5ac70f0Sopenharmony_ci if (snd_config_get_integer(n, &list->device_input) < 0) { 342d5ac70f0Sopenharmony_ci SNDERR("(%s) device_input must be an integer", buf); 343d5ac70f0Sopenharmony_ci err = -EINVAL; 344d5ac70f0Sopenharmony_ci goto __cleanup; 345d5ac70f0Sopenharmony_ci } 346d5ac70f0Sopenharmony_ci /* skip the counterpart if only a single direction is defined */ 347d5ac70f0Sopenharmony_ci if (list->device_output < 0) 348d5ac70f0Sopenharmony_ci list->device_output = DEV_SKIP; 349d5ac70f0Sopenharmony_ci } 350d5ac70f0Sopenharmony_ci if (snd_config_search(cfg, "device_output", &n) >= 0) { 351d5ac70f0Sopenharmony_ci if (snd_config_get_integer(n, &list->device_output) < 0) { 352d5ac70f0Sopenharmony_ci SNDERR("(%s) device_output must be an integer", buf); 353d5ac70f0Sopenharmony_ci err = -EINVAL; 354d5ac70f0Sopenharmony_ci goto __cleanup; 355d5ac70f0Sopenharmony_ci } 356d5ac70f0Sopenharmony_ci /* skip the counterpart if only a single direction is defined */ 357d5ac70f0Sopenharmony_ci if (list->device_input < 0) 358d5ac70f0Sopenharmony_ci list->device_input = DEV_SKIP; 359d5ac70f0Sopenharmony_ci } 360d5ac70f0Sopenharmony_ci } else if (level == 1 && !list->show_all) 361d5ac70f0Sopenharmony_ci goto __skip_add; 362d5ac70f0Sopenharmony_ci if (snd_config_search(cfg1, "slave", &cfg) >= 0 && 363d5ac70f0Sopenharmony_ci snd_config_search(cfg, base, &cfg1) >= 0) 364d5ac70f0Sopenharmony_ci goto __hint; 365d5ac70f0Sopenharmony_ci snd_config_delete(res); 366d5ac70f0Sopenharmony_ci res = NULL; 367d5ac70f0Sopenharmony_ci cleanup_res = 0; 368d5ac70f0Sopenharmony_ci if (strchr(buf, ':') != NULL) 369d5ac70f0Sopenharmony_ci goto __ok; 370d5ac70f0Sopenharmony_ci /* find, if all parameters have a default, */ 371d5ac70f0Sopenharmony_ci /* otherwise filter this definition */ 372d5ac70f0Sopenharmony_ci eh = snd_lib_error_set_local(&zero_handler); 373d5ac70f0Sopenharmony_ci err = snd_config_search_alias_hooks(config, base, buf, &res); 374d5ac70f0Sopenharmony_ci snd_lib_error_set_local(eh); 375d5ac70f0Sopenharmony_ci if (err < 0) 376d5ac70f0Sopenharmony_ci goto __cleanup; 377d5ac70f0Sopenharmony_ci if (snd_config_search(res, "@args", &cfg) >= 0) { 378d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, cfg) { 379d5ac70f0Sopenharmony_ci /* skip the argument list */ 380d5ac70f0Sopenharmony_ci if (snd_config_get_id(snd_config_iterator_entry(i), &str) < 0) 381d5ac70f0Sopenharmony_ci continue; 382d5ac70f0Sopenharmony_ci while (*str && *str >= '0' && *str <= '9') str++; 383d5ac70f0Sopenharmony_ci if (*str == '\0') 384d5ac70f0Sopenharmony_ci continue; 385d5ac70f0Sopenharmony_ci /* the argument definition must have the default */ 386d5ac70f0Sopenharmony_ci if (snd_config_search(snd_config_iterator_entry(i), 387d5ac70f0Sopenharmony_ci "default", NULL) < 0) { 388d5ac70f0Sopenharmony_ci err = -EINVAL; 389d5ac70f0Sopenharmony_ci goto __cleanup; 390d5ac70f0Sopenharmony_ci } 391d5ac70f0Sopenharmony_ci } 392d5ac70f0Sopenharmony_ci } 393d5ac70f0Sopenharmony_ci __ok: 394d5ac70f0Sopenharmony_ci err = 0; 395d5ac70f0Sopenharmony_ci __cleanup: 396d5ac70f0Sopenharmony_ci if (err >= 0) { 397d5ac70f0Sopenharmony_ci list->device = dev; 398d5ac70f0Sopenharmony_ci str = list->card >= 0 ? get_dev_name(list) : NULL; 399d5ac70f0Sopenharmony_ci if (str != NULL) { 400d5ac70f0Sopenharmony_ci level = (buf1 == NULL ? 0 : strlen(buf1)) + 1 + strlen(str); 401d5ac70f0Sopenharmony_ci buf2 = realloc((char *)str, level + 1); 402d5ac70f0Sopenharmony_ci if (buf2 != NULL) { 403d5ac70f0Sopenharmony_ci if (buf1 != NULL) { 404d5ac70f0Sopenharmony_ci str = strchr(buf2, '|'); 405d5ac70f0Sopenharmony_ci if (str != NULL) 406d5ac70f0Sopenharmony_ci memmove(buf2 + (level - strlen(str)), str, strlen(str)); 407d5ac70f0Sopenharmony_ci else 408d5ac70f0Sopenharmony_ci str = buf2 + strlen(buf2); 409d5ac70f0Sopenharmony_ci *(char *)str++ = '\n'; 410d5ac70f0Sopenharmony_ci memcpy((char *)str, buf1, strlen(buf1)); 411d5ac70f0Sopenharmony_ci buf2[level] = '\0'; 412d5ac70f0Sopenharmony_ci free(buf1); 413d5ac70f0Sopenharmony_ci } 414d5ac70f0Sopenharmony_ci buf1 = buf2; 415d5ac70f0Sopenharmony_ci } else { 416d5ac70f0Sopenharmony_ci free((char *)str); 417d5ac70f0Sopenharmony_ci } 418d5ac70f0Sopenharmony_ci } else if (list->device >= 0) 419d5ac70f0Sopenharmony_ci goto __skip_add; 420d5ac70f0Sopenharmony_ci err = hint_list_add(list, buf, buf1); 421d5ac70f0Sopenharmony_ci } 422d5ac70f0Sopenharmony_ci __skip_add: 423d5ac70f0Sopenharmony_ci if (res && cleanup_res) 424d5ac70f0Sopenharmony_ci snd_config_delete(res); 425d5ac70f0Sopenharmony_ci if (buf1) 426d5ac70f0Sopenharmony_ci free(buf1); 427d5ac70f0Sopenharmony_ci free(buf); 428d5ac70f0Sopenharmony_ci return err; 429d5ac70f0Sopenharmony_ci} 430d5ac70f0Sopenharmony_ci 431d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 432d5ac70f0Sopenharmony_ci#define IFACE(v, fcn) [SND_CTL_ELEM_IFACE_##v] = (next_devices_t)fcn 433d5ac70f0Sopenharmony_ci 434d5ac70f0Sopenharmony_citypedef int (*next_devices_t)(snd_ctl_t *, int *); 435d5ac70f0Sopenharmony_ci 436d5ac70f0Sopenharmony_cistatic const next_devices_t next_devices[] = { 437d5ac70f0Sopenharmony_ci IFACE(CARD, NULL), 438d5ac70f0Sopenharmony_ci IFACE(HWDEP, snd_ctl_hwdep_next_device), 439d5ac70f0Sopenharmony_ci IFACE(MIXER, NULL), 440d5ac70f0Sopenharmony_ci IFACE(PCM, snd_ctl_pcm_next_device), 441d5ac70f0Sopenharmony_ci IFACE(RAWMIDI, snd_ctl_rawmidi_next_device), 442d5ac70f0Sopenharmony_ci IFACE(TIMER, NULL), 443d5ac70f0Sopenharmony_ci IFACE(SEQUENCER, NULL) 444d5ac70f0Sopenharmony_ci}; 445d5ac70f0Sopenharmony_ci#endif 446d5ac70f0Sopenharmony_ci 447d5ac70f0Sopenharmony_cistatic int add_card(snd_config_t *config, snd_config_t *rw_config, struct hint_list *list, int card) 448d5ac70f0Sopenharmony_ci{ 449d5ac70f0Sopenharmony_ci int err, ok; 450d5ac70f0Sopenharmony_ci snd_config_t *conf, *n; 451d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 452d5ac70f0Sopenharmony_ci const char *str; 453d5ac70f0Sopenharmony_ci char ctl_name[16]; 454d5ac70f0Sopenharmony_ci snd_ctl_card_info_t info = {0}; 455d5ac70f0Sopenharmony_ci int device, max_device = 0; 456d5ac70f0Sopenharmony_ci 457d5ac70f0Sopenharmony_ci list->info = &info; 458d5ac70f0Sopenharmony_ci err = snd_config_search(config, list->siface, &conf); 459d5ac70f0Sopenharmony_ci if (err < 0) 460d5ac70f0Sopenharmony_ci return err; 461d5ac70f0Sopenharmony_ci sprintf(ctl_name, "hw:%i", card); 462d5ac70f0Sopenharmony_ci err = snd_ctl_open(&list->ctl, ctl_name, 0); 463d5ac70f0Sopenharmony_ci if (err < 0) 464d5ac70f0Sopenharmony_ci return err; 465d5ac70f0Sopenharmony_ci err = snd_ctl_card_info(list->ctl, &info); 466d5ac70f0Sopenharmony_ci if (err < 0) 467d5ac70f0Sopenharmony_ci goto __error; 468d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, conf) { 469d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 470d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &str) < 0) 471d5ac70f0Sopenharmony_ci continue; 472d5ac70f0Sopenharmony_ci 473d5ac70f0Sopenharmony_ci if (next_devices[list->iface] != NULL) { 474d5ac70f0Sopenharmony_ci list->card = card; 475d5ac70f0Sopenharmony_ci device = max_device = -1; 476d5ac70f0Sopenharmony_ci err = next_devices[list->iface](list->ctl, &device); 477d5ac70f0Sopenharmony_ci if (device < 0) 478d5ac70f0Sopenharmony_ci err = -EINVAL; 479d5ac70f0Sopenharmony_ci else 480d5ac70f0Sopenharmony_ci max_device = device; 481d5ac70f0Sopenharmony_ci while (err >= 0 && device >= 0) { 482d5ac70f0Sopenharmony_ci err = next_devices[list->iface](list->ctl, &device); 483d5ac70f0Sopenharmony_ci if (err >= 0 && device > max_device) 484d5ac70f0Sopenharmony_ci max_device = device; 485d5ac70f0Sopenharmony_ci } 486d5ac70f0Sopenharmony_ci ok = 0; 487d5ac70f0Sopenharmony_ci for (device = 0; err >= 0 && device <= max_device; device++) { 488d5ac70f0Sopenharmony_ci list->device = device; 489d5ac70f0Sopenharmony_ci err = try_config(rw_config, list, list->siface, str); 490d5ac70f0Sopenharmony_ci if (err < 0) 491d5ac70f0Sopenharmony_ci break; 492d5ac70f0Sopenharmony_ci ok++; 493d5ac70f0Sopenharmony_ci } 494d5ac70f0Sopenharmony_ci if (ok) 495d5ac70f0Sopenharmony_ci continue; 496d5ac70f0Sopenharmony_ci } else { 497d5ac70f0Sopenharmony_ci err = -EINVAL; 498d5ac70f0Sopenharmony_ci } 499d5ac70f0Sopenharmony_ci if (err == -EXDEV) 500d5ac70f0Sopenharmony_ci continue; 501d5ac70f0Sopenharmony_ci if (err < 0) { 502d5ac70f0Sopenharmony_ci list->card = card; 503d5ac70f0Sopenharmony_ci list->device = -1; 504d5ac70f0Sopenharmony_ci err = try_config(rw_config, list, list->siface, str); 505d5ac70f0Sopenharmony_ci } 506d5ac70f0Sopenharmony_ci if (err == -ENOMEM) 507d5ac70f0Sopenharmony_ci goto __error; 508d5ac70f0Sopenharmony_ci } 509d5ac70f0Sopenharmony_ci err = 0; 510d5ac70f0Sopenharmony_ci __error: 511d5ac70f0Sopenharmony_ci snd_ctl_close(list->ctl); 512d5ac70f0Sopenharmony_ci return err; 513d5ac70f0Sopenharmony_ci} 514d5ac70f0Sopenharmony_ci 515d5ac70f0Sopenharmony_cistatic int get_card_name(struct hint_list *list, int card) 516d5ac70f0Sopenharmony_ci{ 517d5ac70f0Sopenharmony_ci char scard[16], *s; 518d5ac70f0Sopenharmony_ci int err; 519d5ac70f0Sopenharmony_ci 520d5ac70f0Sopenharmony_ci free(list->cardname); 521d5ac70f0Sopenharmony_ci list->cardname = NULL; 522d5ac70f0Sopenharmony_ci err = snd_card_get_name(card, &list->cardname); 523d5ac70f0Sopenharmony_ci if (err <= 0) 524d5ac70f0Sopenharmony_ci return 0; 525d5ac70f0Sopenharmony_ci sprintf(scard, " #%i", card); 526d5ac70f0Sopenharmony_ci s = realloc(list->cardname, strlen(list->cardname) + strlen(scard) + 1); 527d5ac70f0Sopenharmony_ci if (s == NULL) 528d5ac70f0Sopenharmony_ci return -ENOMEM; 529d5ac70f0Sopenharmony_ci list->cardname = s; 530d5ac70f0Sopenharmony_ci return 0; 531d5ac70f0Sopenharmony_ci} 532d5ac70f0Sopenharmony_ci 533d5ac70f0Sopenharmony_cistatic int add_software_devices(snd_config_t *config, snd_config_t *rw_config, 534d5ac70f0Sopenharmony_ci struct hint_list *list) 535d5ac70f0Sopenharmony_ci{ 536d5ac70f0Sopenharmony_ci int err; 537d5ac70f0Sopenharmony_ci snd_config_t *conf, *n; 538d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 539d5ac70f0Sopenharmony_ci const char *str; 540d5ac70f0Sopenharmony_ci 541d5ac70f0Sopenharmony_ci err = snd_config_search(config, list->siface, &conf); 542d5ac70f0Sopenharmony_ci if (err < 0) 543d5ac70f0Sopenharmony_ci return err; 544d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, conf) { 545d5ac70f0Sopenharmony_ci n = snd_config_iterator_entry(i); 546d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &str) < 0) 547d5ac70f0Sopenharmony_ci continue; 548d5ac70f0Sopenharmony_ci list->card = -1; 549d5ac70f0Sopenharmony_ci list->device = -1; 550d5ac70f0Sopenharmony_ci err = try_config(rw_config, list, list->siface, str); 551d5ac70f0Sopenharmony_ci if (err == -ENOMEM) 552d5ac70f0Sopenharmony_ci return -ENOMEM; 553d5ac70f0Sopenharmony_ci } 554d5ac70f0Sopenharmony_ci return 0; 555d5ac70f0Sopenharmony_ci} 556d5ac70f0Sopenharmony_ci 557d5ac70f0Sopenharmony_ci/** 558d5ac70f0Sopenharmony_ci * \brief Get a set of device name hints 559d5ac70f0Sopenharmony_ci * \param card Card number or -1 (means all cards) 560d5ac70f0Sopenharmony_ci * \param iface Interface identification (like "pcm", "rawmidi", "timer", "seq") 561d5ac70f0Sopenharmony_ci * \param hints Result - array of device name hints 562d5ac70f0Sopenharmony_ci * \result zero if success, otherwise a negative error code 563d5ac70f0Sopenharmony_ci * 564d5ac70f0Sopenharmony_ci * hints will receive a NULL-terminated array of device name hints, 565d5ac70f0Sopenharmony_ci * which can be passed to #snd_device_name_get_hint to extract usable 566d5ac70f0Sopenharmony_ci * values. When no longer needed, hints should be passed to 567d5ac70f0Sopenharmony_ci * #snd_device_name_free_hint to release resources. 568d5ac70f0Sopenharmony_ci * 569d5ac70f0Sopenharmony_ci * User-defined hints are gathered from namehint.IFACE tree like: 570d5ac70f0Sopenharmony_ci * 571d5ac70f0Sopenharmony_ci * <code> 572d5ac70f0Sopenharmony_ci * namehint.pcm [<br> 573d5ac70f0Sopenharmony_ci * myfile "file:FILE=/tmp/soundwave.raw|Save sound output to /tmp/soundwave.raw"<br> 574d5ac70f0Sopenharmony_ci * myplug "plug:front|Do all conversions for front speakers"<br> 575d5ac70f0Sopenharmony_ci * ] 576d5ac70f0Sopenharmony_ci * </code> 577d5ac70f0Sopenharmony_ci * 578d5ac70f0Sopenharmony_ci * Note: The device description is separated with '|' char. 579d5ac70f0Sopenharmony_ci * 580d5ac70f0Sopenharmony_ci * Special variables: defaults.namehint.showall specifies if all device 581d5ac70f0Sopenharmony_ci * definitions are accepted (boolean type). 582d5ac70f0Sopenharmony_ci */ 583d5ac70f0Sopenharmony_ciint snd_device_name_hint(int card, const char *iface, void ***hints) 584d5ac70f0Sopenharmony_ci{ 585d5ac70f0Sopenharmony_ci struct hint_list list; 586d5ac70f0Sopenharmony_ci char ehints[24]; 587d5ac70f0Sopenharmony_ci const char *str; 588d5ac70f0Sopenharmony_ci snd_config_t *conf, *local_config = NULL, *local_config_rw = NULL; 589d5ac70f0Sopenharmony_ci snd_config_update_t *local_config_update = NULL; 590d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 591d5ac70f0Sopenharmony_ci int err; 592d5ac70f0Sopenharmony_ci 593d5ac70f0Sopenharmony_ci if (hints == NULL) 594d5ac70f0Sopenharmony_ci return -EINVAL; 595d5ac70f0Sopenharmony_ci err = snd_config_update_r(&local_config, &local_config_update, NULL); 596d5ac70f0Sopenharmony_ci if (err < 0) 597d5ac70f0Sopenharmony_ci return err; 598d5ac70f0Sopenharmony_ci err = snd_config_copy(&local_config_rw, local_config); 599d5ac70f0Sopenharmony_ci if (err < 0) 600d5ac70f0Sopenharmony_ci return err; 601d5ac70f0Sopenharmony_ci list.list = NULL; 602d5ac70f0Sopenharmony_ci list.count = list.allocated = 0; 603d5ac70f0Sopenharmony_ci list.siface = iface; 604d5ac70f0Sopenharmony_ci list.show_all = 0; 605d5ac70f0Sopenharmony_ci list.cardname = NULL; 606d5ac70f0Sopenharmony_ci if (strcmp(iface, "pcm") == 0) 607d5ac70f0Sopenharmony_ci list.iface = SND_CTL_ELEM_IFACE_PCM; 608d5ac70f0Sopenharmony_ci else if (strcmp(iface, "rawmidi") == 0) 609d5ac70f0Sopenharmony_ci list.iface = SND_CTL_ELEM_IFACE_RAWMIDI; 610d5ac70f0Sopenharmony_ci else if (strcmp(iface, "timer") == 0) 611d5ac70f0Sopenharmony_ci list.iface = SND_CTL_ELEM_IFACE_TIMER; 612d5ac70f0Sopenharmony_ci else if (strcmp(iface, "seq") == 0) 613d5ac70f0Sopenharmony_ci list.iface = SND_CTL_ELEM_IFACE_SEQUENCER; 614d5ac70f0Sopenharmony_ci else if (strcmp(iface, "hwdep") == 0) 615d5ac70f0Sopenharmony_ci list.iface = SND_CTL_ELEM_IFACE_HWDEP; 616d5ac70f0Sopenharmony_ci else if (strcmp(iface, "ctl") == 0) 617d5ac70f0Sopenharmony_ci list.iface = SND_CTL_ELEM_IFACE_MIXER; 618d5ac70f0Sopenharmony_ci else { 619d5ac70f0Sopenharmony_ci err = -EINVAL; 620d5ac70f0Sopenharmony_ci goto __error; 621d5ac70f0Sopenharmony_ci } 622d5ac70f0Sopenharmony_ci 623d5ac70f0Sopenharmony_ci if (snd_config_search(local_config, "defaults.namehint.showall", &conf) >= 0) 624d5ac70f0Sopenharmony_ci list.show_all = snd_config_get_bool(conf) > 0; 625d5ac70f0Sopenharmony_ci if (card >= 0) { 626d5ac70f0Sopenharmony_ci err = get_card_name(&list, card); 627d5ac70f0Sopenharmony_ci if (err >= 0) 628d5ac70f0Sopenharmony_ci err = add_card(local_config, local_config_rw, &list, card); 629d5ac70f0Sopenharmony_ci } else { 630d5ac70f0Sopenharmony_ci add_software_devices(local_config, local_config_rw, &list); 631d5ac70f0Sopenharmony_ci err = snd_card_next(&card); 632d5ac70f0Sopenharmony_ci if (err < 0) 633d5ac70f0Sopenharmony_ci goto __error; 634d5ac70f0Sopenharmony_ci while (card >= 0) { 635d5ac70f0Sopenharmony_ci err = get_card_name(&list, card); 636d5ac70f0Sopenharmony_ci if (err < 0) 637d5ac70f0Sopenharmony_ci goto __error; 638d5ac70f0Sopenharmony_ci err = add_card(local_config, local_config_rw, &list, card); 639d5ac70f0Sopenharmony_ci if (err < 0) 640d5ac70f0Sopenharmony_ci goto __error; 641d5ac70f0Sopenharmony_ci err = snd_card_next(&card); 642d5ac70f0Sopenharmony_ci if (err < 0) 643d5ac70f0Sopenharmony_ci goto __error; 644d5ac70f0Sopenharmony_ci } 645d5ac70f0Sopenharmony_ci } 646d5ac70f0Sopenharmony_ci sprintf(ehints, "namehint.%s", list.siface); 647d5ac70f0Sopenharmony_ci err = snd_config_search(local_config, ehints, &conf); 648d5ac70f0Sopenharmony_ci if (err >= 0) { 649d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, conf) { 650d5ac70f0Sopenharmony_ci if (snd_config_get_string(snd_config_iterator_entry(i), 651d5ac70f0Sopenharmony_ci &str) < 0) 652d5ac70f0Sopenharmony_ci continue; 653d5ac70f0Sopenharmony_ci err = hint_list_add_custom(&list, str); 654d5ac70f0Sopenharmony_ci if (err < 0) 655d5ac70f0Sopenharmony_ci goto __error; 656d5ac70f0Sopenharmony_ci } 657d5ac70f0Sopenharmony_ci } 658d5ac70f0Sopenharmony_ci err = 0; 659d5ac70f0Sopenharmony_ci __error: 660d5ac70f0Sopenharmony_ci /* add an empty entry if nothing has been added yet; the caller 661d5ac70f0Sopenharmony_ci * expects non-NULL return 662d5ac70f0Sopenharmony_ci */ 663d5ac70f0Sopenharmony_ci if (!err && !list.list) 664d5ac70f0Sopenharmony_ci err = hint_list_add(&list, NULL, NULL); 665d5ac70f0Sopenharmony_ci if (err < 0) 666d5ac70f0Sopenharmony_ci snd_device_name_free_hint((void **)list.list); 667d5ac70f0Sopenharmony_ci else 668d5ac70f0Sopenharmony_ci *hints = (void **)list.list; 669d5ac70f0Sopenharmony_ci free(list.cardname); 670d5ac70f0Sopenharmony_ci if (local_config_rw) 671d5ac70f0Sopenharmony_ci snd_config_delete(local_config_rw); 672d5ac70f0Sopenharmony_ci if (local_config) 673d5ac70f0Sopenharmony_ci snd_config_delete(local_config); 674d5ac70f0Sopenharmony_ci if (local_config_update) 675d5ac70f0Sopenharmony_ci snd_config_update_free(local_config_update); 676d5ac70f0Sopenharmony_ci return err; 677d5ac70f0Sopenharmony_ci} 678d5ac70f0Sopenharmony_ci 679d5ac70f0Sopenharmony_ci/** 680d5ac70f0Sopenharmony_ci * \brief Free a list of device name hints. 681d5ac70f0Sopenharmony_ci * \param hints List to free 682d5ac70f0Sopenharmony_ci * \result zero if success, otherwise a negative error code 683d5ac70f0Sopenharmony_ci */ 684d5ac70f0Sopenharmony_ciint snd_device_name_free_hint(void **hints) 685d5ac70f0Sopenharmony_ci{ 686d5ac70f0Sopenharmony_ci char **h; 687d5ac70f0Sopenharmony_ci 688d5ac70f0Sopenharmony_ci if (hints == NULL) 689d5ac70f0Sopenharmony_ci return 0; 690d5ac70f0Sopenharmony_ci h = (char **)hints; 691d5ac70f0Sopenharmony_ci while (*h) { 692d5ac70f0Sopenharmony_ci free(*h); 693d5ac70f0Sopenharmony_ci h++; 694d5ac70f0Sopenharmony_ci } 695d5ac70f0Sopenharmony_ci free(hints); 696d5ac70f0Sopenharmony_ci return 0; 697d5ac70f0Sopenharmony_ci} 698d5ac70f0Sopenharmony_ci 699d5ac70f0Sopenharmony_ci/** 700d5ac70f0Sopenharmony_ci * \brief Extract a value from a hint 701d5ac70f0Sopenharmony_ci * \param hint A pointer to hint 702d5ac70f0Sopenharmony_ci * \param id Hint value to extract ("NAME", "DESC", or "IOID", see below) 703d5ac70f0Sopenharmony_ci * \result an allocated ASCII string if success, otherwise NULL 704d5ac70f0Sopenharmony_ci * 705d5ac70f0Sopenharmony_ci * List of valid IDs: 706d5ac70f0Sopenharmony_ci * NAME - name of device 707d5ac70f0Sopenharmony_ci * DESC - description of device 708d5ac70f0Sopenharmony_ci * IOID - input / output identification ("Input" or "Output"), NULL means both 709d5ac70f0Sopenharmony_ci * 710d5ac70f0Sopenharmony_ci * The return value should be freed when no longer needed. 711d5ac70f0Sopenharmony_ci */ 712d5ac70f0Sopenharmony_cichar *snd_device_name_get_hint(const void *hint, const char *id) 713d5ac70f0Sopenharmony_ci{ 714d5ac70f0Sopenharmony_ci const char *hint1 = (const char *)hint, *delim; 715d5ac70f0Sopenharmony_ci char *res; 716d5ac70f0Sopenharmony_ci unsigned size; 717d5ac70f0Sopenharmony_ci 718d5ac70f0Sopenharmony_ci if (strlen(id) != 4) 719d5ac70f0Sopenharmony_ci return NULL; 720d5ac70f0Sopenharmony_ci while (*hint1 != '\0') { 721d5ac70f0Sopenharmony_ci delim = strchr(hint1, '|'); 722d5ac70f0Sopenharmony_ci if (memcmp(id, hint1, 4) != 0) { 723d5ac70f0Sopenharmony_ci if (delim == NULL) 724d5ac70f0Sopenharmony_ci return NULL; 725d5ac70f0Sopenharmony_ci hint1 = delim + 1; 726d5ac70f0Sopenharmony_ci continue; 727d5ac70f0Sopenharmony_ci } 728d5ac70f0Sopenharmony_ci if (delim == NULL) 729d5ac70f0Sopenharmony_ci return strdup(hint1 + 4); 730d5ac70f0Sopenharmony_ci size = delim - hint1 - 4; 731d5ac70f0Sopenharmony_ci res = malloc(size + 1); 732d5ac70f0Sopenharmony_ci if (res != NULL) { 733d5ac70f0Sopenharmony_ci memcpy(res, hint1 + 4, size); 734d5ac70f0Sopenharmony_ci res[size] = '\0'; 735d5ac70f0Sopenharmony_ci } 736d5ac70f0Sopenharmony_ci return res; 737d5ac70f0Sopenharmony_ci } 738d5ac70f0Sopenharmony_ci return NULL; 739d5ac70f0Sopenharmony_ci} 740