1c72fcc34Sopenharmony_ci/*
2c72fcc34Sopenharmony_ci * mixer_controls.c - handles mixer controls and mapping from selems
3c72fcc34Sopenharmony_ci * Copyright (c) 1998,1999 Tim Janik
4c72fcc34Sopenharmony_ci *                         Jaroslav Kysela <perex@perex.cz>
5c72fcc34Sopenharmony_ci * Copyright (c) 2009      Clemens Ladisch <clemens@ladisch.de>
6c72fcc34Sopenharmony_ci *
7c72fcc34Sopenharmony_ci * This program is free software: you can redistribute it and/or modify
8c72fcc34Sopenharmony_ci * it under the terms of the GNU General Public License as published by
9c72fcc34Sopenharmony_ci * the Free Software Foundation, either version 2 of the License, or
10c72fcc34Sopenharmony_ci * (at your option) any later version.
11c72fcc34Sopenharmony_ci *
12c72fcc34Sopenharmony_ci * This program is distributed in the hope that it will be useful,
13c72fcc34Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
14c72fcc34Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15c72fcc34Sopenharmony_ci * GNU General Public License for more details.
16c72fcc34Sopenharmony_ci *
17c72fcc34Sopenharmony_ci * You should have received a copy of the GNU General Public License
18c72fcc34Sopenharmony_ci * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19c72fcc34Sopenharmony_ci */
20c72fcc34Sopenharmony_ci
21c72fcc34Sopenharmony_ci#include "aconfig.h"
22c72fcc34Sopenharmony_ci#include <stdlib.h>
23c72fcc34Sopenharmony_ci#include <string.h>
24c72fcc34Sopenharmony_ci#include <assert.h>
25c72fcc34Sopenharmony_ci#include CURSESINC
26c72fcc34Sopenharmony_ci#include <alsa/asoundlib.h>
27c72fcc34Sopenharmony_ci#include "utils.h"
28c72fcc34Sopenharmony_ci#include "mem.h"
29c72fcc34Sopenharmony_ci#include "mixer_display.h"
30c72fcc34Sopenharmony_ci#include "mixer_widget.h"
31c72fcc34Sopenharmony_ci#include "mixer_controls.h"
32c72fcc34Sopenharmony_ci
33c72fcc34Sopenharmony_cistruct control *controls;
34c72fcc34Sopenharmony_ciunsigned int controls_count;
35c72fcc34Sopenharmony_ci
36c72fcc34Sopenharmony_cistatic const snd_mixer_selem_channel_id_t supported_channels[] = {
37c72fcc34Sopenharmony_ci	SND_MIXER_SCHN_FRONT_LEFT,
38c72fcc34Sopenharmony_ci	SND_MIXER_SCHN_FRONT_RIGHT,
39c72fcc34Sopenharmony_ci	SND_MIXER_SCHN_REAR_LEFT,
40c72fcc34Sopenharmony_ci	SND_MIXER_SCHN_REAR_RIGHT,
41c72fcc34Sopenharmony_ci	SND_MIXER_SCHN_FRONT_CENTER,
42c72fcc34Sopenharmony_ci	SND_MIXER_SCHN_WOOFER,
43c72fcc34Sopenharmony_ci	SND_MIXER_SCHN_SIDE_LEFT,
44c72fcc34Sopenharmony_ci	SND_MIXER_SCHN_SIDE_RIGHT,
45c72fcc34Sopenharmony_ci};
46c72fcc34Sopenharmony_ci#define LAST_SUPPORTED_CHANNEL SND_MIXER_SCHN_SIDE_RIGHT
47c72fcc34Sopenharmony_ci
48c72fcc34Sopenharmony_cistatic const snd_mixer_selem_channel_id_t control_channels[][2] = {
49c72fcc34Sopenharmony_ci	{ SND_MIXER_SCHN_FRONT_LEFT, SND_MIXER_SCHN_FRONT_RIGHT },
50c72fcc34Sopenharmony_ci	{ SND_MIXER_SCHN_REAR_LEFT, SND_MIXER_SCHN_REAR_RIGHT },
51c72fcc34Sopenharmony_ci	{ SND_MIXER_SCHN_FRONT_CENTER, SND_MIXER_SCHN_UNKNOWN },
52c72fcc34Sopenharmony_ci	{ SND_MIXER_SCHN_WOOFER, SND_MIXER_SCHN_UNKNOWN },
53c72fcc34Sopenharmony_ci	{ SND_MIXER_SCHN_SIDE_LEFT, SND_MIXER_SCHN_SIDE_RIGHT },
54c72fcc34Sopenharmony_ci};
55c72fcc34Sopenharmony_ci
56c72fcc34Sopenharmony_cibool are_there_any_controls(void)
57c72fcc34Sopenharmony_ci{
58c72fcc34Sopenharmony_ci	snd_mixer_elem_t *elem;
59c72fcc34Sopenharmony_ci	unsigned int i;
60c72fcc34Sopenharmony_ci
61c72fcc34Sopenharmony_ci	for (elem = snd_mixer_first_elem(mixer);
62c72fcc34Sopenharmony_ci	     elem;
63c72fcc34Sopenharmony_ci	     elem = snd_mixer_elem_next(elem)) {
64c72fcc34Sopenharmony_ci		if (snd_mixer_elem_get_type(elem) != SND_MIXER_ELEM_SIMPLE)
65c72fcc34Sopenharmony_ci			continue;
66c72fcc34Sopenharmony_ci		if (snd_mixer_selem_is_enumerated(elem))
67c72fcc34Sopenharmony_ci			return TRUE;
68c72fcc34Sopenharmony_ci		if (snd_mixer_selem_has_playback_volume_joined(elem) ||
69c72fcc34Sopenharmony_ci		    snd_mixer_selem_has_capture_volume_joined(elem) ||
70c72fcc34Sopenharmony_ci		    snd_mixer_selem_has_playback_switch_joined(elem) ||
71c72fcc34Sopenharmony_ci		    snd_mixer_selem_has_capture_switch_joined(elem))
72c72fcc34Sopenharmony_ci			return TRUE;
73c72fcc34Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(supported_channels); ++i)
74c72fcc34Sopenharmony_ci			if (snd_mixer_selem_has_playback_channel(elem, supported_channels[i]) ||
75c72fcc34Sopenharmony_ci			    snd_mixer_selem_has_capture_channel(elem, supported_channels[i]))
76c72fcc34Sopenharmony_ci				return TRUE;
77c72fcc34Sopenharmony_ci	}
78c72fcc34Sopenharmony_ci	return FALSE;
79c72fcc34Sopenharmony_ci}
80c72fcc34Sopenharmony_ci
81c72fcc34Sopenharmony_cistatic bool has_more_than_front_capture_channels(snd_mixer_elem_t *elem)
82c72fcc34Sopenharmony_ci{
83c72fcc34Sopenharmony_ci	unsigned int i;
84c72fcc34Sopenharmony_ci
85c72fcc34Sopenharmony_ci	for (i = 2; i < ARRAY_SIZE(supported_channels); ++i)
86c72fcc34Sopenharmony_ci		if (snd_mixer_selem_has_capture_channel(elem, supported_channels[i]))
87c72fcc34Sopenharmony_ci			return TRUE;
88c72fcc34Sopenharmony_ci	return FALSE;
89c72fcc34Sopenharmony_ci}
90c72fcc34Sopenharmony_ci
91c72fcc34Sopenharmony_cistatic bool has_any_control_channel(snd_mixer_elem_t *elem,
92c72fcc34Sopenharmony_ci				    const snd_mixer_selem_channel_id_t channels[2],
93c72fcc34Sopenharmony_ci				    int (*has_channel)(snd_mixer_elem_t *, snd_mixer_selem_channel_id_t))
94c72fcc34Sopenharmony_ci{
95c72fcc34Sopenharmony_ci	return has_channel(elem, channels[0]) ||
96c72fcc34Sopenharmony_ci	       (channels[1] != SND_MIXER_SCHN_UNKNOWN && has_channel(elem, channels[1]));
97c72fcc34Sopenharmony_ci}
98c72fcc34Sopenharmony_ci
99c72fcc34Sopenharmony_cistatic bool has_merged_cswitch(snd_mixer_elem_t *elem)
100c72fcc34Sopenharmony_ci{
101c72fcc34Sopenharmony_ci	bool pvol, psw;
102c72fcc34Sopenharmony_ci	unsigned int i;
103c72fcc34Sopenharmony_ci
104c72fcc34Sopenharmony_ci	pvol = snd_mixer_selem_has_playback_volume(elem);
105c72fcc34Sopenharmony_ci	psw = snd_mixer_selem_has_playback_switch(elem);
106c72fcc34Sopenharmony_ci	if ((pvol || psw) &&
107c72fcc34Sopenharmony_ci	    snd_mixer_selem_has_capture_switch(elem) &&
108c72fcc34Sopenharmony_ci	    !snd_mixer_selem_has_capture_volume(elem)) {
109c72fcc34Sopenharmony_ci		if (snd_mixer_selem_has_capture_switch_joined(elem))
110c72fcc34Sopenharmony_ci			return TRUE;
111c72fcc34Sopenharmony_ci		else if (((pvol && snd_mixer_selem_has_playback_volume_joined(elem)) ||
112c72fcc34Sopenharmony_ci			  (psw && snd_mixer_selem_has_playback_switch_joined(elem))) &&
113c72fcc34Sopenharmony_ci			 has_more_than_front_capture_channels(elem))
114c72fcc34Sopenharmony_ci			return FALSE;
115c72fcc34Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(control_channels); ++i) {
116c72fcc34Sopenharmony_ci			if (has_any_control_channel(elem, control_channels[i], snd_mixer_selem_has_capture_channel) &&
117c72fcc34Sopenharmony_ci			    !has_any_control_channel(elem, control_channels[i], snd_mixer_selem_has_playback_channel))
118c72fcc34Sopenharmony_ci				return FALSE;
119c72fcc34Sopenharmony_ci		}
120c72fcc34Sopenharmony_ci		return TRUE;
121c72fcc34Sopenharmony_ci	}
122c72fcc34Sopenharmony_ci	return FALSE;
123c72fcc34Sopenharmony_ci}
124c72fcc34Sopenharmony_ci
125c72fcc34Sopenharmony_cistatic unsigned int get_playback_controls_count(snd_mixer_elem_t *elem)
126c72fcc34Sopenharmony_ci{
127c72fcc34Sopenharmony_ci	unsigned int count = 0;
128c72fcc34Sopenharmony_ci	unsigned int i;
129c72fcc34Sopenharmony_ci	int has_vol, has_sw;
130c72fcc34Sopenharmony_ci
131c72fcc34Sopenharmony_ci	has_vol = snd_mixer_selem_has_playback_volume(elem);
132c72fcc34Sopenharmony_ci	has_sw = snd_mixer_selem_has_playback_switch(elem);
133c72fcc34Sopenharmony_ci	if (!has_vol && !has_sw)
134c72fcc34Sopenharmony_ci		return 0;
135c72fcc34Sopenharmony_ci	if ((!has_vol || snd_mixer_selem_has_playback_volume_joined(elem)) &&
136c72fcc34Sopenharmony_ci	    (!has_sw || snd_mixer_selem_has_playback_switch_joined(elem)))
137c72fcc34Sopenharmony_ci		return 1;
138c72fcc34Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(control_channels); ++i) {
139c72fcc34Sopenharmony_ci		if (snd_mixer_selem_has_playback_channel(elem, control_channels[i][0]) ||
140c72fcc34Sopenharmony_ci		    (control_channels[i][1] != SND_MIXER_SCHN_UNKNOWN &&
141c72fcc34Sopenharmony_ci		     snd_mixer_selem_has_playback_channel(elem, control_channels[i][1])))
142c72fcc34Sopenharmony_ci			++count;
143c72fcc34Sopenharmony_ci	}
144c72fcc34Sopenharmony_ci	return count;
145c72fcc34Sopenharmony_ci}
146c72fcc34Sopenharmony_ci
147c72fcc34Sopenharmony_cistatic unsigned int get_capture_controls_count(snd_mixer_elem_t *elem)
148c72fcc34Sopenharmony_ci{
149c72fcc34Sopenharmony_ci	unsigned int count = 0;
150c72fcc34Sopenharmony_ci	unsigned int i;
151c72fcc34Sopenharmony_ci	int has_vol, has_sw;
152c72fcc34Sopenharmony_ci
153c72fcc34Sopenharmony_ci	has_vol = snd_mixer_selem_has_capture_volume(elem);
154c72fcc34Sopenharmony_ci	has_sw = snd_mixer_selem_has_capture_switch(elem);
155c72fcc34Sopenharmony_ci	if ((!has_vol && !has_sw) ||
156c72fcc34Sopenharmony_ci	    (view_mode == VIEW_MODE_ALL && has_merged_cswitch(elem)))
157c72fcc34Sopenharmony_ci		return 0;
158c72fcc34Sopenharmony_ci	if ((!has_vol || snd_mixer_selem_has_capture_volume_joined(elem)) &&
159c72fcc34Sopenharmony_ci	    (!has_sw || snd_mixer_selem_has_capture_switch_joined(elem)))
160c72fcc34Sopenharmony_ci		return 1;
161c72fcc34Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(control_channels); ++i) {
162c72fcc34Sopenharmony_ci		if (snd_mixer_selem_has_capture_channel(elem, control_channels[i][0]) ||
163c72fcc34Sopenharmony_ci		    (control_channels[i][1] != SND_MIXER_SCHN_UNKNOWN &&
164c72fcc34Sopenharmony_ci		     snd_mixer_selem_has_capture_channel(elem, control_channels[i][1])))
165c72fcc34Sopenharmony_ci			++count;
166c72fcc34Sopenharmony_ci	}
167c72fcc34Sopenharmony_ci	return count;
168c72fcc34Sopenharmony_ci}
169c72fcc34Sopenharmony_ci
170c72fcc34Sopenharmony_cistatic unsigned int get_controls_count_for_elem(snd_mixer_elem_t *elem)
171c72fcc34Sopenharmony_ci{
172c72fcc34Sopenharmony_ci	unsigned int p, c;
173c72fcc34Sopenharmony_ci
174c72fcc34Sopenharmony_ci	if (snd_mixer_elem_get_type(elem) != SND_MIXER_ELEM_SIMPLE)
175c72fcc34Sopenharmony_ci		return 0;
176c72fcc34Sopenharmony_ci	if (snd_mixer_selem_is_enumerated(elem)) {
177c72fcc34Sopenharmony_ci		switch (view_mode) {
178c72fcc34Sopenharmony_ci		case VIEW_MODE_PLAYBACK:
179c72fcc34Sopenharmony_ci			return snd_mixer_selem_is_enum_capture(elem) ? 0 : 1;
180c72fcc34Sopenharmony_ci		case VIEW_MODE_CAPTURE:
181c72fcc34Sopenharmony_ci			return snd_mixer_selem_is_enum_capture(elem) ? 1 : 0;
182c72fcc34Sopenharmony_ci		case VIEW_MODE_ALL:
183c72fcc34Sopenharmony_ci		default:
184c72fcc34Sopenharmony_ci			return 1;
185c72fcc34Sopenharmony_ci		}
186c72fcc34Sopenharmony_ci	}
187c72fcc34Sopenharmony_ci	switch (view_mode) {
188c72fcc34Sopenharmony_ci	case VIEW_MODE_PLAYBACK:
189c72fcc34Sopenharmony_ci		return get_playback_controls_count(elem);
190c72fcc34Sopenharmony_ci	case VIEW_MODE_CAPTURE:
191c72fcc34Sopenharmony_ci		return get_capture_controls_count(elem);
192c72fcc34Sopenharmony_ci	case VIEW_MODE_ALL:
193c72fcc34Sopenharmony_ci	default:
194c72fcc34Sopenharmony_ci		p = get_playback_controls_count(elem);
195c72fcc34Sopenharmony_ci		c = get_capture_controls_count(elem);
196c72fcc34Sopenharmony_ci		return has_merged_cswitch(elem) ? p : p + c;
197c72fcc34Sopenharmony_ci	}
198c72fcc34Sopenharmony_ci}
199c72fcc34Sopenharmony_ci
200c72fcc34Sopenharmony_cistatic void create_name(struct control *control)
201c72fcc34Sopenharmony_ci{
202c72fcc34Sopenharmony_ci	unsigned int index;
203c72fcc34Sopenharmony_ci	char *s;
204c72fcc34Sopenharmony_ci
205c72fcc34Sopenharmony_ci	index = snd_mixer_selem_get_index(control->elem);
206c72fcc34Sopenharmony_ci	if (index > 0)
207c72fcc34Sopenharmony_ci		control->name = casprintf("%s %u", snd_mixer_selem_get_name(control->elem), index);
208c72fcc34Sopenharmony_ci	else
209c72fcc34Sopenharmony_ci		control->name = cstrdup(snd_mixer_selem_get_name(control->elem));
210c72fcc34Sopenharmony_ci
211c72fcc34Sopenharmony_ci	while ((s = strstr(control->name, "IEC958")) != NULL)
212c72fcc34Sopenharmony_ci		memcpy(s, "S/PDIF", 6);
213c72fcc34Sopenharmony_ci}
214c72fcc34Sopenharmony_ci
215c72fcc34Sopenharmony_cistatic unsigned int create_controls_for_elem(snd_mixer_elem_t *elem, struct control *control)
216c72fcc34Sopenharmony_ci{
217c72fcc34Sopenharmony_ci	unsigned int count = 0;
218c72fcc34Sopenharmony_ci	unsigned int i;
219c72fcc34Sopenharmony_ci	unsigned int enum_index;
220c72fcc34Sopenharmony_ci	struct control *front_control = NULL;
221c72fcc34Sopenharmony_ci	bool has_pvol, has_psw;
222c72fcc34Sopenharmony_ci	bool has_cvol, has_csw;
223c72fcc34Sopenharmony_ci	bool has_channel[LAST_SUPPORTED_CHANNEL + 1];
224c72fcc34Sopenharmony_ci	bool merged_cswitch;
225c72fcc34Sopenharmony_ci	bool has_ch0, has_ch1;
226c72fcc34Sopenharmony_ci
227c72fcc34Sopenharmony_ci	if (snd_mixer_elem_get_type(elem) != SND_MIXER_ELEM_SIMPLE)
228c72fcc34Sopenharmony_ci		return 0;
229c72fcc34Sopenharmony_ci	if (snd_mixer_selem_is_enumerated(elem)) {
230c72fcc34Sopenharmony_ci		if ((view_mode == VIEW_MODE_PLAYBACK && snd_mixer_selem_is_enum_capture(elem)) ||
231c72fcc34Sopenharmony_ci		    (view_mode == VIEW_MODE_CAPTURE && !snd_mixer_selem_is_enum_capture(elem)))
232c72fcc34Sopenharmony_ci			return 0;
233c72fcc34Sopenharmony_ci		control->elem = elem;
234c72fcc34Sopenharmony_ci		control->flags = TYPE_ENUM;
235c72fcc34Sopenharmony_ci		control->enum_channel_bits = 0;
236c72fcc34Sopenharmony_ci		for (i = 0; i <= SND_MIXER_SCHN_LAST; ++i)
237c72fcc34Sopenharmony_ci			if (snd_mixer_selem_get_enum_item(control->elem, (snd_mixer_selem_channel_id_t)i, &enum_index) >= 0)
238c72fcc34Sopenharmony_ci				control->enum_channel_bits |= 1 << i;
239c72fcc34Sopenharmony_ci		if (snd_mixer_selem_is_active(control->elem))
240c72fcc34Sopenharmony_ci			control->flags |= IS_ACTIVE;
241c72fcc34Sopenharmony_ci		create_name(control);
242c72fcc34Sopenharmony_ci		return 1;
243c72fcc34Sopenharmony_ci	}
244c72fcc34Sopenharmony_ci	has_pvol = snd_mixer_selem_has_playback_volume(elem);
245c72fcc34Sopenharmony_ci	has_psw = snd_mixer_selem_has_playback_switch(elem);
246c72fcc34Sopenharmony_ci	has_cvol = snd_mixer_selem_has_capture_volume(elem);
247c72fcc34Sopenharmony_ci	has_csw = snd_mixer_selem_has_capture_switch(elem);
248c72fcc34Sopenharmony_ci	merged_cswitch = view_mode == VIEW_MODE_ALL && has_merged_cswitch(elem);
249c72fcc34Sopenharmony_ci	if (view_mode != VIEW_MODE_CAPTURE && (has_pvol || has_psw)) {
250c72fcc34Sopenharmony_ci		if ((!has_pvol || snd_mixer_selem_has_playback_volume_joined(elem)) &&
251c72fcc34Sopenharmony_ci		    (!has_psw || snd_mixer_selem_has_playback_switch_joined(elem))) {
252c72fcc34Sopenharmony_ci			control->elem = elem;
253c72fcc34Sopenharmony_ci			if (has_pvol) {
254c72fcc34Sopenharmony_ci				control->flags |= TYPE_PVOLUME | HAS_VOLUME_0;
255c72fcc34Sopenharmony_ci				control->volume_channels[0] = 0;
256c72fcc34Sopenharmony_ci			}
257c72fcc34Sopenharmony_ci			if (has_psw) {
258c72fcc34Sopenharmony_ci				control->flags |= TYPE_PSWITCH | HAS_PSWITCH_0;
259c72fcc34Sopenharmony_ci				control->pswitch_channels[0] = 0;
260c72fcc34Sopenharmony_ci			}
261c72fcc34Sopenharmony_ci			if (merged_cswitch) {
262c72fcc34Sopenharmony_ci				control->flags |= TYPE_CSWITCH;
263c72fcc34Sopenharmony_ci				if (snd_mixer_selem_has_capture_switch_joined(elem)) {
264c72fcc34Sopenharmony_ci					control->flags |= HAS_CSWITCH_0;
265c72fcc34Sopenharmony_ci					control->cswitch_channels[0] = 0;
266c72fcc34Sopenharmony_ci				} else {
267c72fcc34Sopenharmony_ci					if (snd_mixer_selem_has_capture_channel(elem, control_channels[0][0])) {
268c72fcc34Sopenharmony_ci						control->flags |= HAS_CSWITCH_0;
269c72fcc34Sopenharmony_ci						control->cswitch_channels[0] = control_channels[0][0];
270c72fcc34Sopenharmony_ci					}
271c72fcc34Sopenharmony_ci					if (control_channels[0][1] != SND_MIXER_SCHN_UNKNOWN &&
272c72fcc34Sopenharmony_ci					    snd_mixer_selem_has_capture_channel(elem, control_channels[0][1])) {
273c72fcc34Sopenharmony_ci						control->flags |= HAS_CSWITCH_1;
274c72fcc34Sopenharmony_ci						control->cswitch_channels[1] = control_channels[0][1];
275c72fcc34Sopenharmony_ci					}
276c72fcc34Sopenharmony_ci				}
277c72fcc34Sopenharmony_ci				if ((control->flags & (HAS_CSWITCH_0 | HAS_CSWITCH_1)) == HAS_CSWITCH_1) {
278c72fcc34Sopenharmony_ci					control->flags ^= HAS_CSWITCH_0 | HAS_CSWITCH_1;
279c72fcc34Sopenharmony_ci					control->cswitch_channels[0] = control->cswitch_channels[1];
280c72fcc34Sopenharmony_ci				}
281c72fcc34Sopenharmony_ci			}
282c72fcc34Sopenharmony_ci			if (snd_mixer_selem_is_active(control->elem))
283c72fcc34Sopenharmony_ci				control->flags |= IS_ACTIVE;
284c72fcc34Sopenharmony_ci			create_name(control);
285c72fcc34Sopenharmony_ci			++control;
286c72fcc34Sopenharmony_ci			++count;
287c72fcc34Sopenharmony_ci		} else {
288c72fcc34Sopenharmony_ci			for (i = 0; i < ARRAY_SIZE(supported_channels); ++i)
289c72fcc34Sopenharmony_ci				has_channel[supported_channels[i]] =
290c72fcc34Sopenharmony_ci					snd_mixer_selem_has_playback_channel(elem, supported_channels[i]);
291c72fcc34Sopenharmony_ci			for (i = 0; i < ARRAY_SIZE(control_channels); ++i) {
292c72fcc34Sopenharmony_ci				has_ch0 = has_channel[control_channels[i][0]];
293c72fcc34Sopenharmony_ci				has_ch1 = control_channels[i][1] != SND_MIXER_SCHN_UNKNOWN &&
294c72fcc34Sopenharmony_ci					has_channel[control_channels[i][1]];
295c72fcc34Sopenharmony_ci				if (!has_ch0 && !has_ch1)
296c72fcc34Sopenharmony_ci					continue;
297c72fcc34Sopenharmony_ci				control->elem = elem;
298c72fcc34Sopenharmony_ci				if (has_pvol) {
299c72fcc34Sopenharmony_ci					control->flags |= TYPE_PVOLUME;
300c72fcc34Sopenharmony_ci					if (snd_mixer_selem_has_playback_volume_joined(elem)) {
301c72fcc34Sopenharmony_ci						control->flags |= HAS_VOLUME_0;
302c72fcc34Sopenharmony_ci						control->volume_channels[0] = 0;
303c72fcc34Sopenharmony_ci					} else {
304c72fcc34Sopenharmony_ci						if (has_ch0) {
305c72fcc34Sopenharmony_ci							control->flags |= HAS_VOLUME_0;
306c72fcc34Sopenharmony_ci							control->volume_channels[0] = control_channels[i][0];
307c72fcc34Sopenharmony_ci						}
308c72fcc34Sopenharmony_ci						if (has_ch1) {
309c72fcc34Sopenharmony_ci							control->flags |= HAS_VOLUME_1;
310c72fcc34Sopenharmony_ci							control->volume_channels[1] = control_channels[i][1];
311c72fcc34Sopenharmony_ci						}
312c72fcc34Sopenharmony_ci					}
313c72fcc34Sopenharmony_ci				}
314c72fcc34Sopenharmony_ci				if (has_psw) {
315c72fcc34Sopenharmony_ci					control->flags |= TYPE_PSWITCH;
316c72fcc34Sopenharmony_ci					if (snd_mixer_selem_has_playback_switch_joined(elem)) {
317c72fcc34Sopenharmony_ci						control->flags |= HAS_PSWITCH_0;
318c72fcc34Sopenharmony_ci						control->pswitch_channels[0] = 0;
319c72fcc34Sopenharmony_ci					} else {
320c72fcc34Sopenharmony_ci						if (has_ch0) {
321c72fcc34Sopenharmony_ci							control->flags |= HAS_PSWITCH_0;
322c72fcc34Sopenharmony_ci							control->pswitch_channels[0] = control_channels[i][0];
323c72fcc34Sopenharmony_ci						}
324c72fcc34Sopenharmony_ci						if (has_ch1) {
325c72fcc34Sopenharmony_ci							control->flags |= HAS_PSWITCH_1;
326c72fcc34Sopenharmony_ci							control->pswitch_channels[1] = control_channels[i][1];
327c72fcc34Sopenharmony_ci						}
328c72fcc34Sopenharmony_ci					}
329c72fcc34Sopenharmony_ci				}
330c72fcc34Sopenharmony_ci				if (merged_cswitch) {
331c72fcc34Sopenharmony_ci					control->flags |= TYPE_CSWITCH;
332c72fcc34Sopenharmony_ci					if (snd_mixer_selem_has_capture_switch_joined(elem)) {
333c72fcc34Sopenharmony_ci						control->flags |= HAS_CSWITCH_0;
334c72fcc34Sopenharmony_ci						control->cswitch_channels[0] = 0;
335c72fcc34Sopenharmony_ci					} else {
336c72fcc34Sopenharmony_ci						if (snd_mixer_selem_has_capture_channel(elem, control_channels[i][0])) {
337c72fcc34Sopenharmony_ci							control->flags |= HAS_CSWITCH_0;
338c72fcc34Sopenharmony_ci							control->cswitch_channels[0] = control_channels[i][0];
339c72fcc34Sopenharmony_ci						}
340c72fcc34Sopenharmony_ci						if (control_channels[i][1] != SND_MIXER_SCHN_UNKNOWN &&
341c72fcc34Sopenharmony_ci						    snd_mixer_selem_has_capture_channel(elem, control_channels[i][1])) {
342c72fcc34Sopenharmony_ci							control->flags |= HAS_CSWITCH_1;
343c72fcc34Sopenharmony_ci							control->cswitch_channels[1] = control_channels[i][1];
344c72fcc34Sopenharmony_ci						}
345c72fcc34Sopenharmony_ci					}
346c72fcc34Sopenharmony_ci				}
347c72fcc34Sopenharmony_ci				if ((control->flags & (HAS_VOLUME_0 | HAS_VOLUME_1)) == HAS_VOLUME_1) {
348c72fcc34Sopenharmony_ci					control->flags ^= HAS_VOLUME_0 | HAS_VOLUME_1;
349c72fcc34Sopenharmony_ci					control->volume_channels[0] = control->volume_channels[1];
350c72fcc34Sopenharmony_ci				}
351c72fcc34Sopenharmony_ci				if ((control->flags & (HAS_PSWITCH_0 | HAS_PSWITCH_1)) == HAS_PSWITCH_1) {
352c72fcc34Sopenharmony_ci					control->flags ^= HAS_PSWITCH_0 | HAS_PSWITCH_1;
353c72fcc34Sopenharmony_ci					control->pswitch_channels[0] = control->pswitch_channels[1];
354c72fcc34Sopenharmony_ci				}
355c72fcc34Sopenharmony_ci				if ((control->flags & (HAS_CSWITCH_0 | HAS_CSWITCH_1)) == HAS_CSWITCH_1) {
356c72fcc34Sopenharmony_ci					control->flags ^= HAS_CSWITCH_0 | HAS_CSWITCH_1;
357c72fcc34Sopenharmony_ci					control->cswitch_channels[0] = control->cswitch_channels[1];
358c72fcc34Sopenharmony_ci				}
359c72fcc34Sopenharmony_ci				if (snd_mixer_selem_is_active(control->elem))
360c72fcc34Sopenharmony_ci					control->flags |= IS_ACTIVE;
361c72fcc34Sopenharmony_ci				create_name(control);
362c72fcc34Sopenharmony_ci				if (i == 0)
363c72fcc34Sopenharmony_ci					front_control = control;
364c72fcc34Sopenharmony_ci				else {
365c72fcc34Sopenharmony_ci					front_control->flags |= IS_MULTICH | 0;
366c72fcc34Sopenharmony_ci					control->flags |= IS_MULTICH | i;
367c72fcc34Sopenharmony_ci				}
368c72fcc34Sopenharmony_ci				++control;
369c72fcc34Sopenharmony_ci				++count;
370c72fcc34Sopenharmony_ci			}
371c72fcc34Sopenharmony_ci		}
372c72fcc34Sopenharmony_ci	}
373c72fcc34Sopenharmony_ci	if (view_mode != VIEW_MODE_PLAYBACK && (has_cvol || has_csw) && !merged_cswitch) {
374c72fcc34Sopenharmony_ci		if ((!has_cvol || snd_mixer_selem_has_capture_volume_joined(elem)) &&
375c72fcc34Sopenharmony_ci		    (!has_csw || snd_mixer_selem_has_capture_switch_joined(elem))) {
376c72fcc34Sopenharmony_ci			control->elem = elem;
377c72fcc34Sopenharmony_ci			if (has_cvol) {
378c72fcc34Sopenharmony_ci				control->flags |= TYPE_CVOLUME | HAS_VOLUME_0;
379c72fcc34Sopenharmony_ci				control->volume_channels[0] = 0;
380c72fcc34Sopenharmony_ci			}
381c72fcc34Sopenharmony_ci			if (has_csw) {
382c72fcc34Sopenharmony_ci				control->flags |= TYPE_CSWITCH | HAS_CSWITCH_0;
383c72fcc34Sopenharmony_ci				control->cswitch_channels[0] = 0;
384c72fcc34Sopenharmony_ci			}
385c72fcc34Sopenharmony_ci			if (snd_mixer_selem_is_active(control->elem))
386c72fcc34Sopenharmony_ci				control->flags |= IS_ACTIVE;
387c72fcc34Sopenharmony_ci			create_name(control);
388c72fcc34Sopenharmony_ci			++control;
389c72fcc34Sopenharmony_ci			++count;
390c72fcc34Sopenharmony_ci		} else {
391c72fcc34Sopenharmony_ci			for (i = 0; i < ARRAY_SIZE(supported_channels); ++i)
392c72fcc34Sopenharmony_ci				has_channel[supported_channels[i]] =
393c72fcc34Sopenharmony_ci					snd_mixer_selem_has_capture_channel(elem, supported_channels[i]);
394c72fcc34Sopenharmony_ci			for (i = 0; i < ARRAY_SIZE(control_channels); ++i) {
395c72fcc34Sopenharmony_ci				has_ch0 = has_channel[control_channels[i][0]];
396c72fcc34Sopenharmony_ci				has_ch1 = control_channels[i][1] != SND_MIXER_SCHN_UNKNOWN &&
397c72fcc34Sopenharmony_ci					has_channel[control_channels[i][1]];
398c72fcc34Sopenharmony_ci				if (!has_ch0 && !has_ch1)
399c72fcc34Sopenharmony_ci					continue;
400c72fcc34Sopenharmony_ci				control->elem = elem;
401c72fcc34Sopenharmony_ci				if (has_cvol) {
402c72fcc34Sopenharmony_ci					control->flags |= TYPE_CVOLUME;
403c72fcc34Sopenharmony_ci					if (snd_mixer_selem_has_capture_volume_joined(elem)) {
404c72fcc34Sopenharmony_ci						control->flags |= HAS_VOLUME_0;
405c72fcc34Sopenharmony_ci						control->volume_channels[0] = 0;
406c72fcc34Sopenharmony_ci					} else {
407c72fcc34Sopenharmony_ci						if (has_ch0) {
408c72fcc34Sopenharmony_ci							control->flags |= HAS_VOLUME_0;
409c72fcc34Sopenharmony_ci							control->volume_channels[0] = control_channels[i][0];
410c72fcc34Sopenharmony_ci						}
411c72fcc34Sopenharmony_ci						if (has_ch1) {
412c72fcc34Sopenharmony_ci							control->flags |= HAS_VOLUME_1;
413c72fcc34Sopenharmony_ci							control->volume_channels[1] = control_channels[i][1];
414c72fcc34Sopenharmony_ci						}
415c72fcc34Sopenharmony_ci					}
416c72fcc34Sopenharmony_ci				}
417c72fcc34Sopenharmony_ci				if (has_csw) {
418c72fcc34Sopenharmony_ci					control->flags |= TYPE_CSWITCH;
419c72fcc34Sopenharmony_ci					if (snd_mixer_selem_has_capture_switch_joined(elem)) {
420c72fcc34Sopenharmony_ci						control->flags |= HAS_CSWITCH_0;
421c72fcc34Sopenharmony_ci						control->cswitch_channels[0] = 0;
422c72fcc34Sopenharmony_ci					} else {
423c72fcc34Sopenharmony_ci						if (has_ch0) {
424c72fcc34Sopenharmony_ci							control->flags |= HAS_CSWITCH_0;
425c72fcc34Sopenharmony_ci							control->cswitch_channels[0] = control_channels[i][0];
426c72fcc34Sopenharmony_ci						}
427c72fcc34Sopenharmony_ci						if (has_ch1) {
428c72fcc34Sopenharmony_ci							control->flags |= HAS_CSWITCH_1;
429c72fcc34Sopenharmony_ci							control->cswitch_channels[1] = control_channels[i][1];
430c72fcc34Sopenharmony_ci						}
431c72fcc34Sopenharmony_ci					}
432c72fcc34Sopenharmony_ci				}
433c72fcc34Sopenharmony_ci				if ((control->flags & (HAS_VOLUME_0 | HAS_VOLUME_1)) == HAS_VOLUME_1) {
434c72fcc34Sopenharmony_ci					control->flags ^= HAS_VOLUME_0 | HAS_VOLUME_1;
435c72fcc34Sopenharmony_ci					control->volume_channels[0] = control->volume_channels[1];
436c72fcc34Sopenharmony_ci				}
437c72fcc34Sopenharmony_ci				if ((control->flags & (HAS_CSWITCH_0 | HAS_CSWITCH_1)) == HAS_CSWITCH_1) {
438c72fcc34Sopenharmony_ci					control->flags ^= HAS_CSWITCH_0 | HAS_CSWITCH_1;
439c72fcc34Sopenharmony_ci					control->cswitch_channels[0] = control->cswitch_channels[1];
440c72fcc34Sopenharmony_ci				}
441c72fcc34Sopenharmony_ci				if (snd_mixer_selem_is_active(control->elem))
442c72fcc34Sopenharmony_ci					control->flags |= IS_ACTIVE;
443c72fcc34Sopenharmony_ci				create_name(control);
444c72fcc34Sopenharmony_ci				if (i == 0)
445c72fcc34Sopenharmony_ci					front_control = control;
446c72fcc34Sopenharmony_ci				else {
447c72fcc34Sopenharmony_ci					front_control->flags |= IS_MULTICH | 0;
448c72fcc34Sopenharmony_ci					control->flags |= IS_MULTICH | i;
449c72fcc34Sopenharmony_ci				}
450c72fcc34Sopenharmony_ci				++control;
451c72fcc34Sopenharmony_ci				++count;
452c72fcc34Sopenharmony_ci			}
453c72fcc34Sopenharmony_ci		}
454c72fcc34Sopenharmony_ci	}
455c72fcc34Sopenharmony_ci	return count;
456c72fcc34Sopenharmony_ci}
457c72fcc34Sopenharmony_ci
458c72fcc34Sopenharmony_cistatic void search_for_focus_control(void)
459c72fcc34Sopenharmony_ci{
460c72fcc34Sopenharmony_ci	snd_mixer_elem_t *elem;
461c72fcc34Sopenharmony_ci	unsigned int i;
462c72fcc34Sopenharmony_ci
463c72fcc34Sopenharmony_ci	elem = snd_mixer_find_selem(mixer, current_selem_id);
464c72fcc34Sopenharmony_ci	if (elem)
465c72fcc34Sopenharmony_ci		for (i = 0; i < controls_count; ++i)
466c72fcc34Sopenharmony_ci			if (controls[i].elem == elem) {
467c72fcc34Sopenharmony_ci				focus_control_index = i;
468c72fcc34Sopenharmony_ci				for (;;) {
469c72fcc34Sopenharmony_ci					++i;
470c72fcc34Sopenharmony_ci					if (i >= controls_count || controls[i].elem != elem)
471c72fcc34Sopenharmony_ci						return;
472c72fcc34Sopenharmony_ci					if (controls[i].flags == current_control_flags) {
473c72fcc34Sopenharmony_ci						focus_control_index = i;
474c72fcc34Sopenharmony_ci						return;
475c72fcc34Sopenharmony_ci					}
476c72fcc34Sopenharmony_ci				}
477c72fcc34Sopenharmony_ci			}
478c72fcc34Sopenharmony_ci	focus_control_index = 0;
479c72fcc34Sopenharmony_ci}
480c72fcc34Sopenharmony_ci
481c72fcc34Sopenharmony_civoid free_controls(void)
482c72fcc34Sopenharmony_ci{
483c72fcc34Sopenharmony_ci	unsigned int i;
484c72fcc34Sopenharmony_ci
485c72fcc34Sopenharmony_ci	for (i = 0; i < controls_count; ++i)
486c72fcc34Sopenharmony_ci		free(controls[i].name);
487c72fcc34Sopenharmony_ci	free(controls);
488c72fcc34Sopenharmony_ci	controls = NULL;
489c72fcc34Sopenharmony_ci	controls_count = 0;
490c72fcc34Sopenharmony_ci}
491c72fcc34Sopenharmony_ci
492c72fcc34Sopenharmony_civoid create_controls(void)
493c72fcc34Sopenharmony_ci{
494c72fcc34Sopenharmony_ci	snd_mixer_elem_t *elem;
495c72fcc34Sopenharmony_ci	struct control *control;
496c72fcc34Sopenharmony_ci
497c72fcc34Sopenharmony_ci	free_controls();
498c72fcc34Sopenharmony_ci
499c72fcc34Sopenharmony_ci	for (elem = snd_mixer_first_elem(mixer);
500c72fcc34Sopenharmony_ci	     elem;
501c72fcc34Sopenharmony_ci	     elem = snd_mixer_elem_next(elem))
502c72fcc34Sopenharmony_ci		controls_count += get_controls_count_for_elem(elem);
503c72fcc34Sopenharmony_ci
504c72fcc34Sopenharmony_ci	if (controls_count > 0) {
505c72fcc34Sopenharmony_ci		controls = ccalloc(controls_count, sizeof *controls);
506c72fcc34Sopenharmony_ci		control = controls;
507c72fcc34Sopenharmony_ci		for (elem = snd_mixer_first_elem(mixer);
508c72fcc34Sopenharmony_ci		     elem;
509c72fcc34Sopenharmony_ci		     elem = snd_mixer_elem_next(elem))
510c72fcc34Sopenharmony_ci			control += create_controls_for_elem(elem, control);
511c72fcc34Sopenharmony_ci		assert(control == controls + controls_count);
512c72fcc34Sopenharmony_ci	}
513c72fcc34Sopenharmony_ci
514c72fcc34Sopenharmony_ci	compute_controls_layout();
515c72fcc34Sopenharmony_ci	display_view_mode();
516c72fcc34Sopenharmony_ci
517c72fcc34Sopenharmony_ci	search_for_focus_control();
518c72fcc34Sopenharmony_ci	refocus_control();
519c72fcc34Sopenharmony_ci}
520