brintos

brintos / linux-shallow public Read only

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