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