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