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 5
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_SHELL 5
53 #define SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE 6
54 #define SEQUENCE_ELEMENT_TYPE_CSET_TLV 7
55 #define SEQUENCE_ELEMENT_TYPE_CSET_NEW 8
56 #define SEQUENCE_ELEMENT_TYPE_CTL_REMOVE 9
57 #define SEQUENCE_ELEMENT_TYPE_CMPT_SEQ 10
58 #define SEQUENCE_ELEMENT_TYPE_SYSSET 11
59 #define SEQUENCE_ELEMENT_TYPE_CFGSAVE 12
60
61 struct ucm_value {
62 struct list_head list;
63 char *name;
64 char *data;
65 };
66
67 /* sequence of a component device */
68 struct component_sequence {
69 struct use_case_device *device; /* component device */
70 int enable; /* flag to choose enable or disable list of the device */
71 };
72
73 struct sequence_element {
74 struct list_head list;
75 unsigned int type;
76 union {
77 long sleep; /* Sleep time in microseconds if sleep element, else 0 */
78 char *cdev;
79 char *cset;
80 char *exec;
81 char *sysw;
82 char *cfgsave;
83 struct component_sequence cmpt_seq; /* component sequence */
84 } data;
85 };
86
87 /*
88 * Transition sequences. i.e. transition between one verb, device, mod to another
89 */
90 struct transition_sequence {
91 struct list_head list;
92 char *name;
93 struct list_head transition_list;
94 };
95
96 /*
97 * Modifier Supported Devices.
98 */
99 enum dev_list_type {
100 DEVLIST_NONE,
101 DEVLIST_SUPPORTED,
102 DEVLIST_CONFLICTING
103 };
104
105 struct dev_list_node {
106 struct list_head list;
107 char *name;
108 };
109
110 struct dev_list {
111 enum dev_list_type type;
112 struct list_head list;
113 };
114
115 struct ctl_dev {
116 struct list_head list;
117 char *device;
118 };
119
120 struct ctl_list {
121 struct list_head list;
122 struct list_head dev_list;
123 snd_ctl_t *ctl;
124 snd_ctl_card_info_t *ctl_info;
125 int slave;
126 int ucm_group;
127 };
128
129 struct ucm_dev_name {
130 struct list_head list;
131 char *name1;
132 char *name2;
133 };
134
135 /*
136 * Describes a Use Case Modifier and it's enable and disable sequences.
137 * A use case verb can have N modifiers.
138 */
139 struct use_case_modifier {
140 struct list_head list;
141 struct list_head active_list;
142
143 char *name;
144 char *comment;
145
146 /* modifier enable and disable sequences */
147 struct list_head enable_list;
148 struct list_head disable_list;
149
150 /* modifier transition list */
151 struct list_head transition_list;
152
153 /* list of devices supported or conflicting */
154 struct dev_list dev_list;
155
156 /* values */
157 struct list_head value_list;
158 };
159
160 /*
161 * Describes a Use Case Device and it's enable and disable sequences.
162 * A use case verb can have N devices.
163 */
164 struct use_case_device {
165 struct list_head list;
166 struct list_head active_list;
167
168 char *name;
169 char *comment;
170
171 /* device enable and disable sequences */
172 struct list_head enable_list;
173 struct list_head disable_list;
174
175 /* device transition list */
176 struct list_head transition_list;
177
178 /* list of devices supported or conflicting */
179 struct dev_list dev_list;
180
181 /* value list */
182 struct list_head value_list;
183 };
184
185 /*
186 * Describes a Use Case Verb and it's enable and disable sequences.
187 * A use case verb can have N devices and N modifiers.
188 */
189 struct use_case_verb {
190 struct list_head list;
191
192 unsigned int active: 1;
193
194 char *name;
195 char *comment;
196
197 /* verb enable and disable sequences */
198 struct list_head enable_list;
199 struct list_head disable_list;
200
201 /* verb transition list */
202 struct list_head transition_list;
203
204 struct list_head device_list;
205
206 /* component device list */
207 struct list_head cmpt_device_list;
208
209 /* modifiers that can be used with this use case */
210 struct list_head modifier_list;
211
212 /* value list */
213 struct list_head value_list;
214
215 /* temporary modifications lists */
216 struct list_head rename_list;
217 struct list_head remove_list;
218 };
219
220 /*
221 * Manages a sound card and all its use cases.
222 */
223 struct snd_use_case_mgr {
224 char *card_name;
225 char *conf_file_name;
226 char *conf_dir_name;
227 char *comment;
228 int conf_format;
229 unsigned int ucm_card_number;
230 int suppress_nodev_errors;
231
232 /* UCM cards list */
233 struct list_head cards_list;
234
235 /* use case verb, devices and modifier configs parsed from files */
236 struct list_head verb_list;
237
238 /* force boot settings - sequence */
239 struct list_head fixedboot_list;
240
241 /* boot settings - sequence */
242 struct list_head boot_list;
243
244 /* default settings - sequence */
245 struct list_head default_list;
246 int default_list_executed;
247
248 /* default settings - value list */
249 struct list_head value_list;
250
251 /* current status */
252 struct use_case_verb *active_verb;
253 struct list_head active_devices;
254 struct list_head active_modifiers;
255
256 /* locking */
257 pthread_mutex_t mutex;
258
259 /* UCM internal variables defined in configuration files */
260 struct list_head variable_list;
261
262 /* list of opened control devices */
263 struct list_head ctl_list;
264
265 /* local library configuration */
266 snd_config_t *local_config;
267
268 /* Components don't define cdev, the card device. When executing
269 * a sequence of a component device, ucm manager enters component
270 * domain and needs to provide cdev to the component. This cdev
271 * should be defined by the machine, parent of the component.
272 */
273 int in_component_domain;
274 char *cdev;
275 };
276
277 #define uc_error SNDERR
278
279 #ifdef UC_MGR_DEBUG
280 #define uc_dbg SNDERR
281 #else
282 #define uc_dbg(fmt, arg...) do { } while (0)
283 #endif
284
285 void uc_mgr_error(const char *fmt, ...);
286 void uc_mgr_stdout(const char *fmt, ...);
287
288 const char *uc_mgr_sysfs_root(void);
289 const char *uc_mgr_config_dir(int format);
290 int uc_mgr_config_load_into(int format, const char *file, snd_config_t *cfg);
291 int uc_mgr_config_load(int format, const char *file, snd_config_t **cfg);
292 int uc_mgr_config_load_file(snd_use_case_mgr_t *uc_mgr, const char *file, snd_config_t **cfg);
293 int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr);
294 int uc_mgr_scan_master_configs(const char **_list[]);
295
296 int uc_mgr_put_to_dev_list(struct dev_list *dev_list, const char *name);
297 int uc_mgr_remove_device(struct use_case_verb *verb, const char *name);
298 int uc_mgr_rename_device(struct use_case_verb *verb, const char *src,
299 const char *dst);
300
301 void uc_mgr_free_dev_name_list(struct list_head *base);
302 void uc_mgr_free_sequence_element(struct sequence_element *seq);
303 void uc_mgr_free_transition_element(struct transition_sequence *seq);
304 void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr);
305 void uc_mgr_free(snd_use_case_mgr_t *uc_mgr);
306
uc_mgr_has_local_config(snd_use_case_mgr_t * uc_mgr)307 static inline int uc_mgr_has_local_config(snd_use_case_mgr_t *uc_mgr)
308 {
309 return uc_mgr && snd_config_iterator_first(uc_mgr->local_config) !=
310 snd_config_iterator_end(uc_mgr->local_config);
311 }
312
313 int uc_mgr_card_open(snd_use_case_mgr_t *uc_mgr);
314 void uc_mgr_card_close(snd_use_case_mgr_t *uc_mgr);
315
316 int uc_mgr_open_ctl(snd_use_case_mgr_t *uc_mgr,
317 struct ctl_list **ctl_list,
318 const char *device,
319 int slave);
320
321 struct ctl_list *uc_mgr_get_master_ctl(snd_use_case_mgr_t *uc_mgr);
322 struct ctl_list *uc_mgr_get_ctl_by_card(snd_use_case_mgr_t *uc_mgr, int card);
323 struct ctl_list *uc_mgr_get_ctl_by_name(snd_use_case_mgr_t *uc_mgr,
324 const char *name, int idx);
325 snd_ctl_t *uc_mgr_get_ctl(snd_use_case_mgr_t *uc_mgr);
326 void uc_mgr_free_ctl_list(snd_use_case_mgr_t *uc_mgr);
327
328 int uc_mgr_add_value(struct list_head *base, const char *key, char *val);
329
330 const char *uc_mgr_get_variable(snd_use_case_mgr_t *uc_mgr,
331 const char *name);
332
333 int uc_mgr_set_variable(snd_use_case_mgr_t *uc_mgr,
334 const char *name,
335 const char *val);
336
337 int uc_mgr_get_substituted_value(snd_use_case_mgr_t *uc_mgr,
338 char **_rvalue,
339 const char *value);
340
341 int uc_mgr_substitute_tree(snd_use_case_mgr_t *uc_mgr,
342 snd_config_t *node);
343
344 int uc_mgr_config_tree_merge(snd_use_case_mgr_t *uc_mgr,
345 snd_config_t *parent, snd_config_t *new_ctx,
346 snd_config_t *before, snd_config_t *after);
347
348 int uc_mgr_evaluate_inplace(snd_use_case_mgr_t *uc_mgr,
349 snd_config_t *cfg);
350
351 int uc_mgr_evaluate_include(snd_use_case_mgr_t *uc_mgr,
352 snd_config_t *parent,
353 snd_config_t *inc);
354
355 int uc_mgr_evaluate_condition(snd_use_case_mgr_t *uc_mgr,
356 snd_config_t *parent,
357 snd_config_t *cond);
358
359 int uc_mgr_define_regex(snd_use_case_mgr_t *uc_mgr,
360 const char *name,
361 snd_config_t *eval);
362
363 int uc_mgr_exec(const char *prog);
364
365 /** The name of the environment variable containing the UCM directory */
366 #define ALSA_CONFIG_UCM_VAR "ALSA_CONFIG_UCM"
367
368 /** The name of the environment variable containing the UCM directory (new syntax) */
369 #define ALSA_CONFIG_UCM2_VAR "ALSA_CONFIG_UCM2"
370