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