2 * \file control/setup.c
3 * \brief Routines to setup control primitives from configuration
4 * \author Abramo Bagnara <abramo@alsa-project.org>
5 * \author Jaroslav Kysela <perex@perex.cz>
8 * Routines to setup control primitives from configuration
11 * Control Interface - routines for setup from configuration
12 * Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org>
13 * Jaroslav Kysela <perex@perex.cz>
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
43 unsigned int preserve: 1;
44 snd_ctl_elem_id_t *id;
45 snd_ctl_elem_info_t *info;
46 snd_ctl_elem_value_t *val;
47 snd_ctl_elem_value_t *mask;
48 snd_ctl_elem_value_t *old;
49 struct list_head list;
55 struct list_head elems;
57 #endif /* DOC_HIDDEN */
59 static int free_elems(snd_sctl_t *h)
62 while (!list_empty(&h->elems)) {
63 snd_sctl_elem_t *elem = list_entry(h->elems.next, snd_sctl_elem_t, list);
64 snd_ctl_elem_id_free(elem->id);
65 snd_ctl_elem_info_free(elem->info);
66 snd_ctl_elem_value_free(elem->val);
67 snd_ctl_elem_value_free(elem->mask);
68 snd_ctl_elem_value_free(elem->old);
69 list_del(&elem->list);
72 if ((h->mode & SND_SCTL_NOFREE) == 0)
73 err = snd_ctl_close(h->ctl);
79 * \brief Install given values to control elements
80 * \param h Setup control handle
81 * \result zero if success, otherwise a negative error code
83 int snd_sctl_install(snd_sctl_t *h)
85 struct list_head *pos;
89 list_for_each(pos, &h->elems) {
90 snd_sctl_elem_t *elem = list_entry(pos, snd_sctl_elem_t, list);
92 snd_ctl_elem_type_t type;
94 err = snd_ctl_elem_lock(h->ctl, elem->id);
96 SNDERR("Cannot lock ctl elem");
100 err = snd_ctl_elem_read(h->ctl, elem->old);
102 SNDERR("Cannot read ctl elem");
105 count = snd_ctl_elem_info_get_count(elem->info);
106 type = snd_ctl_elem_info_get_type(elem->info);
108 case SND_CTL_ELEM_TYPE_BOOLEAN:
109 for (k = 0; k < count; ++k) {
111 old = snd_ctl_elem_value_get_boolean(elem->old, k);
112 mask = snd_ctl_elem_value_get_boolean(elem->mask, k);
115 val = snd_ctl_elem_value_get_boolean(elem->val, k);
117 snd_ctl_elem_value_set_boolean(elem->val, k, val);
121 case SND_CTL_ELEM_TYPE_INTEGER:
122 for (k = 0; k < count; ++k) {
124 old = snd_ctl_elem_value_get_integer(elem->old, k);
125 mask = snd_ctl_elem_value_get_integer(elem->mask, k);
128 val = snd_ctl_elem_value_get_integer(elem->val, k);
130 snd_ctl_elem_value_set_integer(elem->val, k, val);
134 case SND_CTL_ELEM_TYPE_ENUMERATED:
135 for (k = 0; k < count; ++k) {
136 unsigned int old, val, mask;
137 old = snd_ctl_elem_value_get_enumerated(elem->old, k);
138 mask = snd_ctl_elem_value_get_enumerated(elem->mask, k);
141 val = snd_ctl_elem_value_get_enumerated(elem->val, k);
143 snd_ctl_elem_value_set_enumerated(elem->val, k, val);
147 case SND_CTL_ELEM_TYPE_IEC958:
148 count = sizeof(snd_aes_iec958_t);
150 case SND_CTL_ELEM_TYPE_BYTES:
151 for (k = 0; k < count; ++k) {
152 unsigned char old, val, mask;
153 old = snd_ctl_elem_value_get_byte(elem->old, k);
154 mask = snd_ctl_elem_value_get_byte(elem->mask, k);
157 val = snd_ctl_elem_value_get_byte(elem->val, k);
159 snd_ctl_elem_value_set_byte(elem->val, k, val);
167 err = snd_ctl_elem_write(h->ctl, elem->val);
169 SNDERR("Cannot write ctl elem");
177 * \brief Remove (restore) previous values from control elements
178 * \param h Setup control handle
179 * \result zero if success, otherwise a negative error code
181 int snd_sctl_remove(snd_sctl_t *h)
183 struct list_head *pos;
186 list_for_each(pos, &h->elems) {
187 snd_sctl_elem_t *elem = list_entry(pos, snd_sctl_elem_t, list);
189 err = snd_ctl_elem_unlock(h->ctl, elem->id);
191 SNDERR("Cannot unlock ctl elem");
195 if (elem->preserve) {
196 err = snd_ctl_elem_write(h->ctl, elem->old);
198 SNDERR("Cannot restore ctl elem");
206 static int snd_config_get_ctl_elem_enumerated(snd_config_t *n, snd_ctl_t *ctl,
207 snd_ctl_elem_info_t *info)
211 unsigned int idx, items;
212 switch (snd_config_get_type(n)) {
213 case SND_CONFIG_TYPE_INTEGER:
214 snd_config_get_integer(n, &val);
216 case SND_CONFIG_TYPE_STRING:
217 snd_config_get_string(n, &str);
222 items = snd_ctl_elem_info_get_items(info);
223 for (idx = 0; idx < items; idx++) {
225 snd_ctl_elem_info_set_item(info, idx);
226 err = snd_ctl_elem_info(ctl, info);
228 SNDERR("Cannot obtain info for CTL elem");
231 if (strcmp(str, snd_ctl_elem_info_get_item_name(info)) == 0)
237 static int snd_config_get_ctl_elem_value(snd_config_t *conf,
239 snd_ctl_elem_value_t *val,
240 snd_ctl_elem_value_t *mask,
241 snd_ctl_elem_info_t *info)
244 snd_config_iterator_t i, next;
245 snd_ctl_elem_id_t *id;
246 snd_ctl_elem_type_t type;
250 snd_ctl_elem_id_alloca(&id);
251 snd_ctl_elem_value_get_id(val, id);
252 count = snd_ctl_elem_info_get_count(info);
253 type = snd_ctl_elem_info_get_type(info);
256 case SND_CTL_ELEM_TYPE_BOOLEAN:
257 v = snd_config_get_bool(conf);
259 snd_ctl_elem_value_set_boolean(val, 0, v);
261 snd_ctl_elem_value_set_boolean(mask, 0, 1);
265 case SND_CTL_ELEM_TYPE_INTEGER:
266 err = snd_config_get_integer(conf, &v);
268 snd_ctl_elem_value_set_integer(val, 0, v);
270 snd_ctl_elem_value_set_integer(mask, 0, ~0L);
274 case SND_CTL_ELEM_TYPE_ENUMERATED:
275 v = snd_config_get_ctl_elem_enumerated(conf, ctl, info);
277 snd_ctl_elem_value_set_enumerated(val, 0, v);
279 snd_ctl_elem_value_set_enumerated(mask, 0, ~0);
283 case SND_CTL_ELEM_TYPE_BYTES:
284 case SND_CTL_ELEM_TYPE_IEC958:
287 SNDERR("Unknown control type: %d", type);
292 case SND_CTL_ELEM_TYPE_IEC958:
293 count = sizeof(snd_aes_iec958_t);
295 case SND_CTL_ELEM_TYPE_BYTES:
298 err = snd_config_get_string(conf, &buf);
301 unsigned int len = strlen(buf);
302 unsigned int idx = 0;
303 if (len % 2 != 0 || len > count * 2) {
305 SNDERR("bad value content\n");
310 if (c >= '0' && c <= '9')
312 else if (c >= 'a' && c <= 'f')
314 else if (c >= 'A' && c <= 'F')
320 snd_ctl_elem_value_set_byte(val, idx / 2, c1 << 4 | c);
322 snd_ctl_elem_value_set_byte(mask, idx / 2, 0xff);
333 if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND) {
334 SNDERR("bad value type");
338 snd_config_for_each(i, next, conf) {
339 snd_config_t *n = snd_config_iterator_entry(i);
341 if (snd_config_get_id(n, &id) < 0)
343 err = safe_strtol(id, &idx);
344 if (err < 0 || idx < 0 || (unsigned int) idx >= count) {
345 SNDERR("bad value index");
349 case SND_CTL_ELEM_TYPE_BOOLEAN:
350 v = snd_config_get_bool(n);
353 snd_ctl_elem_value_set_boolean(val, idx, v);
355 snd_ctl_elem_value_set_boolean(mask, idx, 1);
357 case SND_CTL_ELEM_TYPE_INTEGER:
358 err = snd_config_get_integer(n, &v);
361 snd_ctl_elem_value_set_integer(val, idx, v);
363 snd_ctl_elem_value_set_integer(mask, idx, ~0L);
365 case SND_CTL_ELEM_TYPE_ENUMERATED:
366 v = snd_config_get_ctl_elem_enumerated(n, ctl, info);
369 snd_ctl_elem_value_set_enumerated(val, idx, v);
371 snd_ctl_elem_value_set_enumerated(mask, idx, ~0);
373 case SND_CTL_ELEM_TYPE_BYTES:
374 case SND_CTL_ELEM_TYPE_IEC958:
375 err = snd_config_get_integer(n, &v);
376 if (err < 0 || v < 0 || v > 255)
378 snd_ctl_elem_value_set_byte(val, idx, v);
380 snd_ctl_elem_value_set_byte(mask, idx, 0xff);
389 static int add_elem(snd_sctl_t *h, snd_config_t *_conf, snd_config_t *private_data)
392 snd_config_iterator_t i, next;
394 int iface = SND_CTL_ELEM_IFACE_MIXER;
395 const char *name = NULL;
402 snd_config_t *value = NULL, *mask = NULL;
403 snd_sctl_elem_t *elem = NULL;
405 err = snd_config_expand(_conf, _conf, NULL, private_data, &conf);
408 snd_config_for_each(i, next, conf) {
409 snd_config_t *n = snd_config_iterator_entry(i);
411 if (snd_config_get_id(n, &id) < 0)
413 if (strcmp(id, "comment") == 0)
415 if (strcmp(id, "iface") == 0 || strcmp(id, "interface") == 0) {
417 if ((err = snd_config_get_string(n, &ptr)) < 0) {
418 SNDERR("field %s is not a string", id);
421 if ((err = snd_config_get_ctl_iface_ascii(ptr)) < 0) {
422 SNDERR("Invalid value for '%s'", id);
428 if (strcmp(id, "name") == 0) {
429 if ((err = snd_config_get_string(n, &name)) < 0) {
430 SNDERR("field %s is not a string", id);
435 if (strcmp(id, "index") == 0) {
436 if ((err = snd_config_get_integer(n, &index)) < 0) {
437 SNDERR("field %s is not an integer", id);
442 if (strcmp(id, "device") == 0) {
443 if ((err = snd_config_get_integer(n, &device)) < 0) {
444 SNDERR("field %s is not an integer", id);
449 if (strcmp(id, "subdevice") == 0) {
450 if ((err = snd_config_get_integer(n, &subdevice)) < 0) {
451 SNDERR("field %s is not an integer", id);
456 if (strcmp(id, "lock") == 0) {
457 if ((err = snd_config_get_ascii(n, &tmp)) < 0) {
458 SNDERR("field %s has an invalid type", id);
461 err = snd_config_get_bool_ascii(tmp);
463 SNDERR("field %s is not a boolean", id);
471 if (strcmp(id, "preserve") == 0) {
472 if ((err = snd_config_get_ascii(n, &tmp)) < 0) {
473 SNDERR("field %s has an invalid type", id);
476 err = snd_config_get_bool_ascii(tmp);
478 SNDERR("field %s is not a boolean", id);
486 if (strcmp(id, "value") == 0) {
490 if (strcmp(id, "mask") == 0) {
494 if (strcmp(id, "optional") == 0) {
495 if ((err = snd_config_get_ascii(n, &tmp)) < 0) {
496 SNDERR("field %s has an invalid type", id);
499 err = snd_config_get_bool_ascii(tmp);
501 SNDERR("field %s is not a boolean", id);
509 SNDERR("Unknown field %s", id);
513 SNDERR("Missing control name");
518 SNDERR("Missing control value");
526 elem = calloc(1, sizeof(*elem));
529 err = snd_ctl_elem_id_malloc(&elem->id);
532 err = snd_ctl_elem_info_malloc(&elem->info);
535 err = snd_ctl_elem_value_malloc(&elem->val);
538 err = snd_ctl_elem_value_malloc(&elem->mask);
541 err = snd_ctl_elem_value_malloc(&elem->old);
545 elem->preserve = preserve;
546 snd_ctl_elem_id_set_interface(elem->id, iface);
547 snd_ctl_elem_id_set_name(elem->id, name);
548 snd_ctl_elem_id_set_index(elem->id, index);
549 snd_ctl_elem_id_set_device(elem->id, device);
550 snd_ctl_elem_id_set_subdevice(elem->id, subdevice);
551 snd_ctl_elem_info_set_id(elem->info, elem->id);
552 err = snd_ctl_elem_info(h->ctl, elem->info);
555 SNDERR("Cannot obtain info for CTL elem (%s,'%s',%li,%li,%li): %s", snd_ctl_elem_iface_name(iface), name, index, device, subdevice, snd_strerror(err));
558 snd_ctl_elem_value_set_id(elem->val, elem->id);
559 snd_ctl_elem_value_set_id(elem->old, elem->id);
561 err = snd_config_get_ctl_elem_value(value, h->ctl, elem->val, NULL, elem->info);
564 err = snd_config_get_ctl_elem_value(mask, h->ctl, elem->mask, NULL, elem->info);
568 err = snd_config_get_ctl_elem_value(value, h->ctl, elem->val, elem->mask, elem->info);
573 err = snd_config_get_ctl_elem_value(value, h->ctl, elem->val, elem->mask, elem->info);
576 list_add_tail(&elem->list, &h->elems);
579 if (err < 0 && elem) {
581 snd_ctl_elem_id_free(elem->id);
583 snd_ctl_elem_info_free(elem->info);
585 snd_ctl_elem_value_free(elem->val);
587 snd_ctl_elem_value_free(elem->mask);
589 snd_ctl_elem_value_free(elem->old);
591 if (err != -ENOMEM && optional)
592 err = 0; /* ignore the error */
595 snd_config_delete(conf);
600 * \brief Build setup control handle
601 * \param sctl Result - setup control handle
602 * \param handle Master control handle
603 * \param conf Setup configuration
604 * \param private_data Private data for runtime evaluation
605 * \param mode Build mode - SND_SCTL_xxxx
606 * \result zero if success, otherwise a negative error code
608 int snd_sctl_build(snd_sctl_t **sctl, snd_ctl_t *handle, snd_config_t *conf, snd_config_t *private_data, int mode)
611 snd_config_iterator_t i, next;
618 if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND)
620 h = calloc(1, sizeof(*h));
622 if (mode & SND_SCTL_NOFREE)
624 snd_ctl_close(handle);
629 INIT_LIST_HEAD(&h->elems);
630 snd_config_for_each(i, next, conf) {
631 snd_config_t *n = snd_config_iterator_entry(i);
632 err = add_elem(h, n, private_data);
643 * \brief Free setup control handle
644 * \param sctl Setup control handle
645 * \result zero if success, otherwise a negative error code
647 int snd_sctl_free(snd_sctl_t *sctl)
650 return free_elems(sctl);