xref: /third_party/alsa-utils/alsactl/clean.c (revision c72fcc34)
1/*
2 *  Advanced Linux Sound Architecture Control Program
3 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
4 *
5 *
6 *   This program is free software; you can redistribute it and/or modify
7 *   it under the terms of the GNU General Public License as published by
8 *   the Free Software Foundation; either version 2 of the License, or
9 *   (at your option) any later version.
10 *
11 *   This program is distributed in the hope that it will be useful,
12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *   GNU General Public License for more details.
15 *
16 *   You should have received a copy of the GNU General Public License
17 *   along with this program; if not, write to the Free Software
18 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19 *
20 */
21
22#include "aconfig.h"
23#include "version.h"
24#include <getopt.h>
25#include <stdarg.h>
26#include <stdio.h>
27#include <assert.h>
28#include <errno.h>
29#include "alsactl.h"
30
31static int clean_one_control(snd_ctl_t *handle, snd_ctl_elem_id_t *elem_id,
32			     snd_ctl_elem_id_t **filter)
33{
34	snd_ctl_elem_info_t *info;
35	char *s;
36	int err;
37
38	snd_ctl_elem_info_alloca(&info);
39	snd_ctl_elem_info_set_id(info, elem_id);
40	err = snd_ctl_elem_info(handle, info);
41	if (err < 0) {
42		s = snd_ctl_ascii_elem_id_get(elem_id);
43		error("Cannot read control info '%s': %s", s, snd_strerror(err));
44		free(s);
45		return err;
46	}
47
48	if (!snd_ctl_elem_info_is_user(info))
49		return 0;
50
51	s = snd_ctl_ascii_elem_id_get(elem_id);
52	dbg("Application control \"%s\" found.", s);
53	if (filter) {
54		for (; *filter; filter++) {
55			if (snd_ctl_elem_id_compare_set(elem_id, *filter) == 0)
56				break;
57		}
58		if (*filter == NULL) {
59			free(s);
60			return 0;
61		}
62	}
63
64	err = snd_ctl_elem_remove(handle, elem_id);
65	if (err < 0) {
66		error("Cannot remove control '%s': %s", s, snd_strerror(err));
67		free(s);
68		return err;
69	}
70	dbg("Application control \"%s\" removed.", s);
71	free(s);
72	return 0;
73}
74
75static void filter_controls_free(snd_ctl_elem_id_t **_filter)
76{
77	snd_ctl_elem_id_t **filter;
78
79	for (filter = _filter; filter; filter++)
80		free(*filter);
81	free(_filter);
82}
83
84static int filter_controls_parse(char *const *controls, snd_ctl_elem_id_t ***_filter)
85{
86	snd_ctl_elem_id_t **filter = NULL;
87	char *const *c;
88	char *s;
89	unsigned int count, idx;
90	int err;
91
92	if (!controls)
93		goto fin;
94	for (count = 0, c = controls; *c; c++, count++);
95	if (count == 0)
96		goto fin;
97	filter = calloc(count + 1, sizeof(snd_ctl_elem_id_t *));
98	if (filter == NULL) {
99nomem:
100		error("No enough memory...");
101		return -ENOMEM;
102	}
103	filter[count] = NULL;
104	for (idx = 0; idx < count; idx++) {
105		err = snd_ctl_elem_id_malloc(&filter[idx]);
106		if (err < 0) {
107			filter_controls_free(filter);
108			goto nomem;
109		}
110		err = snd_ctl_ascii_elem_id_parse(filter[idx], controls[idx]);
111		if (err < 0) {
112			error("Cannot parse id '%s': %s", controls[idx], snd_strerror(err));
113			filter_controls_free(filter);
114			return err;
115		}
116		s = snd_ctl_ascii_elem_id_get(filter[idx]);
117		dbg("Add to filter: \"%s\"", s);
118		free(s);
119	}
120fin:
121	*_filter = filter;
122	return 0;
123}
124
125static int clean_controls(int cardno, char *const *controls)
126{
127	snd_ctl_t *handle;
128	snd_ctl_elem_list_t *list;
129	snd_ctl_elem_id_t *elem_id;
130	snd_ctl_elem_id_t **filter;
131	char name[32];
132	unsigned int idx, count;
133	int err;
134
135	snd_ctl_elem_id_alloca(&elem_id);
136	snd_ctl_elem_list_alloca(&list);
137
138	err = filter_controls_parse(controls, &filter);
139	if (err < 0)
140		return err;
141
142	sprintf(name, "hw:%d", cardno);
143	err = snd_ctl_open(&handle, name, 0);
144	if (err < 0) {
145		error("snd_ctl_open error: %s", snd_strerror(err));
146		filter_controls_free(filter);
147		return err;
148	}
149	dbg("Control device '%s' opened.", name);
150	err = snd_ctl_elem_list(handle, list);
151	if (err < 0) {
152		error("Cannot determine controls: %s", snd_strerror(err));
153		goto fin_err;
154	}
155	count = snd_ctl_elem_list_get_count(list);
156	if (count == 0)
157		goto fin_ok;
158	snd_ctl_elem_list_set_offset(list, 0);
159	if ((err = snd_ctl_elem_list_alloc_space(list, count)) < 0) {
160		error("No enough memory...");
161		goto fin_err;
162	}
163	if ((err = snd_ctl_elem_list(handle, list)) < 0) {
164		error("Cannot determine controls (2): %s", snd_strerror(err));
165		goto fin_err;
166	}
167	for (idx = 0; idx < count; idx++) {
168		snd_ctl_elem_list_get_id(list, idx, elem_id);
169		err = clean_one_control(handle, elem_id, filter);
170		if (err < 0)
171			goto fin_err;
172	}
173fin_ok:
174	filter_controls_free(filter);
175	snd_ctl_close(handle);
176	return 0;
177fin_err:
178	filter_controls_free(filter);
179	snd_ctl_close(handle);
180	return err;
181}
182
183int clean(const char *cardname, char *const *extra_args)
184{
185	struct snd_card_iterator iter;
186	int err;
187
188	err = snd_card_iterator_sinit(&iter, cardname);
189	if (err < 0)
190		return err;
191	while (snd_card_iterator_next(&iter)) {
192		if ((err = clean_controls(iter.card, extra_args)))
193			return err;
194	}
195	return snd_card_iterator_error(&iter);
196}
197