1 /* Copyright 2016 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 <stdlib.h>
7 #include <string.h>
8 #include <syslog.h>
9 
10 #include "cras_alsa_ucm_section.h"
11 #include "cras_alsa_mixer_name.h"
12 #include "utlist.h"
13 
14 static void ucm_section_free(struct ucm_section *section) {
15 	if (section->name)
16 		free((void *)section->name);
17 	if (section->jack_name)
18 		free((void *)section->jack_name);
19 	if (section->jack_type)
20 		free((void *)section->jack_type);
21 	if (section->mixer_name)
22 		free((void *)section->mixer_name);
23 	mixer_name_free(section->coupled);
24 	free(section);
25 }
26 
27 void ucm_section_free_list(struct ucm_section *sections)
28 {
29 	struct ucm_section *section;
30 	DL_FOREACH(sections, section) {
31 		DL_DELETE(sections, section);
32 		ucm_section_free(section);
33 	}
34 }
35 
36 struct ucm_section *ucm_section_create(const char *name,
37 				       int dev_idx,
38 				       enum CRAS_STREAM_DIRECTION dir,
39 				       const char *jack_name,
40 				       const char *jack_type)
41 {
42 	struct ucm_section *section_list = NULL;
43 	struct ucm_section *section;
44 
45 	if (!name)
46 		return NULL;
47 
48 	section = (struct ucm_section *)
49 		  calloc(1, sizeof(struct ucm_section));
50 	if (!section)
51 		return NULL;
52 
53 	section->dev_idx = dev_idx;
54 	section->dir = dir;
55 	section->name = strdup(name);
56 	if (!section->name)
57 		goto error;
58 
59 	if (jack_name) {
60 		section->jack_name = strdup(jack_name);
61 		if (!section->jack_name)
62 			goto error;
63 	}
64 	if (jack_type) {
65 		section->jack_type = strdup(jack_type);
66 		if (!section->jack_type)
67 			goto error;
68 	}
69 	/* Default to -1 which means auto-detect. */
70 	section->jack_switch = -1;
71 
72 	/* Make sure to initialize this item as a list. */
73 	DL_APPEND(section_list, section);
74 	return section_list;
75 
76 error:
77 	ucm_section_free(section);
78 	return NULL;
79 }
80 
81 int ucm_section_set_mixer_name(struct ucm_section *section,
82 			       const char *name)
83 {
84 	if (!section || !name)
85 		return -EINVAL;
86 
87 	if (section->mixer_name)
88 		free((void *)section->mixer_name);
89 	section->mixer_name = strdup(name);
90 	if (!section->mixer_name)
91 		return -ENOMEM;
92 	return 0;
93 }
94 
95 int ucm_section_add_coupled(struct ucm_section *section,
96 			    const char *name,
97 			    mixer_name_type type)
98 {
99 	struct mixer_name *m_name;
100 
101 	if (!section || !name || type == MIXER_NAME_UNDEFINED)
102 		return -EINVAL;
103 
104 	m_name = mixer_name_add(NULL, name, section->dir, type);
105 	if (!m_name)
106 		return -ENOMEM;
107 	DL_APPEND(section->coupled, m_name);
108 	return 0;
109 }
110 
111 int ucm_section_concat_coupled(struct ucm_section *section,
112 			       struct mixer_name *coupled)
113 {
114 	if (!section || !coupled)
115 		return -EINVAL;
116 	DL_CONCAT(section->coupled, coupled);
117 	return 0;
118 }
119 
120 void ucm_section_dump(struct ucm_section *section)
121 {
122 	syslog(LOG_DEBUG, "section: %s [%d] (%s)",
123 		section->name, section->dev_idx,
124 		section->dir == CRAS_STREAM_OUTPUT ? "output" : "input");
125 	syslog(LOG_DEBUG, "  jack: %s %s",
126 		section->jack_name, section->jack_type);
127 	syslog(LOG_DEBUG, "  mixer_name: %s", section->mixer_name);
128 	mixer_name_dump(section->coupled, "  coupled");
129 }
130