15aaf9effSMark Brown // SPDX-License-Identifier: GPL-2.0 25aaf9effSMark Brown // 35aaf9effSMark Brown // kselftest for the ALSA mixer API 45aaf9effSMark Brown // 55aaf9effSMark Brown // Original author: Mark Brown <broonie@kernel.org> 65aaf9effSMark Brown // Copyright (c) 2021 Arm Limited 75aaf9effSMark Brown 85aaf9effSMark Brown // This test will iterate over all cards detected in the system, exercising 95aaf9effSMark Brown // every mixer control it can find. This may conflict with other system 105aaf9effSMark Brown // software if there is audio activity so is best run on a system with a 115aaf9effSMark Brown // minimal active userspace. 125aaf9effSMark Brown 135aaf9effSMark Brown #include <stdio.h> 145aaf9effSMark Brown #include <stdlib.h> 155aaf9effSMark Brown #include <stdbool.h> 16*88b61322SMark Brown #include <limits.h> 175aaf9effSMark Brown #include <string.h> 185aaf9effSMark Brown #include <getopt.h> 195aaf9effSMark Brown #include <stdarg.h> 205aaf9effSMark Brown #include <ctype.h> 215aaf9effSMark Brown #include <math.h> 225aaf9effSMark Brown #include <errno.h> 235aaf9effSMark Brown #include <assert.h> 245aaf9effSMark Brown #include <alsa/asoundlib.h> 255aaf9effSMark Brown #include <poll.h> 265aaf9effSMark Brown #include <stdint.h> 275aaf9effSMark Brown 285aaf9effSMark Brown #include "../kselftest.h" 295aaf9effSMark Brown 30*88b61322SMark Brown #define TESTS_PER_CONTROL 4 315aaf9effSMark Brown 325aaf9effSMark Brown struct card_data { 335aaf9effSMark Brown snd_ctl_t *handle; 345aaf9effSMark Brown int card; 355aaf9effSMark Brown int num_ctls; 365aaf9effSMark Brown snd_ctl_elem_list_t *ctls; 375aaf9effSMark Brown struct card_data *next; 385aaf9effSMark Brown }; 395aaf9effSMark Brown 405aaf9effSMark Brown struct ctl_data { 415aaf9effSMark Brown const char *name; 425aaf9effSMark Brown snd_ctl_elem_id_t *id; 435aaf9effSMark Brown snd_ctl_elem_info_t *info; 445aaf9effSMark Brown snd_ctl_elem_value_t *def_val; 455aaf9effSMark Brown int elem; 465aaf9effSMark Brown struct card_data *card; 475aaf9effSMark Brown struct ctl_data *next; 485aaf9effSMark Brown }; 495aaf9effSMark Brown 50b73dad80SJaroslav Kysela static const char *alsa_config = 51b73dad80SJaroslav Kysela "ctl.hw {\n" 52b73dad80SJaroslav Kysela " @args [ CARD ]\n" 53b73dad80SJaroslav Kysela " @args.CARD.type string\n" 54b73dad80SJaroslav Kysela " type hw\n" 55b73dad80SJaroslav Kysela " card $CARD\n" 56b73dad80SJaroslav Kysela "}\n" 57b73dad80SJaroslav Kysela ; 58b73dad80SJaroslav Kysela 595aaf9effSMark Brown int num_cards = 0; 605aaf9effSMark Brown int num_controls = 0; 615aaf9effSMark Brown struct card_data *card_list = NULL; 625aaf9effSMark Brown struct ctl_data *ctl_list = NULL; 635aaf9effSMark Brown 64b73dad80SJaroslav Kysela #ifdef SND_LIB_VER 65b73dad80SJaroslav Kysela #if SND_LIB_VERSION >= SND_LIB_VER(1, 2, 6) 66b73dad80SJaroslav Kysela #define LIB_HAS_LOAD_STRING 67b73dad80SJaroslav Kysela #endif 68b73dad80SJaroslav Kysela #endif 69b73dad80SJaroslav Kysela 70b73dad80SJaroslav Kysela #ifndef LIB_HAS_LOAD_STRING 71b73dad80SJaroslav Kysela int snd_config_load_string(snd_config_t **config, const char *s, size_t size) 72b73dad80SJaroslav Kysela { 73b73dad80SJaroslav Kysela snd_input_t *input; 74b73dad80SJaroslav Kysela snd_config_t *dst; 75b73dad80SJaroslav Kysela int err; 76b73dad80SJaroslav Kysela 77b73dad80SJaroslav Kysela assert(config && s); 78b73dad80SJaroslav Kysela if (size == 0) 79b73dad80SJaroslav Kysela size = strlen(s); 80b73dad80SJaroslav Kysela err = snd_input_buffer_open(&input, s, size); 81b73dad80SJaroslav Kysela if (err < 0) 82b73dad80SJaroslav Kysela return err; 83b73dad80SJaroslav Kysela err = snd_config_top(&dst); 84b73dad80SJaroslav Kysela if (err < 0) { 85b73dad80SJaroslav Kysela snd_input_close(input); 86b73dad80SJaroslav Kysela return err; 87b73dad80SJaroslav Kysela } 88b73dad80SJaroslav Kysela err = snd_config_load(dst, input); 89b73dad80SJaroslav Kysela snd_input_close(input); 90b73dad80SJaroslav Kysela if (err < 0) { 91b73dad80SJaroslav Kysela snd_config_delete(dst); 92b73dad80SJaroslav Kysela return err; 93b73dad80SJaroslav Kysela } 94b73dad80SJaroslav Kysela *config = dst; 95b73dad80SJaroslav Kysela return 0; 96b73dad80SJaroslav Kysela } 97b73dad80SJaroslav Kysela #endif 98b73dad80SJaroslav Kysela 995aaf9effSMark Brown void find_controls(void) 1005aaf9effSMark Brown { 1015aaf9effSMark Brown char name[32]; 1025aaf9effSMark Brown int card, ctl, err; 1035aaf9effSMark Brown struct card_data *card_data; 1045aaf9effSMark Brown struct ctl_data *ctl_data; 105b73dad80SJaroslav Kysela snd_config_t *config; 1065aaf9effSMark Brown 1075aaf9effSMark Brown card = -1; 1085aaf9effSMark Brown if (snd_card_next(&card) < 0 || card < 0) 1095aaf9effSMark Brown return; 1105aaf9effSMark Brown 111b73dad80SJaroslav Kysela err = snd_config_load_string(&config, alsa_config, strlen(alsa_config)); 112b73dad80SJaroslav Kysela if (err < 0) { 113b73dad80SJaroslav Kysela ksft_print_msg("Unable to parse custom alsa-lib configuration: %s\n", 114b73dad80SJaroslav Kysela snd_strerror(err)); 115b73dad80SJaroslav Kysela ksft_exit_fail(); 116b73dad80SJaroslav Kysela } 117b73dad80SJaroslav Kysela 1185aaf9effSMark Brown while (card >= 0) { 1195aaf9effSMark Brown sprintf(name, "hw:%d", card); 1205aaf9effSMark Brown 1215aaf9effSMark Brown card_data = malloc(sizeof(*card_data)); 1225aaf9effSMark Brown if (!card_data) 1235aaf9effSMark Brown ksft_exit_fail_msg("Out of memory\n"); 1245aaf9effSMark Brown 125b73dad80SJaroslav Kysela err = snd_ctl_open_lconf(&card_data->handle, name, 0, config); 1265aaf9effSMark Brown if (err < 0) { 1275aaf9effSMark Brown ksft_print_msg("Failed to get hctl for card %d: %s\n", 1285aaf9effSMark Brown card, snd_strerror(err)); 1295aaf9effSMark Brown goto next_card; 1305aaf9effSMark Brown } 1315aaf9effSMark Brown 1325aaf9effSMark Brown /* Count controls */ 1335aaf9effSMark Brown snd_ctl_elem_list_malloc(&card_data->ctls); 1345aaf9effSMark Brown snd_ctl_elem_list(card_data->handle, card_data->ctls); 1355aaf9effSMark Brown card_data->num_ctls = snd_ctl_elem_list_get_count(card_data->ctls); 1365aaf9effSMark Brown 1375aaf9effSMark Brown /* Enumerate control information */ 1385aaf9effSMark Brown snd_ctl_elem_list_alloc_space(card_data->ctls, card_data->num_ctls); 1395aaf9effSMark Brown snd_ctl_elem_list(card_data->handle, card_data->ctls); 1405aaf9effSMark Brown 1415aaf9effSMark Brown card_data->card = num_cards++; 1425aaf9effSMark Brown card_data->next = card_list; 1435aaf9effSMark Brown card_list = card_data; 1445aaf9effSMark Brown 1455aaf9effSMark Brown num_controls += card_data->num_ctls; 1465aaf9effSMark Brown 1475aaf9effSMark Brown for (ctl = 0; ctl < card_data->num_ctls; ctl++) { 1485aaf9effSMark Brown ctl_data = malloc(sizeof(*ctl_data)); 1495aaf9effSMark Brown if (!ctl_data) 1505aaf9effSMark Brown ksft_exit_fail_msg("Out of memory\n"); 1515aaf9effSMark Brown 1525aaf9effSMark Brown ctl_data->card = card_data; 1535aaf9effSMark Brown ctl_data->elem = ctl; 1545aaf9effSMark Brown ctl_data->name = snd_ctl_elem_list_get_name(card_data->ctls, 1555aaf9effSMark Brown ctl); 1565aaf9effSMark Brown 1575aaf9effSMark Brown err = snd_ctl_elem_id_malloc(&ctl_data->id); 1585aaf9effSMark Brown if (err < 0) 1595aaf9effSMark Brown ksft_exit_fail_msg("Out of memory\n"); 1605aaf9effSMark Brown 1615aaf9effSMark Brown err = snd_ctl_elem_info_malloc(&ctl_data->info); 1625aaf9effSMark Brown if (err < 0) 1635aaf9effSMark Brown ksft_exit_fail_msg("Out of memory\n"); 1645aaf9effSMark Brown 1655aaf9effSMark Brown err = snd_ctl_elem_value_malloc(&ctl_data->def_val); 1665aaf9effSMark Brown if (err < 0) 1675aaf9effSMark Brown ksft_exit_fail_msg("Out of memory\n"); 1685aaf9effSMark Brown 1695aaf9effSMark Brown snd_ctl_elem_list_get_id(card_data->ctls, ctl, 1705aaf9effSMark Brown ctl_data->id); 1715aaf9effSMark Brown snd_ctl_elem_info_set_id(ctl_data->info, ctl_data->id); 1725aaf9effSMark Brown err = snd_ctl_elem_info(card_data->handle, 1735aaf9effSMark Brown ctl_data->info); 1745aaf9effSMark Brown if (err < 0) { 1755aaf9effSMark Brown ksft_print_msg("%s getting info for %d\n", 1765aaf9effSMark Brown snd_strerror(err), 1775aaf9effSMark Brown ctl_data->name); 1785aaf9effSMark Brown } 1795aaf9effSMark Brown 1805aaf9effSMark Brown snd_ctl_elem_value_set_id(ctl_data->def_val, 1815aaf9effSMark Brown ctl_data->id); 1825aaf9effSMark Brown 1835aaf9effSMark Brown ctl_data->next = ctl_list; 1845aaf9effSMark Brown ctl_list = ctl_data; 1855aaf9effSMark Brown } 1865aaf9effSMark Brown 1875aaf9effSMark Brown next_card: 1885aaf9effSMark Brown if (snd_card_next(&card) < 0) { 1895aaf9effSMark Brown ksft_print_msg("snd_card_next"); 1905aaf9effSMark Brown break; 1915aaf9effSMark Brown } 1925aaf9effSMark Brown } 193b73dad80SJaroslav Kysela 194b73dad80SJaroslav Kysela snd_config_delete(config); 1955aaf9effSMark Brown } 1965aaf9effSMark Brown 1973f48b137SMark Brown bool ctl_value_index_valid(struct ctl_data *ctl, snd_ctl_elem_value_t *val, 1983f48b137SMark Brown int index) 1993f48b137SMark Brown { 2003f48b137SMark Brown long int_val; 2013f48b137SMark Brown long long int64_val; 2023f48b137SMark Brown 2033f48b137SMark Brown switch (snd_ctl_elem_info_get_type(ctl->info)) { 2043f48b137SMark Brown case SND_CTL_ELEM_TYPE_NONE: 2053f48b137SMark Brown ksft_print_msg("%s.%d Invalid control type NONE\n", 2063f48b137SMark Brown ctl->name, index); 2073f48b137SMark Brown return false; 2083f48b137SMark Brown 2093f48b137SMark Brown case SND_CTL_ELEM_TYPE_BOOLEAN: 2103f48b137SMark Brown int_val = snd_ctl_elem_value_get_boolean(val, index); 2113f48b137SMark Brown switch (int_val) { 2123f48b137SMark Brown case 0: 2133f48b137SMark Brown case 1: 2143f48b137SMark Brown break; 2153f48b137SMark Brown default: 2163f48b137SMark Brown ksft_print_msg("%s.%d Invalid boolean value %ld\n", 2173f48b137SMark Brown ctl->name, index, int_val); 2183f48b137SMark Brown return false; 2193f48b137SMark Brown } 2203f48b137SMark Brown break; 2213f48b137SMark Brown 2223f48b137SMark Brown case SND_CTL_ELEM_TYPE_INTEGER: 2233f48b137SMark Brown int_val = snd_ctl_elem_value_get_integer(val, index); 2243f48b137SMark Brown 2253f48b137SMark Brown if (int_val < snd_ctl_elem_info_get_min(ctl->info)) { 2263f48b137SMark Brown ksft_print_msg("%s.%d value %ld less than minimum %ld\n", 2273f48b137SMark Brown ctl->name, index, int_val, 2283f48b137SMark Brown snd_ctl_elem_info_get_min(ctl->info)); 2293f48b137SMark Brown return false; 2303f48b137SMark Brown } 2313f48b137SMark Brown 2323f48b137SMark Brown if (int_val > snd_ctl_elem_info_get_max(ctl->info)) { 2333f48b137SMark Brown ksft_print_msg("%s.%d value %ld more than maximum %ld\n", 2343f48b137SMark Brown ctl->name, index, int_val, 2353f48b137SMark Brown snd_ctl_elem_info_get_max(ctl->info)); 2363f48b137SMark Brown return false; 2373f48b137SMark Brown } 2383f48b137SMark Brown 2393f48b137SMark Brown /* Only check step size if there is one and we're in bounds */ 2403f48b137SMark Brown if (snd_ctl_elem_info_get_step(ctl->info) && 2413f48b137SMark Brown (int_val - snd_ctl_elem_info_get_min(ctl->info) % 2423f48b137SMark Brown snd_ctl_elem_info_get_step(ctl->info))) { 2433f48b137SMark Brown ksft_print_msg("%s.%d value %ld invalid for step %ld minimum %ld\n", 2443f48b137SMark Brown ctl->name, index, int_val, 2453f48b137SMark Brown snd_ctl_elem_info_get_step(ctl->info), 2463f48b137SMark Brown snd_ctl_elem_info_get_min(ctl->info)); 2473f48b137SMark Brown return false; 2483f48b137SMark Brown } 2493f48b137SMark Brown break; 2503f48b137SMark Brown 2513f48b137SMark Brown case SND_CTL_ELEM_TYPE_INTEGER64: 2523f48b137SMark Brown int64_val = snd_ctl_elem_value_get_integer64(val, index); 2533f48b137SMark Brown 2543f48b137SMark Brown if (int64_val < snd_ctl_elem_info_get_min64(ctl->info)) { 2553f48b137SMark Brown ksft_print_msg("%s.%d value %lld less than minimum %lld\n", 2563f48b137SMark Brown ctl->name, index, int64_val, 2573f48b137SMark Brown snd_ctl_elem_info_get_min64(ctl->info)); 2583f48b137SMark Brown return false; 2593f48b137SMark Brown } 2603f48b137SMark Brown 2613f48b137SMark Brown if (int64_val > snd_ctl_elem_info_get_max64(ctl->info)) { 2623f48b137SMark Brown ksft_print_msg("%s.%d value %lld more than maximum %lld\n", 2633f48b137SMark Brown ctl->name, index, int64_val, 2643f48b137SMark Brown snd_ctl_elem_info_get_max(ctl->info)); 2653f48b137SMark Brown return false; 2663f48b137SMark Brown } 2673f48b137SMark Brown 2683f48b137SMark Brown /* Only check step size if there is one and we're in bounds */ 2693f48b137SMark Brown if (snd_ctl_elem_info_get_step64(ctl->info) && 2703f48b137SMark Brown (int64_val - snd_ctl_elem_info_get_min64(ctl->info)) % 2713f48b137SMark Brown snd_ctl_elem_info_get_step64(ctl->info)) { 2723f48b137SMark Brown ksft_print_msg("%s.%d value %lld invalid for step %lld minimum %lld\n", 2733f48b137SMark Brown ctl->name, index, int64_val, 2743f48b137SMark Brown snd_ctl_elem_info_get_step64(ctl->info), 2753f48b137SMark Brown snd_ctl_elem_info_get_min64(ctl->info)); 2763f48b137SMark Brown return false; 2773f48b137SMark Brown } 2783f48b137SMark Brown break; 2793f48b137SMark Brown 28010f2f194SMark Brown case SND_CTL_ELEM_TYPE_ENUMERATED: 28110f2f194SMark Brown int_val = snd_ctl_elem_value_get_enumerated(val, index); 28210f2f194SMark Brown 28310f2f194SMark Brown if (int_val < 0) { 28410f2f194SMark Brown ksft_print_msg("%s.%d negative value %ld for enumeration\n", 28510f2f194SMark Brown ctl->name, index, int_val); 28610f2f194SMark Brown return false; 28710f2f194SMark Brown } 28810f2f194SMark Brown 28910f2f194SMark Brown if (int_val >= snd_ctl_elem_info_get_items(ctl->info)) { 29010f2f194SMark Brown ksft_print_msg("%s.%d value %ld more than item count %ld\n", 29110f2f194SMark Brown ctl->name, index, int_val, 29210f2f194SMark Brown snd_ctl_elem_info_get_items(ctl->info)); 29310f2f194SMark Brown return false; 29410f2f194SMark Brown } 29510f2f194SMark Brown break; 29610f2f194SMark Brown 2973f48b137SMark Brown default: 2983f48b137SMark Brown /* No tests for other types */ 2993f48b137SMark Brown break; 3003f48b137SMark Brown } 3013f48b137SMark Brown 3023f48b137SMark Brown return true; 3033f48b137SMark Brown } 3043f48b137SMark Brown 3053f48b137SMark Brown /* 3063f48b137SMark Brown * Check that the provided value meets the constraints for the 3073f48b137SMark Brown * provided control. 3083f48b137SMark Brown */ 3093f48b137SMark Brown bool ctl_value_valid(struct ctl_data *ctl, snd_ctl_elem_value_t *val) 3103f48b137SMark Brown { 3113f48b137SMark Brown int i; 3123f48b137SMark Brown bool valid = true; 3133f48b137SMark Brown 3143f48b137SMark Brown for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) 3153f48b137SMark Brown if (!ctl_value_index_valid(ctl, val, i)) 3163f48b137SMark Brown valid = false; 3173f48b137SMark Brown 3183f48b137SMark Brown return valid; 3193f48b137SMark Brown } 3203f48b137SMark Brown 3215aaf9effSMark Brown /* 3225aaf9effSMark Brown * Check that we can read the default value and it is valid. Write 3235aaf9effSMark Brown * tests use the read value to restore the default. 3245aaf9effSMark Brown */ 3255aaf9effSMark Brown void test_ctl_get_value(struct ctl_data *ctl) 3265aaf9effSMark Brown { 3275aaf9effSMark Brown int err; 3285aaf9effSMark Brown 3295aaf9effSMark Brown /* If the control is turned off let's be polite */ 3305aaf9effSMark Brown if (snd_ctl_elem_info_is_inactive(ctl->info)) { 3315aaf9effSMark Brown ksft_print_msg("%s is inactive\n", ctl->name); 3325aaf9effSMark Brown ksft_test_result_skip("get_value.%d.%d\n", 3335aaf9effSMark Brown ctl->card->card, ctl->elem); 3345aaf9effSMark Brown return; 3355aaf9effSMark Brown } 3365aaf9effSMark Brown 3375aaf9effSMark Brown /* Can't test reading on an unreadable control */ 3385aaf9effSMark Brown if (!snd_ctl_elem_info_is_readable(ctl->info)) { 3395aaf9effSMark Brown ksft_print_msg("%s is not readable\n", ctl->name); 3405aaf9effSMark Brown ksft_test_result_skip("get_value.%d.%d\n", 3415aaf9effSMark Brown ctl->card->card, ctl->elem); 3425aaf9effSMark Brown return; 3435aaf9effSMark Brown } 3445aaf9effSMark Brown 3455aaf9effSMark Brown err = snd_ctl_elem_read(ctl->card->handle, ctl->def_val); 3465aaf9effSMark Brown if (err < 0) { 3475aaf9effSMark Brown ksft_print_msg("snd_ctl_elem_read() failed: %s\n", 3485aaf9effSMark Brown snd_strerror(err)); 3495aaf9effSMark Brown goto out; 3505aaf9effSMark Brown } 3515aaf9effSMark Brown 3523f48b137SMark Brown if (!ctl_value_valid(ctl, ctl->def_val)) 3533f48b137SMark Brown err = -EINVAL; 3545aaf9effSMark Brown 3555aaf9effSMark Brown out: 3565aaf9effSMark Brown ksft_test_result(err >= 0, "get_value.%d.%d\n", 3575aaf9effSMark Brown ctl->card->card, ctl->elem); 3585aaf9effSMark Brown } 3595aaf9effSMark Brown 3605aaf9effSMark Brown bool show_mismatch(struct ctl_data *ctl, int index, 3615aaf9effSMark Brown snd_ctl_elem_value_t *read_val, 3625aaf9effSMark Brown snd_ctl_elem_value_t *expected_val) 3635aaf9effSMark Brown { 3645aaf9effSMark Brown long long expected_int, read_int; 3655aaf9effSMark Brown 3665aaf9effSMark Brown /* 3675aaf9effSMark Brown * We factor out the code to compare values representable as 3685aaf9effSMark Brown * integers, ensure that check doesn't log otherwise. 3695aaf9effSMark Brown */ 3705aaf9effSMark Brown expected_int = 0; 3715aaf9effSMark Brown read_int = 0; 3725aaf9effSMark Brown 3735aaf9effSMark Brown switch (snd_ctl_elem_info_get_type(ctl->info)) { 3745aaf9effSMark Brown case SND_CTL_ELEM_TYPE_BOOLEAN: 3755aaf9effSMark Brown expected_int = snd_ctl_elem_value_get_boolean(expected_val, 3765aaf9effSMark Brown index); 3775aaf9effSMark Brown read_int = snd_ctl_elem_value_get_boolean(read_val, index); 3785aaf9effSMark Brown break; 3795aaf9effSMark Brown 3805aaf9effSMark Brown case SND_CTL_ELEM_TYPE_INTEGER: 3815aaf9effSMark Brown expected_int = snd_ctl_elem_value_get_integer(expected_val, 3825aaf9effSMark Brown index); 3835aaf9effSMark Brown read_int = snd_ctl_elem_value_get_integer(read_val, index); 3845aaf9effSMark Brown break; 3855aaf9effSMark Brown 3865aaf9effSMark Brown case SND_CTL_ELEM_TYPE_INTEGER64: 3875aaf9effSMark Brown expected_int = snd_ctl_elem_value_get_integer64(expected_val, 3885aaf9effSMark Brown index); 3895aaf9effSMark Brown read_int = snd_ctl_elem_value_get_integer64(read_val, 3905aaf9effSMark Brown index); 3915aaf9effSMark Brown break; 3925aaf9effSMark Brown 3935aaf9effSMark Brown case SND_CTL_ELEM_TYPE_ENUMERATED: 3945aaf9effSMark Brown expected_int = snd_ctl_elem_value_get_enumerated(expected_val, 3955aaf9effSMark Brown index); 3965aaf9effSMark Brown read_int = snd_ctl_elem_value_get_enumerated(read_val, 3975aaf9effSMark Brown index); 3985aaf9effSMark Brown break; 3995aaf9effSMark Brown 4005aaf9effSMark Brown default: 4015aaf9effSMark Brown break; 4025aaf9effSMark Brown } 4035aaf9effSMark Brown 4045aaf9effSMark Brown if (expected_int != read_int) { 4057cc994f2STakashi Sakamoto /* 4067cc994f2STakashi Sakamoto * NOTE: The volatile attribute means that the hardware 4077cc994f2STakashi Sakamoto * can voluntarily change the state of control element 4087cc994f2STakashi Sakamoto * independent of any operation by software. 4097cc994f2STakashi Sakamoto */ 4107cc994f2STakashi Sakamoto bool is_volatile = snd_ctl_elem_info_is_volatile(ctl->info); 4117cc994f2STakashi Sakamoto ksft_print_msg("%s.%d expected %lld but read %lld, is_volatile %d\n", 4127cc994f2STakashi Sakamoto ctl->name, index, expected_int, read_int, is_volatile); 4137cc994f2STakashi Sakamoto return !is_volatile; 4145aaf9effSMark Brown } else { 4155aaf9effSMark Brown return false; 4165aaf9effSMark Brown } 4175aaf9effSMark Brown } 4185aaf9effSMark Brown 4195aaf9effSMark Brown /* 4205aaf9effSMark Brown * Write a value then if possible verify that we get the expected 4215aaf9effSMark Brown * result. An optional expected value can be provided if we expect 4225aaf9effSMark Brown * the write to fail, for verifying that invalid writes don't corrupt 4235aaf9effSMark Brown * anything. 4245aaf9effSMark Brown */ 4255aaf9effSMark Brown int write_and_verify(struct ctl_data *ctl, 4265aaf9effSMark Brown snd_ctl_elem_value_t *write_val, 4275aaf9effSMark Brown snd_ctl_elem_value_t *expected_val) 4285aaf9effSMark Brown { 4295aaf9effSMark Brown int err, i; 4305aaf9effSMark Brown bool error_expected, mismatch_shown; 4315aaf9effSMark Brown snd_ctl_elem_value_t *read_val, *w_val; 4325aaf9effSMark Brown snd_ctl_elem_value_alloca(&read_val); 4335aaf9effSMark Brown snd_ctl_elem_value_alloca(&w_val); 4345aaf9effSMark Brown 4355aaf9effSMark Brown /* 4365aaf9effSMark Brown * We need to copy the write value since writing can modify 4375aaf9effSMark Brown * the value which causes surprises, and allocate an expected 4385aaf9effSMark Brown * value if we expect to read back what we wrote. 4395aaf9effSMark Brown */ 4405aaf9effSMark Brown snd_ctl_elem_value_copy(w_val, write_val); 4415aaf9effSMark Brown if (expected_val) { 4425aaf9effSMark Brown error_expected = true; 4435aaf9effSMark Brown } else { 4445aaf9effSMark Brown error_expected = false; 4455aaf9effSMark Brown snd_ctl_elem_value_alloca(&expected_val); 4465aaf9effSMark Brown snd_ctl_elem_value_copy(expected_val, write_val); 4475aaf9effSMark Brown } 4485aaf9effSMark Brown 4495aaf9effSMark Brown /* 4505aaf9effSMark Brown * Do the write, if we have an expected value ignore the error 4515aaf9effSMark Brown * and carry on to validate the expected value. 4525aaf9effSMark Brown */ 4535aaf9effSMark Brown err = snd_ctl_elem_write(ctl->card->handle, w_val); 4545aaf9effSMark Brown if (err < 0 && !error_expected) { 4555aaf9effSMark Brown ksft_print_msg("snd_ctl_elem_write() failed: %s\n", 4565aaf9effSMark Brown snd_strerror(err)); 4575aaf9effSMark Brown return err; 4585aaf9effSMark Brown } 4595aaf9effSMark Brown 4605aaf9effSMark Brown /* Can we do the verification part? */ 4615aaf9effSMark Brown if (!snd_ctl_elem_info_is_readable(ctl->info)) 4625aaf9effSMark Brown return err; 4635aaf9effSMark Brown 4645aaf9effSMark Brown snd_ctl_elem_value_set_id(read_val, ctl->id); 4655aaf9effSMark Brown 4665aaf9effSMark Brown err = snd_ctl_elem_read(ctl->card->handle, read_val); 4675aaf9effSMark Brown if (err < 0) { 4685aaf9effSMark Brown ksft_print_msg("snd_ctl_elem_read() failed: %s\n", 4695aaf9effSMark Brown snd_strerror(err)); 4705aaf9effSMark Brown return err; 4715aaf9effSMark Brown } 4725aaf9effSMark Brown 4735aaf9effSMark Brown /* 4745aaf9effSMark Brown * Use the libray to compare values, if there's a mismatch 4755aaf9effSMark Brown * carry on and try to provide a more useful diagnostic than 4765aaf9effSMark Brown * just "mismatch". 4775aaf9effSMark Brown */ 4785aaf9effSMark Brown if (!snd_ctl_elem_value_compare(expected_val, read_val)) 4795aaf9effSMark Brown return 0; 4805aaf9effSMark Brown 4815aaf9effSMark Brown mismatch_shown = false; 4825aaf9effSMark Brown for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) 4835aaf9effSMark Brown if (show_mismatch(ctl, i, read_val, expected_val)) 4845aaf9effSMark Brown mismatch_shown = true; 4855aaf9effSMark Brown 4865aaf9effSMark Brown if (!mismatch_shown) 4875aaf9effSMark Brown ksft_print_msg("%s read and written values differ\n", 4885aaf9effSMark Brown ctl->name); 4895aaf9effSMark Brown 4905aaf9effSMark Brown return -1; 4915aaf9effSMark Brown } 4925aaf9effSMark Brown 4935aaf9effSMark Brown /* 4945aaf9effSMark Brown * Make sure we can write the default value back to the control, this 4955aaf9effSMark Brown * should validate that at least some write works. 4965aaf9effSMark Brown */ 4975aaf9effSMark Brown void test_ctl_write_default(struct ctl_data *ctl) 4985aaf9effSMark Brown { 4995aaf9effSMark Brown int err; 5005aaf9effSMark Brown 5015aaf9effSMark Brown /* If the control is turned off let's be polite */ 5025aaf9effSMark Brown if (snd_ctl_elem_info_is_inactive(ctl->info)) { 5035aaf9effSMark Brown ksft_print_msg("%s is inactive\n", ctl->name); 5045aaf9effSMark Brown ksft_test_result_skip("write_default.%d.%d\n", 5055aaf9effSMark Brown ctl->card->card, ctl->elem); 5065aaf9effSMark Brown return; 5075aaf9effSMark Brown } 5085aaf9effSMark Brown 5095aaf9effSMark Brown if (!snd_ctl_elem_info_is_writable(ctl->info)) { 5105aaf9effSMark Brown ksft_print_msg("%s is not writeable\n", ctl->name); 5115aaf9effSMark Brown ksft_test_result_skip("write_default.%d.%d\n", 5125aaf9effSMark Brown ctl->card->card, ctl->elem); 5135aaf9effSMark Brown return; 5145aaf9effSMark Brown } 5155aaf9effSMark Brown 5165aaf9effSMark Brown /* No idea what the default was for unreadable controls */ 5175aaf9effSMark Brown if (!snd_ctl_elem_info_is_readable(ctl->info)) { 5185aaf9effSMark Brown ksft_print_msg("%s couldn't read default\n", ctl->name); 5195aaf9effSMark Brown ksft_test_result_skip("write_default.%d.%d\n", 5205aaf9effSMark Brown ctl->card->card, ctl->elem); 5215aaf9effSMark Brown return; 5225aaf9effSMark Brown } 5235aaf9effSMark Brown 5245aaf9effSMark Brown err = write_and_verify(ctl, ctl->def_val, NULL); 5255aaf9effSMark Brown 5265aaf9effSMark Brown ksft_test_result(err >= 0, "write_default.%d.%d\n", 5275aaf9effSMark Brown ctl->card->card, ctl->elem); 5285aaf9effSMark Brown } 5295aaf9effSMark Brown 5305aaf9effSMark Brown bool test_ctl_write_valid_boolean(struct ctl_data *ctl) 5315aaf9effSMark Brown { 5325aaf9effSMark Brown int err, i, j; 5335aaf9effSMark Brown bool fail = false; 5345aaf9effSMark Brown snd_ctl_elem_value_t *val; 5355aaf9effSMark Brown snd_ctl_elem_value_alloca(&val); 5365aaf9effSMark Brown 5375aaf9effSMark Brown snd_ctl_elem_value_set_id(val, ctl->id); 5385aaf9effSMark Brown 5395aaf9effSMark Brown for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) { 5405aaf9effSMark Brown for (j = 0; j < 2; j++) { 5415aaf9effSMark Brown snd_ctl_elem_value_set_boolean(val, i, j); 5425aaf9effSMark Brown err = write_and_verify(ctl, val, NULL); 5435aaf9effSMark Brown if (err != 0) 5445aaf9effSMark Brown fail = true; 5455aaf9effSMark Brown } 5465aaf9effSMark Brown } 5475aaf9effSMark Brown 5485aaf9effSMark Brown return !fail; 5495aaf9effSMark Brown } 5505aaf9effSMark Brown 5515aaf9effSMark Brown bool test_ctl_write_valid_integer(struct ctl_data *ctl) 5525aaf9effSMark Brown { 5535aaf9effSMark Brown int err; 5545aaf9effSMark Brown int i; 5555aaf9effSMark Brown long j, step; 5565aaf9effSMark Brown bool fail = false; 5575aaf9effSMark Brown snd_ctl_elem_value_t *val; 5585aaf9effSMark Brown snd_ctl_elem_value_alloca(&val); 5595aaf9effSMark Brown 5605aaf9effSMark Brown snd_ctl_elem_value_set_id(val, ctl->id); 5615aaf9effSMark Brown 5625aaf9effSMark Brown step = snd_ctl_elem_info_get_step(ctl->info); 5635aaf9effSMark Brown if (!step) 5645aaf9effSMark Brown step = 1; 5655aaf9effSMark Brown 5665aaf9effSMark Brown for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) { 5675aaf9effSMark Brown for (j = snd_ctl_elem_info_get_min(ctl->info); 5685aaf9effSMark Brown j <= snd_ctl_elem_info_get_max(ctl->info); j += step) { 5695aaf9effSMark Brown 5705aaf9effSMark Brown snd_ctl_elem_value_set_integer(val, i, j); 5715aaf9effSMark Brown err = write_and_verify(ctl, val, NULL); 5725aaf9effSMark Brown if (err != 0) 5735aaf9effSMark Brown fail = true; 5745aaf9effSMark Brown } 5755aaf9effSMark Brown } 5765aaf9effSMark Brown 5775aaf9effSMark Brown 5785aaf9effSMark Brown return !fail; 5795aaf9effSMark Brown } 5805aaf9effSMark Brown 5815aaf9effSMark Brown bool test_ctl_write_valid_integer64(struct ctl_data *ctl) 5825aaf9effSMark Brown { 5835aaf9effSMark Brown int err, i; 5845aaf9effSMark Brown long long j, step; 5855aaf9effSMark Brown bool fail = false; 5865aaf9effSMark Brown snd_ctl_elem_value_t *val; 5875aaf9effSMark Brown snd_ctl_elem_value_alloca(&val); 5885aaf9effSMark Brown 5895aaf9effSMark Brown snd_ctl_elem_value_set_id(val, ctl->id); 5905aaf9effSMark Brown 5915aaf9effSMark Brown step = snd_ctl_elem_info_get_step64(ctl->info); 5925aaf9effSMark Brown if (!step) 5935aaf9effSMark Brown step = 1; 5945aaf9effSMark Brown 5955aaf9effSMark Brown for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) { 5965aaf9effSMark Brown for (j = snd_ctl_elem_info_get_min64(ctl->info); 5975aaf9effSMark Brown j <= snd_ctl_elem_info_get_max64(ctl->info); j += step) { 5985aaf9effSMark Brown 5995aaf9effSMark Brown snd_ctl_elem_value_set_integer64(val, i, j); 6005aaf9effSMark Brown err = write_and_verify(ctl, val, NULL); 6015aaf9effSMark Brown if (err != 0) 6025aaf9effSMark Brown fail = true; 6035aaf9effSMark Brown } 6045aaf9effSMark Brown } 6055aaf9effSMark Brown 6065aaf9effSMark Brown return !fail; 6075aaf9effSMark Brown } 6085aaf9effSMark Brown 6095aaf9effSMark Brown bool test_ctl_write_valid_enumerated(struct ctl_data *ctl) 6105aaf9effSMark Brown { 6115aaf9effSMark Brown int err, i, j; 6125aaf9effSMark Brown bool fail = false; 6135aaf9effSMark Brown snd_ctl_elem_value_t *val; 6145aaf9effSMark Brown snd_ctl_elem_value_alloca(&val); 6155aaf9effSMark Brown 6165aaf9effSMark Brown snd_ctl_elem_value_set_id(val, ctl->id); 6175aaf9effSMark Brown 6185aaf9effSMark Brown for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) { 6195aaf9effSMark Brown for (j = 0; j < snd_ctl_elem_info_get_items(ctl->info); j++) { 6205aaf9effSMark Brown snd_ctl_elem_value_set_enumerated(val, i, j); 6215aaf9effSMark Brown err = write_and_verify(ctl, val, NULL); 6225aaf9effSMark Brown if (err != 0) 6235aaf9effSMark Brown fail = true; 6245aaf9effSMark Brown } 6255aaf9effSMark Brown } 6265aaf9effSMark Brown 6275aaf9effSMark Brown return !fail; 6285aaf9effSMark Brown } 6295aaf9effSMark Brown 6305aaf9effSMark Brown void test_ctl_write_valid(struct ctl_data *ctl) 6315aaf9effSMark Brown { 6325aaf9effSMark Brown bool pass; 6335aaf9effSMark Brown int err; 6345aaf9effSMark Brown 6355aaf9effSMark Brown /* If the control is turned off let's be polite */ 6365aaf9effSMark Brown if (snd_ctl_elem_info_is_inactive(ctl->info)) { 6375aaf9effSMark Brown ksft_print_msg("%s is inactive\n", ctl->name); 6385aaf9effSMark Brown ksft_test_result_skip("write_valid.%d.%d\n", 6395aaf9effSMark Brown ctl->card->card, ctl->elem); 6405aaf9effSMark Brown return; 6415aaf9effSMark Brown } 6425aaf9effSMark Brown 6435aaf9effSMark Brown if (!snd_ctl_elem_info_is_writable(ctl->info)) { 6445aaf9effSMark Brown ksft_print_msg("%s is not writeable\n", ctl->name); 6455aaf9effSMark Brown ksft_test_result_skip("write_valid.%d.%d\n", 6465aaf9effSMark Brown ctl->card->card, ctl->elem); 6475aaf9effSMark Brown return; 6485aaf9effSMark Brown } 6495aaf9effSMark Brown 6505aaf9effSMark Brown switch (snd_ctl_elem_info_get_type(ctl->info)) { 6515aaf9effSMark Brown case SND_CTL_ELEM_TYPE_BOOLEAN: 6525aaf9effSMark Brown pass = test_ctl_write_valid_boolean(ctl); 6535aaf9effSMark Brown break; 6545aaf9effSMark Brown 6555aaf9effSMark Brown case SND_CTL_ELEM_TYPE_INTEGER: 6565aaf9effSMark Brown pass = test_ctl_write_valid_integer(ctl); 6575aaf9effSMark Brown break; 6585aaf9effSMark Brown 6595aaf9effSMark Brown case SND_CTL_ELEM_TYPE_INTEGER64: 6605aaf9effSMark Brown pass = test_ctl_write_valid_integer64(ctl); 6615aaf9effSMark Brown break; 6625aaf9effSMark Brown 6635aaf9effSMark Brown case SND_CTL_ELEM_TYPE_ENUMERATED: 6645aaf9effSMark Brown pass = test_ctl_write_valid_enumerated(ctl); 6655aaf9effSMark Brown break; 6665aaf9effSMark Brown 6675aaf9effSMark Brown default: 6685aaf9effSMark Brown /* No tests for this yet */ 6695aaf9effSMark Brown ksft_test_result_skip("write_valid.%d.%d\n", 6705aaf9effSMark Brown ctl->card->card, ctl->elem); 6715aaf9effSMark Brown return; 6725aaf9effSMark Brown } 6735aaf9effSMark Brown 6745aaf9effSMark Brown /* Restore the default value to minimise disruption */ 6755aaf9effSMark Brown err = write_and_verify(ctl, ctl->def_val, NULL); 6765aaf9effSMark Brown if (err < 0) 6775aaf9effSMark Brown pass = false; 6785aaf9effSMark Brown 6795aaf9effSMark Brown ksft_test_result(pass, "write_valid.%d.%d\n", 6805aaf9effSMark Brown ctl->card->card, ctl->elem); 6815aaf9effSMark Brown } 6825aaf9effSMark Brown 683*88b61322SMark Brown bool test_ctl_write_invalid_value(struct ctl_data *ctl, 684*88b61322SMark Brown snd_ctl_elem_value_t *val) 685*88b61322SMark Brown { 686*88b61322SMark Brown int err; 687*88b61322SMark Brown long val_read; 688*88b61322SMark Brown 689*88b61322SMark Brown /* Ideally this will fail... */ 690*88b61322SMark Brown err = snd_ctl_elem_write(ctl->card->handle, val); 691*88b61322SMark Brown if (err < 0) 692*88b61322SMark Brown return false; 693*88b61322SMark Brown 694*88b61322SMark Brown /* ...but some devices will clamp to an in range value */ 695*88b61322SMark Brown err = snd_ctl_elem_read(ctl->card->handle, val); 696*88b61322SMark Brown if (err < 0) { 697*88b61322SMark Brown ksft_print_msg("%s failed to read: %s\n", 698*88b61322SMark Brown ctl->name, snd_strerror(err)); 699*88b61322SMark Brown return true; 700*88b61322SMark Brown } 701*88b61322SMark Brown 702*88b61322SMark Brown return !ctl_value_valid(ctl, val); 703*88b61322SMark Brown } 704*88b61322SMark Brown 705*88b61322SMark Brown bool test_ctl_write_invalid_boolean(struct ctl_data *ctl) 706*88b61322SMark Brown { 707*88b61322SMark Brown int err, i; 708*88b61322SMark Brown long val_read; 709*88b61322SMark Brown bool fail = false; 710*88b61322SMark Brown snd_ctl_elem_value_t *val; 711*88b61322SMark Brown snd_ctl_elem_value_alloca(&val); 712*88b61322SMark Brown 713*88b61322SMark Brown for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) { 714*88b61322SMark Brown snd_ctl_elem_value_copy(val, ctl->def_val); 715*88b61322SMark Brown snd_ctl_elem_value_set_boolean(val, i, 2); 716*88b61322SMark Brown 717*88b61322SMark Brown if (test_ctl_write_invalid_value(ctl, val)) 718*88b61322SMark Brown fail = true; 719*88b61322SMark Brown } 720*88b61322SMark Brown 721*88b61322SMark Brown return !fail; 722*88b61322SMark Brown } 723*88b61322SMark Brown 724*88b61322SMark Brown bool test_ctl_write_invalid_integer(struct ctl_data *ctl) 725*88b61322SMark Brown { 726*88b61322SMark Brown int i; 727*88b61322SMark Brown bool fail = false; 728*88b61322SMark Brown snd_ctl_elem_value_t *val; 729*88b61322SMark Brown snd_ctl_elem_value_alloca(&val); 730*88b61322SMark Brown 731*88b61322SMark Brown for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) { 732*88b61322SMark Brown if (snd_ctl_elem_info_get_min(ctl->info) != LONG_MIN) { 733*88b61322SMark Brown /* Just under range */ 734*88b61322SMark Brown snd_ctl_elem_value_copy(val, ctl->def_val); 735*88b61322SMark Brown snd_ctl_elem_value_set_integer(val, i, 736*88b61322SMark Brown snd_ctl_elem_info_get_min(ctl->info) - 1); 737*88b61322SMark Brown 738*88b61322SMark Brown if (test_ctl_write_invalid_value(ctl, val)) 739*88b61322SMark Brown fail = true; 740*88b61322SMark Brown 741*88b61322SMark Brown /* Minimum representable value */ 742*88b61322SMark Brown snd_ctl_elem_value_copy(val, ctl->def_val); 743*88b61322SMark Brown snd_ctl_elem_value_set_integer(val, i, LONG_MIN); 744*88b61322SMark Brown 745*88b61322SMark Brown if (test_ctl_write_invalid_value(ctl, val)) 746*88b61322SMark Brown fail = true; 747*88b61322SMark Brown } 748*88b61322SMark Brown 749*88b61322SMark Brown if (snd_ctl_elem_info_get_max(ctl->info) != LONG_MAX) { 750*88b61322SMark Brown /* Just over range */ 751*88b61322SMark Brown snd_ctl_elem_value_copy(val, ctl->def_val); 752*88b61322SMark Brown snd_ctl_elem_value_set_integer(val, i, 753*88b61322SMark Brown snd_ctl_elem_info_get_max(ctl->info) + 1); 754*88b61322SMark Brown 755*88b61322SMark Brown if (test_ctl_write_invalid_value(ctl, val)) 756*88b61322SMark Brown fail = true; 757*88b61322SMark Brown 758*88b61322SMark Brown /* Maximum representable value */ 759*88b61322SMark Brown snd_ctl_elem_value_copy(val, ctl->def_val); 760*88b61322SMark Brown snd_ctl_elem_value_set_integer(val, i, LONG_MAX); 761*88b61322SMark Brown 762*88b61322SMark Brown if (test_ctl_write_invalid_value(ctl, val)) 763*88b61322SMark Brown fail = true; 764*88b61322SMark Brown } 765*88b61322SMark Brown } 766*88b61322SMark Brown 767*88b61322SMark Brown return !fail; 768*88b61322SMark Brown } 769*88b61322SMark Brown 770*88b61322SMark Brown bool test_ctl_write_invalid_integer64(struct ctl_data *ctl) 771*88b61322SMark Brown { 772*88b61322SMark Brown int i; 773*88b61322SMark Brown bool fail = false; 774*88b61322SMark Brown snd_ctl_elem_value_t *val; 775*88b61322SMark Brown snd_ctl_elem_value_alloca(&val); 776*88b61322SMark Brown 777*88b61322SMark Brown for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) { 778*88b61322SMark Brown if (snd_ctl_elem_info_get_min64(ctl->info) != LLONG_MIN) { 779*88b61322SMark Brown /* Just under range */ 780*88b61322SMark Brown snd_ctl_elem_value_copy(val, ctl->def_val); 781*88b61322SMark Brown snd_ctl_elem_value_set_integer64(val, i, 782*88b61322SMark Brown snd_ctl_elem_info_get_min64(ctl->info) - 1); 783*88b61322SMark Brown 784*88b61322SMark Brown if (test_ctl_write_invalid_value(ctl, val)) 785*88b61322SMark Brown fail = true; 786*88b61322SMark Brown 787*88b61322SMark Brown /* Minimum representable value */ 788*88b61322SMark Brown snd_ctl_elem_value_copy(val, ctl->def_val); 789*88b61322SMark Brown snd_ctl_elem_value_set_integer64(val, i, LLONG_MIN); 790*88b61322SMark Brown 791*88b61322SMark Brown if (test_ctl_write_invalid_value(ctl, val)) 792*88b61322SMark Brown fail = true; 793*88b61322SMark Brown } 794*88b61322SMark Brown 795*88b61322SMark Brown if (snd_ctl_elem_info_get_max64(ctl->info) != LLONG_MAX) { 796*88b61322SMark Brown /* Just over range */ 797*88b61322SMark Brown snd_ctl_elem_value_copy(val, ctl->def_val); 798*88b61322SMark Brown snd_ctl_elem_value_set_integer64(val, i, 799*88b61322SMark Brown snd_ctl_elem_info_get_max64(ctl->info) + 1); 800*88b61322SMark Brown 801*88b61322SMark Brown if (test_ctl_write_invalid_value(ctl, val)) 802*88b61322SMark Brown fail = true; 803*88b61322SMark Brown 804*88b61322SMark Brown /* Maximum representable value */ 805*88b61322SMark Brown snd_ctl_elem_value_copy(val, ctl->def_val); 806*88b61322SMark Brown snd_ctl_elem_value_set_integer64(val, i, LLONG_MAX); 807*88b61322SMark Brown 808*88b61322SMark Brown if (test_ctl_write_invalid_value(ctl, val)) 809*88b61322SMark Brown fail = true; 810*88b61322SMark Brown } 811*88b61322SMark Brown } 812*88b61322SMark Brown 813*88b61322SMark Brown return !fail; 814*88b61322SMark Brown } 815*88b61322SMark Brown 816*88b61322SMark Brown bool test_ctl_write_invalid_enumerated(struct ctl_data *ctl) 817*88b61322SMark Brown { 818*88b61322SMark Brown int err, i; 819*88b61322SMark Brown unsigned int val_read; 820*88b61322SMark Brown bool fail = false; 821*88b61322SMark Brown snd_ctl_elem_value_t *val; 822*88b61322SMark Brown snd_ctl_elem_value_alloca(&val); 823*88b61322SMark Brown 824*88b61322SMark Brown snd_ctl_elem_value_set_id(val, ctl->id); 825*88b61322SMark Brown 826*88b61322SMark Brown for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) { 827*88b61322SMark Brown /* One beyond maximum */ 828*88b61322SMark Brown snd_ctl_elem_value_copy(val, ctl->def_val); 829*88b61322SMark Brown snd_ctl_elem_value_set_enumerated(val, i, 830*88b61322SMark Brown snd_ctl_elem_info_get_items(ctl->info)); 831*88b61322SMark Brown 832*88b61322SMark Brown if (test_ctl_write_invalid_value(ctl, val)) 833*88b61322SMark Brown fail = true; 834*88b61322SMark Brown 835*88b61322SMark Brown /* Maximum representable value */ 836*88b61322SMark Brown snd_ctl_elem_value_copy(val, ctl->def_val); 837*88b61322SMark Brown snd_ctl_elem_value_set_enumerated(val, i, UINT_MAX); 838*88b61322SMark Brown 839*88b61322SMark Brown if (test_ctl_write_invalid_value(ctl, val)) 840*88b61322SMark Brown fail = true; 841*88b61322SMark Brown 842*88b61322SMark Brown } 843*88b61322SMark Brown 844*88b61322SMark Brown return !fail; 845*88b61322SMark Brown } 846*88b61322SMark Brown 847*88b61322SMark Brown 848*88b61322SMark Brown void test_ctl_write_invalid(struct ctl_data *ctl) 849*88b61322SMark Brown { 850*88b61322SMark Brown bool pass; 851*88b61322SMark Brown int err; 852*88b61322SMark Brown 853*88b61322SMark Brown /* If the control is turned off let's be polite */ 854*88b61322SMark Brown if (snd_ctl_elem_info_is_inactive(ctl->info)) { 855*88b61322SMark Brown ksft_print_msg("%s is inactive\n", ctl->name); 856*88b61322SMark Brown ksft_test_result_skip("write_invalid.%d.%d\n", 857*88b61322SMark Brown ctl->card->card, ctl->elem); 858*88b61322SMark Brown return; 859*88b61322SMark Brown } 860*88b61322SMark Brown 861*88b61322SMark Brown if (!snd_ctl_elem_info_is_writable(ctl->info)) { 862*88b61322SMark Brown ksft_print_msg("%s is not writeable\n", ctl->name); 863*88b61322SMark Brown ksft_test_result_skip("write_invalid.%d.%d\n", 864*88b61322SMark Brown ctl->card->card, ctl->elem); 865*88b61322SMark Brown return; 866*88b61322SMark Brown } 867*88b61322SMark Brown 868*88b61322SMark Brown switch (snd_ctl_elem_info_get_type(ctl->info)) { 869*88b61322SMark Brown case SND_CTL_ELEM_TYPE_BOOLEAN: 870*88b61322SMark Brown pass = test_ctl_write_invalid_boolean(ctl); 871*88b61322SMark Brown break; 872*88b61322SMark Brown 873*88b61322SMark Brown case SND_CTL_ELEM_TYPE_INTEGER: 874*88b61322SMark Brown pass = test_ctl_write_invalid_integer(ctl); 875*88b61322SMark Brown break; 876*88b61322SMark Brown 877*88b61322SMark Brown case SND_CTL_ELEM_TYPE_INTEGER64: 878*88b61322SMark Brown pass = test_ctl_write_invalid_integer64(ctl); 879*88b61322SMark Brown break; 880*88b61322SMark Brown 881*88b61322SMark Brown case SND_CTL_ELEM_TYPE_ENUMERATED: 882*88b61322SMark Brown pass = test_ctl_write_invalid_enumerated(ctl); 883*88b61322SMark Brown break; 884*88b61322SMark Brown 885*88b61322SMark Brown default: 886*88b61322SMark Brown /* No tests for this yet */ 887*88b61322SMark Brown ksft_test_result_skip("write_invalid.%d.%d\n", 888*88b61322SMark Brown ctl->card->card, ctl->elem); 889*88b61322SMark Brown return; 890*88b61322SMark Brown } 891*88b61322SMark Brown 892*88b61322SMark Brown /* Restore the default value to minimise disruption */ 893*88b61322SMark Brown err = write_and_verify(ctl, ctl->def_val, NULL); 894*88b61322SMark Brown if (err < 0) 895*88b61322SMark Brown pass = false; 896*88b61322SMark Brown 897*88b61322SMark Brown ksft_test_result(pass, "write_invalid.%d.%d\n", 898*88b61322SMark Brown ctl->card->card, ctl->elem); 899*88b61322SMark Brown } 900*88b61322SMark Brown 9015aaf9effSMark Brown int main(void) 9025aaf9effSMark Brown { 9035aaf9effSMark Brown struct ctl_data *ctl; 9045aaf9effSMark Brown 9055aaf9effSMark Brown ksft_print_header(); 9065aaf9effSMark Brown 9075aaf9effSMark Brown find_controls(); 9085aaf9effSMark Brown 9095aaf9effSMark Brown ksft_set_plan(num_controls * TESTS_PER_CONTROL); 9105aaf9effSMark Brown 9115aaf9effSMark Brown for (ctl = ctl_list; ctl != NULL; ctl = ctl->next) { 9125aaf9effSMark Brown /* 9135aaf9effSMark Brown * Must test get_value() before we write anything, the 9145aaf9effSMark Brown * test stores the default value for later cleanup. 9155aaf9effSMark Brown */ 9165aaf9effSMark Brown test_ctl_get_value(ctl); 9175aaf9effSMark Brown test_ctl_write_default(ctl); 9185aaf9effSMark Brown test_ctl_write_valid(ctl); 919*88b61322SMark Brown test_ctl_write_invalid(ctl); 9205aaf9effSMark Brown } 9215aaf9effSMark Brown 9225aaf9effSMark Brown ksft_exit_pass(); 9235aaf9effSMark Brown 9245aaf9effSMark Brown return 0; 9255aaf9effSMark Brown } 926