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