• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
clean_one_control(snd_ctl_t * handle,snd_ctl_elem_id_t * elem_id,snd_ctl_elem_id_t ** filter)31 static 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 
filter_controls_free(snd_ctl_elem_id_t ** _filter)75 static 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 
filter_controls_parse(char * const * controls,snd_ctl_elem_id_t *** _filter)84 static 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) {
99 nomem:
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 	}
120 fin:
121 	*_filter = filter;
122 	return 0;
123 }
124 
clean_controls(int cardno,char * const * controls)125 static 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 	}
173 fin_ok:
174 	filter_controls_free(filter);
175 	snd_ctl_close(handle);
176 	return 0;
177 fin_err:
178 	filter_controls_free(filter);
179 	snd_ctl_close(handle);
180 	return err;
181 }
182 
clean(const char * cardname,char * const * extra_args)183 int 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