~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/alsa/mixer-test.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 //
  3 // kselftest for the ALSA mixer API
  4 //
  5 // Original author: Mark Brown <broonie@kernel.org>
  6 // Copyright (c) 2021-2 Arm Limited
  7 
  8 // This test will iterate over all cards detected in the system, exercising
  9 // every mixer control it can find.  This may conflict with other system
 10 // software if there is audio activity so is best run on a system with a
 11 // minimal active userspace.
 12 
 13 #include <stdio.h>
 14 #include <stdlib.h>
 15 #include <stdbool.h>
 16 #include <limits.h>
 17 #include <string.h>
 18 #include <getopt.h>
 19 #include <stdarg.h>
 20 #include <ctype.h>
 21 #include <math.h>
 22 #include <errno.h>
 23 #include <assert.h>
 24 #include <alsa/asoundlib.h>
 25 #include <poll.h>
 26 #include <stdint.h>
 27 
 28 #include "../kselftest.h"
 29 #include "alsa-local.h"
 30 
 31 #define TESTS_PER_CONTROL 7
 32 
 33 struct 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 
 44 struct 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 
 56 int num_cards = 0;
 57 int num_controls = 0;
 58 struct card_data *card_list = NULL;
 59 struct ctl_data *ctl_list = NULL;
 60 
 61 static 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 value
205  * on error, 0 for no event and 1 for an event.
206  */
207 static 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 
276 static 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 the
387  * provided control.
388  */
389 static 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. Write
403  * tests use the read value to restore the default.
404  */
405 static 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 
435 out:
436         ksft_test_result(err >= 0, "get_value.%s.%d\n",
437                          ctl->card->card_name, ctl->elem);
438 }
439 
440 static 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 
450 static 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 
480 static 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 
522 static 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 as
530          * 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 hardware
569                  * can voluntarily change the state of control element
570                  * 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 expected
583  * result.  An optional expected value can be provided if we expect
584  * the write to fail, for verifying that invalid writes don't corrupt
585  * anything.
586  */
587 static 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 modify
600          * the value which causes surprises, and allocate an expected
601          * 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 error
626          * 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 controls
650          * but we should still check that whatever we read is a valid
651          * 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 that
665          * there was none if it didn't.  We rely on the kernel
666          * generating the notification before it returns from the
667          * write, this is currently true, should that ever change this
668          * 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 mismatch
689          * carry on and try to provide a more useful diagnostic than
690          * 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, this
709  * should validate that at least some write works.
710  */
711 static 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 
744 static 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 
765 static 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 
795 static 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 
823 static 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 
844 static 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 
894 static 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 
915 static 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 
933 static 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 
979 static 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 
1025 static 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 
1056 static 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 
1106 static 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 
1112 static 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 
1118 int 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, the
1131                  * 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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php