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