0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <stdio.h>
0014 #include <stdlib.h>
0015 #include <stdbool.h>
0016 #include <limits.h>
0017 #include <string.h>
0018 #include <getopt.h>
0019 #include <stdarg.h>
0020 #include <ctype.h>
0021 #include <math.h>
0022 #include <errno.h>
0023 #include <assert.h>
0024 #include <alsa/asoundlib.h>
0025 #include <poll.h>
0026 #include <stdint.h>
0027
0028 #include "../kselftest.h"
0029
0030 #define TESTS_PER_CONTROL 7
0031
0032 struct card_data {
0033 snd_ctl_t *handle;
0034 int card;
0035 struct pollfd pollfd;
0036 int num_ctls;
0037 snd_ctl_elem_list_t *ctls;
0038 struct card_data *next;
0039 };
0040
0041 struct ctl_data {
0042 const char *name;
0043 snd_ctl_elem_id_t *id;
0044 snd_ctl_elem_info_t *info;
0045 snd_ctl_elem_value_t *def_val;
0046 int elem;
0047 int event_missing;
0048 int event_spurious;
0049 struct card_data *card;
0050 struct ctl_data *next;
0051 };
0052
0053 static const char *alsa_config =
0054 "ctl.hw {\n"
0055 " @args [ CARD ]\n"
0056 " @args.CARD.type string\n"
0057 " type hw\n"
0058 " card $CARD\n"
0059 "}\n"
0060 ;
0061
0062 int num_cards = 0;
0063 int num_controls = 0;
0064 struct card_data *card_list = NULL;
0065 struct ctl_data *ctl_list = NULL;
0066
0067 #ifdef SND_LIB_VER
0068 #if SND_LIB_VERSION >= SND_LIB_VER(1, 2, 6)
0069 #define LIB_HAS_LOAD_STRING
0070 #endif
0071 #endif
0072
0073 #ifndef LIB_HAS_LOAD_STRING
0074 static int snd_config_load_string(snd_config_t **config, const char *s,
0075 size_t size)
0076 {
0077 snd_input_t *input;
0078 snd_config_t *dst;
0079 int err;
0080
0081 assert(config && s);
0082 if (size == 0)
0083 size = strlen(s);
0084 err = snd_input_buffer_open(&input, s, size);
0085 if (err < 0)
0086 return err;
0087 err = snd_config_top(&dst);
0088 if (err < 0) {
0089 snd_input_close(input);
0090 return err;
0091 }
0092 err = snd_config_load(dst, input);
0093 snd_input_close(input);
0094 if (err < 0) {
0095 snd_config_delete(dst);
0096 return err;
0097 }
0098 *config = dst;
0099 return 0;
0100 }
0101 #endif
0102
0103 static void find_controls(void)
0104 {
0105 char name[32];
0106 int card, ctl, err;
0107 struct card_data *card_data;
0108 struct ctl_data *ctl_data;
0109 snd_config_t *config;
0110
0111 card = -1;
0112 if (snd_card_next(&card) < 0 || card < 0)
0113 return;
0114
0115 err = snd_config_load_string(&config, alsa_config, strlen(alsa_config));
0116 if (err < 0) {
0117 ksft_print_msg("Unable to parse custom alsa-lib configuration: %s\n",
0118 snd_strerror(err));
0119 ksft_exit_fail();
0120 }
0121
0122 while (card >= 0) {
0123 sprintf(name, "hw:%d", card);
0124
0125 card_data = malloc(sizeof(*card_data));
0126 if (!card_data)
0127 ksft_exit_fail_msg("Out of memory\n");
0128
0129 err = snd_ctl_open_lconf(&card_data->handle, name, 0, config);
0130 if (err < 0) {
0131 ksft_print_msg("Failed to get hctl for card %d: %s\n",
0132 card, snd_strerror(err));
0133 goto next_card;
0134 }
0135
0136
0137 snd_ctl_elem_list_malloc(&card_data->ctls);
0138 snd_ctl_elem_list(card_data->handle, card_data->ctls);
0139 card_data->num_ctls = snd_ctl_elem_list_get_count(card_data->ctls);
0140
0141
0142 snd_ctl_elem_list_alloc_space(card_data->ctls, card_data->num_ctls);
0143 snd_ctl_elem_list(card_data->handle, card_data->ctls);
0144
0145 card_data->card = num_cards++;
0146 card_data->next = card_list;
0147 card_list = card_data;
0148
0149 num_controls += card_data->num_ctls;
0150
0151 for (ctl = 0; ctl < card_data->num_ctls; ctl++) {
0152 ctl_data = malloc(sizeof(*ctl_data));
0153 if (!ctl_data)
0154 ksft_exit_fail_msg("Out of memory\n");
0155
0156 memset(ctl_data, 0, sizeof(*ctl_data));
0157 ctl_data->card = card_data;
0158 ctl_data->elem = ctl;
0159 ctl_data->name = snd_ctl_elem_list_get_name(card_data->ctls,
0160 ctl);
0161
0162 err = snd_ctl_elem_id_malloc(&ctl_data->id);
0163 if (err < 0)
0164 ksft_exit_fail_msg("Out of memory\n");
0165
0166 err = snd_ctl_elem_info_malloc(&ctl_data->info);
0167 if (err < 0)
0168 ksft_exit_fail_msg("Out of memory\n");
0169
0170 err = snd_ctl_elem_value_malloc(&ctl_data->def_val);
0171 if (err < 0)
0172 ksft_exit_fail_msg("Out of memory\n");
0173
0174 snd_ctl_elem_list_get_id(card_data->ctls, ctl,
0175 ctl_data->id);
0176 snd_ctl_elem_info_set_id(ctl_data->info, ctl_data->id);
0177 err = snd_ctl_elem_info(card_data->handle,
0178 ctl_data->info);
0179 if (err < 0) {
0180 ksft_print_msg("%s getting info for %d\n",
0181 snd_strerror(err),
0182 ctl_data->name);
0183 }
0184
0185 snd_ctl_elem_value_set_id(ctl_data->def_val,
0186 ctl_data->id);
0187
0188 ctl_data->next = ctl_list;
0189 ctl_list = ctl_data;
0190 }
0191
0192
0193 err = snd_ctl_subscribe_events(card_data->handle, true);
0194 if (err < 0) {
0195 ksft_exit_fail_msg("snd_ctl_subscribe_events() failed for card %d: %d\n",
0196 card, err);
0197 }
0198
0199 err = snd_ctl_poll_descriptors_count(card_data->handle);
0200 if (err != 1) {
0201 ksft_exit_fail_msg("Unexpected descriptor count %d for card %d\n",
0202 err, card);
0203 }
0204
0205 err = snd_ctl_poll_descriptors(card_data->handle,
0206 &card_data->pollfd, 1);
0207 if (err != 1) {
0208 ksft_exit_fail_msg("snd_ctl_poll_descriptors() failed for %d\n",
0209 card, err);
0210 }
0211
0212 next_card:
0213 if (snd_card_next(&card) < 0) {
0214 ksft_print_msg("snd_card_next");
0215 break;
0216 }
0217 }
0218
0219 snd_config_delete(config);
0220 }
0221
0222
0223
0224
0225
0226 static int wait_for_event(struct ctl_data *ctl, int timeout)
0227 {
0228 unsigned short revents;
0229 snd_ctl_event_t *event;
0230 int count, err;
0231 unsigned int mask = 0;
0232 unsigned int ev_id;
0233
0234 snd_ctl_event_alloca(&event);
0235
0236 do {
0237 err = poll(&(ctl->card->pollfd), 1, timeout);
0238 if (err < 0) {
0239 ksft_print_msg("poll() failed for %s: %s (%d)\n",
0240 ctl->name, strerror(errno), errno);
0241 return -1;
0242 }
0243
0244 if (err == 0)
0245 return 0;
0246
0247 err = snd_ctl_poll_descriptors_revents(ctl->card->handle,
0248 &(ctl->card->pollfd),
0249 1, &revents);
0250 if (err < 0) {
0251 ksft_print_msg("snd_ctl_poll_descriptors_revents() failed for %s: %d\n",
0252 ctl->name, err);
0253 return err;
0254 }
0255 if (revents & POLLERR) {
0256 ksft_print_msg("snd_ctl_poll_descriptors_revents() reported POLLERR for %s\n",
0257 ctl->name);
0258 return -1;
0259 }
0260
0261 if (!(revents & POLLIN)) {
0262 ksft_print_msg("No POLLIN\n");
0263 continue;
0264 }
0265
0266 err = snd_ctl_read(ctl->card->handle, event);
0267 if (err < 0) {
0268 ksft_print_msg("snd_ctl_read() failed for %s: %d\n",
0269 ctl->name, err);
0270 return err;
0271 }
0272
0273 if (snd_ctl_event_get_type(event) != SND_CTL_EVENT_ELEM)
0274 continue;
0275
0276
0277 mask = snd_ctl_event_elem_get_mask(event);
0278 ev_id = snd_ctl_event_elem_get_numid(event);
0279 if (ev_id != snd_ctl_elem_info_get_numid(ctl->info)) {
0280 ksft_print_msg("Event for unexpected ctl %s\n",
0281 snd_ctl_event_elem_get_name(event));
0282 continue;
0283 }
0284
0285 if ((mask & SND_CTL_EVENT_MASK_REMOVE) == SND_CTL_EVENT_MASK_REMOVE) {
0286 ksft_print_msg("Removal event for %s\n",
0287 ctl->name);
0288 return -1;
0289 }
0290 } while ((mask & SND_CTL_EVENT_MASK_VALUE) != SND_CTL_EVENT_MASK_VALUE);
0291
0292 return 1;
0293 }
0294
0295 static bool ctl_value_index_valid(struct ctl_data *ctl,
0296 snd_ctl_elem_value_t *val,
0297 int index)
0298 {
0299 long int_val;
0300 long long int64_val;
0301
0302 switch (snd_ctl_elem_info_get_type(ctl->info)) {
0303 case SND_CTL_ELEM_TYPE_NONE:
0304 ksft_print_msg("%s.%d Invalid control type NONE\n",
0305 ctl->name, index);
0306 return false;
0307
0308 case SND_CTL_ELEM_TYPE_BOOLEAN:
0309 int_val = snd_ctl_elem_value_get_boolean(val, index);
0310 switch (int_val) {
0311 case 0:
0312 case 1:
0313 break;
0314 default:
0315 ksft_print_msg("%s.%d Invalid boolean value %ld\n",
0316 ctl->name, index, int_val);
0317 return false;
0318 }
0319 break;
0320
0321 case SND_CTL_ELEM_TYPE_INTEGER:
0322 int_val = snd_ctl_elem_value_get_integer(val, index);
0323
0324 if (int_val < snd_ctl_elem_info_get_min(ctl->info)) {
0325 ksft_print_msg("%s.%d value %ld less than minimum %ld\n",
0326 ctl->name, index, int_val,
0327 snd_ctl_elem_info_get_min(ctl->info));
0328 return false;
0329 }
0330
0331 if (int_val > snd_ctl_elem_info_get_max(ctl->info)) {
0332 ksft_print_msg("%s.%d value %ld more than maximum %ld\n",
0333 ctl->name, index, int_val,
0334 snd_ctl_elem_info_get_max(ctl->info));
0335 return false;
0336 }
0337
0338
0339 if (snd_ctl_elem_info_get_step(ctl->info) &&
0340 (int_val - snd_ctl_elem_info_get_min(ctl->info) %
0341 snd_ctl_elem_info_get_step(ctl->info))) {
0342 ksft_print_msg("%s.%d value %ld invalid for step %ld minimum %ld\n",
0343 ctl->name, index, int_val,
0344 snd_ctl_elem_info_get_step(ctl->info),
0345 snd_ctl_elem_info_get_min(ctl->info));
0346 return false;
0347 }
0348 break;
0349
0350 case SND_CTL_ELEM_TYPE_INTEGER64:
0351 int64_val = snd_ctl_elem_value_get_integer64(val, index);
0352
0353 if (int64_val < snd_ctl_elem_info_get_min64(ctl->info)) {
0354 ksft_print_msg("%s.%d value %lld less than minimum %lld\n",
0355 ctl->name, index, int64_val,
0356 snd_ctl_elem_info_get_min64(ctl->info));
0357 return false;
0358 }
0359
0360 if (int64_val > snd_ctl_elem_info_get_max64(ctl->info)) {
0361 ksft_print_msg("%s.%d value %lld more than maximum %lld\n",
0362 ctl->name, index, int64_val,
0363 snd_ctl_elem_info_get_max(ctl->info));
0364 return false;
0365 }
0366
0367
0368 if (snd_ctl_elem_info_get_step64(ctl->info) &&
0369 (int64_val - snd_ctl_elem_info_get_min64(ctl->info)) %
0370 snd_ctl_elem_info_get_step64(ctl->info)) {
0371 ksft_print_msg("%s.%d value %lld invalid for step %lld minimum %lld\n",
0372 ctl->name, index, int64_val,
0373 snd_ctl_elem_info_get_step64(ctl->info),
0374 snd_ctl_elem_info_get_min64(ctl->info));
0375 return false;
0376 }
0377 break;
0378
0379 case SND_CTL_ELEM_TYPE_ENUMERATED:
0380 int_val = snd_ctl_elem_value_get_enumerated(val, index);
0381
0382 if (int_val < 0) {
0383 ksft_print_msg("%s.%d negative value %ld for enumeration\n",
0384 ctl->name, index, int_val);
0385 return false;
0386 }
0387
0388 if (int_val >= snd_ctl_elem_info_get_items(ctl->info)) {
0389 ksft_print_msg("%s.%d value %ld more than item count %ld\n",
0390 ctl->name, index, int_val,
0391 snd_ctl_elem_info_get_items(ctl->info));
0392 return false;
0393 }
0394 break;
0395
0396 default:
0397
0398 break;
0399 }
0400
0401 return true;
0402 }
0403
0404
0405
0406
0407
0408 static bool ctl_value_valid(struct ctl_data *ctl, snd_ctl_elem_value_t *val)
0409 {
0410 int i;
0411 bool valid = true;
0412
0413 for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++)
0414 if (!ctl_value_index_valid(ctl, val, i))
0415 valid = false;
0416
0417 return valid;
0418 }
0419
0420
0421
0422
0423
0424 static void test_ctl_get_value(struct ctl_data *ctl)
0425 {
0426 int err;
0427
0428
0429 if (snd_ctl_elem_info_is_inactive(ctl->info)) {
0430 ksft_print_msg("%s is inactive\n", ctl->name);
0431 ksft_test_result_skip("get_value.%d.%d\n",
0432 ctl->card->card, ctl->elem);
0433 return;
0434 }
0435
0436
0437 if (!snd_ctl_elem_info_is_readable(ctl->info)) {
0438 ksft_print_msg("%s is not readable\n", ctl->name);
0439 ksft_test_result_skip("get_value.%d.%d\n",
0440 ctl->card->card, ctl->elem);
0441 return;
0442 }
0443
0444 err = snd_ctl_elem_read(ctl->card->handle, ctl->def_val);
0445 if (err < 0) {
0446 ksft_print_msg("snd_ctl_elem_read() failed: %s\n",
0447 snd_strerror(err));
0448 goto out;
0449 }
0450
0451 if (!ctl_value_valid(ctl, ctl->def_val))
0452 err = -EINVAL;
0453
0454 out:
0455 ksft_test_result(err >= 0, "get_value.%d.%d\n",
0456 ctl->card->card, ctl->elem);
0457 }
0458
0459 static bool strend(const char *haystack, const char *needle)
0460 {
0461 size_t haystack_len = strlen(haystack);
0462 size_t needle_len = strlen(needle);
0463
0464 if (needle_len > haystack_len)
0465 return false;
0466 return strcmp(haystack + haystack_len - needle_len, needle) == 0;
0467 }
0468
0469 static void test_ctl_name(struct ctl_data *ctl)
0470 {
0471 bool name_ok = true;
0472 bool check;
0473
0474
0475 if (strend(ctl->name, " Switch")) {
0476 if (snd_ctl_elem_info_get_type(ctl->info) != SND_CTL_ELEM_TYPE_BOOLEAN) {
0477 ksft_print_msg("%d.%d %s ends in Switch but is not boolean\n",
0478 ctl->card->card, ctl->elem, ctl->name);
0479 name_ok = false;
0480 }
0481 }
0482
0483
0484 if (snd_ctl_elem_info_get_type(ctl->info) == SND_CTL_ELEM_TYPE_BOOLEAN &&
0485 snd_ctl_elem_info_is_writable(ctl->info)) {
0486 if (!strend(ctl->name, " Switch")) {
0487 ksft_print_msg("%d.%d %s is a writeable boolean but not a Switch\n",
0488 ctl->card->card, ctl->elem, ctl->name);
0489 name_ok = false;
0490 }
0491 }
0492
0493 ksft_test_result(name_ok, "name.%d.%d\n",
0494 ctl->card->card, ctl->elem);
0495 }
0496
0497 static bool show_mismatch(struct ctl_data *ctl, int index,
0498 snd_ctl_elem_value_t *read_val,
0499 snd_ctl_elem_value_t *expected_val)
0500 {
0501 long long expected_int, read_int;
0502
0503
0504
0505
0506
0507 expected_int = 0;
0508 read_int = 0;
0509
0510 switch (snd_ctl_elem_info_get_type(ctl->info)) {
0511 case SND_CTL_ELEM_TYPE_BOOLEAN:
0512 expected_int = snd_ctl_elem_value_get_boolean(expected_val,
0513 index);
0514 read_int = snd_ctl_elem_value_get_boolean(read_val, index);
0515 break;
0516
0517 case SND_CTL_ELEM_TYPE_INTEGER:
0518 expected_int = snd_ctl_elem_value_get_integer(expected_val,
0519 index);
0520 read_int = snd_ctl_elem_value_get_integer(read_val, index);
0521 break;
0522
0523 case SND_CTL_ELEM_TYPE_INTEGER64:
0524 expected_int = snd_ctl_elem_value_get_integer64(expected_val,
0525 index);
0526 read_int = snd_ctl_elem_value_get_integer64(read_val,
0527 index);
0528 break;
0529
0530 case SND_CTL_ELEM_TYPE_ENUMERATED:
0531 expected_int = snd_ctl_elem_value_get_enumerated(expected_val,
0532 index);
0533 read_int = snd_ctl_elem_value_get_enumerated(read_val,
0534 index);
0535 break;
0536
0537 default:
0538 break;
0539 }
0540
0541 if (expected_int != read_int) {
0542
0543
0544
0545
0546
0547 bool is_volatile = snd_ctl_elem_info_is_volatile(ctl->info);
0548 ksft_print_msg("%s.%d expected %lld but read %lld, is_volatile %d\n",
0549 ctl->name, index, expected_int, read_int, is_volatile);
0550 return !is_volatile;
0551 } else {
0552 return false;
0553 }
0554 }
0555
0556
0557
0558
0559
0560
0561
0562 static int write_and_verify(struct ctl_data *ctl,
0563 snd_ctl_elem_value_t *write_val,
0564 snd_ctl_elem_value_t *expected_val)
0565 {
0566 int err, i;
0567 bool error_expected, mismatch_shown;
0568 snd_ctl_elem_value_t *initial_val, *read_val, *w_val;
0569 snd_ctl_elem_value_alloca(&initial_val);
0570 snd_ctl_elem_value_alloca(&read_val);
0571 snd_ctl_elem_value_alloca(&w_val);
0572
0573
0574
0575
0576
0577
0578 snd_ctl_elem_value_copy(w_val, write_val);
0579 if (expected_val) {
0580 error_expected = true;
0581 } else {
0582 error_expected = false;
0583 snd_ctl_elem_value_alloca(&expected_val);
0584 snd_ctl_elem_value_copy(expected_val, write_val);
0585 }
0586
0587
0588 if (snd_ctl_elem_info_is_readable(ctl->info)) {
0589 snd_ctl_elem_value_set_id(initial_val, ctl->id);
0590
0591 err = snd_ctl_elem_read(ctl->card->handle, initial_val);
0592 if (err < 0) {
0593 ksft_print_msg("snd_ctl_elem_read() failed: %s\n",
0594 snd_strerror(err));
0595 return err;
0596 }
0597 }
0598
0599
0600
0601
0602
0603 err = snd_ctl_elem_write(ctl->card->handle, w_val);
0604 if (err < 0 && !error_expected) {
0605 ksft_print_msg("snd_ctl_elem_write() failed: %s\n",
0606 snd_strerror(err));
0607 return err;
0608 }
0609
0610
0611 if (!snd_ctl_elem_info_is_readable(ctl->info))
0612 return err;
0613
0614 snd_ctl_elem_value_set_id(read_val, ctl->id);
0615
0616 err = snd_ctl_elem_read(ctl->card->handle, read_val);
0617 if (err < 0) {
0618 ksft_print_msg("snd_ctl_elem_read() failed: %s\n",
0619 snd_strerror(err));
0620 return err;
0621 }
0622
0623
0624
0625
0626
0627
0628
0629
0630 if (!snd_ctl_elem_info_is_volatile(ctl->info)) {
0631 err = wait_for_event(ctl, 0);
0632 if (snd_ctl_elem_value_compare(initial_val, read_val)) {
0633 if (err < 1) {
0634 ksft_print_msg("No event generated for %s\n",
0635 ctl->name);
0636 ctl->event_missing++;
0637 }
0638 } else {
0639 if (err != 0) {
0640 ksft_print_msg("Spurious event generated for %s\n",
0641 ctl->name);
0642 ctl->event_spurious++;
0643 }
0644 }
0645 }
0646
0647
0648
0649
0650
0651
0652 if (!snd_ctl_elem_value_compare(expected_val, read_val))
0653 return 0;
0654
0655 mismatch_shown = false;
0656 for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++)
0657 if (show_mismatch(ctl, i, read_val, expected_val))
0658 mismatch_shown = true;
0659
0660 if (!mismatch_shown)
0661 ksft_print_msg("%s read and written values differ\n",
0662 ctl->name);
0663
0664 return -1;
0665 }
0666
0667
0668
0669
0670
0671 static void test_ctl_write_default(struct ctl_data *ctl)
0672 {
0673 int err;
0674
0675
0676 if (snd_ctl_elem_info_is_inactive(ctl->info)) {
0677 ksft_print_msg("%s is inactive\n", ctl->name);
0678 ksft_test_result_skip("write_default.%d.%d\n",
0679 ctl->card->card, ctl->elem);
0680 return;
0681 }
0682
0683 if (!snd_ctl_elem_info_is_writable(ctl->info)) {
0684 ksft_print_msg("%s is not writeable\n", ctl->name);
0685 ksft_test_result_skip("write_default.%d.%d\n",
0686 ctl->card->card, ctl->elem);
0687 return;
0688 }
0689
0690
0691 if (!snd_ctl_elem_info_is_readable(ctl->info)) {
0692 ksft_print_msg("%s couldn't read default\n", ctl->name);
0693 ksft_test_result_skip("write_default.%d.%d\n",
0694 ctl->card->card, ctl->elem);
0695 return;
0696 }
0697
0698 err = write_and_verify(ctl, ctl->def_val, NULL);
0699
0700 ksft_test_result(err >= 0, "write_default.%d.%d\n",
0701 ctl->card->card, ctl->elem);
0702 }
0703
0704 static bool test_ctl_write_valid_boolean(struct ctl_data *ctl)
0705 {
0706 int err, i, j;
0707 bool fail = false;
0708 snd_ctl_elem_value_t *val;
0709 snd_ctl_elem_value_alloca(&val);
0710
0711 snd_ctl_elem_value_set_id(val, ctl->id);
0712
0713 for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
0714 for (j = 0; j < 2; j++) {
0715 snd_ctl_elem_value_set_boolean(val, i, j);
0716 err = write_and_verify(ctl, val, NULL);
0717 if (err != 0)
0718 fail = true;
0719 }
0720 }
0721
0722 return !fail;
0723 }
0724
0725 static bool test_ctl_write_valid_integer(struct ctl_data *ctl)
0726 {
0727 int err;
0728 int i;
0729 long j, step;
0730 bool fail = false;
0731 snd_ctl_elem_value_t *val;
0732 snd_ctl_elem_value_alloca(&val);
0733
0734 snd_ctl_elem_value_set_id(val, ctl->id);
0735
0736 step = snd_ctl_elem_info_get_step(ctl->info);
0737 if (!step)
0738 step = 1;
0739
0740 for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
0741 for (j = snd_ctl_elem_info_get_min(ctl->info);
0742 j <= snd_ctl_elem_info_get_max(ctl->info); j += step) {
0743
0744 snd_ctl_elem_value_set_integer(val, i, j);
0745 err = write_and_verify(ctl, val, NULL);
0746 if (err != 0)
0747 fail = true;
0748 }
0749 }
0750
0751
0752 return !fail;
0753 }
0754
0755 static bool test_ctl_write_valid_integer64(struct ctl_data *ctl)
0756 {
0757 int err, i;
0758 long long j, step;
0759 bool fail = false;
0760 snd_ctl_elem_value_t *val;
0761 snd_ctl_elem_value_alloca(&val);
0762
0763 snd_ctl_elem_value_set_id(val, ctl->id);
0764
0765 step = snd_ctl_elem_info_get_step64(ctl->info);
0766 if (!step)
0767 step = 1;
0768
0769 for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
0770 for (j = snd_ctl_elem_info_get_min64(ctl->info);
0771 j <= snd_ctl_elem_info_get_max64(ctl->info); j += step) {
0772
0773 snd_ctl_elem_value_set_integer64(val, i, j);
0774 err = write_and_verify(ctl, val, NULL);
0775 if (err != 0)
0776 fail = true;
0777 }
0778 }
0779
0780 return !fail;
0781 }
0782
0783 static bool test_ctl_write_valid_enumerated(struct ctl_data *ctl)
0784 {
0785 int err, i, j;
0786 bool fail = false;
0787 snd_ctl_elem_value_t *val;
0788 snd_ctl_elem_value_alloca(&val);
0789
0790 snd_ctl_elem_value_set_id(val, ctl->id);
0791
0792 for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
0793 for (j = 0; j < snd_ctl_elem_info_get_items(ctl->info); j++) {
0794 snd_ctl_elem_value_set_enumerated(val, i, j);
0795 err = write_and_verify(ctl, val, NULL);
0796 if (err != 0)
0797 fail = true;
0798 }
0799 }
0800
0801 return !fail;
0802 }
0803
0804 static void test_ctl_write_valid(struct ctl_data *ctl)
0805 {
0806 bool pass;
0807 int err;
0808
0809
0810 if (snd_ctl_elem_info_is_inactive(ctl->info)) {
0811 ksft_print_msg("%s is inactive\n", ctl->name);
0812 ksft_test_result_skip("write_valid.%d.%d\n",
0813 ctl->card->card, ctl->elem);
0814 return;
0815 }
0816
0817 if (!snd_ctl_elem_info_is_writable(ctl->info)) {
0818 ksft_print_msg("%s is not writeable\n", ctl->name);
0819 ksft_test_result_skip("write_valid.%d.%d\n",
0820 ctl->card->card, ctl->elem);
0821 return;
0822 }
0823
0824 switch (snd_ctl_elem_info_get_type(ctl->info)) {
0825 case SND_CTL_ELEM_TYPE_BOOLEAN:
0826 pass = test_ctl_write_valid_boolean(ctl);
0827 break;
0828
0829 case SND_CTL_ELEM_TYPE_INTEGER:
0830 pass = test_ctl_write_valid_integer(ctl);
0831 break;
0832
0833 case SND_CTL_ELEM_TYPE_INTEGER64:
0834 pass = test_ctl_write_valid_integer64(ctl);
0835 break;
0836
0837 case SND_CTL_ELEM_TYPE_ENUMERATED:
0838 pass = test_ctl_write_valid_enumerated(ctl);
0839 break;
0840
0841 default:
0842
0843 ksft_test_result_skip("write_valid.%d.%d\n",
0844 ctl->card->card, ctl->elem);
0845 return;
0846 }
0847
0848
0849 err = write_and_verify(ctl, ctl->def_val, NULL);
0850 if (err < 0)
0851 pass = false;
0852
0853 ksft_test_result(pass, "write_valid.%d.%d\n",
0854 ctl->card->card, ctl->elem);
0855 }
0856
0857 static bool test_ctl_write_invalid_value(struct ctl_data *ctl,
0858 snd_ctl_elem_value_t *val)
0859 {
0860 int err;
0861 long val_read;
0862
0863
0864 err = snd_ctl_elem_write(ctl->card->handle, val);
0865 if (err < 0)
0866 return false;
0867
0868
0869 err = snd_ctl_elem_read(ctl->card->handle, val);
0870 if (err < 0) {
0871 ksft_print_msg("%s failed to read: %s\n",
0872 ctl->name, snd_strerror(err));
0873 return true;
0874 }
0875
0876 return !ctl_value_valid(ctl, val);
0877 }
0878
0879 static bool test_ctl_write_invalid_boolean(struct ctl_data *ctl)
0880 {
0881 int err, i;
0882 long val_read;
0883 bool fail = false;
0884 snd_ctl_elem_value_t *val;
0885 snd_ctl_elem_value_alloca(&val);
0886
0887 for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
0888 snd_ctl_elem_value_copy(val, ctl->def_val);
0889 snd_ctl_elem_value_set_boolean(val, i, 2);
0890
0891 if (test_ctl_write_invalid_value(ctl, val))
0892 fail = true;
0893 }
0894
0895 return !fail;
0896 }
0897
0898 static bool test_ctl_write_invalid_integer(struct ctl_data *ctl)
0899 {
0900 int i;
0901 bool fail = false;
0902 snd_ctl_elem_value_t *val;
0903 snd_ctl_elem_value_alloca(&val);
0904
0905 for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
0906 if (snd_ctl_elem_info_get_min(ctl->info) != LONG_MIN) {
0907
0908 snd_ctl_elem_value_copy(val, ctl->def_val);
0909 snd_ctl_elem_value_set_integer(val, i,
0910 snd_ctl_elem_info_get_min(ctl->info) - 1);
0911
0912 if (test_ctl_write_invalid_value(ctl, val))
0913 fail = true;
0914
0915
0916 snd_ctl_elem_value_copy(val, ctl->def_val);
0917 snd_ctl_elem_value_set_integer(val, i, LONG_MIN);
0918
0919 if (test_ctl_write_invalid_value(ctl, val))
0920 fail = true;
0921 }
0922
0923 if (snd_ctl_elem_info_get_max(ctl->info) != LONG_MAX) {
0924
0925 snd_ctl_elem_value_copy(val, ctl->def_val);
0926 snd_ctl_elem_value_set_integer(val, i,
0927 snd_ctl_elem_info_get_max(ctl->info) + 1);
0928
0929 if (test_ctl_write_invalid_value(ctl, val))
0930 fail = true;
0931
0932
0933 snd_ctl_elem_value_copy(val, ctl->def_val);
0934 snd_ctl_elem_value_set_integer(val, i, LONG_MAX);
0935
0936 if (test_ctl_write_invalid_value(ctl, val))
0937 fail = true;
0938 }
0939 }
0940
0941 return !fail;
0942 }
0943
0944 static bool test_ctl_write_invalid_integer64(struct ctl_data *ctl)
0945 {
0946 int i;
0947 bool fail = false;
0948 snd_ctl_elem_value_t *val;
0949 snd_ctl_elem_value_alloca(&val);
0950
0951 for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
0952 if (snd_ctl_elem_info_get_min64(ctl->info) != LLONG_MIN) {
0953
0954 snd_ctl_elem_value_copy(val, ctl->def_val);
0955 snd_ctl_elem_value_set_integer64(val, i,
0956 snd_ctl_elem_info_get_min64(ctl->info) - 1);
0957
0958 if (test_ctl_write_invalid_value(ctl, val))
0959 fail = true;
0960
0961
0962 snd_ctl_elem_value_copy(val, ctl->def_val);
0963 snd_ctl_elem_value_set_integer64(val, i, LLONG_MIN);
0964
0965 if (test_ctl_write_invalid_value(ctl, val))
0966 fail = true;
0967 }
0968
0969 if (snd_ctl_elem_info_get_max64(ctl->info) != LLONG_MAX) {
0970
0971 snd_ctl_elem_value_copy(val, ctl->def_val);
0972 snd_ctl_elem_value_set_integer64(val, i,
0973 snd_ctl_elem_info_get_max64(ctl->info) + 1);
0974
0975 if (test_ctl_write_invalid_value(ctl, val))
0976 fail = true;
0977
0978
0979 snd_ctl_elem_value_copy(val, ctl->def_val);
0980 snd_ctl_elem_value_set_integer64(val, i, LLONG_MAX);
0981
0982 if (test_ctl_write_invalid_value(ctl, val))
0983 fail = true;
0984 }
0985 }
0986
0987 return !fail;
0988 }
0989
0990 static bool test_ctl_write_invalid_enumerated(struct ctl_data *ctl)
0991 {
0992 int err, i;
0993 unsigned int val_read;
0994 bool fail = false;
0995 snd_ctl_elem_value_t *val;
0996 snd_ctl_elem_value_alloca(&val);
0997
0998 snd_ctl_elem_value_set_id(val, ctl->id);
0999
1000 for (i = 0; i < snd_ctl_elem_info_get_count(ctl->info); i++) {
1001
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
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
1022 static void test_ctl_write_invalid(struct ctl_data *ctl)
1023 {
1024 bool pass;
1025 int err;
1026
1027
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
1061 ksft_test_result_skip("write_invalid.%d.%d\n",
1062 ctl->card->card, ctl->elem);
1063 return;
1064 }
1065
1066
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
1075 static 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
1081 static 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
1087 int 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
1100
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 }