• 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 <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, round to nearest if dir == 0,
380  *            rounds down if dir < 0
381  * \param dBvalue pointer to returned dB value
382  * \return 0 on success otherwise a negative error code
383  */
snd_mixer_selem_ask_playback_dB_vol(snd_mixer_elem_t * elem,long dBvalue,int dir,long * value)384 int snd_mixer_selem_ask_playback_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value)
385 {
386 	CHECK_BASIC(elem);
387 	CHECK_DIR(elem, SM_CAP_PVOLUME);
388 	return sm_selem_ops(elem)->ask_dB_vol(elem, SM_PLAY, dBvalue, value, dir);
389 }
390 
391 /**
392  * \brief Return value of playback volume control of a mixer simple element
393  * \param elem Mixer simple element handle
394  * \param channel mixer simple element channel identifier
395  * \param value pointer to returned value
396  * \return 0 on success otherwise a negative error code
397  */
snd_mixer_selem_get_playback_volume(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,long * value)398 int snd_mixer_selem_get_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value)
399 {
400 	CHECK_BASIC(elem);
401 	CHECK_DIR_CHN(elem, SM_CAP_PVOLUME, SM_CAP_PVOLUME_JOIN, channel);
402 	return sm_selem_ops(elem)->get_volume(elem, SM_PLAY, channel, value);
403 }
404 
405 /**
406  * \brief Return value of playback volume in dB control of a mixer simple element
407  * \param elem Mixer simple element handle
408  * \param channel mixer simple element channel identifier
409  * \param value pointer to returned value (dB * 100)
410  * \return 0 on success otherwise a negative error code
411  */
snd_mixer_selem_get_playback_dB(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,long * value)412 int snd_mixer_selem_get_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value)
413 {
414 	unsigned int caps;
415 
416 	CHECK_BASIC(elem);
417 	caps = ((sm_selem_t *)elem->private_data)->caps;
418 	if (!(caps & SM_CAP_PVOLUME))
419 		return -EINVAL;
420 	if (caps & SM_CAP_PVOLUME_JOIN)
421 		channel = 0;
422 	return sm_selem_ops(elem)->get_dB(elem, SM_PLAY, channel, value);
423 }
424 
425 /**
426  * \brief Return value of playback switch control of a mixer simple element
427  * \param elem Mixer simple element handle
428  * \param channel mixer simple element channel identifier
429  * \param value pointer to returned value
430  * \return 0 on success otherwise a negative error code
431  */
snd_mixer_selem_get_playback_switch(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,int * value)432 int snd_mixer_selem_get_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value)
433 {
434 	CHECK_BASIC(elem);
435 	CHECK_DIR_CHN(elem, SM_CAP_PSWITCH, SM_CAP_PSWITCH_JOIN, channel);
436 	return sm_selem_ops(elem)->get_switch(elem, SM_PLAY, channel, value);
437 }
438 
439 /**
440  * \brief Set value of playback volume control of a mixer simple element
441  * \param elem Mixer simple element handle
442  * \param channel mixer simple element channel identifier
443  * \param value control value
444  * \return 0 on success otherwise a negative error code
445  */
snd_mixer_selem_set_playback_volume(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,long value)446 int snd_mixer_selem_set_playback_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value)
447 {
448 	CHECK_BASIC(elem);
449 	CHECK_DIR_CHN(elem, SM_CAP_PVOLUME, SM_CAP_PVOLUME_JOIN, channel);
450 	return sm_selem_ops(elem)->set_volume(elem, SM_PLAY, channel, value);
451 }
452 
453 /**
454  * \brief Set value in dB of playback volume control of a mixer simple element
455  * \param elem Mixer simple element handle
456  * \param channel mixer simple element channel identifier
457  * \param value control value in dB * 100
458  * \param dir rounding mode - rounds up if dir > 0, round to nearest if dir == 0,
459  *            rounds down if dir < 0
460  * \return 0 on success otherwise a negative error code
461  */
snd_mixer_selem_set_playback_dB(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,long value,int dir)462 int snd_mixer_selem_set_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir)
463 {
464 	CHECK_BASIC(elem);
465 	CHECK_DIR_CHN(elem, SM_CAP_PVOLUME, SM_CAP_PVOLUME_JOIN, channel);
466 	return sm_selem_ops(elem)->set_dB(elem, SM_PLAY, channel, value, dir);
467 }
468 
469 /**
470  * \brief Set value of playback volume control for all channels of a mixer simple element
471  * \param elem Mixer simple element handle
472  * \param value control value
473  * \return 0 on success otherwise a negative error code
474  */
snd_mixer_selem_set_playback_volume_all(snd_mixer_elem_t * elem,long value)475 int snd_mixer_selem_set_playback_volume_all(snd_mixer_elem_t *elem, long value)
476 {
477 	snd_mixer_selem_channel_id_t chn;
478 	int err;
479 
480 	for (chn = 0; chn < 32; chn++) {
481 		if (!snd_mixer_selem_has_playback_channel(elem, chn))
482 			continue;
483 		err = snd_mixer_selem_set_playback_volume(elem, chn, value);
484 		if (err < 0)
485 			return err;
486 		if (chn == 0 && snd_mixer_selem_has_playback_volume_joined(elem))
487 			return 0;
488 	}
489 	return 0;
490 }
491 
492 /**
493  * \brief Set value in dB of playback volume control for all channels of a mixer simple element
494  * \param elem Mixer simple element handle
495  * \param value control value in dB * 100
496  * \param dir rounding mode - rounds up if dir > 0, round to nearest if dir == 0,
497  *            rounds down if dir < 0
498  * \return 0 on success otherwise a negative error code
499  */
snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t * elem,long value,int dir)500 int snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t *elem, long value, int dir)
501 {
502 	snd_mixer_selem_channel_id_t chn;
503 	int err;
504 
505 	for (chn = 0; chn < 32; chn++) {
506 		if (!snd_mixer_selem_has_playback_channel(elem, chn))
507 			continue;
508 		err = snd_mixer_selem_set_playback_dB(elem, chn, value, dir);
509 		if (err < 0)
510 			return err;
511 		if (chn == 0 && snd_mixer_selem_has_playback_volume_joined(elem))
512 			return 0;
513 	}
514 	return 0;
515 }
516 
517 /**
518  * \brief Set value of playback switch control of a mixer simple element
519  * \param elem Mixer simple element handle
520  * \param channel mixer simple element channel identifier
521  * \param value control value
522  * \return 0 on success otherwise a negative error code
523  */
snd_mixer_selem_set_playback_switch(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,int value)524 int snd_mixer_selem_set_playback_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value)
525 {
526 	CHECK_BASIC(elem);
527 	CHECK_DIR_CHN(elem, SM_CAP_PSWITCH, SM_CAP_PSWITCH_JOIN, channel);
528 	return sm_selem_ops(elem)->set_switch(elem, SM_PLAY, channel, value);
529 }
530 
531 /**
532  * \brief Set value of playback switch control for all channels of a mixer simple element
533  * \param elem Mixer simple element handle
534  * \param value control value
535  * \return 0 on success otherwise a negative error code
536  */
snd_mixer_selem_set_playback_switch_all(snd_mixer_elem_t * elem,int value)537 int snd_mixer_selem_set_playback_switch_all(snd_mixer_elem_t *elem, int value)
538 {
539 	snd_mixer_selem_channel_id_t chn;
540 	int err;
541 
542 	CHECK_BASIC(elem);
543 	for (chn = 0; chn < 32; chn++) {
544 		if (!snd_mixer_selem_has_playback_channel(elem, chn))
545 			continue;
546 		err = snd_mixer_selem_set_playback_switch(elem, chn, value);
547 		if (err < 0)
548 			return err;
549 		if (chn == 0 && snd_mixer_selem_has_playback_switch_joined(elem))
550 			return 0;
551 	}
552 	return 0;
553 }
554 
555 /**
556  * \brief Get info about channels of capture stream of a mixer simple element
557  * \param elem Mixer simple element handle
558  * \return 0 if not mono, 1 if mono
559  */
snd_mixer_selem_is_capture_mono(snd_mixer_elem_t * elem)560 int snd_mixer_selem_is_capture_mono(snd_mixer_elem_t *elem)
561 {
562 	CHECK_BASIC(elem);
563 	CHECK_DIR(elem, SM_CAP_CVOLUME|SM_CAP_CSWITCH);
564 	return sm_selem_ops(elem)->is(elem, SM_CAPT, SM_OPS_IS_MONO, 0);
565 }
566 
567 /**
568  * \brief Get info about channels of capture stream of a mixer simple element
569  * \param elem Mixer simple element handle
570  * \param channel Mixer simple element channel identifier
571  * \return 0 if channel is not present, 1 if present
572  */
snd_mixer_selem_has_capture_channel(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel)573 int snd_mixer_selem_has_capture_channel(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel)
574 {
575 	CHECK_BASIC(elem);
576 	CHECK_DIR(elem, SM_CAP_CVOLUME|SM_CAP_CSWITCH);
577 	return sm_selem_ops(elem)->is(elem, SM_CAPT, SM_OPS_IS_CHANNEL, channel);
578 }
579 
580 /**
581  * \brief Get range for capture volume of a mixer simple element
582  * \param elem Mixer simple element handle
583  * \param min Pointer to returned minimum
584  * \param max Pointer to returned maximum
585  */
snd_mixer_selem_get_capture_volume_range(snd_mixer_elem_t * elem,long * min,long * max)586 int snd_mixer_selem_get_capture_volume_range(snd_mixer_elem_t *elem,
587 					     long *min, long *max)
588 {
589 	CHECK_BASIC(elem);
590 	CHECK_DIR(elem, SM_CAP_CVOLUME);
591 	return sm_selem_ops(elem)->get_range(elem, SM_CAPT, min, max);
592 }
593 
594 /**
595  * \brief Get range in dB for capture volume of a mixer simple element
596  * \param elem Mixer simple element handle
597  * \param min Pointer to returned minimum (dB * 100)
598  * \param max Pointer to returned maximum (dB * 100)
599  */
snd_mixer_selem_get_capture_dB_range(snd_mixer_elem_t * elem,long * min,long * max)600 int snd_mixer_selem_get_capture_dB_range(snd_mixer_elem_t *elem,
601 					 long *min, long *max)
602 {
603 	CHECK_BASIC(elem);
604 	CHECK_DIR(elem, SM_CAP_CVOLUME);
605 	return sm_selem_ops(elem)->get_dB_range(elem, SM_CAPT, min, max);
606 }
607 
608 /**
609  * \brief Set range for capture volume of a mixer simple element
610  * \param elem Mixer simple element handle
611  * \param min minimum volume value
612  * \param max maximum volume value
613  */
snd_mixer_selem_set_capture_volume_range(snd_mixer_elem_t * elem,long min,long max)614 int snd_mixer_selem_set_capture_volume_range(snd_mixer_elem_t *elem,
615 					     long min, long max)
616 {
617 	CHECK_BASIC(elem);
618 	assert(min < max);
619 	CHECK_DIR(elem, SM_CAP_CVOLUME);
620 	return sm_selem_ops(elem)->set_range(elem, SM_CAPT, min, max);
621 }
622 
623 /**
624  * \brief Return info about capture volume control of a mixer simple element
625  * \param elem Mixer simple element handle
626  * \return 0 if no control is present, 1 if it's present
627  */
snd_mixer_selem_has_capture_volume(snd_mixer_elem_t * elem)628 int snd_mixer_selem_has_capture_volume(snd_mixer_elem_t *elem)
629 {
630 	CHECK_BASIC(elem);
631 	return COND_CAPS(elem, SM_CAP_CVOLUME);
632 }
633 
634 /**
635  * \brief Return info about capture volume control of a mixer simple element
636  * \param elem Mixer simple element handle
637  * \return 0 if control is separated per channel, 1 if control acts on all channels together
638  */
snd_mixer_selem_has_capture_volume_joined(snd_mixer_elem_t * elem)639 int snd_mixer_selem_has_capture_volume_joined(snd_mixer_elem_t *elem)
640 {
641 	CHECK_BASIC(elem);
642 	return COND_CAPS(elem, SM_CAP_CVOLUME_JOIN);
643 }
644 
645 /**
646  * \brief Return info about capture switch control existence of a mixer simple element
647  * \param elem Mixer simple element handle
648  * \return 0 if no control is present, 1 if it's present
649  */
snd_mixer_selem_has_capture_switch(snd_mixer_elem_t * elem)650 int snd_mixer_selem_has_capture_switch(snd_mixer_elem_t *elem)
651 {
652 	CHECK_BASIC(elem);
653 	return COND_CAPS(elem, SM_CAP_CSWITCH);
654 }
655 
656 /**
657  * \brief Return info about capture switch control of a mixer simple element
658  * \param elem Mixer simple element handle
659  * \return 0 if control is separated per channel, 1 if control acts on all channels together
660  */
snd_mixer_selem_has_capture_switch_joined(snd_mixer_elem_t * elem)661 int snd_mixer_selem_has_capture_switch_joined(snd_mixer_elem_t *elem)
662 {
663 	CHECK_BASIC(elem);
664 	return COND_CAPS(elem, SM_CAP_CSWITCH_JOIN);
665 }
666 
667 /**
668  * \brief Return info about capture switch control of a mixer simple element
669  * \param elem Mixer simple element handle
670  * \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)
671  */
snd_mixer_selem_has_capture_switch_exclusive(snd_mixer_elem_t * elem)672 int snd_mixer_selem_has_capture_switch_exclusive(snd_mixer_elem_t *elem)
673 {
674 	CHECK_BASIC(elem);
675 	return COND_CAPS(elem, SM_CAP_CSWITCH_EXCL);
676 }
677 
678 /**
679  * \brief Return info about capture switch control of a mixer simple element
680  * \param elem Mixer simple element handle
681  * \return group for switch exclusivity (see #snd_mixer_selem_has_capture_switch_exclusive)
682  */
snd_mixer_selem_get_capture_group(snd_mixer_elem_t * elem)683 int snd_mixer_selem_get_capture_group(snd_mixer_elem_t *elem)
684 {
685 	sm_selem_t *s;
686 	CHECK_BASIC(elem);
687 	s = elem->private_data;
688 	if (! (s->caps & SM_CAP_CSWITCH_EXCL))
689 		return -EINVAL;
690 	return s->capture_group;
691 }
692 
693 /**
694  * \brief Return corresponding dB value to an integer capture volume for a mixer simple element
695  * \param elem Mixer simple element handle
696  * \param value value to be converted to dB range
697  * \param dBvalue pointer to returned dB value
698  * \return 0 on success otherwise a negative error code
699  */
snd_mixer_selem_ask_capture_vol_dB(snd_mixer_elem_t * elem,long value,long * dBvalue)700 int snd_mixer_selem_ask_capture_vol_dB(snd_mixer_elem_t *elem, long value, long *dBvalue)
701 {
702 	CHECK_BASIC(elem);
703 	CHECK_DIR(elem, SM_CAP_CVOLUME);
704 	return sm_selem_ops(elem)->ask_vol_dB(elem, SM_CAPT, value, dBvalue);
705 }
706 
707 /**
708  * \brief Return corresponding integer capture volume for given dB value for a mixer simple element
709  * \param elem Mixer simple element handle
710  * \param dBvalue dB value to be converted to integer range
711  * \param value pointer to returned integer value
712  * \param dir rounding mode - rounds up if dir > 0, round to nearest if dir == 0,
713  *            rounds down if dir < 0
714  * \return 0 on success otherwise a negative error code
715  */
snd_mixer_selem_ask_capture_dB_vol(snd_mixer_elem_t * elem,long dBvalue,int dir,long * value)716 int snd_mixer_selem_ask_capture_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value)
717 {
718 	CHECK_BASIC(elem);
719 	CHECK_DIR(elem, SM_CAP_CVOLUME);
720 	return sm_selem_ops(elem)->ask_dB_vol(elem, SM_CAPT, dBvalue, value, dir);
721 }
722 
723 /**
724  * \brief Return value of capture volume control of a mixer simple element
725  * \param elem Mixer simple element handle
726  * \param channel mixer simple element channel identifier
727  * \param value pointer to returned value
728  * \return 0 on success otherwise a negative error code
729  */
snd_mixer_selem_get_capture_volume(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,long * value)730 int snd_mixer_selem_get_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value)
731 {
732 	CHECK_BASIC(elem);
733 	CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel);
734 	return sm_selem_ops(elem)->get_volume(elem, SM_CAPT, channel, value);
735 }
736 
737 /**
738  * \brief Return value of capture volume in dB control of a mixer simple element
739  * \param elem Mixer simple element handle
740  * \param channel mixer simple element channel identifier
741  * \param value pointer to returned value (dB * 100)
742  * \return 0 on success otherwise a negative error code
743  */
snd_mixer_selem_get_capture_dB(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,long * value)744 int snd_mixer_selem_get_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long *value)
745 {
746 	CHECK_BASIC(elem);
747 	CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel);
748 	return sm_selem_ops(elem)->get_dB(elem, SM_CAPT, channel, value);
749 }
750 
751 /**
752  * \brief Return value of capture switch control of a mixer simple element
753  * \param elem Mixer simple element handle
754  * \param channel mixer simple element channel identifier
755  * \param value pointer to returned value
756  * \return 0 on success otherwise a negative error code
757  */
snd_mixer_selem_get_capture_switch(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,int * value)758 int snd_mixer_selem_get_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int *value)
759 {
760 	CHECK_BASIC(elem);
761 	CHECK_DIR_CHN(elem, SM_CAP_CSWITCH, SM_CAP_CSWITCH_JOIN, channel);
762 	return sm_selem_ops(elem)->get_switch(elem, SM_CAPT, channel, value);
763 }
764 
765 /**
766  * \brief Set value of capture volume control of a mixer simple element
767  * \param elem Mixer simple element handle
768  * \param channel mixer simple element channel identifier
769  * \param value control value
770  * \return 0 on success otherwise a negative error code
771  */
snd_mixer_selem_set_capture_volume(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,long value)772 int snd_mixer_selem_set_capture_volume(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value)
773 {
774 	CHECK_BASIC(elem);
775 	CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel);
776 	return sm_selem_ops(elem)->set_volume(elem, SM_CAPT, channel, value);
777 }
778 
779 /**
780  * \brief Set value in dB of capture volume control of a mixer simple element
781  * \param elem Mixer simple element handle
782  * \param channel mixer simple element channel identifier
783  * \param value control value in dB * 100
784  * \param dir rounding mode - rounds up if dir > 0, round to nearest if dir == 0,
785  *            rounds down if dir < 0
786  * \return 0 on success otherwise a negative error code
787  */
snd_mixer_selem_set_capture_dB(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,long value,int dir)788 int snd_mixer_selem_set_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir)
789 {
790 	CHECK_BASIC(elem);
791 	CHECK_DIR_CHN(elem, SM_CAP_CVOLUME, SM_CAP_CVOLUME_JOIN, channel);
792 	return sm_selem_ops(elem)->set_dB(elem, SM_CAPT, channel, value, dir);
793 }
794 
795 /**
796  * \brief Set value of capture volume control for all channels of a mixer simple element
797  * \param elem Mixer simple element handle
798  * \param value control value
799  * \return 0 on success otherwise a negative error code
800  */
snd_mixer_selem_set_capture_volume_all(snd_mixer_elem_t * elem,long value)801 int snd_mixer_selem_set_capture_volume_all(snd_mixer_elem_t *elem, long value)
802 {
803 	snd_mixer_selem_channel_id_t chn;
804 	int err;
805 
806 	for (chn = 0; chn < 32; chn++) {
807 		if (!snd_mixer_selem_has_capture_channel(elem, chn))
808 			continue;
809 		err = snd_mixer_selem_set_capture_volume(elem, chn, value);
810 		if (err < 0)
811 			return err;
812 		if (chn == 0 && snd_mixer_selem_has_capture_volume_joined(elem))
813 			return 0;
814 	}
815 	return 0;
816 }
817 
818 /**
819  * \brief Set value in dB of capture volume control for all channels of a mixer simple element
820  * \param elem Mixer simple element handle
821  * \param value control value in dB * 100
822  * \param dir rounding mode - rounds up if dir > 0, round to nearest if dir == 0,
823  *            rounds down if dir < 0
824  * \return 0 on success otherwise a negative error code
825  */
snd_mixer_selem_set_capture_dB_all(snd_mixer_elem_t * elem,long value,int dir)826 int snd_mixer_selem_set_capture_dB_all(snd_mixer_elem_t *elem, long value, int dir)
827 {
828 	snd_mixer_selem_channel_id_t chn;
829 	int err;
830 
831 	for (chn = 0; chn < 32; chn++) {
832 		if (!snd_mixer_selem_has_capture_channel(elem, chn))
833 			continue;
834 		err = snd_mixer_selem_set_capture_dB(elem, chn, value, dir);
835 		if (err < 0)
836 			return err;
837 		if (chn == 0 && snd_mixer_selem_has_capture_volume_joined(elem))
838 			return 0;
839 	}
840 	return 0;
841 }
842 
843 /**
844  * \brief Set value of capture switch control of a mixer simple element
845  * \param elem Mixer simple element handle
846  * \param channel mixer simple element channel identifier
847  * \param value control value
848  * \return 0 on success otherwise a negative error code
849  */
snd_mixer_selem_set_capture_switch(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,int value)850 int snd_mixer_selem_set_capture_switch(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, int value)
851 {
852 	CHECK_BASIC(elem);
853 	CHECK_DIR_CHN(elem, SM_CAP_CSWITCH, SM_CAP_CSWITCH_JOIN, channel);
854 	return sm_selem_ops(elem)->set_switch(elem, SM_CAPT, channel, value);
855 }
856 
857 /**
858  * \brief Set value of capture switch control for all channels of a mixer simple element
859  * \param elem Mixer simple element handle
860  * \param value control value
861  * \return 0 on success otherwise a negative error code
862  */
snd_mixer_selem_set_capture_switch_all(snd_mixer_elem_t * elem,int value)863 int snd_mixer_selem_set_capture_switch_all(snd_mixer_elem_t *elem, int value)
864 {
865 	snd_mixer_selem_channel_id_t chn;
866 	int err;
867 
868 	for (chn = 0; chn < 32; chn++) {
869 		if (!snd_mixer_selem_has_capture_channel(elem, chn))
870 			continue;
871 		err = snd_mixer_selem_set_capture_switch(elem, chn, value);
872 		if (err < 0)
873 			return err;
874 		if (chn == 0 && snd_mixer_selem_has_capture_switch_joined(elem))
875 			return 0;
876 	}
877 	return 0;
878 }
879 
880 /**
881  * \brief Return true if mixer simple element is an enumerated control
882  * \param elem Mixer simple element handle
883  * \return 0 normal volume/switch control, 1 enumerated control
884  */
snd_mixer_selem_is_enumerated(snd_mixer_elem_t * elem)885 int snd_mixer_selem_is_enumerated(snd_mixer_elem_t *elem)
886 {
887 	CHECK_BASIC(elem);
888 	return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMERATED, 0);
889 }
890 
891 /**
892  * \brief Return true if mixer simple enumerated element belongs to the playback direction
893  * \param elem Mixer simple element handle
894  * \return 0 no playback direction, 1 playback direction
895  */
snd_mixer_selem_is_enum_playback(snd_mixer_elem_t * elem)896 int snd_mixer_selem_is_enum_playback(snd_mixer_elem_t *elem)
897 {
898 	CHECK_BASIC(elem);
899 	return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMERATED, 1);
900 }
901 
902 /**
903  * \brief Return true if mixer simple enumerated element belongs to the capture direction
904  * \param elem Mixer simple element handle
905  * \return 0 no capture direction, 1 capture direction
906  */
snd_mixer_selem_is_enum_capture(snd_mixer_elem_t * elem)907 int snd_mixer_selem_is_enum_capture(snd_mixer_elem_t *elem)
908 {
909 	CHECK_BASIC(elem);
910 	return sm_selem_ops(elem)->is(elem, SM_CAPT, SM_OPS_IS_ENUMERATED, 1);
911 }
912 
913 /**
914  * \brief Return the number of enumerated items of the given mixer simple element
915  * \param elem Mixer simple element handle
916  * \return the number of enumerated items, otherwise a negative error code
917  */
snd_mixer_selem_get_enum_items(snd_mixer_elem_t * elem)918 int snd_mixer_selem_get_enum_items(snd_mixer_elem_t *elem)
919 {
920 	CHECK_BASIC(elem);
921 	CHECK_ENUM(elem);
922 	return sm_selem_ops(elem)->is(elem, SM_PLAY, SM_OPS_IS_ENUMCNT, 0);
923 }
924 
925 /**
926  * \brief get the enumerated item string for the given mixer simple element
927  * \param elem Mixer simple element handle
928  * \param item the index of the enumerated item to query
929  * \param maxlen the maximal length to be stored
930  * \param buf the buffer to store the name string
931  * \return 0 if successful, otherwise a negative error code
932  */
snd_mixer_selem_get_enum_item_name(snd_mixer_elem_t * elem,unsigned int item,size_t maxlen,char * buf)933 int snd_mixer_selem_get_enum_item_name(snd_mixer_elem_t *elem,
934 				       unsigned int item,
935 				       size_t maxlen, char *buf)
936 {
937 	CHECK_BASIC(elem);
938 	CHECK_ENUM(elem);
939 	return sm_selem_ops(elem)->enum_item_name(elem, item, maxlen, buf);
940 }
941 
942 /**
943  * \brief get the current selected enumerated item for the given mixer simple element
944  * \param elem Mixer simple element handle
945  * \param channel mixer simple element channel identifier
946  * \param itemp the pointer to store the index of the enumerated item
947  * \return 0 if successful, otherwise a negative error code
948  */
snd_mixer_selem_get_enum_item(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,unsigned int * itemp)949 int snd_mixer_selem_get_enum_item(snd_mixer_elem_t *elem,
950 				  snd_mixer_selem_channel_id_t channel,
951 				  unsigned int *itemp)
952 {
953 	CHECK_BASIC(elem);
954 	CHECK_ENUM(elem);
955 	return sm_selem_ops(elem)->get_enum_item(elem, channel, itemp);
956 }
957 
958 /**
959  * \brief set the current selected enumerated item for the given mixer simple element
960  * \param elem Mixer simple element handle
961  * \param channel mixer simple element channel identifier
962  * \param item the enumerated item index
963  * \return 0 if successful, otherwise a negative error code
964  */
snd_mixer_selem_set_enum_item(snd_mixer_elem_t * elem,snd_mixer_selem_channel_id_t channel,unsigned int item)965 int snd_mixer_selem_set_enum_item(snd_mixer_elem_t *elem,
966 				  snd_mixer_selem_channel_id_t channel,
967 				  unsigned int item)
968 {
969 	CHECK_BASIC(elem);
970 	CHECK_ENUM(elem);
971 	return sm_selem_ops(elem)->set_enum_item(elem, channel, item);
972 }
973 
974 /**
975  * \brief get size of #snd_mixer_selem_id_t
976  * \return size in bytes
977  */
snd_mixer_selem_id_sizeof()978 size_t snd_mixer_selem_id_sizeof()
979 {
980 	return sizeof(snd_mixer_selem_id_t);
981 }
982 
983 /**
984  * \brief allocate an invalid #snd_mixer_selem_id_t using standard malloc
985  * \param ptr returned pointer
986  * \return 0 on success otherwise negative error code
987  */
snd_mixer_selem_id_malloc(snd_mixer_selem_id_t ** ptr)988 int snd_mixer_selem_id_malloc(snd_mixer_selem_id_t **ptr)
989 {
990 	assert(ptr);
991 	*ptr = calloc(1, sizeof(snd_mixer_selem_id_t));
992 	if (!*ptr)
993 		return -ENOMEM;
994 	return 0;
995 }
996 
997 /**
998  * \brief frees a previously allocated #snd_mixer_selem_id_t
999  * \param obj pointer to object to free
1000  */
snd_mixer_selem_id_free(snd_mixer_selem_id_t * obj)1001 void snd_mixer_selem_id_free(snd_mixer_selem_id_t *obj)
1002 {
1003 	free(obj);
1004 }
1005 
1006 /**
1007  * \brief copy one #snd_mixer_selem_id_t to another
1008  * \param dst pointer to destination
1009  * \param src pointer to source
1010  */
snd_mixer_selem_id_copy(snd_mixer_selem_id_t * dst,const snd_mixer_selem_id_t * src)1011 void snd_mixer_selem_id_copy(snd_mixer_selem_id_t *dst, const snd_mixer_selem_id_t *src)
1012 {
1013 	assert(dst && src);
1014 	*dst = *src;
1015 }
1016 
1017 /**
1018  * \brief Get name part of a mixer simple element identifier
1019  * \param obj Mixer simple element identifier
1020  * \return name part
1021  */
snd_mixer_selem_id_get_name(const snd_mixer_selem_id_t * obj)1022 const char *snd_mixer_selem_id_get_name(const snd_mixer_selem_id_t *obj)
1023 {
1024 	assert(obj);
1025 	return obj->name;
1026 }
1027 
1028 /**
1029  * \brief Get index part of a mixer simple element identifier
1030  * \param obj Mixer simple element identifier
1031  * \return index part
1032  */
snd_mixer_selem_id_get_index(const snd_mixer_selem_id_t * obj)1033 unsigned int snd_mixer_selem_id_get_index(const snd_mixer_selem_id_t *obj)
1034 {
1035 	assert(obj);
1036 	return obj->index;
1037 }
1038 
1039 /**
1040  * \brief Set name part of a mixer simple element identifier
1041  * \param obj Mixer simple element identifier
1042  * \param val name part
1043  */
snd_mixer_selem_id_set_name(snd_mixer_selem_id_t * obj,const char * val)1044 void snd_mixer_selem_id_set_name(snd_mixer_selem_id_t *obj, const char *val)
1045 {
1046 	assert(obj);
1047 	strncpy(obj->name, val, sizeof(obj->name));
1048 	obj->name[sizeof(obj->name)-1] = '\0';
1049 }
1050 
1051 /**
1052  * \brief Set index part of a mixer simple element identifier
1053  * \param obj Mixer simple element identifier
1054  * \param val index part
1055  */
snd_mixer_selem_id_set_index(snd_mixer_selem_id_t * obj,unsigned int val)1056 void snd_mixer_selem_id_set_index(snd_mixer_selem_id_t *obj, unsigned int val)
1057 {
1058 	assert(obj);
1059 	obj->index = val;
1060 }
1061 
1062 /**
1063  * \brief Parse ASCII simple mixer element identifier
1064  * \param dst Parsed simple mixer element identifier
1065  * \param str Mixer simple element ASCII representation
1066  */
snd_mixer_selem_id_parse(snd_mixer_selem_id_t * dst,const char * str)1067 int snd_mixer_selem_id_parse(snd_mixer_selem_id_t *dst, const char *str)
1068 {
1069 	int c, size;
1070 	char buf[128];
1071 	char *ptr = buf;
1072 
1073 	memset(dst, 0, sizeof(*dst));
1074 	while (*str == ' ' || *str == '\t')
1075 		str++;
1076 	if (!(*str))
1077 		return -EINVAL;
1078 	size = 1;	/* for '\0' */
1079 	if (*str != '"' && *str != '\'') {
1080 		while (*str && *str != ',') {
1081 			if (size < (int)sizeof(buf)) {
1082 				*ptr++ = *str;
1083 				size++;
1084 			}
1085 			str++;
1086 		}
1087 	} else {
1088 		c = *str++;
1089 		while (*str && *str != c) {
1090 			if (size < (int)sizeof(buf)) {
1091 				*ptr++ = *str;
1092 				size++;
1093 			}
1094 			str++;
1095 		}
1096 		if (*str == c)
1097 			str++;
1098 	}
1099 	if (*str == '\0') {
1100 		*ptr = 0;
1101 		goto _set;
1102 	}
1103 	if (*str != ',')
1104 		return -EINVAL;
1105 	*ptr = 0;	/* terminate the string */
1106 	str++;
1107 	if (str[0] < '0' || str[1] > '9')
1108 		return -EINVAL;
1109 	dst->index = atoi(str);
1110        _set:
1111 	snd_strlcpy(dst->name, buf, sizeof(dst->name));
1112 	return 0;
1113 }
1114