xref: /openbmc/linux/tools/testing/selftests/alsa/mixer-test.c (revision b73dad806533cad55df41a9c0349969b56d4ff7f)
15aaf9effSMark Brown // SPDX-License-Identifier: GPL-2.0
25aaf9effSMark Brown //
35aaf9effSMark Brown // kselftest for the ALSA mixer API
45aaf9effSMark Brown //
55aaf9effSMark Brown // Original author: Mark Brown <broonie@kernel.org>
65aaf9effSMark Brown // Copyright (c) 2021 Arm Limited
75aaf9effSMark Brown 
85aaf9effSMark Brown // This test will iterate over all cards detected in the system, exercising
95aaf9effSMark Brown // every mixer control it can find.  This may conflict with other system
105aaf9effSMark Brown // software if there is audio activity so is best run on a system with a
115aaf9effSMark Brown // minimal active userspace.
125aaf9effSMark Brown 
135aaf9effSMark Brown #include <stdio.h>
145aaf9effSMark Brown #include <stdlib.h>
155aaf9effSMark Brown #include <stdbool.h>
165aaf9effSMark Brown #include <string.h>
175aaf9effSMark Brown #include <getopt.h>
185aaf9effSMark Brown #include <stdarg.h>
195aaf9effSMark Brown #include <ctype.h>
205aaf9effSMark Brown #include <math.h>
215aaf9effSMark Brown #include <errno.h>
225aaf9effSMark Brown #include <assert.h>
235aaf9effSMark Brown #include <alsa/asoundlib.h>
245aaf9effSMark Brown #include <poll.h>
255aaf9effSMark Brown #include <stdint.h>
265aaf9effSMark Brown 
275aaf9effSMark Brown #include "../kselftest.h"
285aaf9effSMark Brown 
295aaf9effSMark Brown #define TESTS_PER_CONTROL 3
305aaf9effSMark Brown 
315aaf9effSMark Brown struct card_data {
325aaf9effSMark Brown 	snd_ctl_t *handle;
335aaf9effSMark Brown 	int card;
345aaf9effSMark Brown 	int num_ctls;
355aaf9effSMark Brown 	snd_ctl_elem_list_t *ctls;
365aaf9effSMark Brown 	struct card_data *next;
375aaf9effSMark Brown };
385aaf9effSMark Brown 
395aaf9effSMark Brown struct ctl_data {
405aaf9effSMark Brown 	const char *name;
415aaf9effSMark Brown 	snd_ctl_elem_id_t *id;
425aaf9effSMark Brown 	snd_ctl_elem_info_t *info;
435aaf9effSMark Brown 	snd_ctl_elem_value_t *def_val;
445aaf9effSMark Brown 	int elem;
455aaf9effSMark Brown 	struct card_data *card;
465aaf9effSMark Brown 	struct ctl_data *next;
475aaf9effSMark Brown };
485aaf9effSMark Brown 
49*b73dad80SJaroslav Kysela static const char *alsa_config =
50*b73dad80SJaroslav Kysela "ctl.hw {\n"
51*b73dad80SJaroslav Kysela "	@args [ CARD ]\n"
52*b73dad80SJaroslav Kysela "	@args.CARD.type string\n"
53*b73dad80SJaroslav Kysela "	type hw\n"
54*b73dad80SJaroslav Kysela "	card $CARD\n"
55*b73dad80SJaroslav Kysela "}\n"
56*b73dad80SJaroslav Kysela ;
57*b73dad80SJaroslav Kysela 
585aaf9effSMark Brown int num_cards = 0;
595aaf9effSMark Brown int num_controls = 0;
605aaf9effSMark Brown struct card_data *card_list = NULL;
615aaf9effSMark Brown struct ctl_data *ctl_list = NULL;
625aaf9effSMark Brown 
63*b73dad80SJaroslav Kysela #ifdef SND_LIB_VER
64*b73dad80SJaroslav Kysela #if SND_LIB_VERSION >= SND_LIB_VER(1, 2, 6)
65*b73dad80SJaroslav Kysela #define LIB_HAS_LOAD_STRING
66*b73dad80SJaroslav Kysela #endif
67*b73dad80SJaroslav Kysela #endif
68*b73dad80SJaroslav Kysela 
69*b73dad80SJaroslav Kysela #ifndef LIB_HAS_LOAD_STRING
70*b73dad80SJaroslav Kysela int snd_config_load_string(snd_config_t **config, const char *s, size_t size)
71*b73dad80SJaroslav Kysela {
72*b73dad80SJaroslav Kysela 	snd_input_t *input;
73*b73dad80SJaroslav Kysela 	snd_config_t *dst;
74*b73dad80SJaroslav Kysela 	int err;
75*b73dad80SJaroslav Kysela 
76*b73dad80SJaroslav Kysela 	assert(config && s);
77*b73dad80SJaroslav Kysela 	if (size == 0)
78*b73dad80SJaroslav Kysela 		size = strlen(s);
79*b73dad80SJaroslav Kysela 	err = snd_input_buffer_open(&input, s, size);
80*b73dad80SJaroslav Kysela 	if (err < 0)
81*b73dad80SJaroslav Kysela 		return err;
82*b73dad80SJaroslav Kysela 	err = snd_config_top(&dst);
83*b73dad80SJaroslav Kysela 	if (err < 0) {
84*b73dad80SJaroslav Kysela 		snd_input_close(input);
85*b73dad80SJaroslav Kysela 		return err;
86*b73dad80SJaroslav Kysela 	}
87*b73dad80SJaroslav Kysela 	err = snd_config_load(dst, input);
88*b73dad80SJaroslav Kysela 	snd_input_close(input);
89*b73dad80SJaroslav Kysela 	if (err < 0) {
90*b73dad80SJaroslav Kysela 		snd_config_delete(dst);
91*b73dad80SJaroslav Kysela 		return err;
92*b73dad80SJaroslav Kysela 	}
93*b73dad80SJaroslav Kysela 	*config = dst;
94*b73dad80SJaroslav Kysela 	return 0;
95*b73dad80SJaroslav Kysela }
96*b73dad80SJaroslav Kysela #endif
97*b73dad80SJaroslav Kysela 
985aaf9effSMark Brown void find_controls(void)
995aaf9effSMark Brown {
1005aaf9effSMark Brown 	char name[32];
1015aaf9effSMark Brown 	int card, ctl, err;
1025aaf9effSMark Brown 	struct card_data *card_data;
1035aaf9effSMark Brown 	struct ctl_data *ctl_data;
104*b73dad80SJaroslav Kysela 	snd_config_t *config;
1055aaf9effSMark Brown 
1065aaf9effSMark Brown 	card = -1;
1075aaf9effSMark Brown 	if (snd_card_next(&card) < 0 || card < 0)
1085aaf9effSMark Brown 		return;
1095aaf9effSMark Brown 
110*b73dad80SJaroslav Kysela 	err = snd_config_load_string(&config, alsa_config, strlen(alsa_config));
111*b73dad80SJaroslav Kysela 	if (err < 0) {
112*b73dad80SJaroslav Kysela 		ksft_print_msg("Unable to parse custom alsa-lib configuration: %s\n",
113*b73dad80SJaroslav Kysela 			       snd_strerror(err));
114*b73dad80SJaroslav Kysela 		ksft_exit_fail();
115*b73dad80SJaroslav Kysela 	}
116*b73dad80SJaroslav Kysela 
1175aaf9effSMark Brown 	while (card >= 0) {
1185aaf9effSMark Brown 		sprintf(name, "hw:%d", card);
1195aaf9effSMark Brown 
1205aaf9effSMark Brown 		card_data = malloc(sizeof(*card_data));
1215aaf9effSMark Brown 		if (!card_data)
1225aaf9effSMark Brown 			ksft_exit_fail_msg("Out of memory\n");
1235aaf9effSMark Brown 
124*b73dad80SJaroslav Kysela 		err = snd_ctl_open_lconf(&card_data->handle, name, 0, config);
1255aaf9effSMark Brown 		if (err < 0) {
1265aaf9effSMark Brown 			ksft_print_msg("Failed to get hctl for card %d: %s\n",
1275aaf9effSMark Brown 				       card, snd_strerror(err));
1285aaf9effSMark Brown 			goto next_card;
1295aaf9effSMark Brown 		}
1305aaf9effSMark Brown 
1315aaf9effSMark Brown 		/* Count controls */
1325aaf9effSMark Brown 		snd_ctl_elem_list_malloc(&card_data->ctls);
1335aaf9effSMark Brown 		snd_ctl_elem_list(card_data->handle, card_data->ctls);
1345aaf9effSMark Brown 		card_data->num_ctls = snd_ctl_elem_list_get_count(card_data->ctls);
1355aaf9effSMark Brown 
1365aaf9effSMark Brown 		/* Enumerate control information */
1375aaf9effSMark Brown 		snd_ctl_elem_list_alloc_space(card_data->ctls, card_data->num_ctls);
1385aaf9effSMark Brown 		snd_ctl_elem_list(card_data->handle, card_data->ctls);
1395aaf9effSMark Brown 
1405aaf9effSMark Brown 		card_data->card = num_cards++;
1415aaf9effSMark Brown 		card_data->next = card_list;
1425aaf9effSMark Brown 		card_list = card_data;
1435aaf9effSMark Brown 
1445aaf9effSMark Brown 		num_controls += card_data->num_ctls;
1455aaf9effSMark Brown 
1465aaf9effSMark Brown 		for (ctl = 0; ctl < card_data->num_ctls; ctl++) {
1475aaf9effSMark Brown 			ctl_data = malloc(sizeof(*ctl_data));
1485aaf9effSMark Brown 			if (!ctl_data)
1495aaf9effSMark Brown 				ksft_exit_fail_msg("Out of memory\n");
1505aaf9effSMark Brown 
1515aaf9effSMark Brown 			ctl_data->card = card_data;
1525aaf9effSMark Brown 			ctl_data->elem = ctl;
1535aaf9effSMark Brown 			ctl_data->name = snd_ctl_elem_list_get_name(card_data->ctls,
1545aaf9effSMark Brown 								    ctl);
1555aaf9effSMark Brown 
1565aaf9effSMark Brown 			err = snd_ctl_elem_id_malloc(&ctl_data->id);
1575aaf9effSMark Brown 			if (err < 0)
1585aaf9effSMark Brown 				ksft_exit_fail_msg("Out of memory\n");
1595aaf9effSMark Brown 
1605aaf9effSMark Brown 			err = snd_ctl_elem_info_malloc(&ctl_data->info);
1615aaf9effSMark Brown 			if (err < 0)
1625aaf9effSMark Brown 				ksft_exit_fail_msg("Out of memory\n");
1635aaf9effSMark Brown 
1645aaf9effSMark Brown 			err = snd_ctl_elem_value_malloc(&ctl_data->def_val);
1655aaf9effSMark Brown 			if (err < 0)
1665aaf9effSMark Brown 				ksft_exit_fail_msg("Out of memory\n");
1675aaf9effSMark Brown 
1685aaf9effSMark Brown 			snd_ctl_elem_list_get_id(card_data->ctls, ctl,
1695aaf9effSMark Brown 						 ctl_data->id);
1705aaf9effSMark Brown 			snd_ctl_elem_info_set_id(ctl_data->info, ctl_data->id);
1715aaf9effSMark Brown 			err = snd_ctl_elem_info(card_data->handle,
1725aaf9effSMark Brown 						ctl_data->info);
1735aaf9effSMark Brown 			if (err < 0) {
1745aaf9effSMark Brown 				ksft_print_msg("%s getting info for %d\n",
1755aaf9effSMark Brown 					       snd_strerror(err),
1765aaf9effSMark Brown 					       ctl_data->name);
1775aaf9effSMark Brown 			}
1785aaf9effSMark Brown 
1795aaf9effSMark Brown 			snd_ctl_elem_value_set_id(ctl_data->def_val,
1805aaf9effSMark Brown 						  ctl_data->id);
1815aaf9effSMark Brown 
1825aaf9effSMark Brown 			ctl_data->next = ctl_list;
1835aaf9effSMark Brown 			ctl_list = ctl_data;
1845aaf9effSMark Brown 		}
1855aaf9effSMark Brown 
1865aaf9effSMark Brown 	next_card:
1875aaf9effSMark Brown 		if (snd_card_next(&card) < 0) {
1885aaf9effSMark Brown 			ksft_print_msg("snd_card_next");
1895aaf9effSMark Brown 			break;
1905aaf9effSMark Brown 		}
1915aaf9effSMark Brown 	}
192*b73dad80SJaroslav Kysela 
193*b73dad80SJaroslav Kysela 	snd_config_delete(config);
1945aaf9effSMark Brown }
1955aaf9effSMark Brown 
1965aaf9effSMark Brown /*
1975aaf9effSMark Brown  * Check that we can read the default value and it is valid. Write
1985aaf9effSMark Brown  * tests use the read value to restore the default.
1995aaf9effSMark Brown  */
2005aaf9effSMark Brown void test_ctl_get_value(struct ctl_data *ctl)
2015aaf9effSMark Brown {
2025aaf9effSMark Brown 	int err;
2035aaf9effSMark Brown 	long int_val;
2045aaf9effSMark Brown 	long long int64_val;
2055aaf9effSMark Brown 
2065aaf9effSMark Brown 	/* If the control is turned off let's be polite */
2075aaf9effSMark Brown 	if (snd_ctl_elem_info_is_inactive(ctl->info)) {
2085aaf9effSMark Brown 		ksft_print_msg("%s is inactive\n", ctl->name);
2095aaf9effSMark Brown 		ksft_test_result_skip("get_value.%d.%d\n",
2105aaf9effSMark Brown 				      ctl->card->card, ctl->elem);
2115aaf9effSMark Brown 		return;
2125aaf9effSMark Brown 	}
2135aaf9effSMark Brown 
2145aaf9effSMark Brown 	/* Can't test reading on an unreadable control */
2155aaf9effSMark Brown 	if (!snd_ctl_elem_info_is_readable(ctl->info)) {
2165aaf9effSMark Brown 		ksft_print_msg("%s is not readable\n", ctl->name);
2175aaf9effSMark Brown 		ksft_test_result_skip("get_value.%d.%d\n",
2185aaf9effSMark Brown 				      ctl->card->card, ctl->elem);
2195aaf9effSMark Brown 		return;
2205aaf9effSMark Brown 	}
2215aaf9effSMark Brown 
2225aaf9effSMark Brown 	err = snd_ctl_elem_read(ctl->card->handle, ctl->def_val);
2235aaf9effSMark Brown 	if (err < 0) {
2245aaf9effSMark Brown 		ksft_print_msg("snd_ctl_elem_read() failed: %s\n",
2255aaf9effSMark Brown 			       snd_strerror(err));
2265aaf9effSMark Brown 		goto out;
2275aaf9effSMark Brown 	}
2285aaf9effSMark Brown 
2295aaf9effSMark Brown 	switch (snd_ctl_elem_info_get_type(ctl->info)) {
2305aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_NONE:
2315aaf9effSMark Brown 		ksft_print_msg("%s Invalid control type NONE\n", ctl->name);
2325aaf9effSMark Brown 		err = -1;
2335aaf9effSMark Brown 		break;
2345aaf9effSMark Brown 
2355aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_BOOLEAN:
2365aaf9effSMark Brown 		int_val = snd_ctl_elem_value_get_boolean(ctl->def_val, 0);
2375aaf9effSMark Brown 		switch (int_val) {
2385aaf9effSMark Brown 		case 0:
2395aaf9effSMark Brown 		case 1:
2405aaf9effSMark Brown 			break;
2415aaf9effSMark Brown 		default:
2425aaf9effSMark Brown 			ksft_print_msg("%s Invalid boolean value %ld\n",
2435aaf9effSMark Brown 				       ctl->name, int_val);
2445aaf9effSMark Brown 			err = -1;
2455aaf9effSMark Brown 			break;
2465aaf9effSMark Brown 		}
2475aaf9effSMark Brown 		break;
2485aaf9effSMark Brown 
2495aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_INTEGER:
2505aaf9effSMark Brown 		int_val = snd_ctl_elem_value_get_integer(ctl->def_val, 0);
2515aaf9effSMark Brown 
2525aaf9effSMark Brown 		if (int_val < snd_ctl_elem_info_get_min(ctl->info)) {
2535aaf9effSMark Brown 			ksft_print_msg("%s value %ld less than minimum %ld\n",
2545aaf9effSMark Brown 				       ctl->name, int_val,
2555aaf9effSMark Brown 				       snd_ctl_elem_info_get_min(ctl->info));
2565aaf9effSMark Brown 			err = -1;
2575aaf9effSMark Brown 		}
2585aaf9effSMark Brown 
2595aaf9effSMark Brown 		if (int_val > snd_ctl_elem_info_get_max(ctl->info)) {
2605aaf9effSMark Brown 			ksft_print_msg("%s value %ld more than maximum %ld\n",
2615aaf9effSMark Brown 				       ctl->name, int_val,
2625aaf9effSMark Brown 				       snd_ctl_elem_info_get_max(ctl->info));
2635aaf9effSMark Brown 			err = -1;
2645aaf9effSMark Brown 		}
2655aaf9effSMark Brown 
2665aaf9effSMark Brown 		/* Only check step size if there is one and we're in bounds */
2675aaf9effSMark Brown 		if (err >= 0 && snd_ctl_elem_info_get_step(ctl->info) &&
2685aaf9effSMark Brown 		    (int_val - snd_ctl_elem_info_get_min(ctl->info) %
2695aaf9effSMark Brown 		     snd_ctl_elem_info_get_step(ctl->info))) {
2705aaf9effSMark Brown 			ksft_print_msg("%s value %ld invalid for step %ld minimum %ld\n",
2715aaf9effSMark Brown 				       ctl->name, int_val,
2725aaf9effSMark Brown 				       snd_ctl_elem_info_get_step(ctl->info),
2735aaf9effSMark Brown 				       snd_ctl_elem_info_get_min(ctl->info));
2745aaf9effSMark Brown 			err = -1;
2755aaf9effSMark Brown 		}
2765aaf9effSMark Brown 		break;
2775aaf9effSMark Brown 
2785aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_INTEGER64:
2795aaf9effSMark Brown 		int64_val = snd_ctl_elem_value_get_integer64(ctl->def_val, 0);
2805aaf9effSMark Brown 
2815aaf9effSMark Brown 		if (int64_val < snd_ctl_elem_info_get_min64(ctl->info)) {
2825aaf9effSMark Brown 			ksft_print_msg("%s value %lld less than minimum %lld\n",
2835aaf9effSMark Brown 				       ctl->name, int64_val,
2845aaf9effSMark Brown 				       snd_ctl_elem_info_get_min64(ctl->info));
2855aaf9effSMark Brown 			err = -1;
2865aaf9effSMark Brown 		}
2875aaf9effSMark Brown 
2885aaf9effSMark Brown 		if (int64_val > snd_ctl_elem_info_get_max64(ctl->info)) {
2895aaf9effSMark Brown 			ksft_print_msg("%s value %lld more than maximum %lld\n",
2905aaf9effSMark Brown 				       ctl->name, int64_val,
2915aaf9effSMark Brown 				       snd_ctl_elem_info_get_max(ctl->info));
2925aaf9effSMark Brown 			err = -1;
2935aaf9effSMark Brown 		}
2945aaf9effSMark Brown 
2955aaf9effSMark Brown 		/* Only check step size if there is one and we're in bounds */
2965aaf9effSMark Brown 		if (err >= 0 && snd_ctl_elem_info_get_step64(ctl->info) &&
2975aaf9effSMark Brown 		    (int64_val - snd_ctl_elem_info_get_min64(ctl->info)) %
2985aaf9effSMark Brown 		    snd_ctl_elem_info_get_step64(ctl->info)) {
2995aaf9effSMark Brown 			ksft_print_msg("%s value %lld invalid for step %lld minimum %lld\n",
3005aaf9effSMark Brown 				       ctl->name, int64_val,
3015aaf9effSMark Brown 				       snd_ctl_elem_info_get_step64(ctl->info),
3025aaf9effSMark Brown 				       snd_ctl_elem_info_get_min64(ctl->info));
3035aaf9effSMark Brown 			err = -1;
3045aaf9effSMark Brown 		}
3055aaf9effSMark Brown 		break;
3065aaf9effSMark Brown 
3075aaf9effSMark Brown 	default:
3085aaf9effSMark Brown 		/* No tests for other types */
3095aaf9effSMark Brown 		ksft_test_result_skip("get_value.%d.%d\n",
3105aaf9effSMark Brown 				      ctl->card->card, ctl->elem);
3115aaf9effSMark Brown 		return;
3125aaf9effSMark Brown 	}
3135aaf9effSMark Brown 
3145aaf9effSMark Brown out:
3155aaf9effSMark Brown 	ksft_test_result(err >= 0, "get_value.%d.%d\n",
3165aaf9effSMark Brown 			 ctl->card->card, ctl->elem);
3175aaf9effSMark Brown }
3185aaf9effSMark Brown 
3195aaf9effSMark Brown bool show_mismatch(struct ctl_data *ctl, int index,
3205aaf9effSMark Brown 		   snd_ctl_elem_value_t *read_val,
3215aaf9effSMark Brown 		   snd_ctl_elem_value_t *expected_val)
3225aaf9effSMark Brown {
3235aaf9effSMark Brown 	long long expected_int, read_int;
3245aaf9effSMark Brown 
3255aaf9effSMark Brown 	/*
3265aaf9effSMark Brown 	 * We factor out the code to compare values representable as
3275aaf9effSMark Brown 	 * integers, ensure that check doesn't log otherwise.
3285aaf9effSMark Brown 	 */
3295aaf9effSMark Brown 	expected_int = 0;
3305aaf9effSMark Brown 	read_int = 0;
3315aaf9effSMark Brown 
3325aaf9effSMark Brown 	switch (snd_ctl_elem_info_get_type(ctl->info)) {
3335aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_BOOLEAN:
3345aaf9effSMark Brown 		expected_int = snd_ctl_elem_value_get_boolean(expected_val,
3355aaf9effSMark Brown 							      index);
3365aaf9effSMark Brown 		read_int = snd_ctl_elem_value_get_boolean(read_val, index);
3375aaf9effSMark Brown 		break;
3385aaf9effSMark Brown 
3395aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_INTEGER:
3405aaf9effSMark Brown 		expected_int = snd_ctl_elem_value_get_integer(expected_val,
3415aaf9effSMark Brown 							      index);
3425aaf9effSMark Brown 		read_int = snd_ctl_elem_value_get_integer(read_val, index);
3435aaf9effSMark Brown 		break;
3445aaf9effSMark Brown 
3455aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_INTEGER64:
3465aaf9effSMark Brown 		expected_int = snd_ctl_elem_value_get_integer64(expected_val,
3475aaf9effSMark Brown 								index);
3485aaf9effSMark Brown 		read_int = snd_ctl_elem_value_get_integer64(read_val,
3495aaf9effSMark Brown 							    index);
3505aaf9effSMark Brown 		break;
3515aaf9effSMark Brown 
3525aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_ENUMERATED:
3535aaf9effSMark Brown 		expected_int = snd_ctl_elem_value_get_enumerated(expected_val,
3545aaf9effSMark Brown 								 index);
3555aaf9effSMark Brown 		read_int = snd_ctl_elem_value_get_enumerated(read_val,
3565aaf9effSMark Brown 							     index);
3575aaf9effSMark Brown 		break;
3585aaf9effSMark Brown 
3595aaf9effSMark Brown 	default:
3605aaf9effSMark Brown 		break;
3615aaf9effSMark Brown 	}
3625aaf9effSMark Brown 
3635aaf9effSMark Brown 	if (expected_int != read_int) {
3647cc994f2STakashi Sakamoto 		/*
3657cc994f2STakashi Sakamoto 		 * NOTE: The volatile attribute means that the hardware
3667cc994f2STakashi Sakamoto 		 * can voluntarily change the state of control element
3677cc994f2STakashi Sakamoto 		 * independent of any operation by software.
3687cc994f2STakashi Sakamoto 		 */
3697cc994f2STakashi Sakamoto 		bool is_volatile = snd_ctl_elem_info_is_volatile(ctl->info);
3707cc994f2STakashi Sakamoto 		ksft_print_msg("%s.%d expected %lld but read %lld, is_volatile %d\n",
3717cc994f2STakashi Sakamoto 			       ctl->name, index, expected_int, read_int, is_volatile);
3727cc994f2STakashi Sakamoto 		return !is_volatile;
3735aaf9effSMark Brown 	} else {
3745aaf9effSMark Brown 		return false;
3755aaf9effSMark Brown 	}
3765aaf9effSMark Brown }
3775aaf9effSMark Brown 
3785aaf9effSMark Brown /*
3795aaf9effSMark Brown  * Write a value then if possible verify that we get the expected
3805aaf9effSMark Brown  * result.  An optional expected value can be provided if we expect
3815aaf9effSMark Brown  * the write to fail, for verifying that invalid writes don't corrupt
3825aaf9effSMark Brown  * anything.
3835aaf9effSMark Brown  */
3845aaf9effSMark Brown int write_and_verify(struct ctl_data *ctl,
3855aaf9effSMark Brown 		     snd_ctl_elem_value_t *write_val,
3865aaf9effSMark Brown 		     snd_ctl_elem_value_t *expected_val)
3875aaf9effSMark Brown {
3885aaf9effSMark Brown 	int err, i;
3895aaf9effSMark Brown 	bool error_expected, mismatch_shown;
3905aaf9effSMark Brown 	snd_ctl_elem_value_t *read_val, *w_val;
3915aaf9effSMark Brown 	snd_ctl_elem_value_alloca(&read_val);
3925aaf9effSMark Brown 	snd_ctl_elem_value_alloca(&w_val);
3935aaf9effSMark Brown 
3945aaf9effSMark Brown 	/*
3955aaf9effSMark Brown 	 * We need to copy the write value since writing can modify
3965aaf9effSMark Brown 	 * the value which causes surprises, and allocate an expected
3975aaf9effSMark Brown 	 * value if we expect to read back what we wrote.
3985aaf9effSMark Brown 	 */
3995aaf9effSMark Brown 	snd_ctl_elem_value_copy(w_val, write_val);
4005aaf9effSMark Brown 	if (expected_val) {
4015aaf9effSMark Brown 		error_expected = true;
4025aaf9effSMark Brown 	} else {
4035aaf9effSMark Brown 		error_expected = false;
4045aaf9effSMark Brown 		snd_ctl_elem_value_alloca(&expected_val);
4055aaf9effSMark Brown 		snd_ctl_elem_value_copy(expected_val, write_val);
4065aaf9effSMark Brown 	}
4075aaf9effSMark Brown 
4085aaf9effSMark Brown 	/*
4095aaf9effSMark Brown 	 * Do the write, if we have an expected value ignore the error
4105aaf9effSMark Brown 	 * and carry on to validate the expected value.
4115aaf9effSMark Brown 	 */
4125aaf9effSMark Brown 	err = snd_ctl_elem_write(ctl->card->handle, w_val);
4135aaf9effSMark Brown 	if (err < 0 && !error_expected) {
4145aaf9effSMark Brown 		ksft_print_msg("snd_ctl_elem_write() failed: %s\n",
4155aaf9effSMark Brown 			       snd_strerror(err));
4165aaf9effSMark Brown 		return err;
4175aaf9effSMark Brown 	}
4185aaf9effSMark Brown 
4195aaf9effSMark Brown 	/* Can we do the verification part? */
4205aaf9effSMark Brown 	if (!snd_ctl_elem_info_is_readable(ctl->info))
4215aaf9effSMark Brown 		return err;
4225aaf9effSMark Brown 
4235aaf9effSMark Brown 	snd_ctl_elem_value_set_id(read_val, ctl->id);
4245aaf9effSMark Brown 
4255aaf9effSMark Brown 	err = snd_ctl_elem_read(ctl->card->handle, read_val);
4265aaf9effSMark Brown 	if (err < 0) {
4275aaf9effSMark Brown 		ksft_print_msg("snd_ctl_elem_read() failed: %s\n",
4285aaf9effSMark Brown 			       snd_strerror(err));
4295aaf9effSMark Brown 		return err;
4305aaf9effSMark Brown 	}
4315aaf9effSMark Brown 
4325aaf9effSMark Brown 	/*
4335aaf9effSMark Brown 	 * Use the libray to compare values, if there's a mismatch
4345aaf9effSMark Brown 	 * carry on and try to provide a more useful diagnostic than
4355aaf9effSMark Brown 	 * just "mismatch".
4365aaf9effSMark Brown 	 */
4375aaf9effSMark Brown 	if (!snd_ctl_elem_value_compare(expected_val, read_val))
4385aaf9effSMark Brown 		return 0;
4395aaf9effSMark Brown 
4405aaf9effSMark Brown 	mismatch_shown = false;
4415aaf9effSMark Brown 	for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++)
4425aaf9effSMark Brown 		if (show_mismatch(ctl, i, read_val, expected_val))
4435aaf9effSMark Brown 			mismatch_shown = true;
4445aaf9effSMark Brown 
4455aaf9effSMark Brown 	if (!mismatch_shown)
4465aaf9effSMark Brown 		ksft_print_msg("%s read and written values differ\n",
4475aaf9effSMark Brown 			       ctl->name);
4485aaf9effSMark Brown 
4495aaf9effSMark Brown 	return -1;
4505aaf9effSMark Brown }
4515aaf9effSMark Brown 
4525aaf9effSMark Brown /*
4535aaf9effSMark Brown  * Make sure we can write the default value back to the control, this
4545aaf9effSMark Brown  * should validate that at least some write works.
4555aaf9effSMark Brown  */
4565aaf9effSMark Brown void test_ctl_write_default(struct ctl_data *ctl)
4575aaf9effSMark Brown {
4585aaf9effSMark Brown 	int err;
4595aaf9effSMark Brown 
4605aaf9effSMark Brown 	/* If the control is turned off let's be polite */
4615aaf9effSMark Brown 	if (snd_ctl_elem_info_is_inactive(ctl->info)) {
4625aaf9effSMark Brown 		ksft_print_msg("%s is inactive\n", ctl->name);
4635aaf9effSMark Brown 		ksft_test_result_skip("write_default.%d.%d\n",
4645aaf9effSMark Brown 				      ctl->card->card, ctl->elem);
4655aaf9effSMark Brown 		return;
4665aaf9effSMark Brown 	}
4675aaf9effSMark Brown 
4685aaf9effSMark Brown 	if (!snd_ctl_elem_info_is_writable(ctl->info)) {
4695aaf9effSMark Brown 		ksft_print_msg("%s is not writeable\n", ctl->name);
4705aaf9effSMark Brown 		ksft_test_result_skip("write_default.%d.%d\n",
4715aaf9effSMark Brown 				      ctl->card->card, ctl->elem);
4725aaf9effSMark Brown 		return;
4735aaf9effSMark Brown 	}
4745aaf9effSMark Brown 
4755aaf9effSMark Brown 	/* No idea what the default was for unreadable controls */
4765aaf9effSMark Brown 	if (!snd_ctl_elem_info_is_readable(ctl->info)) {
4775aaf9effSMark Brown 		ksft_print_msg("%s couldn't read default\n", ctl->name);
4785aaf9effSMark Brown 		ksft_test_result_skip("write_default.%d.%d\n",
4795aaf9effSMark Brown 				      ctl->card->card, ctl->elem);
4805aaf9effSMark Brown 		return;
4815aaf9effSMark Brown 	}
4825aaf9effSMark Brown 
4835aaf9effSMark Brown 	err = write_and_verify(ctl, ctl->def_val, NULL);
4845aaf9effSMark Brown 
4855aaf9effSMark Brown 	ksft_test_result(err >= 0, "write_default.%d.%d\n",
4865aaf9effSMark Brown 			 ctl->card->card, ctl->elem);
4875aaf9effSMark Brown }
4885aaf9effSMark Brown 
4895aaf9effSMark Brown bool test_ctl_write_valid_boolean(struct ctl_data *ctl)
4905aaf9effSMark Brown {
4915aaf9effSMark Brown 	int err, i, j;
4925aaf9effSMark Brown 	bool fail = false;
4935aaf9effSMark Brown 	snd_ctl_elem_value_t *val;
4945aaf9effSMark Brown 	snd_ctl_elem_value_alloca(&val);
4955aaf9effSMark Brown 
4965aaf9effSMark Brown 	snd_ctl_elem_value_set_id(val, ctl->id);
4975aaf9effSMark Brown 
4985aaf9effSMark Brown 	for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
4995aaf9effSMark Brown 		for (j = 0; j < 2; j++) {
5005aaf9effSMark Brown 			snd_ctl_elem_value_set_boolean(val, i, j);
5015aaf9effSMark Brown 			err = write_and_verify(ctl, val, NULL);
5025aaf9effSMark Brown 			if (err != 0)
5035aaf9effSMark Brown 				fail = true;
5045aaf9effSMark Brown 		}
5055aaf9effSMark Brown 	}
5065aaf9effSMark Brown 
5075aaf9effSMark Brown 	return !fail;
5085aaf9effSMark Brown }
5095aaf9effSMark Brown 
5105aaf9effSMark Brown bool test_ctl_write_valid_integer(struct ctl_data *ctl)
5115aaf9effSMark Brown {
5125aaf9effSMark Brown 	int err;
5135aaf9effSMark Brown 	int i;
5145aaf9effSMark Brown 	long j, step;
5155aaf9effSMark Brown 	bool fail = false;
5165aaf9effSMark Brown 	snd_ctl_elem_value_t *val;
5175aaf9effSMark Brown 	snd_ctl_elem_value_alloca(&val);
5185aaf9effSMark Brown 
5195aaf9effSMark Brown 	snd_ctl_elem_value_set_id(val, ctl->id);
5205aaf9effSMark Brown 
5215aaf9effSMark Brown 	step = snd_ctl_elem_info_get_step(ctl->info);
5225aaf9effSMark Brown 	if (!step)
5235aaf9effSMark Brown 		step = 1;
5245aaf9effSMark Brown 
5255aaf9effSMark Brown 	for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
5265aaf9effSMark Brown 		for (j = snd_ctl_elem_info_get_min(ctl->info);
5275aaf9effSMark Brown 		     j <= snd_ctl_elem_info_get_max(ctl->info); j += step) {
5285aaf9effSMark Brown 
5295aaf9effSMark Brown 			snd_ctl_elem_value_set_integer(val, i, j);
5305aaf9effSMark Brown 			err = write_and_verify(ctl, val, NULL);
5315aaf9effSMark Brown 			if (err != 0)
5325aaf9effSMark Brown 				fail = true;
5335aaf9effSMark Brown 		}
5345aaf9effSMark Brown 	}
5355aaf9effSMark Brown 
5365aaf9effSMark Brown 
5375aaf9effSMark Brown 	return !fail;
5385aaf9effSMark Brown }
5395aaf9effSMark Brown 
5405aaf9effSMark Brown bool test_ctl_write_valid_integer64(struct ctl_data *ctl)
5415aaf9effSMark Brown {
5425aaf9effSMark Brown 	int err, i;
5435aaf9effSMark Brown 	long long j, step;
5445aaf9effSMark Brown 	bool fail = false;
5455aaf9effSMark Brown 	snd_ctl_elem_value_t *val;
5465aaf9effSMark Brown 	snd_ctl_elem_value_alloca(&val);
5475aaf9effSMark Brown 
5485aaf9effSMark Brown 	snd_ctl_elem_value_set_id(val, ctl->id);
5495aaf9effSMark Brown 
5505aaf9effSMark Brown 	step = snd_ctl_elem_info_get_step64(ctl->info);
5515aaf9effSMark Brown 	if (!step)
5525aaf9effSMark Brown 		step = 1;
5535aaf9effSMark Brown 
5545aaf9effSMark Brown 	for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
5555aaf9effSMark Brown 		for (j = snd_ctl_elem_info_get_min64(ctl->info);
5565aaf9effSMark Brown 		     j <= snd_ctl_elem_info_get_max64(ctl->info); j += step) {
5575aaf9effSMark Brown 
5585aaf9effSMark Brown 			snd_ctl_elem_value_set_integer64(val, i, j);
5595aaf9effSMark Brown 			err = write_and_verify(ctl, val, NULL);
5605aaf9effSMark Brown 			if (err != 0)
5615aaf9effSMark Brown 				fail = true;
5625aaf9effSMark Brown 		}
5635aaf9effSMark Brown 	}
5645aaf9effSMark Brown 
5655aaf9effSMark Brown 	return !fail;
5665aaf9effSMark Brown }
5675aaf9effSMark Brown 
5685aaf9effSMark Brown bool test_ctl_write_valid_enumerated(struct ctl_data *ctl)
5695aaf9effSMark Brown {
5705aaf9effSMark Brown 	int err, i, j;
5715aaf9effSMark Brown 	bool fail = false;
5725aaf9effSMark Brown 	snd_ctl_elem_value_t *val;
5735aaf9effSMark Brown 	snd_ctl_elem_value_alloca(&val);
5745aaf9effSMark Brown 
5755aaf9effSMark Brown 	snd_ctl_elem_value_set_id(val, ctl->id);
5765aaf9effSMark Brown 
5775aaf9effSMark Brown 	for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
5785aaf9effSMark Brown 		for (j = 0; j < snd_ctl_elem_info_get_items(ctl->info); j++) {
5795aaf9effSMark Brown 			snd_ctl_elem_value_set_enumerated(val, i, j);
5805aaf9effSMark Brown 			err = write_and_verify(ctl, val, NULL);
5815aaf9effSMark Brown 			if (err != 0)
5825aaf9effSMark Brown 				fail = true;
5835aaf9effSMark Brown 		}
5845aaf9effSMark Brown 	}
5855aaf9effSMark Brown 
5865aaf9effSMark Brown 	return !fail;
5875aaf9effSMark Brown }
5885aaf9effSMark Brown 
5895aaf9effSMark Brown void test_ctl_write_valid(struct ctl_data *ctl)
5905aaf9effSMark Brown {
5915aaf9effSMark Brown 	bool pass;
5925aaf9effSMark Brown 	int err;
5935aaf9effSMark Brown 
5945aaf9effSMark Brown 	/* If the control is turned off let's be polite */
5955aaf9effSMark Brown 	if (snd_ctl_elem_info_is_inactive(ctl->info)) {
5965aaf9effSMark Brown 		ksft_print_msg("%s is inactive\n", ctl->name);
5975aaf9effSMark Brown 		ksft_test_result_skip("write_valid.%d.%d\n",
5985aaf9effSMark Brown 				      ctl->card->card, ctl->elem);
5995aaf9effSMark Brown 		return;
6005aaf9effSMark Brown 	}
6015aaf9effSMark Brown 
6025aaf9effSMark Brown 	if (!snd_ctl_elem_info_is_writable(ctl->info)) {
6035aaf9effSMark Brown 		ksft_print_msg("%s is not writeable\n", ctl->name);
6045aaf9effSMark Brown 		ksft_test_result_skip("write_valid.%d.%d\n",
6055aaf9effSMark Brown 				      ctl->card->card, ctl->elem);
6065aaf9effSMark Brown 		return;
6075aaf9effSMark Brown 	}
6085aaf9effSMark Brown 
6095aaf9effSMark Brown 	switch (snd_ctl_elem_info_get_type(ctl->info)) {
6105aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_BOOLEAN:
6115aaf9effSMark Brown 		pass = test_ctl_write_valid_boolean(ctl);
6125aaf9effSMark Brown 		break;
6135aaf9effSMark Brown 
6145aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_INTEGER:
6155aaf9effSMark Brown 		pass = test_ctl_write_valid_integer(ctl);
6165aaf9effSMark Brown 		break;
6175aaf9effSMark Brown 
6185aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_INTEGER64:
6195aaf9effSMark Brown 		pass = test_ctl_write_valid_integer64(ctl);
6205aaf9effSMark Brown 		break;
6215aaf9effSMark Brown 
6225aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_ENUMERATED:
6235aaf9effSMark Brown 		pass = test_ctl_write_valid_enumerated(ctl);
6245aaf9effSMark Brown 		break;
6255aaf9effSMark Brown 
6265aaf9effSMark Brown 	default:
6275aaf9effSMark Brown 		/* No tests for this yet */
6285aaf9effSMark Brown 		ksft_test_result_skip("write_valid.%d.%d\n",
6295aaf9effSMark Brown 				      ctl->card->card, ctl->elem);
6305aaf9effSMark Brown 		return;
6315aaf9effSMark Brown 	}
6325aaf9effSMark Brown 
6335aaf9effSMark Brown 	/* Restore the default value to minimise disruption */
6345aaf9effSMark Brown 	err = write_and_verify(ctl, ctl->def_val, NULL);
6355aaf9effSMark Brown 	if (err < 0)
6365aaf9effSMark Brown 		pass = false;
6375aaf9effSMark Brown 
6385aaf9effSMark Brown 	ksft_test_result(pass, "write_valid.%d.%d\n",
6395aaf9effSMark Brown 			 ctl->card->card, ctl->elem);
6405aaf9effSMark Brown }
6415aaf9effSMark Brown 
6425aaf9effSMark Brown int main(void)
6435aaf9effSMark Brown {
6445aaf9effSMark Brown 	struct ctl_data *ctl;
6455aaf9effSMark Brown 
6465aaf9effSMark Brown 	ksft_print_header();
6475aaf9effSMark Brown 
6485aaf9effSMark Brown 	find_controls();
6495aaf9effSMark Brown 
6505aaf9effSMark Brown 	ksft_set_plan(num_controls * TESTS_PER_CONTROL);
6515aaf9effSMark Brown 
6525aaf9effSMark Brown 	for (ctl = ctl_list; ctl != NULL; ctl = ctl->next) {
6535aaf9effSMark Brown 		/*
6545aaf9effSMark Brown 		 * Must test get_value() before we write anything, the
6555aaf9effSMark Brown 		 * test stores the default value for later cleanup.
6565aaf9effSMark Brown 		 */
6575aaf9effSMark Brown 		test_ctl_get_value(ctl);
6585aaf9effSMark Brown 		test_ctl_write_default(ctl);
6595aaf9effSMark Brown 		test_ctl_write_valid(ctl);
6605aaf9effSMark Brown 	}
6615aaf9effSMark Brown 
6625aaf9effSMark Brown 	ksft_exit_pass();
6635aaf9effSMark Brown 
6645aaf9effSMark Brown 	return 0;
6655aaf9effSMark Brown }
666