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