mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-11-03 09:01:52 -05:00 
			
		
		
		
	
		
			
	
	
		
			574 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			574 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * user-control-element-set.c - a program to test in-kernel implementation of
							 | 
						||
| 
								 | 
							
								 *				user-defined control element set.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Copyright (c) 2015-2016 Takashi Sakamoto
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Licensed under the terms of the GNU General Public License, version 2.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "../include/asoundlib.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								struct elem_set_trial {
							 | 
						||
| 
								 | 
							
									snd_ctl_t *handle;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									snd_ctl_elem_type_t type;
							 | 
						||
| 
								 | 
							
									unsigned int member_count;
							 | 
						||
| 
								 | 
							
									unsigned int element_count;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									snd_ctl_elem_id_t *id;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									int (*add_elem_set)(struct elem_set_trial *trial);
							 | 
						||
| 
								 | 
							
									int (*check_elem_props)(struct elem_set_trial *trial,
							 | 
						||
| 
								 | 
							
												snd_ctl_elem_info_t *info);
							 | 
						||
| 
								 | 
							
									void (*change_elem_members)(struct elem_set_trial *trial,
							 | 
						||
| 
								 | 
							
												    snd_ctl_elem_value_t *elem_data);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Operations for elements in an element set with boolean type. */
							 | 
						||
| 
								 | 
							
								static int add_bool_elem_set(struct elem_set_trial *trial)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return snd_ctl_elem_add_boolean_set(trial->handle, trial->id,
							 | 
						||
| 
								 | 
							
												trial->element_count, trial->member_count);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void change_bool_elem_members(struct elem_set_trial *trial,
							 | 
						||
| 
								 | 
							
												     snd_ctl_elem_value_t *elem_data)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									int val;
							 | 
						||
| 
								 | 
							
									unsigned int i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for (i = 0; i < trial->member_count; ++i) {
							 | 
						||
| 
								 | 
							
										val = snd_ctl_elem_value_get_boolean(elem_data, i);
							 | 
						||
| 
								 | 
							
										snd_ctl_elem_value_set_boolean(elem_data, i, !val);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Operations for elements in an element set with integer type. */
							 | 
						||
| 
								 | 
							
								static int add_int_elem_set(struct elem_set_trial *trial)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return snd_ctl_elem_add_integer_set(trial->handle, trial->id,
							 | 
						||
| 
								 | 
							
												trial->element_count, trial->member_count,
							 | 
						||
| 
								 | 
							
												0, 99, 1);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int check_int_elem_props(struct elem_set_trial *trial,
							 | 
						||
| 
								 | 
							
												snd_ctl_elem_info_t *info)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									if (snd_ctl_elem_info_get_min(info) != 0)
							 | 
						||
| 
								 | 
							
										return -EIO;
							 | 
						||
| 
								 | 
							
									if (snd_ctl_elem_info_get_max(info) != 99)
							 | 
						||
| 
								 | 
							
										return -EIO;
							 | 
						||
| 
								 | 
							
									if (snd_ctl_elem_info_get_step(info) != 1)
							 | 
						||
| 
								 | 
							
										return -EIO;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void change_int_elem_members(struct elem_set_trial *trial,
							 | 
						||
| 
								 | 
							
												    snd_ctl_elem_value_t *elem_data)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									long val;
							 | 
						||
| 
								 | 
							
									unsigned int i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for (i = 0; i < trial->member_count; ++i) {
							 | 
						||
| 
								 | 
							
										val = snd_ctl_elem_value_get_integer(elem_data, i);
							 | 
						||
| 
								 | 
							
										snd_ctl_elem_value_set_integer(elem_data, i, ++val);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Operations for elements in an element set with enumerated type. */
							 | 
						||
| 
								 | 
							
								static const char *const labels[] = {
							 | 
						||
| 
								 | 
							
									"trusty",
							 | 
						||
| 
								 | 
							
									"utopic",
							 | 
						||
| 
								 | 
							
									"vivid",
							 | 
						||
| 
								 | 
							
									"willy",
							 | 
						||
| 
								 | 
							
									"xenial",
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int add_enum_elem_set(struct elem_set_trial *trial)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return snd_ctl_elem_add_enumerated_set(trial->handle, trial->id,
							 | 
						||
| 
								 | 
							
												trial->element_count, trial->member_count,
							 | 
						||
| 
								 | 
							
												sizeof(labels) / sizeof(labels[0]),
							 | 
						||
| 
								 | 
							
												labels);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int check_enum_elem_props(struct elem_set_trial *trial,
							 | 
						||
| 
								 | 
							
												 snd_ctl_elem_info_t *info)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									unsigned int items;
							 | 
						||
| 
								 | 
							
									unsigned int i;
							 | 
						||
| 
								 | 
							
									const char *label;
							 | 
						||
| 
								 | 
							
									int err;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									items = snd_ctl_elem_info_get_items(info);
							 | 
						||
| 
								 | 
							
									if (items != sizeof(labels) / sizeof(labels[0]))
							 | 
						||
| 
								 | 
							
										return -EIO;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* Enumerate and validate all of labels registered to this element. */
							 | 
						||
| 
								 | 
							
									for (i = 0; i < items; ++i) {
							 | 
						||
| 
								 | 
							
										snd_ctl_elem_info_set_item(info, i);
							 | 
						||
| 
								 | 
							
										err = snd_ctl_elem_info(trial->handle, info);
							 | 
						||
| 
								 | 
							
										if (err < 0)
							 | 
						||
| 
								 | 
							
											return err;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										label = snd_ctl_elem_info_get_item_name(info);
							 | 
						||
| 
								 | 
							
										if (strncmp(label, labels[i], strlen(labels[i])) != 0)
							 | 
						||
| 
								 | 
							
											return -EIO;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void change_enum_elem_members(struct elem_set_trial *trial,
							 | 
						||
| 
								 | 
							
												     snd_ctl_elem_value_t *elem_data)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									unsigned int val;
							 | 
						||
| 
								 | 
							
									unsigned int i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for (i = 0; i < trial->member_count; ++i) {
							 | 
						||
| 
								 | 
							
										val = snd_ctl_elem_value_get_enumerated(elem_data, i);
							 | 
						||
| 
								 | 
							
										snd_ctl_elem_value_set_enumerated(elem_data, i, ++val);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Operations for elements in an element set with bytes type. */
							 | 
						||
| 
								 | 
							
								static int add_bytes_elem_set(struct elem_set_trial *trial)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return snd_ctl_elem_add_bytes_set(trial->handle, trial->id,
							 | 
						||
| 
								 | 
							
												trial->element_count, trial->member_count);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void change_bytes_elem_members(struct elem_set_trial *trial,
							 | 
						||
| 
								 | 
							
												      snd_ctl_elem_value_t *elem_data)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									unsigned char val;
							 | 
						||
| 
								 | 
							
									unsigned int i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for (i = 0; i < trial->member_count; ++i) {
							 | 
						||
| 
								 | 
							
										val = snd_ctl_elem_value_get_byte(elem_data, i);
							 | 
						||
| 
								 | 
							
										snd_ctl_elem_value_set_byte(elem_data, i, ++val);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Operations for elements in an element set with iec958 type. */
							 | 
						||
| 
								 | 
							
								static int add_iec958_elem_set(struct elem_set_trial *trial)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return snd_ctl_elem_add_iec958(trial->handle, trial->id);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void change_iec958_elem_members(struct elem_set_trial *trial,
							 | 
						||
| 
								 | 
							
												       snd_ctl_elem_value_t *elem_data)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									snd_aes_iec958_t data;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* To suppress GCC warnings. */
							 | 
						||
| 
								 | 
							
									trial->element_count = 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									snd_ctl_elem_value_get_iec958(elem_data, &data);
							 | 
						||
| 
								 | 
							
									/* This is an arbitrary number. */
							 | 
						||
| 
								 | 
							
									data.pad = 10;
							 | 
						||
| 
								 | 
							
									snd_ctl_elem_value_set_iec958(elem_data, &data);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Operations for elements in an element set with integer64 type. */
							 | 
						||
| 
								 | 
							
								static int add_int64_elem_set(struct elem_set_trial *trial)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									return snd_ctl_elem_add_integer64_set(trial->handle, trial->id,
							 | 
						||
| 
								 | 
							
												trial->element_count, trial->member_count,
							 | 
						||
| 
								 | 
							
												100, 10000, 30);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int check_int64_elem_props(struct elem_set_trial *trial,
							 | 
						||
| 
								 | 
							
												  snd_ctl_elem_info_t *info)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									if (snd_ctl_elem_info_get_min64(info) != 100)
							 | 
						||
| 
								 | 
							
										return -EIO;
							 | 
						||
| 
								 | 
							
									if (snd_ctl_elem_info_get_max64(info) != 10000)
							 | 
						||
| 
								 | 
							
										return -EIO;
							 | 
						||
| 
								 | 
							
									if (snd_ctl_elem_info_get_step64(info) != 30)
							 | 
						||
| 
								 | 
							
										return -EIO;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void change_int64_elem_members(struct elem_set_trial *trial,
							 | 
						||
| 
								 | 
							
												      snd_ctl_elem_value_t *elem_data)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									long long val;
							 | 
						||
| 
								 | 
							
									unsigned int i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for (i = 0; i < trial->member_count; ++i) {
							 | 
						||
| 
								 | 
							
										val = snd_ctl_elem_value_get_integer64(elem_data, i);
							 | 
						||
| 
								 | 
							
										snd_ctl_elem_value_set_integer64(elem_data, i, ++val);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* Common operations. */
							 | 
						||
| 
								 | 
							
								static int add_elem_set(struct elem_set_trial *trial)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									char name[64] = {0};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									snprintf(name, 64, "userspace-control-element-%s",
							 | 
						||
| 
								 | 
							
										 snd_ctl_elem_type_name(trial->type));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									memset(trial->id, 0, snd_ctl_elem_id_sizeof());
							 | 
						||
| 
								 | 
							
									snd_ctl_elem_id_set_interface(trial->id, SND_CTL_ELEM_IFACE_MIXER);
							 | 
						||
| 
								 | 
							
									snd_ctl_elem_id_set_name(trial->id, name);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return trial->add_elem_set(trial);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int check_event(struct elem_set_trial *trial, unsigned int mask,
							 | 
						||
| 
								 | 
							
										       unsigned int expected_count)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									struct pollfd pfds;
							 | 
						||
| 
								 | 
							
									int count;
							 | 
						||
| 
								 | 
							
									unsigned short revents;
							 | 
						||
| 
								 | 
							
									snd_ctl_event_t *event;
							 | 
						||
| 
								 | 
							
									int err;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									snd_ctl_event_alloca(&event);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (snd_ctl_poll_descriptors_count(trial->handle) != 1)
							 | 
						||
| 
								 | 
							
										return -ENXIO;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (snd_ctl_poll_descriptors(trial->handle, &pfds, 1) != 1)
							 | 
						||
| 
								 | 
							
										return -ENXIO;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									while (expected_count > 0) {
							 | 
						||
| 
								 | 
							
										count = poll(&pfds, 1, 1000);
							 | 
						||
| 
								 | 
							
										if (count < 0)
							 | 
						||
| 
								 | 
							
											return errno;
							 | 
						||
| 
								 | 
							
										/* Some events are already supplied. */
							 | 
						||
| 
								 | 
							
										if (count == 0)
							 | 
						||
| 
								 | 
							
											return -ETIMEDOUT;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										err = snd_ctl_poll_descriptors_revents(trial->handle, &pfds,
							 | 
						||
| 
								 | 
							
														       count, &revents);
							 | 
						||
| 
								 | 
							
										if (err < 0)
							 | 
						||
| 
								 | 
							
											return err;
							 | 
						||
| 
								 | 
							
										if (revents & POLLERR)
							 | 
						||
| 
								 | 
							
											return -EIO;
							 | 
						||
| 
								 | 
							
										if (!(revents & POLLIN))
							 | 
						||
| 
								 | 
							
											continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										err = snd_ctl_read(trial->handle, event);
							 | 
						||
| 
								 | 
							
										if (err < 0)
							 | 
						||
| 
								 | 
							
											return err;
							 | 
						||
| 
								 | 
							
										if (snd_ctl_event_get_type(event) != SND_CTL_EVENT_ELEM)
							 | 
						||
| 
								 | 
							
											continue;
							 | 
						||
| 
								 | 
							
										/*
							 | 
						||
| 
								 | 
							
										 * I expect each event is generated separately to the same
							 | 
						||
| 
								 | 
							
										 * element.
							 | 
						||
| 
								 | 
							
										 */
							 | 
						||
| 
								 | 
							
										if (!(snd_ctl_event_elem_get_mask(event) & mask))
							 | 
						||
| 
								 | 
							
											continue;
							 | 
						||
| 
								 | 
							
										--expected_count;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (expected_count != 0)
							 | 
						||
| 
								 | 
							
										return -EIO;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int check_elem_set_props(struct elem_set_trial *trial)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									snd_ctl_elem_id_t *id;
							 | 
						||
| 
								 | 
							
									snd_ctl_elem_info_t *info;
							 | 
						||
| 
								 | 
							
									unsigned int numid;
							 | 
						||
| 
								 | 
							
									unsigned int i;
							 | 
						||
| 
								 | 
							
									int err;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									snd_ctl_elem_id_alloca(&id);
							 | 
						||
| 
								 | 
							
									snd_ctl_elem_info_alloca(&info);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									snd_ctl_elem_info_set_id(info, trial->id);
							 | 
						||
| 
								 | 
							
									numid = snd_ctl_elem_info_get_numid(info);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for (i = 0; i < trial->element_count; ++i) {
							 | 
						||
| 
								 | 
							
										snd_ctl_elem_info_set_numid(info, numid + i);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										err = snd_ctl_elem_info(trial->handle, info);
							 | 
						||
| 
								 | 
							
										if (err < 0)
							 | 
						||
| 
								 | 
							
											return err;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* Check some common properties. */
							 | 
						||
| 
								 | 
							
										if (snd_ctl_elem_info_get_type(info) != trial->type)
							 | 
						||
| 
								 | 
							
											return -EIO;
							 | 
						||
| 
								 | 
							
										if (snd_ctl_elem_info_get_count(info) != trial->member_count)
							 | 
						||
| 
								 | 
							
											return -EIO;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/*
							 | 
						||
| 
								 | 
							
										 * In a case of IPC, this is the others. But in this case,
							 | 
						||
| 
								 | 
							
										 * it's myself.
							 | 
						||
| 
								 | 
							
										 */
							 | 
						||
| 
								 | 
							
										if (snd_ctl_elem_info_get_owner(info) != getpid())
							 | 
						||
| 
								 | 
							
											return -EIO;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/*
							 | 
						||
| 
								 | 
							
										 * Just adding an element set by userspace applications,
							 | 
						||
| 
								 | 
							
										 * included elements are initially locked.
							 | 
						||
| 
								 | 
							
										 */
							 | 
						||
| 
								 | 
							
										if (!snd_ctl_elem_info_is_locked(info))
							 | 
						||
| 
								 | 
							
											return -EIO;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* Check type-specific properties. */
							 | 
						||
| 
								 | 
							
										if (trial->check_elem_props != NULL) {
							 | 
						||
| 
								 | 
							
											err = trial->check_elem_props(trial, info);
							 | 
						||
| 
								 | 
							
											if (err < 0)
							 | 
						||
| 
								 | 
							
												return err;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										snd_ctl_elem_info_get_id(info, id);
							 | 
						||
| 
								 | 
							
										err = snd_ctl_elem_unlock(trial->handle, id);
							 | 
						||
| 
								 | 
							
										if (err < 0)
							 | 
						||
| 
								 | 
							
											return err;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int check_elems(struct elem_set_trial *trial)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									snd_ctl_elem_value_t *data;
							 | 
						||
| 
								 | 
							
									unsigned int numid;
							 | 
						||
| 
								 | 
							
									unsigned int i;
							 | 
						||
| 
								 | 
							
									int err;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									snd_ctl_elem_value_alloca(&data);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									snd_ctl_elem_value_set_id(data, trial->id);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/*
							 | 
						||
| 
								 | 
							
									 * Get the value of numid field in identical information for the first
							 | 
						||
| 
								 | 
							
									 * element of this element set.
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									numid = snd_ctl_elem_value_get_numid(data);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for (i = 0; i < trial->element_count; ++i) {
							 | 
						||
| 
								 | 
							
										/*
							 | 
						||
| 
								 | 
							
										 * Here, I increment numid, while we can also increment offset
							 | 
						||
| 
								 | 
							
										 * to enumerate each element in this element set.
							 | 
						||
| 
								 | 
							
										 */
							 | 
						||
| 
								 | 
							
										snd_ctl_elem_value_set_numid(data, numid + i);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										err = snd_ctl_elem_read(trial->handle, data);
							 | 
						||
| 
								 | 
							
										if (err < 0)
							 | 
						||
| 
								 | 
							
											return err;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* Change members of an element in this element set. */
							 | 
						||
| 
								 | 
							
										trial->change_elem_members(trial, data);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										err = snd_ctl_elem_write(trial->handle, data);
							 | 
						||
| 
								 | 
							
										if (err < 0)
							 | 
						||
| 
								 | 
							
											return err;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static int check_tlv(struct elem_set_trial *trial)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									unsigned int orig[8], curr[8];
							 | 
						||
| 
								 | 
							
									int err;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/*
							 | 
						||
| 
								 | 
							
									 * See a layout of 'struct snd_ctl_tlv'. I don't know the reason to
							 | 
						||
| 
								 | 
							
									 * construct this buffer with the same layout. It should be abstracted
							 | 
						||
| 
								 | 
							
									 * inner userspace library...
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									orig[0] = snd_ctl_elem_id_get_numid(trial->id);
							 | 
						||
| 
								 | 
							
									orig[1] = 6 * sizeof(orig[0]);
							 | 
						||
| 
								 | 
							
									orig[2] = 'a';
							 | 
						||
| 
								 | 
							
									orig[3] = 'b';
							 | 
						||
| 
								 | 
							
									orig[4] = 'c';
							 | 
						||
| 
								 | 
							
									orig[5] = 'd';
							 | 
						||
| 
								 | 
							
									orig[6] = 'e';
							 | 
						||
| 
								 | 
							
									orig[7] = 'f';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/*
							 | 
						||
| 
								 | 
							
									 * In in-kernel implementation, write and command operations are the
							 | 
						||
| 
								 | 
							
									 * same  for an element set added by userspace applications. Here, I
							 | 
						||
| 
								 | 
							
									 * use write.
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									err = snd_ctl_elem_tlv_write(trial->handle, trial->id,
							 | 
						||
| 
								 | 
							
												     (const unsigned int *)orig);
							 | 
						||
| 
								 | 
							
									if (err < 0)
							 | 
						||
| 
								 | 
							
										return err;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									err = snd_ctl_elem_tlv_read(trial->handle, trial->id, curr,
							 | 
						||
| 
								 | 
							
												    sizeof(curr));
							 | 
						||
| 
								 | 
							
									if (err < 0)
							 | 
						||
| 
								 | 
							
										return err;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (memcmp(curr, orig, sizeof(orig)) != 0)
							 | 
						||
| 
								 | 
							
										return -EIO;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return 0;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								int main(void)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									struct elem_set_trial trial = {0};
							 | 
						||
| 
								 | 
							
									unsigned int i;
							 | 
						||
| 
								 | 
							
									int err;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									snd_ctl_elem_id_alloca(&trial.id);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									err = snd_ctl_open(&trial.handle, "hw:0", 0);
							 | 
						||
| 
								 | 
							
									if (err < 0)
							 | 
						||
| 
								 | 
							
										return EXIT_FAILURE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									err = snd_ctl_subscribe_events(trial.handle, 1);
							 | 
						||
| 
								 | 
							
									if (err < 0)
							 | 
						||
| 
								 | 
							
										return EXIT_FAILURE;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/* Test all of types. */
							 | 
						||
| 
								 | 
							
									for (i = 0; i < SND_CTL_ELEM_TYPE_LAST; ++i) {
							 | 
						||
| 
								 | 
							
										trial.type = i + 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* Assign type-dependent operations. */
							 | 
						||
| 
								 | 
							
										switch (trial.type) {
							 | 
						||
| 
								 | 
							
										case SND_CTL_ELEM_TYPE_BOOLEAN:
							 | 
						||
| 
								 | 
							
											trial.element_count = 900;
							 | 
						||
| 
								 | 
							
											trial.member_count = 128;
							 | 
						||
| 
								 | 
							
											trial.add_elem_set = add_bool_elem_set;
							 | 
						||
| 
								 | 
							
											trial.check_elem_props = NULL;
							 | 
						||
| 
								 | 
							
											trial.change_elem_members = change_bool_elem_members;
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										case SND_CTL_ELEM_TYPE_INTEGER:
							 | 
						||
| 
								 | 
							
											trial.element_count = 900;
							 | 
						||
| 
								 | 
							
											trial.member_count = 128;
							 | 
						||
| 
								 | 
							
											trial.add_elem_set = add_int_elem_set;
							 | 
						||
| 
								 | 
							
											trial.check_elem_props = check_int_elem_props;
							 | 
						||
| 
								 | 
							
											trial.change_elem_members = change_int_elem_members;
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										case SND_CTL_ELEM_TYPE_ENUMERATED:
							 | 
						||
| 
								 | 
							
											trial.element_count = 900;
							 | 
						||
| 
								 | 
							
											trial.member_count = 128;
							 | 
						||
| 
								 | 
							
											trial.add_elem_set = add_enum_elem_set;
							 | 
						||
| 
								 | 
							
											trial.check_elem_props = check_enum_elem_props;
							 | 
						||
| 
								 | 
							
											trial.change_elem_members = change_enum_elem_members;
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										case SND_CTL_ELEM_TYPE_BYTES:
							 | 
						||
| 
								 | 
							
											trial.element_count = 900;
							 | 
						||
| 
								 | 
							
											trial.member_count = 512;
							 | 
						||
| 
								 | 
							
											trial.add_elem_set = add_bytes_elem_set;
							 | 
						||
| 
								 | 
							
											trial.check_elem_props = NULL;
							 | 
						||
| 
								 | 
							
											trial.change_elem_members = change_bytes_elem_members;
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										case SND_CTL_ELEM_TYPE_IEC958:
							 | 
						||
| 
								 | 
							
											trial.element_count = 1;
							 | 
						||
| 
								 | 
							
											trial.member_count = 1;
							 | 
						||
| 
								 | 
							
											trial.add_elem_set = add_iec958_elem_set;
							 | 
						||
| 
								 | 
							
											trial.check_elem_props = NULL;
							 | 
						||
| 
								 | 
							
											trial.change_elem_members = change_iec958_elem_members;
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										case SND_CTL_ELEM_TYPE_INTEGER64:
							 | 
						||
| 
								 | 
							
										default:
							 | 
						||
| 
								 | 
							
											trial.element_count = 900;
							 | 
						||
| 
								 | 
							
											trial.member_count = 64;
							 | 
						||
| 
								 | 
							
											trial.add_elem_set = add_int64_elem_set;
							 | 
						||
| 
								 | 
							
											trial.check_elem_props = check_int64_elem_props;
							 | 
						||
| 
								 | 
							
											trial.change_elem_members = change_int64_elem_members;
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* Test an operation to add an element set. */
							 | 
						||
| 
								 | 
							
										err = add_elem_set(&trial);
							 | 
						||
| 
								 | 
							
										if (err < 0) {
							 | 
						||
| 
								 | 
							
											printf("Fail to add an element set with %s type.\n",
							 | 
						||
| 
								 | 
							
											       snd_ctl_elem_type_name(trial.type));
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										err = check_event(&trial, SND_CTL_EVENT_MASK_ADD,
							 | 
						||
| 
								 | 
							
												  trial.element_count);
							 | 
						||
| 
								 | 
							
										if (err < 0) {
							 | 
						||
| 
								 | 
							
											printf("Fail to check some events to add elements with "
							 | 
						||
| 
								 | 
							
											       "%s type.\n",
							 | 
						||
| 
								 | 
							
											       snd_ctl_elem_type_name(trial.type));
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* Check properties of each element in this element set. */
							 | 
						||
| 
								 | 
							
										err = check_elem_set_props(&trial);
							 | 
						||
| 
								 | 
							
										if (err < 0) {
							 | 
						||
| 
								 | 
							
											printf("Fail to check propetries of each element with "
							 | 
						||
| 
								 | 
							
											       "%s type.\n",
							 | 
						||
| 
								 | 
							
											       snd_ctl_elem_type_name(trial.type));
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/*
							 | 
						||
| 
								 | 
							
										 * Test operations to change the state of members in each
							 | 
						||
| 
								 | 
							
										 * element in the element set.
							 | 
						||
| 
								 | 
							
										 */
							 | 
						||
| 
								 | 
							
										err = check_elems(&trial);
							 | 
						||
| 
								 | 
							
										if (err < 0) {
							 | 
						||
| 
								 | 
							
											printf("Fail to change status of each element with %s "
							 | 
						||
| 
								 | 
							
											       "type.\n",
							 | 
						||
| 
								 | 
							
											       snd_ctl_elem_type_name(trial.type));
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										err = check_event(&trial, SND_CTL_EVENT_MASK_VALUE,
							 | 
						||
| 
								 | 
							
												  trial.element_count);
							 | 
						||
| 
								 | 
							
										if (err < 0) {
							 | 
						||
| 
								 | 
							
											printf("Fail to check some events to change status of "
							 | 
						||
| 
								 | 
							
											       "each elements with %s type.\n",
							 | 
						||
| 
								 | 
							
											       snd_ctl_elem_type_name(trial.type));
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/*
							 | 
						||
| 
								 | 
							
										 * Test an operation to change threshold data of this element set,
							 | 
						||
| 
								 | 
							
										 * except for IEC958 type.
							 | 
						||
| 
								 | 
							
										 */
							 | 
						||
| 
								 | 
							
										if (trial.type != SND_CTL_ELEM_TYPE_IEC958) {
							 | 
						||
| 
								 | 
							
											err = check_tlv(&trial);
							 | 
						||
| 
								 | 
							
											if (err < 0) {
							 | 
						||
| 
								 | 
							
												printf("Fail to change threshold level of an "
							 | 
						||
| 
								 | 
							
												       "element set with %s type.\n",
							 | 
						||
| 
								 | 
							
												       snd_ctl_elem_type_name(trial.type));
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											err = check_event(&trial, SND_CTL_EVENT_MASK_TLV, 1);
							 | 
						||
| 
								 | 
							
											if (err < 0) {
							 | 
						||
| 
								 | 
							
												printf("Fail to check an event to change "
							 | 
						||
| 
								 | 
							
												       "threshold level of an an element set "
							 | 
						||
| 
								 | 
							
												       "with %s type.\n",
							 | 
						||
| 
								 | 
							
												       snd_ctl_elem_type_name(trial.type));
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* Test an operation to remove elements in this element set. */
							 | 
						||
| 
								 | 
							
										err = snd_ctl_elem_remove(trial.handle, trial.id);
							 | 
						||
| 
								 | 
							
										if (err < 0) {
							 | 
						||
| 
								 | 
							
											printf("Fail to remove elements with %s type.\n",
							 | 
						||
| 
								 | 
							
											       snd_ctl_elem_type_name(trial.type));
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										err = check_event(&trial, SND_CTL_EVENT_MASK_REMOVE,
							 | 
						||
| 
								 | 
							
														  trial.element_count);
							 | 
						||
| 
								 | 
							
										if (err < 0) {
							 | 
						||
| 
								 | 
							
											printf("Fail to check some events to remove each "
							 | 
						||
| 
								 | 
							
											       "element with %s type.\n",
							 | 
						||
| 
								 | 
							
											       snd_ctl_elem_type_name(trial.type));
							 | 
						||
| 
								 | 
							
											break;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (err < 0) {
							 | 
						||
| 
								 | 
							
										printf("%s\n", snd_strerror(err));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* To ensure. */
							 | 
						||
| 
								 | 
							
										snd_ctl_elem_remove(trial.handle, trial.id);
							 | 
						||
| 
								 | 
							
										return EXIT_FAILURE;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return EXIT_SUCCESS;
							 | 
						||
| 
								 | 
							
								}
							 |