1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file control/control.c 3d5ac70f0Sopenharmony_ci * \brief CTL interface - parse ASCII identifiers and values 4d5ac70f0Sopenharmony_ci * \author Jaroslav Kysela <perex@perex.cz> 5d5ac70f0Sopenharmony_ci * \date 2010 6d5ac70f0Sopenharmony_ci */ 7d5ac70f0Sopenharmony_ci/* 8d5ac70f0Sopenharmony_ci * Control Interface - ASCII parser 9d5ac70f0Sopenharmony_ci * Copyright (c) 2010 by Jaroslav Kysela <perex@perex.cz> 10d5ac70f0Sopenharmony_ci * 11d5ac70f0Sopenharmony_ci * 12d5ac70f0Sopenharmony_ci * This library is free software; you can redistribute it and/or modify 13d5ac70f0Sopenharmony_ci * it under the terms of the GNU Lesser General Public License as 14d5ac70f0Sopenharmony_ci * published by the Free Software Foundation; either version 2.1 of 15d5ac70f0Sopenharmony_ci * the License, or (at your option) any later version. 16d5ac70f0Sopenharmony_ci * 17d5ac70f0Sopenharmony_ci * This program is distributed in the hope that it will be useful, 18d5ac70f0Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 19d5ac70f0Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20d5ac70f0Sopenharmony_ci * GNU Lesser General Public License for more details. 21d5ac70f0Sopenharmony_ci * 22d5ac70f0Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public 23d5ac70f0Sopenharmony_ci * License along with this library; if not, write to the Free Software 24d5ac70f0Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 25d5ac70f0Sopenharmony_ci * 26d5ac70f0Sopenharmony_ci */ 27d5ac70f0Sopenharmony_ci 28d5ac70f0Sopenharmony_ci#include "control_local.h" 29d5ac70f0Sopenharmony_ci#include <unistd.h> 30d5ac70f0Sopenharmony_ci#include <string.h> 31d5ac70f0Sopenharmony_ci#include <ctype.h> 32d5ac70f0Sopenharmony_ci#include <math.h> 33d5ac70f0Sopenharmony_ci 34d5ac70f0Sopenharmony_ci/* Function to convert from percentage to volume. val = percentage */ 35d5ac70f0Sopenharmony_ci 36d5ac70f0Sopenharmony_cistatic inline long int convert_prange1(long perc, long min, long max) 37d5ac70f0Sopenharmony_ci{ 38d5ac70f0Sopenharmony_ci long tmp; 39d5ac70f0Sopenharmony_ci 40d5ac70f0Sopenharmony_ci#ifdef HAVE_SOFT_FLOAT 41d5ac70f0Sopenharmony_ci tmp = perc * (max - min); 42d5ac70f0Sopenharmony_ci tmp = tmp / 100 + ((tmp % 100) < 50 ? 0 : 1); 43d5ac70f0Sopenharmony_ci#else 44d5ac70f0Sopenharmony_ci tmp = rint((double)perc * (double)(max - min) * 0.01); 45d5ac70f0Sopenharmony_ci#endif 46d5ac70f0Sopenharmony_ci if (tmp == 0 && perc > 0) 47d5ac70f0Sopenharmony_ci tmp++; 48d5ac70f0Sopenharmony_ci return tmp + min; 49d5ac70f0Sopenharmony_ci} 50d5ac70f0Sopenharmony_ci 51d5ac70f0Sopenharmony_ci#define check_range(val, min, max) \ 52d5ac70f0Sopenharmony_ci ((val < min) ? (min) : ((val > max) ? (max) : (val))) 53d5ac70f0Sopenharmony_ci 54d5ac70f0Sopenharmony_cistatic long get_integer(const char **ptr, long min, long max) 55d5ac70f0Sopenharmony_ci{ 56d5ac70f0Sopenharmony_ci long val = min; 57d5ac70f0Sopenharmony_ci char *p = (char *)*ptr, *s; 58d5ac70f0Sopenharmony_ci 59d5ac70f0Sopenharmony_ci if (*p == ':') 60d5ac70f0Sopenharmony_ci p++; 61d5ac70f0Sopenharmony_ci if (*p == '\0' || (!isdigit(*p) && *p != '-')) 62d5ac70f0Sopenharmony_ci goto out; 63d5ac70f0Sopenharmony_ci 64d5ac70f0Sopenharmony_ci s = p; 65d5ac70f0Sopenharmony_ci val = strtol(s, &p, 0); 66d5ac70f0Sopenharmony_ci if (*p == '.') { 67d5ac70f0Sopenharmony_ci p++; 68d5ac70f0Sopenharmony_ci (void)strtol(p, &p, 10); 69d5ac70f0Sopenharmony_ci } 70d5ac70f0Sopenharmony_ci if (*p == '%') { 71d5ac70f0Sopenharmony_ci val = (long)convert_prange1(strtod(s, NULL), min, max); 72d5ac70f0Sopenharmony_ci p++; 73d5ac70f0Sopenharmony_ci } 74d5ac70f0Sopenharmony_ci val = check_range(val, min, max); 75d5ac70f0Sopenharmony_ci if (*p == ',') 76d5ac70f0Sopenharmony_ci p++; 77d5ac70f0Sopenharmony_ci out: 78d5ac70f0Sopenharmony_ci *ptr = p; 79d5ac70f0Sopenharmony_ci return val; 80d5ac70f0Sopenharmony_ci} 81d5ac70f0Sopenharmony_ci 82d5ac70f0Sopenharmony_cistatic long long get_integer64(const char **ptr, long long min, long long max) 83d5ac70f0Sopenharmony_ci{ 84d5ac70f0Sopenharmony_ci long long val = min; 85d5ac70f0Sopenharmony_ci char *p = (char *)*ptr, *s; 86d5ac70f0Sopenharmony_ci 87d5ac70f0Sopenharmony_ci if (*p == ':') 88d5ac70f0Sopenharmony_ci p++; 89d5ac70f0Sopenharmony_ci if (*p == '\0' || (!isdigit(*p) && *p != '-')) 90d5ac70f0Sopenharmony_ci goto out; 91d5ac70f0Sopenharmony_ci 92d5ac70f0Sopenharmony_ci s = p; 93d5ac70f0Sopenharmony_ci val = strtol(s, &p, 0); 94d5ac70f0Sopenharmony_ci if (*p == '.') { 95d5ac70f0Sopenharmony_ci p++; 96d5ac70f0Sopenharmony_ci (void)strtol(p, &p, 10); 97d5ac70f0Sopenharmony_ci } 98d5ac70f0Sopenharmony_ci if (*p == '%') { 99d5ac70f0Sopenharmony_ci val = (long long)convert_prange1(strtod(s, NULL), min, max); 100d5ac70f0Sopenharmony_ci p++; 101d5ac70f0Sopenharmony_ci } 102d5ac70f0Sopenharmony_ci val = check_range(val, min, max); 103d5ac70f0Sopenharmony_ci if (*p == ',') 104d5ac70f0Sopenharmony_ci p++; 105d5ac70f0Sopenharmony_ci out: 106d5ac70f0Sopenharmony_ci *ptr = p; 107d5ac70f0Sopenharmony_ci return val; 108d5ac70f0Sopenharmony_ci} 109d5ac70f0Sopenharmony_ci 110d5ac70f0Sopenharmony_ci/** 111d5ac70f0Sopenharmony_ci * \brief return ASCII CTL element identifier name 112d5ac70f0Sopenharmony_ci * \param id CTL identifier 113d5ac70f0Sopenharmony_ci * \return ascii identifier of CTL element 114d5ac70f0Sopenharmony_ci * 115d5ac70f0Sopenharmony_ci * The string is allocated using strdup(). 116d5ac70f0Sopenharmony_ci */ 117d5ac70f0Sopenharmony_cichar *snd_ctl_ascii_elem_id_get(snd_ctl_elem_id_t *id) 118d5ac70f0Sopenharmony_ci{ 119d5ac70f0Sopenharmony_ci unsigned int numid, index, device, subdevice; 120d5ac70f0Sopenharmony_ci char buf[256], buf1[32]; 121d5ac70f0Sopenharmony_ci const char *iface; 122d5ac70f0Sopenharmony_ci 123d5ac70f0Sopenharmony_ci numid = snd_ctl_elem_id_get_numid(id); 124d5ac70f0Sopenharmony_ci iface = snd_ctl_elem_iface_name(snd_ctl_elem_id_get_interface(id)); 125d5ac70f0Sopenharmony_ci if (numid > 0) { 126d5ac70f0Sopenharmony_ci snprintf(buf, sizeof(buf), "numid=%u,iface=%s,name='%s'", 127d5ac70f0Sopenharmony_ci numid, iface, snd_ctl_elem_id_get_name(id)); 128d5ac70f0Sopenharmony_ci } else { 129d5ac70f0Sopenharmony_ci snprintf(buf, sizeof(buf), "iface=%s,name='%s'", 130d5ac70f0Sopenharmony_ci iface, snd_ctl_elem_id_get_name(id)); 131d5ac70f0Sopenharmony_ci } 132d5ac70f0Sopenharmony_ci buf[sizeof(buf)-1] = '\0'; 133d5ac70f0Sopenharmony_ci index = snd_ctl_elem_id_get_index(id); 134d5ac70f0Sopenharmony_ci device = snd_ctl_elem_id_get_device(id); 135d5ac70f0Sopenharmony_ci subdevice = snd_ctl_elem_id_get_subdevice(id); 136d5ac70f0Sopenharmony_ci if (index) { 137d5ac70f0Sopenharmony_ci snprintf(buf1, sizeof(buf1), ",index=%u", index); 138d5ac70f0Sopenharmony_ci if (strlen(buf) + strlen(buf1) < sizeof(buf)) 139d5ac70f0Sopenharmony_ci strcat(buf, buf1); 140d5ac70f0Sopenharmony_ci } 141d5ac70f0Sopenharmony_ci if (device) { 142d5ac70f0Sopenharmony_ci snprintf(buf1, sizeof(buf1), ",device=%u", device); 143d5ac70f0Sopenharmony_ci if (strlen(buf) + strlen(buf1) < sizeof(buf)) 144d5ac70f0Sopenharmony_ci strcat(buf, buf1); 145d5ac70f0Sopenharmony_ci } 146d5ac70f0Sopenharmony_ci if (subdevice) { 147d5ac70f0Sopenharmony_ci snprintf(buf1, sizeof(buf1), ",subdevice=%u", subdevice); 148d5ac70f0Sopenharmony_ci if (strlen(buf) + strlen(buf1) < sizeof(buf)) 149d5ac70f0Sopenharmony_ci strcat(buf, buf1); 150d5ac70f0Sopenharmony_ci } 151d5ac70f0Sopenharmony_ci return strdup(buf); 152d5ac70f0Sopenharmony_ci} 153d5ac70f0Sopenharmony_ci 154d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 155d5ac70f0Sopenharmony_ci/* used by UCM parser, too */ 156d5ac70f0Sopenharmony_ciint __snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, const char *str, 157d5ac70f0Sopenharmony_ci const char **ret_ptr) 158d5ac70f0Sopenharmony_ci{ 159d5ac70f0Sopenharmony_ci int c, size, numid; 160d5ac70f0Sopenharmony_ci int err = -EINVAL; 161d5ac70f0Sopenharmony_ci char *ptr; 162d5ac70f0Sopenharmony_ci 163d5ac70f0Sopenharmony_ci while (isspace(*str)) 164d5ac70f0Sopenharmony_ci str++; 165d5ac70f0Sopenharmony_ci if (!(*str)) 166d5ac70f0Sopenharmony_ci goto out; 167d5ac70f0Sopenharmony_ci snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_MIXER); /* default */ 168d5ac70f0Sopenharmony_ci while (*str) { 169d5ac70f0Sopenharmony_ci if (!strncasecmp(str, "numid=", 6)) { 170d5ac70f0Sopenharmony_ci str += 6; 171d5ac70f0Sopenharmony_ci numid = atoi(str); 172d5ac70f0Sopenharmony_ci if (numid <= 0) { 173d5ac70f0Sopenharmony_ci fprintf(stderr, "amixer: Invalid numid %d\n", numid); 174d5ac70f0Sopenharmony_ci goto out; 175d5ac70f0Sopenharmony_ci } 176d5ac70f0Sopenharmony_ci snd_ctl_elem_id_set_numid(dst, atoi(str)); 177d5ac70f0Sopenharmony_ci while (isdigit(*str)) 178d5ac70f0Sopenharmony_ci str++; 179d5ac70f0Sopenharmony_ci } else if (!strncasecmp(str, "iface=", 6)) { 180d5ac70f0Sopenharmony_ci str += 6; 181d5ac70f0Sopenharmony_ci if (!strncasecmp(str, "card", 4)) { 182d5ac70f0Sopenharmony_ci snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_CARD); 183d5ac70f0Sopenharmony_ci str += 4; 184d5ac70f0Sopenharmony_ci } else if (!strncasecmp(str, "mixer", 5)) { 185d5ac70f0Sopenharmony_ci snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_MIXER); 186d5ac70f0Sopenharmony_ci str += 5; 187d5ac70f0Sopenharmony_ci } else if (!strncasecmp(str, "pcm", 3)) { 188d5ac70f0Sopenharmony_ci snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_PCM); 189d5ac70f0Sopenharmony_ci str += 3; 190d5ac70f0Sopenharmony_ci } else if (!strncasecmp(str, "rawmidi", 7)) { 191d5ac70f0Sopenharmony_ci snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_RAWMIDI); 192d5ac70f0Sopenharmony_ci str += 7; 193d5ac70f0Sopenharmony_ci } else if (!strncasecmp(str, "timer", 5)) { 194d5ac70f0Sopenharmony_ci snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_TIMER); 195d5ac70f0Sopenharmony_ci str += 5; 196d5ac70f0Sopenharmony_ci } else if (!strncasecmp(str, "sequencer", 9)) { 197d5ac70f0Sopenharmony_ci snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_SEQUENCER); 198d5ac70f0Sopenharmony_ci str += 9; 199d5ac70f0Sopenharmony_ci } else { 200d5ac70f0Sopenharmony_ci goto out; 201d5ac70f0Sopenharmony_ci } 202d5ac70f0Sopenharmony_ci } else if (!strncasecmp(str, "name=", 5)) { 203d5ac70f0Sopenharmony_ci char buf[64]; 204d5ac70f0Sopenharmony_ci str += 5; 205d5ac70f0Sopenharmony_ci ptr = buf; 206d5ac70f0Sopenharmony_ci size = 0; 207d5ac70f0Sopenharmony_ci if (*str == '\'' || *str == '\"') { 208d5ac70f0Sopenharmony_ci c = *str++; 209d5ac70f0Sopenharmony_ci while (*str && *str != c) { 210d5ac70f0Sopenharmony_ci if (size < (int)sizeof(buf)) { 211d5ac70f0Sopenharmony_ci *ptr++ = *str; 212d5ac70f0Sopenharmony_ci size++; 213d5ac70f0Sopenharmony_ci } 214d5ac70f0Sopenharmony_ci str++; 215d5ac70f0Sopenharmony_ci } 216d5ac70f0Sopenharmony_ci if (*str == c) 217d5ac70f0Sopenharmony_ci str++; 218d5ac70f0Sopenharmony_ci } else { 219d5ac70f0Sopenharmony_ci while (*str && *str != ',') { 220d5ac70f0Sopenharmony_ci if (size < (int)sizeof(buf)) { 221d5ac70f0Sopenharmony_ci *ptr++ = *str; 222d5ac70f0Sopenharmony_ci size++; 223d5ac70f0Sopenharmony_ci } 224d5ac70f0Sopenharmony_ci str++; 225d5ac70f0Sopenharmony_ci } 226d5ac70f0Sopenharmony_ci } 227d5ac70f0Sopenharmony_ci *ptr = '\0'; 228d5ac70f0Sopenharmony_ci snd_ctl_elem_id_set_name(dst, buf); 229d5ac70f0Sopenharmony_ci } else if (!strncasecmp(str, "index=", 6)) { 230d5ac70f0Sopenharmony_ci str += 6; 231d5ac70f0Sopenharmony_ci snd_ctl_elem_id_set_index(dst, atoi(str)); 232d5ac70f0Sopenharmony_ci while (isdigit(*str)) 233d5ac70f0Sopenharmony_ci str++; 234d5ac70f0Sopenharmony_ci } else if (!strncasecmp(str, "device=", 7)) { 235d5ac70f0Sopenharmony_ci str += 7; 236d5ac70f0Sopenharmony_ci snd_ctl_elem_id_set_device(dst, atoi(str)); 237d5ac70f0Sopenharmony_ci while (isdigit(*str)) 238d5ac70f0Sopenharmony_ci str++; 239d5ac70f0Sopenharmony_ci } else if (!strncasecmp(str, "subdevice=", 10)) { 240d5ac70f0Sopenharmony_ci str += 10; 241d5ac70f0Sopenharmony_ci snd_ctl_elem_id_set_subdevice(dst, atoi(str)); 242d5ac70f0Sopenharmony_ci while (isdigit(*str)) 243d5ac70f0Sopenharmony_ci str++; 244d5ac70f0Sopenharmony_ci } 245d5ac70f0Sopenharmony_ci if (*str == ',') { 246d5ac70f0Sopenharmony_ci str++; 247d5ac70f0Sopenharmony_ci } else { 248d5ac70f0Sopenharmony_ci /* when ret_ptr is given, allow to terminate gracefully 249d5ac70f0Sopenharmony_ci * at the next space letter 250d5ac70f0Sopenharmony_ci */ 251d5ac70f0Sopenharmony_ci if (ret_ptr && isspace(*str)) 252d5ac70f0Sopenharmony_ci break; 253d5ac70f0Sopenharmony_ci if (*str) 254d5ac70f0Sopenharmony_ci goto out; 255d5ac70f0Sopenharmony_ci } 256d5ac70f0Sopenharmony_ci } 257d5ac70f0Sopenharmony_ci err = 0; 258d5ac70f0Sopenharmony_ci 259d5ac70f0Sopenharmony_ci out: 260d5ac70f0Sopenharmony_ci if (ret_ptr) 261d5ac70f0Sopenharmony_ci *ret_ptr = str; 262d5ac70f0Sopenharmony_ci return err; 263d5ac70f0Sopenharmony_ci} 264d5ac70f0Sopenharmony_ci#endif 265d5ac70f0Sopenharmony_ci 266d5ac70f0Sopenharmony_ci/** 267d5ac70f0Sopenharmony_ci * \brief parse ASCII string as CTL element identifier 268d5ac70f0Sopenharmony_ci * \param dst destination CTL identifier 269d5ac70f0Sopenharmony_ci * \param str source ASCII string 270d5ac70f0Sopenharmony_ci * \return zero on success, otherwise a negative error code 271d5ac70f0Sopenharmony_ci */ 272d5ac70f0Sopenharmony_ciint snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, const char *str) 273d5ac70f0Sopenharmony_ci{ 274d5ac70f0Sopenharmony_ci return __snd_ctl_ascii_elem_id_parse(dst, str, NULL); 275d5ac70f0Sopenharmony_ci} 276d5ac70f0Sopenharmony_ci 277d5ac70f0Sopenharmony_cistatic int get_ctl_enum_item_index(snd_ctl_t *handle, 278d5ac70f0Sopenharmony_ci snd_ctl_elem_info_t *info, 279d5ac70f0Sopenharmony_ci const char **ptrp) 280d5ac70f0Sopenharmony_ci{ 281d5ac70f0Sopenharmony_ci char *ptr = (char *)*ptrp; 282d5ac70f0Sopenharmony_ci int items, i, len; 283d5ac70f0Sopenharmony_ci const char *name; 284d5ac70f0Sopenharmony_ci char end; 285d5ac70f0Sopenharmony_ci 286d5ac70f0Sopenharmony_ci items = snd_ctl_elem_info_get_items(info); 287d5ac70f0Sopenharmony_ci if (items <= 0) 288d5ac70f0Sopenharmony_ci return -1; 289d5ac70f0Sopenharmony_ci 290d5ac70f0Sopenharmony_ci end = *ptr; 291d5ac70f0Sopenharmony_ci if (end == '\'' || end == '"') 292d5ac70f0Sopenharmony_ci ptr++; 293d5ac70f0Sopenharmony_ci else 294d5ac70f0Sopenharmony_ci end = '\0'; 295d5ac70f0Sopenharmony_ci 296d5ac70f0Sopenharmony_ci for (i = 0; i < items; i++) { 297d5ac70f0Sopenharmony_ci snd_ctl_elem_info_set_item(info, i); 298d5ac70f0Sopenharmony_ci if (snd_ctl_elem_info(handle, info) < 0) 299d5ac70f0Sopenharmony_ci return -1; 300d5ac70f0Sopenharmony_ci name = snd_ctl_elem_info_get_item_name(info); 301d5ac70f0Sopenharmony_ci len = strlen(name); 302d5ac70f0Sopenharmony_ci if (strncmp(name, ptr, len)) 303d5ac70f0Sopenharmony_ci continue; 304d5ac70f0Sopenharmony_ci if (end == '\0' && (ptr[len] == '\0' || ptr[len] == ',' || ptr[len] == '\n')) { 305d5ac70f0Sopenharmony_ci *ptrp = ptr + len; 306d5ac70f0Sopenharmony_ci return i; 307d5ac70f0Sopenharmony_ci } 308d5ac70f0Sopenharmony_ci if (end != '\0' && ptr[len] == end) { 309d5ac70f0Sopenharmony_ci *ptrp = ptr + len + 1; 310d5ac70f0Sopenharmony_ci return i; 311d5ac70f0Sopenharmony_ci } 312d5ac70f0Sopenharmony_ci } 313d5ac70f0Sopenharmony_ci return -1; 314d5ac70f0Sopenharmony_ci} 315d5ac70f0Sopenharmony_ci 316d5ac70f0Sopenharmony_cistatic unsigned int get_ctl_type_max_elements(snd_ctl_elem_type_t type) 317d5ac70f0Sopenharmony_ci{ 318d5ac70f0Sopenharmony_ci struct snd_ctl_elem_value value; 319d5ac70f0Sopenharmony_ci 320d5ac70f0Sopenharmony_ci switch (type) { 321d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_BOOLEAN: 322d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_INTEGER: 323d5ac70f0Sopenharmony_ci return ARRAY_SIZE(value.value.integer.value); 324d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_INTEGER64: 325d5ac70f0Sopenharmony_ci return ARRAY_SIZE(value.value.integer64.value); 326d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_ENUMERATED: 327d5ac70f0Sopenharmony_ci return ARRAY_SIZE(value.value.enumerated.item); 328d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_BYTES: 329d5ac70f0Sopenharmony_ci return ARRAY_SIZE(value.value.bytes.data); 330d5ac70f0Sopenharmony_ci default: 331d5ac70f0Sopenharmony_ci return 0; 332d5ac70f0Sopenharmony_ci } 333d5ac70f0Sopenharmony_ci} 334d5ac70f0Sopenharmony_ci 335d5ac70f0Sopenharmony_ci/** 336d5ac70f0Sopenharmony_ci * \brief parse ASCII string as CTL element value 337d5ac70f0Sopenharmony_ci * \param handle CTL handle 338d5ac70f0Sopenharmony_ci * \param dst destination CTL element value 339d5ac70f0Sopenharmony_ci * \param info CTL element info structure 340d5ac70f0Sopenharmony_ci * \param value source ASCII string 341d5ac70f0Sopenharmony_ci * \return zero on success, otherwise a negative error code 342d5ac70f0Sopenharmony_ci * 343d5ac70f0Sopenharmony_ci * Note: For toggle command, the dst must contain previous (current) 344d5ac70f0Sopenharmony_ci * state (do the #snd_ctl_elem_read call to obtain it). 345d5ac70f0Sopenharmony_ci */ 346d5ac70f0Sopenharmony_ciint snd_ctl_ascii_value_parse(snd_ctl_t *handle, 347d5ac70f0Sopenharmony_ci snd_ctl_elem_value_t *dst, 348d5ac70f0Sopenharmony_ci snd_ctl_elem_info_t *info, 349d5ac70f0Sopenharmony_ci const char *value) 350d5ac70f0Sopenharmony_ci{ 351d5ac70f0Sopenharmony_ci const char *ptr = value; 352d5ac70f0Sopenharmony_ci snd_ctl_elem_id_t myid = {0}; 353d5ac70f0Sopenharmony_ci snd_ctl_elem_type_t type; 354d5ac70f0Sopenharmony_ci unsigned int idx, count; 355d5ac70f0Sopenharmony_ci long tmp; 356d5ac70f0Sopenharmony_ci long long tmp64; 357d5ac70f0Sopenharmony_ci 358d5ac70f0Sopenharmony_ci snd_ctl_elem_info_get_id(info, &myid); 359d5ac70f0Sopenharmony_ci type = snd_ctl_elem_info_get_type(info); 360d5ac70f0Sopenharmony_ci count = snd_ctl_elem_info_get_count(info); 361d5ac70f0Sopenharmony_ci snd_ctl_elem_value_set_id(dst, &myid); 362d5ac70f0Sopenharmony_ci 363d5ac70f0Sopenharmony_ci if (count > get_ctl_type_max_elements(type)) 364d5ac70f0Sopenharmony_ci count = get_ctl_type_max_elements(type); 365d5ac70f0Sopenharmony_ci 366d5ac70f0Sopenharmony_ci for (idx = 0; idx < count && ptr && *ptr; idx++) { 367d5ac70f0Sopenharmony_ci if (*ptr == ',') 368d5ac70f0Sopenharmony_ci goto skip; 369d5ac70f0Sopenharmony_ci switch (type) { 370d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_BOOLEAN: 371d5ac70f0Sopenharmony_ci tmp = 0; 372d5ac70f0Sopenharmony_ci if (!strncasecmp(ptr, "on", 2) || 373d5ac70f0Sopenharmony_ci !strncasecmp(ptr, "up", 2)) { 374d5ac70f0Sopenharmony_ci tmp = 1; 375d5ac70f0Sopenharmony_ci ptr += 2; 376d5ac70f0Sopenharmony_ci } else if (!strncasecmp(ptr, "yes", 3)) { 377d5ac70f0Sopenharmony_ci tmp = 1; 378d5ac70f0Sopenharmony_ci ptr += 3; 379d5ac70f0Sopenharmony_ci } else if (!strncasecmp(ptr, "toggle", 6)) { 380d5ac70f0Sopenharmony_ci tmp = snd_ctl_elem_value_get_boolean(dst, idx); 381d5ac70f0Sopenharmony_ci tmp = tmp > 0 ? 0 : 1; 382d5ac70f0Sopenharmony_ci ptr += 6; 383d5ac70f0Sopenharmony_ci } else if (isdigit(*ptr)) { 384d5ac70f0Sopenharmony_ci tmp = atoi(ptr) > 0 ? 1 : 0; 385d5ac70f0Sopenharmony_ci while (isdigit(*ptr)) 386d5ac70f0Sopenharmony_ci ptr++; 387d5ac70f0Sopenharmony_ci } else { 388d5ac70f0Sopenharmony_ci while (*ptr && *ptr != ',') 389d5ac70f0Sopenharmony_ci ptr++; 390d5ac70f0Sopenharmony_ci } 391d5ac70f0Sopenharmony_ci snd_ctl_elem_value_set_boolean(dst, idx, tmp); 392d5ac70f0Sopenharmony_ci break; 393d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_INTEGER: 394d5ac70f0Sopenharmony_ci tmp = get_integer(&ptr, 395d5ac70f0Sopenharmony_ci snd_ctl_elem_info_get_min(info), 396d5ac70f0Sopenharmony_ci snd_ctl_elem_info_get_max(info)); 397d5ac70f0Sopenharmony_ci snd_ctl_elem_value_set_integer(dst, idx, tmp); 398d5ac70f0Sopenharmony_ci break; 399d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_INTEGER64: 400d5ac70f0Sopenharmony_ci tmp64 = get_integer64(&ptr, 401d5ac70f0Sopenharmony_ci snd_ctl_elem_info_get_min64(info), 402d5ac70f0Sopenharmony_ci snd_ctl_elem_info_get_max64(info)); 403d5ac70f0Sopenharmony_ci snd_ctl_elem_value_set_integer64(dst, idx, tmp64); 404d5ac70f0Sopenharmony_ci break; 405d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_ENUMERATED: 406d5ac70f0Sopenharmony_ci tmp = get_ctl_enum_item_index(handle, info, &ptr); 407d5ac70f0Sopenharmony_ci if (tmp < 0) 408d5ac70f0Sopenharmony_ci tmp = get_integer(&ptr, 0, 409d5ac70f0Sopenharmony_ci snd_ctl_elem_info_get_items(info) - 1); 410d5ac70f0Sopenharmony_ci snd_ctl_elem_value_set_enumerated(dst, idx, tmp); 411d5ac70f0Sopenharmony_ci break; 412d5ac70f0Sopenharmony_ci case SND_CTL_ELEM_TYPE_BYTES: 413d5ac70f0Sopenharmony_ci tmp = get_integer(&ptr, 0, 255); 414d5ac70f0Sopenharmony_ci snd_ctl_elem_value_set_byte(dst, idx, tmp); 415d5ac70f0Sopenharmony_ci break; 416d5ac70f0Sopenharmony_ci default: 417d5ac70f0Sopenharmony_ci break; 418d5ac70f0Sopenharmony_ci } 419d5ac70f0Sopenharmony_ci skip: 420d5ac70f0Sopenharmony_ci if (!strchr(value, ',')) 421d5ac70f0Sopenharmony_ci ptr = value; 422d5ac70f0Sopenharmony_ci else if (*ptr == ',') 423d5ac70f0Sopenharmony_ci ptr++; 424d5ac70f0Sopenharmony_ci } 425d5ac70f0Sopenharmony_ci return 0; 426d5ac70f0Sopenharmony_ci} 427