Blame alsamixer/mixer_controls.c

Packit Service a9274b
/*
Packit Service a9274b
 * mixer_controls.c - handles mixer controls and mapping from selems
Packit Service a9274b
 * Copyright (c) 1998,1999 Tim Janik
Packit Service a9274b
 *                         Jaroslav Kysela <perex@perex.cz>
Packit Service a9274b
 * Copyright (c) 2009      Clemens Ladisch <clemens@ladisch.de>
Packit Service a9274b
 *
Packit Service a9274b
 * This program is free software: you can redistribute it and/or modify
Packit Service a9274b
 * it under the terms of the GNU General Public License as published by
Packit Service a9274b
 * the Free Software Foundation, either version 2 of the License, or
Packit Service a9274b
 * (at your option) any later version.
Packit Service a9274b
 *
Packit Service a9274b
 * This program is distributed in the hope that it will be useful,
Packit Service a9274b
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a9274b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a9274b
 * GNU General Public License for more details.
Packit Service a9274b
 *
Packit Service a9274b
 * You should have received a copy of the GNU General Public License
Packit Service a9274b
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit Service a9274b
 */
Packit Service a9274b
Packit Service a9274b
#include "aconfig.h"
Packit Service a9274b
#include <stdlib.h>
Packit Service a9274b
#include <string.h>
Packit Service a9274b
#include <assert.h>
Packit Service a9274b
#include CURSESINC
Packit Service a9274b
#include <alsa/asoundlib.h>
Packit Service a9274b
#include "utils.h"
Packit Service a9274b
#include "mem.h"
Packit Service a9274b
#include "mixer_display.h"
Packit Service a9274b
#include "mixer_widget.h"
Packit Service a9274b
#include "mixer_controls.h"
Packit Service a9274b
Packit Service a9274b
struct control *controls;
Packit Service a9274b
unsigned int controls_count;
Packit Service a9274b
Packit Service a9274b
static const snd_mixer_selem_channel_id_t supported_channels[] = {
Packit Service a9274b
	SND_MIXER_SCHN_FRONT_LEFT,
Packit Service a9274b
	SND_MIXER_SCHN_FRONT_RIGHT,
Packit Service a9274b
	SND_MIXER_SCHN_REAR_LEFT,
Packit Service a9274b
	SND_MIXER_SCHN_REAR_RIGHT,
Packit Service a9274b
	SND_MIXER_SCHN_FRONT_CENTER,
Packit Service a9274b
	SND_MIXER_SCHN_WOOFER,
Packit Service a9274b
	SND_MIXER_SCHN_SIDE_LEFT,
Packit Service a9274b
	SND_MIXER_SCHN_SIDE_RIGHT,
Packit Service a9274b
};
Packit Service a9274b
#define LAST_SUPPORTED_CHANNEL SND_MIXER_SCHN_SIDE_RIGHT
Packit Service a9274b
Packit Service a9274b
static const snd_mixer_selem_channel_id_t control_channels[][2] = {
Packit Service a9274b
	{ SND_MIXER_SCHN_FRONT_LEFT, SND_MIXER_SCHN_FRONT_RIGHT },
Packit Service a9274b
	{ SND_MIXER_SCHN_REAR_LEFT, SND_MIXER_SCHN_REAR_RIGHT },
Packit Service a9274b
	{ SND_MIXER_SCHN_FRONT_CENTER, SND_MIXER_SCHN_UNKNOWN },
Packit Service a9274b
	{ SND_MIXER_SCHN_WOOFER, SND_MIXER_SCHN_UNKNOWN },
Packit Service a9274b
	{ SND_MIXER_SCHN_SIDE_LEFT, SND_MIXER_SCHN_SIDE_RIGHT },
Packit Service a9274b
};
Packit Service a9274b
Packit Service a9274b
bool are_there_any_controls(void)
Packit Service a9274b
{
Packit Service a9274b
	snd_mixer_elem_t *elem;
Packit Service a9274b
	unsigned int i;
Packit Service a9274b
Packit Service a9274b
	for (elem = snd_mixer_first_elem(mixer);
Packit Service a9274b
	     elem;
Packit Service a9274b
	     elem = snd_mixer_elem_next(elem)) {
Packit Service a9274b
		if (snd_mixer_elem_get_type(elem) != SND_MIXER_ELEM_SIMPLE)
Packit Service a9274b
			continue;
Packit Service a9274b
		if (snd_mixer_selem_is_enumerated(elem))
Packit Service a9274b
			return TRUE;
Packit Service a9274b
		if (snd_mixer_selem_has_playback_volume_joined(elem) ||
Packit Service a9274b
		    snd_mixer_selem_has_capture_volume_joined(elem) ||
Packit Service a9274b
		    snd_mixer_selem_has_playback_switch_joined(elem) ||
Packit Service a9274b
		    snd_mixer_selem_has_capture_switch_joined(elem))
Packit Service a9274b
			return TRUE;
Packit Service a9274b
		for (i = 0; i < ARRAY_SIZE(supported_channels); ++i)
Packit Service a9274b
			if (snd_mixer_selem_has_playback_channel(elem, supported_channels[i]) ||
Packit Service a9274b
			    snd_mixer_selem_has_capture_channel(elem, supported_channels[i]))
Packit Service a9274b
				return TRUE;
Packit Service a9274b
	}
Packit Service a9274b
	return FALSE;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static bool has_more_than_front_capture_channels(snd_mixer_elem_t *elem)
Packit Service a9274b
{
Packit Service a9274b
	unsigned int i;
Packit Service a9274b
Packit Service a9274b
	for (i = 2; i < ARRAY_SIZE(supported_channels); ++i)
Packit Service a9274b
		if (snd_mixer_selem_has_capture_channel(elem, supported_channels[i]))
Packit Service a9274b
			return TRUE;
Packit Service a9274b
	return FALSE;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static bool has_any_control_channel(snd_mixer_elem_t *elem,
Packit Service a9274b
				    const snd_mixer_selem_channel_id_t channels[2],
Packit Service a9274b
				    int (*has_channel)(snd_mixer_elem_t *, snd_mixer_selem_channel_id_t))
Packit Service a9274b
{
Packit Service a9274b
	return has_channel(elem, channels[0]) ||
Packit Service a9274b
	       (channels[1] != SND_MIXER_SCHN_UNKNOWN && has_channel(elem, channels[1]));
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static bool has_merged_cswitch(snd_mixer_elem_t *elem)
Packit Service a9274b
{
Packit Service a9274b
	bool pvol, psw;
Packit Service a9274b
	unsigned int i;
Packit Service a9274b
Packit Service a9274b
	pvol = snd_mixer_selem_has_playback_volume(elem);
Packit Service a9274b
	psw = snd_mixer_selem_has_playback_switch(elem);
Packit Service a9274b
	if ((pvol || psw) &&
Packit Service a9274b
	    snd_mixer_selem_has_capture_switch(elem) &&
Packit Service a9274b
	    !snd_mixer_selem_has_capture_volume(elem)) {
Packit Service a9274b
		if (snd_mixer_selem_has_capture_switch_joined(elem))
Packit Service a9274b
			return TRUE;
Packit Service a9274b
		else if (((pvol && snd_mixer_selem_has_playback_volume_joined(elem)) ||
Packit Service a9274b
			  (psw && snd_mixer_selem_has_playback_switch_joined(elem))) &&
Packit Service a9274b
			 has_more_than_front_capture_channels(elem))
Packit Service a9274b
			return FALSE;
Packit Service a9274b
		for (i = 0; i < ARRAY_SIZE(control_channels); ++i) {
Packit Service a9274b
			if (has_any_control_channel(elem, control_channels[i], snd_mixer_selem_has_capture_channel) &&
Packit Service a9274b
			    !has_any_control_channel(elem, control_channels[i], snd_mixer_selem_has_playback_channel))
Packit Service a9274b
				return FALSE;
Packit Service a9274b
		}
Packit Service a9274b
		return TRUE;
Packit Service a9274b
	}
Packit Service a9274b
	return FALSE;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static unsigned int get_playback_controls_count(snd_mixer_elem_t *elem)
Packit Service a9274b
{
Packit Service a9274b
	unsigned int count = 0;
Packit Service a9274b
	unsigned int i;
Packit Service a9274b
	int has_vol, has_sw;
Packit Service a9274b
Packit Service a9274b
	has_vol = snd_mixer_selem_has_playback_volume(elem);
Packit Service a9274b
	has_sw = snd_mixer_selem_has_playback_switch(elem);
Packit Service a9274b
	if (!has_vol && !has_sw)
Packit Service a9274b
		return 0;
Packit Service a9274b
	if ((!has_vol || snd_mixer_selem_has_playback_volume_joined(elem)) &&
Packit Service a9274b
	    (!has_sw || snd_mixer_selem_has_playback_switch_joined(elem)))
Packit Service a9274b
		return 1;
Packit Service a9274b
	for (i = 0; i < ARRAY_SIZE(control_channels); ++i) {
Packit Service a9274b
		if (snd_mixer_selem_has_playback_channel(elem, control_channels[i][0]) ||
Packit Service a9274b
		    (control_channels[i][1] != SND_MIXER_SCHN_UNKNOWN &&
Packit Service a9274b
		     snd_mixer_selem_has_playback_channel(elem, control_channels[i][1])))
Packit Service a9274b
			++count;
Packit Service a9274b
	}
Packit Service a9274b
	return count;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static unsigned int get_capture_controls_count(snd_mixer_elem_t *elem)
Packit Service a9274b
{
Packit Service a9274b
	unsigned int count = 0;
Packit Service a9274b
	unsigned int i;
Packit Service a9274b
	int has_vol, has_sw;
Packit Service a9274b
Packit Service a9274b
	has_vol = snd_mixer_selem_has_capture_volume(elem);
Packit Service a9274b
	has_sw = snd_mixer_selem_has_capture_switch(elem);
Packit Service a9274b
	if ((!has_vol && !has_sw) ||
Packit Service a9274b
	    (view_mode == VIEW_MODE_ALL && has_merged_cswitch(elem)))
Packit Service a9274b
		return 0;
Packit Service a9274b
	if ((!has_vol || snd_mixer_selem_has_capture_volume_joined(elem)) &&
Packit Service a9274b
	    (!has_sw || snd_mixer_selem_has_capture_switch_joined(elem)))
Packit Service a9274b
		return 1;
Packit Service a9274b
	for (i = 0; i < ARRAY_SIZE(control_channels); ++i) {
Packit Service a9274b
		if (snd_mixer_selem_has_capture_channel(elem, control_channels[i][0]) ||
Packit Service a9274b
		    (control_channels[i][1] != SND_MIXER_SCHN_UNKNOWN &&
Packit Service a9274b
		     snd_mixer_selem_has_capture_channel(elem, control_channels[i][1])))
Packit Service a9274b
			++count;
Packit Service a9274b
	}
Packit Service a9274b
	return count;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static unsigned int get_controls_count_for_elem(snd_mixer_elem_t *elem)
Packit Service a9274b
{
Packit Service a9274b
	unsigned int p, c;
Packit Service a9274b
Packit Service a9274b
	if (snd_mixer_elem_get_type(elem) != SND_MIXER_ELEM_SIMPLE)
Packit Service a9274b
		return 0;
Packit Service a9274b
	if (snd_mixer_selem_is_enumerated(elem)) {
Packit Service a9274b
		switch (view_mode) {
Packit Service a9274b
		case VIEW_MODE_PLAYBACK:
Packit Service a9274b
			return snd_mixer_selem_is_enum_capture(elem) ? 0 : 1;
Packit Service a9274b
		case VIEW_MODE_CAPTURE:
Packit Service a9274b
			return snd_mixer_selem_is_enum_capture(elem) ? 1 : 0;
Packit Service a9274b
		case VIEW_MODE_ALL:
Packit Service a9274b
		default:
Packit Service a9274b
			return 1;
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
	switch (view_mode) {
Packit Service a9274b
	case VIEW_MODE_PLAYBACK:
Packit Service a9274b
		return get_playback_controls_count(elem);
Packit Service a9274b
	case VIEW_MODE_CAPTURE:
Packit Service a9274b
		return get_capture_controls_count(elem);
Packit Service a9274b
	case VIEW_MODE_ALL:
Packit Service a9274b
	default:
Packit Service a9274b
		p = get_playback_controls_count(elem);
Packit Service a9274b
		c = get_capture_controls_count(elem);
Packit Service a9274b
		return has_merged_cswitch(elem) ? p : p + c;
Packit Service a9274b
	}
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void create_name(struct control *control)
Packit Service a9274b
{
Packit Service a9274b
	unsigned int index;
Packit Service a9274b
	char *s;
Packit Service a9274b
Packit Service a9274b
	index = snd_mixer_selem_get_index(control->elem);
Packit Service a9274b
	if (index > 0)
Packit Service a9274b
		control->name = casprintf("%s %u", snd_mixer_selem_get_name(control->elem), index);
Packit Service a9274b
	else
Packit Service a9274b
		control->name = cstrdup(snd_mixer_selem_get_name(control->elem));
Packit Service a9274b
Packit Service a9274b
	while ((s = strstr(control->name, "IEC958")) != NULL)
Packit Service a9274b
		memcpy(s, "S/PDIF", 6);
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static unsigned int create_controls_for_elem(snd_mixer_elem_t *elem, struct control *control)
Packit Service a9274b
{
Packit Service a9274b
	unsigned int count = 0;
Packit Service a9274b
	unsigned int i;
Packit Service a9274b
	unsigned int enum_index;
Packit Service a9274b
	struct control *front_control = NULL;
Packit Service a9274b
	bool has_pvol, has_psw;
Packit Service a9274b
	bool has_cvol, has_csw;
Packit Service a9274b
	bool has_channel[LAST_SUPPORTED_CHANNEL + 1];
Packit Service a9274b
	bool merged_cswitch;
Packit Service a9274b
	bool has_ch0, has_ch1;
Packit Service a9274b
Packit Service a9274b
	if (snd_mixer_elem_get_type(elem) != SND_MIXER_ELEM_SIMPLE)
Packit Service a9274b
		return 0;
Packit Service a9274b
	if (snd_mixer_selem_is_enumerated(elem)) {
Packit Service a9274b
		if ((view_mode == VIEW_MODE_PLAYBACK && snd_mixer_selem_is_enum_capture(elem)) ||
Packit Service a9274b
		    (view_mode == VIEW_MODE_CAPTURE && !snd_mixer_selem_is_enum_capture(elem)))
Packit Service a9274b
			return 0;
Packit Service a9274b
		control->elem = elem;
Packit Service a9274b
		control->flags = TYPE_ENUM;
Packit Service a9274b
		control->enum_channel_bits = 0;
Packit Service a9274b
		for (i = 0; i <= SND_MIXER_SCHN_LAST; ++i)
Packit Service a9274b
			if (snd_mixer_selem_get_enum_item(control->elem, (snd_mixer_selem_channel_id_t)i, &enum_index) >= 0)
Packit Service a9274b
				control->enum_channel_bits |= 1 << i;
Packit Service a9274b
		if (snd_mixer_selem_is_active(control->elem))
Packit Service a9274b
			control->flags |= IS_ACTIVE;
Packit Service a9274b
		create_name(control);
Packit Service a9274b
		return 1;
Packit Service a9274b
	}
Packit Service a9274b
	has_pvol = snd_mixer_selem_has_playback_volume(elem);
Packit Service a9274b
	has_psw = snd_mixer_selem_has_playback_switch(elem);
Packit Service a9274b
	has_cvol = snd_mixer_selem_has_capture_volume(elem);
Packit Service a9274b
	has_csw = snd_mixer_selem_has_capture_switch(elem);
Packit Service a9274b
	merged_cswitch = view_mode == VIEW_MODE_ALL && has_merged_cswitch(elem);
Packit Service a9274b
	if (view_mode != VIEW_MODE_CAPTURE && (has_pvol || has_psw)) {
Packit Service a9274b
		if ((!has_pvol || snd_mixer_selem_has_playback_volume_joined(elem)) &&
Packit Service a9274b
		    (!has_psw || snd_mixer_selem_has_playback_switch_joined(elem))) {
Packit Service a9274b
			control->elem = elem;
Packit Service a9274b
			if (has_pvol) {
Packit Service a9274b
				control->flags |= TYPE_PVOLUME | HAS_VOLUME_0;
Packit Service a9274b
				control->volume_channels[0] = 0;
Packit Service a9274b
			}
Packit Service a9274b
			if (has_psw) {
Packit Service a9274b
				control->flags |= TYPE_PSWITCH | HAS_PSWITCH_0;
Packit Service a9274b
				control->pswitch_channels[0] = 0;
Packit Service a9274b
			}
Packit Service a9274b
			if (merged_cswitch) {
Packit Service a9274b
				control->flags |= TYPE_CSWITCH;
Packit Service a9274b
				if (snd_mixer_selem_has_capture_switch_joined(elem)) {
Packit Service a9274b
					control->flags |= HAS_CSWITCH_0;
Packit Service a9274b
					control->cswitch_channels[0] = 0;
Packit Service a9274b
				} else {
Packit Service a9274b
					if (snd_mixer_selem_has_capture_channel(elem, control_channels[0][0])) {
Packit Service a9274b
						control->flags |= HAS_CSWITCH_0;
Packit Service a9274b
						control->cswitch_channels[0] = control_channels[0][0];
Packit Service a9274b
					}
Packit Service a9274b
					if (control_channels[0][1] != SND_MIXER_SCHN_UNKNOWN &&
Packit Service a9274b
					    snd_mixer_selem_has_capture_channel(elem, control_channels[0][1])) {
Packit Service a9274b
						control->flags |= HAS_CSWITCH_1;
Packit Service a9274b
						control->cswitch_channels[1] = control_channels[0][1];
Packit Service a9274b
					}
Packit Service a9274b
				}
Packit Service a9274b
				if ((control->flags & (HAS_CSWITCH_0 | HAS_CSWITCH_1)) == HAS_CSWITCH_1) {
Packit Service a9274b
					control->flags ^= HAS_CSWITCH_0 | HAS_CSWITCH_1;
Packit Service a9274b
					control->cswitch_channels[0] = control->cswitch_channels[1];
Packit Service a9274b
				}
Packit Service a9274b
			}
Packit Service a9274b
			if (snd_mixer_selem_is_active(control->elem))
Packit Service a9274b
				control->flags |= IS_ACTIVE;
Packit Service a9274b
			create_name(control);
Packit Service a9274b
			++control;
Packit Service a9274b
			++count;
Packit Service a9274b
		} else {
Packit Service a9274b
			for (i = 0; i < ARRAY_SIZE(supported_channels); ++i)
Packit Service a9274b
				has_channel[supported_channels[i]] =
Packit Service a9274b
					snd_mixer_selem_has_playback_channel(elem, supported_channels[i]);
Packit Service a9274b
			for (i = 0; i < ARRAY_SIZE(control_channels); ++i) {
Packit Service a9274b
				has_ch0 = has_channel[control_channels[i][0]];
Packit Service a9274b
				has_ch1 = control_channels[i][1] != SND_MIXER_SCHN_UNKNOWN &&
Packit Service a9274b
					has_channel[control_channels[i][1]];
Packit Service a9274b
				if (!has_ch0 && !has_ch1)
Packit Service a9274b
					continue;
Packit Service a9274b
				control->elem = elem;
Packit Service a9274b
				if (has_pvol) {
Packit Service a9274b
					control->flags |= TYPE_PVOLUME;
Packit Service a9274b
					if (snd_mixer_selem_has_playback_volume_joined(elem)) {
Packit Service a9274b
						control->flags |= HAS_VOLUME_0;
Packit Service a9274b
						control->volume_channels[0] = 0;
Packit Service a9274b
					} else {
Packit Service a9274b
						if (has_ch0) {
Packit Service a9274b
							control->flags |= HAS_VOLUME_0;
Packit Service a9274b
							control->volume_channels[0] = control_channels[i][0];
Packit Service a9274b
						}
Packit Service a9274b
						if (has_ch1) {
Packit Service a9274b
							control->flags |= HAS_VOLUME_1;
Packit Service a9274b
							control->volume_channels[1] = control_channels[i][1];
Packit Service a9274b
						}
Packit Service a9274b
					}
Packit Service a9274b
				}
Packit Service a9274b
				if (has_psw) {
Packit Service a9274b
					control->flags |= TYPE_PSWITCH;
Packit Service a9274b
					if (snd_mixer_selem_has_playback_switch_joined(elem)) {
Packit Service a9274b
						control->flags |= HAS_PSWITCH_0;
Packit Service a9274b
						control->pswitch_channels[0] = 0;
Packit Service a9274b
					} else {
Packit Service a9274b
						if (has_ch0) {
Packit Service a9274b
							control->flags |= HAS_PSWITCH_0;
Packit Service a9274b
							control->pswitch_channels[0] = control_channels[i][0];
Packit Service a9274b
						}
Packit Service a9274b
						if (has_ch1) {
Packit Service a9274b
							control->flags |= HAS_PSWITCH_1;
Packit Service a9274b
							control->pswitch_channels[1] = control_channels[i][1];
Packit Service a9274b
						}
Packit Service a9274b
					}
Packit Service a9274b
				}
Packit Service a9274b
				if (merged_cswitch) {
Packit Service a9274b
					control->flags |= TYPE_CSWITCH;
Packit Service a9274b
					if (snd_mixer_selem_has_capture_switch_joined(elem)) {
Packit Service a9274b
						control->flags |= HAS_CSWITCH_0;
Packit Service a9274b
						control->cswitch_channels[0] = 0;
Packit Service a9274b
					} else {
Packit Service a9274b
						if (snd_mixer_selem_has_capture_channel(elem, control_channels[i][0])) {
Packit Service a9274b
							control->flags |= HAS_CSWITCH_0;
Packit Service a9274b
							control->cswitch_channels[0] = control_channels[i][0];
Packit Service a9274b
						}
Packit Service a9274b
						if (control_channels[i][1] != SND_MIXER_SCHN_UNKNOWN &&
Packit Service a9274b
						    snd_mixer_selem_has_capture_channel(elem, control_channels[i][1])) {
Packit Service a9274b
							control->flags |= HAS_CSWITCH_1;
Packit Service a9274b
							control->cswitch_channels[1] = control_channels[i][1];
Packit Service a9274b
						}
Packit Service a9274b
					}
Packit Service a9274b
				}
Packit Service a9274b
				if ((control->flags & (HAS_VOLUME_0 | HAS_VOLUME_1)) == HAS_VOLUME_1) {
Packit Service a9274b
					control->flags ^= HAS_VOLUME_0 | HAS_VOLUME_1;
Packit Service a9274b
					control->volume_channels[0] = control->volume_channels[1];
Packit Service a9274b
				}
Packit Service a9274b
				if ((control->flags & (HAS_PSWITCH_0 | HAS_PSWITCH_1)) == HAS_PSWITCH_1) {
Packit Service a9274b
					control->flags ^= HAS_PSWITCH_0 | HAS_PSWITCH_1;
Packit Service a9274b
					control->pswitch_channels[0] = control->pswitch_channels[1];
Packit Service a9274b
				}
Packit Service a9274b
				if ((control->flags & (HAS_CSWITCH_0 | HAS_CSWITCH_1)) == HAS_CSWITCH_1) {
Packit Service a9274b
					control->flags ^= HAS_CSWITCH_0 | HAS_CSWITCH_1;
Packit Service a9274b
					control->cswitch_channels[0] = control->cswitch_channels[1];
Packit Service a9274b
				}
Packit Service a9274b
				if (snd_mixer_selem_is_active(control->elem))
Packit Service a9274b
					control->flags |= IS_ACTIVE;
Packit Service a9274b
				create_name(control);
Packit Service a9274b
				if (i == 0)
Packit Service a9274b
					front_control = control;
Packit Service a9274b
				else {
Packit Service a9274b
					front_control->flags |= IS_MULTICH | 0;
Packit Service a9274b
					control->flags |= IS_MULTICH | i;
Packit Service a9274b
				}
Packit Service a9274b
				++control;
Packit Service a9274b
				++count;
Packit Service a9274b
			}
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
	if (view_mode != VIEW_MODE_PLAYBACK && (has_cvol || has_csw) && !merged_cswitch) {
Packit Service a9274b
		if ((!has_cvol || snd_mixer_selem_has_capture_volume_joined(elem)) &&
Packit Service a9274b
		    (!has_csw || snd_mixer_selem_has_capture_switch_joined(elem))) {
Packit Service a9274b
			control->elem = elem;
Packit Service a9274b
			if (has_cvol) {
Packit Service a9274b
				control->flags |= TYPE_CVOLUME | HAS_VOLUME_0;
Packit Service a9274b
				control->volume_channels[0] = 0;
Packit Service a9274b
			}
Packit Service a9274b
			if (has_csw) {
Packit Service a9274b
				control->flags |= TYPE_CSWITCH | HAS_CSWITCH_0;
Packit Service a9274b
				control->cswitch_channels[0] = 0;
Packit Service a9274b
			}
Packit Service a9274b
			if (snd_mixer_selem_is_active(control->elem))
Packit Service a9274b
				control->flags |= IS_ACTIVE;
Packit Service a9274b
			create_name(control);
Packit Service a9274b
			++control;
Packit Service a9274b
			++count;
Packit Service a9274b
		} else {
Packit Service a9274b
			for (i = 0; i < ARRAY_SIZE(supported_channels); ++i)
Packit Service a9274b
				has_channel[supported_channels[i]] =
Packit Service a9274b
					snd_mixer_selem_has_capture_channel(elem, supported_channels[i]);
Packit Service a9274b
			for (i = 0; i < ARRAY_SIZE(control_channels); ++i) {
Packit Service a9274b
				has_ch0 = has_channel[control_channels[i][0]];
Packit Service a9274b
				has_ch1 = control_channels[i][1] != SND_MIXER_SCHN_UNKNOWN &&
Packit Service a9274b
					has_channel[control_channels[i][1]];
Packit Service a9274b
				if (!has_ch0 && !has_ch1)
Packit Service a9274b
					continue;
Packit Service a9274b
				control->elem = elem;
Packit Service a9274b
				if (has_cvol) {
Packit Service a9274b
					control->flags |= TYPE_CVOLUME;
Packit Service a9274b
					if (snd_mixer_selem_has_capture_volume_joined(elem)) {
Packit Service a9274b
						control->flags |= HAS_VOLUME_0;
Packit Service a9274b
						control->volume_channels[0] = 0;
Packit Service a9274b
					} else {
Packit Service a9274b
						if (has_ch0) {
Packit Service a9274b
							control->flags |= HAS_VOLUME_0;
Packit Service a9274b
							control->volume_channels[0] = control_channels[i][0];
Packit Service a9274b
						}
Packit Service a9274b
						if (has_ch1) {
Packit Service a9274b
							control->flags |= HAS_VOLUME_1;
Packit Service a9274b
							control->volume_channels[1] = control_channels[i][1];
Packit Service a9274b
						}
Packit Service a9274b
					}
Packit Service a9274b
				}
Packit Service a9274b
				if (has_csw) {
Packit Service a9274b
					control->flags |= TYPE_CSWITCH;
Packit Service a9274b
					if (snd_mixer_selem_has_capture_switch_joined(elem)) {
Packit Service a9274b
						control->flags |= HAS_CSWITCH_0;
Packit Service a9274b
						control->cswitch_channels[0] = 0;
Packit Service a9274b
					} else {
Packit Service a9274b
						if (has_ch0) {
Packit Service a9274b
							control->flags |= HAS_CSWITCH_0;
Packit Service a9274b
							control->cswitch_channels[0] = control_channels[i][0];
Packit Service a9274b
						}
Packit Service a9274b
						if (has_ch1) {
Packit Service a9274b
							control->flags |= HAS_CSWITCH_1;
Packit Service a9274b
							control->cswitch_channels[1] = control_channels[i][1];
Packit Service a9274b
						}
Packit Service a9274b
					}
Packit Service a9274b
				}
Packit Service a9274b
				if ((control->flags & (HAS_VOLUME_0 | HAS_VOLUME_1)) == HAS_VOLUME_1) {
Packit Service a9274b
					control->flags ^= HAS_VOLUME_0 | HAS_VOLUME_1;
Packit Service a9274b
					control->volume_channels[0] = control->volume_channels[1];
Packit Service a9274b
				}
Packit Service a9274b
				if ((control->flags & (HAS_CSWITCH_0 | HAS_CSWITCH_1)) == HAS_CSWITCH_1) {
Packit Service a9274b
					control->flags ^= HAS_CSWITCH_0 | HAS_CSWITCH_1;
Packit Service a9274b
					control->cswitch_channels[0] = control->cswitch_channels[1];
Packit Service a9274b
				}
Packit Service a9274b
				if (snd_mixer_selem_is_active(control->elem))
Packit Service a9274b
					control->flags |= IS_ACTIVE;
Packit Service a9274b
				create_name(control);
Packit Service a9274b
				if (i == 0)
Packit Service a9274b
					front_control = control;
Packit Service a9274b
				else {
Packit Service a9274b
					front_control->flags |= IS_MULTICH | 0;
Packit Service a9274b
					control->flags |= IS_MULTICH | i;
Packit Service a9274b
				}
Packit Service a9274b
				++control;
Packit Service a9274b
				++count;
Packit Service a9274b
			}
Packit Service a9274b
		}
Packit Service a9274b
	}
Packit Service a9274b
	return count;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
static void search_for_focus_control(void)
Packit Service a9274b
{
Packit Service a9274b
	snd_mixer_elem_t *elem;
Packit Service a9274b
	unsigned int i;
Packit Service a9274b
Packit Service a9274b
	elem = snd_mixer_find_selem(mixer, current_selem_id);
Packit Service a9274b
	if (elem)
Packit Service a9274b
		for (i = 0; i < controls_count; ++i)
Packit Service a9274b
			if (controls[i].elem == elem) {
Packit Service a9274b
				focus_control_index = i;
Packit Service a9274b
				for (;;) {
Packit Service a9274b
					++i;
Packit Service a9274b
					if (i >= controls_count || controls[i].elem != elem)
Packit Service a9274b
						return;
Packit Service a9274b
					if (controls[i].flags == current_control_flags) {
Packit Service a9274b
						focus_control_index = i;
Packit Service a9274b
						return;
Packit Service a9274b
					}
Packit Service a9274b
				}
Packit Service a9274b
			}
Packit Service a9274b
	focus_control_index = 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
void free_controls(void)
Packit Service a9274b
{
Packit Service a9274b
	unsigned int i;
Packit Service a9274b
Packit Service a9274b
	for (i = 0; i < controls_count; ++i)
Packit Service a9274b
		free(controls[i].name);
Packit Service a9274b
	free(controls);
Packit Service a9274b
	controls = NULL;
Packit Service a9274b
	controls_count = 0;
Packit Service a9274b
}
Packit Service a9274b
Packit Service a9274b
void create_controls(void)
Packit Service a9274b
{
Packit Service a9274b
	snd_mixer_elem_t *elem;
Packit Service a9274b
	struct control *control;
Packit Service a9274b
Packit Service a9274b
	free_controls();
Packit Service a9274b
Packit Service a9274b
	for (elem = snd_mixer_first_elem(mixer);
Packit Service a9274b
	     elem;
Packit Service a9274b
	     elem = snd_mixer_elem_next(elem))
Packit Service a9274b
		controls_count += get_controls_count_for_elem(elem);
Packit Service a9274b
Packit Service a9274b
	if (controls_count > 0) {
Packit Service a9274b
		controls = ccalloc(controls_count, sizeof *controls);
Packit Service a9274b
		control = controls;
Packit Service a9274b
		for (elem = snd_mixer_first_elem(mixer);
Packit Service a9274b
		     elem;
Packit Service a9274b
		     elem = snd_mixer_elem_next(elem))
Packit Service a9274b
			control += create_controls_for_elem(elem, control);
Packit Service a9274b
		assert(control == controls + controls_count);
Packit Service a9274b
	}
Packit Service a9274b
Packit Service a9274b
	compute_controls_layout();
Packit Service a9274b
	display_view_mode();
Packit Service a9274b
Packit Service a9274b
	search_for_focus_control();
Packit Service a9274b
	refocus_control();
Packit Service a9274b
}