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