1 /*
2  *  This library is free software; you can redistribute it and/or
3  *  modify it under the terms of the GNU Lesser General Public
4  *  License as published by the Free Software Foundation; either
5  *  version 2 of the License, or (at your option) any later version.
6  *
7  *  This library is distributed in the hope that it will be useful,
8  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10  *  Lesser General Public License for more details.
11  *
12  *  You should have received a copy of the GNU Lesser General Public
13  *  License along with this library; if not, write to the Free Software
14  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
15  *
16  *  Support for the verb/device/modifier core logic and API,
17  *  command line tool and file parser was kindly sponsored by
18  *  Texas Instruments Inc.
19  *  Support for multiple active modifiers and devices,
20  *  transition sequences, multiple client access and user defined use
21  *  cases was kindly sponsored by Wolfson Microelectronics PLC.
22  *
23  *  Copyright (C) 2008-2010 SlimLogic Ltd
24  *  Copyright (C) 2010 Wolfson Microelectronics PLC
25  *  Copyright (C) 2010 Texas Instruments Inc.
26  *  Copyright (C) 2010 Red Hat Inc.
27  *  Authors: Liam Girdwood <lrg@slimlogic.co.uk>
28  *	         Stefan Schmidt <stefan@slimlogic.co.uk>
29  *	         Justin Xu <justinx@slimlogic.co.uk>
30  *               Jaroslav Kysela <perex@perex.cz>
31  */
32 
33 
34 
35 #if 0
36 #define UC_MGR_DEBUG
37 #endif
38 
39 #include "local.h"
40 #include <pthread.h>
41 #include "use-case.h"
42 
43 #define SYNTAX_VERSION_MAX	2
44 
45 #define MAX_CARD_SHORT_NAME	32
46 #define MAX_CARD_LONG_NAME	80
47 
48 #define SEQUENCE_ELEMENT_TYPE_CDEV	1
49 #define SEQUENCE_ELEMENT_TYPE_CSET	2
50 #define SEQUENCE_ELEMENT_TYPE_SLEEP	3
51 #define SEQUENCE_ELEMENT_TYPE_EXEC	4
52 #define SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE	5
53 #define SEQUENCE_ELEMENT_TYPE_CSET_TLV	6
54 #define SEQUENCE_ELEMENT_TYPE_CMPT_SEQ	7
55 
56 struct ucm_value {
57         struct list_head list;
58         char *name;
59         char *data;
60 };
61 
62 /* sequence of a component device */
63 struct component_sequence {
64 	struct use_case_device *device; /* component device */
65 	int enable; /* flag to choose enable or disable list of the device */
66 };
67 
68 struct sequence_element {
69 	struct list_head list;
70 	unsigned int type;
71 	union {
72 		long sleep; /* Sleep time in microseconds if sleep element, else 0 */
73 		char *cdev;
74 		char *cset;
75 		char *exec;
76 		struct component_sequence cmpt_seq; /* component sequence */
77 	} data;
78 };
79 
80 /*
81  * Transition sequences. i.e. transition between one verb, device, mod to another
82  */
83 struct transition_sequence {
84 	struct list_head list;
85 	char *name;
86 	struct list_head transition_list;
87 };
88 
89 /*
90  * Modifier Supported Devices.
91  */
92 enum dev_list_type {
93 	DEVLIST_NONE,
94 	DEVLIST_SUPPORTED,
95 	DEVLIST_CONFLICTING
96 };
97 
98 struct dev_list_node {
99 	struct list_head list;
100 	char *name;
101 };
102 
103 struct dev_list {
104 	enum dev_list_type type;
105 	struct list_head list;
106 };
107 
108 struct ctl_dev {
109 	struct list_head list;
110 	char *device;
111 };
112 
113 struct ctl_list {
114 	struct list_head list;
115 	struct list_head dev_list;
116 	snd_ctl_t *ctl;
117 	snd_ctl_card_info_t *ctl_info;
118 };
119 
120 struct ucm_dev_name {
121 	struct list_head list;
122 	char *name1;
123 	char *name2;
124 };
125 
126 /*
127  * Describes a Use Case Modifier and it's enable and disable sequences.
128  * A use case verb can have N modifiers.
129  */
130 struct use_case_modifier {
131 	struct list_head list;
132 	struct list_head active_list;
133 
134 	char *name;
135 	char *comment;
136 
137 	/* modifier enable and disable sequences */
138 	struct list_head enable_list;
139 	struct list_head disable_list;
140 
141 	/* modifier transition list */
142 	struct list_head transition_list;
143 
144 	/* list of devices supported or conflicting */
145 	struct dev_list dev_list;
146 
147 	/* values */
148 	struct list_head value_list;
149 };
150 
151 /*
152  * Describes a Use Case Device and it's enable and disable sequences.
153  * A use case verb can have N devices.
154  */
155 struct use_case_device {
156 	struct list_head list;
157 	struct list_head active_list;
158 
159 	char *name;
160 	char *comment;
161 
162 	/* device enable and disable sequences */
163 	struct list_head enable_list;
164 	struct list_head disable_list;
165 
166 	/* device transition list */
167 	struct list_head transition_list;
168 
169 	/* list of devices supported or conflicting */
170 	struct dev_list dev_list;
171 
172 	/* value list */
173 	struct list_head value_list;
174 };
175 
176 /*
177  * Describes a Use Case Verb and it's enable and disable sequences.
178  * A use case verb can have N devices and N modifiers.
179  */
180 struct use_case_verb {
181 	struct list_head list;
182 
183 	unsigned int active: 1;
184 
185 	char *name;
186 	char *comment;
187 
188 	/* verb enable and disable sequences */
189 	struct list_head enable_list;
190 	struct list_head disable_list;
191 
192 	/* verb transition list */
193 	struct list_head transition_list;
194 
195 	struct list_head device_list;
196 
197 	/* component device list */
198 	struct list_head cmpt_device_list;
199 
200 	/* modifiers that can be used with this use case */
201 	struct list_head modifier_list;
202 
203 	/* value list */
204 	struct list_head value_list;
205 
206 	/* temporary modifications lists */
207 	struct list_head rename_list;
208 	struct list_head remove_list;
209 };
210 
211 /*
212  *  Manages a sound card and all its use cases.
213  */
214 struct snd_use_case_mgr {
215 	char *card_name;
216 	char *conf_file_name;
217 	char *conf_dir_name;
218 	char *comment;
219 	int conf_format;
220 
221 	/* use case verb, devices and modifier configs parsed from files */
222 	struct list_head verb_list;
223 
224 	/* default settings - sequence */
225 	struct list_head default_list;
226 
227 	/* default settings - value list */
228 	struct list_head value_list;
229 
230 	/* current status */
231 	struct use_case_verb *active_verb;
232 	struct list_head active_devices;
233 	struct list_head active_modifiers;
234 
235 	/* locking */
236 	pthread_mutex_t mutex;
237 
238 	/* list of opened control devices */
239 	struct list_head ctl_list;
240 
241 	/* Components don't define cdev, the card device. When executing
242 	 * a sequence of a component device, ucm manager enters component
243 	 * domain and needs to provide cdev to the component. This cdev
244 	 * should be defined by the machine, parent of the component.
245 	 */
246 	int in_component_domain;
247 	char *cdev;
248 };
249 
250 #define uc_error SNDERR
251 
252 #ifdef UC_MGR_DEBUG
253 #define uc_dbg SNDERR
254 #else
255 #define uc_dbg(fmt, arg...) do { } while (0)
256 #endif
257 
258 void uc_mgr_error(const char *fmt, ...);
259 void uc_mgr_stdout(const char *fmt, ...);
260 
261 int uc_mgr_config_load(int format, const char *file, snd_config_t **cfg);
262 int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr);
263 int uc_mgr_scan_master_configs(const char **_list[]);
264 
265 int uc_mgr_put_to_dev_list(struct dev_list *dev_list, const char *name);
266 int uc_mgr_remove_device(struct use_case_verb *verb, const char *name);
267 int uc_mgr_rename_device(struct use_case_verb *verb, const char *src,
268 			 const char *dst);
269 
270 void uc_mgr_free_dev_name_list(struct list_head *base);
271 void uc_mgr_free_sequence_element(struct sequence_element *seq);
272 void uc_mgr_free_transition_element(struct transition_sequence *seq);
273 void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr);
274 void uc_mgr_free(snd_use_case_mgr_t *uc_mgr);
275 
276 int uc_mgr_open_ctl(snd_use_case_mgr_t *uc_mgr,
277                     snd_ctl_t **ctl,
278                     const char *device);
279 
280 struct ctl_list *uc_mgr_get_one_ctl(snd_use_case_mgr_t *uc_mgr);
281 snd_ctl_t *uc_mgr_get_ctl(snd_use_case_mgr_t *uc_mgr);
282 void uc_mgr_free_ctl_list(snd_use_case_mgr_t *uc_mgr);
283 
284 int uc_mgr_add_value(struct list_head *base, const char *key, char *val);
285 
286 int uc_mgr_get_substituted_value(snd_use_case_mgr_t *uc_mgr,
287 				 char **_rvalue,
288 				 const char *value);
289 
290 int uc_mgr_evaluate_condition(snd_use_case_mgr_t *uc_mgr,
291 			      snd_config_t *parent,
292 			      snd_config_t *cond);
293 
294 /** The name of the environment variable containing the UCM directory */
295 #define ALSA_CONFIG_UCM_VAR "ALSA_CONFIG_UCM"
296 
297 /** The name of the environment variable containing the UCM directory (new syntax) */
298 #define ALSA_CONFIG_UCM2_VAR "ALSA_CONFIG_UCM2"
299