1 /**
2  * \file mixer/simple.c
3  * \brief Mixer Simple Element Class Interface
4  * \author Jaroslav Kysela <perex@perex.cz>
5  * \author Abramo Bagnara <abramo@alsa-project.org>
6  * \date 2001-2004
7  *
8  * Mixer simple element class interface.
9  */
10 /*
11  *  Mixer Interface - simple controls
12  *  Copyright (c) 2000,2004 by Jaroslav Kysela <perex@perex.cz>
13  *  Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org>
14  *
15  *
16  *   This library is free software; you can redistribute it and/or modify
17  *   it under the terms of the GNU Lesser General Public License as
18  *   published by the Free Software Foundation; either version 2.1 of
19  *   the License, or (at your option) any later version.
20  *
21  *   This program is distributed in the hope that it will be useful,
22  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
23  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  *   GNU Lesser General Public License for more details.
25  *
26  *   You should have received a copy of the GNU Lesser General Public
27  *   License along with this library; if not, write to the Free Software
28  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
29  *
30  */
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <string.h>
36 #include <fcntl.h>
37 #include <sys/ioctl.h>
38 #include <math.h>
39 #include "config.h"
40 #include "mixer_local.h"
41 #include "mixer_simple.h"
42 
43 /**
44  * \brief Register mixer simple element class
45  * \param mixer Mixer handle
46  * \param options Options container
47  * \param classp Pointer to returned mixer simple element class handle (or NULL)
48  * \return 0 on success otherwise a negative error code
49  */
snd_mixer_selem_register(snd_mixer_t * mixer,struct snd_mixer_selem_regopt * options,snd_mixer_class_t ** classp)50 int snd_mixer_selem_register(snd_mixer_t *mixer,
51 			     struct snd_mixer_selem_regopt *options,
52 			     snd_mixer_class_t **classp)
53 {
54 	if (options && options->ver == 1) {
55 		if (options->device != NULL &&
56 		    (options->playback_pcm != NULL ||
57 		     options->capture_pcm != NULL))
58 			return -EINVAL;
59 		if (options->device == NULL &&
60 		    options->playback_pcm == NULL &&
61 		    options->capture_pcm == NULL)
62 			return -EINVAL;
63 	}
64 	if (options == NULL ||
65 	    (options->ver == 1 && options->abstract == SND_MIXER_SABSTRACT_NONE)) {
66 		int err = snd_mixer_simple_none_register(mixer, options, classp);
67 		if (err < 0)
68 			return err;
69 		if (options != NULL) {
70 			err = snd_mixer_attach(mixer, options->device);
71 			if (err < 0)
72 				return err;
73 		}
74 		return 0;
75 	} else if (options->ver == 1) {
76 		if (options->abstract == SND_MIXER_SABSTRACT_BASIC)
77 			return snd_mixer_simple_basic_register(mixer, options, classp);
78 	}
79 	return -ENXIO;
80 }
81 
82 #ifndef DOC_HIDDEN
83 
84 #define CHECK_BASIC(xelem) \
85 { \
86 	assert(xelem); \
87 	assert((xelem)->type == SND_MIXER_ELEM_SIMPLE); \
88 }
89 
90 #define CHECK_DIR(xelem, xwhat) \
91 { \
92 	unsigned int xcaps = ((sm_selem_t *)(elem)->private_data)->caps; \
93 	if (! (xcaps & (xwhat))) \
94 		return -EINVAL; \
95 }
96 
97 #define CHECK_DIR_CHN(xelem, xwhat, xjoin, xchannel) \
98 { \
99 	unsigned int xcaps = ((sm_selem_t *)(elem)->private_data)->caps; \
100 	if (! (xcaps & (xwhat))) \
101 		return -EINVAL; \
102 	if (xcaps & (xjoin)) \
103 		xchannel = 0; \
104 }
105 
106 #define CHECK_ENUM(xelem) \
107 	if (!(((sm_selem_t *)(elem)->private_data)->caps & (SM_CAP_PENUM|SM_CAP_CENUM))) \
108 		return -EINVAL;
109 
110 #define COND_CAPS(xelem, what) \
111 	!!(((sm_selem_t *)(elem)->private_data)->caps & (what))
112 
113 #endif /* !DOC_HIDDEN */
114 
115 #ifndef DOC_HIDDEN
snd_mixer_selem_compare(const snd_mixer_elem_t * c1,const snd_mixer_elem_t * c2)116 int snd_mixer_selem_compare(const snd_mixer_elem_t *c1, const snd_mixer_elem_t *c2)
117 {
118 	sm_selem_t *s1 = c1->private_data;
119 	sm_selem_t *s2 = c2->private_data;
120 	int res = strcmp(s1->id->name, s2->id->name);
121 	if (res)
122 		return res;
123 	return s1->id->index - s2->id->index;
124 }
125 #endif
126 
127 /**
128  * \brief Find a mixer simple element
129  * \param mixer Mixer handle
130  * \param id Mixer simple element identifier
131  * \return mixer simple element handle or NULL if not found
132  */
snd_mixer_find_selem(snd_mixer_t * mixer,const snd_mixer_selem_id_t * id)133 snd_mixer_elem_t *snd_mixer_find_selem(snd_mixer_t *mixer,
134 				       const snd_mixer_selem_id_t *id)
135 {
136 	struct list_head *list;
137 	snd_mixer_elem_t *e;
138 	sm_selem_t *s;
139 
140 	list_for_each(list, &mixer->elems) {
141 		e = list_entry(list, snd_mixer_elem_t, list);
142 		if (e->type != SND_MIXER_ELEM_SIMPLE)
143 			continue;
144 		s = e->private_data;
145 		if (!strcmp(s->id->name, id->name) && s->id->index == id->index)
146 			return e;
147 	}
148 	return NULL;
149 }
150 
151 /**
152  * \brief Get mixer simple element identifier
153  * \param elem Mixer simple element handle
154  * \param id returned mixer simple element identifier
155  */
snd_mixer_selem_get_id(snd_mixer_elem_t * elem,snd_mixer_selem_id_t * id)156 void snd_mixer_selem_get_id(snd_mixer_elem_t *elem,
157 			    snd_mixer_selem_id_t *id)
158 {
159 	sm_selem_t *s;
160 	assert(id);
161 	CHECK_BASIC(elem);
162 	s = elem->private_data;
163 	*id = *s->id;
164 }
165 
166 /**
167  * \brief Get name part of mixer simple element identifier
168  * \param elem Mixer simple element handle
169  * \return name part of simple element identifier
170  */
snd_mixer_selem_get_name(snd_mixer_elem_t * elem)171 const char *snd_mixer_selem_get_name(snd_mixer_elem_t *elem)
172 {
173 	sm_selem_t *s;
174 	CHECK_BASIC(elem);
175 	s = elem->private_data;
176 	return s->id->name;
177 }
178 
179 /**
180  * \brief Get index part of mixer simple element identifier
181  * \param elem Mixer simple element handle
182  * \return index part of simple element identifier
183  */
snd_mixer_selem_get_index(snd_mixer_elem_t * elem)184 unsigned int snd_mixer_selem_get_index(snd_mixer_elem_t *elem)
185 {
186 	sm_selem_t *s;
187 	CHECK_BASIC(elem);
188 	s = elem->private_data;
189 	return s->id->index;
190 }
191 
192 /**
193  * \brief Return true if mixer simple element has only one volume control for both playback and capture
194  * \param elem Mixer simple element handle
195  * \return 0 separated control, 1 common control
196  */
snd_mixer_selem_has_common_volume(snd_mixer_elem_t * elem)197 int snd_mixer_selem_has_common_volume(snd_mixer_elem_t *elem)
198 {
199 	CHECK_BASIC(elem);
200 	return COND_CAPS(elem, SM_CAP_GVOLUME);
201 }
202 
203 /**
204  * \brief Return true if mixer simple element has only one switch control for both playback and capture
205  * \param elem Mixer simple element handle
206  * \return 0 separated control, 1 common control
207  */
snd_mixer_selem_has_common_switch(snd_mixer_elem_t * elem)208 int snd_mixer_selem_has_common_switch(snd_mixer_elem_t *elem)
209 {
210 	CHECK_BASIC(elem);
211 	return COND_CAPS(elem, SM_CAP_GSWITCH);
212 }
213 
214 /**
215  * \brief Return name of mixer simple element channel
216  * \param channel mixer simple element channel identifier
217  * \return channel name
218  */
snd_mixer_selem_channel_name(snd_mixer_selem_channel_id_t channel)219 const char *snd_mixer_selem_channel_name(snd_mixer_selem_channel_id_t channel)
220 {
221 	static const char *const array[SND_MIXER_SCHN_LAST + 1] = {
222 		[SND_MIXER_SCHN_FRONT_LEFT] = "Front Left",
223 		[SND_MIXER_SCHN_FRONT_RIGHT] = "Front Right",
224 		[SND_MIXER_SCHN_REAR_LEFT] = "Rear Left",
225 		[SND_MIXER_SCHN_REAR_RIGHT] = "Rear Right",
226 		[SND_MIXER_SCHN_FRONT_CENTER] = "Front Center",
227 		[SND_MIXER_SCHN_WOOFER] = "Woofer",
228 		[SND_MIXER_SCHN_SIDE_LEFT] = "Side Left",
229 		[SND_MIXER_SCHN_SIDE_RIGHT] = "Side Right",
230 		[SND_MIXER_SCHN_REAR_CENTER] = "Rear Center"
231 	};
232 	const char *p;
233 	assert(channel <= SND_MIXER_SCHN_LAST);
234 	p = array[channel];
235 	if (!p)
236 		return "?";
237 	return p;
238 }
239 
240 /**
241  * \brief Get info about the active state of a mixer simple element
242  * \param elem Mixer simple element handle
243  * \return 0 if not active, 1 if active
244  */
snd_mixer_selem_is_active(snd_mixer_elem_t * elem)245 int snd_mixer_selem_is_active(snd_mixer_elem_t *elem)
246 {
247 	CHECK_BASIC(elem);
248 	return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ACTIVE, 0);
249 }
250 
251 /**
252  * \brief Get info about channels of playback stream of a mixer simple element
253  * \param elem Mixer simple element handle
254  * \return 0 if not mono, 1 if mono
255  */
snd_mixer_selem_is_playback_mono(snd_mixer_elem_t * elem)256 int snd_mixer_selem_is_playback_mono(snd_mixer_elem_t *elem)
257 {
258 	CHECK_BASIC(elem);
259 	return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_MONO, 0);
260 }
261 
262 /**
263  * \brief Get info about channels of playback stream of a mixer simple element
264  * \param elem Mixer simple element handle
265  * \param channel Mixer simple element channel identifier
266  * \return 0 if channel is not present, 1 if present
267  */
snd_mixer_selem_has_playback_channel(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel)268 int snd_mixer_selem_has_playback_channel(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel)
269 {
270 	CHECK_BASIC(elem);
271 	return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_CHANNEL, (int)channel);
272 }
273 
274 /**
275  * \brief Get range for playback volume of a mixer simple element
276  * \param elem Mixer simple element handle
277  * \param min Pointer to returned minimum
278  * \param max Pointer to returned maximum
279  */
snd_mixer_selem_get_playback_volume_range(snd_mixer_elem_t * elem,long * min,long * max)280 int snd_mixer_selem_get_playback_volume_range(snd_mixer_elem_t *elem,
281 					       long *min, long *max)
282 {
283 	CHECK_BASIC(elem);
284 	CHECK_DIR(elem, SM_CAP_PVOLUME);
285 	return sm_selem_ops(elem)->get_range(elem, SM_PLAY, min, max);
286 }
287 
288 /**
289  * \brief Get range in dB for playback volume of a mixer simple element
290  * \param elem Mixer simple element handle
291  * \param min Pointer to returned minimum (dB * 100)
292  * \param max Pointer to returned maximum (dB * 100)
293  */
snd_mixer_selem_get_playback_dB_range(snd_mixer_elem_t * elem,long * min,long * max)294 int snd_mixer_selem_get_playback_dB_range(snd_mixer_elem_t *elem,
295 					  long *min, long *max)
296 {
297 	CHECK_BASIC(elem);
298 	CHECK_DIR(elem, SM_CAP_PVOLUME);
299 	return sm_selem_ops(elem)->get_dB_range(elem, SM_PLAY, min, max);
300 }
301 
302 /**
303  * \brief Set range for playback volume of a mixer simple element
304  * \param elem Mixer simple element handle
305  * \param min minimum volume value
306  * \param max maximum volume value
307  */
snd_mixer_selem_set_playback_volume_range(snd_mixer_elem_t * elem,long min,long max)308 int snd_mixer_selem_set_playback_volume_range(snd_mixer_elem_t *elem,
309 					      long min, long max)
310 {
311 	CHECK_BASIC(elem);
312 	assert(min < max);
313 	CHECK_DIR(elem, SM_CAP_PVOLUME);
314 	return sm_selem_ops(elem)->set_range(elem, SM_PLAY, min, max);
315 }
316 
317 /**
318  * \brief Return info about playback volume control of a mixer simple element
319  * \param elem Mixer simple element handle
320  * \return 0 if no control is present, 1 if it's present
321  */
snd_mixer_selem_has_playback_volume(snd_mixer_elem_t * elem)322 int snd_mixer_selem_has_playback_volume(snd_mixer_elem_t *elem)
323 {
324 	CHECK_BASIC(elem);
325 	return COND_CAPS(elem, SM_CAP_PVOLUME);
326 }
327 
328 /**
329  * \brief Return info about playback volume control of a mixer simple element
330  * \param elem Mixer simple element handle
331  * \return 0 if control is separated per channel, 1 if control acts on all channels together
332  */
snd_mixer_selem_has_playback_volume_joined(snd_mixer_elem_t * elem)333 int snd_mixer_selem_has_playback_volume_joined(snd_mixer_elem_t *elem)
334 {
335 	CHECK_BASIC(elem);
336 	return COND_CAPS(elem, SM_CAP_PVOLUME_JOIN);
337 }
338 
339 /**
340  * \brief Return info about playback switch control existence of a mixer simple element
341  * \param elem Mixer simple element handle
342  * \return 0 if no control is present, 1 if it's present
343  */
snd_mixer_selem_has_playback_switch(snd_mixer_elem_t * elem)344 int snd_mixer_selem_has_playback_switch(snd_mixer_elem_t *elem)
345 {
346 	CHECK_BASIC(elem);
347 	return COND_CAPS(elem, SM_CAP_PSWITCH);
348 }
349 
350 /**
351  * \brief Return info about playback switch control of a mixer simple element
352  * \param elem Mixer simple element handle
353  * \return 0 if control is separated per channel, 1 if control acts on all channels together
354  */
snd_mixer_selem_has_playback_switch_joined(snd_mixer_elem_t * elem)355 int snd_mixer_selem_has_playback_switch_joined(snd_mixer_elem_t *elem)
356 {
357 	CHECK_BASIC(elem);
358 	return COND_CAPS(elem, SM_CAP_PSWITCH_JOIN);
359 }
360 
361 /**
362  * \brief Return corresponding dB value to an integer playback volume for a mixer simple element
363  * \param elem Mixer simple element handle
364  * \param value value to be converted to dB range
365  * \param dBvalue pointer to returned dB value
366  * \return 0 on success otherwise a negative error code
367  */
snd_mixer_selem_ask_playback_vol_dB(snd_mixer_elem_t * elem,long value,long * dBvalue)368 int snd_mixer_selem_ask_playback_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue)
369 {
370 	CHECK_BASIC(elem);
371 	CHECK_DIR(elem, SM_CAP_PVOLUME);
372 	return sm_selem_ops(elem)->ask_vol_dB(elem, SM_PLAY, value, dBvalue);
373 }
374 
375 /**
376  * \brief Return corresponding integer playback volume for given dB value for a mixer simple element
377  * \param elem Mixer simple element handle
378  * \param value value to be converted to dB range
379  * \param dir rounding mode - rounds up if dir > 0, otherwise rounds down
380  * \param dBvalue pointer to returned dB value
381  * \return 0 on success otherwise a negative error code
382  */
snd_mixer_selem_ask_playback_dB_vol(snd_mixer_elem_t * elem,long dBvalue,int dir,long * value)383 int snd_mixer_selem_ask_playback_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value)
384 {
385 	CHECK_BASIC(elem);
386 	CHECK_DIR(elem, SM_CAP_PVOLUME);
387 	return sm_selem_ops(elem)->ask_dB_vol(elem, SM_PLAY, dBvalue, value, dir);
388 }
389 
390 /**
391  * \brief Return value of playback volume control of a mixer simple element
392  * \param elem Mixer simple element handle
393  * \param channel mixer simple element channel identifier
394  * \param value pointer to returned value
395  * \return 0 on success otherwise a negative error code
396  */
snd_mixer_selem_get_playback_volume(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,long * value)397 int snd_mixer_selem_get_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value)
398 {
399 	CHECK_BASIC(elem);
400 	CHECK_DIR_CHN(elem, SM_CAP_PVOLUME, SM_CAP_PVOLUME_JOIN, channel);
401 	return sm_selem_ops(elem)->get_volume(elem, SM_PLAY, channel, value);
402 }
403 
404 /**
405  * \brief Return value of playback volume in dB control of a mixer simple element
406  * \param elem Mixer simple element handle
407  * \param channel mixer simple element channel identifier
408  * \param value pointer to returned value (dB * 100)
409  * \return 0 on success otherwise a negative error code
410  */
snd_mixer_selem_get_playback_dB(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,long * value)411 int snd_mixer_selem_get_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value)
412 {
413 	unsigned int caps;
414 
415 	CHECK_BASIC(elem);
416 	caps = ((sm_selem_t *)elem->private_data)->caps;
417 	if (!(caps & SM_CAP_PVOLUME))
418 		return -EINVAL;
419 	if (caps & SM_CAP_PVOLUME_JOIN)
420 		channel = 0;
421 	return sm_selem_ops(elem)->get_dB(elem, SM_PLAY, channel, value);
422 }
423 
424 /**
425  * \brief Return value of playback switch control of a mixer simple element
426  * \param elem Mixer simple element handle
427  * \param channel mixer simple element channel identifier
428  * \param value pointer to returned value
429  * \return 0 on success otherwise a negative error code
430  */
snd_mixer_selem_get_playback_switch(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,int * value)431 int snd_mixer_selem_get_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value)
432 {
433 	CHECK_BASIC(elem);
434 	CHECK_DIR_CHN(elem, SM_CAP_PSWITCH, SM_CAP_PSWITCH_JOIN, channel);
435 	return sm_selem_ops(elem)->get_switch(elem, SM_PLAY, channel, value);
436 }
437 
438 /**
439  * \brief Set value of playback volume control of a mixer simple element
440  * \param elem Mixer simple element handle
441  * \param channel mixer simple element channel identifier
442  * \param value control value
443  * \return 0 on success otherwise a negative error code
444  */
snd_mixer_selem_set_playback_volume(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,long value)445 int snd_mixer_selem_set_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value)
446 {
447 	CHECK_BASIC(elem);
448 	CHECK_DIR_CHN(elem, SM_CAP_PVOLUME, SM_CAP_PVOLUME_JOIN, channel);
449 	return sm_selem_ops(elem)->set_volume(elem, SM_PLAY, channel, value);
450 }
451 
452 /**
453  * \brief Set value in dB of playback volume control of a mixer simple element
454  * \param elem Mixer simple element handle
455  * \param channel mixer simple element channel identifier
456  * \param value control value in dB * 100
457  * \param dir rounding mode - rounds up if dir > 0, otherwise rounds down
458  * \return 0 on success otherwise a negative error code
459  */
snd_mixer_selem_set_playback_dB(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,long value,int dir)460 int snd_mixer_selem_set_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir)
461 {
462 	CHECK_BASIC(elem);
463 	CHECK_DIR_CHN(elem, SM_CAP_PVOLUME, SM_CAP_PVOLUME_JOIN, channel);
464 	return sm_selem_ops(elem)->set_dB(elem, SM_PLAY, channel, value, dir);
465 }
466 
467 /**
468  * \brief Set value of playback volume control for all channels of a mixer simple element
469  * \param elem Mixer simple element handle
470  * \param value control value
471  * \return 0 on success otherwise a negative error code
472  */
snd_mixer_selem_set_playback_volume_all(snd_mixer_elem_t * elem,long value)473 int snd_mixer_selem_set_playback_volume_all(snd_mixer_elem_t *elem, long value)
474 {
475 	snd_mixer_selem_channel_id_t chn;
476 	int err;
477 
478 	for (chn = 0; chn < 32; chn++) {
479 		if (!snd_mixer_selem_has_playback_channel(elem, chn))
480 			continue;
481 		err = snd_mixer_selem_set_playback_volume(elem, chn, value);
482 		if (err < 0)
483 			return err;
484 		if (chn == 0 && snd_mixer_selem_has_playback_volume_joined(elem))
485 			return 0;
486 	}
487 	return 0;
488 }
489 
490 /**
491  * \brief Set value in dB of playback volume control for all channels of a mixer simple element
492  * \param elem Mixer simple element handle
493  * \param value control value in dB * 100
494  * \param dir rounding mode - rounds up if dir > 0, otherwise rounds down
495  * \return 0 on success otherwise a negative error code
496  */
snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t * elem,long value,int dir)497 int snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t *elem, long value, int dir)
498 {
499 	snd_mixer_selem_channel_id_t chn;
500 	int err;
501 
502 	for (chn = 0; chn < 32; chn++) {
503 		if (!snd_mixer_selem_has_playback_channel(elem, chn))
504 			continue;
505 		err = snd_mixer_selem_set_playback_dB(elem, chn, value, dir);
506 		if (err < 0)
507 			return err;
508 		if (chn == 0 && snd_mixer_selem_has_playback_volume_joined(elem))
509 			return 0;
510 	}
511 	return 0;
512 }
513 
514 /**
515  * \brief Set value of playback switch control of a mixer simple element
516  * \param elem Mixer simple element handle
517  * \param channel mixer simple element channel identifier
518  * \param value control value
519  * \return 0 on success otherwise a negative error code
520  */
snd_mixer_selem_set_playback_switch(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,int value)521 int snd_mixer_selem_set_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value)
522 {
523 	CHECK_BASIC(elem);
524 	CHECK_DIR_CHN(elem, SM_CAP_PSWITCH, SM_CAP_PSWITCH_JOIN, channel);
525 	return sm_selem_ops(elem)->set_switch(elem, SM_PLAY, channel, value);
526 }
527 
528 /**
529  * \brief Set value of playback switch control for all channels of a mixer simple element
530  * \param elem Mixer simple element handle
531  * \param value control value
532  * \return 0 on success otherwise a negative error code
533  */
snd_mixer_selem_set_playback_switch_all(snd_mixer_elem_t * elem,int value)534 int snd_mixer_selem_set_playback_switch_all(snd_mixer_elem_t *elem, int value)
535 {
536 	snd_mixer_selem_channel_id_t chn;
537 	int err;
538 
539 	CHECK_BASIC(elem);
540 	for (chn = 0; chn < 32; chn++) {
541 		if (!snd_mixer_selem_has_playback_channel(elem, chn))
542 			continue;
543 		err = snd_mixer_selem_set_playback_switch(elem, chn, value);
544 		if (err < 0)
545 			return err;
546 		if (chn == 0 && snd_mixer_selem_has_playback_switch_joined(elem))
547 			return 0;
548 	}
549 	return 0;
550 }
551 
552 /**
553  * \brief Get info about channels of capture stream of a mixer simple element
554  * \param elem Mixer simple element handle
555  * \return 0 if not mono, 1 if mono
556  */
snd_mixer_selem_is_capture_mono(snd_mixer_elem_t * elem)557 int snd_mixer_selem_is_capture_mono(snd_mixer_elem_t *elem)
558 {
559 	CHECK_BASIC(elem);
560 	CHECK_DIR(elem, SM_CAP_CVOLUME|SM_CAP_CSWITCH);
561 	return sm_selem_ops(elem)->is(elem, SM_CAPT, SM_OPS_IS_MONO, 0);
562 }
563 
564 /**
565  * \brief Get info about channels of capture stream of a mixer simple element
566  * \param elem Mixer simple element handle
567  * \param channel Mixer simple element channel identifier
568  * \return 0 if channel is not present, 1 if present
569  */
snd_mixer_selem_has_capture_channel(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel)570 int snd_mixer_selem_has_capture_channel(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel)
571 {
572 	CHECK_BASIC(elem);
573 	CHECK_DIR(elem, SM_CAP_CVOLUME|SM_CAP_CSWITCH);
574 	return sm_selem_ops(elem)->is(elem, SM_CAPT, SM_OPS_IS_CHANNEL, channel);
575 }
576 
577 /**
578  * \brief Get range for capture volume of a mixer simple element
579  * \param elem Mixer simple element handle
580  * \param min Pointer to returned minimum
581  * \param max Pointer to returned maximum
582  */
snd_mixer_selem_get_capture_volume_range(snd_mixer_elem_t * elem,long * min,long * max)583 int snd_mixer_selem_get_capture_volume_range(snd_mixer_elem_t *elem,
584 					     long *min, long *max)
585 {
586 	CHECK_BASIC(elem);
587 	CHECK_DIR(elem, SM_CAP_CVOLUME);
588 	return sm_selem_ops(elem)->get_range(elem, SM_CAPT, min, max);
589 }
590 
591 /**
592  * \brief Get range in dB for capture volume of a mixer simple element
593  * \param elem Mixer simple element handle
594  * \param min Pointer to returned minimum (dB * 100)
595  * \param max Pointer to returned maximum (dB * 100)
596  */
snd_mixer_selem_get_capture_dB_range(snd_mixer_elem_t * elem,long * min,long * max)597 int snd_mixer_selem_get_capture_dB_range(snd_mixer_elem_t *elem,
598 					 long *min, long *max)
599 {
600 	CHECK_BASIC(elem);
601 	CHECK_DIR(elem, SM_CAP_CVOLUME);
602 	return sm_selem_ops(elem)->get_dB_range(elem, SM_CAPT, min, max);
603 }
604 
605 /**
606  * \brief Set range for capture volume of a mixer simple element
607  * \param elem Mixer simple element handle
608  * \param min minimum volume value
609  * \param max maximum volume value
610  */
snd_mixer_selem_set_capture_volume_range(snd_mixer_elem_t * elem,long min,long max)611 int snd_mixer_selem_set_capture_volume_range(snd_mixer_elem_t *elem,
612 					     long min, long max)
613 {
614 	CHECK_BASIC(elem);
615 	assert(min < max);
616 	CHECK_DIR(elem, SM_CAP_CVOLUME);
617 	return sm_selem_ops(elem)->set_range(elem, SM_CAPT, min, max);
618 }
619 
620 /**
621  * \brief Return info about capture volume control of a mixer simple element
622  * \param elem Mixer simple element handle
623  * \return 0 if no control is present, 1 if it's present
624  */
snd_mixer_selem_has_capture_volume(snd_mixer_elem_t * elem)625 int snd_mixer_selem_has_capture_volume(snd_mixer_elem_t *elem)
626 {
627 	CHECK_BASIC(elem);
628 	return COND_CAPS(elem, SM_CAP_CVOLUME);
629 }
630 
631 /**
632  * \brief Return info about capture volume control of a mixer simple element
633  * \param elem Mixer simple element handle
634  * \return 0 if control is separated per channel, 1 if control acts on all channels together
635  */
snd_mixer_selem_has_capture_volume_joined(snd_mixer_elem_t * elem)636 int snd_mixer_selem_has_capture_volume_joined(snd_mixer_elem_t *elem)
637 {
638 	CHECK_BASIC(elem);
639 	return COND_CAPS(elem, SM_CAP_CVOLUME_JOIN);
640 }
641 
642 /**
643  * \brief Return info about capture switch control existence of a mixer simple element
644  * \param elem Mixer simple element handle
645  * \return 0 if no control is present, 1 if it's present
646  */
snd_mixer_selem_has_capture_switch(snd_mixer_elem_t * elem)647 int snd_mixer_selem_has_capture_switch(snd_mixer_elem_t *elem)
648 {
649 	CHECK_BASIC(elem);
650 	return COND_CAPS(elem, SM_CAP_CSWITCH);
651 }
652 
653 /**
654  * \brief Return info about capture switch control of a mixer simple element
655  * \param elem Mixer simple element handle
656  * \return 0 if control is separated per channel, 1 if control acts on all channels together
657  */
snd_mixer_selem_has_capture_switch_joined(snd_mixer_elem_t * elem)658 int snd_mixer_selem_has_capture_switch_joined(snd_mixer_elem_t *elem)
659 {
660 	CHECK_BASIC(elem);
661 	return COND_CAPS(elem, SM_CAP_CSWITCH_JOIN);
662 }
663 
664 /**
665  * \brief Return info about capture switch control of a mixer simple element
666  * \param elem Mixer simple element handle
667  * \return 0 if control is separated per element, 1 if control acts on other elements too (i.e. only one active at a time inside a group)
668  */
snd_mixer_selem_has_capture_switch_exclusive(snd_mixer_elem_t * elem)669 int snd_mixer_selem_has_capture_switch_exclusive(snd_mixer_elem_t *elem)
670 {
671 	CHECK_BASIC(elem);
672 	return COND_CAPS(elem, SM_CAP_CSWITCH_EXCL);
673 }
674 
675 /**
676  * \brief Return info about capture switch control of a mixer simple element
677  * \param elem Mixer simple element handle
678  * \return group for switch exclusivity (see #snd_mixer_selem_has_capture_switch_exclusive)
679  */
snd_mixer_selem_get_capture_group(snd_mixer_elem_t * elem)680 int snd_mixer_selem_get_capture_group(snd_mixer_elem_t *elem)
681 {
682 	sm_selem_t *s;
683 	CHECK_BASIC(elem);
684 	s = elem->private_data;
685 	if (! (s->caps & SM_CAP_CSWITCH_EXCL))
686 		return -EINVAL;
687 	return s->capture_group;
688 }
689 
690 /**
691  * \brief Return corresponding dB value to an integer capture volume for a mixer simple element
692  * \param elem Mixer simple element handle
693  * \param value value to be converted to dB range
694  * \param dBvalue pointer to returned dB value
695  * \return 0 on success otherwise a negative error code
696  */
snd_mixer_selem_ask_capture_vol_dB(snd_mixer_elem_t * elem,long value,long * dBvalue)697 int snd_mixer_selem_ask_capture_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue)
698 {
699 	CHECK_BASIC(elem);
700 	CHECK_DIR(elem, SM_CAP_CVOLUME);
701 	return sm_selem_ops(elem)->ask_vol_dB(elem, SM_CAPT, value, dBvalue);
702 }
703 
704 /**
705  * \brief Return corresponding integer capture volume for given dB value for a mixer simple element
706  * \param elem Mixer simple element handle
707  * \param dBvalue dB value to be converted to integer range
708  * \param value pointer to returned integer value
709  * \param dir rounding mode - rounds up if dir > 0, otherwise rounds down
710  * \return 0 on success otherwise a negative error code
711  */
snd_mixer_selem_ask_capture_dB_vol(snd_mixer_elem_t * elem,long dBvalue,int dir,long * value)712 int snd_mixer_selem_ask_capture_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value)
713 {
714 	CHECK_BASIC(elem);
715 	CHECK_DIR(elem, SM_CAP_CVOLUME);
716 	return sm_selem_ops(elem)->ask_dB_vol(elem, SM_CAPT, dBvalue, value, dir);
717 }
718 
719 /**
720  * \brief Return value of capture volume control of a mixer simple element
721  * \param elem Mixer simple element handle
722  * \param channel mixer simple element channel identifier
723  * \param value pointer to returned value
724  * \return 0 on success otherwise a negative error code
725  */
snd_mixer_selem_get_capture_volume(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,long * value)726 int snd_mixer_selem_get_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value)
727 {
728 	CHECK_BASIC(elem);
729 	CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel);
730 	return sm_selem_ops(elem)->get_volume(elem, SM_CAPT, channel, value);
731 }
732 
733 /**
734  * \brief Return value of capture volume in dB control of a mixer simple element
735  * \param elem Mixer simple element handle
736  * \param channel mixer simple element channel identifier
737  * \param value pointer to returned value (dB * 100)
738  * \return 0 on success otherwise a negative error code
739  */
snd_mixer_selem_get_capture_dB(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,long * value)740 int snd_mixer_selem_get_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value)
741 {
742 	CHECK_BASIC(elem);
743 	CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel);
744 	return sm_selem_ops(elem)->get_dB(elem, SM_CAPT, channel, value);
745 }
746 
747 /**
748  * \brief Return value of capture switch control of a mixer simple element
749  * \param elem Mixer simple element handle
750  * \param channel mixer simple element channel identifier
751  * \param value pointer to returned value
752  * \return 0 on success otherwise a negative error code
753  */
snd_mixer_selem_get_capture_switch(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,int * value)754 int snd_mixer_selem_get_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value)
755 {
756 	CHECK_BASIC(elem);
757 	CHECK_DIR_CHN(elem, SM_CAP_CSWITCH, SM_CAP_CSWITCH_JOIN, channel);
758 	return sm_selem_ops(elem)->get_switch(elem, SM_CAPT, channel, value);
759 }
760 
761 /**
762  * \brief Set value of capture volume control of a mixer simple element
763  * \param elem Mixer simple element handle
764  * \param channel mixer simple element channel identifier
765  * \param value control value
766  * \return 0 on success otherwise a negative error code
767  */
snd_mixer_selem_set_capture_volume(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,long value)768 int snd_mixer_selem_set_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value)
769 {
770 	CHECK_BASIC(elem);
771 	CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel);
772 	return sm_selem_ops(elem)->set_volume(elem, SM_CAPT, channel, value);
773 }
774 
775 /**
776  * \brief Set value in dB of capture volume control of a mixer simple element
777  * \param elem Mixer simple element handle
778  * \param channel mixer simple element channel identifier
779  * \param value control value in dB * 100
780  * \param dir rounding mode - rounds up if dir > 0, otherwise rounds down
781  * \return 0 on success otherwise a negative error code
782  */
snd_mixer_selem_set_capture_dB(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,long value,int dir)783 int snd_mixer_selem_set_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir)
784 {
785 	CHECK_BASIC(elem);
786 	CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel);
787 	return sm_selem_ops(elem)->set_dB(elem, SM_CAPT, channel, value, dir);
788 }
789 
790 /**
791  * \brief Set value of capture volume control for all channels of a mixer simple element
792  * \param elem Mixer simple element handle
793  * \param value control value
794  * \return 0 on success otherwise a negative error code
795  */
snd_mixer_selem_set_capture_volume_all(snd_mixer_elem_t * elem,long value)796 int snd_mixer_selem_set_capture_volume_all(snd_mixer_elem_t *elem, long value)
797 {
798 	snd_mixer_selem_channel_id_t chn;
799 	int err;
800 
801 	for (chn = 0; chn < 32; chn++) {
802 		if (!snd_mixer_selem_has_capture_channel(elem, chn))
803 			continue;
804 		err = snd_mixer_selem_set_capture_volume(elem, chn, value);
805 		if (err < 0)
806 			return err;
807 		if (chn == 0 && snd_mixer_selem_has_capture_volume_joined(elem))
808 			return 0;
809 	}
810 	return 0;
811 }
812 
813 /**
814  * \brief Set value in dB of capture volume control for all channels of a mixer simple element
815  * \param elem Mixer simple element handle
816  * \param value control value in dB * 100
817  * \param dir rounding mode - rounds up if dir > 0, otherwise rounds down
818  * \return 0 on success otherwise a negative error code
819  */
snd_mixer_selem_set_capture_dB_all(snd_mixer_elem_t * elem,long value,int dir)820 int snd_mixer_selem_set_capture_dB_all(snd_mixer_elem_t *elem, long value, int dir)
821 {
822 	snd_mixer_selem_channel_id_t chn;
823 	int err;
824 
825 	for (chn = 0; chn < 32; chn++) {
826 		if (!snd_mixer_selem_has_capture_channel(elem, chn))
827 			continue;
828 		err = snd_mixer_selem_set_capture_dB(elem, chn, value, dir);
829 		if (err < 0)
830 			return err;
831 		if (chn == 0 && snd_mixer_selem_has_capture_volume_joined(elem))
832 			return 0;
833 	}
834 	return 0;
835 }
836 
837 /**
838  * \brief Set value of capture switch control of a mixer simple element
839  * \param elem Mixer simple element handle
840  * \param channel mixer simple element channel identifier
841  * \param value control value
842  * \return 0 on success otherwise a negative error code
843  */
snd_mixer_selem_set_capture_switch(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,int value)844 int snd_mixer_selem_set_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value)
845 {
846 	CHECK_BASIC(elem);
847 	CHECK_DIR_CHN(elem, SM_CAP_CSWITCH, SM_CAP_CSWITCH_JOIN, channel);
848 	return sm_selem_ops(elem)->set_switch(elem, SM_CAPT, channel, value);
849 }
850 
851 /**
852  * \brief Set value of capture switch control for all channels of a mixer simple element
853  * \param elem Mixer simple element handle
854  * \param value control value
855  * \return 0 on success otherwise a negative error code
856  */
snd_mixer_selem_set_capture_switch_all(snd_mixer_elem_t * elem,int value)857 int snd_mixer_selem_set_capture_switch_all(snd_mixer_elem_t *elem, int value)
858 {
859 	snd_mixer_selem_channel_id_t chn;
860 	int err;
861 
862 	for (chn = 0; chn < 32; chn++) {
863 		if (!snd_mixer_selem_has_capture_channel(elem, chn))
864 			continue;
865 		err = snd_mixer_selem_set_capture_switch(elem, chn, value);
866 		if (err < 0)
867 			return err;
868 		if (chn == 0 && snd_mixer_selem_has_capture_switch_joined(elem))
869 			return 0;
870 	}
871 	return 0;
872 }
873 
874 /**
875  * \brief Return true if mixer simple element is an enumerated control
876  * \param elem Mixer simple element handle
877  * \return 0 normal volume/switch control, 1 enumerated control
878  */
snd_mixer_selem_is_enumerated(snd_mixer_elem_t * elem)879 int snd_mixer_selem_is_enumerated(snd_mixer_elem_t *elem)
880 {
881 	CHECK_BASIC(elem);
882 	return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMERATED, 0);
883 }
884 
885 /**
886  * \brief Return true if mixer simple enumerated element belongs to the playback direction
887  * \param elem Mixer simple element handle
888  * \return 0 no playback direction, 1 playback direction
889  */
snd_mixer_selem_is_enum_playback(snd_mixer_elem_t * elem)890 int snd_mixer_selem_is_enum_playback(snd_mixer_elem_t *elem)
891 {
892 	CHECK_BASIC(elem);
893 	return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMERATED, 1);
894 }
895 
896 /**
897  * \brief Return true if mixer simple enumerated element belongs to the capture direction
898  * \param elem Mixer simple element handle
899  * \return 0 no capture direction, 1 capture direction
900  */
snd_mixer_selem_is_enum_capture(snd_mixer_elem_t * elem)901 int snd_mixer_selem_is_enum_capture(snd_mixer_elem_t *elem)
902 {
903 	CHECK_BASIC(elem);
904 	return sm_selem_ops(elem)->is(elem, SM_CAPT, SM_OPS_IS_ENUMERATED, 1);
905 }
906 
907 /**
908  * \brief Return the number of enumerated items of the given mixer simple element
909  * \param elem Mixer simple element handle
910  * \return the number of enumerated items, otherwise a negative error code
911  */
snd_mixer_selem_get_enum_items(snd_mixer_elem_t * elem)912 int snd_mixer_selem_get_enum_items(snd_mixer_elem_t *elem)
913 {
914 	CHECK_BASIC(elem);
915 	CHECK_ENUM(elem);
916 	return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMCNT, 0);
917 }
918 
919 /**
920  * \brief get the enumerated item string for the given mixer simple element
921  * \param elem Mixer simple element handle
922  * \param item the index of the enumerated item to query
923  * \param maxlen the maximal length to be stored
924  * \param buf the buffer to store the name string
925  * \return 0 if successful, otherwise a negative error code
926  */
snd_mixer_selem_get_enum_item_name(snd_mixer_elem_t * elem,unsigned int item,size_t maxlen,char * buf)927 int snd_mixer_selem_get_enum_item_name(snd_mixer_elem_t *elem,
928 				       unsigned int item,
929 				       size_t maxlen, char *buf)
930 {
931 	CHECK_BASIC(elem);
932 	CHECK_ENUM(elem);
933 	return sm_selem_ops(elem)->enum_item_name(elem, item, maxlen, buf);
934 }
935 
936 /**
937  * \brief get the current selected enumerated item for the given mixer simple element
938  * \param elem Mixer simple element handle
939  * \param channel mixer simple element channel identifier
940  * \param itemp the pointer to store the index of the enumerated item
941  * \return 0 if successful, otherwise a negative error code
942  */
snd_mixer_selem_get_enum_item(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,unsigned int * itemp)943 int snd_mixer_selem_get_enum_item(snd_mixer_elem_t *elem,
944 				  snd_mixer_selem_channel_id_t channel,
945 				  unsigned int *itemp)
946 {
947 	CHECK_BASIC(elem);
948 	CHECK_ENUM(elem);
949 	return sm_selem_ops(elem)->get_enum_item(elem, channel, itemp);
950 }
951 
952 /**
953  * \brief set the current selected enumerated item for the given mixer simple element
954  * \param elem Mixer simple element handle
955  * \param channel mixer simple element channel identifier
956  * \param item the enumerated item index
957  * \return 0 if successful, otherwise a negative error code
958  */
snd_mixer_selem_set_enum_item(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,unsigned int item)959 int snd_mixer_selem_set_enum_item(snd_mixer_elem_t *elem,
960 				  snd_mixer_selem_channel_id_t channel,
961 				  unsigned int item)
962 {
963 	CHECK_BASIC(elem);
964 	CHECK_ENUM(elem);
965 	return sm_selem_ops(elem)->set_enum_item(elem, channel, item);
966 }
967 
968 /**
969  * \brief get size of #snd_mixer_selem_id_t
970  * \return size in bytes
971  */
snd_mixer_selem_id_sizeof()972 size_t snd_mixer_selem_id_sizeof()
973 {
974 	return sizeof(snd_mixer_selem_id_t);
975 }
976 
977 /**
978  * \brief allocate an invalid #snd_mixer_selem_id_t using standard malloc
979  * \param ptr returned pointer
980  * \return 0 on success otherwise negative error code
981  */
snd_mixer_selem_id_malloc(snd_mixer_selem_id_t ** ptr)982 int snd_mixer_selem_id_malloc(snd_mixer_selem_id_t **ptr)
983 {
984 	assert(ptr);
985 	*ptr = calloc(1, sizeof(snd_mixer_selem_id_t));
986 	if (!*ptr)
987 		return -ENOMEM;
988 	return 0;
989 }
990 
991 /**
992  * \brief frees a previously allocated #snd_mixer_selem_id_t
993  * \param obj pointer to object to free
994  */
snd_mixer_selem_id_free(snd_mixer_selem_id_t * obj)995 void snd_mixer_selem_id_free(snd_mixer_selem_id_t *obj)
996 {
997 	free(obj);
998 }
999 
1000 /**
1001  * \brief copy one #snd_mixer_selem_id_t to another
1002  * \param dst pointer to destination
1003  * \param src pointer to source
1004  */
snd_mixer_selem_id_copy(snd_mixer_selem_id_t * dst,const snd_mixer_selem_id_t * src)1005 void snd_mixer_selem_id_copy(snd_mixer_selem_id_t *dst, const snd_mixer_selem_id_t *src)
1006 {
1007 	assert(dst && src);
1008 	*dst = *src;
1009 }
1010 
1011 /**
1012  * \brief Get name part of a mixer simple element identifier
1013  * \param obj Mixer simple element identifier
1014  * \return name part
1015  */
snd_mixer_selem_id_get_name(const snd_mixer_selem_id_t * obj)1016 const char *snd_mixer_selem_id_get_name(const snd_mixer_selem_id_t *obj)
1017 {
1018 	assert(obj);
1019 	return obj->name;
1020 }
1021 
1022 /**
1023  * \brief Get index part of a mixer simple element identifier
1024  * \param obj Mixer simple element identifier
1025  * \return index part
1026  */
snd_mixer_selem_id_get_index(const snd_mixer_selem_id_t * obj)1027 unsigned int snd_mixer_selem_id_get_index(const snd_mixer_selem_id_t *obj)
1028 {
1029 	assert(obj);
1030 	return obj->index;
1031 }
1032 
1033 /**
1034  * \brief Set name part of a mixer simple element identifier
1035  * \param obj Mixer simple element identifier
1036  * \param val name part
1037  */
snd_mixer_selem_id_set_name(snd_mixer_selem_id_t * obj,const char * val)1038 void snd_mixer_selem_id_set_name(snd_mixer_selem_id_t *obj, const char *val)
1039 {
1040 	assert(obj);
1041 	strncpy(obj->name, val, sizeof(obj->name));
1042 	obj->name[sizeof(obj->name)-1] = '\0';
1043 }
1044 
1045 /**
1046  * \brief Set index part of a mixer simple element identifier
1047  * \param obj Mixer simple element identifier
1048  * \param val index part
1049  */
snd_mixer_selem_id_set_index(snd_mixer_selem_id_t * obj,unsigned int val)1050 void snd_mixer_selem_id_set_index(snd_mixer_selem_id_t *obj, unsigned int val)
1051 {
1052 	assert(obj);
1053 	obj->index = val;
1054 }
1055 
1056 /**
1057  * \brief Parse ASCII simple mixer element identifier
1058  * \param dst Parsed simple mixer element identifier
1059  * \param str Mixer simple element ASCII representation
1060  */
snd_mixer_selem_id_parse(snd_mixer_selem_id_t * dst,const char * str)1061 int snd_mixer_selem_id_parse(snd_mixer_selem_id_t *dst, const char *str)
1062 {
1063 	int c, size;
1064 	char buf[128];
1065 	char *ptr = buf;
1066 
1067 	memset(dst, 0, sizeof(*dst));
1068 	while (*str == ' ' || *str == '\t')
1069 		str++;
1070 	if (!(*str))
1071 		return -EINVAL;
1072 	size = 1;	/* for '\0' */
1073 	if (*str != '"' && *str != '\'') {
1074 		while (*str && *str != ',') {
1075 			if (size < (int)sizeof(buf)) {
1076 				*ptr++ = *str;
1077 				size++;
1078 			}
1079 			str++;
1080 		}
1081 	} else {
1082 		c = *str++;
1083 		while (*str && *str != c) {
1084 			if (size < (int)sizeof(buf)) {
1085 				*ptr++ = *str;
1086 				size++;
1087 			}
1088 			str++;
1089 		}
1090 		if (*str == c)
1091 			str++;
1092 	}
1093 	if (*str == '\0') {
1094 		*ptr = 0;
1095 		goto _set;
1096 	}
1097 	if (*str != ',')
1098 		return -EINVAL;
1099 	*ptr = 0;	/* terminate the string */
1100 	str++;
1101 	if (str[0] < '0' || str[1] > '9')
1102 		return -EINVAL;
1103 	dst->index = atoi(str);
1104        _set:
1105 	snd_strlcpy(dst->name, buf, sizeof(dst->name));
1106 	return 0;
1107 }
1108