Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // kselftest for the ALSA mixer API
0004 //
0005 // Original author: Mark Brown <broonie@kernel.org>
0006 // Copyright (c) 2021-2 Arm Limited
0007 
0008 // This test will iterate over all cards detected in the system, exercising
0009 // every mixer control it can find.  This may conflict with other system
0010 // software if there is audio activity so is best run on a system with a
0011 // minimal active userspace.
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         /* Count controls */
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         /* Enumerate control information */
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         /* Set up for events */
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  * Block for up to timeout ms for an event, returns a negative value
0224  * on error, 0 for no event and 1 for an event.
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         /* Timeout */
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         /* No read events */
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         /* The ID returned from the event is 1 less than numid */
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         /* Only check step size if there is one and we're in bounds */
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         /* Only check step size if there is one and we're in bounds */
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         /* No tests for other types */
0398         break;
0399     }
0400 
0401     return true;
0402 }
0403 
0404 /*
0405  * Check that the provided value meets the constraints for the
0406  * provided control.
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  * Check that we can read the default value and it is valid. Write
0422  * tests use the read value to restore the default.
0423  */
0424 static void test_ctl_get_value(struct ctl_data *ctl)
0425 {
0426     int err;
0427 
0428     /* If the control is turned off let's be polite */
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     /* Can't test reading on an unreadable control */
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     /* Only boolean controls should end in Switch */
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     /* Writeable boolean controls should end in Switch */
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      * We factor out the code to compare values representable as
0505      * integers, ensure that check doesn't log otherwise.
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          * NOTE: The volatile attribute means that the hardware
0544          * can voluntarily change the state of control element
0545          * independent of any operation by software.  
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  * Write a value then if possible verify that we get the expected
0558  * result.  An optional expected value can be provided if we expect
0559  * the write to fail, for verifying that invalid writes don't corrupt
0560  * anything.
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      * We need to copy the write value since writing can modify
0575      * the value which causes surprises, and allocate an expected
0576      * value if we expect to read back what we wrote.
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     /* Store the value before we write */
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      * Do the write, if we have an expected value ignore the error
0601      * and carry on to validate the expected value.
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     /* Can we do the verification part? */
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      * Check for an event if the value changed, or confirm that
0625      * there was none if it didn't.  We rely on the kernel
0626      * generating the notification before it returns from the
0627      * write, this is currently true, should that ever change this
0628      * will most likely break and need updating.
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      * Use the libray to compare values, if there's a mismatch
0649      * carry on and try to provide a more useful diagnostic than
0650      * just "mismatch".
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  * Make sure we can write the default value back to the control, this
0669  * should validate that at least some write works.
0670  */
0671 static void test_ctl_write_default(struct ctl_data *ctl)
0672 {
0673     int err;
0674 
0675     /* If the control is turned off let's be polite */
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     /* No idea what the default was for unreadable controls */
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     /* If the control is turned off let's be polite */
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         /* No tests for this yet */
0843         ksft_test_result_skip("write_valid.%d.%d\n",
0844                       ctl->card->card, ctl->elem);
0845         return;
0846     }
0847 
0848     /* Restore the default value to minimise disruption */
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     /* Ideally this will fail... */
0864     err = snd_ctl_elem_write(ctl->card->handle, val);
0865     if (err < 0)
0866         return false;
0867 
0868     /* ...but some devices will clamp to an in range value */
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             /* Just under range */
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             /* Minimum representable value */
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             /* Just over range */
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             /* Maximum representable value */
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             /* Just under range */
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             /* Minimum representable value */
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             /* Just over range */
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             /* Maximum representable value */
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         /* 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 
1022 static 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 
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          * 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 }