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