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