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
14static 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
27void 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
36struct 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
76error:
77	ucm_section_free(section);
78	return NULL;
79}
80
81int 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
95int 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
111int 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
120void 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