1 /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
6 #include <alsa/asoundlib.h>
7 #include <alsa/use-case.h>
8 #include <ctype.h>
9 #include <string.h>
10 #include <syslog.h>
11
12 #include "cras_alsa_ucm.h"
13 #include "cras_util.h"
14 #include "utlist.h"
15
16 static const char jack_var[] = "JackName";
17 static const char jack_type_var[] = "JackType";
18 static const char jack_switch_var[] = "JackSwitch";
19 static const char edid_var[] = "EDIDFile";
20 static const char cap_var[] = "CaptureControl";
21 static const char mic_positions[] = "MicPositions";
22 static const char override_type_name_var[] = "OverrideNodeType";
23 static const char output_dsp_name_var[] = "OutputDspName";
24 static const char input_dsp_name_var[] = "InputDspName";
25 static const char mixer_var[] = "MixerName";
26 static const char swap_mode_suffix[] = "Swap Mode";
27 static const char min_buffer_level_var[] = "MinBufferLevel";
28 static const char dma_period_var[] = "DmaPeriodMicrosecs";
29 static const char disable_software_volume[] = "DisableSoftwareVolume";
30 static const char playback_device_name_var[] = "PlaybackPCM";
31 static const char playback_device_rate_var[] = "PlaybackRate";
32 static const char capture_device_name_var[] = "CapturePCM";
33 static const char capture_device_rate_var[] = "CaptureRate";
34 static const char capture_channel_map_var[] = "CaptureChannelMap";
35 static const char coupled_mixers[] = "CoupledMixers";
36 static const char preempt_hotword_var[] = "PreemptHotword";
37 static const char echo_reference_dev_name_var[] = "EchoReferenceDev";
38 /*
39 * Set this value in a SectionDevice to specify the minimum software gain in
40 * 0.01 dB and enable software gain on this node. It must be used with
41 * MaxSoftwareGain. If not, the value will be ignored.
42 */
43 static const char min_software_gain[] = "MinSoftwareGain";
44 /*
45 * Set this value in a SectionDevice to specify the maximum software gain in
46 * 0.01 dB and enable software gain on this node.
47 */
48 static const char max_software_gain[] = "MaxSoftwareGain";
49 /*
50 * Set this value in a SectionDevice to specify the default node gain in
51 * 0.01 dB.
52 */
53 static const char default_node_gain[] = "DefaultNodeGain";
54 static const char hotword_model_prefix[] = "Hotword Model";
55 static const char fully_specified_ucm_var[] = "FullySpecifiedUCM";
56 static const char main_volume_names[] = "MainVolumeNames";
57 static const char enable_htimestamp_var[] = "EnableHtimestamp";
58
59 /* Use case verbs corresponding to CRAS_STREAM_TYPE. */
60 static const char *use_case_verbs[] = {
61 "HiFi",
62 "Multimedia",
63 "Voice Call",
64 "Speech",
65 "Pro Audio",
66 "Accessibility",
67 };
68
69 /* Represents a list of section names found in UCM. */
70 struct section_name {
71 const char* name;
72 struct section_name *prev, *next;
73 };
74
75 struct cras_use_case_mgr {
76 snd_use_case_mgr_t *mgr;
77 const char *name;
78 unsigned int avail_use_cases;
79 enum CRAS_STREAM_TYPE use_case;
80 };
81
uc_verb(struct cras_use_case_mgr * mgr)82 static inline const char *uc_verb(struct cras_use_case_mgr *mgr)
83 {
84 return use_case_verbs[mgr->use_case];
85 }
86
device_enabled(struct cras_use_case_mgr * mgr,const char * dev)87 static int device_enabled(struct cras_use_case_mgr *mgr, const char *dev)
88 {
89 const char **list;
90 unsigned int i;
91 int num_devs;
92 int enabled = 0;
93
94 num_devs = snd_use_case_get_list(mgr->mgr, "_enadevs", &list);
95 if (num_devs <= 0)
96 return 0;
97
98 for (i = 0; i < (unsigned int)num_devs; i++)
99 if (!strcmp(dev, list[i])) {
100 enabled = 1;
101 break;
102 }
103
104 snd_use_case_free_list(list, num_devs);
105 return enabled;
106 }
107
modifier_enabled(struct cras_use_case_mgr * mgr,const char * mod)108 static int modifier_enabled(struct cras_use_case_mgr *mgr, const char *mod)
109 {
110 const char **list;
111 unsigned int mod_idx;
112 int num_mods;
113
114 num_mods = snd_use_case_get_list(mgr->mgr, "_enamods", &list);
115 if (num_mods <= 0)
116 return 0;
117
118 for (mod_idx = 0; mod_idx < (unsigned int)num_mods; mod_idx++)
119 if (!strcmp(mod, list[mod_idx]))
120 break;
121
122 snd_use_case_free_list(list, num_mods);
123 return (mod_idx < (unsigned int)num_mods);
124 }
125
get_var(struct cras_use_case_mgr * mgr,const char * var,const char * dev,const char * verb,const char ** value)126 static int get_var(struct cras_use_case_mgr *mgr, const char *var,
127 const char *dev, const char *verb, const char **value)
128 {
129 char *id;
130 int rc;
131 size_t len = strlen(var) + strlen(dev) + strlen(verb) + 4;
132
133 id = (char *)malloc(len);
134 if (!id)
135 return -ENOMEM;
136 snprintf(id, len, "=%s/%s/%s", var, dev, verb);
137 rc = snd_use_case_get(mgr->mgr, id, value);
138
139 free((void *)id);
140 return rc;
141 }
142
get_int(struct cras_use_case_mgr * mgr,const char * var,const char * dev,const char * verb,int * value)143 static int get_int(struct cras_use_case_mgr *mgr, const char *var,
144 const char *dev, const char *verb, int *value)
145 {
146 const char *str_value;
147 int rc;
148
149 if (!value)
150 return -EINVAL;
151 rc = get_var(mgr, var, dev, verb, &str_value);
152 if (rc != 0)
153 return rc;
154 *value = atoi(str_value);
155 free((void *)str_value);
156 return 0;
157 }
158
ucm_set_modifier_enabled(struct cras_use_case_mgr * mgr,const char * mod,int enable)159 static int ucm_set_modifier_enabled(struct cras_use_case_mgr *mgr,
160 const char *mod, int enable)
161 {
162 return snd_use_case_set(mgr->mgr, enable ? "_enamod" : "_dismod", mod);
163 }
164
ucm_str_ends_with_suffix(const char * str,const char * suffix)165 static int ucm_str_ends_with_suffix(const char *str, const char *suffix)
166 {
167 if (!str || !suffix)
168 return 0;
169 size_t len_str = strlen(str);
170 size_t len_suffix = strlen(suffix);
171 if (len_suffix > len_str)
172 return 0;
173 return strncmp(str + len_str - len_suffix, suffix, len_suffix) == 0;
174 }
175
ucm_section_exists_with_name(struct cras_use_case_mgr * mgr,const char * name,const char * identifier)176 static int ucm_section_exists_with_name(struct cras_use_case_mgr *mgr,
177 const char *name, const char *identifier)
178 {
179 const char **list;
180 unsigned int i;
181 int num_entries;
182 int exist = 0;
183
184 num_entries = snd_use_case_get_list(mgr->mgr, identifier, &list);
185 if (num_entries <= 0)
186 return 0;
187
188 for (i = 0; i < (unsigned int)num_entries; i+=2) {
189
190 if (!list[i])
191 continue;
192
193 if (strcmp(list[i], name) == 0) {
194 exist = 1;
195 break;
196 }
197 }
198 snd_use_case_free_list(list, num_entries);
199 return exist;
200 }
201
ucm_section_exists_with_suffix(struct cras_use_case_mgr * mgr,const char * suffix,const char * identifier)202 static int ucm_section_exists_with_suffix(struct cras_use_case_mgr *mgr,
203 const char *suffix, const char *identifier)
204 {
205 const char **list;
206 unsigned int i;
207 int num_entries;
208 int exist = 0;
209
210 num_entries = snd_use_case_get_list(mgr->mgr, identifier, &list);
211 if (num_entries <= 0)
212 return 0;
213
214 for (i = 0; i < (unsigned int)num_entries; i+=2) {
215
216 if (!list[i])
217 continue;
218
219 if (ucm_str_ends_with_suffix(list[i], suffix)) {
220 exist = 1;
221 break;
222 }
223 }
224 snd_use_case_free_list(list, num_entries);
225 return exist;
226 }
227
ucm_mod_exists_with_suffix(struct cras_use_case_mgr * mgr,const char * suffix)228 static int ucm_mod_exists_with_suffix(struct cras_use_case_mgr *mgr,
229 const char *suffix)
230 {
231 char *identifier;
232 int rc;
233
234 identifier = snd_use_case_identifier("_modifiers/%s", uc_verb(mgr));
235 rc = ucm_section_exists_with_suffix(mgr, suffix, identifier);
236 free(identifier);
237 return rc;
238 }
239
ucm_mod_exists_with_name(struct cras_use_case_mgr * mgr,const char * name)240 static int ucm_mod_exists_with_name(struct cras_use_case_mgr *mgr,
241 const char *name)
242 {
243 char *identifier;
244 int rc;
245
246 identifier = snd_use_case_identifier("_modifiers/%s", uc_verb(mgr));
247 rc = ucm_section_exists_with_name(mgr, name, identifier);
248 free(identifier);
249 return rc;
250 }
251
252 /* Get a list of section names whose variable is the matched value. */
ucm_get_sections_for_var(struct cras_use_case_mgr * mgr,const char * var,const char * value,const char * identifier,enum CRAS_STREAM_DIRECTION direction)253 static struct section_name * ucm_get_sections_for_var(
254 struct cras_use_case_mgr *mgr,
255 const char *var, const char *value,
256 const char *identifier,
257 enum CRAS_STREAM_DIRECTION direction)
258 {
259 const char **list;
260 struct section_name *section_names = NULL, *s_name;
261 unsigned int i;
262 int num_entries;
263 int rc;
264
265 num_entries = snd_use_case_get_list(mgr->mgr, identifier, &list);
266 if (num_entries <= 0)
267 return NULL;
268
269 /* snd_use_case_get_list fills list with pairs of device name and
270 * comment, so device names are in even-indexed elements. */
271 for (i = 0; i < (unsigned int)num_entries; i+=2) {
272 const char *this_value;
273
274 if (!list[i])
275 continue;
276
277 rc = get_var(mgr, var, list[i], uc_verb(mgr), &this_value);
278 if (rc)
279 continue;
280
281 if (!strcmp(value, this_value)) {
282 s_name = (struct section_name *)malloc(
283 sizeof(struct section_name));
284
285 if (!s_name) {
286 syslog(LOG_ERR, "Failed to allocate memory");
287 free((void *)this_value);
288 break;
289 }
290
291 s_name->name = strdup(list[i]);
292 DL_APPEND(section_names, s_name);
293 }
294 free((void *)this_value);
295 }
296
297 snd_use_case_free_list(list, num_entries);
298 return section_names;
299 }
300
ucm_get_devices_for_var(struct cras_use_case_mgr * mgr,const char * var,const char * value,enum CRAS_STREAM_DIRECTION dir)301 static struct section_name *ucm_get_devices_for_var(
302 struct cras_use_case_mgr *mgr,
303 const char *var, const char *value,
304 enum CRAS_STREAM_DIRECTION dir)
305 {
306 char *identifier;
307 struct section_name *section_names;
308
309 identifier = snd_use_case_identifier("_devices/%s", uc_verb(mgr));
310 section_names = ucm_get_sections_for_var(mgr, var, value, identifier,
311 dir);
312 free(identifier);
313 return section_names;
314 }
315
ucm_get_playback_device_name_for_dev(struct cras_use_case_mgr * mgr,const char * dev)316 static const char *ucm_get_playback_device_name_for_dev(
317 struct cras_use_case_mgr *mgr, const char *dev)
318 {
319 const char *name = NULL;
320 int rc;
321
322 rc = get_var(mgr, playback_device_name_var, dev, uc_verb(mgr), &name);
323 if (rc)
324 return NULL;
325
326 return name;
327 }
328
ucm_get_capture_device_name_for_dev(struct cras_use_case_mgr * mgr,const char * dev)329 static const char *ucm_get_capture_device_name_for_dev(
330 struct cras_use_case_mgr *mgr, const char *dev)
331 {
332 const char *name = NULL;
333 int rc;
334
335 rc = get_var(mgr, capture_device_name_var, dev, uc_verb(mgr), &name);
336 if (rc)
337 return NULL;
338
339 return name;
340 }
341
342 /* Get a list of mixer names specified in a UCM variable separated by ",".
343 * E.g. "Left Playback,Right Playback".
344 */
ucm_get_mixer_names(struct cras_use_case_mgr * mgr,const char * dev,const char * var,enum CRAS_STREAM_DIRECTION dir,mixer_name_type type)345 static struct mixer_name *ucm_get_mixer_names(struct cras_use_case_mgr *mgr,
346 const char *dev, const char* var,
347 enum CRAS_STREAM_DIRECTION dir,
348 mixer_name_type type)
349 {
350 const char *names_in_string = NULL;
351 int rc;
352 char *tokens, *name;
353 char *laststr = NULL;
354 struct mixer_name *names = NULL;
355
356 rc = get_var(mgr, var, dev, uc_verb(mgr), &names_in_string);
357 if (rc)
358 return NULL;
359
360 tokens = strdup(names_in_string);
361 name = strtok_r(tokens, ",", &laststr);
362 while (name != NULL) {
363 names = mixer_name_add(names, name, dir, type);
364 name = strtok_r(NULL, ",", &laststr);
365 }
366 free((void*)names_in_string);
367 free(tokens);
368 return names;
369 }
370
371 /* Exported Interface */
372
ucm_create(const char * name)373 struct cras_use_case_mgr *ucm_create(const char *name)
374 {
375 struct cras_use_case_mgr *mgr;
376 int rc;
377 const char **list;
378 int num_verbs, i, j;
379
380 assert_on_compile(ARRAY_SIZE(use_case_verbs) == CRAS_STREAM_NUM_TYPES);
381
382 if (!name)
383 return NULL;
384
385 mgr = (struct cras_use_case_mgr *)malloc(sizeof(*mgr));
386 if (!mgr)
387 return NULL;
388
389 rc = snd_use_case_mgr_open(&mgr->mgr, name);
390 if (rc) {
391 syslog(LOG_WARNING, "Can not open ucm for card %s, rc = %d",
392 name, rc);
393 goto cleanup;
394 }
395
396 mgr->name = name;
397 mgr->avail_use_cases = 0;
398 num_verbs = snd_use_case_get_list(mgr->mgr, "_verbs", &list);
399 for (i = 0; i < num_verbs; i += 2) {
400 for (j = 0; j < CRAS_STREAM_NUM_TYPES; ++j) {
401 if (strcmp(list[i], use_case_verbs[j]) == 0)
402 break;
403 }
404 if (j < CRAS_STREAM_NUM_TYPES)
405 mgr->avail_use_cases |= (1 << j);
406 }
407 if (num_verbs > 0)
408 snd_use_case_free_list(list, num_verbs);
409
410 rc = ucm_set_use_case(mgr, CRAS_STREAM_TYPE_DEFAULT);
411 if (rc)
412 goto cleanup_mgr;
413
414 return mgr;
415
416 cleanup_mgr:
417 snd_use_case_mgr_close(mgr->mgr);
418 cleanup:
419 free(mgr);
420 return NULL;
421 }
422
ucm_destroy(struct cras_use_case_mgr * mgr)423 void ucm_destroy(struct cras_use_case_mgr *mgr)
424 {
425 snd_use_case_mgr_close(mgr->mgr);
426 free(mgr);
427 }
428
ucm_set_use_case(struct cras_use_case_mgr * mgr,enum CRAS_STREAM_TYPE use_case)429 int ucm_set_use_case(struct cras_use_case_mgr *mgr,
430 enum CRAS_STREAM_TYPE use_case)
431 {
432 int rc;
433
434 if (mgr->avail_use_cases & (1 << use_case)) {
435 mgr->use_case = use_case;
436 } else {
437 syslog(LOG_ERR, "Unavailable use case %d for card %s",
438 use_case, mgr->name);
439 return -1;
440 }
441
442 rc = snd_use_case_set(mgr->mgr, "_verb", uc_verb(mgr));
443 if (rc) {
444 syslog(LOG_ERR, "Can not set verb %s for card %s, rc = %d",
445 uc_verb(mgr), mgr->name, rc);
446 return rc;
447 }
448
449 return 0;
450 }
451
ucm_swap_mode_exists(struct cras_use_case_mgr * mgr)452 int ucm_swap_mode_exists(struct cras_use_case_mgr *mgr)
453 {
454 return ucm_mod_exists_with_suffix(mgr, swap_mode_suffix);
455 }
456
ucm_enable_swap_mode(struct cras_use_case_mgr * mgr,const char * node_name,int enable)457 int ucm_enable_swap_mode(struct cras_use_case_mgr *mgr, const char *node_name,
458 int enable)
459 {
460 char *swap_mod = NULL;
461 int rc;
462 size_t len = strlen(node_name) + 1 + strlen(swap_mode_suffix) + 1;
463 swap_mod = (char *)malloc(len);
464 if (!swap_mod)
465 return -ENOMEM;
466 snprintf(swap_mod, len, "%s %s", node_name, swap_mode_suffix);
467 if (!ucm_mod_exists_with_name(mgr, swap_mod)) {
468 syslog(LOG_ERR, "Can not find swap mode modifier %s.", swap_mod);
469 free((void *)swap_mod);
470 return -EPERM;
471 }
472 if (modifier_enabled(mgr, swap_mod) == !!enable) {
473 free((void *)swap_mod);
474 return 0;
475 }
476 rc = ucm_set_modifier_enabled(mgr, swap_mod, enable);
477 free((void *)swap_mod);
478 return rc;
479 }
480
ucm_set_enabled(struct cras_use_case_mgr * mgr,const char * dev,int enable)481 int ucm_set_enabled(struct cras_use_case_mgr *mgr, const char *dev, int enable)
482 {
483 if (device_enabled(mgr, dev) == !!enable)
484 return 0;
485 syslog(LOG_DEBUG, "UCM %s %s", enable ? "enable" : "disable", dev);
486 return snd_use_case_set(mgr->mgr, enable ? "_enadev" : "_disdev", dev);
487 }
488
ucm_get_flag(struct cras_use_case_mgr * mgr,const char * flag_name)489 char *ucm_get_flag(struct cras_use_case_mgr *mgr, const char *flag_name)
490 {
491 char *flag_value = NULL;
492 const char *value;
493 int rc;
494
495 /* Set device to empty string since flag is specified in verb section */
496 rc = get_var(mgr, flag_name, "", uc_verb(mgr), &value);
497 if (!rc) {
498 flag_value = strdup(value);
499 free((void *)value);
500 }
501
502 return flag_value;
503 }
504
ucm_get_cap_control(struct cras_use_case_mgr * mgr,const char * ucm_dev)505 char *ucm_get_cap_control(struct cras_use_case_mgr *mgr, const char *ucm_dev)
506 {
507 char *control_name = NULL;
508 const char *value;
509 int rc;
510
511 rc = get_var(mgr, cap_var, ucm_dev, uc_verb(mgr), &value);
512 if (!rc) {
513 control_name = strdup(value);
514 free((void *)value);
515 }
516
517 return control_name;
518 }
519
ucm_get_mic_positions(struct cras_use_case_mgr * mgr)520 char *ucm_get_mic_positions(struct cras_use_case_mgr *mgr)
521 {
522 char *control_name = NULL;
523 const char *value;
524 int rc;
525
526 rc = get_var(mgr, mic_positions, "", uc_verb(mgr), &value);
527 if (!rc) {
528 control_name = strdup(value);
529 free((void *)value);
530 }
531
532 return control_name;
533 }
534
ucm_get_override_type_name(struct cras_use_case_mgr * mgr,const char * dev)535 const char *ucm_get_override_type_name(struct cras_use_case_mgr *mgr,
536 const char *dev)
537 {
538 const char *override_type_name;
539 int rc;
540
541 rc = get_var(mgr, override_type_name_var, dev, uc_verb(mgr),
542 &override_type_name);
543 if (rc)
544 return NULL;
545
546 return override_type_name;
547 }
548
ucm_get_dev_for_jack(struct cras_use_case_mgr * mgr,const char * jack,enum CRAS_STREAM_DIRECTION direction)549 char *ucm_get_dev_for_jack(struct cras_use_case_mgr *mgr, const char *jack,
550 enum CRAS_STREAM_DIRECTION direction)
551 {
552 struct section_name *section_names, *c;
553 char *ret = NULL;
554
555 section_names = ucm_get_devices_for_var(mgr, jack_var, jack, direction);
556
557 DL_FOREACH(section_names, c) {
558 if (!strcmp(c->name, "Mic")) {
559 /* Skip mic section for output */
560 if (direction == CRAS_STREAM_OUTPUT)
561 continue;
562 } else {
563 /* Only check mic for input. */
564 if (direction == CRAS_STREAM_INPUT)
565 continue;
566 }
567 ret = strdup(c->name);
568 break;
569 }
570
571 DL_FOREACH(section_names, c) {
572 DL_DELETE(section_names, c);
573 free((void*)c->name);
574 free(c);
575 }
576
577 return ret;
578 }
579
ucm_get_dev_for_mixer(struct cras_use_case_mgr * mgr,const char * mixer,enum CRAS_STREAM_DIRECTION dir)580 char *ucm_get_dev_for_mixer(struct cras_use_case_mgr *mgr, const char *mixer,
581 enum CRAS_STREAM_DIRECTION dir)
582 {
583 struct section_name *section_names, *c;
584 char *ret = NULL;
585
586 section_names = ucm_get_devices_for_var(mgr, mixer_var, mixer, dir);
587
588 if (section_names)
589 ret = strdup(section_names->name);
590
591 DL_FOREACH(section_names, c) {
592 DL_DELETE(section_names, c);
593 free((void*)c->name);
594 free(c);
595 }
596
597 return ret;
598 }
599
ucm_get_edid_file_for_dev(struct cras_use_case_mgr * mgr,const char * dev)600 const char *ucm_get_edid_file_for_dev(struct cras_use_case_mgr *mgr,
601 const char *dev)
602 {
603 const char *file_name;
604 int rc;
605
606 rc = get_var(mgr, edid_var, dev, uc_verb(mgr), &file_name);
607 if (rc)
608 return NULL;
609
610 return file_name;
611 }
612
ucm_get_dsp_name(struct cras_use_case_mgr * mgr,const char * ucm_dev,int direction)613 const char *ucm_get_dsp_name(struct cras_use_case_mgr *mgr, const char *ucm_dev,
614 int direction)
615 {
616 const char *var = (direction == CRAS_STREAM_OUTPUT)
617 ? output_dsp_name_var
618 : input_dsp_name_var;
619 const char *dsp_name = NULL;
620 int rc;
621
622 rc = get_var(mgr, var, ucm_dev, uc_verb(mgr), &dsp_name);
623 if (rc)
624 return NULL;
625
626 return dsp_name;
627 }
628
ucm_get_dsp_name_default(struct cras_use_case_mgr * mgr,int direction)629 const char *ucm_get_dsp_name_default(struct cras_use_case_mgr *mgr,
630 int direction)
631 {
632 return ucm_get_dsp_name(mgr, "", direction);
633 }
634
ucm_get_min_buffer_level(struct cras_use_case_mgr * mgr,unsigned int * level)635 int ucm_get_min_buffer_level(struct cras_use_case_mgr *mgr,
636 unsigned int *level)
637 {
638 int value;
639 int rc;
640
641 rc = get_int(mgr, min_buffer_level_var, "", uc_verb(mgr), &value);
642 if (rc)
643 return -ENOENT;
644 *level = value;
645
646 return 0;
647 }
648
ucm_get_disable_software_volume(struct cras_use_case_mgr * mgr)649 unsigned int ucm_get_disable_software_volume(struct cras_use_case_mgr *mgr)
650 {
651 int value;
652 int rc;
653
654 rc = get_int(mgr, disable_software_volume, "", uc_verb(mgr), &value);
655 if (rc)
656 return 0;
657
658 return value;
659 }
660
ucm_get_min_software_gain(struct cras_use_case_mgr * mgr,const char * dev,long * gain)661 int ucm_get_min_software_gain(struct cras_use_case_mgr *mgr, const char *dev,
662 long *gain)
663 {
664 int value;
665 int rc;
666
667 rc = get_int(mgr, min_software_gain, dev, uc_verb(mgr), &value);
668 if (rc)
669 return rc;
670 *gain = value;
671 return 0;
672 }
673
ucm_get_max_software_gain(struct cras_use_case_mgr * mgr,const char * dev,long * gain)674 int ucm_get_max_software_gain(struct cras_use_case_mgr *mgr, const char *dev,
675 long *gain)
676 {
677 int value;
678 int rc;
679
680 rc = get_int(mgr, max_software_gain, dev, uc_verb(mgr), &value);
681 if (rc)
682 return rc;
683 *gain = value;
684 return 0;
685 }
686
ucm_get_default_node_gain(struct cras_use_case_mgr * mgr,const char * dev,long * gain)687 int ucm_get_default_node_gain(struct cras_use_case_mgr *mgr, const char *dev,
688 long *gain)
689 {
690 int value;
691 int rc;
692
693 rc = get_int(mgr, default_node_gain, dev, uc_verb(mgr), &value);
694 if (rc)
695 return rc;
696 *gain = value;
697 return 0;
698 }
699
ucm_get_preempt_hotword(struct cras_use_case_mgr * mgr,const char * dev)700 int ucm_get_preempt_hotword(struct cras_use_case_mgr *mgr, const char *dev)
701 {
702 int value;
703 int rc;
704
705 rc = get_int(mgr, preempt_hotword_var, dev, uc_verb(mgr), &value);
706 if (rc)
707 return 0;
708 return value;
709 }
710
ucm_get_device_name_for_dev(struct cras_use_case_mgr * mgr,const char * dev,enum CRAS_STREAM_DIRECTION direction)711 const char *ucm_get_device_name_for_dev(
712 struct cras_use_case_mgr *mgr, const char *dev,
713 enum CRAS_STREAM_DIRECTION direction)
714 {
715 if (direction == CRAS_STREAM_OUTPUT)
716 return ucm_get_playback_device_name_for_dev(mgr, dev);
717 else if (direction == CRAS_STREAM_INPUT)
718 return ucm_get_capture_device_name_for_dev(mgr, dev);
719 return NULL;
720 }
721
ucm_get_echo_reference_dev_name_for_dev(struct cras_use_case_mgr * mgr,const char * dev)722 const char *ucm_get_echo_reference_dev_name_for_dev(
723 struct cras_use_case_mgr *mgr, const char *dev)
724 {
725 const char *name = NULL;
726 int rc;
727
728 rc = get_var(mgr, echo_reference_dev_name_var, dev,
729 uc_verb(mgr), &name);
730 if (rc)
731 return NULL;
732 return name;
733 }
734
ucm_get_sample_rate_for_dev(struct cras_use_case_mgr * mgr,const char * dev,enum CRAS_STREAM_DIRECTION direction)735 int ucm_get_sample_rate_for_dev(struct cras_use_case_mgr *mgr, const char *dev,
736 enum CRAS_STREAM_DIRECTION direction)
737 {
738 int value;
739 int rc;
740 const char *var_name;
741
742 if (direction == CRAS_STREAM_OUTPUT)
743 var_name = playback_device_rate_var;
744 else if (direction == CRAS_STREAM_INPUT)
745 var_name = capture_device_rate_var;
746 else
747 return -EINVAL;
748
749 rc = get_int(mgr, var_name, dev, uc_verb(mgr), &value);
750 if (rc)
751 return rc;
752
753 return value;
754 }
755
ucm_get_capture_chmap_for_dev(struct cras_use_case_mgr * mgr,const char * dev,int8_t * channel_layout)756 int ucm_get_capture_chmap_for_dev(struct cras_use_case_mgr *mgr,
757 const char *dev,
758 int8_t *channel_layout)
759 {
760 const char *var_str;
761 char *tokens, *token;
762 int i, rc;
763
764 rc = get_var(mgr, capture_channel_map_var, dev, uc_verb(mgr), &var_str);
765 if (rc)
766 return rc;
767
768 tokens = strdup(var_str);
769 token = strtok(tokens, " ");
770 for (i = 0; token && (i < CRAS_CH_MAX); i++) {
771 channel_layout[i] = atoi(token);
772 token = strtok(NULL, " ");
773 }
774
775 free((void *)tokens);
776 free((void *)var_str);
777 return (i == CRAS_CH_MAX) ? 0 : -EINVAL;
778 }
779
ucm_get_coupled_mixer_names(struct cras_use_case_mgr * mgr,const char * dev)780 struct mixer_name *ucm_get_coupled_mixer_names(
781 struct cras_use_case_mgr *mgr, const char *dev)
782 {
783 return ucm_get_mixer_names(mgr, dev, coupled_mixers,
784 CRAS_STREAM_OUTPUT,
785 MIXER_NAME_VOLUME);
786 }
787
get_device_index_from_target(const char * target_device_name)788 static int get_device_index_from_target(const char *target_device_name)
789 {
790 /* Expects a string in the form: hw:card-name,<num> */
791 const char *pos = target_device_name;
792 if (!pos)
793 return -1;
794 while (*pos && *pos != ',')
795 ++pos;
796 if (*pos == ',') {
797 ++pos;
798 return atoi(pos);
799 }
800 return -1;
801 }
802
ucm_get_sections(struct cras_use_case_mgr * mgr)803 struct ucm_section *ucm_get_sections(struct cras_use_case_mgr *mgr)
804 {
805 struct ucm_section *sections = NULL;
806 struct ucm_section *dev_sec;
807 const char **list;
808 int num_devs;
809 int i;
810 char *identifier;
811
812 /* Find the list of all mixers using the control names defined in
813 * the header definintion for this function. */
814 identifier = snd_use_case_identifier("_devices/%s", uc_verb(mgr));
815 num_devs = snd_use_case_get_list(mgr->mgr, identifier, &list);
816 free(identifier);
817
818 /* snd_use_case_get_list fills list with pairs of device name and
819 * comment, so device names are in even-indexed elements. */
820 const char *dev_name;
821 for (i = 0; i < num_devs; i += 2) {
822 enum CRAS_STREAM_DIRECTION dir = CRAS_STREAM_UNDEFINED;
823 int dev_idx = -1;
824 const char *jack_name;
825 const char *jack_type;
826 const char *mixer_name;
827 struct mixer_name *m_name;
828 int rc;
829 const char *target_device_name;
830
831 dev_name = strdup(list[i]);
832 if (!dev_name)
833 continue;
834
835 target_device_name =
836 ucm_get_playback_device_name_for_dev(mgr, dev_name);
837 if (target_device_name)
838 dir = CRAS_STREAM_OUTPUT;
839 else {
840 target_device_name =
841 ucm_get_capture_device_name_for_dev(
842 mgr, dev_name);
843 if (target_device_name)
844 dir = CRAS_STREAM_INPUT;
845 }
846 if (target_device_name) {
847 dev_idx = get_device_index_from_target(
848 target_device_name);
849 free((void *)target_device_name);
850 }
851
852 if (dir == CRAS_STREAM_UNDEFINED) {
853 syslog(LOG_ERR,
854 "UCM configuration for device '%s' missing"
855 " PlaybackPCM or CapturePCM definition.",
856 dev_name);
857 goto error_cleanup;
858 }
859
860 if (dev_idx == -1) {
861 syslog(LOG_ERR,
862 "PlaybackPCM or CapturePCM for '%s' must be in"
863 " the form 'hw:<card>,<number>'", dev_name);
864 goto error_cleanup;
865 }
866
867 jack_name = ucm_get_jack_name_for_dev(mgr, dev_name);
868 jack_type = ucm_get_jack_type_for_dev(mgr, dev_name);
869 mixer_name = ucm_get_mixer_name_for_dev(mgr, dev_name);
870
871 dev_sec = ucm_section_create(dev_name, dev_idx, dir,
872 jack_name, jack_type);
873 if (jack_name)
874 free((void *)jack_name);
875 if (jack_type)
876 free((void *)jack_type);
877
878 if (!dev_sec) {
879 syslog(LOG_ERR, "Failed to allocate memory.");
880 if (mixer_name)
881 free((void *)mixer_name);
882 goto error_cleanup;
883 }
884
885 dev_sec->jack_switch =
886 ucm_get_jack_switch_for_dev(mgr, dev_name);
887
888 if (mixer_name) {
889 rc = ucm_section_set_mixer_name(dev_sec, mixer_name);
890 free((void *)mixer_name);
891 if (rc)
892 goto error_cleanup;
893 }
894
895 m_name = ucm_get_mixer_names(mgr, dev_name, coupled_mixers,
896 dir, MIXER_NAME_VOLUME);
897 ucm_section_concat_coupled(dev_sec, m_name);
898
899 DL_APPEND(sections, dev_sec);
900 ucm_section_dump(dev_sec);
901 free((void *)dev_name);
902 }
903
904 if (num_devs > 0)
905 snd_use_case_free_list(list, num_devs);
906 return sections;
907
908 error_cleanup:
909 if (num_devs > 0)
910 snd_use_case_free_list(list, num_devs);
911 ucm_section_free_list(sections);
912 free((void *)dev_name);
913 return NULL;
914 }
915
ucm_get_hotword_models(struct cras_use_case_mgr * mgr)916 char *ucm_get_hotword_models(struct cras_use_case_mgr *mgr)
917 {
918 const char **list;
919 int i, num_entries;
920 int models_len = 0;
921 char *models = NULL;
922 const char *tmp;
923 char *identifier;
924
925 identifier = snd_use_case_identifier("_modifiers/%s", uc_verb(mgr));
926 num_entries = snd_use_case_get_list(mgr->mgr, identifier, &list);
927 free(identifier);
928 if (num_entries <= 0)
929 return 0;
930 models = (char *)malloc(num_entries * 8);
931 for (i = 0; i < num_entries; i+=2) {
932 if (!list[i])
933 continue;
934 if (0 == strncmp(list[i], hotword_model_prefix,
935 strlen(hotword_model_prefix))) {
936 tmp = list[i] + strlen(hotword_model_prefix);
937 while (isspace(*tmp))
938 tmp++;
939 strcpy(models + models_len, tmp);
940 models_len += strlen(tmp);
941 if (i + 2 >= num_entries)
942 models[models_len] = '\0';
943 else
944 models[models_len++] = ',';
945 }
946 }
947 snd_use_case_free_list(list, num_entries);
948
949 return models;
950 }
951
ucm_set_hotword_model(struct cras_use_case_mgr * mgr,const char * model)952 int ucm_set_hotword_model(struct cras_use_case_mgr *mgr, const char *model)
953 {
954 const char **list;
955 int num_enmods, mod_idx;
956 char *model_mod = NULL;
957 size_t model_mod_size = strlen(model) + 1 +
958 strlen(hotword_model_prefix) + 1;
959 model_mod = (char *)malloc(model_mod_size);
960 if (!model_mod)
961 return -ENOMEM;
962 snprintf(model_mod, model_mod_size,
963 "%s %s", hotword_model_prefix, model);
964 if (!ucm_mod_exists_with_name(mgr, model_mod)) {
965 free((void *)model_mod);
966 return -EINVAL;
967 }
968
969 /* Disable all currently enabled horword model modifiers. */
970 num_enmods = snd_use_case_get_list(mgr->mgr, "_enamods", &list);
971 if (num_enmods <= 0)
972 goto enable_mod;
973
974 for (mod_idx = 0; mod_idx < num_enmods; mod_idx++) {
975 if (!strncmp(list[mod_idx], hotword_model_prefix,
976 strlen(hotword_model_prefix)))
977 ucm_set_modifier_enabled(mgr, list[mod_idx], 0);
978 }
979 snd_use_case_free_list(list, num_enmods);
980
981 enable_mod:
982 ucm_set_modifier_enabled(mgr, model_mod, 1);
983 free((void *)model_mod);
984 return 0;
985 }
986
ucm_has_fully_specified_ucm_flag(struct cras_use_case_mgr * mgr)987 int ucm_has_fully_specified_ucm_flag(struct cras_use_case_mgr *mgr)
988 {
989 char *flag;
990 int ret = 0;
991 flag = ucm_get_flag(mgr, fully_specified_ucm_var);
992 if (!flag)
993 return 0;
994 ret = !strcmp(flag, "1");
995 free(flag);
996 return ret;
997 }
998
ucm_get_mixer_name_for_dev(struct cras_use_case_mgr * mgr,const char * dev)999 const char *ucm_get_mixer_name_for_dev(struct cras_use_case_mgr *mgr, const char *dev)
1000 {
1001 const char *name = NULL;
1002 int rc;
1003
1004 rc = get_var(mgr, mixer_var, dev, uc_verb(mgr), &name);
1005 if (rc)
1006 return NULL;
1007
1008 return name;
1009 }
1010
ucm_get_main_volume_names(struct cras_use_case_mgr * mgr)1011 struct mixer_name *ucm_get_main_volume_names(struct cras_use_case_mgr *mgr)
1012 {
1013 return ucm_get_mixer_names(mgr, "", main_volume_names,
1014 CRAS_STREAM_OUTPUT, MIXER_NAME_MAIN_VOLUME);
1015 }
1016
ucm_list_section_devices_by_device_name(struct cras_use_case_mgr * mgr,enum CRAS_STREAM_DIRECTION direction,const char * device_name,ucm_list_section_devices_callback cb,void * cb_arg)1017 int ucm_list_section_devices_by_device_name(
1018 struct cras_use_case_mgr *mgr,
1019 enum CRAS_STREAM_DIRECTION direction,
1020 const char *device_name,
1021 ucm_list_section_devices_callback cb,
1022 void *cb_arg)
1023 {
1024 int listed= 0;
1025 struct section_name *section_names, *c;
1026 const char* var;
1027 char *identifier;
1028
1029 if (direction == CRAS_STREAM_OUTPUT)
1030 var = playback_device_name_var;
1031 else if (direction == CRAS_STREAM_INPUT)
1032 var = capture_device_name_var;
1033 else
1034 return 0;
1035
1036 identifier = snd_use_case_identifier("_devices/%s", uc_verb(mgr));
1037 section_names = ucm_get_sections_for_var(
1038 mgr, var, device_name, identifier, direction);
1039 free(identifier);
1040 if (!section_names)
1041 return 0;
1042
1043 DL_FOREACH(section_names, c) {
1044 cb(c->name, cb_arg);
1045 listed++;
1046 }
1047
1048 DL_FOREACH(section_names, c) {
1049 DL_DELETE(section_names, c);
1050 free((void*)c->name);
1051 free(c);
1052 }
1053 return listed;
1054 }
1055
ucm_get_jack_name_for_dev(struct cras_use_case_mgr * mgr,const char * dev)1056 const char *ucm_get_jack_name_for_dev(struct cras_use_case_mgr *mgr,
1057 const char *dev)
1058 {
1059 const char *name = NULL;
1060 int rc;
1061
1062 rc = get_var(mgr, jack_var, dev, uc_verb(mgr), &name);
1063 if (rc)
1064 return NULL;
1065
1066 return name;
1067 }
1068
ucm_get_jack_type_for_dev(struct cras_use_case_mgr * mgr,const char * dev)1069 const char *ucm_get_jack_type_for_dev(struct cras_use_case_mgr *mgr,
1070 const char *dev)
1071 {
1072 const char *name = NULL;
1073 int rc;
1074
1075 rc = get_var(mgr, jack_type_var, dev, uc_verb(mgr), &name);
1076 if (rc)
1077 return NULL;
1078
1079 if (strcmp(name, "hctl") && strcmp(name, "gpio")) {
1080 syslog(LOG_ERR, "Unknown jack type: %s", name);
1081 if(name)
1082 free((void *)name);
1083 return NULL;
1084 }
1085 return name;
1086 }
1087
ucm_get_jack_switch_for_dev(struct cras_use_case_mgr * mgr,const char * dev)1088 int ucm_get_jack_switch_for_dev(struct cras_use_case_mgr *mgr, const char *dev)
1089 {
1090 int value;
1091
1092 int rc = get_int(mgr, jack_switch_var, dev, uc_verb(mgr), &value);
1093 if (rc || value < 0)
1094 return -1;
1095 return value;
1096 }
1097
ucm_get_dma_period_for_dev(struct cras_use_case_mgr * mgr,const char * dev)1098 unsigned int ucm_get_dma_period_for_dev(struct cras_use_case_mgr *mgr,
1099 const char *dev)
1100 {
1101 int value;
1102
1103 int rc = get_int(mgr, dma_period_var, dev, uc_verb(mgr), &value);
1104 if (rc || value < 0)
1105 return 0;
1106 return value;
1107 }
1108
ucm_get_enable_htimestamp_flag(struct cras_use_case_mgr * mgr)1109 unsigned int ucm_get_enable_htimestamp_flag(struct cras_use_case_mgr *mgr)
1110 {
1111 char *flag;
1112 int ret = 0;
1113 flag = ucm_get_flag(mgr, enable_htimestamp_var);
1114 if (!flag)
1115 return 0;
1116 ret = !strcmp(flag, "1");
1117 free(flag);
1118 return ret;
1119 }
1120