1c72fcc34Sopenharmony_ci/*
2c72fcc34Sopenharmony_ci *  Advanced Linux Sound Architecture Control Program - General info
3c72fcc34Sopenharmony_ci *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
4c72fcc34Sopenharmony_ci *
5c72fcc34Sopenharmony_ci *
6c72fcc34Sopenharmony_ci *   This program is free software; you can redistribute it and/or modify
7c72fcc34Sopenharmony_ci *   it under the terms of the GNU General Public License as published by
8c72fcc34Sopenharmony_ci *   the Free Software Foundation; either version 2 of the License, or
9c72fcc34Sopenharmony_ci *   (at your option) any later version.
10c72fcc34Sopenharmony_ci *
11c72fcc34Sopenharmony_ci *   This program is distributed in the hope that it will be useful,
12c72fcc34Sopenharmony_ci *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13c72fcc34Sopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14c72fcc34Sopenharmony_ci *   GNU General Public License for more details.
15c72fcc34Sopenharmony_ci *
16c72fcc34Sopenharmony_ci *   You should have received a copy of the GNU General Public License
17c72fcc34Sopenharmony_ci *   along with this program; if not, write to the Free Software
18c72fcc34Sopenharmony_ci *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19c72fcc34Sopenharmony_ci *
20c72fcc34Sopenharmony_ci */
21c72fcc34Sopenharmony_ci
22c72fcc34Sopenharmony_ci#include "aconfig.h"
23c72fcc34Sopenharmony_ci#include "alsactl.h"
24c72fcc34Sopenharmony_ci
25c72fcc34Sopenharmony_cistatic int pcm_device_list(snd_ctl_t *ctl, snd_pcm_stream_t stream, bool *first)
26c72fcc34Sopenharmony_ci{
27c72fcc34Sopenharmony_ci#ifdef __ALSA_PCM_H
28c72fcc34Sopenharmony_ci	int err, dev, idx;
29c72fcc34Sopenharmony_ci	unsigned int count;
30c72fcc34Sopenharmony_ci	snd_pcm_info_t *pcminfo;
31c72fcc34Sopenharmony_ci	snd_pcm_info_alloca(&pcminfo);
32c72fcc34Sopenharmony_ci	bool streamfirst, subfirst;
33c72fcc34Sopenharmony_ci
34c72fcc34Sopenharmony_ci	dev = -1;
35c72fcc34Sopenharmony_ci	streamfirst = true;
36c72fcc34Sopenharmony_ci	while (1) {
37c72fcc34Sopenharmony_ci		if ((err = snd_ctl_pcm_next_device(ctl, &dev)) < 0) {
38c72fcc34Sopenharmony_ci			error("snd_ctl_pcm_next_device");
39c72fcc34Sopenharmony_ci			return err;
40c72fcc34Sopenharmony_ci		}
41c72fcc34Sopenharmony_ci		if (dev < 0)
42c72fcc34Sopenharmony_ci			break;
43c72fcc34Sopenharmony_ci		snd_pcm_info_set_device(pcminfo, dev);
44c72fcc34Sopenharmony_ci		snd_pcm_info_set_subdevice(pcminfo, 0);
45c72fcc34Sopenharmony_ci		snd_pcm_info_set_stream(pcminfo, stream);
46c72fcc34Sopenharmony_ci		if ((err = snd_ctl_pcm_info(ctl, pcminfo)) < 0) {
47c72fcc34Sopenharmony_ci			if (err != -ENOENT)
48c72fcc34Sopenharmony_ci				return err;
49c72fcc34Sopenharmony_ci			continue;
50c72fcc34Sopenharmony_ci		}
51c72fcc34Sopenharmony_ci		if (*first) {
52c72fcc34Sopenharmony_ci			printf("  pcm:\n");
53c72fcc34Sopenharmony_ci			*first = false;
54c72fcc34Sopenharmony_ci		}
55c72fcc34Sopenharmony_ci		if (streamfirst) {
56c72fcc34Sopenharmony_ci			printf("    - stream: %s\n      devices:\n", snd_pcm_stream_name(stream));
57c72fcc34Sopenharmony_ci			streamfirst = false;
58c72fcc34Sopenharmony_ci		}
59c72fcc34Sopenharmony_ci		printf("        - device: %d\n          id: %s\n          name: %s\n",
60c72fcc34Sopenharmony_ci				dev,
61c72fcc34Sopenharmony_ci				snd_pcm_info_get_id(pcminfo),
62c72fcc34Sopenharmony_ci				snd_pcm_info_get_name(pcminfo));
63c72fcc34Sopenharmony_ci		count = snd_pcm_info_get_subdevices_count(pcminfo);
64c72fcc34Sopenharmony_ci		subfirst = true;
65c72fcc34Sopenharmony_ci		for (idx = 0; idx < (int)count; idx++) {
66c72fcc34Sopenharmony_ci			snd_pcm_info_set_subdevice(pcminfo, idx);
67c72fcc34Sopenharmony_ci			if ((err = snd_ctl_pcm_info(ctl, pcminfo)) < 0) {
68c72fcc34Sopenharmony_ci				error("control digital audio playback info (%s): %s", snd_ctl_name(ctl), snd_strerror(err));
69c72fcc34Sopenharmony_ci				return err;
70c72fcc34Sopenharmony_ci			}
71c72fcc34Sopenharmony_ci			if (subfirst) {
72c72fcc34Sopenharmony_ci				printf("          subdevices:\n");
73c72fcc34Sopenharmony_ci				subfirst = false;
74c72fcc34Sopenharmony_ci			}
75c72fcc34Sopenharmony_ci			printf("            - subdevice: %d\n              name: %s\n",
76c72fcc34Sopenharmony_ci						idx, snd_pcm_info_get_subdevice_name(pcminfo));
77c72fcc34Sopenharmony_ci		}
78c72fcc34Sopenharmony_ci	}
79c72fcc34Sopenharmony_ci#endif
80c72fcc34Sopenharmony_ci	return 0;
81c72fcc34Sopenharmony_ci}
82c72fcc34Sopenharmony_ci
83c72fcc34Sopenharmony_cistatic const char *snd_rawmidi_stream_name(snd_rawmidi_stream_t stream)
84c72fcc34Sopenharmony_ci{
85c72fcc34Sopenharmony_ci	if (stream == SND_RAWMIDI_STREAM_INPUT)
86c72fcc34Sopenharmony_ci		return "INPUT";
87c72fcc34Sopenharmony_ci	if (stream == SND_RAWMIDI_STREAM_OUTPUT)
88c72fcc34Sopenharmony_ci		return "OUTPUT";
89c72fcc34Sopenharmony_ci	return "???";
90c72fcc34Sopenharmony_ci}
91c72fcc34Sopenharmony_ci
92c72fcc34Sopenharmony_cistatic int rawmidi_device_list(snd_ctl_t *ctl, snd_rawmidi_stream_t stream, bool *first)
93c72fcc34Sopenharmony_ci{
94c72fcc34Sopenharmony_ci#ifdef __ALSA_RAWMIDI_H
95c72fcc34Sopenharmony_ci	int err, dev, idx;
96c72fcc34Sopenharmony_ci	unsigned int count;
97c72fcc34Sopenharmony_ci	snd_rawmidi_info_t *info;
98c72fcc34Sopenharmony_ci	snd_rawmidi_info_alloca(&info);
99c72fcc34Sopenharmony_ci	bool streamfirst, subfirst;
100c72fcc34Sopenharmony_ci
101c72fcc34Sopenharmony_ci	dev = -1;
102c72fcc34Sopenharmony_ci	streamfirst = true;
103c72fcc34Sopenharmony_ci	while (1) {
104c72fcc34Sopenharmony_ci		if ((err = snd_ctl_rawmidi_next_device(ctl, &dev)) < 0) {
105c72fcc34Sopenharmony_ci			error("snd_ctl_rawmidi_next_device");
106c72fcc34Sopenharmony_ci			return err;
107c72fcc34Sopenharmony_ci		}
108c72fcc34Sopenharmony_ci		if (dev < 0)
109c72fcc34Sopenharmony_ci			break;
110c72fcc34Sopenharmony_ci		snd_rawmidi_info_set_device(info, dev);
111c72fcc34Sopenharmony_ci		snd_rawmidi_info_set_subdevice(info, 0);
112c72fcc34Sopenharmony_ci		snd_rawmidi_info_set_stream(info, stream);
113c72fcc34Sopenharmony_ci		if ((err = snd_ctl_rawmidi_info(ctl, info)) < 0) {
114c72fcc34Sopenharmony_ci			if (err != -ENOENT)
115c72fcc34Sopenharmony_ci				return err;
116c72fcc34Sopenharmony_ci			continue;
117c72fcc34Sopenharmony_ci		}
118c72fcc34Sopenharmony_ci		if (*first) {
119c72fcc34Sopenharmony_ci			printf("  rawmidi:\n");
120c72fcc34Sopenharmony_ci			*first = false;
121c72fcc34Sopenharmony_ci		}
122c72fcc34Sopenharmony_ci		if (streamfirst) {
123c72fcc34Sopenharmony_ci			printf("    - stream: %s\n      devices:\n", snd_rawmidi_stream_name(stream));
124c72fcc34Sopenharmony_ci			streamfirst = false;
125c72fcc34Sopenharmony_ci		}
126c72fcc34Sopenharmony_ci		printf("        - device: %d\n          id: %s\n          name: %s\n",
127c72fcc34Sopenharmony_ci				dev,
128c72fcc34Sopenharmony_ci				snd_rawmidi_info_get_id(info),
129c72fcc34Sopenharmony_ci				snd_rawmidi_info_get_name(info));
130c72fcc34Sopenharmony_ci		count = snd_rawmidi_info_get_subdevices_count(info);
131c72fcc34Sopenharmony_ci		subfirst = true;
132c72fcc34Sopenharmony_ci		for (idx = 0; idx < (int)count; idx++) {
133c72fcc34Sopenharmony_ci			snd_rawmidi_info_set_subdevice(info, idx);
134c72fcc34Sopenharmony_ci			if ((err = snd_ctl_rawmidi_info(ctl, info)) < 0) {
135c72fcc34Sopenharmony_ci				error("control digital audio playback info (%s): %s", snd_ctl_name(ctl), snd_strerror(err));
136c72fcc34Sopenharmony_ci				return err;
137c72fcc34Sopenharmony_ci			}
138c72fcc34Sopenharmony_ci			if (subfirst) {
139c72fcc34Sopenharmony_ci				printf("          subdevices:\n");
140c72fcc34Sopenharmony_ci				subfirst = false;
141c72fcc34Sopenharmony_ci			}
142c72fcc34Sopenharmony_ci			printf("            - subdevice: %d\n              name: %s\n",
143c72fcc34Sopenharmony_ci						idx, snd_rawmidi_info_get_subdevice_name(info));
144c72fcc34Sopenharmony_ci		}
145c72fcc34Sopenharmony_ci	}
146c72fcc34Sopenharmony_ci#endif
147c72fcc34Sopenharmony_ci	return 0;
148c72fcc34Sopenharmony_ci}
149c72fcc34Sopenharmony_ci
150c72fcc34Sopenharmony_cistatic int hwdep_device_list(snd_ctl_t *ctl)
151c72fcc34Sopenharmony_ci{
152c72fcc34Sopenharmony_ci#ifdef __ALSA_HWDEP_H
153c72fcc34Sopenharmony_ci	int err, dev;
154c72fcc34Sopenharmony_ci	snd_hwdep_info_t *info;
155c72fcc34Sopenharmony_ci	snd_hwdep_info_alloca(&info);
156c72fcc34Sopenharmony_ci	bool first;
157c72fcc34Sopenharmony_ci
158c72fcc34Sopenharmony_ci	dev = -1;
159c72fcc34Sopenharmony_ci	first = true;
160c72fcc34Sopenharmony_ci	while (1) {
161c72fcc34Sopenharmony_ci		if ((err = snd_ctl_hwdep_next_device(ctl, &dev)) < 0) {
162c72fcc34Sopenharmony_ci			error("snd_ctl_pcm_next_device");
163c72fcc34Sopenharmony_ci			return err;
164c72fcc34Sopenharmony_ci		}
165c72fcc34Sopenharmony_ci		if (dev < 0)
166c72fcc34Sopenharmony_ci			break;
167c72fcc34Sopenharmony_ci		snd_hwdep_info_set_device(info, dev);
168c72fcc34Sopenharmony_ci		if ((err = snd_ctl_hwdep_info(ctl, info)) < 0) {
169c72fcc34Sopenharmony_ci			if (err != -ENOENT)
170c72fcc34Sopenharmony_ci				return err;
171c72fcc34Sopenharmony_ci			continue;
172c72fcc34Sopenharmony_ci		}
173c72fcc34Sopenharmony_ci		if (first) {
174c72fcc34Sopenharmony_ci			printf("  hwdep:\n");
175c72fcc34Sopenharmony_ci			first = false;
176c72fcc34Sopenharmony_ci		}
177c72fcc34Sopenharmony_ci		printf("    - device: %d\n      id: %s\n      name: %s\n      iface: %d\n",
178c72fcc34Sopenharmony_ci				dev,
179c72fcc34Sopenharmony_ci				snd_hwdep_info_get_id(info),
180c72fcc34Sopenharmony_ci				snd_hwdep_info_get_name(info),
181c72fcc34Sopenharmony_ci				snd_hwdep_info_get_iface(info));
182c72fcc34Sopenharmony_ci	}
183c72fcc34Sopenharmony_ci#endif
184c72fcc34Sopenharmony_ci	return 0;
185c72fcc34Sopenharmony_ci}
186c72fcc34Sopenharmony_ci
187c72fcc34Sopenharmony_cistatic int card_info(snd_ctl_t *ctl)
188c72fcc34Sopenharmony_ci{
189c72fcc34Sopenharmony_ci	snd_ctl_card_info_t *info;
190c72fcc34Sopenharmony_ci	snd_ctl_elem_list_t *clist;
191c72fcc34Sopenharmony_ci	int err;
192c72fcc34Sopenharmony_ci
193c72fcc34Sopenharmony_ci	snd_ctl_card_info_alloca(&info);
194c72fcc34Sopenharmony_ci	snd_ctl_elem_list_alloca(&clist);
195c72fcc34Sopenharmony_ci
196c72fcc34Sopenharmony_ci	if ((err = snd_ctl_card_info(ctl, info)) < 0) {
197c72fcc34Sopenharmony_ci		error("Control device %s hw info error: %s", snd_ctl_name(ctl), snd_strerror(err));
198c72fcc34Sopenharmony_ci		return err;
199c72fcc34Sopenharmony_ci	}
200c72fcc34Sopenharmony_ci	printf("#\n# Sound card\n#\n");
201c72fcc34Sopenharmony_ci	printf("- card: %i\n  id: %s\n  name: %s\n  longname: %s\n",
202c72fcc34Sopenharmony_ci		snd_ctl_card_info_get_card(info),
203c72fcc34Sopenharmony_ci		snd_ctl_card_info_get_id(info),
204c72fcc34Sopenharmony_ci		snd_ctl_card_info_get_name(info),
205c72fcc34Sopenharmony_ci		snd_ctl_card_info_get_longname(info));
206c72fcc34Sopenharmony_ci	printf("  driver_name: %s\n", snd_ctl_card_info_get_driver(info));
207c72fcc34Sopenharmony_ci	printf("  mixer_name: %s\n", snd_ctl_card_info_get_mixername(info));
208c72fcc34Sopenharmony_ci	printf("  components: %s\n", snd_ctl_card_info_get_components(info));
209c72fcc34Sopenharmony_ci	if ((err = snd_ctl_elem_list(ctl, clist)) < 0) {
210c72fcc34Sopenharmony_ci		error("snd_ctl_elem_list failure: %s", snd_strerror(err));
211c72fcc34Sopenharmony_ci	} else {
212c72fcc34Sopenharmony_ci		printf("  controls_count: %i\n", snd_ctl_elem_list_get_count(clist));
213c72fcc34Sopenharmony_ci	}
214c72fcc34Sopenharmony_ci	return err;
215c72fcc34Sopenharmony_ci}
216c72fcc34Sopenharmony_ci
217c72fcc34Sopenharmony_ciint general_card_info(int cardno)
218c72fcc34Sopenharmony_ci{
219c72fcc34Sopenharmony_ci	snd_ctl_t *ctl;
220c72fcc34Sopenharmony_ci	char dev[16];
221c72fcc34Sopenharmony_ci	bool first;
222c72fcc34Sopenharmony_ci	int err;
223c72fcc34Sopenharmony_ci
224c72fcc34Sopenharmony_ci	snprintf(dev, sizeof(dev), "hw:%i", cardno);
225c72fcc34Sopenharmony_ci	if ((err = snd_ctl_open(&ctl, dev, 0)) < 0) {
226c72fcc34Sopenharmony_ci		error("Control device %s open error: %s", dev, snd_strerror(err));
227c72fcc34Sopenharmony_ci		return err;
228c72fcc34Sopenharmony_ci	}
229c72fcc34Sopenharmony_ci	err = card_info(ctl);
230c72fcc34Sopenharmony_ci
231c72fcc34Sopenharmony_ci	first = true;
232c72fcc34Sopenharmony_ci	if (err >= 0)
233c72fcc34Sopenharmony_ci		err = pcm_device_list(ctl, SND_PCM_STREAM_PLAYBACK, &first);
234c72fcc34Sopenharmony_ci	if (err >= 0)
235c72fcc34Sopenharmony_ci		err = pcm_device_list(ctl, SND_PCM_STREAM_CAPTURE, &first);
236c72fcc34Sopenharmony_ci
237c72fcc34Sopenharmony_ci	first = true;
238c72fcc34Sopenharmony_ci	if (err >= 0)
239c72fcc34Sopenharmony_ci		err = rawmidi_device_list(ctl, SND_RAWMIDI_STREAM_INPUT, &first);
240c72fcc34Sopenharmony_ci	if (err >= 0)
241c72fcc34Sopenharmony_ci		err = rawmidi_device_list(ctl, SND_RAWMIDI_STREAM_OUTPUT, &first);
242c72fcc34Sopenharmony_ci
243c72fcc34Sopenharmony_ci	if (err >= 0)
244c72fcc34Sopenharmony_ci		err = hwdep_device_list(ctl);
245c72fcc34Sopenharmony_ci	snd_ctl_close(ctl);
246c72fcc34Sopenharmony_ci	return err;
247c72fcc34Sopenharmony_ci}
248c72fcc34Sopenharmony_ci
249c72fcc34Sopenharmony_ciint general_info(const char *cardname)
250c72fcc34Sopenharmony_ci{
251c72fcc34Sopenharmony_ci	struct snd_card_iterator iter;
252c72fcc34Sopenharmony_ci	int err;
253c72fcc34Sopenharmony_ci
254c72fcc34Sopenharmony_ci	err = snd_card_iterator_sinit(&iter, cardname);
255c72fcc34Sopenharmony_ci	if (err < 0)
256c72fcc34Sopenharmony_ci		return err;
257c72fcc34Sopenharmony_ci	while (snd_card_iterator_next(&iter)) {
258c72fcc34Sopenharmony_ci		if ((err = general_card_info(iter.card)))
259c72fcc34Sopenharmony_ci			return err;
260c72fcc34Sopenharmony_ci	}
261c72fcc34Sopenharmony_ci	return snd_card_iterator_error(&iter);
262c72fcc34Sopenharmony_ci}
263