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