xref: /openbmc/linux/tools/testing/selftests/alsa/mixer-test.c (revision 5aaf9efffc57ea31a13af6f0bf41e96f073ed6d5)
1*5aaf9effSMark Brown // SPDX-License-Identifier: GPL-2.0
2*5aaf9effSMark Brown //
3*5aaf9effSMark Brown // kselftest for the ALSA mixer API
4*5aaf9effSMark Brown //
5*5aaf9effSMark Brown // Original author: Mark Brown <broonie@kernel.org>
6*5aaf9effSMark Brown // Copyright (c) 2021 Arm Limited
7*5aaf9effSMark Brown 
8*5aaf9effSMark Brown // This test will iterate over all cards detected in the system, exercising
9*5aaf9effSMark Brown // every mixer control it can find.  This may conflict with other system
10*5aaf9effSMark Brown // software if there is audio activity so is best run on a system with a
11*5aaf9effSMark Brown // minimal active userspace.
12*5aaf9effSMark Brown 
13*5aaf9effSMark Brown #include <stdio.h>
14*5aaf9effSMark Brown #include <stdlib.h>
15*5aaf9effSMark Brown #include <stdbool.h>
16*5aaf9effSMark Brown #include <string.h>
17*5aaf9effSMark Brown #include <getopt.h>
18*5aaf9effSMark Brown #include <stdarg.h>
19*5aaf9effSMark Brown #include <ctype.h>
20*5aaf9effSMark Brown #include <math.h>
21*5aaf9effSMark Brown #include <errno.h>
22*5aaf9effSMark Brown #include <assert.h>
23*5aaf9effSMark Brown #include <alsa/asoundlib.h>
24*5aaf9effSMark Brown #include <poll.h>
25*5aaf9effSMark Brown #include <stdint.h>
26*5aaf9effSMark Brown 
27*5aaf9effSMark Brown #include "../kselftest.h"
28*5aaf9effSMark Brown 
29*5aaf9effSMark Brown #define TESTS_PER_CONTROL 3
30*5aaf9effSMark Brown 
31*5aaf9effSMark Brown struct card_data {
32*5aaf9effSMark Brown 	snd_ctl_t *handle;
33*5aaf9effSMark Brown 	int card;
34*5aaf9effSMark Brown 	int num_ctls;
35*5aaf9effSMark Brown 	snd_ctl_elem_list_t *ctls;
36*5aaf9effSMark Brown 	struct card_data *next;
37*5aaf9effSMark Brown };
38*5aaf9effSMark Brown 
39*5aaf9effSMark Brown struct ctl_data {
40*5aaf9effSMark Brown 	const char *name;
41*5aaf9effSMark Brown 	snd_ctl_elem_id_t *id;
42*5aaf9effSMark Brown 	snd_ctl_elem_info_t *info;
43*5aaf9effSMark Brown 	snd_ctl_elem_value_t *def_val;
44*5aaf9effSMark Brown 	int elem;
45*5aaf9effSMark Brown 	struct card_data *card;
46*5aaf9effSMark Brown 	struct ctl_data *next;
47*5aaf9effSMark Brown };
48*5aaf9effSMark Brown 
49*5aaf9effSMark Brown int num_cards = 0;
50*5aaf9effSMark Brown int num_controls = 0;
51*5aaf9effSMark Brown struct card_data *card_list = NULL;
52*5aaf9effSMark Brown struct ctl_data *ctl_list = NULL;
53*5aaf9effSMark Brown 
54*5aaf9effSMark Brown void find_controls(void)
55*5aaf9effSMark Brown {
56*5aaf9effSMark Brown 	char name[32];
57*5aaf9effSMark Brown 	int card, ctl, err;
58*5aaf9effSMark Brown 	struct card_data *card_data;
59*5aaf9effSMark Brown 	struct ctl_data *ctl_data;
60*5aaf9effSMark Brown 
61*5aaf9effSMark Brown 	card = -1;
62*5aaf9effSMark Brown 	if (snd_card_next(&card) < 0 || card < 0)
63*5aaf9effSMark Brown 		return;
64*5aaf9effSMark Brown 
65*5aaf9effSMark Brown 	while (card >= 0) {
66*5aaf9effSMark Brown 		sprintf(name, "hw:%d", card);
67*5aaf9effSMark Brown 
68*5aaf9effSMark Brown 		card_data = malloc(sizeof(*card_data));
69*5aaf9effSMark Brown 		if (!card_data)
70*5aaf9effSMark Brown 			ksft_exit_fail_msg("Out of memory\n");
71*5aaf9effSMark Brown 
72*5aaf9effSMark Brown 		err = snd_ctl_open(&card_data->handle, name, 0);
73*5aaf9effSMark Brown 		if (err < 0) {
74*5aaf9effSMark Brown 			ksft_print_msg("Failed to get hctl for card %d: %s\n",
75*5aaf9effSMark Brown 				       card, snd_strerror(err));
76*5aaf9effSMark Brown 			goto next_card;
77*5aaf9effSMark Brown 		}
78*5aaf9effSMark Brown 
79*5aaf9effSMark Brown 		/* Count controls */
80*5aaf9effSMark Brown 		snd_ctl_elem_list_malloc(&card_data->ctls);
81*5aaf9effSMark Brown 		snd_ctl_elem_list(card_data->handle, card_data->ctls);
82*5aaf9effSMark Brown 		card_data->num_ctls = snd_ctl_elem_list_get_count(card_data->ctls);
83*5aaf9effSMark Brown 
84*5aaf9effSMark Brown 		/* Enumerate control information */
85*5aaf9effSMark Brown 		snd_ctl_elem_list_alloc_space(card_data->ctls, card_data->num_ctls);
86*5aaf9effSMark Brown 		snd_ctl_elem_list(card_data->handle, card_data->ctls);
87*5aaf9effSMark Brown 
88*5aaf9effSMark Brown 		card_data->card = num_cards++;
89*5aaf9effSMark Brown 		card_data->next = card_list;
90*5aaf9effSMark Brown 		card_list = card_data;
91*5aaf9effSMark Brown 
92*5aaf9effSMark Brown 		num_controls += card_data->num_ctls;
93*5aaf9effSMark Brown 
94*5aaf9effSMark Brown 		for (ctl = 0; ctl < card_data->num_ctls; ctl++) {
95*5aaf9effSMark Brown 			ctl_data = malloc(sizeof(*ctl_data));
96*5aaf9effSMark Brown 			if (!ctl_data)
97*5aaf9effSMark Brown 				ksft_exit_fail_msg("Out of memory\n");
98*5aaf9effSMark Brown 
99*5aaf9effSMark Brown 			ctl_data->card = card_data;
100*5aaf9effSMark Brown 			ctl_data->elem = ctl;
101*5aaf9effSMark Brown 			ctl_data->name = snd_ctl_elem_list_get_name(card_data->ctls,
102*5aaf9effSMark Brown 								    ctl);
103*5aaf9effSMark Brown 
104*5aaf9effSMark Brown 			err = snd_ctl_elem_id_malloc(&ctl_data->id);
105*5aaf9effSMark Brown 			if (err < 0)
106*5aaf9effSMark Brown 				ksft_exit_fail_msg("Out of memory\n");
107*5aaf9effSMark Brown 
108*5aaf9effSMark Brown 			err = snd_ctl_elem_info_malloc(&ctl_data->info);
109*5aaf9effSMark Brown 			if (err < 0)
110*5aaf9effSMark Brown 				ksft_exit_fail_msg("Out of memory\n");
111*5aaf9effSMark Brown 
112*5aaf9effSMark Brown 			err = snd_ctl_elem_value_malloc(&ctl_data->def_val);
113*5aaf9effSMark Brown 			if (err < 0)
114*5aaf9effSMark Brown 				ksft_exit_fail_msg("Out of memory\n");
115*5aaf9effSMark Brown 
116*5aaf9effSMark Brown 			snd_ctl_elem_list_get_id(card_data->ctls, ctl,
117*5aaf9effSMark Brown 						 ctl_data->id);
118*5aaf9effSMark Brown 			snd_ctl_elem_info_set_id(ctl_data->info, ctl_data->id);
119*5aaf9effSMark Brown 			err = snd_ctl_elem_info(card_data->handle,
120*5aaf9effSMark Brown 						ctl_data->info);
121*5aaf9effSMark Brown 			if (err < 0) {
122*5aaf9effSMark Brown 				ksft_print_msg("%s getting info for %d\n",
123*5aaf9effSMark Brown 					       snd_strerror(err),
124*5aaf9effSMark Brown 					       ctl_data->name);
125*5aaf9effSMark Brown 			}
126*5aaf9effSMark Brown 
127*5aaf9effSMark Brown 			snd_ctl_elem_value_set_id(ctl_data->def_val,
128*5aaf9effSMark Brown 						  ctl_data->id);
129*5aaf9effSMark Brown 
130*5aaf9effSMark Brown 			ctl_data->next = ctl_list;
131*5aaf9effSMark Brown 			ctl_list = ctl_data;
132*5aaf9effSMark Brown 		}
133*5aaf9effSMark Brown 
134*5aaf9effSMark Brown 	next_card:
135*5aaf9effSMark Brown 		if (snd_card_next(&card) < 0) {
136*5aaf9effSMark Brown 			ksft_print_msg("snd_card_next");
137*5aaf9effSMark Brown 			break;
138*5aaf9effSMark Brown 		}
139*5aaf9effSMark Brown 	}
140*5aaf9effSMark Brown }
141*5aaf9effSMark Brown 
142*5aaf9effSMark Brown /*
143*5aaf9effSMark Brown  * Check that we can read the default value and it is valid. Write
144*5aaf9effSMark Brown  * tests use the read value to restore the default.
145*5aaf9effSMark Brown  */
146*5aaf9effSMark Brown void test_ctl_get_value(struct ctl_data *ctl)
147*5aaf9effSMark Brown {
148*5aaf9effSMark Brown 	int err;
149*5aaf9effSMark Brown 	long int_val;
150*5aaf9effSMark Brown 	long long int64_val;
151*5aaf9effSMark Brown 
152*5aaf9effSMark Brown 	/* If the control is turned off let's be polite */
153*5aaf9effSMark Brown 	if (snd_ctl_elem_info_is_inactive(ctl->info)) {
154*5aaf9effSMark Brown 		ksft_print_msg("%s is inactive\n", ctl->name);
155*5aaf9effSMark Brown 		ksft_test_result_skip("get_value.%d.%d\n",
156*5aaf9effSMark Brown 				      ctl->card->card, ctl->elem);
157*5aaf9effSMark Brown 		return;
158*5aaf9effSMark Brown 	}
159*5aaf9effSMark Brown 
160*5aaf9effSMark Brown 	/* Can't test reading on an unreadable control */
161*5aaf9effSMark Brown 	if (!snd_ctl_elem_info_is_readable(ctl->info)) {
162*5aaf9effSMark Brown 		ksft_print_msg("%s is not readable\n", ctl->name);
163*5aaf9effSMark Brown 		ksft_test_result_skip("get_value.%d.%d\n",
164*5aaf9effSMark Brown 				      ctl->card->card, ctl->elem);
165*5aaf9effSMark Brown 		return;
166*5aaf9effSMark Brown 	}
167*5aaf9effSMark Brown 
168*5aaf9effSMark Brown 	err = snd_ctl_elem_read(ctl->card->handle, ctl->def_val);
169*5aaf9effSMark Brown 	if (err < 0) {
170*5aaf9effSMark Brown 		ksft_print_msg("snd_ctl_elem_read() failed: %s\n",
171*5aaf9effSMark Brown 			       snd_strerror(err));
172*5aaf9effSMark Brown 		goto out;
173*5aaf9effSMark Brown 	}
174*5aaf9effSMark Brown 
175*5aaf9effSMark Brown 	switch (snd_ctl_elem_info_get_type(ctl->info)) {
176*5aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_NONE:
177*5aaf9effSMark Brown 		ksft_print_msg("%s Invalid control type NONE\n", ctl->name);
178*5aaf9effSMark Brown 		err = -1;
179*5aaf9effSMark Brown 		break;
180*5aaf9effSMark Brown 
181*5aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_BOOLEAN:
182*5aaf9effSMark Brown 		int_val = snd_ctl_elem_value_get_boolean(ctl->def_val, 0);
183*5aaf9effSMark Brown 		switch (int_val) {
184*5aaf9effSMark Brown 		case 0:
185*5aaf9effSMark Brown 		case 1:
186*5aaf9effSMark Brown 			break;
187*5aaf9effSMark Brown 		default:
188*5aaf9effSMark Brown 			ksft_print_msg("%s Invalid boolean value %ld\n",
189*5aaf9effSMark Brown 				       ctl->name, int_val);
190*5aaf9effSMark Brown 			err = -1;
191*5aaf9effSMark Brown 			break;
192*5aaf9effSMark Brown 		}
193*5aaf9effSMark Brown 		break;
194*5aaf9effSMark Brown 
195*5aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_INTEGER:
196*5aaf9effSMark Brown 		int_val = snd_ctl_elem_value_get_integer(ctl->def_val, 0);
197*5aaf9effSMark Brown 
198*5aaf9effSMark Brown 		if (int_val < snd_ctl_elem_info_get_min(ctl->info)) {
199*5aaf9effSMark Brown 			ksft_print_msg("%s value %ld less than minimum %ld\n",
200*5aaf9effSMark Brown 				       ctl->name, int_val,
201*5aaf9effSMark Brown 				       snd_ctl_elem_info_get_min(ctl->info));
202*5aaf9effSMark Brown 			err = -1;
203*5aaf9effSMark Brown 		}
204*5aaf9effSMark Brown 
205*5aaf9effSMark Brown 		if (int_val > snd_ctl_elem_info_get_max(ctl->info)) {
206*5aaf9effSMark Brown 			ksft_print_msg("%s value %ld more than maximum %ld\n",
207*5aaf9effSMark Brown 				       ctl->name, int_val,
208*5aaf9effSMark Brown 				       snd_ctl_elem_info_get_max(ctl->info));
209*5aaf9effSMark Brown 			err = -1;
210*5aaf9effSMark Brown 		}
211*5aaf9effSMark Brown 
212*5aaf9effSMark Brown 		/* Only check step size if there is one and we're in bounds */
213*5aaf9effSMark Brown 		if (err >= 0 && snd_ctl_elem_info_get_step(ctl->info) &&
214*5aaf9effSMark Brown 		    (int_val - snd_ctl_elem_info_get_min(ctl->info) %
215*5aaf9effSMark Brown 		     snd_ctl_elem_info_get_step(ctl->info))) {
216*5aaf9effSMark Brown 			ksft_print_msg("%s value %ld invalid for step %ld minimum %ld\n",
217*5aaf9effSMark Brown 				       ctl->name, int_val,
218*5aaf9effSMark Brown 				       snd_ctl_elem_info_get_step(ctl->info),
219*5aaf9effSMark Brown 				       snd_ctl_elem_info_get_min(ctl->info));
220*5aaf9effSMark Brown 			err = -1;
221*5aaf9effSMark Brown 		}
222*5aaf9effSMark Brown 		break;
223*5aaf9effSMark Brown 
224*5aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_INTEGER64:
225*5aaf9effSMark Brown 		int64_val = snd_ctl_elem_value_get_integer64(ctl->def_val, 0);
226*5aaf9effSMark Brown 
227*5aaf9effSMark Brown 		if (int64_val < snd_ctl_elem_info_get_min64(ctl->info)) {
228*5aaf9effSMark Brown 			ksft_print_msg("%s value %lld less than minimum %lld\n",
229*5aaf9effSMark Brown 				       ctl->name, int64_val,
230*5aaf9effSMark Brown 				       snd_ctl_elem_info_get_min64(ctl->info));
231*5aaf9effSMark Brown 			err = -1;
232*5aaf9effSMark Brown 		}
233*5aaf9effSMark Brown 
234*5aaf9effSMark Brown 		if (int64_val > snd_ctl_elem_info_get_max64(ctl->info)) {
235*5aaf9effSMark Brown 			ksft_print_msg("%s value %lld more than maximum %lld\n",
236*5aaf9effSMark Brown 				       ctl->name, int64_val,
237*5aaf9effSMark Brown 				       snd_ctl_elem_info_get_max(ctl->info));
238*5aaf9effSMark Brown 			err = -1;
239*5aaf9effSMark Brown 		}
240*5aaf9effSMark Brown 
241*5aaf9effSMark Brown 		/* Only check step size if there is one and we're in bounds */
242*5aaf9effSMark Brown 		if (err >= 0 && snd_ctl_elem_info_get_step64(ctl->info) &&
243*5aaf9effSMark Brown 		    (int64_val - snd_ctl_elem_info_get_min64(ctl->info)) %
244*5aaf9effSMark Brown 		    snd_ctl_elem_info_get_step64(ctl->info)) {
245*5aaf9effSMark Brown 			ksft_print_msg("%s value %lld invalid for step %lld minimum %lld\n",
246*5aaf9effSMark Brown 				       ctl->name, int64_val,
247*5aaf9effSMark Brown 				       snd_ctl_elem_info_get_step64(ctl->info),
248*5aaf9effSMark Brown 				       snd_ctl_elem_info_get_min64(ctl->info));
249*5aaf9effSMark Brown 			err = -1;
250*5aaf9effSMark Brown 		}
251*5aaf9effSMark Brown 		break;
252*5aaf9effSMark Brown 
253*5aaf9effSMark Brown 	default:
254*5aaf9effSMark Brown 		/* No tests for other types */
255*5aaf9effSMark Brown 		ksft_test_result_skip("get_value.%d.%d\n",
256*5aaf9effSMark Brown 				      ctl->card->card, ctl->elem);
257*5aaf9effSMark Brown 		return;
258*5aaf9effSMark Brown 	}
259*5aaf9effSMark Brown 
260*5aaf9effSMark Brown out:
261*5aaf9effSMark Brown 	ksft_test_result(err >= 0, "get_value.%d.%d\n",
262*5aaf9effSMark Brown 			 ctl->card->card, ctl->elem);
263*5aaf9effSMark Brown }
264*5aaf9effSMark Brown 
265*5aaf9effSMark Brown bool show_mismatch(struct ctl_data *ctl, int index,
266*5aaf9effSMark Brown 		   snd_ctl_elem_value_t *read_val,
267*5aaf9effSMark Brown 		   snd_ctl_elem_value_t *expected_val)
268*5aaf9effSMark Brown {
269*5aaf9effSMark Brown 	long long expected_int, read_int;
270*5aaf9effSMark Brown 
271*5aaf9effSMark Brown 	/*
272*5aaf9effSMark Brown 	 * We factor out the code to compare values representable as
273*5aaf9effSMark Brown 	 * integers, ensure that check doesn't log otherwise.
274*5aaf9effSMark Brown 	 */
275*5aaf9effSMark Brown 	expected_int = 0;
276*5aaf9effSMark Brown 	read_int = 0;
277*5aaf9effSMark Brown 
278*5aaf9effSMark Brown 	switch (snd_ctl_elem_info_get_type(ctl->info)) {
279*5aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_BOOLEAN:
280*5aaf9effSMark Brown 		expected_int = snd_ctl_elem_value_get_boolean(expected_val,
281*5aaf9effSMark Brown 							      index);
282*5aaf9effSMark Brown 		read_int = snd_ctl_elem_value_get_boolean(read_val, index);
283*5aaf9effSMark Brown 		break;
284*5aaf9effSMark Brown 
285*5aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_INTEGER:
286*5aaf9effSMark Brown 		expected_int = snd_ctl_elem_value_get_integer(expected_val,
287*5aaf9effSMark Brown 							      index);
288*5aaf9effSMark Brown 		read_int = snd_ctl_elem_value_get_integer(read_val, index);
289*5aaf9effSMark Brown 		break;
290*5aaf9effSMark Brown 
291*5aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_INTEGER64:
292*5aaf9effSMark Brown 		expected_int = snd_ctl_elem_value_get_integer64(expected_val,
293*5aaf9effSMark Brown 								index);
294*5aaf9effSMark Brown 		read_int = snd_ctl_elem_value_get_integer64(read_val,
295*5aaf9effSMark Brown 							    index);
296*5aaf9effSMark Brown 		break;
297*5aaf9effSMark Brown 
298*5aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_ENUMERATED:
299*5aaf9effSMark Brown 		expected_int = snd_ctl_elem_value_get_enumerated(expected_val,
300*5aaf9effSMark Brown 								 index);
301*5aaf9effSMark Brown 		read_int = snd_ctl_elem_value_get_enumerated(read_val,
302*5aaf9effSMark Brown 							     index);
303*5aaf9effSMark Brown 		break;
304*5aaf9effSMark Brown 
305*5aaf9effSMark Brown 	default:
306*5aaf9effSMark Brown 		break;
307*5aaf9effSMark Brown 	}
308*5aaf9effSMark Brown 
309*5aaf9effSMark Brown 	if (expected_int != read_int) {
310*5aaf9effSMark Brown 		ksft_print_msg("%s.%d expected %lld but read %lld\n",
311*5aaf9effSMark Brown 			       ctl->name, index, expected_int, read_int);
312*5aaf9effSMark Brown 		return true;
313*5aaf9effSMark Brown 	} else {
314*5aaf9effSMark Brown 		return false;
315*5aaf9effSMark Brown 	}
316*5aaf9effSMark Brown }
317*5aaf9effSMark Brown 
318*5aaf9effSMark Brown /*
319*5aaf9effSMark Brown  * Write a value then if possible verify that we get the expected
320*5aaf9effSMark Brown  * result.  An optional expected value can be provided if we expect
321*5aaf9effSMark Brown  * the write to fail, for verifying that invalid writes don't corrupt
322*5aaf9effSMark Brown  * anything.
323*5aaf9effSMark Brown  */
324*5aaf9effSMark Brown int write_and_verify(struct ctl_data *ctl,
325*5aaf9effSMark Brown 		     snd_ctl_elem_value_t *write_val,
326*5aaf9effSMark Brown 		     snd_ctl_elem_value_t *expected_val)
327*5aaf9effSMark Brown {
328*5aaf9effSMark Brown 	int err, i;
329*5aaf9effSMark Brown 	bool error_expected, mismatch_shown;
330*5aaf9effSMark Brown 	snd_ctl_elem_value_t *read_val, *w_val;
331*5aaf9effSMark Brown 	snd_ctl_elem_value_alloca(&read_val);
332*5aaf9effSMark Brown 	snd_ctl_elem_value_alloca(&w_val);
333*5aaf9effSMark Brown 
334*5aaf9effSMark Brown 	/*
335*5aaf9effSMark Brown 	 * We need to copy the write value since writing can modify
336*5aaf9effSMark Brown 	 * the value which causes surprises, and allocate an expected
337*5aaf9effSMark Brown 	 * value if we expect to read back what we wrote.
338*5aaf9effSMark Brown 	 */
339*5aaf9effSMark Brown 	snd_ctl_elem_value_copy(w_val, write_val);
340*5aaf9effSMark Brown 	if (expected_val) {
341*5aaf9effSMark Brown 		error_expected = true;
342*5aaf9effSMark Brown 	} else {
343*5aaf9effSMark Brown 		error_expected = false;
344*5aaf9effSMark Brown 		snd_ctl_elem_value_alloca(&expected_val);
345*5aaf9effSMark Brown 		snd_ctl_elem_value_copy(expected_val, write_val);
346*5aaf9effSMark Brown 	}
347*5aaf9effSMark Brown 
348*5aaf9effSMark Brown 	/*
349*5aaf9effSMark Brown 	 * Do the write, if we have an expected value ignore the error
350*5aaf9effSMark Brown 	 * and carry on to validate the expected value.
351*5aaf9effSMark Brown 	 */
352*5aaf9effSMark Brown 	err = snd_ctl_elem_write(ctl->card->handle, w_val);
353*5aaf9effSMark Brown 	if (err < 0 && !error_expected) {
354*5aaf9effSMark Brown 		ksft_print_msg("snd_ctl_elem_write() failed: %s\n",
355*5aaf9effSMark Brown 			       snd_strerror(err));
356*5aaf9effSMark Brown 		return err;
357*5aaf9effSMark Brown 	}
358*5aaf9effSMark Brown 
359*5aaf9effSMark Brown 	/* Can we do the verification part? */
360*5aaf9effSMark Brown 	if (!snd_ctl_elem_info_is_readable(ctl->info))
361*5aaf9effSMark Brown 		return err;
362*5aaf9effSMark Brown 
363*5aaf9effSMark Brown 	snd_ctl_elem_value_set_id(read_val, ctl->id);
364*5aaf9effSMark Brown 
365*5aaf9effSMark Brown 	err = snd_ctl_elem_read(ctl->card->handle, read_val);
366*5aaf9effSMark Brown 	if (err < 0) {
367*5aaf9effSMark Brown 		ksft_print_msg("snd_ctl_elem_read() failed: %s\n",
368*5aaf9effSMark Brown 			       snd_strerror(err));
369*5aaf9effSMark Brown 		return err;
370*5aaf9effSMark Brown 	}
371*5aaf9effSMark Brown 
372*5aaf9effSMark Brown 	/*
373*5aaf9effSMark Brown 	 * Use the libray to compare values, if there's a mismatch
374*5aaf9effSMark Brown 	 * carry on and try to provide a more useful diagnostic than
375*5aaf9effSMark Brown 	 * just "mismatch".
376*5aaf9effSMark Brown 	 */
377*5aaf9effSMark Brown 	if (!snd_ctl_elem_value_compare(expected_val, read_val))
378*5aaf9effSMark Brown 		return 0;
379*5aaf9effSMark Brown 
380*5aaf9effSMark Brown 	mismatch_shown = false;
381*5aaf9effSMark Brown 	for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++)
382*5aaf9effSMark Brown 		if (show_mismatch(ctl, i, read_val, expected_val))
383*5aaf9effSMark Brown 			mismatch_shown = true;
384*5aaf9effSMark Brown 
385*5aaf9effSMark Brown 	if (!mismatch_shown)
386*5aaf9effSMark Brown 		ksft_print_msg("%s read and written values differ\n",
387*5aaf9effSMark Brown 			       ctl->name);
388*5aaf9effSMark Brown 
389*5aaf9effSMark Brown 	return -1;
390*5aaf9effSMark Brown }
391*5aaf9effSMark Brown 
392*5aaf9effSMark Brown /*
393*5aaf9effSMark Brown  * Make sure we can write the default value back to the control, this
394*5aaf9effSMark Brown  * should validate that at least some write works.
395*5aaf9effSMark Brown  */
396*5aaf9effSMark Brown void test_ctl_write_default(struct ctl_data *ctl)
397*5aaf9effSMark Brown {
398*5aaf9effSMark Brown 	int err;
399*5aaf9effSMark Brown 
400*5aaf9effSMark Brown 	/* If the control is turned off let's be polite */
401*5aaf9effSMark Brown 	if (snd_ctl_elem_info_is_inactive(ctl->info)) {
402*5aaf9effSMark Brown 		ksft_print_msg("%s is inactive\n", ctl->name);
403*5aaf9effSMark Brown 		ksft_test_result_skip("write_default.%d.%d\n",
404*5aaf9effSMark Brown 				      ctl->card->card, ctl->elem);
405*5aaf9effSMark Brown 		return;
406*5aaf9effSMark Brown 	}
407*5aaf9effSMark Brown 
408*5aaf9effSMark Brown 	if (!snd_ctl_elem_info_is_writable(ctl->info)) {
409*5aaf9effSMark Brown 		ksft_print_msg("%s is not writeable\n", ctl->name);
410*5aaf9effSMark Brown 		ksft_test_result_skip("write_default.%d.%d\n",
411*5aaf9effSMark Brown 				      ctl->card->card, ctl->elem);
412*5aaf9effSMark Brown 		return;
413*5aaf9effSMark Brown 	}
414*5aaf9effSMark Brown 
415*5aaf9effSMark Brown 	/* No idea what the default was for unreadable controls */
416*5aaf9effSMark Brown 	if (!snd_ctl_elem_info_is_readable(ctl->info)) {
417*5aaf9effSMark Brown 		ksft_print_msg("%s couldn't read default\n", ctl->name);
418*5aaf9effSMark Brown 		ksft_test_result_skip("write_default.%d.%d\n",
419*5aaf9effSMark Brown 				      ctl->card->card, ctl->elem);
420*5aaf9effSMark Brown 		return;
421*5aaf9effSMark Brown 	}
422*5aaf9effSMark Brown 
423*5aaf9effSMark Brown 	err = write_and_verify(ctl, ctl->def_val, NULL);
424*5aaf9effSMark Brown 
425*5aaf9effSMark Brown 	ksft_test_result(err >= 0, "write_default.%d.%d\n",
426*5aaf9effSMark Brown 			 ctl->card->card, ctl->elem);
427*5aaf9effSMark Brown }
428*5aaf9effSMark Brown 
429*5aaf9effSMark Brown bool test_ctl_write_valid_boolean(struct ctl_data *ctl)
430*5aaf9effSMark Brown {
431*5aaf9effSMark Brown 	int err, i, j;
432*5aaf9effSMark Brown 	bool fail = false;
433*5aaf9effSMark Brown 	snd_ctl_elem_value_t *val;
434*5aaf9effSMark Brown 	snd_ctl_elem_value_alloca(&val);
435*5aaf9effSMark Brown 
436*5aaf9effSMark Brown 	snd_ctl_elem_value_set_id(val, ctl->id);
437*5aaf9effSMark Brown 
438*5aaf9effSMark Brown 	for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
439*5aaf9effSMark Brown 		for (j = 0; j < 2; j++) {
440*5aaf9effSMark Brown 			snd_ctl_elem_value_set_boolean(val, i, j);
441*5aaf9effSMark Brown 			err = write_and_verify(ctl, val, NULL);
442*5aaf9effSMark Brown 			if (err != 0)
443*5aaf9effSMark Brown 				fail = true;
444*5aaf9effSMark Brown 		}
445*5aaf9effSMark Brown 	}
446*5aaf9effSMark Brown 
447*5aaf9effSMark Brown 	return !fail;
448*5aaf9effSMark Brown }
449*5aaf9effSMark Brown 
450*5aaf9effSMark Brown bool test_ctl_write_valid_integer(struct ctl_data *ctl)
451*5aaf9effSMark Brown {
452*5aaf9effSMark Brown 	int err;
453*5aaf9effSMark Brown 	int i;
454*5aaf9effSMark Brown 	long j, step;
455*5aaf9effSMark Brown 	bool fail = false;
456*5aaf9effSMark Brown 	snd_ctl_elem_value_t *val;
457*5aaf9effSMark Brown 	snd_ctl_elem_value_alloca(&val);
458*5aaf9effSMark Brown 
459*5aaf9effSMark Brown 	snd_ctl_elem_value_set_id(val, ctl->id);
460*5aaf9effSMark Brown 
461*5aaf9effSMark Brown 	step = snd_ctl_elem_info_get_step(ctl->info);
462*5aaf9effSMark Brown 	if (!step)
463*5aaf9effSMark Brown 		step = 1;
464*5aaf9effSMark Brown 
465*5aaf9effSMark Brown 	for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
466*5aaf9effSMark Brown 		for (j = snd_ctl_elem_info_get_min(ctl->info);
467*5aaf9effSMark Brown 		     j <= snd_ctl_elem_info_get_max(ctl->info); j += step) {
468*5aaf9effSMark Brown 
469*5aaf9effSMark Brown 			snd_ctl_elem_value_set_integer(val, i, j);
470*5aaf9effSMark Brown 			err = write_and_verify(ctl, val, NULL);
471*5aaf9effSMark Brown 			if (err != 0)
472*5aaf9effSMark Brown 				fail = true;
473*5aaf9effSMark Brown 		}
474*5aaf9effSMark Brown 	}
475*5aaf9effSMark Brown 
476*5aaf9effSMark Brown 
477*5aaf9effSMark Brown 	return !fail;
478*5aaf9effSMark Brown }
479*5aaf9effSMark Brown 
480*5aaf9effSMark Brown bool test_ctl_write_valid_integer64(struct ctl_data *ctl)
481*5aaf9effSMark Brown {
482*5aaf9effSMark Brown 	int err, i;
483*5aaf9effSMark Brown 	long long j, step;
484*5aaf9effSMark Brown 	bool fail = false;
485*5aaf9effSMark Brown 	snd_ctl_elem_value_t *val;
486*5aaf9effSMark Brown 	snd_ctl_elem_value_alloca(&val);
487*5aaf9effSMark Brown 
488*5aaf9effSMark Brown 	snd_ctl_elem_value_set_id(val, ctl->id);
489*5aaf9effSMark Brown 
490*5aaf9effSMark Brown 	step = snd_ctl_elem_info_get_step64(ctl->info);
491*5aaf9effSMark Brown 	if (!step)
492*5aaf9effSMark Brown 		step = 1;
493*5aaf9effSMark Brown 
494*5aaf9effSMark Brown 	for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
495*5aaf9effSMark Brown 		for (j = snd_ctl_elem_info_get_min64(ctl->info);
496*5aaf9effSMark Brown 		     j <= snd_ctl_elem_info_get_max64(ctl->info); j += step) {
497*5aaf9effSMark Brown 
498*5aaf9effSMark Brown 			snd_ctl_elem_value_set_integer64(val, i, j);
499*5aaf9effSMark Brown 			err = write_and_verify(ctl, val, NULL);
500*5aaf9effSMark Brown 			if (err != 0)
501*5aaf9effSMark Brown 				fail = true;
502*5aaf9effSMark Brown 		}
503*5aaf9effSMark Brown 	}
504*5aaf9effSMark Brown 
505*5aaf9effSMark Brown 	return !fail;
506*5aaf9effSMark Brown }
507*5aaf9effSMark Brown 
508*5aaf9effSMark Brown bool test_ctl_write_valid_enumerated(struct ctl_data *ctl)
509*5aaf9effSMark Brown {
510*5aaf9effSMark Brown 	int err, i, j;
511*5aaf9effSMark Brown 	bool fail = false;
512*5aaf9effSMark Brown 	snd_ctl_elem_value_t *val;
513*5aaf9effSMark Brown 	snd_ctl_elem_value_alloca(&val);
514*5aaf9effSMark Brown 
515*5aaf9effSMark Brown 	snd_ctl_elem_value_set_id(val, ctl->id);
516*5aaf9effSMark Brown 
517*5aaf9effSMark Brown 	for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
518*5aaf9effSMark Brown 		for (j = 0; j < snd_ctl_elem_info_get_items(ctl->info); j++) {
519*5aaf9effSMark Brown 			snd_ctl_elem_value_set_enumerated(val, i, j);
520*5aaf9effSMark Brown 			err = write_and_verify(ctl, val, NULL);
521*5aaf9effSMark Brown 			if (err != 0)
522*5aaf9effSMark Brown 				fail = true;
523*5aaf9effSMark Brown 		}
524*5aaf9effSMark Brown 	}
525*5aaf9effSMark Brown 
526*5aaf9effSMark Brown 	return !fail;
527*5aaf9effSMark Brown }
528*5aaf9effSMark Brown 
529*5aaf9effSMark Brown void test_ctl_write_valid(struct ctl_data *ctl)
530*5aaf9effSMark Brown {
531*5aaf9effSMark Brown 	bool pass;
532*5aaf9effSMark Brown 	int err;
533*5aaf9effSMark Brown 
534*5aaf9effSMark Brown 	/* If the control is turned off let's be polite */
535*5aaf9effSMark Brown 	if (snd_ctl_elem_info_is_inactive(ctl->info)) {
536*5aaf9effSMark Brown 		ksft_print_msg("%s is inactive\n", ctl->name);
537*5aaf9effSMark Brown 		ksft_test_result_skip("write_valid.%d.%d\n",
538*5aaf9effSMark Brown 				      ctl->card->card, ctl->elem);
539*5aaf9effSMark Brown 		return;
540*5aaf9effSMark Brown 	}
541*5aaf9effSMark Brown 
542*5aaf9effSMark Brown 	if (!snd_ctl_elem_info_is_writable(ctl->info)) {
543*5aaf9effSMark Brown 		ksft_print_msg("%s is not writeable\n", ctl->name);
544*5aaf9effSMark Brown 		ksft_test_result_skip("write_valid.%d.%d\n",
545*5aaf9effSMark Brown 				      ctl->card->card, ctl->elem);
546*5aaf9effSMark Brown 		return;
547*5aaf9effSMark Brown 	}
548*5aaf9effSMark Brown 
549*5aaf9effSMark Brown 	switch (snd_ctl_elem_info_get_type(ctl->info)) {
550*5aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_BOOLEAN:
551*5aaf9effSMark Brown 		pass = test_ctl_write_valid_boolean(ctl);
552*5aaf9effSMark Brown 		break;
553*5aaf9effSMark Brown 
554*5aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_INTEGER:
555*5aaf9effSMark Brown 		pass = test_ctl_write_valid_integer(ctl);
556*5aaf9effSMark Brown 		break;
557*5aaf9effSMark Brown 
558*5aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_INTEGER64:
559*5aaf9effSMark Brown 		pass = test_ctl_write_valid_integer64(ctl);
560*5aaf9effSMark Brown 		break;
561*5aaf9effSMark Brown 
562*5aaf9effSMark Brown 	case SND_CTL_ELEM_TYPE_ENUMERATED:
563*5aaf9effSMark Brown 		pass = test_ctl_write_valid_enumerated(ctl);
564*5aaf9effSMark Brown 		break;
565*5aaf9effSMark Brown 
566*5aaf9effSMark Brown 	default:
567*5aaf9effSMark Brown 		/* No tests for this yet */
568*5aaf9effSMark Brown 		ksft_test_result_skip("write_valid.%d.%d\n",
569*5aaf9effSMark Brown 				      ctl->card->card, ctl->elem);
570*5aaf9effSMark Brown 		return;
571*5aaf9effSMark Brown 	}
572*5aaf9effSMark Brown 
573*5aaf9effSMark Brown 	/* Restore the default value to minimise disruption */
574*5aaf9effSMark Brown 	err = write_and_verify(ctl, ctl->def_val, NULL);
575*5aaf9effSMark Brown 	if (err < 0)
576*5aaf9effSMark Brown 		pass = false;
577*5aaf9effSMark Brown 
578*5aaf9effSMark Brown 	ksft_test_result(pass, "write_valid.%d.%d\n",
579*5aaf9effSMark Brown 			 ctl->card->card, ctl->elem);
580*5aaf9effSMark Brown }
581*5aaf9effSMark Brown 
582*5aaf9effSMark Brown int main(void)
583*5aaf9effSMark Brown {
584*5aaf9effSMark Brown 	struct ctl_data *ctl;
585*5aaf9effSMark Brown 
586*5aaf9effSMark Brown 	ksft_print_header();
587*5aaf9effSMark Brown 
588*5aaf9effSMark Brown 	find_controls();
589*5aaf9effSMark Brown 
590*5aaf9effSMark Brown 	ksft_set_plan(num_controls * TESTS_PER_CONTROL);
591*5aaf9effSMark Brown 
592*5aaf9effSMark Brown 	for (ctl = ctl_list; ctl != NULL; ctl = ctl->next) {
593*5aaf9effSMark Brown 		/*
594*5aaf9effSMark Brown 		 * Must test get_value() before we write anything, the
595*5aaf9effSMark Brown 		 * test stores the default value for later cleanup.
596*5aaf9effSMark Brown 		 */
597*5aaf9effSMark Brown 		test_ctl_get_value(ctl);
598*5aaf9effSMark Brown 		test_ctl_write_default(ctl);
599*5aaf9effSMark Brown 		test_ctl_write_valid(ctl);
600*5aaf9effSMark Brown 	}
601*5aaf9effSMark Brown 
602*5aaf9effSMark Brown 	ksft_exit_pass();
603*5aaf9effSMark Brown 
604*5aaf9effSMark Brown 	return 0;
605*5aaf9effSMark Brown }
606