1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file mixer/simple_none.c 3d5ac70f0Sopenharmony_ci * \brief Mixer Simple Element Class Interface 4d5ac70f0Sopenharmony_ci * \author Jaroslav Kysela <perex@perex.cz> 5d5ac70f0Sopenharmony_ci * \author Abramo Bagnara <abramo@alsa-project.org> 6d5ac70f0Sopenharmony_ci * \date 2001-2004 7d5ac70f0Sopenharmony_ci * 8d5ac70f0Sopenharmony_ci * Mixer simple element class interface. 9d5ac70f0Sopenharmony_ci */ 10d5ac70f0Sopenharmony_ci/* 11d5ac70f0Sopenharmony_ci * Mixer Interface - simple controls 12d5ac70f0Sopenharmony_ci * Copyright (c) 2000,2004 by Jaroslav Kysela <perex@perex.cz> 13d5ac70f0Sopenharmony_ci * Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org> 14d5ac70f0Sopenharmony_ci * 15d5ac70f0Sopenharmony_ci * 16d5ac70f0Sopenharmony_ci * This library is free software; you can redistribute it and/or modify 17d5ac70f0Sopenharmony_ci * it under the terms of the GNU Lesser General Public License as 18d5ac70f0Sopenharmony_ci * published by the Free Software Foundation; either version 2.1 of 19d5ac70f0Sopenharmony_ci * the License, or (at your option) any later version. 20d5ac70f0Sopenharmony_ci * 21d5ac70f0Sopenharmony_ci * This program is distributed in the hope that it will be useful, 22d5ac70f0Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 23d5ac70f0Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24d5ac70f0Sopenharmony_ci * GNU Lesser General Public License for more details. 25d5ac70f0Sopenharmony_ci * 26d5ac70f0Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public 27d5ac70f0Sopenharmony_ci * License along with this library; if not, write to the Free Software 28d5ac70f0Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 29d5ac70f0Sopenharmony_ci * 30d5ac70f0Sopenharmony_ci */ 31d5ac70f0Sopenharmony_ci 32d5ac70f0Sopenharmony_ci#include "local.h" 33d5ac70f0Sopenharmony_ci#include "mixer_simple.h" 34d5ac70f0Sopenharmony_ci#include <stdio.h> 35d5ac70f0Sopenharmony_ci#include <stdlib.h> 36d5ac70f0Sopenharmony_ci#include <unistd.h> 37d5ac70f0Sopenharmony_ci#include <string.h> 38d5ac70f0Sopenharmony_ci#include <fcntl.h> 39d5ac70f0Sopenharmony_ci#include <sys/ioctl.h> 40d5ac70f0Sopenharmony_ci#include <assert.h> 41d5ac70f0Sopenharmony_ci#include <math.h> 42d5ac70f0Sopenharmony_ci#include <limits.h> 43d5ac70f0Sopenharmony_ci 44d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 45d5ac70f0Sopenharmony_ci 46d5ac70f0Sopenharmony_ci#define MIXER_COMPARE_WEIGHT_SIMPLE_BASE 0 47d5ac70f0Sopenharmony_ci#define MIXER_COMPARE_WEIGHT_NEXT_BASE 10000000 48d5ac70f0Sopenharmony_ci#define MIXER_COMPARE_WEIGHT_NOT_FOUND 1000000000 49d5ac70f0Sopenharmony_ci 50d5ac70f0Sopenharmony_citypedef enum _selem_ctl_type { 51d5ac70f0Sopenharmony_ci CTL_SINGLE, 52d5ac70f0Sopenharmony_ci CTL_GLOBAL_ENUM, 53d5ac70f0Sopenharmony_ci CTL_GLOBAL_SWITCH, 54d5ac70f0Sopenharmony_ci CTL_GLOBAL_VOLUME, 55d5ac70f0Sopenharmony_ci CTL_GLOBAL_ROUTE, 56d5ac70f0Sopenharmony_ci CTL_PLAYBACK_ENUM, 57d5ac70f0Sopenharmony_ci CTL_PLAYBACK_SWITCH, 58d5ac70f0Sopenharmony_ci CTL_PLAYBACK_VOLUME, 59d5ac70f0Sopenharmony_ci CTL_PLAYBACK_ROUTE, 60d5ac70f0Sopenharmony_ci CTL_CAPTURE_ENUM, 61d5ac70f0Sopenharmony_ci CTL_CAPTURE_SWITCH, 62d5ac70f0Sopenharmony_ci CTL_CAPTURE_VOLUME, 63d5ac70f0Sopenharmony_ci CTL_CAPTURE_ROUTE, 64d5ac70f0Sopenharmony_ci CTL_CAPTURE_SOURCE, 65d5ac70f0Sopenharmony_ci CTL_LAST = CTL_CAPTURE_SOURCE, 66d5ac70f0Sopenharmony_ci} selem_ctl_type_t; 67d5ac70f0Sopenharmony_ci 68d5ac70f0Sopenharmony_citypedef struct _selem_ctl { 69d5ac70f0Sopenharmony_ci snd_hctl_elem_t *elem; 70d5ac70f0Sopenharmony_ci snd_ctl_elem_type_t type; 71d5ac70f0Sopenharmony_ci unsigned int inactive: 1; 72d5ac70f0Sopenharmony_ci unsigned int values; 73d5ac70f0Sopenharmony_ci long min, max; 74d5ac70f0Sopenharmony_ci} selem_ctl_t; 75d5ac70f0Sopenharmony_ci 76d5ac70f0Sopenharmony_citypedef struct _selem_none { 77d5ac70f0Sopenharmony_ci sm_selem_t selem; 78d5ac70f0Sopenharmony_ci selem_ctl_t ctls[CTL_LAST + 1]; 79d5ac70f0Sopenharmony_ci unsigned int capture_item; 80d5ac70f0Sopenharmony_ci struct selem_str { 81d5ac70f0Sopenharmony_ci unsigned int range: 1; /* Forced range */ 82d5ac70f0Sopenharmony_ci unsigned int db_initialized: 1; 83d5ac70f0Sopenharmony_ci unsigned int db_init_error: 1; 84d5ac70f0Sopenharmony_ci long min, max; 85d5ac70f0Sopenharmony_ci unsigned int channels; 86d5ac70f0Sopenharmony_ci long vol[32]; 87d5ac70f0Sopenharmony_ci unsigned int sw; 88d5ac70f0Sopenharmony_ci unsigned int *db_info; 89d5ac70f0Sopenharmony_ci } str[2]; 90d5ac70f0Sopenharmony_ci} selem_none_t; 91d5ac70f0Sopenharmony_ci 92d5ac70f0Sopenharmony_cistatic const struct mixer_name_table { 93d5ac70f0Sopenharmony_ci const char *longname; 94d5ac70f0Sopenharmony_ci const char *shortname; 95d5ac70f0Sopenharmony_ci} name_table[] = { 96d5ac70f0Sopenharmony_ci {"Tone Control - Switch", "Tone"}, 97d5ac70f0Sopenharmony_ci {"Tone Control - Bass", "Bass"}, 98d5ac70f0Sopenharmony_ci {"Tone Control - Treble", "Treble"}, 99d5ac70f0Sopenharmony_ci {"Synth Tone Control - Switch", "Synth Tone"}, 100d5ac70f0Sopenharmony_ci {"Synth Tone Control - Bass", "Synth Bass"}, 101d5ac70f0Sopenharmony_ci {"Synth Tone Control - Treble", "Synth Treble"}, 102d5ac70f0Sopenharmony_ci {0, 0}, 103d5ac70f0Sopenharmony_ci}; 104d5ac70f0Sopenharmony_ci 105d5ac70f0Sopenharmony_ci#endif /* !DOC_HIDDEN */ 106d5ac70f0Sopenharmony_ci 107d5ac70f0Sopenharmony_cistatic const char *get_short_name(const char *lname) 108d5ac70f0Sopenharmony_ci{ 109d5ac70f0Sopenharmony_ci const struct mixer_name_table *p; 110d5ac70f0Sopenharmony_ci for (p = name_table; p->longname; p++) { 111d5ac70f0Sopenharmony_ci if (!strcmp(lname, p->longname)) 112d5ac70f0Sopenharmony_ci return p->shortname; 113d5ac70f0Sopenharmony_ci } 114d5ac70f0Sopenharmony_ci return lname; 115d5ac70f0Sopenharmony_ci} 116d5ac70f0Sopenharmony_ci 117d5ac70f0Sopenharmony_cistatic int compare_mixer_priority_lookup(const char **name, const char * const *names, int coef) 118d5ac70f0Sopenharmony_ci{ 119d5ac70f0Sopenharmony_ci int res; 120d5ac70f0Sopenharmony_ci 121d5ac70f0Sopenharmony_ci for (res = 0; *names; names++, res += coef) { 122d5ac70f0Sopenharmony_ci if (!strncmp(*name, *names, strlen(*names))) { 123d5ac70f0Sopenharmony_ci *name += strlen(*names); 124d5ac70f0Sopenharmony_ci if (**name == ' ') 125d5ac70f0Sopenharmony_ci (*name)++; 126d5ac70f0Sopenharmony_ci return res+1; 127d5ac70f0Sopenharmony_ci } 128d5ac70f0Sopenharmony_ci } 129d5ac70f0Sopenharmony_ci return MIXER_COMPARE_WEIGHT_NOT_FOUND; 130d5ac70f0Sopenharmony_ci} 131d5ac70f0Sopenharmony_ci 132d5ac70f0Sopenharmony_cistatic int get_compare_weight(const char *name, unsigned int idx) 133d5ac70f0Sopenharmony_ci{ 134d5ac70f0Sopenharmony_ci static const char *const names[] = { 135d5ac70f0Sopenharmony_ci "Master", 136d5ac70f0Sopenharmony_ci "Headphone", 137d5ac70f0Sopenharmony_ci "Speaker", 138d5ac70f0Sopenharmony_ci "Tone", 139d5ac70f0Sopenharmony_ci "Bass", 140d5ac70f0Sopenharmony_ci "Treble", 141d5ac70f0Sopenharmony_ci "3D Control", 142d5ac70f0Sopenharmony_ci "PCM", 143d5ac70f0Sopenharmony_ci "Front", 144d5ac70f0Sopenharmony_ci "Surround", 145d5ac70f0Sopenharmony_ci "Center", 146d5ac70f0Sopenharmony_ci "LFE", 147d5ac70f0Sopenharmony_ci "Side", 148d5ac70f0Sopenharmony_ci "Synth", 149d5ac70f0Sopenharmony_ci "FM", 150d5ac70f0Sopenharmony_ci "Wave", 151d5ac70f0Sopenharmony_ci "Music", 152d5ac70f0Sopenharmony_ci "DSP", 153d5ac70f0Sopenharmony_ci "Line", 154d5ac70f0Sopenharmony_ci "CD", 155d5ac70f0Sopenharmony_ci "Mic", 156d5ac70f0Sopenharmony_ci "Video", 157d5ac70f0Sopenharmony_ci "Zoom Video", 158d5ac70f0Sopenharmony_ci "Phone", 159d5ac70f0Sopenharmony_ci "I2S", 160d5ac70f0Sopenharmony_ci "IEC958", 161d5ac70f0Sopenharmony_ci "PC Speaker", 162d5ac70f0Sopenharmony_ci "Beep", 163d5ac70f0Sopenharmony_ci "Aux", 164d5ac70f0Sopenharmony_ci "Mono", 165d5ac70f0Sopenharmony_ci "Playback", 166d5ac70f0Sopenharmony_ci "Capture", 167d5ac70f0Sopenharmony_ci "Mix", 168d5ac70f0Sopenharmony_ci NULL 169d5ac70f0Sopenharmony_ci }; 170d5ac70f0Sopenharmony_ci static const char *const names1[] = { 171d5ac70f0Sopenharmony_ci "-", 172d5ac70f0Sopenharmony_ci NULL, 173d5ac70f0Sopenharmony_ci }; 174d5ac70f0Sopenharmony_ci static const char *const names2[] = { 175d5ac70f0Sopenharmony_ci "Mono", 176d5ac70f0Sopenharmony_ci "Digital", 177d5ac70f0Sopenharmony_ci "Switch", 178d5ac70f0Sopenharmony_ci "Depth", 179d5ac70f0Sopenharmony_ci "Wide", 180d5ac70f0Sopenharmony_ci "Space", 181d5ac70f0Sopenharmony_ci "Level", 182d5ac70f0Sopenharmony_ci "Center", 183d5ac70f0Sopenharmony_ci "Output", 184d5ac70f0Sopenharmony_ci "Boost", 185d5ac70f0Sopenharmony_ci "Tone", 186d5ac70f0Sopenharmony_ci "Bass", 187d5ac70f0Sopenharmony_ci "Treble", 188d5ac70f0Sopenharmony_ci NULL, 189d5ac70f0Sopenharmony_ci }; 190d5ac70f0Sopenharmony_ci const char *name1; 191d5ac70f0Sopenharmony_ci int res, res1; 192d5ac70f0Sopenharmony_ci 193d5ac70f0Sopenharmony_ci if ((res = compare_mixer_priority_lookup((const char **)&name, names, 1000)) == MIXER_COMPARE_WEIGHT_NOT_FOUND) 194d5ac70f0Sopenharmony_ci return MIXER_COMPARE_WEIGHT_NOT_FOUND; 195d5ac70f0Sopenharmony_ci if (*name == '\0') 196d5ac70f0Sopenharmony_ci goto __res; 197d5ac70f0Sopenharmony_ci for (name1 = name; *name1 != '\0'; name1++); 198d5ac70f0Sopenharmony_ci for (name1--; name1 != name && *name1 != ' '; name1--); 199d5ac70f0Sopenharmony_ci while (name1 != name && *name1 == ' ') 200d5ac70f0Sopenharmony_ci name1--; 201d5ac70f0Sopenharmony_ci if (name1 != name) { 202d5ac70f0Sopenharmony_ci for (; name1 != name && *name1 != ' '; name1--); 203d5ac70f0Sopenharmony_ci name = name1; 204d5ac70f0Sopenharmony_ci if ((res1 = compare_mixer_priority_lookup((const char **)&name, names1, 200)) == MIXER_COMPARE_WEIGHT_NOT_FOUND) 205d5ac70f0Sopenharmony_ci return res; 206d5ac70f0Sopenharmony_ci res += res1; 207d5ac70f0Sopenharmony_ci } else { 208d5ac70f0Sopenharmony_ci name = name1; 209d5ac70f0Sopenharmony_ci } 210d5ac70f0Sopenharmony_ci if ((res1 = compare_mixer_priority_lookup((const char **)&name, names2, 20)) == MIXER_COMPARE_WEIGHT_NOT_FOUND) 211d5ac70f0Sopenharmony_ci return res; 212d5ac70f0Sopenharmony_ci __res: 213d5ac70f0Sopenharmony_ci return MIXER_COMPARE_WEIGHT_SIMPLE_BASE + res + idx; 214d5ac70f0Sopenharmony_ci} 215d5ac70f0Sopenharmony_ci 216d5ac70f0Sopenharmony_cistatic long to_user(selem_none_t *s, int dir, selem_ctl_t *c, long value) 217d5ac70f0Sopenharmony_ci{ 218d5ac70f0Sopenharmony_ci int64_t n; 219d5ac70f0Sopenharmony_ci if (c->max == c->min) 220d5ac70f0Sopenharmony_ci return s->str[dir].min; 221d5ac70f0Sopenharmony_ci n = (int64_t) (value - c->min) * (s->str[dir].max - s->str[dir].min); 222d5ac70f0Sopenharmony_ci return s->str[dir].min + (n + (c->max - c->min) / 2) / (c->max - c->min); 223d5ac70f0Sopenharmony_ci} 224d5ac70f0Sopenharmony_ci 225d5ac70f0Sopenharmony_cistatic long from_user(selem_none_t *s, int dir, selem_ctl_t *c, long value) 226d5ac70f0Sopenharmony_ci{ 227d5ac70f0Sopenharmony_ci int64_t n; 228d5ac70f0Sopenharmony_ci if (s->str[dir].max == s->str[dir].min) 229d5ac70f0Sopenharmony_ci return c->min; 230d5ac70f0Sopenharmony_ci n = (int64_t) (value - s->str[dir].min) * (c->max - c->min); 231d5ac70f0Sopenharmony_ci return c->min + (n + (s->str[dir].max - s->str[dir].min) / 2) / (s->str[dir].max - s->str[dir].min); 232d5ac70f0Sopenharmony_ci} 233d5ac70f0Sopenharmony_ci 234d5ac70f0Sopenharmony_cistatic int elem_read_volume(selem_none_t *s, int dir, selem_ctl_type_t type) 235d5ac70f0Sopenharmony_ci{ 236d5ac70f0Sopenharmony_ci snd_ctl_elem_value_t ctl = {0}; 237d5ac70f0Sopenharmony_ci unsigned int idx; 238d5ac70f0Sopenharmony_ci int err; 239d5ac70f0Sopenharmony_ci selem_ctl_t *c = &s->ctls[type]; 240d5ac70f0Sopenharmony_ci if ((err = snd_hctl_elem_read(c->elem, &ctl)) < 0) 241d5ac70f0Sopenharmony_ci return err; 242d5ac70f0Sopenharmony_ci for (idx = 0; idx < s->str[dir].channels; idx++) { 243d5ac70f0Sopenharmony_ci unsigned int idx1 = idx; 244d5ac70f0Sopenharmony_ci if (idx >= c->values) 245d5ac70f0Sopenharmony_ci idx1 = 0; 246d5ac70f0Sopenharmony_ci s->str[dir].vol[idx] = 247d5ac70f0Sopenharmony_ci to_user(s, dir, c, 248d5ac70f0Sopenharmony_ci snd_ctl_elem_value_get_integer(&ctl, idx1)); 249d5ac70f0Sopenharmony_ci } 250d5ac70f0Sopenharmony_ci return 0; 251d5ac70f0Sopenharmony_ci} 252d5ac70f0Sopenharmony_ci 253d5ac70f0Sopenharmony_cistatic int elem_read_switch(selem_none_t *s, int dir, selem_ctl_type_t type) 254d5ac70f0Sopenharmony_ci{ 255d5ac70f0Sopenharmony_ci snd_ctl_elem_value_t ctl = {0}; 256d5ac70f0Sopenharmony_ci unsigned int idx; 257d5ac70f0Sopenharmony_ci int err; 258d5ac70f0Sopenharmony_ci selem_ctl_t *c = &s->ctls[type]; 259d5ac70f0Sopenharmony_ci if ((err = snd_hctl_elem_read(c->elem, &ctl)) < 0) 260d5ac70f0Sopenharmony_ci return err; 261d5ac70f0Sopenharmony_ci for (idx = 0; idx < s->str[dir].channels; idx++) { 262d5ac70f0Sopenharmony_ci unsigned int idx1 = idx; 263d5ac70f0Sopenharmony_ci if (idx >= c->values) 264d5ac70f0Sopenharmony_ci idx1 = 0; 265d5ac70f0Sopenharmony_ci if (!snd_ctl_elem_value_get_integer(&ctl, idx1)) 266d5ac70f0Sopenharmony_ci s->str[dir].sw &= ~(1 << idx); 267d5ac70f0Sopenharmony_ci } 268d5ac70f0Sopenharmony_ci return 0; 269d5ac70f0Sopenharmony_ci} 270d5ac70f0Sopenharmony_ci 271d5ac70f0Sopenharmony_cistatic int elem_read_route(selem_none_t *s, int dir, selem_ctl_type_t type) 272d5ac70f0Sopenharmony_ci{ 273d5ac70f0Sopenharmony_ci snd_ctl_elem_value_t ctl = {0}; 274d5ac70f0Sopenharmony_ci unsigned int idx; 275d5ac70f0Sopenharmony_ci int err; 276d5ac70f0Sopenharmony_ci selem_ctl_t *c = &s->ctls[type]; 277d5ac70f0Sopenharmony_ci if ((err = snd_hctl_elem_read(c->elem, &ctl)) < 0) 278d5ac70f0Sopenharmony_ci return err; 279d5ac70f0Sopenharmony_ci for (idx = 0; idx < s->str[dir].channels; idx++) { 280d5ac70f0Sopenharmony_ci unsigned int idx1 = idx; 281d5ac70f0Sopenharmony_ci if (idx >= c->values) 282d5ac70f0Sopenharmony_ci idx1 = 0; 283d5ac70f0Sopenharmony_ci if (!snd_ctl_elem_value_get_integer(&ctl, 284d5ac70f0Sopenharmony_ci idx1 * c->values + idx1)) 285d5ac70f0Sopenharmony_ci s->str[dir].sw &= ~(1 << idx); 286d5ac70f0Sopenharmony_ci } 287d5ac70f0Sopenharmony_ci return 0; 288d5ac70f0Sopenharmony_ci} 289d5ac70f0Sopenharmony_ci 290d5ac70f0Sopenharmony_cistatic int elem_read_enum(selem_none_t *s) 291d5ac70f0Sopenharmony_ci{ 292d5ac70f0Sopenharmony_ci snd_ctl_elem_value_t ctl = {0}; 293d5ac70f0Sopenharmony_ci unsigned int idx; 294d5ac70f0Sopenharmony_ci int err; 295d5ac70f0Sopenharmony_ci int type; 296d5ac70f0Sopenharmony_ci selem_ctl_t *c; 297d5ac70f0Sopenharmony_ci type = CTL_GLOBAL_ENUM; 298d5ac70f0Sopenharmony_ci if ((s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM)) == 299d5ac70f0Sopenharmony_ci (SM_CAP_CENUM | SM_CAP_PENUM)) 300d5ac70f0Sopenharmony_ci type = CTL_GLOBAL_ENUM; 301d5ac70f0Sopenharmony_ci else if (s->selem.caps & SM_CAP_PENUM) 302d5ac70f0Sopenharmony_ci type = CTL_PLAYBACK_ENUM; 303d5ac70f0Sopenharmony_ci else if (s->selem.caps & SM_CAP_CENUM) 304d5ac70f0Sopenharmony_ci type = CTL_CAPTURE_ENUM; 305d5ac70f0Sopenharmony_ci c = &s->ctls[type]; 306d5ac70f0Sopenharmony_ci if ((err = snd_hctl_elem_read(c->elem, &ctl)) < 0) 307d5ac70f0Sopenharmony_ci return err; 308d5ac70f0Sopenharmony_ci for (idx = 0; idx < s->str[0].channels; idx++) { 309d5ac70f0Sopenharmony_ci unsigned int idx1 = idx; 310d5ac70f0Sopenharmony_ci if (idx >= c->values) 311d5ac70f0Sopenharmony_ci idx1 = 0; 312d5ac70f0Sopenharmony_ci s->str[0].vol[idx] = 313d5ac70f0Sopenharmony_ci snd_ctl_elem_value_get_enumerated(&ctl, idx1); 314d5ac70f0Sopenharmony_ci } 315d5ac70f0Sopenharmony_ci return 0; 316d5ac70f0Sopenharmony_ci} 317d5ac70f0Sopenharmony_ci 318d5ac70f0Sopenharmony_cistatic int selem_read(snd_mixer_elem_t *elem) 319d5ac70f0Sopenharmony_ci{ 320d5ac70f0Sopenharmony_ci selem_none_t *s; 321d5ac70f0Sopenharmony_ci unsigned int idx; 322d5ac70f0Sopenharmony_ci int err = 0; 323d5ac70f0Sopenharmony_ci long pvol[32], cvol[32]; 324d5ac70f0Sopenharmony_ci unsigned int psw, csw; 325d5ac70f0Sopenharmony_ci 326d5ac70f0Sopenharmony_ci assert(snd_mixer_elem_get_type(elem) == SND_MIXER_ELEM_SIMPLE); 327d5ac70f0Sopenharmony_ci s = snd_mixer_elem_get_private(elem); 328d5ac70f0Sopenharmony_ci 329d5ac70f0Sopenharmony_ci memcpy(pvol, s->str[SM_PLAY].vol, sizeof(pvol)); 330d5ac70f0Sopenharmony_ci memset(&s->str[SM_PLAY].vol, 0, sizeof(s->str[SM_PLAY].vol)); 331d5ac70f0Sopenharmony_ci psw = s->str[SM_PLAY].sw; 332d5ac70f0Sopenharmony_ci s->str[SM_PLAY].sw = ~0U; 333d5ac70f0Sopenharmony_ci memcpy(cvol, s->str[SM_CAPT].vol, sizeof(cvol)); 334d5ac70f0Sopenharmony_ci memset(&s->str[SM_CAPT].vol, 0, sizeof(s->str[SM_CAPT].vol)); 335d5ac70f0Sopenharmony_ci csw = s->str[SM_CAPT].sw; 336d5ac70f0Sopenharmony_ci s->str[SM_CAPT].sw = ~0U; 337d5ac70f0Sopenharmony_ci 338d5ac70f0Sopenharmony_ci if (s->ctls[CTL_GLOBAL_ENUM].elem) { 339d5ac70f0Sopenharmony_ci err = elem_read_enum(s); 340d5ac70f0Sopenharmony_ci if (err < 0) 341d5ac70f0Sopenharmony_ci return err; 342d5ac70f0Sopenharmony_ci goto __skip_cswitch; 343d5ac70f0Sopenharmony_ci } 344d5ac70f0Sopenharmony_ci 345d5ac70f0Sopenharmony_ci if (s->ctls[CTL_CAPTURE_ENUM].elem) { 346d5ac70f0Sopenharmony_ci err = elem_read_enum(s); 347d5ac70f0Sopenharmony_ci if (err < 0) 348d5ac70f0Sopenharmony_ci return err; 349d5ac70f0Sopenharmony_ci goto __skip_cswitch; 350d5ac70f0Sopenharmony_ci } 351d5ac70f0Sopenharmony_ci 352d5ac70f0Sopenharmony_ci if (s->ctls[CTL_PLAYBACK_ENUM].elem) { 353d5ac70f0Sopenharmony_ci err = elem_read_enum(s); 354d5ac70f0Sopenharmony_ci if (err < 0) 355d5ac70f0Sopenharmony_ci return err; 356d5ac70f0Sopenharmony_ci goto __skip_cswitch; 357d5ac70f0Sopenharmony_ci } 358d5ac70f0Sopenharmony_ci 359d5ac70f0Sopenharmony_ci 360d5ac70f0Sopenharmony_ci if (s->ctls[CTL_PLAYBACK_VOLUME].elem) 361d5ac70f0Sopenharmony_ci err = elem_read_volume(s, SM_PLAY, CTL_PLAYBACK_VOLUME); 362d5ac70f0Sopenharmony_ci else if (s->ctls[CTL_GLOBAL_VOLUME].elem) 363d5ac70f0Sopenharmony_ci err = elem_read_volume(s, SM_PLAY, CTL_GLOBAL_VOLUME); 364d5ac70f0Sopenharmony_ci else if (s->ctls[CTL_SINGLE].elem && 365d5ac70f0Sopenharmony_ci s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_INTEGER) 366d5ac70f0Sopenharmony_ci err = elem_read_volume(s, SM_PLAY, CTL_SINGLE); 367d5ac70f0Sopenharmony_ci if (err < 0) 368d5ac70f0Sopenharmony_ci return err; 369d5ac70f0Sopenharmony_ci 370d5ac70f0Sopenharmony_ci if ((s->selem.caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH)) == 0) { 371d5ac70f0Sopenharmony_ci s->str[SM_PLAY].sw = 0; 372d5ac70f0Sopenharmony_ci goto __skip_pswitch; 373d5ac70f0Sopenharmony_ci } 374d5ac70f0Sopenharmony_ci if (s->ctls[CTL_PLAYBACK_SWITCH].elem) { 375d5ac70f0Sopenharmony_ci err = elem_read_switch(s, SM_PLAY, CTL_PLAYBACK_SWITCH); 376d5ac70f0Sopenharmony_ci if (err < 0) 377d5ac70f0Sopenharmony_ci return err; 378d5ac70f0Sopenharmony_ci } 379d5ac70f0Sopenharmony_ci if (s->ctls[CTL_GLOBAL_SWITCH].elem) { 380d5ac70f0Sopenharmony_ci err = elem_read_switch(s, SM_PLAY, CTL_GLOBAL_SWITCH); 381d5ac70f0Sopenharmony_ci if (err < 0) 382d5ac70f0Sopenharmony_ci return err; 383d5ac70f0Sopenharmony_ci } 384d5ac70f0Sopenharmony_ci if (s->ctls[CTL_SINGLE].elem && 385d5ac70f0Sopenharmony_ci s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_BOOLEAN) { 386d5ac70f0Sopenharmony_ci err = elem_read_switch(s, SM_PLAY, CTL_SINGLE); 387d5ac70f0Sopenharmony_ci if (err < 0) 388d5ac70f0Sopenharmony_ci return err; 389d5ac70f0Sopenharmony_ci } 390d5ac70f0Sopenharmony_ci if (s->ctls[CTL_PLAYBACK_ROUTE].elem) { 391d5ac70f0Sopenharmony_ci err = elem_read_route(s, SM_PLAY, CTL_PLAYBACK_ROUTE); 392d5ac70f0Sopenharmony_ci if (err < 0) 393d5ac70f0Sopenharmony_ci return err; 394d5ac70f0Sopenharmony_ci } 395d5ac70f0Sopenharmony_ci if (s->ctls[CTL_GLOBAL_ROUTE].elem) { 396d5ac70f0Sopenharmony_ci err = elem_read_route(s, SM_PLAY, CTL_GLOBAL_ROUTE); 397d5ac70f0Sopenharmony_ci if (err < 0) 398d5ac70f0Sopenharmony_ci return err; 399d5ac70f0Sopenharmony_ci } 400d5ac70f0Sopenharmony_ci __skip_pswitch: 401d5ac70f0Sopenharmony_ci 402d5ac70f0Sopenharmony_ci if (s->ctls[CTL_CAPTURE_VOLUME].elem) 403d5ac70f0Sopenharmony_ci err = elem_read_volume(s, SM_CAPT, CTL_CAPTURE_VOLUME); 404d5ac70f0Sopenharmony_ci else if (s->ctls[CTL_GLOBAL_VOLUME].elem) 405d5ac70f0Sopenharmony_ci err = elem_read_volume(s, SM_CAPT, CTL_GLOBAL_VOLUME); 406d5ac70f0Sopenharmony_ci else if (s->ctls[CTL_SINGLE].elem && 407d5ac70f0Sopenharmony_ci s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_INTEGER) 408d5ac70f0Sopenharmony_ci err = elem_read_volume(s, SM_CAPT, CTL_SINGLE); 409d5ac70f0Sopenharmony_ci if (err < 0) 410d5ac70f0Sopenharmony_ci return err; 411d5ac70f0Sopenharmony_ci 412d5ac70f0Sopenharmony_ci if ((s->selem.caps & (SM_CAP_GSWITCH|SM_CAP_CSWITCH)) == 0) { 413d5ac70f0Sopenharmony_ci s->str[SM_CAPT].sw = 0; 414d5ac70f0Sopenharmony_ci goto __skip_cswitch; 415d5ac70f0Sopenharmony_ci } 416d5ac70f0Sopenharmony_ci if (s->ctls[CTL_CAPTURE_SWITCH].elem) { 417d5ac70f0Sopenharmony_ci err = elem_read_switch(s, SM_CAPT, CTL_CAPTURE_SWITCH); 418d5ac70f0Sopenharmony_ci if (err < 0) 419d5ac70f0Sopenharmony_ci return err; 420d5ac70f0Sopenharmony_ci } 421d5ac70f0Sopenharmony_ci if (s->ctls[CTL_GLOBAL_SWITCH].elem) { 422d5ac70f0Sopenharmony_ci err = elem_read_switch(s, SM_CAPT, CTL_GLOBAL_SWITCH); 423d5ac70f0Sopenharmony_ci if (err < 0) 424d5ac70f0Sopenharmony_ci return err; 425d5ac70f0Sopenharmony_ci } 426d5ac70f0Sopenharmony_ci if (s->ctls[CTL_SINGLE].elem && 427d5ac70f0Sopenharmony_ci s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_BOOLEAN) { 428d5ac70f0Sopenharmony_ci err = elem_read_switch(s, SM_CAPT, CTL_SINGLE); 429d5ac70f0Sopenharmony_ci if (err < 0) 430d5ac70f0Sopenharmony_ci return err; 431d5ac70f0Sopenharmony_ci } 432d5ac70f0Sopenharmony_ci if (s->ctls[CTL_CAPTURE_ROUTE].elem) { 433d5ac70f0Sopenharmony_ci err = elem_read_route(s, SM_CAPT, CTL_CAPTURE_ROUTE); 434d5ac70f0Sopenharmony_ci if (err < 0) 435d5ac70f0Sopenharmony_ci return err; 436d5ac70f0Sopenharmony_ci } 437d5ac70f0Sopenharmony_ci if (s->ctls[CTL_GLOBAL_ROUTE].elem) { 438d5ac70f0Sopenharmony_ci err = elem_read_route(s, SM_CAPT, CTL_GLOBAL_ROUTE); 439d5ac70f0Sopenharmony_ci if (err < 0) 440d5ac70f0Sopenharmony_ci return err; 441d5ac70f0Sopenharmony_ci } 442d5ac70f0Sopenharmony_ci if (s->ctls[CTL_CAPTURE_SOURCE].elem) { 443d5ac70f0Sopenharmony_ci snd_ctl_elem_value_t ctl = {0}; 444d5ac70f0Sopenharmony_ci selem_ctl_t *c = &s->ctls[CTL_CAPTURE_SOURCE]; 445d5ac70f0Sopenharmony_ci err = snd_hctl_elem_read(c->elem, &ctl); 446d5ac70f0Sopenharmony_ci if (err < 0) 447d5ac70f0Sopenharmony_ci return err; 448d5ac70f0Sopenharmony_ci for (idx = 0; idx < s->str[SM_CAPT].channels; idx++) { 449d5ac70f0Sopenharmony_ci unsigned int idx1 = idx; 450d5ac70f0Sopenharmony_ci if (idx >= c->values) 451d5ac70f0Sopenharmony_ci idx1 = 0; 452d5ac70f0Sopenharmony_ci if (snd_ctl_elem_value_get_enumerated(&ctl, idx1) != 453d5ac70f0Sopenharmony_ci s->capture_item) 454d5ac70f0Sopenharmony_ci s->str[SM_CAPT].sw &= ~(1 << idx); 455d5ac70f0Sopenharmony_ci } 456d5ac70f0Sopenharmony_ci } 457d5ac70f0Sopenharmony_ci __skip_cswitch: 458d5ac70f0Sopenharmony_ci 459d5ac70f0Sopenharmony_ci if (memcmp(pvol, s->str[SM_PLAY].vol, sizeof(pvol)) || 460d5ac70f0Sopenharmony_ci psw != s->str[SM_PLAY].sw || 461d5ac70f0Sopenharmony_ci memcmp(cvol, s->str[SM_CAPT].vol, sizeof(cvol)) || 462d5ac70f0Sopenharmony_ci csw != s->str[SM_CAPT].sw) 463d5ac70f0Sopenharmony_ci return 1; 464d5ac70f0Sopenharmony_ci return 0; 465d5ac70f0Sopenharmony_ci} 466d5ac70f0Sopenharmony_ci 467d5ac70f0Sopenharmony_cistatic int elem_write_volume(selem_none_t *s, int dir, selem_ctl_type_t type) 468d5ac70f0Sopenharmony_ci{ 469d5ac70f0Sopenharmony_ci snd_ctl_elem_value_t ctl = {0}; 470d5ac70f0Sopenharmony_ci unsigned int idx; 471d5ac70f0Sopenharmony_ci int err; 472d5ac70f0Sopenharmony_ci selem_ctl_t *c = &s->ctls[type]; 473d5ac70f0Sopenharmony_ci if ((err = snd_hctl_elem_read(c->elem, &ctl)) < 0) 474d5ac70f0Sopenharmony_ci return err; 475d5ac70f0Sopenharmony_ci for (idx = 0; idx < c->values; idx++) 476d5ac70f0Sopenharmony_ci snd_ctl_elem_value_set_integer(&ctl, idx, 477d5ac70f0Sopenharmony_ci from_user(s, dir, c, s->str[dir].vol[idx])); 478d5ac70f0Sopenharmony_ci if ((err = snd_hctl_elem_write(c->elem, &ctl)) < 0) 479d5ac70f0Sopenharmony_ci return err; 480d5ac70f0Sopenharmony_ci return 0; 481d5ac70f0Sopenharmony_ci} 482d5ac70f0Sopenharmony_ci 483d5ac70f0Sopenharmony_cistatic int elem_write_switch(selem_none_t *s, int dir, selem_ctl_type_t type) 484d5ac70f0Sopenharmony_ci{ 485d5ac70f0Sopenharmony_ci snd_ctl_elem_value_t ctl = {0}; 486d5ac70f0Sopenharmony_ci unsigned int idx; 487d5ac70f0Sopenharmony_ci int err; 488d5ac70f0Sopenharmony_ci selem_ctl_t *c = &s->ctls[type]; 489d5ac70f0Sopenharmony_ci if ((err = snd_hctl_elem_read(c->elem, &ctl)) < 0) 490d5ac70f0Sopenharmony_ci return err; 491d5ac70f0Sopenharmony_ci for (idx = 0; idx < c->values; idx++) 492d5ac70f0Sopenharmony_ci snd_ctl_elem_value_set_integer(&ctl, idx, 493d5ac70f0Sopenharmony_ci !!(s->str[dir].sw & (1 << idx))); 494d5ac70f0Sopenharmony_ci if ((err = snd_hctl_elem_write(c->elem, &ctl)) < 0) 495d5ac70f0Sopenharmony_ci return err; 496d5ac70f0Sopenharmony_ci return 0; 497d5ac70f0Sopenharmony_ci} 498d5ac70f0Sopenharmony_ci 499d5ac70f0Sopenharmony_cistatic int elem_write_switch_constant(selem_none_t *s, selem_ctl_type_t type, int val) 500d5ac70f0Sopenharmony_ci{ 501d5ac70f0Sopenharmony_ci snd_ctl_elem_value_t ctl = {0}; 502d5ac70f0Sopenharmony_ci unsigned int idx; 503d5ac70f0Sopenharmony_ci int err; 504d5ac70f0Sopenharmony_ci selem_ctl_t *c = &s->ctls[type]; 505d5ac70f0Sopenharmony_ci if ((err = snd_hctl_elem_read(c->elem, &ctl)) < 0) 506d5ac70f0Sopenharmony_ci return err; 507d5ac70f0Sopenharmony_ci for (idx = 0; idx < c->values; idx++) 508d5ac70f0Sopenharmony_ci snd_ctl_elem_value_set_integer(&ctl, idx, !!val); 509d5ac70f0Sopenharmony_ci if ((err = snd_hctl_elem_write(c->elem, &ctl)) < 0) 510d5ac70f0Sopenharmony_ci return err; 511d5ac70f0Sopenharmony_ci return 0; 512d5ac70f0Sopenharmony_ci} 513d5ac70f0Sopenharmony_ci 514d5ac70f0Sopenharmony_cistatic int elem_write_route(selem_none_t *s, int dir, selem_ctl_type_t type) 515d5ac70f0Sopenharmony_ci{ 516d5ac70f0Sopenharmony_ci snd_ctl_elem_value_t ctl = {0}; 517d5ac70f0Sopenharmony_ci unsigned int idx; 518d5ac70f0Sopenharmony_ci int err; 519d5ac70f0Sopenharmony_ci selem_ctl_t *c = &s->ctls[type]; 520d5ac70f0Sopenharmony_ci if ((err = snd_hctl_elem_read(c->elem, &ctl)) < 0) 521d5ac70f0Sopenharmony_ci return err; 522d5ac70f0Sopenharmony_ci for (idx = 0; idx < c->values * c->values; idx++) 523d5ac70f0Sopenharmony_ci snd_ctl_elem_value_set_integer(&ctl, idx, 0); 524d5ac70f0Sopenharmony_ci for (idx = 0; idx < c->values; idx++) 525d5ac70f0Sopenharmony_ci snd_ctl_elem_value_set_integer(&ctl, idx * c->values + idx, 526d5ac70f0Sopenharmony_ci !!(s->str[dir].sw & (1 << idx))); 527d5ac70f0Sopenharmony_ci if ((err = snd_hctl_elem_write(c->elem, &ctl)) < 0) 528d5ac70f0Sopenharmony_ci return err; 529d5ac70f0Sopenharmony_ci return 0; 530d5ac70f0Sopenharmony_ci} 531d5ac70f0Sopenharmony_ci 532d5ac70f0Sopenharmony_cistatic int elem_write_enum(selem_none_t *s) 533d5ac70f0Sopenharmony_ci{ 534d5ac70f0Sopenharmony_ci snd_ctl_elem_value_t ctl = {0}; 535d5ac70f0Sopenharmony_ci unsigned int idx; 536d5ac70f0Sopenharmony_ci int err; 537d5ac70f0Sopenharmony_ci int type; 538d5ac70f0Sopenharmony_ci selem_ctl_t *c; 539d5ac70f0Sopenharmony_ci type = CTL_GLOBAL_ENUM; 540d5ac70f0Sopenharmony_ci if ((s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM)) == 541d5ac70f0Sopenharmony_ci (SM_CAP_CENUM | SM_CAP_PENUM)) 542d5ac70f0Sopenharmony_ci type = CTL_GLOBAL_ENUM; 543d5ac70f0Sopenharmony_ci else if (s->selem.caps & SM_CAP_PENUM) 544d5ac70f0Sopenharmony_ci type = CTL_PLAYBACK_ENUM; 545d5ac70f0Sopenharmony_ci else if (s->selem.caps & SM_CAP_CENUM) 546d5ac70f0Sopenharmony_ci type = CTL_CAPTURE_ENUM; 547d5ac70f0Sopenharmony_ci c = &s->ctls[type]; 548d5ac70f0Sopenharmony_ci if ((err = snd_hctl_elem_read(c->elem, &ctl)) < 0) 549d5ac70f0Sopenharmony_ci return err; 550d5ac70f0Sopenharmony_ci for (idx = 0; idx < c->values; idx++) 551d5ac70f0Sopenharmony_ci snd_ctl_elem_value_set_enumerated(&ctl, idx, 552d5ac70f0Sopenharmony_ci (unsigned int)s->str[0].vol[idx]); 553d5ac70f0Sopenharmony_ci if ((err = snd_hctl_elem_write(c->elem, &ctl)) < 0) 554d5ac70f0Sopenharmony_ci return err; 555d5ac70f0Sopenharmony_ci return 0; 556d5ac70f0Sopenharmony_ci} 557d5ac70f0Sopenharmony_ci 558d5ac70f0Sopenharmony_cistatic int selem_write_main(snd_mixer_elem_t *elem) 559d5ac70f0Sopenharmony_ci{ 560d5ac70f0Sopenharmony_ci selem_none_t *s; 561d5ac70f0Sopenharmony_ci unsigned int idx; 562d5ac70f0Sopenharmony_ci int err; 563d5ac70f0Sopenharmony_ci 564d5ac70f0Sopenharmony_ci assert(snd_mixer_elem_get_type(elem) == SND_MIXER_ELEM_SIMPLE); 565d5ac70f0Sopenharmony_ci s = snd_mixer_elem_get_private(elem); 566d5ac70f0Sopenharmony_ci 567d5ac70f0Sopenharmony_ci if (s->ctls[CTL_GLOBAL_ENUM].elem) 568d5ac70f0Sopenharmony_ci return elem_write_enum(s); 569d5ac70f0Sopenharmony_ci 570d5ac70f0Sopenharmony_ci if (s->ctls[CTL_PLAYBACK_ENUM].elem) 571d5ac70f0Sopenharmony_ci return elem_write_enum(s); 572d5ac70f0Sopenharmony_ci 573d5ac70f0Sopenharmony_ci if (s->ctls[CTL_CAPTURE_ENUM].elem) 574d5ac70f0Sopenharmony_ci return elem_write_enum(s); 575d5ac70f0Sopenharmony_ci 576d5ac70f0Sopenharmony_ci if (s->ctls[CTL_SINGLE].elem) { 577d5ac70f0Sopenharmony_ci if (s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_INTEGER) 578d5ac70f0Sopenharmony_ci err = elem_write_volume(s, SM_PLAY, CTL_SINGLE); 579d5ac70f0Sopenharmony_ci else 580d5ac70f0Sopenharmony_ci err = elem_write_switch(s, SM_PLAY, CTL_SINGLE); 581d5ac70f0Sopenharmony_ci if (err < 0) 582d5ac70f0Sopenharmony_ci return err; 583d5ac70f0Sopenharmony_ci } 584d5ac70f0Sopenharmony_ci if (s->ctls[CTL_GLOBAL_VOLUME].elem) { 585d5ac70f0Sopenharmony_ci err = elem_write_volume(s, SM_PLAY, CTL_GLOBAL_VOLUME); 586d5ac70f0Sopenharmony_ci if (err < 0) 587d5ac70f0Sopenharmony_ci return err; 588d5ac70f0Sopenharmony_ci } 589d5ac70f0Sopenharmony_ci if (s->ctls[CTL_GLOBAL_SWITCH].elem) { 590d5ac70f0Sopenharmony_ci if (s->ctls[CTL_PLAYBACK_SWITCH].elem && 591d5ac70f0Sopenharmony_ci s->ctls[CTL_CAPTURE_SWITCH].elem) 592d5ac70f0Sopenharmony_ci err = elem_write_switch_constant(s, CTL_GLOBAL_SWITCH, 593d5ac70f0Sopenharmony_ci 1); 594d5ac70f0Sopenharmony_ci else 595d5ac70f0Sopenharmony_ci err = elem_write_switch(s, SM_PLAY, CTL_GLOBAL_SWITCH); 596d5ac70f0Sopenharmony_ci if (err < 0) 597d5ac70f0Sopenharmony_ci return err; 598d5ac70f0Sopenharmony_ci } 599d5ac70f0Sopenharmony_ci if (s->ctls[CTL_PLAYBACK_VOLUME].elem) { 600d5ac70f0Sopenharmony_ci err = elem_write_volume(s, SM_PLAY, CTL_PLAYBACK_VOLUME); 601d5ac70f0Sopenharmony_ci if (err < 0) 602d5ac70f0Sopenharmony_ci return err; 603d5ac70f0Sopenharmony_ci } 604d5ac70f0Sopenharmony_ci if (s->ctls[CTL_PLAYBACK_SWITCH].elem) { 605d5ac70f0Sopenharmony_ci err = elem_write_switch(s, SM_PLAY, CTL_PLAYBACK_SWITCH); 606d5ac70f0Sopenharmony_ci if (err < 0) 607d5ac70f0Sopenharmony_ci return err; 608d5ac70f0Sopenharmony_ci } 609d5ac70f0Sopenharmony_ci if (s->ctls[CTL_PLAYBACK_ROUTE].elem) { 610d5ac70f0Sopenharmony_ci err = elem_write_route(s, SM_PLAY, CTL_PLAYBACK_ROUTE); 611d5ac70f0Sopenharmony_ci if (err < 0) 612d5ac70f0Sopenharmony_ci return err; 613d5ac70f0Sopenharmony_ci } 614d5ac70f0Sopenharmony_ci if (s->ctls[CTL_CAPTURE_VOLUME].elem) { 615d5ac70f0Sopenharmony_ci err = elem_write_volume(s, SM_CAPT, CTL_CAPTURE_VOLUME); 616d5ac70f0Sopenharmony_ci if (err < 0) 617d5ac70f0Sopenharmony_ci return err; 618d5ac70f0Sopenharmony_ci } 619d5ac70f0Sopenharmony_ci if (s->ctls[CTL_CAPTURE_SWITCH].elem) { 620d5ac70f0Sopenharmony_ci err = elem_write_switch(s, SM_CAPT, CTL_CAPTURE_SWITCH); 621d5ac70f0Sopenharmony_ci if (err < 0) 622d5ac70f0Sopenharmony_ci return err; 623d5ac70f0Sopenharmony_ci } 624d5ac70f0Sopenharmony_ci if (s->ctls[CTL_CAPTURE_ROUTE].elem) { 625d5ac70f0Sopenharmony_ci err = elem_write_route(s, SM_CAPT, CTL_CAPTURE_ROUTE); 626d5ac70f0Sopenharmony_ci if (err < 0) 627d5ac70f0Sopenharmony_ci return err; 628d5ac70f0Sopenharmony_ci } 629d5ac70f0Sopenharmony_ci if (s->ctls[CTL_CAPTURE_SOURCE].elem) { 630d5ac70f0Sopenharmony_ci snd_ctl_elem_value_t ctl = {0}; 631d5ac70f0Sopenharmony_ci selem_ctl_t *c = &s->ctls[CTL_CAPTURE_SOURCE]; 632d5ac70f0Sopenharmony_ci if ((err = snd_hctl_elem_read(c->elem, &ctl)) < 0) 633d5ac70f0Sopenharmony_ci return err; 634d5ac70f0Sopenharmony_ci for (idx = 0; idx < c->values; idx++) { 635d5ac70f0Sopenharmony_ci if (s->str[SM_CAPT].sw & (1 << idx)) 636d5ac70f0Sopenharmony_ci snd_ctl_elem_value_set_enumerated(&ctl, 637d5ac70f0Sopenharmony_ci idx, s->capture_item); 638d5ac70f0Sopenharmony_ci } 639d5ac70f0Sopenharmony_ci if ((err = snd_hctl_elem_write(c->elem, &ctl)) < 0) 640d5ac70f0Sopenharmony_ci return err; 641d5ac70f0Sopenharmony_ci /* update the element, don't remove */ 642d5ac70f0Sopenharmony_ci err = selem_read(elem); 643d5ac70f0Sopenharmony_ci if (err < 0) 644d5ac70f0Sopenharmony_ci return err; 645d5ac70f0Sopenharmony_ci } 646d5ac70f0Sopenharmony_ci return 0; 647d5ac70f0Sopenharmony_ci} 648d5ac70f0Sopenharmony_ci 649d5ac70f0Sopenharmony_cistatic int selem_write(snd_mixer_elem_t *elem) 650d5ac70f0Sopenharmony_ci{ 651d5ac70f0Sopenharmony_ci int err; 652d5ac70f0Sopenharmony_ci 653d5ac70f0Sopenharmony_ci err = selem_write_main(elem); 654d5ac70f0Sopenharmony_ci if (err < 0) 655d5ac70f0Sopenharmony_ci selem_read(elem); 656d5ac70f0Sopenharmony_ci return err; 657d5ac70f0Sopenharmony_ci} 658d5ac70f0Sopenharmony_ci 659d5ac70f0Sopenharmony_cistatic void selem_free(snd_mixer_elem_t *elem) 660d5ac70f0Sopenharmony_ci{ 661d5ac70f0Sopenharmony_ci selem_none_t *simple = snd_mixer_elem_get_private(elem); 662d5ac70f0Sopenharmony_ci assert(snd_mixer_elem_get_type(elem) == SND_MIXER_ELEM_SIMPLE); 663d5ac70f0Sopenharmony_ci if (simple->selem.id) 664d5ac70f0Sopenharmony_ci snd_mixer_selem_id_free(simple->selem.id); 665d5ac70f0Sopenharmony_ci /* free db range information */ 666d5ac70f0Sopenharmony_ci free(simple->str[0].db_info); 667d5ac70f0Sopenharmony_ci free(simple->str[1].db_info); 668d5ac70f0Sopenharmony_ci free(simple); 669d5ac70f0Sopenharmony_ci} 670d5ac70f0Sopenharmony_ci 671d5ac70f0Sopenharmony_cistatic int simple_update(snd_mixer_elem_t *melem) 672d5ac70f0Sopenharmony_ci{ 673d5ac70f0Sopenharmony_ci selem_none_t *simple; 674d5ac70f0Sopenharmony_ci unsigned int caps, pchannels, cchannels; 675d5ac70f0Sopenharmony_ci long pmin, pmax, cmin, cmax; 676d5ac70f0Sopenharmony_ci selem_ctl_t *ctl; 677d5ac70f0Sopenharmony_ci 678d5ac70f0Sopenharmony_ci caps = 0; 679d5ac70f0Sopenharmony_ci pchannels = 0; 680d5ac70f0Sopenharmony_ci pmin = LONG_MAX; 681d5ac70f0Sopenharmony_ci pmax = LONG_MIN; 682d5ac70f0Sopenharmony_ci cchannels = 0; 683d5ac70f0Sopenharmony_ci cmin = LONG_MAX; 684d5ac70f0Sopenharmony_ci cmax = LONG_MIN; 685d5ac70f0Sopenharmony_ci assert(snd_mixer_elem_get_type(melem) == SND_MIXER_ELEM_SIMPLE); 686d5ac70f0Sopenharmony_ci simple = snd_mixer_elem_get_private(melem); 687d5ac70f0Sopenharmony_ci ctl = &simple->ctls[CTL_SINGLE]; 688d5ac70f0Sopenharmony_ci if (ctl->elem) { 689d5ac70f0Sopenharmony_ci pchannels = cchannels = ctl->values; 690d5ac70f0Sopenharmony_ci if (ctl->type == SND_CTL_ELEM_TYPE_INTEGER) { 691d5ac70f0Sopenharmony_ci caps |= SM_CAP_GVOLUME; 692d5ac70f0Sopenharmony_ci pmin = cmin = ctl->min; 693d5ac70f0Sopenharmony_ci pmax = cmax = ctl->max; 694d5ac70f0Sopenharmony_ci } else 695d5ac70f0Sopenharmony_ci caps |= SM_CAP_GSWITCH; 696d5ac70f0Sopenharmony_ci } 697d5ac70f0Sopenharmony_ci ctl = &simple->ctls[CTL_GLOBAL_SWITCH]; 698d5ac70f0Sopenharmony_ci if (ctl->elem) { 699d5ac70f0Sopenharmony_ci if (pchannels < ctl->values) 700d5ac70f0Sopenharmony_ci pchannels = ctl->values; 701d5ac70f0Sopenharmony_ci if (cchannels < ctl->values) 702d5ac70f0Sopenharmony_ci cchannels = ctl->values; 703d5ac70f0Sopenharmony_ci caps |= SM_CAP_GSWITCH; 704d5ac70f0Sopenharmony_ci } 705d5ac70f0Sopenharmony_ci ctl = &simple->ctls[CTL_GLOBAL_ROUTE]; 706d5ac70f0Sopenharmony_ci if (ctl->elem) { 707d5ac70f0Sopenharmony_ci if (pchannels < ctl->values) 708d5ac70f0Sopenharmony_ci pchannels = ctl->values; 709d5ac70f0Sopenharmony_ci if (cchannels < ctl->values) 710d5ac70f0Sopenharmony_ci cchannels = ctl->values; 711d5ac70f0Sopenharmony_ci caps |= SM_CAP_GSWITCH; 712d5ac70f0Sopenharmony_ci } 713d5ac70f0Sopenharmony_ci ctl = &simple->ctls[CTL_GLOBAL_VOLUME]; 714d5ac70f0Sopenharmony_ci if (ctl->elem) { 715d5ac70f0Sopenharmony_ci if (pchannels < ctl->values) 716d5ac70f0Sopenharmony_ci pchannels = ctl->values; 717d5ac70f0Sopenharmony_ci if (pmin > ctl->min) 718d5ac70f0Sopenharmony_ci pmin = ctl->min; 719d5ac70f0Sopenharmony_ci if (pmax < ctl->max) 720d5ac70f0Sopenharmony_ci pmax = ctl->max; 721d5ac70f0Sopenharmony_ci if (cchannels < ctl->values) 722d5ac70f0Sopenharmony_ci cchannels = ctl->values; 723d5ac70f0Sopenharmony_ci if (cmin > ctl->min) 724d5ac70f0Sopenharmony_ci cmin = ctl->min; 725d5ac70f0Sopenharmony_ci if (cmax < ctl->max) 726d5ac70f0Sopenharmony_ci cmax = ctl->max; 727d5ac70f0Sopenharmony_ci caps |= SM_CAP_GVOLUME; 728d5ac70f0Sopenharmony_ci } 729d5ac70f0Sopenharmony_ci ctl = &simple->ctls[CTL_PLAYBACK_SWITCH]; 730d5ac70f0Sopenharmony_ci if (ctl->elem) { 731d5ac70f0Sopenharmony_ci if (pchannels < ctl->values) 732d5ac70f0Sopenharmony_ci pchannels = ctl->values; 733d5ac70f0Sopenharmony_ci caps |= SM_CAP_PSWITCH; 734d5ac70f0Sopenharmony_ci caps &= ~SM_CAP_GSWITCH; 735d5ac70f0Sopenharmony_ci } 736d5ac70f0Sopenharmony_ci ctl = &simple->ctls[CTL_PLAYBACK_ROUTE]; 737d5ac70f0Sopenharmony_ci if (ctl->elem) { 738d5ac70f0Sopenharmony_ci if (pchannels < ctl->values) 739d5ac70f0Sopenharmony_ci pchannels = ctl->values; 740d5ac70f0Sopenharmony_ci caps |= SM_CAP_PSWITCH; 741d5ac70f0Sopenharmony_ci caps &= ~SM_CAP_GSWITCH; 742d5ac70f0Sopenharmony_ci } 743d5ac70f0Sopenharmony_ci ctl = &simple->ctls[CTL_CAPTURE_SWITCH]; 744d5ac70f0Sopenharmony_ci if (ctl->elem) { 745d5ac70f0Sopenharmony_ci if (cchannels < ctl->values) 746d5ac70f0Sopenharmony_ci cchannels = ctl->values; 747d5ac70f0Sopenharmony_ci caps |= SM_CAP_CSWITCH; 748d5ac70f0Sopenharmony_ci caps &= ~SM_CAP_GSWITCH; 749d5ac70f0Sopenharmony_ci } 750d5ac70f0Sopenharmony_ci ctl = &simple->ctls[CTL_CAPTURE_ROUTE]; 751d5ac70f0Sopenharmony_ci if (ctl->elem) { 752d5ac70f0Sopenharmony_ci if (cchannels < ctl->values) 753d5ac70f0Sopenharmony_ci cchannels = ctl->values; 754d5ac70f0Sopenharmony_ci caps |= SM_CAP_CSWITCH; 755d5ac70f0Sopenharmony_ci caps &= ~SM_CAP_GSWITCH; 756d5ac70f0Sopenharmony_ci } 757d5ac70f0Sopenharmony_ci ctl = &simple->ctls[CTL_PLAYBACK_VOLUME]; 758d5ac70f0Sopenharmony_ci if (ctl->elem) { 759d5ac70f0Sopenharmony_ci if (pchannels < ctl->values) 760d5ac70f0Sopenharmony_ci pchannels = ctl->values; 761d5ac70f0Sopenharmony_ci if (pmin > ctl->min) 762d5ac70f0Sopenharmony_ci pmin = ctl->min; 763d5ac70f0Sopenharmony_ci if (pmax < ctl->max) 764d5ac70f0Sopenharmony_ci pmax = ctl->max; 765d5ac70f0Sopenharmony_ci caps |= SM_CAP_PVOLUME; 766d5ac70f0Sopenharmony_ci caps &= ~SM_CAP_GVOLUME; 767d5ac70f0Sopenharmony_ci } 768d5ac70f0Sopenharmony_ci ctl = &simple->ctls[CTL_CAPTURE_VOLUME]; 769d5ac70f0Sopenharmony_ci if (ctl->elem) { 770d5ac70f0Sopenharmony_ci if (cchannels < ctl->values) 771d5ac70f0Sopenharmony_ci cchannels = ctl->values; 772d5ac70f0Sopenharmony_ci if (cmin > ctl->min) 773d5ac70f0Sopenharmony_ci cmin = ctl->min; 774d5ac70f0Sopenharmony_ci if (cmax < ctl->max) 775d5ac70f0Sopenharmony_ci cmax = ctl->max; 776d5ac70f0Sopenharmony_ci caps |= SM_CAP_CVOLUME; 777d5ac70f0Sopenharmony_ci caps &= ~SM_CAP_GVOLUME; 778d5ac70f0Sopenharmony_ci } 779d5ac70f0Sopenharmony_ci ctl = &simple->ctls[CTL_CAPTURE_SOURCE]; 780d5ac70f0Sopenharmony_ci if (ctl->elem) { 781d5ac70f0Sopenharmony_ci if (cchannels < ctl->values) 782d5ac70f0Sopenharmony_ci cchannels = ctl->values; 783d5ac70f0Sopenharmony_ci caps |= SM_CAP_CSWITCH | SM_CAP_CSWITCH_EXCL; 784d5ac70f0Sopenharmony_ci caps &= ~SM_CAP_GSWITCH; 785d5ac70f0Sopenharmony_ci } 786d5ac70f0Sopenharmony_ci ctl = &simple->ctls[CTL_GLOBAL_ENUM]; 787d5ac70f0Sopenharmony_ci if (ctl->elem) { 788d5ac70f0Sopenharmony_ci if (pchannels < ctl->values) 789d5ac70f0Sopenharmony_ci pchannels = ctl->values; 790d5ac70f0Sopenharmony_ci caps |= SM_CAP_PENUM | SM_CAP_CENUM; 791d5ac70f0Sopenharmony_ci } 792d5ac70f0Sopenharmony_ci ctl = &simple->ctls[CTL_PLAYBACK_ENUM]; 793d5ac70f0Sopenharmony_ci if (ctl->elem) { 794d5ac70f0Sopenharmony_ci if (pchannels < ctl->values) 795d5ac70f0Sopenharmony_ci pchannels = ctl->values; 796d5ac70f0Sopenharmony_ci caps |= SM_CAP_PENUM; 797d5ac70f0Sopenharmony_ci } 798d5ac70f0Sopenharmony_ci ctl = &simple->ctls[CTL_CAPTURE_ENUM]; 799d5ac70f0Sopenharmony_ci if (ctl->elem) { 800d5ac70f0Sopenharmony_ci if (pchannels < ctl->values) 801d5ac70f0Sopenharmony_ci pchannels = ctl->values; 802d5ac70f0Sopenharmony_ci caps |= SM_CAP_CENUM; 803d5ac70f0Sopenharmony_ci } 804d5ac70f0Sopenharmony_ci if (pchannels > 32) 805d5ac70f0Sopenharmony_ci pchannels = 32; 806d5ac70f0Sopenharmony_ci if (cchannels > 32) 807d5ac70f0Sopenharmony_ci cchannels = 32; 808d5ac70f0Sopenharmony_ci if (caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH)) 809d5ac70f0Sopenharmony_ci caps |= SM_CAP_PSWITCH_JOIN; 810d5ac70f0Sopenharmony_ci if (caps & (SM_CAP_GVOLUME|SM_CAP_PVOLUME)) 811d5ac70f0Sopenharmony_ci caps |= SM_CAP_PVOLUME_JOIN; 812d5ac70f0Sopenharmony_ci if (caps & (SM_CAP_GSWITCH|SM_CAP_CSWITCH)) 813d5ac70f0Sopenharmony_ci caps |= SM_CAP_CSWITCH_JOIN; 814d5ac70f0Sopenharmony_ci if (caps & (SM_CAP_GVOLUME|SM_CAP_CVOLUME)) 815d5ac70f0Sopenharmony_ci caps |= SM_CAP_CVOLUME_JOIN; 816d5ac70f0Sopenharmony_ci if (pchannels > 1 || cchannels > 1) { 817d5ac70f0Sopenharmony_ci if (simple->ctls[CTL_SINGLE].elem && 818d5ac70f0Sopenharmony_ci simple->ctls[CTL_SINGLE].values > 1) { 819d5ac70f0Sopenharmony_ci if (caps & SM_CAP_GSWITCH) 820d5ac70f0Sopenharmony_ci caps &= ~(SM_CAP_PSWITCH_JOIN|SM_CAP_CSWITCH_JOIN); 821d5ac70f0Sopenharmony_ci else 822d5ac70f0Sopenharmony_ci caps &= ~(SM_CAP_PVOLUME_JOIN|SM_CAP_CVOLUME_JOIN); 823d5ac70f0Sopenharmony_ci } 824d5ac70f0Sopenharmony_ci if (simple->ctls[CTL_GLOBAL_ROUTE].elem || 825d5ac70f0Sopenharmony_ci (simple->ctls[CTL_GLOBAL_SWITCH].elem && 826d5ac70f0Sopenharmony_ci simple->ctls[CTL_GLOBAL_SWITCH].values > 1)) { 827d5ac70f0Sopenharmony_ci caps &= ~(SM_CAP_PSWITCH_JOIN|SM_CAP_CSWITCH_JOIN); 828d5ac70f0Sopenharmony_ci } 829d5ac70f0Sopenharmony_ci if (simple->ctls[CTL_GLOBAL_VOLUME].elem && 830d5ac70f0Sopenharmony_ci simple->ctls[CTL_GLOBAL_VOLUME].values > 1) { 831d5ac70f0Sopenharmony_ci caps &= ~(SM_CAP_PVOLUME_JOIN|SM_CAP_CVOLUME_JOIN); 832d5ac70f0Sopenharmony_ci } 833d5ac70f0Sopenharmony_ci } 834d5ac70f0Sopenharmony_ci if (pchannels > 1) { 835d5ac70f0Sopenharmony_ci if (simple->ctls[CTL_PLAYBACK_ROUTE].elem || 836d5ac70f0Sopenharmony_ci (simple->ctls[CTL_PLAYBACK_SWITCH].elem && 837d5ac70f0Sopenharmony_ci simple->ctls[CTL_PLAYBACK_SWITCH].values > 1)) { 838d5ac70f0Sopenharmony_ci caps &= ~SM_CAP_PSWITCH_JOIN; 839d5ac70f0Sopenharmony_ci } 840d5ac70f0Sopenharmony_ci if (simple->ctls[CTL_PLAYBACK_VOLUME].elem && 841d5ac70f0Sopenharmony_ci simple->ctls[CTL_PLAYBACK_VOLUME].values > 1) { 842d5ac70f0Sopenharmony_ci caps &= ~SM_CAP_PVOLUME_JOIN; 843d5ac70f0Sopenharmony_ci } 844d5ac70f0Sopenharmony_ci } 845d5ac70f0Sopenharmony_ci if (cchannels > 1) { 846d5ac70f0Sopenharmony_ci if (simple->ctls[CTL_CAPTURE_ROUTE].elem || 847d5ac70f0Sopenharmony_ci (simple->ctls[CTL_CAPTURE_SWITCH].elem && 848d5ac70f0Sopenharmony_ci simple->ctls[CTL_CAPTURE_SWITCH].values > 1) || 849d5ac70f0Sopenharmony_ci (simple->ctls[CTL_CAPTURE_SOURCE].elem && 850d5ac70f0Sopenharmony_ci simple->ctls[CTL_CAPTURE_SOURCE].values > 1)) { 851d5ac70f0Sopenharmony_ci caps &= ~SM_CAP_CSWITCH_JOIN; 852d5ac70f0Sopenharmony_ci } 853d5ac70f0Sopenharmony_ci if (simple->ctls[CTL_CAPTURE_VOLUME].elem && 854d5ac70f0Sopenharmony_ci simple->ctls[CTL_CAPTURE_VOLUME].values > 1) { 855d5ac70f0Sopenharmony_ci caps &= ~SM_CAP_CVOLUME_JOIN; 856d5ac70f0Sopenharmony_ci } 857d5ac70f0Sopenharmony_ci } 858d5ac70f0Sopenharmony_ci 859d5ac70f0Sopenharmony_ci /* exceptions */ 860d5ac70f0Sopenharmony_ci if ((caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH|SM_CAP_CSWITCH)) && 861d5ac70f0Sopenharmony_ci (caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH|SM_CAP_CSWITCH)) == (caps & SM_CAP_GSWITCH)) { 862d5ac70f0Sopenharmony_ci caps &= ~(SM_CAP_GSWITCH|SM_CAP_CSWITCH_JOIN|SM_CAP_CSWITCH_EXCL); 863d5ac70f0Sopenharmony_ci caps |= SM_CAP_PSWITCH; 864d5ac70f0Sopenharmony_ci } 865d5ac70f0Sopenharmony_ci 866d5ac70f0Sopenharmony_ci if ((caps & SM_CAP_GSWITCH) && 867d5ac70f0Sopenharmony_ci (caps & (SM_CAP_PSWITCH|SM_CAP_CSWITCH)) == 0) 868d5ac70f0Sopenharmony_ci caps |= SM_CAP_PSWITCH|SM_CAP_CSWITCH; 869d5ac70f0Sopenharmony_ci 870d5ac70f0Sopenharmony_ci if ((caps & SM_CAP_GVOLUME) && 871d5ac70f0Sopenharmony_ci (caps & (SM_CAP_PVOLUME|SM_CAP_CVOLUME)) == 0) 872d5ac70f0Sopenharmony_ci caps |= SM_CAP_PVOLUME|SM_CAP_CVOLUME; 873d5ac70f0Sopenharmony_ci 874d5ac70f0Sopenharmony_ci simple->selem.caps = caps; 875d5ac70f0Sopenharmony_ci simple->str[SM_PLAY].channels = pchannels; 876d5ac70f0Sopenharmony_ci if (!simple->str[SM_PLAY].range) { 877d5ac70f0Sopenharmony_ci simple->str[SM_PLAY].min = pmin != LONG_MAX ? pmin : 0; 878d5ac70f0Sopenharmony_ci simple->str[SM_PLAY].max = pmax != LONG_MIN ? pmax : 0; 879d5ac70f0Sopenharmony_ci } 880d5ac70f0Sopenharmony_ci simple->str[SM_CAPT].channels = cchannels; 881d5ac70f0Sopenharmony_ci if (!simple->str[SM_CAPT].range) { 882d5ac70f0Sopenharmony_ci simple->str[SM_CAPT].min = cmin != LONG_MAX ? cmin : 0; 883d5ac70f0Sopenharmony_ci simple->str[SM_CAPT].max = cmax != LONG_MIN ? cmax : 0; 884d5ac70f0Sopenharmony_ci } 885d5ac70f0Sopenharmony_ci return 0; 886d5ac70f0Sopenharmony_ci} 887d5ac70f0Sopenharmony_ci 888d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 889d5ac70f0Sopenharmony_cistatic const struct suf { 890d5ac70f0Sopenharmony_ci const char *suffix; 891d5ac70f0Sopenharmony_ci selem_ctl_type_t type; 892d5ac70f0Sopenharmony_ci} suffixes[] = { 893d5ac70f0Sopenharmony_ci {" Playback Enum", CTL_PLAYBACK_ENUM}, 894d5ac70f0Sopenharmony_ci {" Playback Switch", CTL_PLAYBACK_SWITCH}, 895d5ac70f0Sopenharmony_ci {" Playback Route", CTL_PLAYBACK_ROUTE}, 896d5ac70f0Sopenharmony_ci {" Playback Volume", CTL_PLAYBACK_VOLUME}, 897d5ac70f0Sopenharmony_ci {" Capture Enum", CTL_CAPTURE_ENUM}, 898d5ac70f0Sopenharmony_ci {" Capture Switch", CTL_CAPTURE_SWITCH}, 899d5ac70f0Sopenharmony_ci {" Capture Route", CTL_CAPTURE_ROUTE}, 900d5ac70f0Sopenharmony_ci {" Capture Volume", CTL_CAPTURE_VOLUME}, 901d5ac70f0Sopenharmony_ci {" Enum", CTL_GLOBAL_ENUM}, 902d5ac70f0Sopenharmony_ci {" Switch", CTL_GLOBAL_SWITCH}, 903d5ac70f0Sopenharmony_ci {" Route", CTL_GLOBAL_ROUTE}, 904d5ac70f0Sopenharmony_ci {" Volume", CTL_GLOBAL_VOLUME}, 905d5ac70f0Sopenharmony_ci {NULL, 0} 906d5ac70f0Sopenharmony_ci}; 907d5ac70f0Sopenharmony_ci#endif 908d5ac70f0Sopenharmony_ci 909d5ac70f0Sopenharmony_ci/* Return base length */ 910d5ac70f0Sopenharmony_cistatic int base_len(const char *name, selem_ctl_type_t *type) 911d5ac70f0Sopenharmony_ci{ 912d5ac70f0Sopenharmony_ci const struct suf *p; 913d5ac70f0Sopenharmony_ci size_t nlen = strlen(name); 914d5ac70f0Sopenharmony_ci 915d5ac70f0Sopenharmony_ci /* exception: "Capture Volume" and "Capture Switch" */ 916d5ac70f0Sopenharmony_ci if (!strcmp(name, "Capture Volume")) { 917d5ac70f0Sopenharmony_ci *type = CTL_CAPTURE_VOLUME; 918d5ac70f0Sopenharmony_ci return strlen("Capture"); 919d5ac70f0Sopenharmony_ci } 920d5ac70f0Sopenharmony_ci if (!strcmp(name, "Capture Switch")) { 921d5ac70f0Sopenharmony_ci *type = CTL_CAPTURE_SWITCH; 922d5ac70f0Sopenharmony_ci return strlen("Capture"); 923d5ac70f0Sopenharmony_ci } 924d5ac70f0Sopenharmony_ci 925d5ac70f0Sopenharmony_ci for (p = suffixes; p->suffix; p++) { 926d5ac70f0Sopenharmony_ci size_t slen = strlen(p->suffix); 927d5ac70f0Sopenharmony_ci size_t l; 928d5ac70f0Sopenharmony_ci if (nlen > slen) { 929d5ac70f0Sopenharmony_ci l = nlen - slen; 930d5ac70f0Sopenharmony_ci if (strncmp(name + l, p->suffix, slen) == 0 && 931d5ac70f0Sopenharmony_ci (l < 1 || name[l-1] != '-')) { /* 3D Control - Switch */ 932d5ac70f0Sopenharmony_ci *type = p->type; 933d5ac70f0Sopenharmony_ci return l; 934d5ac70f0Sopenharmony_ci } 935d5ac70f0Sopenharmony_ci } 936d5ac70f0Sopenharmony_ci } 937d5ac70f0Sopenharmony_ci 938d5ac70f0Sopenharmony_ci /* Special case - handle "Input Source" as a capture route. 939d5ac70f0Sopenharmony_ci * Note that it's *NO* capture source. A capture source is split over 940d5ac70f0Sopenharmony_ci * sub-elements, and multiple capture-sources will result in an error. 941d5ac70f0Sopenharmony_ci * That's why some drivers use "Input Source" as a workaround. 942d5ac70f0Sopenharmony_ci * Hence, this is a workaround for a workaround to get the things 943d5ac70f0Sopenharmony_ci * straight back again. Sigh. 944d5ac70f0Sopenharmony_ci */ 945d5ac70f0Sopenharmony_ci if (!strcmp(name, "Input Source")) { 946d5ac70f0Sopenharmony_ci *type = CTL_CAPTURE_ROUTE; 947d5ac70f0Sopenharmony_ci return strlen(name); 948d5ac70f0Sopenharmony_ci } 949d5ac70f0Sopenharmony_ci if (strstr(name, "3D Control")) { 950d5ac70f0Sopenharmony_ci if (strstr(name, "Depth")) { 951d5ac70f0Sopenharmony_ci *type = CTL_PLAYBACK_VOLUME; 952d5ac70f0Sopenharmony_ci return strlen(name); 953d5ac70f0Sopenharmony_ci } 954d5ac70f0Sopenharmony_ci } 955d5ac70f0Sopenharmony_ci 956d5ac70f0Sopenharmony_ci *type = CTL_SINGLE; 957d5ac70f0Sopenharmony_ci return strlen(name); 958d5ac70f0Sopenharmony_ci} 959d5ac70f0Sopenharmony_ci 960d5ac70f0Sopenharmony_ci 961d5ac70f0Sopenharmony_ci/* 962d5ac70f0Sopenharmony_ci * Simple Mixer Operations 963d5ac70f0Sopenharmony_ci */ 964d5ac70f0Sopenharmony_ci 965d5ac70f0Sopenharmony_cistatic int _snd_mixer_selem_set_volume(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, long value) 966d5ac70f0Sopenharmony_ci{ 967d5ac70f0Sopenharmony_ci selem_none_t *s = snd_mixer_elem_get_private(elem); 968d5ac70f0Sopenharmony_ci if (s->selem.caps & SM_CAP_GVOLUME) 969d5ac70f0Sopenharmony_ci dir = SM_PLAY; 970d5ac70f0Sopenharmony_ci if ((unsigned int) channel >= s->str[dir].channels) 971d5ac70f0Sopenharmony_ci return 0; 972d5ac70f0Sopenharmony_ci if (value < s->str[dir].min || value > s->str[dir].max) 973d5ac70f0Sopenharmony_ci return 0; 974d5ac70f0Sopenharmony_ci if (s->selem.caps & 975d5ac70f0Sopenharmony_ci (dir == SM_PLAY ? SM_CAP_PVOLUME_JOIN : SM_CAP_CVOLUME_JOIN)) 976d5ac70f0Sopenharmony_ci channel = 0; 977d5ac70f0Sopenharmony_ci if (value != s->str[dir].vol[channel]) { 978d5ac70f0Sopenharmony_ci s->str[dir].vol[channel] = value; 979d5ac70f0Sopenharmony_ci return 1; 980d5ac70f0Sopenharmony_ci } 981d5ac70f0Sopenharmony_ci return 0; 982d5ac70f0Sopenharmony_ci} 983d5ac70f0Sopenharmony_ci 984d5ac70f0Sopenharmony_cistatic int _snd_mixer_selem_set_switch(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, int value) 985d5ac70f0Sopenharmony_ci{ 986d5ac70f0Sopenharmony_ci selem_none_t *s = snd_mixer_elem_get_private(elem); 987d5ac70f0Sopenharmony_ci if ((unsigned int) channel >= s->str[dir].channels) 988d5ac70f0Sopenharmony_ci return 0; 989d5ac70f0Sopenharmony_ci if (s->selem.caps & 990d5ac70f0Sopenharmony_ci (dir == SM_PLAY ? SM_CAP_PSWITCH_JOIN : SM_CAP_CSWITCH_JOIN)) 991d5ac70f0Sopenharmony_ci channel = 0; 992d5ac70f0Sopenharmony_ci if (value) { 993d5ac70f0Sopenharmony_ci if (!(s->str[dir].sw & (1 << channel))) { 994d5ac70f0Sopenharmony_ci s->str[dir].sw |= 1 << channel; 995d5ac70f0Sopenharmony_ci return 1; 996d5ac70f0Sopenharmony_ci } 997d5ac70f0Sopenharmony_ci } else { 998d5ac70f0Sopenharmony_ci if (s->str[dir].sw & (1 << channel)) { 999d5ac70f0Sopenharmony_ci s->str[dir].sw &= ~(1 << channel); 1000d5ac70f0Sopenharmony_ci return 1; 1001d5ac70f0Sopenharmony_ci } 1002d5ac70f0Sopenharmony_ci } 1003d5ac70f0Sopenharmony_ci return 0; 1004d5ac70f0Sopenharmony_ci} 1005d5ac70f0Sopenharmony_ci 1006d5ac70f0Sopenharmony_cistatic int is_ops(snd_mixer_elem_t *elem, int dir, int cmd, int val) 1007d5ac70f0Sopenharmony_ci{ 1008d5ac70f0Sopenharmony_ci selem_none_t *s = snd_mixer_elem_get_private(elem); 1009d5ac70f0Sopenharmony_ci 1010d5ac70f0Sopenharmony_ci switch (cmd) { 1011d5ac70f0Sopenharmony_ci 1012d5ac70f0Sopenharmony_ci case SM_OPS_IS_ACTIVE: { 1013d5ac70f0Sopenharmony_ci selem_ctl_type_t ctl; 1014d5ac70f0Sopenharmony_ci for (ctl = CTL_SINGLE; ctl <= CTL_LAST; ctl++) 1015d5ac70f0Sopenharmony_ci if (s->ctls[ctl].elem != NULL && s->ctls[ctl].inactive) 1016d5ac70f0Sopenharmony_ci return 0; 1017d5ac70f0Sopenharmony_ci return 1; 1018d5ac70f0Sopenharmony_ci } 1019d5ac70f0Sopenharmony_ci 1020d5ac70f0Sopenharmony_ci case SM_OPS_IS_MONO: 1021d5ac70f0Sopenharmony_ci return s->str[dir].channels == 1; 1022d5ac70f0Sopenharmony_ci 1023d5ac70f0Sopenharmony_ci case SM_OPS_IS_CHANNEL: 1024d5ac70f0Sopenharmony_ci return (unsigned int) val < s->str[dir].channels; 1025d5ac70f0Sopenharmony_ci 1026d5ac70f0Sopenharmony_ci case SM_OPS_IS_ENUMERATED: 1027d5ac70f0Sopenharmony_ci if (val == 1) { 1028d5ac70f0Sopenharmony_ci if (dir == SM_PLAY && (s->selem.caps & SM_CAP_PENUM) && !(s->selem.caps & SM_CAP_CENUM) ) 1029d5ac70f0Sopenharmony_ci return 1; 1030d5ac70f0Sopenharmony_ci if (dir == SM_CAPT && (s->selem.caps & SM_CAP_CENUM) && !(s->selem.caps & SM_CAP_PENUM) ) 1031d5ac70f0Sopenharmony_ci return 1; 1032d5ac70f0Sopenharmony_ci return 0; 1033d5ac70f0Sopenharmony_ci } 1034d5ac70f0Sopenharmony_ci if (s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM) ) 1035d5ac70f0Sopenharmony_ci return 1; 1036d5ac70f0Sopenharmony_ci return 0; 1037d5ac70f0Sopenharmony_ci 1038d5ac70f0Sopenharmony_ci case SM_OPS_IS_ENUMCNT: 1039d5ac70f0Sopenharmony_ci /* Both */ 1040d5ac70f0Sopenharmony_ci if ( (s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM)) == (SM_CAP_CENUM | SM_CAP_PENUM) ) { 1041d5ac70f0Sopenharmony_ci if (! s->ctls[CTL_GLOBAL_ENUM].elem) 1042d5ac70f0Sopenharmony_ci return -EINVAL; 1043d5ac70f0Sopenharmony_ci return s->ctls[CTL_GLOBAL_ENUM].max; 1044d5ac70f0Sopenharmony_ci /* Only Playback */ 1045d5ac70f0Sopenharmony_ci } else if (s->selem.caps & SM_CAP_PENUM ) { 1046d5ac70f0Sopenharmony_ci if (! s->ctls[CTL_PLAYBACK_ENUM].elem) 1047d5ac70f0Sopenharmony_ci return -EINVAL; 1048d5ac70f0Sopenharmony_ci return s->ctls[CTL_PLAYBACK_ENUM].max; 1049d5ac70f0Sopenharmony_ci /* Only Capture */ 1050d5ac70f0Sopenharmony_ci } else if (s->selem.caps & SM_CAP_CENUM ) { 1051d5ac70f0Sopenharmony_ci if (! s->ctls[CTL_CAPTURE_ENUM].elem) 1052d5ac70f0Sopenharmony_ci return -EINVAL; 1053d5ac70f0Sopenharmony_ci return s->ctls[CTL_CAPTURE_ENUM].max; 1054d5ac70f0Sopenharmony_ci } 1055d5ac70f0Sopenharmony_ci 1056d5ac70f0Sopenharmony_ci } 1057d5ac70f0Sopenharmony_ci 1058d5ac70f0Sopenharmony_ci return 1; 1059d5ac70f0Sopenharmony_ci} 1060d5ac70f0Sopenharmony_ci 1061d5ac70f0Sopenharmony_cistatic int get_range_ops(snd_mixer_elem_t *elem, int dir, 1062d5ac70f0Sopenharmony_ci long *min, long *max) 1063d5ac70f0Sopenharmony_ci{ 1064d5ac70f0Sopenharmony_ci selem_none_t *s = snd_mixer_elem_get_private(elem); 1065d5ac70f0Sopenharmony_ci *min = s->str[dir].min; 1066d5ac70f0Sopenharmony_ci *max = s->str[dir].max; 1067d5ac70f0Sopenharmony_ci return 0; 1068d5ac70f0Sopenharmony_ci} 1069d5ac70f0Sopenharmony_ci 1070d5ac70f0Sopenharmony_cistatic int set_range_ops(snd_mixer_elem_t *elem, int dir, 1071d5ac70f0Sopenharmony_ci long min, long max) 1072d5ac70f0Sopenharmony_ci{ 1073d5ac70f0Sopenharmony_ci selem_none_t *s = snd_mixer_elem_get_private(elem); 1074d5ac70f0Sopenharmony_ci int err; 1075d5ac70f0Sopenharmony_ci 1076d5ac70f0Sopenharmony_ci s->str[dir].range = 1; 1077d5ac70f0Sopenharmony_ci s->str[dir].min = min; 1078d5ac70f0Sopenharmony_ci s->str[dir].max = max; 1079d5ac70f0Sopenharmony_ci if ((err = selem_read(elem)) < 0) 1080d5ac70f0Sopenharmony_ci return err; 1081d5ac70f0Sopenharmony_ci return 0; 1082d5ac70f0Sopenharmony_ci} 1083d5ac70f0Sopenharmony_ci 1084d5ac70f0Sopenharmony_cistatic int get_volume_ops(snd_mixer_elem_t *elem, int dir, 1085d5ac70f0Sopenharmony_ci snd_mixer_selem_channel_id_t channel, long *value) 1086d5ac70f0Sopenharmony_ci{ 1087d5ac70f0Sopenharmony_ci selem_none_t *s = snd_mixer_elem_get_private(elem); 1088d5ac70f0Sopenharmony_ci if (s->selem.caps & SM_CAP_GVOLUME) 1089d5ac70f0Sopenharmony_ci dir = SM_PLAY; 1090d5ac70f0Sopenharmony_ci if ((unsigned int) channel >= s->str[dir].channels) 1091d5ac70f0Sopenharmony_ci return -EINVAL; 1092d5ac70f0Sopenharmony_ci *value = s->str[dir].vol[channel]; 1093d5ac70f0Sopenharmony_ci return 0; 1094d5ac70f0Sopenharmony_ci} 1095d5ac70f0Sopenharmony_ci 1096d5ac70f0Sopenharmony_cistatic int init_db_range(snd_hctl_elem_t *ctl, struct selem_str *rec); 1097d5ac70f0Sopenharmony_ci 1098d5ac70f0Sopenharmony_cistatic int convert_to_dB(snd_hctl_elem_t *ctl, struct selem_str *rec, 1099d5ac70f0Sopenharmony_ci long volume, long *db_gain) 1100d5ac70f0Sopenharmony_ci{ 1101d5ac70f0Sopenharmony_ci if (init_db_range(ctl, rec) < 0) 1102d5ac70f0Sopenharmony_ci return -EINVAL; 1103d5ac70f0Sopenharmony_ci return snd_tlv_convert_to_dB(rec->db_info, rec->min, rec->max, 1104d5ac70f0Sopenharmony_ci volume, db_gain); 1105d5ac70f0Sopenharmony_ci} 1106d5ac70f0Sopenharmony_ci 1107d5ac70f0Sopenharmony_ci/* initialize dB range information, reading TLV via hcontrol 1108d5ac70f0Sopenharmony_ci */ 1109d5ac70f0Sopenharmony_cistatic int init_db_range(snd_hctl_elem_t *ctl, struct selem_str *rec) 1110d5ac70f0Sopenharmony_ci{ 1111d5ac70f0Sopenharmony_ci snd_ctl_elem_info_t info = {0}; 1112d5ac70f0Sopenharmony_ci unsigned int *tlv = NULL; 1113d5ac70f0Sopenharmony_ci const unsigned int tlv_size = 4096; 1114d5ac70f0Sopenharmony_ci unsigned int *dbrec; 1115d5ac70f0Sopenharmony_ci int db_size; 1116d5ac70f0Sopenharmony_ci 1117d5ac70f0Sopenharmony_ci if (rec->db_init_error) 1118d5ac70f0Sopenharmony_ci return -EINVAL; 1119d5ac70f0Sopenharmony_ci if (rec->db_initialized) 1120d5ac70f0Sopenharmony_ci return 0; 1121d5ac70f0Sopenharmony_ci 1122d5ac70f0Sopenharmony_ci if (snd_hctl_elem_info(ctl, &info) < 0) 1123d5ac70f0Sopenharmony_ci goto error; 1124d5ac70f0Sopenharmony_ci if (!snd_ctl_elem_info_is_tlv_readable(&info)) 1125d5ac70f0Sopenharmony_ci goto error; 1126d5ac70f0Sopenharmony_ci tlv = malloc(tlv_size); 1127d5ac70f0Sopenharmony_ci if (!tlv) 1128d5ac70f0Sopenharmony_ci return -ENOMEM; 1129d5ac70f0Sopenharmony_ci if (snd_hctl_elem_tlv_read(ctl, tlv, tlv_size) < 0) 1130d5ac70f0Sopenharmony_ci goto error; 1131d5ac70f0Sopenharmony_ci db_size = snd_tlv_parse_dB_info(tlv, tlv_size, &dbrec); 1132d5ac70f0Sopenharmony_ci if (db_size < 0) 1133d5ac70f0Sopenharmony_ci goto error; 1134d5ac70f0Sopenharmony_ci rec->db_info = malloc(db_size); 1135d5ac70f0Sopenharmony_ci if (!rec->db_info) 1136d5ac70f0Sopenharmony_ci goto error; 1137d5ac70f0Sopenharmony_ci memcpy(rec->db_info, dbrec, db_size); 1138d5ac70f0Sopenharmony_ci free(tlv); 1139d5ac70f0Sopenharmony_ci rec->db_initialized = 1; 1140d5ac70f0Sopenharmony_ci return 0; 1141d5ac70f0Sopenharmony_ci 1142d5ac70f0Sopenharmony_ci error: 1143d5ac70f0Sopenharmony_ci free(tlv); 1144d5ac70f0Sopenharmony_ci rec->db_init_error = 1; 1145d5ac70f0Sopenharmony_ci return -EINVAL; 1146d5ac70f0Sopenharmony_ci} 1147d5ac70f0Sopenharmony_ci 1148d5ac70f0Sopenharmony_ci/* get selem_ctl for TLV access */ 1149d5ac70f0Sopenharmony_cistatic selem_ctl_t *get_selem_ctl(selem_none_t *s, int dir) 1150d5ac70f0Sopenharmony_ci{ 1151d5ac70f0Sopenharmony_ci selem_ctl_t *c; 1152d5ac70f0Sopenharmony_ci if (dir == SM_PLAY) 1153d5ac70f0Sopenharmony_ci c = &s->ctls[CTL_PLAYBACK_VOLUME]; 1154d5ac70f0Sopenharmony_ci else if (dir == SM_CAPT) 1155d5ac70f0Sopenharmony_ci c = &s->ctls[CTL_CAPTURE_VOLUME]; 1156d5ac70f0Sopenharmony_ci else 1157d5ac70f0Sopenharmony_ci return NULL; 1158d5ac70f0Sopenharmony_ci if (! c->elem) 1159d5ac70f0Sopenharmony_ci c = &s->ctls[CTL_GLOBAL_VOLUME]; 1160d5ac70f0Sopenharmony_ci if (! c->elem) 1161d5ac70f0Sopenharmony_ci c = &s->ctls[CTL_SINGLE]; 1162d5ac70f0Sopenharmony_ci if (! c->elem) 1163d5ac70f0Sopenharmony_ci return NULL; 1164d5ac70f0Sopenharmony_ci if (c->type != SND_CTL_ELEM_TYPE_INTEGER) 1165d5ac70f0Sopenharmony_ci return NULL; 1166d5ac70f0Sopenharmony_ci return c; 1167d5ac70f0Sopenharmony_ci} 1168d5ac70f0Sopenharmony_ci 1169d5ac70f0Sopenharmony_cistatic int get_dB_range(snd_hctl_elem_t *ctl, struct selem_str *rec, 1170d5ac70f0Sopenharmony_ci long *min, long *max) 1171d5ac70f0Sopenharmony_ci{ 1172d5ac70f0Sopenharmony_ci if (init_db_range(ctl, rec) < 0) 1173d5ac70f0Sopenharmony_ci return -EINVAL; 1174d5ac70f0Sopenharmony_ci 1175d5ac70f0Sopenharmony_ci return snd_tlv_get_dB_range(rec->db_info, rec->min, rec->max, min, max); 1176d5ac70f0Sopenharmony_ci} 1177d5ac70f0Sopenharmony_ci 1178d5ac70f0Sopenharmony_cistatic int get_dB_range_ops(snd_mixer_elem_t *elem, int dir, 1179d5ac70f0Sopenharmony_ci long *min, long *max) 1180d5ac70f0Sopenharmony_ci{ 1181d5ac70f0Sopenharmony_ci selem_none_t *s = snd_mixer_elem_get_private(elem); 1182d5ac70f0Sopenharmony_ci selem_ctl_t *c; 1183d5ac70f0Sopenharmony_ci 1184d5ac70f0Sopenharmony_ci if (s->selem.caps & SM_CAP_GVOLUME) 1185d5ac70f0Sopenharmony_ci dir = SM_PLAY; 1186d5ac70f0Sopenharmony_ci c = get_selem_ctl(s, dir); 1187d5ac70f0Sopenharmony_ci if (! c) 1188d5ac70f0Sopenharmony_ci return -EINVAL; 1189d5ac70f0Sopenharmony_ci return get_dB_range(c->elem, &s->str[dir], min, max); 1190d5ac70f0Sopenharmony_ci} 1191d5ac70f0Sopenharmony_ci 1192d5ac70f0Sopenharmony_cistatic int convert_from_dB(snd_hctl_elem_t *ctl, struct selem_str *rec, 1193d5ac70f0Sopenharmony_ci long db_gain, long *value, int xdir) 1194d5ac70f0Sopenharmony_ci{ 1195d5ac70f0Sopenharmony_ci if (init_db_range(ctl, rec) < 0) 1196d5ac70f0Sopenharmony_ci return -EINVAL; 1197d5ac70f0Sopenharmony_ci 1198d5ac70f0Sopenharmony_ci return snd_tlv_convert_from_dB(rec->db_info, rec->min, rec->max, 1199d5ac70f0Sopenharmony_ci db_gain, value, xdir); 1200d5ac70f0Sopenharmony_ci} 1201d5ac70f0Sopenharmony_ci 1202d5ac70f0Sopenharmony_cistatic int ask_vol_dB_ops(snd_mixer_elem_t *elem, 1203d5ac70f0Sopenharmony_ci int dir, 1204d5ac70f0Sopenharmony_ci long value, 1205d5ac70f0Sopenharmony_ci long *dBvalue) 1206d5ac70f0Sopenharmony_ci{ 1207d5ac70f0Sopenharmony_ci selem_none_t *s = snd_mixer_elem_get_private(elem); 1208d5ac70f0Sopenharmony_ci selem_ctl_t *c; 1209d5ac70f0Sopenharmony_ci 1210d5ac70f0Sopenharmony_ci c = get_selem_ctl(s, dir); 1211d5ac70f0Sopenharmony_ci if (! c) 1212d5ac70f0Sopenharmony_ci return -EINVAL; 1213d5ac70f0Sopenharmony_ci int res = convert_to_dB(c->elem, &s->str[dir], value, dBvalue); 1214d5ac70f0Sopenharmony_ci return res; 1215d5ac70f0Sopenharmony_ci} 1216d5ac70f0Sopenharmony_ci 1217d5ac70f0Sopenharmony_cistatic int get_dB_ops(snd_mixer_elem_t *elem, 1218d5ac70f0Sopenharmony_ci int dir, 1219d5ac70f0Sopenharmony_ci snd_mixer_selem_channel_id_t channel, 1220d5ac70f0Sopenharmony_ci long *value) 1221d5ac70f0Sopenharmony_ci{ 1222d5ac70f0Sopenharmony_ci selem_none_t *s = snd_mixer_elem_get_private(elem); 1223d5ac70f0Sopenharmony_ci selem_ctl_t *c; 1224d5ac70f0Sopenharmony_ci int err; 1225d5ac70f0Sopenharmony_ci long volume, db_gain; 1226d5ac70f0Sopenharmony_ci 1227d5ac70f0Sopenharmony_ci if (s->selem.caps & SM_CAP_GVOLUME) 1228d5ac70f0Sopenharmony_ci dir = SM_PLAY; 1229d5ac70f0Sopenharmony_ci c = get_selem_ctl(s, dir); 1230d5ac70f0Sopenharmony_ci if (! c) 1231d5ac70f0Sopenharmony_ci return -EINVAL; 1232d5ac70f0Sopenharmony_ci if ((err = get_volume_ops(elem, dir, channel, &volume)) < 0) 1233d5ac70f0Sopenharmony_ci goto _err; 1234d5ac70f0Sopenharmony_ci if ((err = convert_to_dB(c->elem, &s->str[dir], volume, &db_gain)) < 0) 1235d5ac70f0Sopenharmony_ci goto _err; 1236d5ac70f0Sopenharmony_ci err = 0; 1237d5ac70f0Sopenharmony_ci *value = db_gain; 1238d5ac70f0Sopenharmony_ci _err: 1239d5ac70f0Sopenharmony_ci return err; 1240d5ac70f0Sopenharmony_ci} 1241d5ac70f0Sopenharmony_ci 1242d5ac70f0Sopenharmony_cistatic int get_switch_ops(snd_mixer_elem_t *elem, int dir, 1243d5ac70f0Sopenharmony_ci snd_mixer_selem_channel_id_t channel, int *value) 1244d5ac70f0Sopenharmony_ci{ 1245d5ac70f0Sopenharmony_ci selem_none_t *s = snd_mixer_elem_get_private(elem); 1246d5ac70f0Sopenharmony_ci if (s->selem.caps & SM_CAP_GSWITCH) 1247d5ac70f0Sopenharmony_ci dir = SM_PLAY; 1248d5ac70f0Sopenharmony_ci if ((unsigned int) channel >= s->str[dir].channels) 1249d5ac70f0Sopenharmony_ci return -EINVAL; 1250d5ac70f0Sopenharmony_ci *value = !!(s->str[dir].sw & (1 << channel)); 1251d5ac70f0Sopenharmony_ci return 0; 1252d5ac70f0Sopenharmony_ci} 1253d5ac70f0Sopenharmony_ci 1254d5ac70f0Sopenharmony_cistatic int set_volume_ops(snd_mixer_elem_t *elem, int dir, 1255d5ac70f0Sopenharmony_ci snd_mixer_selem_channel_id_t channel, long value) 1256d5ac70f0Sopenharmony_ci{ 1257d5ac70f0Sopenharmony_ci int changed; 1258d5ac70f0Sopenharmony_ci changed = _snd_mixer_selem_set_volume(elem, dir, channel, value); 1259d5ac70f0Sopenharmony_ci if (changed < 0) 1260d5ac70f0Sopenharmony_ci return changed; 1261d5ac70f0Sopenharmony_ci if (changed) 1262d5ac70f0Sopenharmony_ci return selem_write(elem); 1263d5ac70f0Sopenharmony_ci return 0; 1264d5ac70f0Sopenharmony_ci} 1265d5ac70f0Sopenharmony_ci 1266d5ac70f0Sopenharmony_cistatic int ask_dB_vol_ops(snd_mixer_elem_t *elem, int dir, 1267d5ac70f0Sopenharmony_ci long dbValue, long *value, int xdir) 1268d5ac70f0Sopenharmony_ci{ 1269d5ac70f0Sopenharmony_ci selem_none_t *s = snd_mixer_elem_get_private(elem); 1270d5ac70f0Sopenharmony_ci selem_ctl_t *c; 1271d5ac70f0Sopenharmony_ci 1272d5ac70f0Sopenharmony_ci if (s->selem.caps & SM_CAP_GVOLUME) 1273d5ac70f0Sopenharmony_ci dir = SM_PLAY; 1274d5ac70f0Sopenharmony_ci c = get_selem_ctl(s, dir); 1275d5ac70f0Sopenharmony_ci if (! c) 1276d5ac70f0Sopenharmony_ci return -EINVAL; 1277d5ac70f0Sopenharmony_ci return convert_from_dB(c->elem, &s->str[dir], dbValue, value, xdir); 1278d5ac70f0Sopenharmony_ci} 1279d5ac70f0Sopenharmony_ci 1280d5ac70f0Sopenharmony_cistatic int set_dB_ops(snd_mixer_elem_t *elem, int dir, 1281d5ac70f0Sopenharmony_ci snd_mixer_selem_channel_id_t channel, 1282d5ac70f0Sopenharmony_ci long db_gain, int xdir) 1283d5ac70f0Sopenharmony_ci{ 1284d5ac70f0Sopenharmony_ci selem_none_t *s = snd_mixer_elem_get_private(elem); 1285d5ac70f0Sopenharmony_ci selem_ctl_t *c; 1286d5ac70f0Sopenharmony_ci long value; 1287d5ac70f0Sopenharmony_ci int err; 1288d5ac70f0Sopenharmony_ci 1289d5ac70f0Sopenharmony_ci if (s->selem.caps & SM_CAP_GVOLUME) 1290d5ac70f0Sopenharmony_ci dir = SM_PLAY; 1291d5ac70f0Sopenharmony_ci c = get_selem_ctl(s, dir); 1292d5ac70f0Sopenharmony_ci if (! c) 1293d5ac70f0Sopenharmony_ci return -EINVAL; 1294d5ac70f0Sopenharmony_ci err = convert_from_dB(c->elem, &s->str[dir], db_gain, &value, xdir); 1295d5ac70f0Sopenharmony_ci if (err < 0) 1296d5ac70f0Sopenharmony_ci return err; 1297d5ac70f0Sopenharmony_ci return set_volume_ops(elem, dir, channel, value); 1298d5ac70f0Sopenharmony_ci} 1299d5ac70f0Sopenharmony_ci 1300d5ac70f0Sopenharmony_cistatic int set_switch_ops(snd_mixer_elem_t *elem, int dir, 1301d5ac70f0Sopenharmony_ci snd_mixer_selem_channel_id_t channel, int value) 1302d5ac70f0Sopenharmony_ci{ 1303d5ac70f0Sopenharmony_ci int changed; 1304d5ac70f0Sopenharmony_ci selem_none_t *s = snd_mixer_elem_get_private(elem); 1305d5ac70f0Sopenharmony_ci if (s->selem.caps & SM_CAP_GSWITCH) 1306d5ac70f0Sopenharmony_ci dir = SM_PLAY; 1307d5ac70f0Sopenharmony_ci if (dir == SM_PLAY) { 1308d5ac70f0Sopenharmony_ci if (! (s->selem.caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH))) 1309d5ac70f0Sopenharmony_ci return -EINVAL; 1310d5ac70f0Sopenharmony_ci } else { 1311d5ac70f0Sopenharmony_ci if (! (s->selem.caps & (SM_CAP_GSWITCH|SM_CAP_CSWITCH))) 1312d5ac70f0Sopenharmony_ci return -EINVAL; 1313d5ac70f0Sopenharmony_ci } 1314d5ac70f0Sopenharmony_ci changed = _snd_mixer_selem_set_switch(elem, dir, channel, value); 1315d5ac70f0Sopenharmony_ci if (changed < 0) 1316d5ac70f0Sopenharmony_ci return changed; 1317d5ac70f0Sopenharmony_ci if (changed) 1318d5ac70f0Sopenharmony_ci return selem_write(elem); 1319d5ac70f0Sopenharmony_ci return 0; 1320d5ac70f0Sopenharmony_ci} 1321d5ac70f0Sopenharmony_ci 1322d5ac70f0Sopenharmony_cistatic int enum_item_name_ops(snd_mixer_elem_t *elem, 1323d5ac70f0Sopenharmony_ci unsigned int item, 1324d5ac70f0Sopenharmony_ci size_t maxlen, char *buf) 1325d5ac70f0Sopenharmony_ci{ 1326d5ac70f0Sopenharmony_ci selem_none_t *s = snd_mixer_elem_get_private(elem); 1327d5ac70f0Sopenharmony_ci snd_ctl_elem_info_t info = {0}; 1328d5ac70f0Sopenharmony_ci snd_hctl_elem_t *helem; 1329d5ac70f0Sopenharmony_ci int type; 1330d5ac70f0Sopenharmony_ci 1331d5ac70f0Sopenharmony_ci type = CTL_GLOBAL_ENUM; 1332d5ac70f0Sopenharmony_ci helem = s->ctls[type].elem; 1333d5ac70f0Sopenharmony_ci if (!helem) { 1334d5ac70f0Sopenharmony_ci type = CTL_PLAYBACK_ENUM; 1335d5ac70f0Sopenharmony_ci helem = s->ctls[type].elem; 1336d5ac70f0Sopenharmony_ci } 1337d5ac70f0Sopenharmony_ci if (!helem) { 1338d5ac70f0Sopenharmony_ci type = CTL_CAPTURE_ENUM; 1339d5ac70f0Sopenharmony_ci helem = s->ctls[type].elem; 1340d5ac70f0Sopenharmony_ci } 1341d5ac70f0Sopenharmony_ci assert(helem); 1342d5ac70f0Sopenharmony_ci if (item >= (unsigned int)s->ctls[type].max) 1343d5ac70f0Sopenharmony_ci return -EINVAL; 1344d5ac70f0Sopenharmony_ci snd_hctl_elem_info(helem, &info); 1345d5ac70f0Sopenharmony_ci snd_ctl_elem_info_set_item(&info, item); 1346d5ac70f0Sopenharmony_ci snd_hctl_elem_info(helem, &info); 1347d5ac70f0Sopenharmony_ci strncpy(buf, snd_ctl_elem_info_get_item_name(&info), maxlen); 1348d5ac70f0Sopenharmony_ci return 0; 1349d5ac70f0Sopenharmony_ci} 1350d5ac70f0Sopenharmony_ci 1351d5ac70f0Sopenharmony_cistatic int get_enum_item_ops(snd_mixer_elem_t *elem, 1352d5ac70f0Sopenharmony_ci snd_mixer_selem_channel_id_t channel, 1353d5ac70f0Sopenharmony_ci unsigned int *itemp) 1354d5ac70f0Sopenharmony_ci{ 1355d5ac70f0Sopenharmony_ci selem_none_t *s = snd_mixer_elem_get_private(elem); 1356d5ac70f0Sopenharmony_ci snd_ctl_elem_value_t ctl = {0}; 1357d5ac70f0Sopenharmony_ci snd_hctl_elem_t *helem; 1358d5ac70f0Sopenharmony_ci int err; 1359d5ac70f0Sopenharmony_ci 1360d5ac70f0Sopenharmony_ci if ((unsigned int) channel >= s->str[0].channels) 1361d5ac70f0Sopenharmony_ci return -EINVAL; 1362d5ac70f0Sopenharmony_ci helem = s->ctls[CTL_GLOBAL_ENUM].elem; 1363d5ac70f0Sopenharmony_ci if (!helem) helem = s->ctls[CTL_PLAYBACK_ENUM].elem; 1364d5ac70f0Sopenharmony_ci if (!helem) helem = s->ctls[CTL_CAPTURE_ENUM].elem; 1365d5ac70f0Sopenharmony_ci assert(helem); 1366d5ac70f0Sopenharmony_ci err = snd_hctl_elem_read(helem, &ctl); 1367d5ac70f0Sopenharmony_ci if (! err) 1368d5ac70f0Sopenharmony_ci *itemp = snd_ctl_elem_value_get_enumerated(&ctl, channel); 1369d5ac70f0Sopenharmony_ci return err; 1370d5ac70f0Sopenharmony_ci} 1371d5ac70f0Sopenharmony_ci 1372d5ac70f0Sopenharmony_cistatic int set_enum_item_ops(snd_mixer_elem_t *elem, 1373d5ac70f0Sopenharmony_ci snd_mixer_selem_channel_id_t channel, 1374d5ac70f0Sopenharmony_ci unsigned int item) 1375d5ac70f0Sopenharmony_ci{ 1376d5ac70f0Sopenharmony_ci selem_none_t *s = snd_mixer_elem_get_private(elem); 1377d5ac70f0Sopenharmony_ci snd_ctl_elem_value_t ctl = {0}; 1378d5ac70f0Sopenharmony_ci snd_hctl_elem_t *helem; 1379d5ac70f0Sopenharmony_ci int err; 1380d5ac70f0Sopenharmony_ci int type; 1381d5ac70f0Sopenharmony_ci 1382d5ac70f0Sopenharmony_ci if ((unsigned int) channel >= s->str[0].channels) { 1383d5ac70f0Sopenharmony_ci return -EINVAL; 1384d5ac70f0Sopenharmony_ci } 1385d5ac70f0Sopenharmony_ci type = CTL_GLOBAL_ENUM; 1386d5ac70f0Sopenharmony_ci helem = s->ctls[type].elem; 1387d5ac70f0Sopenharmony_ci if (!helem) { 1388d5ac70f0Sopenharmony_ci type = CTL_PLAYBACK_ENUM; 1389d5ac70f0Sopenharmony_ci helem = s->ctls[type].elem; 1390d5ac70f0Sopenharmony_ci } 1391d5ac70f0Sopenharmony_ci if (!helem) { 1392d5ac70f0Sopenharmony_ci type = CTL_CAPTURE_ENUM; 1393d5ac70f0Sopenharmony_ci helem = s->ctls[type].elem; 1394d5ac70f0Sopenharmony_ci } 1395d5ac70f0Sopenharmony_ci assert(helem); 1396d5ac70f0Sopenharmony_ci if (item >= (unsigned int)s->ctls[type].max) { 1397d5ac70f0Sopenharmony_ci return -EINVAL; 1398d5ac70f0Sopenharmony_ci } 1399d5ac70f0Sopenharmony_ci err = snd_hctl_elem_read(helem, &ctl); 1400d5ac70f0Sopenharmony_ci if (err < 0) { 1401d5ac70f0Sopenharmony_ci return err; 1402d5ac70f0Sopenharmony_ci } 1403d5ac70f0Sopenharmony_ci snd_ctl_elem_value_set_enumerated(&ctl, channel, item); 1404d5ac70f0Sopenharmony_ci return snd_hctl_elem_write(helem, &ctl); 1405d5ac70f0Sopenharmony_ci} 1406d5ac70f0Sopenharmony_ci 1407d5ac70f0Sopenharmony_cistatic struct sm_elem_ops simple_none_ops = { 1408d5ac70f0Sopenharmony_ci .is = is_ops, 1409d5ac70f0Sopenharmony_ci .get_range = get_range_ops, 1410d5ac70f0Sopenharmony_ci .get_dB_range = get_dB_range_ops, 1411d5ac70f0Sopenharmony_ci .set_range = set_range_ops, 1412d5ac70f0Sopenharmony_ci .ask_vol_dB = ask_vol_dB_ops, 1413d5ac70f0Sopenharmony_ci .ask_dB_vol = ask_dB_vol_ops, 1414d5ac70f0Sopenharmony_ci .get_volume = get_volume_ops, 1415d5ac70f0Sopenharmony_ci .get_dB = get_dB_ops, 1416d5ac70f0Sopenharmony_ci .set_volume = set_volume_ops, 1417d5ac70f0Sopenharmony_ci .set_dB = set_dB_ops, 1418d5ac70f0Sopenharmony_ci .get_switch = get_switch_ops, 1419d5ac70f0Sopenharmony_ci .set_switch = set_switch_ops, 1420d5ac70f0Sopenharmony_ci .enum_item_name = enum_item_name_ops, 1421d5ac70f0Sopenharmony_ci .get_enum_item = get_enum_item_ops, 1422d5ac70f0Sopenharmony_ci .set_enum_item = set_enum_item_ops 1423d5ac70f0Sopenharmony_ci}; 1424d5ac70f0Sopenharmony_ci 1425d5ac70f0Sopenharmony_cistatic int simple_add1(snd_mixer_class_t *class, const char *name, 1426d5ac70f0Sopenharmony_ci snd_hctl_elem_t *helem, selem_ctl_type_t type, 1427d5ac70f0Sopenharmony_ci unsigned int value) 1428d5ac70f0Sopenharmony_ci{ 1429d5ac70f0Sopenharmony_ci snd_mixer_elem_t *melem; 1430d5ac70f0Sopenharmony_ci snd_mixer_selem_id_t *id; 1431d5ac70f0Sopenharmony_ci int new = 0; 1432d5ac70f0Sopenharmony_ci int err; 1433d5ac70f0Sopenharmony_ci snd_ctl_elem_info_t info = {0}; 1434d5ac70f0Sopenharmony_ci selem_none_t *simple; 1435d5ac70f0Sopenharmony_ci const char *name1; 1436d5ac70f0Sopenharmony_ci snd_ctl_elem_type_t ctype; 1437d5ac70f0Sopenharmony_ci unsigned long values; 1438d5ac70f0Sopenharmony_ci 1439d5ac70f0Sopenharmony_ci err = snd_hctl_elem_info(helem, &info); 1440d5ac70f0Sopenharmony_ci if (err < 0) 1441d5ac70f0Sopenharmony_ci return err; 1442d5ac70f0Sopenharmony_ci ctype = snd_ctl_elem_info_get_type(&info); 1443d5ac70f0Sopenharmony_ci values = snd_ctl_elem_info_get_count(&info); 1444d5ac70f0Sopenharmony_ci switch (type) { 1445d5ac70f0Sopenharmony_ci case CTL_SINGLE: 1446d5ac70f0Sopenharmony_ci if (ctype == SND_CTL_ELEM_TYPE_ENUMERATED) 1447d5ac70f0Sopenharmony_ci type = CTL_GLOBAL_ENUM; 1448d5ac70f0Sopenharmony_ci else if (ctype != SND_CTL_ELEM_TYPE_BOOLEAN && 1449d5ac70f0Sopenharmony_ci ctype != SND_CTL_ELEM_TYPE_INTEGER) 1450d5ac70f0Sopenharmony_ci return 0; 1451d5ac70f0Sopenharmony_ci break; 1452d5ac70f0Sopenharmony_ci case CTL_GLOBAL_ROUTE: 1453d5ac70f0Sopenharmony_ci case CTL_PLAYBACK_ROUTE: 1454d5ac70f0Sopenharmony_ci case CTL_CAPTURE_ROUTE: 1455d5ac70f0Sopenharmony_ci { 1456d5ac70f0Sopenharmony_ci unsigned int n; 1457d5ac70f0Sopenharmony_ci if (ctype == SND_CTL_ELEM_TYPE_ENUMERATED) { 1458d5ac70f0Sopenharmony_ci if (type == CTL_PLAYBACK_ROUTE) 1459d5ac70f0Sopenharmony_ci type = CTL_PLAYBACK_ENUM; 1460d5ac70f0Sopenharmony_ci else if (type == CTL_CAPTURE_ROUTE) 1461d5ac70f0Sopenharmony_ci type = CTL_CAPTURE_ENUM; 1462d5ac70f0Sopenharmony_ci else 1463d5ac70f0Sopenharmony_ci type = CTL_GLOBAL_ENUM; 1464d5ac70f0Sopenharmony_ci break; 1465d5ac70f0Sopenharmony_ci } 1466d5ac70f0Sopenharmony_ci if (ctype != SND_CTL_ELEM_TYPE_BOOLEAN) 1467d5ac70f0Sopenharmony_ci return 0; 1468d5ac70f0Sopenharmony_ci#ifdef HAVE_SOFT_FLOAT 1469d5ac70f0Sopenharmony_ci /* up to 256 channels */ 1470d5ac70f0Sopenharmony_ci for (n = 1; n < 256; n++) 1471d5ac70f0Sopenharmony_ci if (n * n == values) 1472d5ac70f0Sopenharmony_ci break; 1473d5ac70f0Sopenharmony_ci#else 1474d5ac70f0Sopenharmony_ci n = sqrt((double)values); 1475d5ac70f0Sopenharmony_ci#endif 1476d5ac70f0Sopenharmony_ci if (n * n != values) 1477d5ac70f0Sopenharmony_ci return 0; 1478d5ac70f0Sopenharmony_ci values = n; 1479d5ac70f0Sopenharmony_ci break; 1480d5ac70f0Sopenharmony_ci } 1481d5ac70f0Sopenharmony_ci case CTL_GLOBAL_SWITCH: 1482d5ac70f0Sopenharmony_ci case CTL_PLAYBACK_SWITCH: 1483d5ac70f0Sopenharmony_ci case CTL_CAPTURE_SWITCH: 1484d5ac70f0Sopenharmony_ci if (ctype == SND_CTL_ELEM_TYPE_ENUMERATED) { 1485d5ac70f0Sopenharmony_ci if (type == CTL_PLAYBACK_SWITCH) 1486d5ac70f0Sopenharmony_ci type = CTL_PLAYBACK_ENUM; 1487d5ac70f0Sopenharmony_ci else if (type == CTL_CAPTURE_SWITCH) 1488d5ac70f0Sopenharmony_ci type = CTL_CAPTURE_ENUM; 1489d5ac70f0Sopenharmony_ci else 1490d5ac70f0Sopenharmony_ci type = CTL_GLOBAL_ENUM; 1491d5ac70f0Sopenharmony_ci break; 1492d5ac70f0Sopenharmony_ci } 1493d5ac70f0Sopenharmony_ci if (ctype != SND_CTL_ELEM_TYPE_BOOLEAN) 1494d5ac70f0Sopenharmony_ci return 0; 1495d5ac70f0Sopenharmony_ci break; 1496d5ac70f0Sopenharmony_ci case CTL_GLOBAL_VOLUME: 1497d5ac70f0Sopenharmony_ci case CTL_PLAYBACK_VOLUME: 1498d5ac70f0Sopenharmony_ci case CTL_CAPTURE_VOLUME: 1499d5ac70f0Sopenharmony_ci if (ctype == SND_CTL_ELEM_TYPE_ENUMERATED) { 1500d5ac70f0Sopenharmony_ci if (type == CTL_PLAYBACK_VOLUME) 1501d5ac70f0Sopenharmony_ci type = CTL_PLAYBACK_ENUM; 1502d5ac70f0Sopenharmony_ci else if (type == CTL_CAPTURE_VOLUME) 1503d5ac70f0Sopenharmony_ci type = CTL_CAPTURE_ENUM; 1504d5ac70f0Sopenharmony_ci else 1505d5ac70f0Sopenharmony_ci type = CTL_GLOBAL_ENUM; 1506d5ac70f0Sopenharmony_ci break; 1507d5ac70f0Sopenharmony_ci } 1508d5ac70f0Sopenharmony_ci if (ctype != SND_CTL_ELEM_TYPE_INTEGER) 1509d5ac70f0Sopenharmony_ci return 0; 1510d5ac70f0Sopenharmony_ci break; 1511d5ac70f0Sopenharmony_ci case CTL_CAPTURE_SOURCE: 1512d5ac70f0Sopenharmony_ci if (ctype != SND_CTL_ELEM_TYPE_ENUMERATED) 1513d5ac70f0Sopenharmony_ci return 0; 1514d5ac70f0Sopenharmony_ci break; 1515d5ac70f0Sopenharmony_ci case CTL_GLOBAL_ENUM: 1516d5ac70f0Sopenharmony_ci case CTL_PLAYBACK_ENUM: 1517d5ac70f0Sopenharmony_ci case CTL_CAPTURE_ENUM: 1518d5ac70f0Sopenharmony_ci if (ctype != SND_CTL_ELEM_TYPE_ENUMERATED) 1519d5ac70f0Sopenharmony_ci return 0; 1520d5ac70f0Sopenharmony_ci break; 1521d5ac70f0Sopenharmony_ci default: 1522d5ac70f0Sopenharmony_ci assert(0); 1523d5ac70f0Sopenharmony_ci break; 1524d5ac70f0Sopenharmony_ci } 1525d5ac70f0Sopenharmony_ci name1 = get_short_name(name); 1526d5ac70f0Sopenharmony_ci if (snd_mixer_selem_id_malloc(&id)) 1527d5ac70f0Sopenharmony_ci return -ENOMEM; 1528d5ac70f0Sopenharmony_ci snd_mixer_selem_id_set_name(id, name1); 1529d5ac70f0Sopenharmony_ci snd_mixer_selem_id_set_index(id, snd_hctl_elem_get_index(helem)); 1530d5ac70f0Sopenharmony_ci melem = snd_mixer_find_selem(snd_mixer_class_get_mixer(class), id); 1531d5ac70f0Sopenharmony_ci if (!melem) { 1532d5ac70f0Sopenharmony_ci simple = calloc(1, sizeof(*simple)); 1533d5ac70f0Sopenharmony_ci if (!simple) { 1534d5ac70f0Sopenharmony_ci snd_mixer_selem_id_free(id); 1535d5ac70f0Sopenharmony_ci return -ENOMEM; 1536d5ac70f0Sopenharmony_ci } 1537d5ac70f0Sopenharmony_ci simple->selem.id = id; 1538d5ac70f0Sopenharmony_ci simple->selem.ops = &simple_none_ops; 1539d5ac70f0Sopenharmony_ci err = snd_mixer_elem_new(&melem, SND_MIXER_ELEM_SIMPLE, 1540d5ac70f0Sopenharmony_ci get_compare_weight( 1541d5ac70f0Sopenharmony_ci snd_mixer_selem_id_get_name(simple->selem.id), 1542d5ac70f0Sopenharmony_ci snd_mixer_selem_id_get_index(simple->selem.id)), 1543d5ac70f0Sopenharmony_ci simple, selem_free); 1544d5ac70f0Sopenharmony_ci if (err < 0) { 1545d5ac70f0Sopenharmony_ci snd_mixer_selem_id_free(id); 1546d5ac70f0Sopenharmony_ci free(simple); 1547d5ac70f0Sopenharmony_ci return err; 1548d5ac70f0Sopenharmony_ci } 1549d5ac70f0Sopenharmony_ci new = 1; 1550d5ac70f0Sopenharmony_ci } else { 1551d5ac70f0Sopenharmony_ci simple = snd_mixer_elem_get_private(melem); 1552d5ac70f0Sopenharmony_ci snd_mixer_selem_id_free(id); 1553d5ac70f0Sopenharmony_ci } 1554d5ac70f0Sopenharmony_ci if (simple->ctls[type].elem) { 1555d5ac70f0Sopenharmony_ci SNDERR("helem (%s,'%s',%u,%u,%u) appears twice or more", 1556d5ac70f0Sopenharmony_ci snd_ctl_elem_iface_name( 1557d5ac70f0Sopenharmony_ci snd_hctl_elem_get_interface(helem)), 1558d5ac70f0Sopenharmony_ci snd_hctl_elem_get_name(helem), 1559d5ac70f0Sopenharmony_ci snd_hctl_elem_get_index(helem), 1560d5ac70f0Sopenharmony_ci snd_hctl_elem_get_device(helem), 1561d5ac70f0Sopenharmony_ci snd_hctl_elem_get_subdevice(helem)); 1562d5ac70f0Sopenharmony_ci err = -EINVAL; 1563d5ac70f0Sopenharmony_ci goto __error; 1564d5ac70f0Sopenharmony_ci } 1565d5ac70f0Sopenharmony_ci simple->ctls[type].elem = helem; 1566d5ac70f0Sopenharmony_ci simple->ctls[type].type = snd_ctl_elem_info_get_type(&info); 1567d5ac70f0Sopenharmony_ci simple->ctls[type].inactive = snd_ctl_elem_info_is_inactive(&info); 1568d5ac70f0Sopenharmony_ci simple->ctls[type].values = values; 1569d5ac70f0Sopenharmony_ci if ( (type == CTL_GLOBAL_ENUM) || 1570d5ac70f0Sopenharmony_ci (type == CTL_PLAYBACK_ENUM) || 1571d5ac70f0Sopenharmony_ci (type == CTL_CAPTURE_ENUM) ) { 1572d5ac70f0Sopenharmony_ci simple->ctls[type].min = 0; 1573d5ac70f0Sopenharmony_ci simple->ctls[type].max = snd_ctl_elem_info_get_items(&info); 1574d5ac70f0Sopenharmony_ci } else { 1575d5ac70f0Sopenharmony_ci if (ctype == SND_CTL_ELEM_TYPE_INTEGER) { 1576d5ac70f0Sopenharmony_ci simple->ctls[type].min = 1577d5ac70f0Sopenharmony_ci snd_ctl_elem_info_get_min(&info); 1578d5ac70f0Sopenharmony_ci simple->ctls[type].max = 1579d5ac70f0Sopenharmony_ci snd_ctl_elem_info_get_max(&info); 1580d5ac70f0Sopenharmony_ci } 1581d5ac70f0Sopenharmony_ci } 1582d5ac70f0Sopenharmony_ci switch (type) { 1583d5ac70f0Sopenharmony_ci case CTL_CAPTURE_SOURCE: 1584d5ac70f0Sopenharmony_ci simple->capture_item = value; 1585d5ac70f0Sopenharmony_ci break; 1586d5ac70f0Sopenharmony_ci default: 1587d5ac70f0Sopenharmony_ci break; 1588d5ac70f0Sopenharmony_ci } 1589d5ac70f0Sopenharmony_ci err = snd_mixer_elem_attach(melem, helem); 1590d5ac70f0Sopenharmony_ci if (err < 0) 1591d5ac70f0Sopenharmony_ci goto __error; 1592d5ac70f0Sopenharmony_ci err = simple_update(melem); 1593d5ac70f0Sopenharmony_ci if (err < 0) { 1594d5ac70f0Sopenharmony_ci if (new) 1595d5ac70f0Sopenharmony_ci goto __error; 1596d5ac70f0Sopenharmony_ci return err; 1597d5ac70f0Sopenharmony_ci } 1598d5ac70f0Sopenharmony_ci if (new) 1599d5ac70f0Sopenharmony_ci err = snd_mixer_elem_add(melem, class); 1600d5ac70f0Sopenharmony_ci else 1601d5ac70f0Sopenharmony_ci err = snd_mixer_elem_info(melem); 1602d5ac70f0Sopenharmony_ci if (err < 0) 1603d5ac70f0Sopenharmony_ci return err; 1604d5ac70f0Sopenharmony_ci err = selem_read(melem); 1605d5ac70f0Sopenharmony_ci if (err < 0) 1606d5ac70f0Sopenharmony_ci return err; 1607d5ac70f0Sopenharmony_ci if (err) 1608d5ac70f0Sopenharmony_ci err = snd_mixer_elem_value(melem); 1609d5ac70f0Sopenharmony_ci return err; 1610d5ac70f0Sopenharmony_ci __error: 1611d5ac70f0Sopenharmony_ci if (new) 1612d5ac70f0Sopenharmony_ci snd_mixer_elem_free(melem); 1613d5ac70f0Sopenharmony_ci return -EINVAL; 1614d5ac70f0Sopenharmony_ci} 1615d5ac70f0Sopenharmony_ci 1616d5ac70f0Sopenharmony_cistatic int simple_event_add(snd_mixer_class_t *class, snd_hctl_elem_t *helem) 1617d5ac70f0Sopenharmony_ci{ 1618d5ac70f0Sopenharmony_ci const char *name = snd_hctl_elem_get_name(helem); 1619d5ac70f0Sopenharmony_ci selem_ctl_type_t type; 1620d5ac70f0Sopenharmony_ci char ename[128]; 1621d5ac70f0Sopenharmony_ci size_t len; 1622d5ac70f0Sopenharmony_ci 1623d5ac70f0Sopenharmony_ci if (snd_hctl_elem_get_interface(helem) != SND_CTL_ELEM_IFACE_MIXER) 1624d5ac70f0Sopenharmony_ci return 0; 1625d5ac70f0Sopenharmony_ci if (strcmp(name, "Capture Source") == 0) { 1626d5ac70f0Sopenharmony_ci snd_ctl_elem_info_t info = {0}; 1627d5ac70f0Sopenharmony_ci unsigned int k, items; 1628d5ac70f0Sopenharmony_ci int err; 1629d5ac70f0Sopenharmony_ci err = snd_hctl_elem_info(helem, &info); 1630d5ac70f0Sopenharmony_ci assert(err >= 0); 1631d5ac70f0Sopenharmony_ci if (snd_ctl_elem_info_get_type(&info) != 1632d5ac70f0Sopenharmony_ci SND_CTL_ELEM_TYPE_ENUMERATED) 1633d5ac70f0Sopenharmony_ci return 0; 1634d5ac70f0Sopenharmony_ci items = snd_ctl_elem_info_get_items(&info); 1635d5ac70f0Sopenharmony_ci for (k = 0; k < items; ++k) { 1636d5ac70f0Sopenharmony_ci const char *n; 1637d5ac70f0Sopenharmony_ci snd_ctl_elem_info_set_item(&info, k); 1638d5ac70f0Sopenharmony_ci err = snd_hctl_elem_info(helem, &info); 1639d5ac70f0Sopenharmony_ci if (err < 0) 1640d5ac70f0Sopenharmony_ci return err; 1641d5ac70f0Sopenharmony_ci n = snd_ctl_elem_info_get_item_name(&info); 1642d5ac70f0Sopenharmony_ci err = simple_add1(class, n, helem, CTL_CAPTURE_SOURCE, 1643d5ac70f0Sopenharmony_ci k); 1644d5ac70f0Sopenharmony_ci if (err < 0) 1645d5ac70f0Sopenharmony_ci return err; 1646d5ac70f0Sopenharmony_ci } 1647d5ac70f0Sopenharmony_ci return 0; 1648d5ac70f0Sopenharmony_ci } 1649d5ac70f0Sopenharmony_ci 1650d5ac70f0Sopenharmony_ci len = base_len(name, &type); 1651d5ac70f0Sopenharmony_ci if (len >= sizeof(ename)) 1652d5ac70f0Sopenharmony_ci len = sizeof(ename) - 1; 1653d5ac70f0Sopenharmony_ci memcpy(ename, name, len); 1654d5ac70f0Sopenharmony_ci ename[len] = 0; 1655d5ac70f0Sopenharmony_ci 1656d5ac70f0Sopenharmony_ci return simple_add1(class, ename, helem, type, 0); 1657d5ac70f0Sopenharmony_ci} 1658d5ac70f0Sopenharmony_ci 1659d5ac70f0Sopenharmony_cistatic int simple_event_remove(snd_hctl_elem_t *helem, 1660d5ac70f0Sopenharmony_ci snd_mixer_elem_t *melem) 1661d5ac70f0Sopenharmony_ci{ 1662d5ac70f0Sopenharmony_ci selem_none_t *simple = snd_mixer_elem_get_private(melem); 1663d5ac70f0Sopenharmony_ci int err; 1664d5ac70f0Sopenharmony_ci int k; 1665d5ac70f0Sopenharmony_ci for (k = 0; k <= CTL_LAST; k++) { 1666d5ac70f0Sopenharmony_ci if (simple->ctls[k].elem == helem) 1667d5ac70f0Sopenharmony_ci break; 1668d5ac70f0Sopenharmony_ci } 1669d5ac70f0Sopenharmony_ci assert(k <= CTL_LAST); 1670d5ac70f0Sopenharmony_ci simple->ctls[k].elem = NULL; 1671d5ac70f0Sopenharmony_ci err = snd_mixer_elem_detach(melem, helem); 1672d5ac70f0Sopenharmony_ci if (err < 0) 1673d5ac70f0Sopenharmony_ci return err; 1674d5ac70f0Sopenharmony_ci if (snd_mixer_elem_empty(melem)) 1675d5ac70f0Sopenharmony_ci return snd_mixer_elem_remove(melem); 1676d5ac70f0Sopenharmony_ci err = simple_update(melem); 1677d5ac70f0Sopenharmony_ci return snd_mixer_elem_info(melem); 1678d5ac70f0Sopenharmony_ci} 1679d5ac70f0Sopenharmony_ci 1680d5ac70f0Sopenharmony_cistatic int simple_event(snd_mixer_class_t *class, unsigned int mask, 1681d5ac70f0Sopenharmony_ci snd_hctl_elem_t *helem, snd_mixer_elem_t *melem) 1682d5ac70f0Sopenharmony_ci{ 1683d5ac70f0Sopenharmony_ci int err; 1684d5ac70f0Sopenharmony_ci if (mask == SND_CTL_EVENT_MASK_REMOVE) 1685d5ac70f0Sopenharmony_ci return simple_event_remove(helem, melem); 1686d5ac70f0Sopenharmony_ci if (mask & SND_CTL_EVENT_MASK_ADD) { 1687d5ac70f0Sopenharmony_ci err = simple_event_add(class, helem); 1688d5ac70f0Sopenharmony_ci if (err < 0) 1689d5ac70f0Sopenharmony_ci return err; 1690d5ac70f0Sopenharmony_ci } 1691d5ac70f0Sopenharmony_ci if (mask & SND_CTL_EVENT_MASK_INFO) { 1692d5ac70f0Sopenharmony_ci err = simple_event_remove(helem, melem); 1693d5ac70f0Sopenharmony_ci if (err < 0) 1694d5ac70f0Sopenharmony_ci return err; 1695d5ac70f0Sopenharmony_ci err = simple_event_add(class, helem); 1696d5ac70f0Sopenharmony_ci if (err < 0) 1697d5ac70f0Sopenharmony_ci return err; 1698d5ac70f0Sopenharmony_ci return 0; 1699d5ac70f0Sopenharmony_ci } 1700d5ac70f0Sopenharmony_ci if (mask & SND_CTL_EVENT_MASK_VALUE) { 1701d5ac70f0Sopenharmony_ci err = selem_read(melem); 1702d5ac70f0Sopenharmony_ci if (err < 0) 1703d5ac70f0Sopenharmony_ci return err; 1704d5ac70f0Sopenharmony_ci if (err) { 1705d5ac70f0Sopenharmony_ci err = snd_mixer_elem_value(melem); 1706d5ac70f0Sopenharmony_ci if (err < 0) 1707d5ac70f0Sopenharmony_ci return err; 1708d5ac70f0Sopenharmony_ci } 1709d5ac70f0Sopenharmony_ci } 1710d5ac70f0Sopenharmony_ci return 0; 1711d5ac70f0Sopenharmony_ci} 1712d5ac70f0Sopenharmony_ci 1713d5ac70f0Sopenharmony_ci/** 1714d5ac70f0Sopenharmony_ci * \brief Register mixer simple element class - none abstraction 1715d5ac70f0Sopenharmony_ci * \param mixer Mixer handle 1716d5ac70f0Sopenharmony_ci * \param options Options container 1717d5ac70f0Sopenharmony_ci * \param classp Pointer to returned mixer simple element class handle (or NULL) 1718d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code 1719d5ac70f0Sopenharmony_ci */ 1720d5ac70f0Sopenharmony_ciint snd_mixer_simple_none_register(snd_mixer_t *mixer, 1721d5ac70f0Sopenharmony_ci struct snd_mixer_selem_regopt *options ATTRIBUTE_UNUSED, 1722d5ac70f0Sopenharmony_ci snd_mixer_class_t **classp) 1723d5ac70f0Sopenharmony_ci{ 1724d5ac70f0Sopenharmony_ci snd_mixer_class_t *class; 1725d5ac70f0Sopenharmony_ci int err; 1726d5ac70f0Sopenharmony_ci 1727d5ac70f0Sopenharmony_ci if (snd_mixer_class_malloc(&class)) 1728d5ac70f0Sopenharmony_ci return -ENOMEM; 1729d5ac70f0Sopenharmony_ci snd_mixer_class_set_event(class, simple_event); 1730d5ac70f0Sopenharmony_ci snd_mixer_class_set_compare(class, snd_mixer_selem_compare); 1731d5ac70f0Sopenharmony_ci err = snd_mixer_class_register(class, mixer); 1732d5ac70f0Sopenharmony_ci if (err < 0) { 1733d5ac70f0Sopenharmony_ci free(class); 1734d5ac70f0Sopenharmony_ci return err; 1735d5ac70f0Sopenharmony_ci } 1736d5ac70f0Sopenharmony_ci if (classp) 1737d5ac70f0Sopenharmony_ci *classp = class; 1738d5ac70f0Sopenharmony_ci return 0; 1739d5ac70f0Sopenharmony_ci} 1740