1 /*
2  *  Advanced Linux Sound Architecture Control Program - General info
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 "alsactl.h"
24 
pcm_device_list(snd_ctl_t *ctl, snd_pcm_stream_t stream, bool *first)25 static int pcm_device_list(snd_ctl_t *ctl, snd_pcm_stream_t stream, bool *first)
26 {
27 #ifdef __ALSA_PCM_H
28 	int err, dev, idx;
29 	unsigned int count;
30 	snd_pcm_info_t *pcminfo;
31 	snd_pcm_info_alloca(&pcminfo);
32 	bool streamfirst, subfirst;
33 
34 	dev = -1;
35 	streamfirst = true;
36 	while (1) {
37 		if ((err = snd_ctl_pcm_next_device(ctl, &dev)) < 0) {
38 			error("snd_ctl_pcm_next_device");
39 			return err;
40 		}
41 		if (dev < 0)
42 			break;
43 		snd_pcm_info_set_device(pcminfo, dev);
44 		snd_pcm_info_set_subdevice(pcminfo, 0);
45 		snd_pcm_info_set_stream(pcminfo, stream);
46 		if ((err = snd_ctl_pcm_info(ctl, pcminfo)) < 0) {
47 			if (err != -ENOENT)
48 				return err;
49 			continue;
50 		}
51 		if (*first) {
52 			printf("  pcm:\n");
53 			*first = false;
54 		}
55 		if (streamfirst) {
56 			printf("    - stream: %s\n      devices:\n", snd_pcm_stream_name(stream));
57 			streamfirst = false;
58 		}
59 		printf("        - device: %d\n          id: %s\n          name: %s\n",
60 				dev,
61 				snd_pcm_info_get_id(pcminfo),
62 				snd_pcm_info_get_name(pcminfo));
63 		count = snd_pcm_info_get_subdevices_count(pcminfo);
64 		subfirst = true;
65 		for (idx = 0; idx < (int)count; idx++) {
66 			snd_pcm_info_set_subdevice(pcminfo, idx);
67 			if ((err = snd_ctl_pcm_info(ctl, pcminfo)) < 0) {
68 				error("control digital audio playback info (%s): %s", snd_ctl_name(ctl), snd_strerror(err));
69 				return err;
70 			}
71 			if (subfirst) {
72 				printf("          subdevices:\n");
73 				subfirst = false;
74 			}
75 			printf("            - subdevice: %d\n              name: %s\n",
76 						idx, snd_pcm_info_get_subdevice_name(pcminfo));
77 		}
78 	}
79 #endif
80 	return 0;
81 }
82 
snd_rawmidi_stream_name(snd_rawmidi_stream_t stream)83 static const char *snd_rawmidi_stream_name(snd_rawmidi_stream_t stream)
84 {
85 	if (stream == SND_RAWMIDI_STREAM_INPUT)
86 		return "INPUT";
87 	if (stream == SND_RAWMIDI_STREAM_OUTPUT)
88 		return "OUTPUT";
89 	return "???";
90 }
91 
rawmidi_device_list(snd_ctl_t *ctl, snd_rawmidi_stream_t stream, bool *first)92 static int rawmidi_device_list(snd_ctl_t *ctl, snd_rawmidi_stream_t stream, bool *first)
93 {
94 #ifdef __ALSA_RAWMIDI_H
95 	int err, dev, idx;
96 	unsigned int count;
97 	snd_rawmidi_info_t *info;
98 	snd_rawmidi_info_alloca(&info);
99 	bool streamfirst, subfirst;
100 
101 	dev = -1;
102 	streamfirst = true;
103 	while (1) {
104 		if ((err = snd_ctl_rawmidi_next_device(ctl, &dev)) < 0) {
105 			error("snd_ctl_rawmidi_next_device");
106 			return err;
107 		}
108 		if (dev < 0)
109 			break;
110 		snd_rawmidi_info_set_device(info, dev);
111 		snd_rawmidi_info_set_subdevice(info, 0);
112 		snd_rawmidi_info_set_stream(info, stream);
113 		if ((err = snd_ctl_rawmidi_info(ctl, info)) < 0) {
114 			if (err != -ENOENT)
115 				return err;
116 			continue;
117 		}
118 		if (*first) {
119 			printf("  rawmidi:\n");
120 			*first = false;
121 		}
122 		if (streamfirst) {
123 			printf("    - stream: %s\n      devices:\n", snd_rawmidi_stream_name(stream));
124 			streamfirst = false;
125 		}
126 		printf("        - device: %d\n          id: %s\n          name: %s\n",
127 				dev,
128 				snd_rawmidi_info_get_id(info),
129 				snd_rawmidi_info_get_name(info));
130 		count = snd_rawmidi_info_get_subdevices_count(info);
131 		subfirst = true;
132 		for (idx = 0; idx < (int)count; idx++) {
133 			snd_rawmidi_info_set_subdevice(info, idx);
134 			if ((err = snd_ctl_rawmidi_info(ctl, info)) < 0) {
135 				error("control digital audio playback info (%s): %s", snd_ctl_name(ctl), snd_strerror(err));
136 				return err;
137 			}
138 			if (subfirst) {
139 				printf("          subdevices:\n");
140 				subfirst = false;
141 			}
142 			printf("            - subdevice: %d\n              name: %s\n",
143 						idx, snd_rawmidi_info_get_subdevice_name(info));
144 		}
145 	}
146 #endif
147 	return 0;
148 }
149 
hwdep_device_list(snd_ctl_t *ctl)150 static int hwdep_device_list(snd_ctl_t *ctl)
151 {
152 #ifdef __ALSA_HWDEP_H
153 	int err, dev;
154 	snd_hwdep_info_t *info;
155 	snd_hwdep_info_alloca(&info);
156 	bool first;
157 
158 	dev = -1;
159 	first = true;
160 	while (1) {
161 		if ((err = snd_ctl_hwdep_next_device(ctl, &dev)) < 0) {
162 			error("snd_ctl_pcm_next_device");
163 			return err;
164 		}
165 		if (dev < 0)
166 			break;
167 		snd_hwdep_info_set_device(info, dev);
168 		if ((err = snd_ctl_hwdep_info(ctl, info)) < 0) {
169 			if (err != -ENOENT)
170 				return err;
171 			continue;
172 		}
173 		if (first) {
174 			printf("  hwdep:\n");
175 			first = false;
176 		}
177 		printf("    - device: %d\n      id: %s\n      name: %s\n      iface: %d\n",
178 				dev,
179 				snd_hwdep_info_get_id(info),
180 				snd_hwdep_info_get_name(info),
181 				snd_hwdep_info_get_iface(info));
182 	}
183 #endif
184 	return 0;
185 }
186 
card_info(snd_ctl_t *ctl)187 static int card_info(snd_ctl_t *ctl)
188 {
189 	snd_ctl_card_info_t *info;
190 	snd_ctl_elem_list_t *clist;
191 	int err;
192 
193 	snd_ctl_card_info_alloca(&info);
194 	snd_ctl_elem_list_alloca(&clist);
195 
196 	if ((err = snd_ctl_card_info(ctl, info)) < 0) {
197 		error("Control device %s hw info error: %s", snd_ctl_name(ctl), snd_strerror(err));
198 		return err;
199 	}
200 	printf("#\n# Sound card\n#\n");
201 	printf("- card: %i\n  id: %s\n  name: %s\n  longname: %s\n",
202 		snd_ctl_card_info_get_card(info),
203 		snd_ctl_card_info_get_id(info),
204 		snd_ctl_card_info_get_name(info),
205 		snd_ctl_card_info_get_longname(info));
206 	printf("  driver_name: %s\n", snd_ctl_card_info_get_driver(info));
207 	printf("  mixer_name: %s\n", snd_ctl_card_info_get_mixername(info));
208 	printf("  components: %s\n", snd_ctl_card_info_get_components(info));
209 	if ((err = snd_ctl_elem_list(ctl, clist)) < 0) {
210 		error("snd_ctl_elem_list failure: %s", snd_strerror(err));
211 	} else {
212 		printf("  controls_count: %i\n", snd_ctl_elem_list_get_count(clist));
213 	}
214 	return err;
215 }
216 
general_card_info(int cardno)217 int general_card_info(int cardno)
218 {
219 	snd_ctl_t *ctl;
220 	char dev[16];
221 	bool first;
222 	int err;
223 
224 	snprintf(dev, sizeof(dev), "hw:%i", cardno);
225 	if ((err = snd_ctl_open(&ctl, dev, 0)) < 0) {
226 		error("Control device %s open error: %s", dev, snd_strerror(err));
227 		return err;
228 	}
229 	err = card_info(ctl);
230 
231 	first = true;
232 	if (err >= 0)
233 		err = pcm_device_list(ctl, SND_PCM_STREAM_PLAYBACK, &first);
234 	if (err >= 0)
235 		err = pcm_device_list(ctl, SND_PCM_STREAM_CAPTURE, &first);
236 
237 	first = true;
238 	if (err >= 0)
239 		err = rawmidi_device_list(ctl, SND_RAWMIDI_STREAM_INPUT, &first);
240 	if (err >= 0)
241 		err = rawmidi_device_list(ctl, SND_RAWMIDI_STREAM_OUTPUT, &first);
242 
243 	if (err >= 0)
244 		err = hwdep_device_list(ctl);
245 	snd_ctl_close(ctl);
246 	return err;
247 }
248 
general_info(const char *cardname)249 int general_info(const char *cardname)
250 {
251 	struct snd_card_iterator iter;
252 	int err;
253 
254 	err = snd_card_iterator_sinit(&iter, cardname);
255 	if (err < 0)
256 		return err;
257 	while (snd_card_iterator_next(&iter)) {
258 		if ((err = general_card_info(iter.card)))
259 			return err;
260 	}
261 	return snd_card_iterator_error(&iter);
262 }
263