- Backport upstream fixes (bsc#1012594): - A few PCM bugs have been fixed: * Stall of dmix and others in a wrong PCM state * Refactoring of PCM locking scheme * SHM initialization race fix * plug PCM memory leaks * Improvement of dshare/dmix delay calculation * Fix endless dshare draining * Fix semaphore discard race fix of direct plugins - UCM fixes and updates for DB410c and skylake-r5286 - Mixer code cleanup not to install bogus plugin codes - Documentation fixes / updates 0001-ucm-Add-ucm-files-for-DB410c-board.patch 0002-mixer-Fix-rounding-mode-documentation.patch 0003-pcm-Fix-shm-initialization-race-condition.patch 0004-pcm-Better-understandable-locking-code.patch 0005-ucm-fix-crash-when-calling-snd_use_case_geti-with-no.patch 0006-ucm-docs-typeset-lists-of-identifiers-explicitly.patch 0007-Update-include-sound-tlv.h-from-4.9-pre-kernel-uapi.patch 0008-test-use-actual-information-for-TLV-operation.patch 0009-ctl-improve-API-documentation-for-TLV-operation.patch 0010-ctl-improve-documentation-about-TLV-related-APIs.patch 0011-ctl-correct-documentation-about-TLV-feature.patch 0012-conf-ucm-skylake-add-skylake-rt286-conf-files.patch 0013-pcm_plug-Clear-plugins-on-all-error-conditions.patch 0014-mixer-Don-t-install-smixer-modules-unless-python-is-.patch 0015-pcm_dshare-Do-not-discard-slave-reported-delay-in-st.patch 0016-pcm-direct-Protect-from-freeing-semaphore-when-alrea.patch 0017-pcm-dshare-Fix-endless-playback-of-buffer.patch 0018-pcm-Add-the-PCM-state-checks-to-plugins.patch OBS-URL: https://build.opensuse.org/request/show/442719 OBS-URL: https://build.opensuse.org/package/show/multimedia:libs/alsa?expand=0&rev=202
387 lines
12 KiB
Diff
387 lines
12 KiB
Diff
From ee1182d2cbb4930ca1166bc03f3b0fcfbb594145 Mon Sep 17 00:00:00 2001
|
|
From: Takashi Sakamoto <o-takashi@sakamocchi.jp>
|
|
Date: Thu, 29 Sep 2016 08:57:21 +0900
|
|
Subject: [PATCH] test: use actual information for TLV operation
|
|
|
|
Currently, this test program uses undefined type of TLV data. This can
|
|
bring confusions to userspace applications.
|
|
|
|
This commit replaces the array with valid information, constructed by newly
|
|
exported TLV macros from kernel land.
|
|
|
|
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
|
|
Signed-off-by: Takashi Iwai <tiwai@suse.de>
|
|
---
|
|
test/user-ctl-element-set.c | 214 ++++++++++++++++++++++++++++++++++++--------
|
|
1 file changed, 178 insertions(+), 36 deletions(-)
|
|
|
|
diff --git a/test/user-ctl-element-set.c b/test/user-ctl-element-set.c
|
|
index 9b9dc598f0af..75083d219fe6 100644
|
|
--- a/test/user-ctl-element-set.c
|
|
+++ b/test/user-ctl-element-set.c
|
|
@@ -8,6 +8,7 @@
|
|
*/
|
|
|
|
#include "../include/asoundlib.h"
|
|
+#include <sound/tlv.h>
|
|
|
|
struct elem_set_trial {
|
|
snd_ctl_t *handle;
|
|
@@ -25,8 +26,30 @@ struct elem_set_trial {
|
|
snd_ctl_elem_info_t *info);
|
|
void (*change_elem_members)(struct elem_set_trial *trial,
|
|
snd_ctl_elem_value_t *elem_data);
|
|
+ int (*allocate_elem_set_tlv)(struct elem_set_trial *trial,
|
|
+ unsigned int **tlv);
|
|
};
|
|
|
|
+struct chmap_entry {
|
|
+ unsigned int type;
|
|
+ unsigned int length;
|
|
+ unsigned int maps[0];
|
|
+};
|
|
+
|
|
+/*
|
|
+ * History of TLV feature:
|
|
+ *
|
|
+ * 2016/09/15: 398fa4db6c69 ("ALSA: control: move layout of TLV payload to UAPI
|
|
+ * header")
|
|
+ * 2012/07/21: 2d3391ec0ecc ("ALSA: PCM: channel mapping API implementation")
|
|
+ * 2011/11/20: bf1d1c9b6179 ("ALSA: tlv: add DECLARE_TLV_DB_RANGE()")
|
|
+ * 2009/07/16: 085f30654175 ("ALSA: Add new TLV types for dBwith min/max")
|
|
+ * 2006/09/06: 55a29af5ed5d ("[ALSA] Add definition of TLV dB range compound")
|
|
+ * 2006/08/28: 063a40d9111c ("Add the definition of linear volume TLV")
|
|
+ * 2006/08/28: 42750b04c5ba ("[ALSA] Control API - TLV implementation for
|
|
+ * additional information like dB scale")
|
|
+ */
|
|
+
|
|
/* Operations for elements in an element set with boolean type. */
|
|
static int add_bool_elem_set(struct elem_set_trial *trial,
|
|
snd_ctl_elem_info_t *info)
|
|
@@ -47,13 +70,30 @@ static void change_bool_elem_members(struct elem_set_trial *trial,
|
|
}
|
|
}
|
|
|
|
+static int allocate_bool_elem_set_tlv(struct elem_set_trial *trial,
|
|
+ unsigned int **tlv)
|
|
+{
|
|
+ /*
|
|
+ * Performs like a toggle switch for attenuation, because they're bool
|
|
+ * elements.
|
|
+ */
|
|
+ static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(range, -10000, 0);
|
|
+
|
|
+ *tlv = malloc(sizeof(range));
|
|
+ if (*tlv == NULL)
|
|
+ return -ENOMEM;
|
|
+ memcpy(*tlv, range, sizeof(range));
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/* Operations for elements in an element set with integer type. */
|
|
static int add_int_elem_set(struct elem_set_trial *trial,
|
|
snd_ctl_elem_info_t *info)
|
|
{
|
|
return snd_ctl_add_integer_elem_set(trial->handle, info,
|
|
trial->element_count, trial->member_count,
|
|
- 0, 99, 1);
|
|
+ 0, 25, 1);
|
|
}
|
|
|
|
static int check_int_elem_props(struct elem_set_trial *trial,
|
|
@@ -61,7 +101,7 @@ static int check_int_elem_props(struct elem_set_trial *trial,
|
|
{
|
|
if (snd_ctl_elem_info_get_min(info) != 0)
|
|
return -EIO;
|
|
- if (snd_ctl_elem_info_get_max(info) != 99)
|
|
+ if (snd_ctl_elem_info_get_max(info) != 25)
|
|
return -EIO;
|
|
if (snd_ctl_elem_info_get_step(info) != 1)
|
|
return -EIO;
|
|
@@ -81,6 +121,41 @@ static void change_int_elem_members(struct elem_set_trial *trial,
|
|
}
|
|
}
|
|
|
|
+static int allocate_int_elem_set_tlv(struct elem_set_trial *trial,
|
|
+ unsigned int **tlv)
|
|
+{
|
|
+ unsigned int len, pos;
|
|
+ unsigned int i, j;
|
|
+ struct chmap_entry *entry;
|
|
+
|
|
+ /* Calculate size of TLV packet for channel-mapping information. */
|
|
+ len = 0;
|
|
+ for (i = 1; i <= 25; ++i) {
|
|
+ len += sizeof(struct chmap_entry);
|
|
+ len += i * sizeof(unsigned int);
|
|
+ }
|
|
+
|
|
+ *tlv = malloc(len);
|
|
+ if (*tlv == NULL)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ /*
|
|
+ * Emulate channel-mapping information in in-kernel implementation.
|
|
+ * Here, 25 entries are for each different channel.
|
|
+ */
|
|
+ pos = 0;
|
|
+ for (i = 1; i <= 25 && pos < len; ++i) {
|
|
+ entry = (struct chmap_entry *)&(*tlv)[pos];
|
|
+ entry->type = SNDRV_CTL_TLVT_CHMAP_FIXED;
|
|
+ entry->length = i * sizeof(unsigned int);
|
|
+ for (j = 0; j < i; ++j)
|
|
+ entry->maps[j] = SND_CHMAP_MONO + j;
|
|
+ pos += sizeof(struct chmap_entry) + i * sizeof(unsigned int);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/* Operations for elements in an element set with enumerated type. */
|
|
static const char *const labels[] = {
|
|
"trusty",
|
|
@@ -158,6 +233,24 @@ static void change_bytes_elem_members(struct elem_set_trial *trial,
|
|
}
|
|
}
|
|
|
|
+static int allocate_bytes_elem_set_tlv(struct elem_set_trial *trial,
|
|
+ unsigned int **tlv)
|
|
+{
|
|
+ /*
|
|
+ * Emulate AK4396.
|
|
+ * 20 * log10(x/255) (dB)
|
|
+ * Here, x is written value.
|
|
+ */
|
|
+ static const SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(range, -4813, 0);
|
|
+
|
|
+ *tlv = malloc(sizeof(range));
|
|
+ if (*tlv == NULL)
|
|
+ return -ENOMEM;
|
|
+ memcpy(*tlv, range, sizeof(range));
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/* Operations for elements in an element set with iec958 type. */
|
|
static int add_iec958_elem_set(struct elem_set_trial *trial,
|
|
snd_ctl_elem_info_t *info)
|
|
@@ -197,17 +290,17 @@ static int add_int64_elem_set(struct elem_set_trial *trial,
|
|
{
|
|
return snd_ctl_add_integer64_elem_set(trial->handle, info,
|
|
trial->element_count, trial->member_count,
|
|
- 100, 10000, 30);
|
|
+ 0, 10000, 1);
|
|
}
|
|
|
|
static int check_int64_elem_props(struct elem_set_trial *trial,
|
|
snd_ctl_elem_info_t *info)
|
|
{
|
|
- if (snd_ctl_elem_info_get_min64(info) != 100)
|
|
+ if (snd_ctl_elem_info_get_min64(info) != 0)
|
|
return -EIO;
|
|
if (snd_ctl_elem_info_get_max64(info) != 10000)
|
|
return -EIO;
|
|
- if (snd_ctl_elem_info_get_step64(info) != 30)
|
|
+ if (snd_ctl_elem_info_get_step64(info) != 1)
|
|
return -EIO;
|
|
|
|
return 0;
|
|
@@ -225,6 +318,45 @@ static void change_int64_elem_members(struct elem_set_trial *trial,
|
|
}
|
|
}
|
|
|
|
+static int allocate_int64_elem_set_tlv(struct elem_set_trial *trial,
|
|
+ unsigned int **tlv)
|
|
+{
|
|
+ /*
|
|
+ * Use this fomula between linear/dB value:
|
|
+ *
|
|
+ * Linear: dB range (coeff)
|
|
+ * 0<-> 4: -59.40<->-56.36 (44)
|
|
+ * 4<->22: -56.36<->-45.56 (60)
|
|
+ * 22<->33: -45.56<->-40.72 (76)
|
|
+ * 33<->37: -40.72<->-38.32 (44)
|
|
+ * 37<->48: -38.32<->-29.96 (76)
|
|
+ * 48<->66: -29.96<->-22.04 (60)
|
|
+ * 66<->84: -22.04<-> -8.36 (44)
|
|
+ * 84<->95: -8.36<-> -1.76 (60)
|
|
+ * 95<->99: -1.76<-> 0.00 (76)
|
|
+ * 100<->..: 0.0
|
|
+ */
|
|
+ static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(range,
|
|
+ 0, 4, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-5940, 44, 1),
|
|
+ 4, 22, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-5636, 60, 0),
|
|
+ 22, 33, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-4556, 76, 0),
|
|
+ 33, 37, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-4072, 44, 0),
|
|
+ 37, 48, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-3832, 76, 0),
|
|
+ 48, 66, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-2996, 60, 0),
|
|
+ 66, 84, SNDRV_CTL_TLVD_DB_SCALE_ITEM(-2204, 44, 0),
|
|
+ 84, 95, SNDRV_CTL_TLVD_DB_SCALE_ITEM( -836, 60, 0),
|
|
+ 95, 99, SNDRV_CTL_TLVD_DB_SCALE_ITEM( -176, 76, 0),
|
|
+ 100, 10000, SNDRV_CTL_TLVD_DB_SCALE_ITEM(0, 0, 0),
|
|
+ );
|
|
+
|
|
+ *tlv = malloc(sizeof(range));
|
|
+ if (*tlv == NULL)
|
|
+ return -ENOMEM;
|
|
+ memcpy(*tlv, range, sizeof(range));
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/* Common operations. */
|
|
static int add_elem_set(struct elem_set_trial *trial)
|
|
{
|
|
@@ -414,41 +546,41 @@ static int check_elems(struct elem_set_trial *trial)
|
|
|
|
static int check_tlv(struct elem_set_trial *trial)
|
|
{
|
|
- unsigned int orig[8], curr[8];
|
|
+ unsigned int *tlv;
|
|
+ unsigned int len;
|
|
+ unsigned int *curr;
|
|
int err;
|
|
|
|
- /*
|
|
- * See a layout of 'struct snd_ctl_tlv'. I don't know the reason to
|
|
- * construct this buffer with the same layout. It should be abstracted
|
|
- * inner userspace library...
|
|
- */
|
|
- orig[0] = snd_ctl_elem_id_get_numid(trial->id);
|
|
- orig[1] = 6 * sizeof(orig[0]);
|
|
- orig[2] = 'a';
|
|
- orig[3] = 'b';
|
|
- orig[4] = 'c';
|
|
- orig[5] = 'd';
|
|
- orig[6] = 'e';
|
|
- orig[7] = 'f';
|
|
+ err = trial->allocate_elem_set_tlv(trial, &tlv);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+
|
|
+ len = tlv[1] + sizeof(unsigned int) * 2;
|
|
+ curr = malloc(len);
|
|
+ if (curr == NULL) {
|
|
+ free(tlv);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
|
|
/*
|
|
* In in-kernel implementation, write and command operations are the
|
|
- * same for an element set added by userspace applications. Here, I
|
|
+ * same for an element set added by userspace applications. Here, I
|
|
* use write.
|
|
*/
|
|
err = snd_ctl_elem_tlv_write(trial->handle, trial->id,
|
|
- (const unsigned int *)orig);
|
|
+ (const unsigned int *)tlv);
|
|
if (err < 0)
|
|
- return err;
|
|
+ goto end;
|
|
|
|
- err = snd_ctl_elem_tlv_read(trial->handle, trial->id, curr,
|
|
- sizeof(curr));
|
|
+ err = snd_ctl_elem_tlv_read(trial->handle, trial->id, curr, len);
|
|
if (err < 0)
|
|
- return err;
|
|
-
|
|
- if (memcmp(curr, orig, sizeof(orig)) != 0)
|
|
- return -EIO;
|
|
+ goto end;
|
|
|
|
+ if (memcmp(curr, tlv, len) != 0)
|
|
+ err = -EIO;
|
|
+end:
|
|
+ free(tlv);
|
|
+ free(curr);
|
|
return 0;
|
|
}
|
|
|
|
@@ -484,6 +616,8 @@ int main(void)
|
|
trial.add_elem_set = add_bool_elem_set;
|
|
trial.check_elem_props = NULL;
|
|
trial.change_elem_members = change_bool_elem_members;
|
|
+ trial.allocate_elem_set_tlv =
|
|
+ allocate_bool_elem_set_tlv;
|
|
break;
|
|
case SND_CTL_ELEM_TYPE_INTEGER:
|
|
trial.element_count = 900;
|
|
@@ -495,6 +629,8 @@ int main(void)
|
|
trial.add_elem_set = add_int_elem_set;
|
|
trial.check_elem_props = check_int_elem_props;
|
|
trial.change_elem_members = change_int_elem_members;
|
|
+ trial.allocate_elem_set_tlv =
|
|
+ allocate_int_elem_set_tlv;
|
|
break;
|
|
case SND_CTL_ELEM_TYPE_ENUMERATED:
|
|
trial.element_count = 900;
|
|
@@ -506,6 +642,7 @@ int main(void)
|
|
trial.add_elem_set = add_enum_elem_set;
|
|
trial.check_elem_props = check_enum_elem_props;
|
|
trial.change_elem_members = change_enum_elem_members;
|
|
+ trial.allocate_elem_set_tlv = NULL;
|
|
break;
|
|
case SND_CTL_ELEM_TYPE_BYTES:
|
|
trial.element_count = 900;
|
|
@@ -517,6 +654,8 @@ int main(void)
|
|
trial.add_elem_set = add_bytes_elem_set;
|
|
trial.check_elem_props = NULL;
|
|
trial.change_elem_members = change_bytes_elem_members;
|
|
+ trial.allocate_elem_set_tlv =
|
|
+ allocate_bytes_elem_set_tlv;
|
|
break;
|
|
case SND_CTL_ELEM_TYPE_IEC958:
|
|
trial.element_count = 1;
|
|
@@ -528,6 +667,7 @@ int main(void)
|
|
trial.add_elem_set = add_iec958_elem_set;
|
|
trial.check_elem_props = NULL;
|
|
trial.change_elem_members = change_iec958_elem_members;
|
|
+ trial.allocate_elem_set_tlv = NULL;
|
|
break;
|
|
case SND_CTL_ELEM_TYPE_INTEGER64:
|
|
default:
|
|
@@ -540,6 +680,8 @@ int main(void)
|
|
trial.add_elem_set = add_int64_elem_set;
|
|
trial.check_elem_props = check_int64_elem_props;
|
|
trial.change_elem_members = change_int64_elem_members;
|
|
+ trial.allocate_elem_set_tlv =
|
|
+ allocate_int64_elem_set_tlv;
|
|
break;
|
|
}
|
|
|
|
@@ -589,22 +731,22 @@ int main(void)
|
|
}
|
|
|
|
/*
|
|
- * Test an operation to change threshold data of this element set,
|
|
- * except for IEC958 type.
|
|
+ * Test an operation to change TLV data of this element set,
|
|
+ * except for enumerated and IEC958 type.
|
|
*/
|
|
- if (trial.type != SND_CTL_ELEM_TYPE_IEC958) {
|
|
+ if (trial.allocate_elem_set_tlv != NULL) {
|
|
err = check_tlv(&trial);
|
|
if (err < 0) {
|
|
- printf("Fail to change threshold level of an "
|
|
- "element set with %s type.\n",
|
|
+ printf("Fail to change TLV data of an element "
|
|
+ "set with %s type.\n",
|
|
snd_ctl_elem_type_name(trial.type));
|
|
break;
|
|
}
|
|
err = check_event(&trial, SND_CTL_EVENT_MASK_TLV, 1);
|
|
if (err < 0) {
|
|
- printf("Fail to check an event to change "
|
|
- "threshold level of an an element set "
|
|
- "with %s type.\n",
|
|
+ printf("Fail to check an event to change TLV"
|
|
+ "data of an an element set with %s "
|
|
+ "type.\n",
|
|
snd_ctl_elem_type_name(trial.type));
|
|
break;
|
|
}
|
|
--
|
|
2.10.2
|
|
|