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