From 04f6d16da5d84705918b44bf60678355f566e85f Mon Sep 17 00:00:00 2001 From: Bernhard M. Wiedemann Date: Dec 08 2020 06:56:39 +0000 Subject: update 2020-10-03 20:30 --- diff --git a/0001-ucm-substitution-remove-duplicate-allow_empty-assign.patch b/0001-ucm-substitution-remove-duplicate-allow_empty-assign.patch new file mode 100644 index 0000000..9658ac6 --- /dev/null +++ b/0001-ucm-substitution-remove-duplicate-allow_empty-assign.patch @@ -0,0 +1,36 @@ +From 485930ea5dc8a14e0d215de44557372ca41b15f4 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Tue, 30 Jun 2020 09:22:12 +0200 +Subject: [PATCH 01/32] ucm: substitution - remove duplicate allow_empty + assignment + +Signed-off-by: Jaroslav Kysela +--- + src/ucm/ucm_subs.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/ucm/ucm_subs.c b/src/ucm/ucm_subs.c +index a154aa510ee8..d40e5478b084 100644 +--- a/src/ucm/ucm_subs.c ++++ b/src/ucm/ucm_subs.c +@@ -303,7 +303,6 @@ __std: + } else if (value[1] != '{') { + goto __std; + } +- allow_empty = false; + fcn2 = NULL; + MATCH_VARIABLE(value, "${OpenName}", rval_open_name, false); + MATCH_VARIABLE(value, "${ConfTopDir}", rval_conf_topdir, false); +@@ -365,7 +364,8 @@ __rval: + } + strncpy(r, value, idsize); + r[idsize] = '\0'; +- uc_error("variable '%s' is not defined in this context!", r); ++ uc_error("variable '%s' is %s in this context!", r, ++ rval ? "empty" : "not defined"); + err = -EINVAL; + goto __error; + } +-- +2.16.4 + diff --git a/0002-ucm-fix-parse_get_safe_name-safe-name-must-be-checke.patch b/0002-ucm-fix-parse_get_safe_name-safe-name-must-be-checke.patch new file mode 100644 index 0000000..ecbddca --- /dev/null +++ b/0002-ucm-fix-parse_get_safe_name-safe-name-must-be-checke.patch @@ -0,0 +1,35 @@ +From 30d12e930cfcba777a29af502a9c1dbfa5e37c04 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Fri, 3 Jul 2020 14:48:18 +0200 +Subject: [PATCH 02/32] ucm: fix parse_get_safe_name() - safe name must be + checked after substitution + +Signed-off-by: Jaroslav Kysela +--- + src/ucm/parser.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/src/ucm/parser.c b/src/ucm/parser.c +index 3b7fc931362f..d034b8598a85 100644 +--- a/src/ucm/parser.c ++++ b/src/ucm/parser.c +@@ -234,9 +234,14 @@ int parse_get_safe_name(snd_use_case_mgr_t *uc_mgr, snd_config_t *n, + if (err < 0) + return err; + } +- if (!parse_is_name_safe(id)) ++ err = get_string3(uc_mgr, id, name); ++ if (err < 0) ++ return err; ++ if (!parse_is_name_safe(*name)) { ++ free(*name); + return -EINVAL; +- return get_string3(uc_mgr, id, name); ++ } ++ return 0; + } + + /* +-- +2.16.4 + diff --git a/0003-ucm-substitute-the-merged-tree-completely.patch b/0003-ucm-substitute-the-merged-tree-completely.patch new file mode 100644 index 0000000..ecc1586 --- /dev/null +++ b/0003-ucm-substitute-the-merged-tree-completely.patch @@ -0,0 +1,147 @@ +From 32addac948a61c4770f9cdf459fa29879602df38 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Mon, 6 Jul 2020 16:34:33 +0200 +Subject: [PATCH 03/32] ucm: substitute the merged tree completely + +We need to define the common shared configuration like for multiple +HDMI devices or so. Substitute the whole merged configuration tree +including identifiers. + +Fixes: https://github.com/alsa-project/alsa-lib/issues/67 +Fixes: https://github.com/alsa-project/alsa-ucm-conf/commit/dcef48f13d4f5db79b006755074940b94730a883 +Signed-off-by: Jaroslav Kysela +--- + src/ucm/ucm_cond.c | 2 +- + src/ucm/ucm_include.c | 9 +++++++-- + src/ucm/ucm_local.h | 6 +++++- + src/ucm/ucm_subs.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 66 insertions(+), 4 deletions(-) + +diff --git a/src/ucm/ucm_cond.c b/src/ucm/ucm_cond.c +index cc4915396d71..3ca3096e0b19 100644 +--- a/src/ucm/ucm_cond.c ++++ b/src/ucm/ucm_cond.c +@@ -401,7 +401,7 @@ int uc_mgr_evaluate_condition(snd_use_case_mgr_t *uc_mgr, + err = uc_mgr_evaluate_inplace(uc_mgr, a); + if (err < 0) + return err; +- err = uc_mgr_config_tree_merge(parent, a, before, after); ++ err = uc_mgr_config_tree_merge(uc_mgr, parent, a, before, after); + if (err < 0) + return err; + snd_config_delete(a); +diff --git a/src/ucm/ucm_include.c b/src/ucm/ucm_include.c +index c69490f49c6e..94ae944d2001 100644 +--- a/src/ucm/ucm_include.c ++++ b/src/ucm/ucm_include.c +@@ -206,7 +206,8 @@ static int compound_merge(const char *id, + return 0; + } + +-int uc_mgr_config_tree_merge(snd_config_t *parent, snd_config_t *new_ctx, ++int uc_mgr_config_tree_merge(snd_use_case_mgr_t *uc_mgr, ++ snd_config_t *parent, snd_config_t *new_ctx, + snd_config_t *before, snd_config_t *after) + { + snd_config_iterator_t i, next; +@@ -214,6 +215,10 @@ int uc_mgr_config_tree_merge(snd_config_t *parent, snd_config_t *new_ctx, + const char *id; + int err; + ++ err = uc_mgr_substitute_tree(uc_mgr, new_ctx); ++ if (err < 0) ++ return err; ++ + snd_config_for_each(i, next, new_ctx) { + n = snd_config_iterator_entry(i); + err = snd_config_remove(n); +@@ -271,7 +276,7 @@ int uc_mgr_evaluate_include(snd_use_case_mgr_t *uc_mgr, + err = uc_mgr_evaluate_inplace(uc_mgr, a); + if (err < 0) + return err; +- err = uc_mgr_config_tree_merge(parent, a, before, after); ++ err = uc_mgr_config_tree_merge(uc_mgr, parent, a, before, after); + if (err < 0) + return err; + snd_config_delete(a); +diff --git a/src/ucm/ucm_local.h b/src/ucm/ucm_local.h +index 709f4cbd5a20..dd72e3f55f95 100644 +--- a/src/ucm/ucm_local.h ++++ b/src/ucm/ucm_local.h +@@ -307,7 +307,11 @@ int uc_mgr_get_substituted_value(snd_use_case_mgr_t *uc_mgr, + char **_rvalue, + const char *value); + +-int uc_mgr_config_tree_merge(snd_config_t *parent, snd_config_t *new_ctx, ++int uc_mgr_substitute_tree(snd_use_case_mgr_t *uc_mgr, ++ snd_config_t *node); ++ ++int uc_mgr_config_tree_merge(snd_use_case_mgr_t *uc_mgr, ++ snd_config_t *parent, snd_config_t *new_ctx, + snd_config_t *before, snd_config_t *after); + + int uc_mgr_evaluate_inplace(snd_use_case_mgr_t *uc_mgr, +diff --git a/src/ucm/ucm_subs.c b/src/ucm/ucm_subs.c +index d40e5478b084..f608bb0955a6 100644 +--- a/src/ucm/ucm_subs.c ++++ b/src/ucm/ucm_subs.c +@@ -395,3 +395,56 @@ __error: + free(r); + return err; + } ++ ++static inline int uc_mgr_substitute_check(const char *s) ++{ ++ return s && strstr(s, "${") != NULL; ++} ++ ++int uc_mgr_substitute_tree(snd_use_case_mgr_t *uc_mgr, snd_config_t *node) ++{ ++ snd_config_iterator_t i, next; ++ snd_config_t *n; ++ const char *id, *s2; ++ char *s; ++ int err; ++ ++ err = snd_config_get_id(node, &id); ++ if (err < 0) ++ return err; ++ if (uc_mgr_substitute_check(id)) { ++ err = uc_mgr_get_substituted_value(uc_mgr, &s, id); ++ if (err < 0) ++ return err; ++ err = snd_config_set_id(node, s); ++ free(s); ++ if (err < 0) { ++ uc_error("unable to set substituted id '%s' (old id '%s')", s, id); ++ return err; ++ } ++ } ++ if (snd_config_get_type(node) != SND_CONFIG_TYPE_COMPOUND) { ++ if (snd_config_get_type(node) == SND_CONFIG_TYPE_STRING) { ++ err = snd_config_get_string(node, &s2); ++ if (err < 0) ++ return err; ++ if (!uc_mgr_substitute_check(s2)) ++ return 0; ++ err = uc_mgr_get_substituted_value(uc_mgr, &s, s2); ++ if (err < 0) ++ return err; ++ err = snd_config_set_string(node, s); ++ free(s); ++ if (err < 0) ++ return err; ++ } ++ return 0; ++ } ++ snd_config_for_each(i, next, node) { ++ n = snd_config_iterator_entry(i); ++ err = uc_mgr_substitute_tree(uc_mgr, n); ++ if (err < 0) ++ return err; ++ } ++ return 0; ++} +-- +2.16.4 + diff --git a/0004-ctl-improve-documentation-for-identifier-of-control-.patch b/0004-ctl-improve-documentation-for-identifier-of-control-.patch new file mode 100644 index 0000000..5ecdb47 --- /dev/null +++ b/0004-ctl-improve-documentation-for-identifier-of-control-.patch @@ -0,0 +1,36 @@ +From 877bdf95fdfdac840a7a664362ec69b85c59ecb0 Mon Sep 17 00:00:00 2001 +From: Takashi Sakamoto +Date: Fri, 3 Jul 2020 09:37:51 +0900 +Subject: [PATCH 04/32] ctl: improve documentation for identifier of control + element + +In documentation, there're two ways relevant to the identifier of control +element. However, the case of combination has the lack of parameters. + +This commit improves documentation in this point. + +Fixes: f3c24de8c0df ("ctl: add an overview for design of ALSA control interface") +Signed-off-by: Takashi Sakamoto +Signed-off-by: Jaroslav Kysela +--- + src/control/control.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/control/control.c b/src/control/control.c +index 19528ae30a0b..e21e8f1d2621 100644 +--- a/src/control/control.c ++++ b/src/control/control.c +@@ -49,8 +49,8 @@ are managed according to below model. + - An element includes some members to have a value. The value of each member + can be changed by both of userspace applications and drivers in kernel. + +-Each element can be identified by two ways; a combination of name and index, or +-numerical number (numid). ++Each element can be identified by two ways; the numerical number (numid), or the ++combination of interface, device, subdevice, name, and index. + + The type of element set is one of integer, integerr64, boolean, enumerators, + bytes and IEC958 structure. This indicates the type of value for each member in +-- +2.16.4 + diff --git a/0005-pcm-dmix-make-lockless-operation-optional.patch b/0005-pcm-dmix-make-lockless-operation-optional.patch new file mode 100644 index 0000000..d31425c --- /dev/null +++ b/0005-pcm-dmix-make-lockless-operation-optional.patch @@ -0,0 +1,107 @@ +From 4759865c861c708ce4a68fc08060fc820628ccaf Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Fri, 19 Jun 2020 18:57:05 +0200 +Subject: [PATCH 05/32] pcm: dmix: make lockless operation optional + +The recently reported (but a long-standing) bug about the +unconditional semaphore usage in the dmix implies that basically we've +had no problem with the locking in the practical usages over years. +Although the lockless operation has a clear merit, it's a much higher +CPU usage (especially on some uncached pages), and it might lead to a +potential deadlock in theory (which is hard to reproduce at will, +though). + +This patch introduces a new configure option "--enable-lockless-dmix" +or "--disable-lockless-dmix" to let user choose the default dmix +operation mode. The usage of the lockless mixing has been already +conditionally enabled via asoundrc and card config +"direct_memory_access", so we just need to set the default value based +on it. + +In this patch, the default is set off to the lockless mixing, i.e. the +generic mixing is chosen. It makes more sense from the performance +POV. For any users who still require the lockless operation, it can +be enabled either via configure option or the asoundrc. + +The magic number used in the shmem is also changed depending on the +operation mode. It's just for safety, not to conflict both operation +modes with each other. + +Reviewed-by: Jaroslav Kysela +Signed-off-by: Takashi Iwai +--- + configure.ac | 13 +++++++++++++ + src/pcm/pcm_direct.c | 16 +++++++++++++--- + 2 files changed, 26 insertions(+), 3 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 93a54c909d1d..01357fb9310f 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -629,6 +629,19 @@ if test "$build_pcm_mmap_emul" = "yes"; then + AC_DEFINE([BUILD_PCM_PLUGIN_MMAP_EMUL], "1", [Build PCM mmap-emul plugin]) + fi + ++if test "$build_pcm_dmix" = "yes"; then ++AC_MSG_CHECKING(for default lockless dmix) ++AC_ARG_ENABLE(lockless-dmix, ++ AS_HELP_STRING([--enable-lockless-dmix], ++ [use lockless dmix as default on x86]), ++ lockless_dmix="$enableval", lockless_dmix="no") ++if test "$lockless_dmix" = "yes"; then ++ AC_MSG_RESULT(yes) ++ AC_DEFINE([LOCKLESS_DMIX_DEFAULT], "1", [Lockless dmix as default]) ++else ++ AC_MSG_RESULT(no) ++fi ++fi + + dnl Create PCM plugin symbol list for static library + rm -f "$srcdir"/src/pcm/pcm_symbols_list.c +diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c +index 665340954cf3..19c5a811262f 100644 +--- a/src/pcm/pcm_direct.c ++++ b/src/pcm/pcm_direct.c +@@ -82,7 +82,13 @@ int snd_pcm_direct_semaphore_create_or_connect(snd_pcm_direct_t *dmix) + return 0; + } + +-#define SND_PCM_DIRECT_MAGIC (0xa15ad300 + sizeof(snd_pcm_direct_share_t)) ++static unsigned int snd_pcm_direct_magic(snd_pcm_direct_t *dmix) ++{ ++ if (!dmix->direct_memory_access) ++ return 0xa15ad300 + sizeof(snd_pcm_direct_share_t); ++ else ++ return 0xb15ad300 + sizeof(snd_pcm_direct_share_t); ++} + + /* + * global shared memory area +@@ -132,10 +138,10 @@ retryget: + buf.shm_perm.gid = dmix->ipc_gid; + shmctl(dmix->shmid, IPC_SET, &buf); + } +- dmix->shmptr->magic = SND_PCM_DIRECT_MAGIC; ++ dmix->shmptr->magic = snd_pcm_direct_magic(dmix); + return 1; + } else { +- if (dmix->shmptr->magic != SND_PCM_DIRECT_MAGIC) { ++ if (dmix->shmptr->magic != snd_pcm_direct_magic(dmix)) { + snd_pcm_direct_shm_discard(dmix); + return -EINVAL; + } +@@ -1892,7 +1898,11 @@ int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf, + rec->slowptr = 1; + rec->max_periods = 0; + rec->var_periodsize = 0; ++#ifdef LOCKLESS_DMIX_DEFAULT + rec->direct_memory_access = 1; ++#else ++ rec->direct_memory_access = 0; ++#endif + rec->hw_ptr_alignment = SND_PCM_HW_PTR_ALIGNMENT_AUTO; + rec->tstamp_type = -1; + +-- +2.16.4 + diff --git a/0006-pcm-dmix-Fix-semaphore-usage-with-lockless-operation.patch b/0006-pcm-dmix-Fix-semaphore-usage-with-lockless-operation.patch new file mode 100644 index 0000000..197e19b --- /dev/null +++ b/0006-pcm-dmix-Fix-semaphore-usage-with-lockless-operation.patch @@ -0,0 +1,110 @@ +From d824b461ae807ea436e2df36da9c2212e485e3e6 Mon Sep 17 00:00:00 2001 +From: Takashi Iwai +Date: Fri, 19 Jun 2020 18:40:46 +0200 +Subject: [PATCH 06/32] pcm: dmix: Fix semaphore usage with lockless operation + +As Maarten Baert recently reported, the current dmix code applies the +semaphore unnecessarily around mixing streams even when the lockless +mix operation is used on x86. This was rather introduced mistakenly +at the commit 267d7c728196 ("Add support of little-endian on +i386/x86_64 dmix") where the generic dmix code was included on x86, +too. + +For achieving the original performance back, this patch changes the +semaphore handling to be checked at run time instead of statically at +compile time. + +Reviewed-by: Jaroslav Kysela +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_direct.h | 1 + + src/pcm/pcm_dmix.c | 18 +++++++++++------- + src/pcm/pcm_dmix_generic.c | 2 +- + src/pcm/pcm_dmix_i386.c | 1 + + src/pcm/pcm_dmix_x86_64.c | 1 + + 5 files changed, 15 insertions(+), 8 deletions(-) + +diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h +index 8a236970a3a1..2150bce15449 100644 +--- a/src/pcm/pcm_direct.h ++++ b/src/pcm/pcm_direct.h +@@ -186,6 +186,7 @@ struct snd_pcm_direct { + mix_areas_32_t *remix_areas_32; + mix_areas_24_t *remix_areas_24; + mix_areas_u8_t *remix_areas_u8; ++ unsigned int use_sem; + } dmix; + struct { + unsigned long long chn_mask; +diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c +index 843fa3168756..e9343b19a536 100644 +--- a/src/pcm/pcm_dmix.c ++++ b/src/pcm/pcm_dmix.c +@@ -292,13 +292,17 @@ static void remix_areas(snd_pcm_direct_t *dmix, + * the area via semaphore + */ + #ifndef DOC_HIDDEN +-#ifdef NO_CONCURRENT_ACCESS +-#define dmix_down_sem(dmix) snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT) +-#define dmix_up_sem(dmix) snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT) +-#else +-#define dmix_down_sem(dmix) +-#define dmix_up_sem(dmix) +-#endif ++static void dmix_down_sem(snd_pcm_direct_t *dmix) ++{ ++ if (dmix->u.dmix.use_sem) ++ snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT); ++} ++ ++static void dmix_up_sem(snd_pcm_direct_t *dmix) ++{ ++ if (dmix->u.dmix.use_sem) ++ snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); ++} + #endif + + /* +diff --git a/src/pcm/pcm_dmix_generic.c b/src/pcm/pcm_dmix_generic.c +index 40c08747a74a..8a5b6f148556 100644 +--- a/src/pcm/pcm_dmix_generic.c ++++ b/src/pcm/pcm_dmix_generic.c +@@ -43,7 +43,6 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, + #ifndef ARCH_ADD + #define ARCH_ADD(p,a) (*(p) += (a)) + #define ARCH_CMPXCHG(p,a,b) (*(p)) /* fake */ +-#define NO_CONCURRENT_ACCESS /* use semaphore to avoid race */ + #define IS_CONCURRENT 0 /* no race check */ + #endif + +@@ -530,6 +529,7 @@ static void generic_mix_select_callbacks(snd_pcm_direct_t *dmix) + dmix->u.dmix.mix_areas_u8 = generic_mix_areas_u8; + dmix->u.dmix.remix_areas_24 = generic_remix_areas_24; + dmix->u.dmix.remix_areas_u8 = generic_remix_areas_u8; ++ dmix->u.dmix.use_sem = 1; + } + + #endif +diff --git a/src/pcm/pcm_dmix_i386.c b/src/pcm/pcm_dmix_i386.c +index 1ab983a8a373..82a91c5c2897 100644 +--- a/src/pcm/pcm_dmix_i386.c ++++ b/src/pcm/pcm_dmix_i386.c +@@ -135,4 +135,5 @@ static void mix_select_callbacks(snd_pcm_direct_t *dmix) + dmix->u.dmix.mix_areas_24 = smp > 1 ? mix_areas_24_smp: mix_areas_24; + dmix->u.dmix.remix_areas_24 = smp > 1 ? remix_areas_24_smp: remix_areas_24; + } ++ dmix->u.dmix.use_sem = 0; + } +diff --git a/src/pcm/pcm_dmix_x86_64.c b/src/pcm/pcm_dmix_x86_64.c +index 34c40d4e9d1d..4d882bfd01bf 100644 +--- a/src/pcm/pcm_dmix_x86_64.c ++++ b/src/pcm/pcm_dmix_x86_64.c +@@ -102,4 +102,5 @@ static void mix_select_callbacks(snd_pcm_direct_t *dmix) + dmix->u.dmix.remix_areas_32 = smp > 1 ? remix_areas_32_smp : remix_areas_32; + dmix->u.dmix.mix_areas_24 = smp > 1 ? mix_areas_24_smp : mix_areas_24; + dmix->u.dmix.remix_areas_24 = smp > 1 ? remix_areas_24_smp : remix_areas_24; ++ dmix->u.dmix.use_sem = 0; + } +-- +2.16.4 + diff --git a/0007-pcm-iec958-implement-HDMI-HBR-audio-formatting.patch b/0007-pcm-iec958-implement-HDMI-HBR-audio-formatting.patch new file mode 100644 index 0000000..31f7db2 --- /dev/null +++ b/0007-pcm-iec958-implement-HDMI-HBR-audio-formatting.patch @@ -0,0 +1,151 @@ +From 8defc5c2a65345a1aee613ebf0999d203c2e0433 Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Mon, 13 Jul 2020 23:17:03 +0200 +Subject: [PATCH 07/32] pcm: iec958: implement HDMI HBR audio formatting + +High bitrate compressed audio data like DTS HD or MAT is usually +packed into 8-channel data. The HDMI specs state this has to be +formatted as a single IEC958 stream, compared to normal multi- +channel PCM data which has to be formatted as parallel IEC958 streams. + +As this single-stream formatting mode may break existing setups that +expect non-PCM multichannel data to be formatted as parallel IEC958 +streams it needs to be explicitly selected by setting the hdmi_mode +option to true. + +The single-stream formatting implementation is prepared to cope with +arbitrary channel counts but only limited testing was done for channel +counts other than 8. + +Signed-off-by: Matthias Reichl +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_iec958.c | 37 +++++++++++++++++++++++++++++++++---- + 1 file changed, 33 insertions(+), 4 deletions(-) + +diff --git a/src/pcm/pcm_iec958.c b/src/pcm/pcm_iec958.c +index 76d3ca7b8e3c..17ade9571cae 100644 +--- a/src/pcm/pcm_iec958.c ++++ b/src/pcm/pcm_iec958.c +@@ -63,6 +63,7 @@ struct snd_pcm_iec958 { + unsigned int byteswap; + unsigned char preamble[3]; /* B/M/W or Z/X/Y */ + snd_pcm_fast_ops_t fops; ++ int hdmi_mode; + }; + + enum { PREAMBLE_Z, PREAMBLE_X, PREAMBLE_Y }; +@@ -193,6 +194,10 @@ static void snd_pcm_iec958_encode(snd_pcm_iec958_t *iec, + unsigned int channel; + int32_t sample = 0; + int counter = iec->counter; ++ int single_stream = iec->hdmi_mode && ++ (iec->status[0] & IEC958_AES0_NONAUDIO) && ++ (channels == 8); ++ int counter_step = single_stream ? ((channels + 1) >> 1) : 1; + for (channel = 0; channel < channels; ++channel) { + const char *src; + uint32_t *dst; +@@ -205,7 +210,12 @@ static void snd_pcm_iec958_encode(snd_pcm_iec958_t *iec, + src_step = snd_pcm_channel_area_step(src_area); + dst_step = snd_pcm_channel_area_step(dst_area) / sizeof(uint32_t); + frames1 = frames; +- iec->counter = counter; ++ ++ if (single_stream) ++ iec->counter = (counter + (channel >> 1)) % 192; ++ else ++ iec->counter = counter; ++ + while (frames1-- > 0) { + goto *get; + #define GET32_END after +@@ -217,9 +227,11 @@ static void snd_pcm_iec958_encode(snd_pcm_iec958_t *iec, + *dst = sample; + src += src_step; + dst += dst_step; +- iec->counter++; ++ iec->counter += counter_step; + iec->counter %= 192; + } ++ if (single_stream) /* set counter to ch0 value for next iteration */ ++ iec->counter = (counter + frames * counter_step) % 192; + } + } + #endif /* DOC_HIDDEN */ +@@ -473,6 +485,7 @@ static const snd_pcm_ops_t snd_pcm_iec958_ops = { + * \param close_slave When set, the slave PCM handle is closed with copy PCM + * \param status_bits The IEC958 status bits + * \param preamble_vals The preamble byte values ++ * \param hdmi_mode When set, enable HDMI compliant formatting + * \retval zero on success otherwise a negative error code + * \warning Using of this function might be dangerous in the sense + * of compatibility reasons. The prototype might be freely +@@ -481,7 +494,8 @@ static const snd_pcm_ops_t snd_pcm_iec958_ops = { + int snd_pcm_iec958_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sformat, + snd_pcm_t *slave, int close_slave, + const unsigned char *status_bits, +- const unsigned char *preamble_vals) ++ const unsigned char *preamble_vals, ++ int hdmi_mode) + { + snd_pcm_t *pcm; + snd_pcm_iec958_t *iec; +@@ -519,6 +533,8 @@ int snd_pcm_iec958_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfo + + memcpy(iec->preamble, preamble_vals, 3); + ++ iec->hdmi_mode = hdmi_mode; ++ + err = snd_pcm_new(&pcm, SND_PCM_TYPE_IEC958, name, slave->stream, slave->mode); + if (err < 0) { + free(iec); +@@ -566,9 +582,14 @@ pcm.name { + [preamble.z or preamble.b val] + [preamble.x or preamble.m val] + [preamble.y or preamble.w val] ++ [hdmi_mode true] + } + \endcode + ++When hdmi_mode is true, 8-channel compressed data is ++formatted as 4 contiguous frames of a single IEC958 stream as required ++by the HDMI HBR specification. ++ + \subsection pcm_plugins_iec958_funcref Function reference + +
    +@@ -605,6 +626,7 @@ int _snd_pcm_iec958_open(snd_pcm_t **pcmp, const char *name, + unsigned char preamble_vals[3] = { + 0x08, 0x02, 0x04 /* Z, X, Y */ + }; ++ int hdmi_mode = 0; + + snd_config_for_each(i, next, conf) { + snd_config_t *n = snd_config_iterator_entry(i); +@@ -633,6 +655,13 @@ int _snd_pcm_iec958_open(snd_pcm_t **pcmp, const char *name, + preamble = n; + continue; + } ++ if (strcmp(id, "hdmi_mode") == 0) { ++ err = snd_config_get_bool(n); ++ if (err < 0) ++ continue; ++ hdmi_mode = err; ++ continue; ++ } + SNDERR("Unknown field %s", id); + return -EINVAL; + } +@@ -707,7 +736,7 @@ int _snd_pcm_iec958_open(snd_pcm_t **pcmp, const char *name, + return err; + err = snd_pcm_iec958_open(pcmp, name, sformat, spcm, 1, + status ? status_bits : NULL, +- preamble_vals); ++ preamble_vals, hdmi_mode); + if (err < 0) + snd_pcm_close(spcm); + return err; +-- +2.16.4 + diff --git a/0008-pcm-iec958-set-channel-status-bits-according-to-rate.patch b/0008-pcm-iec958-set-channel-status-bits-according-to-rate.patch new file mode 100644 index 0000000..38e0cd2 --- /dev/null +++ b/0008-pcm-iec958-set-channel-status-bits-according-to-rate.patch @@ -0,0 +1,123 @@ +From 36e4b296d2f4ad0034f7028256c64b8af003068d Mon Sep 17 00:00:00 2001 +From: Matthias Reichl +Date: Mon, 13 Jul 2020 23:17:04 +0200 +Subject: [PATCH 08/32] pcm: iec958: set channel status bits according to rate + and format + +This mimics snd_pcm_create_iec958_consumer in the kernel. + +The rate and wordlength bits will only be modified if they are +set to "not indicated", which is now the default if no status +option is used. + +This allows applications to override parameters determined from +the stream or implement channel status bits extensions without +needing to change pcm_iec958 code. + +Signed-off-by: Matthias Reichl +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_iec958.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 76 insertions(+), 4 deletions(-) + +diff --git a/src/pcm/pcm_iec958.c b/src/pcm/pcm_iec958.c +index 17ade9571cae..a11a043924f6 100644 +--- a/src/pcm/pcm_iec958.c ++++ b/src/pcm/pcm_iec958.c +@@ -365,9 +365,80 @@ static int snd_pcm_iec958_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params + iec->byteswap = format != SND_PCM_FORMAT_IEC958_SUBFRAME; + } + } +- /* FIXME: needs to adjust status_bits according to the format +- * and sample rate +- */ ++ ++ if ((iec->status[0] & IEC958_AES0_PROFESSIONAL) == 0) { ++ if ((iec->status[3] & IEC958_AES3_CON_FS) == IEC958_AES3_CON_FS_NOTID) { ++ unsigned int rate = 0; ++ unsigned char fs; ++ ++ err = INTERNAL(snd_pcm_hw_params_get_rate)(params, &rate, 0); ++ if (err < 0) ++ rate = 0; ++ ++ switch (rate) { ++ case 22050: ++ fs = IEC958_AES3_CON_FS_22050; ++ break; ++ case 24000: ++ fs = IEC958_AES3_CON_FS_24000; ++ break; ++ case 32000: ++ fs = IEC958_AES3_CON_FS_32000; ++ break; ++ case 44100: ++ fs = IEC958_AES3_CON_FS_44100; ++ break; ++ case 48000: ++ fs = IEC958_AES3_CON_FS_48000; ++ break; ++ case 88200: ++ fs = IEC958_AES3_CON_FS_88200; ++ break; ++ case 96000: ++ fs = IEC958_AES3_CON_FS_96000; ++ break; ++ case 176400: ++ fs = IEC958_AES3_CON_FS_176400; ++ break; ++ case 192000: ++ fs = IEC958_AES3_CON_FS_192000; ++ break; ++ case 768000: ++ fs = IEC958_AES3_CON_FS_768000; ++ break; ++ default: ++ fs = IEC958_AES3_CON_FS_NOTID; ++ break; ++ } ++ ++ iec->status[3] &= ~IEC958_AES3_CON_FS; ++ iec->status[3] |= fs; ++ } ++ ++ if ((iec->status[4] & IEC958_AES4_CON_WORDLEN) == IEC958_AES4_CON_WORDLEN_NOTID) { ++ unsigned char ws; ++ switch (snd_pcm_format_width(format)) { ++ case 16: ++ ws = IEC958_AES4_CON_WORDLEN_20_16; ++ break; ++ case 18: ++ ws = IEC958_AES4_CON_WORDLEN_22_18; ++ break; ++ case 20: ++ ws = IEC958_AES4_CON_WORDLEN_20_16 | IEC958_AES4_CON_MAX_WORDLEN_24; ++ break; ++ case 24: ++ case 32: /* Assume 24-bit width for 32-bit samples. */ ++ ws = IEC958_AES4_CON_WORDLEN_24_20 | IEC958_AES4_CON_MAX_WORDLEN_24; ++ break; ++ default: ++ ws = IEC958_AES4_CON_WORDLEN_NOTID; ++ break; ++ } ++ iec->status[4] &= ~(IEC958_AES4_CON_MAX_WORDLEN_24 | IEC958_AES4_CON_WORDLEN); ++ iec->status[4] |= ws; ++ } ++ } + return 0; + } + +@@ -504,7 +575,8 @@ int snd_pcm_iec958_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfo + IEC958_AES0_CON_EMPHASIS_NONE, + IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER, + 0, +- IEC958_AES3_CON_FS_48000 ++ IEC958_AES3_CON_FS_NOTID, /* will be set in hwparams */ ++ IEC958_AES4_CON_WORDLEN_NOTID /* will be set in hwparams */ + }; + + assert(pcmp && slave); +-- +2.16.4 + diff --git a/0009-conf-pcm-USB-Added-S-PDIF-fix-for-Asus-Xonar-SE.patch b/0009-conf-pcm-USB-Added-S-PDIF-fix-for-Asus-Xonar-SE.patch new file mode 100644 index 0000000..8e12634 --- /dev/null +++ b/0009-conf-pcm-USB-Added-S-PDIF-fix-for-Asus-Xonar-SE.patch @@ -0,0 +1,27 @@ +From a80606d1abfd3c2bccfa179c31af8b6e7c0a9031 Mon Sep 17 00:00:00 2001 +From: omar +Date: Mon, 20 Jul 2020 11:46:46 -0400 +Subject: [PATCH 09/32] conf: pcm - USB - Added S/PDIF fix for Asus Xonar SE + +Resolves #70 +From: omar +Signed-off-by: Jaroslav Kysela +--- + src/conf/cards/USB-Audio.conf | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/conf/cards/USB-Audio.conf b/src/conf/cards/USB-Audio.conf +index 01664abfc263..297629f34d77 100644 +--- a/src/conf/cards/USB-Audio.conf ++++ b/src/conf/cards/USB-Audio.conf +@@ -42,6 +42,7 @@ USB-Audio.pcm.iec958_device { + "ASUS XONAR U5" 1 + "XONAR U5" 1 + "XONAR SOUND CARD" 1 ++ "Xonar SoundCard" 2 + + # The below don't have digital in/out, so prevent them from being opened. + "Andrea PureAudio USB-SA Headset" 999 +-- +2.16.4 + diff --git a/0010-control-ctlparse-fix-enum-values-in-or.patch b/0010-control-ctlparse-fix-enum-values-in-or.patch new file mode 100644 index 0000000..ecef084 --- /dev/null +++ b/0010-control-ctlparse-fix-enum-values-in-or.patch @@ -0,0 +1,60 @@ +From a3ca4803cb8db73d01231c69620e2d18573ffba9 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Mon, 27 Jul 2020 13:18:20 +0200 +Subject: [PATCH 10/32] control: ctlparse - fix enum values in '' or "" + +This comit fixes the enum value string parser +(fixes aaf3a081bff1cc85635f7a3c3d4287c4addbbd84). + +BugLink: https://github.com/alsa-project/alsa-ucm-conf/pull/40 +Signed-off-by: Jaroslav Kysela +--- + src/control/ctlparse.c | 26 +++++++++++++++----------- + 1 file changed, 15 insertions(+), 11 deletions(-) + +diff --git a/src/control/ctlparse.c b/src/control/ctlparse.c +index ee1e0602cbf7..74f76cca9ca4 100644 +--- a/src/control/ctlparse.c ++++ b/src/control/ctlparse.c +@@ -282,23 +282,27 @@ static int get_ctl_enum_item_index(snd_ctl_t *handle, + if (items <= 0) + return -1; + ++ end = *ptr; ++ if (end == '\'' || end == '"') ++ ptr++; ++ else ++ end = '\0'; ++ + for (i = 0; i < items; i++) { + snd_ctl_elem_info_set_item(info, i); + if (snd_ctl_elem_info(handle, info) < 0) + return -1; + name = snd_ctl_elem_info_get_item_name(info); +- end = *ptr; +- if (end == '\'' || end == '"') +- ptr++; +- else +- end = '\0'; + len = strlen(name); +- if (strncmp(name, ptr, len) == 0) { +- if (ptr[len] == end || ptr[len] == ',' || ptr[len] == '\n') { +- ptr += len; +- *ptrp = ptr; +- return i; +- } ++ if (strncmp(name, ptr, len)) ++ continue; ++ if (end == '\0' && (ptr[len] == '\0' || ptr[len] == ',' || ptr[len] == '\n')) { ++ *ptrp = ptr + len; ++ return i; ++ } ++ if (end != '\0' && ptr[len] == end) { ++ *ptrp = ptr + len + 1; ++ return i; + } + } + return -1; +-- +2.16.4 + diff --git a/0011-conf-USB-Audio-Disable-IEC958-on-Lenovo-ThinkStation.patch b/0011-conf-USB-Audio-Disable-IEC958-on-Lenovo-ThinkStation.patch new file mode 100644 index 0000000..78fc871 --- /dev/null +++ b/0011-conf-USB-Audio-Disable-IEC958-on-Lenovo-ThinkStation.patch @@ -0,0 +1,31 @@ +From 464c2f8b61855cb22d61c4b232f74d6767fac5fb Mon Sep 17 00:00:00 2001 +From: Kai-Heng Feng +Date: Mon, 3 Aug 2020 23:57:45 +0800 +Subject: [PATCH 11/32] conf: USB-Audio: Disable IEC958 on Lenovo ThinkStation + P620 + +Both USB audio cards on Lenovo ThinkStation P620 don't support IEC958, +so disable IEC958 accordingly. + +Signed-off-by: Kai-Heng Feng +Signed-off-by: Takashi Iwai +--- + src/conf/cards/USB-Audio.conf | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/conf/cards/USB-Audio.conf b/src/conf/cards/USB-Audio.conf +index 297629f34d77..9b64af3c0da9 100644 +--- a/src/conf/cards/USB-Audio.conf ++++ b/src/conf/cards/USB-Audio.conf +@@ -63,6 +63,8 @@ USB-Audio.pcm.iec958_device { + "Scarlett 2i4 USB" 999 + "Sennheiser USB headset" 999 + "SWTOR Gaming Headset by Razer" 999 ++ "ThinkStation P620 Main" 999 ++ "ThinkStation P620 Rear" 999 + "Thunderbolt Dock Audio Headset" 999 + "Thunderbolt Dock Audio Module" 999 + "USB Device 0x46d_0x821" 999 +-- +2.16.4 + diff --git a/0012-pcm-dmix-fix-access-to-sum-buffer-in-non-interleaved.patch b/0012-pcm-dmix-fix-access-to-sum-buffer-in-non-interleaved.patch new file mode 100644 index 0000000..a4a8854 --- /dev/null +++ b/0012-pcm-dmix-fix-access-to-sum-buffer-in-non-interleaved.patch @@ -0,0 +1,92 @@ +From 82cb27c165d4337fe3183668bd0fa21ff6287e8e Mon Sep 17 00:00:00 2001 +From: Vijay Palaniswamy +Date: Thu, 23 Jul 2020 11:49:10 +0530 +Subject: [PATCH 12/32] pcm: dmix: fix access to sum-buffer in non-interleaved + mixing mode + +When dmix uses non-interleaved mixing mode the offset and step width +to sum_buffer was calculated by using the dmix channels instead of +the slave channels. This leads to audio distortions due to frame +corruption. + +example: +- With below configuratio, Do aplay on both device in parallel for +audio distortion + +pcm.dmix_2_channels { + type dmix + ipc_key 5678293 + ipc_perm 0660 + ipc_gid audio + bindings [0 1] + + slave { + pcm "hardware" + channels 2 + periods 4 + period_time 40000 + } +} + +pcm.dmix_1_channels { + type dmix + ipc_key 5678293 + ipc_perm 0660 + ipc_gid audio + bindings [0] + + slave { + pcm "hardware" + channels 1 + periods 4 + period_time 40000 + } +} + +pcm.hardware { + type hw + card 0 + channels 2 + rate 48000 + format S16_LE +} + +Signed-off-by: Vijay Palaniswamy +Signed-off-by: Takashi Iwai +--- + src/pcm/pcm_dmix.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c +index e9343b19a536..8bce7aca85f7 100644 +--- a/src/pcm/pcm_dmix.c ++++ b/src/pcm/pcm_dmix.c +@@ -212,10 +212,10 @@ static void mix_areas(snd_pcm_direct_t *dmix, + do_mix_areas(size, + ((unsigned char *)dst_areas[dchn].addr + dst_areas[dchn].first / 8) + dst_ofs * dst_step, + ((unsigned char *)src_areas[chn].addr + src_areas[chn].first / 8) + src_ofs * src_step, +- dmix->u.dmix.sum_buffer + channels * dst_ofs + chn, ++ dmix->u.dmix.sum_buffer + dmix->shmptr->s.channels * dst_ofs + dchn, + dst_step, + src_step, +- channels * sizeof(signed int)); ++ dmix->shmptr->s.channels * sizeof(signed int)); + } + } + +@@ -280,10 +280,10 @@ static void remix_areas(snd_pcm_direct_t *dmix, + do_remix_areas(size, + ((unsigned char *)dst_areas[dchn].addr + dst_areas[dchn].first / 8) + dst_ofs * dst_step, + ((unsigned char *)src_areas[chn].addr + src_areas[chn].first / 8) + src_ofs * src_step, +- dmix->u.dmix.sum_buffer + channels * dst_ofs + chn, ++ dmix->u.dmix.sum_buffer + dmix->shmptr->s.channels * dst_ofs + dchn, + dst_step, + src_step, +- channels * sizeof(signed int)); ++ dmix->shmptr->s.channels * sizeof(signed int)); + } + } + +-- +2.16.4 + diff --git a/0014-control-Add-documentation-for-snd_ctl_elem_list_.patch b/0014-control-Add-documentation-for-snd_ctl_elem_list_.patch new file mode 100644 index 0000000..6d4e8c4 --- /dev/null +++ b/0014-control-Add-documentation-for-snd_ctl_elem_list_.patch @@ -0,0 +1,278 @@ +From e097dd491a8f25418a90d38aea549bb4668de955 Mon Sep 17 00:00:00 2001 +From: "Tanjeff-N. Moos" +Date: Fri, 14 Aug 2020 08:40:28 +0200 +Subject: [PATCH 14/32] control: Add documentation for snd_ctl_elem_list_*. + +Signed-off-by: Tanjeff-N. Moos +Signed-off-by: Takashi Iwai +--- + include/control.h | 81 +++++++++++++++++++++++++++++++++++++++++++++++++-- + src/control/control.c | 80 +++++++++++++++++++++++++++++++++++++++++++------- + 2 files changed, 148 insertions(+), 13 deletions(-) + +diff --git a/include/control.h b/include/control.h +index 02db72d413ae..9deec6f3dee4 100644 +--- a/include/control.h ++++ b/include/control.h +@@ -56,7 +56,75 @@ typedef struct _snd_ctl_card_info snd_ctl_card_info_t; + /** CTL element identifier container */ + typedef struct _snd_ctl_elem_id snd_ctl_elem_id_t; + +-/** CTL element identifier list container */ ++/** CTL element list container ++ * ++ * This is a list of CTL elements. The list contains management ++ * information (e.g. how many elements the sound card has) as well as ++ * the element identifiers. All functions which operate on the list ++ * are named snd_ctl_elem_list_*(). ++ * ++ * \par Memory management ++ * ++ * There are two memory areas to deal with: The list container itself ++ * and the memory for the element identifiers. ++ * ++ * To manage the area for the list container, the following functions ++ * are used: ++ * ++ * - snd_ctl_elem_list_malloc() / snd_ctl_elem_list_free() to allocate ++ * and free memory on the heap, or ++ * - snd_ctl_elem_list_alloca() to allocate the memory on the ++ * stack. This memory is auto-released when the stack is unwound. ++ * ++ * To manage the space for the element identifiers, the ++ * snd_ctl_elem_list_alloc_space() and snd_ctl_elem_list_free_space() ++ * are used. Allocating the right amount of space can be achieved by ++ * first obtaining the number of elements and then calling ++ * snd_ctl_elem_list_alloc_space(): ++ * ++ * \code ++ * snd_ctl_elem_list_t* list; ++ * int count; ++ * ++ * // Initialise list ++ * snd_ctl_elem_list_malloc(&list); ++ * ++ * // Get number of elements ++ * snd_ctl_elem_list(ctl, list); ++ * count = snd_ctl_elem_list_get_count(list); ++ * ++ * // Allocate space for identifiers ++ * snd_ctl_elem_list_alloc_space(list, count); ++ * ++ * // Get identifiers ++ * snd_ctl_elem_list(ctl, list); // yes, this is same as above :) ++ * ++ * // Do something useful with the list... ++ * ++ * // Cleanup ++ * snd_ctl_elem_list_free_space(list); ++ * snd_ctl_elem_list_free(list); ++ * \endcode ++ * ++ * ++ * \par The Elements ++ * ++ * The elements in the list are accessed using an index. This index is ++ * the location in the list; Don't confuse it with the 'index' of the ++ * element identifier. For example: ++ * ++ * \code ++ * snd_ctl_elem_list_t list; ++ * unsigned int element_index; ++ * ++ * // Allocate space, fill list ... ++ * ++ * element_index = snd_ctl_elem_list_get_index(&list, 2); ++ * \endcode ++ * ++ * This will access the 3rd element in the list (index=2) and get the ++ * elements index from the driver (which might be 13, for example). ++ */ + typedef struct _snd_ctl_elem_list snd_ctl_elem_list_t; + + /** CTL element info container */ +@@ -354,11 +422,18 @@ void snd_ctl_event_copy(snd_ctl_event_t *dst, const snd_ctl_event_t *src); + snd_ctl_event_type_t snd_ctl_event_get_type(const snd_ctl_event_t *obj); + + size_t snd_ctl_elem_list_sizeof(void); ++ + /** \hideinitializer +- * \brief allocate an invalid #snd_ctl_elem_list_t using standard alloca +- * \param ptr returned pointer ++ * ++ * \brief Allocate a #snd_ctl_elem_list_t using standard alloca. ++ * ++ * The memory is allocated on the stack and will automatically be ++ * released when the stack unwinds (i.e. no free() is needed). ++ * ++ * \param ptr Pointer to allocated memory. + */ + #define snd_ctl_elem_list_alloca(ptr) __snd_alloca(ptr, snd_ctl_elem_list) ++ + int snd_ctl_elem_list_malloc(snd_ctl_elem_list_t **ptr); + void snd_ctl_elem_list_free(snd_ctl_elem_list_t *obj); + void snd_ctl_elem_list_clear(snd_ctl_elem_list_t *obj); +diff --git a/src/control/control.c b/src/control/control.c +index e21e8f1d2621..1bcf1ab2e431 100644 +--- a/src/control/control.c ++++ b/src/control/control.c +@@ -280,6 +280,21 @@ int snd_ctl_card_info(snd_ctl_t *ctl, snd_ctl_card_info_t *info) + + /** + * \brief Get a list of element identifiers ++ * ++ * Before calling this function, memoru must be allocated using ++ * snd_ctl_elem_list_malloc(). ++ * ++ * This function obtains data from the sound card driver and puts it ++ * into the list. ++ * ++ * If there was space allocated for the element identifiers (using ++ * snd_ctl_elem_list_alloc_space()), information will be filled in. If ++ * too little space was allocated, only a part of the elements will be ++ * queried. If there was too much space allocated, some of it remains ++ * unused. Use snd_ctl_elem_list_get_count() and ++ * snd_ctl_elem_list_get_used() to obtain information about space ++ * usage. See #snd_ctl_elem_list_t to learn more. ++ * + * \param ctl CTL handle + * \param list CTL element identifiers list pointer + * \return 0 on success otherwise a negative error code +@@ -1508,9 +1523,14 @@ const char *snd_ctl_event_type_name(snd_ctl_event_type_t type) + + /** + * \brief allocate space for CTL element identifiers list +- * \param obj CTL element identifiers list +- * \param entries Entries to allocate +- * \return 0 on success otherwise a negative error code ++ * ++ * The space can be released with snd_ctl_elem_list_free_space(). ++ * ++ * \param obj CTL element identifiers list. ++ * \param entries How many entries to allocate. See ++ * #snd_ctl_elem_list_t to learn how to obtain ++ * this number in advance. ++ * \return 0 on success otherwise a negative error code. + */ + int snd_ctl_elem_list_alloc_space(snd_ctl_elem_list_t *obj, unsigned int entries) + { +@@ -1526,6 +1546,10 @@ int snd_ctl_elem_list_alloc_space(snd_ctl_elem_list_t *obj, unsigned int entries + + /** + * \brief free previously allocated space for CTL element identifiers list ++ * ++ * Releases space previously allocated using ++ * snd_ctl_elem_list_alloc_space(). ++ * + * \param obj CTL element identifiers list + */ + void snd_ctl_elem_list_free_space(snd_ctl_elem_list_t *obj) +@@ -2016,7 +2040,7 @@ snd_ctl_event_type_t snd_ctl_event_get_type(const snd_ctl_event_t *obj) + } + + /** +- * \brief get size of #snd_ctl_elem_list_t ++ * \brief get size of #snd_ctl_elem_list_t. + * \return size in bytes + */ + size_t snd_ctl_elem_list_sizeof() +@@ -2025,7 +2049,10 @@ size_t snd_ctl_elem_list_sizeof() + } + + /** +- * \brief allocate an invalid #snd_ctl_elem_list_t using standard malloc ++ * \brief allocate a #snd_ctl_elem_list_t using standard malloc. ++ * ++ * The memory can be released using snd_ctl_elem_list_free(). ++ * + * \param ptr returned pointer + * \return 0 on success otherwise negative error code + */ +@@ -2039,7 +2066,15 @@ int snd_ctl_elem_list_malloc(snd_ctl_elem_list_t **ptr) + } + + /** +- * \brief frees a previously allocated #snd_ctl_elem_list_t ++ * \brief frees a previously allocated #snd_ctl_elem_list_t. ++ * ++ * Release memory previously allocated using ++ * snd_ctl_elem_list_malloc(). ++ * ++ * If you used snd_ctl_elem_list_alloc_space() on the list, you must ++ * use snd_ctl_elem_list_free_space() \em before calling this ++ * function. ++ * + * \param obj pointer to object to free + */ + void snd_ctl_elem_list_free(snd_ctl_elem_list_t *obj) +@@ -2048,7 +2083,15 @@ void snd_ctl_elem_list_free(snd_ctl_elem_list_t *obj) + } + + /** +- * \brief clear given #snd_ctl_elem_list_t object ++ * \brief Clear given #snd_ctl_elem_list_t object. ++ * ++ * This will make the stored identifiers inaccessible without freeing ++ * their space. ++ * ++ * \warning The element identifier space cannot be freed after calling ++ * this function. Therefore, snd_ctl_elem_list_free_space() ++ * must be called in advance. ++ * + * \param obj pointer to object to clear + */ + void snd_ctl_elem_list_clear(snd_ctl_elem_list_t *obj) +@@ -2057,7 +2100,11 @@ void snd_ctl_elem_list_clear(snd_ctl_elem_list_t *obj) + } + + /** +- * \brief copy one #snd_ctl_elem_list_t to another ++ * \brief copy one #snd_ctl_elem_list_t to another. ++ * ++ * This performs a shallow copy. That means the both lists will share ++ * the same space for the elements. The elements will not be copied. ++ * + * \param dst pointer to destination + * \param src pointer to source + */ +@@ -2080,6 +2127,12 @@ void snd_ctl_elem_list_set_offset(snd_ctl_elem_list_t *obj, unsigned int val) + + /** + * \brief Get number of used entries in CTL element identifiers list ++ * ++ * This function returns how many entries are actually filled with ++ * useful information. ++ * ++ * See also snd_ctl_elem_list_get_count(). ++ * + * \param obj CTL element identifier list + * \return number of used entries + */ +@@ -2090,7 +2143,14 @@ unsigned int snd_ctl_elem_list_get_used(const snd_ctl_elem_list_t *obj) + } + + /** +- * \brief Get total count of elements present in CTL device (information present in every filled CTL element identifiers list) ++ * \brief Get total count of elements present in CTL device ++ * ++ * This function returns how many entries were allocated using ++ * snd_ctl_elem_list_alloc_space(). This information is present after ++ * snd_ctl_elem_list() was called. ++ * ++ * See also snd_ctl_elem_list_get_used(). ++ * + * \param obj CTL element identifier list + * \return total number of elements + */ +@@ -2140,7 +2200,7 @@ snd_ctl_elem_iface_t snd_ctl_elem_list_get_interface(const snd_ctl_elem_list_t * + } + + /** +- * \brief Get device part of CTL element identifier for an entry of a CTL element identifiers list ++ * \brief Get the device part of CTL element identifier for an entry of a CTL element identifiers list + * \param obj CTL element identifier list + * \param idx Index of entry + * \return CTL element related device +-- +2.16.4 + diff --git a/0015-conf-quote-also-strings-with-and-characters-in-strin.patch b/0015-conf-quote-also-strings-with-and-characters-in-strin.patch new file mode 100644 index 0000000..ac737a9 --- /dev/null +++ b/0015-conf-quote-also-strings-with-and-characters-in-strin.patch @@ -0,0 +1,27 @@ +From ed752498522b0a99a9fbec99247d9c73b10abb3e Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Tue, 18 Aug 2020 16:53:23 +0200 +Subject: [PATCH 15/32] conf: quote also strings with '*' and '#' characters in + string_print() + +Signed-off-by: Jaroslav Kysela +--- + src/conf.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/conf.c b/src/conf.c +index 8518f90c5d60..7df2b4e77759 100644 +--- a/src/conf.c ++++ b/src/conf.c +@@ -1536,6 +1536,8 @@ static void string_print(char *str, int id, snd_output_t *out) + case ']': + case '\'': + case '"': ++ case '*': ++ case '#': + goto quoted; + default: + if (*p <= 31 || *p >= 127) +-- +2.16.4 + diff --git a/0016-topology-decode-Fix-channel-map-memory-allocation.patch b/0016-topology-decode-Fix-channel-map-memory-allocation.patch new file mode 100644 index 0000000..fc88125 --- /dev/null +++ b/0016-topology-decode-Fix-channel-map-memory-allocation.patch @@ -0,0 +1,54 @@ +From 1ac965184eaefe503939e454273223a1d8d32f41 Mon Sep 17 00:00:00 2001 +From: Piotr Maziarz +Date: Mon, 31 Aug 2020 11:08:54 +0200 +Subject: [PATCH 16/32] topology: decode: Fix channel map memory allocation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Memory allocated on the stack was referenced outside of the function scope +caused undefined behaviour. + +Signed-off-by: Piotr Maziarz +Reviewed-by: Cezary Rojewski +Reviewed-by: Amadeusz Sławiński +Reviewed-by: Pierre-Louis Bossart +Signed-off-by: Jaroslav Kysela +--- + src/topology/ctl.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/src/topology/ctl.c b/src/topology/ctl.c +index 90241b6318c5..6e6c1d163aa3 100644 +--- a/src/topology/ctl.c ++++ b/src/topology/ctl.c +@@ -1330,7 +1330,6 @@ int tplg_decode_control_enum1(snd_tplg_t *tplg, + void *bin, size_t size) + { + struct snd_soc_tplg_enum_control *ec = bin; +- struct snd_tplg_channel_map_template cmt; + int i; + + if (size < sizeof(*ec)) { +@@ -1375,11 +1374,13 @@ int tplg_decode_control_enum1(snd_tplg_t *tplg, + } + } + +- et->map = &cmt; +- memset(&cmt, 0, sizeof(cmt)); +- cmt.num_channels = ec->num_channels; +- for (i = 0; i < cmt.num_channels; i++) { +- struct snd_tplg_channel_elem *channel = &cmt.channel[i]; ++ et->map = tplg_calloc(heap, sizeof(struct snd_tplg_channel_map_template)); ++ if (!et->map) ++ return -ENOMEM; ++ et->map->num_channels = ec->num_channels; ++ for (i = 0; i < et->map->num_channels; i++) { ++ struct snd_tplg_channel_elem *channel = &et->map->channel[i]; ++ + tplg_log(tplg, 'D', pos + ((void *)&ec->channel[i] - (void *)ec), + "enum: channel size %d", ec->channel[i].size); + channel->reg = ec->channel[i].reg; +-- +2.16.4 + diff --git a/0017-topology-decode-Fix-infinite-loop-in-decoding-enum-c.patch b/0017-topology-decode-Fix-infinite-loop-in-decoding-enum-c.patch new file mode 100644 index 0000000..8e4ce01 --- /dev/null +++ b/0017-topology-decode-Fix-infinite-loop-in-decoding-enum-c.patch @@ -0,0 +1,36 @@ +From 346a5efa87c38a0d5ff9bd5b5d08be27b6c9bfaf Mon Sep 17 00:00:00 2001 +From: Piotr Maziarz +Date: Mon, 31 Aug 2020 11:08:55 +0200 +Subject: [PATCH 17/32] topology: decode: Fix infinite loop in decoding enum + control +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Accessing memory outside of allocated boundaries caused segmentation fault. + +Signed-off-by: Piotr Maziarz +Reviewed-by: Cezary Rojewski +Reviewed-by: Amadeusz Sławiński +Reviewed-by: Pierre-Louis Bossart +Signed-off-by: Jaroslav Kysela +--- + src/topology/ctl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/topology/ctl.c b/src/topology/ctl.c +index 6e6c1d163aa3..0aa49ab82c1e 100644 +--- a/src/topology/ctl.c ++++ b/src/topology/ctl.c +@@ -1367,7 +1367,7 @@ int tplg_decode_control_enum1(snd_tplg_t *tplg, + et->texts = tplg_calloc(heap, sizeof(char *) * ec->items); + if (!et->texts) + return -ENOMEM; +- for (i = 0; ec->items; i++) { ++ for (i = 0; i < ec->items; i++) { + unsigned int j = i * sizeof(int) * ENUM_VAL_SIZE; + et->texts[i] = ec->texts[i]; + et->values[i] = (int *)&ec->values[j]; +-- +2.16.4 + diff --git a/0018-topology-decode-Remove-decoding-values-for-enum-cont.patch b/0018-topology-decode-Remove-decoding-values-for-enum-cont.patch new file mode 100644 index 0000000..3dc3f47 --- /dev/null +++ b/0018-topology-decode-Remove-decoding-values-for-enum-cont.patch @@ -0,0 +1,42 @@ +From 11d4a5aa721dce2c3f7430996caf244a73dd5099 Mon Sep 17 00:00:00 2001 +From: Piotr Maziarz +Date: Mon, 31 Aug 2020 11:08:56 +0200 +Subject: [PATCH 18/32] topology: decode: Remove decoding values for enum + control +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Values have no representation in standard ALSA configuration files, +therefore there is no need to populate them. Also memory for values +wasn't allocated which was causing undefined behaviour. + +Signed-off-by: Piotr Maziarz +Reviewed-by: Cezary Rojewski +Reviewed-by: Amadeusz Sławiński +Reviewed-by: Pierre-Louis Bossart +Signed-off-by: Jaroslav Kysela +--- + src/topology/ctl.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/src/topology/ctl.c b/src/topology/ctl.c +index 0aa49ab82c1e..02e482e7d05d 100644 +--- a/src/topology/ctl.c ++++ b/src/topology/ctl.c +@@ -1367,11 +1367,8 @@ int tplg_decode_control_enum1(snd_tplg_t *tplg, + et->texts = tplg_calloc(heap, sizeof(char *) * ec->items); + if (!et->texts) + return -ENOMEM; +- for (i = 0; i < ec->items; i++) { +- unsigned int j = i * sizeof(int) * ENUM_VAL_SIZE; ++ for (i = 0; i < ec->items; i++) + et->texts[i] = ec->texts[i]; +- et->values[i] = (int *)&ec->values[j]; +- } + } + + et->map = tplg_calloc(heap, sizeof(struct snd_tplg_channel_map_template)); +-- +2.16.4 + diff --git a/0019-topology-decode-Add-enum-control-texts-as-separate-e.patch b/0019-topology-decode-Add-enum-control-texts-as-separate-e.patch new file mode 100644 index 0000000..ae1e1a4 --- /dev/null +++ b/0019-topology-decode-Add-enum-control-texts-as-separate-e.patch @@ -0,0 +1,50 @@ +From f1435207a2fbe35bf616c6d58eecd8801dbe5642 Mon Sep 17 00:00:00 2001 +From: Piotr Maziarz +Date: Mon, 31 Aug 2020 11:08:57 +0200 +Subject: [PATCH 19/32] topology: decode: Add enum control texts as separate + element +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Texts are separate sections that should referenced by enum control. + +Signed-off-by: Piotr Maziarz +Reviewed-by: Cezary Rojewski +Reviewed-by: Amadeusz Sławiński +Reviewed-by: Pierre-Louis Bossart +Signed-off-by: Jaroslav Kysela +--- + src/topology/ctl.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/src/topology/ctl.c b/src/topology/ctl.c +index 02e482e7d05d..1f3984616a65 100644 +--- a/src/topology/ctl.c ++++ b/src/topology/ctl.c +@@ -1088,11 +1088,19 @@ int tplg_add_enum(snd_tplg_t *tplg, struct snd_tplg_enum_template *enum_ctl, + } + + if (enum_ctl->texts != NULL) { ++ struct tplg_elem *texts = tplg_elem_new_common(tplg, NULL, ++ enum_ctl->hdr.name, SND_TPLG_TYPE_TEXT); ++ ++ texts->texts->num_items = num_items; + for (i = 0; i < num_items; i++) { +- if (enum_ctl->texts[i] != NULL) +- snd_strlcpy(ec->texts[i], enum_ctl->texts[i], +- SNDRV_CTL_ELEM_ID_NAME_MAXLEN); ++ if (!enum_ctl->texts[i]) ++ continue; ++ snd_strlcpy(ec->texts[i], enum_ctl->texts[i], ++ SNDRV_CTL_ELEM_ID_NAME_MAXLEN); ++ snd_strlcpy(texts->texts->items[i], enum_ctl->texts[i], ++ SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + } ++ tplg_ref_add(elem, SND_TPLG_TYPE_TEXT, enum_ctl->hdr.name); + } + + if (enum_ctl->values != NULL) { +-- +2.16.4 + diff --git a/0020-topology-decode-Fix-printing-texts-section.patch b/0020-topology-decode-Fix-printing-texts-section.patch new file mode 100644 index 0000000..c046797 --- /dev/null +++ b/0020-topology-decode-Fix-printing-texts-section.patch @@ -0,0 +1,33 @@ +From 56a096ca2ceaf1dec944258d961c274e6550b27a Mon Sep 17 00:00:00 2001 +From: Piotr Maziarz +Date: Mon, 31 Aug 2020 11:08:58 +0200 +Subject: [PATCH 20/32] topology: decode: Fix printing texts section +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Piotr Maziarz +Reviewed-by: Cezary Rojewski +Reviewed-by: Amadeusz Sławiński +Reviewed-by: Pierre-Louis Bossart +Signed-off-by: Jaroslav Kysela +--- + src/topology/text.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/topology/text.c b/src/topology/text.c +index 507c5450ab14..b899b2813ab4 100644 +--- a/src/topology/text.c ++++ b/src/topology/text.c +@@ -103,7 +103,7 @@ int tplg_save_text(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + return 0; + err = tplg_save_printf(dst, pfx, "'%s'.values [\n", elem->id); + for (i = 0; err >= 0 && i < texts->num_items; i++) +- err = tplg_save_printf(dst, pfx, "\t'%s'\n", texts->items[i][0]); ++ err = tplg_save_printf(dst, pfx, "\t'%s'\n", texts->items[i]); + if (err >= 0) + err = tplg_save_printf(dst, pfx, "]\n"); + return err; +-- +2.16.4 + diff --git a/0021-topology-decode-Change-declaration-of-enum-decoding-.patch b/0021-topology-decode-Change-declaration-of-enum-decoding-.patch new file mode 100644 index 0000000..b4e4bda --- /dev/null +++ b/0021-topology-decode-Change-declaration-of-enum-decoding-.patch @@ -0,0 +1,95 @@ +From c32498603aea7cc2f3fa3f850f9e4ea0f6ce03b2 Mon Sep 17 00:00:00 2001 +From: Piotr Maziarz +Date: Mon, 31 Aug 2020 11:08:59 +0200 +Subject: [PATCH 21/32] topology: decode: Change declaration of enum decoding + function +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Size constraints are always checked before invoking +tplg_decode_control_enum1. There is no need to validate it twice. +Alos moved debug print about size to invoking function, since now it's it +responsibility to check size. + +Signed-off-by: Piotr Maziarz +Reviewed-by: Cezary Rojewski +Reviewed-by: Amadeusz Sławiński +Reviewed-by: Pierre-Louis Bossart +Signed-off-by: Jaroslav Kysela +--- + src/topology/ctl.c | 19 +++++-------------- + src/topology/dapm.c | 3 +-- + src/topology/tplg_local.h | 2 +- + 3 files changed, 7 insertions(+), 17 deletions(-) + +diff --git a/src/topology/ctl.c b/src/topology/ctl.c +index 1f3984616a65..47db400fd4d1 100644 +--- a/src/topology/ctl.c ++++ b/src/topology/ctl.c +@@ -1335,22 +1335,10 @@ int tplg_decode_control_enum1(snd_tplg_t *tplg, + struct list_head *heap, + struct snd_tplg_enum_template *et, + size_t pos, +- void *bin, size_t size) ++ struct snd_soc_tplg_enum_control *ec) + { +- struct snd_soc_tplg_enum_control *ec = bin; + int i; + +- if (size < sizeof(*ec)) { +- SNDERR("enum: small size %d", size); +- return -EINVAL; +- } +- +- tplg_log(tplg, 'D', pos, "enum: size %d private size %d", +- ec->size, ec->priv.size); +- if (size != ec->size + ec->priv.size) { +- SNDERR("enum: unexpected element size %d", size); +- return -EINVAL; +- } + if (ec->num_channels > SND_TPLG_MAX_CHAN || + ec->num_channels > SND_SOC_TPLG_MAX_CHAN) { + SNDERR("enum: unexpected channel count %d", ec->num_channels); +@@ -1427,7 +1415,10 @@ next: + return -EINVAL; + } + +- err = tplg_decode_control_enum1(tplg, &heap, &et, pos, bin, size); ++ tplg_log(tplg, 'D', pos, "enum: size %d private size %d", ++ ec->size, ec->priv.size); ++ ++ err = tplg_decode_control_enum1(tplg, &heap, &et, pos, ec); + if (err >= 0) { + t.enum_ctl = &et; + err = snd_tplg_add_object(tplg, &t); +diff --git a/src/topology/dapm.c b/src/topology/dapm.c +index cd1a87704681..73a9390340c2 100644 +--- a/src/topology/dapm.c ++++ b/src/topology/dapm.c +@@ -972,8 +972,7 @@ next: + err = -EINVAL; + goto retval; + } +- err = tplg_decode_control_enum1(tplg, &heap, et, pos, +- bin, size2); ++ err = tplg_decode_control_enum1(tplg, &heap, et, pos, ec); + break; + case SND_SOC_TPLG_TYPE_BYTES: + bt = tplg_calloc(&heap, sizeof(*bt)); +diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h +index 5ace0d1919e1..acb01a831f30 100644 +--- a/src/topology/tplg_local.h ++++ b/src/topology/tplg_local.h +@@ -398,7 +398,7 @@ int tplg_decode_control_enum1(snd_tplg_t *tplg, + struct list_head *heap, + struct snd_tplg_enum_template *et, + size_t pos, +- void *bin, size_t size); ++ struct snd_soc_tplg_enum_control *ec); + int tplg_decode_control_enum(snd_tplg_t *tplg, size_t pos, + struct snd_soc_tplg_hdr *hdr, + void *bin, size_t size); +-- +2.16.4 + diff --git a/0022-topology-decode-Fix-decoding-PCM-formats-and-rates.patch b/0022-topology-decode-Fix-decoding-PCM-formats-and-rates.patch new file mode 100644 index 0000000..420eb18 --- /dev/null +++ b/0022-topology-decode-Fix-decoding-PCM-formats-and-rates.patch @@ -0,0 +1,46 @@ +From acbb0e3b1741107d01f03ee06f7819fd7f90bec4 Mon Sep 17 00:00:00 2001 +From: Piotr Maziarz +Date: Mon, 31 Aug 2020 11:09:00 +0200 +Subject: [PATCH 22/32] topology: decode: Fix decoding PCM formats and rates +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Not checking _LAST format and rate, which are valid indexes in arrays, +makes data loss while converting binary to standard ALSA configuration +file. + +Signed-off-by: Piotr Maziarz +Reviewed-by: Cezary Rojewski +Reviewed-by: Amadeusz Sławiński +Reviewed-by: Pierre-Louis Bossart +Signed-off-by: Jaroslav Kysela +--- + src/topology/pcm.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/topology/pcm.c b/src/topology/pcm.c +index b15b95045ab5..db401145f3ec 100644 +--- a/src/topology/pcm.c ++++ b/src/topology/pcm.c +@@ -549,7 +549,7 @@ int tplg_save_stream_caps(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + if (err >= 0 && sc->formats) { + err = tplg_save_printf(dst, pfx, "\tformats '"); + first = 1; +- for (i = 0; err >= 0 && i < SND_PCM_FORMAT_LAST; i++) { ++ for (i = 0; err >= 0 && i <= SND_PCM_FORMAT_LAST; i++) { + if (sc->formats & (1ULL << i)) { + s = snd_pcm_format_name(i); + err = tplg_save_printf(dst, NULL, "%s%s", +@@ -563,7 +563,7 @@ int tplg_save_stream_caps(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + if (err >= 0 && sc->rates) { + err = tplg_save_printf(dst, pfx, "\trates '"); + first = 1; +- for (i = 0; err >= 0 && i < SND_PCM_RATE_LAST; i++) { ++ for (i = 0; err >= 0 && i <= SND_PCM_RATE_LAST; i++) { + if (sc->rates & (1ULL << i)) { + s = get_rate_name(i); + err = tplg_save_printf(dst, NULL, "%s%s", +-- +2.16.4 + diff --git a/0023-topology-decode-Print-sig_bits-field-in-PCM-capabili.patch b/0023-topology-decode-Print-sig_bits-field-in-PCM-capabili.patch new file mode 100644 index 0000000..186960a --- /dev/null +++ b/0023-topology-decode-Print-sig_bits-field-in-PCM-capabili.patch @@ -0,0 +1,38 @@ +From d93b3462996a20951bc0ca753d0304bbbb9850fc Mon Sep 17 00:00:00 2001 +From: Piotr Maziarz +Date: Mon, 31 Aug 2020 11:09:01 +0200 +Subject: [PATCH 23/32] topology: decode: Print sig_bits field in PCM + capabilities section +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Not printing this field makes data loss while converting from binary +to standard ALSA configuration file. + +Signed-off-by: Piotr Maziarz +Reviewed-by: Cezary Rojewski +Reviewed-by: Amadeusz Sławiński +Reviewed-by: Pierre-Louis Bossart +Signed-off-by: Jaroslav Kysela +--- + src/topology/pcm.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/topology/pcm.c b/src/topology/pcm.c +index db401145f3ec..49c5eaba8b82 100644 +--- a/src/topology/pcm.c ++++ b/src/topology/pcm.c +@@ -604,6 +604,9 @@ int tplg_save_stream_caps(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + if (err >= 0 && sc->buffer_size_max) + err = tplg_save_printf(dst, pfx, "\tbuffer_size_max %u\n", + sc->buffer_size_max); ++ if (err >= 0 && sc->sig_bits) ++ err = tplg_save_printf(dst, pfx, "\tsig_bits %u\n", ++ sc->sig_bits); + if (err >= 0) + err = tplg_save_printf(dst, pfx, "}\n"); + return err; +-- +2.16.4 + diff --git a/0024-topology-decode-Add-DAI-name-printing.patch b/0024-topology-decode-Add-DAI-name-printing.patch new file mode 100644 index 0000000..7e083e1 --- /dev/null +++ b/0024-topology-decode-Add-DAI-name-printing.patch @@ -0,0 +1,38 @@ +From 6b0fb2bc7e0cfac8e1aedfcad183ab247c85173d Mon Sep 17 00:00:00 2001 +From: Piotr Maziarz +Date: Mon, 31 Aug 2020 11:09:02 +0200 +Subject: [PATCH 24/32] topology: decode: Add DAI name printing +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +DAI name is a part of topology binary. Not printing makes data loss while +converting from binary to standard ALSA configuration file. + +Signed-off-by: Piotr Maziarz +Reviewed-by: Cezary Rojewski +Reviewed-by: Amadeusz Sławiński +Reviewed-by: Pierre-Louis Bossart +Signed-off-by: Jaroslav Kysela +--- + src/topology/pcm.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/topology/pcm.c b/src/topology/pcm.c +index 49c5eaba8b82..5a54e1534c95 100644 +--- a/src/topology/pcm.c ++++ b/src/topology/pcm.c +@@ -781,7 +781,9 @@ int tplg_save_fe_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + struct snd_soc_tplg_pcm *pcm = elem->pcm; + int err = 0; + +- if (pcm->dai_id > 0) ++ if (strlen(pcm->dai_name)) ++ err = tplg_save_printf(dst, pfx, "dai.'%s'.id %u\n", pcm->dai_name, pcm->dai_id); ++ else if (pcm->dai_id > 0) + err = tplg_save_printf(dst, pfx, "dai.0.id %u\n", pcm->dai_id); + return err; + } +-- +2.16.4 + diff --git a/0025-topology-Make-buffer-for-saving-dynamic-size.patch b/0025-topology-Make-buffer-for-saving-dynamic-size.patch new file mode 100644 index 0000000..1071158 --- /dev/null +++ b/0025-topology-Make-buffer-for-saving-dynamic-size.patch @@ -0,0 +1,94 @@ +From d04e72c9a593015952e4858b92ab3f9d821560d9 Mon Sep 17 00:00:00 2001 +From: Piotr Maziarz +Date: Mon, 31 Aug 2020 11:09:03 +0200 +Subject: [PATCH 25/32] topology: Make buffer for saving dynamic size +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Some fields can exceed size limit, e.g. private data has no size +restriction. Therefore it needs to be dynamically increased. + +Signed-off-by: Piotr Maziarz +Reviewed-by: Cezary Rojewski +Reviewed-by: Amadeusz Sławiński +Reviewed-by: Pierre-Louis Bossart +Signed-off-by: Jaroslav Kysela +--- + src/topology/save.c | 34 +++++++++++++++++++++++++++++----- + 1 file changed, 29 insertions(+), 5 deletions(-) + +diff --git a/src/topology/save.c b/src/topology/save.c +index 4ecf86c3ade4..9c74735aea36 100644 +--- a/src/topology/save.c ++++ b/src/topology/save.c +@@ -19,22 +19,43 @@ + #include "tplg_local.h" + + #define SAVE_ALLOC_SHIFT (13) /* 8192 bytes */ ++#define PRINT_BUF_SIZE (1024) ++#define PRINT_BUF_SIZE_MAX (1024 * 1024) + + int tplg_save_printf(char **dst, const char *pfx, const char *fmt, ...) + { + va_list va; +- char buf[1024], *s; ++ char *buf, *s; + size_t n, l, t, pl; ++ int ret = 0; ++ ++ buf = malloc(PRINT_BUF_SIZE); ++ if (!buf) ++ return -ENOMEM; + + if (pfx == NULL) + pfx = ""; + + va_start(va, fmt); +- n = vsnprintf(buf, sizeof(buf), fmt, va); ++ n = vsnprintf(buf, PRINT_BUF_SIZE, fmt, va); + va_end(va); + +- if (n >= sizeof(buf)) +- return -EOVERFLOW; ++ if (n >= PRINT_BUF_SIZE_MAX) { ++ ret = -EOVERFLOW; ++ goto end; ++ } ++ ++ if (n >= PRINT_BUF_SIZE) { ++ char *tmp = realloc(buf, n + 1); ++ if (!tmp) { ++ ret = -ENOMEM; ++ goto end; ++ } ++ buf = tmp; ++ va_start(va, fmt); ++ n = vsnprintf(buf, n + 1, fmt, va); ++ va_end(va); ++ } + + pl = strlen(pfx); + l = *dst ? strlen(*dst) : 0; +@@ -47,7 +68,8 @@ int tplg_save_printf(char **dst, const char *pfx, const char *fmt, ...) + if (s == NULL) { + free(*dst); + *dst = NULL; +- return -ENOMEM; ++ ret = -ENOMEM; ++ goto end; + } + } else { + s = *dst; +@@ -57,6 +79,8 @@ int tplg_save_printf(char **dst, const char *pfx, const char *fmt, ...) + strcpy(s + l, pfx); + strcpy(s + l + pl, buf); + *dst = s; ++end: ++ free(buf); + return 0; + } + +-- +2.16.4 + diff --git a/0026-topology-return-correct-value-in-tplg_save_printf.patch b/0026-topology-return-correct-value-in-tplg_save_printf.patch new file mode 100644 index 0000000..1848b1f --- /dev/null +++ b/0026-topology-return-correct-value-in-tplg_save_printf.patch @@ -0,0 +1,26 @@ +From dc778bade60812a71b98ac827c2c6e3c02f14cf1 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Mon, 31 Aug 2020 13:21:26 +0200 +Subject: [PATCH 26/32] topology: return correct value in tplg_save_printf() + +Signed-off-by: Jaroslav Kysela +--- + src/topology/save.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/topology/save.c b/src/topology/save.c +index 9c74735aea36..16fd694638ef 100644 +--- a/src/topology/save.c ++++ b/src/topology/save.c +@@ -81,7 +81,7 @@ int tplg_save_printf(char **dst, const char *pfx, const char *fmt, ...) + *dst = s; + end: + free(buf); +- return 0; ++ return ret; + } + + int tplg_nice_value_format(char *dst, size_t dst_size, unsigned int value) +-- +2.16.4 + diff --git a/0027-topology-fix-some-gcc10-warnings-labs-signess.patch b/0027-topology-fix-some-gcc10-warnings-labs-signess.patch new file mode 100644 index 0000000..0386342 --- /dev/null +++ b/0027-topology-fix-some-gcc10-warnings-labs-signess.patch @@ -0,0 +1,40 @@ +From 6ca1ddfbcdf97ad46c3767ba314d1144119361fd Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Mon, 31 Aug 2020 13:25:01 +0200 +Subject: [PATCH 27/32] topology: fix some gcc10 warnings (labs, signess) + +Signed-off-by: Jaroslav Kysela +--- + src/topology/builder.c | 2 +- + src/topology/ctl.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/topology/builder.c b/src/topology/builder.c +index 15757668d7d4..f8aba830320e 100644 +--- a/src/topology/builder.c ++++ b/src/topology/builder.c +@@ -55,7 +55,7 @@ static ssize_t write_block_header(snd_tplg_t *tplg, unsigned int type, + " offset 0x%zx is %s by %ld bytes", + tplg->next_hdr_pos, tplg->bin_pos, + tplg->bin_pos > tplg->next_hdr_pos ? "ahead" : "behind", +- labs(tplg->bin_pos - tplg->next_hdr_pos)); ++ tplg->bin_pos - tplg->next_hdr_pos); + return -EINVAL; + } + +diff --git a/src/topology/ctl.c b/src/topology/ctl.c +index 47db400fd4d1..1d31b4944abf 100644 +--- a/src/topology/ctl.c ++++ b/src/topology/ctl.c +@@ -1363,7 +1363,7 @@ int tplg_decode_control_enum1(snd_tplg_t *tplg, + et->texts = tplg_calloc(heap, sizeof(char *) * ec->items); + if (!et->texts) + return -ENOMEM; +- for (i = 0; i < ec->items; i++) ++ for (i = 0; (unsigned int)i < ec->items; i++) + et->texts[i] = ec->texts[i]; + } + +-- +2.16.4 + diff --git a/0028-topology-fix-sort_config.patch b/0028-topology-fix-sort_config.patch new file mode 100644 index 0000000..77b0640 --- /dev/null +++ b/0028-topology-fix-sort_config.patch @@ -0,0 +1,48 @@ +From 84c6aeef5ca89c0686ae2a9ed90504010f8fe9e6 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Mon, 31 Aug 2020 14:25:56 +0200 +Subject: [PATCH 28/32] topology: fix sort_config() + +The temporary config array must be initialized for all compound types. + +Signed-off-by: Jaroslav Kysela +--- + src/topology/save.c | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +diff --git a/src/topology/save.c b/src/topology/save.c +index 16fd694638ef..631d84b273bf 100644 +--- a/src/topology/save.c ++++ b/src/topology/save.c +@@ -143,7 +143,6 @@ static snd_config_t *sort_config(const char *id, snd_config_t *src) + int index, array, count; + + if (snd_config_get_type(src) != SND_CONFIG_TYPE_COMPOUND) { +- + if (snd_config_copy(&dst, src) >= 0) + return dst; + return NULL; +@@ -155,14 +154,13 @@ static snd_config_t *sort_config(const char *id, snd_config_t *src) + if (a == NULL) + return NULL; + array = snd_config_is_array(src); +- if (array <= 0) { +- index = 0; +- snd_config_for_each(i, next, src) { +- snd_config_t *s = snd_config_iterator_entry(i); +- a[index++] = s; +- } +- qsort(a, count, sizeof(a[0]), _compar); ++ index = 0; ++ snd_config_for_each(i, next, src) { ++ snd_config_t *s = snd_config_iterator_entry(i); ++ a[index++] = s; + } ++ if (array <= 0) ++ qsort(a, count, sizeof(a[0]), _compar); + if (snd_config_make_compound(&dst, id, count == 1)) { + free(a); + return NULL; +-- +2.16.4 + diff --git a/0029-topology-fix-the-unaligned-access.patch b/0029-topology-fix-the-unaligned-access.patch new file mode 100644 index 0000000..020a7fe --- /dev/null +++ b/0029-topology-fix-the-unaligned-access.patch @@ -0,0 +1,159 @@ +From ab73253924ad8d46f94ab1212e0f05ebc2e3dcc5 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Mon, 31 Aug 2020 14:27:26 +0200 +Subject: [PATCH 29/32] topology: fix the unaligned access + +Introduce unaligned_get32/put32 helpers to deal with the +packed structures. + +Use the gcc __BYTE_ORDER__ defines for the endian checks. +It may be improved to support other compilation environment. + +Signed-off-by: Jaroslav Kysela +--- + src/topology/parser.c | 6 ++---- + src/topology/pcm.c | 26 ++++++++++++++------------ + src/topology/tplg_local.h | 13 +++++++++++++ + 3 files changed, 29 insertions(+), 16 deletions(-) + +diff --git a/src/topology/parser.c b/src/topology/parser.c +index 436e48416a43..f34de01bdc53 100644 +--- a/src/topology/parser.c ++++ b/src/topology/parser.c +@@ -427,10 +427,8 @@ void snd_tplg_verbose(snd_tplg_t *tplg, int verbose) + + static bool is_little_endian(void) + { +-#ifdef __BYTE_ORDER +- #if __BYTE_ORDER == __LITTLE_ENDIAN +- return true; +- #endif ++#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_INT__ == 4 ++ return true; + #endif + return false; + } +diff --git a/src/topology/pcm.c b/src/topology/pcm.c +index 5a54e1534c95..a60ba00d979a 100644 +--- a/src/topology/pcm.c ++++ b/src/topology/pcm.c +@@ -376,19 +376,19 @@ static int split_rate(struct snd_soc_tplg_stream_caps *caps, char *str) + return 0; + } + +-static int parse_unsigned(snd_config_t *n, unsigned int *dst) ++static int parse_unsigned(snd_config_t *n, void *dst) + { + int ival; + + if (tplg_get_integer(n, &ival, 0) < 0) + return -EINVAL; + +- *dst = ival; ++ unaligned_put32(dst, ival); + #if TPLG_DEBUG + { + const char *id; + if (snd_config_get_id(n, &id) >= 0) +- tplg_dbg("\t\t%s: %d", id, *dst); ++ tplg_dbg("\t\t%s: %d", id, ival); + } + #endif + return 0; +@@ -621,7 +621,7 @@ static int tplg_parse_streams(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + struct tplg_elem *elem = private; + struct snd_soc_tplg_pcm *pcm; + struct snd_soc_tplg_dai *dai; +- unsigned int *playback, *capture; ++ void *playback, *capture; + struct snd_soc_tplg_stream_caps *caps; + const char *id, *value; + int stream; +@@ -651,10 +651,10 @@ static int tplg_parse_streams(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + + if (strcmp(id, "playback") == 0) { + stream = SND_SOC_TPLG_STREAM_PLAYBACK; +- *playback = 1; ++ unaligned_put32(playback, 1); + } else if (strcmp(id, "capture") == 0) { + stream = SND_SOC_TPLG_STREAM_CAPTURE; +- *capture = 1; ++ unaligned_put32(capture, 1); + } else + return -EINVAL; + +@@ -747,6 +747,7 @@ static int tplg_parse_fe_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + snd_config_iterator_t i, next; + snd_config_t *n; + const char *id; ++ unsigned int dai_id; + + snd_config_get_id(cfg, &id); + tplg_dbg("\t\tFE DAI %s:", id); +@@ -761,12 +762,13 @@ static int tplg_parse_fe_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + continue; + + if (strcmp(id, "id") == 0) { +- if (tplg_get_unsigned(n, &pcm->dai_id, 0)) { ++ if (tplg_get_unsigned(n, &dai_id, 0)) { + SNDERR("invalid fe dai ID"); + return -EINVAL; + } + +- tplg_dbg("\t\t\tindex: %d", pcm->dai_id); ++ unaligned_put32(&pcm->dai_id, dai_id); ++ tplg_dbg("\t\t\tindex: %d", dai_id); + } + } + +@@ -790,7 +792,7 @@ int tplg_save_fe_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + + /* parse a flag bit of the given mask */ + static int parse_flag(snd_config_t *n, unsigned int mask_in, +- unsigned int *mask, unsigned int *flags) ++ void *mask, void *flags) + { + int ret; + +@@ -798,11 +800,11 @@ static int parse_flag(snd_config_t *n, unsigned int mask_in, + if (ret < 0) + return ret; + +- *mask |= mask_in; ++ unaligned_put32(mask, unaligned_get32(mask) | mask_in); + if (ret) +- *flags |= mask_in; ++ unaligned_put32(flags, unaligned_get32(flags) | mask_in); + else +- *flags &= ~mask_in; ++ unaligned_put32(flags, unaligned_get32(flags) & (~mask_in)); + + return 0; + } +diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h +index acb01a831f30..0c7be2001a63 100644 +--- a/src/topology/tplg_local.h ++++ b/src/topology/tplg_local.h +@@ -225,6 +225,19 @@ struct tplg_table { + extern struct tplg_table tplg_table[]; + extern unsigned int tplg_table_items; + ++#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ && __SIZEOF_INT__ == 4 ++static inline unsigned int unaligned_get32(void *src) ++{ ++ unsigned int ret; ++ memcpy(&ret, src, sizeof(ret)); ++ return ret; ++} ++static inline void unaligned_put32(void *dst, unsigned int val) ++{ ++ memcpy(dst, &val, sizeof(val)); ++} ++#endif ++ + #define tplg_log(tplg, type, pos, fmt, args...) do { \ + if ((tplg)->verbose) \ + tplg_log_((tplg), (type), (pos), (fmt), ##args); \ +-- +2.16.4 + diff --git a/0030-topology-improve-the-printf-buffer-management.patch b/0030-topology-improve-the-printf-buffer-management.patch new file mode 100644 index 0000000..3bae1bd --- /dev/null +++ b/0030-topology-improve-the-printf-buffer-management.patch @@ -0,0 +1,666 @@ +From 472ab5db67a0ed04de634214773e7b17d10b5415 Mon Sep 17 00:00:00 2001 +From: Jaroslav Kysela +Date: Mon, 31 Aug 2020 19:44:46 +0200 +Subject: [PATCH 30/32] topology: improve the printf buffer management + +The commit d04e72c9a593015952e4858b92ab3f9d821560d9 introduced +the dynamic printf buffer allocation for each tplg_save_printf() +call. + +Introduce 'struct tplg_buf' which carries extra information about +the temporary printf buffer and the destination buffer to save allocation +requests. + +The printf buffer is also allocated using 1024 bytes chunks. + +A comparison between 'alloc everyting' and 'cache+chunk alloc' for the +random picked topology file: + + 1: 18,620 allocs, 18,620 frees, 7,239,688 bytes allocated + 2: 12,490 allocs, 12,490 frees, 962,568 bytes allocated + +Signed-off-by: Jaroslav Kysela +--- + src/topology/channel.c | 3 +- + src/topology/ctl.c | 14 +++--- + src/topology/dapm.c | 5 ++- + src/topology/data.c | 15 ++++--- + src/topology/ops.c | 6 +-- + src/topology/pcm.c | 18 ++++---- + src/topology/save.c | 108 ++++++++++++++++++++++++++++------------------ + src/topology/text.c | 2 +- + src/topology/tplg_local.h | 56 +++++++++++++----------- + 9 files changed, 130 insertions(+), 97 deletions(-) + +diff --git a/src/topology/channel.c b/src/topology/channel.c +index 47d5ea4c419a..ebdff46968f6 100644 +--- a/src/topology/channel.c ++++ b/src/topology/channel.c +@@ -138,7 +138,8 @@ int tplg_parse_channel(snd_tplg_t *tplg, snd_config_t *cfg, + + int tplg_save_channels(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + struct snd_soc_tplg_channel *channel, +- unsigned int count, char **dst, const char *pfx) ++ unsigned int count, struct tplg_buf *dst, ++ const char *pfx) + { + struct snd_soc_tplg_channel *c; + const char *s; +diff --git a/src/topology/ctl.c b/src/topology/ctl.c +index 1d31b4944abf..a38399631c54 100644 +--- a/src/topology/ctl.c ++++ b/src/topology/ctl.c +@@ -105,8 +105,8 @@ int parse_access(snd_config_t *cfg, + + /* Save Access */ + static int tplg_save_access(snd_tplg_t *tplg ATTRIBUTE_UNUSED, +- struct snd_soc_tplg_ctl_hdr *hdr, char **dst, +- const char *pfx) ++ struct snd_soc_tplg_ctl_hdr *hdr, ++ struct tplg_buf *dst, const char *pfx) + { + const char *last; + unsigned int j, count, access, cval; +@@ -399,7 +399,7 @@ int tplg_parse_tlv(snd_tplg_t *tplg, snd_config_t *cfg, + /* save TLV data */ + int tplg_save_tlv(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + struct tplg_elem *elem, +- char **dst, const char *pfx) ++ struct tplg_buf *dst, const char *pfx) + { + struct snd_soc_tplg_ctl_tlv *tlv = elem->tlv; + struct snd_soc_tplg_tlv_dbscale *scale; +@@ -557,7 +557,7 @@ int tplg_parse_control_bytes(snd_tplg_t *tplg, + /* save control bytes */ + int tplg_save_control_bytes(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + struct tplg_elem *elem, +- char **dst, const char *pfx) ++ struct tplg_buf *dst, const char *pfx) + { + struct snd_soc_tplg_bytes_control *be = elem->bytes_ext; + char pfx2[16]; +@@ -697,7 +697,7 @@ int tplg_parse_control_enum(snd_tplg_t *tplg, snd_config_t *cfg, + /* save control eunm */ + int tplg_save_control_enum(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + struct tplg_elem *elem, +- char **dst, const char *pfx) ++ struct tplg_buf *dst, const char *pfx) + { + struct snd_soc_tplg_enum_control *ec = elem->enum_ctrl; + char pfx2[16]; +@@ -858,8 +858,8 @@ int tplg_parse_control_mixer(snd_tplg_t *tplg, + } + + int tplg_save_control_mixer(snd_tplg_t *tplg ATTRIBUTE_UNUSED, +- struct tplg_elem *elem, char **dst, +- const char *pfx) ++ struct tplg_elem *elem, ++ struct tplg_buf *dst, const char *pfx) + { + struct snd_soc_tplg_mixer_control *mc = elem->mixer_ctrl; + char pfx2[16]; +diff --git a/src/topology/dapm.c b/src/topology/dapm.c +index 73a9390340c2..46f2f8b3dae5 100644 +--- a/src/topology/dapm.c ++++ b/src/topology/dapm.c +@@ -416,7 +416,8 @@ int tplg_parse_dapm_graph(snd_tplg_t *tplg, snd_config_t *cfg, + } + + /* save DAPM graph */ +-int tplg_save_dapm_graph(snd_tplg_t *tplg, int index, char **dst, const char *pfx) ++int tplg_save_dapm_graph(snd_tplg_t *tplg, int index, ++ struct tplg_buf *dst, const char *pfx) + { + struct snd_soc_tplg_dapm_graph_elem *route; + struct list_head *pos; +@@ -669,7 +670,7 @@ int tplg_parse_dapm_widget(snd_tplg_t *tplg, + /* save DAPM widget */ + int tplg_save_dapm_widget(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + struct tplg_elem *elem, +- char **dst, const char *pfx) ++ struct tplg_buf *dst, const char *pfx) + { + struct snd_soc_tplg_dapm_widget *widget = elem->widget; + const char *s; +diff --git a/src/topology/data.c b/src/topology/data.c +index 5742b35773f6..3585af309499 100644 +--- a/src/topology/data.c ++++ b/src/topology/data.c +@@ -121,7 +121,8 @@ int tplg_parse_refs(snd_config_t *cfg, struct tplg_elem *elem, + /* save references */ + int tplg_save_refs(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + struct tplg_elem *elem, unsigned int type, +- const char *id, char **dst, const char *pfx) ++ const char *id, struct tplg_buf *dst, ++ const char *pfx) + { + struct tplg_ref *ref, *last; + struct list_head *pos; +@@ -890,7 +891,7 @@ err: + /* save tuple set */ + static int tplg_save_tuple_set(struct tplg_vendor_tuples *tuples, + unsigned int set_index, +- char **dst, const char *pfx) ++ struct tplg_buf *dst, const char *pfx) + { + struct tplg_tuple_set *set; + struct tplg_tuple *tuple; +@@ -1014,7 +1015,7 @@ static int parse_tuple_sets(snd_config_t *cfg, + /* save tuple sets */ + int tplg_save_tuple_sets(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + struct tplg_elem *elem, +- char **dst, const char *pfx) ++ struct tplg_buf *dst, const char *pfx) + { + struct tplg_vendor_tuples *tuples = elem->tuples; + unsigned int i; +@@ -1085,7 +1086,7 @@ int tplg_parse_tokens(snd_tplg_t *tplg, snd_config_t *cfg, + /* save vendor tokens */ + int tplg_save_tokens(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + struct tplg_elem *elem, +- char **dst, const char *pfx) ++ struct tplg_buf *dst, const char *pfx) + { + struct tplg_vendor_tokens *tokens = elem->tokens; + unsigned int i; +@@ -1156,7 +1157,7 @@ int tplg_parse_tuples(snd_tplg_t *tplg, snd_config_t *cfg, + /* save vendor tuples */ + int tplg_save_tuples(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + struct tplg_elem *elem, +- char **dst, const char *pfx) ++ struct tplg_buf *dst, const char *pfx) + { + char pfx2[16]; + int err; +@@ -1242,7 +1243,7 @@ int tplg_parse_manifest_data(snd_tplg_t *tplg, snd_config_t *cfg, + + /* save manifest data */ + int tplg_save_manifest_data(snd_tplg_t *tplg ATTRIBUTE_UNUSED, +- struct tplg_elem *elem, char **dst, ++ struct tplg_elem *elem, struct tplg_buf *dst, + const char *pfx) + { + struct list_head *pos; +@@ -1420,7 +1421,7 @@ int tplg_parse_data(snd_tplg_t *tplg, snd_config_t *cfg, + /* save data element */ + int tplg_save_data(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + struct tplg_elem *elem, +- char **dst, const char *pfx) ++ struct tplg_buf *dst, const char *pfx) + { + struct snd_soc_tplg_private *priv = elem->data; + struct list_head *pos; +diff --git a/src/topology/ops.c b/src/topology/ops.c +index 110eef58851d..da175608557a 100644 +--- a/src/topology/ops.c ++++ b/src/topology/ops.c +@@ -105,8 +105,8 @@ int tplg_parse_ops(snd_tplg_t *tplg ATTRIBUTE_UNUSED, snd_config_t *cfg, + + /* save control operations */ + int tplg_save_ops(snd_tplg_t *tplg ATTRIBUTE_UNUSED, +- struct snd_soc_tplg_ctl_hdr *hdr, char **dst, +- const char *pfx) ++ struct snd_soc_tplg_ctl_hdr *hdr, ++ struct tplg_buf *dst, const char *pfx) + { + const char *s; + int err; +@@ -191,7 +191,7 @@ int tplg_parse_ext_ops(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + /* save external control operations */ + int tplg_save_ext_ops(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + struct snd_soc_tplg_bytes_control *be, +- char **dst, const char *pfx) ++ struct tplg_buf *dst, const char *pfx) + { + const char *s; + int err; +diff --git a/src/topology/pcm.c b/src/topology/pcm.c +index a60ba00d979a..191b7a0a92da 100644 +--- a/src/topology/pcm.c ++++ b/src/topology/pcm.c +@@ -538,7 +538,7 @@ int tplg_parse_stream_caps(snd_tplg_t *tplg, + /* save stream caps */ + int tplg_save_stream_caps(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + struct tplg_elem *elem, +- char **dst, const char *pfx) ++ struct tplg_buf *dst, const char *pfx) + { + struct snd_soc_tplg_stream_caps *sc = elem->stream_caps; + const char *s; +@@ -686,7 +686,7 @@ static int tplg_parse_streams(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + /* Save the caps and config of a pcm stream */ + int tplg_save_streams(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + struct tplg_elem *elem, +- char **dst, const char *pfx) ++ struct tplg_buf *dst, const char *pfx) + { + static const char *stream_ids[2] = { + "playback", +@@ -778,7 +778,7 @@ static int tplg_parse_fe_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + /* Save the caps and config of a pcm stream */ + int tplg_save_fe_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + struct tplg_elem *elem, +- char **dst, const char *pfx) ++ struct tplg_buf *dst, const char *pfx) + { + struct snd_soc_tplg_pcm *pcm = elem->pcm; + int err = 0; +@@ -810,7 +810,7 @@ static int parse_flag(snd_config_t *n, unsigned int mask_in, + } + + static int save_flags(unsigned int flags, unsigned int mask, +- char **dst, const char *pfx) ++ struct tplg_buf *dst, const char *pfx) + { + static unsigned int flag_masks[3] = { + SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES, +@@ -944,7 +944,7 @@ int tplg_parse_pcm(snd_tplg_t *tplg, snd_config_t *cfg, + /* save PCM */ + int tplg_save_pcm(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + struct tplg_elem *elem, +- char **dst, const char *pfx) ++ struct tplg_buf *dst, const char *pfx) + { + struct snd_soc_tplg_pcm *pcm = elem->pcm; + char pfx2[16]; +@@ -1081,7 +1081,7 @@ int tplg_parse_dai(snd_tplg_t *tplg, snd_config_t *cfg, + /* save DAI */ + int tplg_save_dai(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + struct tplg_elem *elem, +- char **dst, const char *pfx) ++ struct tplg_buf *dst, const char *pfx) + { + struct snd_soc_tplg_dai *dai = elem->dai; + char pfx2[16]; +@@ -1235,7 +1235,7 @@ int tplg_parse_link(snd_tplg_t *tplg, snd_config_t *cfg, + /* save physical link */ + int tplg_save_link(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + struct tplg_elem *elem, +- char **dst, const char *pfx) ++ struct tplg_buf *dst, const char *pfx) + { + struct snd_soc_tplg_link_config *link = elem->link; + char pfx2[16]; +@@ -1315,7 +1315,7 @@ int tplg_parse_cc(snd_tplg_t *tplg, snd_config_t *cfg, + /* save CC */ + int tplg_save_cc(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + struct tplg_elem *elem, +- char **dst, const char *pfx) ++ struct tplg_buf *dst, const char *pfx) + { + struct snd_soc_tplg_link_config *link = elem->link; + char pfx2[16]; +@@ -1611,7 +1611,7 @@ int tplg_parse_hw_config(snd_tplg_t *tplg, snd_config_t *cfg, + /* save hw config */ + int tplg_save_hw_config(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + struct tplg_elem *elem, +- char **dst, const char *pfx) ++ struct tplg_buf *dst, const char *pfx) + { + struct snd_soc_tplg_hw_config *hc = elem->hw_cfg; + int err; +diff --git a/src/topology/save.c b/src/topology/save.c +index 631d84b273bf..56250af308b2 100644 +--- a/src/topology/save.c ++++ b/src/topology/save.c +@@ -19,25 +19,43 @@ + #include "tplg_local.h" + + #define SAVE_ALLOC_SHIFT (13) /* 8192 bytes */ +-#define PRINT_BUF_SIZE (1024) ++#define PRINT_ALLOC_SHIFT (10) /* 1024 bytes */ + #define PRINT_BUF_SIZE_MAX (1024 * 1024) ++#define NEXT_CHUNK(val, shift) ((((val) >> (shift)) + 1) << (shift)) + +-int tplg_save_printf(char **dst, const char *pfx, const char *fmt, ...) ++void tplg_buf_init(struct tplg_buf *buf) ++{ ++ buf->dst = NULL; ++ buf->dst_len = 0; ++ buf->printf_buf = NULL; ++ buf->printf_buf_size = 0; ++} ++ ++void tplg_buf_free(struct tplg_buf *buf) ++{ ++ free(buf->dst); ++ free(buf->printf_buf); ++} ++ ++char *tplg_buf_detach(struct tplg_buf *buf) ++{ ++ char *ret = buf->dst; ++ free(buf->printf_buf); ++ return ret; ++} ++ ++int tplg_save_printf(struct tplg_buf *dst, const char *pfx, const char *fmt, ...) + { + va_list va; +- char *buf, *s; ++ char *s; + size_t n, l, t, pl; + int ret = 0; + +- buf = malloc(PRINT_BUF_SIZE); +- if (!buf) +- return -ENOMEM; +- + if (pfx == NULL) + pfx = ""; + + va_start(va, fmt); +- n = vsnprintf(buf, PRINT_BUF_SIZE, fmt, va); ++ n = vsnprintf(dst->printf_buf, dst->printf_buf_size, fmt, va); + va_end(va); + + if (n >= PRINT_BUF_SIZE_MAX) { +@@ -45,42 +63,41 @@ int tplg_save_printf(char **dst, const char *pfx, const char *fmt, ...) + goto end; + } + +- if (n >= PRINT_BUF_SIZE) { +- char *tmp = realloc(buf, n + 1); +- if (!tmp) { ++ if (n >= dst->printf_buf_size) { ++ t = NEXT_CHUNK(n + 1, PRINT_ALLOC_SHIFT); ++ s = realloc(dst->printf_buf, t); ++ if (!s) { + ret = -ENOMEM; + goto end; + } +- buf = tmp; ++ dst->printf_buf = s; ++ dst->printf_buf_size = t; + va_start(va, fmt); +- n = vsnprintf(buf, n + 1, fmt, va); ++ n = vsnprintf(dst->printf_buf, n + 1, fmt, va); + va_end(va); + } + + pl = strlen(pfx); +- l = *dst ? strlen(*dst) : 0; ++ l = dst->dst_len; + t = l + pl + n + 1; + /* allocate chunks */ +- if (*dst == NULL || ++ if (dst->dst == NULL || + (l >> SAVE_ALLOC_SHIFT) != (t >> SAVE_ALLOC_SHIFT)) { +- s = realloc(*dst, ((t >> SAVE_ALLOC_SHIFT) + 1) << +- SAVE_ALLOC_SHIFT); ++ s = realloc(dst->dst, NEXT_CHUNK(t, SAVE_ALLOC_SHIFT)); + if (s == NULL) { +- free(*dst); +- *dst = NULL; + ret = -ENOMEM; + goto end; + } + } else { +- s = *dst; ++ s = dst->dst; + } + + if (pl > 0) + strcpy(s + l, pfx); +- strcpy(s + l + pl, buf); +- *dst = s; ++ strcpy(s + l + pl, dst->printf_buf); ++ dst->dst = s; ++ dst->dst_len = t - 1; + end: +- free(buf); + return ret; + } + +@@ -209,7 +226,7 @@ static int tplg_check_quoted(const unsigned char *p) + return 0; + } + +-static int tplg_save_quoted(char **dst, const char *str) ++static int tplg_save_quoted(struct tplg_buf *dst, const char *str) + { + static const char nibble[16] = "0123456789abcdef"; + unsigned char *p, *d, *t; +@@ -263,7 +280,7 @@ static int tplg_save_quoted(char **dst, const char *str) + return tplg_save_printf(dst, NULL, "'%s'", d); + } + +-static int tplg_save_string(char **dst, const char *str, int id) ++static int tplg_save_string(struct tplg_buf *dst, const char *str, int id) + { + const unsigned char *p = (const unsigned char *)str; + +@@ -279,7 +296,7 @@ static int tplg_save_string(char **dst, const char *str, int id) + return tplg_save_printf(dst, NULL, "%s", str); + } + +-static int save_config(char **dst, int level, const char *delim, snd_config_t *src) ++static int save_config(struct tplg_buf *dst, int level, const char *delim, snd_config_t *src) + { + snd_config_iterator_t i, next; + snd_config_t *s; +@@ -400,7 +417,8 @@ retval: + return 0; + } + +-static int tplg_save(snd_tplg_t *tplg, char **dst, int gindex, const char *prefix) ++static int tplg_save(snd_tplg_t *tplg, struct tplg_buf *dst, ++ int gindex, const char *prefix) + { + struct tplg_table *tptr; + struct tplg_elem *elem; +@@ -484,8 +502,6 @@ static int tplg_save(snd_tplg_t *tplg, char **dst, int gindex, const char *prefi + return 0; + + _err: +- free(*dst); +- *dst = NULL; + return err; + } + +@@ -540,9 +556,9 @@ static int tplg_index_groups(snd_tplg_t *tplg, int **indexes) + + int snd_tplg_save(snd_tplg_t *tplg, char **dst, int flags) + { ++ struct tplg_buf buf, buf2; + snd_input_t *in; + snd_config_t *top, *top2; +- char *dst2; + int *indexes, *a; + int err; + +@@ -550,35 +566,41 @@ int snd_tplg_save(snd_tplg_t *tplg, char **dst, int flags) + assert(dst); + *dst = NULL; + ++ tplg_buf_init(&buf); ++ + if (flags & SND_TPLG_SAVE_GROUPS) { + err = tplg_index_groups(tplg, &indexes); + if (err < 0) + return err; + for (a = indexes; err >= 0 && *a >= 0; a++) { +- err = tplg_save_printf(dst, NULL, ++ err = tplg_save_printf(&buf, NULL, + "IndexGroup.%d {\n", + *a); + if (err >= 0) +- err = tplg_save(tplg, dst, *a, "\t"); ++ err = tplg_save(tplg, &buf, *a, "\t"); + if (err >= 0) +- err = tplg_save_printf(dst, NULL, "}\n"); ++ err = tplg_save_printf(&buf, NULL, "}\n"); + } + free(indexes); + } else { +- err = tplg_save(tplg, dst, -1, NULL); ++ err = tplg_save(tplg, &buf, -1, NULL); + } + + if (err < 0) + goto _err; + +- if (*dst == NULL) +- return -EINVAL; ++ if (buf.dst == NULL) { ++ err = -EINVAL; ++ goto _err; ++ } + +- if (flags & SND_TPLG_SAVE_NOCHECK) ++ if (flags & SND_TPLG_SAVE_NOCHECK) { ++ *dst = tplg_buf_detach(&buf); + return 0; ++ } + + /* always load configuration - check */ +- err = snd_input_buffer_open(&in, *dst, strlen(*dst)); ++ err = snd_input_buffer_open(&in, buf.dst, strlen(buf.dst)); + if (err < 0) { + SNDERR("could not create input buffer"); + goto _err; +@@ -610,20 +632,20 @@ int snd_tplg_save(snd_tplg_t *tplg, char **dst, int flags) + top = top2; + } + +- dst2 = NULL; +- err = save_config(&dst2, 0, NULL, top); ++ tplg_buf_init(&buf2); ++ err = save_config(&buf2, 0, NULL, top); + snd_config_delete(top); + if (err < 0) { + SNDERR("could not save configuration"); + goto _err; + } + +- free(*dst); +- *dst = dst2; ++ tplg_buf_free(&buf); ++ *dst = tplg_buf_detach(&buf2); + return 0; + + _err: +- free(*dst); ++ tplg_buf_free(&buf); + *dst = NULL; + return err; + } +diff --git a/src/topology/text.c b/src/topology/text.c +index b899b2813ab4..b07feb999db9 100644 +--- a/src/topology/text.c ++++ b/src/topology/text.c +@@ -93,7 +93,7 @@ int tplg_parse_text(snd_tplg_t *tplg, snd_config_t *cfg, + /* save text data */ + int tplg_save_text(snd_tplg_t *tplg ATTRIBUTE_UNUSED, + struct tplg_elem *elem, +- char **dst, const char *pfx) ++ struct tplg_buf *dst, const char *pfx) + { + struct tplg_texts *texts = elem->texts; + unsigned int i; +diff --git a/src/topology/tplg_local.h b/src/topology/tplg_local.h +index 0c7be2001a63..d553117e2333 100644 +--- a/src/topology/tplg_local.h ++++ b/src/topology/tplg_local.h +@@ -200,6 +200,14 @@ struct map_elem { + int id; + }; + ++/* output buffer */ ++struct tplg_buf { ++ char *dst; ++ size_t dst_len; ++ char *printf_buf; ++ size_t printf_buf_size; ++}; ++ + /* mapping table */ + struct tplg_table { + const char *name; +@@ -214,9 +222,9 @@ struct tplg_table { + void (*free)(void *); + int (*parse)(snd_tplg_t *tplg, snd_config_t *cfg, void *priv); + int (*save)(snd_tplg_t *tplg, struct tplg_elem *elem, +- char **dst, const char *prefix); ++ struct tplg_buf *dst, const char *prefix); + int (*gsave)(snd_tplg_t *tplg, int index, +- char **dst, const char *prefix); ++ struct tplg_buf *dst, const char *prefix); + int (*decod)(snd_tplg_t *tplg, size_t pos, + struct snd_soc_tplg_hdr *hdr, + void *bin, size_t size); +@@ -348,49 +356,49 @@ int tplg_add_dai_object(snd_tplg_t *tplg, snd_tplg_obj_template_t *t); + + int tplg_nice_value_format(char *dst, size_t dst_size, unsigned int value); + +-int tplg_save_printf(char **dst, const char *prefix, const char *fmt, ...); ++int tplg_save_printf(struct tplg_buf *dst, const char *prefix, const char *fmt, ...); + int tplg_save_refs(snd_tplg_t *tplg, struct tplg_elem *elem, unsigned int type, +- const char *id, char **dst, const char *pfx); ++ const char *id, struct tplg_buf *dst, const char *pfx); + int tplg_save_channels(snd_tplg_t *tplg, struct snd_soc_tplg_channel *channel, +- unsigned int channel_count, char **dst, const char *pfx); ++ unsigned int channel_count, struct tplg_buf *dst, const char *pfx); + int tplg_save_ops(snd_tplg_t *tplg, struct snd_soc_tplg_ctl_hdr *hdr, +- char **dst, const char *pfx); ++ struct tplg_buf *dst, const char *pfx); + int tplg_save_ext_ops(snd_tplg_t *tplg, struct snd_soc_tplg_bytes_control *be, +- char **dst, const char *pfx); ++ struct tplg_buf *dst, const char *pfx); + int tplg_save_manifest_data(snd_tplg_t *tplg, struct tplg_elem *elem, +- char **dst, const char *pfx); ++ struct tplg_buf *dst, const char *pfx); + int tplg_save_control_mixer(snd_tplg_t *tplg, struct tplg_elem *elem, +- char **dst, const char *pfx); ++ struct tplg_buf *dst, const char *pfx); + int tplg_save_control_enum(snd_tplg_t *tplg, struct tplg_elem *elem, +- char **dst, const char *pfx); ++ struct tplg_buf *dst, const char *pfx); + int tplg_save_control_bytes(snd_tplg_t *tplg, struct tplg_elem *elem, +- char **dst, const char *pfx); ++ struct tplg_buf *dst, const char *pfx); + int tplg_save_tlv(snd_tplg_t *tplg, struct tplg_elem *elem, +- char **dst, const char *pfx); ++ struct tplg_buf *dst, const char *pfx); + int tplg_save_data(snd_tplg_t *tplg, struct tplg_elem *elem, +- char **dst, const char *pfx); ++ struct tplg_buf *dst, const char *pfx); + int tplg_save_text(snd_tplg_t *tplg, struct tplg_elem *elem, +- char **dst, const char *pfx); ++ struct tplg_buf *dst, const char *pfx); + int tplg_save_tokens(snd_tplg_t *tplg, struct tplg_elem *elem, +- char **dst, const char *pfx); ++ struct tplg_buf *dst, const char *pfx); + int tplg_save_tuples(snd_tplg_t *tplg, struct tplg_elem *elem, +- char **dst, const char *pfx); ++ struct tplg_buf *dst, const char *pfx); + int tplg_save_dapm_graph(snd_tplg_t *tplg, int index, +- char **dst, const char *pfx); ++ struct tplg_buf *dst, const char *pfx); + int tplg_save_dapm_widget(snd_tplg_t *tplg, struct tplg_elem *elem, +- char **dst, const char *pfx); ++ struct tplg_buf *dst, const char *pfx); + int tplg_save_link(snd_tplg_t *tplg, struct tplg_elem *elem, +- char **dst, const char *pfx); ++ struct tplg_buf *dst, const char *pfx); + int tplg_save_cc(snd_tplg_t *tplg, struct tplg_elem *elem, +- char **dst, const char *pfx); ++ struct tplg_buf *dst, const char *pfx); + int tplg_save_pcm(snd_tplg_t *tplg, struct tplg_elem *elem, +- char **dst, const char *pfx); ++ struct tplg_buf *dst, const char *pfx); + int tplg_save_hw_config(snd_tplg_t *tplg, struct tplg_elem *elem, +- char **dst, const char *pfx); ++ struct tplg_buf *dst, const char *pfx); + int tplg_save_stream_caps(snd_tplg_t *tplg, struct tplg_elem *elem, +- char **dst, const char *pfx); ++ struct tplg_buf *dst, const char *pfx); + int tplg_save_dai(snd_tplg_t *tplg, struct tplg_elem *elem, +- char **dst, const char *pfx); ++ struct tplg_buf *dst, const char *pfx); + + int tplg_decode_template(snd_tplg_t *tplg, + size_t pos, +-- +2.16.4 + diff --git a/0031-control-Improve-general-control-interface-documentat.patch b/0031-control-Improve-general-control-interface-documentat.patch new file mode 100644 index 0000000..a65dc12 --- /dev/null +++ b/0031-control-Improve-general-control-interface-documentat.patch @@ -0,0 +1,111 @@ +From 84185b5c94ec8a214103b8ec02d272f0158c24e6 Mon Sep 17 00:00:00 2001 +From: "Tanjeff-N. Moos" +Date: Wed, 2 Sep 2020 11:27:26 +0200 +Subject: [PATCH 31/32] control: Improve general control interface + documentation. + +Signed-off-by: Tanjeff-N. Moos +Signed-off-by: Takashi Iwai +--- + src/control/control.c | 72 ++++++++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 63 insertions(+), 9 deletions(-) + +diff --git a/src/control/control.c b/src/control/control.c +index 1bcf1ab2e431..497a5399b7e6 100644 +--- a/src/control/control.c ++++ b/src/control/control.c +@@ -31,7 +31,7 @@ + /*! \page control Control interface + +

    Control interface is designed to access primitive controls. There is +-also interface notifying about control and structure changes. ++also an interface for notifying about control and structure changes. + + \section control_general_overview General overview + +@@ -43,20 +43,74 @@ are managed according to below model. + Some element sets can be added to a sound card by drivers in kernel and + userspace applications. + - element +- - An element can be identified by userspace applications. Each element has +- own identical information. ++ - A control element might be a master volume control, for example, or a ++ read-only indicator, such as a sync status. An element has a type (e.g. ++ INTEGER or BOOLEAN) and - depending on the type - min/max values, a step ++ size, a set of possible values (for enums), etc. + - member +- - An element includes some members to have a value. The value of each member +- can be changed by both of userspace applications and drivers in kernel. + +-Each element can be identified by two ways; the numerical number (numid), or the +-combination of interface, device, subdevice, name, and index. ++ - An element includes one or more member(s) to have a value. For ++ example, a stereo volume control element has two members (for ++ left/right). The members share the same properties (e.g. both ++ volume controls have the same min/max values). The value of each ++ member can be changed by both of userspace applications and ++ drivers in kernel. + +-The type of element set is one of integer, integerr64, boolean, enumerators, ++ ++\section identifying_elements Identifying the Elements ++ ++Each element has the following identifying properties: ++ ++ - The numid (a numeric identifier, assigned when the sound card is ++ detected, constant while the sound card is kept connected) ++ ++ - The interface type (e.g. MIXER, CARD or PCM) ++ - The device ++ - The subdevice ++ - Its name ++ - Its index ++ ++An element can be identified either by its numid or by the tuple ++(interface type, device, subdevice, name, index). This tuple is always ++the same (driver updates can change it, but in practice this is ++rare). The numid can change on each boot. In case of an USB sound ++card, the numid can also change when it is reconnected. ++ ++ ++\section element_lists Element Lists ++ ++An element list can be used to obtain a list of all elements of the ++sound card. The list contains generic information (e.g. how many ++elements the card has), and the identifying properties of the elements ++(numid, card, name, ...). See #snd_ctl_elem_list_t to learn more about ++element lists. ++ ++ ++\section working_with_elements Working with Elements ++ ++It is possible to obtain information about an element using the ++snd_ctl_elem_info_*() functions. For enums, the allowed values can be ++obtained, for integers, the min/max values can be obtained, and so ++on. In addition, these functions can report the identifying ++properties. E.g. when the element is addressed using its numid, the ++functions complements the name, index, etc. ++ ++To access the values of a control, use the snd_ctl_elem_value*() ++functions. These allow to get and set the actual values or ++settings. It is also possible to get and set the ID values (such as ++the numid or the name). ++ ++ ++\section element_sets Element Sets ++ ++The type of element set is one of integer, integer64, boolean, enumerators, + bytes and IEC958 structure. This indicates the type of value for each member in + elements included in the element set. + +-When the value of member is changed, corresponding events are transferred to ++ ++\section events Events ++ ++When the value of a member is changed, corresponding events are transferred to + userspace applications. The applications should subscribe any events in advance. + + \section tlv_blob Supplemental data for elements in an element set +-- +2.16.4 + diff --git a/0032-control-Add-documentation-for-snd_ctl_elem_value_.patch b/0032-control-Add-documentation-for-snd_ctl_elem_value_.patch new file mode 100644 index 0000000..cb7f4d3 --- /dev/null +++ b/0032-control-Add-documentation-for-snd_ctl_elem_value_.patch @@ -0,0 +1,828 @@ +From c1e72460de5ddcfdc8b93e73952c6fe9d6f60591 Mon Sep 17 00:00:00 2001 +From: "Tanjeff-N. Moos" +Date: Wed, 2 Sep 2020 11:27:27 +0200 +Subject: [PATCH 32/32] control: Add documentation for snd_ctl_elem_value_*. + +Signed-off-by: Tanjeff-N. Moos +Signed-off-by: Takashi Iwai +--- + include/control.h | 61 ++++++- + src/control/control.c | 454 +++++++++++++++++++++++++++++++++----------------- + 2 files changed, 357 insertions(+), 158 deletions(-) + +diff --git a/include/control.h b/include/control.h +index 9deec6f3dee4..8766f44097ea 100644 +--- a/include/control.h ++++ b/include/control.h +@@ -130,7 +130,53 @@ typedef struct _snd_ctl_elem_list snd_ctl_elem_list_t; + /** CTL element info container */ + typedef struct _snd_ctl_elem_info snd_ctl_elem_info_t; + +-/** CTL element value container */ ++/** CTL element value container ++ * ++ * Contains the value(s) (i.e. members) of a single element. All ++ * values of a given element are of the same type. ++ * ++ * \par Memory management ++ * ++ * To access a value, a snd_ctl_elem_value_t must be allocated using ++ * snd_ctl_elem_value_alloca() or snd_ctl_elem_value_malloc(). When ++ * using the latter, it must be freed again using ++ * snd_ctl_elem_value_free(). ++ * ++ * \par Identifier ++ * ++ * Then, the ID must be filled. It is sufficient to fill only the ++ * numid, if known. Otherwise, interface type, device, subdevice, ++ * name, index must all be given. The following functions can be used ++ * to fill the ID: ++ * ++ * - snd_ctl_elem_value_set_id(): Set the ID. Requires an ++ * snd_ctl_elem_id_t object. ++ * - snd_ctl_elem_value_set_numid(): Set the numid. ++ * - Or use all of the following: ++ * ++ * - snd_ctl_elem_value_set_interface() ++ * - snd_ctl_elem_value_set_device() ++ * - snd_ctl_elem_value_set_subdevice() ++ * - snd_ctl_elem_value_set_name() ++ * - snd_ctl_elem_value_set_index() ++ * ++ * When communicating with the driver (snd_ctl_elem_read(), ++ * snd_ctl_elem_write()), and the numid was given, the interface, ++ * device, ... are filled (even if you set the before). When the numid ++ * is unset (i.e. it is 0), it is filled. ++ * ++ * \par Communicating with the driver ++ * ++ * After the value container was created and filled with the ID of the ++ * desired element, the value(s) can be fetched from the driver (and ++ * thus from the hardware) or written to the driver. ++ * ++ * To fetch a value, use snd_ctl_elem_read(). Thereafter, use the ++ * snd_ctl_elem_value_get_*() functions to obtain the actual value. ++ * ++ * To write a new value, first use a snd_ctl_elem_value_set_*() to set ++ * it, then call snd_ctl_elem_write() to write it to the driver. ++ */ + typedef struct _snd_ctl_elem_value snd_ctl_elem_value_t; + + /** CTL event container */ +@@ -529,11 +575,20 @@ int snd_ctl_elem_add_iec958(snd_ctl_t *ctl, const snd_ctl_elem_id_t *id); + int snd_ctl_elem_remove(snd_ctl_t *ctl, snd_ctl_elem_id_t *id); + + size_t snd_ctl_elem_value_sizeof(void); ++ + /** \hideinitializer +- * \brief allocate an invalid #snd_ctl_elem_value_t using standard alloca +- * \param ptr returned pointer ++ * \brief Allocate an invalid #snd_ctl_elem_value_t on the stack. ++ * ++ * Allocate space for a value object on the stack. The allocated ++ * memory need not be freed, because is on the stack. ++ * ++ * See snd_ctl_elem_value_t for details. ++ * ++ * \param ptr Pointer to a snd_ctl_elem_value_t pointer. The address ++ * of the allocated space will returned here. + */ + #define snd_ctl_elem_value_alloca(ptr) __snd_alloca(ptr, snd_ctl_elem_value) ++ + int snd_ctl_elem_value_malloc(snd_ctl_elem_value_t **ptr); + void snd_ctl_elem_value_free(snd_ctl_elem_value_t *obj); + void snd_ctl_elem_value_clear(snd_ctl_elem_value_t *obj); +diff --git a/src/control/control.c b/src/control/control.c +index 497a5399b7e6..08058c067e28 100644 +--- a/src/control/control.c ++++ b/src/control/control.c +@@ -38,32 +38,39 @@ also an interface for notifying about control and structure changes. + In ALSA control feature, each sound card can have control elements. The elements + are managed according to below model. + +- - element set ++ - Element set ++ + - A set of elements with the same attribute (i.e. name, get/put operations). + Some element sets can be added to a sound card by drivers in kernel and + userspace applications. +- - element ++ ++ - Element ++ + - A control element might be a master volume control, for example, or a + read-only indicator, such as a sync status. An element has a type (e.g. +- INTEGER or BOOLEAN) and - depending on the type - min/max values, a step +- size, a set of possible values (for enums), etc. +- - member ++ SNDRV_CTL_ELEM_TYPE_INTEGER or SNDRV_CTL_ELEM_TYPE_BOOLEAN) and - depending ++ on the type - min/max values, a step size, a set of possible values (for ++ enums), etc. ++ ++ - Member + +- - An element includes one or more member(s) to have a value. For +- example, a stereo volume control element has two members (for +- left/right). The members share the same properties (e.g. both +- volume controls have the same min/max values). The value of each +- member can be changed by both of userspace applications and +- drivers in kernel. ++ - An element usually includes one or more member(s) to have a value. For ++ example, a stereo volume control element has two members (for left/right), ++ while a mono volume has only one member. The member count can be obtained ++ using snd_ctl_elem_info_get_count(). Elements of type ++ "SNDRV_CTL_ELEM_TYPE_BYTES" or "SNDRV_CTL_ELEM_TYPE_IEC958" have no members ++ at all (and thus no member count), they have just a single value. The ++ members share the same properties (e.g. both volume control members have ++ the same min/max values). The value of each member can be changed by both ++ of userspace applications and drivers in kernel. + + +-\section identifying_elements Identifying the Elements ++\section identifying_elements Identifying Elements + + Each element has the following identifying properties: + + - The numid (a numeric identifier, assigned when the sound card is + detected, constant while the sound card is kept connected) +- + - The interface type (e.g. MIXER, CARD or PCM) + - The device + - The subdevice +@@ -95,10 +102,10 @@ on. In addition, these functions can report the identifying + properties. E.g. when the element is addressed using its numid, the + functions complements the name, index, etc. + +-To access the values of a control, use the snd_ctl_elem_value*() +-functions. These allow to get and set the actual values or +-settings. It is also possible to get and set the ID values (such as +-the numid or the name). ++To access the members (i.e. values) of a control, use the ++snd_ctl_elem_value*() functions. These allow to get and set the ++actual values or settings. It is also possible to get and set the ID ++values (such as the numid or the name). + + + \section element_sets Element Sets +@@ -931,10 +938,19 @@ int snd_ctl_elem_remove(snd_ctl_t *ctl, snd_ctl_elem_id_t *id) + } + + /** +- * \brief Get CTL element value +- * \param ctl CTL handle +- * \param data Data of an element. +- * \return 0 on success otherwise a negative error code ++ * \brief Get CTL element value. ++ * ++ * Read information from sound card. You must set the ID of the ++ * element before calling this function. ++ * ++ * See snd_ctl_elem_value_t for details. ++ * ++ * \param ctl CTL handle. ++ * \param data The element value. The ID must be set before calling ++ * the function, and the actual value will be returned ++ * here. ++ * ++ * \return 0 on success otherwise a negative error code. + */ + int snd_ctl_elem_read(snd_ctl_t *ctl, snd_ctl_elem_value_t *data) + { +@@ -943,9 +959,16 @@ int snd_ctl_elem_read(snd_ctl_t *ctl, snd_ctl_elem_value_t *data) + } + + /** +- * \brief Set CTL element value +- * \param ctl CTL handle +- * \param data Data of an element. ++ * \brief Set CTL element value. ++ * ++ * Write new value(s) to the sound card. You must set the ID and the ++ * value of the element before calling this function. ++ * ++ * See snd_ctl_elem_value_t for details. ++ * ++ * \param ctl CTL handle. ++ * \param data The new value. ++ * + * \retval 0 on success + * \retval >0 on success when value was changed + * \retval <0 a negative error code +@@ -2877,9 +2900,16 @@ size_t snd_ctl_elem_value_sizeof() + } + + /** +- * \brief Allocate an invalid #snd_ctl_elem_value_t using standard malloc(3). +- * \param ptr Returned pointer for data of an element. +- * \return 0 on success otherwise negative error code. ++ * \brief Allocate an invalid #snd_ctl_elem_value_t on the heap. ++ * ++ * Allocate space for a value object on the head. The allocated memory ++ * must be freed using snd_ctl_elem_value_free(). ++ * ++ * See snd_ctl_elem_value_t for details. ++ * ++ * \param ptr Pointer to a snd_ctl_elem_value_t pointer. The address ++ * of the allocated space will be returned here. ++ * \return 0 on success, otherwise a negative error code. + */ + int snd_ctl_elem_value_malloc(snd_ctl_elem_value_t **ptr) + { +@@ -2891,8 +2921,10 @@ int snd_ctl_elem_value_malloc(snd_ctl_elem_value_t **ptr) + } + + /** +- * \brief Frees a previously allocated data of an element. +- * \param obj Data of an element. ++ * \brief Free an #snd_ctl_elem_value_t previously allocated using ++ * snd_ctl_elem_value_malloc(). ++ * ++ * \param obj Pointer to the snd_ctl_elem_value_t. + */ + void snd_ctl_elem_value_free(snd_ctl_elem_value_t *obj) + { +@@ -2901,6 +2933,9 @@ void snd_ctl_elem_value_free(snd_ctl_elem_value_t *obj) + + /** + * \brief Clear given data of an element. ++ * ++ * See snd_ctl_elem_value_t for details. ++ * + * \param obj Data of an element. + */ + void snd_ctl_elem_value_clear(snd_ctl_elem_value_t *obj) +@@ -2909,7 +2944,7 @@ void snd_ctl_elem_value_clear(snd_ctl_elem_value_t *obj) + } + + /** +- * \brief Copy two data of elements. ++ * \brief Bitwise copy of a snd_ctl_elem_value_t value. + * \param dst Pointer to destination. + * \param src Pointer to source. + */ +@@ -2921,9 +2956,10 @@ void snd_ctl_elem_value_copy(snd_ctl_elem_value_t *dst, + } + + /** +- * \brief Compare one data of an element to the other. +- * \param left Pointer to first data. +- * \param right Pointer to second data. ++ * \brief Compare two snd_ctl_elem_value_t values, bytewise. ++ * ++ * \param left First value. ++ * \param right Second value. + * \return 0 on match, less than or greater than otherwise, see memcmp(3). + */ + int snd_ctl_elem_value_compare(snd_ctl_elem_value_t *left, +@@ -2934,9 +2970,13 @@ int snd_ctl_elem_value_compare(snd_ctl_elem_value_t *left, + } + + /** +- * \brief Get element identifier from given data of an element. +- * \param obj Data of an element. +- * \param ptr Pointer for element identifier. ++ * \brief Get the element identifier from the given element value. ++ * ++ * See snd_ctl_elem_value_t for more details. ++ * ++ * \param obj The element value. ++ * \param ptr Pointer to an identifier object. The identifier is ++ * stored there. + */ + void snd_ctl_elem_value_get_id(const snd_ctl_elem_value_t *obj, snd_ctl_elem_id_t *ptr) + { +@@ -2945,9 +2985,12 @@ void snd_ctl_elem_value_get_id(const snd_ctl_elem_value_t *obj, snd_ctl_elem_id_ + } + + /** +- * \brief Get element numeric identifier from given data of an element. +- * \param obj Data of an element. +- * \return Element numeric identifier. ++ * \brief Get the identifiers 'numid' part from the given element value. ++ * ++ * See snd_ctl_elem_value_t for more details. ++ * ++ * \param obj The element value. ++ * \return The numid. + */ + unsigned int snd_ctl_elem_value_get_numid(const snd_ctl_elem_value_t *obj) + { +@@ -2956,10 +2999,12 @@ unsigned int snd_ctl_elem_value_get_numid(const snd_ctl_elem_value_t *obj) + } + + /** +- * \brief Get interface part of element identifier from given data of an +- * element. +- * \param obj Data of an element. +- * \return Interface part of element identifier. ++ * \brief Get the identifiers 'interface' part from the given element value. ++ * ++ * See snd_ctl_elem_value_t for more details. ++ * ++ * \param obj The element value. ++ * \return The interface part of element identifier. + */ + snd_ctl_elem_iface_t snd_ctl_elem_value_get_interface(const snd_ctl_elem_value_t *obj) + { +@@ -2968,9 +3013,12 @@ snd_ctl_elem_iface_t snd_ctl_elem_value_get_interface(const snd_ctl_elem_value_t + } + + /** +- * \brief Get device part of element identifier from given data of an element. +- * \param obj Data of an element. +- * \return Device part of element identifier. ++ * \brief Get the identifiers 'device' part from the given element value. ++ * ++ * See snd_ctl_elem_value_t for more details. ++ * ++ * \param obj The element value. ++ * \return The device part of element identifier. + */ + unsigned int snd_ctl_elem_value_get_device(const snd_ctl_elem_value_t *obj) + { +@@ -2979,10 +3027,12 @@ unsigned int snd_ctl_elem_value_get_device(const snd_ctl_elem_value_t *obj) + } + + /** +- * \brief Get subdevice part of element identifier from given data of an +- * element. +- * \param obj Data of an element. +- * \return Subdevice part of element identifier. ++ * \brief Get the identifiers 'subdevice' part from the given element value. ++ * ++ * See snd_ctl_elem_value_t for more details. ++ * ++ * \param obj The element value. ++ * \return The subdevice part of element identifier. + */ + unsigned int snd_ctl_elem_value_get_subdevice(const snd_ctl_elem_value_t *obj) + { +@@ -2991,9 +3041,12 @@ unsigned int snd_ctl_elem_value_get_subdevice(const snd_ctl_elem_value_t *obj) + } + + /** +- * \brief Get name part of element identifier from given data of an element. +- * \param obj Data of an element. +- * \return Name part of element identifier. ++ * \brief Get the identifiers 'name' part from the given element value. ++ * ++ * See snd_ctl_elem_value_t for more details. ++ * ++ * \param obj The element value. ++ * \return The "name" part of element identifier. + */ + const char *snd_ctl_elem_value_get_name(const snd_ctl_elem_value_t *obj) + { +@@ -3002,9 +3055,12 @@ const char *snd_ctl_elem_value_get_name(const snd_ctl_elem_value_t *obj) + } + + /** +- * \brief Get index part of element identifier from given data of an element. +- * \param obj Data of an element. +- * \return Index part of element identifier. ++ * \brief Get the identifiers 'index' part from the given element value. ++ * ++ * See snd_ctl_elem_value_t for more details. ++ * ++ * \param obj The element value. ++ * \return The index part of element identifier. + */ + unsigned int snd_ctl_elem_value_get_index(const snd_ctl_elem_value_t *obj) + { +@@ -3012,10 +3068,14 @@ unsigned int snd_ctl_elem_value_get_index(const snd_ctl_elem_value_t *obj) + return obj->id.index; + } + ++ + /** +- * \brief Set element identifier to given data of an element. +- * \param obj Data of an element. +- * \param ptr Pointer to an element identifier. ++ * \brief Set the element identifier within the given element value. ++ * ++ * See snd_ctl_elem_value_t for more details. ++ * ++ * \param obj The element value. ++ * \param ptr The new identifier. + */ + void snd_ctl_elem_value_set_id(snd_ctl_elem_value_t *obj, const snd_ctl_elem_id_t *ptr) + { +@@ -3024,9 +3084,12 @@ void snd_ctl_elem_value_set_id(snd_ctl_elem_value_t *obj, const snd_ctl_elem_id_ + } + + /** +- * \brief Set numeric identifier to given data of an element. +- * \param obj Data of an element. +- * \param val Value for numeric identifier. ++ * \brief Set the identifiers 'numid' part within the given element value. ++ * ++ * See snd_ctl_elem_value_t for more details. ++ * ++ * \param obj The element value. ++ * \param val The new numid. + */ + void snd_ctl_elem_value_set_numid(snd_ctl_elem_value_t *obj, unsigned int val) + { +@@ -3035,9 +3098,12 @@ void snd_ctl_elem_value_set_numid(snd_ctl_elem_value_t *obj, unsigned int val) + } + + /** +- * \brief Set interface part of element identifier to given data of an element. +- * \param obj Data of an element. +- * \param val Value for interface part of element identifier. ++ * \brief Set the identifiers 'interface' part within the given element value. ++ * ++ * See snd_ctl_elem_value_t for more details. ++ * ++ * \param obj The element value. ++ * \param val The new interface. + */ + void snd_ctl_elem_value_set_interface(snd_ctl_elem_value_t *obj, snd_ctl_elem_iface_t val) + { +@@ -3046,9 +3112,12 @@ void snd_ctl_elem_value_set_interface(snd_ctl_elem_value_t *obj, snd_ctl_elem_if + } + + /** +- * \brief Set device part of element identifier to given data of an element. +- * \param obj Data of an element. +- * \param val Value for device part of element identifier. ++ * \brief Set the identifiers 'device' part within the given element value. ++ * ++ * See snd_ctl_elem_value_t for more details. ++ * ++ * \param obj The element value. ++ * \param val The new device. + */ + void snd_ctl_elem_value_set_device(snd_ctl_elem_value_t *obj, unsigned int val) + { +@@ -3057,9 +3126,12 @@ void snd_ctl_elem_value_set_device(snd_ctl_elem_value_t *obj, unsigned int val) + } + + /** +- * \brief Set subdevice part of element identifier to given data of an element. +- * \param obj Data of an element. +- * \param val Value for subdevice part of element identifier. ++ * \brief Set the identifiers 'subdevice' part within the given element value. ++ * ++ * See snd_ctl_elem_value_t for more details. ++ * ++ * \param obj The element value. ++ * \param val The new subdevice. + */ + void snd_ctl_elem_value_set_subdevice(snd_ctl_elem_value_t *obj, unsigned int val) + { +@@ -3068,9 +3140,12 @@ void snd_ctl_elem_value_set_subdevice(snd_ctl_elem_value_t *obj, unsigned int va + } + + /** +- * \brief Set name part of element identifier to given data of an element. +- * \param obj Data of an element. +- * \param val Value for name part of element identifier, ++ * \brief Set the identifiers 'name' part within the given element value. ++ * ++ * See snd_ctl_elem_value_t for more details. ++ * ++ * \param obj The element value. ++ * \param val The new name. + */ + void snd_ctl_elem_value_set_name(snd_ctl_elem_value_t *obj, const char *val) + { +@@ -3079,9 +3154,12 @@ void snd_ctl_elem_value_set_name(snd_ctl_elem_value_t *obj, const char *val) + } + + /** +- * \brief Set index part of element identifier to given data of an element. +- * \param obj Data of an element. +- * \param val Value for index part of element identifier. ++ * \brief Set the identifiers 'index' part within the given element value. ++ * ++ * See snd_ctl_elem_value_t for more details. ++ * ++ * \param obj The element value. ++ * \param val The new index. + */ + void snd_ctl_elem_value_set_index(snd_ctl_elem_value_t *obj, unsigned int val) + { +@@ -3090,12 +3168,16 @@ void snd_ctl_elem_value_set_index(snd_ctl_elem_value_t *obj, unsigned int val) + } + + /** +- * \brief Get value of a specified member from given data as an element of +- * boolean type. +- * \param obj Data of an element. +- * \param idx Index of member in the element. +- * \return Value for the member. +- */ ++ * \brief Get an element members value. ++ * ++ * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_BOOLEAN. It ++ * returns the value of one member. See \ref snd_ctl_elem_value_t and \ref ++ * control for more details. ++ * ++ * \param obj The element value object ++ * \param idx The index of the member. ++ * \return The members value. ++ */ + int snd_ctl_elem_value_get_boolean(const snd_ctl_elem_value_t *obj, unsigned int idx) + { + assert(obj); +@@ -3104,12 +3186,16 @@ int snd_ctl_elem_value_get_boolean(const snd_ctl_elem_value_t *obj, unsigned int + } + + /** +- * \brief Get value of a specified member from given data as an element of +- * integer type. +- * \param obj Data of an element. +- * \param idx Index of member in the element. +- * \return Value for the member. +- */ ++ * \brief Get an element members value. ++ * ++ * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_INTEGER. It ++ * returns the value of one member. See \ref snd_ctl_elem_value_t and \ref ++ * control for more details. ++ * ++ * \param obj The element value object. ++ * \param idx The index of the member. ++ * \return The members value. ++ */ + long snd_ctl_elem_value_get_integer(const snd_ctl_elem_value_t *obj, unsigned int idx) + { + assert(obj); +@@ -3118,12 +3204,16 @@ long snd_ctl_elem_value_get_integer(const snd_ctl_elem_value_t *obj, unsigned in + } + + /** +- * \brief Get value of a specified member from given data as an element of +- * integer64 type. +- * \param obj Data of an element. +- * \param idx Index of member in the element. +- * \return Value for the member. +- */ ++ * \brief Get an element members value. ++ * ++ * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_INTEGER64. It ++ * returns the value of one member. See \ref snd_ctl_elem_value_t and \ref ++ * control for more details. ++ * ++ * \param obj The element value object. ++ * \param idx The index of the member. ++ * \return The members value. ++ */ + long long snd_ctl_elem_value_get_integer64(const snd_ctl_elem_value_t *obj, unsigned int idx) + { + assert(obj); +@@ -3132,12 +3222,16 @@ long long snd_ctl_elem_value_get_integer64(const snd_ctl_elem_value_t *obj, unsi + } + + /** +- * \brief Get value of a specified member from given data as an element of +- * enumerated type. +- * \param obj Data of an element. +- * \param idx Index of member in the element. +- * \return Value for the member. This is an index of name set in the element. +- */ ++ * \brief Get an element members value. ++ * ++ * Use this function if the element is of type ++ * SNDRV_CTL_ELEM_TYPE_ENUMERATED. It returns the index of the active item. See ++ * \ref snd_ctl_elem_value_t and \ref control for more details. ++ * ++ * \param obj The element value object. ++ * \param idx The index of the requested member. ++ * \return The index of the active item. ++ */ + unsigned int snd_ctl_elem_value_get_enumerated(const snd_ctl_elem_value_t *obj, unsigned int idx) + { + assert(obj); +@@ -3146,12 +3240,16 @@ unsigned int snd_ctl_elem_value_get_enumerated(const snd_ctl_elem_value_t *obj, + } + + /** +- * \brief Get value of a specified member from given data as an element of +- * bytes type. +- * \param obj Data of an element. +- * \param idx Index of member in the element. +- * \return Value for the member. +- */ ++ * \brief Get an element members value. ++ * ++ * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_BYTE. It ++ * returns the value of one member. See \ref snd_ctl_elem_value_t and \ref ++ * control for more details. ++ * ++ * \param obj The element value object. ++ * \param idx The index of the member. ++ * \return The members value. ++ */ + unsigned char snd_ctl_elem_value_get_byte(const snd_ctl_elem_value_t *obj, unsigned int idx) + { + assert(obj); +@@ -3160,12 +3258,16 @@ unsigned char snd_ctl_elem_value_get_byte(const snd_ctl_elem_value_t *obj, unsig + } + + /** +- * \brief Set value of a specified member to given data as an element of +- * boolean type. +- * \param obj Data of an element. +- * \param idx Index of member in the element. +- * \param val Value for the member. +- */ ++ * \brief Set an element members value. ++ * ++ * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_BOOLEAN. It ++ * sets the value of one member. See \ref snd_ctl_elem_value_t and \ref control ++ * for more details. ++ * ++ * \param obj The element value object. ++ * \param idx The index of the member. ++ * \param val The new value. ++ */ + void snd_ctl_elem_value_set_boolean(snd_ctl_elem_value_t *obj, unsigned int idx, long val) + { + assert(obj); +@@ -3174,12 +3276,16 @@ void snd_ctl_elem_value_set_boolean(snd_ctl_elem_value_t *obj, unsigned int idx, + } + + /** +- * \brief Set value of a specified member to given data as an element of +- * integer type. +- * \param obj Data of an element. +- * \param idx Index of member in the element. +- * \param val Value for the member. +- */ ++ * \brief Set an element members value. ++ * ++ * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_INTEGER. It ++ * sets the value of one member. See \ref snd_ctl_elem_value_t and \ref control ++ * for more details. ++ * ++ * \param obj The element value object. ++ * \param idx The index of the member. ++ * \param val The new value. ++ */ + void snd_ctl_elem_value_set_integer(snd_ctl_elem_value_t *obj, unsigned int idx, long val) + { + assert(obj); +@@ -3188,12 +3294,16 @@ void snd_ctl_elem_value_set_integer(snd_ctl_elem_value_t *obj, unsigned int idx, + } + + /** +- * \brief Set value of a specified member to given data as an element of +- * integer64 type. +- * \param obj Data of an element. +- * \param idx Index of member in the element. +- * \param val Value for the member. +- */ ++ * \brief Set an element members value. ++ * ++ * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_INTEGER64. It ++ * sets the value of one member. See \ref snd_ctl_elem_value_t and \ref control ++ * for more details. ++ * ++ * \param obj The element value object. ++ * \param idx The index of the member. ++ * \param val The new value. ++ */ + void snd_ctl_elem_value_set_integer64(snd_ctl_elem_value_t *obj, unsigned int idx, long long val) + { + assert(obj); +@@ -3202,12 +3312,16 @@ void snd_ctl_elem_value_set_integer64(snd_ctl_elem_value_t *obj, unsigned int id + } + + /** +- * \brief Set value of a specified member to given data as an element of +- * enumerated type. +- * \param obj Data of an element. +- * \param idx Index of member in the element. +- * \param val Value for the member. +- */ ++ * \brief Set an element members value. ++ * ++ * Use this function if the element is of type ++ * SNDRV_CTL_ELEM_TYPE_ENUMERATED. It activates the specified item. See \ref ++ * snd_ctl_elem_value_t and \ref control for more details. ++ * ++ * \param obj The element value object. ++ * \param idx The index of the requested member. ++ * \param val The new index of the item to be activated. ++ */ + void snd_ctl_elem_value_set_enumerated(snd_ctl_elem_value_t *obj, unsigned int idx, unsigned int val) + { + assert(obj); +@@ -3216,12 +3330,16 @@ void snd_ctl_elem_value_set_enumerated(snd_ctl_elem_value_t *obj, unsigned int i + } + + /** +- * \brief Set value for a specified member to given data as an element of byte +- * type. +- * \param obj Data of an element. +- * \param idx Index of member in the element. +- * \param val Value for the member. +- */ ++ * \brief Set an element members value. ++ * ++ * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_BYTE. It ++ * sets the value of one member. See \ref snd_ctl_elem_value_t and \ref control ++ * for more details. ++ * ++ * \param obj The element value object. ++ * \param idx The index of the member. ++ * \param val The new value. ++ */ + void snd_ctl_elem_value_set_byte(snd_ctl_elem_value_t *obj, unsigned int idx, unsigned char val) + { + assert(obj); +@@ -3230,10 +3348,17 @@ void snd_ctl_elem_value_set_byte(snd_ctl_elem_value_t *obj, unsigned int idx, un + } + + /** +- * \brief Set values to given data as an element of bytes type. +- * \param obj Data of an element. +- * \param data Pointer for byte array. +- * \param size The number of bytes included in the memory block. ++ * \brief Replace the data stored within the element. ++ * ++ * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_BYTES. It ++ * replaces the data stored in the element. Note that "bytes" elements don't ++ * have members. They have only one single block of data. ++ * ++ * See \ref snd_ctl_elem_value_t and \ref control for more details. ++ * ++ * \param obj The element value object. ++ * \param data Pointer to the new data. ++ * \param size The size of the new data, in bytes. + */ + void snd_ctl_elem_set_bytes(snd_ctl_elem_value_t *obj, void *data, size_t size) + { +@@ -3243,10 +3368,17 @@ void snd_ctl_elem_set_bytes(snd_ctl_elem_value_t *obj, void *data, size_t size) + } + + /** +- * \brief Get memory block from given data as an element of bytes type. +- * \param obj Data of an element. +- * \return Pointer for byte array. +- */ ++ * \brief Get the data stored within the element. ++ * ++ * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_BYTES. It ++ * returns the data stored in the element. Note that "bytes" elements don't have ++ * members. They have only one single block of data. ++ * ++ * See \ref snd_ctl_elem_value_t and \ref control for more details. ++ * ++ * \param obj The element value object. ++ * \return Pointer to the elements data. ++ */ + const void * snd_ctl_elem_value_get_bytes(const snd_ctl_elem_value_t *obj) + { + assert(obj); +@@ -3254,11 +3386,17 @@ const void * snd_ctl_elem_value_get_bytes(const snd_ctl_elem_value_t *obj) + } + + /** +- * \brief Get value from given data to given pointer as an element of IEC958 +- * type. +- * \param obj Data of an element. +- * \param ptr Pointer to IEC958 data. +- */ ++ * \brief Get an elements IEC958 data. ++ * ++ * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_IEC958. Note that ++ * "IEC958" elements don't have members. They have only one single ++ * IEC958 information block. ++ * ++ * See \ref snd_ctl_elem_value_t and \ref control for more details. ++ * ++ * \param obj The element value object. ++ * \param ptr Pointer to an IEC958 structure. The data is stored there. ++ */ + void snd_ctl_elem_value_get_iec958(const snd_ctl_elem_value_t *obj, snd_aes_iec958_t *ptr) + { + assert(obj && ptr); +@@ -3266,11 +3404,17 @@ void snd_ctl_elem_value_get_iec958(const snd_ctl_elem_value_t *obj, snd_aes_iec9 + } + + /** +- * \brief Set value from given pointer to given data as an element of IEC958 +- * type. +- * \param obj Data of an element. +- * \param ptr Pointer to IEC958 data. +- */ ++ * \brief Set an elements IEC958 data. ++ * ++ * Use this function if the element is of type SNDRV_CTL_ELEM_TYPE_IEC958. Note ++ * that "IEC958" elements don't have members. They have only one single IEC958 ++ * information block. ++ * ++ * See \ref snd_ctl_elem_value_t and \ref control for more details. ++ * ++ * \param obj The element value object. ++ * \param ptr Pointer to the new IEC958 data. ++ */ + void snd_ctl_elem_value_set_iec958(snd_ctl_elem_value_t *obj, const snd_aes_iec958_t *ptr) + { + assert(obj && ptr); +-- +2.16.4 + diff --git a/alsa.changes b/alsa.changes index 3240adb..91e769e 100644 --- a/alsa.changes +++ b/alsa.changes @@ -1,4 +1,47 @@ ------------------------------------------------------------------- +Tue Sep 29 08:57:00 UTC 2020 - Guillaume GARDET + +- Enable topology support for aarch64 + +------------------------------------------------------------------- +Wed Sep 23 16:49:23 CEST 2020 - tiwai@suse.de + +- Backport upstream fixes: + 0001-ucm-substitution-remove-duplicate-allow_empty-assign.patch + 0002-ucm-fix-parse_get_safe_name-safe-name-must-be-checke.patch + 0003-ucm-substitute-the-merged-tree-completely.patch + 0004-ctl-improve-documentation-for-identifier-of-control-.patch + 0005-pcm-dmix-make-lockless-operation-optional.patch + 0006-pcm-dmix-Fix-semaphore-usage-with-lockless-operation.patch + 0007-pcm-iec958-implement-HDMI-HBR-audio-formatting.patch + 0008-pcm-iec958-set-channel-status-bits-according-to-rate.patch + 0009-conf-pcm-USB-Added-S-PDIF-fix-for-Asus-Xonar-SE.patch + 0010-control-ctlparse-fix-enum-values-in-or.patch + 0011-conf-USB-Audio-Disable-IEC958-on-Lenovo-ThinkStation.patch + 0012-pcm-dmix-fix-access-to-sum-buffer-in-non-interleaved.patch + 0014-control-Add-documentation-for-snd_ctl_elem_list_.patch + 0015-conf-quote-also-strings-with-and-characters-in-strin.patch + 0016-topology-decode-Fix-channel-map-memory-allocation.patch + 0017-topology-decode-Fix-infinite-loop-in-decoding-enum-c.patch + 0018-topology-decode-Remove-decoding-values-for-enum-cont.patch + 0019-topology-decode-Add-enum-control-texts-as-separate-e.patch + 0020-topology-decode-Fix-printing-texts-section.patch + 0021-topology-decode-Change-declaration-of-enum-decoding-.patch + 0022-topology-decode-Fix-decoding-PCM-formats-and-rates.patch + 0023-topology-decode-Print-sig_bits-field-in-PCM-capabili.patch + 0024-topology-decode-Add-DAI-name-printing.patch + 0025-topology-Make-buffer-for-saving-dynamic-size.patch + 0026-topology-return-correct-value-in-tplg_save_printf.patch + 0027-topology-fix-some-gcc10-warnings-labs-signess.patch + 0028-topology-fix-sort_config.patch + 0029-topology-fix-the-unaligned-access.patch + 0030-topology-improve-the-printf-buffer-management.patch + 0031-control-Improve-general-control-interface-documentat.patch + 0032-control-Add-documentation-for-snd_ctl_elem_value_.patch +- Build topology library conditionally; + currently it's supported only for little-endian + +------------------------------------------------------------------- Thu Jul 9 16:01:13 CEST 2020 - tiwai@suse.de - Update to alsa-lib 1.2.3.2: diff --git a/alsa.spec b/alsa.spec index ebd9fd8..e278abe 100644 --- a/alsa.spec +++ b/alsa.spec @@ -25,6 +25,12 @@ %define _udevrulesdir /lib/udev/rules.d/ %endif +%ifarch %ix86 x86_64 %arm aarch64 ppc64le +%define enable_topology 1 +%else +%define enable_topology 0 +%endif + Name: alsa Version: 1.2.3.2 Release: 0 @@ -47,6 +53,37 @@ Source30: all_notes_off Source31: all_notes_off.bin Source32: all_notes_off.mid Source34: alsa-init.sh +Patch1: 0001-ucm-substitution-remove-duplicate-allow_empty-assign.patch +Patch2: 0002-ucm-fix-parse_get_safe_name-safe-name-must-be-checke.patch +Patch3: 0003-ucm-substitute-the-merged-tree-completely.patch +Patch4: 0004-ctl-improve-documentation-for-identifier-of-control-.patch +Patch5: 0005-pcm-dmix-make-lockless-operation-optional.patch +Patch6: 0006-pcm-dmix-Fix-semaphore-usage-with-lockless-operation.patch +Patch7: 0007-pcm-iec958-implement-HDMI-HBR-audio-formatting.patch +Patch8: 0008-pcm-iec958-set-channel-status-bits-according-to-rate.patch +Patch9: 0009-conf-pcm-USB-Added-S-PDIF-fix-for-Asus-Xonar-SE.patch +Patch10: 0010-control-ctlparse-fix-enum-values-in-or.patch +Patch11: 0011-conf-USB-Audio-Disable-IEC958-on-Lenovo-ThinkStation.patch +Patch12: 0012-pcm-dmix-fix-access-to-sum-buffer-in-non-interleaved.patch +Patch14: 0014-control-Add-documentation-for-snd_ctl_elem_list_.patch +Patch15: 0015-conf-quote-also-strings-with-and-characters-in-strin.patch +Patch16: 0016-topology-decode-Fix-channel-map-memory-allocation.patch +Patch17: 0017-topology-decode-Fix-infinite-loop-in-decoding-enum-c.patch +Patch18: 0018-topology-decode-Remove-decoding-values-for-enum-cont.patch +Patch19: 0019-topology-decode-Add-enum-control-texts-as-separate-e.patch +Patch20: 0020-topology-decode-Fix-printing-texts-section.patch +Patch21: 0021-topology-decode-Change-declaration-of-enum-decoding-.patch +Patch22: 0022-topology-decode-Fix-decoding-PCM-formats-and-rates.patch +Patch23: 0023-topology-decode-Print-sig_bits-field-in-PCM-capabili.patch +Patch24: 0024-topology-decode-Add-DAI-name-printing.patch +Patch25: 0025-topology-Make-buffer-for-saving-dynamic-size.patch +Patch26: 0026-topology-return-correct-value-in-tplg_save_printf.patch +Patch27: 0027-topology-fix-some-gcc10-warnings-labs-signess.patch +Patch28: 0028-topology-fix-sort_config.patch +Patch29: 0029-topology-fix-the-unaligned-access.patch +Patch30: 0030-topology-improve-the-printf-buffer-management.patch +Patch31: 0031-control-Improve-general-control-interface-documentat.patch +Patch32: 0032-control-Add-documentation-for-snd_ctl_elem_value_.patch # rest suse fixes Patch101: alsa-lib-ignore-non-accessible-ALSA_CONFIG_PATH.patch BuildRequires: doxygen @@ -88,6 +125,7 @@ Provides: alsadev = %{version} This package contains all necessary include files and libraries needed to develop applications that require ALSA. +%if %enable_topology %package topology-devel Summary: Header files for ALSA topology development License: LGPL-2.1-or-later @@ -98,6 +136,7 @@ Requires: libatopology2 = %{version} %description topology-devel This package contains all necessary include files and libraries needed to develop applications that require ALSA topology. +%endif %package docs Summary: Additional Package Documentation for ALSA @@ -121,6 +160,7 @@ Provides: alsa-lib This package contains the library for ALSA, Advanced Linux Sound Architecture. +%if %enable_topology %package -n libatopology2 Summary: ALSA Topology Library License: LGPL-2.1-or-later @@ -128,9 +168,41 @@ Group: System/Libraries %description -n libatopology2 This package contains the library for ALSA topology support. +%endif %prep %setup -q -n alsa-lib-%{version} +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch14 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 +%patch20 -p1 +%patch21 -p1 +%patch22 -p1 +%patch23 -p1 +%patch24 -p1 +%patch25 -p1 +%patch26 -p1 +%patch27 -p1 +%patch28 -p1 +%patch29 -p1 +%patch30 -p1 +%patch31 -p1 +%patch32 -p1 %patch101 -p1 %build @@ -144,6 +216,9 @@ autoreconf -fi --enable-symbolic-functions \ --disable-aload \ --disable-alisp \ +%if !%enable_topology + --disable-topology \ +%endif --disable-python make V=1 %{?_smp_mflags} # run doxygen @@ -156,6 +231,9 @@ make -C doc doc %{?_smp_mflags} rm -f %{buildroot}%{_libdir}/*.*a # rm -f %{buildroot}%{_libdir}/alsa-lib/smixer/*.*a rm -f %{buildroot}%{_bindir}/aserver +%if !%enable_topology +rm -f %{buildroot}%{_libdir}/pkgconfig/alsa-topology.pc +%endif # # install helper scripts mkdir -p %{buildroot}%{_bindir} @@ -242,8 +320,10 @@ exit 0 %post -n libasound2 -p /sbin/ldconfig %postun -n libasound2 -p /sbin/ldconfig +%if %enable_topology %post -n libatopology2 -p /sbin/ldconfig %postun -n libatopology2 -p /sbin/ldconfig +%endif %files %defattr(-, root, root) @@ -266,16 +346,20 @@ exit 0 %{_libdir}/libasound.so %{_includedir}/sys/* %{_includedir}/alsa +%if %enable_topology %exclude %{_includedir}/alsa/topology.h +%endif %{_includedir}/asoundlib.h %{_datadir}/aclocal/*.m4 %{_libdir}/pkgconfig/alsa.pc +%if %enable_topology %files topology-devel %defattr(-, root, root) %{_libdir}/libatopology.so %{_includedir}/alsa/topology.h %{_libdir}/pkgconfig/alsa-topology.pc +%endif %files docs %defattr(-, root, root) @@ -286,8 +370,10 @@ exit 0 %{_libdir}/libasound.so.* %{_datadir}/alsa +%if %enable_topology %files -n libatopology2 %defattr(-, root, root) %{_libdir}/libatopology.so.* +%endif %changelog