Codebase list alsa-lib / 620cc7c
New upstream version 1.2.3.2 Jordi Mallach 3 years ago
58 changed file(s) with 2808 addition(s) and 1146 deletion(s). Raw diff Collapse all Expand all
00 #! /bin/sh
11 # Guess values for system-dependent variables and create Makefiles.
2 # Generated by GNU Autoconf 2.69 for alsa-lib 1.2.2.
2 # Generated by GNU Autoconf 2.69 for alsa-lib 1.2.3.2.
33 #
44 #
55 # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
586586 # Identity of this package.
587587 PACKAGE_NAME='alsa-lib'
588588 PACKAGE_TARNAME='alsa-lib'
589 PACKAGE_VERSION='1.2.2'
590 PACKAGE_STRING='alsa-lib 1.2.2'
589 PACKAGE_VERSION='1.2.3.2'
590 PACKAGE_STRING='alsa-lib 1.2.3.2'
591591 PACKAGE_BUGREPORT=''
592592 PACKAGE_URL=''
593593
14561456 # Omit some internal or obsolete options to make the list less imposing.
14571457 # This message is too long to be a string in the A/UX 3.1 sh.
14581458 cat <<_ACEOF
1459 \`configure' configures alsa-lib 1.2.2 to adapt to many kinds of systems.
1459 \`configure' configures alsa-lib 1.2.3.2 to adapt to many kinds of systems.
14601460
14611461 Usage: $0 [OPTION]... [VAR=VALUE]...
14621462
15261526
15271527 if test -n "$ac_init_help"; then
15281528 case $ac_init_help in
1529 short | recursive ) echo "Configuration of alsa-lib 1.2.2:";;
1529 short | recursive ) echo "Configuration of alsa-lib 1.2.3.2:";;
15301530 esac
15311531 cat <<\_ACEOF
15321532
16871687 test -n "$ac_init_help" && exit $ac_status
16881688 if $ac_init_version; then
16891689 cat <<\_ACEOF
1690 alsa-lib configure 1.2.2
1690 alsa-lib configure 1.2.3.2
16911691 generated by GNU Autoconf 2.69
16921692
16931693 Copyright (C) 2012 Free Software Foundation, Inc.
20982098 This file contains any messages produced by compilers while
20992099 running configure, to aid debugging if configure makes a mistake.
21002100
2101 It was created by alsa-lib $as_me 1.2.2, which was
2101 It was created by alsa-lib $as_me 1.2.3.2, which was
21022102 generated by GNU Autoconf 2.69. Invocation command line was
21032103
21042104 $ $0 $@
30363036
30373037 # Define the identity of the package.
30383038 PACKAGE='alsa-lib'
3039 VERSION='1.2.2'
3039 VERSION='1.2.3.2'
30403040
30413041
30423042 cat >>confdefs.h <<_ACEOF
1350413504 pythonlibs0=
1350513505 pythoninc0=
1350613506 if test "$build_python2" != "yes"; then
13507 pythonlibs0=$(python3-config --libs)
13507 pythonlibs0=$(python3-config --libs --embed 2> /dev/null)
13508 if test -z "$pythonlibs0"; then
13509 pythonlibs0=$(python3-config --libs)
13510 fi
1350813511 pythoninc0=$(python3-config --includes)
1350913512 fi
1351013513 if test -z "$pythonlibs0"; then
1370313706 fi
1370413707 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_have_atomics" >&5
1370513708 $as_echo "$gcc_have_atomics" >&6; }
13709
13710
13711 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
13712 /* end confdefs.h. */
13713
13714 int
13715 main ()
13716 {
13717 __asm__ volatile ("" : : : "mm0");
13718 ;
13719 return 0;
13720 }
13721 _ACEOF
13722 if ac_fn_c_try_link "$LINENO"; then :
13723
13724 $as_echo "#define HAVE_MMX \"1\"" >>confdefs.h
13725
13726 fi
13727 rm -f core conftest.err conftest.$ac_objext \
13728 conftest$ac_exeext conftest.$ac_ext
1370613729
1370713730 PCM_PLUGIN_LIST="copy linear route mulaw alaw adpcm rate plug multi shm file null empty share meter hooks lfloat ladspa dmix dshare dsnoop asym iec958 softvol extplug ioplug mmap_emul"
1370813731
1486314886 # report actual input values of CONFIG_FILES etc. instead of their
1486414887 # values after options handling.
1486514888 ac_log="
14866 This file was extended by alsa-lib $as_me 1.2.2, which was
14889 This file was extended by alsa-lib $as_me 1.2.3.2, which was
1486714890 generated by GNU Autoconf 2.69. Invocation command line was
1486814891
1486914892 CONFIG_FILES = $CONFIG_FILES
1492914952 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
1493014953 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
1493114954 ac_cs_version="\\
14932 alsa-lib config.status 1.2.2
14955 alsa-lib config.status 1.2.3.2
1493314956 configured by $0, generated by GNU Autoconf 2.69,
1493414957 with options \\"\$ac_cs_config\\"
1493514958
00 dnl Process this file with autoconf to produce a configure script.
11 AC_PREREQ(2.59)
2 AC_INIT(alsa-lib, 1.2.2)
2 AC_INIT(alsa-lib, 1.2.3.2)
33
44 AC_CONFIG_SRCDIR([src/control/control.c])
55 AC_CONFIG_MACRO_DIR([m4])
422422 pythonlibs0=
423423 pythoninc0=
424424 if test "$build_python2" != "yes"; then
425 pythonlibs0=$(python3-config --libs)
425 pythonlibs0=$(python3-config --libs --embed 2> /dev/null)
426 if test -z "$pythonlibs0"; then
427 pythonlibs0=$(python3-config --libs)
428 fi
426429 pythoninc0=$(python3-config --includes)
427430 fi
428431 if test -z "$pythonlibs0"; then
511514 [gcc_have_atomics=no])
512515 fi
513516 AC_MSG_RESULT($gcc_have_atomics)
517
518 dnl check mmx register for pcm_dmix_i386
519
520 AC_TRY_LINK([],
521 [__asm__ volatile ("" : : : "mm0");],
522 [AC_DEFINE([HAVE_MMX], "1", [MMX technology is enabled])],
523 [])
514524
515525 PCM_PLUGIN_LIST="copy linear route mulaw alaw adpcm rate plug multi shm file null empty share meter hooks lfloat ladspa dmix dshare dsnoop asym iec958 softvol extplug ioplug mmap_emul"
516526
138138 int snd_config_imake_pointer(snd_config_t **config, const char *key, const void *ptr);
139139
140140 snd_config_type_t snd_config_get_type(const snd_config_t *config);
141 int snd_config_is_array(const snd_config_t *config);
141142
142143 int snd_config_set_id(snd_config_t *config, const char *id);
143144 int snd_config_set_integer(snd_config_t *config, long value);
8585
8686 /* Define to 1 if you have the <memory.h> header file. */
8787 #undef HAVE_MEMORY_H
88
89 /* MMX technology is enabled */
90 #undef HAVE_MMX
8891
8992 /* Define if your pthreads implementation have PTHREAD_MUTEX_RECURSIVE */
9093 #undef HAVE_PTHREAD_MUTEX_RECURSIVE
9696 /** \brief Returns the version of a dynamic symbol as a string. */
9797 #define SND_DLSYM_VERSION(version) __STRING(version)
9898
99 int snd_dlpath(char *path, size_t path_len, const char *name);
99100 void *snd_dlopen(const char *file, int mode, char *errbuf, size_t errbuflen);
100101 void *snd_dlsym(void *handle, const char *name, const char *version);
101102 int snd_dlclose(void *handle);
0 /* workaround for building with old glibc / kernel headers */
1 #ifdef __linux__
2 #include <linux/types.h>
3 #else
4 #include <sys/types.h>
5 #endif
6 #ifndef __kernel_long_t
7 #define __kernel_long_t long
8 #endif
9
010 #include <alsa/sound/uapi/asound.h>
116116 *
117117 * If multiple devices with the same name exists, the number suffixes should
118118 * be added to these names like HDMI1,HDMI2,HDMI3 etc. No number gaps are
119 * allowed. The names with numbers must be continuous.
119 * allowed. The names with numbers must be continuous. It is allowed to put
120 * a whitespace between name and index (like 'Line 1') for the better
121 * readability. The device names 'Line 1' and 'Line1' are equal for
122 * this purpose.
120123 *
121124 * If EnableSequence/DisableSequence controls independent paths in the hardware
122125 * it is also recommended to split playback and capture UCM devices and use
136139 #define SND_USE_CASE_DEV_EARPIECE "Earpiece" /**< Earpiece Device */
137140 #define SND_USE_CASE_DEV_SPDIF "SPDIF" /**< SPDIF Device */
138141 #define SND_USE_CASE_DEV_HDMI "HDMI" /**< HDMI Device */
142 #define SND_USE_CASE_DEV_USB "USB" /**< USB Device (multifunctional) */
139143 /* add new devices to end of list */
140144
141145
144148 *
145149 * The use case modifier allows runtime configuration changes to deal with
146150 * asynchronous events.
151 *
152 * If multiple modifiers with the same name exists, the number suffixes should
153 * be added to these names like 'Echo Reference 1','Echo Reference 2' etc.
154 * No number gaps are allowed. The names with numbers must be continuous.
155 * It is allowed to put a whitespace between name and index for the better
156 * readability. The modifier names 'Something 1' and 'Something1' are equal
157 * for this purpose.
147158 *
148159 * e.g. to record a voice call :-
149160 * 1. Set verb to SND_USE_CASE_VERB_VOICECALL (for voice call)
271282 * "=Variable/Modifier/Verb"
272283 *
273284 * Recommended names for values:
285 * - Linked
286 * - value "True" or "1" (case insensitive)
287 * - this is a linked UCM card
288 * - don't use this UCM card, because the other UCM card refers devices
289 * - valid only in the ValueDefaults section (query '=Linked')
274290 * - TQ
275291 * - Tone Quality
276292 * - Priority
401417 * \return Zero if success, otherwise a negative error code
402418 *
403419 * Known identifiers:
420 * - _boot - execute the boot sequence (value = NULL)
421 * - _defaults - execute the 'defaults' sequence (value = NULL)
404422 * - _verb - set current verb = value
405423 * - _enadev - enable given device = value
406424 * - _disdev - disable given device = value
33
44 #define SND_LIB_MAJOR 1 /**< major number of library version */
55 #define SND_LIB_MINOR 2 /**< minor number of library version */
6 #define SND_LIB_SUBMINOR 2 /**< subminor number of library version */
6 #define SND_LIB_SUBMINOR 3 /**< subminor number of library version */
77 #define SND_LIB_EXTRAVER 1000000 /**< extra version number, used mainly for betas */
88 /** library version */
99 #define SND_LIB_VERSION ((SND_LIB_MAJOR<<16)|\
1010 (SND_LIB_MINOR<<8)|\
1111 SND_LIB_SUBMINOR)
1212 /** library version (string) */
13 #define SND_LIB_VERSION_STR "1.2.2"
13 #define SND_LIB_VERSION_STR "1.2.3.2"
1414
00 #! /bin/sh
1 # Generated automatically by config.status (alsa-lib) 1.2.2
1 # Generated automatically by config.status (alsa-lib) 1.2.3.2
22 # Libtool was configured on host e010f88cea4a:
33 # NOTE: Changes made to this file will be lost: look at ltmain.sh.
44
2020
2121 #include "Python.h"
2222 #include <stddef.h>
23 #include <limits.h>
2324 #include "config.h"
2425 #include "asoundlib.h"
2526 #include "mixer_abst.h"
3536 PyObject *py_mixer;
3637 };
3738
38 #define SCRIPT ALSA_PLUGIN_DIR "/smixer/python/main.py"
39 #define SCRIPT "smixer/python/main.py"
3940
4041 struct pymelem {
4142 PyObject_HEAD
11091110 FILE *fp;
11101111 const char *file;
11111112 PyObject *obj, *py_mod;
1113 char path[PATH_MAX];
11121114
11131115 priv = calloc(1, sizeof(*priv));
11141116 if (priv == NULL)
11181120 snd_mixer_sbasic_set_private_free(class, alsa_mixer_simple_free);
11191121
11201122 file = getenv("ALSA_MIXER_SIMPLE_MPYTHON");
1121 if (file == NULL)
1122 file = SCRIPT;
1123 if (file == NULL) {
1124 snd_dlpath(path, sizeof(path), SCRIPT);
1125 file = path;
1126 }
11231127
11241128 fp = fopen(file, "r");
11251129 if (fp == NULL) {
3232 #include "mixer_abst.h"
3333 #include "sbase.h"
3434
35 #define SO_PATH ALSA_PLUGIN_DIR "/smixer"
35 #define SO_PATH "smixer"
3636
3737 int mixer_simple_basic_dlopen(snd_mixer_class_t *class,
3838 bclass_base_ops_t **ops)
77 {
88 func load
99 files [
10 "/usr/etc/alsa/conf.d"
1011 "/etc/alsa/conf.d"
11 "/etc/asound.conf"
12 "/etc/asound.conf|||/usr/etc/asound.conf"
1213 "~/.asoundrc"
14 {
15 @func concat
16 strings [
17 {
18 @func getenv
19 vars [
20 XDG_CONFIG_HOME
21 ]
22 default "~/.config"
23 }
24 "/alsa/asoundrc"
25 ]
26 }
1327 ]
1428 errors false
1529 }
6882 defaults.pcm.ipc_key 5678293
6983 defaults.pcm.ipc_gid audio
7084 defaults.pcm.ipc_perm 0660
85 defaults.pcm.tstamp_type default
7186 defaults.pcm.dmix.max_periods 0
7287 defaults.pcm.dmix.channels 2
7388 defaults.pcm.dmix.rate 48000
74 defaults.pcm.dmix.format "unchanged"
89 defaults.pcm.dmix.format unchanged
7590 defaults.pcm.dmix.card defaults.pcm.card
7691 defaults.pcm.dmix.device defaults.pcm.device
7792 defaults.pcm.dsnoop.card defaults.pcm.card
100115 defaults.pcm.iec958.device defaults.pcm.device
101116 defaults.pcm.modem.card defaults.pcm.card
102117 defaults.pcm.modem.device defaults.pcm.device
103 # truncate files via file or tee PCM
104 defaults.pcm.file_format "raw"
105 defaults.pcm.file_truncate true
118 defaults.pcm.file_format raw
119 defaults.pcm.file_truncate true # truncate files via file or tee PCM
106120 defaults.rawmidi.card 0
107121 defaults.rawmidi.device 0
108122 defaults.rawmidi.subdevice -1
117131 #
118132 # PCM interface
119133 #
134
135 pcm.hw {
136 @args [ CARD DEV SUBDEV ]
137 @args.CARD {
138 type string
139 default {
140 @func getenv
141 vars [
142 ALSA_PCM_CARD
143 ALSA_CARD
144 ]
145 default {
146 @func refer
147 name defaults.pcm.card
148 }
149 }
150 }
151 @args.DEV {
152 type integer
153 default {
154 @func igetenv
155 vars [
156 ALSA_PCM_DEVICE
157 ]
158 default {
159 @func refer
160 name defaults.pcm.device
161 }
162 }
163 }
164 @args.SUBDEV {
165 type integer
166 default {
167 @func refer
168 name defaults.pcm.subdevice
169 }
170 }
171 type hw
172 card $CARD
173 device $DEV
174 subdevice $SUBDEV
175 hint {
176 show {
177 @func refer
178 name defaults.namehint.extended
179 }
180 description "Direct hardware device without any conversions"
181 }
182 }
183
184 pcm.plughw {
185 @args [ CARD DEV SUBDEV ]
186 @args.CARD {
187 type string
188 default {
189 @func getenv
190 vars [
191 ALSA_PCM_CARD
192 ALSA_CARD
193 ]
194 default {
195 @func refer
196 name defaults.pcm.card
197 }
198 }
199 }
200 @args.DEV {
201 type integer
202 default {
203 @func igetenv
204 vars [
205 ALSA_PCM_DEVICE
206 ]
207 default {
208 @func refer
209 name defaults.pcm.device
210 }
211 }
212 }
213 @args.SUBDEV {
214 type integer
215 default {
216 @func refer
217 name defaults.pcm.subdevice
218 }
219 }
220 type plug
221 slave.pcm {
222 type hw
223 card $CARD
224 device $DEV
225 subdevice $SUBDEV
226 }
227 hint {
228 show {
229 @func refer
230 name defaults.namehint.extended
231 }
232 description "Hardware device with all software conversions"
233 }
234 }
235
236 pcm.plug {
237 @args [ SLAVE ]
238 @args.SLAVE {
239 type string
240 }
241 type plug
242 slave.pcm $SLAVE
243 }
244
245 pcm.shm {
246 @args [ SOCKET PCM ]
247 @args.SOCKET {
248 type string
249 }
250 @args.PCM {
251 type string
252 }
253 type shm
254 server $SOCKET
255 pcm $PCM
256 }
257
258 pcm.tee {
259 @args [ SLAVE FILE FORMAT ]
260 @args.SLAVE {
261 type string
262 }
263 @args.FILE {
264 type string
265 }
266 @args.FORMAT {
267 type string
268 default {
269 @func refer
270 name defaults.pcm.file_format
271 }
272 }
273 type file
274 slave.pcm $SLAVE
275 file $FILE
276 format $FORMAT
277 truncate {
278 @func refer
279 name defaults.pcm.file_truncate
280 }
281 }
282
283 pcm.file {
284 @args [ FILE FORMAT ]
285 @args.FILE {
286 type string
287 }
288 @args.FORMAT {
289 type string
290 default {
291 @func refer
292 name defaults.pcm.file_format
293 }
294 }
295 type file
296 slave.pcm null
297 file $FILE
298 format $FORMAT
299 truncate {
300 @func refer
301 name defaults.pcm.file_truncate
302 }
303 }
304
305 pcm.null {
306 type null
307 hint {
308 show {
309 @func refer
310 name defaults.namehint.basic
311 }
312 description "Discard all samples (playback) or generate zero samples (capture)"
313 }
314 }
120315
121316 # redirect to load-on-demand extended pcm definitions
122317 pcm.cards cards.pcm
141336 pcm.modem cards.pcm.modem
142337 pcm.phoneline cards.pcm.phoneline
143338
144 pcm.hw {
145 @args [ CARD DEV SUBDEV ]
146 @args.CARD {
147 type string
148 default {
149 @func getenv
150 vars [
151 ALSA_PCM_CARD
152 ALSA_CARD
153 ]
154 default {
155 @func refer
156 name defaults.pcm.card
157 }
158 }
159 }
160 @args.DEV {
161 type integer
162 default {
163 @func igetenv
164 vars [
165 ALSA_PCM_DEVICE
166 ]
167 default {
168 @func refer
169 name defaults.pcm.device
170 }
171 }
172 }
173 @args.SUBDEV {
174 type integer
175 default {
176 @func refer
177 name defaults.pcm.subdevice
178 }
179 }
180 type hw
181 card $CARD
182 device $DEV
183 subdevice $SUBDEV
184 hint {
185 show {
186 @func refer
187 name defaults.namehint.extended
188 }
189 description "Direct hardware device without any conversions"
190 }
191 }
192
193 pcm.plughw {
194 @args [ CARD DEV SUBDEV ]
195 @args.CARD {
196 type string
197 default {
198 @func getenv
199 vars [
200 ALSA_PCM_CARD
201 ALSA_CARD
202 ]
203 default {
204 @func refer
205 name defaults.pcm.card
206 }
207 }
208 }
209 @args.DEV {
210 type integer
211 default {
212 @func igetenv
213 vars [
214 ALSA_PCM_DEVICE
215 ]
216 default {
217 @func refer
218 name defaults.pcm.device
219 }
220 }
221 }
222 @args.SUBDEV {
223 type integer
224 default {
225 @func refer
226 name defaults.pcm.subdevice
227 }
228 }
229 type plug
230 slave.pcm {
231 type hw
232 card $CARD
233 device $DEV
234 subdevice $SUBDEV
235 }
236 hint {
237 show {
238 @func refer
239 name defaults.namehint.extended
240 }
241 description "Hardware device with all software conversions"
242 }
243 }
244
245 pcm.plug {
246 @args [ SLAVE ]
247 @args.SLAVE {
248 type string
249 }
250 type plug
251 slave.pcm $SLAVE
252 }
253
254 pcm.shm {
255 @args [ SOCKET PCM ]
256 @args.SOCKET {
257 type string
258 }
259 @args.PCM {
260 type string
261 }
262 type shm
263 server $SOCKET
264 pcm $PCM
265 }
266
267 pcm.tee {
268 @args [ SLAVE FILE FORMAT ]
269 @args.SLAVE {
270 type string
271 }
272 @args.FILE {
273 type string
274 }
275 @args.FORMAT {
276 type string
277 default {
278 @func refer
279 name defaults.pcm.file_format
280 }
281 }
282 type file
283 slave.pcm $SLAVE
284 file $FILE
285 format $FORMAT
286 truncate {
287 @func refer
288 name defaults.pcm.file_truncate
289 }
290 }
291
292 pcm.file {
293 @args [ FILE FORMAT ]
294 @args.FILE {
295 type string
296 }
297 @args.FORMAT {
298 type string
299 default {
300 @func refer
301 name defaults.pcm.file_format
302 }
303 }
304 type file
305 slave.pcm null
306 file $FILE
307 format $FORMAT
308 truncate {
309 @func refer
310 name defaults.pcm.file_truncate
311 }
312 }
313
314 pcm.null {
315 type null
316 hint {
317 show {
318 @func refer
319 name defaults.namehint.basic
320 }
321 description "Discard all samples (playback) or generate zero samples (capture)"
322 }
323 }
324
325339 #
326340 # Control interface
327341 #
3838 # "NoiseBlaster 3000" 42
3939 "USB Sound Blaster HD" 1
4040 "Xonar U7" 1
41
41 "ASUS XONAR U5" 1
42 "XONAR U5" 1
43 "XONAR SOUND CARD" 1
44
4245 # The below don't have digital in/out, so prevent them from being opened.
4346 "Andrea PureAudio USB-SA Headset" 999
4447 "Blue Snowball" 999
48 "C-Media USB Headphone Set" 999
4549 "HP Digital Stereo Headset" 999
4650 "GN 9330" 999
4751 "Logitech Speaker Lapdesk N700" 999
5761 "Scarlett 2i4 USB" 999
5862 "Sennheiser USB headset" 999
5963 "SWTOR Gaming Headset by Razer" 999
64 "Thunderbolt Dock Audio Headset" 999
65 "Thunderbolt Dock Audio Module" 999
6066 "USB Device 0x46d_0x821" 999
6167 "USB Device 0x46d_0x992" 999
6268 "WD15 Dock" 999
5454 ipc_perm {
5555 @func refer
5656 name defaults.pcm.ipc_perm
57 }
58 tstamp_type {
59 @func refer
60 name defaults.pcm.tstamp_type
5761 }
5862 slave {
5963 pcm {
4747 ipc_perm {
4848 @func refer
4949 name defaults.pcm.ipc_perm
50 }
51 tstamp_type {
52 @func refer
53 name defaults.pcm.tstamp_type
5054 }
5155 slave {
5256 pcm {
5151 @func refer
5252 name defaults.namehint.basic
5353 }
54 description "Front speakers"
55 device $DEV
54 description "Front output / input"
55 device_output $DEV
56 device_input $DEV
57 omit_noargs true
5658 }
5759 }
7777 name defaults.namehint.basic
7878 }
7979 description "IEC958 (S/PDIF) Digital Audio Output"
80 device $DEV
80 device_output $DEV
8181 }
8282 }
5656 hint {
5757 description "2.1 Surround output to Front and Subwoofer speakers"
5858 device_output $DEV
59 omit_noargs true
5960 }
6061 }
5454 hint {
5555 description "4.0 Surround output to Front and Rear speakers"
5656 device_output $DEV
57 omit_noargs true
5758 }
5859 }
6060 hint {
6161 description "4.1 Surround output to Front, Rear and Subwoofer speakers"
6262 device_output $DEV
63 omit_noargs true
6364 }
6465 }
6060 hint {
6161 description "5.0 Surround output to Front, Center and Rear speakers"
6262 device_output $DEV
63 omit_noargs true
6364 }
6465 }
5656 hint {
5757 description "5.1 Surround output to Front, Center, Rear and Subwoofer speakers"
5858 device_output $DEV
59 omit_noargs true
5960 }
6061 }
5858 hint {
5959 description "7.1 Surround output to Front, Center, Side, Rear and Woofer speakers"
6060 device_output $DEV
61 omit_noargs true
6162 }
6263 }
415415
416416 #include "local.h"
417417 #include <stdarg.h>
418 #include <stdbool.h>
418419 #include <limits.h>
419420 #include <sys/stat.h>
420421 #include <dirent.h>
442443 const void *ptr;
443444 struct {
444445 struct list_head fields;
445 int join;
446 bool join;
446447 } compound;
447448 } u;
448449 struct list_head list;
13921393 SNDERR("%s is not a compound", id);
13931394 return -EINVAL;
13941395 }
1395 n->u.compound.join = 1;
1396 n->u.compound.join = true;
13961397 parent = n;
13971398 free(id);
13981399 continue;
14071408 err = _snd_config_make_add(&n, &id, SND_CONFIG_TYPE_COMPOUND, parent);
14081409 if (err < 0)
14091410 goto __end;
1410 n->u.compound.join = 1;
1411 n->u.compound.join = true;
14111412 parent = n;
14121413 }
14131414 if (c == '=') {
17821783 return config->type;
17831784 }
17841785
1786 static int check_array_item(const char *id, int index)
1787 {
1788 const char *p;
1789 long val;
1790
1791 for (p = id; *p; p++) {
1792 if (*p < '0' || *p > '9')
1793 return 0;
1794 }
1795
1796 if (safe_strtol(id, &val))
1797 return 0;
1798 return val == index;
1799 }
1800
1801 /**
1802 * \brief Returns if the compound is an array.
1803 * \param config Handle to the configuration node.
1804 * \return A positive value when true, zero when false, otherwise a negative error code.
1805 */
1806 int snd_config_is_array(const snd_config_t *config)
1807 {
1808 int idx;
1809 snd_config_iterator_t i, next;
1810 snd_config_t *node;
1811
1812 assert(config);
1813 if (config->type != SND_CONFIG_TYPE_COMPOUND)
1814 return -EINVAL;
1815 idx = 0;
1816 snd_config_for_each(i, next, config) {
1817 node = snd_config_iterator_entry(i);
1818 if (!check_array_item(node->id, idx))
1819 return 0;
1820 idx++;
1821 }
1822 return 1;
1823 }
1824
17851825 /**
17861826 * \brief Returns the id of a configuration node.
17871827 * \param[in] config Handle to the configuration node.
37783818 return err;
37793819 }
37803820
3821 static int config_file_load(snd_config_t *root, const char *fn, int errors)
3822 {
3823 struct stat st;
3824 struct dirent **namelist;
3825 int err, n;
3826
3827 if (!errors && access(fn, R_OK) < 0)
3828 return 1;
3829 if (stat(fn, &st) < 0) {
3830 SNDERR("cannot stat file/directory %s", fn);
3831 return 1;
3832 }
3833 if (!S_ISDIR(st.st_mode))
3834 return config_file_open(root, fn);
3835 #ifndef DOC_HIDDEN
3836 #if defined(_GNU_SOURCE) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__sun) && !defined(ANDROID)
3837 #define SORTFUNC versionsort
3838 #else
3839 #define SORTFUNC alphasort
3840 #endif
3841 #endif
3842 n = scandir(fn, &namelist, config_filename_filter, SORTFUNC);
3843 if (n > 0) {
3844 int j;
3845 err = 0;
3846 for (j = 0; j < n; ++j) {
3847 if (err >= 0) {
3848 int sl = strlen(fn) + strlen(namelist[j]->d_name) + 2;
3849 char *filename = malloc(sl);
3850 snprintf(filename, sl, "%s/%s", fn, namelist[j]->d_name);
3851 filename[sl-1] = '\0';
3852
3853 err = config_file_open(root, filename);
3854 free(filename);
3855 }
3856 free(namelist[j]);
3857 }
3858 free(namelist);
3859 if (err < 0)
3860 return err;
3861 }
3862 return 0;
3863 }
3864
3865 static int config_file_load_user(snd_config_t *root, const char *fn, int errors)
3866 {
3867 char *fn2;
3868 int err;
3869
3870 err = snd_user_file(fn, &fn2);
3871 if (err < 0)
3872 return config_file_load(root, fn, errors);
3873 err = config_file_load(root, fn2, errors);
3874 free(fn2);
3875 return err;
3876 }
3877
37813878 /**
37823879 * \brief Loads and parses the given configurations files.
37833880 * \param[in] root Handle to the root configuration node.
37943891 {
37953892 snd_config_t *n;
37963893 snd_config_iterator_t i, next;
3797 struct finfo *fi = NULL;
3798 int err, idx = 0, fi_count = 0, errors = 1, hit;
3894 int err, idx = 0, errors = 1, hit;
37993895
38003896 assert(root && dst);
38013897 if ((err = snd_config_search(config, "errors", &n)) >= 0) {
38203916 }
38213917 if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
38223918 SNDERR("Invalid type for field filenames");
3823 goto _err;
3824 }
3825 snd_config_for_each(i, next, n) {
3826 snd_config_t *c = snd_config_iterator_entry(i);
3827 const char *str;
3828 if ((err = snd_config_get_string(c, &str)) < 0) {
3829 SNDERR("Field %s is not a string", c->id);
3830 goto _err;
3831 }
3832 fi_count++;
3833 }
3834 fi = calloc(fi_count, sizeof(*fi));
3835 if (fi == NULL) {
3836 err = -ENOMEM;
38373919 goto _err;
38383920 }
38393921 do {
38493931 goto _err;
38503932 }
38513933 if (i == idx) {
3852 char *name;
3934 char *name, *name2, *remain;
38533935 if ((err = snd_config_get_ascii(n, &name)) < 0)
38543936 goto _err;
3855 if ((err = snd_user_file(name, &fi[idx].name)) < 0)
3856 fi[idx].name = name;
3857 else
3858 free(name);
3937 name2 = name;
3938 remain = strstr(name, "|||");
3939 while (1) {
3940 if (remain) {
3941 *remain = '\0';
3942 remain += 3;
3943 }
3944 err = config_file_load_user(root, name2, errors);
3945 if (err < 0)
3946 goto _err;
3947 if (err == 0) /* first hit wins */
3948 break;
3949 if (!remain)
3950 break;
3951 name2 = remain;
3952 remain = strstr(remain, "|||");
3953 }
3954 free(name);
38593955 idx++;
38603956 hit = 1;
38613957 }
38623958 }
38633959 } while (hit);
3864 for (idx = 0; idx < fi_count; idx++) {
3865 struct stat st;
3866 if (!errors && access(fi[idx].name, R_OK) < 0)
3867 continue;
3868 if (stat(fi[idx].name, &st) < 0) {
3869 SNDERR("cannot stat file/directory %s", fi[idx].name);
3870 continue;
3871 }
3872 if (S_ISDIR(st.st_mode)) {
3873 struct dirent **namelist;
3874 int n;
3875
3876 #ifndef DOC_HIDDEN
3877 #if defined(_GNU_SOURCE) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__sun) && !defined(ANDROID)
3878 #define SORTFUNC versionsort
3879 #else
3880 #define SORTFUNC alphasort
3881 #endif
3882 #endif
3883 n = scandir(fi[idx].name, &namelist, config_filename_filter, SORTFUNC);
3884 if (n > 0) {
3885 int j;
3886 err = 0;
3887 for (j = 0; j < n; ++j) {
3888 if (err >= 0) {
3889 int sl = strlen(fi[idx].name) + strlen(namelist[j]->d_name) + 2;
3890 char *filename = malloc(sl);
3891 snprintf(filename, sl, "%s/%s", fi[idx].name, namelist[j]->d_name);
3892 filename[sl-1] = '\0';
3893
3894 err = config_file_open(root, filename);
3895 free(filename);
3896 }
3897 free(namelist[j]);
3898 }
3899 free(namelist);
3900 if (err < 0)
3901 goto _err;
3902 }
3903 } else if ((err = config_file_open(root, fi[idx].name)) < 0)
3904 goto _err;
3905 }
39063960 *dst = NULL;
39073961 err = 0;
39083962 _err:
3909 if (fi)
3910 for (idx = 0; idx < fi_count; idx++)
3911 free(fi[idx].name);
3912 free(fi);
39133963 snd_config_delete(n);
39143964 return err;
39153965 }
13361336 build_in++;
13371337 }
13381338 if (*build_in == NULL) {
1339 buf1 = malloc(strlen(str) + sizeof(ALSA_PLUGIN_DIR) + 32);
1339 buf1 = malloc(strlen(str) + 32);
13401340 if (buf1 == NULL) {
13411341 err = -ENOMEM;
13421342 goto _err;
13431343 }
13441344 lib = buf1;
1345 sprintf(buf1, "%s/libasound_module_ctl_%s.so", ALSA_PLUGIN_DIR, str);
1345 sprintf(buf1, "libasound_module_ctl_%s.so", str);
13461346 }
13471347 }
13481348 #ifndef PIC
3232
3333 /* Function to convert from percentage to volume. val = percentage */
3434
35 static inline long int convert_prange1(long perc, long min, long max)
36 {
37 long tmp;
38
3539 #ifdef HAVE_SOFT_FLOAT
36 static inline long int convert_prange1(long val, long min, long max)
37 {
38 long temp = val * (max - min);
39 return temp / 100 + min + ((temp % 100) == 0 ? 0 : 1);
40 }
40 tmp = perc * (max - min);
41 tmp = tmp / 100 + ((tmp % 100) < 50 ? 0 : 1);
4142 #else
42
43 #define convert_prange1(val, min, max) \
44 ceil((val) * ((max) - (min)) * 0.01 + (min))
43 tmp = rint((double)perc * (double)(max - min) * 0.01);
4544 #endif
45 if (tmp == 0 && perc > 0)
46 tmp++;
47 return tmp + min;
48 }
4649
4750 #define check_range(val, min, max) \
4851 ((val < min) ? (min) : ((val > max) ? (max) : (val)))
300303 return -1;
301304 }
302305
306 static unsigned int get_ctl_type_max_elements(snd_ctl_elem_type_t type)
307 {
308 struct snd_ctl_elem_value value;
309
310 switch (type) {
311 case SND_CTL_ELEM_TYPE_BOOLEAN:
312 case SND_CTL_ELEM_TYPE_INTEGER:
313 return ARRAY_SIZE(value.value.integer.value);
314 case SND_CTL_ELEM_TYPE_INTEGER64:
315 return ARRAY_SIZE(value.value.integer64.value);
316 case SND_CTL_ELEM_TYPE_ENUMERATED:
317 return ARRAY_SIZE(value.value.enumerated.item);
318 case SND_CTL_ELEM_TYPE_BYTES:
319 return ARRAY_SIZE(value.value.bytes.data);
320 default:
321 return 0;
322 }
323 }
324
303325 /**
304326 * \brief parse ASCII string as CTL element value
305327 * \param handle CTL handle
327349 type = snd_ctl_elem_info_get_type(info);
328350 count = snd_ctl_elem_info_get_count(info);
329351 snd_ctl_elem_value_set_id(dst, &myid);
352
353 if (count > get_ctl_type_max_elements(type))
354 count = get_ctl_type_max_elements(type);
330355
331 for (idx = 0; idx < count && idx < 128 && ptr && *ptr; idx++) {
356 for (idx = 0; idx < count && ptr && *ptr; idx++) {
332357 if (*ptr == ',')
333358 goto skip;
334359 switch (type) {
7575 }
7676 list->list[list->count++] = x;
7777 return 0;
78 }
79
80 /**
81 * Add a namehint from string given in a user configuration file
82 */
83 static int hint_list_add_custom(struct hint_list *list,
84 const char *entry)
85 {
86 int err;
87 const char *sep;
88 char *name;
89
90 assert(entry);
91
92 sep = strchr(entry, '|');
93 if (sep == NULL)
94 return hint_list_add(list, entry, NULL);
95
96 name = strndup(entry, sep - entry);
97 if (name == NULL)
98 return -ENOMEM;
99
100 err = hint_list_add(list, name, sep + 1);
101 free(name);
102 return err;
78103 }
79104
80105 static void zero_handler(const char *file ATTRIBUTE_UNUSED,
269294 if (snd_config_search(cfg1, "type", &cfg) >= 0 &&
270295 snd_config_get_string(cfg, &str) >= 0 &&
271296 strcmp(str, "hw") == 0) {
272 list->device_input = -1;
273 list->device_output = -1;
274297 if (snd_config_search(cfg1, "device", &cfg) >= 0) {
275298 if (snd_config_get_integer(cfg, &dev) < 0) {
276299 SNDERR("(%s) device must be an integer", buf);
286309 err = -EINVAL;
287310 goto __cleanup;
288311 }
312 if (list->card < 0 &&
313 snd_config_search(cfg, "omit_noargs", &n) >= 0 &&
314 snd_config_get_bool(n) > 0)
315 goto __skip_add;
289316 if (level == 1 &&
290317 snd_config_search(cfg, "show", &n) >= 0 &&
291318 snd_config_get_bool(n) <= 0)
292 goto __skip_add;
319 goto __skip_add;
293320 if (buf1 == NULL &&
294321 snd_config_search(cfg, "description", &n) >= 0 &&
295322 snd_config_get_string(n, &str) >= 0) {
540567 * User-defined hints are gathered from namehint.IFACE tree like:
541568 *
542569 * <code>
543 * namehint.pcm {<br>
570 * namehint.pcm [<br>
544571 * myfile "file:FILE=/tmp/soundwave.raw|Save sound output to /tmp/soundwave.raw"<br>
545 * myplug "plug:front:Do all conversions for front speakers"<br>
546 * }
572 * myplug "plug:front|Do all conversions for front speakers"<br>
573 * ]
547574 * </code>
548575 *
549576 * Note: The device description is separated with '|' char.
623650 if (snd_config_get_string(snd_config_iterator_entry(i),
624651 &str) < 0)
625652 continue;
626 err = hint_list_add(&list, str, NULL);
653 err = hint_list_add_custom(&list, str);
627654 if (err < 0)
628655 goto __error;
629656 }
285285 * \param db_gain the dB gain to convert (in 0.01dB unit)
286286 * \param value the pointer to store the converted raw volume value
287287 * \param xdir the direction for round-up. The value is round up
288 * when this is positive.
288 * when this is positive. A negative value means round down.
289 * Zero means round-up to nearest.
289290 * \return 0 if successful, or a negative error code
290291 */
291292 int snd_tlv_convert_from_dB(unsigned int *tlv, long rangemin, long rangemax,
345346 long v = (db_gain - min) * (rangemax - rangemin);
346347 if (xdir > 0)
347348 v += (max - min) - 1;
349 else if (xdir == 0)
350 v += ((max - min) + 1) / 2;
348351 v = v / (max - min) + rangemin;
349352 *value = v;
350353 }
367370 long v = (db_gain - min) * (rangemax - rangemin);
368371 if (xdir > 0)
369372 v += (max - min) - 1;
373 else if (xdir == 0)
374 v += ((max - min) + 1) / 2;
370375 v = v / (max - min) + rangemin;
371376 *value = v;
372377 }
391396 v = (v - vmin) * (rangemax - rangemin) / (vmax - vmin);
392397 if (xdir > 0)
393398 v = ceil(v);
399 else if (xdir == 0)
400 v = lrint(v);
394401 *value = (long)v + rangemin;
395402 }
396403 return 0;
3131 #ifdef HAVE_LIBPTHREAD
3232 #include <pthread.h>
3333 #endif
34 #include <limits.h>
35
36 #if defined(HAVE_LIBDL) && defined(__GLIBC__) && !defined(__UCLIBC__)
37 #define DL_ORIGIN_AVAILABLE 1
38 #endif
3439
3540 #ifndef DOC_HIDDEN
3641 #ifndef PIC
3742 struct snd_dlsym_link *snd_dlsym_start = NULL;
3843 #endif
39 #endif
44 #ifdef DL_ORIGIN_AVAILABLE
45 static int snd_libdir_plugin_dir_set = 0;
46 static char *snd_libdir_origin = NULL;
47 #endif
48 #endif
49
50 #if defined(DL_ORIGIN_AVAILABLE) && defined(HAVE_LIBPTHREAD)
51 static pthread_mutex_t snd_dlpath_mutex = PTHREAD_MUTEX_INITIALIZER;
52
53 static inline void snd_dlpath_lock(void)
54 {
55 pthread_mutex_lock(&snd_dlpath_mutex);
56 }
57
58 static inline void snd_dlpath_unlock(void)
59 {
60 pthread_mutex_unlock(&snd_dlpath_mutex);
61 }
62 #else
63 static inline void snd_dlpath_lock(void) {}
64 static inline void snd_dlpath_unlock(void) {}
65 #endif
66
67 /**
68 *
69 * \brief Compose the dynamic path
70 * \param path Returned path (string)
71 * \param path_len Returned path max size (with trailing zero)
72 * \param name Plugin name (relative)
73 * \return Zero on success, otherwise a negative error code
74 */
75 int snd_dlpath(char *path, size_t path_len, const char *name)
76 {
77 #ifdef DL_ORIGIN_AVAILABLE
78 snd_dlpath_lock();
79 if (!snd_libdir_plugin_dir_set) {
80 struct link_map *links;
81 Dl_info info;
82 char origin[PATH_MAX];
83 if (dladdr1(&snd_dlpath, &info, (void**)&links, RTLD_DL_LINKMAP) == 0)
84 links = NULL;
85 if (links != NULL && dlinfo(links, RTLD_DI_ORIGIN, origin) == 0) {
86 snprintf(path, path_len, "%s/alsa-lib", origin);
87 if (access(path, X_OK) == 0)
88 snd_libdir_origin = strdup(origin);
89 }
90 snd_libdir_plugin_dir_set = 1;
91 }
92 if (snd_libdir_origin) {
93 snprintf(path, path_len, "%s/alsa-lib/%s", snd_libdir_origin, name);
94 } else {
95 snprintf(path, path_len, "%s/%s", ALSA_PLUGIN_DIR, name);
96 }
97 snd_dlpath_unlock();
98 #else
99 snprintf(path, path_len, "%s/%s", ALSA_PLUGIN_DIR, name);
100 #endif
101 return 0;
102 }
40103
41104 /**
42105 * \brief Opens a dynamic library - ALSA wrapper for \c dlopen.
78141 * via ld.so.conf.
79142 */
80143 void *handle = NULL;
81 char *filename = NULL;
144 const char *filename = NULL;
145 char path[PATH_MAX];
82146
83147 if (name && name[0] != '/') {
84 filename = alloca(sizeof(ALSA_PLUGIN_DIR) + 1 + strlen(name) + 1);
85 if (filename) {
86 strcpy(filename, ALSA_PLUGIN_DIR);
87 strcat(filename, "/");
88 strcat(filename, name);
148 if (snd_dlpath(path, sizeof(path), name) == 0) {
149 filename = path;
89150 handle = dlopen(filename, mode);
90151 if (!handle) {
91152 /* if the filename exists and cannot be opened */
96157 }
97158 }
98159 if (!handle) {
160 filename = name;
99161 handle = dlopen(name, mode);
100162 if (!handle)
101163 goto errpath;
384446 free((void *)c->lib); /* shut up gcc warning */
385447 free(c);
386448 }
387
388449 snd_dlobj_unlock();
389 }
390 #endif
450 #ifdef DL_ORIGIN_AVAILABLE
451 snd_dlpath_lock();
452 snd_libdir_plugin_dir_set = 0;
453 free(snd_libdir_origin);
454 snd_libdir_origin = NULL;
455 snd_dlpath_unlock();
456 #endif
457 }
458 #endif
375375 * \brief Return corresponding integer playback volume for given dB value for a mixer simple element
376376 * \param elem Mixer simple element handle
377377 * \param value value to be converted to dB range
378 * \param dir rounding mode - rounds up if dir > 0, otherwise rounds down
378 * \param dir rounding mode - rounds up if dir > 0, round to nearest if dir == 0,
379 * rounds down if dir < 0
379380 * \param dBvalue pointer to returned dB value
380381 * \return 0 on success otherwise a negative error code
381382 */
453454 * \param elem Mixer simple element handle
454455 * \param channel mixer simple element channel identifier
455456 * \param value control value in dB * 100
456 * \param dir rounding mode - rounds up if dir > 0, otherwise rounds down
457 * \param dir rounding mode - rounds up if dir > 0, round to nearest if dir == 0,
458 * rounds down if dir < 0
457459 * \return 0 on success otherwise a negative error code
458460 */
459461 int snd_mixer_selem_set_playback_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir)
490492 * \brief Set value in dB of playback volume control for all channels of a mixer simple element
491493 * \param elem Mixer simple element handle
492494 * \param value control value in dB * 100
493 * \param dir rounding mode - rounds up if dir > 0, otherwise rounds down
495 * \param dir rounding mode - rounds up if dir > 0, round to nearest if dir == 0,
496 * rounds down if dir < 0
494497 * \return 0 on success otherwise a negative error code
495498 */
496499 int snd_mixer_selem_set_playback_dB_all(snd_mixer_elem_t *elem, long value, int dir)
705708 * \param elem Mixer simple element handle
706709 * \param dBvalue dB value to be converted to integer range
707710 * \param value pointer to returned integer value
708 * \param dir rounding mode - rounds up if dir > 0, otherwise rounds down
711 * \param dir rounding mode - rounds up if dir > 0, round to nearest if dir == 0,
712 * rounds down if dir < 0
709713 * \return 0 on success otherwise a negative error code
710714 */
711715 int snd_mixer_selem_ask_capture_dB_vol(snd_mixer_elem_t *elem, long dBvalue, int dir, long *value)
776780 * \param elem Mixer simple element handle
777781 * \param channel mixer simple element channel identifier
778782 * \param value control value in dB * 100
779 * \param dir rounding mode - rounds up if dir > 0, otherwise rounds down
783 * \param dir rounding mode - rounds up if dir > 0, round to nearest if dir == 0,
784 * rounds down if dir < 0
780785 * \return 0 on success otherwise a negative error code
781786 */
782787 int snd_mixer_selem_set_capture_dB(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t channel, long value, int dir)
813818 * \brief Set value in dB of capture volume control for all channels of a mixer simple element
814819 * \param elem Mixer simple element handle
815820 * \param value control value in dB * 100
816 * \param dir rounding mode - rounds up if dir > 0, otherwise rounds down
821 * \param dir rounding mode - rounds up if dir > 0, round to nearest if dir == 0,
822 * rounds down if dir < 0
817823 * \return 0 on success otherwise a negative error code
818824 */
819825 int snd_mixer_selem_set_capture_dB_all(snd_mixer_elem_t *elem, long value, int dir)
3939
4040 #ifndef DOC_HIDDEN
4141
42 #define SO_PATH ALSA_PLUGIN_DIR "/smixer"
42 #define SO_PATH "smixer"
4343
4444 typedef struct _class_priv {
4545 char *device;
283283 \par -EBADFD
284284
285285 This error means that the device is in a bad state. It means that
286 the handskahe between application and alsa-lib is corrupted.
286 the handshake between application and alsa-lib is corrupted.
287287
288288 \par -ENOTTY, -ENODEV
289289
290290 This error can happen when device is physically removed (for example
291291 some hotplug devices like USB or PCMCIA, CardBus or ExpressCard
292292 can be removed on the fly).
293
294 \par -ENODATA
295
296 This error can happen if the device data transfer is dependent on
297 an external condition and that condition is not met. For example,
298 PCM device for echo reference as described by SND_USE_CASE_MOD_ECHO_REF
299 UCM token, may return -ENODATA if the linked playback stream has not been
300 started.
301
302 There is no defined recovery or event mechanism to signal the data / link
303 availability at the moment. The PCM must be completely restarted until
304 the mechanism is designed. The #snd_pcm_recover() function cannot be
305 used for this.
293306
294307 \section pcm_params Managing parameters
295308
679692 P_STATE(DRAINING))
680693
681694 /* check whether the PCM is in the unexpected state */
682 static int bad_pcm_state(snd_pcm_t *pcm, unsigned int supported_states)
695 static int bad_pcm_state(snd_pcm_t *pcm, unsigned int supported_states,
696 unsigned int noop_states)
683697 {
684698 snd_pcm_state_t state;
685699 int err;
687701 if (pcm->own_state_check)
688702 return 0; /* don't care, the plugin checks by itself */
689703 state = snd_pcm_state(pcm);
704 if (noop_states & (1U << state))
705 return 1; /* OK, return immediately */
690706 if (supported_states & (1U << state))
691707 return 0; /* OK */
692708 err = pcm_state_to_error(state);
12051221 SNDMSG("PCM not set up");
12061222 return -EIO;
12071223 }
1208 err = bad_pcm_state(pcm, ~P_STATE(DISCONNECTED));
1224 err = bad_pcm_state(pcm, ~P_STATE(DISCONNECTED), 0);
12091225 if (err < 0)
12101226 return err;
12111227 snd_pcm_lock(pcm->fast_op_arg);
12601276 SNDMSG("PCM not set up");
12611277 return -EIO;
12621278 }
1263 err = bad_pcm_state(pcm, P_STATE(PREPARED));
1279 err = bad_pcm_state(pcm, P_STATE(PREPARED), 0);
12641280 if (err < 0)
12651281 return err;
12661282 snd_pcm_lock(pcm->fast_op_arg);
12921308 return -EIO;
12931309 }
12941310 err = bad_pcm_state(pcm, P_STATE_RUNNABLE | P_STATE(SETUP) |
1295 P_STATE(SUSPENDED));
1311 P_STATE(SUSPENDED), 0);
12961312 if (err < 0)
12971313 return err;
12981314 snd_pcm_lock(pcm->fast_op_arg);
13281344 SNDMSG("PCM not set up");
13291345 return -EIO;
13301346 }
1331 err = bad_pcm_state(pcm, P_STATE_RUNNABLE);
1347 err = bad_pcm_state(pcm, P_STATE_RUNNABLE | P_STATE(SETUP), P_STATE(SETUP));
13321348 if (err < 0)
13331349 return err;
1350 if (err == 1)
1351 return 0;
13341352 /* lock handled in the callback */
13351353 if (pcm->fast_ops->drain)
13361354 err = pcm->fast_ops->drain(pcm->fast_op_arg);
13601378 SNDMSG("PCM not set up");
13611379 return -EIO;
13621380 }
1363 err = bad_pcm_state(pcm, P_STATE_RUNNABLE);
1381 err = bad_pcm_state(pcm, P_STATE_RUNNABLE, 0);
13641382 if (err < 0)
13651383 return err;
13661384 snd_pcm_lock(pcm->fast_op_arg);
13931411 SNDMSG("PCM not set up");
13941412 return -EIO;
13951413 }
1396 err = bad_pcm_state(pcm, P_STATE_RUNNABLE);
1414 err = bad_pcm_state(pcm, P_STATE_RUNNABLE, 0);
13971415 if (err < 0)
13981416 return err;
13991417 snd_pcm_lock(pcm->fast_op_arg);
14261444 }
14271445 if (frames == 0)
14281446 return 0;
1429 err = bad_pcm_state(pcm, P_STATE_RUNNABLE);
1447 err = bad_pcm_state(pcm, P_STATE_RUNNABLE, 0);
14301448 if (err < 0)
14311449 return err;
14321450 snd_pcm_lock(pcm->fast_op_arg);
14591477 SNDMSG("PCM not set up");
14601478 return -EIO;
14611479 }
1462 err = bad_pcm_state(pcm, P_STATE_RUNNABLE);
1480 err = bad_pcm_state(pcm, P_STATE_RUNNABLE, 0);
14631481 if (err < 0)
14641482 return err;
14651483 snd_pcm_lock(pcm->fast_op_arg);
14961514 }
14971515 if (frames == 0)
14981516 return 0;
1499 err = bad_pcm_state(pcm, P_STATE_RUNNABLE);
1517 err = bad_pcm_state(pcm, P_STATE_RUNNABLE, 0);
15001518 if (err < 0)
15011519 return err;
15021520 snd_pcm_lock(pcm->fast_op_arg);
15421560 SNDMSG("invalid access type %s", snd_pcm_access_name(pcm->access));
15431561 return -EINVAL;
15441562 }
1545 err = bad_pcm_state(pcm, P_STATE_RUNNABLE);
1563 err = bad_pcm_state(pcm, P_STATE_RUNNABLE, 0);
15461564 if (err < 0)
15471565 return err;
15481566 return _snd_pcm_writei(pcm, buffer, size);
15811599 SNDMSG("invalid access type %s", snd_pcm_access_name(pcm->access));
15821600 return -EINVAL;
15831601 }
1584 err = bad_pcm_state(pcm, P_STATE_RUNNABLE);
1602 err = bad_pcm_state(pcm, P_STATE_RUNNABLE, 0);
15851603 if (err < 0)
15861604 return err;
15871605 return _snd_pcm_writen(pcm, bufs, size);
16201638 SNDMSG("invalid access type %s", snd_pcm_access_name(pcm->access));
16211639 return -EINVAL;
16221640 }
1623 err = bad_pcm_state(pcm, P_STATE_RUNNABLE);
1641 err = bad_pcm_state(pcm, P_STATE_RUNNABLE, 0);
16241642 if (err < 0)
16251643 return err;
16261644 return _snd_pcm_readi(pcm, buffer, size);
16591677 SNDMSG("invalid access type %s", snd_pcm_access_name(pcm->access));
16601678 return -EINVAL;
16611679 }
1662 err = bad_pcm_state(pcm, P_STATE_RUNNABLE);
1680 err = bad_pcm_state(pcm, P_STATE_RUNNABLE, 0);
16631681 if (err < 0)
16641682 return err;
16651683 return _snd_pcm_readn(pcm, bufs, size);
25722590 build_in++;
25732591 }
25742592 if (*build_in == NULL) {
2575 buf1 = malloc(strlen(str) + sizeof(ALSA_PLUGIN_DIR) + 32);
2593 buf1 = malloc(strlen(str) + 32);
25762594 if (buf1 == NULL) {
25772595 err = -ENOMEM;
25782596 goto _err;
25792597 }
25802598 lib = buf1;
2581 sprintf(buf1, "%s/libasound_module_pcm_%s.so", ALSA_PLUGIN_DIR, str);
2599 sprintf(buf1, "libasound_module_pcm_%s.so", str);
25822600 }
25832601 }
25842602 #ifndef PIC
27442762 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
27452763 #endif
27462764 pthread_mutex_init(&pcm->lock, &attr);
2765 pthread_mutexattr_destroy(&attr);
27472766 /* use locking as default;
27482767 * each plugin may suppress this in its open call
27492768 */
71887207 {
71897208 int err;
71907209
7191 err = bad_pcm_state(pcm, P_STATE_RUNNABLE);
7210 err = bad_pcm_state(pcm, P_STATE_RUNNABLE, 0);
71927211 if (err < 0)
71937212 return err;
71947213 snd_pcm_lock(pcm->fast_op_arg);
72937312 snd_pcm_sframes_t result;
72947313 int err;
72957314
7296 err = bad_pcm_state(pcm, P_STATE_RUNNABLE);
7315 err = bad_pcm_state(pcm, P_STATE_RUNNABLE, 0);
72977316 if (err < 0)
72987317 return err;
72997318 snd_pcm_lock(pcm->fast_op_arg);
928928 return err;
929929 if (dshare->var_periodsize) {
930930 /* more tolerant settings... */
931 if (dshare->shmptr->hw.buffer_size.max / 2 > period_size.max)
931 if (dshare->shmptr->hw.buffer_size.max / 2 > period_size.max) {
932932 period_size.max = dshare->shmptr->hw.buffer_size.max / 2;
933 if (dshare->shmptr->hw.buffer_time.max / 2 > period_time.max)
933 period_size.openmax = dshare->shmptr->hw.buffer_size.openmax;
934 }
935 if (dshare->shmptr->hw.buffer_time.max / 2 > period_time.max) {
934936 period_time.max = dshare->shmptr->hw.buffer_time.max / 2;
937 period_time.openmax = dshare->shmptr->hw.buffer_time.openmax;
938 }
935939 }
936940
937941 err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE,
990994 return 0;
991995 }
992996
993 int snd_pcm_direct_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t * params ATTRIBUTE_UNUSED)
994 {
997 int snd_pcm_direct_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
998 {
999 if (params->tstamp_type != pcm->tstamp_type)
1000 return -EINVAL;
1001
9951002 /* values are cached in the pcm structure */
9961003 return 0;
9971004 }
13171324 return ret;
13181325 }
13191326
1327 if (dmix->tstamp_type != -1) {
1328 ret = snd_pcm_sw_params_set_tstamp_type(spcm, &sw_params,
1329 dmix->tstamp_type);
1330 if (ret < 0) {
1331 SNDERR("unable to set tstamp type");
1332 return ret;
1333 }
1334 }
1335
13201336 if (dmix->type != SND_PCM_TYPE_DMIX &&
13211337 dmix->type != SND_PCM_TYPE_DSHARE)
13221338 goto __skip_silencing;
18771893 rec->var_periodsize = 0;
18781894 rec->direct_memory_access = 1;
18791895 rec->hw_ptr_alignment = SND_PCM_HW_PTR_ALIGNMENT_AUTO;
1896 rec->tstamp_type = -1;
18801897
18811898 /* read defaults */
18821899 if (snd_config_search(root, "defaults.pcm.dmix_max_periods", &n) >= 0) {
19381955 return -EINVAL;
19391956 }
19401957
1958 continue;
1959 }
1960 if (strcmp(id, "tstamp_type") == 0) {
1961 const char *str;
1962 err = snd_config_get_string(n, &str);
1963 if (err < 0) {
1964 SNDERR("Invalid type for %s", id);
1965 return -EINVAL;
1966 }
1967 if (strcmp(str, "default") == 0)
1968 rec->tstamp_type = -1;
1969 else if (strcmp(str, "gettimeofday") == 0)
1970 rec->tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY;
1971 else if (strcmp(str, "monotonic") == 0)
1972 rec->tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC;
1973 else if (strcmp(str, "monotonic_raw") == 0)
1974 rec->tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW;
1975 else {
1976 SNDERR("The field tstamp_type is invalid : %s", str);
1977 return -EINVAL;
1978 }
19411979 continue;
19421980 }
19431981 if (strcmp(id, "ipc_gid") == 0) {
172172 unsigned int recoveries; /* mirror of executed recoveries on slave */
173173 int direct_memory_access; /* use arch-optimized buffer RW */
174174 snd_pcm_direct_hw_ptr_alignment_t hw_ptr_alignment;
175 int tstamp_type; /* cached from conf, can be -1(default) on top of real types */
175176 union {
176177 struct {
177178 int shmid_sum; /* IPC global sum ring buffer memory identification */
356357 int var_periodsize;
357358 int direct_memory_access;
358359 snd_pcm_direct_hw_ptr_alignment_t hw_ptr_alignment;
360 int tstamp_type;
359361 snd_config_t *slave;
360362 snd_config_t *bindings;
361363 };
10371037 dmix->ipc_key = opts->ipc_key;
10381038 dmix->ipc_perm = opts->ipc_perm;
10391039 dmix->ipc_gid = opts->ipc_gid;
1040 dmix->tstamp_type = opts->tstamp_type;
10401041 dmix->semid = -1;
10411042 dmix->shmid = -1;
10421043
12361237 # roundup
12371238 # rounddown
12381239 # auto (default)
1240 tstamp_type STR # timestamp type
1241 # STR can be one of the below strings :
1242 # default, gettimeofday, monotonic, monotonic_raw
12391243 slave STR
12401244 # or
12411245 slave { # Slave definition
2525 *
2626 */
2727
28 #if defined(__GNUC__) && __GNUC__ < 5 && defined(__PIC__)
29 # define BOUNDED_EBX
30 #endif
31
2832 /*
2933 * for plain i386
3034 */
3337 volatile signed int *sum, size_t dst_step,
3438 size_t src_step, size_t sum_step)
3539 {
40 #ifdef BOUNDED_EBX
3641 unsigned int old_ebx;
37
42 #endif
3843 /*
3944 * ESI - src
4045 * EDI - dst
4550 */
4651 __asm__ __volatile__ (
4752 "\n"
48
49 "\tmovl %%ebx, %7\n" /* ebx is GOT pointer (-fPIC) */
53 #ifdef BOUNDED_EBX
54 "\tmovl %%ebx, %[old_ebx]\n" /* ebx is GOT pointer (-fPIC) */
55 #endif
5056 /*
5157 * initialization, load ESI, EDI, EBX registers
5258 */
53 "\tmovl %1, %%edi\n"
54 "\tmovl %2, %%esi\n"
55 "\tmovl %3, %%ebx\n"
56 "\tcmpl $0, %0\n"
59 "\tmovl %[dst], %%edi\n"
60 "\tmovl %[src], %%esi\n"
61 "\tmovl %[sum], %%ebx\n"
62 "\tcmpl $0, %[size]\n"
5763 "\tjnz 2f\n"
5864 "\tjmp 7f\n"
5965
6369 */
6470 "\t.p2align 4,,15\n"
6571 "1:"
66 "\tadd %4, %%edi\n"
67 "\tadd %5, %%esi\n"
68 "\tadd %6, %%ebx\n"
72 "\tadd %[dst_step], %%edi\n"
73 "\tadd %[src_step], %%esi\n"
74 "\tadd %[sum_step], %%ebx\n"
6975
7076 /*
7177 * sample = *src;
107113 /*
108114 * while (size-- > 0)
109115 */
110 "\tdecl %0\n"
116 "\tdecl %[size]\n"
111117 "\tjnz 1b\n"
112118 "\tjmp 7f\n"
113119
121127 "\tmovw $0x7fff, (%%edi)\n"
122128 "\tcmpl %%ecx,(%%ebx)\n"
123129 "\tjnz 4b\n"
124 "\tdecl %0\n"
130 "\tdecl %[size]\n"
125131 "\tjnz 1b\n"
126132 "\tjmp 7f\n"
127133
135141 "\tmovw $-0x8000, (%%edi)\n"
136142 "\tcmpl %%ecx, (%%ebx)\n"
137143 "\tjnz 4b\n"
138 "\tdecl %0\n"
144 "\tdecl %[size]\n"
139145 "\tjnz 1b\n"
140
146
141147 "7:"
142 "\tmovl %7, %%ebx\n" /* ebx is GOT pointer (-fPIC) */
143
144 : /* no output regs */
145 : "m" (size), "m" (dst), "m" (src),
146 "m" (sum), "m" (dst_step), "m" (src_step),
147 "m" (sum_step), "m" (old_ebx)
148 : "esi", "edi", "edx", "ecx", "eax"
148 #ifdef BOUNDED_EBX
149 "\tmovl %[old_ebx], %%ebx\n" /* ebx is GOT pointer (-fPIC) */
150 #endif
151 : [size] "+&rm" (size)
152 #ifdef BOUNDED_EBX
153 , [old_ebx] "=m" (old_ebx)
154 #endif
155 : [dst] "m" (dst), [src] "m" (src), [sum] "m" (sum),
156 [dst_step] "im" (dst_step), [src_step] "im" (src_step),
157 [sum_step] "im" (sum_step)
158 : "esi", "edi", "edx", "ecx", "eax", "memory", "cc"
159 #ifndef BOUNDED_EBX
160 , "ebx"
161 #endif
149162 );
150163 }
151164
157170 volatile signed int *sum, size_t dst_step,
158171 size_t src_step, size_t sum_step)
159172 {
173 #ifdef BOUNDED_EBX
160174 unsigned int old_ebx;
161
175 #endif
162176 /*
163177 * ESI - src
164178 * EDI - dst
169183 */
170184 __asm__ __volatile__ (
171185 "\n"
172
173 "\tmovl %%ebx, %7\n" /* ebx is GOT pointer (-fPIC) */
186 #ifdef BOUNDED_EBX
187 "\tmovl %%ebx, %[old_ebx]\n" /* ebx is GOT pointer (-fPIC) */
188 #endif
174189 /*
175190 * initialization, load ESI, EDI, EBX registers
176191 */
177 "\tmovl %1, %%edi\n"
178 "\tmovl %2, %%esi\n"
179 "\tmovl %3, %%ebx\n"
180 "\tcmpl $0, %0\n"
192 "\tmovl %[dst], %%edi\n"
193 "\tmovl %[src], %%esi\n"
194 "\tmovl %[sum], %%ebx\n"
195 "\tcmpl $0, %[size]\n"
181196 "\tjnz 2f\n"
182197 "\tjmp 5f\n"
183198
184199 "\t.p2align 4,,15\n"
185200 "1:"
186 "\tadd %4, %%edi\n"
187 "\tadd %5, %%esi\n"
188 "\tadd %6, %%ebx\n"
201 "\tadd %[dst_step], %%edi\n"
202 "\tadd %[src_step], %%esi\n"
203 "\tadd %[sum_step], %%ebx\n"
189204
190205 "2:"
191206 /*
225240 /*
226241 * while (size-- > 0)
227242 */
228 "\tdecl %0\n"
243 "\tdecl %[size]\n"
229244 "\tjnz 1b\n"
230245 "\temms\n"
231246 "5:"
232 "\tmovl %7, %%ebx\n" /* ebx is GOT pointer (-fPIC) */
233
234 : /* no output regs */
235 : "m" (size), "m" (dst), "m" (src),
236 "m" (sum), "m" (dst_step), "m" (src_step),
237 "m" (sum_step), "m" (old_ebx)
238 : "esi", "edi", "edx", "ecx", "eax"
247 #ifdef BOUNDED_EBX
248 "\tmovl %[old_ebx], %%ebx\n" /* ebx is GOT pointer (-fPIC) */
249 #endif
250 : [size] "+&rm" (size)
251 #ifdef BOUNDED_EBX
252 , [old_ebx] "=m" (old_ebx)
253 #endif
254 : [dst] "m" (dst), [src] "m" (src), [sum] "m" (sum),
255 [dst_step] "im" (dst_step), [src_step] "im" (src_step),
256 [sum_step] "im" (sum_step)
257 : "esi", "edi", "edx", "ecx", "eax", "memory", "cc"
258 #ifndef BOUNDED_EBX
259 , "ebx"
260 #endif
261 #ifdef HAVE_MMX
262 , "mm0"
263 #else
264 , "st", "st(1)", "st(2)", "st(3)",
265 "st(4)", "st(5)", "st(6)", "st(7)"
266 #endif
239267 );
240268 }
241269
247275 volatile signed int *sum, size_t dst_step,
248276 size_t src_step, size_t sum_step)
249277 {
278 #ifdef BOUNDED_EBX
250279 unsigned int old_ebx;
251
280 #endif
252281 /*
253282 * ESI - src
254283 * EDI - dst
259288 */
260289 __asm__ __volatile__ (
261290 "\n"
262
263 "\tmovl %%ebx, %7\n" /* ebx is GOT pointer (-fPIC) */
291 #ifdef BOUNDED_EBX
292 "\tmovl %%ebx, %[old_ebx]\n" /* ebx is GOT pointer (-fPIC) */
293 #endif
264294 /*
265295 * initialization, load ESI, EDI, EBX registers
266296 */
267 "\tmovl %1, %%edi\n"
268 "\tmovl %2, %%esi\n"
269 "\tmovl %3, %%ebx\n"
270 "\tcmpl $0, %0\n"
297 "\tmovl %[dst], %%edi\n"
298 "\tmovl %[src], %%esi\n"
299 "\tmovl %[sum], %%ebx\n"
300 "\tcmpl $0, %[size]\n"
271301 "\tjnz 1f\n"
272302 "\tjmp 6f\n"
273303
334364 /*
335365 * while (size-- > 0)
336366 */
337 "\tdecl %0\n"
367 "\tdecl %[size]\n"
338368 "\tjz 6f\n"
339 "\tadd %4, %%edi\n"
340 "\tadd %5, %%esi\n"
341 "\tadd %6, %%ebx\n"
369 "\tadd %[dst_step], %%edi\n"
370 "\tadd %[src_step], %%esi\n"
371 "\tadd %[sum_step], %%ebx\n"
342372 "\tjmp 1b\n"
343
373
344374 "6:"
345 "\tmovl %7, %%ebx\n" /* ebx is GOT pointer (-fPIC) */
346
347 : /* no output regs */
348 : "m" (size), "m" (dst), "m" (src),
349 "m" (sum), "m" (dst_step), "m" (src_step),
350 "m" (sum_step), "m" (old_ebx)
351 : "esi", "edi", "edx", "ecx", "eax"
375 #ifdef BOUNDED_EBX
376 "\tmovl %[old_ebx], %%ebx\n" /* ebx is GOT pointer (-fPIC) */
377 #endif
378 : [size] "+&rm" (size)
379 #ifdef BOUNDED_EBX
380 , [old_ebx] "=m" (old_ebx)
381 #endif
382 : [dst] "m" (dst), [src] "m" (src), [sum] "m" (sum),
383 [dst_step] "im" (dst_step), [src_step] "im" (src_step),
384 [sum_step] "im" (sum_step)
385 : "esi", "edi", "edx", "ecx", "eax", "memory", "cc"
386 #ifndef BOUNDED_EBX
387 , "ebx"
388 #endif
352389 );
353390 }
354391
360397 volatile signed int *sum, size_t dst_step,
361398 size_t src_step, size_t sum_step)
362399 {
400 #ifdef BOUNDED_EBX
363401 unsigned int old_ebx;
364
402 #endif
365403 /*
366404 * ESI - src
367405 * EDI - dst
372410 */
373411 __asm__ __volatile__ (
374412 "\n"
375
376 "\tmovl %%ebx, %7\n" /* ebx is GOT pointer (-fPIC) */
413 #ifdef BOUNDED_EBX
414 "\tmovl %%ebx, %[old_ebx]\n" /* ebx is GOT pointer (-fPIC) */
415 #endif
377416 /*
378417 * initialization, load ESI, EDI, EBX registers
379418 */
380 "\tmovl %1, %%edi\n"
381 "\tmovl %2, %%esi\n"
382 "\tmovl %3, %%ebx\n"
383 "\tcmpl $0, %0\n"
419 "\tmovl %[dst], %%edi\n"
420 "\tmovl %[src], %%esi\n"
421 "\tmovl %[sum], %%ebx\n"
422 "\tcmpl $0, %[size]\n"
384423 "\tjnz 1f\n"
385424 "\tjmp 6f\n"
386425
440479 /*
441480 * while (size-- > 0)
442481 */
443 "\tdecl %0\n"
482 "\tdecl %[size]\n"
444483 "\tjz 6f\n"
445 "\tadd %4, %%edi\n"
446 "\tadd %5, %%esi\n"
447 "\tadd %6, %%ebx\n"
484 "\tadd %[dst_step], %%edi\n"
485 "\tadd %[src_step], %%esi\n"
486 "\tadd %[sum_step], %%ebx\n"
448487 "\tjmp 1b\n"
449
488
450489 "6:"
451 "\tmovl %7, %%ebx\n" /* ebx is GOT pointer (-fPIC) */
452
453 : /* no output regs */
454 : "m" (size), "m" (dst), "m" (src),
455 "m" (sum), "m" (dst_step), "m" (src_step),
456 "m" (sum_step), "m" (old_ebx)
457 : "esi", "edi", "edx", "ecx", "eax"
490 #ifdef BOUNDED_EBX
491 "\tmovl %[old_ebx], %%ebx\n" /* ebx is GOT pointer (-fPIC) */
492 #endif
493 : [size] "+&rm" (size)
494 #ifdef BOUNDED_EBX
495 , [old_ebx] "=m" (old_ebx)
496 #endif
497 : [dst] "m" (dst), [src] "m" (src), [sum] "m" (sum),
498 [dst_step] "im" (dst_step), [src_step] "im" (src_step),
499 [sum_step] "im" (sum_step)
500 : "esi", "edi", "edx", "ecx", "eax", "memory", "cc"
501 #ifndef BOUNDED_EBX
502 , "ebx"
503 #endif
458504 );
459505 }
460506
466512 volatile signed int *sum, size_t dst_step,
467513 size_t src_step, size_t sum_step)
468514 {
515 #ifdef BOUNDED_EBX
469516 unsigned int old_ebx;
470
517 #endif
471518 /*
472519 * ESI - src
473520 * EDI - dst
478525 */
479526 __asm__ __volatile__ (
480527 "\n"
481
482 "\tmovl %%ebx, %7\n" /* ebx is GOT pointer (-fPIC) */
528 #ifdef BOUNDED_EBX
529 "\tmovl %%ebx, %[old_ebx]\n" /* ebx is GOT pointer (-fPIC) */
530 #endif
483531 /*
484532 * initialization, load ESI, EDI, EBX registers
485533 */
486 "\tmovl %1, %%edi\n"
487 "\tmovl %2, %%esi\n"
488 "\tmovl %3, %%ebx\n"
489 "\tcmpl $0, %0\n"
534 "\tmovl %[dst], %%edi\n"
535 "\tmovl %[src], %%esi\n"
536 "\tmovl %[sum], %%ebx\n"
537 "\tcmpl $0, %[size]\n"
490538 "\tjz 6f\n"
491539
492540 "\t.p2align 4,,15\n"
540588 /*
541589 * while (size-- > 0)
542590 */
543 "\tadd %4, %%edi\n"
544 "\tadd %5, %%esi\n"
545 "\tadd %6, %%ebx\n"
546 "\tdecl %0\n"
591 "\tadd %[dst_step], %%edi\n"
592 "\tadd %[src_step], %%esi\n"
593 "\tadd %[sum_step], %%ebx\n"
594 "\tdecl %[size]\n"
547595 "\tjnz 1b\n"
548
596
549597 "6:"
550 "\tmovl %7, %%ebx\n" /* ebx is GOT pointer (-fPIC) */
551
552 : /* no output regs */
553 : "m" (size), "m" (dst), "m" (src),
554 "m" (sum), "m" (dst_step), "m" (src_step),
555 "m" (sum_step), "m" (old_ebx)
556 : "esi", "edi", "edx", "ecx", "eax"
598 #ifdef BOUNDED_EBX
599 "\tmovl %[old_ebx], %%ebx\n" /* ebx is GOT pointer (-fPIC) */
600 #endif
601 : [size] "+&rm" (size)
602 #ifdef BOUNDED_EBX
603 , [old_ebx] "=m" (old_ebx)
604 #endif
605 : [dst] "m" (dst), [src] "m" (src), [sum] "m" (sum),
606 [dst_step] "im" (dst_step), [src_step] "im" (src_step),
607 [sum_step] "im" (sum_step)
608 : "esi", "edi", "edx", "ecx", "eax", "memory", "cc"
609 #ifndef BOUNDED_EBX
610 , "ebx"
611 #endif
557612 );
558613 }
614
615 #ifdef BOUNDED_EBX
616 # undef BOUNDED_EBX
617 #endif
2626 *
2727 */
2828
29 #if defined(__GNUC__) && __GNUC__ < 5 && defined(__PIC__)
30 # define BOUNDED_RBX
31 #endif
32
2933 /*
3034 * MMX optimized
3135 */
3438 volatile signed int *sum, size_t dst_step,
3539 size_t src_step, size_t sum_step)
3640 {
41 #ifdef BOUNDED_RBX
3742 unsigned long long old_rbx;
38
43 #endif
3944 /*
4045 * RSI - src
4146 * RDI - dst
4651 */
4752 __asm__ __volatile__ (
4853 "\n"
49
50 "\tmovq %%rbx, %7\n"
54 #ifdef BOUNDED_RBX
55 "\tmovq %%rbx, %[old_rbx]\n"
56 #endif
5157 /*
5258 * initialization, load RSI, RDI, RBX registers
5359 */
54 "\tmovq %1, %%rdi\n"
55 "\tmovq %2, %%rsi\n"
56 "\tmovq %3, %%rbx\n"
60 #ifndef _ILP32
61 "\tmovq %[dst], %%rdi\n"
62 "\tmovq %[src], %%rsi\n"
63 "\tmovq %[sum], %%rbx\n"
64 #else
65 "\tmovl %[dst], %%edi\n"
66 "\tmovl %[src], %%esi\n"
67 "\tmovl %[sum], %%ebx\n"
68 #endif
5769
5870 /*
5971 * while (size-- > 0) {
6072 */
61 "\tcmpl $0, %0\n"
73 "\tcmpl $0, %[size]\n"
6274 "jz 6f\n"
6375
6476 "\t.p2align 4,,15\n"
102114 /*
103115 * while (size-- > 0)
104116 */
105 "\tadd %4, %%rdi\n"
106 "\tadd %5, %%rsi\n"
107 "\tadd %6, %%rbx\n"
108 "\tdecl %0\n"
117 #ifndef _ILP32
118 "\taddq %[dst_step], %%rdi\n"
119 "\taddq %[src_step], %%rsi\n"
120 "\taddq %[sum_step], %%rbx\n"
121 #else
122 "\taddl %[dst_step], %%edi\n"
123 "\taddl %[src_step], %%esi\n"
124 "\taddl %[sum_step], %%ebx\n"
125 #endif
126 "\tdecl %[size]\n"
109127 "\tjnz 1b\n"
110128
111129 "6:"
112
130
113131 "\temms\n"
114 "\tmovq %7, %%rbx\n"
115
116 : /* no output regs */
117 : "m" (size), "m" (dst), "m" (src),
118 "m" (sum), "m" (dst_step), "m" (src_step),
119 "m" (sum_step), "m" (old_rbx)
120 : "rsi", "rdi", "edx", "ecx", "eax"
132 #ifdef BOUNDED_RBX
133 "\tmovq %[old_rbx], %%rbx\n"
134 #endif
135 : [size] "+&rm" (size)
136 #ifdef BOUNDED_RBX
137 , [old_rbx] "=m" (old_rbx)
138 #endif
139 : [dst] "m" (dst), [src] "m" (src), [sum] "m" (sum),
140 [dst_step] "im" (dst_step), [src_step] "im" (src_step),
141 [sum_step] "im" (sum_step)
142 : "rsi", "rdi", "edx", "ecx", "eax", "memory", "cc"
143 #ifndef BOUNDED_RBX
144 , "rbx"
145 #endif
146 #ifdef HAVE_MMX
147 , "mm0"
148 #else
149 , "st", "st(1)", "st(2)", "st(3)",
150 "st(4)", "st(5)", "st(6)", "st(7)"
151 #endif
121152 );
122153 }
123154
129160 volatile signed int *sum, size_t dst_step,
130161 size_t src_step, size_t sum_step)
131162 {
163 #ifdef BOUNDED_RBX
132164 unsigned long long old_rbx;
133
165 #endif
134166 /*
135167 * RSI - src
136168 * RDI - dst
141173 */
142174 __asm__ __volatile__ (
143175 "\n"
144
145 "\tmovq %%rbx, %7\n"
146 /*
147 * initialization, load ESI, EDI, EBX registers
148 */
149 "\tmovq %1, %%rdi\n"
150 "\tmovq %2, %%rsi\n"
151 "\tmovq %3, %%rbx\n"
176 #ifdef BOUNDED_RBX
177 "\tmovq %%rbx, %[old_rbx]\n"
178 #endif
179 /*
180 * initialization, load RSI, RDI, RBX registers
181 */
182 #ifndef _ILP32
183 "\tmovq %[dst], %%rdi\n"
184 "\tmovq %[src], %%rsi\n"
185 "\tmovq %[sum], %%rbx\n"
186 #else
187 "\tmovl %[dst], %%edi\n"
188 "\tmovl %[src], %%esi\n"
189 "\tmovl %[sum], %%ebx\n"
190 #endif
152191
153192 /*
154193 * while (size-- > 0) {
155194 */
156 "\tcmpl $0, %0\n"
195 "\tcmpl $0, %[size]\n"
157196 "jz 6f\n"
158197
159198 "\t.p2align 4,,15\n"
219258 /*
220259 * while (size-- > 0)
221260 */
222 "\tadd %4, %%rdi\n"
223 "\tadd %5, %%rsi\n"
224 "\tadd %6, %%rbx\n"
225 "\tdecl %0\n"
261 #ifndef _ILP32
262 "\taddq %[dst_step], %%rdi\n"
263 "\taddq %[src_step], %%rsi\n"
264 "\taddq %[sum_step], %%rbx\n"
265 #else
266 "\taddl %[dst_step], %%edi\n"
267 "\taddl %[src_step], %%esi\n"
268 "\taddl %[sum_step], %%ebx\n"
269 #endif
270 "\tdecl %[size]\n"
226271 "\tjnz 1b\n"
227
272
228273 "6:"
229 "\tmovq %7, %%rbx\n"
230
231 : /* no output regs */
232 : "m" (size), "m" (dst), "m" (src),
233 "m" (sum), "m" (dst_step), "m" (src_step),
234 "m" (sum_step), "m" (old_rbx)
235 : "rsi", "rdi", "edx", "ecx", "eax"
274 #ifdef BOUNDED_RBX
275 "\tmovq %[old_rbx], %%rbx\n"
276 #endif
277 : [size] "+&rm" (size)
278 #ifdef BOUNDED_RBX
279 , [old_rbx] "=m" (old_rbx)
280 #endif
281 : [dst] "m" (dst), [src] "m" (src), [sum] "m" (sum),
282 [dst_step] "im" (dst_step), [src_step] "im" (src_step),
283 [sum_step] "im" (sum_step)
284 : "rsi", "rdi", "edx", "ecx", "eax", "memory", "cc"
285 #ifndef BOUNDED_RBX
286 , "rbx"
287 #endif
236288 );
237289 }
238290
244296 volatile signed int *sum, size_t dst_step,
245297 size_t src_step, size_t sum_step)
246298 {
299 #ifdef BOUNDED_RBX
247300 unsigned long long old_rbx;
248
301 #endif
249302 /*
250303 * RSI - src
251304 * RDI - dst
256309 */
257310 __asm__ __volatile__ (
258311 "\n"
259
260 "\tmovq %%rbx, %7\n"
261 /*
262 * initialization, load ESI, EDI, EBX registers
263 */
264 "\tmovq %1, %%rdi\n"
265 "\tmovq %2, %%rsi\n"
266 "\tmovq %3, %%rbx\n"
312 #ifdef BOUNDED_RBX
313 "\tmovq %%rbx, %[old_rbx]\n"
314 #endif
315 /*
316 * initialization, load RSI, RDI, RBX registers
317 */
318 #ifndef _ILP32
319 "\tmovq %[dst], %%rdi\n"
320 "\tmovq %[src], %%rsi\n"
321 "\tmovq %[sum], %%rbx\n"
322 #else
323 "\tmovl %[dst], %%edi\n"
324 "\tmovl %[src], %%esi\n"
325 "\tmovl %[sum], %%ebx\n"
326 #endif
267327
268328 /*
269329 * while (size-- > 0) {
270330 */
271 "\tcmpl $0, %0\n"
331 "\tcmpl $0, %[size]\n"
272332 "jz 6f\n"
273333
274334 "\t.p2align 4,,15\n"
315375 "\tmovw %%ax, (%%rdi)\n"
316376 "\tshrl $16, %%eax\n"
317377 "\tmovb %%al, 2(%%rdi)\n"
318
378
319379 "\tcmpl %%ecx, (%%rbx)\n"
320380 "\tjnz 3b\n"
321381
322382 /*
323383 * while (size-- > 0)
324384 */
325 "\tadd %4, %%rdi\n"
326 "\tadd %5, %%rsi\n"
327 "\tadd %6, %%rbx\n"
328 "\tdecl %0\n"
385 #ifndef _ILP32
386 "\taddq %[dst_step], %%rdi\n"
387 "\taddq %[src_step], %%rsi\n"
388 "\taddq %[sum_step], %%rbx\n"
389 #else
390 "\taddl %[dst_step], %%edi\n"
391 "\taddl %[src_step], %%esi\n"
392 "\taddl %[sum_step], %%ebx\n"
393 #endif
394 "\tdecl %[size]\n"
329395 "\tjnz 1b\n"
330
396
331397 "6:"
332 "\tmovq %7, %%rbx\n"
333
334 : /* no output regs */
335 : "m" (size), "m" (dst), "m" (src),
336 "m" (sum), "m" (dst_step), "m" (src_step),
337 "m" (sum_step), "m" (old_rbx)
338 : "rsi", "rdi", "edx", "ecx", "eax"
398 #ifdef BOUNDED_RBX
399 "\tmovq %[old_rbx], %%rbx\n"
400 #endif
401 : [size] "+&rm" (size)
402 #ifdef BOUNDED_RBX
403 , [old_rbx] "=m" (old_rbx)
404 #endif
405 : [dst] "m" (dst), [src] "m" (src), [sum] "m" (sum),
406 [dst_step] "im" (dst_step), [src_step] "im" (src_step),
407 [sum_step] "im" (sum_step)
408 : "rsi", "rdi", "edx", "ecx", "eax", "memory", "cc"
409 #ifndef BOUNDED_RBX
410 , "rbx"
411 #endif
339412 );
340413 }
414
415 #ifdef BOUNDED_RBX
416 # undef BOUNDED_RBX
417 #endif
722722 dshare->ipc_key = opts->ipc_key;
723723 dshare->ipc_perm = opts->ipc_perm;
724724 dshare->ipc_gid = opts->ipc_gid;
725 dshare->tstamp_type = opts->tstamp_type;
725726 dshare->semid = -1;
726727 dshare->shmid = -1;
727728
928929 # roundup
929930 # rounddown
930931 # auto (default)
932 tstamp_type STR # timestamp type
933 # STR can be one of the below strings :
934 # default, gettimeofday, monotonic, monotonic_raw
931935 slave STR
932936 # or
933937 slave { # Slave definition
164164 // printf("sync ptr diff = %li\n", diff);
165165 if (pcm->stop_threshold >= pcm->boundary) /* don't care */
166166 return 0;
167 if ((avail = snd_pcm_mmap_capture_hw_avail(pcm)) >= pcm->stop_threshold) {
167 if ((avail = snd_pcm_mmap_capture_avail(pcm)) >= pcm->stop_threshold) {
168168 gettimestamp(&dsnoop->trigger_tstamp, pcm->tstamp_type);
169169 dsnoop->state = SND_PCM_STATE_XRUN;
170170 dsnoop->avail_max = avail;
240240 /* Fall through */
241241 case SNDRV_PCM_STATE_PREPARED:
242242 case SNDRV_PCM_STATE_SUSPENDED:
243 *delayp = snd_pcm_mmap_capture_hw_avail(pcm);
243 *delayp = snd_pcm_mmap_capture_avail(pcm);
244244 return 0;
245245 case SNDRV_PCM_STATE_XRUN:
246246 return -EPIPE;
351351
352352 static snd_pcm_sframes_t snd_pcm_dsnoop_rewindable(snd_pcm_t *pcm)
353353 {
354 return snd_pcm_mmap_capture_hw_avail(pcm);
354 return snd_pcm_mmap_capture_hw_rewindable(pcm);
355355 }
356356
357357 static snd_pcm_sframes_t snd_pcm_dsnoop_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
590590 dsnoop->ipc_key = opts->ipc_key;
591591 dsnoop->ipc_perm = opts->ipc_perm;
592592 dsnoop->ipc_gid = opts->ipc_gid;
593 dsnoop->tstamp_type = opts->tstamp_type;
593594 dsnoop->semid = -1;
594595 dsnoop->shmid = -1;
595596
779780 # roundup
780781 # rounddown
781782 # auto (default)
783 tstamp_type STR # timestamp type
784 # STR can be one of the below strings :
785 # default, gettimeofday, monotonic, monotonic_raw
782786 slave STR
783787 # or
784788 slave { # Slave definition
731731 pcm->private_data = ext;
732732 pcm->poll_fd = spcm->poll_fd;
733733 pcm->poll_events = spcm->poll_events;
734 pcm->tstamp_type = spcm->tstamp_type;
734735 snd_pcm_set_hw_ptr(pcm, &ext->plug.hw_ptr, -1, 0);
735736 snd_pcm_set_appl_ptr(pcm, &ext->plug.appl_ptr, -1, 0);
736737
479479 return err;
480480 }
481481
482 /**
483 * \retval number of frames available to the application for playback
484 *
485 * This is how far ahead the hardware position in the ring buffer is,
486 * compared to the application position. ie. for playback it's the
487 * number of frames in the empty part of the ring buffer.
488 */
482489 static inline snd_pcm_uframes_t __snd_pcm_playback_avail(snd_pcm_t *pcm,
483490 const snd_pcm_uframes_t hw_ptr,
484491 const snd_pcm_uframes_t appl_ptr)
497504 return __snd_pcm_playback_avail(pcm, *pcm->hw.ptr, *pcm->appl.ptr);
498505 }
499506
507 /*
508 * \retval number of frames available to the application for capture
509 *
510 * This is how far ahead the hardware position in the ring buffer is
511 * compared to the application position. ie. for capture, it's the
512 * number of frames in the filled part of the ring buffer.
513 */
500514 static inline snd_pcm_uframes_t __snd_pcm_capture_avail(snd_pcm_t *pcm,
501515 const snd_pcm_uframes_t hw_ptr,
502516 const snd_pcm_uframes_t appl_ptr)
528542 return __snd_pcm_avail(pcm, *pcm->hw.ptr, *pcm->appl.ptr);
529543 }
530544
545 /*
546 * \retval number of frames available to the hardware for playback
547 *
548 * ie. the filled part of the ring buffer
549 */
531550 static inline snd_pcm_sframes_t snd_pcm_mmap_playback_hw_avail(snd_pcm_t *pcm)
532551 {
533552 return pcm->buffer_size - snd_pcm_mmap_playback_avail(pcm);
534553 }
535554
555 /*
556 * \retval number of frames available to the hardware for capture
557 *
558 * ie. the empty part of the ring buffer.
559 */
536560 static inline snd_pcm_sframes_t snd_pcm_mmap_capture_hw_avail(snd_pcm_t *pcm)
537561 {
538562 return pcm->buffer_size - snd_pcm_mmap_capture_avail(pcm);
581605 return *pcm->hw.ptr % pcm->buffer_size;
582606 }
583607
608 /*
609 * \retval number of frames pending from application to hardware
610 */
584611 static inline snd_pcm_uframes_t snd_pcm_mmap_playback_delay(snd_pcm_t *pcm)
585612 {
586613 return snd_pcm_mmap_playback_hw_avail(pcm);
587614 }
588615
616 /*
617 * \retval number of frames pending from hardware to application
618 */
589619 static inline snd_pcm_uframes_t snd_pcm_mmap_capture_delay(snd_pcm_t *pcm)
590620 {
591 return snd_pcm_mmap_capture_hw_avail(pcm);
621 return snd_pcm_mmap_capture_avail(pcm);
592622 }
593623
594624 static inline snd_pcm_sframes_t snd_pcm_mmap_delay(snd_pcm_t *pcm)
927957
928958 int snd_pcm_sw_params_set_tstamp_mode(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_tstamp_t val);
929959 int INTERNAL(snd_pcm_sw_params_get_tstamp_mode)(const snd_pcm_sw_params_t *params, snd_pcm_tstamp_t *val);
960 int snd_pcm_sw_params_set_tstamp_type(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_tstamp_type_t val);
961 int snd_pcm_sw_params_get_tstamp_type(const snd_pcm_sw_params_t *params, snd_pcm_tstamp_type_t *val);
930962 int snd_pcm_sw_params_set_avail_min(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
931963 int INTERNAL(snd_pcm_sw_params_get_avail_min)(const snd_pcm_sw_params_t *params, snd_pcm_uframes_t *val);
932964 int snd_pcm_sw_params_set_start_threshold(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val);
10501050 /* commit the remaining fraction (if any) */
10511051 snd_pcm_uframes_t size, ofs, saved_avail_min;
10521052 snd_pcm_sw_params_t sw_params;
1053 int commit_err = 0;
10531054
10541055 __snd_pcm_lock(pcm);
10551056 /* temporarily set avail_min to one */
10591060 snd_pcm_sw_params(rate->gen.slave, &sw_params);
10601061
10611062 size = rate->appl_ptr - rate->last_commit_ptr;
1063 if (size > pcm->boundary)
1064 size -= pcm->boundary;
10621065 ofs = rate->last_commit_ptr % pcm->buffer_size;
10631066 while (size > 0) {
10641067 snd_pcm_uframes_t psize, spsize;
10761079 if (! spsize)
10771080 break;
10781081 }
1079 snd_pcm_rate_commit_area(pcm, rate, ofs,
1082 commit_err = snd_pcm_rate_commit_area(pcm, rate, ofs,
10801083 psize, spsize);
1084 if (commit_err == 1) {
1085 rate->last_commit_ptr += psize;
1086 if (rate->last_commit_ptr >= pcm->boundary)
1087 rate->last_commit_ptr = 0;
1088 } else if (commit_err == 0) {
1089 if (pcm->mode & SND_PCM_NONBLOCK) {
1090 commit_err = -EAGAIN;
1091 break;
1092 }
1093 continue;
1094 } else
1095 break;
1096
10811097 ofs = (ofs + psize) % pcm->buffer_size;
10821098 size -= psize;
10831099 }
10841100 sw_params.avail_min = saved_avail_min;
10851101 snd_pcm_sw_params(rate->gen.slave, &sw_params);
10861102 __snd_pcm_unlock(pcm);
1103 if (commit_err < 0)
1104 return commit_err;
10871105 }
10881106 return snd_pcm_drain(rate->gen.slave);
10891107 }
12621280
12631281 static int rate_open_func(snd_pcm_rate_t *rate, const char *type, const snd_config_t *converter_conf, int verbose)
12641282 {
1265 char open_name[64], open_conf_name[64], lib_name[128], *lib = NULL;
1283 char open_name[64], open_conf_name[64], lib_name[64], *lib = NULL;
12661284 snd_pcm_rate_open_func_t open_func;
12671285 snd_pcm_rate_open_conf_func_t open_conf_func;
12681286 int err;
12711289 snprintf(open_conf_name, sizeof(open_conf_name), "_snd_pcm_rate_%s_open_conf", type);
12721290 if (!is_builtin_plugin(type)) {
12731291 snprintf(lib_name, sizeof(lib_name),
1274 "%s/libasound_module_rate_%s.so", ALSA_PLUGIN_DIR, type);
1292 "libasound_module_rate_%s.so", type);
12751293 lib = lib_name;
12761294 }
12771295
103103 int schannels;
104104 snd_pcm_route_params_t params;
105105 snd_pcm_chmap_t *chmap;
106 snd_pcm_chmap_query_t **chmap_override;
106107 } snd_pcm_route_t;
107108
108109 #endif /* DOC_HIDDEN */
440441 free(params->dsts);
441442 }
442443 free(route->chmap);
444 snd_pcm_free_chmaps(route->chmap_override);
443445 return snd_pcm_generic_close(pcm);
444446 }
445447
633635 snd_pcm_chmap_t *map, *slave_map;
634636 unsigned int src, dst, nsrcs;
635637
638 if (route->chmap_override)
639 return _snd_pcm_choose_fixed_chmap(pcm, route->chmap_override);
640
636641 slave_map = snd_pcm_generic_get_chmap(pcm);
637642 if (!slave_map)
638643 return NULL;
659664
660665 static snd_pcm_chmap_query_t **snd_pcm_route_query_chmaps(snd_pcm_t *pcm)
661666 {
667 snd_pcm_route_t *route = pcm->private_data;
662668 snd_pcm_chmap_query_t **maps;
663 snd_pcm_chmap_t *map = snd_pcm_route_get_chmap(pcm);
669 snd_pcm_chmap_t *map;
670
671 if (route->chmap_override)
672 return _snd_pcm_copy_chmap_query(route->chmap_override);
673
674 map = snd_pcm_route_get_chmap(pcm);
664675 if (!map)
665676 return NULL;
666677 maps = _snd_pcm_make_single_query_chmaps(map);
817828 return -EINVAL;
818829 }
819830
820 static int find_matching_chmap(snd_pcm_t *spcm, snd_pcm_chmap_t *tt_chmap,
831 static int find_matching_chmap(snd_pcm_chmap_query_t **chmaps,
832 snd_pcm_chmap_t *tt_chmap,
821833 snd_pcm_chmap_t **found_chmap, int *schannels)
822834 {
823 snd_pcm_chmap_query_t** chmaps = snd_pcm_query_chmaps(spcm);
824835 int i;
825836
826837 *found_chmap = NULL;
853864 int size = sizeof(snd_pcm_chmap_t) + c->channels * sizeof(unsigned int);
854865 *found_chmap = malloc(size);
855866 if (!*found_chmap) {
856 snd_pcm_free_chmaps(chmaps);
857867 return -ENOMEM;
858868 }
859869 memcpy(*found_chmap, c, size);
861871 break;
862872 }
863873 }
864
865 snd_pcm_free_chmaps(chmaps);
866874
867875 if (*found_chmap == NULL) {
868876 SNDERR("Found no matching channel map");
12511259 SCHANNEL REAL # route value (0.0 - 1.0)
12521260 }
12531261 }
1262 [chmap MAP] # Override channel maps; MAP is a string array
12541263 }
12551264 \endcode
12561265
12911300 snd_pcm_route_ttable_entry_t *ttable = NULL;
12921301 unsigned int csize, ssize;
12931302 unsigned int cused, sused;
1303 snd_pcm_chmap_query_t **chmaps = NULL;
12941304 snd_config_for_each(i, next, conf) {
12951305 snd_config_t *n = snd_config_iterator_entry(i);
12961306 const char *id;
13051315 if (strcmp(id, "ttable") == 0) {
13061316 if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
13071317 SNDERR("Invalid type for %s", id);
1318 snd_pcm_free_chmaps(chmaps);
13081319 return -EINVAL;
13091320 }
13101321 tt = n;
13111322 continue;
13121323 }
1324 if (strcmp(id, "chmap") == 0) {
1325 chmaps = _snd_pcm_parse_config_chmaps(n);
1326 if (!chmaps) {
1327 SNDERR("Invalid channel map for %s", id);
1328 return -EINVAL;
1329 }
1330 continue;
1331 }
13131332 SNDERR("Unknown field %s", id);
13141333 return -EINVAL;
13151334 }
13161335 if (!slave) {
13171336 SNDERR("slave is not defined");
1337 snd_pcm_free_chmaps(chmaps);
13181338 return -EINVAL;
13191339 }
13201340 if (!tt) {
13211341 SNDERR("ttable is not defined");
1342 snd_pcm_free_chmaps(chmaps);
13221343 return -EINVAL;
13231344 }
13241345 err = snd_pcm_slave_conf(root, slave, &sconf, 2,
13251346 SND_PCM_HW_PARAM_FORMAT, 0, &sformat,
13261347 SND_PCM_HW_PARAM_CHANNELS, 0, &schannels);
1327 if (err < 0)
1348 if (err < 0) {
1349 snd_pcm_free_chmaps(chmaps);
13281350 return err;
1351 }
13291352 if (sformat != SND_PCM_FORMAT_UNKNOWN &&
13301353 snd_pcm_format_linear(sformat) != 1) {
13311354 snd_config_delete(sconf);
13321355 SNDERR("slave format is not linear");
1356 snd_pcm_free_chmaps(chmaps);
13331357 return -EINVAL;
13341358 }
13351359
13441368 if (err < 0) {
13451369 free(tt_chmap);
13461370 free(ttable);
1371 snd_pcm_free_chmaps(chmaps);
13471372 return err;
13481373 }
13491374
13501375 if (tt_chmap) {
1351 err = find_matching_chmap(spcm, tt_chmap, &chmap, &schannels);
1376 if (!chmaps)
1377 chmaps = snd_pcm_query_chmaps(spcm);
1378 if (chmaps)
1379 err = find_matching_chmap(chmaps, tt_chmap, &chmap,
1380 &schannels);
13521381 free(tt_chmap);
1353 if (err < 0) {
1382 if (chmaps && err < 0) {
1383 snd_pcm_free_chmaps(chmaps);
13541384 snd_pcm_close(spcm);
13551385 return err;
13561386 }
13591389 err = _snd_pcm_route_determine_ttable(tt, &csize, &ssize, chmap);
13601390 if (err < 0) {
13611391 free(chmap);
1392 snd_pcm_free_chmaps(chmaps);
13621393 snd_pcm_close(spcm);
13631394 return err;
13641395 }
13651396 ttable = malloc(csize * ssize * sizeof(snd_pcm_route_ttable_entry_t));
13661397 if (ttable == NULL) {
13671398 free(chmap);
1399 snd_pcm_free_chmaps(chmaps);
13681400 snd_pcm_close(spcm);
13691401 return -ENOMEM;
13701402 }
13731405 if (err < 0) {
13741406 free(chmap);
13751407 free(ttable);
1408 snd_pcm_free_chmaps(chmaps);
13761409 snd_pcm_close(spcm);
13771410 return err;
13781411 }
13841417 free(ttable);
13851418 if (err < 0) {
13861419 free(chmap);
1420 snd_pcm_free_chmaps(chmaps);
13871421 snd_pcm_close(spcm);
13881422 } else {
1389 ((snd_pcm_route_t*) (*pcmp)->private_data)->chmap = chmap;
1423 snd_pcm_route_t *route = (*pcmp)->private_data;
1424
1425 route->chmap = chmap;
1426 route->chmap_override = chmaps;
13901427 }
13911428
13921429 return err;
4242 {"effect", SND_SOC_TPLG_DAPM_EFFECT},
4343 {"siggen", SND_SOC_TPLG_DAPM_SIGGEN},
4444 {"src", SND_SOC_TPLG_DAPM_SRC},
45 {"asrc", SND_SOC_TPLG_DAPM_ASRC},
4546 {"encoder", SND_SOC_TPLG_DAPM_ENCODER},
4647 {"decoder", SND_SOC_TPLG_DAPM_DECODER},
4748 };
593594 }
594595
595596 if (strcmp(id, "invert") == 0) {
596 if (tplg_get_integer(n, &ival, 0))
597 ival = snd_config_get_bool(n);
598 if (ival < 0)
597599 return -EINVAL;
598600
599601 widget->invert = ival;
20522052 }
20532053
20542054 /* decode dai from the binary input */
2055 int tplg_decode_dai(snd_tplg_t *tplg,
2056 size_t pos,
2057 struct snd_soc_tplg_hdr *hdr,
2058 void *bin, size_t size)
2055 int tplg_decode_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
2056 size_t pos ATTRIBUTE_UNUSED,
2057 struct snd_soc_tplg_hdr *hdr ATTRIBUTE_UNUSED,
2058 void *bin ATTRIBUTE_UNUSED,
2059 size_t size ATTRIBUTE_UNUSED)
20592060 {
20602061 SNDERR("not implemented");
20612062 return -ENXIO;
20622063 }
20632064
20642065 /* decode cc from the binary input */
2065 int tplg_decode_cc(snd_tplg_t *tplg,
2066 size_t pos,
2067 struct snd_soc_tplg_hdr *hdr,
2068 void *bin, size_t size)
2066 int tplg_decode_cc(snd_tplg_t *tplg ATTRIBUTE_UNUSED,
2067 size_t pos ATTRIBUTE_UNUSED,
2068 struct snd_soc_tplg_hdr *hdr ATTRIBUTE_UNUSED,
2069 void *bin ATTRIBUTE_UNUSED,
2070 size_t size ATTRIBUTE_UNUSED)
20692071 {
20702072 SNDERR("not implemented");
20712073 return -ENXIO;
101101 return 0;
102102 }
103103
104 static int tplg_check_array_item(const char *id, int index)
105 {
106 const char *p;
107 long int val;
108
109 for (p = id; *p; p++) {
110 if (*p < '0' || *p > '9')
111 return 0;
112 }
113
114 errno = 0;
115 val = strtol(id, NULL, 10);
116 return errno == 0 && val == index;
117 }
118
119104 static int _compar(const void *a, const void *b)
120105 {
121106 const snd_config_t *c1 = *(snd_config_t **)a;
144129 a = malloc(sizeof(dst) * count);
145130 if (a == NULL)
146131 return NULL;
147 index = array = 0;
148 snd_config_for_each(i, next, src) {
149 snd_config_t *s = snd_config_iterator_entry(i);
150 const char *id2;
151 a[index++] = s;
152 if (array < 0)
153 continue;
154 if (snd_config_get_id(s, &id2)) {
155 free(a);
156 return NULL;
157 }
158 if (array >= 0 && tplg_check_array_item(id2, array))
159 array++;
160 else
161 array = -1;
162 }
163 if (array < 0)
132 array = snd_config_is_array(src);
133 if (array <= 0) {
134 index = 0;
135 snd_config_for_each(i, next, src) {
136 snd_config_t *s = snd_config_iterator_entry(i);
137 a[index++] = s;
138 }
164139 qsort(a, count, sizeof(a[0]), _compar);
140 }
165141 if (snd_config_make_compound(&dst, id, count == 1)) {
166142 free(a);
167143 return NULL;
328304
329305 count = 0;
330306 quoted = 0;
331 array = 0;
307 array = snd_config_is_array(src);
332308 s = NULL;
333309 snd_config_for_each(i, next, src) {
334310 s = snd_config_iterator_entry(i);
337313 return err;
338314 if (!quoted && tplg_check_quoted((unsigned char *)id))
339315 quoted = 1;
340 if (array >= 0 && tplg_check_array_item(id, array))
341 array++;
342 else
343 array = -1;
344316 count++;
345317 }
346318 if (count == 0)
363335
364336 if (level > 0) {
365337 err = tplg_save_printf(dst, NULL, "%s%s\n", delim,
366 array >= 0 ? "[" : "{");
338 array > 0 ? "[" : "{");
367339 if (err < 0)
368340 return err;
369341 }
377349 err = tplg_save_printf(dst, pfx, "");
378350 if (err < 0)
379351 return err;
380 if (array < 0) {
352 if (array <= 0) {
381353 delim = " ";
382354 if (quoted) {
383355 err = tplg_save_quoted(dst, id);
397369 if (level > 0) {
398370 pfx[level - 1] = '\0';
399371 err = tplg_save_printf(dst, pfx, "%s\n",
400 array >= 0 ? "]" : "}");
372 array > 0 ? "]" : "}");
401373 if (err < 0)
402374 return err;
403375 }
00 EXTRA_LTLIBRARIES = libucm.la
11
2 libucm_la_SOURCES = utils.c parser.c ucm_cond.c ucm_subs.c main.c
2 libucm_la_SOURCES = utils.c parser.c ucm_cond.c ucm_subs.c ucm_include.c \
3 ucm_regex.c main.c
34
45 noinst_HEADERS = ucm_local.h
56
104104 CONFIG_CLEAN_VPATH_FILES =
105105 libucm_la_LIBADD =
106106 am_libucm_la_OBJECTS = utils.lo parser.lo ucm_cond.lo ucm_subs.lo \
107 main.lo
107 ucm_include.lo ucm_regex.lo main.lo
108108 libucm_la_OBJECTS = $(am_libucm_la_OBJECTS)
109109 AM_V_lt = $(am__v_lt_@AM_V@)
110110 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
126126 depcomp = $(SHELL) $(top_srcdir)/depcomp
127127 am__maybe_remake_depfiles = depfiles
128128 am__depfiles_remade = ./$(DEPDIR)/main.Plo ./$(DEPDIR)/parser.Plo \
129 ./$(DEPDIR)/ucm_cond.Plo ./$(DEPDIR)/ucm_subs.Plo \
129 ./$(DEPDIR)/ucm_cond.Plo ./$(DEPDIR)/ucm_include.Plo \
130 ./$(DEPDIR)/ucm_regex.Plo ./$(DEPDIR)/ucm_subs.Plo \
130131 ./$(DEPDIR)/utils.Plo
131132 am__mv = mv -f
132133 COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
307308 top_builddir = @top_builddir@
308309 top_srcdir = @top_srcdir@
309310 EXTRA_LTLIBRARIES = libucm.la
310 libucm_la_SOURCES = utils.c parser.c ucm_cond.c ucm_subs.c main.c
311 libucm_la_SOURCES = utils.c parser.c ucm_cond.c ucm_subs.c ucm_include.c \
312 ucm_regex.c main.c
313
311314 noinst_HEADERS = ucm_local.h
312315 AM_CPPFLAGS = -I$(top_srcdir)/include
313316 all: all-am
356359 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Plo@am__quote@ # am--include-marker
357360 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser.Plo@am__quote@ # am--include-marker
358361 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ucm_cond.Plo@am__quote@ # am--include-marker
362 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ucm_include.Plo@am__quote@ # am--include-marker
363 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ucm_regex.Plo@am__quote@ # am--include-marker
359364 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ucm_subs.Plo@am__quote@ # am--include-marker
360365 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Plo@am__quote@ # am--include-marker
361366
519524 -rm -f ./$(DEPDIR)/main.Plo
520525 -rm -f ./$(DEPDIR)/parser.Plo
521526 -rm -f ./$(DEPDIR)/ucm_cond.Plo
527 -rm -f ./$(DEPDIR)/ucm_include.Plo
528 -rm -f ./$(DEPDIR)/ucm_regex.Plo
522529 -rm -f ./$(DEPDIR)/ucm_subs.Plo
523530 -rm -f ./$(DEPDIR)/utils.Plo
524531 -rm -f Makefile
569576 -rm -f ./$(DEPDIR)/main.Plo
570577 -rm -f ./$(DEPDIR)/parser.Plo
571578 -rm -f ./$(DEPDIR)/ucm_cond.Plo
579 -rm -f ./$(DEPDIR)/ucm_include.Plo
580 -rm -f ./$(DEPDIR)/ucm_regex.Plo
572581 -rm -f ./$(DEPDIR)/ucm_subs.Plo
573582 -rm -f ./$(DEPDIR)/utils.Plo
574583 -rm -f Makefile
332332 struct sequence_element *s;
333333 char *cdev = NULL;
334334 snd_ctl_t *ctl = NULL;
335 struct ctl_list *ctl_list;
335336 int err = 0;
336337
337338 list_for_each(pos, seq) {
399400 }
400401 }
401402 if (ctl == NULL) {
402 err = uc_mgr_open_ctl(uc_mgr, &ctl, cdev);
403 err = uc_mgr_open_ctl(uc_mgr, &ctl_list, cdev, 1);
403404 if (err < 0) {
404405 uc_error("unable to open ctl device '%s'", cdev);
405406 goto __fail;
406407 }
408 ctl = ctl_list->ctl;
407409 }
408410 err = execute_cset(ctl, s->data.cset, s->type);
409411 if (err < 0) {
515517 char buf[40];
516518 int err;
517519
518 ctl_list = uc_mgr_get_one_ctl(uc_mgr);
520 ctl_list = uc_mgr_get_master_ctl(uc_mgr);
519521 if (ctl_list) {
520522 id = snd_ctl_card_info_get_id(ctl_list->ctl_info);
521523 snprintf(buf, sizeof(buf), "hw:%s", id);
530532 }
531533
532534 /**
535 * \brief execute default commands
536 * \param uc_mgr Use case manager
537 * \return zero on success, otherwise a negative error code
538 */
539 static int set_defaults(snd_use_case_mgr_t *uc_mgr)
540 {
541 int err;
542
543 if (uc_mgr->default_list_executed)
544 return 0;
545 err = execute_sequence(uc_mgr, &uc_mgr->default_list,
546 &uc_mgr->value_list, NULL, NULL);
547 if (err < 0) {
548 uc_error("Unable to execute default sequence");
549 return err;
550 }
551 uc_mgr->default_list_executed = 1;
552 return 0;
553 }
554
555 /**
533556 * \brief Import master config and execute the default sequence
534557 * \param uc_mgr Use case manager
535558 * \return zero on success, otherwise a negative error code
541564 err = uc_mgr_import_master_config(uc_mgr);
542565 if (err < 0)
543566 return err;
544 err = add_auto_values(uc_mgr);
545 if (err < 0)
546 return err;
547 err = execute_sequence(uc_mgr, &uc_mgr->default_list,
548 &uc_mgr->value_list, NULL, NULL);
549 if (err < 0)
550 uc_error("Unable to execute default sequence");
551 return err;
567 return add_auto_values(uc_mgr);
552568 }
553569
554570 /**
844860 int err;
845861
846862 if (enable) {
863 err = set_defaults(uc_mgr);
864 if (err < 0)
865 return err;
847866 seq = &verb->enable_list;
848867 } else {
849868 seq = &verb->disable_list;
942961 if (mgr == NULL)
943962 return -ENOMEM;
944963 INIT_LIST_HEAD(&mgr->verb_list);
964 INIT_LIST_HEAD(&mgr->once_list);
945965 INIT_LIST_HEAD(&mgr->default_list);
946966 INIT_LIST_HEAD(&mgr->value_list);
947967 INIT_LIST_HEAD(&mgr->active_modifiers);
948968 INIT_LIST_HEAD(&mgr->active_devices);
949969 INIT_LIST_HEAD(&mgr->ctl_list);
970 INIT_LIST_HEAD(&mgr->variable_list);
950971 pthread_mutex_init(&mgr->mutex, NULL);
951972
952973 mgr->card_name = strdup(card_name);
9831004 pthread_mutex_lock(&uc_mgr->mutex);
9841005
9851006 uc_mgr_free_verb(uc_mgr);
1007
1008 uc_mgr->default_list_executed = 0;
9861009
9871010 /* reload all use cases */
9881011 err = import_master_config(uc_mgr);
18251848 return err;
18261849 }
18271850
1851 static int set_boot_user(snd_use_case_mgr_t *uc_mgr,
1852 const char *value)
1853 {
1854 int err;
1855
1856 if (value != NULL && *value) {
1857 uc_error("error: wrong value for _boot (%s)", value);
1858 return -EINVAL;
1859 }
1860 err = execute_sequence(uc_mgr, &uc_mgr->once_list,
1861 &uc_mgr->value_list, NULL, NULL);
1862 if (err < 0) {
1863 uc_error("Unable to execute once sequence");
1864 return err;
1865 }
1866 return err;
1867 }
1868
1869 static int set_defaults_user(snd_use_case_mgr_t *uc_mgr,
1870 const char *value)
1871 {
1872 if (value != NULL && *value) {
1873 uc_error("error: wrong value for _defaults (%s)", value);
1874 return -EINVAL;
1875 }
1876 return set_defaults(uc_mgr);
1877 }
1878
18281879 static int handle_transition_verb(snd_use_case_mgr_t *uc_mgr,
18291880 struct use_case_verb *new_verb)
18301881 {
20362087 int err = 0;
20372088
20382089 pthread_mutex_lock(&uc_mgr->mutex);
2039 if (strcmp(identifier, "_verb") == 0)
2090 if (strcmp(identifier, "_boot") == 0)
2091 err = set_boot_user(uc_mgr, value);
2092 else if (strcmp(identifier, "_defaults") == 0)
2093 err = set_defaults_user(uc_mgr, value);
2094 else if (strcmp(identifier, "_verb") == 0)
20402095 err = set_verb_user(uc_mgr, value);
20412096 else if (strcmp(identifier, "_enadev") == 0)
20422097 err = set_device_user(uc_mgr, value, 1);
6161 snd_config_t *cfg);
6262
6363 /*
64 * compose configuration file
65 */
66 static void configuration_filename2(char *fn, size_t fn_len, int format,
67 const char *dir, const char *file,
68 const char *suffix)
69 {
70 snprintf(fn, fn_len, "%s/ucm%s/%s/%s%s",
71 snd_config_topdir(), format >= 2 ? "2" : "",
72 dir, file, suffix);
73 }
74
75 static void configuration_filename(snd_use_case_mgr_t *uc_mgr,
76 char *fn, size_t fn_len,
77 const char *dir, const char *file,
78 const char *suffix)
79 {
80 const char *env;
81
82 if (uc_mgr->conf_format > 0) {
83 /* known format */
84 env = getenv(uc_mgr->conf_format >= 2 ? ALSA_CONFIG_UCM2_VAR :
85 ALSA_CONFIG_UCM_VAR);
86 } else {
87 /* auto-detect */
88 env = getenv(ALSA_CONFIG_UCM2_VAR);
89 if (env == NULL) {
90 env = getenv(ALSA_CONFIG_UCM_VAR);
91 if (env)
92 uc_mgr->conf_format = 1;
93 } else {
94 uc_mgr->conf_format = 2;
95 }
96 }
97 if (env) {
98 snprintf(fn, fn_len, "%s/%s/%s%s", env, dir, file, suffix);
99 return;
100 }
101
102 if (uc_mgr->conf_format > 0) {
103 configuration_filename2(fn, fn_len, uc_mgr->conf_format,
104 dir, file, suffix);
105 return;
106 }
107
108 configuration_filename2(fn, fn_len, 2, dir, file, suffix);
109 if (access(fn, R_OK) == 0) {
110 /* Found an ucm2 file, only look in the ucm2 dir from now on */
111 uc_mgr->conf_format = 2;
112 return;
113 }
114
115 configuration_filename2(fn, fn_len, 0, dir, file, suffix);
116 if (access(fn, R_OK) == 0) {
117 /* Found an ucm1 file, only look in the ucm dir from now on */
118 uc_mgr->conf_format = 1;
119 return;
120 }
121
122 /* make sure that the error message refers to the new path */
123 configuration_filename2(fn, fn_len, 2, dir, file, suffix);
64 * compose the absolute ucm filename
65 */
66 static void ucm_filename(char *fn, size_t fn_len, long version,
67 const char *dir, const char *file)
68 {
69 const char *env = getenv(version > 1 ? ALSA_CONFIG_UCM2_VAR : ALSA_CONFIG_UCM_VAR);
70
71 if (env == NULL)
72 snprintf(fn, fn_len, "%s/%s/%s%s%s",
73 snd_config_topdir(), version > 1 ? "ucm2" : "ucm",
74 dir ?: "", dir ? "/" : "", file);
75 else
76 snprintf(fn, fn_len, "%s/%s%s%s",
77 env, dir ?: "", dir ? "/" : "", file);
78 }
79
80 /*
81 *
82 */
83 int uc_mgr_config_load_file(snd_use_case_mgr_t *uc_mgr,
84 const char *file, snd_config_t **cfg)
85 {
86 char filename[PATH_MAX];
87 int err;
88
89 ucm_filename(filename, sizeof(filename), uc_mgr->conf_format,
90 file[0] == '/' ? NULL : uc_mgr->conf_dir_name,
91 file);
92 err = uc_mgr_config_load(uc_mgr->conf_format, filename, cfg);
93 if (err < 0) {
94 uc_error("error: failed to open file %s : %d", filename, -errno);
95 return err;
96 }
97 return 0;
12498 }
12599
126100 /*
129103 static char *replace_string(char **dst, const char *value)
130104 {
131105 free(*dst);
132 *dst = strdup(value);
106 *dst = value ? strdup(value) : NULL;
133107 return *dst;
134108 }
135109
150124 }
151125
152126 /*
127 * Parse string and substitute
128 */
129 int parse_string_substitute(snd_use_case_mgr_t *uc_mgr,
130 snd_config_t *n, char **res)
131 {
132 const char *str;
133 char *s;
134 int err;
135
136 err = snd_config_get_string(n, &str);
137 if (err < 0)
138 return err;
139 err = uc_mgr_get_substituted_value(uc_mgr, &s, str);
140 if (err >= 0)
141 *res = s;
142 return err;
143 }
144
145 /*
146 * Parse string and substitute
147 */
148 int parse_string_substitute3(snd_use_case_mgr_t *uc_mgr,
149 snd_config_t *n, char **res)
150 {
151 if (uc_mgr->conf_format < 3)
152 return parse_string(n, res);
153 return parse_string_substitute(uc_mgr, n, res);
154 }
155
156 /*
157 * Parse integer with substitution
158 */
159 int parse_integer_substitute(snd_use_case_mgr_t *uc_mgr,
160 snd_config_t *n, long *res)
161 {
162 char *s1, *s2;
163 int err;
164
165 err = snd_config_get_ascii(n, &s1);
166 if (err < 0)
167 return err;
168 err = uc_mgr_get_substituted_value(uc_mgr, &s2, s1);
169 if (err >= 0)
170 err = safe_strtol(s2, res);
171 free(s2);
172 free(s1);
173 return err;
174 }
175
176 /*
177 * Parse integer with substitution
178 */
179 int parse_integer_substitute3(snd_use_case_mgr_t *uc_mgr,
180 snd_config_t *n, long *res)
181 {
182 char *s1, *s2;
183 int err;
184
185 err = snd_config_get_ascii(n, &s1);
186 if (err < 0)
187 return err;
188 if (uc_mgr->conf_format < 3)
189 s2 = s1;
190 else
191 err = uc_mgr_get_substituted_value(uc_mgr, &s2, s1);
192 if (err >= 0)
193 err = safe_strtol(s2, res);
194 if (s1 != s2)
195 free(s2);
196 free(s1);
197 return err;
198 }
199
200 /*
153201 * Parse safe ID
154202 */
155203 int parse_is_name_safe(const char *name)
161209 return 1;
162210 }
163211
164 int parse_get_safe_id(snd_config_t *n, const char **id)
165 {
166 int err;
167
168 err = snd_config_get_id(n, id);
212 int get_string3(snd_use_case_mgr_t *uc_mgr, const char *s1, char **s)
213 {
214 if (uc_mgr->conf_format < 3) {
215 *s = strdup(s1);
216 if (*s == NULL)
217 return -ENOMEM;
218 return 0;
219 }
220 return uc_mgr_get_substituted_value(uc_mgr, s, s1);
221 }
222
223 int parse_get_safe_name(snd_use_case_mgr_t *uc_mgr, snd_config_t *n,
224 const char *alt, char **name)
225 {
226 const char *id;
227 int err;
228
229 if (alt) {
230 id = alt;
231 } else {
232 err = snd_config_get_id(n, &id);
233 if (err < 0)
234 return err;
235 }
236 if (!parse_is_name_safe(id))
237 return -EINVAL;
238 return get_string3(uc_mgr, id, name);
239 }
240
241 /*
242 * Evaluate variable regex definitions (in-place delete)
243 */
244 static int evaluate_regex(snd_use_case_mgr_t *uc_mgr,
245 snd_config_t *cfg)
246 {
247 snd_config_iterator_t i, next;
248 snd_config_t *d, *n;
249 const char *id;
250 int err;
251
252 err = snd_config_search(cfg, "DefineRegex", &d);
253 if (err == -ENOENT)
254 return 1;
169255 if (err < 0)
170256 return err;
171 if (!parse_is_name_safe((char *)(*id)))
172 return -EINVAL;
257
258 if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) {
259 uc_error("compound type expected for DefineRegex");
260 return -EINVAL;
261 }
262
263 if (uc_mgr->conf_format < 3) {
264 uc_error("DefineRegex is supported in v3+ syntax");
265 return -EINVAL;
266 }
267
268 snd_config_for_each(i, next, d) {
269 n = snd_config_iterator_entry(i);
270 err = snd_config_get_id(n, &id);
271 if (err < 0)
272 return err;
273 err = uc_mgr_define_regex(uc_mgr, id, n);
274 if (err < 0)
275 return err;
276 }
277
278 snd_config_delete(d);
173279 return 0;
280 }
281
282 /*
283 * Evaluate variable definitions (in-place delete)
284 */
285 static int evaluate_define(snd_use_case_mgr_t *uc_mgr,
286 snd_config_t *cfg)
287 {
288 snd_config_iterator_t i, next;
289 snd_config_t *d, *n;
290 const char *id;
291 char *var, *s;
292 int err;
293
294 err = snd_config_search(cfg, "Define", &d);
295 if (err == -ENOENT)
296 return evaluate_regex(uc_mgr, cfg);
297 if (err < 0)
298 return err;
299
300 if (snd_config_get_type(d) != SND_CONFIG_TYPE_COMPOUND) {
301 uc_error("compound type expected for Define");
302 return -EINVAL;
303 }
304
305 if (uc_mgr->conf_format < 3) {
306 uc_error("Define is supported in v3+ syntax");
307 return -EINVAL;
308 }
309
310 snd_config_for_each(i, next, d) {
311 n = snd_config_iterator_entry(i);
312 err = snd_config_get_id(n, &id);
313 if (err < 0)
314 return err;
315 err = snd_config_get_ascii(n, &var);
316 if (err < 0)
317 return err;
318 err = uc_mgr_get_substituted_value(uc_mgr, &s, var);
319 free(var);
320 if (err < 0)
321 return err;
322 uc_mgr_set_variable(uc_mgr, id, s);
323 free(s);
324 }
325
326 snd_config_delete(d);
327
328 return evaluate_regex(uc_mgr, cfg);
329 }
330
331 /*
332 * Evaluate include (in-place)
333 */
334 static int evaluate_include(snd_use_case_mgr_t *uc_mgr,
335 snd_config_t *cfg)
336 {
337 snd_config_t *n;
338 int err;
339
340 err = snd_config_search(cfg, "Include", &n);
341 if (err == -ENOENT)
342 return 1;
343 if (err < 0)
344 return err;
345
346 err = uc_mgr_evaluate_include(uc_mgr, cfg, n);
347 snd_config_delete(n);
348 return err;
174349 }
175350
176351 /*
184359
185360 err = snd_config_search(cfg, "If", &n);
186361 if (err == -ENOENT)
187 return 0;
362 return 1;
188363 if (err < 0)
189364 return err;
190365
191366 err = uc_mgr_evaluate_condition(uc_mgr, cfg, n);
192367 snd_config_delete(n);
193368 return err;
369 }
370
371 /*
372 * In-place evaluate
373 */
374 int uc_mgr_evaluate_inplace(snd_use_case_mgr_t *uc_mgr,
375 snd_config_t *cfg)
376 {
377 int err1 = 0, err2 = 0, err3 = 0;
378
379 while (err1 == 0 || err2 == 0 || err3 == 0) {
380 /* variables at first */
381 err1 = evaluate_define(uc_mgr, cfg);
382 if (err1 < 0)
383 return err1;
384 /* include at second */
385 err2 = evaluate_include(uc_mgr, cfg);
386 if (err2 < 0)
387 return err2;
388 /* include may define another variables */
389 /* conditions may depend on them */
390 if (err2 == 0)
391 continue;
392 err3 = evaluate_condition(uc_mgr, cfg);
393 if (err3 < 0)
394 return err3;
395 }
396 return 0;
194397 }
195398
196399 /*
225428 return -ENOMEM;
226429 INIT_LIST_HEAD(&tseq->transition_list);
227430
228 tseq->name = strdup(id);
229 if (tseq->name == NULL) {
431 err = get_string3(uc_mgr, id, &tseq->name);
432 if (err < 0) {
230433 free(tseq);
231 return -ENOMEM;
434 return err;
232435 }
233436
234437 err = parse_sequence(uc_mgr, &tseq->transition_list, n);
329532 sdev = calloc(1, sizeof(struct dev_list_node));
330533 if (sdev == NULL)
331534 return -ENOMEM;
332 err = parse_string(n, &sdev->name);
535 err = parse_string_substitute3(uc_mgr, n, &sdev->name);
333536 if (err < 0) {
334537 free(sdev);
335538 return err;
402605 * disable sequence is needed by its parenet device.
403606 */
404607 static int parse_component_seq(snd_use_case_mgr_t *uc_mgr,
405 snd_config_t *n, int enable,
406 struct component_sequence *cmpt_seq)
407 {
408 const char *val;
409 int err;
410
411 err = snd_config_get_string(n, &val);
608 snd_config_t *n, int enable,
609 struct component_sequence *cmpt_seq)
610 {
611 char *val;
612 int err;
613
614 err = parse_string_substitute3(uc_mgr, n, &val);
412615 if (err < 0)
413616 return err;
414617
415618 cmpt_seq->device = find_component_dev(uc_mgr, val);
416619 if (!cmpt_seq->device) {
417620 uc_error("error: Cannot find component device %s", val);
418 return -EINVAL;
419 }
621 free(val);
622 return -EINVAL;
623 }
624 free(val);
420625
421626 /* Parent needs its enable or disable sequence */
422627 cmpt_seq->enable = enable;
481686
482687 if (strcmp(cmd, "cdev") == 0) {
483688 curr->type = SEQUENCE_ELEMENT_TYPE_CDEV;
484 err = parse_string(n, &curr->data.cdev);
689 err = parse_string_substitute3(uc_mgr, n, &curr->data.cdev);
485690 if (err < 0) {
486691 uc_error("error: cdev requires a string!");
487692 return err;
491696
492697 if (strcmp(cmd, "cset") == 0) {
493698 curr->type = SEQUENCE_ELEMENT_TYPE_CSET;
494 err = parse_string(n, &curr->data.cset);
699 err = parse_string_substitute3(uc_mgr, n, &curr->data.cset);
495700 if (err < 0) {
496701 uc_error("error: cset requires a string!");
497702 return err;
525730
526731 if (strcmp(cmd, "cset-bin-file") == 0) {
527732 curr->type = SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE;
528 err = parse_string(n, &curr->data.cset);
733 err = parse_string_substitute3(uc_mgr, n, &curr->data.cset);
529734 if (err < 0) {
530735 uc_error("error: cset-bin-file requires a string!");
531736 return err;
535740
536741 if (strcmp(cmd, "cset-tlv") == 0) {
537742 curr->type = SEQUENCE_ELEMENT_TYPE_CSET_TLV;
538 err = parse_string(n, &curr->data.cset);
743 err = parse_string_substitute3(uc_mgr, n, &curr->data.cset);
539744 if (err < 0) {
540745 uc_error("error: cset-tlv requires a string!");
541746 return err;
545750
546751 if (strcmp(cmd, "usleep") == 0) {
547752 curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP;
548 err = snd_config_get_integer(n, &curr->data.sleep);
753 err = parse_integer_substitute3(uc_mgr, n, &curr->data.sleep);
549754 if (err < 0) {
550755 uc_error("error: usleep requires integer!");
551756 return err;
555760
556761 if (strcmp(cmd, "msleep") == 0) {
557762 curr->type = SEQUENCE_ELEMENT_TYPE_SLEEP;
558 err = snd_config_get_integer(n, &curr->data.sleep);
763 err = parse_integer_substitute3(uc_mgr, n, &curr->data.sleep);
559764 if (err < 0) {
560765 uc_error("error: msleep requires integer!");
561766 return err;
566771
567772 if (strcmp(cmd, "exec") == 0) {
568773 curr->type = SEQUENCE_ELEMENT_TYPE_EXEC;
569 err = parse_string(n, &curr->data.exec);
774 err = parse_string_substitute3(uc_mgr, n, &curr->data.exec);
570775 if (err < 0) {
571776 uc_error("error: exec requires a string!");
572777 return err;
628833 return -EINVAL;
629834 }
630835
631 /* in-place condition evaluation */
632 err = evaluate_condition(uc_mgr, cfg);
836 /* in-place evaluation */
837 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
633838 if (err < 0)
634839 return err;
635840
652857 }
653858 break;
654859 case SND_CONFIG_TYPE_STRING:
655 err = parse_string(n, &s);
860 err = parse_string_substitute(uc_mgr, n, &s);
656861 if (err < 0) {
657862 uc_error("error: unable to parse a string for id '%s'!", id);
658863 return err;
715920 * Both are optional.
716921 */
717922 static int parse_modifier(snd_use_case_mgr_t *uc_mgr,
718 snd_config_t *cfg,
719 void *data1,
720 void *data2)
923 snd_config_t *cfg,
924 void *data1, void *data2)
721925 {
722926 struct use_case_verb *verb = data1;
723927 struct use_case_modifier *modifier;
724 const char *name;
928 char *name;
725929 snd_config_iterator_t i, next;
726930 snd_config_t *n;
727931 int err;
728932
729 if (data2) {
730 name = data2;
731 if (!parse_is_name_safe(name))
732 return -EINVAL;
733 }
734 else {
735 if (parse_get_safe_id(cfg, &name) < 0)
736 return -EINVAL;
737 }
933 if (parse_get_safe_name(uc_mgr, cfg, data2, &name) < 0)
934 return -EINVAL;
738935
739936 /* allocate modifier */
740937 modifier = calloc(1, sizeof(*modifier));
741 if (modifier == NULL)
938 if (modifier == NULL) {
939 free(name);
742940 return -ENOMEM;
941 }
743942 INIT_LIST_HEAD(&modifier->enable_list);
744943 INIT_LIST_HEAD(&modifier->disable_list);
745944 INIT_LIST_HEAD(&modifier->transition_list);
746945 INIT_LIST_HEAD(&modifier->dev_list.list);
747946 INIT_LIST_HEAD(&modifier->value_list);
748947 list_add_tail(&modifier->list, &verb->modifier_list);
749 modifier->name = strdup(name);
750
751 /* in-place condition evaluation */
752 err = evaluate_condition(uc_mgr, cfg);
948 modifier->name = name;
949
950 /* in-place evaluation */
951 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
753952 if (err < 0)
754953 return err;
755954
760959 continue;
761960
762961 if (strcmp(id, "Comment") == 0) {
763 err = parse_string(n, &modifier->comment);
962 err = parse_string_substitute3(uc_mgr, n, &modifier->comment);
764963 if (err < 0) {
765964 uc_error("error: failed to get modifier comment");
766965 return err;
8681067 */
8691068 static int parse_device(snd_use_case_mgr_t *uc_mgr,
8701069 snd_config_t *cfg,
871 void *data1,
872 void *data2)
1070 void *data1, void *data2)
8731071 {
8741072 struct use_case_verb *verb = data1;
875 const char *name;
1073 char *name;
8761074 struct use_case_device *device;
8771075 snd_config_iterator_t i, next;
8781076 snd_config_t *n;
8791077 int err;
8801078
881 if (data2) {
882 name = data2;
883 if (!parse_is_name_safe(name))
884 return -EINVAL;
885 }
886 else {
887 if (parse_get_safe_id(cfg, &name) < 0)
888 return -EINVAL;
889 }
1079 if (parse_get_safe_name(uc_mgr, cfg, data2, &name) < 0)
1080 return -EINVAL;
8901081
8911082 device = calloc(1, sizeof(*device));
892 if (device == NULL)
1083 if (device == NULL) {
1084 free(name);
8931085 return -ENOMEM;
1086 }
8941087 INIT_LIST_HEAD(&device->enable_list);
8951088 INIT_LIST_HEAD(&device->disable_list);
8961089 INIT_LIST_HEAD(&device->transition_list);
8971090 INIT_LIST_HEAD(&device->dev_list.list);
8981091 INIT_LIST_HEAD(&device->value_list);
8991092 list_add_tail(&device->list, &verb->device_list);
900 device->name = strdup(name);
901
902 /* in-place condition evaluation */
903 err = evaluate_condition(uc_mgr, cfg);
1093 device->name = name;
1094
1095 /* in-place evaluation */
1096 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
9041097 if (err < 0)
9051098 return err;
9061099
9111104 continue;
9121105
9131106 if (strcmp(id, "Comment") == 0) {
914 err = parse_string(n, &device->comment);
1107 err = parse_string_substitute3(uc_mgr, n, &device->comment);
9151108 if (err < 0) {
9161109 uc_error("error: failed to get device comment");
9171110 return err;
9931186 * RenameDevice."Speaker1" "Speaker"
9941187 * RemoveDevice."Speaker2" "Speaker2"
9951188 */
996 static int parse_dev_name_list(snd_config_t *cfg,
1189 static int parse_dev_name_list(snd_use_case_mgr_t *uc_mgr,
1190 snd_config_t *cfg,
9971191 struct list_head *list)
9981192 {
9991193 snd_config_t *n;
10001194 snd_config_iterator_t i, next;
10011195 const char *id, *name1;
1002 char *name2;
1196 char *name1s, *name2;
10031197 struct ucm_dev_name *dev;
10041198 snd_config_iterator_t pos;
10051199 int err;
10181212 if (snd_config_get_id(n, &name1) < 0)
10191213 return -EINVAL;
10201214
1021 err = parse_string(n, &name2);
1215 err = get_string3(uc_mgr, name1, &name1s);
1216 if (err < 0)
1217 return err;
1218
1219 err = parse_string_substitute3(uc_mgr, n, &name2);
10221220 if (err < 0) {
1221 free(name1s);
10231222 uc_error("error: failed to get target device name for '%s'", name1);
10241223 return err;
10251224 }
10271226 /* skip duplicates */
10281227 list_for_each(pos, list) {
10291228 dev = list_entry(pos, struct ucm_dev_name, list);
1030 if (strcmp(dev->name1, name1) == 0) {
1229 if (strcmp(dev->name1, name1s) == 0) {
10311230 free(name2);
1231 free(name1s);
10321232 return 0;
10331233 }
10341234 }
10351235
1236 free(name1s);
1237
10361238 dev = calloc(1, sizeof(*dev));
1037 if (dev == NULL)
1239 if (dev == NULL) {
1240 free(name2);
10381241 return -ENOMEM;
1242 }
10391243 dev->name1 = strdup(name1);
10401244 if (dev->name1 == NULL) {
10411245 free(dev);
11751379 }
11761380
11771381 /* remove devices */
1178 list_for_each(pos, &verb->rename_list) {
1382 list_for_each(pos, &verb->remove_list) {
11791383 dev = list_entry(pos, struct ucm_dev_name, list);
11801384 err = uc_mgr_remove_device(verb, dev->name2);
11811385 if (err < 0) {
12371441 snd_config_t *n;
12381442 int err;
12391443
1240 /* in-place condition evaluation */
1241 err = evaluate_condition(uc_mgr, cfg);
1444 /* in-place evaluation */
1445 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
12421446 if (err < 0)
12431447 return err;
12441448
13111515 snd_config_t *n;
13121516 struct use_case_verb *verb;
13131517 snd_config_t *cfg;
1314 char filename[PATH_MAX];
13151518 int err;
13161519
13171520 /* allocate verb */
13411544 }
13421545
13431546 /* open Verb file for reading */
1344 configuration_filename(uc_mgr, filename, sizeof(filename),
1345 uc_mgr->conf_dir_name, file, "");
1346 err = uc_mgr_config_load(uc_mgr->conf_format, filename, &cfg);
1347 if (err < 0) {
1348 uc_error("error: failed to open verb file %s : %d",
1349 filename, -errno);
1350 return err;
1351 }
1352
1353 /* in-place condition evaluation */
1354 err = evaluate_condition(uc_mgr, cfg);
1547 err = uc_mgr_config_load_file(uc_mgr, file, &cfg);
1548 if (err < 0)
1549 return err;
1550
1551 /* in-place evaluation */
1552 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
13551553 if (err < 0)
13561554 return err;
13571555
13991597
14001598 /* device renames */
14011599 if (strcmp(id, "RenameDevice") == 0) {
1402 err = parse_dev_name_list(n, &verb->rename_list);
1600 err = parse_dev_name_list(uc_mgr, n, &verb->rename_list);
14031601 if (err < 0) {
14041602 uc_error("error: %s failed to parse device rename",
14051603 file);
14091607
14101608 /* device remove */
14111609 if (strcmp(id, "RemoveDevice") == 0) {
1412 err = parse_dev_name_list(n, &verb->remove_list);
1610 err = parse_dev_name_list(uc_mgr, n, &verb->remove_list);
14131611 if (err < 0) {
14141612 uc_error("error: %s failed to parse device remove",
14151613 file);
14491647 {
14501648 snd_config_iterator_t i, next;
14511649 snd_config_t *n;
1452 const char *use_case_name, *file = NULL, *comment = NULL;
1453 int err;
1454
1455 if (snd_config_get_id(cfg, &use_case_name) < 0) {
1456 uc_error("unable to get name for use case section");
1457 return -EINVAL;
1458 }
1650 char *use_case_name, *file = NULL, *comment = NULL;
1651 int err;
14591652
14601653 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
14611654 uc_error("compound type expected for use case section");
14621655 return -EINVAL;
14631656 }
14641657
1465 /* in-place condition evaluation */
1466 err = evaluate_condition(uc_mgr, cfg);
1658 err = parse_get_safe_name(uc_mgr, cfg, NULL, &use_case_name);
1659 if (err < 0) {
1660 uc_error("unable to get name for use case section");
1661 return err;
1662 }
1663
1664 /* in-place evaluation */
1665 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
14671666 if (err < 0)
1468 return err;
1667 goto __error;
14691668
14701669 /* parse master config sections */
14711670 snd_config_for_each(i, next, cfg) {
14761675
14771676 /* get use case verb file name */
14781677 if (strcmp(id, "File") == 0) {
1479 err = snd_config_get_string(n, &file);
1678 err = parse_string_substitute3(uc_mgr, n, &file);
14801679 if (err < 0) {
14811680 uc_error("failed to get File");
1482 return err;
1681 goto __error;
14831682 }
14841683 continue;
14851684 }
14861685
14871686 /* get optional use case comment */
14881687 if (strncmp(id, "Comment", 7) == 0) {
1489 err = snd_config_get_string(n, &comment);
1688 err = parse_string_substitute3(uc_mgr, n, &comment);
14901689 if (err < 0) {
14911690 uc_error("error: failed to get Comment");
1492 return err;
1691 goto __error;
14931692 }
14941693 continue;
14951694 }
15021701 /* do we have both use case name and file ? */
15031702 if (!file) {
15041703 uc_error("error: use case missing file");
1505 return -EINVAL;
1704 err = -EINVAL;
1705 goto __error;
15061706 }
15071707
15081708 /* parse verb file */
1509 return parse_verb_file(uc_mgr, use_case_name, comment, file);
1709 err = parse_verb_file(uc_mgr, use_case_name, comment, file);
1710
1711 __error:
1712 free(use_case_name);
1713 free(file);
1714 free(comment);
1715 return err;
1716 }
1717
1718 /*
1719 * parse controls which should be run only at initial boot
1720 */
1721 static int parse_controls_boot(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
1722 {
1723 int err;
1724
1725 if (!list_empty(&uc_mgr->once_list)) {
1726 uc_error("Once list is not empty");
1727 return -EINVAL;
1728 }
1729 err = parse_sequence(uc_mgr, &uc_mgr->once_list, cfg);
1730 if (err < 0) {
1731 uc_error("Unable to parse BootSequence");
1732 return err;
1733 }
1734
1735 return 0;
15101736 }
15111737
15121738 /*
15151741 static int parse_controls(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
15161742 {
15171743 int err;
1518
1744
15191745 if (!list_empty(&uc_mgr->default_list)) {
15201746 uc_error("Default list is not empty");
15211747 return -EINVAL;
15251751 uc_error("Unable to parse SectionDefaults");
15261752 return err;
15271753 }
1528
1754
15291755 return 0;
15301756 }
15311757
15571783 * CaptureCTL "hw:CARD=0"
15581784 * }
15591785 *
1786 * # The initial boot (run once) configuration.
1787 *
1788 * BootSequence [
1789 * cset "name='Master Playback Switch',index=2 1,1"
1790 * cset "name='Master Playback Volume',index=2 25,25"
1791 * ]
1792 *
15601793 * # This file also stores the default sound card state.
15611794 *
15621795 * SectionDefaults [
1563 * cset "name='Master Playback Switch',index=2 1,1"
1564 * cset "name='Master Playback Volume',index=2 25,25"
15651796 * cset "name='Master Mono Playback',index=1 0"
15661797 * cset "name='Master Mono Playback Volume',index=1 0"
15671798 * cset "name='PCM Switch',index=2 1,1"
16021833 }
16031834 /* delete this field to avoid strcmp() call in the loop */
16041835 snd_config_delete(n);
1605 }
1606
1607 /* in-place condition evaluation */
1608 err = evaluate_condition(uc_mgr, cfg);
1836 uc_mgr->conf_format = l;
1837 }
1838
1839 /* in-place evaluation */
1840 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
16091841 if (err < 0)
16101842 return err;
16111843
16351867 continue;
16361868 }
16371869
1870 /* find default control values section (first boot only) */
1871 if (strcmp(id, "BootSequence") == 0) {
1872 err = parse_controls_boot(uc_mgr, n);
1873 if (err < 0)
1874 return err;
1875 continue;
1876 }
1877
16381878 /* find default control values section and parse it */
16391879 if (strcmp(id, "SectionDefaults") == 0) {
16401880 err = parse_controls(uc_mgr, n);
16611901 /* get the card info */
16621902 static int get_card_info(snd_use_case_mgr_t *mgr,
16631903 const char *ctl_name,
1664 snd_ctl_t **_handle,
1665 snd_ctl_card_info_t *info)
1666 {
1667 snd_ctl_t *handle;
1668 int err;
1669
1670 *_handle = NULL;
1671
1672 err = uc_mgr_open_ctl(mgr, &handle, ctl_name);
1904 snd_ctl_card_info_t **info)
1905 {
1906 struct ctl_list *ctl_list;
1907 int err;
1908
1909 err = uc_mgr_open_ctl(mgr, &ctl_list, ctl_name, 0);
16731910 if (err < 0)
16741911 return err;
16751912
1676 err = snd_ctl_card_info(handle, info);
1677 if (err < 0) {
1678 uc_error("control hardware info (%s): %s", ctl_name, snd_strerror(err));
1679 } else {
1680 *_handle = handle;
1681 }
1682
1913 if (info)
1914 *info = ctl_list->ctl_info;
16831915 return err;
16841916 }
16851917
1686 /* find the card in the local machine and store the card long name */
1687 static int get_card_long_name(snd_use_case_mgr_t *mgr, char *longname)
1688 {
1689 const char *card_name = mgr->card_name;
1918 /* find the card in the local machine */
1919 static int get_by_card_name(snd_use_case_mgr_t *mgr, const char *card_name)
1920 {
16901921 int card, err;
1691 snd_ctl_t *ctl;
16921922 snd_ctl_card_info_t *info;
16931923 const char *_driver, *_name, *_long_name;
16941924
17031933 while (card >= 0) {
17041934 char name[32];
17051935
1706 /* most probably, we do not need to cache all CTL devices here */
1936 /* clear the list, keep the only one CTL device */
17071937 uc_mgr_free_ctl_list(mgr);
17081938
17091939 sprintf(name, "hw:%d", card);
1710 err = get_card_info(mgr, name, &ctl, info);
1940 err = get_card_info(mgr, name, &info);
17111941
17121942 if (err == 0) {
17131943 _driver = snd_ctl_card_info_get_driver(info);
17151945 _long_name = snd_ctl_card_info_get_longname(info);
17161946 if (!strcmp(card_name, _driver) ||
17171947 !strcmp(card_name, _name) ||
1718 !strcmp(card_name, _long_name)) {
1719 snd_strlcpy(longname, _long_name, MAX_CARD_LONG_NAME);
1948 !strcmp(card_name, _long_name))
17201949 return 0;
1721 }
17221950 }
17231951
17241952 if (snd_card_next(&card) < 0) {
17331961 }
17341962
17351963 /* set the driver name and long name by the card ctl name */
1736 static int get_by_card(snd_use_case_mgr_t *mgr, const char *ctl_name, char *longname)
1737 {
1738 snd_ctl_t *ctl;
1739 snd_ctl_card_info_t *info;
1740 const char *_driver, *_long_name;
1741 int err;
1742
1743 snd_ctl_card_info_alloca(&info);
1744
1745 err = get_card_info(mgr, ctl_name, &ctl, info);
1746 if (err)
1747 return err;
1748
1749 _driver = snd_ctl_card_info_get_driver(info);
1750 if (replace_string(&mgr->conf_dir_name, _driver) == NULL)
1751 return -ENOMEM;
1752 _long_name = snd_ctl_card_info_get_longname(info);
1753 snd_strlcpy(longname, _long_name, MAX_CARD_LONG_NAME);
1754
1755 return 0;
1756 }
1757
1758 static int load_master_config(snd_use_case_mgr_t *uc_mgr,
1759 const char *card_name, snd_config_t **cfg, int longname)
1964 static inline int get_by_card(snd_use_case_mgr_t *mgr, const char *ctl_name)
1965 {
1966 return get_card_info(mgr, ctl_name, NULL);
1967 }
1968
1969 static int parse_toplevel_path(snd_use_case_mgr_t *uc_mgr,
1970 char *filename,
1971 snd_config_t *cfg)
1972 {
1973 snd_config_iterator_t i, next, i2, next2;
1974 snd_config_t *n, *n2;
1975 const char *id;
1976 char *dir = NULL, *file = NULL, fn[PATH_MAX];
1977 long version;
1978 int err;
1979
1980 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
1981 uc_error("compound type expected for UseCasePath node");
1982 return -EINVAL;
1983 }
1984
1985 /* parse use case path config sections */
1986 snd_config_for_each(i, next, cfg) {
1987 n = snd_config_iterator_entry(i);
1988
1989 if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
1990 uc_error("compound type expected for UseCasePath.something node");
1991 return -EINVAL;
1992 }
1993
1994 if (snd_config_get_id(n, &id) < 0)
1995 continue;
1996
1997 version = 2;
1998
1999 /* parse use case path config sections */
2000 snd_config_for_each(i2, next2, n) {
2001
2002 n2 = snd_config_iterator_entry(i2);
2003 if (snd_config_get_id(n2, &id) < 0)
2004 continue;
2005
2006 if (strcmp(id, "Version") == 0) {
2007 err = parse_integer_substitute(uc_mgr, n2, &version);
2008 if (err < 0) {
2009 uc_error("unable to parse UcmDirectory");
2010 goto __error;
2011 }
2012 if (version < 1 || version > 2) {
2013 uc_error("Version must be 1 or 2");
2014 err = -EINVAL;
2015 goto __error;
2016 }
2017 continue;
2018 }
2019
2020 if (strcmp(id, "Directory") == 0) {
2021 err = parse_string_substitute(uc_mgr, n2, &dir);
2022 if (err < 0) {
2023 uc_error("unable to parse Directory");
2024 goto __error;
2025 }
2026 continue;
2027 }
2028
2029 if (strcmp(id, "File") == 0) {
2030 err = parse_string_substitute(uc_mgr, n2, &file);
2031 if (err < 0) {
2032 uc_error("unable to parse File");
2033 goto __error;
2034 }
2035 continue;
2036 }
2037
2038 uc_error("unknown UseCasePath field %s", id);
2039 }
2040
2041 if (dir == NULL) {
2042 uc_error("Directory is not defined in %s!", filename);
2043 goto __next;
2044 }
2045 if (file == NULL) {
2046 uc_error("File is not defined in %s!", filename);
2047 goto __next;
2048 }
2049
2050 ucm_filename(fn, sizeof(fn), version, dir, file);
2051 if (access(fn, R_OK) == 0) {
2052 if (replace_string(&uc_mgr->conf_dir_name, dir) == NULL) {
2053 err = -ENOMEM;
2054 goto __error;
2055 }
2056 if (replace_string(&uc_mgr->conf_file_name, file) == NULL) {
2057 err = -ENOMEM;
2058 goto __error;
2059 }
2060 strncpy(filename, fn, PATH_MAX);
2061 uc_mgr->conf_format = version;
2062 goto __ok;
2063 }
2064
2065 __next:
2066 free(file);
2067 free(dir);
2068 dir = NULL;
2069 file = NULL;
2070 }
2071
2072 err = -ENOENT;
2073 goto __error;
2074
2075 __ok:
2076 err = 0;
2077 __error:
2078 free(file);
2079 free(dir);
2080 return err;
2081 }
2082
2083 static int parse_toplevel_config(snd_use_case_mgr_t *uc_mgr,
2084 char *filename,
2085 snd_config_t *cfg)
2086 {
2087 snd_config_iterator_t i, next;
2088 snd_config_t *n;
2089 const char *id;
2090 long l;
2091 int err;
2092
2093 if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
2094 uc_error("compound type expected for toplevel file");
2095 return -EINVAL;
2096 }
2097
2098 err = snd_config_search(cfg, "Syntax", &n);
2099 if (err < 0) {
2100 uc_error("Syntax field not found in %s", filename);
2101 return -EINVAL;
2102 }
2103 err = snd_config_get_integer(n, &l);
2104 if (err < 0) {
2105 uc_error("Syntax field is invalid in %s", filename);
2106 return err;
2107 }
2108 if (l < 2 || l > SYNTAX_VERSION_MAX) {
2109 uc_error("Incompatible syntax %d in %s", l, filename);
2110 return -EINVAL;
2111 }
2112 /* delete this field to avoid strcmp() call in the loop */
2113 snd_config_delete(n);
2114 uc_mgr->conf_format = l;
2115
2116 /* in-place evaluation */
2117 err = uc_mgr_evaluate_inplace(uc_mgr, cfg);
2118 if (err < 0)
2119 return err;
2120
2121 /* parse toplevel config sections */
2122 snd_config_for_each(i, next, cfg) {
2123
2124 n = snd_config_iterator_entry(i);
2125 if (snd_config_get_id(n, &id) < 0)
2126 continue;
2127
2128 if (strcmp(id, "UseCasePath") == 0) {
2129 err = parse_toplevel_path(uc_mgr, filename, n);
2130 if (err == 0)
2131 return err;
2132 continue;
2133 }
2134
2135 uc_error("uknown toplevel field %s", id);
2136 }
2137
2138 return -ENOENT;
2139 }
2140
2141 static int load_toplevel_config(snd_use_case_mgr_t *uc_mgr,
2142 snd_config_t **cfg)
17602143 {
17612144 char filename[PATH_MAX];
1762 int err;
1763
1764 if (strnlen(card_name, MAX_CARD_LONG_NAME) == MAX_CARD_LONG_NAME) {
1765 uc_error("error: invalid card name %s (at most %d chars)",
1766 card_name, MAX_CARD_LONG_NAME - 1);
1767 return -EINVAL;
1768 }
1769
1770 uc_mgr->conf_format = 0;
1771 if (longname) {
1772 if (getenv(ALSA_CONFIG_UCM2_VAR) || !getenv(ALSA_CONFIG_UCM_VAR)) {
1773 uc_mgr->conf_format = 2;
1774 configuration_filename(uc_mgr, filename, sizeof(filename),
1775 uc_mgr->conf_dir_name, card_name, ".conf");
1776 if (access(filename, R_OK) == 0)
1777 goto __load;
1778 }
1779 /* try the old ucm directory */
1780 uc_mgr->conf_format = 1;
1781 configuration_filename(uc_mgr, filename, sizeof(filename),
1782 card_name, card_name, ".conf");
1783 if (access(filename, R_OK) != 0)
1784 return -ENOENT;
1785 } else {
1786 configuration_filename(uc_mgr, filename, sizeof(filename),
1787 card_name, card_name, ".conf");
1788 }
1789
1790 __load:
2145 snd_config_t *tcfg;
2146 int err;
2147
2148 ucm_filename(filename, sizeof(filename), 2, NULL, "ucm.conf");
2149
2150 if (access(filename, R_OK) != 0) {
2151 uc_error("Unable to find the top-level configuration file '%s'.", filename);
2152 return -ENOENT;
2153 }
2154
2155 err = uc_mgr_config_load(2, filename, &tcfg);
2156 if (err < 0)
2157 goto __error;
2158
2159 /* filename is shared for function input and output! */
2160 err = parse_toplevel_config(uc_mgr, filename, tcfg);
2161 snd_config_delete(tcfg);
2162 if (err < 0)
2163 goto __error;
2164
17912165 err = uc_mgr_config_load(uc_mgr->conf_format, filename, cfg);
17922166 if (err < 0) {
17932167 uc_error("error: could not parse configuration for card %s",
1794 card_name);
1795 return err;
1796 }
1797
1798 if (replace_string(&uc_mgr->conf_file_name, card_name) == NULL)
1799 return -ENOMEM;
2168 uc_mgr->card_name);
2169 goto __error;
2170 }
18002171
18012172 return 0;
1802 }
1803
1804 /* load master use case file for sound card
1805 *
1806 * The same ASoC machine driver can be shared by many different devices.
1807 * For user space to differentiate them and get the best device-specific
1808 * configuration, ASoC machine drivers may use the DMI info
1809 * (vendor-product-version-board) as the card long name. And user space can
1810 * define configuration files like longnamei/longname.conf for a specific device.
1811 *
1812 * This function will try to find the card in the local machine and get its
1813 * long name, then load the file longname/longname.conf to get the best
1814 * device-specific configuration. If the card is not found in the local
1815 * machine or the device-specific file is not available, fall back to load
1816 * the default configuration file name/name.conf.
2173
2174 __error:
2175 return err;
2176 }
2177
2178 /* load master use case file for sound card based on rules in ucm2/ucm.conf
18172179 */
18182180 int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr)
18192181 {
18202182 snd_config_t *cfg;
1821 const char *name = uc_mgr->card_name;
1822 char longname[MAX_CARD_LONG_NAME];
1823 int err;
1824
1825 if (replace_string(&uc_mgr->conf_dir_name, uc_mgr->card_name) == NULL)
1826 return -ENOMEM;
1827
2183 const char *name;
2184 int err;
2185
2186 name = uc_mgr->card_name;
18282187 if (strncmp(name, "hw:", 3) == 0) {
1829 err = get_by_card(uc_mgr, name, longname);
1830 if (err == 0)
1831 goto __longname;
1832 uc_error("card '%s' is not valid", name);
1833 goto __error;
2188 err = get_by_card(uc_mgr, name);
2189 if (err < 0) {
2190 uc_error("card '%s' is not valid", name);
2191 goto __error;
2192 }
18342193 } else if (strncmp(name, "strict:", 7)) {
1835 err = get_card_long_name(uc_mgr, longname);
1836 if (err == 0) { /* load file that matches the card long name */
1837 __longname:
1838 err = load_master_config(uc_mgr, longname, &cfg, 1);
1839 }
1840
1841 if (err == 0) {
1842 /* got device-specific file that matches the card long name */
1843 if (uc_mgr->conf_format < 2)
1844 snd_strlcpy(uc_mgr->conf_dir_name, longname,
1845 sizeof(uc_mgr->conf_dir_name));
1846 goto __parse;
1847 }
1848 }
1849
1850 /* standard path */
1851 err = load_master_config(uc_mgr, uc_mgr->conf_dir_name, &cfg, 0);
2194 /* do not handle the error here */
2195 /* we can refer the virtual UCM config */
2196 get_by_card_name(uc_mgr, name);
2197 }
2198
2199 err = load_toplevel_config(uc_mgr, &cfg);
18522200 if (err < 0)
18532201 goto __error;
18542202
1855 __parse:
18562203 err = parse_master_file(uc_mgr, cfg);
18572204 snd_config_delete(cfg);
18582205 if (err < 0) {
18642211
18652212 __error:
18662213 uc_mgr_free_ctl_list(uc_mgr);
1867 uc_mgr->conf_dir_name[0] = '\0';
2214 replace_string(&uc_mgr->conf_dir_name, NULL);
18682215 return err;
18692216 }
18702217
19092256 */
19102257 int uc_mgr_scan_master_configs(const char **_list[])
19112258 {
1912 char filename[PATH_MAX], dfl[PATH_MAX];
2259 char filename[PATH_MAX], dfl[PATH_MAX], fn[FILENAME_MAX];
19132260 char *env = getenv(ALSA_CONFIG_UCM2_VAR);
19142261 const char **list, *d_name;
19152262 snd_config_t *cfg, *c;
19662313 if (is_component_directory(d_name))
19672314 continue;
19682315
1969 configuration_filename2(filename, sizeof(filename), 2,
1970 d_name, d_name, ".conf");
2316 snprintf(fn, sizeof(fn), "%s.conf", d_name);
2317 ucm_filename(filename, sizeof(filename), 2, d_name, fn);
2318 if (eaccess(filename, R_OK))
2319 continue;
2320
19712321 err = uc_mgr_config_load(2, filename, &cfg);
19722322 if (err < 0)
19732323 goto __err;
4343 char *s1, *s2;
4444 int err;
4545
46 if (uc_mgr->conf_format >= 3) {
47 err = get_string(eval, "Empty", &string1);
48 if (err < 0 && err != -ENOENT) {
49 uc_error("String error (If.Condition.Empty)");
50 return -EINVAL;
51 }
52
53 if (string1) {
54 err = uc_mgr_get_substituted_value(uc_mgr, &s1, string1);
55 if (err < 0)
56 return err;
57 err = s1 == NULL || s1[0] == '\0';
58 free(s1);
59 return err;
60 }
61 }
62
4663 err = get_string(eval, "String1", &string1);
4764 if (err < 0 && err != -ENOENT) {
4865 uc_error("String error (If.Condition.String1)");
162179 static int if_eval_control_exists(snd_use_case_mgr_t *uc_mgr, snd_config_t *eval)
163180 {
164181 snd_ctl_t *ctl;
182 struct ctl_list *ctl_list;
165183 const char *device = NULL, *ctldef, *enumval = NULL, *name;
166184 snd_ctl_elem_id_t *elem_id;
167185 snd_ctl_elem_info_t *elem_info;
210228 err = uc_mgr_get_substituted_value(uc_mgr, &s, device);
211229 if (err < 0)
212230 return err;
213 err = uc_mgr_open_ctl(uc_mgr, &ctl, s);
231 err = uc_mgr_open_ctl(uc_mgr, &ctl_list, s, 1);
214232 free(s);
215233 if (err < 0)
216234 return err;
235 ctl = ctl_list->ctl;
217236 }
218237
219238 snd_ctl_elem_info_set_id(elem_info, elem_id);
265284 return -EINVAL;
266285 }
267286
287 if (strcmp(type, "AlwaysTrue") == 0)
288 return 1;
289
290 if (strcmp(type, "String") == 0)
291 return if_eval_string(uc_mgr, eval);
292
268293 if (strcmp(type, "ControlExists") == 0)
269294 return if_eval_control_exists(uc_mgr, eval);
270
271 if (strcmp(type, "String") == 0)
272 return if_eval_string(uc_mgr, eval);
273295
274296 if (strcmp(type, "RegexMatch") == 0)
275297 return if_eval_regex_match(uc_mgr, eval);
346368 }
347369 #endif
348370
349 static int compound_merge(const char *id,
350 snd_config_t *dst, snd_config_t *src,
351 snd_config_t *before, snd_config_t *after)
352 {
353 snd_config_iterator_t i, next;
354 snd_config_t *n, *_before = NULL, *_after = NULL;
355 const char *s;
356 int err;
357
358 if (snd_config_get_type(src) != SND_CONFIG_TYPE_COMPOUND) {
359 uc_error("compound type expected for If True/False block");
360 return -EINVAL;
361 }
362
363 if (before) {
364 err = get_string(before, id, &s);
365 if (err < 0 && err != -ENOENT)
366 return err;
367 if (err == 0) {
368 err = snd_config_search(dst, s, &_before);
369 if (err < 0 && err != -ENOENT)
370 return err;
371 }
372 }
373 if (after) {
374 err = get_string(after, id, &s);
375 if (err < 0 && err != -ENOENT)
376 return err;
377 if (err == 0) {
378 err = snd_config_search(dst, s, &_after);
379 if (err < 0 && err != -ENOENT)
380 return err;
381 }
382 }
383
384 if (_before && _after) {
385 uc_error("defined both before and after identifiers in the If block");
386 return -EINVAL;
387 }
388
389 snd_config_for_each(i, next, src) {
390 n = snd_config_iterator_entry(i);
391 err = snd_config_remove(n);
392 if (err < 0)
393 return err;
394 if (_before) {
395 err = snd_config_add_before(_before, n);
396 if (err < 0)
397 return err;
398 _before = NULL;
399 _after = n;
400 } else if (_after) {
401 err = snd_config_add_after(_after, n);
402 if (err < 0)
403 return err;
404 _after = n;
405 } else {
406 err = snd_config_add(dst, n);
407 if (err < 0)
408 return err;
409 }
410 }
411
412 return 0;
413 }
414
415371 /*
416372 * put back the result from all conditions to the parent
417373 */
419375 snd_config_t *parent,
420376 snd_config_t *cond)
421377 {
422 snd_config_iterator_t i, i2, next, next2;
423 snd_config_t *a, *n, *n2, *parent2, *before, *after;
424 const char *id;
378 snd_config_iterator_t i, next;
379 snd_config_t *a, *n, *before, *after;
425380 int err;
426381
427382 if (uc_mgr->conf_format < 2) {
442397 return err;
443398 if (a == NULL)
444399 continue;
445 err = snd_config_search(a, "If", &n2);
446 if (err < 0 && err != -ENOENT) {
447 uc_error("If block error (If)");
448 return -EINVAL;
449 } else if (err == 0) {
450 err = uc_mgr_evaluate_condition(uc_mgr, a, n2);
451 if (err < 0)
452 return err;
453 snd_config_delete(n2);
454 }
455 snd_config_for_each(i2, next2, a) {
456 n2 = snd_config_iterator_entry(i2);
457 err = snd_config_remove(n2);
458 if (err < 0)
459 return err;
460 err = snd_config_get_id(n2, &id);
461 if (err < 0) {
462 __add:
463 err = snd_config_add(parent, n2);
464 if (err < 0)
465 return err;
466 continue;
467 } else {
468 err = snd_config_search(parent, id, &parent2);
469 if (err == -ENOENT)
470 goto __add;
471 err = compound_merge(id, parent2, n2, before, after);
472 if (err < 0)
473 return err;
474 }
475 snd_config_delete(n2);
476 }
400 err = uc_mgr_evaluate_inplace(uc_mgr, a);
401 if (err < 0)
402 return err;
403 err = uc_mgr_config_tree_merge(parent, a, before, after);
404 if (err < 0)
405 return err;
406 snd_config_delete(a);
477407 }
478408 return 0;
479409 }
0 /*
1 * This library is free software; you can redistribute it and/or
2 * modify it under the terms of the GNU Lesser General Public
3 * License as published by the Free Software Foundation; either
4 * version 2 of the License, or (at your option) any later version.
5 *
6 * This library is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 * Lesser General Public License for more details.
10 *
11 * You should have received a copy of the GNU Lesser General Public
12 * License along with this library; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
14 *
15 * Support for the verb/device/modifier core logic and API,
16 * command line tool and file parser was kindly sponsored by
17 * Texas Instruments Inc.
18 * Support for multiple active modifiers and devices,
19 * transition sequences, multiple client access and user defined use
20 * cases was kindly sponsored by Wolfson Microelectronics PLC.
21 *
22 * Copyright (C) 2020 Red Hat Inc.
23 * Authors: Jaroslav Kysela <perex@perex.cz>
24 */
25
26 #include "ucm_local.h"
27
28 static int get_string(snd_config_t *compound, const char *key, const char **str)
29 {
30 snd_config_t *node;
31 int err;
32
33 err = snd_config_search(compound, key, &node);
34 if (err < 0)
35 return err;
36 return snd_config_get_string(node, str);
37 }
38
39 static int include_eval_one(snd_use_case_mgr_t *uc_mgr,
40 snd_config_t *inc,
41 snd_config_t **result,
42 snd_config_t **before,
43 snd_config_t **after)
44 {
45 const char *file;
46 char *s;
47 int err;
48
49 *result = NULL;
50
51 if (snd_config_get_type(inc) != SND_CONFIG_TYPE_COMPOUND) {
52 uc_error("compound type expected for Include.1");
53 return -EINVAL;
54 }
55
56 err = get_string(inc, "File", &file);
57 if (err < 0) {
58 uc_error("file expected (Include)");
59 return -EINVAL;
60 }
61
62 err = snd_config_search(inc, "Before", before);
63 if (err < 0 && err != -ENOENT) {
64 uc_error("before block identifier error");
65 return -EINVAL;
66 }
67
68 err = snd_config_search(inc, "After", after);
69 if (err < 0 && err != -ENOENT) {
70 uc_error("before block identifier error");
71 return -EINVAL;
72 }
73
74 err = uc_mgr_get_substituted_value(uc_mgr, &s, file);
75 if (err < 0)
76 return err;
77 err = uc_mgr_config_load_file(uc_mgr, s, result);
78 free(s);
79 return err;
80 }
81
82 #if 0
83 static void config_dump(snd_config_t *cfg)
84 {
85 snd_output_t *out;
86 snd_output_stdio_attach(&out, stderr, 0);
87 snd_output_printf(out, "-----\n");
88 snd_config_save(cfg, out);
89 snd_output_close(out);
90 }
91 #endif
92
93 static int find_position_node(snd_config_t **res, snd_config_t *dst,
94 const char *id, snd_config_t *pos)
95 {
96 const char *s;
97 int err;
98
99 err = get_string(pos, id, &s);
100 if (err < 0 && err != -ENOENT)
101 return err;
102 if (err == 0) {
103 err = snd_config_search(dst, s, res);
104 if (err < 0 && err != -ENOENT)
105 return err;
106 }
107 return 0;
108 }
109
110 static int compound_merge(const char *id,
111 snd_config_t *dst, snd_config_t *src,
112 snd_config_t *before, snd_config_t *after)
113 {
114 snd_config_iterator_t i, next;
115 snd_config_t *n, *_before = NULL, *_after = NULL;
116 char tmpid[32];
117 int err, array, idx;
118
119 if (snd_config_get_type(src) != SND_CONFIG_TYPE_COMPOUND) {
120 uc_error("compound type expected for the merged block");
121 return -EINVAL;
122 }
123
124 if (before) {
125 err = find_position_node(&_before, dst, id, before);
126 if (err < 0)
127 return err;
128 }
129 if (after) {
130 err = find_position_node(&_after, dst, id, after);
131 if (err < 0)
132 return err;
133 }
134
135 if (_before && _after) {
136 uc_error("defined both before and after identifiers in the If or Include block");
137 return -EINVAL;
138 }
139
140 array = snd_config_is_array(dst);
141 if (array < 0) {
142 uc_error("destination configuration node is not a compound");
143 return array;
144 }
145 if (array && snd_config_is_array(src) <= 0) {
146 uc_error("source configuration node is not an array");
147 return -EINVAL;
148 }
149
150 idx = 0;
151
152 /* for array, use a temporary non-clashing identifier */
153 if (array > 0) {
154 snd_config_for_each(i, next, dst) {
155 n = snd_config_iterator_entry(i);
156 snprintf(tmpid, sizeof(tmpid), "_tmp_%d", idx++);
157 err = snd_config_set_id(n, tmpid);
158 if (err < 0)
159 return err;
160 }
161 }
162
163 snd_config_for_each(i, next, src) {
164 n = snd_config_iterator_entry(i);
165 err = snd_config_remove(n);
166 if (err < 0)
167 return err;
168 /* for array, use a temporary non-clashing identifier */
169 if (array > 0) {
170 snprintf(tmpid, sizeof(tmpid), "_tmp_%d", idx++);
171 err = snd_config_set_id(n, tmpid);
172 if (err < 0)
173 return err;
174 }
175 if (_before) {
176 err = snd_config_add_before(_before, n);
177 if (err < 0)
178 return err;
179 _before = NULL;
180 _after = n;
181 } else if (_after) {
182 err = snd_config_add_after(_after, n);
183 if (err < 0)
184 return err;
185 _after = n;
186 } else {
187 err = snd_config_add(dst, n);
188 if (err < 0)
189 return err;
190 }
191 }
192
193 /* set new indexes for the final array */
194 if (array > 0) {
195 idx = 0;
196 snd_config_for_each(i, next, dst) {
197 n = snd_config_iterator_entry(i);
198 snprintf(tmpid, sizeof(tmpid), "%d", idx++);
199 err = snd_config_set_id(n, tmpid);
200 if (err < 0)
201 return err;
202 }
203 }
204
205 return 0;
206 }
207
208 int uc_mgr_config_tree_merge(snd_config_t *parent, snd_config_t *new_ctx,
209 snd_config_t *before, snd_config_t *after)
210 {
211 snd_config_iterator_t i, next;
212 snd_config_t *n, *parent2;
213 const char *id;
214 int err;
215
216 snd_config_for_each(i, next, new_ctx) {
217 n = snd_config_iterator_entry(i);
218 err = snd_config_remove(n);
219 if (err < 0)
220 return err;
221 err = snd_config_get_id(n, &id);
222 if (err < 0) {
223 __add:
224 err = snd_config_add(parent, n);
225 if (err < 0)
226 return err;
227 continue;
228 } else {
229 err = snd_config_search(parent, id, &parent2);
230 if (err == -ENOENT)
231 goto __add;
232 err = compound_merge(id, parent2, n, before, after);
233 if (err < 0)
234 return err;
235 }
236 snd_config_delete(n);
237 }
238 return 0;
239 }
240
241 /*
242 * put back the included configuration to the parent
243 */
244 int uc_mgr_evaluate_include(snd_use_case_mgr_t *uc_mgr,
245 snd_config_t *parent,
246 snd_config_t *inc)
247 {
248 snd_config_iterator_t i, next;
249 snd_config_t *a, *n, *before, *after;
250 int err;
251
252 if (uc_mgr->conf_format < 3) {
253 uc_error("in-place include is supported in v3+ syntax");
254 return -EINVAL;
255 }
256
257 if (snd_config_get_type(inc) != SND_CONFIG_TYPE_COMPOUND) {
258 uc_error("compound type expected for Include");
259 return -EINVAL;
260 }
261
262 snd_config_for_each(i, next, inc) {
263 n = snd_config_iterator_entry(i);
264 before = after = NULL;
265 err = include_eval_one(uc_mgr, n, &a, &before, &after);
266 if (err < 0)
267 return err;
268 if (a == NULL)
269 continue;
270 err = uc_mgr_evaluate_inplace(uc_mgr, a);
271 if (err < 0)
272 return err;
273 err = uc_mgr_config_tree_merge(parent, a, before, after);
274 if (err < 0)
275 return err;
276 snd_config_delete(a);
277
278 }
279 return 0;
280 }
3939 #include <pthread.h>
4040 #include "use-case.h"
4141
42 #define SYNTAX_VERSION_MAX 2
42 #define SYNTAX_VERSION_MAX 3
4343
4444 #define MAX_CARD_SHORT_NAME 32
4545 #define MAX_CARD_LONG_NAME 80
114114 struct list_head dev_list;
115115 snd_ctl_t *ctl;
116116 snd_ctl_card_info_t *ctl_info;
117 int slave;
117118 };
118119
119120 struct ucm_dev_name {
220221 /* use case verb, devices and modifier configs parsed from files */
221222 struct list_head verb_list;
222223
224 /* boot settings - sequence */
225 struct list_head once_list;
226
223227 /* default settings - sequence */
224228 struct list_head default_list;
229 int default_list_executed;
225230
226231 /* default settings - value list */
227232 struct list_head value_list;
233238
234239 /* locking */
235240 pthread_mutex_t mutex;
241
242 /* UCM internal variables defined in configuration files */
243 struct list_head variable_list;
236244
237245 /* list of opened control devices */
238246 struct list_head ctl_list;
257265 void uc_mgr_error(const char *fmt, ...);
258266 void uc_mgr_stdout(const char *fmt, ...);
259267
268 const char *uc_mgr_config_dir(int format);
260269 int uc_mgr_config_load(int format, const char *file, snd_config_t **cfg);
270 int uc_mgr_config_load_file(snd_use_case_mgr_t *uc_mgr, const char *file, snd_config_t **cfg);
261271 int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr);
262272 int uc_mgr_scan_master_configs(const char **_list[]);
263273
273283 void uc_mgr_free(snd_use_case_mgr_t *uc_mgr);
274284
275285 int uc_mgr_open_ctl(snd_use_case_mgr_t *uc_mgr,
276 snd_ctl_t **ctl,
277 const char *device);
278
279 struct ctl_list *uc_mgr_get_one_ctl(snd_use_case_mgr_t *uc_mgr);
286 struct ctl_list **ctl_list,
287 const char *device,
288 int slave);
289
290 struct ctl_list *uc_mgr_get_master_ctl(snd_use_case_mgr_t *uc_mgr);
291 struct ctl_list *uc_mgr_get_ctl_by_name(snd_use_case_mgr_t *uc_mgr,
292 const char *name, int idx);
280293 snd_ctl_t *uc_mgr_get_ctl(snd_use_case_mgr_t *uc_mgr);
281294 void uc_mgr_free_ctl_list(snd_use_case_mgr_t *uc_mgr);
282295
283296 int uc_mgr_add_value(struct list_head *base, const char *key, char *val);
297
298 const char *uc_mgr_get_variable(snd_use_case_mgr_t *uc_mgr,
299 const char *name);
300
301 int uc_mgr_set_variable(snd_use_case_mgr_t *uc_mgr,
302 const char *name,
303 const char *val);
284304
285305 int uc_mgr_get_substituted_value(snd_use_case_mgr_t *uc_mgr,
286306 char **_rvalue,
287307 const char *value);
288308
309 int uc_mgr_config_tree_merge(snd_config_t *parent, snd_config_t *new_ctx,
310 snd_config_t *before, snd_config_t *after);
311
312 int uc_mgr_evaluate_inplace(snd_use_case_mgr_t *uc_mgr,
313 snd_config_t *cfg);
314
315 int uc_mgr_evaluate_include(snd_use_case_mgr_t *uc_mgr,
316 snd_config_t *parent,
317 snd_config_t *inc);
318
289319 int uc_mgr_evaluate_condition(snd_use_case_mgr_t *uc_mgr,
290320 snd_config_t *parent,
291321 snd_config_t *cond);
292322
323 int uc_mgr_define_regex(snd_use_case_mgr_t *uc_mgr,
324 const char *name,
325 snd_config_t *eval);
326
293327 /** The name of the environment variable containing the UCM directory */
294328 #define ALSA_CONFIG_UCM_VAR "ALSA_CONFIG_UCM"
295329
0 /*
1 * This library is free software; you can redistribute it and/or
2 * modify it under the terms of the GNU Lesser General Public
3 * License as published by the Free Software Foundation; either
4 * version 2 of the License, or (at your option) any later version.
5 *
6 * This library is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 * Lesser General Public License for more details.
10 *
11 * You should have received a copy of the GNU Lesser General Public
12 * License along with this library; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
14 *
15 * Support for the verb/device/modifier core logic and API,
16 * command line tool and file parser was kindly sponsored by
17 * Texas Instruments Inc.
18 * Support for multiple active modifiers and devices,
19 * transition sequences, multiple client access and user defined use
20 * cases was kindly sponsored by Wolfson Microelectronics PLC.
21 *
22 * Copyright (C) 2019 Red Hat Inc.
23 * Authors: Jaroslav Kysela <perex@perex.cz>
24 */
25
26 #include "ucm_local.h"
27 #include <ctype.h>
28 #include <regex.h>
29
30 static int get_string(snd_config_t *compound, const char *key, const char **str)
31 {
32 snd_config_t *node;
33 int err;
34
35 err = snd_config_search(compound, key, &node);
36 if (err < 0)
37 return err;
38 return snd_config_get_string(node, str);
39 }
40
41 static char *extract_substring(const char *data, regmatch_t *match)
42 {
43 char *s;
44 size_t len;
45
46 len = match->rm_eo - match->rm_so;
47 s = malloc(len + 1);
48 if (s == NULL)
49 return NULL;
50 memcpy(s, data + match->rm_so, len);
51 s[len] = '\0';
52 return s;
53 }
54
55 static int set_variables(snd_use_case_mgr_t *uc_mgr, const char *data,
56 unsigned int match_size, regmatch_t *match,
57 const char *name)
58 {
59 size_t name2_len = strlen(name) + 16;
60 char *name2 = alloca(name2_len);
61 char *s;
62 unsigned int i;
63 int err;
64
65 if (match[0].rm_so < 0 || match[0].rm_eo < 0)
66 return 0;
67 s = extract_substring(data, &match[0]);
68 if (s == NULL)
69 return -ENOMEM;
70 err = uc_mgr_set_variable(uc_mgr, name, s);
71 free(s);
72 if (err < 0)
73 return err;
74 for (i = 1; i < match_size; i++) {
75 if (match[0].rm_so < 0 || match[0].rm_eo < 0)
76 return 0;
77 s = extract_substring(data, &match[i]);
78 if (s == NULL)
79 return -ENOMEM;
80 snprintf(name2, name2_len, "%s%u", name, i);
81 err = uc_mgr_set_variable(uc_mgr, name2, s);
82 free(s);
83 if (err < 0)
84 return err;
85 }
86 return 0;
87 }
88
89 int uc_mgr_define_regex(snd_use_case_mgr_t *uc_mgr, const char *name,
90 snd_config_t *eval)
91 {
92 const char *string, *regex_string, *flags_string;
93 char *s;
94 regex_t re;
95 int options = 0;
96 regmatch_t match[20];
97 int err;
98
99 if (uc_mgr->conf_format < 3) {
100 uc_error("define regex is supported in v3+ syntax");
101 return -EINVAL;
102 }
103
104 if (snd_config_get_type(eval) != SND_CONFIG_TYPE_COMPOUND) {
105 uc_error("compound type expected for DefineRegex");
106 return -EINVAL;
107 }
108
109 err = get_string(eval, "String", &string);
110 if (err < 0) {
111 uc_error("DefineRegex error (String)");
112 return -EINVAL;
113 }
114
115 err = get_string(eval, "Regex", &regex_string);
116 if (err < 0) {
117 uc_error("DefineRegex error (Regex string)");
118 return -EINVAL;
119 }
120
121 err = get_string(eval, "Flags", &flags_string);
122 if (err == -ENOENT) {
123 options = REG_EXTENDED;
124 } else if (err < 0) {
125 uc_error("DefineRegex error (Flags string)");
126 return -EINVAL;
127 } else {
128 while (*flags_string) {
129 switch (tolower(*flags_string)) {
130 case 'e':
131 options |= REG_EXTENDED;
132 break;
133 case 'i':
134 options |= REG_ICASE;
135 break;
136 case 's':
137 options |= REG_NOSUB;
138 break;
139 case 'n':
140 options |= REG_NEWLINE;
141 break;
142 default:
143 uc_error("DefineRegex error (unknown flag '%c')", *flags_string);
144 return -EINVAL;
145 }
146 flags_string++;
147 }
148 }
149
150 err = uc_mgr_get_substituted_value(uc_mgr, &s, regex_string);
151 if (err < 0)
152 return err;
153 err = regcomp(&re, s, options);
154 free(s);
155 if (err) {
156 uc_error("Regex '%s' compilation failed (code %d)", err);
157 return -EINVAL;
158 }
159
160 err = uc_mgr_get_substituted_value(uc_mgr, &s, string);
161 if (err < 0) {
162 regfree(&re);
163 return err;
164 }
165 err = regexec(&re, s, ARRAY_SIZE(match), match, 0);
166 if (err < 0)
167 err = -errno;
168 else
169 err = set_variables(uc_mgr, s, ARRAY_SIZE(match), match, name);
170 free(s);
171 regfree(&re);
172 return err;
173 }
2828 #include <sys/stat.h>
2929 #include <limits.h>
3030
31 static char *rval_open_name(snd_use_case_mgr_t *uc_mgr)
32 {
33 const char *name;
34 if (uc_mgr->conf_format < 3)
35 return NULL;
36 name = uc_mgr->card_name;
37 if (name) {
38 if (strncmp(name, "strict:", 7) == 0)
39 name += 7;
40 return strdup(name);
41 }
42 return NULL;
43 }
44
45 static char *rval_conf_topdir(snd_use_case_mgr_t *uc_mgr)
46 {
47 const char *dir;
48
49 if (uc_mgr->conf_format < 3)
50 return NULL;
51 dir = uc_mgr_config_dir(uc_mgr->conf_format);
52 if (dir && dir[0])
53 return strdup(dir);
54 return NULL;
55 }
56
57 static char *rval_conf_dir(snd_use_case_mgr_t *uc_mgr)
58 {
59 if (uc_mgr->conf_format < 3)
60 return NULL;
61 if (uc_mgr->conf_dir_name && uc_mgr->conf_dir_name[0])
62 return strdup(uc_mgr->conf_dir_name);
63 return NULL;
64 }
65
3166 static char *rval_conf_name(snd_use_case_mgr_t *uc_mgr)
3267 {
3368 if (uc_mgr->conf_file_name && uc_mgr->conf_file_name[0])
3570 return NULL;
3671 }
3772
73 static char *get_card_number(struct ctl_list *ctl_list)
74 {
75 char num[16];
76
77 if (ctl_list == NULL)
78 return strdup("");
79 snprintf(num, sizeof(num), "%i", snd_ctl_card_info_get_card(ctl_list->ctl_info));
80 return strdup(num);
81 }
82
83 static char *rval_card_number(snd_use_case_mgr_t *uc_mgr)
84 {
85 if (uc_mgr->conf_format < 3)
86 return NULL;
87 return get_card_number(uc_mgr_get_master_ctl(uc_mgr));
88 }
89
3890 static char *rval_card_id(snd_use_case_mgr_t *uc_mgr)
3991 {
4092 struct ctl_list *ctl_list;
4193
42 ctl_list = uc_mgr_get_one_ctl(uc_mgr);
94 ctl_list = uc_mgr_get_master_ctl(uc_mgr);
4395 if (ctl_list == NULL)
4496 return NULL;
4597 return strdup(snd_ctl_card_info_get_id(ctl_list->ctl_info));
49101 {
50102 struct ctl_list *ctl_list;
51103
52 ctl_list = uc_mgr_get_one_ctl(uc_mgr);
104 ctl_list = uc_mgr_get_master_ctl(uc_mgr);
53105 if (ctl_list == NULL)
54106 return NULL;
55107 return strdup(snd_ctl_card_info_get_driver(ctl_list->ctl_info));
59111 {
60112 struct ctl_list *ctl_list;
61113
62 ctl_list = uc_mgr_get_one_ctl(uc_mgr);
114 ctl_list = uc_mgr_get_master_ctl(uc_mgr);
63115 if (ctl_list == NULL)
64116 return NULL;
65117 return strdup(snd_ctl_card_info_get_name(ctl_list->ctl_info));
69121 {
70122 struct ctl_list *ctl_list;
71123
72 ctl_list = uc_mgr_get_one_ctl(uc_mgr);
124 ctl_list = uc_mgr_get_master_ctl(uc_mgr);
73125 if (ctl_list == NULL)
74126 return NULL;
75127 return strdup(snd_ctl_card_info_get_longname(ctl_list->ctl_info));
79131 {
80132 struct ctl_list *ctl_list;
81133
82 ctl_list = uc_mgr_get_one_ctl(uc_mgr);
134 ctl_list = uc_mgr_get_master_ctl(uc_mgr);
83135 if (ctl_list == NULL)
84136 return NULL;
85137 return strdup(snd_ctl_card_info_get_components(ctl_list->ctl_info));
138 }
139
140 static struct ctl_list *get_ctl_list_by_name(snd_use_case_mgr_t *uc_mgr, const char *id)
141 {
142 char *name, *index;
143 long idx = 0;
144
145 name = alloca(strlen(id) + 1);
146 strcpy(name, id);
147 index = strchr(name, '#');
148 if (index) {
149 *index = '\0';
150 if (safe_strtol(index + 1, &idx))
151 return NULL;
152 }
153 return uc_mgr_get_ctl_by_name(uc_mgr, name, idx);
154 }
155
156 static char *rval_card_number_by_name(snd_use_case_mgr_t *uc_mgr, const char *id)
157 {
158 if (uc_mgr->conf_format < 3) {
159 uc_error("CardNumberByName substitution is supported in v3+ syntax");
160 return NULL;
161 }
162
163 return get_card_number(get_ctl_list_by_name(uc_mgr, id));
164 }
165
166 static char *rval_card_id_by_name(snd_use_case_mgr_t *uc_mgr, const char *id)
167 {
168 struct ctl_list *ctl_list;
169
170 if (uc_mgr->conf_format < 3) {
171 uc_error("CardIdByName substitution is supported in v3+ syntax");
172 return NULL;
173 }
174
175 ctl_list = get_ctl_list_by_name(uc_mgr, id);
176 if (ctl_list == NULL)
177 return NULL;
178 return strdup(snd_ctl_card_info_get_id(ctl_list->ctl_info));
86179 }
87180
88181 static char *rval_env(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED, const char *id)
145238 return strdup(path);
146239 }
147240
241 static char *rval_var(snd_use_case_mgr_t *uc_mgr, const char *id)
242 {
243 const char *v;
244
245 if (uc_mgr->conf_format < 3) {
246 uc_error("variable substitution is supported in v3+ syntax");
247 return NULL;
248 }
249
250 v = uc_mgr_get_variable(uc_mgr, id);
251 if (v)
252 return strdup(v);
253 return NULL;
254 }
255
148256 #define MATCH_VARIABLE(name, id, fcn, empty_ok) \
149257 if (strncmp((name), (id), sizeof(id) - 1) == 0) { \
150258 rval = fcn(uc_mgr); \
153261 goto __rval; \
154262 }
155263
156 #define MATCH_VARIABLE2(name, id, fcn) \
264 #define MATCH_VARIABLE2(name, id, fcn, empty_ok) \
157265 if (strncmp((name), (id), sizeof(id) - 1) == 0) { \
158266 idsize = sizeof(id) - 1; \
159 tmp = strchr(value + idsize, '}'); \
160 if (tmp) { \
161 rvalsize = tmp - (value + idsize); \
162 if (rvalsize > sizeof(v2)) { \
163 err = -ENOMEM; \
164 goto __error; \
165 } \
166 strncpy(v2, value + idsize, rvalsize); \
167 v2[rvalsize] = '\0'; \
168 idsize += rvalsize + 1; \
169 rval = fcn(uc_mgr, v2); \
170 goto __rval; \
171 } \
267 allow_empty = (empty_ok); \
268 fcn2 = (fcn); \
269 goto __match2; \
172270 }
173271
174272 int uc_mgr_get_substituted_value(snd_use_case_mgr_t *uc_mgr,
177275 {
178276 size_t size, nsize, idsize, rvalsize, dpos = 0;
179277 const char *tmp;
180 char *r, *nr, *rval, v2[32];
278 char *r, *nr, *rval, v2[48];
279 bool ignore_error, allow_empty;
280 char *(*fcn2)(snd_use_case_mgr_t *, const char *id);
181281 int err;
182282
183283 if (value == NULL)
189289 return -ENOMEM;
190290
191291 while (*value) {
192 if (*value == '$' && *(value+1) == '{') {
193 bool allow_empty = false;
194
195 MATCH_VARIABLE(value, "${ConfName}", rval_conf_name, false);
196 MATCH_VARIABLE(value, "${CardId}", rval_card_id, false);
197 MATCH_VARIABLE(value, "${CardDriver}", rval_card_driver, false);
198 MATCH_VARIABLE(value, "${CardName}", rval_card_name, false);
199 MATCH_VARIABLE(value, "${CardLongName}", rval_card_longname, false);
200 MATCH_VARIABLE(value, "${CardComponents}", rval_card_components, true);
201 MATCH_VARIABLE2(value, "${env:", rval_env);
202 MATCH_VARIABLE2(value, "${sys:", rval_sysfs);
203 err = -EINVAL;
204 tmp = strchr(value, '}');
205 if (tmp) {
206 strncpy(r, value, tmp + 1 - value);
207 r[tmp + 1 - value] = '\0';
208 uc_error("variable '%s' is not known!", r);
209 } else {
210 uc_error("variable reference '%s' is not complete", value);
211 }
212 goto __error;
213 __rval:
214 if (rval == NULL || (!allow_empty && rval[0] == '\0')) {
215 free(rval);
216 strncpy(r, value, idsize);
217 r[idsize] = '\0';
218 uc_error("variable '%s' is not defined in this context!", r);
219 err = -EINVAL;
292 if (*value != '$') {
293 __std:
294 r[dpos++] = *value;
295 value++;
296 continue;
297 }
298 ignore_error = false;
299 if (value[1] == '$' && value[2] == '{' && uc_mgr->conf_format >= 3) {
300 value++;
301 ignore_error = true;
302 } else if (value[1] != '{') {
303 goto __std;
304 }
305 allow_empty = false;
306 fcn2 = NULL;
307 MATCH_VARIABLE(value, "${OpenName}", rval_open_name, false);
308 MATCH_VARIABLE(value, "${ConfTopDir}", rval_conf_topdir, false);
309 MATCH_VARIABLE(value, "${ConfDir}", rval_conf_dir, false);
310 MATCH_VARIABLE(value, "${ConfName}", rval_conf_name, false);
311 MATCH_VARIABLE(value, "${CardNumber}", rval_card_number, true);
312 MATCH_VARIABLE(value, "${CardId}", rval_card_id, false);
313 MATCH_VARIABLE(value, "${CardDriver}", rval_card_driver, false);
314 MATCH_VARIABLE(value, "${CardName}", rval_card_name, false);
315 MATCH_VARIABLE(value, "${CardLongName}", rval_card_longname, false);
316 MATCH_VARIABLE(value, "${CardComponents}", rval_card_components, true);
317 MATCH_VARIABLE2(value, "${env:", rval_env, false);
318 MATCH_VARIABLE2(value, "${sys:", rval_sysfs, false);
319 MATCH_VARIABLE2(value, "${var:", rval_var, true);
320 MATCH_VARIABLE2(value, "${CardNumberByName:", rval_card_number_by_name, false);
321 MATCH_VARIABLE2(value, "${CardIdByName:", rval_card_id_by_name, false);
322 __merr:
323 err = -EINVAL;
324 tmp = strchr(value, '}');
325 if (tmp) {
326 strncpy(r, value, tmp + 1 - value);
327 r[tmp + 1 - value] = '\0';
328 uc_error("variable '%s' is not known!", r);
329 } else {
330 uc_error("variable reference '%s' is not complete", value);
331 }
332 goto __error;
333 __match2:
334 tmp = strchr(value + idsize, '}');
335 if (tmp) {
336 rvalsize = tmp - (value + idsize);
337 if (rvalsize >= sizeof(v2)) {
338 err = -ENOMEM;
220339 goto __error;
221340 }
222 value += idsize;
223 rvalsize = strlen(rval);
224 nsize = size + rvalsize - idsize;
225 if (nsize > size) {
226 nr = realloc(r, nsize);
227 if (nr == NULL) {
228 free(rval);
229 err = -ENOMEM;
230 goto __error;
341 strncpy(v2, value + idsize, rvalsize);
342 v2[rvalsize] = '\0';
343 idsize += rvalsize + 1;
344 if (*v2 == '$' && uc_mgr->conf_format >= 3) {
345 tmp = uc_mgr_get_variable(uc_mgr, v2 + 1);
346 if (tmp == NULL) {
347 uc_error("define '%s' is not reachable in this context!", v2 + 1);
348 rval = NULL;
349 } else {
350 rval = fcn2(uc_mgr, tmp);
231351 }
232 size = nsize;
233 r = nr;
352 } else {
353 rval = fcn2(uc_mgr, v2);
234354 }
235 strcpy(r + dpos, rval);
236 dpos += rvalsize;
355 goto __rval;
356 }
357 goto __merr;
358 __rval:
359 if (rval == NULL || (!allow_empty && rval[0] == '\0')) {
237360 free(rval);
238 } else {
239 r[dpos++] = *value;
240 value++;
241 }
361 if (ignore_error) {
362 value += idsize;
363 continue;
364 }
365 strncpy(r, value, idsize);
366 r[idsize] = '\0';
367 uc_error("variable '%s' is not defined in this context!", r);
368 err = -EINVAL;
369 goto __error;
370 }
371 value += idsize;
372 rvalsize = strlen(rval);
373 nsize = size + rvalsize - idsize;
374 if (nsize > size) {
375 nr = realloc(r, nsize);
376 if (nr == NULL) {
377 free(rval);
378 err = -ENOMEM;
379 goto __error;
380 }
381 size = nsize;
382 r = nr;
383 }
384 strcpy(r + dpos, rval);
385 dpos += rvalsize;
386 free(rval);
242387 }
243388 r[dpos] = '\0';
244389
4848 va_end(va);
4949 }
5050
51 struct ctl_list *uc_mgr_get_one_ctl(snd_use_case_mgr_t *uc_mgr)
51 struct ctl_list *uc_mgr_get_master_ctl(snd_use_case_mgr_t *uc_mgr)
5252 {
5353 struct list_head *pos;
54 struct ctl_list *ctl_list = NULL;
54 struct ctl_list *ctl_list = NULL, *ctl_list2;
5555
5656 list_for_each(pos, &uc_mgr->ctl_list) {
57 ctl_list2 = list_entry(pos, struct ctl_list, list);
58 if (ctl_list2->slave)
59 continue;
5760 if (ctl_list) {
5861 uc_error("multiple control device names were found!");
5962 return NULL;
6063 }
64 ctl_list = ctl_list2;
65 }
66 return ctl_list;
67 }
68
69 struct ctl_list *uc_mgr_get_ctl_by_name(snd_use_case_mgr_t *uc_mgr, const char *name, int idx)
70 {
71 struct list_head *pos;
72 struct ctl_list *ctl_list = NULL;
73 const char *s;
74 char cname[32];
75 int idx2, card, err;
76
77 idx2 = idx;
78 list_for_each(pos, &uc_mgr->ctl_list) {
6179 ctl_list = list_entry(pos, struct ctl_list, list);
62 }
63 return ctl_list;
80 s = snd_ctl_card_info_get_name(ctl_list->ctl_info);
81 if (s == NULL)
82 continue;
83 if (strcmp(s, name) == 0) {
84 if (idx2 == 0)
85 return ctl_list;
86 idx2--;
87 }
88 }
89
90 idx2 = idx;
91 card = -1;
92 if (snd_card_next(&card) < 0 || card < 0)
93 return NULL;
94
95 while (card >= 0) {
96 sprintf(cname, "hw:%d", card);
97 err = uc_mgr_open_ctl(uc_mgr, &ctl_list, cname, 1);
98 if (err < 0)
99 continue; /* really? */
100 s = snd_ctl_card_info_get_name(ctl_list->ctl_info);
101 if (s && strcmp(s, name) == 0) {
102 if (idx2 == 0)
103 return ctl_list;
104 idx2--;
105 }
106 if (snd_card_next(&card) < 0)
107 break;
108 }
109
110 return NULL;
64111 }
65112
66113 snd_ctl_t *uc_mgr_get_ctl(snd_use_case_mgr_t *uc_mgr)
67114 {
68115 struct ctl_list *ctl_list;
69116
70 ctl_list = uc_mgr_get_one_ctl(uc_mgr);
117 ctl_list = uc_mgr_get_master_ctl(uc_mgr);
71118 if (ctl_list)
72119 return ctl_list->ctl;
73120 return NULL;
126173 }
127174
128175 static int uc_mgr_ctl_add(snd_use_case_mgr_t *uc_mgr,
129 struct ctl_list *ctl_list,
176 struct ctl_list **ctl_list,
130177 snd_ctl_t *ctl, int card,
131178 snd_ctl_card_info_t *info,
132 const char *device)
179 const char *device,
180 int slave)
133181 {
134182 struct ctl_list *cl = NULL;
135183 const char *id = snd_ctl_card_info_get_id(info);
138186
139187 if (id == NULL || id[0] == '\0')
140188 return -ENOENT;
141 if (!ctl_list) {
189 if (!(*ctl_list)) {
142190 cl = malloc(sizeof(*cl));
143191 if (cl == NULL)
144192 return -ENOMEM;
149197 return -ENOMEM;
150198 }
151199 snd_ctl_card_info_copy(cl->ctl_info, info);
152 ctl_list = cl;
200 cl->slave = slave;
201 *ctl_list = cl;
202 } else {
203 if (!slave)
204 (*ctl_list)->slave = slave;
153205 }
154206 if (card >= 0) {
155207 snprintf(dev, sizeof(dev), "hw:%d", card);
156208 hit |= !!(device && (strcmp(dev, device) == 0));
157 err = uc_mgr_ctl_add_dev(ctl_list, dev);
209 err = uc_mgr_ctl_add_dev(*ctl_list, dev);
158210 if (err < 0)
159211 goto __nomem;
160212 }
161213 snprintf(dev, sizeof(dev), "hw:%s", id);
162214 hit |= !!(device && (strcmp(dev, device) == 0));
163 err = uc_mgr_ctl_add_dev(ctl_list, dev);
215 err = uc_mgr_ctl_add_dev(*ctl_list, dev);
164216 if (err < 0)
165217 goto __nomem;
166218 /* the UCM name not based on the card name / id */
167219 if (!hit && device) {
168 err = uc_mgr_ctl_add_dev(ctl_list, device);
220 err = uc_mgr_ctl_add_dev(*ctl_list, device);
169221 if (err < 0)
170222 goto __nomem;
171223 }
172224
173 list_add_tail(&ctl_list->list, &uc_mgr->ctl_list);
225 list_add_tail(&(*ctl_list)->list, &uc_mgr->ctl_list);
174226 return 0;
175227
176228 __nomem:
177 if (ctl_list == cl)
229 if (*ctl_list == cl) {
178230 uc_mgr_free_ctl(cl);
231 *ctl_list = NULL;
232 }
179233 return -ENOMEM;
180234 }
181235
182236 int uc_mgr_open_ctl(snd_use_case_mgr_t *uc_mgr,
183 snd_ctl_t **ctl,
184 const char *device)
237 struct ctl_list **ctll,
238 const char *device,
239 int slave)
185240 {
186241 struct list_head *pos1, *pos2;
242 snd_ctl_t *ctl;
187243 struct ctl_list *ctl_list;
188244 struct ctl_dev *ctl_dev;
189245 snd_ctl_card_info_t *info;
198254 list_for_each(pos2, &ctl_list->dev_list) {
199255 ctl_dev = list_entry(pos2, struct ctl_dev, list);
200256 if (strcmp(ctl_dev->device, device) == 0) {
201 *ctl = ctl_list->ctl;
257 *ctll = ctl_list;
258 if (!slave)
259 ctl_list->slave = 0;
202260 return 0;
203261 }
204262 }
205263 }
206264
207 err = snd_ctl_open(ctl, device, 0);
265 err = snd_ctl_open(&ctl, device, 0);
208266 if (err < 0)
209267 return err;
210268
211269 id = NULL;
212 err = snd_ctl_card_info(*ctl, info);
270 err = snd_ctl_card_info(ctl, info);
213271 if (err == 0)
214272 id = snd_ctl_card_info_get_id(info);
215273 if (err < 0 || id == NULL || id[0] == '\0') {
216274 uc_error("control hardware info (%s): %s", device, snd_strerror(err));
217 snd_ctl_close(*ctl);
218 *ctl = NULL;
219 return err;
275 snd_ctl_close(ctl);
276 return err >= 0 ? -EINVAL : err;
220277 }
221278
222279 /* insert to cache, if just name differs */
224281 ctl_list = list_entry(pos1, struct ctl_list, list);
225282 if (strcmp(id, snd_ctl_card_info_get_id(ctl_list->ctl_info)) == 0) {
226283 card = snd_card_get_index(id);
227 err = uc_mgr_ctl_add(uc_mgr, ctl_list, *ctl, card, info, device);
284 err = uc_mgr_ctl_add(uc_mgr, &ctl_list, ctl, card, info, device, slave);
228285 if (err < 0)
229286 goto __nomem;
230 snd_ctl_close(*ctl);
231 *ctl = ctl_list->ctl;
287 snd_ctl_close(ctl);
288 *ctll = ctl_list;
232289 return 0;
233290 }
234291 }
235292
236 err = uc_mgr_ctl_add(uc_mgr, NULL, *ctl, -1, info, device);
293 ctl_list = NULL;
294 err = uc_mgr_ctl_add(uc_mgr, &ctl_list, ctl, -1, info, device, slave);
237295 if (err < 0)
238296 goto __nomem;
239297
298 *ctll = ctl_list;
240299 return 0;
241300
242301 __nomem:
243 snd_ctl_close(*ctl);
244 *ctl = NULL;
302 snd_ctl_close(ctl);
245303 return -ENOMEM;
246304 }
247305
248 int uc_mgr_config_load(int format, const char *file, snd_config_t **cfg)
249 {
250 FILE *fp;
251 snd_input_t *in;
252 snd_config_t *top;
253 const char *path, *default_paths[2];
254 int err;
255
256 fp = fopen(file, "r");
257 if (!fp) {
258 err = -errno;
259 __err0:
260 uc_error("could not open configuration file %s", file);
261 return err;
262 }
263 err = snd_input_stdio_attach(&in, fp, 1);
264 if (err < 0)
265 goto __err0;
266 err = snd_config_top(&top);
267 if (err < 0)
268 goto __err1;
306 const char *uc_mgr_config_dir(int format)
307 {
308 const char *path;
269309
270310 if (format >= 2) {
271311 path = getenv(ALSA_CONFIG_UCM2_VAR);
276316 if (!path || path[0] == '\0')
277317 path = ALSA_CONFIG_DIR "/ucm";
278318 }
279
280 default_paths[0] = path;
319 return path;
320 }
321
322 int uc_mgr_config_load(int format, const char *file, snd_config_t **cfg)
323 {
324 FILE *fp;
325 snd_input_t *in;
326 snd_config_t *top;
327 const char *default_paths[2];
328 int err;
329
330 fp = fopen(file, "r");
331 if (!fp) {
332 err = -errno;
333 __err0:
334 uc_error("could not open configuration file %s", file);
335 return err;
336 }
337 err = snd_input_stdio_attach(&in, fp, 1);
338 if (err < 0)
339 goto __err0;
340 err = snd_config_top(&top);
341 if (err < 0)
342 goto __err1;
343
344 default_paths[0] = uc_mgr_config_dir(format);
281345 default_paths[1] = NULL;
282346 err = _snd_config_load_with_include(top, in, 0, default_paths);
283347 if (err < 0) {
370434 return 0;
371435 }
372436 }
373 return -ENOENT;
437 return -ENODEV;
374438 }
375439
376440 int uc_mgr_remove_from_dev_list(struct dev_list *dev_list, const char *name)
527591 {
528592 struct use_case_device *device;
529593 struct list_head *pos, *npos;
594 int err, found = 0;
530595
531596 list_for_each_safe(pos, npos, &verb->device_list) {
532597 device = list_entry(pos, struct use_case_device, list);
533598 if (strcmp(device->name, name) == 0) {
534599 uc_mgr_free_device(device);
600 found++;
535601 continue;
536602 }
537 uc_mgr_remove_from_dev_list(&device->dev_list, name);
538 return 0;
539 }
540 return -ENOENT;
603 err = uc_mgr_remove_from_dev_list(&device->dev_list, name);
604 if (err < 0 && err != -ENODEV)
605 return err;
606 if (err == 0)
607 found++;
608 }
609 return found == 0 ? -ENODEV : 0;
610 }
611
612 const char *uc_mgr_get_variable(snd_use_case_mgr_t *uc_mgr, const char *name)
613 {
614 struct list_head *pos;
615 struct ucm_value *value;
616
617 list_for_each(pos, &uc_mgr->variable_list) {
618 value = list_entry(pos, struct ucm_value, list);
619 if (strcmp(value->name, name) == 0)
620 return value->data;
621 }
622 return NULL;
623 }
624
625 int uc_mgr_set_variable(snd_use_case_mgr_t *uc_mgr, const char *name,
626 const char *val)
627 {
628 struct list_head *pos;
629 struct ucm_value *curr;
630 char *val2;
631
632 list_for_each(pos, &uc_mgr->variable_list) {
633 curr = list_entry(pos, struct ucm_value, list);
634 if (strcmp(curr->name, name) == 0) {
635 val2 = strdup(val);
636 if (val2 == NULL)
637 return -ENOMEM;
638 free(curr->data);
639 curr->data = val2;
640 return 0;
641 }
642 }
643
644 curr = calloc(1, sizeof(struct ucm_value));
645 if (curr == NULL)
646 return -ENOMEM;
647 curr->name = strdup(name);
648 if (curr->name == NULL) {
649 free(curr);
650 return -ENOMEM;
651 }
652 curr->data = strdup(val);
653 if (curr->data == NULL) {
654 free(curr->name);
655 free(curr);
656 return -ENOMEM;
657 }
658 list_add_tail(&curr->list, &uc_mgr->variable_list);
659 return 0;
541660 }
542661
543662 void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr)
561680 list_del(&verb->list);
562681 free(verb);
563682 }
683 uc_mgr_free_sequence(&uc_mgr->once_list);
564684 uc_mgr_free_sequence(&uc_mgr->default_list);
565685 uc_mgr_free_value(&uc_mgr->value_list);
686 uc_mgr_free_value(&uc_mgr->variable_list);
566687 free(uc_mgr->comment);
567688 free(uc_mgr->conf_dir_name);
568689 free(uc_mgr->conf_file_name);
44 #include "../include/asoundlib.h"
55
66 static char *device = "default"; /* playback device */
7
8 snd_output_t *output = NULL;
97 unsigned char buffer[16*1024]; /* some random data */
108
119 int main(void)
1210 {
13 int err;
14 unsigned int i;
15 snd_pcm_t *handle;
16 snd_pcm_sframes_t frames;
11 int err;
12 unsigned int i;
13 snd_pcm_t *handle;
14 snd_pcm_sframes_t frames;
1715
18 for (i = 0; i < sizeof(buffer); i++)
19 buffer[i] = random() & 0xff;
16 for (i = 0; i < sizeof(buffer); i++)
17 buffer[i] = random() & 0xff;
2018
2119 if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
2220 printf("Playback open error: %s\n", snd_strerror(err));
2321 exit(EXIT_FAILURE);
2422 }
2523 if ((err = snd_pcm_set_params(handle,
26 SND_PCM_FORMAT_U8,
27 SND_PCM_ACCESS_RW_INTERLEAVED,
28 1,
29 48000,
30 1,
31 500000)) < 0) { /* 0.5sec */
24 SND_PCM_FORMAT_U8,
25 SND_PCM_ACCESS_RW_INTERLEAVED,
26 1,
27 48000,
28 1,
29 500000)) < 0) { /* 0.5sec */
3230 printf("Playback open error: %s\n", snd_strerror(err));
3331 exit(EXIT_FAILURE);
3432 }
3533
3634 for (i = 0; i < 16; i++) {
37 frames = snd_pcm_writei(handle, buffer, sizeof(buffer));
38 if (frames < 0)
39 frames = snd_pcm_recover(handle, frames, 0);
40 if (frames < 0) {
41 printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
42 break;
43 }
44 if (frames > 0 && frames < (long)sizeof(buffer))
45 printf("Short write (expected %li, wrote %li)\n", (long)sizeof(buffer), frames);
46 }
35 frames = snd_pcm_writei(handle, buffer, sizeof(buffer));
36 if (frames < 0)
37 frames = snd_pcm_recover(handle, frames, 0);
38 if (frames < 0) {
39 printf("snd_pcm_writei failed: %s\n", snd_strerror(frames));
40 break;
41 }
42 if (frames > 0 && frames < (long)sizeof(buffer))
43 printf("Short write (expected %li, wrote %li)\n", (long)sizeof(buffer), frames);
44 }
4745
46 /* pass the remaining samples, otherwise they're dropped in close */
47 err = snd_pcm_drain(handle);
48 if (err < 0)
49 printf("snd_pcm_drain failed: %s\n", snd_strerror(err));
4850 snd_pcm_close(handle);
4951 return 0;
5052 }
0 1.2.2
0 1.2.3.2