1c72fcc34Sopenharmony_ci/*
2c72fcc34Sopenharmony_ci *   ALSA command line mixer utility
3c72fcc34Sopenharmony_ci *   Copyright (c) 1999-2000 by Jaroslav Kysela <perex@perex.cz>
4c72fcc34Sopenharmony_ci *
5c72fcc34Sopenharmony_ci *   This program is free software; you can redistribute it and/or modify
6c72fcc34Sopenharmony_ci *   it under the terms of the GNU General Public License as published by
7c72fcc34Sopenharmony_ci *   the Free Software Foundation; either version 2 of the License, or
8c72fcc34Sopenharmony_ci *   (at your option) any later version.
9c72fcc34Sopenharmony_ci *
10c72fcc34Sopenharmony_ci *   This program is distributed in the hope that it will be useful,
11c72fcc34Sopenharmony_ci *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12c72fcc34Sopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13c72fcc34Sopenharmony_ci *   GNU General Public License for more details.
14c72fcc34Sopenharmony_ci *
15c72fcc34Sopenharmony_ci *   You should have received a copy of the GNU General Public License
16c72fcc34Sopenharmony_ci *   along with this program; if not, write to the Free Software
17c72fcc34Sopenharmony_ci *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18c72fcc34Sopenharmony_ci *
19c72fcc34Sopenharmony_ci */
20c72fcc34Sopenharmony_ci
21c72fcc34Sopenharmony_ci#include "aconfig.h"
22c72fcc34Sopenharmony_ci#include <stdio.h>
23c72fcc34Sopenharmony_ci#include <stdlib.h>
24c72fcc34Sopenharmony_ci#include <string.h>
25c72fcc34Sopenharmony_ci#include <getopt.h>
26c72fcc34Sopenharmony_ci#include <stdarg.h>
27c72fcc34Sopenharmony_ci#include <ctype.h>
28c72fcc34Sopenharmony_ci#include <math.h>
29c72fcc34Sopenharmony_ci#include <errno.h>
30c72fcc34Sopenharmony_ci#include <assert.h>
31c72fcc34Sopenharmony_ci#include <alsa/asoundlib.h>
32c72fcc34Sopenharmony_ci#include <poll.h>
33c72fcc34Sopenharmony_ci#include <stdint.h>
34c72fcc34Sopenharmony_ci#include "amixer.h"
35c72fcc34Sopenharmony_ci#include "../alsamixer/volume_mapping.h"
36c72fcc34Sopenharmony_ci
37c72fcc34Sopenharmony_ci#define LEVEL_BASIC		(1<<0)
38c72fcc34Sopenharmony_ci#define LEVEL_INACTIVE		(1<<1)
39c72fcc34Sopenharmony_ci#define LEVEL_ID		(1<<2)
40c72fcc34Sopenharmony_ci
41c72fcc34Sopenharmony_cistatic int quiet = 0;
42c72fcc34Sopenharmony_cistatic int debugflag = 0;
43c72fcc34Sopenharmony_cistatic int no_check = 0;
44c72fcc34Sopenharmony_cistatic int smixer_level = 0;
45c72fcc34Sopenharmony_cistatic int ignore_error = 0;
46c72fcc34Sopenharmony_cistatic struct snd_mixer_selem_regopt smixer_options;
47c72fcc34Sopenharmony_cistatic char card[64] = "default";
48c72fcc34Sopenharmony_ci
49c72fcc34Sopenharmony_cistatic void error(const char *fmt,...)
50c72fcc34Sopenharmony_ci{
51c72fcc34Sopenharmony_ci	va_list va;
52c72fcc34Sopenharmony_ci
53c72fcc34Sopenharmony_ci	va_start(va, fmt);
54c72fcc34Sopenharmony_ci	fprintf(stderr, "amixer: ");
55c72fcc34Sopenharmony_ci	vfprintf(stderr, fmt, va);
56c72fcc34Sopenharmony_ci	fprintf(stderr, "\n");
57c72fcc34Sopenharmony_ci	va_end(va);
58c72fcc34Sopenharmony_ci}
59c72fcc34Sopenharmony_ci
60c72fcc34Sopenharmony_cistatic int help(void)
61c72fcc34Sopenharmony_ci{
62c72fcc34Sopenharmony_ci	printf("Usage: amixer <options> [command]\n");
63c72fcc34Sopenharmony_ci	printf("\nAvailable options:\n");
64c72fcc34Sopenharmony_ci	printf("  -h,--help       this help\n");
65c72fcc34Sopenharmony_ci	printf("  -c,--card N     select the card\n");
66c72fcc34Sopenharmony_ci	printf("  -D,--device N   select the device, default '%s'\n", card);
67c72fcc34Sopenharmony_ci	printf("  -d,--debug      debug mode\n");
68c72fcc34Sopenharmony_ci	printf("  -n,--nocheck    do not perform range checking\n");
69c72fcc34Sopenharmony_ci	printf("  -v,--version    print version of this program\n");
70c72fcc34Sopenharmony_ci	printf("  -q,--quiet      be quiet\n");
71c72fcc34Sopenharmony_ci	printf("  -i,--inactive   show also inactive controls\n");
72c72fcc34Sopenharmony_ci	printf("  -a,--abstract L select abstraction level (none or basic)\n");
73c72fcc34Sopenharmony_ci	printf("  -s,--stdin      Read and execute commands from stdin sequentially\n");
74c72fcc34Sopenharmony_ci	printf("  -R,--raw-volume Use the raw value (default)\n");
75c72fcc34Sopenharmony_ci	printf("  -M,--mapped-volume Use the mapped volume\n");
76c72fcc34Sopenharmony_ci	printf("\nAvailable commands:\n");
77c72fcc34Sopenharmony_ci	printf("  scontrols       show all mixer simple controls\n");
78c72fcc34Sopenharmony_ci	printf("  scontents	  show contents of all mixer simple controls (default command)\n");
79c72fcc34Sopenharmony_ci	printf("  sset sID P      set contents for one mixer simple control\n");
80c72fcc34Sopenharmony_ci	printf("  sget sID        get contents for one mixer simple control\n");
81c72fcc34Sopenharmony_ci	printf("  controls        show all controls for given card\n");
82c72fcc34Sopenharmony_ci	printf("  contents        show contents of all controls for given card\n");
83c72fcc34Sopenharmony_ci	printf("  cset cID P      set control contents for one control\n");
84c72fcc34Sopenharmony_ci	printf("  cget cID        get control contents for one control\n");
85c72fcc34Sopenharmony_ci	printf("\nAvailable advanced commands:\n");
86c72fcc34Sopenharmony_ci	printf("  sevents	  show the mixer events for simple controls\n");
87c72fcc34Sopenharmony_ci	printf("  events	  show the mixer events for controls\n");
88c72fcc34Sopenharmony_ci	return 0;
89c72fcc34Sopenharmony_ci}
90c72fcc34Sopenharmony_ci
91c72fcc34Sopenharmony_cistatic int info(void)
92c72fcc34Sopenharmony_ci{
93c72fcc34Sopenharmony_ci	int err;
94c72fcc34Sopenharmony_ci	snd_ctl_t *handle;
95c72fcc34Sopenharmony_ci	snd_mixer_t *mhandle;
96c72fcc34Sopenharmony_ci	snd_ctl_card_info_t *info;
97c72fcc34Sopenharmony_ci	snd_ctl_elem_list_t *clist;
98c72fcc34Sopenharmony_ci	snd_ctl_card_info_alloca(&info);
99c72fcc34Sopenharmony_ci	snd_ctl_elem_list_alloca(&clist);
100c72fcc34Sopenharmony_ci
101c72fcc34Sopenharmony_ci	if ((err = snd_ctl_open(&handle, card, 0)) < 0) {
102c72fcc34Sopenharmony_ci		error("Control device %s open error: %s", card, snd_strerror(err));
103c72fcc34Sopenharmony_ci		return err;
104c72fcc34Sopenharmony_ci	}
105c72fcc34Sopenharmony_ci
106c72fcc34Sopenharmony_ci	if ((err = snd_ctl_card_info(handle, info)) < 0) {
107c72fcc34Sopenharmony_ci		error("Control device %s hw info error: %s", card, snd_strerror(err));
108c72fcc34Sopenharmony_ci		return err;
109c72fcc34Sopenharmony_ci	}
110c72fcc34Sopenharmony_ci	printf("Card %s '%s'/'%s'\n", card, snd_ctl_card_info_get_id(info),
111c72fcc34Sopenharmony_ci	       snd_ctl_card_info_get_longname(info));
112c72fcc34Sopenharmony_ci	printf("  Mixer name	: '%s'\n", snd_ctl_card_info_get_mixername(info));
113c72fcc34Sopenharmony_ci	printf("  Components	: '%s'\n", snd_ctl_card_info_get_components(info));
114c72fcc34Sopenharmony_ci	if ((err = snd_ctl_elem_list(handle, clist)) < 0) {
115c72fcc34Sopenharmony_ci		error("snd_ctl_elem_list failure: %s", snd_strerror(err));
116c72fcc34Sopenharmony_ci	} else {
117c72fcc34Sopenharmony_ci		printf("  Controls      : %i\n", snd_ctl_elem_list_get_count(clist));
118c72fcc34Sopenharmony_ci	}
119c72fcc34Sopenharmony_ci	snd_ctl_close(handle);
120c72fcc34Sopenharmony_ci	if ((err = snd_mixer_open(&mhandle, 0)) < 0) {
121c72fcc34Sopenharmony_ci		error("Mixer open error: %s", snd_strerror(err));
122c72fcc34Sopenharmony_ci		return err;
123c72fcc34Sopenharmony_ci	}
124c72fcc34Sopenharmony_ci	if (smixer_level == 0 && (err = snd_mixer_attach(mhandle, card)) < 0) {
125c72fcc34Sopenharmony_ci		error("Mixer attach %s error: %s", card, snd_strerror(err));
126c72fcc34Sopenharmony_ci		snd_mixer_close(mhandle);
127c72fcc34Sopenharmony_ci		return err;
128c72fcc34Sopenharmony_ci	}
129c72fcc34Sopenharmony_ci	if ((err = snd_mixer_selem_register(mhandle, smixer_level > 0 ? &smixer_options : NULL, NULL)) < 0) {
130c72fcc34Sopenharmony_ci		error("Mixer register error: %s", snd_strerror(err));
131c72fcc34Sopenharmony_ci		snd_mixer_close(mhandle);
132c72fcc34Sopenharmony_ci		return err;
133c72fcc34Sopenharmony_ci	}
134c72fcc34Sopenharmony_ci	err = snd_mixer_load(mhandle);
135c72fcc34Sopenharmony_ci	if (err < 0) {
136c72fcc34Sopenharmony_ci		error("Mixer load %s error: %s", card, snd_strerror(err));
137c72fcc34Sopenharmony_ci		snd_mixer_close(mhandle);
138c72fcc34Sopenharmony_ci		return err;
139c72fcc34Sopenharmony_ci	}
140c72fcc34Sopenharmony_ci	printf("  Simple ctrls  : %i\n", snd_mixer_get_count(mhandle));
141c72fcc34Sopenharmony_ci	snd_mixer_close(mhandle);
142c72fcc34Sopenharmony_ci	return 0;
143c72fcc34Sopenharmony_ci}
144c72fcc34Sopenharmony_ci
145c72fcc34Sopenharmony_cistatic const char *control_type(snd_ctl_elem_info_t *info)
146c72fcc34Sopenharmony_ci{
147c72fcc34Sopenharmony_ci	return snd_ctl_elem_type_name(snd_ctl_elem_info_get_type(info));
148c72fcc34Sopenharmony_ci}
149c72fcc34Sopenharmony_ci
150c72fcc34Sopenharmony_cistatic const char *control_access(snd_ctl_elem_info_t *info)
151c72fcc34Sopenharmony_ci{
152c72fcc34Sopenharmony_ci	static char result[10];
153c72fcc34Sopenharmony_ci	char *res = result;
154c72fcc34Sopenharmony_ci
155c72fcc34Sopenharmony_ci	*res++ = snd_ctl_elem_info_is_readable(info) ? 'r' : '-';
156c72fcc34Sopenharmony_ci	*res++ = snd_ctl_elem_info_is_writable(info) ? 'w' : '-';
157c72fcc34Sopenharmony_ci	*res++ = snd_ctl_elem_info_is_inactive(info) ? 'i' : '-';
158c72fcc34Sopenharmony_ci	*res++ = snd_ctl_elem_info_is_volatile(info) ? 'v' : '-';
159c72fcc34Sopenharmony_ci	*res++ = snd_ctl_elem_info_is_locked(info) ? 'l' : '-';
160c72fcc34Sopenharmony_ci	*res++ = snd_ctl_elem_info_is_tlv_readable(info) ? 'R' : '-';
161c72fcc34Sopenharmony_ci	*res++ = snd_ctl_elem_info_is_tlv_writable(info) ? 'W' : '-';
162c72fcc34Sopenharmony_ci	*res++ = snd_ctl_elem_info_is_tlv_commandable(info) ? 'C' : '-';
163c72fcc34Sopenharmony_ci	*res++ = '\0';
164c72fcc34Sopenharmony_ci	return result;
165c72fcc34Sopenharmony_ci}
166c72fcc34Sopenharmony_ci
167c72fcc34Sopenharmony_ci#define check_range(val, min, max) \
168c72fcc34Sopenharmony_ci	(no_check ? (val) : ((val < min) ? (min) : (val > max) ? (max) : (val)))
169c72fcc34Sopenharmony_ci#if 0
170c72fcc34Sopenharmony_cistatic int convert_range(int val, int omin, int omax, int nmin, int nmax)
171c72fcc34Sopenharmony_ci{
172c72fcc34Sopenharmony_ci	int orange = omax - omin, nrange = nmax - nmin;
173c72fcc34Sopenharmony_ci
174c72fcc34Sopenharmony_ci	if (orange == 0)
175c72fcc34Sopenharmony_ci		return 0;
176c72fcc34Sopenharmony_ci	return rint((((double)nrange * ((double)val - (double)omin)) + ((double)orange / 2.0)) / ((double)orange + (double)nmin));
177c72fcc34Sopenharmony_ci}
178c72fcc34Sopenharmony_ci#endif
179c72fcc34Sopenharmony_ci
180c72fcc34Sopenharmony_ci#if 0
181c72fcc34Sopenharmony_cistatic int convert_db_range(int val, int omin, int omax, int nmin, int nmax)
182c72fcc34Sopenharmony_ci{
183c72fcc34Sopenharmony_ci	int orange = omax - omin, nrange = nmax - nmin;
184c72fcc34Sopenharmony_ci
185c72fcc34Sopenharmony_ci	if (orange == 0)
186c72fcc34Sopenharmony_ci		return 0;
187c72fcc34Sopenharmony_ci	return rint((((double)nrange * ((double)val - (double)omin)) + ((double)orange / 2.0)) / (double)orange + (double)nmin);
188c72fcc34Sopenharmony_ci}
189c72fcc34Sopenharmony_ci#endif
190c72fcc34Sopenharmony_ci
191c72fcc34Sopenharmony_ci/* Fuction to convert from volume to percentage. val = volume */
192c72fcc34Sopenharmony_ci
193c72fcc34Sopenharmony_cistatic int convert_prange(long val, long min, long max)
194c72fcc34Sopenharmony_ci{
195c72fcc34Sopenharmony_ci	long range = max - min;
196c72fcc34Sopenharmony_ci	int tmp;
197c72fcc34Sopenharmony_ci
198c72fcc34Sopenharmony_ci	if (range == 0)
199c72fcc34Sopenharmony_ci		return min;
200c72fcc34Sopenharmony_ci	val -= min;
201c72fcc34Sopenharmony_ci	tmp = rint((double)val/(double)range * 100);
202c72fcc34Sopenharmony_ci	return tmp;
203c72fcc34Sopenharmony_ci}
204c72fcc34Sopenharmony_ci
205c72fcc34Sopenharmony_ci/* Function to convert from percentage to volume. perc = percentage */
206c72fcc34Sopenharmony_cistatic long convert_prange1(long perc, long min, long max)
207c72fcc34Sopenharmony_ci{
208c72fcc34Sopenharmony_ci	long tmp;
209c72fcc34Sopenharmony_ci
210c72fcc34Sopenharmony_ci	tmp = rint((double)perc * (double)(max - min) * 0.01);
211c72fcc34Sopenharmony_ci	if (tmp == 0 && perc > 0)
212c72fcc34Sopenharmony_ci		tmp++;
213c72fcc34Sopenharmony_ci	return tmp + min;
214c72fcc34Sopenharmony_ci}
215c72fcc34Sopenharmony_ci
216c72fcc34Sopenharmony_cistruct volume_ops {
217c72fcc34Sopenharmony_ci	int (*get_range)(snd_mixer_elem_t *elem, long *min, long *max);
218c72fcc34Sopenharmony_ci	int (*get)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t c,
219c72fcc34Sopenharmony_ci		   long *value);
220c72fcc34Sopenharmony_ci	int (*set)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t c,
221c72fcc34Sopenharmony_ci		   long value, int dir);
222c72fcc34Sopenharmony_ci};
223c72fcc34Sopenharmony_ci
224c72fcc34Sopenharmony_cienum { VOL_RAW, VOL_DB, VOL_MAP };
225c72fcc34Sopenharmony_ci
226c72fcc34Sopenharmony_cistruct volume_ops_set {
227c72fcc34Sopenharmony_ci	int (*has_volume)(snd_mixer_elem_t *elem);
228c72fcc34Sopenharmony_ci	struct volume_ops v[3];
229c72fcc34Sopenharmony_ci};
230c72fcc34Sopenharmony_ci
231c72fcc34Sopenharmony_cistatic int set_playback_dB(snd_mixer_elem_t *elem,
232c72fcc34Sopenharmony_ci			   snd_mixer_selem_channel_id_t c, long value, int dir)
233c72fcc34Sopenharmony_ci{
234c72fcc34Sopenharmony_ci	return snd_mixer_selem_set_playback_dB(elem, c, value, dir);
235c72fcc34Sopenharmony_ci}
236c72fcc34Sopenharmony_ci
237c72fcc34Sopenharmony_cistatic int set_capture_dB(snd_mixer_elem_t *elem,
238c72fcc34Sopenharmony_ci			  snd_mixer_selem_channel_id_t c, long value, int dir)
239c72fcc34Sopenharmony_ci{
240c72fcc34Sopenharmony_ci	return snd_mixer_selem_set_capture_dB(elem, c, value, dir);
241c72fcc34Sopenharmony_ci}
242c72fcc34Sopenharmony_ci
243c72fcc34Sopenharmony_cistatic int set_playback_raw_volume(snd_mixer_elem_t *elem,
244c72fcc34Sopenharmony_ci				   snd_mixer_selem_channel_id_t c,
245c72fcc34Sopenharmony_ci				   long value, int dir ATTRIBUTE_UNUSED)
246c72fcc34Sopenharmony_ci{
247c72fcc34Sopenharmony_ci	return snd_mixer_selem_set_playback_volume(elem, c, value);
248c72fcc34Sopenharmony_ci}
249c72fcc34Sopenharmony_ci
250c72fcc34Sopenharmony_cistatic int set_capture_raw_volume(snd_mixer_elem_t *elem,
251c72fcc34Sopenharmony_ci				  snd_mixer_selem_channel_id_t c,
252c72fcc34Sopenharmony_ci				  long value, int dir ATTRIBUTE_UNUSED)
253c72fcc34Sopenharmony_ci{
254c72fcc34Sopenharmony_ci	return snd_mixer_selem_set_capture_volume(elem, c, value);
255c72fcc34Sopenharmony_ci}
256c72fcc34Sopenharmony_ci
257c72fcc34Sopenharmony_ci/* FIXME: normalize to int32 space to be compatible with other types */
258c72fcc34Sopenharmony_ci#define MAP_VOL_RES	(INT32_MAX / 100)
259c72fcc34Sopenharmony_ci
260c72fcc34Sopenharmony_cistatic int get_mapped_volume_range(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED,
261c72fcc34Sopenharmony_ci				   long *pmin, long *pmax)
262c72fcc34Sopenharmony_ci{
263c72fcc34Sopenharmony_ci	*pmin = 0;
264c72fcc34Sopenharmony_ci	*pmax = MAP_VOL_RES;
265c72fcc34Sopenharmony_ci	return 0;
266c72fcc34Sopenharmony_ci}
267c72fcc34Sopenharmony_ci
268c72fcc34Sopenharmony_cistatic int get_playback_mapped_volume(snd_mixer_elem_t *elem,
269c72fcc34Sopenharmony_ci				      snd_mixer_selem_channel_id_t c,
270c72fcc34Sopenharmony_ci				      long *value)
271c72fcc34Sopenharmony_ci{
272c72fcc34Sopenharmony_ci	*value = (rint)(get_normalized_playback_volume(elem, c) * MAP_VOL_RES);
273c72fcc34Sopenharmony_ci	return 0;
274c72fcc34Sopenharmony_ci}
275c72fcc34Sopenharmony_ci
276c72fcc34Sopenharmony_cistatic int set_playback_mapped_volume(snd_mixer_elem_t *elem,
277c72fcc34Sopenharmony_ci				      snd_mixer_selem_channel_id_t c,
278c72fcc34Sopenharmony_ci				      long value, int dir)
279c72fcc34Sopenharmony_ci{
280c72fcc34Sopenharmony_ci	return set_normalized_playback_volume(elem, c,
281c72fcc34Sopenharmony_ci					      (double)value / MAP_VOL_RES, dir);
282c72fcc34Sopenharmony_ci}
283c72fcc34Sopenharmony_ci
284c72fcc34Sopenharmony_cistatic int get_capture_mapped_volume(snd_mixer_elem_t *elem,
285c72fcc34Sopenharmony_ci				     snd_mixer_selem_channel_id_t c,
286c72fcc34Sopenharmony_ci				     long *value)
287c72fcc34Sopenharmony_ci{
288c72fcc34Sopenharmony_ci	*value = (rint)(get_normalized_capture_volume(elem, c) * MAP_VOL_RES);
289c72fcc34Sopenharmony_ci	return 0;
290c72fcc34Sopenharmony_ci}
291c72fcc34Sopenharmony_ci
292c72fcc34Sopenharmony_cistatic int set_capture_mapped_volume(snd_mixer_elem_t *elem,
293c72fcc34Sopenharmony_ci				     snd_mixer_selem_channel_id_t c,
294c72fcc34Sopenharmony_ci				     long value, int dir)
295c72fcc34Sopenharmony_ci{
296c72fcc34Sopenharmony_ci	return set_normalized_capture_volume(elem, c,
297c72fcc34Sopenharmony_ci					     (double)value / MAP_VOL_RES, dir);
298c72fcc34Sopenharmony_ci}
299c72fcc34Sopenharmony_ci
300c72fcc34Sopenharmony_cistatic const struct volume_ops_set vol_ops[2] = {
301c72fcc34Sopenharmony_ci	{
302c72fcc34Sopenharmony_ci		.has_volume = snd_mixer_selem_has_playback_volume,
303c72fcc34Sopenharmony_ci		.v = {{ snd_mixer_selem_get_playback_volume_range,
304c72fcc34Sopenharmony_ci			snd_mixer_selem_get_playback_volume,
305c72fcc34Sopenharmony_ci			set_playback_raw_volume },
306c72fcc34Sopenharmony_ci		      { snd_mixer_selem_get_playback_dB_range,
307c72fcc34Sopenharmony_ci			snd_mixer_selem_get_playback_dB,
308c72fcc34Sopenharmony_ci			set_playback_dB },
309c72fcc34Sopenharmony_ci		      { get_mapped_volume_range,
310c72fcc34Sopenharmony_ci			get_playback_mapped_volume,
311c72fcc34Sopenharmony_ci			set_playback_mapped_volume },
312c72fcc34Sopenharmony_ci		},
313c72fcc34Sopenharmony_ci	},
314c72fcc34Sopenharmony_ci	{
315c72fcc34Sopenharmony_ci		.has_volume = snd_mixer_selem_has_capture_volume,
316c72fcc34Sopenharmony_ci		.v = {{ snd_mixer_selem_get_capture_volume_range,
317c72fcc34Sopenharmony_ci			snd_mixer_selem_get_capture_volume,
318c72fcc34Sopenharmony_ci			set_capture_raw_volume },
319c72fcc34Sopenharmony_ci		      { snd_mixer_selem_get_capture_dB_range,
320c72fcc34Sopenharmony_ci			snd_mixer_selem_get_capture_dB,
321c72fcc34Sopenharmony_ci			set_capture_dB },
322c72fcc34Sopenharmony_ci		      { get_mapped_volume_range,
323c72fcc34Sopenharmony_ci			get_capture_mapped_volume,
324c72fcc34Sopenharmony_ci			set_capture_mapped_volume },
325c72fcc34Sopenharmony_ci		},
326c72fcc34Sopenharmony_ci	},
327c72fcc34Sopenharmony_ci};
328c72fcc34Sopenharmony_ci
329c72fcc34Sopenharmony_cistatic int std_vol_type = VOL_RAW;
330c72fcc34Sopenharmony_ci
331c72fcc34Sopenharmony_cistatic int set_volume_simple(snd_mixer_elem_t *elem,
332c72fcc34Sopenharmony_ci			     snd_mixer_selem_channel_id_t chn,
333c72fcc34Sopenharmony_ci			     char **ptr, int dir)
334c72fcc34Sopenharmony_ci{
335c72fcc34Sopenharmony_ci	long val, orig, pmin, pmax;
336c72fcc34Sopenharmony_ci	char *p = *ptr, *s;
337c72fcc34Sopenharmony_ci	int invalid = 0, percent = 0, err = 0;
338c72fcc34Sopenharmony_ci	int vol_type;
339c72fcc34Sopenharmony_ci	double scale = 1.0;
340c72fcc34Sopenharmony_ci	int correct = 0;
341c72fcc34Sopenharmony_ci
342c72fcc34Sopenharmony_ci	if (! vol_ops[dir].has_volume(elem))
343c72fcc34Sopenharmony_ci		invalid = 1;
344c72fcc34Sopenharmony_ci
345c72fcc34Sopenharmony_ci	if (*p == ':')
346c72fcc34Sopenharmony_ci		p++;
347c72fcc34Sopenharmony_ci	if (*p == '\0' || (!isdigit(*p) && *p != '-'))
348c72fcc34Sopenharmony_ci		goto skip;
349c72fcc34Sopenharmony_ci
350c72fcc34Sopenharmony_ci	s = p;
351c72fcc34Sopenharmony_ci	val = strtol(s, &p, 10);
352c72fcc34Sopenharmony_ci	if (*p == '.') {
353c72fcc34Sopenharmony_ci		p++;
354c72fcc34Sopenharmony_ci		strtol(p, &p, 10);
355c72fcc34Sopenharmony_ci	}
356c72fcc34Sopenharmony_ci	if (*p == '%') {
357c72fcc34Sopenharmony_ci		vol_type = std_vol_type;
358c72fcc34Sopenharmony_ci		percent = 1;
359c72fcc34Sopenharmony_ci		p++;
360c72fcc34Sopenharmony_ci	} else if (toupper(p[0]) == 'D' && toupper(p[1]) == 'B') {
361c72fcc34Sopenharmony_ci		vol_type = VOL_DB;
362c72fcc34Sopenharmony_ci		p += 2;
363c72fcc34Sopenharmony_ci		scale = 100;
364c72fcc34Sopenharmony_ci	} else {
365c72fcc34Sopenharmony_ci		vol_type = VOL_RAW;
366c72fcc34Sopenharmony_ci	}
367c72fcc34Sopenharmony_ci
368c72fcc34Sopenharmony_ci	if (*p && !strchr(",:+-", *p))
369c72fcc34Sopenharmony_ci		invalid = 1;
370c72fcc34Sopenharmony_ci
371c72fcc34Sopenharmony_ci	val = (long)(strtod(s, NULL) * scale);
372c72fcc34Sopenharmony_ci	if (vol_ops[dir].v[vol_type].get_range(elem, &pmin, &pmax) < 0)
373c72fcc34Sopenharmony_ci		invalid = 1;
374c72fcc34Sopenharmony_ci	if (percent)
375c72fcc34Sopenharmony_ci		val = (long)convert_prange1(val, pmin, pmax);
376c72fcc34Sopenharmony_ci	if (*p == '+' || *p == '-') {
377c72fcc34Sopenharmony_ci		if (! invalid) {
378c72fcc34Sopenharmony_ci			if (vol_ops[dir].v[vol_type].get(elem, chn, &orig) < 0)
379c72fcc34Sopenharmony_ci				invalid = 1;
380c72fcc34Sopenharmony_ci			if (*p == '+') {
381c72fcc34Sopenharmony_ci				val = orig + val;
382c72fcc34Sopenharmony_ci				correct = 1;
383c72fcc34Sopenharmony_ci			} else {
384c72fcc34Sopenharmony_ci				val = orig - val;
385c72fcc34Sopenharmony_ci				correct = -1;
386c72fcc34Sopenharmony_ci			}
387c72fcc34Sopenharmony_ci		}
388c72fcc34Sopenharmony_ci		p++;
389c72fcc34Sopenharmony_ci	}
390c72fcc34Sopenharmony_ci
391c72fcc34Sopenharmony_ci	if (*p && !strchr(",:", *p))
392c72fcc34Sopenharmony_ci		invalid = 1;
393c72fcc34Sopenharmony_ci
394c72fcc34Sopenharmony_ci	if (! invalid) {
395c72fcc34Sopenharmony_ci		val = check_range(val, pmin, pmax);
396c72fcc34Sopenharmony_ci		err = vol_ops[dir].v[vol_type].set(elem, chn, val, correct);
397c72fcc34Sopenharmony_ci	}
398c72fcc34Sopenharmony_ci skip:
399c72fcc34Sopenharmony_ci	if (*p == ',')
400c72fcc34Sopenharmony_ci		p++;
401c72fcc34Sopenharmony_ci	*ptr = p;
402c72fcc34Sopenharmony_ci	return err ? err : (invalid ? -ENOENT : 0);
403c72fcc34Sopenharmony_ci}
404c72fcc34Sopenharmony_ci
405c72fcc34Sopenharmony_cistatic int get_bool_simple(char **ptr, char *str, int invert, int orig)
406c72fcc34Sopenharmony_ci{
407c72fcc34Sopenharmony_ci	if (**ptr == ':')
408c72fcc34Sopenharmony_ci		(*ptr)++;
409c72fcc34Sopenharmony_ci	if (!strncasecmp(*ptr, str, strlen(str))) {
410c72fcc34Sopenharmony_ci		orig = 1 ^ (invert ? 1 : 0);
411c72fcc34Sopenharmony_ci		while (**ptr != '\0' && **ptr != ',' && **ptr != ':')
412c72fcc34Sopenharmony_ci			(*ptr)++;
413c72fcc34Sopenharmony_ci	}
414c72fcc34Sopenharmony_ci	if (**ptr == ',' || **ptr == ':')
415c72fcc34Sopenharmony_ci		(*ptr)++;
416c72fcc34Sopenharmony_ci	return orig;
417c72fcc34Sopenharmony_ci}
418c72fcc34Sopenharmony_ci
419c72fcc34Sopenharmony_cistatic int simple_skip_word(char **ptr, char *str)
420c72fcc34Sopenharmony_ci{
421c72fcc34Sopenharmony_ci	char *xptr = *ptr;
422c72fcc34Sopenharmony_ci	if (*xptr == ':')
423c72fcc34Sopenharmony_ci		xptr++;
424c72fcc34Sopenharmony_ci	if (!strncasecmp(xptr, str, strlen(str))) {
425c72fcc34Sopenharmony_ci		while (*xptr != '\0' && *xptr != ',' && *xptr != ':')
426c72fcc34Sopenharmony_ci			xptr++;
427c72fcc34Sopenharmony_ci		if (*xptr == ',' || *xptr == ':')
428c72fcc34Sopenharmony_ci			xptr++;
429c72fcc34Sopenharmony_ci		*ptr = xptr;
430c72fcc34Sopenharmony_ci		return 1;
431c72fcc34Sopenharmony_ci	}
432c72fcc34Sopenharmony_ci	return 0;
433c72fcc34Sopenharmony_ci}
434c72fcc34Sopenharmony_ci
435c72fcc34Sopenharmony_cistatic void show_control_id(snd_ctl_elem_id_t *id)
436c72fcc34Sopenharmony_ci{
437c72fcc34Sopenharmony_ci	char *str;
438c72fcc34Sopenharmony_ci
439c72fcc34Sopenharmony_ci	str = snd_ctl_ascii_elem_id_get(id);
440c72fcc34Sopenharmony_ci	if (str)
441c72fcc34Sopenharmony_ci		printf("%s", str);
442c72fcc34Sopenharmony_ci	free(str);
443c72fcc34Sopenharmony_ci}
444c72fcc34Sopenharmony_ci
445c72fcc34Sopenharmony_cistatic void print_spaces(unsigned int spaces)
446c72fcc34Sopenharmony_ci{
447c72fcc34Sopenharmony_ci	while (spaces-- > 0)
448c72fcc34Sopenharmony_ci		putc(' ', stdout);
449c72fcc34Sopenharmony_ci}
450c72fcc34Sopenharmony_ci
451c72fcc34Sopenharmony_cistatic void print_dB(long dB)
452c72fcc34Sopenharmony_ci{
453c72fcc34Sopenharmony_ci	if (dB < 0) {
454c72fcc34Sopenharmony_ci		printf("-%li.%02lidB", -dB / 100, -dB % 100);
455c72fcc34Sopenharmony_ci	} else {
456c72fcc34Sopenharmony_ci		printf("%li.%02lidB", dB / 100, dB % 100);
457c72fcc34Sopenharmony_ci	}
458c72fcc34Sopenharmony_ci}
459c72fcc34Sopenharmony_ci
460c72fcc34Sopenharmony_cistatic void decode_tlv(unsigned int spaces, unsigned int *tlv, unsigned int tlv_size)
461c72fcc34Sopenharmony_ci{
462c72fcc34Sopenharmony_ci	unsigned int type = tlv[0];
463c72fcc34Sopenharmony_ci	unsigned int size;
464c72fcc34Sopenharmony_ci	unsigned int idx = 0;
465c72fcc34Sopenharmony_ci	const char *chmap_type = NULL;
466c72fcc34Sopenharmony_ci	int lf = 1;
467c72fcc34Sopenharmony_ci
468c72fcc34Sopenharmony_ci	if (tlv_size < 2 * sizeof(unsigned int)) {
469c72fcc34Sopenharmony_ci		printf("TLV size error!\n");
470c72fcc34Sopenharmony_ci		return;
471c72fcc34Sopenharmony_ci	}
472c72fcc34Sopenharmony_ci	print_spaces(spaces);
473c72fcc34Sopenharmony_ci	printf("| ");
474c72fcc34Sopenharmony_ci	type = tlv[idx++];
475c72fcc34Sopenharmony_ci	size = tlv[idx++];
476c72fcc34Sopenharmony_ci	tlv_size -= 2 * sizeof(unsigned int);
477c72fcc34Sopenharmony_ci	if (size > tlv_size) {
478c72fcc34Sopenharmony_ci		printf("TLV size error (%u, %u, %u)!\n", type, size, tlv_size);
479c72fcc34Sopenharmony_ci		return;
480c72fcc34Sopenharmony_ci	}
481c72fcc34Sopenharmony_ci	switch (type) {
482c72fcc34Sopenharmony_ci	case SND_CTL_TLVT_CONTAINER:
483c72fcc34Sopenharmony_ci		printf("container\n");
484c72fcc34Sopenharmony_ci		size += sizeof(unsigned int) -1;
485c72fcc34Sopenharmony_ci		size /= sizeof(unsigned int);
486c72fcc34Sopenharmony_ci		while (idx < size) {
487c72fcc34Sopenharmony_ci			if (tlv[idx+1] > (size - idx) * sizeof(unsigned int)) {
488c72fcc34Sopenharmony_ci				printf("TLV size error in compound!\n");
489c72fcc34Sopenharmony_ci				return;
490c72fcc34Sopenharmony_ci			}
491c72fcc34Sopenharmony_ci			decode_tlv(spaces + 2, tlv + idx, tlv[idx+1] + 8);
492c72fcc34Sopenharmony_ci			idx += 2 + (tlv[idx+1] + sizeof(unsigned int) - 1) / sizeof(unsigned int);
493c72fcc34Sopenharmony_ci		}
494c72fcc34Sopenharmony_ci		lf = 0;
495c72fcc34Sopenharmony_ci		break;
496c72fcc34Sopenharmony_ci	case SND_CTL_TLVT_DB_SCALE:
497c72fcc34Sopenharmony_ci		printf("dBscale-");
498c72fcc34Sopenharmony_ci		if (size != 2 * sizeof(unsigned int)) {
499c72fcc34Sopenharmony_ci			while (size > 0) {
500c72fcc34Sopenharmony_ci				printf("0x%08x,", tlv[idx++]);
501c72fcc34Sopenharmony_ci				size -= sizeof(unsigned int);
502c72fcc34Sopenharmony_ci			}
503c72fcc34Sopenharmony_ci		} else {
504c72fcc34Sopenharmony_ci			printf("min=");
505c72fcc34Sopenharmony_ci			print_dB((int)tlv[2]);
506c72fcc34Sopenharmony_ci			printf(",step=");
507c72fcc34Sopenharmony_ci			print_dB(tlv[3] & 0xffff);
508c72fcc34Sopenharmony_ci			printf(",mute=%i", (tlv[3] >> 16) & 1);
509c72fcc34Sopenharmony_ci		}
510c72fcc34Sopenharmony_ci		break;
511c72fcc34Sopenharmony_ci#ifdef SND_CTL_TLVT_DB_LINEAR
512c72fcc34Sopenharmony_ci	case SND_CTL_TLVT_DB_LINEAR:
513c72fcc34Sopenharmony_ci		printf("dBlinear-");
514c72fcc34Sopenharmony_ci		if (size != 2 * sizeof(unsigned int)) {
515c72fcc34Sopenharmony_ci			while (size > 0) {
516c72fcc34Sopenharmony_ci				printf("0x%08x,", tlv[idx++]);
517c72fcc34Sopenharmony_ci				size -= sizeof(unsigned int);
518c72fcc34Sopenharmony_ci			}
519c72fcc34Sopenharmony_ci		} else {
520c72fcc34Sopenharmony_ci			printf("min=");
521c72fcc34Sopenharmony_ci			print_dB((int)tlv[2]);
522c72fcc34Sopenharmony_ci			printf(",max=");
523c72fcc34Sopenharmony_ci			print_dB((int)tlv[3]);
524c72fcc34Sopenharmony_ci		}
525c72fcc34Sopenharmony_ci		break;
526c72fcc34Sopenharmony_ci#endif
527c72fcc34Sopenharmony_ci#ifdef SND_CTL_TLVT_DB_RANGE
528c72fcc34Sopenharmony_ci	case SND_CTL_TLVT_DB_RANGE:
529c72fcc34Sopenharmony_ci		printf("dBrange-\n");
530c72fcc34Sopenharmony_ci		if ((size % (6 * sizeof(unsigned int))) != 0) {
531c72fcc34Sopenharmony_ci			while (size > 0) {
532c72fcc34Sopenharmony_ci				printf("0x%08x,", tlv[idx++]);
533c72fcc34Sopenharmony_ci				size -= sizeof(unsigned int);
534c72fcc34Sopenharmony_ci			}
535c72fcc34Sopenharmony_ci			break;
536c72fcc34Sopenharmony_ci		}
537c72fcc34Sopenharmony_ci		while (size > 0) {
538c72fcc34Sopenharmony_ci			print_spaces(spaces + 2);
539c72fcc34Sopenharmony_ci			printf("rangemin=%i,", tlv[idx++]);
540c72fcc34Sopenharmony_ci			printf(",rangemax=%i\n", tlv[idx++]);
541c72fcc34Sopenharmony_ci			decode_tlv(spaces + 4, tlv + idx, 4 * sizeof(unsigned int));
542c72fcc34Sopenharmony_ci			idx += 4;
543c72fcc34Sopenharmony_ci			size -= 6 * sizeof(unsigned int);
544c72fcc34Sopenharmony_ci		}
545c72fcc34Sopenharmony_ci		break;
546c72fcc34Sopenharmony_ci#endif
547c72fcc34Sopenharmony_ci#ifdef SND_CTL_TLVT_DB_MINMAX
548c72fcc34Sopenharmony_ci	case SND_CTL_TLVT_DB_MINMAX:
549c72fcc34Sopenharmony_ci	case SND_CTL_TLVT_DB_MINMAX_MUTE:
550c72fcc34Sopenharmony_ci		if (type == SND_CTL_TLVT_DB_MINMAX_MUTE)
551c72fcc34Sopenharmony_ci			printf("dBminmaxmute-");
552c72fcc34Sopenharmony_ci		else
553c72fcc34Sopenharmony_ci			printf("dBminmax-");
554c72fcc34Sopenharmony_ci		if (size != 2 * sizeof(unsigned int)) {
555c72fcc34Sopenharmony_ci			while (size > 0) {
556c72fcc34Sopenharmony_ci				printf("0x%08x,", tlv[idx++]);
557c72fcc34Sopenharmony_ci				size -= sizeof(unsigned int);
558c72fcc34Sopenharmony_ci			}
559c72fcc34Sopenharmony_ci		} else {
560c72fcc34Sopenharmony_ci			printf("min=");
561c72fcc34Sopenharmony_ci			print_dB((int)tlv[2]);
562c72fcc34Sopenharmony_ci			printf(",max=");
563c72fcc34Sopenharmony_ci			print_dB((int)tlv[3]);
564c72fcc34Sopenharmony_ci		}
565c72fcc34Sopenharmony_ci		break;
566c72fcc34Sopenharmony_ci#endif
567c72fcc34Sopenharmony_ci#ifdef SND_CTL_TLVT_CHMAP_FIXED
568c72fcc34Sopenharmony_ci	case SND_CTL_TLVT_CHMAP_FIXED:
569c72fcc34Sopenharmony_ci		chmap_type = "fixed";
570c72fcc34Sopenharmony_ci		/* Fall through */
571c72fcc34Sopenharmony_ci	case SND_CTL_TLVT_CHMAP_VAR:
572c72fcc34Sopenharmony_ci		if (!chmap_type)
573c72fcc34Sopenharmony_ci			chmap_type = "variable";
574c72fcc34Sopenharmony_ci		/* Fall through */
575c72fcc34Sopenharmony_ci	case SND_CTL_TLVT_CHMAP_PAIRED:
576c72fcc34Sopenharmony_ci		if (!chmap_type)
577c72fcc34Sopenharmony_ci			chmap_type = "paired";
578c72fcc34Sopenharmony_ci		printf("chmap-%s=", chmap_type);
579c72fcc34Sopenharmony_ci
580c72fcc34Sopenharmony_ci		while (size > 0) {
581c72fcc34Sopenharmony_ci			printf("%s", snd_pcm_chmap_name(tlv[idx++]));
582c72fcc34Sopenharmony_ci			size -= sizeof(unsigned int);
583c72fcc34Sopenharmony_ci			if (size > 0)
584c72fcc34Sopenharmony_ci				printf(",");
585c72fcc34Sopenharmony_ci		}
586c72fcc34Sopenharmony_ci		break;
587c72fcc34Sopenharmony_ci#endif
588c72fcc34Sopenharmony_ci	default:
589c72fcc34Sopenharmony_ci		printf("unk-%u-", type);
590c72fcc34Sopenharmony_ci		while (size > 0) {
591c72fcc34Sopenharmony_ci			printf("0x%08x,", tlv[idx++]);
592c72fcc34Sopenharmony_ci			size -= sizeof(unsigned int);
593c72fcc34Sopenharmony_ci		}
594c72fcc34Sopenharmony_ci		break;
595c72fcc34Sopenharmony_ci	}
596c72fcc34Sopenharmony_ci	if (lf)
597c72fcc34Sopenharmony_ci		putc('\n', stdout);
598c72fcc34Sopenharmony_ci}
599c72fcc34Sopenharmony_ci
600c72fcc34Sopenharmony_cistatic int show_control(const char *space, snd_hctl_elem_t *elem,
601c72fcc34Sopenharmony_ci			int level)
602c72fcc34Sopenharmony_ci{
603c72fcc34Sopenharmony_ci	int err;
604c72fcc34Sopenharmony_ci	unsigned int item, idx, count, *tlv;
605c72fcc34Sopenharmony_ci	snd_ctl_elem_type_t type;
606c72fcc34Sopenharmony_ci	snd_ctl_elem_id_t *id;
607c72fcc34Sopenharmony_ci	snd_ctl_elem_info_t *info;
608c72fcc34Sopenharmony_ci	snd_ctl_elem_value_t *control;
609c72fcc34Sopenharmony_ci	snd_aes_iec958_t iec958;
610c72fcc34Sopenharmony_ci	snd_ctl_elem_id_alloca(&id);
611c72fcc34Sopenharmony_ci	snd_ctl_elem_info_alloca(&info);
612c72fcc34Sopenharmony_ci	snd_ctl_elem_value_alloca(&control);
613c72fcc34Sopenharmony_ci	if ((err = snd_hctl_elem_info(elem, info)) < 0) {
614c72fcc34Sopenharmony_ci		error("Control %s snd_hctl_elem_info error: %s\n", card, snd_strerror(err));
615c72fcc34Sopenharmony_ci		return err;
616c72fcc34Sopenharmony_ci	}
617c72fcc34Sopenharmony_ci	if (level & LEVEL_ID) {
618c72fcc34Sopenharmony_ci		snd_hctl_elem_get_id(elem, id);
619c72fcc34Sopenharmony_ci		show_control_id(id);
620c72fcc34Sopenharmony_ci		printf("\n");
621c72fcc34Sopenharmony_ci	}
622c72fcc34Sopenharmony_ci	count = snd_ctl_elem_info_get_count(info);
623c72fcc34Sopenharmony_ci	type = snd_ctl_elem_info_get_type(info);
624c72fcc34Sopenharmony_ci	printf("%s; type=%s,access=%s,values=%u", space, control_type(info), control_access(info), count);
625c72fcc34Sopenharmony_ci	switch (type) {
626c72fcc34Sopenharmony_ci	case SND_CTL_ELEM_TYPE_INTEGER:
627c72fcc34Sopenharmony_ci		printf(",min=%li,max=%li,step=%li\n",
628c72fcc34Sopenharmony_ci		       snd_ctl_elem_info_get_min(info),
629c72fcc34Sopenharmony_ci		       snd_ctl_elem_info_get_max(info),
630c72fcc34Sopenharmony_ci		       snd_ctl_elem_info_get_step(info));
631c72fcc34Sopenharmony_ci		break;
632c72fcc34Sopenharmony_ci	case SND_CTL_ELEM_TYPE_INTEGER64:
633c72fcc34Sopenharmony_ci		printf(",min=%lli,max=%lli,step=%lli\n",
634c72fcc34Sopenharmony_ci		       snd_ctl_elem_info_get_min64(info),
635c72fcc34Sopenharmony_ci		       snd_ctl_elem_info_get_max64(info),
636c72fcc34Sopenharmony_ci		       snd_ctl_elem_info_get_step64(info));
637c72fcc34Sopenharmony_ci		break;
638c72fcc34Sopenharmony_ci	case SND_CTL_ELEM_TYPE_ENUMERATED:
639c72fcc34Sopenharmony_ci	{
640c72fcc34Sopenharmony_ci		unsigned int items = snd_ctl_elem_info_get_items(info);
641c72fcc34Sopenharmony_ci		printf(",items=%u\n", items);
642c72fcc34Sopenharmony_ci		for (item = 0; item < items; item++) {
643c72fcc34Sopenharmony_ci			snd_ctl_elem_info_set_item(info, item);
644c72fcc34Sopenharmony_ci			if ((err = snd_hctl_elem_info(elem, info)) < 0) {
645c72fcc34Sopenharmony_ci				error("Control %s element info error: %s\n", card, snd_strerror(err));
646c72fcc34Sopenharmony_ci				return err;
647c72fcc34Sopenharmony_ci			}
648c72fcc34Sopenharmony_ci			printf("%s; Item #%u '%s'\n", space, item, snd_ctl_elem_info_get_item_name(info));
649c72fcc34Sopenharmony_ci		}
650c72fcc34Sopenharmony_ci		break;
651c72fcc34Sopenharmony_ci	}
652c72fcc34Sopenharmony_ci	default:
653c72fcc34Sopenharmony_ci		printf("\n");
654c72fcc34Sopenharmony_ci		break;
655c72fcc34Sopenharmony_ci	}
656c72fcc34Sopenharmony_ci	if (level & LEVEL_BASIC) {
657c72fcc34Sopenharmony_ci		if (!snd_ctl_elem_info_is_readable(info))
658c72fcc34Sopenharmony_ci			goto __skip_read;
659c72fcc34Sopenharmony_ci		if ((err = snd_hctl_elem_read(elem, control)) < 0) {
660c72fcc34Sopenharmony_ci			error("Control %s element read error: %s\n", card, snd_strerror(err));
661c72fcc34Sopenharmony_ci			return err;
662c72fcc34Sopenharmony_ci		}
663c72fcc34Sopenharmony_ci		printf("%s: values=", space);
664c72fcc34Sopenharmony_ci		for (idx = 0; idx < count; idx++) {
665c72fcc34Sopenharmony_ci			if (idx > 0)
666c72fcc34Sopenharmony_ci				printf(",");
667c72fcc34Sopenharmony_ci			switch (type) {
668c72fcc34Sopenharmony_ci			case SND_CTL_ELEM_TYPE_BOOLEAN:
669c72fcc34Sopenharmony_ci				printf("%s", snd_ctl_elem_value_get_boolean(control, idx) ? "on" : "off");
670c72fcc34Sopenharmony_ci				break;
671c72fcc34Sopenharmony_ci			case SND_CTL_ELEM_TYPE_INTEGER:
672c72fcc34Sopenharmony_ci				printf("%li", snd_ctl_elem_value_get_integer(control, idx));
673c72fcc34Sopenharmony_ci				break;
674c72fcc34Sopenharmony_ci			case SND_CTL_ELEM_TYPE_INTEGER64:
675c72fcc34Sopenharmony_ci				printf("%lli", snd_ctl_elem_value_get_integer64(control, idx));
676c72fcc34Sopenharmony_ci				break;
677c72fcc34Sopenharmony_ci			case SND_CTL_ELEM_TYPE_ENUMERATED:
678c72fcc34Sopenharmony_ci				printf("%u", snd_ctl_elem_value_get_enumerated(control, idx));
679c72fcc34Sopenharmony_ci				break;
680c72fcc34Sopenharmony_ci			case SND_CTL_ELEM_TYPE_BYTES:
681c72fcc34Sopenharmony_ci				printf("0x%02x", snd_ctl_elem_value_get_byte(control, idx));
682c72fcc34Sopenharmony_ci				break;
683c72fcc34Sopenharmony_ci			case SND_CTL_ELEM_TYPE_IEC958:
684c72fcc34Sopenharmony_ci				snd_ctl_elem_value_get_iec958(control, &iec958);
685c72fcc34Sopenharmony_ci				printf("[AES0=0x%02x AES1=0x%02x AES2=0x%02x AES3=0x%02x]",
686c72fcc34Sopenharmony_ci				       iec958.status[0], iec958.status[1],
687c72fcc34Sopenharmony_ci				       iec958.status[2], iec958.status[3]);
688c72fcc34Sopenharmony_ci				break;
689c72fcc34Sopenharmony_ci			default:
690c72fcc34Sopenharmony_ci				printf("?");
691c72fcc34Sopenharmony_ci				break;
692c72fcc34Sopenharmony_ci			}
693c72fcc34Sopenharmony_ci		}
694c72fcc34Sopenharmony_ci		printf("\n");
695c72fcc34Sopenharmony_ci	      __skip_read:
696c72fcc34Sopenharmony_ci		if (!snd_ctl_elem_info_is_tlv_readable(info))
697c72fcc34Sopenharmony_ci			goto __skip_tlv;
698c72fcc34Sopenharmony_ci		/* skip ASoC ext bytes controls that may have huge binary TLV data */
699c72fcc34Sopenharmony_ci		if (type == SND_CTL_ELEM_TYPE_BYTES &&
700c72fcc34Sopenharmony_ci				!snd_ctl_elem_info_is_readable(info) &&
701c72fcc34Sopenharmony_ci				!snd_ctl_elem_info_is_writable(info)) {
702c72fcc34Sopenharmony_ci			printf("%s; ASoC TLV Byte control, skipping bytes dump\n", space);
703c72fcc34Sopenharmony_ci			goto __skip_tlv;
704c72fcc34Sopenharmony_ci		}
705c72fcc34Sopenharmony_ci
706c72fcc34Sopenharmony_ci		tlv = malloc(4096);
707c72fcc34Sopenharmony_ci		if ((err = snd_hctl_elem_tlv_read(elem, tlv, 4096)) < 0) {
708c72fcc34Sopenharmony_ci			error("Control %s element TLV read error: %s\n", card, snd_strerror(err));
709c72fcc34Sopenharmony_ci			free(tlv);
710c72fcc34Sopenharmony_ci			return err;
711c72fcc34Sopenharmony_ci		}
712c72fcc34Sopenharmony_ci		decode_tlv(strlen(space), tlv, 4096);
713c72fcc34Sopenharmony_ci		free(tlv);
714c72fcc34Sopenharmony_ci	}
715c72fcc34Sopenharmony_ci      __skip_tlv:
716c72fcc34Sopenharmony_ci	return 0;
717c72fcc34Sopenharmony_ci}
718c72fcc34Sopenharmony_ci
719c72fcc34Sopenharmony_cistatic int controls(int level)
720c72fcc34Sopenharmony_ci{
721c72fcc34Sopenharmony_ci	int err;
722c72fcc34Sopenharmony_ci	snd_hctl_t *handle;
723c72fcc34Sopenharmony_ci	snd_hctl_elem_t *elem;
724c72fcc34Sopenharmony_ci	snd_ctl_elem_id_t *id;
725c72fcc34Sopenharmony_ci	snd_ctl_elem_info_t *info;
726c72fcc34Sopenharmony_ci	snd_ctl_elem_id_alloca(&id);
727c72fcc34Sopenharmony_ci	snd_ctl_elem_info_alloca(&info);
728c72fcc34Sopenharmony_ci
729c72fcc34Sopenharmony_ci	if ((err = snd_hctl_open(&handle, card, 0)) < 0) {
730c72fcc34Sopenharmony_ci		error("Control %s open error: %s", card, snd_strerror(err));
731c72fcc34Sopenharmony_ci		return err;
732c72fcc34Sopenharmony_ci	}
733c72fcc34Sopenharmony_ci	if ((err = snd_hctl_load(handle)) < 0) {
734c72fcc34Sopenharmony_ci		error("Control %s local error: %s\n", card, snd_strerror(err));
735c72fcc34Sopenharmony_ci		return err;
736c72fcc34Sopenharmony_ci	}
737c72fcc34Sopenharmony_ci	for (elem = snd_hctl_first_elem(handle); elem; elem = snd_hctl_elem_next(elem)) {
738c72fcc34Sopenharmony_ci		if ((err = snd_hctl_elem_info(elem, info)) < 0) {
739c72fcc34Sopenharmony_ci			error("Control %s snd_hctl_elem_info error: %s\n", card, snd_strerror(err));
740c72fcc34Sopenharmony_ci			return err;
741c72fcc34Sopenharmony_ci		}
742c72fcc34Sopenharmony_ci		if (!(level & LEVEL_INACTIVE) && snd_ctl_elem_info_is_inactive(info))
743c72fcc34Sopenharmony_ci			continue;
744c72fcc34Sopenharmony_ci		snd_hctl_elem_get_id(elem, id);
745c72fcc34Sopenharmony_ci		show_control_id(id);
746c72fcc34Sopenharmony_ci		printf("\n");
747c72fcc34Sopenharmony_ci		if (level & LEVEL_BASIC)
748c72fcc34Sopenharmony_ci			show_control("  ", elem, 1);
749c72fcc34Sopenharmony_ci	}
750c72fcc34Sopenharmony_ci	snd_hctl_close(handle);
751c72fcc34Sopenharmony_ci	return 0;
752c72fcc34Sopenharmony_ci}
753c72fcc34Sopenharmony_ci
754c72fcc34Sopenharmony_cistatic void show_selem_volume(snd_mixer_elem_t *elem,
755c72fcc34Sopenharmony_ci			      snd_mixer_selem_channel_id_t chn, int dir,
756c72fcc34Sopenharmony_ci			      long min, long max)
757c72fcc34Sopenharmony_ci{
758c72fcc34Sopenharmony_ci	long raw, val;
759c72fcc34Sopenharmony_ci	vol_ops[dir].v[VOL_RAW].get(elem, chn, &raw);
760c72fcc34Sopenharmony_ci	if (std_vol_type == VOL_RAW)
761c72fcc34Sopenharmony_ci		val = convert_prange(raw, min, max);
762c72fcc34Sopenharmony_ci	else {
763c72fcc34Sopenharmony_ci		vol_ops[dir].v[std_vol_type].get(elem, chn, &val);
764c72fcc34Sopenharmony_ci		val = convert_prange(val, 0, MAP_VOL_RES);
765c72fcc34Sopenharmony_ci	}
766c72fcc34Sopenharmony_ci	printf(" %li [%li%%]", raw, val);
767c72fcc34Sopenharmony_ci	if (!vol_ops[dir].v[VOL_DB].get(elem, chn, &val)) {
768c72fcc34Sopenharmony_ci		printf(" [");
769c72fcc34Sopenharmony_ci		print_dB(val);
770c72fcc34Sopenharmony_ci		printf("]");
771c72fcc34Sopenharmony_ci	}
772c72fcc34Sopenharmony_ci}
773c72fcc34Sopenharmony_ci
774c72fcc34Sopenharmony_cistatic int show_selem(snd_mixer_t *handle, snd_mixer_selem_id_t *id, const char *space, int level)
775c72fcc34Sopenharmony_ci{
776c72fcc34Sopenharmony_ci	snd_mixer_selem_channel_id_t chn;
777c72fcc34Sopenharmony_ci	long pmin = 0, pmax = 0;
778c72fcc34Sopenharmony_ci	long cmin = 0, cmax = 0;
779c72fcc34Sopenharmony_ci	int psw, csw;
780c72fcc34Sopenharmony_ci	int pmono, cmono, mono_ok = 0;
781c72fcc34Sopenharmony_ci	snd_mixer_elem_t *elem;
782c72fcc34Sopenharmony_ci
783c72fcc34Sopenharmony_ci	elem = snd_mixer_find_selem(handle, id);
784c72fcc34Sopenharmony_ci	if (!elem) {
785c72fcc34Sopenharmony_ci		error("Mixer %s simple element not found", card);
786c72fcc34Sopenharmony_ci		return -ENOENT;
787c72fcc34Sopenharmony_ci	}
788c72fcc34Sopenharmony_ci
789c72fcc34Sopenharmony_ci	if (level & LEVEL_BASIC) {
790c72fcc34Sopenharmony_ci		printf("%sCapabilities:", space);
791c72fcc34Sopenharmony_ci		if (snd_mixer_selem_has_common_volume(elem)) {
792c72fcc34Sopenharmony_ci			printf(" volume");
793c72fcc34Sopenharmony_ci			if (snd_mixer_selem_has_playback_volume_joined(elem))
794c72fcc34Sopenharmony_ci				printf(" volume-joined");
795c72fcc34Sopenharmony_ci		} else {
796c72fcc34Sopenharmony_ci			if (snd_mixer_selem_has_playback_volume(elem)) {
797c72fcc34Sopenharmony_ci				printf(" pvolume");
798c72fcc34Sopenharmony_ci				if (snd_mixer_selem_has_playback_volume_joined(elem))
799c72fcc34Sopenharmony_ci					printf(" pvolume-joined");
800c72fcc34Sopenharmony_ci			}
801c72fcc34Sopenharmony_ci			if (snd_mixer_selem_has_capture_volume(elem)) {
802c72fcc34Sopenharmony_ci				printf(" cvolume");
803c72fcc34Sopenharmony_ci				if (snd_mixer_selem_has_capture_volume_joined(elem))
804c72fcc34Sopenharmony_ci					printf(" cvolume-joined");
805c72fcc34Sopenharmony_ci			}
806c72fcc34Sopenharmony_ci		}
807c72fcc34Sopenharmony_ci		if (snd_mixer_selem_has_common_switch(elem)) {
808c72fcc34Sopenharmony_ci			printf(" switch");
809c72fcc34Sopenharmony_ci			if (snd_mixer_selem_has_playback_switch_joined(elem))
810c72fcc34Sopenharmony_ci				printf(" switch-joined");
811c72fcc34Sopenharmony_ci		} else {
812c72fcc34Sopenharmony_ci			if (snd_mixer_selem_has_playback_switch(elem)) {
813c72fcc34Sopenharmony_ci				printf(" pswitch");
814c72fcc34Sopenharmony_ci				if (snd_mixer_selem_has_playback_switch_joined(elem))
815c72fcc34Sopenharmony_ci					printf(" pswitch-joined");
816c72fcc34Sopenharmony_ci			}
817c72fcc34Sopenharmony_ci			if (snd_mixer_selem_has_capture_switch(elem)) {
818c72fcc34Sopenharmony_ci				printf(" cswitch");
819c72fcc34Sopenharmony_ci				if (snd_mixer_selem_has_capture_switch_joined(elem))
820c72fcc34Sopenharmony_ci					printf(" cswitch-joined");
821c72fcc34Sopenharmony_ci				if (snd_mixer_selem_has_capture_switch_exclusive(elem))
822c72fcc34Sopenharmony_ci					printf(" cswitch-exclusive");
823c72fcc34Sopenharmony_ci			}
824c72fcc34Sopenharmony_ci		}
825c72fcc34Sopenharmony_ci		if (snd_mixer_selem_is_enum_playback(elem)) {
826c72fcc34Sopenharmony_ci			printf(" penum");
827c72fcc34Sopenharmony_ci		} else if (snd_mixer_selem_is_enum_capture(elem)) {
828c72fcc34Sopenharmony_ci			printf(" cenum");
829c72fcc34Sopenharmony_ci		} else if (snd_mixer_selem_is_enumerated(elem)) {
830c72fcc34Sopenharmony_ci			printf(" enum");
831c72fcc34Sopenharmony_ci		}
832c72fcc34Sopenharmony_ci		printf("\n");
833c72fcc34Sopenharmony_ci		if (snd_mixer_selem_is_enumerated(elem)) {
834c72fcc34Sopenharmony_ci			int i, items;
835c72fcc34Sopenharmony_ci			unsigned int idx;
836c72fcc34Sopenharmony_ci			/*
837c72fcc34Sopenharmony_ci			 * See snd_ctl_elem_init_enum_names() in
838c72fcc34Sopenharmony_ci			 * sound/core/control.c.
839c72fcc34Sopenharmony_ci			 */
840c72fcc34Sopenharmony_ci			char itemname[64];
841c72fcc34Sopenharmony_ci			items = snd_mixer_selem_get_enum_items(elem);
842c72fcc34Sopenharmony_ci			printf("  Items:");
843c72fcc34Sopenharmony_ci			for (i = 0; i < items; i++) {
844c72fcc34Sopenharmony_ci				snd_mixer_selem_get_enum_item_name(elem, i, sizeof(itemname) - 1, itemname);
845c72fcc34Sopenharmony_ci				printf(" '%s'", itemname);
846c72fcc34Sopenharmony_ci			}
847c72fcc34Sopenharmony_ci			printf("\n");
848c72fcc34Sopenharmony_ci			for (i = 0; !snd_mixer_selem_get_enum_item(elem, i, &idx); i++) {
849c72fcc34Sopenharmony_ci				snd_mixer_selem_get_enum_item_name(elem, idx, sizeof(itemname) - 1, itemname);
850c72fcc34Sopenharmony_ci				printf("  Item%d: '%s'\n", i, itemname);
851c72fcc34Sopenharmony_ci			}
852c72fcc34Sopenharmony_ci			return 0; /* no more thing to do */
853c72fcc34Sopenharmony_ci		}
854c72fcc34Sopenharmony_ci		if (snd_mixer_selem_has_capture_switch_exclusive(elem))
855c72fcc34Sopenharmony_ci			printf("%sCapture exclusive group: %i\n", space,
856c72fcc34Sopenharmony_ci			       snd_mixer_selem_get_capture_group(elem));
857c72fcc34Sopenharmony_ci		if (snd_mixer_selem_has_playback_volume(elem) ||
858c72fcc34Sopenharmony_ci		    snd_mixer_selem_has_playback_switch(elem)) {
859c72fcc34Sopenharmony_ci			printf("%sPlayback channels:", space);
860c72fcc34Sopenharmony_ci			if (snd_mixer_selem_is_playback_mono(elem)) {
861c72fcc34Sopenharmony_ci				printf(" Mono");
862c72fcc34Sopenharmony_ci			} else {
863c72fcc34Sopenharmony_ci				int first = 1;
864c72fcc34Sopenharmony_ci				for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++){
865c72fcc34Sopenharmony_ci					if (!snd_mixer_selem_has_playback_channel(elem, chn))
866c72fcc34Sopenharmony_ci						continue;
867c72fcc34Sopenharmony_ci					if (!first)
868c72fcc34Sopenharmony_ci						printf(" -");
869c72fcc34Sopenharmony_ci					printf(" %s", snd_mixer_selem_channel_name(chn));
870c72fcc34Sopenharmony_ci					first = 0;
871c72fcc34Sopenharmony_ci				}
872c72fcc34Sopenharmony_ci			}
873c72fcc34Sopenharmony_ci			printf("\n");
874c72fcc34Sopenharmony_ci		}
875c72fcc34Sopenharmony_ci		if (snd_mixer_selem_has_capture_volume(elem) ||
876c72fcc34Sopenharmony_ci		    snd_mixer_selem_has_capture_switch(elem)) {
877c72fcc34Sopenharmony_ci			printf("%sCapture channels:", space);
878c72fcc34Sopenharmony_ci			if (snd_mixer_selem_is_capture_mono(elem)) {
879c72fcc34Sopenharmony_ci				printf(" Mono");
880c72fcc34Sopenharmony_ci			} else {
881c72fcc34Sopenharmony_ci				int first = 1;
882c72fcc34Sopenharmony_ci				for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++){
883c72fcc34Sopenharmony_ci					if (!snd_mixer_selem_has_capture_channel(elem, chn))
884c72fcc34Sopenharmony_ci						continue;
885c72fcc34Sopenharmony_ci					if (!first)
886c72fcc34Sopenharmony_ci						printf(" -");
887c72fcc34Sopenharmony_ci					printf(" %s", snd_mixer_selem_channel_name(chn));
888c72fcc34Sopenharmony_ci					first = 0;
889c72fcc34Sopenharmony_ci				}
890c72fcc34Sopenharmony_ci			}
891c72fcc34Sopenharmony_ci			printf("\n");
892c72fcc34Sopenharmony_ci		}
893c72fcc34Sopenharmony_ci		if (snd_mixer_selem_has_playback_volume(elem) ||
894c72fcc34Sopenharmony_ci		    snd_mixer_selem_has_capture_volume(elem)) {
895c72fcc34Sopenharmony_ci			printf("%sLimits:", space);
896c72fcc34Sopenharmony_ci			if (snd_mixer_selem_has_common_volume(elem)) {
897c72fcc34Sopenharmony_ci				snd_mixer_selem_get_playback_volume_range(elem, &pmin, &pmax);
898c72fcc34Sopenharmony_ci				snd_mixer_selem_get_capture_volume_range(elem, &cmin, &cmax);
899c72fcc34Sopenharmony_ci				printf(" %li - %li", pmin, pmax);
900c72fcc34Sopenharmony_ci			} else {
901c72fcc34Sopenharmony_ci				if (snd_mixer_selem_has_playback_volume(elem)) {
902c72fcc34Sopenharmony_ci					snd_mixer_selem_get_playback_volume_range(elem, &pmin, &pmax);
903c72fcc34Sopenharmony_ci					printf(" Playback %li - %li", pmin, pmax);
904c72fcc34Sopenharmony_ci				}
905c72fcc34Sopenharmony_ci				if (snd_mixer_selem_has_capture_volume(elem)) {
906c72fcc34Sopenharmony_ci					snd_mixer_selem_get_capture_volume_range(elem, &cmin, &cmax);
907c72fcc34Sopenharmony_ci					printf(" Capture %li - %li", cmin, cmax);
908c72fcc34Sopenharmony_ci				}
909c72fcc34Sopenharmony_ci			}
910c72fcc34Sopenharmony_ci			printf("\n");
911c72fcc34Sopenharmony_ci		}
912c72fcc34Sopenharmony_ci		pmono = snd_mixer_selem_has_playback_channel(elem, SND_MIXER_SCHN_MONO) &&
913c72fcc34Sopenharmony_ci		        (snd_mixer_selem_is_playback_mono(elem) ||
914c72fcc34Sopenharmony_ci			 (!snd_mixer_selem_has_playback_volume(elem) &&
915c72fcc34Sopenharmony_ci			  !snd_mixer_selem_has_playback_switch(elem)));
916c72fcc34Sopenharmony_ci		cmono = snd_mixer_selem_has_capture_channel(elem, SND_MIXER_SCHN_MONO) &&
917c72fcc34Sopenharmony_ci		        (snd_mixer_selem_is_capture_mono(elem) ||
918c72fcc34Sopenharmony_ci			 (!snd_mixer_selem_has_capture_volume(elem) &&
919c72fcc34Sopenharmony_ci			  !snd_mixer_selem_has_capture_switch(elem)));
920c72fcc34Sopenharmony_ci#if 0
921c72fcc34Sopenharmony_ci		printf("pmono = %i, cmono = %i (%i, %i, %i, %i)\n", pmono, cmono,
922c72fcc34Sopenharmony_ci				snd_mixer_selem_has_capture_channel(elem, SND_MIXER_SCHN_MONO),
923c72fcc34Sopenharmony_ci				snd_mixer_selem_is_capture_mono(elem),
924c72fcc34Sopenharmony_ci				snd_mixer_selem_has_capture_volume(elem),
925c72fcc34Sopenharmony_ci				snd_mixer_selem_has_capture_switch(elem));
926c72fcc34Sopenharmony_ci#endif
927c72fcc34Sopenharmony_ci		if (pmono || cmono) {
928c72fcc34Sopenharmony_ci			if (!mono_ok) {
929c72fcc34Sopenharmony_ci				printf("%s%s:", space, "Mono");
930c72fcc34Sopenharmony_ci				mono_ok = 1;
931c72fcc34Sopenharmony_ci			}
932c72fcc34Sopenharmony_ci			if (snd_mixer_selem_has_common_volume(elem)) {
933c72fcc34Sopenharmony_ci				show_selem_volume(elem, SND_MIXER_SCHN_MONO, 0, pmin, pmax);
934c72fcc34Sopenharmony_ci			}
935c72fcc34Sopenharmony_ci			if (snd_mixer_selem_has_common_switch(elem)) {
936c72fcc34Sopenharmony_ci				snd_mixer_selem_get_playback_switch(elem, SND_MIXER_SCHN_MONO, &psw);
937c72fcc34Sopenharmony_ci				printf(" [%s]", psw ? "on" : "off");
938c72fcc34Sopenharmony_ci			}
939c72fcc34Sopenharmony_ci		}
940c72fcc34Sopenharmony_ci		if (pmono && snd_mixer_selem_has_playback_channel(elem, SND_MIXER_SCHN_MONO)) {
941c72fcc34Sopenharmony_ci			int title = 0;
942c72fcc34Sopenharmony_ci			if (!mono_ok) {
943c72fcc34Sopenharmony_ci				printf("%s%s:", space, "Mono");
944c72fcc34Sopenharmony_ci				mono_ok = 1;
945c72fcc34Sopenharmony_ci			}
946c72fcc34Sopenharmony_ci			if (!snd_mixer_selem_has_common_volume(elem)) {
947c72fcc34Sopenharmony_ci				if (snd_mixer_selem_has_playback_volume(elem)) {
948c72fcc34Sopenharmony_ci					printf(" Playback");
949c72fcc34Sopenharmony_ci					title = 1;
950c72fcc34Sopenharmony_ci					show_selem_volume(elem, SND_MIXER_SCHN_MONO, 0, pmin, pmax);
951c72fcc34Sopenharmony_ci				}
952c72fcc34Sopenharmony_ci			}
953c72fcc34Sopenharmony_ci			if (!snd_mixer_selem_has_common_switch(elem)) {
954c72fcc34Sopenharmony_ci				if (snd_mixer_selem_has_playback_switch(elem)) {
955c72fcc34Sopenharmony_ci					if (!title)
956c72fcc34Sopenharmony_ci						printf(" Playback");
957c72fcc34Sopenharmony_ci					snd_mixer_selem_get_playback_switch(elem, SND_MIXER_SCHN_MONO, &psw);
958c72fcc34Sopenharmony_ci					printf(" [%s]", psw ? "on" : "off");
959c72fcc34Sopenharmony_ci				}
960c72fcc34Sopenharmony_ci			}
961c72fcc34Sopenharmony_ci		}
962c72fcc34Sopenharmony_ci		if (cmono && snd_mixer_selem_has_capture_channel(elem, SND_MIXER_SCHN_MONO)) {
963c72fcc34Sopenharmony_ci			int title = 0;
964c72fcc34Sopenharmony_ci			if (!mono_ok) {
965c72fcc34Sopenharmony_ci				printf("%s%s:", space, "Mono");
966c72fcc34Sopenharmony_ci				mono_ok = 1;
967c72fcc34Sopenharmony_ci			}
968c72fcc34Sopenharmony_ci			if (!snd_mixer_selem_has_common_volume(elem)) {
969c72fcc34Sopenharmony_ci				if (snd_mixer_selem_has_capture_volume(elem)) {
970c72fcc34Sopenharmony_ci					printf(" Capture");
971c72fcc34Sopenharmony_ci					title = 1;
972c72fcc34Sopenharmony_ci					show_selem_volume(elem, SND_MIXER_SCHN_MONO, 1, cmin, cmax);
973c72fcc34Sopenharmony_ci				}
974c72fcc34Sopenharmony_ci			}
975c72fcc34Sopenharmony_ci			if (!snd_mixer_selem_has_common_switch(elem)) {
976c72fcc34Sopenharmony_ci				if (snd_mixer_selem_has_capture_switch(elem)) {
977c72fcc34Sopenharmony_ci					if (!title)
978c72fcc34Sopenharmony_ci						printf(" Capture");
979c72fcc34Sopenharmony_ci					snd_mixer_selem_get_capture_switch(elem, SND_MIXER_SCHN_MONO, &csw);
980c72fcc34Sopenharmony_ci					printf(" [%s]", csw ? "on" : "off");
981c72fcc34Sopenharmony_ci				}
982c72fcc34Sopenharmony_ci			}
983c72fcc34Sopenharmony_ci		}
984c72fcc34Sopenharmony_ci		if (pmono || cmono)
985c72fcc34Sopenharmony_ci			printf("\n");
986c72fcc34Sopenharmony_ci		if (!pmono || !cmono) {
987c72fcc34Sopenharmony_ci			for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) {
988c72fcc34Sopenharmony_ci				if ((pmono || !snd_mixer_selem_has_playback_channel(elem, chn)) &&
989c72fcc34Sopenharmony_ci				    (cmono || !snd_mixer_selem_has_capture_channel(elem, chn)))
990c72fcc34Sopenharmony_ci					continue;
991c72fcc34Sopenharmony_ci				printf("%s%s:", space, snd_mixer_selem_channel_name(chn));
992c72fcc34Sopenharmony_ci				if (!pmono && !cmono && snd_mixer_selem_has_common_volume(elem)) {
993c72fcc34Sopenharmony_ci					show_selem_volume(elem, chn, 0, pmin, pmax);
994c72fcc34Sopenharmony_ci				}
995c72fcc34Sopenharmony_ci				if (!pmono && !cmono && snd_mixer_selem_has_common_switch(elem)) {
996c72fcc34Sopenharmony_ci					snd_mixer_selem_get_playback_switch(elem, chn, &psw);
997c72fcc34Sopenharmony_ci					printf(" [%s]", psw ? "on" : "off");
998c72fcc34Sopenharmony_ci				}
999c72fcc34Sopenharmony_ci				if (!pmono && snd_mixer_selem_has_playback_channel(elem, chn)) {
1000c72fcc34Sopenharmony_ci					int title = 0;
1001c72fcc34Sopenharmony_ci					if (!snd_mixer_selem_has_common_volume(elem)) {
1002c72fcc34Sopenharmony_ci						if (snd_mixer_selem_has_playback_volume(elem)) {
1003c72fcc34Sopenharmony_ci							printf(" Playback");
1004c72fcc34Sopenharmony_ci							title = 1;
1005c72fcc34Sopenharmony_ci							show_selem_volume(elem, chn, 0, pmin, pmax);
1006c72fcc34Sopenharmony_ci						}
1007c72fcc34Sopenharmony_ci					}
1008c72fcc34Sopenharmony_ci					if (!snd_mixer_selem_has_common_switch(elem)) {
1009c72fcc34Sopenharmony_ci						if (snd_mixer_selem_has_playback_switch(elem)) {
1010c72fcc34Sopenharmony_ci							if (!title)
1011c72fcc34Sopenharmony_ci								printf(" Playback");
1012c72fcc34Sopenharmony_ci							snd_mixer_selem_get_playback_switch(elem, chn, &psw);
1013c72fcc34Sopenharmony_ci							printf(" [%s]", psw ? "on" : "off");
1014c72fcc34Sopenharmony_ci						}
1015c72fcc34Sopenharmony_ci					}
1016c72fcc34Sopenharmony_ci				}
1017c72fcc34Sopenharmony_ci				if (!cmono && snd_mixer_selem_has_capture_channel(elem, chn)) {
1018c72fcc34Sopenharmony_ci					int title = 0;
1019c72fcc34Sopenharmony_ci					if (!snd_mixer_selem_has_common_volume(elem)) {
1020c72fcc34Sopenharmony_ci						if (snd_mixer_selem_has_capture_volume(elem)) {
1021c72fcc34Sopenharmony_ci							printf(" Capture");
1022c72fcc34Sopenharmony_ci							title = 1;
1023c72fcc34Sopenharmony_ci							show_selem_volume(elem, chn, 1, cmin, cmax);
1024c72fcc34Sopenharmony_ci						}
1025c72fcc34Sopenharmony_ci					}
1026c72fcc34Sopenharmony_ci					if (!snd_mixer_selem_has_common_switch(elem)) {
1027c72fcc34Sopenharmony_ci						if (snd_mixer_selem_has_capture_switch(elem)) {
1028c72fcc34Sopenharmony_ci							if (!title)
1029c72fcc34Sopenharmony_ci								printf(" Capture");
1030c72fcc34Sopenharmony_ci							snd_mixer_selem_get_capture_switch(elem, chn, &csw);
1031c72fcc34Sopenharmony_ci							printf(" [%s]", csw ? "on" : "off");
1032c72fcc34Sopenharmony_ci						}
1033c72fcc34Sopenharmony_ci					}
1034c72fcc34Sopenharmony_ci				}
1035c72fcc34Sopenharmony_ci				printf("\n");
1036c72fcc34Sopenharmony_ci			}
1037c72fcc34Sopenharmony_ci		}
1038c72fcc34Sopenharmony_ci	}
1039c72fcc34Sopenharmony_ci	return 0;
1040c72fcc34Sopenharmony_ci}
1041c72fcc34Sopenharmony_ci
1042c72fcc34Sopenharmony_cistatic int selems(int level)
1043c72fcc34Sopenharmony_ci{
1044c72fcc34Sopenharmony_ci	int err;
1045c72fcc34Sopenharmony_ci	snd_mixer_t *handle;
1046c72fcc34Sopenharmony_ci	snd_mixer_selem_id_t *sid;
1047c72fcc34Sopenharmony_ci	snd_mixer_elem_t *elem;
1048c72fcc34Sopenharmony_ci	snd_mixer_selem_id_alloca(&sid);
1049c72fcc34Sopenharmony_ci
1050c72fcc34Sopenharmony_ci	if ((err = snd_mixer_open(&handle, 0)) < 0) {
1051c72fcc34Sopenharmony_ci		error("Mixer %s open error: %s", card, snd_strerror(err));
1052c72fcc34Sopenharmony_ci		return err;
1053c72fcc34Sopenharmony_ci	}
1054c72fcc34Sopenharmony_ci	if (smixer_level == 0 && (err = snd_mixer_attach(handle, card)) < 0) {
1055c72fcc34Sopenharmony_ci		error("Mixer attach %s error: %s", card, snd_strerror(err));
1056c72fcc34Sopenharmony_ci		snd_mixer_close(handle);
1057c72fcc34Sopenharmony_ci		return err;
1058c72fcc34Sopenharmony_ci	}
1059c72fcc34Sopenharmony_ci	if ((err = snd_mixer_selem_register(handle, smixer_level > 0 ? &smixer_options : NULL, NULL)) < 0) {
1060c72fcc34Sopenharmony_ci		error("Mixer register error: %s", snd_strerror(err));
1061c72fcc34Sopenharmony_ci		snd_mixer_close(handle);
1062c72fcc34Sopenharmony_ci		return err;
1063c72fcc34Sopenharmony_ci	}
1064c72fcc34Sopenharmony_ci	err = snd_mixer_load(handle);
1065c72fcc34Sopenharmony_ci	if (err < 0) {
1066c72fcc34Sopenharmony_ci		error("Mixer %s load error: %s", card, snd_strerror(err));
1067c72fcc34Sopenharmony_ci		snd_mixer_close(handle);
1068c72fcc34Sopenharmony_ci		return err;
1069c72fcc34Sopenharmony_ci	}
1070c72fcc34Sopenharmony_ci	for (elem = snd_mixer_first_elem(handle); elem; elem = snd_mixer_elem_next(elem)) {
1071c72fcc34Sopenharmony_ci		snd_mixer_selem_get_id(elem, sid);
1072c72fcc34Sopenharmony_ci		if (!(level & LEVEL_INACTIVE) && !snd_mixer_selem_is_active(elem))
1073c72fcc34Sopenharmony_ci			continue;
1074c72fcc34Sopenharmony_ci		printf("Simple mixer control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
1075c72fcc34Sopenharmony_ci		show_selem(handle, sid, "  ", level);
1076c72fcc34Sopenharmony_ci	}
1077c72fcc34Sopenharmony_ci	snd_mixer_close(handle);
1078c72fcc34Sopenharmony_ci	return 0;
1079c72fcc34Sopenharmony_ci}
1080c72fcc34Sopenharmony_ci
1081c72fcc34Sopenharmony_cistatic int parse_simple_id(const char *str, snd_mixer_selem_id_t *sid)
1082c72fcc34Sopenharmony_ci{
1083c72fcc34Sopenharmony_ci	int c, size;
1084c72fcc34Sopenharmony_ci	char buf[128];
1085c72fcc34Sopenharmony_ci	char *ptr = buf;
1086c72fcc34Sopenharmony_ci
1087c72fcc34Sopenharmony_ci	while (*str == ' ' || *str == '\t')
1088c72fcc34Sopenharmony_ci		str++;
1089c72fcc34Sopenharmony_ci	if (!(*str))
1090c72fcc34Sopenharmony_ci		return -EINVAL;
1091c72fcc34Sopenharmony_ci	size = 1;	/* for '\0' */
1092c72fcc34Sopenharmony_ci	if (*str != '"' && *str != '\'') {
1093c72fcc34Sopenharmony_ci		while (*str && *str != ',') {
1094c72fcc34Sopenharmony_ci			if (size < (int)sizeof(buf)) {
1095c72fcc34Sopenharmony_ci				*ptr++ = *str;
1096c72fcc34Sopenharmony_ci				size++;
1097c72fcc34Sopenharmony_ci			}
1098c72fcc34Sopenharmony_ci			str++;
1099c72fcc34Sopenharmony_ci		}
1100c72fcc34Sopenharmony_ci	} else {
1101c72fcc34Sopenharmony_ci		c = *str++;
1102c72fcc34Sopenharmony_ci		while (*str && *str != c) {
1103c72fcc34Sopenharmony_ci			if (size < (int)sizeof(buf)) {
1104c72fcc34Sopenharmony_ci				*ptr++ = *str;
1105c72fcc34Sopenharmony_ci				size++;
1106c72fcc34Sopenharmony_ci			}
1107c72fcc34Sopenharmony_ci			str++;
1108c72fcc34Sopenharmony_ci		}
1109c72fcc34Sopenharmony_ci		if (*str == c)
1110c72fcc34Sopenharmony_ci			str++;
1111c72fcc34Sopenharmony_ci	}
1112c72fcc34Sopenharmony_ci	if (*str == '\0') {
1113c72fcc34Sopenharmony_ci		snd_mixer_selem_id_set_index(sid, 0);
1114c72fcc34Sopenharmony_ci		*ptr = 0;
1115c72fcc34Sopenharmony_ci		goto _set;
1116c72fcc34Sopenharmony_ci	}
1117c72fcc34Sopenharmony_ci	if (*str != ',')
1118c72fcc34Sopenharmony_ci		return -EINVAL;
1119c72fcc34Sopenharmony_ci	*ptr = 0;	/* terminate the string */
1120c72fcc34Sopenharmony_ci	str++;
1121c72fcc34Sopenharmony_ci	if (!isdigit(*str))
1122c72fcc34Sopenharmony_ci		return -EINVAL;
1123c72fcc34Sopenharmony_ci	snd_mixer_selem_id_set_index(sid, atoi(str));
1124c72fcc34Sopenharmony_ci       _set:
1125c72fcc34Sopenharmony_ci	snd_mixer_selem_id_set_name(sid, buf);
1126c72fcc34Sopenharmony_ci	return 0;
1127c72fcc34Sopenharmony_ci}
1128c72fcc34Sopenharmony_ci
1129c72fcc34Sopenharmony_cistatic int cset(int argc, char *argv[], int roflag, int keep_handle)
1130c72fcc34Sopenharmony_ci{
1131c72fcc34Sopenharmony_ci	int err;
1132c72fcc34Sopenharmony_ci	static snd_ctl_t *handle = NULL;
1133c72fcc34Sopenharmony_ci	snd_ctl_elem_info_t *info;
1134c72fcc34Sopenharmony_ci	snd_ctl_elem_id_t *id;
1135c72fcc34Sopenharmony_ci	snd_ctl_elem_value_t *control;
1136c72fcc34Sopenharmony_ci	snd_ctl_elem_info_alloca(&info);
1137c72fcc34Sopenharmony_ci	snd_ctl_elem_id_alloca(&id);
1138c72fcc34Sopenharmony_ci	snd_ctl_elem_value_alloca(&control);
1139c72fcc34Sopenharmony_ci
1140c72fcc34Sopenharmony_ci	if (argc < 1) {
1141c72fcc34Sopenharmony_ci		fprintf(stderr, "Specify a full control identifier: [[iface=<iface>,][name='name',][index=<index>,][device=<device>,][subdevice=<subdevice>]]|[numid=<numid>]\n");
1142c72fcc34Sopenharmony_ci		return -EINVAL;
1143c72fcc34Sopenharmony_ci	}
1144c72fcc34Sopenharmony_ci	if (snd_ctl_ascii_elem_id_parse(id, argv[0])) {
1145c72fcc34Sopenharmony_ci		fprintf(stderr, "Wrong control identifier: %s\n", argv[0]);
1146c72fcc34Sopenharmony_ci		return -EINVAL;
1147c72fcc34Sopenharmony_ci	}
1148c72fcc34Sopenharmony_ci	if (debugflag) {
1149c72fcc34Sopenharmony_ci		printf("VERIFY ID: ");
1150c72fcc34Sopenharmony_ci		show_control_id(id);
1151c72fcc34Sopenharmony_ci		printf("\n");
1152c72fcc34Sopenharmony_ci	}
1153c72fcc34Sopenharmony_ci	if (handle == NULL &&
1154c72fcc34Sopenharmony_ci	    (err = snd_ctl_open(&handle, card, 0)) < 0) {
1155c72fcc34Sopenharmony_ci		error("Control %s open error: %s\n", card, snd_strerror(err));
1156c72fcc34Sopenharmony_ci		return err;
1157c72fcc34Sopenharmony_ci	}
1158c72fcc34Sopenharmony_ci	snd_ctl_elem_info_set_id(info, id);
1159c72fcc34Sopenharmony_ci	if ((err = snd_ctl_elem_info(handle, info)) < 0) {
1160c72fcc34Sopenharmony_ci		if (ignore_error)
1161c72fcc34Sopenharmony_ci			return 0;
1162c72fcc34Sopenharmony_ci		error("Cannot find the given element from control %s\n", card);
1163c72fcc34Sopenharmony_ci		if (! keep_handle) {
1164c72fcc34Sopenharmony_ci			snd_ctl_close(handle);
1165c72fcc34Sopenharmony_ci			handle = NULL;
1166c72fcc34Sopenharmony_ci		}
1167c72fcc34Sopenharmony_ci		return err;
1168c72fcc34Sopenharmony_ci	}
1169c72fcc34Sopenharmony_ci	snd_ctl_elem_info_get_id(info, id);     /* FIXME: Remove it when hctl find works ok !!! */
1170c72fcc34Sopenharmony_ci	if (!roflag) {
1171c72fcc34Sopenharmony_ci		snd_ctl_elem_value_set_id(control, id);
1172c72fcc34Sopenharmony_ci		if ((err = snd_ctl_elem_read(handle, control)) < 0) {
1173c72fcc34Sopenharmony_ci			if (ignore_error)
1174c72fcc34Sopenharmony_ci				return 0;
1175c72fcc34Sopenharmony_ci			error("Cannot read the given element from control %s\n", card);
1176c72fcc34Sopenharmony_ci			if (! keep_handle) {
1177c72fcc34Sopenharmony_ci				snd_ctl_close(handle);
1178c72fcc34Sopenharmony_ci				handle = NULL;
1179c72fcc34Sopenharmony_ci			}
1180c72fcc34Sopenharmony_ci			return err;
1181c72fcc34Sopenharmony_ci		}
1182c72fcc34Sopenharmony_ci		err = snd_ctl_ascii_value_parse(handle, control, info, argv[1]);
1183c72fcc34Sopenharmony_ci		if (err < 0) {
1184c72fcc34Sopenharmony_ci 			if (!ignore_error)
1185c72fcc34Sopenharmony_ci				error("Control %s parse error: %s\n", card, snd_strerror(err));
1186c72fcc34Sopenharmony_ci			if (!keep_handle) {
1187c72fcc34Sopenharmony_ci				snd_ctl_close(handle);
1188c72fcc34Sopenharmony_ci				handle = NULL;
1189c72fcc34Sopenharmony_ci			}
1190c72fcc34Sopenharmony_ci			return ignore_error ? 0 : err;
1191c72fcc34Sopenharmony_ci		}
1192c72fcc34Sopenharmony_ci		if ((err = snd_ctl_elem_write(handle, control)) < 0) {
1193c72fcc34Sopenharmony_ci			if (!ignore_error)
1194c72fcc34Sopenharmony_ci				error("Control %s element write error: %s\n", card, snd_strerror(err));
1195c72fcc34Sopenharmony_ci			if (!keep_handle) {
1196c72fcc34Sopenharmony_ci				snd_ctl_close(handle);
1197c72fcc34Sopenharmony_ci				handle = NULL;
1198c72fcc34Sopenharmony_ci			}
1199c72fcc34Sopenharmony_ci			return ignore_error ? 0 : err;
1200c72fcc34Sopenharmony_ci		}
1201c72fcc34Sopenharmony_ci	}
1202c72fcc34Sopenharmony_ci	if (! keep_handle) {
1203c72fcc34Sopenharmony_ci		snd_ctl_close(handle);
1204c72fcc34Sopenharmony_ci		handle = NULL;
1205c72fcc34Sopenharmony_ci	}
1206c72fcc34Sopenharmony_ci	if (!quiet) {
1207c72fcc34Sopenharmony_ci		snd_hctl_t *hctl;
1208c72fcc34Sopenharmony_ci		snd_hctl_elem_t *elem;
1209c72fcc34Sopenharmony_ci		if ((err = snd_hctl_open(&hctl, card, 0)) < 0) {
1210c72fcc34Sopenharmony_ci			error("Control %s open error: %s\n", card, snd_strerror(err));
1211c72fcc34Sopenharmony_ci			return err;
1212c72fcc34Sopenharmony_ci		}
1213c72fcc34Sopenharmony_ci		if ((err = snd_hctl_load(hctl)) < 0) {
1214c72fcc34Sopenharmony_ci			error("Control %s load error: %s\n", card, snd_strerror(err));
1215c72fcc34Sopenharmony_ci			return err;
1216c72fcc34Sopenharmony_ci		}
1217c72fcc34Sopenharmony_ci		elem = snd_hctl_find_elem(hctl, id);
1218c72fcc34Sopenharmony_ci		if (elem)
1219c72fcc34Sopenharmony_ci			show_control("  ", elem, LEVEL_BASIC | LEVEL_ID);
1220c72fcc34Sopenharmony_ci		else
1221c72fcc34Sopenharmony_ci			printf("Could not find the specified element\n");
1222c72fcc34Sopenharmony_ci		snd_hctl_close(hctl);
1223c72fcc34Sopenharmony_ci	}
1224c72fcc34Sopenharmony_ci	return 0;
1225c72fcc34Sopenharmony_ci}
1226c72fcc34Sopenharmony_ci
1227c72fcc34Sopenharmony_citypedef struct channel_mask {
1228c72fcc34Sopenharmony_ci	char *name;
1229c72fcc34Sopenharmony_ci	unsigned int mask;
1230c72fcc34Sopenharmony_ci} channel_mask_t;
1231c72fcc34Sopenharmony_cistatic const channel_mask_t chanmask[] = {
1232c72fcc34Sopenharmony_ci	{"frontleft", 1 << SND_MIXER_SCHN_FRONT_LEFT},
1233c72fcc34Sopenharmony_ci	{"frontright", 1 << SND_MIXER_SCHN_FRONT_RIGHT},
1234c72fcc34Sopenharmony_ci	{"frontcenter", 1 << SND_MIXER_SCHN_FRONT_CENTER},
1235c72fcc34Sopenharmony_ci	{"front", ((1 << SND_MIXER_SCHN_FRONT_LEFT) |
1236c72fcc34Sopenharmony_ci		   (1 << SND_MIXER_SCHN_FRONT_RIGHT))},
1237c72fcc34Sopenharmony_ci	{"center", 1 << SND_MIXER_SCHN_FRONT_CENTER},
1238c72fcc34Sopenharmony_ci	{"rearleft", 1 << SND_MIXER_SCHN_REAR_LEFT},
1239c72fcc34Sopenharmony_ci	{"rearright", 1 << SND_MIXER_SCHN_REAR_RIGHT},
1240c72fcc34Sopenharmony_ci	{"rear", ((1 << SND_MIXER_SCHN_REAR_LEFT) |
1241c72fcc34Sopenharmony_ci		  (1 << SND_MIXER_SCHN_REAR_RIGHT))},
1242c72fcc34Sopenharmony_ci	{"woofer", 1 << SND_MIXER_SCHN_WOOFER},
1243c72fcc34Sopenharmony_ci	{NULL, 0}
1244c72fcc34Sopenharmony_ci};
1245c72fcc34Sopenharmony_ci
1246c72fcc34Sopenharmony_cistatic unsigned int channels_mask(char **arg, unsigned int def)
1247c72fcc34Sopenharmony_ci{
1248c72fcc34Sopenharmony_ci	const channel_mask_t *c;
1249c72fcc34Sopenharmony_ci
1250c72fcc34Sopenharmony_ci	for (c = chanmask; c->name; c++) {
1251c72fcc34Sopenharmony_ci		if (strncasecmp(*arg, c->name, strlen(c->name)) == 0) {
1252c72fcc34Sopenharmony_ci			while (**arg != '\0' && **arg != ',' && **arg != ' ' && **arg != '\t')
1253c72fcc34Sopenharmony_ci				(*arg)++;
1254c72fcc34Sopenharmony_ci			if (**arg == ',' || **arg == ' ' || **arg == '\t')
1255c72fcc34Sopenharmony_ci				(*arg)++;
1256c72fcc34Sopenharmony_ci			return c->mask;
1257c72fcc34Sopenharmony_ci		}
1258c72fcc34Sopenharmony_ci	}
1259c72fcc34Sopenharmony_ci	return def;
1260c72fcc34Sopenharmony_ci}
1261c72fcc34Sopenharmony_ci
1262c72fcc34Sopenharmony_cistatic unsigned int dir_mask(char **arg, unsigned int def)
1263c72fcc34Sopenharmony_ci{
1264c72fcc34Sopenharmony_ci	int findend = 0;
1265c72fcc34Sopenharmony_ci
1266c72fcc34Sopenharmony_ci	if (strncasecmp(*arg, "playback", 8) == 0)
1267c72fcc34Sopenharmony_ci		def = findend = 1;
1268c72fcc34Sopenharmony_ci	else if (strncasecmp(*arg, "capture", 8) == 0)
1269c72fcc34Sopenharmony_ci		def = findend = 2;
1270c72fcc34Sopenharmony_ci	if (findend) {
1271c72fcc34Sopenharmony_ci		while (**arg != '\0' && **arg != ',' && **arg != ' ' && **arg != '\t')
1272c72fcc34Sopenharmony_ci			(*arg)++;
1273c72fcc34Sopenharmony_ci		if (**arg == ',' || **arg == ' ' || **arg == '\t')
1274c72fcc34Sopenharmony_ci			(*arg)++;
1275c72fcc34Sopenharmony_ci	}
1276c72fcc34Sopenharmony_ci	return def;
1277c72fcc34Sopenharmony_ci}
1278c72fcc34Sopenharmony_ci
1279c72fcc34Sopenharmony_cistatic int get_enum_item_index(snd_mixer_elem_t *elem, char **ptrp)
1280c72fcc34Sopenharmony_ci{
1281c72fcc34Sopenharmony_ci	char *ptr = *ptrp;
1282c72fcc34Sopenharmony_ci	int items, i, len;
1283c72fcc34Sopenharmony_ci
1284c72fcc34Sopenharmony_ci	/* See snd_ctl_elem_init_enum_names() in sound/core/control.c. */
1285c72fcc34Sopenharmony_ci	char name[64];
1286c72fcc34Sopenharmony_ci
1287c72fcc34Sopenharmony_ci	items = snd_mixer_selem_get_enum_items(elem);
1288c72fcc34Sopenharmony_ci	if (items <= 0)
1289c72fcc34Sopenharmony_ci		return -1;
1290c72fcc34Sopenharmony_ci
1291c72fcc34Sopenharmony_ci	for (i = 0; i < items; i++) {
1292c72fcc34Sopenharmony_ci		if (snd_mixer_selem_get_enum_item_name(elem, i, sizeof(name)-1, name) < 0)
1293c72fcc34Sopenharmony_ci			continue;
1294c72fcc34Sopenharmony_ci
1295c72fcc34Sopenharmony_ci		len = strlen(name);
1296c72fcc34Sopenharmony_ci		if (! strncmp(name, ptr, len)) {
1297c72fcc34Sopenharmony_ci			if (! ptr[len] || ptr[len] == ',' || ptr[len] == '\n') {
1298c72fcc34Sopenharmony_ci				ptr += len;
1299c72fcc34Sopenharmony_ci				*ptrp = ptr;
1300c72fcc34Sopenharmony_ci				return i;
1301c72fcc34Sopenharmony_ci			}
1302c72fcc34Sopenharmony_ci		}
1303c72fcc34Sopenharmony_ci	}
1304c72fcc34Sopenharmony_ci	return -1;
1305c72fcc34Sopenharmony_ci}
1306c72fcc34Sopenharmony_ci
1307c72fcc34Sopenharmony_cistatic int sset_enum(snd_mixer_elem_t *elem, unsigned int argc, char **argv)
1308c72fcc34Sopenharmony_ci{
1309c72fcc34Sopenharmony_ci	unsigned int idx, item = 0;
1310c72fcc34Sopenharmony_ci	int check_flag = ignore_error ? 0 : -1;
1311c72fcc34Sopenharmony_ci
1312c72fcc34Sopenharmony_ci	for (idx = 1; idx < argc; idx++) {
1313c72fcc34Sopenharmony_ci		char *ptr = argv[idx];
1314c72fcc34Sopenharmony_ci		while (*ptr) {
1315c72fcc34Sopenharmony_ci			int ival = get_enum_item_index(elem, &ptr);
1316c72fcc34Sopenharmony_ci			if (ival < 0)
1317c72fcc34Sopenharmony_ci				return check_flag;
1318c72fcc34Sopenharmony_ci			if (snd_mixer_selem_set_enum_item(elem, item++, ival) >= 0)
1319c72fcc34Sopenharmony_ci				check_flag = 1;
1320c72fcc34Sopenharmony_ci			/* skip separators */
1321c72fcc34Sopenharmony_ci			while (*ptr == ',' || isspace(*ptr))
1322c72fcc34Sopenharmony_ci				ptr++;
1323c72fcc34Sopenharmony_ci		}
1324c72fcc34Sopenharmony_ci	}
1325c72fcc34Sopenharmony_ci	return check_flag;
1326c72fcc34Sopenharmony_ci}
1327c72fcc34Sopenharmony_ci
1328c72fcc34Sopenharmony_cistatic int sset_channels(snd_mixer_elem_t *elem, unsigned int argc, char **argv)
1329c72fcc34Sopenharmony_ci{
1330c72fcc34Sopenharmony_ci	unsigned int channels = ~0U;
1331c72fcc34Sopenharmony_ci	unsigned int dir = 3, okflag = 3;
1332c72fcc34Sopenharmony_ci	unsigned int idx;
1333c72fcc34Sopenharmony_ci	snd_mixer_selem_channel_id_t chn;
1334c72fcc34Sopenharmony_ci	int check_flag = ignore_error ? 0 : -1;
1335c72fcc34Sopenharmony_ci
1336c72fcc34Sopenharmony_ci	for (idx = 1; idx < argc; idx++) {
1337c72fcc34Sopenharmony_ci		char *ptr = argv[idx], *optr;
1338c72fcc34Sopenharmony_ci		int multi, firstchn = 1;
1339c72fcc34Sopenharmony_ci		channels = channels_mask(&ptr, channels);
1340c72fcc34Sopenharmony_ci		if (*ptr == '\0')
1341c72fcc34Sopenharmony_ci			continue;
1342c72fcc34Sopenharmony_ci		dir = dir_mask(&ptr, dir);
1343c72fcc34Sopenharmony_ci		if (*ptr == '\0')
1344c72fcc34Sopenharmony_ci			continue;
1345c72fcc34Sopenharmony_ci		multi = (strchr(ptr, ',') != NULL);
1346c72fcc34Sopenharmony_ci		optr = ptr;
1347c72fcc34Sopenharmony_ci		for (chn = 0; chn <= SND_MIXER_SCHN_LAST; chn++) {
1348c72fcc34Sopenharmony_ci			char *sptr = NULL;
1349c72fcc34Sopenharmony_ci			int ival;
1350c72fcc34Sopenharmony_ci
1351c72fcc34Sopenharmony_ci			if (!(channels & (1 << chn)))
1352c72fcc34Sopenharmony_ci				continue;
1353c72fcc34Sopenharmony_ci
1354c72fcc34Sopenharmony_ci			if ((dir & 1) && snd_mixer_selem_has_playback_channel(elem, chn)) {
1355c72fcc34Sopenharmony_ci				sptr = ptr;
1356c72fcc34Sopenharmony_ci				if (!strncmp(ptr, "mute", 4) && snd_mixer_selem_has_playback_switch(elem)) {
1357c72fcc34Sopenharmony_ci					snd_mixer_selem_get_playback_switch(elem, chn, &ival);
1358c72fcc34Sopenharmony_ci					if (snd_mixer_selem_set_playback_switch(elem, chn, get_bool_simple(&ptr, "mute", 1, ival)) >= 0)
1359c72fcc34Sopenharmony_ci						check_flag = 1;
1360c72fcc34Sopenharmony_ci				} else if (!strncmp(ptr, "off", 3) && snd_mixer_selem_has_playback_switch(elem)) {
1361c72fcc34Sopenharmony_ci					snd_mixer_selem_get_playback_switch(elem, chn, &ival);
1362c72fcc34Sopenharmony_ci					if (snd_mixer_selem_set_playback_switch(elem, chn, get_bool_simple(&ptr, "off", 1, ival)) >= 0)
1363c72fcc34Sopenharmony_ci						check_flag = 1;
1364c72fcc34Sopenharmony_ci				} else if (!strncmp(ptr, "unmute", 6) && snd_mixer_selem_has_playback_switch(elem)) {
1365c72fcc34Sopenharmony_ci					snd_mixer_selem_get_playback_switch(elem, chn, &ival);
1366c72fcc34Sopenharmony_ci					if (snd_mixer_selem_set_playback_switch(elem, chn, get_bool_simple(&ptr, "unmute", 0, ival)) >= 0)
1367c72fcc34Sopenharmony_ci						check_flag = 1;
1368c72fcc34Sopenharmony_ci				} else if (!strncmp(ptr, "on", 2) && snd_mixer_selem_has_playback_switch(elem)) {
1369c72fcc34Sopenharmony_ci					snd_mixer_selem_get_playback_switch(elem, chn, &ival);
1370c72fcc34Sopenharmony_ci					if (snd_mixer_selem_set_playback_switch(elem, chn, get_bool_simple(&ptr, "on", 0, ival)) >= 0)
1371c72fcc34Sopenharmony_ci						check_flag = 1;
1372c72fcc34Sopenharmony_ci				} else if (!strncmp(ptr, "toggle", 6) && snd_mixer_selem_has_playback_switch(elem)) {
1373c72fcc34Sopenharmony_ci					if (firstchn || !snd_mixer_selem_has_playback_switch_joined(elem)) {
1374c72fcc34Sopenharmony_ci						snd_mixer_selem_get_playback_switch(elem, chn, &ival);
1375c72fcc34Sopenharmony_ci						if (snd_mixer_selem_set_playback_switch(elem, chn, (ival ? 1 : 0) ^ 1) >= 0)
1376c72fcc34Sopenharmony_ci							check_flag = 1;
1377c72fcc34Sopenharmony_ci					}
1378c72fcc34Sopenharmony_ci					simple_skip_word(&ptr, "toggle");
1379c72fcc34Sopenharmony_ci				} else if (isdigit(*ptr) || *ptr == '-' || *ptr == '+') {
1380c72fcc34Sopenharmony_ci					if (set_volume_simple(elem, chn, &ptr, 0) >= 0)
1381c72fcc34Sopenharmony_ci						check_flag = 1;
1382c72fcc34Sopenharmony_ci				} else if (simple_skip_word(&ptr, "cap") || simple_skip_word(&ptr, "rec") ||
1383c72fcc34Sopenharmony_ci					   simple_skip_word(&ptr, "nocap") || simple_skip_word(&ptr, "norec")) {
1384c72fcc34Sopenharmony_ci					/* nothing */
1385c72fcc34Sopenharmony_ci				} else {
1386c72fcc34Sopenharmony_ci					okflag &= ~1;
1387c72fcc34Sopenharmony_ci				}
1388c72fcc34Sopenharmony_ci			}
1389c72fcc34Sopenharmony_ci			if ((dir & 2) && snd_mixer_selem_has_capture_channel(elem, chn)) {
1390c72fcc34Sopenharmony_ci				if (sptr != NULL)
1391c72fcc34Sopenharmony_ci					ptr = sptr;
1392c72fcc34Sopenharmony_ci				sptr = ptr;
1393c72fcc34Sopenharmony_ci				if (!strncmp(ptr, "cap", 3) && snd_mixer_selem_has_capture_switch(elem)) {
1394c72fcc34Sopenharmony_ci					snd_mixer_selem_get_capture_switch(elem, chn, &ival);
1395c72fcc34Sopenharmony_ci					if (snd_mixer_selem_set_capture_switch(elem, chn, get_bool_simple(&ptr, "cap", 0, ival)) >= 0)
1396c72fcc34Sopenharmony_ci						check_flag = 1;
1397c72fcc34Sopenharmony_ci				} else if (!strncmp(ptr, "rec", 3) && snd_mixer_selem_has_capture_switch(elem)) {
1398c72fcc34Sopenharmony_ci					snd_mixer_selem_get_capture_switch(elem, chn, &ival);
1399c72fcc34Sopenharmony_ci					if (snd_mixer_selem_set_capture_switch(elem, chn, get_bool_simple(&ptr, "rec", 0, ival)) >= 0)
1400c72fcc34Sopenharmony_ci						check_flag = 1;
1401c72fcc34Sopenharmony_ci				} else if (!strncmp(ptr, "nocap", 5) && snd_mixer_selem_has_capture_switch(elem)) {
1402c72fcc34Sopenharmony_ci					snd_mixer_selem_get_capture_switch(elem, chn, &ival);
1403c72fcc34Sopenharmony_ci					if (snd_mixer_selem_set_capture_switch(elem, chn, get_bool_simple(&ptr, "nocap", 1, ival)) >= 0)
1404c72fcc34Sopenharmony_ci						check_flag = 1;
1405c72fcc34Sopenharmony_ci				} else if (!strncmp(ptr, "norec", 5) && snd_mixer_selem_has_capture_switch(elem)) {
1406c72fcc34Sopenharmony_ci					snd_mixer_selem_get_capture_switch(elem, chn, &ival);
1407c72fcc34Sopenharmony_ci					if (snd_mixer_selem_set_capture_switch(elem, chn, get_bool_simple(&ptr, "norec", 1, ival)) >= 0)
1408c72fcc34Sopenharmony_ci						check_flag = 1;
1409c72fcc34Sopenharmony_ci				} else if (!strncmp(ptr, "toggle", 6) && snd_mixer_selem_has_capture_switch(elem)) {
1410c72fcc34Sopenharmony_ci					if (firstchn || !snd_mixer_selem_has_capture_switch_joined(elem)) {
1411c72fcc34Sopenharmony_ci						snd_mixer_selem_get_capture_switch(elem, chn, &ival);
1412c72fcc34Sopenharmony_ci						if (snd_mixer_selem_set_capture_switch(elem, chn, (ival ? 1 : 0) ^ 1) >= 0)
1413c72fcc34Sopenharmony_ci							check_flag = 1;
1414c72fcc34Sopenharmony_ci					}
1415c72fcc34Sopenharmony_ci					simple_skip_word(&ptr, "toggle");
1416c72fcc34Sopenharmony_ci				} else if (isdigit(*ptr) || *ptr == '-' || *ptr == '+') {
1417c72fcc34Sopenharmony_ci					if (set_volume_simple(elem, chn, &ptr, 1) >= 0)
1418c72fcc34Sopenharmony_ci						check_flag = 1;
1419c72fcc34Sopenharmony_ci				} else if (simple_skip_word(&ptr, "mute") || simple_skip_word(&ptr, "off") ||
1420c72fcc34Sopenharmony_ci					   simple_skip_word(&ptr, "unmute") || simple_skip_word(&ptr, "on")) {
1421c72fcc34Sopenharmony_ci					/* nothing */
1422c72fcc34Sopenharmony_ci				} else {
1423c72fcc34Sopenharmony_ci					okflag &= ~2;
1424c72fcc34Sopenharmony_ci				}
1425c72fcc34Sopenharmony_ci			}
1426c72fcc34Sopenharmony_ci			if (okflag == 0) {
1427c72fcc34Sopenharmony_ci				if (debugflag) {
1428c72fcc34Sopenharmony_ci					if (dir & 1)
1429c72fcc34Sopenharmony_ci						error("Unknown playback setup '%s'..", ptr);
1430c72fcc34Sopenharmony_ci					if (dir & 2)
1431c72fcc34Sopenharmony_ci						error("Unknown capture setup '%s'..", ptr);
1432c72fcc34Sopenharmony_ci				}
1433c72fcc34Sopenharmony_ci				return 0; /* just skip it */
1434c72fcc34Sopenharmony_ci			}
1435c72fcc34Sopenharmony_ci			if (!multi)
1436c72fcc34Sopenharmony_ci				ptr = optr;
1437c72fcc34Sopenharmony_ci			firstchn = 0;
1438c72fcc34Sopenharmony_ci		}
1439c72fcc34Sopenharmony_ci	}
1440c72fcc34Sopenharmony_ci	return check_flag;
1441c72fcc34Sopenharmony_ci}
1442c72fcc34Sopenharmony_ci
1443c72fcc34Sopenharmony_cistatic int sset(unsigned int argc, char *argv[], int roflag, int keep_handle)
1444c72fcc34Sopenharmony_ci{
1445c72fcc34Sopenharmony_ci	int err = 0;
1446c72fcc34Sopenharmony_ci	static snd_mixer_t *handle = NULL;
1447c72fcc34Sopenharmony_ci	snd_mixer_elem_t *elem;
1448c72fcc34Sopenharmony_ci	snd_mixer_selem_id_t *sid;
1449c72fcc34Sopenharmony_ci	snd_mixer_selem_id_alloca(&sid);
1450c72fcc34Sopenharmony_ci
1451c72fcc34Sopenharmony_ci	if (argc < 1) {
1452c72fcc34Sopenharmony_ci		fprintf(stderr, "Specify a scontrol identifier: 'name',index\n");
1453c72fcc34Sopenharmony_ci		return 1;
1454c72fcc34Sopenharmony_ci	}
1455c72fcc34Sopenharmony_ci	if (parse_simple_id(argv[0], sid)) {
1456c72fcc34Sopenharmony_ci		fprintf(stderr, "Wrong scontrol identifier: %s\n", argv[0]);
1457c72fcc34Sopenharmony_ci		return 1;
1458c72fcc34Sopenharmony_ci	}
1459c72fcc34Sopenharmony_ci	if (!roflag && argc < 2) {
1460c72fcc34Sopenharmony_ci		fprintf(stderr, "Specify what you want to set...\n");
1461c72fcc34Sopenharmony_ci		return 1;
1462c72fcc34Sopenharmony_ci	}
1463c72fcc34Sopenharmony_ci	if (handle == NULL) {
1464c72fcc34Sopenharmony_ci		if ((err = snd_mixer_open(&handle, 0)) < 0) {
1465c72fcc34Sopenharmony_ci			error("Mixer %s open error: %s\n", card, snd_strerror(err));
1466c72fcc34Sopenharmony_ci			return err;
1467c72fcc34Sopenharmony_ci		}
1468c72fcc34Sopenharmony_ci		if (smixer_level == 0 && (err = snd_mixer_attach(handle, card)) < 0) {
1469c72fcc34Sopenharmony_ci			error("Mixer attach %s error: %s", card, snd_strerror(err));
1470c72fcc34Sopenharmony_ci			snd_mixer_close(handle);
1471c72fcc34Sopenharmony_ci			handle = NULL;
1472c72fcc34Sopenharmony_ci			return err;
1473c72fcc34Sopenharmony_ci		}
1474c72fcc34Sopenharmony_ci		if ((err = snd_mixer_selem_register(handle, smixer_level > 0 ? &smixer_options : NULL, NULL)) < 0) {
1475c72fcc34Sopenharmony_ci			error("Mixer register error: %s", snd_strerror(err));
1476c72fcc34Sopenharmony_ci			snd_mixer_close(handle);
1477c72fcc34Sopenharmony_ci			handle = NULL;
1478c72fcc34Sopenharmony_ci			return err;
1479c72fcc34Sopenharmony_ci		}
1480c72fcc34Sopenharmony_ci		err = snd_mixer_load(handle);
1481c72fcc34Sopenharmony_ci		if (err < 0) {
1482c72fcc34Sopenharmony_ci			error("Mixer %s load error: %s", card, snd_strerror(err));
1483c72fcc34Sopenharmony_ci			snd_mixer_close(handle);
1484c72fcc34Sopenharmony_ci			handle = NULL;
1485c72fcc34Sopenharmony_ci			return err;
1486c72fcc34Sopenharmony_ci		}
1487c72fcc34Sopenharmony_ci	}
1488c72fcc34Sopenharmony_ci	elem = snd_mixer_find_selem(handle, sid);
1489c72fcc34Sopenharmony_ci	if (!elem) {
1490c72fcc34Sopenharmony_ci		if (ignore_error)
1491c72fcc34Sopenharmony_ci			return 0;
1492c72fcc34Sopenharmony_ci		error("Unable to find simple control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
1493c72fcc34Sopenharmony_ci		snd_mixer_close(handle);
1494c72fcc34Sopenharmony_ci		handle = NULL;
1495c72fcc34Sopenharmony_ci		return -ENOENT;
1496c72fcc34Sopenharmony_ci	}
1497c72fcc34Sopenharmony_ci	if (!roflag) {
1498c72fcc34Sopenharmony_ci		/* enum control */
1499c72fcc34Sopenharmony_ci		if (snd_mixer_selem_is_enumerated(elem))
1500c72fcc34Sopenharmony_ci			err = sset_enum(elem, argc, argv);
1501c72fcc34Sopenharmony_ci		else
1502c72fcc34Sopenharmony_ci			err = sset_channels(elem, argc, argv);
1503c72fcc34Sopenharmony_ci
1504c72fcc34Sopenharmony_ci		if (!err)
1505c72fcc34Sopenharmony_ci			goto done;
1506c72fcc34Sopenharmony_ci		if (err < 0) {
1507c72fcc34Sopenharmony_ci			error("Invalid command!");
1508c72fcc34Sopenharmony_ci			goto done;
1509c72fcc34Sopenharmony_ci		}
1510c72fcc34Sopenharmony_ci	}
1511c72fcc34Sopenharmony_ci	if (!quiet) {
1512c72fcc34Sopenharmony_ci		printf("Simple mixer control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
1513c72fcc34Sopenharmony_ci		show_selem(handle, sid, "  ", 1);
1514c72fcc34Sopenharmony_ci	}
1515c72fcc34Sopenharmony_ci done:
1516c72fcc34Sopenharmony_ci	if (! keep_handle) {
1517c72fcc34Sopenharmony_ci		snd_mixer_close(handle);
1518c72fcc34Sopenharmony_ci		handle = NULL;
1519c72fcc34Sopenharmony_ci	}
1520c72fcc34Sopenharmony_ci	return err < 0 ? 1 : 0;
1521c72fcc34Sopenharmony_ci}
1522c72fcc34Sopenharmony_ci
1523c72fcc34Sopenharmony_cistatic void events_info(snd_hctl_elem_t *helem)
1524c72fcc34Sopenharmony_ci{
1525c72fcc34Sopenharmony_ci	snd_ctl_elem_id_t *id;
1526c72fcc34Sopenharmony_ci	snd_ctl_elem_id_alloca(&id);
1527c72fcc34Sopenharmony_ci	snd_hctl_elem_get_id(helem, id);
1528c72fcc34Sopenharmony_ci	printf("event info: ");
1529c72fcc34Sopenharmony_ci	show_control_id(id);
1530c72fcc34Sopenharmony_ci	printf("\n");
1531c72fcc34Sopenharmony_ci}
1532c72fcc34Sopenharmony_ci
1533c72fcc34Sopenharmony_cistatic void events_value(snd_hctl_elem_t *helem)
1534c72fcc34Sopenharmony_ci{
1535c72fcc34Sopenharmony_ci	snd_ctl_elem_id_t *id;
1536c72fcc34Sopenharmony_ci	snd_ctl_elem_id_alloca(&id);
1537c72fcc34Sopenharmony_ci	snd_hctl_elem_get_id(helem, id);
1538c72fcc34Sopenharmony_ci	printf("event value: ");
1539c72fcc34Sopenharmony_ci	show_control_id(id);
1540c72fcc34Sopenharmony_ci	printf("\n");
1541c72fcc34Sopenharmony_ci}
1542c72fcc34Sopenharmony_ci
1543c72fcc34Sopenharmony_cistatic void events_remove(snd_hctl_elem_t *helem)
1544c72fcc34Sopenharmony_ci{
1545c72fcc34Sopenharmony_ci	snd_ctl_elem_id_t *id;
1546c72fcc34Sopenharmony_ci	snd_ctl_elem_id_alloca(&id);
1547c72fcc34Sopenharmony_ci	snd_hctl_elem_get_id(helem, id);
1548c72fcc34Sopenharmony_ci	printf("event remove: ");
1549c72fcc34Sopenharmony_ci	show_control_id(id);
1550c72fcc34Sopenharmony_ci	printf("\n");
1551c72fcc34Sopenharmony_ci}
1552c72fcc34Sopenharmony_ci
1553c72fcc34Sopenharmony_cistatic int element_callback(snd_hctl_elem_t *elem, unsigned int mask)
1554c72fcc34Sopenharmony_ci{
1555c72fcc34Sopenharmony_ci	if (mask == SND_CTL_EVENT_MASK_REMOVE) {
1556c72fcc34Sopenharmony_ci		events_remove(elem);
1557c72fcc34Sopenharmony_ci		return 0;
1558c72fcc34Sopenharmony_ci	}
1559c72fcc34Sopenharmony_ci	if (mask & SND_CTL_EVENT_MASK_INFO)
1560c72fcc34Sopenharmony_ci		events_info(elem);
1561c72fcc34Sopenharmony_ci	if (mask & SND_CTL_EVENT_MASK_VALUE)
1562c72fcc34Sopenharmony_ci		events_value(elem);
1563c72fcc34Sopenharmony_ci	return 0;
1564c72fcc34Sopenharmony_ci}
1565c72fcc34Sopenharmony_ci
1566c72fcc34Sopenharmony_cistatic void events_add(snd_hctl_elem_t *helem)
1567c72fcc34Sopenharmony_ci{
1568c72fcc34Sopenharmony_ci	snd_ctl_elem_id_t *id;
1569c72fcc34Sopenharmony_ci	snd_ctl_elem_id_alloca(&id);
1570c72fcc34Sopenharmony_ci	snd_hctl_elem_get_id(helem, id);
1571c72fcc34Sopenharmony_ci	printf("event add: ");
1572c72fcc34Sopenharmony_ci	show_control_id(id);
1573c72fcc34Sopenharmony_ci	printf("\n");
1574c72fcc34Sopenharmony_ci	snd_hctl_elem_set_callback(helem, element_callback);
1575c72fcc34Sopenharmony_ci}
1576c72fcc34Sopenharmony_ci
1577c72fcc34Sopenharmony_cistatic int ctl_callback(snd_hctl_t *ctl ATTRIBUTE_UNUSED, unsigned int mask,
1578c72fcc34Sopenharmony_ci			snd_hctl_elem_t *elem)
1579c72fcc34Sopenharmony_ci{
1580c72fcc34Sopenharmony_ci	if (mask & SND_CTL_EVENT_MASK_ADD)
1581c72fcc34Sopenharmony_ci		events_add(elem);
1582c72fcc34Sopenharmony_ci	return 0;
1583c72fcc34Sopenharmony_ci}
1584c72fcc34Sopenharmony_ci
1585c72fcc34Sopenharmony_cistatic int events(int argc ATTRIBUTE_UNUSED, char *argv[] ATTRIBUTE_UNUSED)
1586c72fcc34Sopenharmony_ci{
1587c72fcc34Sopenharmony_ci	snd_hctl_t *handle;
1588c72fcc34Sopenharmony_ci	snd_hctl_elem_t *helem;
1589c72fcc34Sopenharmony_ci	int err;
1590c72fcc34Sopenharmony_ci
1591c72fcc34Sopenharmony_ci	if ((err = snd_hctl_open(&handle, card, 0)) < 0) {
1592c72fcc34Sopenharmony_ci		error("Control %s open error: %s\n", card, snd_strerror(err));
1593c72fcc34Sopenharmony_ci		return err;
1594c72fcc34Sopenharmony_ci	}
1595c72fcc34Sopenharmony_ci	snd_hctl_set_callback(handle, ctl_callback);
1596c72fcc34Sopenharmony_ci	if ((err = snd_hctl_load(handle)) < 0) {
1597c72fcc34Sopenharmony_ci		error("Control %s hbuild error: %s\n", card, snd_strerror(err));
1598c72fcc34Sopenharmony_ci		return err;
1599c72fcc34Sopenharmony_ci	}
1600c72fcc34Sopenharmony_ci	for (helem = snd_hctl_first_elem(handle); helem; helem = snd_hctl_elem_next(helem)) {
1601c72fcc34Sopenharmony_ci		snd_hctl_elem_set_callback(helem, element_callback);
1602c72fcc34Sopenharmony_ci	}
1603c72fcc34Sopenharmony_ci	printf("Ready to listen...\n");
1604c72fcc34Sopenharmony_ci	while (1) {
1605c72fcc34Sopenharmony_ci		int res = snd_hctl_wait(handle, -1);
1606c72fcc34Sopenharmony_ci		if (res >= 0) {
1607c72fcc34Sopenharmony_ci			printf("Poll ok: %i\n", res);
1608c72fcc34Sopenharmony_ci			res = snd_hctl_handle_events(handle);
1609c72fcc34Sopenharmony_ci			if (res < 0)
1610c72fcc34Sopenharmony_ci				printf("ERR: %s (%d)\n", snd_strerror(res), res);
1611c72fcc34Sopenharmony_ci		}
1612c72fcc34Sopenharmony_ci	}
1613c72fcc34Sopenharmony_ci	snd_hctl_close(handle);
1614c72fcc34Sopenharmony_ci	return 0;
1615c72fcc34Sopenharmony_ci}
1616c72fcc34Sopenharmony_ci
1617c72fcc34Sopenharmony_cistatic void sevents_value(snd_mixer_selem_id_t *sid)
1618c72fcc34Sopenharmony_ci{
1619c72fcc34Sopenharmony_ci	printf("event value: '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
1620c72fcc34Sopenharmony_ci}
1621c72fcc34Sopenharmony_ci
1622c72fcc34Sopenharmony_cistatic void sevents_info(snd_mixer_selem_id_t *sid)
1623c72fcc34Sopenharmony_ci{
1624c72fcc34Sopenharmony_ci	printf("event info: '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
1625c72fcc34Sopenharmony_ci}
1626c72fcc34Sopenharmony_ci
1627c72fcc34Sopenharmony_cistatic void sevents_remove(snd_mixer_selem_id_t *sid)
1628c72fcc34Sopenharmony_ci{
1629c72fcc34Sopenharmony_ci	printf("event remove: '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
1630c72fcc34Sopenharmony_ci}
1631c72fcc34Sopenharmony_ci
1632c72fcc34Sopenharmony_cistatic int melem_event(snd_mixer_elem_t *elem, unsigned int mask)
1633c72fcc34Sopenharmony_ci{
1634c72fcc34Sopenharmony_ci	snd_mixer_selem_id_t *sid;
1635c72fcc34Sopenharmony_ci	snd_mixer_selem_id_alloca(&sid);
1636c72fcc34Sopenharmony_ci	snd_mixer_selem_get_id(elem, sid);
1637c72fcc34Sopenharmony_ci	if (mask == SND_CTL_EVENT_MASK_REMOVE) {
1638c72fcc34Sopenharmony_ci		sevents_remove(sid);
1639c72fcc34Sopenharmony_ci		return 0;
1640c72fcc34Sopenharmony_ci	}
1641c72fcc34Sopenharmony_ci	if (mask & SND_CTL_EVENT_MASK_INFO)
1642c72fcc34Sopenharmony_ci		sevents_info(sid);
1643c72fcc34Sopenharmony_ci	if (mask & SND_CTL_EVENT_MASK_VALUE)
1644c72fcc34Sopenharmony_ci		sevents_value(sid);
1645c72fcc34Sopenharmony_ci	return 0;
1646c72fcc34Sopenharmony_ci}
1647c72fcc34Sopenharmony_ci
1648c72fcc34Sopenharmony_cistatic void sevents_add(snd_mixer_elem_t *elem)
1649c72fcc34Sopenharmony_ci{
1650c72fcc34Sopenharmony_ci	snd_mixer_selem_id_t *sid;
1651c72fcc34Sopenharmony_ci	snd_mixer_selem_id_alloca(&sid);
1652c72fcc34Sopenharmony_ci	snd_mixer_selem_get_id(elem, sid);
1653c72fcc34Sopenharmony_ci	printf("event add: '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
1654c72fcc34Sopenharmony_ci	snd_mixer_elem_set_callback(elem, melem_event);
1655c72fcc34Sopenharmony_ci}
1656c72fcc34Sopenharmony_ci
1657c72fcc34Sopenharmony_cistatic int mixer_event(snd_mixer_t *mixer ATTRIBUTE_UNUSED, unsigned int mask,
1658c72fcc34Sopenharmony_ci		       snd_mixer_elem_t *elem)
1659c72fcc34Sopenharmony_ci{
1660c72fcc34Sopenharmony_ci	if (mask & SND_CTL_EVENT_MASK_ADD)
1661c72fcc34Sopenharmony_ci		sevents_add(elem);
1662c72fcc34Sopenharmony_ci	return 0;
1663c72fcc34Sopenharmony_ci}
1664c72fcc34Sopenharmony_ci
1665c72fcc34Sopenharmony_cistatic int sevents(int argc ATTRIBUTE_UNUSED, char *argv[] ATTRIBUTE_UNUSED)
1666c72fcc34Sopenharmony_ci{
1667c72fcc34Sopenharmony_ci	snd_mixer_t *handle;
1668c72fcc34Sopenharmony_ci	int err;
1669c72fcc34Sopenharmony_ci
1670c72fcc34Sopenharmony_ci	if ((err = snd_mixer_open(&handle, 0)) < 0) {
1671c72fcc34Sopenharmony_ci		error("Mixer %s open error: %s", card, snd_strerror(err));
1672c72fcc34Sopenharmony_ci		return err;
1673c72fcc34Sopenharmony_ci	}
1674c72fcc34Sopenharmony_ci	if (smixer_level == 0 && (err = snd_mixer_attach(handle, card)) < 0) {
1675c72fcc34Sopenharmony_ci		error("Mixer attach %s error: %s", card, snd_strerror(err));
1676c72fcc34Sopenharmony_ci		snd_mixer_close(handle);
1677c72fcc34Sopenharmony_ci		return err;
1678c72fcc34Sopenharmony_ci	}
1679c72fcc34Sopenharmony_ci	if ((err = snd_mixer_selem_register(handle, smixer_level > 0 ? &smixer_options : NULL, NULL)) < 0) {
1680c72fcc34Sopenharmony_ci		error("Mixer register error: %s", snd_strerror(err));
1681c72fcc34Sopenharmony_ci		snd_mixer_close(handle);
1682c72fcc34Sopenharmony_ci		return err;
1683c72fcc34Sopenharmony_ci	}
1684c72fcc34Sopenharmony_ci	snd_mixer_set_callback(handle, mixer_event);
1685c72fcc34Sopenharmony_ci	err = snd_mixer_load(handle);
1686c72fcc34Sopenharmony_ci	if (err < 0) {
1687c72fcc34Sopenharmony_ci		error("Mixer %s load error: %s", card, snd_strerror(err));
1688c72fcc34Sopenharmony_ci		snd_mixer_close(handle);
1689c72fcc34Sopenharmony_ci		return err;
1690c72fcc34Sopenharmony_ci	}
1691c72fcc34Sopenharmony_ci
1692c72fcc34Sopenharmony_ci	printf("Ready to listen...\n");
1693c72fcc34Sopenharmony_ci	while (1) {
1694c72fcc34Sopenharmony_ci		int res;
1695c72fcc34Sopenharmony_ci		res = snd_mixer_wait(handle, -1);
1696c72fcc34Sopenharmony_ci		if (res >= 0) {
1697c72fcc34Sopenharmony_ci			printf("Poll ok: %i\n", res);
1698c72fcc34Sopenharmony_ci			res = snd_mixer_handle_events(handle);
1699c72fcc34Sopenharmony_ci			assert(res >= 0);
1700c72fcc34Sopenharmony_ci		}
1701c72fcc34Sopenharmony_ci	}
1702c72fcc34Sopenharmony_ci	snd_mixer_close(handle);
1703c72fcc34Sopenharmony_ci	return 0;
1704c72fcc34Sopenharmony_ci}
1705c72fcc34Sopenharmony_ci
1706c72fcc34Sopenharmony_ci/*
1707c72fcc34Sopenharmony_ci * split a line into tokens
1708c72fcc34Sopenharmony_ci * the content in the line buffer is modified
1709c72fcc34Sopenharmony_ci */
1710c72fcc34Sopenharmony_cistatic int split_line(char *buf, char **token, int max_token)
1711c72fcc34Sopenharmony_ci{
1712c72fcc34Sopenharmony_ci	char *dst;
1713c72fcc34Sopenharmony_ci	int n, esc, quote;
1714c72fcc34Sopenharmony_ci
1715c72fcc34Sopenharmony_ci	for (n = 0; n < max_token; n++) {
1716c72fcc34Sopenharmony_ci		while (isspace(*buf))
1717c72fcc34Sopenharmony_ci			buf++;
1718c72fcc34Sopenharmony_ci		if (! *buf || *buf == '\n')
1719c72fcc34Sopenharmony_ci			return n;
1720c72fcc34Sopenharmony_ci		/* skip comments */
1721c72fcc34Sopenharmony_ci		if (*buf == '#' || *buf == '!')
1722c72fcc34Sopenharmony_ci			return n;
1723c72fcc34Sopenharmony_ci		esc = 0;
1724c72fcc34Sopenharmony_ci		quote = 0;
1725c72fcc34Sopenharmony_ci		token[n] = buf;
1726c72fcc34Sopenharmony_ci		for (dst = buf; *buf && *buf != '\n'; buf++) {
1727c72fcc34Sopenharmony_ci			if (esc)
1728c72fcc34Sopenharmony_ci				esc = 0;
1729c72fcc34Sopenharmony_ci			else if (isspace(*buf) && !quote) {
1730c72fcc34Sopenharmony_ci				buf++;
1731c72fcc34Sopenharmony_ci				break;
1732c72fcc34Sopenharmony_ci			} else if (*buf == '\\') {
1733c72fcc34Sopenharmony_ci				esc = 1;
1734c72fcc34Sopenharmony_ci				continue;
1735c72fcc34Sopenharmony_ci			} else if (*buf == '\'' || *buf == '"') {
1736c72fcc34Sopenharmony_ci				if (! quote) {
1737c72fcc34Sopenharmony_ci					quote = *buf;
1738c72fcc34Sopenharmony_ci					continue;
1739c72fcc34Sopenharmony_ci				} else if (*buf == quote) {
1740c72fcc34Sopenharmony_ci					quote = 0;
1741c72fcc34Sopenharmony_ci					continue;
1742c72fcc34Sopenharmony_ci				}
1743c72fcc34Sopenharmony_ci			}
1744c72fcc34Sopenharmony_ci			*dst++ = *buf;
1745c72fcc34Sopenharmony_ci		}
1746c72fcc34Sopenharmony_ci		*dst = 0;
1747c72fcc34Sopenharmony_ci	}
1748c72fcc34Sopenharmony_ci	return n;
1749c72fcc34Sopenharmony_ci}
1750c72fcc34Sopenharmony_ci
1751c72fcc34Sopenharmony_ci#define MAX_ARGS	32
1752c72fcc34Sopenharmony_ci
1753c72fcc34Sopenharmony_cistatic int exec_stdin(void)
1754c72fcc34Sopenharmony_ci{
1755c72fcc34Sopenharmony_ci	int narg;
1756c72fcc34Sopenharmony_ci	char buf[256], *args[MAX_ARGS];
1757c72fcc34Sopenharmony_ci	int err = 0;
1758c72fcc34Sopenharmony_ci
1759c72fcc34Sopenharmony_ci	/* quiet = 1; */
1760c72fcc34Sopenharmony_ci	ignore_error = 1;
1761c72fcc34Sopenharmony_ci
1762c72fcc34Sopenharmony_ci	while (fgets(buf, sizeof(buf), stdin)) {
1763c72fcc34Sopenharmony_ci		narg = split_line(buf, args, MAX_ARGS);
1764c72fcc34Sopenharmony_ci		if (narg > 0) {
1765c72fcc34Sopenharmony_ci			if (!strcmp(args[0], "sset") || !strcmp(args[0], "set"))
1766c72fcc34Sopenharmony_ci				err = sset(narg - 1, args + 1, 0, 1);
1767c72fcc34Sopenharmony_ci			else if (!strcmp(args[0], "cset"))
1768c72fcc34Sopenharmony_ci				err = cset(narg - 1, args + 1, 0, 1);
1769c72fcc34Sopenharmony_ci			if (err < 0)
1770c72fcc34Sopenharmony_ci				return 1;
1771c72fcc34Sopenharmony_ci		}
1772c72fcc34Sopenharmony_ci	}
1773c72fcc34Sopenharmony_ci	return 0;
1774c72fcc34Sopenharmony_ci}
1775c72fcc34Sopenharmony_ci
1776c72fcc34Sopenharmony_ci
1777c72fcc34Sopenharmony_ciint main(int argc, char *argv[])
1778c72fcc34Sopenharmony_ci{
1779c72fcc34Sopenharmony_ci	int badopt, retval, level = 0;
1780c72fcc34Sopenharmony_ci	int read_stdin = 0;
1781c72fcc34Sopenharmony_ci	static const struct option long_option[] =
1782c72fcc34Sopenharmony_ci	{
1783c72fcc34Sopenharmony_ci		{"help", 0, NULL, 'h'},
1784c72fcc34Sopenharmony_ci		{"card", 1, NULL, 'c'},
1785c72fcc34Sopenharmony_ci		{"device", 1, NULL, 'D'},
1786c72fcc34Sopenharmony_ci		{"quiet", 0, NULL, 'q'},
1787c72fcc34Sopenharmony_ci		{"inactive", 0, NULL, 'i'},
1788c72fcc34Sopenharmony_ci		{"debug", 0, NULL, 'd'},
1789c72fcc34Sopenharmony_ci		{"nocheck", 0, NULL, 'n'},
1790c72fcc34Sopenharmony_ci		{"version", 0, NULL, 'v'},
1791c72fcc34Sopenharmony_ci		{"abstract", 1, NULL, 'a'},
1792c72fcc34Sopenharmony_ci		{"stdin", 0, NULL, 's'},
1793c72fcc34Sopenharmony_ci		{"raw-volume", 0, NULL, 'R'},
1794c72fcc34Sopenharmony_ci		{"mapped-volume", 0, NULL, 'M'},
1795c72fcc34Sopenharmony_ci		{NULL, 0, NULL, 0},
1796c72fcc34Sopenharmony_ci	};
1797c72fcc34Sopenharmony_ci
1798c72fcc34Sopenharmony_ci	badopt = 0;
1799c72fcc34Sopenharmony_ci	while (1) {
1800c72fcc34Sopenharmony_ci		int c;
1801c72fcc34Sopenharmony_ci
1802c72fcc34Sopenharmony_ci		if ((c = getopt_long(argc, argv, "hc:D:qidnva:sRM", long_option, NULL)) < 0)
1803c72fcc34Sopenharmony_ci			break;
1804c72fcc34Sopenharmony_ci		switch (c) {
1805c72fcc34Sopenharmony_ci		case 'h':
1806c72fcc34Sopenharmony_ci			help();
1807c72fcc34Sopenharmony_ci			return 0;
1808c72fcc34Sopenharmony_ci		case 'c':
1809c72fcc34Sopenharmony_ci			{
1810c72fcc34Sopenharmony_ci				int i;
1811c72fcc34Sopenharmony_ci				i = snd_card_get_index(optarg);
1812c72fcc34Sopenharmony_ci				if (i >= 0 && i < 32)
1813c72fcc34Sopenharmony_ci#if defined(SND_LIB_VER) && SND_LIB_VER(1, 2, 5) <= SND_LIB_VERSION
1814c72fcc34Sopenharmony_ci					sprintf(card, "sysdefault:%i", i);
1815c72fcc34Sopenharmony_ci#else
1816c72fcc34Sopenharmony_ci					sprintf(card, "hw:%i", i);
1817c72fcc34Sopenharmony_ci#endif
1818c72fcc34Sopenharmony_ci				else {
1819c72fcc34Sopenharmony_ci					fprintf(stderr, "Invalid card number '%s'.\n", optarg);
1820c72fcc34Sopenharmony_ci					badopt++;
1821c72fcc34Sopenharmony_ci				}
1822c72fcc34Sopenharmony_ci			}
1823c72fcc34Sopenharmony_ci			break;
1824c72fcc34Sopenharmony_ci		case 'D':
1825c72fcc34Sopenharmony_ci			strncpy(card, optarg, sizeof(card)-1);
1826c72fcc34Sopenharmony_ci			card[sizeof(card)-1] = '\0';
1827c72fcc34Sopenharmony_ci			break;
1828c72fcc34Sopenharmony_ci		case 'q':
1829c72fcc34Sopenharmony_ci			quiet = 1;
1830c72fcc34Sopenharmony_ci			break;
1831c72fcc34Sopenharmony_ci		case 'i':
1832c72fcc34Sopenharmony_ci			level |= LEVEL_INACTIVE;
1833c72fcc34Sopenharmony_ci			break;
1834c72fcc34Sopenharmony_ci		case 'd':
1835c72fcc34Sopenharmony_ci			debugflag = 1;
1836c72fcc34Sopenharmony_ci			break;
1837c72fcc34Sopenharmony_ci		case 'n':
1838c72fcc34Sopenharmony_ci			no_check = 1;
1839c72fcc34Sopenharmony_ci			break;
1840c72fcc34Sopenharmony_ci		case 'v':
1841c72fcc34Sopenharmony_ci			printf("amixer version " SND_UTIL_VERSION_STR "\n");
1842c72fcc34Sopenharmony_ci			return 0;
1843c72fcc34Sopenharmony_ci		case 'a':
1844c72fcc34Sopenharmony_ci			smixer_level = 1;
1845c72fcc34Sopenharmony_ci			memset(&smixer_options, 0, sizeof(smixer_options));
1846c72fcc34Sopenharmony_ci			smixer_options.ver = 1;
1847c72fcc34Sopenharmony_ci			if (!strcmp(optarg, "none"))
1848c72fcc34Sopenharmony_ci				smixer_options.abstract = SND_MIXER_SABSTRACT_NONE;
1849c72fcc34Sopenharmony_ci			else if (!strcmp(optarg, "basic"))
1850c72fcc34Sopenharmony_ci				smixer_options.abstract = SND_MIXER_SABSTRACT_BASIC;
1851c72fcc34Sopenharmony_ci			else {
1852c72fcc34Sopenharmony_ci				fprintf(stderr, "Select correct abstraction level (none or basic)...\n");
1853c72fcc34Sopenharmony_ci				badopt++;
1854c72fcc34Sopenharmony_ci			}
1855c72fcc34Sopenharmony_ci			break;
1856c72fcc34Sopenharmony_ci		case 's':
1857c72fcc34Sopenharmony_ci			read_stdin = 1;
1858c72fcc34Sopenharmony_ci			break;
1859c72fcc34Sopenharmony_ci		case 'R':
1860c72fcc34Sopenharmony_ci			std_vol_type = VOL_RAW;
1861c72fcc34Sopenharmony_ci			break;
1862c72fcc34Sopenharmony_ci		case 'M':
1863c72fcc34Sopenharmony_ci			std_vol_type = VOL_MAP;
1864c72fcc34Sopenharmony_ci			break;
1865c72fcc34Sopenharmony_ci		default:
1866c72fcc34Sopenharmony_ci			fprintf(stderr, "Invalid switch or option -%c needs an argument.\n", c);
1867c72fcc34Sopenharmony_ci			badopt++;
1868c72fcc34Sopenharmony_ci		}
1869c72fcc34Sopenharmony_ci	}
1870c72fcc34Sopenharmony_ci	if (badopt)
1871c72fcc34Sopenharmony_ci		return 1;
1872c72fcc34Sopenharmony_ci
1873c72fcc34Sopenharmony_ci	smixer_options.device = card;
1874c72fcc34Sopenharmony_ci
1875c72fcc34Sopenharmony_ci	if (read_stdin) {
1876c72fcc34Sopenharmony_ci		retval = exec_stdin();
1877c72fcc34Sopenharmony_ci		goto finish;
1878c72fcc34Sopenharmony_ci	}
1879c72fcc34Sopenharmony_ci
1880c72fcc34Sopenharmony_ci	if (argc - optind <= 0) {
1881c72fcc34Sopenharmony_ci		retval = selems(LEVEL_BASIC | level) ? 1 : 0;
1882c72fcc34Sopenharmony_ci		goto finish;
1883c72fcc34Sopenharmony_ci	}
1884c72fcc34Sopenharmony_ci	if (!strcmp(argv[optind], "help")) {
1885c72fcc34Sopenharmony_ci		retval = help() ? 1 : 0;
1886c72fcc34Sopenharmony_ci	} else if (!strcmp(argv[optind], "info")) {
1887c72fcc34Sopenharmony_ci		retval = info() ? 1 : 0;
1888c72fcc34Sopenharmony_ci	} else if (!strcmp(argv[optind], "controls")) {
1889c72fcc34Sopenharmony_ci		retval = controls(level) ? 1 : 0;
1890c72fcc34Sopenharmony_ci	} else if (!strcmp(argv[optind], "contents")) {
1891c72fcc34Sopenharmony_ci		retval = controls(LEVEL_BASIC | level) ? 1 : 0;
1892c72fcc34Sopenharmony_ci	} else if (!strcmp(argv[optind], "scontrols") || !strcmp(argv[optind], "simple")) {
1893c72fcc34Sopenharmony_ci		retval = selems(level) ? 1 : 0;
1894c72fcc34Sopenharmony_ci	} else if (!strcmp(argv[optind], "scontents")) {
1895c72fcc34Sopenharmony_ci		retval = selems(LEVEL_BASIC | level) ? 1 : 0;
1896c72fcc34Sopenharmony_ci	} else if (!strcmp(argv[optind], "sset") || !strcmp(argv[optind], "set")) {
1897c72fcc34Sopenharmony_ci		retval = sset(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL, 0, 0) ? 1 : 0;
1898c72fcc34Sopenharmony_ci	} else if (!strcmp(argv[optind], "sget") || !strcmp(argv[optind], "get")) {
1899c72fcc34Sopenharmony_ci		retval = sset(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL, 1, 0) ? 1 : 0;
1900c72fcc34Sopenharmony_ci	} else if (!strcmp(argv[optind], "cset")) {
1901c72fcc34Sopenharmony_ci		retval = cset(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL, 0, 0) ? 1 : 0;
1902c72fcc34Sopenharmony_ci	} else if (!strcmp(argv[optind], "cget")) {
1903c72fcc34Sopenharmony_ci		retval = cset(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL, 1, 0) ? 1 : 0;
1904c72fcc34Sopenharmony_ci	} else if (!strcmp(argv[optind], "events")) {
1905c72fcc34Sopenharmony_ci		retval = events(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL);
1906c72fcc34Sopenharmony_ci	} else if (!strcmp(argv[optind], "sevents")) {
1907c72fcc34Sopenharmony_ci		retval = sevents(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL);
1908c72fcc34Sopenharmony_ci	} else {
1909c72fcc34Sopenharmony_ci		fprintf(stderr, "amixer: Unknown command '%s'...\n", argv[optind]);
1910c72fcc34Sopenharmony_ci		retval = 0;
1911c72fcc34Sopenharmony_ci	}
1912c72fcc34Sopenharmony_ci
1913c72fcc34Sopenharmony_cifinish:
1914c72fcc34Sopenharmony_ci	snd_config_update_free_global();
1915c72fcc34Sopenharmony_ci
1916c72fcc34Sopenharmony_ci	return retval;
1917c72fcc34Sopenharmony_ci}
1918