1 /*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) any later version.
6 *
7 * This library is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15 *
16 * Support for the verb/device/modifier core logic and API,
17 * command line tool and file parser was kindly sponsored by
18 * Texas Instruments Inc.
19 * Support for multiple active modifiers and devices,
20 * transition sequences, multiple client access and user defined use
21 * cases was kindly sponsored by Wolfson Microelectronics PLC.
22 *
23 * Copyright (C) 2008-2010 SlimLogic Ltd
24 * Copyright (C) 2010 Wolfson Microelectronics PLC
25 * Copyright (C) 2010 Texas Instruments Inc.
26 * Copyright (C) 2010 Red Hat Inc.
27 * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
28 * Stefan Schmidt <stefan@slimlogic.co.uk>
29 * Justin Xu <justinx@slimlogic.co.uk>
30 * Jaroslav Kysela <perex@perex.cz>
31 */
32
33 #include "ucm_local.h"
34 #include "../control/control_local.h"
35 #include <stdbool.h>
36 #include <ctype.h>
37 #include <stdarg.h>
38 #include <pthread.h>
39 #include <sys/stat.h>
40 #include <sys/wait.h>
41 #include <limits.h>
42
43 /*
44 * misc
45 */
46
47 static int get_value(snd_use_case_mgr_t *uc_mgr,
48 const char *identifier,
49 char **value,
50 const char *mod_dev_name,
51 const char *verb_name,
52 int exact);
53 static int get_value1(snd_use_case_mgr_t *uc_mgr, char **value,
54 struct list_head *value_list, const char *identifier);
55 static int get_value3(snd_use_case_mgr_t *uc_mgr,
56 char **value,
57 const char *identifier,
58 struct list_head *value_list1,
59 struct list_head *value_list2,
60 struct list_head *value_list3);
61
62 static int execute_component_seq(snd_use_case_mgr_t *uc_mgr,
63 struct component_sequence *cmpt_seq,
64 struct list_head *value_list1,
65 struct list_head *value_list2,
66 struct list_head *value_list3,
67 char *cdev);
68
check_identifier(const char * identifier,const char * prefix)69 static int check_identifier(const char *identifier, const char *prefix)
70 {
71 int len;
72
73 len = strlen(prefix);
74 if (strncmp(identifier, prefix, len) != 0)
75 return 0;
76
77 if (identifier[len] == 0 || identifier[len] == '/')
78 return 1;
79
80 return 0;
81 }
82
list_count(struct list_head * list)83 static int list_count(struct list_head *list)
84 {
85 struct list_head *pos;
86 int count = 0;
87
88 list_for_each(pos, list) {
89 count += 1;
90 }
91 return count;
92 }
93
alloc_str_list(struct list_head * list,int mult,char ** result[])94 static int alloc_str_list(struct list_head *list, int mult, char **result[])
95 {
96 char **res;
97 int cnt;
98
99 cnt = list_count(list) * mult;
100 if (cnt == 0) {
101 *result = NULL;
102 return cnt;
103 }
104 res = calloc(mult, cnt * sizeof(char *));
105 if (res == NULL)
106 return -ENOMEM;
107 *result = res;
108 return cnt;
109 }
110
111 /**
112 * \brief Create an identifier
113 * \param fmt Format (sprintf like)
114 * \param ... Optional arguments for sprintf like format
115 * \return Allocated string identifier or NULL on error
116 */
snd_use_case_identifier(const char * fmt,...)117 char *snd_use_case_identifier(const char *fmt, ...)
118 {
119 char *str, *res;
120 int size = strlen(fmt) + 512;
121 va_list args;
122
123 str = malloc(size);
124 if (str == NULL)
125 return NULL;
126 va_start(args, fmt);
127 vsnprintf(str, size, fmt, args);
128 va_end(args);
129 str[size-1] = '\0';
130 res = realloc(str, strlen(str) + 1);
131 if (res)
132 return res;
133 return str;
134 }
135
136 /**
137 * \brief Free a string list
138 * \param list The string list to free
139 * \param items Count of strings
140 * \return Zero if success, otherwise a negative error code
141 */
snd_use_case_free_list(const char * list[],int items)142 int snd_use_case_free_list(const char *list[], int items)
143 {
144 int i;
145 if (list == NULL)
146 return 0;
147 for (i = 0; i < items; i++)
148 free((void *)list[i]);
149 free(list);
150 return 0;
151 }
152
read_tlv_file(unsigned int ** res,const char * filepath)153 static int read_tlv_file(unsigned int **res,
154 const char *filepath)
155 {
156 int err = 0;
157 int fd;
158 struct stat st;
159 size_t sz;
160 ssize_t sz_read;
161 struct snd_ctl_tlv *tlv;
162
163 fd = open(filepath, O_RDONLY);
164 if (fd < 0) {
165 err = -errno;
166 return err;
167 }
168 if (fstat(fd, &st) == -1) {
169 err = -errno;
170 goto __fail;
171 }
172 sz = st.st_size;
173 if (sz > 16 * 1024 * 1024 || sz < 8 || sz % 4) {
174 uc_error("File size should be less than 16 MB "
175 "and multiple of 4");
176 err = -EINVAL;
177 goto __fail;
178 }
179 *res = malloc(sz);
180 if (res == NULL) {
181 err = -ENOMEM;
182 goto __fail;
183 }
184 sz_read = read(fd, *res, sz);
185 if (sz_read < 0 || (size_t)sz_read != sz) {
186 err = -EIO;
187 free(*res);
188 *res = NULL;
189 }
190 /* Check if the tlv file specifies valid size. */
191 tlv = (struct snd_ctl_tlv *)(*res);
192 if (tlv->length + 2 * sizeof(unsigned int) != sz) {
193 uc_error("Invalid tlv size: %d", tlv->length);
194 err = -EINVAL;
195 free(*res);
196 *res = NULL;
197 }
198
199 __fail:
200 close(fd);
201 return err;
202 }
203
binary_file_parse(snd_ctl_elem_value_t * dst,snd_ctl_elem_info_t * info,const char * filepath)204 static int binary_file_parse(snd_ctl_elem_value_t *dst,
205 snd_ctl_elem_info_t *info,
206 const char *filepath)
207 {
208 int err = 0;
209 int fd;
210 struct stat st;
211 size_t sz;
212 ssize_t sz_read;
213 char *res;
214 snd_ctl_elem_type_t type;
215 unsigned int idx, count;
216
217 type = snd_ctl_elem_info_get_type(info);
218 if (type != SND_CTL_ELEM_TYPE_BYTES) {
219 uc_error("only support byte type!");
220 err = -EINVAL;
221 return err;
222 }
223 fd = open(filepath, O_RDONLY);
224 if (fd < 0) {
225 err = -errno;
226 return err;
227 }
228 if (stat(filepath, &st) == -1) {
229 err = -errno;
230 goto __fail;
231 }
232 sz = st.st_size;
233 count = snd_ctl_elem_info_get_count(info);
234 if (sz != count || sz > sizeof(dst->value.bytes)) {
235 uc_error("invalid parameter size %d!", sz);
236 err = -EINVAL;
237 goto __fail;
238 }
239 res = malloc(sz);
240 if (res == NULL) {
241 err = -ENOMEM;
242 goto __fail;
243 }
244 sz_read = read(fd, res, sz);
245 if (sz_read < 0 || (size_t)sz_read != sz) {
246 err = -errno;
247 goto __fail_read;
248 }
249 for (idx = 0; idx < sz; idx++)
250 snd_ctl_elem_value_set_byte(dst, idx, *(res + idx));
251 __fail_read:
252 free(res);
253 __fail:
254 close(fd);
255 return err;
256 }
257
parse_type(const char * p,const char * prefix,size_t len,snd_ctl_elem_info_t * info)258 static const char *parse_type(const char *p, const char *prefix, size_t len,
259 snd_ctl_elem_info_t *info)
260 {
261 if (strncasecmp(p, prefix, len))
262 return p;
263 p += len;
264 if (info->type != SND_CTL_ELEM_TYPE_NONE)
265 return NULL;
266 if (strncasecmp(p, "bool", sizeof("bool") - 1) == 0)
267 info->type = SND_CTL_ELEM_TYPE_BOOLEAN;
268 else if (strncasecmp(p, "integer64", sizeof("integer64") - 1) == 0)
269 info->type = SND_CTL_ELEM_TYPE_INTEGER64;
270 else if (strncasecmp(p, "int64", sizeof("int64") - 1) == 0)
271 info->type = SND_CTL_ELEM_TYPE_INTEGER64;
272 else if (strncasecmp(p, "int", sizeof("int") - 1) == 0)
273 info->type = SND_CTL_ELEM_TYPE_INTEGER;
274 else if (strncasecmp(p, "enum", sizeof("enum") - 1) == 0)
275 info->type = SND_CTL_ELEM_TYPE_ENUMERATED;
276 else if (strncasecmp(p, "bytes", sizeof("bytes") - 1) == 0)
277 info->type = SND_CTL_ELEM_TYPE_BYTES;
278 else
279 return NULL;
280 while (isalpha(*p))
281 p++;
282 return p;
283 }
284
parse_uint(const char * p,const char * prefix,size_t len,unsigned int min,unsigned int max,unsigned int * rval)285 static const char *parse_uint(const char *p, const char *prefix, size_t len,
286 unsigned int min, unsigned int max, unsigned int *rval)
287 {
288 long v;
289 char *end;
290
291 if (strncasecmp(p, prefix, len))
292 return p;
293 p += len;
294 v = strtol(p, &end, 0);
295 if (*end != '\0' && *end != ' ' && *end != ',') {
296 uc_error("unable to parse '%s'", prefix);
297 return NULL;
298 }
299 if (v < min || v > max) {
300 uc_error("value '%s' out of range %u-%u %(%ld)", min, max, v);
301 return NULL;
302 }
303 *rval = v;
304 return end;
305 }
306
parse_labels(const char * p,const char * prefix,size_t len,snd_ctl_elem_info_t * info)307 static const char *parse_labels(const char *p, const char *prefix, size_t len,
308 snd_ctl_elem_info_t *info)
309 {
310 const char *s;
311 char *buf, *bp;
312 size_t l;
313 int c;
314
315 if (info->type != SND_CTL_ELEM_TYPE_ENUMERATED)
316 return NULL;
317 if (strncasecmp(p, prefix, len))
318 return p;
319 p += len;
320 s = p;
321 c = *s;
322 l = 0;
323 if (c == '\'' || c == '\"') {
324 s++;
325 while (*s && *s != c) {
326 s++, l++;
327 }
328 if (*s == c)
329 s++;
330 } else {
331 while (*s && *s != ',')
332 l++;
333 }
334 if (l == 0)
335 return NULL;
336 buf = malloc(l + 1);
337 if (buf == NULL)
338 return NULL;
339 memcpy(buf, p + ((c == '\'' || c == '\"') ? 1 : 0), l);
340 buf[l] = '\0';
341 info->value.enumerated.items = 1;
342 for (bp = buf; *bp; bp++) {
343 if (*bp == ';') {
344 if (bp == buf || bp[1] == ';') {
345 free(buf);
346 return NULL;
347 }
348 info->value.enumerated.items++;
349 *bp = '\0';
350 }
351 }
352 info->value.enumerated.names_ptr = (uintptr_t)buf;
353 info->value.enumerated.names_length = l + 1;
354 return s;
355 }
356
parse_cset_new_info(snd_ctl_elem_info_t * info,const char * s,const char ** pos)357 static int parse_cset_new_info(snd_ctl_elem_info_t *info, const char *s, const char **pos)
358 {
359 const char *p = s, *op;
360
361 info->count = 1;
362 while (*s) {
363 op = p;
364 p = parse_type(p, "type=", sizeof("type=") - 1, info);
365 if (p != op)
366 goto next;
367 p = parse_uint(p, "elements=", sizeof("elements=") - 1, 1, 128, (unsigned int *)&info->owner);
368 if (p != op)
369 goto next;
370 p = parse_uint(p, "count=", sizeof("count=") - 1, 1, 128, &info->count);
371 if (p != op)
372 goto next;
373 p = parse_labels(p, "labels=", sizeof("labels=") - 1, info);
374 next:
375 if (p == NULL)
376 goto er;
377 if (*p == ',')
378 p++;
379 if (isspace(*p))
380 break;
381 if (op == p)
382 goto er;
383 }
384 *pos = p;
385 return 0;
386 er:
387 uc_error("unknown syntax '%s'", p);
388 return -EINVAL;
389 }
390
execute_cset(snd_ctl_t * ctl,const char * cset,unsigned int type)391 static int execute_cset(snd_ctl_t *ctl, const char *cset, unsigned int type)
392 {
393 const char *pos;
394 int err;
395 snd_ctl_elem_id_t *id;
396 snd_ctl_elem_value_t *value;
397 snd_ctl_elem_info_t *info, *info2 = NULL;
398 unsigned int *res = NULL;
399
400 snd_ctl_elem_id_malloc(&id);
401 snd_ctl_elem_value_malloc(&value);
402 snd_ctl_elem_info_malloc(&info);
403
404 err = __snd_ctl_ascii_elem_id_parse(id, cset, &pos);
405 if (err < 0)
406 goto __fail;
407 while (*pos && isspace(*pos))
408 pos++;
409 if (type == SEQUENCE_ELEMENT_TYPE_CSET_NEW) {
410 snd_ctl_elem_info_malloc(&info2);
411 snd_ctl_elem_info_set_id(info2, id);
412 err = parse_cset_new_info(info2, pos, &pos);
413 if (err < 0 || !*pos) {
414 uc_error("undefined or wrong id config for cset-new", cset);
415 err = -EINVAL;
416 goto __fail;
417 }
418 while (*pos && isspace(*pos))
419 pos++;
420 }
421 if (!*pos) {
422 if (type != SEQUENCE_ELEMENT_TYPE_CTL_REMOVE) {
423 uc_error("undefined value for cset >%s<", cset);
424 err = -EINVAL;
425 goto __fail;
426 }
427 } else if (type == SEQUENCE_ELEMENT_TYPE_CTL_REMOVE) {
428 uc_error("extra value for ctl-remove >%s<", cset);
429 err = -EINVAL;
430 goto __fail;
431 }
432
433 snd_ctl_elem_info_set_id(info, id);
434 err = snd_ctl_elem_info(ctl, info);
435 if (type == SEQUENCE_ELEMENT_TYPE_CSET_NEW ||
436 type == SEQUENCE_ELEMENT_TYPE_CTL_REMOVE) {
437 if (err >= 0) {
438 err = snd_ctl_elem_remove(ctl, id);
439 if (err < 0) {
440 uc_error("unable to remove control");
441 err = -EINVAL;
442 goto __fail;
443 }
444 }
445 if (type == SEQUENCE_ELEMENT_TYPE_CTL_REMOVE)
446 goto __ok;
447 err = __snd_ctl_add_elem_set(ctl, info2, info2->owner, info2->count);
448 if (err < 0) {
449 uc_error("unable to create new control");
450 goto __fail;
451 }
452 /* new id copy */
453 snd_ctl_elem_info_get_id(info2, id);
454 snd_ctl_elem_info_set_id(info, id);
455 } else if (err < 0)
456 goto __fail;
457 if (type == SEQUENCE_ELEMENT_TYPE_CSET_TLV) {
458 if (!snd_ctl_elem_info_is_tlv_writable(info)) {
459 err = -EINVAL;
460 goto __fail;
461 }
462 err = read_tlv_file(&res, pos);
463 if (err < 0)
464 goto __fail;
465 err = snd_ctl_elem_tlv_write(ctl, id, res);
466 if (err < 0)
467 goto __fail;
468 } else {
469 snd_ctl_elem_value_set_id(value, id);
470 err = snd_ctl_elem_read(ctl, value);
471 if (err < 0)
472 goto __fail;
473 if (type == SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE)
474 err = binary_file_parse(value, info, pos);
475 else
476 err = snd_ctl_ascii_value_parse(ctl, value, info, pos);
477 if (err < 0)
478 goto __fail;
479 err = snd_ctl_elem_write(ctl, value);
480 if (err < 0)
481 goto __fail;
482 if (type == SEQUENCE_ELEMENT_TYPE_CSET_NEW) {
483 unsigned int idx;
484 for (idx = 1; idx < (unsigned int)info2->owner; idx++) {
485 value->id.numid += 1;
486 err = snd_ctl_elem_write(ctl, value);
487 if (err < 0)
488 goto __fail;
489 }
490 }
491 }
492 __ok:
493 err = 0;
494 __fail:
495 free(id);
496 free(value);
497 if (info2) {
498 if (info2->type == SND_CTL_ELEM_TYPE_ENUMERATED)
499 free((void *)info2->value.enumerated.names_ptr);
500 free(info2);
501 }
502 free(info);
503 free(res);
504
505 return err;
506 }
507
execute_sysw(const char * sysw)508 static int execute_sysw(const char *sysw)
509 {
510 char path[PATH_MAX];
511 const char *e;
512 char *s, *value;
513 ssize_t wlen;
514 size_t len;
515 int fd, myerrno;
516 bool ignore_error = false;
517
518 if (sysw == NULL || *sysw == '\0')
519 return 0;
520
521 if (sysw[0] == '-') {
522 ignore_error = true;
523 sysw++;
524 }
525
526 if (sysw[0] == ':')
527 return -EINVAL;
528
529 s = strdup(sysw[0] != '/' ? sysw : sysw + 1);
530 if (s == NULL)
531 return -ENOMEM;
532
533 value = strchr(s, ':');
534 if (!value) {
535 free(s);
536 return -EINVAL;
537 }
538 *value = '\0';
539 value++;
540 len = strlen(value);
541 if (len < 1) {
542 free(s);
543 return -EINVAL;
544 }
545
546 e = uc_mgr_sysfs_root();
547 if (e == NULL) {
548 free(s);
549 return -EINVAL;
550 }
551 snprintf(path, sizeof(path), "%s/%s", e, s);
552
553 fd = open(path, O_WRONLY|O_CLOEXEC);
554 if (fd < 0) {
555 free(s);
556 if (ignore_error)
557 return 0;
558 uc_error("unable to open '%s' for write", path);
559 return -EINVAL;
560 }
561 wlen = write(fd, value, len);
562 myerrno = errno;
563 close(fd);
564 free(s);
565
566 if (ignore_error)
567 return 0;
568
569 if (wlen != (ssize_t)len) {
570 uc_error("unable to write '%s' to '%s': %s", value, path, strerror(myerrno));
571 return -EINVAL;
572 }
573
574 return 0;
575 }
576
577 int _snd_config_save_node_value(snd_config_t *n, snd_output_t *out, unsigned int level);
578
execute_cfgsave(snd_use_case_mgr_t * uc_mgr,const char * filename)579 static int execute_cfgsave(snd_use_case_mgr_t *uc_mgr, const char *filename)
580 {
581 snd_config_t *config = uc_mgr->local_config;
582 char *file, *root;
583 snd_output_t *out;
584 bool with_root = false;
585 int err = 0;
586
587 file = strdup(filename);
588 if (!file)
589 return -ENOMEM;
590 root = strchr(file, ':');
591 if (config && root) {
592 *root++ = '\0';
593 if (*root == '+') {
594 with_root = true;
595 root++;
596 }
597 err = snd_config_search(config, root, &config);
598 if (err < 0) {
599 uc_error("Unable to find subtree '%s'", root);
600 goto _err;
601 }
602 }
603
604 err = snd_output_stdio_open(&out, file, "w+");
605 if (err < 0) {
606 uc_error("unable to open file '%s': %s", file, snd_strerror(err));
607 goto _err;
608 }
609 if (!config || snd_config_is_empty(config)) {
610 snd_output_close(out);
611 goto _err;
612 }
613 if (with_root) {
614 snd_output_printf(out, "%s ", root);
615 err = _snd_config_save_node_value(config, out, 0);
616 } else {
617 err = snd_config_save(config, out);
618 }
619 snd_output_close(out);
620 if (err < 0) {
621 uc_error("unable to save configuration: %s", snd_strerror(err));
622 goto _err;
623 }
624 _err:
625 free(file);
626 return err;
627 }
628
rewrite_device_value(snd_use_case_mgr_t * uc_mgr,const char * name,char ** value)629 static int rewrite_device_value(snd_use_case_mgr_t *uc_mgr, const char *name, char **value)
630 {
631 char *sval;
632 size_t l;
633 static const char **s, *_prefix[] = {
634 "PlaybackCTL",
635 "CaptureCTL",
636 "PlaybackMixer",
637 "CaptureMixer",
638 "PlaybackPCM",
639 "CapturePCM",
640 NULL
641 };
642
643 if (!uc_mgr_has_local_config(uc_mgr))
644 return 0;
645 for (s = _prefix; *s && *value; s++) {
646 if (strcmp(*s, name) != 0)
647 continue;
648 l = strlen(*value) + 9 + 1;
649 sval = malloc(l);
650 if (sval == NULL) {
651 free(*value);
652 *value = NULL;
653 return -ENOMEM;
654 }
655 snprintf(sval, l, "_ucm%04X.%s", uc_mgr->ucm_card_number, *value);
656 free(*value);
657 *value = sval;
658 break;
659 }
660 return 0;
661 }
662
663 /**
664 * \brief Execute the sequence
665 * \param uc_mgr Use case manager
666 * \param seq Sequence
667 * \return zero on success, otherwise a negative error code
668 */
execute_sequence(snd_use_case_mgr_t * uc_mgr,struct list_head * seq,struct list_head * value_list1,struct list_head * value_list2,struct list_head * value_list3)669 static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
670 struct list_head *seq,
671 struct list_head *value_list1,
672 struct list_head *value_list2,
673 struct list_head *value_list3)
674 {
675 struct list_head *pos;
676 struct sequence_element *s;
677 char *cdev = NULL;
678 snd_ctl_t *ctl = NULL;
679 struct ctl_list *ctl_list;
680 bool ignore_error;
681 int err = 0;
682
683 list_for_each(pos, seq) {
684 s = list_entry(pos, struct sequence_element, list);
685 switch (s->type) {
686 case SEQUENCE_ELEMENT_TYPE_CDEV:
687 cdev = strdup(s->data.cdev);
688 if (cdev == NULL)
689 goto __fail_nomem;
690 if (rewrite_device_value(uc_mgr, "PlaybackCTL", &cdev))
691 goto __fail_nomem;
692 break;
693 case SEQUENCE_ELEMENT_TYPE_CSET:
694 case SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE:
695 case SEQUENCE_ELEMENT_TYPE_CSET_TLV:
696 case SEQUENCE_ELEMENT_TYPE_CSET_NEW:
697 case SEQUENCE_ELEMENT_TYPE_CTL_REMOVE:
698 if (cdev == NULL && uc_mgr->in_component_domain) {
699 /* For sequence of a component device, use
700 * its parent's cdev stored by ucm manager.
701 */
702 if (uc_mgr->cdev == NULL) {
703 uc_error("cdev is not defined!");
704 return err;
705 }
706
707 cdev = strndup(uc_mgr->cdev, PATH_MAX);
708 if (!cdev)
709 return -ENOMEM;
710 } else if (cdev == NULL) {
711 char *playback_ctl = NULL;
712 char *capture_ctl = NULL;
713
714 err = get_value3(uc_mgr, &playback_ctl, "PlaybackCTL",
715 value_list1,
716 value_list2,
717 value_list3);
718 if (err < 0 && err != -ENOENT) {
719 uc_error("cdev is not defined!");
720 return err;
721 }
722 err = get_value3(uc_mgr, &capture_ctl, "CaptureCTL",
723 value_list1,
724 value_list2,
725 value_list3);
726 if (err < 0 && err != -ENOENT) {
727 free(playback_ctl);
728 uc_error("cdev is not defined!");
729 return err;
730 }
731 if (playback_ctl == NULL &&
732 capture_ctl == NULL) {
733 uc_error("cdev is not defined!");
734 return -EINVAL;
735 }
736 if (playback_ctl != NULL &&
737 capture_ctl != NULL &&
738 strcmp(playback_ctl, capture_ctl) != 0) {
739 free(playback_ctl);
740 free(capture_ctl);
741 uc_error("cdev is not equal for playback and capture!");
742 return -EINVAL;
743 }
744 if (playback_ctl != NULL) {
745 cdev = playback_ctl;
746 free(capture_ctl);
747 } else {
748 cdev = capture_ctl;
749 }
750 }
751 if (ctl == NULL) {
752 err = uc_mgr_open_ctl(uc_mgr, &ctl_list, cdev, 1);
753 if (err < 0) {
754 uc_error("unable to open ctl device '%s'", cdev);
755 goto __fail;
756 }
757 ctl = ctl_list->ctl;
758 }
759 err = execute_cset(ctl, s->data.cset, s->type);
760 if (err < 0) {
761 uc_error("unable to execute cset '%s'", s->data.cset);
762 goto __fail;
763 }
764 break;
765 case SEQUENCE_ELEMENT_TYPE_SYSSET:
766 err = execute_sysw(s->data.sysw);
767 if (err < 0)
768 goto __fail;
769 break;
770 case SEQUENCE_ELEMENT_TYPE_SLEEP:
771 usleep(s->data.sleep);
772 break;
773 case SEQUENCE_ELEMENT_TYPE_EXEC:
774 if (s->data.exec == NULL)
775 break;
776 ignore_error = s->data.exec[0] == '-';
777 err = uc_mgr_exec(s->data.exec + (ignore_error ? 1 : 0));
778 if (ignore_error == false && err != 0) {
779 uc_error("exec '%s' failed (exit code %d)", s->data.exec, err);
780 goto __fail;
781 }
782 break;
783 case SEQUENCE_ELEMENT_TYPE_SHELL:
784 if (s->data.exec == NULL)
785 break;
786 ignore_error = s->data.exec[0] == '-';
787 shell_retry:
788 err = system(s->data.exec + (ignore_error ? 1 : 0));
789 if (WIFSIGNALED(err)) {
790 err = -EINTR;
791 } if (WIFEXITED(err)) {
792 if (ignore_error == false && WEXITSTATUS(err) != 0) {
793 uc_error("command '%s' failed (exit code %d)", s->data.exec, WEXITSTATUS(err));
794 err = -EINVAL;
795 goto __fail;
796 }
797 } else if (err < 0) {
798 if (errno == EAGAIN)
799 goto shell_retry;
800 err = -errno;
801 goto __fail;
802 }
803 break;
804 case SEQUENCE_ELEMENT_TYPE_CMPT_SEQ:
805 /* Execute enable or disable sequence of a component
806 * device. Pass the cdev defined by the machine device.
807 */
808 err = execute_component_seq(uc_mgr,
809 &s->data.cmpt_seq,
810 value_list1,
811 value_list2,
812 value_list3,
813 cdev);
814 if (err < 0)
815 goto __fail;
816 break;
817 case SEQUENCE_ELEMENT_TYPE_CFGSAVE:
818 err = execute_cfgsave(uc_mgr, s->data.cfgsave);
819 if (err < 0)
820 goto __fail;
821 break;
822 default:
823 uc_error("unknown sequence command %i", s->type);
824 break;
825 }
826 }
827 free(cdev);
828 return 0;
829 __fail_nomem:
830 err = -ENOMEM;
831 __fail:
832 free(cdev);
833 return err;
834
835 }
836
837 /* Execute enable or disable sequence of a component device.
838 *
839 * For a component device (a codec or embedded DSP), its sequence doesn't
840 * specify the sound card device 'cdev', because a component can be reused
841 * by different sound cards (machines). So when executing its sequence, a
842 * parameter 'cdev' is used to pass cdev defined by the sequence of its
843 * parent, the machine device. UCM manger will store the cdev when entering
844 * the component domain.
845 */
execute_component_seq(snd_use_case_mgr_t * uc_mgr,struct component_sequence * cmpt_seq,struct list_head * value_list1 ATTRIBUTE_UNUSED,struct list_head * value_list2 ATTRIBUTE_UNUSED,struct list_head * value_list3 ATTRIBUTE_UNUSED,char * cdev)846 static int execute_component_seq(snd_use_case_mgr_t *uc_mgr,
847 struct component_sequence *cmpt_seq,
848 struct list_head *value_list1 ATTRIBUTE_UNUSED,
849 struct list_head *value_list2 ATTRIBUTE_UNUSED,
850 struct list_head *value_list3 ATTRIBUTE_UNUSED,
851 char *cdev)
852 {
853 struct use_case_device *device = cmpt_seq->device;
854 struct list_head *seq;
855 int err;
856
857 /* enter component domain and store cdev for the component */
858 uc_mgr->in_component_domain = 1;
859 uc_mgr->cdev = cdev;
860
861 /* choose enable or disable sequence of the component device */
862 if (cmpt_seq->enable)
863 seq = &device->enable_list;
864 else
865 seq = &device->disable_list;
866
867 /* excecute the sequence of the component dev */
868 err = execute_sequence(uc_mgr, seq,
869 &device->value_list,
870 &uc_mgr->active_verb->value_list,
871 &uc_mgr->value_list);
872
873 /* exit component domain and clear cdev */
874 uc_mgr->in_component_domain = 0;
875 uc_mgr->cdev = NULL;
876
877 return err;
878 }
879
add_auto_value(snd_use_case_mgr_t * uc_mgr,const char * key,char * value)880 static int add_auto_value(snd_use_case_mgr_t *uc_mgr, const char *key, char *value)
881 {
882 char *s;
883 int err;
884
885 err = get_value1(uc_mgr, &value, &uc_mgr->value_list, key);
886 if (err == -ENOENT) {
887 s = strdup(value);
888 if (s == NULL)
889 return -ENOMEM;
890 return uc_mgr_add_value(&uc_mgr->value_list, key, s);
891 } else if (err < 0) {
892 return err;
893 }
894 free(value);
895 return 0;
896 }
897
add_auto_values(snd_use_case_mgr_t * uc_mgr)898 static int add_auto_values(snd_use_case_mgr_t *uc_mgr)
899 {
900 struct ctl_list *ctl_list;
901 const char *id;
902 char buf[40];
903 int err;
904
905 ctl_list = uc_mgr_get_master_ctl(uc_mgr);
906 if (ctl_list) {
907 id = snd_ctl_card_info_get_id(ctl_list->ctl_info);
908 snprintf(buf, sizeof(buf), "hw:%s", id);
909 err = add_auto_value(uc_mgr, "PlaybackCTL", buf);
910 if (err < 0)
911 return err;
912 err = add_auto_value(uc_mgr, "CaptureCTL", buf);
913 if (err < 0)
914 return err;
915 }
916 return 0;
917 }
918
919 /**
920 * \brief execute default commands
921 * \param uc_mgr Use case manager
922 * \return zero on success, otherwise a negative error code
923 */
set_defaults(snd_use_case_mgr_t * uc_mgr)924 static int set_defaults(snd_use_case_mgr_t *uc_mgr)
925 {
926 int err;
927
928 if (uc_mgr->default_list_executed)
929 return 0;
930 err = execute_sequence(uc_mgr, &uc_mgr->default_list,
931 &uc_mgr->value_list, NULL, NULL);
932 if (err < 0) {
933 uc_error("Unable to execute default sequence");
934 return err;
935 }
936 uc_mgr->default_list_executed = 1;
937 return 0;
938 }
939
940 /**
941 * \brief Import master config and execute the default sequence
942 * \param uc_mgr Use case manager
943 * \return zero on success, otherwise a negative error code
944 */
import_master_config(snd_use_case_mgr_t * uc_mgr)945 static int import_master_config(snd_use_case_mgr_t *uc_mgr)
946 {
947 int err;
948
949 err = uc_mgr_import_master_config(uc_mgr);
950 if (err < 0)
951 return err;
952 return add_auto_values(uc_mgr);
953 }
954
955 /**
956 * \brief Check, if the UCM configuration is empty
957 * \param uc_mgr Use case Manager
958 * \return zero on success, otherwise a negative error code
959 */
check_empty_configuration(snd_use_case_mgr_t * uc_mgr)960 static int check_empty_configuration(snd_use_case_mgr_t *uc_mgr)
961 {
962 int err;
963 char *value;
964
965 err = get_value(uc_mgr, "Linked", &value, NULL, NULL, 1);
966 if (err >= 0) {
967 err = strcasecmp(value, "true") == 0 ||
968 strcmp(value, "1") == 0;
969 free(value);
970 if (err)
971 return 0;
972 }
973 if (!list_empty(&uc_mgr->verb_list))
974 return 0;
975 if (!list_empty(&uc_mgr->fixedboot_list))
976 return 0;
977 if (!list_empty(&uc_mgr->boot_list))
978 return 0;
979 return -ENXIO;
980 }
981
982 /**
983 * \brief Universal find - string in a list
984 * \param list List of structures
985 * \param offset Offset of list structure
986 * \param soffset Offset of string structure
987 * \param match String to match
988 * \return structure on success, otherwise a NULL (not found)
989 */
find0(struct list_head * list,unsigned long offset,unsigned long soffset,const char * match)990 static void *find0(struct list_head *list,
991 unsigned long offset,
992 unsigned long soffset,
993 const char *match)
994 {
995 struct list_head *pos;
996 char *ptr, *str;
997
998 list_for_each(pos, list) {
999 ptr = list_entry_offset(pos, char, offset);
1000 str = *((char **)(ptr + soffset));
1001 if (strcmp(str, match) == 0)
1002 return ptr;
1003 }
1004 return NULL;
1005 }
1006
1007 #define find(list, type, member, value, match) \
1008 find0(list, (unsigned long)(&((type *)0)->member), \
1009 (unsigned long)(&((type *)0)->value), match)
1010
1011 /**
1012 * \brief Universal string list
1013 * \param list List of structures
1014 * \param result Result list
1015 * \param offset Offset of list structure
1016 * \param s1offset Offset of string structure
1017 * \return count of items on success, otherwise a negative error code
1018 */
get_list0(struct list_head * list,const char ** result[],unsigned long offset,unsigned long s1offset)1019 static int get_list0(struct list_head *list,
1020 const char **result[],
1021 unsigned long offset,
1022 unsigned long s1offset)
1023 {
1024 char **res;
1025 int cnt;
1026 struct list_head *pos;
1027 char *ptr, *str1;
1028
1029 cnt = alloc_str_list(list, 1, &res);
1030 if (cnt <= 0) {
1031 *result = NULL;
1032 return cnt;
1033 }
1034 *result = (const char **)res;
1035 list_for_each(pos, list) {
1036 ptr = list_entry_offset(pos, char, offset);
1037 str1 = *((char **)(ptr + s1offset));
1038 if (str1 != NULL) {
1039 *res = strdup(str1);
1040 if (*res == NULL)
1041 goto __fail;
1042 } else {
1043 *res = NULL;
1044 }
1045 res++;
1046 }
1047 return cnt;
1048 __fail:
1049 snd_use_case_free_list(*result, cnt);
1050 return -ENOMEM;
1051 }
1052
1053 #define get_list(list, result, type, member, s1) \
1054 get_list0(list, result, \
1055 (unsigned long)(&((type *)0)->member), \
1056 (unsigned long)(&((type *)0)->s1))
1057
1058 /**
1059 * \brief Universal string list - pair of strings
1060 * \param list List of structures
1061 * \param result Result list
1062 * \param offset Offset of list structure
1063 * \param s1offset Offset of string structure
1064 * \param s1offset Offset of string structure
1065 * \return count of items on success, otherwise a negative error code
1066 */
get_list20(struct list_head * list,const char ** result[],unsigned long offset,unsigned long s1offset,unsigned long s2offset)1067 static int get_list20(struct list_head *list,
1068 const char **result[],
1069 unsigned long offset,
1070 unsigned long s1offset,
1071 unsigned long s2offset)
1072 {
1073 char **res;
1074 int cnt;
1075 struct list_head *pos;
1076 char *ptr, *str1, *str2;
1077
1078 cnt = alloc_str_list(list, 2, &res);
1079 if (cnt <= 0) {
1080 *result = NULL;
1081 return cnt;
1082 }
1083 *result = (const char **)res;
1084 list_for_each(pos, list) {
1085 ptr = list_entry_offset(pos, char, offset);
1086 str1 = *((char **)(ptr + s1offset));
1087 if (str1 != NULL) {
1088 *res = strdup(str1);
1089 if (*res == NULL)
1090 goto __fail;
1091 } else {
1092 *res = NULL;
1093 }
1094 res++;
1095 str2 = *((char **)(ptr + s2offset));
1096 if (str2 != NULL) {
1097 *res = strdup(str2);
1098 if (*res == NULL)
1099 goto __fail;
1100 } else {
1101 *res = NULL;
1102 }
1103 res++;
1104 }
1105 return cnt;
1106 __fail:
1107 snd_use_case_free_list(*result, cnt);
1108 return -ENOMEM;
1109 }
1110
1111 #define get_list2(list, result, type, member, s1, s2) \
1112 get_list20(list, result, \
1113 (unsigned long)(&((type *)0)->member), \
1114 (unsigned long)(&((type *)0)->s1), \
1115 (unsigned long)(&((type *)0)->s2))
1116
1117 /**
1118 * \brief Find verb
1119 * \param uc_mgr Use case manager
1120 * \param verb_name verb to find
1121 * \return structure on success, otherwise a NULL (not found)
1122 */
find_verb(snd_use_case_mgr_t * uc_mgr,const char * verb_name)1123 static inline struct use_case_verb *find_verb(snd_use_case_mgr_t *uc_mgr,
1124 const char *verb_name)
1125 {
1126 return find(&uc_mgr->verb_list,
1127 struct use_case_verb, list, name,
1128 verb_name);
1129 }
1130
is_devlist_supported(snd_use_case_mgr_t * uc_mgr,struct dev_list * dev_list)1131 static int is_devlist_supported(snd_use_case_mgr_t *uc_mgr,
1132 struct dev_list *dev_list)
1133 {
1134 struct dev_list_node *device;
1135 struct use_case_device *adev;
1136 struct list_head *pos, *pos1;
1137 int found_ret;
1138
1139 switch (dev_list->type) {
1140 case DEVLIST_NONE:
1141 default:
1142 return 1;
1143 case DEVLIST_SUPPORTED:
1144 found_ret = 1;
1145 break;
1146 case DEVLIST_CONFLICTING:
1147 found_ret = 0;
1148 break;
1149 }
1150
1151 list_for_each(pos, &dev_list->list) {
1152 device = list_entry(pos, struct dev_list_node, list);
1153
1154 list_for_each(pos1, &uc_mgr->active_devices) {
1155 adev = list_entry(pos1, struct use_case_device,
1156 active_list);
1157 if (!strcmp(device->name, adev->name))
1158 return found_ret;
1159 }
1160 }
1161 return 1 - found_ret;
1162 }
1163
is_modifier_supported(snd_use_case_mgr_t * uc_mgr,struct use_case_modifier * modifier)1164 static inline int is_modifier_supported(snd_use_case_mgr_t *uc_mgr,
1165 struct use_case_modifier *modifier)
1166 {
1167 return is_devlist_supported(uc_mgr, &modifier->dev_list);
1168 }
1169
is_device_supported(snd_use_case_mgr_t * uc_mgr,struct use_case_device * device)1170 static inline int is_device_supported(snd_use_case_mgr_t *uc_mgr,
1171 struct use_case_device *device)
1172 {
1173 return is_devlist_supported(uc_mgr, &device->dev_list);
1174 }
1175
1176 /**
1177 * \brief Find device
1178 * \param verb Use case verb
1179 * \param device_name device to find
1180 * \return structure on success, otherwise a NULL (not found)
1181 */
1182 static inline struct use_case_device *
find_device(snd_use_case_mgr_t * uc_mgr,struct use_case_verb * verb,const char * device_name,int check_supported)1183 find_device(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb,
1184 const char *device_name, int check_supported)
1185 {
1186 struct use_case_device *device;
1187 struct list_head *pos;
1188
1189 list_for_each(pos, &verb->device_list) {
1190 device = list_entry(pos, struct use_case_device, list);
1191
1192 if (strcmp(device_name, device->name))
1193 continue;
1194
1195 if (check_supported &&
1196 !is_device_supported(uc_mgr, device))
1197 continue;
1198
1199 return device;
1200 }
1201 return NULL;
1202 }
1203
1204 /**
1205 * \brief Find modifier
1206 * \param verb Use case verb
1207 * \param modifier_name modifier to find
1208 * \return structure on success, otherwise a NULL (not found)
1209 */
1210 static struct use_case_modifier *
find_modifier(snd_use_case_mgr_t * uc_mgr,struct use_case_verb * verb,const char * modifier_name,int check_supported)1211 find_modifier(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb,
1212 const char *modifier_name, int check_supported)
1213 {
1214 struct use_case_modifier *modifier;
1215 struct list_head *pos;
1216
1217 list_for_each(pos, &verb->modifier_list) {
1218 modifier = list_entry(pos, struct use_case_modifier, list);
1219
1220 if (strcmp(modifier->name, modifier_name))
1221 continue;
1222
1223 if (check_supported &&
1224 !is_modifier_supported(uc_mgr, modifier))
1225 continue;
1226
1227 return modifier;
1228 }
1229 return NULL;
1230 }
1231
device_status(snd_use_case_mgr_t * uc_mgr,const char * device_name)1232 long device_status(snd_use_case_mgr_t *uc_mgr,
1233 const char *device_name)
1234 {
1235 struct use_case_device *dev;
1236 struct list_head *pos;
1237
1238 list_for_each(pos, &uc_mgr->active_devices) {
1239 dev = list_entry(pos, struct use_case_device, active_list);
1240 if (strcmp(dev->name, device_name) == 0)
1241 return 1;
1242 }
1243 return 0;
1244 }
1245
modifier_status(snd_use_case_mgr_t * uc_mgr,const char * modifier_name)1246 long modifier_status(snd_use_case_mgr_t *uc_mgr,
1247 const char *modifier_name)
1248 {
1249 struct use_case_modifier *mod;
1250 struct list_head *pos;
1251
1252 list_for_each(pos, &uc_mgr->active_modifiers) {
1253 mod = list_entry(pos, struct use_case_modifier, active_list);
1254 if (strcmp(mod->name, modifier_name) == 0)
1255 return 1;
1256 }
1257 return 0;
1258 }
1259
1260 /**
1261 * \brief Set verb
1262 * \param uc_mgr Use case manager
1263 * \param verb verb to set
1264 * \param enable nonzero = enable, zero = disable
1265 * \return zero on success, otherwise a negative error code
1266 */
set_verb(snd_use_case_mgr_t * uc_mgr,struct use_case_verb * verb,int enable)1267 static int set_verb(snd_use_case_mgr_t *uc_mgr,
1268 struct use_case_verb *verb,
1269 int enable)
1270 {
1271 struct list_head *seq;
1272 int err;
1273
1274 if (enable) {
1275 err = set_defaults(uc_mgr);
1276 if (err < 0)
1277 return err;
1278 seq = &verb->enable_list;
1279 } else {
1280 seq = &verb->disable_list;
1281 }
1282 err = execute_sequence(uc_mgr, seq,
1283 &verb->value_list,
1284 &uc_mgr->value_list,
1285 NULL);
1286 if (enable && err >= 0)
1287 uc_mgr->active_verb = verb;
1288 return err;
1289 }
1290
1291 /**
1292 * \brief Set modifier
1293 * \param uc_mgr Use case manager
1294 * \param modifier modifier to set
1295 * \param enable nonzero = enable, zero = disable
1296 * \return zero on success, otherwise a negative error code
1297 */
set_modifier(snd_use_case_mgr_t * uc_mgr,struct use_case_modifier * modifier,int enable)1298 static int set_modifier(snd_use_case_mgr_t *uc_mgr,
1299 struct use_case_modifier *modifier,
1300 int enable)
1301 {
1302 struct list_head *seq;
1303 int err;
1304
1305 if (modifier_status(uc_mgr, modifier->name) == enable)
1306 return 0;
1307
1308 if (enable) {
1309 seq = &modifier->enable_list;
1310 } else {
1311 seq = &modifier->disable_list;
1312 }
1313 err = execute_sequence(uc_mgr, seq,
1314 &modifier->value_list,
1315 &uc_mgr->active_verb->value_list,
1316 &uc_mgr->value_list);
1317 if (enable && err >= 0) {
1318 list_add_tail(&modifier->active_list, &uc_mgr->active_modifiers);
1319 } else if (!enable) {
1320 list_del(&modifier->active_list);
1321 }
1322 return err;
1323 }
1324
1325 /**
1326 * \brief Set device
1327 * \param uc_mgr Use case manager
1328 * \param device device to set
1329 * \param enable nonzero = enable, zero = disable
1330 * \return zero on success, otherwise a negative error code
1331 */
set_device(snd_use_case_mgr_t * uc_mgr,struct use_case_device * device,int enable)1332 static int set_device(snd_use_case_mgr_t *uc_mgr,
1333 struct use_case_device *device,
1334 int enable)
1335 {
1336 struct list_head *seq;
1337 int err;
1338
1339 if (device_status(uc_mgr, device->name) == enable)
1340 return 0;
1341
1342 if (enable) {
1343 seq = &device->enable_list;
1344 } else {
1345 seq = &device->disable_list;
1346 }
1347 err = execute_sequence(uc_mgr, seq,
1348 &device->value_list,
1349 &uc_mgr->active_verb->value_list,
1350 &uc_mgr->value_list);
1351 if (enable && err >= 0) {
1352 list_add_tail(&device->active_list, &uc_mgr->active_devices);
1353 } else if (!enable) {
1354 list_del(&device->active_list);
1355 }
1356 return err;
1357 }
1358
1359 /**
1360 * \brief Init sound card use case manager.
1361 * \param uc_mgr Returned use case manager pointer
1362 * \param card_name name of card to open
1363 * \return zero on success, otherwise a negative error code
1364 */
snd_use_case_mgr_open(snd_use_case_mgr_t ** uc_mgr,const char * card_name)1365 int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr,
1366 const char *card_name)
1367 {
1368 snd_use_case_mgr_t *mgr;
1369 int err;
1370
1371 /* create a new UCM */
1372 mgr = calloc(1, sizeof(snd_use_case_mgr_t));
1373 if (mgr == NULL)
1374 return -ENOMEM;
1375 INIT_LIST_HEAD(&mgr->verb_list);
1376 INIT_LIST_HEAD(&mgr->fixedboot_list);
1377 INIT_LIST_HEAD(&mgr->boot_list);
1378 INIT_LIST_HEAD(&mgr->default_list);
1379 INIT_LIST_HEAD(&mgr->value_list);
1380 INIT_LIST_HEAD(&mgr->active_modifiers);
1381 INIT_LIST_HEAD(&mgr->active_devices);
1382 INIT_LIST_HEAD(&mgr->ctl_list);
1383 INIT_LIST_HEAD(&mgr->variable_list);
1384 pthread_mutex_init(&mgr->mutex, NULL);
1385
1386 if (card_name && *card_name == '-') {
1387 card_name++;
1388 mgr->suppress_nodev_errors = 1;
1389 }
1390
1391 err = uc_mgr_card_open(mgr);
1392 if (err < 0) {
1393 uc_mgr_free(mgr);
1394 return err;
1395 }
1396
1397 err = snd_config_top(&mgr->local_config);
1398 if (err < 0)
1399 goto _err;
1400
1401 mgr->card_name = strdup(card_name);
1402 if (mgr->card_name == NULL) {
1403 err = -ENOMEM;
1404 goto _err;
1405 }
1406
1407 /* get info on use_cases and verify against card */
1408 err = import_master_config(mgr);
1409 if (err < 0) {
1410 if (err == -ENXIO && mgr->suppress_nodev_errors)
1411 goto _err;
1412 uc_error("error: failed to import %s use case configuration %d",
1413 card_name, err);
1414 goto _err;
1415 }
1416
1417 err = check_empty_configuration(mgr);
1418 if (err < 0) {
1419 uc_error("error: failed to import %s (empty configuration)", card_name);
1420 goto _err;
1421 }
1422
1423 *uc_mgr = mgr;
1424 return 0;
1425
1426 _err:
1427 uc_mgr_card_close(mgr);
1428 uc_mgr_free(mgr);
1429 return err;
1430 }
1431
1432 /**
1433 * \brief Reload and reparse all use case files.
1434 * \param uc_mgr Use case manager
1435 * \return zero on success, otherwise a negative error code
1436 */
snd_use_case_mgr_reload(snd_use_case_mgr_t * uc_mgr)1437 int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr)
1438 {
1439 int err;
1440
1441 pthread_mutex_lock(&uc_mgr->mutex);
1442
1443 uc_mgr_free_verb(uc_mgr);
1444
1445 uc_mgr->default_list_executed = 0;
1446
1447 /* reload all use cases */
1448 err = import_master_config(uc_mgr);
1449 if (err < 0) {
1450 uc_error("error: failed to reload use cases");
1451 pthread_mutex_unlock(&uc_mgr->mutex);
1452 return -EINVAL;
1453 }
1454
1455 pthread_mutex_unlock(&uc_mgr->mutex);
1456 return err;
1457 }
1458
1459 /**
1460 * \brief Close use case manager.
1461 * \param uc_mgr Use case manager
1462 * \return zero on success, otherwise a negative error code
1463 */
snd_use_case_mgr_close(snd_use_case_mgr_t * uc_mgr)1464 int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr)
1465 {
1466 uc_mgr_card_close(uc_mgr);
1467 uc_mgr_free(uc_mgr);
1468
1469 return 0;
1470 }
1471
1472 /*
1473 * Tear down current use case verb, device and modifier.
1474 */
dismantle_use_case(snd_use_case_mgr_t * uc_mgr)1475 static int dismantle_use_case(snd_use_case_mgr_t *uc_mgr)
1476 {
1477 struct list_head *pos, *npos;
1478 struct use_case_modifier *modifier;
1479 struct use_case_device *device;
1480 int err;
1481
1482 list_for_each_safe(pos, npos, &uc_mgr->active_modifiers) {
1483 modifier = list_entry(pos, struct use_case_modifier,
1484 active_list);
1485 err = set_modifier(uc_mgr, modifier, 0);
1486 if (err < 0)
1487 uc_error("Unable to disable modifier %s", modifier->name);
1488 }
1489 INIT_LIST_HEAD(&uc_mgr->active_modifiers);
1490
1491 list_for_each_safe(pos, npos, &uc_mgr->active_devices) {
1492 device = list_entry(pos, struct use_case_device,
1493 active_list);
1494 err = set_device(uc_mgr, device, 0);
1495 if (err < 0)
1496 uc_error("Unable to disable device %s", device->name);
1497 }
1498 INIT_LIST_HEAD(&uc_mgr->active_devices);
1499
1500 err = set_verb(uc_mgr, uc_mgr->active_verb, 0);
1501 if (err < 0) {
1502 uc_error("Unable to disable verb %s", uc_mgr->active_verb->name);
1503 return err;
1504 }
1505 uc_mgr->active_verb = NULL;
1506
1507 err = execute_sequence(uc_mgr, &uc_mgr->default_list,
1508 &uc_mgr->value_list, NULL, NULL);
1509
1510 return err;
1511 }
1512
1513 /**
1514 * \brief Reset sound card controls to default values.
1515 * \param uc_mgr Use case manager
1516 * \return zero on success, otherwise a negative error code
1517 */
snd_use_case_mgr_reset(snd_use_case_mgr_t * uc_mgr)1518 int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
1519 {
1520 int err;
1521
1522 pthread_mutex_lock(&uc_mgr->mutex);
1523 err = execute_sequence(uc_mgr, &uc_mgr->default_list,
1524 &uc_mgr->value_list, NULL, NULL);
1525 INIT_LIST_HEAD(&uc_mgr->active_modifiers);
1526 INIT_LIST_HEAD(&uc_mgr->active_devices);
1527 uc_mgr->active_verb = NULL;
1528 pthread_mutex_unlock(&uc_mgr->mutex);
1529 return err;
1530 }
1531
1532 /**
1533 * \brief Get list of verbs in pair verbname+comment
1534 * \param list Returned list
1535 * \return Number of list entries if success, otherwise a negative error code
1536 */
get_verb_list(snd_use_case_mgr_t * uc_mgr,const char ** list[])1537 static int get_verb_list(snd_use_case_mgr_t *uc_mgr, const char **list[])
1538 {
1539 return get_list2(&uc_mgr->verb_list, list,
1540 struct use_case_verb, list,
1541 name, comment);
1542 }
1543
1544 /**
1545 * \brief Get list of devices in pair devicename+comment
1546 * \param list Returned list
1547 * \param verbname For verb (NULL = current)
1548 * \return Number of list entries if success, otherwise a negative error code
1549 */
get_device_list(snd_use_case_mgr_t * uc_mgr,const char ** list[],char * verbname)1550 static int get_device_list(snd_use_case_mgr_t *uc_mgr, const char **list[],
1551 char *verbname)
1552 {
1553 struct use_case_verb *verb;
1554
1555 if (verbname) {
1556 verb = find_verb(uc_mgr, verbname);
1557 } else {
1558 verb = uc_mgr->active_verb;
1559 }
1560 if (verb == NULL)
1561 return -ENOENT;
1562 return get_list2(&verb->device_list, list,
1563 struct use_case_device, list,
1564 name, comment);
1565 }
1566
1567 /**
1568 * \brief Get list of modifiers in pair devicename+comment
1569 * \param list Returned list
1570 * \param verbname For verb (NULL = current)
1571 * \return Number of list entries if success, otherwise a negative error code
1572 */
get_modifier_list(snd_use_case_mgr_t * uc_mgr,const char ** list[],char * verbname)1573 static int get_modifier_list(snd_use_case_mgr_t *uc_mgr, const char **list[],
1574 char *verbname)
1575 {
1576 struct use_case_verb *verb;
1577 if (verbname) {
1578 verb = find_verb(uc_mgr, verbname);
1579 } else {
1580 verb = uc_mgr->active_verb;
1581 }
1582 if (verb == NULL)
1583 return -ENOENT;
1584 return get_list2(&verb->modifier_list, list,
1585 struct use_case_modifier, list,
1586 name, comment);
1587 }
1588
1589 /**
1590 * \brief Get list of supported/conflicting devices
1591 * \param list Returned list
1592 * \param name Name of modifier or verb to query
1593 * \param type Type of device list entries to return
1594 * \return Number of list entries if success, otherwise a negative error code
1595 */
get_supcon_device_list(snd_use_case_mgr_t * uc_mgr,const char ** list[],char * name,enum dev_list_type type)1596 static int get_supcon_device_list(snd_use_case_mgr_t *uc_mgr,
1597 const char **list[], char *name,
1598 enum dev_list_type type)
1599 {
1600 char *str;
1601 struct use_case_verb *verb;
1602 struct use_case_modifier *modifier;
1603 struct use_case_device *device;
1604
1605 if (!name)
1606 return -ENOENT;
1607
1608 str = strchr(name, '/');
1609 if (str) {
1610 *str = '\0';
1611 verb = find_verb(uc_mgr, str + 1);
1612 }
1613 else {
1614 verb = uc_mgr->active_verb;
1615 }
1616 if (!verb)
1617 return -ENOENT;
1618
1619 modifier = find_modifier(uc_mgr, verb, name, 0);
1620 if (modifier) {
1621 if (modifier->dev_list.type != type) {
1622 *list = NULL;
1623 return 0;
1624 }
1625 return get_list(&modifier->dev_list.list, list,
1626 struct dev_list_node, list,
1627 name);
1628 }
1629
1630 device = find_device(uc_mgr, verb, name, 0);
1631 if (device) {
1632 if (device->dev_list.type != type) {
1633 *list = NULL;
1634 return 0;
1635 }
1636 return get_list(&device->dev_list.list, list,
1637 struct dev_list_node, list,
1638 name);
1639 }
1640
1641 return -ENOENT;
1642 }
1643
1644 /**
1645 * \brief Get list of supported devices
1646 * \param list Returned list
1647 * \param name Name of verb or modifier to query
1648 * \return Number of list entries if success, otherwise a negative error code
1649 */
get_supported_device_list(snd_use_case_mgr_t * uc_mgr,const char ** list[],char * name)1650 static int get_supported_device_list(snd_use_case_mgr_t *uc_mgr,
1651 const char **list[], char *name)
1652 {
1653 return get_supcon_device_list(uc_mgr, list, name, DEVLIST_SUPPORTED);
1654 }
1655
1656 /**
1657 * \brief Get list of conflicting devices
1658 * \param list Returned list
1659 * \param name Name of verb or modifier to query
1660 * \return Number of list entries if success, otherwise a negative error code
1661 */
get_conflicting_device_list(snd_use_case_mgr_t * uc_mgr,const char ** list[],char * name)1662 static int get_conflicting_device_list(snd_use_case_mgr_t *uc_mgr,
1663 const char **list[], char *name)
1664 {
1665 return get_supcon_device_list(uc_mgr, list, name, DEVLIST_CONFLICTING);
1666 }
1667
1668 #ifndef DOC_HIDDEN
1669 struct myvalue {
1670 struct list_head list;
1671 const char *text;
1672 };
1673 #endif
1674
1675 /**
1676 * \brief Convert myvalue list string list
1677 * \param list myvalue list
1678 * \param res string list
1679 * \retval Number of list entries if success, otherwise a negativer error code
1680 */
myvalue_to_str_list(struct list_head * list,char *** res)1681 static int myvalue_to_str_list(struct list_head *list, char ***res)
1682 {
1683 struct list_head *pos;
1684 struct myvalue *value;
1685 char **p;
1686 int cnt;
1687
1688 cnt = alloc_str_list(list, 1, res);
1689 if (cnt < 0)
1690 return cnt;
1691 p = *res;
1692 list_for_each(pos, list) {
1693 value = list_entry(pos, struct myvalue, list);
1694 *p = strdup(value->text);
1695 if (*p == NULL) {
1696 snd_use_case_free_list((const char **)p, cnt);
1697 return -ENOMEM;
1698 }
1699 p++;
1700 }
1701 return cnt;
1702 }
1703
1704 /**
1705 * \brief Free myvalue list
1706 * \param list myvalue list
1707 */
myvalue_list_free(struct list_head * list)1708 static void myvalue_list_free(struct list_head *list)
1709 {
1710 struct list_head *pos, *npos;
1711 struct myvalue *value;
1712
1713 list_for_each_safe(pos, npos, list) {
1714 value = list_entry(pos, struct myvalue, list);
1715 list_del(&value->list);
1716 free(value);
1717 }
1718 }
1719
1720 /**
1721 * \brief Merge one value to the myvalue list
1722 * \param list The list with values
1723 * \param value The value to be merged (without duplicates)
1724 * \return 1 if dup, 0 if success, otherwise a negative error code
1725 */
merge_value(struct list_head * list,const char * text)1726 static int merge_value(struct list_head *list, const char *text)
1727 {
1728 struct list_head *pos;
1729 struct myvalue *value;
1730
1731 list_for_each(pos, list) {
1732 value = list_entry(pos, struct myvalue, list);
1733 if (strcmp(value->text, text) == 0)
1734 return 1;
1735 }
1736 value = malloc(sizeof(*value));
1737 if (value == NULL)
1738 return -ENOMEM;
1739 value->text = text;
1740 list_add_tail(&value->list, list);
1741 return 0;
1742 }
1743
1744 /**
1745 * \brief Find all values for given identifier
1746 * \param list Returned list
1747 * \param source Source list with ucm_value structures
1748 * \return Zero if success, otherwise a negative error code
1749 */
add_identifiers(struct list_head * list,struct list_head * source)1750 static int add_identifiers(struct list_head *list,
1751 struct list_head *source)
1752 {
1753 struct ucm_value *v;
1754 struct list_head *pos;
1755 int err;
1756
1757 list_for_each(pos, source) {
1758 v = list_entry(pos, struct ucm_value, list);
1759 err = merge_value(list, v->name);
1760 if (err < 0)
1761 return err;
1762 }
1763 return 0;
1764 }
1765
1766 /**
1767 * \brief Find all values for given identifier
1768 * \param list Returned list
1769 * \param identifier Identifier
1770 * \param source Source list with ucm_value structures
1771 */
add_values(struct list_head * list,const char * identifier,struct list_head * source)1772 static int add_values(struct list_head *list,
1773 const char *identifier,
1774 struct list_head *source)
1775 {
1776 struct ucm_value *v;
1777 struct list_head *pos;
1778 int err;
1779
1780 list_for_each(pos, source) {
1781 v = list_entry(pos, struct ucm_value, list);
1782 if (check_identifier(identifier, v->name)) {
1783 err = merge_value(list, v->data);
1784 if (err < 0)
1785 return err;
1786 }
1787 }
1788 return 0;
1789 }
1790
1791 /**
1792 * \brief compare two identifiers
1793 */
identifier_cmp(const void * _a,const void * _b)1794 static int identifier_cmp(const void *_a, const void *_b)
1795 {
1796 const char * const *a = _a;
1797 const char * const *b = _b;
1798 return strcmp(*a, *b);
1799 }
1800
1801 /**
1802 * \brief Get list of available identifiers
1803 * \param list Returned list
1804 * \param name Name of verb or modifier to query
1805 * \return Number of list entries if success, otherwise a negative error code
1806 */
get_identifiers_list(snd_use_case_mgr_t * uc_mgr,const char ** list[],char * name)1807 static int get_identifiers_list(snd_use_case_mgr_t *uc_mgr,
1808 const char **list[], char *name)
1809 {
1810 struct use_case_verb *verb;
1811 struct use_case_modifier *modifier;
1812 struct use_case_device *device;
1813 struct list_head mylist;
1814 struct list_head *value_list;
1815 char *str, **res;
1816 int err;
1817
1818 if (!name)
1819 return -ENOENT;
1820
1821 str = strchr(name, '/');
1822 if (str) {
1823 *str = '\0';
1824 verb = find_verb(uc_mgr, str + 1);
1825 }
1826 else {
1827 verb = uc_mgr->active_verb;
1828 }
1829 if (!verb)
1830 return -ENOENT;
1831
1832 value_list = NULL;
1833 modifier = find_modifier(uc_mgr, verb, name, 0);
1834 if (modifier) {
1835 value_list = &modifier->value_list;
1836 } else {
1837 device = find_device(uc_mgr, verb, name, 0);
1838 if (device)
1839 value_list = &device->value_list;
1840 }
1841 if (value_list == NULL)
1842 return -ENOENT;
1843
1844 INIT_LIST_HEAD(&mylist);
1845 err = add_identifiers(&mylist, &uc_mgr->value_list);
1846 if (err < 0)
1847 goto __fail;
1848 err = add_identifiers(&mylist, &verb->value_list);
1849 if (err < 0)
1850 goto __fail;
1851 err = add_identifiers(&mylist, value_list);
1852 if (err < 0)
1853 goto __fail;
1854 err = myvalue_to_str_list(&mylist, &res);
1855 if (err > 0)
1856 *list = (const char **)res;
1857 else if (err == 0)
1858 *list = NULL;
1859 __fail:
1860 myvalue_list_free(&mylist);
1861 if (err <= 0)
1862 return err;
1863 qsort(*list, err, sizeof(char *), identifier_cmp);
1864 return err;
1865 }
1866
1867 /**
1868 * \brief Get list of values
1869 * \param list Returned list
1870 * \param verbname For verb (NULL = current)
1871 * \return Number of list entries if success, otherwise a negative error code
1872 */
get_value_list(snd_use_case_mgr_t * uc_mgr,const char * identifier,const char ** list[],char * verbname)1873 static int get_value_list(snd_use_case_mgr_t *uc_mgr,
1874 const char *identifier,
1875 const char **list[],
1876 char *verbname)
1877 {
1878 struct list_head mylist, *pos;
1879 struct use_case_verb *verb;
1880 struct use_case_device *dev;
1881 struct use_case_modifier *mod;
1882 char **res;
1883 int err;
1884
1885 if (verbname) {
1886 verb = find_verb(uc_mgr, verbname);
1887 } else {
1888 verb = uc_mgr->active_verb;
1889 }
1890 if (verb == NULL)
1891 return -ENOENT;
1892 INIT_LIST_HEAD(&mylist);
1893 err = add_values(&mylist, identifier, &uc_mgr->value_list);
1894 if (err < 0)
1895 goto __fail;
1896 err = add_values(&mylist, identifier, &verb->value_list);
1897 if (err < 0)
1898 goto __fail;
1899 list_for_each(pos, &verb->device_list) {
1900 dev = list_entry(pos, struct use_case_device, list);
1901 err = add_values(&mylist, identifier, &dev->value_list);
1902 if (err < 0)
1903 goto __fail;
1904 }
1905 list_for_each(pos, &verb->modifier_list) {
1906 mod = list_entry(pos, struct use_case_modifier, list);
1907 err = add_values(&mylist, identifier, &mod->value_list);
1908 if (err < 0)
1909 goto __fail;
1910 }
1911 err = myvalue_to_str_list(&mylist, &res);
1912 if (err > 0)
1913 *list = (const char **)res;
1914 else if (err == 0)
1915 *list = NULL;
1916 __fail:
1917 myvalue_list_free(&mylist);
1918 return err;
1919 }
1920
1921 /**
1922 * \brief Get list of enabled devices
1923 * \param list Returned list
1924 * \param verbname For verb (NULL = current)
1925 * \return Number of list entries if success, otherwise a negative error code
1926 */
get_enabled_device_list(snd_use_case_mgr_t * uc_mgr,const char ** list[])1927 static int get_enabled_device_list(snd_use_case_mgr_t *uc_mgr,
1928 const char **list[])
1929 {
1930 if (uc_mgr->active_verb == NULL)
1931 return -EINVAL;
1932 return get_list(&uc_mgr->active_devices, list,
1933 struct use_case_device, active_list,
1934 name);
1935 }
1936
1937 /**
1938 * \brief Get list of enabled modifiers
1939 * \param list Returned list
1940 * \param verbname For verb (NULL = current)
1941 * \return Number of list entries if success, otherwise a negative error code
1942 */
get_enabled_modifier_list(snd_use_case_mgr_t * uc_mgr,const char ** list[])1943 static int get_enabled_modifier_list(snd_use_case_mgr_t *uc_mgr,
1944 const char **list[])
1945 {
1946 if (uc_mgr->active_verb == NULL)
1947 return -EINVAL;
1948 return get_list(&uc_mgr->active_modifiers, list,
1949 struct use_case_modifier, active_list,
1950 name);
1951 }
1952
1953 /**
1954 * \brief Obtain a list of entries
1955 * \param uc_mgr Use case manager (may be NULL - card list)
1956 * \param identifier (may be NULL - card list)
1957 * \param list Returned allocated list
1958 * \return Number of list entries if success, otherwise a negative error code
1959 */
snd_use_case_get_list(snd_use_case_mgr_t * uc_mgr,const char * identifier,const char ** list[])1960 int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr,
1961 const char *identifier,
1962 const char **list[])
1963 {
1964 char *str, *str1;
1965 int err;
1966
1967 if (uc_mgr == NULL || identifier == NULL)
1968 return uc_mgr_scan_master_configs(list);
1969 pthread_mutex_lock(&uc_mgr->mutex);
1970 if (strcmp(identifier, "_verbs") == 0)
1971 err = get_verb_list(uc_mgr, list);
1972 else if (strcmp(identifier, "_enadevs") == 0)
1973 err = get_enabled_device_list(uc_mgr, list);
1974 else if (strcmp(identifier, "_enamods") == 0)
1975 err = get_enabled_modifier_list(uc_mgr, list);
1976 else {
1977 str1 = strchr(identifier, '/');
1978 if (str1) {
1979 str = strdup(str1 + 1);
1980 if (str == NULL) {
1981 err = -ENOMEM;
1982 goto __end;
1983 }
1984 } else {
1985 str = NULL;
1986 }
1987 if (check_identifier(identifier, "_devices"))
1988 err = get_device_list(uc_mgr, list, str);
1989 else if (check_identifier(identifier, "_modifiers"))
1990 err = get_modifier_list(uc_mgr, list, str);
1991 else if (check_identifier(identifier, "_identifiers"))
1992 err = get_identifiers_list(uc_mgr, list, str);
1993 else if (check_identifier(identifier, "_supporteddevs"))
1994 err = get_supported_device_list(uc_mgr, list, str);
1995 else if (check_identifier(identifier, "_conflictingdevs"))
1996 err = get_conflicting_device_list(uc_mgr, list, str);
1997 else if (identifier[0] == '_')
1998 err = -ENOENT;
1999 else
2000 err = get_value_list(uc_mgr, identifier, list, str);
2001 if (str)
2002 free(str);
2003 }
2004 __end:
2005 pthread_mutex_unlock(&uc_mgr->mutex);
2006 return err;
2007 }
2008
get_value1(snd_use_case_mgr_t * uc_mgr,char ** value,struct list_head * value_list,const char * identifier)2009 static int get_value1(snd_use_case_mgr_t *uc_mgr, char **value,
2010 struct list_head *value_list, const char *identifier)
2011 {
2012 struct ucm_value *val;
2013 struct list_head *pos;
2014 int err;
2015
2016 if (!value_list)
2017 return -ENOENT;
2018
2019 list_for_each(pos, value_list) {
2020 val = list_entry(pos, struct ucm_value, list);
2021 if (check_identifier(identifier, val->name)) {
2022 if (uc_mgr->conf_format < 2) {
2023 *value = strdup(val->data);
2024 if (*value == NULL)
2025 return -ENOMEM;
2026 return 0;
2027 }
2028 err = uc_mgr_get_substituted_value(uc_mgr, value, val->data);
2029 if (err < 0)
2030 return err;
2031 return rewrite_device_value(uc_mgr, val->name, value);
2032 }
2033 }
2034 return -ENOENT;
2035 }
2036
get_value3(snd_use_case_mgr_t * uc_mgr,char ** value,const char * identifier,struct list_head * value_list1,struct list_head * value_list2,struct list_head * value_list3)2037 static int get_value3(snd_use_case_mgr_t *uc_mgr,
2038 char **value,
2039 const char *identifier,
2040 struct list_head *value_list1,
2041 struct list_head *value_list2,
2042 struct list_head *value_list3)
2043 {
2044 int err;
2045
2046 err = get_value1(uc_mgr, value, value_list1, identifier);
2047 if (err >= 0 || err != -ENOENT)
2048 return err;
2049 err = get_value1(uc_mgr, value, value_list2, identifier);
2050 if (err >= 0 || err != -ENOENT)
2051 return err;
2052 err = get_value1(uc_mgr, value, value_list3, identifier);
2053 if (err >= 0 || err != -ENOENT)
2054 return err;
2055 return -ENOENT;
2056 }
2057
2058 /**
2059 * \brief Get value
2060 * \param uc_mgr Use case manager
2061 * \param identifier Value identifier (string)
2062 * \param value Returned value string
2063 * \param item Modifier or Device name (string)
2064 * \return Zero on success (value is filled), otherwise a negative error code
2065 */
get_value(snd_use_case_mgr_t * uc_mgr,const char * identifier,char ** value,const char * mod_dev_name,const char * verb_name,int exact)2066 static int get_value(snd_use_case_mgr_t *uc_mgr,
2067 const char *identifier,
2068 char **value,
2069 const char *mod_dev_name,
2070 const char *verb_name,
2071 int exact)
2072 {
2073 struct use_case_verb *verb;
2074 struct use_case_modifier *mod;
2075 struct use_case_device *dev;
2076 int err;
2077
2078 if (mod_dev_name || verb_name || !exact) {
2079 if (verb_name && strlen(verb_name)) {
2080 verb = find_verb(uc_mgr, verb_name);
2081 } else {
2082 verb = uc_mgr->active_verb;
2083 }
2084 if (verb) {
2085 if (mod_dev_name) {
2086 mod = find_modifier(uc_mgr, verb,
2087 mod_dev_name, 0);
2088 if (mod) {
2089 err = get_value1(uc_mgr, value,
2090 &mod->value_list,
2091 identifier);
2092 if (err >= 0 || err != -ENOENT)
2093 return err;
2094 }
2095
2096 dev = find_device(uc_mgr, verb,
2097 mod_dev_name, 0);
2098 if (dev) {
2099 err = get_value1(uc_mgr, value,
2100 &dev->value_list,
2101 identifier);
2102 if (err >= 0 || err != -ENOENT)
2103 return err;
2104 }
2105
2106 if (exact)
2107 return -ENOENT;
2108 }
2109
2110 err = get_value1(uc_mgr, value, &verb->value_list, identifier);
2111 if (err >= 0 || err != -ENOENT)
2112 return err;
2113 }
2114
2115 if (exact)
2116 return -ENOENT;
2117 }
2118
2119 err = get_value1(uc_mgr, value, &uc_mgr->value_list, identifier);
2120 if (err >= 0 || err != -ENOENT)
2121 return err;
2122
2123 return -ENOENT;
2124 }
2125
2126 /**
2127 * \brief Get private alsa-lib configuration (ASCII)
2128 * \param uc_mgr Use case manager
2129 * \param str Returned value string
2130 * \return Zero on success (value is filled), otherwise a negative error code
2131 */
get_alibcfg(snd_use_case_mgr_t * uc_mgr,char ** str)2132 static int get_alibcfg(snd_use_case_mgr_t *uc_mgr, char **str)
2133 {
2134 snd_output_t *out;
2135 size_t size;
2136 int err;
2137
2138 err = snd_output_buffer_open(&out);
2139 if (err < 0)
2140 return err;
2141 err = snd_config_save(uc_mgr->local_config, out);
2142 if (err >= 0) {
2143 size = snd_output_buffer_steal(out, str);
2144 if (*str)
2145 (*str)[size] = '\0';
2146 }
2147 snd_output_close(out);
2148 return 0;
2149 }
2150
2151 /**
2152 * \brief Get device prefix for private alsa-lib configuration
2153 * \param uc_mgr Use case manager
2154 * \param str Returned value string
2155 * \return Zero on success (value is filled), otherwise a negative error code
2156 */
get_alibpref(snd_use_case_mgr_t * uc_mgr,char ** str)2157 static int get_alibpref(snd_use_case_mgr_t *uc_mgr, char **str)
2158 {
2159 const size_t l = 10;
2160 char *s;
2161
2162 s = malloc(l);
2163 if (s == NULL)
2164 return -ENOMEM;
2165 snprintf(s, l, "_ucm%04X.", uc_mgr->ucm_card_number);
2166 *str = s;
2167 return 0;
2168 }
2169
2170 /**
2171 * \brief Get current - string
2172 * \param uc_mgr Use case manager
2173 * \param identifier
2174 * \param value Value pointer
2175 * \return Zero if success, otherwise a negative error code
2176 *
2177 * Note: String is dynamically allocated, use free() to
2178 * deallocate this string.
2179 */
snd_use_case_get(snd_use_case_mgr_t * uc_mgr,const char * identifier,const char ** value)2180 int snd_use_case_get(snd_use_case_mgr_t *uc_mgr,
2181 const char *identifier,
2182 const char **value)
2183 {
2184 const char *slash1, *slash2, *mod_dev_after;
2185 const char *ident, *mod_dev, *verb;
2186 int exact = 0;
2187 int err;
2188
2189 pthread_mutex_lock(&uc_mgr->mutex);
2190 if (identifier == NULL) {
2191 *value = strdup(uc_mgr->card_name);
2192 if (*value == NULL) {
2193 err = -ENOMEM;
2194 goto __end;
2195 }
2196 err = 0;
2197 } else if (strcmp(identifier, "_verb") == 0) {
2198 if (uc_mgr->active_verb == NULL) {
2199 err = -ENOENT;
2200 goto __end;
2201 }
2202 *value = strdup(uc_mgr->active_verb->name);
2203 if (*value == NULL) {
2204 err = -ENOMEM;
2205 goto __end;
2206 }
2207 err = 0;
2208 } else if (strcmp(identifier, "_file") == 0) {
2209 /* get the conf file name of the opened card */
2210 if ((uc_mgr->card_name == NULL) ||
2211 (uc_mgr->conf_file_name == NULL) ||
2212 (uc_mgr->conf_file_name[0] == '\0')) {
2213 err = -ENOENT;
2214 goto __end;
2215 }
2216 *value = strdup(uc_mgr->conf_file_name);
2217 if (*value == NULL) {
2218 err = -ENOMEM;
2219 goto __end;
2220 }
2221 err = 0;
2222
2223 } else if (strcmp(identifier, "_alibcfg") == 0) {
2224 err = get_alibcfg(uc_mgr, (char **)value);
2225 } else if (strcmp(identifier, "_alibpref") == 0) {
2226 err = get_alibpref(uc_mgr, (char **)value);
2227 } else if (identifier[0] == '_') {
2228 err = -ENOENT;
2229 } else {
2230 if (identifier[0] == '=') {
2231 exact = 1;
2232 identifier++;
2233 }
2234
2235 slash1 = strchr(identifier, '/');
2236 if (slash1) {
2237 ident = strndup(identifier, slash1 - identifier);
2238
2239 slash2 = strchr(slash1 + 1, '/');
2240 if (slash2) {
2241 mod_dev_after = slash2;
2242 verb = slash2 + 1;
2243 }
2244 else {
2245 mod_dev_after = slash1 + strlen(slash1);
2246 verb = NULL;
2247 }
2248
2249 if (mod_dev_after == slash1 + 1)
2250 mod_dev = NULL;
2251 else
2252 mod_dev = strndup(slash1 + 1,
2253 mod_dev_after - (slash1 + 1));
2254 }
2255 else {
2256 ident = identifier;
2257 mod_dev = NULL;
2258 verb = NULL;
2259 }
2260
2261 err = get_value(uc_mgr, ident, (char **)value, mod_dev, verb,
2262 exact);
2263 if (ident != identifier)
2264 free((void *)ident);
2265 if (mod_dev)
2266 free((void *)mod_dev);
2267 }
2268 __end:
2269 pthread_mutex_unlock(&uc_mgr->mutex);
2270 return err;
2271 }
2272
2273
2274 /**
2275 * \brief Get current - integer
2276 * \param uc_mgr Use case manager
2277 * \param identifier
2278 * \return Value if success, otherwise a negative error code
2279 */
snd_use_case_geti(snd_use_case_mgr_t * uc_mgr,const char * identifier,long * value)2280 int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr,
2281 const char *identifier,
2282 long *value)
2283 {
2284 char *str, *str1;
2285 long err;
2286
2287 pthread_mutex_lock(&uc_mgr->mutex);
2288 if (0) {
2289 /* nothing here - prepared for fixed identifiers */
2290 } else {
2291 str1 = strchr(identifier, '/');
2292 if (str1) {
2293 str = strdup(str1 + 1);
2294 if (str == NULL) {
2295 err = -ENOMEM;
2296 goto __end;
2297 }
2298 } else {
2299 str = NULL;
2300 }
2301 if (check_identifier(identifier, "_devstatus")) {
2302 if (!str) {
2303 err = -EINVAL;
2304 goto __end;
2305 }
2306 err = device_status(uc_mgr, str);
2307 if (err >= 0) {
2308 *value = err;
2309 err = 0;
2310 }
2311 } else if (check_identifier(identifier, "_modstatus")) {
2312 if (!str) {
2313 err = -EINVAL;
2314 goto __end;
2315 }
2316 err = modifier_status(uc_mgr, str);
2317 if (err >= 0) {
2318 *value = err;
2319 err = 0;
2320 }
2321 #if 0
2322 /*
2323 * enable this block if the else clause below is expanded to query
2324 * user-supplied values
2325 */
2326 } else if (identifier[0] == '_')
2327 err = -ENOENT;
2328 #endif
2329 } else
2330 err = -ENOENT;
2331 if (str)
2332 free(str);
2333 }
2334 __end:
2335 pthread_mutex_unlock(&uc_mgr->mutex);
2336 return err;
2337 }
2338
set_fixedboot_user(snd_use_case_mgr_t * uc_mgr,const char * value)2339 static int set_fixedboot_user(snd_use_case_mgr_t *uc_mgr,
2340 const char *value)
2341 {
2342 int err;
2343
2344 if (value != NULL && *value) {
2345 uc_error("error: wrong value for _fboot (%s)", value);
2346 return -EINVAL;
2347 }
2348 if (list_empty(&uc_mgr->fixedboot_list))
2349 return -ENOENT;
2350 err = execute_sequence(uc_mgr, &uc_mgr->fixedboot_list,
2351 &uc_mgr->value_list, NULL, NULL);
2352 if (err < 0) {
2353 uc_error("Unable to execute force boot sequence");
2354 return err;
2355 }
2356 return err;
2357 }
2358
set_boot_user(snd_use_case_mgr_t * uc_mgr,const char * value)2359 static int set_boot_user(snd_use_case_mgr_t *uc_mgr,
2360 const char *value)
2361 {
2362 int err;
2363
2364 if (value != NULL && *value) {
2365 uc_error("error: wrong value for _boot (%s)", value);
2366 return -EINVAL;
2367 }
2368 if (list_empty(&uc_mgr->boot_list))
2369 return -ENOENT;
2370 err = execute_sequence(uc_mgr, &uc_mgr->boot_list,
2371 &uc_mgr->value_list, NULL, NULL);
2372 if (err < 0) {
2373 uc_error("Unable to execute boot sequence");
2374 return err;
2375 }
2376 return err;
2377 }
2378
set_defaults_user(snd_use_case_mgr_t * uc_mgr,const char * value)2379 static int set_defaults_user(snd_use_case_mgr_t *uc_mgr,
2380 const char *value)
2381 {
2382 if (value != NULL && *value) {
2383 uc_error("error: wrong value for _defaults (%s)", value);
2384 return -EINVAL;
2385 }
2386 return set_defaults(uc_mgr);
2387 }
2388
handle_transition_verb(snd_use_case_mgr_t * uc_mgr,struct use_case_verb * new_verb)2389 static int handle_transition_verb(snd_use_case_mgr_t *uc_mgr,
2390 struct use_case_verb *new_verb)
2391 {
2392 struct list_head *pos;
2393 struct transition_sequence *trans;
2394 int err;
2395
2396 list_for_each(pos, &uc_mgr->active_verb->transition_list) {
2397 trans = list_entry(pos, struct transition_sequence, list);
2398 if (strcmp(trans->name, new_verb->name) == 0) {
2399 err = execute_sequence(uc_mgr, &trans->transition_list,
2400 &uc_mgr->active_verb->value_list,
2401 &uc_mgr->value_list,
2402 NULL);
2403 if (err >= 0)
2404 return 1;
2405 return err;
2406 }
2407 }
2408 return 0;
2409 }
2410
set_verb_user(snd_use_case_mgr_t * uc_mgr,const char * verb_name)2411 static int set_verb_user(snd_use_case_mgr_t *uc_mgr,
2412 const char *verb_name)
2413 {
2414 struct use_case_verb *verb;
2415 int err = 0;
2416
2417 if (uc_mgr->active_verb &&
2418 strcmp(uc_mgr->active_verb->name, verb_name) == 0)
2419 return 0;
2420 if (strcmp(verb_name, SND_USE_CASE_VERB_INACTIVE) != 0) {
2421 verb = find_verb(uc_mgr, verb_name);
2422 if (verb == NULL)
2423 return -ENOENT;
2424 } else {
2425 verb = NULL;
2426 }
2427 if (uc_mgr->active_verb) {
2428 err = handle_transition_verb(uc_mgr, verb);
2429 if (err == 0) {
2430 err = dismantle_use_case(uc_mgr);
2431 if (err < 0)
2432 return err;
2433 } else if (err == 1) {
2434 uc_mgr->active_verb = verb;
2435 verb = NULL;
2436 } else {
2437 verb = NULL; /* show error */
2438 }
2439 }
2440 if (verb) {
2441 err = set_verb(uc_mgr, verb, 1);
2442 if (err < 0)
2443 uc_error("error: failed to initialize new use case: %s",
2444 verb_name);
2445 }
2446 return err;
2447 }
2448
2449
set_device_user(snd_use_case_mgr_t * uc_mgr,const char * device_name,int enable)2450 static int set_device_user(snd_use_case_mgr_t *uc_mgr,
2451 const char *device_name,
2452 int enable)
2453 {
2454 struct use_case_device *device;
2455
2456 if (uc_mgr->active_verb == NULL)
2457 return -ENOENT;
2458 device = find_device(uc_mgr, uc_mgr->active_verb, device_name, 1);
2459 if (device == NULL)
2460 return -ENOENT;
2461 return set_device(uc_mgr, device, enable);
2462 }
2463
set_modifier_user(snd_use_case_mgr_t * uc_mgr,const char * modifier_name,int enable)2464 static int set_modifier_user(snd_use_case_mgr_t *uc_mgr,
2465 const char *modifier_name,
2466 int enable)
2467 {
2468 struct use_case_modifier *modifier;
2469
2470 if (uc_mgr->active_verb == NULL)
2471 return -ENOENT;
2472
2473 modifier = find_modifier(uc_mgr, uc_mgr->active_verb, modifier_name, 1);
2474 if (modifier == NULL)
2475 return -ENOENT;
2476 return set_modifier(uc_mgr, modifier, enable);
2477 }
2478
switch_device(snd_use_case_mgr_t * uc_mgr,const char * old_device,const char * new_device)2479 static int switch_device(snd_use_case_mgr_t *uc_mgr,
2480 const char *old_device,
2481 const char *new_device)
2482 {
2483 struct use_case_device *xold, *xnew;
2484 struct transition_sequence *trans;
2485 struct list_head *pos;
2486 int err, seq_found = 0;
2487
2488 if (uc_mgr->active_verb == NULL)
2489 return -ENOENT;
2490 if (device_status(uc_mgr, old_device) == 0) {
2491 uc_error("error: device %s not enabled", old_device);
2492 return -EINVAL;
2493 }
2494 if (device_status(uc_mgr, new_device) != 0) {
2495 uc_error("error: device %s already enabled", new_device);
2496 return -EINVAL;
2497 }
2498 xold = find_device(uc_mgr, uc_mgr->active_verb, old_device, 1);
2499 if (xold == NULL)
2500 return -ENOENT;
2501 list_del(&xold->active_list);
2502 xnew = find_device(uc_mgr, uc_mgr->active_verb, new_device, 1);
2503 list_add_tail(&xold->active_list, &uc_mgr->active_devices);
2504 if (xnew == NULL)
2505 return -ENOENT;
2506 err = 0;
2507 list_for_each(pos, &xold->transition_list) {
2508 trans = list_entry(pos, struct transition_sequence, list);
2509 if (strcmp(trans->name, new_device) == 0) {
2510 err = execute_sequence(uc_mgr, &trans->transition_list,
2511 &xold->value_list,
2512 &uc_mgr->active_verb->value_list,
2513 &uc_mgr->value_list);
2514 if (err >= 0) {
2515 list_del(&xold->active_list);
2516 list_add_tail(&xnew->active_list, &uc_mgr->active_devices);
2517 }
2518 seq_found = 1;
2519 break;
2520 }
2521 }
2522 if (!seq_found) {
2523 err = set_device(uc_mgr, xold, 0);
2524 if (err < 0)
2525 return err;
2526 err = set_device(uc_mgr, xnew, 1);
2527 if (err < 0)
2528 return err;
2529 }
2530 return err;
2531 }
2532
switch_modifier(snd_use_case_mgr_t * uc_mgr,const char * old_modifier,const char * new_modifier)2533 static int switch_modifier(snd_use_case_mgr_t *uc_mgr,
2534 const char *old_modifier,
2535 const char *new_modifier)
2536 {
2537 struct use_case_modifier *xold, *xnew;
2538 struct transition_sequence *trans;
2539 struct list_head *pos;
2540 int err, seq_found = 0;
2541
2542 if (uc_mgr->active_verb == NULL)
2543 return -ENOENT;
2544 if (modifier_status(uc_mgr, old_modifier) == 0) {
2545 uc_error("error: modifier %s not enabled", old_modifier);
2546 return -EINVAL;
2547 }
2548 if (modifier_status(uc_mgr, new_modifier) != 0) {
2549 uc_error("error: modifier %s already enabled", new_modifier);
2550 return -EINVAL;
2551 }
2552 xold = find_modifier(uc_mgr, uc_mgr->active_verb, old_modifier, 1);
2553 if (xold == NULL)
2554 return -ENOENT;
2555 xnew = find_modifier(uc_mgr, uc_mgr->active_verb, new_modifier, 1);
2556 if (xnew == NULL)
2557 return -ENOENT;
2558 err = 0;
2559 list_for_each(pos, &xold->transition_list) {
2560 trans = list_entry(pos, struct transition_sequence, list);
2561 if (strcmp(trans->name, new_modifier) == 0) {
2562 err = execute_sequence(uc_mgr, &trans->transition_list,
2563 &xold->value_list,
2564 &uc_mgr->active_verb->value_list,
2565 &uc_mgr->value_list);
2566 if (err >= 0) {
2567 list_del(&xold->active_list);
2568 list_add_tail(&xnew->active_list, &uc_mgr->active_modifiers);
2569 }
2570 seq_found = 1;
2571 break;
2572 }
2573 }
2574 if (!seq_found) {
2575 err = set_modifier(uc_mgr, xold, 0);
2576 if (err < 0)
2577 return err;
2578 err = set_modifier(uc_mgr, xnew, 1);
2579 if (err < 0)
2580 return err;
2581 }
2582 return err;
2583 }
2584
2585 /**
2586 * \brief Set new
2587 * \param uc_mgr Use case manager
2588 * \param identifier
2589 * \param value Value
2590 * \return Zero if success, otherwise a negative error code
2591 */
snd_use_case_set(snd_use_case_mgr_t * uc_mgr,const char * identifier,const char * value)2592 int snd_use_case_set(snd_use_case_mgr_t *uc_mgr,
2593 const char *identifier,
2594 const char *value)
2595 {
2596 char *str, *str1;
2597 int err = 0;
2598
2599 pthread_mutex_lock(&uc_mgr->mutex);
2600 if (strcmp(identifier, "_fboot") == 0)
2601 err = set_fixedboot_user(uc_mgr, value);
2602 else if (strcmp(identifier, "_boot") == 0)
2603 err = set_boot_user(uc_mgr, value);
2604 else if (strcmp(identifier, "_defaults") == 0)
2605 err = set_defaults_user(uc_mgr, value);
2606 else if (strcmp(identifier, "_verb") == 0)
2607 err = set_verb_user(uc_mgr, value);
2608 else if (strcmp(identifier, "_enadev") == 0)
2609 err = set_device_user(uc_mgr, value, 1);
2610 else if (strcmp(identifier, "_disdev") == 0)
2611 err = set_device_user(uc_mgr, value, 0);
2612 else if (strcmp(identifier, "_enamod") == 0)
2613 err = set_modifier_user(uc_mgr, value, 1);
2614 else if (strcmp(identifier, "_dismod") == 0)
2615 err = set_modifier_user(uc_mgr, value, 0);
2616 else {
2617 str1 = strchr(identifier, '/');
2618 if (str1) {
2619 str = strdup(str1 + 1);
2620 if (str == NULL) {
2621 err = -ENOMEM;
2622 goto __end;
2623 }
2624 } else {
2625 err = -EINVAL;
2626 goto __end;
2627 }
2628 if (check_identifier(identifier, "_swdev"))
2629 err = switch_device(uc_mgr, str, value);
2630 else if (check_identifier(identifier, "_swmod"))
2631 err = switch_modifier(uc_mgr, str, value);
2632 else
2633 err = -EINVAL;
2634 if (str)
2635 free(str);
2636 }
2637 __end:
2638 pthread_mutex_unlock(&uc_mgr->mutex);
2639 return err;
2640 }
2641
2642 /**
2643 * \brief Parse control element identifier
2644 * \param elem_id Element identifier
2645 * \param ucm_id Use case identifier
2646 * \param value String value to be parsed
2647 * \return Zero if success, otherwise a negative error code
2648 */
snd_use_case_parse_ctl_elem_id(snd_ctl_elem_id_t * dst,const char * ucm_id,const char * value)2649 int snd_use_case_parse_ctl_elem_id(snd_ctl_elem_id_t *dst,
2650 const char *ucm_id,
2651 const char *value)
2652 {
2653 snd_ctl_elem_iface_t iface;
2654 int jack_control;
2655
2656 jack_control = strcmp(ucm_id, "JackControl") == 0;
2657 if (!jack_control &&
2658 strcmp(ucm_id, "PlaybackVolume") &&
2659 strcmp(ucm_id, "PlaybackSwitch") &&
2660 strcmp(ucm_id, "CaptureVolume") &&
2661 strcmp(ucm_id, "CaptureSwitch"))
2662 return -EINVAL;
2663 snd_ctl_elem_id_clear(dst);
2664 if (strcasestr(ucm_id, "name="))
2665 return __snd_ctl_ascii_elem_id_parse(dst, value, NULL);
2666 iface = SND_CTL_ELEM_IFACE_MIXER;
2667 if (jack_control)
2668 iface = SND_CTL_ELEM_IFACE_CARD;
2669 snd_ctl_elem_id_set_interface(dst, iface);
2670 snd_ctl_elem_id_set_name(dst, value);
2671 return 0;
2672 }
2673
2674 /**
2675 * \brief Parse mixer element identifier
2676 * \param dst Simple mixer element identifier
2677 * \param ucm_id Use case identifier
2678 * \param value String value to be parsed
2679 * \return Zero if success, otherwise a negative error code
2680 */
snd_use_case_parse_selem_id(snd_mixer_selem_id_t * dst,const char * ucm_id,const char * value)2681 int snd_use_case_parse_selem_id(snd_mixer_selem_id_t *dst,
2682 const char *ucm_id,
2683 const char *value)
2684 {
2685 #ifdef BUILD_MIXER
2686 if (strcmp(ucm_id, "PlaybackMixerId") == 0 ||
2687 strcmp(ucm_id, "CaptureMixerId") == 0)
2688 return snd_mixer_selem_id_parse(dst, value);
2689 #endif
2690 return -EINVAL;
2691 }
2692