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