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 <linux/input.h>
8 #include <regex.h>
9 #include <syslog.h>
10
11 #include "cras_alsa_jack.h"
12 #include "cras_alsa_mixer.h"
13 #include "cras_alsa_ucm.h"
14 #include "cras_system_state.h"
15 #include "cras_gpio_jack.h"
16 #include "cras_tm.h"
17 #include "cras_util.h"
18 #include "edid_utils.h"
19 #include "utlist.h"
20
21 static const unsigned int DISPLAY_INFO_RETRY_DELAY_MS = 200;
22 static const unsigned int DISPLAY_INFO_MAX_RETRIES = 10;
23 static const unsigned int DISPLAY_INFO_GPIO_MAX_RETRIES = 25;
24
25 /* Constants used to retrieve monitor name from ELD buffer. */
26 static const unsigned int ELD_MNL_MASK = 31;
27 static const unsigned int ELD_MNL_OFFSET = 4;
28 static const unsigned int ELD_MONITOR_NAME_OFFSET = 20;
29
30 /* Keeps an fd that is registered with system settings. A list of fds must be
31 * kept so that they can be removed when the jack list is destroyed. */
32 struct jack_poll_fd {
33 int fd;
34 struct jack_poll_fd *prev, *next;
35 };
36
37 /* cras_gpio_jack: Describes headphone & microphone jack connected to GPIO
38 *
39 * On Arm-based systems, the headphone & microphone jacks are
40 * connected to GPIOs which are plumbed through the /dev/input/event
41 * system. For these jacks, the software is written to open the
42 * corresponding /dev/input/event file and monitor it for 'insert' &
43 * 'remove' activity.
44 *
45 * fd : File descriptor corresponding to the /dev/input/event file.
46 *
47 * switch_event : Indicates the type of the /dev/input/event file.
48 * Either SW_HEADPHONE_INSERT, or SW_MICROPHONE_INSERT.
49 *
50 * current_state: 0 -> device not plugged in
51 * 1 -> device plugged in
52 * device_name : Device name extracted from /dev/input/event[0..9]+.
53 * Allocated on heap; must free.
54 */
55 struct cras_gpio_jack {
56 int fd;
57 unsigned switch_event;
58 unsigned current_state;
59 char *device_name;
60 };
61
62 /* Represents a single alsa Jack, e.g. "Headphone Jack" or "Mic Jack".
63 * is_gpio: 1 -> gpio switch (union field: gpio)
64 * 0 -> Alsa 'jack' (union field: elem)
65 * elem - alsa hcontrol element for this jack, when is_gpio == 0.
66 * gpio - description of gpio-based jack, when is_gpio != 0.
67 * eld_control - mixer control for ELD info buffer.
68 * jack_list - list of jacks this belongs to.
69 * mixer_output - mixer output control used to control audio to this jack.
70 * This will be null for input jacks.
71 * mixer_input - mixer input control used to control audio to this jack.
72 * This will be null for output jacks.
73 * ucm_device - Name of the ucm device if found, otherwise, NULL.
74 * edid_file - File to read the EDID from (if available, HDMI only).
75 * display_info_timer - Timer used to poll display info for HDMI jacks.
76 * display_info_retries - Number of times to retry reading display info.
77 *
78 * mixer_output/mixer_input fields are only used to find the node for this
79 * jack. These are not used for setting volume or mute. There should be a
80 * 1:1 map between node and jack. node->jack follows the pointer; jack->node
81 * is done by either searching node->jack pointers or searching the node that
82 * has the same mixer_control as the jack.
83 */
84 struct cras_alsa_jack {
85 unsigned is_gpio; /* !0 -> 'gpio' valid
86 * 0 -> 'elem' valid
87 */
88 union {
89 snd_hctl_elem_t *elem;
90 struct cras_gpio_jack gpio;
91 };
92
93 snd_hctl_elem_t *eld_control;
94 struct cras_alsa_jack_list *jack_list;
95 struct mixer_control *mixer_output;
96 struct mixer_control *mixer_input;
97 char *ucm_device;
98 const char *dsp_name;
99 const char* override_type_name;
100 const char *edid_file;
101 struct cras_timer *display_info_timer;
102 unsigned int display_info_retries;
103 struct cras_alsa_jack *prev, *next;
104 };
105
106 /* Contains all Jacks for a given device.
107 * hctl - alsa hcontrol for this device's card
108 * - not opened by the jack list.
109 * mixer - cras mixer for the card providing this device.
110 * ucm - CRAS use case manager if available.
111 * card_index - Index ALSA uses to refer to the card. The X in "hw:X".
112 * card_name - The name of the card.
113 * device_index - Index ALSA uses to refer to the device. The Y in "hw:X,Y".
114 * is_first_device - whether this device is the first device on the card.
115 * direction - Input or output.
116 * change_callback - function to call when the state of a jack changes.
117 * callback_data - data to pass back to the callback.
118 * jacks - list of jacks for this device.
119 */
120 struct cras_alsa_jack_list {
121 snd_hctl_t *hctl;
122 struct cras_alsa_mixer *mixer;
123 struct cras_use_case_mgr *ucm;
124 unsigned int card_index;
125 const char *card_name;
126 size_t device_index;
127 int is_first_device;
128 enum CRAS_STREAM_DIRECTION direction;
129 jack_state_change_callback *change_callback;
130 void *callback_data;
131 struct cras_alsa_jack *jacks;
132 };
133
134 /* Used to contain information needed while looking through GPIO jacks.
135 * jack_list - The current jack_list.
136 * section - An associated UCM section.
137 * result_jack - The resulting jack.
138 * rc - The return code for the operation.
139 */
140 struct gpio_switch_list_data {
141 struct cras_alsa_jack_list *jack_list;
142 struct ucm_section *section;
143 struct cras_alsa_jack *result_jack;
144 int rc;
145 };
146
147 /*
148 * Local Helpers.
149 */
150
151 #define BITS_PER_BYTE (8)
152 #define BITS_PER_LONG (sizeof(long) * BITS_PER_BYTE)
153 #define NBITS(x) ((((x) - 1) / BITS_PER_LONG) + 1)
154 #define OFF(x) ((x) % BITS_PER_LONG)
155 #define BIT(x) (1UL << OFF(x))
156 #define LONG(x) ((x) / BITS_PER_LONG)
157 #define IS_BIT_SET(bit, array) !!((array[LONG(bit)]) & (1UL << OFF(bit)))
158
sys_input_get_switch_state(int fd,unsigned sw,unsigned * state)159 static int sys_input_get_switch_state(int fd, unsigned sw, unsigned *state)
160 {
161 unsigned long bits[NBITS(SW_CNT)];
162 const unsigned long switch_no = sw;
163
164 memset(bits, '\0', sizeof(bits));
165 /* If switch event present & supported, get current state. */
166 if (gpio_switch_eviocgbit(fd, bits, sizeof(bits)) < 0)
167 return -EIO;
168
169 if (IS_BIT_SET(switch_no, bits))
170 if (gpio_switch_eviocgsw(fd, bits, sizeof(bits)) >= 0) {
171 *state = IS_BIT_SET(switch_no, bits);
172 return 0;
173 }
174
175 return -1;
176 }
177
cras_alloc_jack(int is_gpio)178 static inline struct cras_alsa_jack *cras_alloc_jack(int is_gpio)
179 {
180 struct cras_alsa_jack *jack = calloc(1, sizeof(*jack));
181 if (jack == NULL)
182 return NULL;
183 jack->is_gpio = is_gpio;
184 return jack;
185 }
186
cras_free_jack(struct cras_alsa_jack * jack,int rm_select_fd)187 static void cras_free_jack(struct cras_alsa_jack *jack,
188 int rm_select_fd)
189 {
190 if (!jack)
191 return;
192
193 free(jack->ucm_device);
194 free((void *)jack->edid_file);
195 if (jack->display_info_timer)
196 cras_tm_cancel_timer(cras_system_state_get_tm(),
197 jack->display_info_timer);
198
199 if (jack->is_gpio) {
200 free(jack->gpio.device_name);
201 if (jack->gpio.fd >= 0) {
202 if (rm_select_fd)
203 cras_system_rm_select_fd(jack->gpio.fd);
204 close(jack->gpio.fd);
205 }
206 }
207
208 /*
209 * Remove the jack callback set on hctl. Otherwise, snd_hctl_close will
210 * trigger a callback while iodev might already be destroyed.
211 */
212 if (!jack->is_gpio && jack->elem)
213 snd_hctl_elem_set_callback(jack->elem, NULL);
214
215 free((void *)jack->override_type_name);
216 free((void *)jack->dsp_name);
217 free(jack);
218 }
219
220 /* Gets the current plug state of the jack */
get_jack_current_state(struct cras_alsa_jack * jack)221 static int get_jack_current_state(struct cras_alsa_jack *jack)
222 {
223 snd_ctl_elem_value_t *elem_value;
224
225 if (jack->is_gpio)
226 return jack->gpio.current_state;
227
228 snd_ctl_elem_value_alloca(&elem_value);
229 snd_hctl_elem_read(jack->elem, elem_value);
230
231 return snd_ctl_elem_value_get_boolean(elem_value, 0);
232 }
233
read_jack_edid(const struct cras_alsa_jack * jack,uint8_t * edid)234 static int read_jack_edid(const struct cras_alsa_jack *jack, uint8_t *edid)
235 {
236 int fd, nread;
237
238 fd = open(jack->edid_file, O_RDONLY);
239 if (fd < 0)
240 return -1;
241
242 nread = read(fd, edid, EEDID_SIZE);
243 close(fd);
244
245 if (nread < EDID_SIZE || !edid_valid(edid))
246 return -1;
247 return 0;
248 }
249
check_jack_edid(struct cras_alsa_jack * jack)250 static int check_jack_edid(struct cras_alsa_jack *jack)
251 {
252 uint8_t edid[EEDID_SIZE];
253
254 if (read_jack_edid(jack, edid))
255 return -1;
256
257 /* If the jack supports EDID, check that it supports audio, clearing
258 * the plugged state if it doesn't.
259 */
260 if (!edid_lpcm_support(edid, edid[EDID_EXT_FLAG]))
261 jack->gpio.current_state = 0;
262 return 0;
263 }
264
get_jack_edid_monitor_name(const struct cras_alsa_jack * jack,char * buf,unsigned int buf_size)265 static int get_jack_edid_monitor_name(const struct cras_alsa_jack *jack,
266 char *buf,
267 unsigned int buf_size)
268 {
269 uint8_t edid[EEDID_SIZE];
270
271 if (read_jack_edid(jack, edid))
272 return -1;
273
274 return edid_get_monitor_name(edid, buf, buf_size);
275 }
276
277 /* Checks the ELD control of the jack to see if the ELD buffer
278 * is ready to read and report the plug status.
279 */
check_jack_eld(struct cras_alsa_jack * jack)280 static int check_jack_eld(struct cras_alsa_jack *jack)
281 {
282 snd_ctl_elem_info_t *elem_info;
283 snd_ctl_elem_info_alloca(&elem_info);
284
285 /* Poll ELD control by getting the count of ELD buffer.
286 * When seeing zero buffer count, retry after a delay until
287 * it's ready or reached the max number of retries. */
288 if (snd_hctl_elem_info(jack->eld_control, elem_info) != 0)
289 return -1;
290 if (snd_ctl_elem_info_get_count(elem_info) == 0)
291 return -1;
292 return 0;
293 }
294
295 static void display_info_delay_cb(struct cras_timer *timer, void *arg);
296
297 /* Callback function doing following things:
298 * 1. Reset timer and update max number of retries.
299 * 2. Check all conditions to see if it's okay or needed to
300 * report jack status directly. E.g. jack is unplugged or
301 * EDID is not ready for some reason.
302 * 3. Check if max number of retries is reached and decide
303 * to set timer for next callback or report jack state.
304 */
jack_state_change_cb(struct cras_alsa_jack * jack,int retry)305 static inline void jack_state_change_cb(struct cras_alsa_jack *jack, int retry)
306 {
307 struct cras_tm *tm = cras_system_state_get_tm();
308
309 if (jack->display_info_timer) {
310 cras_tm_cancel_timer(tm, jack->display_info_timer);
311 jack->display_info_timer = NULL;
312 }
313 if (retry) {
314 jack->display_info_retries =
315 jack->is_gpio ? DISPLAY_INFO_GPIO_MAX_RETRIES
316 : DISPLAY_INFO_MAX_RETRIES;
317 }
318
319 if (!get_jack_current_state(jack))
320 goto report_jack_state;
321
322 /* If there is an edid file, check it. If it is ready continue, if we
323 * need to try again later, return here as the timer has been armed and
324 * will check again later.
325 */
326 if (jack->edid_file == NULL && jack->eld_control == NULL)
327 goto report_jack_state;
328 if (jack->edid_file && (check_jack_edid(jack) == 0))
329 goto report_jack_state;
330 if (jack->eld_control && (check_jack_eld(jack) == 0))
331 goto report_jack_state;
332
333 if (--jack->display_info_retries == 0) {
334 if (jack->is_gpio)
335 jack->gpio.current_state = 0;
336 if (jack->edid_file)
337 syslog(LOG_ERR, "Timeout to read EDID from %s",
338 jack->edid_file);
339 goto report_jack_state;
340 }
341
342 jack->display_info_timer = cras_tm_create_timer(tm,
343 DISPLAY_INFO_RETRY_DELAY_MS,
344 display_info_delay_cb, jack);
345 return;
346
347 report_jack_state:
348 jack->jack_list->change_callback(jack,
349 get_jack_current_state(jack),
350 jack->jack_list->callback_data);
351 }
352
353 /* gpio_switch_initial_state
354 *
355 * Determines the initial state of a gpio-based switch.
356 */
gpio_switch_initial_state(struct cras_alsa_jack * jack)357 static void gpio_switch_initial_state(struct cras_alsa_jack *jack)
358 {
359 unsigned v;
360 int r = sys_input_get_switch_state(jack->gpio.fd,
361 jack->gpio.switch_event, &v);
362 jack->gpio.current_state = r == 0 ? v : 0;
363 jack_state_change_cb(jack, 1);
364 }
365
366 /* Check if the input event is an audio switch event. */
is_audio_switch_event(const struct input_event * ev,int sw_code)367 static inline int is_audio_switch_event(const struct input_event *ev,
368 int sw_code)
369 {
370 return (ev->type == EV_SW && ev->code == sw_code);
371 }
372
373 /* Timer callback to read display info after a hotplug event for an HDMI jack.
374 */
display_info_delay_cb(struct cras_timer * timer,void * arg)375 static void display_info_delay_cb(struct cras_timer *timer, void *arg)
376 {
377 struct cras_alsa_jack *jack = (struct cras_alsa_jack *)arg;
378
379 jack->display_info_timer = NULL;
380 jack_state_change_cb(jack, 0);
381 }
382
383 /* gpio_switch_callback
384 *
385 * This callback is invoked whenever the associated /dev/input/event
386 * file has data to read. Perform autoswitching to / from the
387 * associated device when data is available.
388 */
gpio_switch_callback(void * arg)389 static void gpio_switch_callback(void *arg)
390 {
391 struct cras_alsa_jack *jack = arg;
392 int i;
393 int r;
394 struct input_event ev[64];
395
396 r = gpio_switch_read(jack->gpio.fd, ev,
397 ARRAY_SIZE(ev) * sizeof(struct input_event));
398 if (r < 0)
399 return;
400
401 for (i = 0; i < r / sizeof(struct input_event); ++i)
402 if (is_audio_switch_event(&ev[i], jack->gpio.switch_event)) {
403 jack->gpio.current_state = ev[i].value;
404
405 jack_state_change_cb(jack, 1);
406 }
407 }
408
409 /* Determines if the GPIO jack should be associated with the device of the
410 * jack list. If the device name is not specified in UCM (common case),
411 * assume it should be associated with the first input device or the first
412 * output device on the card.
413 */
gpio_jack_match_device(const struct cras_alsa_jack * jack,struct cras_alsa_jack_list * jack_list,const char * card_name,enum CRAS_STREAM_DIRECTION direction)414 static unsigned int gpio_jack_match_device(const struct cras_alsa_jack *jack,
415 struct cras_alsa_jack_list* jack_list,
416 const char *card_name,
417 enum CRAS_STREAM_DIRECTION direction)
418 {
419 const char* target_device_name = NULL;
420 char current_device_name[CRAS_IODEV_NAME_BUFFER_SIZE];
421 unsigned int rc;
422
423 /* If the device name is not specified in UCM, assume it should be
424 * associated with device 0. */
425 if (!jack_list->ucm || !jack->ucm_device)
426 return jack_list->is_first_device;
427
428 /* Look for device name specified in a device section of UCM. */
429 target_device_name = ucm_get_device_name_for_dev(
430 jack_list->ucm, jack->ucm_device, direction);
431
432 if (!target_device_name)
433 return jack_list->is_first_device;
434
435 syslog(LOG_DEBUG, "Matching GPIO jack, target device name: %s, "
436 "current card name: %s, device index: %zu\n",
437 target_device_name, card_name, jack_list->device_index);
438
439 /* Device name of format "hw:<card_name>,<device_index>", should fit
440 * in the string of size CRAS_IODEV_NAME_BUFFER_SIZE.*/
441 snprintf(current_device_name,
442 sizeof(current_device_name),
443 "hw:%s,%zu",
444 card_name,
445 jack_list->device_index);
446
447 rc = !strcmp(current_device_name, target_device_name);
448 free((void*)target_device_name);
449 return rc;
450 }
451
create_jack_for_gpio(struct cras_alsa_jack_list * jack_list,const char * pathname,const char * dev_name,unsigned switch_event,struct cras_alsa_jack ** out_jack)452 static int create_jack_for_gpio(struct cras_alsa_jack_list *jack_list,
453 const char *pathname,
454 const char *dev_name,
455 unsigned switch_event,
456 struct cras_alsa_jack **out_jack)
457 {
458 struct cras_alsa_jack *jack;
459 unsigned long bits[NBITS(SW_CNT)];
460 const char *card_name = jack_list->card_name;
461 int r;
462
463 if (!out_jack)
464 return -EINVAL;
465 *out_jack = NULL;
466
467 jack = cras_alloc_jack(1);
468 if (jack == NULL)
469 return -ENOMEM;
470
471 jack->gpio.fd = gpio_switch_open(pathname);
472 if (jack->gpio.fd == -1) {
473 r = -EIO;
474 goto error;
475 }
476
477 jack->gpio.switch_event = switch_event;
478 jack->jack_list = jack_list;
479 jack->gpio.device_name = strdup(dev_name);
480 if (!jack->gpio.device_name) {
481 r = -ENOMEM;
482 goto error;
483 }
484
485 if (!strstr(jack->gpio.device_name, card_name) ||
486 (gpio_switch_eviocgbit(jack->gpio.fd, bits, sizeof(bits)) < 0) ||
487 !IS_BIT_SET(switch_event, bits)) {
488 r = -EIO;
489 goto error;
490 }
491
492 *out_jack = jack;
493 return 0;
494
495 error:
496 /* Not yet registered with system select. */
497 cras_free_jack(jack, 0);
498 return r;
499 }
500
501 /* Take ownership and finish setup of the jack.
502 * Add the jack to the jack_list if everything goes well, or destroy it.
503 */
cras_complete_gpio_jack(struct gpio_switch_list_data * data,struct cras_alsa_jack * jack,unsigned switch_event)504 static int cras_complete_gpio_jack(struct gpio_switch_list_data *data,
505 struct cras_alsa_jack *jack,
506 unsigned switch_event)
507 {
508 struct cras_alsa_jack_list *jack_list = data->jack_list;
509 enum CRAS_STREAM_DIRECTION direction = jack_list->direction;
510 int r;
511
512 if (jack->ucm_device) {
513 jack->edid_file = ucm_get_edid_file_for_dev(jack_list->ucm,
514 jack->ucm_device);
515 jack->dsp_name = ucm_get_dsp_name(
516 jack->jack_list->ucm, jack->ucm_device, direction);
517 }
518
519 r = sys_input_get_switch_state(jack->gpio.fd, switch_event,
520 &jack->gpio.current_state);
521 if (r < 0) {
522 cras_free_jack(jack, 0);
523 return -EIO;
524 }
525 r = cras_system_add_select_fd(jack->gpio.fd,
526 gpio_switch_callback, jack);
527 if (r < 0) {
528 /* Not yet registered with system select. */
529 cras_free_jack(jack, 0);
530 return r;
531 }
532
533 DL_APPEND(jack_list->jacks, jack);
534 if (!data->result_jack)
535 data->result_jack = jack;
536 else if (data->section)
537 syslog(LOG_ERR,
538 "More than one jack for SectionDevice '%s'.",
539 data->section->name);
540 return 0;
541 }
542
543 /* open_and_monitor_gpio:
544 *
545 * Opens a /dev/input/event file associated with a headphone /
546 * microphone jack and watches it for activity.
547 * Returns 0 when a jack has been successfully added.
548 */
open_and_monitor_gpio(struct gpio_switch_list_data * data,const char * pathname,const char * dev_name,unsigned switch_event)549 static int open_and_monitor_gpio(struct gpio_switch_list_data *data,
550 const char *pathname,
551 const char *dev_name,
552 unsigned switch_event)
553 {
554 struct cras_alsa_jack *jack;
555 struct cras_alsa_jack_list *jack_list = data->jack_list;
556 const char *card_name = jack_list->card_name;
557 enum CRAS_STREAM_DIRECTION direction = jack_list->direction;
558 int r;
559
560 r = create_jack_for_gpio(jack_list, pathname, dev_name,
561 switch_event, &jack);
562 if (r != 0)
563 return r;
564
565 if (jack_list->ucm)
566 jack->ucm_device =
567 ucm_get_dev_for_jack(jack_list->ucm,
568 jack->gpio.device_name,
569 direction);
570
571 if (!gpio_jack_match_device(jack, jack_list, card_name, direction)) {
572 cras_free_jack(jack, 0);
573 return -EIO;
574 }
575
576 if (direction == CRAS_STREAM_OUTPUT &&
577 (strstr(jack->gpio.device_name, "Headphone") ||
578 strstr(jack->gpio.device_name, "Headset")))
579 jack->mixer_output = cras_alsa_mixer_get_output_matching_name(
580 jack_list->mixer,
581 "Headphone");
582 else if (direction == CRAS_STREAM_OUTPUT &&
583 strstr(jack->gpio.device_name, "HDMI"))
584 jack->mixer_output = cras_alsa_mixer_get_output_matching_name(
585 jack_list->mixer,
586 "HDMI");
587
588 if (jack->ucm_device && direction == CRAS_STREAM_INPUT) {
589 char *control_name;
590 control_name = ucm_get_cap_control(jack->jack_list->ucm,
591 jack->ucm_device);
592 if (control_name)
593 jack->mixer_input =
594 cras_alsa_mixer_get_input_matching_name(
595 jack_list->mixer,
596 control_name);
597 }
598
599 return cras_complete_gpio_jack(data, jack, switch_event);
600 }
601
open_and_monitor_gpio_with_section(struct gpio_switch_list_data * data,const char * pathname,unsigned switch_event)602 static int open_and_monitor_gpio_with_section(
603 struct gpio_switch_list_data *data,
604 const char *pathname,
605 unsigned switch_event)
606 {
607 struct cras_alsa_jack *jack;
608 struct cras_alsa_jack_list *jack_list = data->jack_list;
609 struct ucm_section *section = data->section;
610 enum CRAS_STREAM_DIRECTION direction = jack_list->direction;
611 int r;
612
613 r = create_jack_for_gpio(jack_list, pathname, section->jack_name,
614 switch_event, &jack);
615 if (r != 0)
616 return r;
617
618 jack->ucm_device = strdup(section->name);
619 if (!jack->ucm_device) {
620 cras_free_jack(jack, 0);
621 return -ENOMEM;
622 }
623
624 if (direction == CRAS_STREAM_OUTPUT)
625 jack->mixer_output = cras_alsa_mixer_get_control_for_section(
626 jack_list->mixer, section);
627 else if (direction == CRAS_STREAM_INPUT)
628 jack->mixer_input = cras_alsa_mixer_get_control_for_section(
629 jack_list->mixer, section);
630
631 return cras_complete_gpio_jack(data, jack, switch_event);
632 }
633
634 /* Monitor GPIO switches for this jack_list.
635 * Args:
636 * data - Data for GPIO switch search.
637 * dev_path - Device full path.
638 * dev_name - Device name.
639 * Returns:
640 * 0 for success, or negative on error. Assumes success if no jack is
641 * found, or if the jack could not be accessed.
642 */
gpio_switches_monitor_device(struct gpio_switch_list_data * data,const char * dev_path,const char * dev_name)643 static int gpio_switches_monitor_device(struct gpio_switch_list_data *data,
644 const char *dev_path,
645 const char *dev_name)
646 {
647 static const int out_switches[] = {SW_HEADPHONE_INSERT,
648 SW_LINEOUT_INSERT};
649 static const int in_switches[] = {SW_MICROPHONE_INSERT};
650 int sw;
651 const int *switches = out_switches;
652 int num_switches = ARRAY_SIZE(out_switches);
653 int success = 1;
654 int rc = 0;
655
656 if (data->section && data->section->jack_switch >= 0) {
657 switches = &data->section->jack_switch;
658 num_switches = 1;
659 }
660 else if (data->jack_list->direction == CRAS_STREAM_INPUT) {
661 switches = in_switches;
662 num_switches = ARRAY_SIZE(in_switches);
663 }
664
665 /* Assume that -EIO is returned for jacks that we shouldn't
666 * be looking at, but stop trying if we run into another
667 * type of error.
668 */
669 for (sw = 0; (rc == 0 || rc == -EIO)
670 && sw < num_switches; sw++) {
671 if (data->section)
672 rc = open_and_monitor_gpio_with_section(
673 data, dev_path, switches[sw]);
674 else
675 rc = open_and_monitor_gpio(
676 data, dev_path, dev_name, switches[sw]);
677 if (rc != 0 && rc != -EIO)
678 success = 0;
679 }
680
681 if (success)
682 return 0;
683 return rc;
684 }
685
gpio_switch_list_with_section(const char * dev_path,const char * dev_name,void * arg)686 static int gpio_switch_list_with_section(const char *dev_path,
687 const char *dev_name,
688 void *arg)
689 {
690 struct gpio_switch_list_data *data =
691 (struct gpio_switch_list_data *)arg;
692
693 if (strcmp(dev_name, data->section->jack_name)) {
694 /* No match: continue searching. */
695 return 0;
696 }
697
698 data->rc = gpio_switches_monitor_device(data, dev_path, dev_name);
699 /* Found the only possible match: stop searching. */
700 return 1;
701 }
702
703 /* Match the given jack name to the given regular expression.
704 * Args:
705 * jack_name - The jack's name.
706 * re - Regular expression string.
707 * Returns:
708 * Non-zero for success, or 0 for failure.
709 */
jack_matches_regex(const char * jack_name,const char * re)710 static int jack_matches_regex(const char *jack_name, const char *re)
711 {
712 regmatch_t m[1];
713 regex_t regex;
714 int rc;
715
716 rc = regcomp(®ex, re, REG_EXTENDED);
717 if (rc != 0) {
718 syslog(LOG_ERR, "Failed to compile regular expression: %s", re);
719 return 0;
720 }
721
722 rc = regexec(®ex, jack_name, ARRAY_SIZE(m), m, 0) == 0;
723 regfree(®ex);
724 return rc;
725 }
726
gpio_switch_list_by_matching(const char * dev_path,const char * dev_name,void * arg)727 static int gpio_switch_list_by_matching(const char *dev_path,
728 const char *dev_name,
729 void *arg)
730 {
731 struct gpio_switch_list_data *data =
732 (struct gpio_switch_list_data *)arg;
733
734 if (data->jack_list->direction == CRAS_STREAM_INPUT) {
735 if (!jack_matches_regex(dev_name, "^.*Mic Jack$") &&
736 !jack_matches_regex(dev_name, "^.*Headset Jack$")) {
737 /* Continue searching. */
738 return 0;
739 }
740 }
741 else if (data->jack_list->direction == CRAS_STREAM_OUTPUT) {
742 if (!jack_matches_regex(dev_name, "^.*Headphone Jack$") &&
743 !jack_matches_regex(dev_name, "^.*Headset Jack$") &&
744 !jack_matches_regex(dev_name, "^.*HDMI Jack$")) {
745 /* Continue searching. */
746 return 0;
747 }
748 }
749
750 data->rc = gpio_switches_monitor_device(data, dev_path, dev_name);
751 /* Stop searching for failure. */
752 return data->rc;
753 }
754
755 /* Find GPIO jacks for this jack_list.
756 * Args:
757 * jack_list - Jack list to add to.
758 * section - UCM section.
759 * result_jack - Filled with a pointer to the resulting cras_alsa_jack.
760 * Returns:
761 * 0 for success, or negative on error. Assumes success if no jack is
762 * found, or if the jack could not be accessed.
763 */
find_gpio_jacks(struct cras_alsa_jack_list * jack_list,struct ucm_section * section,struct cras_alsa_jack ** result_jack)764 static int find_gpio_jacks(struct cras_alsa_jack_list *jack_list,
765 struct ucm_section *section,
766 struct cras_alsa_jack **result_jack)
767 {
768 /* GPIO switches are on Arm-based machines, and are
769 * only associated with on-board devices.
770 */
771 struct gpio_switch_list_data data;
772 int rc;
773
774 rc = wait_for_dev_input_access();
775 if (rc != 0) {
776 syslog(LOG_WARNING, "Could not access /dev/input/event0: %s",
777 strerror(rc));
778 return 0;
779 }
780
781 data.jack_list = jack_list;
782 data.section = section;
783 data.result_jack = NULL;
784 data.rc = 0;
785
786 if (section)
787 gpio_switch_list_for_each(
788 gpio_switch_list_with_section, &data);
789 else
790 gpio_switch_list_for_each(
791 gpio_switch_list_by_matching, &data);
792 if (result_jack)
793 *result_jack = data.result_jack;
794 return data.rc;
795 }
796
797 /* Callback from alsa when a jack control changes. This is registered with
798 * snd_hctl_elem_set_callback in find_jack_controls and run by calling
799 * snd_hctl_handle_events in alsa_control_event_pending below.
800 * Args:
801 * elem - The ALSA control element that has changed.
802 * mask - unused.
803 */
hctl_jack_cb(snd_hctl_elem_t * elem,unsigned int mask)804 static int hctl_jack_cb(snd_hctl_elem_t *elem, unsigned int mask)
805 {
806 const char *name;
807 snd_ctl_elem_value_t *elem_value;
808 struct cras_alsa_jack *jack;
809
810 jack = snd_hctl_elem_get_callback_private(elem);
811 if (jack == NULL) {
812 syslog(LOG_ERR, "Invalid jack from control event.");
813 return -EINVAL;
814 }
815
816 snd_ctl_elem_value_alloca(&elem_value);
817 snd_hctl_elem_read(elem, elem_value);
818 name = snd_hctl_elem_get_name(elem);
819
820 syslog(LOG_DEBUG,
821 "Jack %s %s",
822 name,
823 snd_ctl_elem_value_get_boolean(elem_value, 0) ? "plugged"
824 : "unplugged");
825 jack_state_change_cb(jack, 1);
826 return 0;
827 }
828
829 /* Determines the device associated with this jack if any. If the device cannot
830 * be determined (common case), assume device 0. */
hctl_jack_device_index(const char * name)831 static unsigned int hctl_jack_device_index(const char *name)
832 {
833 /* Look for the substring 'pcm=<device number>' in the element name. */
834 static const char pcm_search[] = "pcm=";
835 const char *substr;
836 int device_index;
837
838 substr = strstr(name, pcm_search);
839 if (substr == NULL)
840 return 0;
841 substr += ARRAY_SIZE(pcm_search) - 1;
842 if (*substr == '\0')
843 return 0;
844 device_index = atoi(substr);
845 if (device_index < 0)
846 return 0;
847 return (unsigned int)device_index;
848 }
849
850 /* For non-gpio jack, check if it's of type hdmi/dp by
851 * matching jack name. */
is_jack_hdmi_dp(const char * jack_name)852 static int is_jack_hdmi_dp(const char *jack_name)
853 {
854 static const char *hdmi_dp = "HDMI/DP";
855 return strncmp(jack_name, hdmi_dp, strlen(hdmi_dp)) == 0;
856 }
857
858 /* Checks if the given control name is in the supplied list of possible jack
859 * control base names. */
is_jack_control_in_list(const char * const * list,unsigned int list_length,const char * control_name)860 static int is_jack_control_in_list(const char * const *list,
861 unsigned int list_length,
862 const char *control_name)
863 {
864 unsigned int i;
865
866 for (i = 0; i < list_length; i++)
867 if (strncmp(control_name, list[i], strlen(list[i])) == 0)
868 return 1;
869 return 0;
870 }
871
872 /* Check if the given name is a jack created for the connector control of a
873 * input/output terminal entity on a USB Audio Class 2.0 device. */
is_jack_uac2(const char * jack_name,enum CRAS_STREAM_DIRECTION direction)874 static int is_jack_uac2(const char *jack_name,
875 enum CRAS_STREAM_DIRECTION direction)
876 {
877 return jack_matches_regex(jack_name, direction == CRAS_STREAM_OUTPUT ?
878 "^.* - Output Jack$" : "^.* - Input Jack$");
879 }
880
881 /* Looks for any JACK controls. Monitors any found controls for changes and
882 * decides to route based on plug/unlpug events. */
find_jack_controls(struct cras_alsa_jack_list * jack_list)883 static int find_jack_controls(struct cras_alsa_jack_list *jack_list)
884 {
885 snd_hctl_elem_t *elem;
886 struct cras_alsa_jack *jack;
887 const char *name;
888 static const char * const output_jack_base_names[] = {
889 "Headphone Jack",
890 "Front Headphone Jack",
891 "HDMI/DP",
892 "Speaker Phantom Jack",
893 };
894 static const char * const input_jack_base_names[] = {
895 "Mic Jack",
896 };
897 static const char eld_control_name[] = "ELD";
898 const char * const *jack_names;
899 unsigned int num_jack_names;
900
901 if (!jack_list->hctl) {
902 syslog(LOG_WARNING, "Can't search hctl for jacks.");
903 return 0;
904 }
905
906 if (jack_list->direction == CRAS_STREAM_OUTPUT) {
907 jack_names = output_jack_base_names;
908 num_jack_names = ARRAY_SIZE(output_jack_base_names);
909 } else {
910 jack_names = input_jack_base_names;
911 num_jack_names = ARRAY_SIZE(input_jack_base_names);
912 }
913
914 for (elem = snd_hctl_first_elem(jack_list->hctl); elem != NULL;
915 elem = snd_hctl_elem_next(elem)) {
916 snd_ctl_elem_iface_t iface;
917
918 iface = snd_hctl_elem_get_interface(elem);
919 if (iface != SND_CTL_ELEM_IFACE_CARD)
920 continue;
921 name = snd_hctl_elem_get_name(elem);
922 if (!is_jack_control_in_list(jack_names, num_jack_names, name) &&
923 !is_jack_uac2(name, jack_list->direction))
924 continue;
925 if (hctl_jack_device_index(name) != jack_list->device_index)
926 continue;
927
928 jack = cras_alloc_jack(0);
929 if (jack == NULL)
930 return -ENOMEM;
931 jack->elem = elem;
932 jack->jack_list = jack_list;
933 DL_APPEND(jack_list->jacks, jack);
934
935 snd_hctl_elem_set_callback(elem, hctl_jack_cb);
936 snd_hctl_elem_set_callback_private(elem, jack);
937
938 if (jack_list->direction == CRAS_STREAM_OUTPUT)
939 jack->mixer_output =
940 cras_alsa_mixer_get_output_matching_name(
941 jack_list->mixer,
942 name);
943 if (jack_list->ucm)
944 jack->ucm_device =
945 ucm_get_dev_for_jack(jack_list->ucm, name,
946 jack_list->direction);
947
948 if (jack->ucm_device && jack_list->direction == CRAS_STREAM_INPUT) {
949 char *control_name;
950 control_name = ucm_get_cap_control(jack->jack_list->ucm,
951 jack->ucm_device);
952 if (control_name)
953 jack->mixer_input =
954 cras_alsa_mixer_get_input_matching_name(
955 jack_list->mixer,
956 control_name);
957 }
958
959 if (jack->ucm_device) {
960 jack->dsp_name = ucm_get_dsp_name(
961 jack->jack_list->ucm, jack->ucm_device,
962 jack_list->direction);
963 jack->override_type_name = ucm_get_override_type_name(
964 jack->jack_list->ucm, jack->ucm_device);
965 }
966 }
967
968 /* Look up ELD controls */
969 DL_FOREACH(jack_list->jacks, jack) {
970 if (jack->is_gpio || jack->eld_control)
971 continue;
972 name = snd_hctl_elem_get_name(jack->elem);
973 if (!is_jack_hdmi_dp(name))
974 continue;
975 for (elem = snd_hctl_first_elem(jack_list->hctl); elem != NULL;
976 elem = snd_hctl_elem_next(elem)) {
977 if (strcmp(snd_hctl_elem_get_name(elem),
978 eld_control_name))
979 continue;
980 if (snd_hctl_elem_get_device(elem)
981 != jack_list->device_index)
982 continue;
983 jack->eld_control = elem;
984 break;
985 }
986 }
987
988 return 0;
989 }
990
991 /*
992 * Exported Interface.
993 */
994
cras_alsa_jack_list_find_jacks_by_name_matching(struct cras_alsa_jack_list * jack_list)995 int cras_alsa_jack_list_find_jacks_by_name_matching(
996 struct cras_alsa_jack_list *jack_list)
997 {
998 int rc;
999
1000 rc = find_jack_controls(jack_list);
1001 if (rc != 0)
1002 return rc;
1003
1004 return find_gpio_jacks(jack_list, NULL, NULL);
1005 }
1006
find_hctl_jack_for_section(struct cras_alsa_jack_list * jack_list,struct ucm_section * section,struct cras_alsa_jack ** result_jack)1007 static int find_hctl_jack_for_section(
1008 struct cras_alsa_jack_list *jack_list,
1009 struct ucm_section *section,
1010 struct cras_alsa_jack **result_jack)
1011 {
1012 static const char eld_control_name[] = "ELD";
1013 snd_hctl_elem_t *elem;
1014 snd_ctl_elem_id_t *elem_id;
1015 struct cras_alsa_jack *jack;
1016
1017 if (!jack_list->hctl) {
1018 syslog(LOG_WARNING, "Can't search hctl for jacks.");
1019 return -ENODEV;
1020 }
1021
1022 snd_ctl_elem_id_alloca(&elem_id);
1023 snd_ctl_elem_id_clear(elem_id);
1024 snd_ctl_elem_id_set_interface(elem_id, SND_CTL_ELEM_IFACE_CARD);
1025 snd_ctl_elem_id_set_device(elem_id, jack_list->device_index);
1026 snd_ctl_elem_id_set_name(elem_id, section->jack_name);
1027 elem = snd_hctl_find_elem(jack_list->hctl, elem_id);
1028 if (!elem)
1029 return -ENOENT;
1030
1031 syslog(LOG_DEBUG, "Found Jack: %s for %s",
1032 section->jack_name, section->name);
1033
1034 jack = cras_alloc_jack(0);
1035 if (jack == NULL)
1036 return -ENOMEM;
1037 jack->elem = elem;
1038 jack->jack_list = jack_list;
1039
1040 jack->ucm_device = strdup(section->name);
1041 if (!jack->ucm_device) {
1042 free(jack);
1043 return -ENOMEM;
1044 }
1045 if (jack_list->direction == CRAS_STREAM_OUTPUT)
1046 jack->mixer_output = cras_alsa_mixer_get_control_for_section(
1047 jack_list->mixer, section);
1048 else if (jack_list->direction == CRAS_STREAM_INPUT)
1049 jack->mixer_input = cras_alsa_mixer_get_control_for_section(
1050 jack_list->mixer, section);
1051
1052 jack->dsp_name = ucm_get_dsp_name(
1053 jack->jack_list->ucm, jack->ucm_device,
1054 jack_list->direction);
1055
1056 snd_hctl_elem_set_callback(elem, hctl_jack_cb);
1057 snd_hctl_elem_set_callback_private(elem, jack);
1058 DL_APPEND(jack_list->jacks, jack);
1059 if (result_jack)
1060 *result_jack = jack;
1061
1062 if (!strcmp(jack->ucm_device, "HDMI") ||
1063 !strcmp(jack->ucm_device, "DP"))
1064 return 0;
1065
1066 /* Look up ELD control. */
1067 snd_ctl_elem_id_set_name(elem_id, eld_control_name);
1068 elem = snd_hctl_find_elem(jack_list->hctl, elem_id);
1069 if (elem)
1070 jack->eld_control = elem;
1071 return 0;
1072 }
1073
1074 /*
1075 * Exported Interface.
1076 */
1077
cras_alsa_jack_list_add_jack_for_section(struct cras_alsa_jack_list * jack_list,struct ucm_section * ucm_section,struct cras_alsa_jack ** result_jack)1078 int cras_alsa_jack_list_add_jack_for_section(
1079 struct cras_alsa_jack_list *jack_list,
1080 struct ucm_section *ucm_section,
1081 struct cras_alsa_jack **result_jack)
1082 {
1083 if (result_jack)
1084 *result_jack = NULL;
1085 if (!ucm_section)
1086 return -EINVAL;
1087
1088 if (!ucm_section->jack_name) {
1089 /* No jacks defined for this device. */
1090 return 0;
1091 }
1092
1093 if (!ucm_section->jack_type) {
1094 syslog(LOG_ERR,
1095 "Must specify the JackType for jack '%s' in '%s'.",
1096 ucm_section->jack_name, ucm_section->name);
1097 return -EINVAL;
1098 }
1099
1100 if (!strcmp(ucm_section->jack_type, "hctl")) {
1101 return find_hctl_jack_for_section(
1102 jack_list, ucm_section, result_jack);
1103 } else if (!strcmp(ucm_section->jack_type, "gpio")) {
1104 return find_gpio_jacks(jack_list, ucm_section, result_jack);
1105 } else {
1106 syslog(LOG_ERR,
1107 "Invalid JackType '%s' in '%s'.",
1108 ucm_section->jack_type, ucm_section->name);
1109 return -EINVAL;
1110 }
1111 }
1112
cras_alsa_jack_list_create(unsigned int card_index,const char * card_name,unsigned int device_index,int is_first_device,struct cras_alsa_mixer * mixer,struct cras_use_case_mgr * ucm,snd_hctl_t * hctl,enum CRAS_STREAM_DIRECTION direction,jack_state_change_callback * cb,void * cb_data)1113 struct cras_alsa_jack_list *cras_alsa_jack_list_create(
1114 unsigned int card_index,
1115 const char *card_name,
1116 unsigned int device_index,
1117 int is_first_device,
1118 struct cras_alsa_mixer *mixer,
1119 struct cras_use_case_mgr *ucm,
1120 snd_hctl_t *hctl,
1121 enum CRAS_STREAM_DIRECTION direction,
1122 jack_state_change_callback *cb,
1123 void *cb_data)
1124 {
1125 struct cras_alsa_jack_list *jack_list;
1126
1127 if (direction != CRAS_STREAM_INPUT && direction != CRAS_STREAM_OUTPUT)
1128 return NULL;
1129
1130 jack_list = (struct cras_alsa_jack_list *)calloc(1, sizeof(*jack_list));
1131 if (jack_list == NULL)
1132 return NULL;
1133
1134 jack_list->change_callback = cb;
1135 jack_list->callback_data = cb_data;
1136 jack_list->mixer = mixer;
1137 jack_list->ucm = ucm;
1138 jack_list->hctl = hctl;
1139 jack_list->card_index = card_index;
1140 jack_list->card_name = card_name;
1141 jack_list->device_index = device_index;
1142 jack_list->is_first_device = is_first_device;
1143 jack_list->direction = direction;
1144
1145 return jack_list;
1146 }
1147
cras_alsa_jack_list_destroy(struct cras_alsa_jack_list * jack_list)1148 void cras_alsa_jack_list_destroy(struct cras_alsa_jack_list *jack_list)
1149 {
1150 struct cras_alsa_jack *jack;
1151
1152 if (jack_list == NULL)
1153 return;
1154 DL_FOREACH(jack_list->jacks, jack) {
1155 DL_DELETE(jack_list->jacks, jack);
1156 cras_free_jack(jack, 1);
1157 }
1158 free(jack_list);
1159 }
1160
cras_alsa_jack_list_has_hctl_jacks(struct cras_alsa_jack_list * jack_list)1161 int cras_alsa_jack_list_has_hctl_jacks(struct cras_alsa_jack_list *jack_list)
1162 {
1163 struct cras_alsa_jack *jack;
1164
1165 if (!jack_list)
1166 return 0;
1167 DL_FOREACH(jack_list->jacks, jack) {
1168 if (!jack->is_gpio)
1169 return 1;
1170 }
1171 return 0;
1172 }
1173
cras_alsa_jack_get_mixer_output(const struct cras_alsa_jack * jack)1174 struct mixer_control *cras_alsa_jack_get_mixer_output(
1175 const struct cras_alsa_jack *jack)
1176 {
1177 if (jack == NULL)
1178 return NULL;
1179 return jack->mixer_output;
1180 }
1181
cras_alsa_jack_get_mixer_input(const struct cras_alsa_jack * jack)1182 struct mixer_control *cras_alsa_jack_get_mixer_input(
1183 const struct cras_alsa_jack *jack)
1184 {
1185 return jack ? jack->mixer_input : NULL;
1186 }
1187
cras_alsa_jack_list_report(const struct cras_alsa_jack_list * jack_list)1188 void cras_alsa_jack_list_report(const struct cras_alsa_jack_list *jack_list)
1189 {
1190 struct cras_alsa_jack *jack;
1191
1192 if (jack_list == NULL)
1193 return;
1194
1195 DL_FOREACH(jack_list->jacks, jack)
1196 if (jack->is_gpio)
1197 gpio_switch_initial_state(jack);
1198 else
1199 hctl_jack_cb(jack->elem, 0);
1200 }
1201
cras_alsa_jack_get_name(const struct cras_alsa_jack * jack)1202 const char *cras_alsa_jack_get_name(const struct cras_alsa_jack *jack)
1203 {
1204 if (jack == NULL)
1205 return NULL;
1206 if (jack->is_gpio)
1207 return jack->gpio.device_name;
1208 return snd_hctl_elem_get_name(jack->elem);
1209 }
1210
cras_alsa_jack_get_ucm_device(const struct cras_alsa_jack * jack)1211 const char *cras_alsa_jack_get_ucm_device(const struct cras_alsa_jack *jack)
1212 {
1213 return jack->ucm_device;
1214 }
1215
cras_alsa_jack_update_monitor_name(const struct cras_alsa_jack * jack,char * name_buf,unsigned int buf_size)1216 void cras_alsa_jack_update_monitor_name(const struct cras_alsa_jack *jack,
1217 char *name_buf,
1218 unsigned int buf_size)
1219 {
1220 snd_ctl_elem_value_t *elem_value;
1221 snd_ctl_elem_info_t *elem_info;
1222 const char *buf = NULL;
1223 int count;
1224 int mnl = 0;
1225
1226 if (!jack->eld_control) {
1227 if (jack->edid_file)
1228 get_jack_edid_monitor_name(jack, name_buf, buf_size);
1229 return;
1230 }
1231
1232 snd_ctl_elem_info_alloca(&elem_info);
1233 if (snd_hctl_elem_info(jack->eld_control, elem_info) < 0)
1234 goto fallback_jack_name;
1235
1236 count = snd_ctl_elem_info_get_count(elem_info);
1237 if (count <= ELD_MNL_OFFSET)
1238 goto fallback_jack_name;
1239
1240 snd_ctl_elem_value_alloca(&elem_value);
1241 if (snd_hctl_elem_read(jack->eld_control, elem_value) < 0)
1242 goto fallback_jack_name;
1243
1244 buf = (const char *)snd_ctl_elem_value_get_bytes(elem_value);
1245 mnl = buf[ELD_MNL_OFFSET] & ELD_MNL_MASK;
1246
1247 if (count < ELD_MONITOR_NAME_OFFSET + mnl)
1248 goto fallback_jack_name;
1249
1250 /* Note that monitor name string does not contain terminate character.
1251 * Check monitor name length with name buffer size.
1252 */
1253 if (mnl >= buf_size)
1254 mnl = buf_size - 1;
1255 strncpy(name_buf, buf + ELD_MONITOR_NAME_OFFSET, mnl);
1256 name_buf[mnl] = '\0';
1257
1258 return;
1259
1260 fallback_jack_name:
1261 buf = cras_alsa_jack_get_name(jack);
1262 strncpy(name_buf, buf, buf_size - 1);
1263
1264 return;
1265 }
1266
cras_alsa_jack_update_node_type(const struct cras_alsa_jack * jack,enum CRAS_NODE_TYPE * type)1267 void cras_alsa_jack_update_node_type(const struct cras_alsa_jack *jack,
1268 enum CRAS_NODE_TYPE *type)
1269 {
1270 if (!jack->override_type_name)
1271 return;
1272 if (!strcmp(jack->override_type_name, "Internal Speaker"))
1273 *type = CRAS_NODE_TYPE_INTERNAL_SPEAKER;
1274 return;
1275 }
1276
cras_alsa_jack_get_dsp_name(const struct cras_alsa_jack * jack)1277 const char *cras_alsa_jack_get_dsp_name(const struct cras_alsa_jack *jack)
1278 {
1279 if (jack == NULL)
1280 return NULL;
1281 return jack->dsp_name;
1282 }
1283
cras_alsa_jack_enable_ucm(const struct cras_alsa_jack * jack,int enable)1284 void cras_alsa_jack_enable_ucm(const struct cras_alsa_jack *jack, int enable)
1285 {
1286 if (jack && jack->ucm_device)
1287 ucm_set_enabled(jack->jack_list->ucm, jack->ucm_device, enable);
1288 }
1289