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