// SPDX-License-Identifier: GPL-2.0
//
// kselftest for the ALSA mixer API
//
// Original author: Mark Brown <broonie@kernel.org>
// Copyright (c) 2021-2 Arm Limited
// This test will iterate over all cards detected in the system, exercising
// every mixer control it can find. This may conflict with other system
// software if there is audio activity so is best run on a system with a
// minimal active userspace.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>
#include <string.h>
#include <getopt.h>
#include <stdarg.h>
#include <ctype.h>
#include <math.h>
#include <errno.h>
#include <assert.h>
#include <alsa/asoundlib.h>
#include <poll.h>
#include <stdint.h>
#include "../kselftest.h"
#include "alsa-local.h"
#define TESTS_PER_CONTROL 7
struct card_data {
snd_ctl_t *handle;
int card;
snd_ctl_card_info_t *info;
const char *card_name;
struct pollfd pollfd;
int num_ctls;
snd_ctl_elem_list_t *ctls;
struct card_data *next;
};
struct ctl_data {
const char *name;
snd_ctl_elem_id_t *id;
snd_ctl_elem_info_t *info;
snd_ctl_elem_value_t *def_val;
int elem;
int event_missing;
int event_spurious;
struct card_data *card;
struct ctl_data *next;
};
int num_cards = 0;
int num_controls = 0;
struct card_data *card_list = NULL;
struct ctl_data *ctl_list = NULL;
static void find_controls(void)
{
char name[32];
int card, ctl, err;
struct card_data *card_data;
struct ctl_data *ctl_data;
snd_config_t *config;
char *card_name, *card_longname;
card = -1;
if (snd_card_next(&card) < 0 || card < 0)
return;
config = get_alsalib_config();
while (card >= 0) {
sprintf(name, "hw:%d", card);
card_data = malloc(sizeof(*card_data));
if (!card_data)
ksft_exit_fail_msg("Out of memory\n");
err = snd_ctl_open_lconf(&card_data->handle, name, 0, config);
if (err < 0) {
ksft_print_msg("Failed to get hctl for card %d: %s\n",
card, snd_strerror(err));
goto next_card;
}
err = snd_card_get_name(card, &card_name);
if (err != 0)
card_name = "Unknown";
err = snd_card_get_longname(card, &card_longname);
if (err != 0)
card_longname = "Unknown";
err = snd_ctl_card_info_malloc(&card_data->info);
if (err != 0)
ksft_exit_fail_msg("Failed to allocate card info: %d\n",
err);
err = snd_ctl_card_info(card_data->handle, card_data->info);
if (err == 0) {
card_data->card_name = snd_ctl_card_info_get_id(card_data->info);
if (!card_data->card_name)
ksft_print_msg("Failed to get card ID\n");
} else {
ksft_print_msg("Failed to get card info: %d\n", err);
}
if (!card_data->card_name)
card_data->card_name = "Unknown";
ksft_print_msg("Card %d/%s - %s (%s)\n", card,
card_data->card_name, card_name, card_longname);
/* Count controls */
snd_ctl_elem_list_malloc(&card_data->ctls);
snd_ctl_elem_list(card_data->handle, card_data->ctls);
card_data->num_ctls = snd_ctl_elem_list_get_count(card_data->ctls);
/* Enumerate control information */
snd_ctl_elem_list_alloc_space(card_data->ctls, card_data->num_ctls);
snd_ctl_elem_list(card_data->handle, card_data->ctls);
card_data->card = num_cards++;
card_data->next = card_list;
card_list = card_data;
num_controls += card_data->num_ctls;
for (ctl = 0; ctl < card_data->num_ctls; ctl++) {
ctl_data = malloc(sizeof(*ctl_data));
if (!ctl_data)
ksft_exit_fail_msg("Out of memory\n");
memset(ctl_data, 0, sizeof(*ctl_data));
ctl_data->card = card_data;
ctl_data->elem = ctl;
ctl_data->name = snd_ctl_elem_list_get_name(card_data->ctls,
ctl);
err