1*053f45beSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0
2*053f45beSAndroid Build Coastguard Worker //
3*053f45beSAndroid Build Coastguard Worker // kselftest for the ALSA mixer API
4*053f45beSAndroid Build Coastguard Worker //
5*053f45beSAndroid Build Coastguard Worker // Original author: Mark Brown <[email protected]>
6*053f45beSAndroid Build Coastguard Worker // Copyright (c) 2021-2 Arm Limited
7*053f45beSAndroid Build Coastguard Worker
8*053f45beSAndroid Build Coastguard Worker // This test will iterate over all cards detected in the system, exercising
9*053f45beSAndroid Build Coastguard Worker // every mixer control it can find. This may conflict with other system
10*053f45beSAndroid Build Coastguard Worker // software if there is audio activity so is best run on a system with a
11*053f45beSAndroid Build Coastguard Worker // minimal active userspace.
12*053f45beSAndroid Build Coastguard Worker
13*053f45beSAndroid Build Coastguard Worker #include <stdio.h>
14*053f45beSAndroid Build Coastguard Worker #include <stdlib.h>
15*053f45beSAndroid Build Coastguard Worker #include <stdbool.h>
16*053f45beSAndroid Build Coastguard Worker #include <limits.h>
17*053f45beSAndroid Build Coastguard Worker #include <string.h>
18*053f45beSAndroid Build Coastguard Worker #include <getopt.h>
19*053f45beSAndroid Build Coastguard Worker #include <stdarg.h>
20*053f45beSAndroid Build Coastguard Worker #include <ctype.h>
21*053f45beSAndroid Build Coastguard Worker #include <math.h>
22*053f45beSAndroid Build Coastguard Worker #include <errno.h>
23*053f45beSAndroid Build Coastguard Worker #include <assert.h>
24*053f45beSAndroid Build Coastguard Worker #include <alsa/asoundlib.h>
25*053f45beSAndroid Build Coastguard Worker #include <poll.h>
26*053f45beSAndroid Build Coastguard Worker #include <stdint.h>
27*053f45beSAndroid Build Coastguard Worker
28*053f45beSAndroid Build Coastguard Worker #include "../kselftest.h"
29*053f45beSAndroid Build Coastguard Worker
30*053f45beSAndroid Build Coastguard Worker #define TESTS_PER_CONTROL 7
31*053f45beSAndroid Build Coastguard Worker
32*053f45beSAndroid Build Coastguard Worker struct card_data {
33*053f45beSAndroid Build Coastguard Worker snd_ctl_t *handle;
34*053f45beSAndroid Build Coastguard Worker int card;
35*053f45beSAndroid Build Coastguard Worker struct pollfd pollfd;
36*053f45beSAndroid Build Coastguard Worker int num_ctls;
37*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_list_t *ctls;
38*053f45beSAndroid Build Coastguard Worker struct card_data *next;
39*053f45beSAndroid Build Coastguard Worker };
40*053f45beSAndroid Build Coastguard Worker
41*053f45beSAndroid Build Coastguard Worker struct ctl_data {
42*053f45beSAndroid Build Coastguard Worker const char *name;
43*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_id_t *id;
44*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_info_t *info;
45*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_t *def_val;
46*053f45beSAndroid Build Coastguard Worker int elem;
47*053f45beSAndroid Build Coastguard Worker int event_missing;
48*053f45beSAndroid Build Coastguard Worker int event_spurious;
49*053f45beSAndroid Build Coastguard Worker struct card_data *card;
50*053f45beSAndroid Build Coastguard Worker struct ctl_data *next;
51*053f45beSAndroid Build Coastguard Worker };
52*053f45beSAndroid Build Coastguard Worker
53*053f45beSAndroid Build Coastguard Worker static const char *alsa_config =
54*053f45beSAndroid Build Coastguard Worker "ctl.hw {\n"
55*053f45beSAndroid Build Coastguard Worker " @args [ CARD ]\n"
56*053f45beSAndroid Build Coastguard Worker " @args.CARD.type string\n"
57*053f45beSAndroid Build Coastguard Worker " type hw\n"
58*053f45beSAndroid Build Coastguard Worker " card $CARD\n"
59*053f45beSAndroid Build Coastguard Worker "}\n"
60*053f45beSAndroid Build Coastguard Worker ;
61*053f45beSAndroid Build Coastguard Worker
62*053f45beSAndroid Build Coastguard Worker int num_cards = 0;
63*053f45beSAndroid Build Coastguard Worker int num_controls = 0;
64*053f45beSAndroid Build Coastguard Worker struct card_data *card_list = NULL;
65*053f45beSAndroid Build Coastguard Worker struct ctl_data *ctl_list = NULL;
66*053f45beSAndroid Build Coastguard Worker
67*053f45beSAndroid Build Coastguard Worker #ifdef SND_LIB_VER
68*053f45beSAndroid Build Coastguard Worker #if SND_LIB_VERSION >= SND_LIB_VER(1, 2, 6)
69*053f45beSAndroid Build Coastguard Worker #define LIB_HAS_LOAD_STRING
70*053f45beSAndroid Build Coastguard Worker #endif
71*053f45beSAndroid Build Coastguard Worker #endif
72*053f45beSAndroid Build Coastguard Worker
73*053f45beSAndroid Build Coastguard Worker #ifndef LIB_HAS_LOAD_STRING
snd_config_load_string(snd_config_t ** config,const char * s,size_t size)74*053f45beSAndroid Build Coastguard Worker static int snd_config_load_string(snd_config_t **config, const char *s,
75*053f45beSAndroid Build Coastguard Worker size_t size)
76*053f45beSAndroid Build Coastguard Worker {
77*053f45beSAndroid Build Coastguard Worker snd_input_t *input;
78*053f45beSAndroid Build Coastguard Worker snd_config_t *dst;
79*053f45beSAndroid Build Coastguard Worker int err;
80*053f45beSAndroid Build Coastguard Worker
81*053f45beSAndroid Build Coastguard Worker assert(config && s);
82*053f45beSAndroid Build Coastguard Worker if (size == 0)
83*053f45beSAndroid Build Coastguard Worker size = strlen(s);
84*053f45beSAndroid Build Coastguard Worker err = snd_input_buffer_open(&input, s, size);
85*053f45beSAndroid Build Coastguard Worker if (err < 0)
86*053f45beSAndroid Build Coastguard Worker return err;
87*053f45beSAndroid Build Coastguard Worker err = snd_config_top(&dst);
88*053f45beSAndroid Build Coastguard Worker if (err < 0) {
89*053f45beSAndroid Build Coastguard Worker snd_input_close(input);
90*053f45beSAndroid Build Coastguard Worker return err;
91*053f45beSAndroid Build Coastguard Worker }
92*053f45beSAndroid Build Coastguard Worker err = snd_config_load(dst, input);
93*053f45beSAndroid Build Coastguard Worker snd_input_close(input);
94*053f45beSAndroid Build Coastguard Worker if (err < 0) {
95*053f45beSAndroid Build Coastguard Worker snd_config_delete(dst);
96*053f45beSAndroid Build Coastguard Worker return err;
97*053f45beSAndroid Build Coastguard Worker }
98*053f45beSAndroid Build Coastguard Worker *config = dst;
99*053f45beSAndroid Build Coastguard Worker return 0;
100*053f45beSAndroid Build Coastguard Worker }
101*053f45beSAndroid Build Coastguard Worker #endif
102*053f45beSAndroid Build Coastguard Worker
find_controls(void)103*053f45beSAndroid Build Coastguard Worker static void find_controls(void)
104*053f45beSAndroid Build Coastguard Worker {
105*053f45beSAndroid Build Coastguard Worker char name[32];
106*053f45beSAndroid Build Coastguard Worker int card, ctl, err;
107*053f45beSAndroid Build Coastguard Worker struct card_data *card_data;
108*053f45beSAndroid Build Coastguard Worker struct ctl_data *ctl_data;
109*053f45beSAndroid Build Coastguard Worker snd_config_t *config;
110*053f45beSAndroid Build Coastguard Worker
111*053f45beSAndroid Build Coastguard Worker card = -1;
112*053f45beSAndroid Build Coastguard Worker if (snd_card_next(&card) < 0 || card < 0)
113*053f45beSAndroid Build Coastguard Worker return;
114*053f45beSAndroid Build Coastguard Worker
115*053f45beSAndroid Build Coastguard Worker err = snd_config_load_string(&config, alsa_config, strlen(alsa_config));
116*053f45beSAndroid Build Coastguard Worker if (err < 0) {
117*053f45beSAndroid Build Coastguard Worker ksft_print_msg("Unable to parse custom alsa-lib configuration: %s\n",
118*053f45beSAndroid Build Coastguard Worker snd_strerror(err));
119*053f45beSAndroid Build Coastguard Worker ksft_exit_fail();
120*053f45beSAndroid Build Coastguard Worker }
121*053f45beSAndroid Build Coastguard Worker
122*053f45beSAndroid Build Coastguard Worker while (card >= 0) {
123*053f45beSAndroid Build Coastguard Worker sprintf(name, "hw:%d", card);
124*053f45beSAndroid Build Coastguard Worker
125*053f45beSAndroid Build Coastguard Worker card_data = malloc(sizeof(*card_data));
126*053f45beSAndroid Build Coastguard Worker if (!card_data)
127*053f45beSAndroid Build Coastguard Worker ksft_exit_fail_msg("Out of memory\n");
128*053f45beSAndroid Build Coastguard Worker
129*053f45beSAndroid Build Coastguard Worker err = snd_ctl_open_lconf(&card_data->handle, name, 0, config);
130*053f45beSAndroid Build Coastguard Worker if (err < 0) {
131*053f45beSAndroid Build Coastguard Worker ksft_print_msg("Failed to get hctl for card %d: %s\n",
132*053f45beSAndroid Build Coastguard Worker card, snd_strerror(err));
133*053f45beSAndroid Build Coastguard Worker goto next_card;
134*053f45beSAndroid Build Coastguard Worker }
135*053f45beSAndroid Build Coastguard Worker
136*053f45beSAndroid Build Coastguard Worker /* Count controls */
137*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_list_malloc(&card_data->ctls);
138*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_list(card_data->handle, card_data->ctls);
139*053f45beSAndroid Build Coastguard Worker card_data->num_ctls = snd_ctl_elem_list_get_count(card_data->ctls);
140*053f45beSAndroid Build Coastguard Worker
141*053f45beSAndroid Build Coastguard Worker /* Enumerate control information */
142*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_list_alloc_space(card_data->ctls, card_data->num_ctls);
143*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_list(card_data->handle, card_data->ctls);
144*053f45beSAndroid Build Coastguard Worker
145*053f45beSAndroid Build Coastguard Worker card_data->card = num_cards++;
146*053f45beSAndroid Build Coastguard Worker card_data->next = card_list;
147*053f45beSAndroid Build Coastguard Worker card_list = card_data;
148*053f45beSAndroid Build Coastguard Worker
149*053f45beSAndroid Build Coastguard Worker num_controls += card_data->num_ctls;
150*053f45beSAndroid Build Coastguard Worker
151*053f45beSAndroid Build Coastguard Worker for (ctl = 0; ctl < card_data->num_ctls; ctl++) {
152*053f45beSAndroid Build Coastguard Worker ctl_data = malloc(sizeof(*ctl_data));
153*053f45beSAndroid Build Coastguard Worker if (!ctl_data)
154*053f45beSAndroid Build Coastguard Worker ksft_exit_fail_msg("Out of memory\n");
155*053f45beSAndroid Build Coastguard Worker
156*053f45beSAndroid Build Coastguard Worker memset(ctl_data, 0, sizeof(*ctl_data));
157*053f45beSAndroid Build Coastguard Worker ctl_data->card = card_data;
158*053f45beSAndroid Build Coastguard Worker ctl_data->elem = ctl;
159*053f45beSAndroid Build Coastguard Worker ctl_data->name = snd_ctl_elem_list_get_name(card_data->ctls,
160*053f45beSAndroid Build Coastguard Worker ctl);
161*053f45beSAndroid Build Coastguard Worker
162*053f45beSAndroid Build Coastguard Worker err = snd_ctl_elem_id_malloc(&ctl_data->id);
163*053f45beSAndroid Build Coastguard Worker if (err < 0)
164*053f45beSAndroid Build Coastguard Worker ksft_exit_fail_msg("Out of memory\n");
165*053f45beSAndroid Build Coastguard Worker
166*053f45beSAndroid Build Coastguard Worker err = snd_ctl_elem_info_malloc(&ctl_data->info);
167*053f45beSAndroid Build Coastguard Worker if (err < 0)
168*053f45beSAndroid Build Coastguard Worker ksft_exit_fail_msg("Out of memory\n");
169*053f45beSAndroid Build Coastguard Worker
170*053f45beSAndroid Build Coastguard Worker err = snd_ctl_elem_value_malloc(&ctl_data->def_val);
171*053f45beSAndroid Build Coastguard Worker if (err < 0)
172*053f45beSAndroid Build Coastguard Worker ksft_exit_fail_msg("Out of memory\n");
173*053f45beSAndroid Build Coastguard Worker
174*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_list_get_id(card_data->ctls, ctl,
175*053f45beSAndroid Build Coastguard Worker ctl_data->id);
176*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_info_set_id(ctl_data->info, ctl_data->id);
177*053f45beSAndroid Build Coastguard Worker err = snd_ctl_elem_info(card_data->handle,
178*053f45beSAndroid Build Coastguard Worker ctl_data->info);
179*053f45beSAndroid Build Coastguard Worker if (err < 0) {
180*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s getting info for %d\n",
181*053f45beSAndroid Build Coastguard Worker snd_strerror(err),
182*053f45beSAndroid Build Coastguard Worker ctl_data->name);
183*053f45beSAndroid Build Coastguard Worker }
184*053f45beSAndroid Build Coastguard Worker
185*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_id(ctl_data->def_val,
186*053f45beSAndroid Build Coastguard Worker ctl_data->id);
187*053f45beSAndroid Build Coastguard Worker
188*053f45beSAndroid Build Coastguard Worker ctl_data->next = ctl_list;
189*053f45beSAndroid Build Coastguard Worker ctl_list = ctl_data;
190*053f45beSAndroid Build Coastguard Worker }
191*053f45beSAndroid Build Coastguard Worker
192*053f45beSAndroid Build Coastguard Worker /* Set up for events */
193*053f45beSAndroid Build Coastguard Worker err = snd_ctl_subscribe_events(card_data->handle, true);
194*053f45beSAndroid Build Coastguard Worker if (err < 0) {
195*053f45beSAndroid Build Coastguard Worker ksft_exit_fail_msg("snd_ctl_subscribe_events() failed for card %d: %d\n",
196*053f45beSAndroid Build Coastguard Worker card, err);
197*053f45beSAndroid Build Coastguard Worker }
198*053f45beSAndroid Build Coastguard Worker
199*053f45beSAndroid Build Coastguard Worker err = snd_ctl_poll_descriptors_count(card_data->handle);
200*053f45beSAndroid Build Coastguard Worker if (err != 1) {
201*053f45beSAndroid Build Coastguard Worker ksft_exit_fail_msg("Unexpected descriptor count %d for card %d\n",
202*053f45beSAndroid Build Coastguard Worker err, card);
203*053f45beSAndroid Build Coastguard Worker }
204*053f45beSAndroid Build Coastguard Worker
205*053f45beSAndroid Build Coastguard Worker err = snd_ctl_poll_descriptors(card_data->handle,
206*053f45beSAndroid Build Coastguard Worker &card_data->pollfd, 1);
207*053f45beSAndroid Build Coastguard Worker if (err != 1) {
208*053f45beSAndroid Build Coastguard Worker ksft_exit_fail_msg("snd_ctl_poll_descriptors() failed for %d\n",
209*053f45beSAndroid Build Coastguard Worker card, err);
210*053f45beSAndroid Build Coastguard Worker }
211*053f45beSAndroid Build Coastguard Worker
212*053f45beSAndroid Build Coastguard Worker next_card:
213*053f45beSAndroid Build Coastguard Worker if (snd_card_next(&card) < 0) {
214*053f45beSAndroid Build Coastguard Worker ksft_print_msg("snd_card_next");
215*053f45beSAndroid Build Coastguard Worker break;
216*053f45beSAndroid Build Coastguard Worker }
217*053f45beSAndroid Build Coastguard Worker }
218*053f45beSAndroid Build Coastguard Worker
219*053f45beSAndroid Build Coastguard Worker snd_config_delete(config);
220*053f45beSAndroid Build Coastguard Worker }
221*053f45beSAndroid Build Coastguard Worker
222*053f45beSAndroid Build Coastguard Worker /*
223*053f45beSAndroid Build Coastguard Worker * Block for up to timeout ms for an event, returns a negative value
224*053f45beSAndroid Build Coastguard Worker * on error, 0 for no event and 1 for an event.
225*053f45beSAndroid Build Coastguard Worker */
wait_for_event(struct ctl_data * ctl,int timeout)226*053f45beSAndroid Build Coastguard Worker static int wait_for_event(struct ctl_data *ctl, int timeout)
227*053f45beSAndroid Build Coastguard Worker {
228*053f45beSAndroid Build Coastguard Worker unsigned short revents;
229*053f45beSAndroid Build Coastguard Worker snd_ctl_event_t *event;
230*053f45beSAndroid Build Coastguard Worker int count, err;
231*053f45beSAndroid Build Coastguard Worker unsigned int mask = 0;
232*053f45beSAndroid Build Coastguard Worker unsigned int ev_id;
233*053f45beSAndroid Build Coastguard Worker
234*053f45beSAndroid Build Coastguard Worker snd_ctl_event_alloca(&event);
235*053f45beSAndroid Build Coastguard Worker
236*053f45beSAndroid Build Coastguard Worker do {
237*053f45beSAndroid Build Coastguard Worker err = poll(&(ctl->card->pollfd), 1, timeout);
238*053f45beSAndroid Build Coastguard Worker if (err < 0) {
239*053f45beSAndroid Build Coastguard Worker ksft_print_msg("poll() failed for %s: %s (%d)\n",
240*053f45beSAndroid Build Coastguard Worker ctl->name, strerror(errno), errno);
241*053f45beSAndroid Build Coastguard Worker return -1;
242*053f45beSAndroid Build Coastguard Worker }
243*053f45beSAndroid Build Coastguard Worker /* Timeout */
244*053f45beSAndroid Build Coastguard Worker if (err == 0)
245*053f45beSAndroid Build Coastguard Worker return 0;
246*053f45beSAndroid Build Coastguard Worker
247*053f45beSAndroid Build Coastguard Worker err = snd_ctl_poll_descriptors_revents(ctl->card->handle,
248*053f45beSAndroid Build Coastguard Worker &(ctl->card->pollfd),
249*053f45beSAndroid Build Coastguard Worker 1, &revents);
250*053f45beSAndroid Build Coastguard Worker if (err < 0) {
251*053f45beSAndroid Build Coastguard Worker ksft_print_msg("snd_ctl_poll_descriptors_revents() failed for %s: %d\n",
252*053f45beSAndroid Build Coastguard Worker ctl->name, err);
253*053f45beSAndroid Build Coastguard Worker return err;
254*053f45beSAndroid Build Coastguard Worker }
255*053f45beSAndroid Build Coastguard Worker if (revents & POLLERR) {
256*053f45beSAndroid Build Coastguard Worker ksft_print_msg("snd_ctl_poll_descriptors_revents() reported POLLERR for %s\n",
257*053f45beSAndroid Build Coastguard Worker ctl->name);
258*053f45beSAndroid Build Coastguard Worker return -1;
259*053f45beSAndroid Build Coastguard Worker }
260*053f45beSAndroid Build Coastguard Worker /* No read events */
261*053f45beSAndroid Build Coastguard Worker if (!(revents & POLLIN)) {
262*053f45beSAndroid Build Coastguard Worker ksft_print_msg("No POLLIN\n");
263*053f45beSAndroid Build Coastguard Worker continue;
264*053f45beSAndroid Build Coastguard Worker }
265*053f45beSAndroid Build Coastguard Worker
266*053f45beSAndroid Build Coastguard Worker err = snd_ctl_read(ctl->card->handle, event);
267*053f45beSAndroid Build Coastguard Worker if (err < 0) {
268*053f45beSAndroid Build Coastguard Worker ksft_print_msg("snd_ctl_read() failed for %s: %d\n",
269*053f45beSAndroid Build Coastguard Worker ctl->name, err);
270*053f45beSAndroid Build Coastguard Worker return err;
271*053f45beSAndroid Build Coastguard Worker }
272*053f45beSAndroid Build Coastguard Worker
273*053f45beSAndroid Build Coastguard Worker if (snd_ctl_event_get_type(event) != SND_CTL_EVENT_ELEM)
274*053f45beSAndroid Build Coastguard Worker continue;
275*053f45beSAndroid Build Coastguard Worker
276*053f45beSAndroid Build Coastguard Worker /* The ID returned from the event is 1 less than numid */
277*053f45beSAndroid Build Coastguard Worker mask = snd_ctl_event_elem_get_mask(event);
278*053f45beSAndroid Build Coastguard Worker ev_id = snd_ctl_event_elem_get_numid(event);
279*053f45beSAndroid Build Coastguard Worker if (ev_id != snd_ctl_elem_info_get_numid(ctl->info)) {
280*053f45beSAndroid Build Coastguard Worker ksft_print_msg("Event for unexpected ctl %s\n",
281*053f45beSAndroid Build Coastguard Worker snd_ctl_event_elem_get_name(event));
282*053f45beSAndroid Build Coastguard Worker continue;
283*053f45beSAndroid Build Coastguard Worker }
284*053f45beSAndroid Build Coastguard Worker
285*053f45beSAndroid Build Coastguard Worker if ((mask & SND_CTL_EVENT_MASK_REMOVE) == SND_CTL_EVENT_MASK_REMOVE) {
286*053f45beSAndroid Build Coastguard Worker ksft_print_msg("Removal event for %s\n",
287*053f45beSAndroid Build Coastguard Worker ctl->name);
288*053f45beSAndroid Build Coastguard Worker return -1;
289*053f45beSAndroid Build Coastguard Worker }
290*053f45beSAndroid Build Coastguard Worker } while ((mask & SND_CTL_EVENT_MASK_VALUE) != SND_CTL_EVENT_MASK_VALUE);
291*053f45beSAndroid Build Coastguard Worker
292*053f45beSAndroid Build Coastguard Worker return 1;
293*053f45beSAndroid Build Coastguard Worker }
294*053f45beSAndroid Build Coastguard Worker
ctl_value_index_valid(struct ctl_data * ctl,snd_ctl_elem_value_t * val,int index)295*053f45beSAndroid Build Coastguard Worker static bool ctl_value_index_valid(struct ctl_data *ctl,
296*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_t *val,
297*053f45beSAndroid Build Coastguard Worker int index)
298*053f45beSAndroid Build Coastguard Worker {
299*053f45beSAndroid Build Coastguard Worker long int_val;
300*053f45beSAndroid Build Coastguard Worker long long int64_val;
301*053f45beSAndroid Build Coastguard Worker
302*053f45beSAndroid Build Coastguard Worker switch (snd_ctl_elem_info_get_type(ctl->info)) {
303*053f45beSAndroid Build Coastguard Worker case SND_CTL_ELEM_TYPE_NONE:
304*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s.%d Invalid control type NONE\n",
305*053f45beSAndroid Build Coastguard Worker ctl->name, index);
306*053f45beSAndroid Build Coastguard Worker return false;
307*053f45beSAndroid Build Coastguard Worker
308*053f45beSAndroid Build Coastguard Worker case SND_CTL_ELEM_TYPE_BOOLEAN:
309*053f45beSAndroid Build Coastguard Worker int_val = snd_ctl_elem_value_get_boolean(val, index);
310*053f45beSAndroid Build Coastguard Worker switch (int_val) {
311*053f45beSAndroid Build Coastguard Worker case 0:
312*053f45beSAndroid Build Coastguard Worker case 1:
313*053f45beSAndroid Build Coastguard Worker break;
314*053f45beSAndroid Build Coastguard Worker default:
315*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s.%d Invalid boolean value %ld\n",
316*053f45beSAndroid Build Coastguard Worker ctl->name, index, int_val);
317*053f45beSAndroid Build Coastguard Worker return false;
318*053f45beSAndroid Build Coastguard Worker }
319*053f45beSAndroid Build Coastguard Worker break;
320*053f45beSAndroid Build Coastguard Worker
321*053f45beSAndroid Build Coastguard Worker case SND_CTL_ELEM_TYPE_INTEGER:
322*053f45beSAndroid Build Coastguard Worker int_val = snd_ctl_elem_value_get_integer(val, index);
323*053f45beSAndroid Build Coastguard Worker
324*053f45beSAndroid Build Coastguard Worker if (int_val < snd_ctl_elem_info_get_min(ctl->info)) {
325*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s.%d value %ld less than minimum %ld\n",
326*053f45beSAndroid Build Coastguard Worker ctl->name, index, int_val,
327*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_info_get_min(ctl->info));
328*053f45beSAndroid Build Coastguard Worker return false;
329*053f45beSAndroid Build Coastguard Worker }
330*053f45beSAndroid Build Coastguard Worker
331*053f45beSAndroid Build Coastguard Worker if (int_val > snd_ctl_elem_info_get_max(ctl->info)) {
332*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s.%d value %ld more than maximum %ld\n",
333*053f45beSAndroid Build Coastguard Worker ctl->name, index, int_val,
334*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_info_get_max(ctl->info));
335*053f45beSAndroid Build Coastguard Worker return false;
336*053f45beSAndroid Build Coastguard Worker }
337*053f45beSAndroid Build Coastguard Worker
338*053f45beSAndroid Build Coastguard Worker /* Only check step size if there is one and we're in bounds */
339*053f45beSAndroid Build Coastguard Worker if (snd_ctl_elem_info_get_step(ctl->info) &&
340*053f45beSAndroid Build Coastguard Worker (int_val - snd_ctl_elem_info_get_min(ctl->info) %
341*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_info_get_step(ctl->info))) {
342*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s.%d value %ld invalid for step %ld minimum %ld\n",
343*053f45beSAndroid Build Coastguard Worker ctl->name, index, int_val,
344*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_info_get_step(ctl->info),
345*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_info_get_min(ctl->info));
346*053f45beSAndroid Build Coastguard Worker return false;
347*053f45beSAndroid Build Coastguard Worker }
348*053f45beSAndroid Build Coastguard Worker break;
349*053f45beSAndroid Build Coastguard Worker
350*053f45beSAndroid Build Coastguard Worker case SND_CTL_ELEM_TYPE_INTEGER64:
351*053f45beSAndroid Build Coastguard Worker int64_val = snd_ctl_elem_value_get_integer64(val, index);
352*053f45beSAndroid Build Coastguard Worker
353*053f45beSAndroid Build Coastguard Worker if (int64_val < snd_ctl_elem_info_get_min64(ctl->info)) {
354*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s.%d value %lld less than minimum %lld\n",
355*053f45beSAndroid Build Coastguard Worker ctl->name, index, int64_val,
356*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_info_get_min64(ctl->info));
357*053f45beSAndroid Build Coastguard Worker return false;
358*053f45beSAndroid Build Coastguard Worker }
359*053f45beSAndroid Build Coastguard Worker
360*053f45beSAndroid Build Coastguard Worker if (int64_val > snd_ctl_elem_info_get_max64(ctl->info)) {
361*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s.%d value %lld more than maximum %lld\n",
362*053f45beSAndroid Build Coastguard Worker ctl->name, index, int64_val,
363*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_info_get_max(ctl->info));
364*053f45beSAndroid Build Coastguard Worker return false;
365*053f45beSAndroid Build Coastguard Worker }
366*053f45beSAndroid Build Coastguard Worker
367*053f45beSAndroid Build Coastguard Worker /* Only check step size if there is one and we're in bounds */
368*053f45beSAndroid Build Coastguard Worker if (snd_ctl_elem_info_get_step64(ctl->info) &&
369*053f45beSAndroid Build Coastguard Worker (int64_val - snd_ctl_elem_info_get_min64(ctl->info)) %
370*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_info_get_step64(ctl->info)) {
371*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s.%d value %lld invalid for step %lld minimum %lld\n",
372*053f45beSAndroid Build Coastguard Worker ctl->name, index, int64_val,
373*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_info_get_step64(ctl->info),
374*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_info_get_min64(ctl->info));
375*053f45beSAndroid Build Coastguard Worker return false;
376*053f45beSAndroid Build Coastguard Worker }
377*053f45beSAndroid Build Coastguard Worker break;
378*053f45beSAndroid Build Coastguard Worker
379*053f45beSAndroid Build Coastguard Worker case SND_CTL_ELEM_TYPE_ENUMERATED:
380*053f45beSAndroid Build Coastguard Worker int_val = snd_ctl_elem_value_get_enumerated(val, index);
381*053f45beSAndroid Build Coastguard Worker
382*053f45beSAndroid Build Coastguard Worker if (int_val < 0) {
383*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s.%d negative value %ld for enumeration\n",
384*053f45beSAndroid Build Coastguard Worker ctl->name, index, int_val);
385*053f45beSAndroid Build Coastguard Worker return false;
386*053f45beSAndroid Build Coastguard Worker }
387*053f45beSAndroid Build Coastguard Worker
388*053f45beSAndroid Build Coastguard Worker if (int_val >= snd_ctl_elem_info_get_items(ctl->info)) {
389*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s.%d value %ld more than item count %ld\n",
390*053f45beSAndroid Build Coastguard Worker ctl->name, index, int_val,
391*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_info_get_items(ctl->info));
392*053f45beSAndroid Build Coastguard Worker return false;
393*053f45beSAndroid Build Coastguard Worker }
394*053f45beSAndroid Build Coastguard Worker break;
395*053f45beSAndroid Build Coastguard Worker
396*053f45beSAndroid Build Coastguard Worker default:
397*053f45beSAndroid Build Coastguard Worker /* No tests for other types */
398*053f45beSAndroid Build Coastguard Worker break;
399*053f45beSAndroid Build Coastguard Worker }
400*053f45beSAndroid Build Coastguard Worker
401*053f45beSAndroid Build Coastguard Worker return true;
402*053f45beSAndroid Build Coastguard Worker }
403*053f45beSAndroid Build Coastguard Worker
404*053f45beSAndroid Build Coastguard Worker /*
405*053f45beSAndroid Build Coastguard Worker * Check that the provided value meets the constraints for the
406*053f45beSAndroid Build Coastguard Worker * provided control.
407*053f45beSAndroid Build Coastguard Worker */
ctl_value_valid(struct ctl_data * ctl,snd_ctl_elem_value_t * val)408*053f45beSAndroid Build Coastguard Worker static bool ctl_value_valid(struct ctl_data *ctl, snd_ctl_elem_value_t *val)
409*053f45beSAndroid Build Coastguard Worker {
410*053f45beSAndroid Build Coastguard Worker int i;
411*053f45beSAndroid Build Coastguard Worker bool valid = true;
412*053f45beSAndroid Build Coastguard Worker
413*053f45beSAndroid Build Coastguard Worker for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++)
414*053f45beSAndroid Build Coastguard Worker if (!ctl_value_index_valid(ctl, val, i))
415*053f45beSAndroid Build Coastguard Worker valid = false;
416*053f45beSAndroid Build Coastguard Worker
417*053f45beSAndroid Build Coastguard Worker return valid;
418*053f45beSAndroid Build Coastguard Worker }
419*053f45beSAndroid Build Coastguard Worker
420*053f45beSAndroid Build Coastguard Worker /*
421*053f45beSAndroid Build Coastguard Worker * Check that we can read the default value and it is valid. Write
422*053f45beSAndroid Build Coastguard Worker * tests use the read value to restore the default.
423*053f45beSAndroid Build Coastguard Worker */
test_ctl_get_value(struct ctl_data * ctl)424*053f45beSAndroid Build Coastguard Worker static void test_ctl_get_value(struct ctl_data *ctl)
425*053f45beSAndroid Build Coastguard Worker {
426*053f45beSAndroid Build Coastguard Worker int err;
427*053f45beSAndroid Build Coastguard Worker
428*053f45beSAndroid Build Coastguard Worker /* If the control is turned off let's be polite */
429*053f45beSAndroid Build Coastguard Worker if (snd_ctl_elem_info_is_inactive(ctl->info)) {
430*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s is inactive\n", ctl->name);
431*053f45beSAndroid Build Coastguard Worker ksft_test_result_skip("get_value.%d.%d\n",
432*053f45beSAndroid Build Coastguard Worker ctl->card->card, ctl->elem);
433*053f45beSAndroid Build Coastguard Worker return;
434*053f45beSAndroid Build Coastguard Worker }
435*053f45beSAndroid Build Coastguard Worker
436*053f45beSAndroid Build Coastguard Worker /* Can't test reading on an unreadable control */
437*053f45beSAndroid Build Coastguard Worker if (!snd_ctl_elem_info_is_readable(ctl->info)) {
438*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s is not readable\n", ctl->name);
439*053f45beSAndroid Build Coastguard Worker ksft_test_result_skip("get_value.%d.%d\n",
440*053f45beSAndroid Build Coastguard Worker ctl->card->card, ctl->elem);
441*053f45beSAndroid Build Coastguard Worker return;
442*053f45beSAndroid Build Coastguard Worker }
443*053f45beSAndroid Build Coastguard Worker
444*053f45beSAndroid Build Coastguard Worker err = snd_ctl_elem_read(ctl->card->handle, ctl->def_val);
445*053f45beSAndroid Build Coastguard Worker if (err < 0) {
446*053f45beSAndroid Build Coastguard Worker ksft_print_msg("snd_ctl_elem_read() failed: %s\n",
447*053f45beSAndroid Build Coastguard Worker snd_strerror(err));
448*053f45beSAndroid Build Coastguard Worker goto out;
449*053f45beSAndroid Build Coastguard Worker }
450*053f45beSAndroid Build Coastguard Worker
451*053f45beSAndroid Build Coastguard Worker if (!ctl_value_valid(ctl, ctl->def_val))
452*053f45beSAndroid Build Coastguard Worker err = -EINVAL;
453*053f45beSAndroid Build Coastguard Worker
454*053f45beSAndroid Build Coastguard Worker out:
455*053f45beSAndroid Build Coastguard Worker ksft_test_result(err >= 0, "get_value.%d.%d\n",
456*053f45beSAndroid Build Coastguard Worker ctl->card->card, ctl->elem);
457*053f45beSAndroid Build Coastguard Worker }
458*053f45beSAndroid Build Coastguard Worker
strend(const char * haystack,const char * needle)459*053f45beSAndroid Build Coastguard Worker static bool strend(const char *haystack, const char *needle)
460*053f45beSAndroid Build Coastguard Worker {
461*053f45beSAndroid Build Coastguard Worker size_t haystack_len = strlen(haystack);
462*053f45beSAndroid Build Coastguard Worker size_t needle_len = strlen(needle);
463*053f45beSAndroid Build Coastguard Worker
464*053f45beSAndroid Build Coastguard Worker if (needle_len > haystack_len)
465*053f45beSAndroid Build Coastguard Worker return false;
466*053f45beSAndroid Build Coastguard Worker return strcmp(haystack + haystack_len - needle_len, needle) == 0;
467*053f45beSAndroid Build Coastguard Worker }
468*053f45beSAndroid Build Coastguard Worker
test_ctl_name(struct ctl_data * ctl)469*053f45beSAndroid Build Coastguard Worker static void test_ctl_name(struct ctl_data *ctl)
470*053f45beSAndroid Build Coastguard Worker {
471*053f45beSAndroid Build Coastguard Worker bool name_ok = true;
472*053f45beSAndroid Build Coastguard Worker bool check;
473*053f45beSAndroid Build Coastguard Worker
474*053f45beSAndroid Build Coastguard Worker /* Only boolean controls should end in Switch */
475*053f45beSAndroid Build Coastguard Worker if (strend(ctl->name, " Switch")) {
476*053f45beSAndroid Build Coastguard Worker if (snd_ctl_elem_info_get_type(ctl->info) != SND_CTL_ELEM_TYPE_BOOLEAN) {
477*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%d.%d %s ends in Switch but is not boolean\n",
478*053f45beSAndroid Build Coastguard Worker ctl->card->card, ctl->elem, ctl->name);
479*053f45beSAndroid Build Coastguard Worker name_ok = false;
480*053f45beSAndroid Build Coastguard Worker }
481*053f45beSAndroid Build Coastguard Worker }
482*053f45beSAndroid Build Coastguard Worker
483*053f45beSAndroid Build Coastguard Worker /* Writeable boolean controls should end in Switch */
484*053f45beSAndroid Build Coastguard Worker if (snd_ctl_elem_info_get_type(ctl->info) == SND_CTL_ELEM_TYPE_BOOLEAN &&
485*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_info_is_writable(ctl->info)) {
486*053f45beSAndroid Build Coastguard Worker if (!strend(ctl->name, " Switch")) {
487*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%d.%d %s is a writeable boolean but not a Switch\n",
488*053f45beSAndroid Build Coastguard Worker ctl->card->card, ctl->elem, ctl->name);
489*053f45beSAndroid Build Coastguard Worker name_ok = false;
490*053f45beSAndroid Build Coastguard Worker }
491*053f45beSAndroid Build Coastguard Worker }
492*053f45beSAndroid Build Coastguard Worker
493*053f45beSAndroid Build Coastguard Worker ksft_test_result(name_ok, "name.%d.%d\n",
494*053f45beSAndroid Build Coastguard Worker ctl->card->card, ctl->elem);
495*053f45beSAndroid Build Coastguard Worker }
496*053f45beSAndroid Build Coastguard Worker
show_mismatch(struct ctl_data * ctl,int index,snd_ctl_elem_value_t * read_val,snd_ctl_elem_value_t * expected_val)497*053f45beSAndroid Build Coastguard Worker static bool show_mismatch(struct ctl_data *ctl, int index,
498*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_t *read_val,
499*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_t *expected_val)
500*053f45beSAndroid Build Coastguard Worker {
501*053f45beSAndroid Build Coastguard Worker long long expected_int, read_int;
502*053f45beSAndroid Build Coastguard Worker
503*053f45beSAndroid Build Coastguard Worker /*
504*053f45beSAndroid Build Coastguard Worker * We factor out the code to compare values representable as
505*053f45beSAndroid Build Coastguard Worker * integers, ensure that check doesn't log otherwise.
506*053f45beSAndroid Build Coastguard Worker */
507*053f45beSAndroid Build Coastguard Worker expected_int = 0;
508*053f45beSAndroid Build Coastguard Worker read_int = 0;
509*053f45beSAndroid Build Coastguard Worker
510*053f45beSAndroid Build Coastguard Worker switch (snd_ctl_elem_info_get_type(ctl->info)) {
511*053f45beSAndroid Build Coastguard Worker case SND_CTL_ELEM_TYPE_BOOLEAN:
512*053f45beSAndroid Build Coastguard Worker expected_int = snd_ctl_elem_value_get_boolean(expected_val,
513*053f45beSAndroid Build Coastguard Worker index);
514*053f45beSAndroid Build Coastguard Worker read_int = snd_ctl_elem_value_get_boolean(read_val, index);
515*053f45beSAndroid Build Coastguard Worker break;
516*053f45beSAndroid Build Coastguard Worker
517*053f45beSAndroid Build Coastguard Worker case SND_CTL_ELEM_TYPE_INTEGER:
518*053f45beSAndroid Build Coastguard Worker expected_int = snd_ctl_elem_value_get_integer(expected_val,
519*053f45beSAndroid Build Coastguard Worker index);
520*053f45beSAndroid Build Coastguard Worker read_int = snd_ctl_elem_value_get_integer(read_val, index);
521*053f45beSAndroid Build Coastguard Worker break;
522*053f45beSAndroid Build Coastguard Worker
523*053f45beSAndroid Build Coastguard Worker case SND_CTL_ELEM_TYPE_INTEGER64:
524*053f45beSAndroid Build Coastguard Worker expected_int = snd_ctl_elem_value_get_integer64(expected_val,
525*053f45beSAndroid Build Coastguard Worker index);
526*053f45beSAndroid Build Coastguard Worker read_int = snd_ctl_elem_value_get_integer64(read_val,
527*053f45beSAndroid Build Coastguard Worker index);
528*053f45beSAndroid Build Coastguard Worker break;
529*053f45beSAndroid Build Coastguard Worker
530*053f45beSAndroid Build Coastguard Worker case SND_CTL_ELEM_TYPE_ENUMERATED:
531*053f45beSAndroid Build Coastguard Worker expected_int = snd_ctl_elem_value_get_enumerated(expected_val,
532*053f45beSAndroid Build Coastguard Worker index);
533*053f45beSAndroid Build Coastguard Worker read_int = snd_ctl_elem_value_get_enumerated(read_val,
534*053f45beSAndroid Build Coastguard Worker index);
535*053f45beSAndroid Build Coastguard Worker break;
536*053f45beSAndroid Build Coastguard Worker
537*053f45beSAndroid Build Coastguard Worker default:
538*053f45beSAndroid Build Coastguard Worker break;
539*053f45beSAndroid Build Coastguard Worker }
540*053f45beSAndroid Build Coastguard Worker
541*053f45beSAndroid Build Coastguard Worker if (expected_int != read_int) {
542*053f45beSAndroid Build Coastguard Worker /*
543*053f45beSAndroid Build Coastguard Worker * NOTE: The volatile attribute means that the hardware
544*053f45beSAndroid Build Coastguard Worker * can voluntarily change the state of control element
545*053f45beSAndroid Build Coastguard Worker * independent of any operation by software.
546*053f45beSAndroid Build Coastguard Worker */
547*053f45beSAndroid Build Coastguard Worker bool is_volatile = snd_ctl_elem_info_is_volatile(ctl->info);
548*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s.%d expected %lld but read %lld, is_volatile %d\n",
549*053f45beSAndroid Build Coastguard Worker ctl->name, index, expected_int, read_int, is_volatile);
550*053f45beSAndroid Build Coastguard Worker return !is_volatile;
551*053f45beSAndroid Build Coastguard Worker } else {
552*053f45beSAndroid Build Coastguard Worker return false;
553*053f45beSAndroid Build Coastguard Worker }
554*053f45beSAndroid Build Coastguard Worker }
555*053f45beSAndroid Build Coastguard Worker
556*053f45beSAndroid Build Coastguard Worker /*
557*053f45beSAndroid Build Coastguard Worker * Write a value then if possible verify that we get the expected
558*053f45beSAndroid Build Coastguard Worker * result. An optional expected value can be provided if we expect
559*053f45beSAndroid Build Coastguard Worker * the write to fail, for verifying that invalid writes don't corrupt
560*053f45beSAndroid Build Coastguard Worker * anything.
561*053f45beSAndroid Build Coastguard Worker */
write_and_verify(struct ctl_data * ctl,snd_ctl_elem_value_t * write_val,snd_ctl_elem_value_t * expected_val)562*053f45beSAndroid Build Coastguard Worker static int write_and_verify(struct ctl_data *ctl,
563*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_t *write_val,
564*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_t *expected_val)
565*053f45beSAndroid Build Coastguard Worker {
566*053f45beSAndroid Build Coastguard Worker int err, i;
567*053f45beSAndroid Build Coastguard Worker bool error_expected, mismatch_shown;
568*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_t *initial_val, *read_val, *w_val;
569*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_alloca(&initial_val);
570*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_alloca(&read_val);
571*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_alloca(&w_val);
572*053f45beSAndroid Build Coastguard Worker
573*053f45beSAndroid Build Coastguard Worker /*
574*053f45beSAndroid Build Coastguard Worker * We need to copy the write value since writing can modify
575*053f45beSAndroid Build Coastguard Worker * the value which causes surprises, and allocate an expected
576*053f45beSAndroid Build Coastguard Worker * value if we expect to read back what we wrote.
577*053f45beSAndroid Build Coastguard Worker */
578*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_copy(w_val, write_val);
579*053f45beSAndroid Build Coastguard Worker if (expected_val) {
580*053f45beSAndroid Build Coastguard Worker error_expected = true;
581*053f45beSAndroid Build Coastguard Worker } else {
582*053f45beSAndroid Build Coastguard Worker error_expected = false;
583*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_alloca(&expected_val);
584*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_copy(expected_val, write_val);
585*053f45beSAndroid Build Coastguard Worker }
586*053f45beSAndroid Build Coastguard Worker
587*053f45beSAndroid Build Coastguard Worker /* Store the value before we write */
588*053f45beSAndroid Build Coastguard Worker if (snd_ctl_elem_info_is_readable(ctl->info)) {
589*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_id(initial_val, ctl->id);
590*053f45beSAndroid Build Coastguard Worker
591*053f45beSAndroid Build Coastguard Worker err = snd_ctl_elem_read(ctl->card->handle, initial_val);
592*053f45beSAndroid Build Coastguard Worker if (err < 0) {
593*053f45beSAndroid Build Coastguard Worker ksft_print_msg("snd_ctl_elem_read() failed: %s\n",
594*053f45beSAndroid Build Coastguard Worker snd_strerror(err));
595*053f45beSAndroid Build Coastguard Worker return err;
596*053f45beSAndroid Build Coastguard Worker }
597*053f45beSAndroid Build Coastguard Worker }
598*053f45beSAndroid Build Coastguard Worker
599*053f45beSAndroid Build Coastguard Worker /*
600*053f45beSAndroid Build Coastguard Worker * Do the write, if we have an expected value ignore the error
601*053f45beSAndroid Build Coastguard Worker * and carry on to validate the expected value.
602*053f45beSAndroid Build Coastguard Worker */
603*053f45beSAndroid Build Coastguard Worker err = snd_ctl_elem_write(ctl->card->handle, w_val);
604*053f45beSAndroid Build Coastguard Worker if (err < 0 && !error_expected) {
605*053f45beSAndroid Build Coastguard Worker ksft_print_msg("snd_ctl_elem_write() failed: %s\n",
606*053f45beSAndroid Build Coastguard Worker snd_strerror(err));
607*053f45beSAndroid Build Coastguard Worker return err;
608*053f45beSAndroid Build Coastguard Worker }
609*053f45beSAndroid Build Coastguard Worker
610*053f45beSAndroid Build Coastguard Worker /* Can we do the verification part? */
611*053f45beSAndroid Build Coastguard Worker if (!snd_ctl_elem_info_is_readable(ctl->info))
612*053f45beSAndroid Build Coastguard Worker return err;
613*053f45beSAndroid Build Coastguard Worker
614*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_id(read_val, ctl->id);
615*053f45beSAndroid Build Coastguard Worker
616*053f45beSAndroid Build Coastguard Worker err = snd_ctl_elem_read(ctl->card->handle, read_val);
617*053f45beSAndroid Build Coastguard Worker if (err < 0) {
618*053f45beSAndroid Build Coastguard Worker ksft_print_msg("snd_ctl_elem_read() failed: %s\n",
619*053f45beSAndroid Build Coastguard Worker snd_strerror(err));
620*053f45beSAndroid Build Coastguard Worker return err;
621*053f45beSAndroid Build Coastguard Worker }
622*053f45beSAndroid Build Coastguard Worker
623*053f45beSAndroid Build Coastguard Worker /*
624*053f45beSAndroid Build Coastguard Worker * Check for an event if the value changed, or confirm that
625*053f45beSAndroid Build Coastguard Worker * there was none if it didn't. We rely on the kernel
626*053f45beSAndroid Build Coastguard Worker * generating the notification before it returns from the
627*053f45beSAndroid Build Coastguard Worker * write, this is currently true, should that ever change this
628*053f45beSAndroid Build Coastguard Worker * will most likely break and need updating.
629*053f45beSAndroid Build Coastguard Worker */
630*053f45beSAndroid Build Coastguard Worker if (!snd_ctl_elem_info_is_volatile(ctl->info)) {
631*053f45beSAndroid Build Coastguard Worker err = wait_for_event(ctl, 0);
632*053f45beSAndroid Build Coastguard Worker if (snd_ctl_elem_value_compare(initial_val, read_val)) {
633*053f45beSAndroid Build Coastguard Worker if (err < 1) {
634*053f45beSAndroid Build Coastguard Worker ksft_print_msg("No event generated for %s\n",
635*053f45beSAndroid Build Coastguard Worker ctl->name);
636*053f45beSAndroid Build Coastguard Worker ctl->event_missing++;
637*053f45beSAndroid Build Coastguard Worker }
638*053f45beSAndroid Build Coastguard Worker } else {
639*053f45beSAndroid Build Coastguard Worker if (err != 0) {
640*053f45beSAndroid Build Coastguard Worker ksft_print_msg("Spurious event generated for %s\n",
641*053f45beSAndroid Build Coastguard Worker ctl->name);
642*053f45beSAndroid Build Coastguard Worker ctl->event_spurious++;
643*053f45beSAndroid Build Coastguard Worker }
644*053f45beSAndroid Build Coastguard Worker }
645*053f45beSAndroid Build Coastguard Worker }
646*053f45beSAndroid Build Coastguard Worker
647*053f45beSAndroid Build Coastguard Worker /*
648*053f45beSAndroid Build Coastguard Worker * Use the libray to compare values, if there's a mismatch
649*053f45beSAndroid Build Coastguard Worker * carry on and try to provide a more useful diagnostic than
650*053f45beSAndroid Build Coastguard Worker * just "mismatch".
651*053f45beSAndroid Build Coastguard Worker */
652*053f45beSAndroid Build Coastguard Worker if (!snd_ctl_elem_value_compare(expected_val, read_val))
653*053f45beSAndroid Build Coastguard Worker return 0;
654*053f45beSAndroid Build Coastguard Worker
655*053f45beSAndroid Build Coastguard Worker mismatch_shown = false;
656*053f45beSAndroid Build Coastguard Worker for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++)
657*053f45beSAndroid Build Coastguard Worker if (show_mismatch(ctl, i, read_val, expected_val))
658*053f45beSAndroid Build Coastguard Worker mismatch_shown = true;
659*053f45beSAndroid Build Coastguard Worker
660*053f45beSAndroid Build Coastguard Worker if (!mismatch_shown)
661*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s read and written values differ\n",
662*053f45beSAndroid Build Coastguard Worker ctl->name);
663*053f45beSAndroid Build Coastguard Worker
664*053f45beSAndroid Build Coastguard Worker return -1;
665*053f45beSAndroid Build Coastguard Worker }
666*053f45beSAndroid Build Coastguard Worker
667*053f45beSAndroid Build Coastguard Worker /*
668*053f45beSAndroid Build Coastguard Worker * Make sure we can write the default value back to the control, this
669*053f45beSAndroid Build Coastguard Worker * should validate that at least some write works.
670*053f45beSAndroid Build Coastguard Worker */
test_ctl_write_default(struct ctl_data * ctl)671*053f45beSAndroid Build Coastguard Worker static void test_ctl_write_default(struct ctl_data *ctl)
672*053f45beSAndroid Build Coastguard Worker {
673*053f45beSAndroid Build Coastguard Worker int err;
674*053f45beSAndroid Build Coastguard Worker
675*053f45beSAndroid Build Coastguard Worker /* If the control is turned off let's be polite */
676*053f45beSAndroid Build Coastguard Worker if (snd_ctl_elem_info_is_inactive(ctl->info)) {
677*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s is inactive\n", ctl->name);
678*053f45beSAndroid Build Coastguard Worker ksft_test_result_skip("write_default.%d.%d\n",
679*053f45beSAndroid Build Coastguard Worker ctl->card->card, ctl->elem);
680*053f45beSAndroid Build Coastguard Worker return;
681*053f45beSAndroid Build Coastguard Worker }
682*053f45beSAndroid Build Coastguard Worker
683*053f45beSAndroid Build Coastguard Worker if (!snd_ctl_elem_info_is_writable(ctl->info)) {
684*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s is not writeable\n", ctl->name);
685*053f45beSAndroid Build Coastguard Worker ksft_test_result_skip("write_default.%d.%d\n",
686*053f45beSAndroid Build Coastguard Worker ctl->card->card, ctl->elem);
687*053f45beSAndroid Build Coastguard Worker return;
688*053f45beSAndroid Build Coastguard Worker }
689*053f45beSAndroid Build Coastguard Worker
690*053f45beSAndroid Build Coastguard Worker /* No idea what the default was for unreadable controls */
691*053f45beSAndroid Build Coastguard Worker if (!snd_ctl_elem_info_is_readable(ctl->info)) {
692*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s couldn't read default\n", ctl->name);
693*053f45beSAndroid Build Coastguard Worker ksft_test_result_skip("write_default.%d.%d\n",
694*053f45beSAndroid Build Coastguard Worker ctl->card->card, ctl->elem);
695*053f45beSAndroid Build Coastguard Worker return;
696*053f45beSAndroid Build Coastguard Worker }
697*053f45beSAndroid Build Coastguard Worker
698*053f45beSAndroid Build Coastguard Worker err = write_and_verify(ctl, ctl->def_val, NULL);
699*053f45beSAndroid Build Coastguard Worker
700*053f45beSAndroid Build Coastguard Worker ksft_test_result(err >= 0, "write_default.%d.%d\n",
701*053f45beSAndroid Build Coastguard Worker ctl->card->card, ctl->elem);
702*053f45beSAndroid Build Coastguard Worker }
703*053f45beSAndroid Build Coastguard Worker
test_ctl_write_valid_boolean(struct ctl_data * ctl)704*053f45beSAndroid Build Coastguard Worker static bool test_ctl_write_valid_boolean(struct ctl_data *ctl)
705*053f45beSAndroid Build Coastguard Worker {
706*053f45beSAndroid Build Coastguard Worker int err, i, j;
707*053f45beSAndroid Build Coastguard Worker bool fail = false;
708*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_t *val;
709*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_alloca(&val);
710*053f45beSAndroid Build Coastguard Worker
711*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_id(val, ctl->id);
712*053f45beSAndroid Build Coastguard Worker
713*053f45beSAndroid Build Coastguard Worker for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
714*053f45beSAndroid Build Coastguard Worker for (j = 0; j < 2; j++) {
715*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_boolean(val, i, j);
716*053f45beSAndroid Build Coastguard Worker err = write_and_verify(ctl, val, NULL);
717*053f45beSAndroid Build Coastguard Worker if (err != 0)
718*053f45beSAndroid Build Coastguard Worker fail = true;
719*053f45beSAndroid Build Coastguard Worker }
720*053f45beSAndroid Build Coastguard Worker }
721*053f45beSAndroid Build Coastguard Worker
722*053f45beSAndroid Build Coastguard Worker return !fail;
723*053f45beSAndroid Build Coastguard Worker }
724*053f45beSAndroid Build Coastguard Worker
test_ctl_write_valid_integer(struct ctl_data * ctl)725*053f45beSAndroid Build Coastguard Worker static bool test_ctl_write_valid_integer(struct ctl_data *ctl)
726*053f45beSAndroid Build Coastguard Worker {
727*053f45beSAndroid Build Coastguard Worker int err;
728*053f45beSAndroid Build Coastguard Worker int i;
729*053f45beSAndroid Build Coastguard Worker long j, step;
730*053f45beSAndroid Build Coastguard Worker bool fail = false;
731*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_t *val;
732*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_alloca(&val);
733*053f45beSAndroid Build Coastguard Worker
734*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_id(val, ctl->id);
735*053f45beSAndroid Build Coastguard Worker
736*053f45beSAndroid Build Coastguard Worker step = snd_ctl_elem_info_get_step(ctl->info);
737*053f45beSAndroid Build Coastguard Worker if (!step)
738*053f45beSAndroid Build Coastguard Worker step = 1;
739*053f45beSAndroid Build Coastguard Worker
740*053f45beSAndroid Build Coastguard Worker for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
741*053f45beSAndroid Build Coastguard Worker for (j = snd_ctl_elem_info_get_min(ctl->info);
742*053f45beSAndroid Build Coastguard Worker j <= snd_ctl_elem_info_get_max(ctl->info); j += step) {
743*053f45beSAndroid Build Coastguard Worker
744*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_integer(val, i, j);
745*053f45beSAndroid Build Coastguard Worker err = write_and_verify(ctl, val, NULL);
746*053f45beSAndroid Build Coastguard Worker if (err != 0)
747*053f45beSAndroid Build Coastguard Worker fail = true;
748*053f45beSAndroid Build Coastguard Worker }
749*053f45beSAndroid Build Coastguard Worker }
750*053f45beSAndroid Build Coastguard Worker
751*053f45beSAndroid Build Coastguard Worker
752*053f45beSAndroid Build Coastguard Worker return !fail;
753*053f45beSAndroid Build Coastguard Worker }
754*053f45beSAndroid Build Coastguard Worker
test_ctl_write_valid_integer64(struct ctl_data * ctl)755*053f45beSAndroid Build Coastguard Worker static bool test_ctl_write_valid_integer64(struct ctl_data *ctl)
756*053f45beSAndroid Build Coastguard Worker {
757*053f45beSAndroid Build Coastguard Worker int err, i;
758*053f45beSAndroid Build Coastguard Worker long long j, step;
759*053f45beSAndroid Build Coastguard Worker bool fail = false;
760*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_t *val;
761*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_alloca(&val);
762*053f45beSAndroid Build Coastguard Worker
763*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_id(val, ctl->id);
764*053f45beSAndroid Build Coastguard Worker
765*053f45beSAndroid Build Coastguard Worker step = snd_ctl_elem_info_get_step64(ctl->info);
766*053f45beSAndroid Build Coastguard Worker if (!step)
767*053f45beSAndroid Build Coastguard Worker step = 1;
768*053f45beSAndroid Build Coastguard Worker
769*053f45beSAndroid Build Coastguard Worker for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
770*053f45beSAndroid Build Coastguard Worker for (j = snd_ctl_elem_info_get_min64(ctl->info);
771*053f45beSAndroid Build Coastguard Worker j <= snd_ctl_elem_info_get_max64(ctl->info); j += step) {
772*053f45beSAndroid Build Coastguard Worker
773*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_integer64(val, i, j);
774*053f45beSAndroid Build Coastguard Worker err = write_and_verify(ctl, val, NULL);
775*053f45beSAndroid Build Coastguard Worker if (err != 0)
776*053f45beSAndroid Build Coastguard Worker fail = true;
777*053f45beSAndroid Build Coastguard Worker }
778*053f45beSAndroid Build Coastguard Worker }
779*053f45beSAndroid Build Coastguard Worker
780*053f45beSAndroid Build Coastguard Worker return !fail;
781*053f45beSAndroid Build Coastguard Worker }
782*053f45beSAndroid Build Coastguard Worker
test_ctl_write_valid_enumerated(struct ctl_data * ctl)783*053f45beSAndroid Build Coastguard Worker static bool test_ctl_write_valid_enumerated(struct ctl_data *ctl)
784*053f45beSAndroid Build Coastguard Worker {
785*053f45beSAndroid Build Coastguard Worker int err, i, j;
786*053f45beSAndroid Build Coastguard Worker bool fail = false;
787*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_t *val;
788*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_alloca(&val);
789*053f45beSAndroid Build Coastguard Worker
790*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_id(val, ctl->id);
791*053f45beSAndroid Build Coastguard Worker
792*053f45beSAndroid Build Coastguard Worker for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
793*053f45beSAndroid Build Coastguard Worker for (j = 0; j < snd_ctl_elem_info_get_items(ctl->info); j++) {
794*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_enumerated(val, i, j);
795*053f45beSAndroid Build Coastguard Worker err = write_and_verify(ctl, val, NULL);
796*053f45beSAndroid Build Coastguard Worker if (err != 0)
797*053f45beSAndroid Build Coastguard Worker fail = true;
798*053f45beSAndroid Build Coastguard Worker }
799*053f45beSAndroid Build Coastguard Worker }
800*053f45beSAndroid Build Coastguard Worker
801*053f45beSAndroid Build Coastguard Worker return !fail;
802*053f45beSAndroid Build Coastguard Worker }
803*053f45beSAndroid Build Coastguard Worker
test_ctl_write_valid(struct ctl_data * ctl)804*053f45beSAndroid Build Coastguard Worker static void test_ctl_write_valid(struct ctl_data *ctl)
805*053f45beSAndroid Build Coastguard Worker {
806*053f45beSAndroid Build Coastguard Worker bool pass;
807*053f45beSAndroid Build Coastguard Worker int err;
808*053f45beSAndroid Build Coastguard Worker
809*053f45beSAndroid Build Coastguard Worker /* If the control is turned off let's be polite */
810*053f45beSAndroid Build Coastguard Worker if (snd_ctl_elem_info_is_inactive(ctl->info)) {
811*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s is inactive\n", ctl->name);
812*053f45beSAndroid Build Coastguard Worker ksft_test_result_skip("write_valid.%d.%d\n",
813*053f45beSAndroid Build Coastguard Worker ctl->card->card, ctl->elem);
814*053f45beSAndroid Build Coastguard Worker return;
815*053f45beSAndroid Build Coastguard Worker }
816*053f45beSAndroid Build Coastguard Worker
817*053f45beSAndroid Build Coastguard Worker if (!snd_ctl_elem_info_is_writable(ctl->info)) {
818*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s is not writeable\n", ctl->name);
819*053f45beSAndroid Build Coastguard Worker ksft_test_result_skip("write_valid.%d.%d\n",
820*053f45beSAndroid Build Coastguard Worker ctl->card->card, ctl->elem);
821*053f45beSAndroid Build Coastguard Worker return;
822*053f45beSAndroid Build Coastguard Worker }
823*053f45beSAndroid Build Coastguard Worker
824*053f45beSAndroid Build Coastguard Worker switch (snd_ctl_elem_info_get_type(ctl->info)) {
825*053f45beSAndroid Build Coastguard Worker case SND_CTL_ELEM_TYPE_BOOLEAN:
826*053f45beSAndroid Build Coastguard Worker pass = test_ctl_write_valid_boolean(ctl);
827*053f45beSAndroid Build Coastguard Worker break;
828*053f45beSAndroid Build Coastguard Worker
829*053f45beSAndroid Build Coastguard Worker case SND_CTL_ELEM_TYPE_INTEGER:
830*053f45beSAndroid Build Coastguard Worker pass = test_ctl_write_valid_integer(ctl);
831*053f45beSAndroid Build Coastguard Worker break;
832*053f45beSAndroid Build Coastguard Worker
833*053f45beSAndroid Build Coastguard Worker case SND_CTL_ELEM_TYPE_INTEGER64:
834*053f45beSAndroid Build Coastguard Worker pass = test_ctl_write_valid_integer64(ctl);
835*053f45beSAndroid Build Coastguard Worker break;
836*053f45beSAndroid Build Coastguard Worker
837*053f45beSAndroid Build Coastguard Worker case SND_CTL_ELEM_TYPE_ENUMERATED:
838*053f45beSAndroid Build Coastguard Worker pass = test_ctl_write_valid_enumerated(ctl);
839*053f45beSAndroid Build Coastguard Worker break;
840*053f45beSAndroid Build Coastguard Worker
841*053f45beSAndroid Build Coastguard Worker default:
842*053f45beSAndroid Build Coastguard Worker /* No tests for this yet */
843*053f45beSAndroid Build Coastguard Worker ksft_test_result_skip("write_valid.%d.%d\n",
844*053f45beSAndroid Build Coastguard Worker ctl->card->card, ctl->elem);
845*053f45beSAndroid Build Coastguard Worker return;
846*053f45beSAndroid Build Coastguard Worker }
847*053f45beSAndroid Build Coastguard Worker
848*053f45beSAndroid Build Coastguard Worker /* Restore the default value to minimise disruption */
849*053f45beSAndroid Build Coastguard Worker err = write_and_verify(ctl, ctl->def_val, NULL);
850*053f45beSAndroid Build Coastguard Worker if (err < 0)
851*053f45beSAndroid Build Coastguard Worker pass = false;
852*053f45beSAndroid Build Coastguard Worker
853*053f45beSAndroid Build Coastguard Worker ksft_test_result(pass, "write_valid.%d.%d\n",
854*053f45beSAndroid Build Coastguard Worker ctl->card->card, ctl->elem);
855*053f45beSAndroid Build Coastguard Worker }
856*053f45beSAndroid Build Coastguard Worker
test_ctl_write_invalid_value(struct ctl_data * ctl,snd_ctl_elem_value_t * val)857*053f45beSAndroid Build Coastguard Worker static bool test_ctl_write_invalid_value(struct ctl_data *ctl,
858*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_t *val)
859*053f45beSAndroid Build Coastguard Worker {
860*053f45beSAndroid Build Coastguard Worker int err;
861*053f45beSAndroid Build Coastguard Worker long val_read;
862*053f45beSAndroid Build Coastguard Worker
863*053f45beSAndroid Build Coastguard Worker /* Ideally this will fail... */
864*053f45beSAndroid Build Coastguard Worker err = snd_ctl_elem_write(ctl->card->handle, val);
865*053f45beSAndroid Build Coastguard Worker if (err < 0)
866*053f45beSAndroid Build Coastguard Worker return false;
867*053f45beSAndroid Build Coastguard Worker
868*053f45beSAndroid Build Coastguard Worker /* ...but some devices will clamp to an in range value */
869*053f45beSAndroid Build Coastguard Worker err = snd_ctl_elem_read(ctl->card->handle, val);
870*053f45beSAndroid Build Coastguard Worker if (err < 0) {
871*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s failed to read: %s\n",
872*053f45beSAndroid Build Coastguard Worker ctl->name, snd_strerror(err));
873*053f45beSAndroid Build Coastguard Worker return true;
874*053f45beSAndroid Build Coastguard Worker }
875*053f45beSAndroid Build Coastguard Worker
876*053f45beSAndroid Build Coastguard Worker return !ctl_value_valid(ctl, val);
877*053f45beSAndroid Build Coastguard Worker }
878*053f45beSAndroid Build Coastguard Worker
test_ctl_write_invalid_boolean(struct ctl_data * ctl)879*053f45beSAndroid Build Coastguard Worker static bool test_ctl_write_invalid_boolean(struct ctl_data *ctl)
880*053f45beSAndroid Build Coastguard Worker {
881*053f45beSAndroid Build Coastguard Worker int err, i;
882*053f45beSAndroid Build Coastguard Worker long val_read;
883*053f45beSAndroid Build Coastguard Worker bool fail = false;
884*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_t *val;
885*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_alloca(&val);
886*053f45beSAndroid Build Coastguard Worker
887*053f45beSAndroid Build Coastguard Worker for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
888*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_copy(val, ctl->def_val);
889*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_boolean(val, i, 2);
890*053f45beSAndroid Build Coastguard Worker
891*053f45beSAndroid Build Coastguard Worker if (test_ctl_write_invalid_value(ctl, val))
892*053f45beSAndroid Build Coastguard Worker fail = true;
893*053f45beSAndroid Build Coastguard Worker }
894*053f45beSAndroid Build Coastguard Worker
895*053f45beSAndroid Build Coastguard Worker return !fail;
896*053f45beSAndroid Build Coastguard Worker }
897*053f45beSAndroid Build Coastguard Worker
test_ctl_write_invalid_integer(struct ctl_data * ctl)898*053f45beSAndroid Build Coastguard Worker static bool test_ctl_write_invalid_integer(struct ctl_data *ctl)
899*053f45beSAndroid Build Coastguard Worker {
900*053f45beSAndroid Build Coastguard Worker int i;
901*053f45beSAndroid Build Coastguard Worker bool fail = false;
902*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_t *val;
903*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_alloca(&val);
904*053f45beSAndroid Build Coastguard Worker
905*053f45beSAndroid Build Coastguard Worker for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
906*053f45beSAndroid Build Coastguard Worker if (snd_ctl_elem_info_get_min(ctl->info) != LONG_MIN) {
907*053f45beSAndroid Build Coastguard Worker /* Just under range */
908*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_copy(val, ctl->def_val);
909*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_integer(val, i,
910*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_info_get_min(ctl->info) - 1);
911*053f45beSAndroid Build Coastguard Worker
912*053f45beSAndroid Build Coastguard Worker if (test_ctl_write_invalid_value(ctl, val))
913*053f45beSAndroid Build Coastguard Worker fail = true;
914*053f45beSAndroid Build Coastguard Worker
915*053f45beSAndroid Build Coastguard Worker /* Minimum representable value */
916*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_copy(val, ctl->def_val);
917*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_integer(val, i, LONG_MIN);
918*053f45beSAndroid Build Coastguard Worker
919*053f45beSAndroid Build Coastguard Worker if (test_ctl_write_invalid_value(ctl, val))
920*053f45beSAndroid Build Coastguard Worker fail = true;
921*053f45beSAndroid Build Coastguard Worker }
922*053f45beSAndroid Build Coastguard Worker
923*053f45beSAndroid Build Coastguard Worker if (snd_ctl_elem_info_get_max(ctl->info) != LONG_MAX) {
924*053f45beSAndroid Build Coastguard Worker /* Just over range */
925*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_copy(val, ctl->def_val);
926*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_integer(val, i,
927*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_info_get_max(ctl->info) + 1);
928*053f45beSAndroid Build Coastguard Worker
929*053f45beSAndroid Build Coastguard Worker if (test_ctl_write_invalid_value(ctl, val))
930*053f45beSAndroid Build Coastguard Worker fail = true;
931*053f45beSAndroid Build Coastguard Worker
932*053f45beSAndroid Build Coastguard Worker /* Maximum representable value */
933*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_copy(val, ctl->def_val);
934*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_integer(val, i, LONG_MAX);
935*053f45beSAndroid Build Coastguard Worker
936*053f45beSAndroid Build Coastguard Worker if (test_ctl_write_invalid_value(ctl, val))
937*053f45beSAndroid Build Coastguard Worker fail = true;
938*053f45beSAndroid Build Coastguard Worker }
939*053f45beSAndroid Build Coastguard Worker }
940*053f45beSAndroid Build Coastguard Worker
941*053f45beSAndroid Build Coastguard Worker return !fail;
942*053f45beSAndroid Build Coastguard Worker }
943*053f45beSAndroid Build Coastguard Worker
test_ctl_write_invalid_integer64(struct ctl_data * ctl)944*053f45beSAndroid Build Coastguard Worker static bool test_ctl_write_invalid_integer64(struct ctl_data *ctl)
945*053f45beSAndroid Build Coastguard Worker {
946*053f45beSAndroid Build Coastguard Worker int i;
947*053f45beSAndroid Build Coastguard Worker bool fail = false;
948*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_t *val;
949*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_alloca(&val);
950*053f45beSAndroid Build Coastguard Worker
951*053f45beSAndroid Build Coastguard Worker for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
952*053f45beSAndroid Build Coastguard Worker if (snd_ctl_elem_info_get_min64(ctl->info) != LLONG_MIN) {
953*053f45beSAndroid Build Coastguard Worker /* Just under range */
954*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_copy(val, ctl->def_val);
955*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_integer64(val, i,
956*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_info_get_min64(ctl->info) - 1);
957*053f45beSAndroid Build Coastguard Worker
958*053f45beSAndroid Build Coastguard Worker if (test_ctl_write_invalid_value(ctl, val))
959*053f45beSAndroid Build Coastguard Worker fail = true;
960*053f45beSAndroid Build Coastguard Worker
961*053f45beSAndroid Build Coastguard Worker /* Minimum representable value */
962*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_copy(val, ctl->def_val);
963*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_integer64(val, i, LLONG_MIN);
964*053f45beSAndroid Build Coastguard Worker
965*053f45beSAndroid Build Coastguard Worker if (test_ctl_write_invalid_value(ctl, val))
966*053f45beSAndroid Build Coastguard Worker fail = true;
967*053f45beSAndroid Build Coastguard Worker }
968*053f45beSAndroid Build Coastguard Worker
969*053f45beSAndroid Build Coastguard Worker if (snd_ctl_elem_info_get_max64(ctl->info) != LLONG_MAX) {
970*053f45beSAndroid Build Coastguard Worker /* Just over range */
971*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_copy(val, ctl->def_val);
972*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_integer64(val, i,
973*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_info_get_max64(ctl->info) + 1);
974*053f45beSAndroid Build Coastguard Worker
975*053f45beSAndroid Build Coastguard Worker if (test_ctl_write_invalid_value(ctl, val))
976*053f45beSAndroid Build Coastguard Worker fail = true;
977*053f45beSAndroid Build Coastguard Worker
978*053f45beSAndroid Build Coastguard Worker /* Maximum representable value */
979*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_copy(val, ctl->def_val);
980*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_integer64(val, i, LLONG_MAX);
981*053f45beSAndroid Build Coastguard Worker
982*053f45beSAndroid Build Coastguard Worker if (test_ctl_write_invalid_value(ctl, val))
983*053f45beSAndroid Build Coastguard Worker fail = true;
984*053f45beSAndroid Build Coastguard Worker }
985*053f45beSAndroid Build Coastguard Worker }
986*053f45beSAndroid Build Coastguard Worker
987*053f45beSAndroid Build Coastguard Worker return !fail;
988*053f45beSAndroid Build Coastguard Worker }
989*053f45beSAndroid Build Coastguard Worker
test_ctl_write_invalid_enumerated(struct ctl_data * ctl)990*053f45beSAndroid Build Coastguard Worker static bool test_ctl_write_invalid_enumerated(struct ctl_data *ctl)
991*053f45beSAndroid Build Coastguard Worker {
992*053f45beSAndroid Build Coastguard Worker int err, i;
993*053f45beSAndroid Build Coastguard Worker unsigned int val_read;
994*053f45beSAndroid Build Coastguard Worker bool fail = false;
995*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_t *val;
996*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_alloca(&val);
997*053f45beSAndroid Build Coastguard Worker
998*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_id(val, ctl->id);
999*053f45beSAndroid Build Coastguard Worker
1000*053f45beSAndroid Build Coastguard Worker for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
1001*053f45beSAndroid Build Coastguard Worker /* One beyond maximum */
1002*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_copy(val, ctl->def_val);
1003*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_enumerated(val, i,
1004*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_info_get_items(ctl->info));
1005*053f45beSAndroid Build Coastguard Worker
1006*053f45beSAndroid Build Coastguard Worker if (test_ctl_write_invalid_value(ctl, val))
1007*053f45beSAndroid Build Coastguard Worker fail = true;
1008*053f45beSAndroid Build Coastguard Worker
1009*053f45beSAndroid Build Coastguard Worker /* Maximum representable value */
1010*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_copy(val, ctl->def_val);
1011*053f45beSAndroid Build Coastguard Worker snd_ctl_elem_value_set_enumerated(val, i, UINT_MAX);
1012*053f45beSAndroid Build Coastguard Worker
1013*053f45beSAndroid Build Coastguard Worker if (test_ctl_write_invalid_value(ctl, val))
1014*053f45beSAndroid Build Coastguard Worker fail = true;
1015*053f45beSAndroid Build Coastguard Worker
1016*053f45beSAndroid Build Coastguard Worker }
1017*053f45beSAndroid Build Coastguard Worker
1018*053f45beSAndroid Build Coastguard Worker return !fail;
1019*053f45beSAndroid Build Coastguard Worker }
1020*053f45beSAndroid Build Coastguard Worker
1021*053f45beSAndroid Build Coastguard Worker
test_ctl_write_invalid(struct ctl_data * ctl)1022*053f45beSAndroid Build Coastguard Worker static void test_ctl_write_invalid(struct ctl_data *ctl)
1023*053f45beSAndroid Build Coastguard Worker {
1024*053f45beSAndroid Build Coastguard Worker bool pass;
1025*053f45beSAndroid Build Coastguard Worker int err;
1026*053f45beSAndroid Build Coastguard Worker
1027*053f45beSAndroid Build Coastguard Worker /* If the control is turned off let's be polite */
1028*053f45beSAndroid Build Coastguard Worker if (snd_ctl_elem_info_is_inactive(ctl->info)) {
1029*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s is inactive\n", ctl->name);
1030*053f45beSAndroid Build Coastguard Worker ksft_test_result_skip("write_invalid.%d.%d\n",
1031*053f45beSAndroid Build Coastguard Worker ctl->card->card, ctl->elem);
1032*053f45beSAndroid Build Coastguard Worker return;
1033*053f45beSAndroid Build Coastguard Worker }
1034*053f45beSAndroid Build Coastguard Worker
1035*053f45beSAndroid Build Coastguard Worker if (!snd_ctl_elem_info_is_writable(ctl->info)) {
1036*053f45beSAndroid Build Coastguard Worker ksft_print_msg("%s is not writeable\n", ctl->name);
1037*053f45beSAndroid Build Coastguard Worker ksft_test_result_skip("write_invalid.%d.%d\n",
1038*053f45beSAndroid Build Coastguard Worker ctl->card->card, ctl->elem);
1039*053f45beSAndroid Build Coastguard Worker return;
1040*053f45beSAndroid Build Coastguard Worker }
1041*053f45beSAndroid Build Coastguard Worker
1042*053f45beSAndroid Build Coastguard Worker switch (snd_ctl_elem_info_get_type(ctl->info)) {
1043*053f45beSAndroid Build Coastguard Worker case SND_CTL_ELEM_TYPE_BOOLEAN:
1044*053f45beSAndroid Build Coastguard Worker pass = test_ctl_write_invalid_boolean(ctl);
1045*053f45beSAndroid Build Coastguard Worker break;
1046*053f45beSAndroid Build Coastguard Worker
1047*053f45beSAndroid Build Coastguard Worker case SND_CTL_ELEM_TYPE_INTEGER:
1048*053f45beSAndroid Build Coastguard Worker pass = test_ctl_write_invalid_integer(ctl);
1049*053f45beSAndroid Build Coastguard Worker break;
1050*053f45beSAndroid Build Coastguard Worker
1051*053f45beSAndroid Build Coastguard Worker case SND_CTL_ELEM_TYPE_INTEGER64:
1052*053f45beSAndroid Build Coastguard Worker pass = test_ctl_write_invalid_integer64(ctl);
1053*053f45beSAndroid Build Coastguard Worker break;
1054*053f45beSAndroid Build Coastguard Worker
1055*053f45beSAndroid Build Coastguard Worker case SND_CTL_ELEM_TYPE_ENUMERATED:
1056*053f45beSAndroid Build Coastguard Worker pass = test_ctl_write_invalid_enumerated(ctl);
1057*053f45beSAndroid Build Coastguard Worker break;
1058*053f45beSAndroid Build Coastguard Worker
1059*053f45beSAndroid Build Coastguard Worker default:
1060*053f45beSAndroid Build Coastguard Worker /* No tests for this yet */
1061*053f45beSAndroid Build Coastguard Worker ksft_test_result_skip("write_invalid.%d.%d\n",
1062*053f45beSAndroid Build Coastguard Worker ctl->card->card, ctl->elem);
1063*053f45beSAndroid Build Coastguard Worker return;
1064*053f45beSAndroid Build Coastguard Worker }
1065*053f45beSAndroid Build Coastguard Worker
1066*053f45beSAndroid Build Coastguard Worker /* Restore the default value to minimise disruption */
1067*053f45beSAndroid Build Coastguard Worker err = write_and_verify(ctl, ctl->def_val, NULL);
1068*053f45beSAndroid Build Coastguard Worker if (err < 0)
1069*053f45beSAndroid Build Coastguard Worker pass = false;
1070*053f45beSAndroid Build Coastguard Worker
1071*053f45beSAndroid Build Coastguard Worker ksft_test_result(pass, "write_invalid.%d.%d\n",
1072*053f45beSAndroid Build Coastguard Worker ctl->card->card, ctl->elem);
1073*053f45beSAndroid Build Coastguard Worker }
1074*053f45beSAndroid Build Coastguard Worker
test_ctl_event_missing(struct ctl_data * ctl)1075*053f45beSAndroid Build Coastguard Worker static void test_ctl_event_missing(struct ctl_data *ctl)
1076*053f45beSAndroid Build Coastguard Worker {
1077*053f45beSAndroid Build Coastguard Worker ksft_test_result(!ctl->event_missing, "event_missing.%d.%d\n",
1078*053f45beSAndroid Build Coastguard Worker ctl->card->card, ctl->elem);
1079*053f45beSAndroid Build Coastguard Worker }
1080*053f45beSAndroid Build Coastguard Worker
test_ctl_event_spurious(struct ctl_data * ctl)1081*053f45beSAndroid Build Coastguard Worker static void test_ctl_event_spurious(struct ctl_data *ctl)
1082*053f45beSAndroid Build Coastguard Worker {
1083*053f45beSAndroid Build Coastguard Worker ksft_test_result(!ctl->event_spurious, "event_spurious.%d.%d\n",
1084*053f45beSAndroid Build Coastguard Worker ctl->card->card, ctl->elem);
1085*053f45beSAndroid Build Coastguard Worker }
1086*053f45beSAndroid Build Coastguard Worker
main(void)1087*053f45beSAndroid Build Coastguard Worker int main(void)
1088*053f45beSAndroid Build Coastguard Worker {
1089*053f45beSAndroid Build Coastguard Worker struct ctl_data *ctl;
1090*053f45beSAndroid Build Coastguard Worker
1091*053f45beSAndroid Build Coastguard Worker ksft_print_header();
1092*053f45beSAndroid Build Coastguard Worker
1093*053f45beSAndroid Build Coastguard Worker find_controls();
1094*053f45beSAndroid Build Coastguard Worker
1095*053f45beSAndroid Build Coastguard Worker ksft_set_plan(num_controls * TESTS_PER_CONTROL);
1096*053f45beSAndroid Build Coastguard Worker
1097*053f45beSAndroid Build Coastguard Worker for (ctl = ctl_list; ctl != NULL; ctl = ctl->next) {
1098*053f45beSAndroid Build Coastguard Worker /*
1099*053f45beSAndroid Build Coastguard Worker * Must test get_value() before we write anything, the
1100*053f45beSAndroid Build Coastguard Worker * test stores the default value for later cleanup.
1101*053f45beSAndroid Build Coastguard Worker */
1102*053f45beSAndroid Build Coastguard Worker test_ctl_get_value(ctl);
1103*053f45beSAndroid Build Coastguard Worker test_ctl_name(ctl);
1104*053f45beSAndroid Build Coastguard Worker test_ctl_write_default(ctl);
1105*053f45beSAndroid Build Coastguard Worker test_ctl_write_valid(ctl);
1106*053f45beSAndroid Build Coastguard Worker test_ctl_write_invalid(ctl);
1107*053f45beSAndroid Build Coastguard Worker test_ctl_event_missing(ctl);
1108*053f45beSAndroid Build Coastguard Worker test_ctl_event_spurious(ctl);
1109*053f45beSAndroid Build Coastguard Worker }
1110*053f45beSAndroid Build Coastguard Worker
1111*053f45beSAndroid Build Coastguard Worker ksft_exit_pass();
1112*053f45beSAndroid Build Coastguard Worker
1113*053f45beSAndroid Build Coastguard Worker return 0;
1114*053f45beSAndroid Build Coastguard Worker }
1115