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