|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \file mixer/simple_none.c
|
|
Packit Service |
db8eaa |
* \brief Mixer Simple Element Class Interface
|
|
Packit Service |
db8eaa |
* \author Jaroslav Kysela <perex@perex.cz>
|
|
Packit Service |
db8eaa |
* \author Abramo Bagnara <abramo@alsa-project.org>
|
|
Packit Service |
db8eaa |
* \date 2001-2004
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
* Mixer simple element class interface.
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
/*
|
|
Packit Service |
db8eaa |
* Mixer Interface - simple controls
|
|
Packit Service |
db8eaa |
* Copyright (c) 2000,2004 by Jaroslav Kysela <perex@perex.cz>
|
|
Packit Service |
db8eaa |
* Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org>
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
* This library is free software; you can redistribute it and/or modify
|
|
Packit Service |
db8eaa |
* it under the terms of the GNU Lesser General Public License as
|
|
Packit Service |
db8eaa |
* published by the Free Software Foundation; either version 2.1 of
|
|
Packit Service |
db8eaa |
* the License, or (at your option) any later version.
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
db8eaa |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
db8eaa |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
db8eaa |
* GNU Lesser General Public License for more details.
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit Service |
db8eaa |
* License along with this library; if not, write to the Free Software
|
|
Packit Service |
db8eaa |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#include <stdio.h>
|
|
Packit Service |
db8eaa |
#include <stdlib.h>
|
|
Packit Service |
db8eaa |
#include <unistd.h>
|
|
Packit Service |
db8eaa |
#include <string.h>
|
|
Packit Service |
db8eaa |
#include <fcntl.h>
|
|
Packit Service |
db8eaa |
#include <sys/ioctl.h>
|
|
Packit Service |
db8eaa |
#include <assert.h>
|
|
Packit Service |
db8eaa |
#include <math.h>
|
|
Packit Service |
db8eaa |
#include <limits.h>
|
|
Packit Service |
db8eaa |
#include "local.h"
|
|
Packit Service |
db8eaa |
#include "config.h"
|
|
Packit Service |
db8eaa |
#include "mixer_simple.h"
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#ifndef DOC_HIDDEN
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#define MIXER_COMPARE_WEIGHT_SIMPLE_BASE 0
|
|
Packit Service |
db8eaa |
#define MIXER_COMPARE_WEIGHT_NEXT_BASE 10000000
|
|
Packit Service |
db8eaa |
#define MIXER_COMPARE_WEIGHT_NOT_FOUND 1000000000
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
typedef enum _selem_ctl_type {
|
|
Packit Service |
db8eaa |
CTL_SINGLE,
|
|
Packit Service |
db8eaa |
CTL_GLOBAL_ENUM,
|
|
Packit Service |
db8eaa |
CTL_GLOBAL_SWITCH,
|
|
Packit Service |
db8eaa |
CTL_GLOBAL_VOLUME,
|
|
Packit Service |
db8eaa |
CTL_GLOBAL_ROUTE,
|
|
Packit Service |
db8eaa |
CTL_PLAYBACK_ENUM,
|
|
Packit Service |
db8eaa |
CTL_PLAYBACK_SWITCH,
|
|
Packit Service |
db8eaa |
CTL_PLAYBACK_VOLUME,
|
|
Packit Service |
db8eaa |
CTL_PLAYBACK_ROUTE,
|
|
Packit Service |
db8eaa |
CTL_CAPTURE_ENUM,
|
|
Packit Service |
db8eaa |
CTL_CAPTURE_SWITCH,
|
|
Packit Service |
db8eaa |
CTL_CAPTURE_VOLUME,
|
|
Packit Service |
db8eaa |
CTL_CAPTURE_ROUTE,
|
|
Packit Service |
db8eaa |
CTL_CAPTURE_SOURCE,
|
|
Packit Service |
db8eaa |
CTL_LAST = CTL_CAPTURE_SOURCE,
|
|
Packit Service |
db8eaa |
} selem_ctl_type_t;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
typedef struct _selem_ctl {
|
|
Packit Service |
db8eaa |
snd_hctl_elem_t *elem;
|
|
Packit Service |
db8eaa |
snd_ctl_elem_type_t type;
|
|
Packit Service |
db8eaa |
unsigned int inactive: 1;
|
|
Packit Service |
db8eaa |
unsigned int values;
|
|
Packit Service |
db8eaa |
long min, max;
|
|
Packit Service |
db8eaa |
} selem_ctl_t;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
typedef struct _selem_none {
|
|
Packit Service |
db8eaa |
sm_selem_t selem;
|
|
Packit Service |
db8eaa |
selem_ctl_t ctls[CTL_LAST + 1];
|
|
Packit Service |
db8eaa |
unsigned int capture_item;
|
|
Packit Service |
db8eaa |
struct selem_str {
|
|
Packit Service |
db8eaa |
unsigned int range: 1; /* Forced range */
|
|
Packit Service |
db8eaa |
unsigned int db_initialized: 1;
|
|
Packit Service |
db8eaa |
unsigned int db_init_error: 1;
|
|
Packit Service |
db8eaa |
long min, max;
|
|
Packit Service |
db8eaa |
unsigned int channels;
|
|
Packit Service |
db8eaa |
long vol[32];
|
|
Packit Service |
db8eaa |
unsigned int sw;
|
|
Packit Service |
db8eaa |
unsigned int *db_info;
|
|
Packit Service |
db8eaa |
} str[2];
|
|
Packit Service |
db8eaa |
} selem_none_t;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static const struct mixer_name_table {
|
|
Packit Service |
db8eaa |
const char *longname;
|
|
Packit Service |
db8eaa |
const char *shortname;
|
|
Packit Service |
db8eaa |
} name_table[] = {
|
|
Packit Service |
db8eaa |
{"Tone Control - Switch", "Tone"},
|
|
Packit Service |
db8eaa |
{"Tone Control - Bass", "Bass"},
|
|
Packit Service |
db8eaa |
{"Tone Control - Treble", "Treble"},
|
|
Packit Service |
db8eaa |
{"Synth Tone Control - Switch", "Synth Tone"},
|
|
Packit Service |
db8eaa |
{"Synth Tone Control - Bass", "Synth Bass"},
|
|
Packit Service |
db8eaa |
{"Synth Tone Control - Treble", "Synth Treble"},
|
|
Packit Service |
db8eaa |
{0, 0},
|
|
Packit Service |
db8eaa |
};
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#endif /* !DOC_HIDDEN */
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static const char *get_short_name(const char *lname)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
const struct mixer_name_table *p;
|
|
Packit Service |
db8eaa |
for (p = name_table; p->longname; p++) {
|
|
Packit Service |
db8eaa |
if (!strcmp(lname, p->longname))
|
|
Packit Service |
db8eaa |
return p->shortname;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return lname;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int compare_mixer_priority_lookup(const char **name, const char * const *names, int coef)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
int res;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
for (res = 0; *names; names++, res += coef) {
|
|
Packit Service |
db8eaa |
if (!strncmp(*name, *names, strlen(*names))) {
|
|
Packit Service |
db8eaa |
*name += strlen(*names);
|
|
Packit Service |
db8eaa |
if (**name == ' ')
|
|
Packit Service |
db8eaa |
(*name)++;
|
|
Packit Service |
db8eaa |
return res+1;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return MIXER_COMPARE_WEIGHT_NOT_FOUND;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int get_compare_weight(const char *name, unsigned int idx)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
static const char *const names[] = {
|
|
Packit Service |
db8eaa |
"Master",
|
|
Packit Service |
db8eaa |
"Headphone",
|
|
Packit Service |
db8eaa |
"Speaker",
|
|
Packit Service |
db8eaa |
"Tone",
|
|
Packit Service |
db8eaa |
"Bass",
|
|
Packit Service |
db8eaa |
"Treble",
|
|
Packit Service |
db8eaa |
"3D Control",
|
|
Packit Service |
db8eaa |
"PCM",
|
|
Packit Service |
db8eaa |
"Front",
|
|
Packit Service |
db8eaa |
"Surround",
|
|
Packit Service |
db8eaa |
"Center",
|
|
Packit Service |
db8eaa |
"LFE",
|
|
Packit Service |
db8eaa |
"Side",
|
|
Packit Service |
db8eaa |
"Synth",
|
|
Packit Service |
db8eaa |
"FM",
|
|
Packit Service |
db8eaa |
"Wave",
|
|
Packit Service |
db8eaa |
"Music",
|
|
Packit Service |
db8eaa |
"DSP",
|
|
Packit Service |
db8eaa |
"Line",
|
|
Packit Service |
db8eaa |
"CD",
|
|
Packit Service |
db8eaa |
"Mic",
|
|
Packit Service |
db8eaa |
"Video",
|
|
Packit Service |
db8eaa |
"Zoom Video",
|
|
Packit Service |
db8eaa |
"Phone",
|
|
Packit Service |
db8eaa |
"I2S",
|
|
Packit Service |
db8eaa |
"IEC958",
|
|
Packit Service |
db8eaa |
"PC Speaker",
|
|
Packit Service |
db8eaa |
"Beep",
|
|
Packit Service |
db8eaa |
"Aux",
|
|
Packit Service |
db8eaa |
"Mono",
|
|
Packit Service |
db8eaa |
"Playback",
|
|
Packit Service |
db8eaa |
"Capture",
|
|
Packit Service |
db8eaa |
"Mix",
|
|
Packit Service |
db8eaa |
NULL
|
|
Packit Service |
db8eaa |
};
|
|
Packit Service |
db8eaa |
static const char *const names1[] = {
|
|
Packit Service |
db8eaa |
"-",
|
|
Packit Service |
db8eaa |
NULL,
|
|
Packit Service |
db8eaa |
};
|
|
Packit Service |
db8eaa |
static const char *const names2[] = {
|
|
Packit Service |
db8eaa |
"Mono",
|
|
Packit Service |
db8eaa |
"Digital",
|
|
Packit Service |
db8eaa |
"Switch",
|
|
Packit Service |
db8eaa |
"Depth",
|
|
Packit Service |
db8eaa |
"Wide",
|
|
Packit Service |
db8eaa |
"Space",
|
|
Packit Service |
db8eaa |
"Level",
|
|
Packit Service |
db8eaa |
"Center",
|
|
Packit Service |
db8eaa |
"Output",
|
|
Packit Service |
db8eaa |
"Boost",
|
|
Packit Service |
db8eaa |
"Tone",
|
|
Packit Service |
db8eaa |
"Bass",
|
|
Packit Service |
db8eaa |
"Treble",
|
|
Packit Service |
db8eaa |
NULL,
|
|
Packit Service |
db8eaa |
};
|
|
Packit Service |
db8eaa |
const char *name1;
|
|
Packit Service |
db8eaa |
int res, res1;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if ((res = compare_mixer_priority_lookup((const char **)&name, names, 1000)) == MIXER_COMPARE_WEIGHT_NOT_FOUND)
|
|
Packit Service |
db8eaa |
return MIXER_COMPARE_WEIGHT_NOT_FOUND;
|
|
Packit Service |
db8eaa |
if (*name == '\0')
|
|
Packit Service |
db8eaa |
goto __res;
|
|
Packit Service |
db8eaa |
for (name1 = name; *name1 != '\0'; name1++);
|
|
Packit Service |
db8eaa |
for (name1--; name1 != name && *name1 != ' '; name1--);
|
|
Packit Service |
db8eaa |
while (name1 != name && *name1 == ' ')
|
|
Packit Service |
db8eaa |
name1--;
|
|
Packit Service |
db8eaa |
if (name1 != name) {
|
|
Packit Service |
db8eaa |
for (; name1 != name && *name1 != ' '; name1--);
|
|
Packit Service |
db8eaa |
name = name1;
|
|
Packit Service |
db8eaa |
if ((res1 = compare_mixer_priority_lookup((const char **)&name, names1, 200)) == MIXER_COMPARE_WEIGHT_NOT_FOUND)
|
|
Packit Service |
db8eaa |
return res;
|
|
Packit Service |
db8eaa |
res += res1;
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
db8eaa |
name = name1;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if ((res1 = compare_mixer_priority_lookup((const char **)&name, names2, 20)) == MIXER_COMPARE_WEIGHT_NOT_FOUND)
|
|
Packit Service |
db8eaa |
return res;
|
|
Packit Service |
db8eaa |
__res:
|
|
Packit Service |
db8eaa |
return MIXER_COMPARE_WEIGHT_SIMPLE_BASE + res + idx;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static long to_user(selem_none_t *s, int dir, selem_ctl_t *c, long value)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
int64_t n;
|
|
Packit Service |
db8eaa |
if (c->max == c->min)
|
|
Packit Service |
db8eaa |
return s->str[dir].min;
|
|
Packit Service |
db8eaa |
n = (int64_t) (value - c->min) * (s->str[dir].max - s->str[dir].min);
|
|
Packit Service |
db8eaa |
return s->str[dir].min + (n + (c->max - c->min) / 2) / (c->max - c->min);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static long from_user(selem_none_t *s, int dir, selem_ctl_t *c, long value)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
int64_t n;
|
|
Packit Service |
db8eaa |
if (s->str[dir].max == s->str[dir].min)
|
|
Packit Service |
db8eaa |
return c->min;
|
|
Packit Service |
db8eaa |
n = (int64_t) (value - s->str[dir].min) * (c->max - c->min);
|
|
Packit Service |
db8eaa |
return c->min + (n + (s->str[dir].max - s->str[dir].min) / 2) / (s->str[dir].max - s->str[dir].min);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int elem_read_volume(selem_none_t *s, int dir, selem_ctl_type_t type)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_t ctl = {0};
|
|
Packit Service |
db8eaa |
unsigned int idx;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
selem_ctl_t *c = &s->ctls[type];
|
|
Packit Service |
db8eaa |
if ((err = snd_hctl_elem_read(c->elem, &ctl)) < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
for (idx = 0; idx < s->str[dir].channels; idx++) {
|
|
Packit Service |
db8eaa |
unsigned int idx1 = idx;
|
|
Packit Service |
db8eaa |
if (idx >= c->values)
|
|
Packit Service |
db8eaa |
idx1 = 0;
|
|
Packit Service |
db8eaa |
s->str[dir].vol[idx] =
|
|
Packit Service |
db8eaa |
to_user(s, dir, c,
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_get_integer(&ctl, idx1));
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int elem_read_switch(selem_none_t *s, int dir, selem_ctl_type_t type)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_t ctl = {0};
|
|
Packit Service |
db8eaa |
unsigned int idx;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
selem_ctl_t *c = &s->ctls[type];
|
|
Packit Service |
db8eaa |
if ((err = snd_hctl_elem_read(c->elem, &ctl)) < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
for (idx = 0; idx < s->str[dir].channels; idx++) {
|
|
Packit Service |
db8eaa |
unsigned int idx1 = idx;
|
|
Packit Service |
db8eaa |
if (idx >= c->values)
|
|
Packit Service |
db8eaa |
idx1 = 0;
|
|
Packit Service |
db8eaa |
if (!snd_ctl_elem_value_get_integer(&ctl, idx1))
|
|
Packit Service |
db8eaa |
s->str[dir].sw &= ~(1 << idx);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int elem_read_route(selem_none_t *s, int dir, selem_ctl_type_t type)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_t ctl = {0};
|
|
Packit Service |
db8eaa |
unsigned int idx;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
selem_ctl_t *c = &s->ctls[type];
|
|
Packit Service |
db8eaa |
if ((err = snd_hctl_elem_read(c->elem, &ctl)) < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
for (idx = 0; idx < s->str[dir].channels; idx++) {
|
|
Packit Service |
db8eaa |
unsigned int idx1 = idx;
|
|
Packit Service |
db8eaa |
if (idx >= c->values)
|
|
Packit Service |
db8eaa |
idx1 = 0;
|
|
Packit Service |
db8eaa |
if (!snd_ctl_elem_value_get_integer(&ctl,
|
|
Packit Service |
db8eaa |
idx1 * c->values + idx1))
|
|
Packit Service |
db8eaa |
s->str[dir].sw &= ~(1 << idx);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int elem_read_enum(selem_none_t *s)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_t ctl = {0};
|
|
Packit Service |
db8eaa |
unsigned int idx;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
int type;
|
|
Packit Service |
db8eaa |
selem_ctl_t *c;
|
|
Packit Service |
db8eaa |
type = CTL_GLOBAL_ENUM;
|
|
Packit Service |
db8eaa |
if ((s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM)) ==
|
|
Packit Service |
db8eaa |
(SM_CAP_CENUM | SM_CAP_PENUM))
|
|
Packit Service |
db8eaa |
type = CTL_GLOBAL_ENUM;
|
|
Packit Service |
db8eaa |
else if (s->selem.caps & SM_CAP_PENUM)
|
|
Packit Service |
db8eaa |
type = CTL_PLAYBACK_ENUM;
|
|
Packit Service |
db8eaa |
else if (s->selem.caps & SM_CAP_CENUM)
|
|
Packit Service |
db8eaa |
type = CTL_CAPTURE_ENUM;
|
|
Packit Service |
db8eaa |
c = &s->ctls[type];
|
|
Packit Service |
db8eaa |
if ((err = snd_hctl_elem_read(c->elem, &ctl)) < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
for (idx = 0; idx < s->str[0].channels; idx++) {
|
|
Packit Service |
db8eaa |
unsigned int idx1 = idx;
|
|
Packit Service |
db8eaa |
if (idx >= c->values)
|
|
Packit Service |
db8eaa |
idx1 = 0;
|
|
Packit Service |
db8eaa |
s->str[0].vol[idx] =
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_get_enumerated(&ctl, idx1);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int selem_read(snd_mixer_elem_t *elem)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
selem_none_t *s;
|
|
Packit Service |
db8eaa |
unsigned int idx;
|
|
Packit Service |
db8eaa |
int err = 0;
|
|
Packit Service |
db8eaa |
long pvol[32], cvol[32];
|
|
Packit Service |
db8eaa |
unsigned int psw, csw;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
assert(snd_mixer_elem_get_type(elem) == SND_MIXER_ELEM_SIMPLE);
|
|
Packit Service |
db8eaa |
s = snd_mixer_elem_get_private(elem);
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
memcpy(pvol, s->str[SM_PLAY].vol, sizeof(pvol));
|
|
Packit Service |
db8eaa |
memset(&s->str[SM_PLAY].vol, 0, sizeof(s->str[SM_PLAY].vol));
|
|
Packit Service |
db8eaa |
psw = s->str[SM_PLAY].sw;
|
|
Packit Service |
db8eaa |
s->str[SM_PLAY].sw = ~0U;
|
|
Packit Service |
db8eaa |
memcpy(cvol, s->str[SM_CAPT].vol, sizeof(cvol));
|
|
Packit Service |
db8eaa |
memset(&s->str[SM_CAPT].vol, 0, sizeof(s->str[SM_CAPT].vol));
|
|
Packit Service |
db8eaa |
csw = s->str[SM_CAPT].sw;
|
|
Packit Service |
db8eaa |
s->str[SM_CAPT].sw = ~0U;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_GLOBAL_ENUM].elem) {
|
|
Packit Service |
db8eaa |
err = elem_read_enum(s);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
goto __skip_cswitch;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_CAPTURE_ENUM].elem) {
|
|
Packit Service |
db8eaa |
err = elem_read_enum(s);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
goto __skip_cswitch;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_PLAYBACK_ENUM].elem) {
|
|
Packit Service |
db8eaa |
err = elem_read_enum(s);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
goto __skip_cswitch;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_PLAYBACK_VOLUME].elem)
|
|
Packit Service |
db8eaa |
err = elem_read_volume(s, SM_PLAY, CTL_PLAYBACK_VOLUME);
|
|
Packit Service |
db8eaa |
else if (s->ctls[CTL_GLOBAL_VOLUME].elem)
|
|
Packit Service |
db8eaa |
err = elem_read_volume(s, SM_PLAY, CTL_GLOBAL_VOLUME);
|
|
Packit Service |
db8eaa |
else if (s->ctls[CTL_SINGLE].elem &&
|
|
Packit Service |
db8eaa |
s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_INTEGER)
|
|
Packit Service |
db8eaa |
err = elem_read_volume(s, SM_PLAY, CTL_SINGLE);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if ((s->selem.caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH)) == 0) {
|
|
Packit Service |
db8eaa |
s->str[SM_PLAY].sw = 0;
|
|
Packit Service |
db8eaa |
goto __skip_pswitch;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_PLAYBACK_SWITCH].elem) {
|
|
Packit Service |
db8eaa |
err = elem_read_switch(s, SM_PLAY, CTL_PLAYBACK_SWITCH);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_GLOBAL_SWITCH].elem) {
|
|
Packit Service |
db8eaa |
err = elem_read_switch(s, SM_PLAY, CTL_GLOBAL_SWITCH);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_SINGLE].elem &&
|
|
Packit Service |
db8eaa |
s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_BOOLEAN) {
|
|
Packit Service |
db8eaa |
err = elem_read_switch(s, SM_PLAY, CTL_SINGLE);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_PLAYBACK_ROUTE].elem) {
|
|
Packit Service |
db8eaa |
err = elem_read_route(s, SM_PLAY, CTL_PLAYBACK_ROUTE);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_GLOBAL_ROUTE].elem) {
|
|
Packit Service |
db8eaa |
err = elem_read_route(s, SM_PLAY, CTL_GLOBAL_ROUTE);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
__skip_pswitch:
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_CAPTURE_VOLUME].elem)
|
|
Packit Service |
db8eaa |
err = elem_read_volume(s, SM_CAPT, CTL_CAPTURE_VOLUME);
|
|
Packit Service |
db8eaa |
else if (s->ctls[CTL_GLOBAL_VOLUME].elem)
|
|
Packit Service |
db8eaa |
err = elem_read_volume(s, SM_CAPT, CTL_GLOBAL_VOLUME);
|
|
Packit Service |
db8eaa |
else if (s->ctls[CTL_SINGLE].elem &&
|
|
Packit Service |
db8eaa |
s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_INTEGER)
|
|
Packit Service |
db8eaa |
err = elem_read_volume(s, SM_CAPT, CTL_SINGLE);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if ((s->selem.caps & (SM_CAP_GSWITCH|SM_CAP_CSWITCH)) == 0) {
|
|
Packit Service |
db8eaa |
s->str[SM_CAPT].sw = 0;
|
|
Packit Service |
db8eaa |
goto __skip_cswitch;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_CAPTURE_SWITCH].elem) {
|
|
Packit Service |
db8eaa |
err = elem_read_switch(s, SM_CAPT, CTL_CAPTURE_SWITCH);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_GLOBAL_SWITCH].elem) {
|
|
Packit Service |
db8eaa |
err = elem_read_switch(s, SM_CAPT, CTL_GLOBAL_SWITCH);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_SINGLE].elem &&
|
|
Packit Service |
db8eaa |
s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_BOOLEAN) {
|
|
Packit Service |
db8eaa |
err = elem_read_switch(s, SM_CAPT, CTL_SINGLE);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_CAPTURE_ROUTE].elem) {
|
|
Packit Service |
db8eaa |
err = elem_read_route(s, SM_CAPT, CTL_CAPTURE_ROUTE);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_GLOBAL_ROUTE].elem) {
|
|
Packit Service |
db8eaa |
err = elem_read_route(s, SM_CAPT, CTL_GLOBAL_ROUTE);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_CAPTURE_SOURCE].elem) {
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_t ctl = {0};
|
|
Packit Service |
db8eaa |
selem_ctl_t *c = &s->ctls[CTL_CAPTURE_SOURCE];
|
|
Packit Service |
db8eaa |
err = snd_hctl_elem_read(c->elem, &ctl;;
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
for (idx = 0; idx < s->str[SM_CAPT].channels; idx++) {
|
|
Packit Service |
db8eaa |
unsigned int idx1 = idx;
|
|
Packit Service |
db8eaa |
if (idx >= c->values)
|
|
Packit Service |
db8eaa |
idx1 = 0;
|
|
Packit Service |
db8eaa |
if (snd_ctl_elem_value_get_enumerated(&ctl, idx1) !=
|
|
Packit Service |
db8eaa |
s->capture_item)
|
|
Packit Service |
db8eaa |
s->str[SM_CAPT].sw &= ~(1 << idx);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
__skip_cswitch:
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (memcmp(pvol, s->str[SM_PLAY].vol, sizeof(pvol)) ||
|
|
Packit Service |
db8eaa |
psw != s->str[SM_PLAY].sw ||
|
|
Packit Service |
db8eaa |
memcmp(cvol, s->str[SM_CAPT].vol, sizeof(cvol)) ||
|
|
Packit Service |
db8eaa |
csw != s->str[SM_CAPT].sw)
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int elem_write_volume(selem_none_t *s, int dir, selem_ctl_type_t type)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_t ctl = {0};
|
|
Packit Service |
db8eaa |
unsigned int idx;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
selem_ctl_t *c = &s->ctls[type];
|
|
Packit Service |
db8eaa |
if ((err = snd_hctl_elem_read(c->elem, &ctl)) < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
for (idx = 0; idx < c->values; idx++)
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_set_integer(&ctl, idx,
|
|
Packit Service |
db8eaa |
from_user(s, dir, c, s->str[dir].vol[idx]));
|
|
Packit Service |
db8eaa |
if ((err = snd_hctl_elem_write(c->elem, &ctl)) < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int elem_write_switch(selem_none_t *s, int dir, selem_ctl_type_t type)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_t ctl = {0};
|
|
Packit Service |
db8eaa |
unsigned int idx;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
selem_ctl_t *c = &s->ctls[type];
|
|
Packit Service |
db8eaa |
if ((err = snd_hctl_elem_read(c->elem, &ctl)) < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
for (idx = 0; idx < c->values; idx++)
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_set_integer(&ctl, idx,
|
|
Packit Service |
db8eaa |
!!(s->str[dir].sw & (1 << idx)));
|
|
Packit Service |
db8eaa |
if ((err = snd_hctl_elem_write(c->elem, &ctl)) < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int elem_write_switch_constant(selem_none_t *s, selem_ctl_type_t type, int val)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_t ctl = {0};
|
|
Packit Service |
db8eaa |
unsigned int idx;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
selem_ctl_t *c = &s->ctls[type];
|
|
Packit Service |
db8eaa |
if ((err = snd_hctl_elem_read(c->elem, &ctl)) < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
for (idx = 0; idx < c->values; idx++)
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_set_integer(&ctl, idx, !!val);
|
|
Packit Service |
db8eaa |
if ((err = snd_hctl_elem_write(c->elem, &ctl)) < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int elem_write_route(selem_none_t *s, int dir, selem_ctl_type_t type)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_t ctl = {0};
|
|
Packit Service |
db8eaa |
unsigned int idx;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
selem_ctl_t *c = &s->ctls[type];
|
|
Packit Service |
db8eaa |
if ((err = snd_hctl_elem_read(c->elem, &ctl)) < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
for (idx = 0; idx < c->values * c->values; idx++)
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_set_integer(&ctl, idx, 0);
|
|
Packit Service |
db8eaa |
for (idx = 0; idx < c->values; idx++)
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_set_integer(&ctl, idx * c->values + idx,
|
|
Packit Service |
db8eaa |
!!(s->str[dir].sw & (1 << idx)));
|
|
Packit Service |
db8eaa |
if ((err = snd_hctl_elem_write(c->elem, &ctl)) < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int elem_write_enum(selem_none_t *s)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_t ctl = {0};
|
|
Packit Service |
db8eaa |
unsigned int idx;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
int type;
|
|
Packit Service |
db8eaa |
selem_ctl_t *c;
|
|
Packit Service |
db8eaa |
type = CTL_GLOBAL_ENUM;
|
|
Packit Service |
db8eaa |
if ((s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM)) ==
|
|
Packit Service |
db8eaa |
(SM_CAP_CENUM | SM_CAP_PENUM))
|
|
Packit Service |
db8eaa |
type = CTL_GLOBAL_ENUM;
|
|
Packit Service |
db8eaa |
else if (s->selem.caps & SM_CAP_PENUM)
|
|
Packit Service |
db8eaa |
type = CTL_PLAYBACK_ENUM;
|
|
Packit Service |
db8eaa |
else if (s->selem.caps & SM_CAP_CENUM)
|
|
Packit Service |
db8eaa |
type = CTL_CAPTURE_ENUM;
|
|
Packit Service |
db8eaa |
c = &s->ctls[type];
|
|
Packit Service |
db8eaa |
if ((err = snd_hctl_elem_read(c->elem, &ctl)) < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
for (idx = 0; idx < c->values; idx++)
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_set_enumerated(&ctl, idx,
|
|
Packit Service |
db8eaa |
(unsigned int)s->str[0].vol[idx]);
|
|
Packit Service |
db8eaa |
if ((err = snd_hctl_elem_write(c->elem, &ctl)) < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int selem_write_main(snd_mixer_elem_t *elem)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
selem_none_t *s;
|
|
Packit Service |
db8eaa |
unsigned int idx;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
assert(snd_mixer_elem_get_type(elem) == SND_MIXER_ELEM_SIMPLE);
|
|
Packit Service |
db8eaa |
s = snd_mixer_elem_get_private(elem);
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_GLOBAL_ENUM].elem)
|
|
Packit Service |
db8eaa |
return elem_write_enum(s);
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_PLAYBACK_ENUM].elem)
|
|
Packit Service |
db8eaa |
return elem_write_enum(s);
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_CAPTURE_ENUM].elem)
|
|
Packit Service |
db8eaa |
return elem_write_enum(s);
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_SINGLE].elem) {
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_SINGLE].type == SND_CTL_ELEM_TYPE_INTEGER)
|
|
Packit Service |
db8eaa |
err = elem_write_volume(s, SM_PLAY, CTL_SINGLE);
|
|
Packit Service |
db8eaa |
else
|
|
Packit Service |
db8eaa |
err = elem_write_switch(s, SM_PLAY, CTL_SINGLE);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_GLOBAL_VOLUME].elem) {
|
|
Packit Service |
db8eaa |
err = elem_write_volume(s, SM_PLAY, CTL_GLOBAL_VOLUME);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_GLOBAL_SWITCH].elem) {
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_PLAYBACK_SWITCH].elem &&
|
|
Packit Service |
db8eaa |
s->ctls[CTL_CAPTURE_SWITCH].elem)
|
|
Packit Service |
db8eaa |
err = elem_write_switch_constant(s, CTL_GLOBAL_SWITCH,
|
|
Packit Service |
db8eaa |
1);
|
|
Packit Service |
db8eaa |
else
|
|
Packit Service |
db8eaa |
err = elem_write_switch(s, SM_PLAY, CTL_GLOBAL_SWITCH);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_PLAYBACK_VOLUME].elem) {
|
|
Packit Service |
db8eaa |
err = elem_write_volume(s, SM_PLAY, CTL_PLAYBACK_VOLUME);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_PLAYBACK_SWITCH].elem) {
|
|
Packit Service |
db8eaa |
err = elem_write_switch(s, SM_PLAY, CTL_PLAYBACK_SWITCH);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_PLAYBACK_ROUTE].elem) {
|
|
Packit Service |
db8eaa |
err = elem_write_route(s, SM_PLAY, CTL_PLAYBACK_ROUTE);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_CAPTURE_VOLUME].elem) {
|
|
Packit Service |
db8eaa |
err = elem_write_volume(s, SM_CAPT, CTL_CAPTURE_VOLUME);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_CAPTURE_SWITCH].elem) {
|
|
Packit Service |
db8eaa |
err = elem_write_switch(s, SM_CAPT, CTL_CAPTURE_SWITCH);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_CAPTURE_ROUTE].elem) {
|
|
Packit Service |
db8eaa |
err = elem_write_route(s, SM_CAPT, CTL_CAPTURE_ROUTE);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (s->ctls[CTL_CAPTURE_SOURCE].elem) {
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_t ctl = {0};
|
|
Packit Service |
db8eaa |
selem_ctl_t *c = &s->ctls[CTL_CAPTURE_SOURCE];
|
|
Packit Service |
db8eaa |
if ((err = snd_hctl_elem_read(c->elem, &ctl)) < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
for (idx = 0; idx < c->values; idx++) {
|
|
Packit Service |
db8eaa |
if (s->str[SM_CAPT].sw & (1 << idx))
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_set_enumerated(&ctl,
|
|
Packit Service |
db8eaa |
idx, s->capture_item);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if ((err = snd_hctl_elem_write(c->elem, &ctl)) < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
/* update the element, don't remove */
|
|
Packit Service |
db8eaa |
err = selem_read(elem);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int selem_write(snd_mixer_elem_t *elem)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
err = selem_write_main(elem);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
selem_read(elem);
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static void selem_free(snd_mixer_elem_t *elem)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
selem_none_t *simple = snd_mixer_elem_get_private(elem);
|
|
Packit Service |
db8eaa |
assert(snd_mixer_elem_get_type(elem) == SND_MIXER_ELEM_SIMPLE);
|
|
Packit Service |
db8eaa |
if (simple->selem.id)
|
|
Packit Service |
db8eaa |
snd_mixer_selem_id_free(simple->selem.id);
|
|
Packit Service |
db8eaa |
/* free db range information */
|
|
Packit Service |
db8eaa |
free(simple->str[0].db_info);
|
|
Packit Service |
db8eaa |
free(simple->str[1].db_info);
|
|
Packit Service |
db8eaa |
free(simple);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int simple_update(snd_mixer_elem_t *melem)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
selem_none_t *simple;
|
|
Packit Service |
db8eaa |
unsigned int caps, pchannels, cchannels;
|
|
Packit Service |
db8eaa |
long pmin, pmax, cmin, cmax;
|
|
Packit Service |
db8eaa |
selem_ctl_t *ctl;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
caps = 0;
|
|
Packit Service |
db8eaa |
pchannels = 0;
|
|
Packit Service |
db8eaa |
pmin = LONG_MAX;
|
|
Packit Service |
db8eaa |
pmax = LONG_MIN;
|
|
Packit Service |
db8eaa |
cchannels = 0;
|
|
Packit Service |
db8eaa |
cmin = LONG_MAX;
|
|
Packit Service |
db8eaa |
cmax = LONG_MIN;
|
|
Packit Service |
db8eaa |
assert(snd_mixer_elem_get_type(melem) == SND_MIXER_ELEM_SIMPLE);
|
|
Packit Service |
db8eaa |
simple = snd_mixer_elem_get_private(melem);
|
|
Packit Service |
db8eaa |
ctl = &simple->ctls[CTL_SINGLE];
|
|
Packit Service |
db8eaa |
if (ctl->elem) {
|
|
Packit Service |
db8eaa |
pchannels = cchannels = ctl->values;
|
|
Packit Service |
db8eaa |
if (ctl->type == SND_CTL_ELEM_TYPE_INTEGER) {
|
|
Packit Service |
db8eaa |
caps |= SM_CAP_GVOLUME;
|
|
Packit Service |
db8eaa |
pmin = cmin = ctl->min;
|
|
Packit Service |
db8eaa |
pmax = cmax = ctl->max;
|
|
Packit Service |
db8eaa |
} else
|
|
Packit Service |
db8eaa |
caps |= SM_CAP_GSWITCH;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
ctl = &simple->ctls[CTL_GLOBAL_SWITCH];
|
|
Packit Service |
db8eaa |
if (ctl->elem) {
|
|
Packit Service |
db8eaa |
if (pchannels < ctl->values)
|
|
Packit Service |
db8eaa |
pchannels = ctl->values;
|
|
Packit Service |
db8eaa |
if (cchannels < ctl->values)
|
|
Packit Service |
db8eaa |
cchannels = ctl->values;
|
|
Packit Service |
db8eaa |
caps |= SM_CAP_GSWITCH;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
ctl = &simple->ctls[CTL_GLOBAL_ROUTE];
|
|
Packit Service |
db8eaa |
if (ctl->elem) {
|
|
Packit Service |
db8eaa |
if (pchannels < ctl->values)
|
|
Packit Service |
db8eaa |
pchannels = ctl->values;
|
|
Packit Service |
db8eaa |
if (cchannels < ctl->values)
|
|
Packit Service |
db8eaa |
cchannels = ctl->values;
|
|
Packit Service |
db8eaa |
caps |= SM_CAP_GSWITCH;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
ctl = &simple->ctls[CTL_GLOBAL_VOLUME];
|
|
Packit Service |
db8eaa |
if (ctl->elem) {
|
|
Packit Service |
db8eaa |
if (pchannels < ctl->values)
|
|
Packit Service |
db8eaa |
pchannels = ctl->values;
|
|
Packit Service |
db8eaa |
if (pmin > ctl->min)
|
|
Packit Service |
db8eaa |
pmin = ctl->min;
|
|
Packit Service |
db8eaa |
if (pmax < ctl->max)
|
|
Packit Service |
db8eaa |
pmax = ctl->max;
|
|
Packit Service |
db8eaa |
if (cchannels < ctl->values)
|
|
Packit Service |
db8eaa |
cchannels = ctl->values;
|
|
Packit Service |
db8eaa |
if (cmin > ctl->min)
|
|
Packit Service |
db8eaa |
cmin = ctl->min;
|
|
Packit Service |
db8eaa |
if (cmax < ctl->max)
|
|
Packit Service |
db8eaa |
cmax = ctl->max;
|
|
Packit Service |
db8eaa |
caps |= SM_CAP_GVOLUME;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
ctl = &simple->ctls[CTL_PLAYBACK_SWITCH];
|
|
Packit Service |
db8eaa |
if (ctl->elem) {
|
|
Packit Service |
db8eaa |
if (pchannels < ctl->values)
|
|
Packit Service |
db8eaa |
pchannels = ctl->values;
|
|
Packit Service |
db8eaa |
caps |= SM_CAP_PSWITCH;
|
|
Packit Service |
db8eaa |
caps &= ~SM_CAP_GSWITCH;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
ctl = &simple->ctls[CTL_PLAYBACK_ROUTE];
|
|
Packit Service |
db8eaa |
if (ctl->elem) {
|
|
Packit Service |
db8eaa |
if (pchannels < ctl->values)
|
|
Packit Service |
db8eaa |
pchannels = ctl->values;
|
|
Packit Service |
db8eaa |
caps |= SM_CAP_PSWITCH;
|
|
Packit Service |
db8eaa |
caps &= ~SM_CAP_GSWITCH;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
ctl = &simple->ctls[CTL_CAPTURE_SWITCH];
|
|
Packit Service |
db8eaa |
if (ctl->elem) {
|
|
Packit Service |
db8eaa |
if (cchannels < ctl->values)
|
|
Packit Service |
db8eaa |
cchannels = ctl->values;
|
|
Packit Service |
db8eaa |
caps |= SM_CAP_CSWITCH;
|
|
Packit Service |
db8eaa |
caps &= ~SM_CAP_GSWITCH;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
ctl = &simple->ctls[CTL_CAPTURE_ROUTE];
|
|
Packit Service |
db8eaa |
if (ctl->elem) {
|
|
Packit Service |
db8eaa |
if (cchannels < ctl->values)
|
|
Packit Service |
db8eaa |
cchannels = ctl->values;
|
|
Packit Service |
db8eaa |
caps |= SM_CAP_CSWITCH;
|
|
Packit Service |
db8eaa |
caps &= ~SM_CAP_GSWITCH;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
ctl = &simple->ctls[CTL_PLAYBACK_VOLUME];
|
|
Packit Service |
db8eaa |
if (ctl->elem) {
|
|
Packit Service |
db8eaa |
if (pchannels < ctl->values)
|
|
Packit Service |
db8eaa |
pchannels = ctl->values;
|
|
Packit Service |
db8eaa |
if (pmin > ctl->min)
|
|
Packit Service |
db8eaa |
pmin = ctl->min;
|
|
Packit Service |
db8eaa |
if (pmax < ctl->max)
|
|
Packit Service |
db8eaa |
pmax = ctl->max;
|
|
Packit Service |
db8eaa |
caps |= SM_CAP_PVOLUME;
|
|
Packit Service |
db8eaa |
caps &= ~SM_CAP_GVOLUME;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
ctl = &simple->ctls[CTL_CAPTURE_VOLUME];
|
|
Packit Service |
db8eaa |
if (ctl->elem) {
|
|
Packit Service |
db8eaa |
if (cchannels < ctl->values)
|
|
Packit Service |
db8eaa |
cchannels = ctl->values;
|
|
Packit Service |
db8eaa |
if (cmin > ctl->min)
|
|
Packit Service |
db8eaa |
cmin = ctl->min;
|
|
Packit Service |
db8eaa |
if (cmax < ctl->max)
|
|
Packit Service |
db8eaa |
cmax = ctl->max;
|
|
Packit Service |
db8eaa |
caps |= SM_CAP_CVOLUME;
|
|
Packit Service |
db8eaa |
caps &= ~SM_CAP_GVOLUME;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
ctl = &simple->ctls[CTL_CAPTURE_SOURCE];
|
|
Packit Service |
db8eaa |
if (ctl->elem) {
|
|
Packit Service |
db8eaa |
if (cchannels < ctl->values)
|
|
Packit Service |
db8eaa |
cchannels = ctl->values;
|
|
Packit Service |
db8eaa |
caps |= SM_CAP_CSWITCH | SM_CAP_CSWITCH_EXCL;
|
|
Packit Service |
db8eaa |
caps &= ~SM_CAP_GSWITCH;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
ctl = &simple->ctls[CTL_GLOBAL_ENUM];
|
|
Packit Service |
db8eaa |
if (ctl->elem) {
|
|
Packit Service |
db8eaa |
if (pchannels < ctl->values)
|
|
Packit Service |
db8eaa |
pchannels = ctl->values;
|
|
Packit Service |
db8eaa |
caps |= SM_CAP_PENUM | SM_CAP_CENUM;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
ctl = &simple->ctls[CTL_PLAYBACK_ENUM];
|
|
Packit Service |
db8eaa |
if (ctl->elem) {
|
|
Packit Service |
db8eaa |
if (pchannels < ctl->values)
|
|
Packit Service |
db8eaa |
pchannels = ctl->values;
|
|
Packit Service |
db8eaa |
caps |= SM_CAP_PENUM;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
ctl = &simple->ctls[CTL_CAPTURE_ENUM];
|
|
Packit Service |
db8eaa |
if (ctl->elem) {
|
|
Packit Service |
db8eaa |
if (pchannels < ctl->values)
|
|
Packit Service |
db8eaa |
pchannels = ctl->values;
|
|
Packit Service |
db8eaa |
caps |= SM_CAP_CENUM;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (pchannels > 32)
|
|
Packit Service |
db8eaa |
pchannels = 32;
|
|
Packit Service |
db8eaa |
if (cchannels > 32)
|
|
Packit Service |
db8eaa |
cchannels = 32;
|
|
Packit Service |
db8eaa |
if (caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH))
|
|
Packit Service |
db8eaa |
caps |= SM_CAP_PSWITCH_JOIN;
|
|
Packit Service |
db8eaa |
if (caps & (SM_CAP_GVOLUME|SM_CAP_PVOLUME))
|
|
Packit Service |
db8eaa |
caps |= SM_CAP_PVOLUME_JOIN;
|
|
Packit Service |
db8eaa |
if (caps & (SM_CAP_GSWITCH|SM_CAP_CSWITCH))
|
|
Packit Service |
db8eaa |
caps |= SM_CAP_CSWITCH_JOIN;
|
|
Packit Service |
db8eaa |
if (caps & (SM_CAP_GVOLUME|SM_CAP_CVOLUME))
|
|
Packit Service |
db8eaa |
caps |= SM_CAP_CVOLUME_JOIN;
|
|
Packit Service |
db8eaa |
if (pchannels > 1 || cchannels > 1) {
|
|
Packit Service |
db8eaa |
if (simple->ctls[CTL_SINGLE].elem &&
|
|
Packit Service |
db8eaa |
simple->ctls[CTL_SINGLE].values > 1) {
|
|
Packit Service |
db8eaa |
if (caps & SM_CAP_GSWITCH)
|
|
Packit Service |
db8eaa |
caps &= ~(SM_CAP_PSWITCH_JOIN|SM_CAP_CSWITCH_JOIN);
|
|
Packit Service |
db8eaa |
else
|
|
Packit Service |
db8eaa |
caps &= ~(SM_CAP_PVOLUME_JOIN|SM_CAP_CVOLUME_JOIN);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (simple->ctls[CTL_GLOBAL_ROUTE].elem ||
|
|
Packit Service |
db8eaa |
(simple->ctls[CTL_GLOBAL_SWITCH].elem &&
|
|
Packit Service |
db8eaa |
simple->ctls[CTL_GLOBAL_SWITCH].values > 1)) {
|
|
Packit Service |
db8eaa |
caps &= ~(SM_CAP_PSWITCH_JOIN|SM_CAP_CSWITCH_JOIN);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (simple->ctls[CTL_GLOBAL_VOLUME].elem &&
|
|
Packit Service |
db8eaa |
simple->ctls[CTL_GLOBAL_VOLUME].values > 1) {
|
|
Packit Service |
db8eaa |
caps &= ~(SM_CAP_PVOLUME_JOIN|SM_CAP_CVOLUME_JOIN);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (pchannels > 1) {
|
|
Packit Service |
db8eaa |
if (simple->ctls[CTL_PLAYBACK_ROUTE].elem ||
|
|
Packit Service |
db8eaa |
(simple->ctls[CTL_PLAYBACK_SWITCH].elem &&
|
|
Packit Service |
db8eaa |
simple->ctls[CTL_PLAYBACK_SWITCH].values > 1)) {
|
|
Packit Service |
db8eaa |
caps &= ~SM_CAP_PSWITCH_JOIN;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (simple->ctls[CTL_PLAYBACK_VOLUME].elem &&
|
|
Packit Service |
db8eaa |
simple->ctls[CTL_PLAYBACK_VOLUME].values > 1) {
|
|
Packit Service |
db8eaa |
caps &= ~SM_CAP_PVOLUME_JOIN;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (cchannels > 1) {
|
|
Packit Service |
db8eaa |
if (simple->ctls[CTL_CAPTURE_ROUTE].elem ||
|
|
Packit Service |
db8eaa |
(simple->ctls[CTL_CAPTURE_SWITCH].elem &&
|
|
Packit Service |
db8eaa |
simple->ctls[CTL_CAPTURE_SWITCH].values > 1) ||
|
|
Packit Service |
db8eaa |
(simple->ctls[CTL_CAPTURE_SOURCE].elem &&
|
|
Packit Service |
db8eaa |
simple->ctls[CTL_CAPTURE_SOURCE].values > 1)) {
|
|
Packit Service |
db8eaa |
caps &= ~SM_CAP_CSWITCH_JOIN;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (simple->ctls[CTL_CAPTURE_VOLUME].elem &&
|
|
Packit Service |
db8eaa |
simple->ctls[CTL_CAPTURE_VOLUME].values > 1) {
|
|
Packit Service |
db8eaa |
caps &= ~SM_CAP_CVOLUME_JOIN;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/* exceptions */
|
|
Packit Service |
db8eaa |
if ((caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH|SM_CAP_CSWITCH)) &&
|
|
Packit Service |
db8eaa |
(caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH|SM_CAP_CSWITCH)) == (caps & SM_CAP_GSWITCH)) {
|
|
Packit Service |
db8eaa |
caps &= ~(SM_CAP_GSWITCH|SM_CAP_CSWITCH_JOIN|SM_CAP_CSWITCH_EXCL);
|
|
Packit Service |
db8eaa |
caps |= SM_CAP_PSWITCH;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if ((caps & SM_CAP_GSWITCH) &&
|
|
Packit Service |
db8eaa |
(caps & (SM_CAP_PSWITCH|SM_CAP_CSWITCH)) == 0)
|
|
Packit Service |
db8eaa |
caps |= SM_CAP_PSWITCH|SM_CAP_CSWITCH;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if ((caps & SM_CAP_GVOLUME) &&
|
|
Packit Service |
db8eaa |
(caps & (SM_CAP_PVOLUME|SM_CAP_CVOLUME)) == 0)
|
|
Packit Service |
db8eaa |
caps |= SM_CAP_PVOLUME|SM_CAP_CVOLUME;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
simple->selem.caps = caps;
|
|
Packit Service |
db8eaa |
simple->str[SM_PLAY].channels = pchannels;
|
|
Packit Service |
db8eaa |
if (!simple->str[SM_PLAY].range) {
|
|
Packit Service |
db8eaa |
simple->str[SM_PLAY].min = pmin != LONG_MAX ? pmin : 0;
|
|
Packit Service |
db8eaa |
simple->str[SM_PLAY].max = pmax != LONG_MIN ? pmax : 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
simple->str[SM_CAPT].channels = cchannels;
|
|
Packit Service |
db8eaa |
if (!simple->str[SM_CAPT].range) {
|
|
Packit Service |
db8eaa |
simple->str[SM_CAPT].min = cmin != LONG_MAX ? cmin : 0;
|
|
Packit Service |
db8eaa |
simple->str[SM_CAPT].max = cmax != LONG_MIN ? cmax : 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#ifndef DOC_HIDDEN
|
|
Packit Service |
db8eaa |
static const struct suf {
|
|
Packit Service |
db8eaa |
const char *suffix;
|
|
Packit Service |
db8eaa |
selem_ctl_type_t type;
|
|
Packit Service |
db8eaa |
} suffixes[] = {
|
|
Packit Service |
db8eaa |
{" Playback Enum", CTL_PLAYBACK_ENUM},
|
|
Packit Service |
db8eaa |
{" Playback Switch", CTL_PLAYBACK_SWITCH},
|
|
Packit Service |
db8eaa |
{" Playback Route", CTL_PLAYBACK_ROUTE},
|
|
Packit Service |
db8eaa |
{" Playback Volume", CTL_PLAYBACK_VOLUME},
|
|
Packit Service |
db8eaa |
{" Capture Enum", CTL_CAPTURE_ENUM},
|
|
Packit Service |
db8eaa |
{" Capture Switch", CTL_CAPTURE_SWITCH},
|
|
Packit Service |
db8eaa |
{" Capture Route", CTL_CAPTURE_ROUTE},
|
|
Packit Service |
db8eaa |
{" Capture Volume", CTL_CAPTURE_VOLUME},
|
|
Packit Service |
db8eaa |
{" Enum", CTL_GLOBAL_ENUM},
|
|
Packit Service |
db8eaa |
{" Switch", CTL_GLOBAL_SWITCH},
|
|
Packit Service |
db8eaa |
{" Route", CTL_GLOBAL_ROUTE},
|
|
Packit Service |
db8eaa |
{" Volume", CTL_GLOBAL_VOLUME},
|
|
Packit Service |
db8eaa |
{NULL, 0}
|
|
Packit Service |
db8eaa |
};
|
|
Packit Service |
db8eaa |
#endif
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/* Return base length or 0 on failure */
|
|
Packit Service |
db8eaa |
static int base_len(const char *name, selem_ctl_type_t *type)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
const struct suf *p;
|
|
Packit Service |
db8eaa |
size_t nlen = strlen(name);
|
|
Packit Service |
db8eaa |
p = suffixes;
|
|
Packit Service |
db8eaa |
while (p->suffix) {
|
|
Packit Service |
db8eaa |
size_t slen = strlen(p->suffix);
|
|
Packit Service |
db8eaa |
size_t l;
|
|
Packit Service |
db8eaa |
if (nlen > slen) {
|
|
Packit Service |
db8eaa |
l = nlen - slen;
|
|
Packit Service |
db8eaa |
if (strncmp(name + l, p->suffix, slen) == 0 &&
|
|
Packit Service |
db8eaa |
(l < 1 || name[l-1] != '-')) { /* 3D Control - Switch */
|
|
Packit Service |
db8eaa |
*type = p->type;
|
|
Packit Service |
db8eaa |
return l;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
p++;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/* Special case - handle "Input Source" as a capture route.
|
|
Packit Service |
db8eaa |
* Note that it's *NO* capture source. A capture source is split over
|
|
Packit Service |
db8eaa |
* sub-elements, and multiple capture-sources will result in an error.
|
|
Packit Service |
db8eaa |
* That's why some drivers use "Input Source" as a workaround.
|
|
Packit Service |
db8eaa |
* Hence, this is a workaround for a workaround to get the things
|
|
Packit Service |
db8eaa |
* straight back again. Sigh.
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
if (!strcmp(name, "Input Source")) {
|
|
Packit Service |
db8eaa |
*type = CTL_CAPTURE_ROUTE;
|
|
Packit Service |
db8eaa |
return strlen(name);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (strstr(name, "3D Control")) {
|
|
Packit Service |
db8eaa |
if (strstr(name, "Depth")) {
|
|
Packit Service |
db8eaa |
*type = CTL_PLAYBACK_VOLUME;
|
|
Packit Service |
db8eaa |
return strlen(name);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/*
|
|
Packit Service |
db8eaa |
* Simple Mixer Operations
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int _snd_mixer_selem_set_volume(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, long value)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
selem_none_t *s = snd_mixer_elem_get_private(elem);
|
|
Packit Service |
db8eaa |
if (s->selem.caps & SM_CAP_GVOLUME)
|
|
Packit Service |
db8eaa |
dir = SM_PLAY;
|
|
Packit Service |
db8eaa |
if ((unsigned int) channel >= s->str[dir].channels)
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
if (value < s->str[dir].min || value > s->str[dir].max)
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
if (s->selem.caps &
|
|
Packit Service |
db8eaa |
(dir == SM_PLAY ? SM_CAP_PVOLUME_JOIN : SM_CAP_CVOLUME_JOIN))
|
|
Packit Service |
db8eaa |
channel = 0;
|
|
Packit Service |
db8eaa |
if (value != s->str[dir].vol[channel]) {
|
|
Packit Service |
db8eaa |
s->str[dir].vol[channel] = value;
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int _snd_mixer_selem_set_switch(snd_mixer_elem_t *elem, int dir, snd_mixer_selem_channel_id_t channel, int value)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
selem_none_t *s = snd_mixer_elem_get_private(elem);
|
|
Packit Service |
db8eaa |
if ((unsigned int) channel >= s->str[dir].channels)
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
if (s->selem.caps &
|
|
Packit Service |
db8eaa |
(dir == SM_PLAY ? SM_CAP_PSWITCH_JOIN : SM_CAP_CSWITCH_JOIN))
|
|
Packit Service |
db8eaa |
channel = 0;
|
|
Packit Service |
db8eaa |
if (value) {
|
|
Packit Service |
db8eaa |
if (!(s->str[dir].sw & (1 << channel))) {
|
|
Packit Service |
db8eaa |
s->str[dir].sw |= 1 << channel;
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
db8eaa |
if (s->str[dir].sw & (1 << channel)) {
|
|
Packit Service |
db8eaa |
s->str[dir].sw &= ~(1 << channel);
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int is_ops(snd_mixer_elem_t *elem, int dir, int cmd, int val)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
selem_none_t *s = snd_mixer_elem_get_private(elem);
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
switch (cmd) {
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
case SM_OPS_IS_ACTIVE: {
|
|
Packit Service |
db8eaa |
selem_ctl_type_t ctl;
|
|
Packit Service |
db8eaa |
for (ctl = CTL_SINGLE; ctl <= CTL_LAST; ctl++)
|
|
Packit Service |
db8eaa |
if (s->ctls[ctl].elem != NULL && s->ctls[ctl].inactive)
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
case SM_OPS_IS_MONO:
|
|
Packit Service |
db8eaa |
return s->str[dir].channels == 1;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
case SM_OPS_IS_CHANNEL:
|
|
Packit Service |
db8eaa |
return (unsigned int) val < s->str[dir].channels;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
case SM_OPS_IS_ENUMERATED:
|
|
Packit Service |
db8eaa |
if (val == 1) {
|
|
Packit Service |
db8eaa |
if (dir == SM_PLAY && (s->selem.caps & SM_CAP_PENUM) && !(s->selem.caps & SM_CAP_CENUM) )
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
if (dir == SM_CAPT && (s->selem.caps & SM_CAP_CENUM) && !(s->selem.caps & SM_CAP_PENUM) )
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM) )
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
case SM_OPS_IS_ENUMCNT:
|
|
Packit Service |
db8eaa |
/* Both */
|
|
Packit Service |
db8eaa |
if ( (s->selem.caps & (SM_CAP_CENUM | SM_CAP_PENUM)) == (SM_CAP_CENUM | SM_CAP_PENUM) ) {
|
|
Packit Service |
db8eaa |
if (! s->ctls[CTL_GLOBAL_ENUM].elem)
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
return s->ctls[CTL_GLOBAL_ENUM].max;
|
|
Packit Service |
db8eaa |
/* Only Playback */
|
|
Packit Service |
db8eaa |
} else if (s->selem.caps & SM_CAP_PENUM ) {
|
|
Packit Service |
db8eaa |
if (! s->ctls[CTL_PLAYBACK_ENUM].elem)
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
return s->ctls[CTL_PLAYBACK_ENUM].max;
|
|
Packit Service |
db8eaa |
/* Only Capture */
|
|
Packit Service |
db8eaa |
} else if (s->selem.caps & SM_CAP_CENUM ) {
|
|
Packit Service |
db8eaa |
if (! s->ctls[CTL_CAPTURE_ENUM].elem)
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
return s->ctls[CTL_CAPTURE_ENUM].max;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int get_range_ops(snd_mixer_elem_t *elem, int dir,
|
|
Packit Service |
db8eaa |
long *min, long *max)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
selem_none_t *s = snd_mixer_elem_get_private(elem);
|
|
Packit Service |
db8eaa |
*min = s->str[dir].min;
|
|
Packit Service |
db8eaa |
*max = s->str[dir].max;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int set_range_ops(snd_mixer_elem_t *elem, int dir,
|
|
Packit Service |
db8eaa |
long min, long max)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
selem_none_t *s = snd_mixer_elem_get_private(elem);
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
s->str[dir].range = 1;
|
|
Packit Service |
db8eaa |
s->str[dir].min = min;
|
|
Packit Service |
db8eaa |
s->str[dir].max = max;
|
|
Packit Service |
db8eaa |
if ((err = selem_read(elem)) < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int get_volume_ops(snd_mixer_elem_t *elem, int dir,
|
|
Packit Service |
db8eaa |
snd_mixer_selem_channel_id_t channel, long *value)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
selem_none_t *s = snd_mixer_elem_get_private(elem);
|
|
Packit Service |
db8eaa |
if (s->selem.caps & SM_CAP_GVOLUME)
|
|
Packit Service |
db8eaa |
dir = SM_PLAY;
|
|
Packit Service |
db8eaa |
if ((unsigned int) channel >= s->str[dir].channels)
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
*value = s->str[dir].vol[channel];
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int init_db_range(snd_hctl_elem_t *ctl, struct selem_str *rec);
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int convert_to_dB(snd_hctl_elem_t *ctl, struct selem_str *rec,
|
|
Packit Service |
db8eaa |
long volume, long *db_gain)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
if (init_db_range(ctl, rec) < 0)
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
return snd_tlv_convert_to_dB(rec->db_info, rec->min, rec->max,
|
|
Packit Service |
db8eaa |
volume, db_gain);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/* initialize dB range information, reading TLV via hcontrol
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
static int init_db_range(snd_hctl_elem_t *ctl, struct selem_str *rec)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_elem_info_t info = {0};
|
|
Packit Service |
db8eaa |
unsigned int *tlv = NULL;
|
|
Packit Service |
db8eaa |
const unsigned int tlv_size = 4096;
|
|
Packit Service |
db8eaa |
unsigned int *dbrec;
|
|
Packit Service |
db8eaa |
int db_size;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (rec->db_init_error)
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
if (rec->db_initialized)
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (snd_hctl_elem_info(ctl, &info) < 0)
|
|
Packit Service |
db8eaa |
goto error;
|
|
Packit Service |
db8eaa |
if (!snd_ctl_elem_info_is_tlv_readable(&info))
|
|
Packit Service |
db8eaa |
goto error;
|
|
Packit Service |
db8eaa |
tlv = malloc(tlv_size);
|
|
Packit Service |
db8eaa |
if (!tlv)
|
|
Packit Service |
db8eaa |
return -ENOMEM;
|
|
Packit Service |
db8eaa |
if (snd_hctl_elem_tlv_read(ctl, tlv, tlv_size) < 0)
|
|
Packit Service |
db8eaa |
goto error;
|
|
Packit Service |
db8eaa |
db_size = snd_tlv_parse_dB_info(tlv, tlv_size, &dbrec);
|
|
Packit Service |
db8eaa |
if (db_size < 0)
|
|
Packit Service |
db8eaa |
goto error;
|
|
Packit Service |
db8eaa |
rec->db_info = malloc(db_size);
|
|
Packit Service |
db8eaa |
if (!rec->db_info)
|
|
Packit Service |
db8eaa |
goto error;
|
|
Packit Service |
db8eaa |
memcpy(rec->db_info, dbrec, db_size);
|
|
Packit Service |
db8eaa |
free(tlv);
|
|
Packit Service |
db8eaa |
rec->db_initialized = 1;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
error:
|
|
Packit Service |
db8eaa |
free(tlv);
|
|
Packit Service |
db8eaa |
rec->db_init_error = 1;
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/* get selem_ctl for TLV access */
|
|
Packit Service |
db8eaa |
static selem_ctl_t *get_selem_ctl(selem_none_t *s, int dir)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
selem_ctl_t *c;
|
|
Packit Service |
db8eaa |
if (dir == SM_PLAY)
|
|
Packit Service |
db8eaa |
c = &s->ctls[CTL_PLAYBACK_VOLUME];
|
|
Packit Service |
db8eaa |
else if (dir == SM_CAPT)
|
|
Packit Service |
db8eaa |
c = &s->ctls[CTL_CAPTURE_VOLUME];
|
|
Packit Service |
db8eaa |
else
|
|
Packit Service |
db8eaa |
return NULL;
|
|
Packit Service |
db8eaa |
if (! c->elem) {
|
|
Packit Service |
db8eaa |
c = &s->ctls[CTL_GLOBAL_VOLUME];
|
|
Packit Service |
db8eaa |
if (! c->elem)
|
|
Packit Service |
db8eaa |
return NULL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (c->type != SND_CTL_ELEM_TYPE_INTEGER)
|
|
Packit Service |
db8eaa |
return NULL;
|
|
Packit Service |
db8eaa |
return c;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int get_dB_range(snd_hctl_elem_t *ctl, struct selem_str *rec,
|
|
Packit Service |
db8eaa |
long *min, long *max)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
if (init_db_range(ctl, rec) < 0)
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
return snd_tlv_get_dB_range(rec->db_info, rec->min, rec->max, min, max);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int get_dB_range_ops(snd_mixer_elem_t *elem, int dir,
|
|
Packit Service |
db8eaa |
long *min, long *max)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
selem_none_t *s = snd_mixer_elem_get_private(elem);
|
|
Packit Service |
db8eaa |
selem_ctl_t *c;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (s->selem.caps & SM_CAP_GVOLUME)
|
|
Packit Service |
db8eaa |
dir = SM_PLAY;
|
|
Packit Service |
db8eaa |
c = get_selem_ctl(s, dir);
|
|
Packit Service |
db8eaa |
if (! c)
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
return get_dB_range(c->elem, &s->str[dir], min, max);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int convert_from_dB(snd_hctl_elem_t *ctl, struct selem_str *rec,
|
|
Packit Service |
db8eaa |
long db_gain, long *value, int xdir)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
if (init_db_range(ctl, rec) < 0)
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
return snd_tlv_convert_from_dB(rec->db_info, rec->min, rec->max,
|
|
Packit Service |
db8eaa |
db_gain, value, xdir);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int ask_vol_dB_ops(snd_mixer_elem_t *elem,
|
|
Packit Service |
db8eaa |
int dir,
|
|
Packit Service |
db8eaa |
long value,
|
|
Packit Service |
db8eaa |
long *dBvalue)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
selem_none_t *s = snd_mixer_elem_get_private(elem);
|
|
Packit Service |
db8eaa |
selem_ctl_t *c;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
c = get_selem_ctl(s, dir);
|
|
Packit Service |
db8eaa |
if (! c)
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
int res = convert_to_dB(c->elem, &s->str[dir], value, dBvalue);
|
|
Packit Service |
db8eaa |
return res;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int get_dB_ops(snd_mixer_elem_t *elem,
|
|
Packit Service |
db8eaa |
int dir,
|
|
Packit Service |
db8eaa |
snd_mixer_selem_channel_id_t channel,
|
|
Packit Service |
db8eaa |
long *value)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
selem_none_t *s = snd_mixer_elem_get_private(elem);
|
|
Packit Service |
db8eaa |
selem_ctl_t *c;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
long volume, db_gain;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (s->selem.caps & SM_CAP_GVOLUME)
|
|
Packit Service |
db8eaa |
dir = SM_PLAY;
|
|
Packit Service |
db8eaa |
c = get_selem_ctl(s, dir);
|
|
Packit Service |
db8eaa |
if (! c)
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
if ((err = get_volume_ops(elem, dir, channel, &volume)) < 0)
|
|
Packit Service |
db8eaa |
goto _err;
|
|
Packit Service |
db8eaa |
if ((err = convert_to_dB(c->elem, &s->str[dir], volume, &db_gain)) < 0)
|
|
Packit Service |
db8eaa |
goto _err;
|
|
Packit Service |
db8eaa |
err = 0;
|
|
Packit Service |
db8eaa |
*value = db_gain;
|
|
Packit Service |
db8eaa |
_err:
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int get_switch_ops(snd_mixer_elem_t *elem, int dir,
|
|
Packit Service |
db8eaa |
snd_mixer_selem_channel_id_t channel, int *value)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
selem_none_t *s = snd_mixer_elem_get_private(elem);
|
|
Packit Service |
db8eaa |
if (s->selem.caps & SM_CAP_GSWITCH)
|
|
Packit Service |
db8eaa |
dir = SM_PLAY;
|
|
Packit Service |
db8eaa |
if ((unsigned int) channel >= s->str[dir].channels)
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
*value = !!(s->str[dir].sw & (1 << channel));
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int set_volume_ops(snd_mixer_elem_t *elem, int dir,
|
|
Packit Service |
db8eaa |
snd_mixer_selem_channel_id_t channel, long value)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
int changed;
|
|
Packit Service |
db8eaa |
changed = _snd_mixer_selem_set_volume(elem, dir, channel, value);
|
|
Packit Service |
db8eaa |
if (changed < 0)
|
|
Packit Service |
db8eaa |
return changed;
|
|
Packit Service |
db8eaa |
if (changed)
|
|
Packit Service |
db8eaa |
return selem_write(elem);
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int ask_dB_vol_ops(snd_mixer_elem_t *elem, int dir,
|
|
Packit Service |
db8eaa |
long dbValue, long *value, int xdir)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
selem_none_t *s = snd_mixer_elem_get_private(elem);
|
|
Packit Service |
db8eaa |
selem_ctl_t *c;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (s->selem.caps & SM_CAP_GVOLUME)
|
|
Packit Service |
db8eaa |
dir = SM_PLAY;
|
|
Packit Service |
db8eaa |
c = get_selem_ctl(s, dir);
|
|
Packit Service |
db8eaa |
if (! c)
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
return convert_from_dB(c->elem, &s->str[dir], dbValue, value, xdir);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int set_dB_ops(snd_mixer_elem_t *elem, int dir,
|
|
Packit Service |
db8eaa |
snd_mixer_selem_channel_id_t channel,
|
|
Packit Service |
db8eaa |
long db_gain, int xdir)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
selem_none_t *s = snd_mixer_elem_get_private(elem);
|
|
Packit Service |
db8eaa |
selem_ctl_t *c;
|
|
Packit Service |
db8eaa |
long value;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (s->selem.caps & SM_CAP_GVOLUME)
|
|
Packit Service |
db8eaa |
dir = SM_PLAY;
|
|
Packit Service |
db8eaa |
c = get_selem_ctl(s, dir);
|
|
Packit Service |
db8eaa |
if (! c)
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
err = convert_from_dB(c->elem, &s->str[dir], db_gain, &value, xdir);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
return set_volume_ops(elem, dir, channel, value);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int set_switch_ops(snd_mixer_elem_t *elem, int dir,
|
|
Packit Service |
db8eaa |
snd_mixer_selem_channel_id_t channel, int value)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
int changed;
|
|
Packit Service |
db8eaa |
selem_none_t *s = snd_mixer_elem_get_private(elem);
|
|
Packit Service |
db8eaa |
if (s->selem.caps & SM_CAP_GSWITCH)
|
|
Packit Service |
db8eaa |
dir = SM_PLAY;
|
|
Packit Service |
db8eaa |
if (dir == SM_PLAY) {
|
|
Packit Service |
db8eaa |
if (! (s->selem.caps & (SM_CAP_GSWITCH|SM_CAP_PSWITCH)))
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
db8eaa |
if (! (s->selem.caps & (SM_CAP_GSWITCH|SM_CAP_CSWITCH)))
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
changed = _snd_mixer_selem_set_switch(elem, dir, channel, value);
|
|
Packit Service |
db8eaa |
if (changed < 0)
|
|
Packit Service |
db8eaa |
return changed;
|
|
Packit Service |
db8eaa |
if (changed)
|
|
Packit Service |
db8eaa |
return selem_write(elem);
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int enum_item_name_ops(snd_mixer_elem_t *elem,
|
|
Packit Service |
db8eaa |
unsigned int item,
|
|
Packit Service |
db8eaa |
size_t maxlen, char *buf)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
selem_none_t *s = snd_mixer_elem_get_private(elem);
|
|
Packit Service |
db8eaa |
snd_ctl_elem_info_t info = {0};
|
|
Packit Service |
db8eaa |
snd_hctl_elem_t *helem;
|
|
Packit Service |
db8eaa |
int type;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
type = CTL_GLOBAL_ENUM;
|
|
Packit Service |
db8eaa |
helem = s->ctls[type].elem;
|
|
Packit Service |
db8eaa |
if (!helem) {
|
|
Packit Service |
db8eaa |
type = CTL_PLAYBACK_ENUM;
|
|
Packit Service |
db8eaa |
helem = s->ctls[type].elem;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (!helem) {
|
|
Packit Service |
db8eaa |
type = CTL_CAPTURE_ENUM;
|
|
Packit Service |
db8eaa |
helem = s->ctls[type].elem;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
assert(helem);
|
|
Packit Service |
db8eaa |
if (item >= (unsigned int)s->ctls[type].max)
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
snd_hctl_elem_info(helem, &info;;
|
|
Packit Service |
db8eaa |
snd_ctl_elem_info_set_item(&info, item);
|
|
Packit Service |
db8eaa |
snd_hctl_elem_info(helem, &info;;
|
|
Packit Service |
db8eaa |
strncpy(buf, snd_ctl_elem_info_get_item_name(&info), maxlen);
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int get_enum_item_ops(snd_mixer_elem_t *elem,
|
|
Packit Service |
db8eaa |
snd_mixer_selem_channel_id_t channel,
|
|
Packit Service |
db8eaa |
unsigned int *itemp)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
selem_none_t *s = snd_mixer_elem_get_private(elem);
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_t ctl = {0};
|
|
Packit Service |
db8eaa |
snd_hctl_elem_t *helem;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if ((unsigned int) channel >= s->str[0].channels)
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
helem = s->ctls[CTL_GLOBAL_ENUM].elem;
|
|
Packit Service |
db8eaa |
if (!helem) helem = s->ctls[CTL_PLAYBACK_ENUM].elem;
|
|
Packit Service |
db8eaa |
if (!helem) helem = s->ctls[CTL_CAPTURE_ENUM].elem;
|
|
Packit Service |
db8eaa |
assert(helem);
|
|
Packit Service |
db8eaa |
err = snd_hctl_elem_read(helem, &ctl;;
|
|
Packit Service |
db8eaa |
if (! err)
|
|
Packit Service |
db8eaa |
*itemp = snd_ctl_elem_value_get_enumerated(&ctl, channel);
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int set_enum_item_ops(snd_mixer_elem_t *elem,
|
|
Packit Service |
db8eaa |
snd_mixer_selem_channel_id_t channel,
|
|
Packit Service |
db8eaa |
unsigned int item)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
selem_none_t *s = snd_mixer_elem_get_private(elem);
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_t ctl = {0};
|
|
Packit Service |
db8eaa |
snd_hctl_elem_t *helem;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
int type;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if ((unsigned int) channel >= s->str[0].channels) {
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
type = CTL_GLOBAL_ENUM;
|
|
Packit Service |
db8eaa |
helem = s->ctls[type].elem;
|
|
Packit Service |
db8eaa |
if (!helem) {
|
|
Packit Service |
db8eaa |
type = CTL_PLAYBACK_ENUM;
|
|
Packit Service |
db8eaa |
helem = s->ctls[type].elem;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (!helem) {
|
|
Packit Service |
db8eaa |
type = CTL_CAPTURE_ENUM;
|
|
Packit Service |
db8eaa |
helem = s->ctls[type].elem;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
assert(helem);
|
|
Packit Service |
db8eaa |
if (item >= (unsigned int)s->ctls[type].max) {
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
err = snd_hctl_elem_read(helem, &ctl;;
|
|
Packit Service |
db8eaa |
if (err < 0) {
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
snd_ctl_elem_value_set_enumerated(&ctl, channel, item);
|
|
Packit Service |
db8eaa |
return snd_hctl_elem_write(helem, &ctl;;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static struct sm_elem_ops simple_none_ops = {
|
|
Packit Service |
db8eaa |
.is = is_ops,
|
|
Packit Service |
db8eaa |
.get_range = get_range_ops,
|
|
Packit Service |
db8eaa |
.get_dB_range = get_dB_range_ops,
|
|
Packit Service |
db8eaa |
.set_range = set_range_ops,
|
|
Packit Service |
db8eaa |
.ask_vol_dB = ask_vol_dB_ops,
|
|
Packit Service |
db8eaa |
.ask_dB_vol = ask_dB_vol_ops,
|
|
Packit Service |
db8eaa |
.get_volume = get_volume_ops,
|
|
Packit Service |
db8eaa |
.get_dB = get_dB_ops,
|
|
Packit Service |
db8eaa |
.set_volume = set_volume_ops,
|
|
Packit Service |
db8eaa |
.set_dB = set_dB_ops,
|
|
Packit Service |
db8eaa |
.get_switch = get_switch_ops,
|
|
Packit Service |
db8eaa |
.set_switch = set_switch_ops,
|
|
Packit Service |
db8eaa |
.enum_item_name = enum_item_name_ops,
|
|
Packit Service |
db8eaa |
.get_enum_item = get_enum_item_ops,
|
|
Packit Service |
db8eaa |
.set_enum_item = set_enum_item_ops
|
|
Packit Service |
db8eaa |
};
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int simple_add1(snd_mixer_class_t *class, const char *name,
|
|
Packit Service |
db8eaa |
snd_hctl_elem_t *helem, selem_ctl_type_t type,
|
|
Packit Service |
db8eaa |
unsigned int value)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_mixer_elem_t *melem;
|
|
Packit Service |
db8eaa |
snd_mixer_selem_id_t *id;
|
|
Packit Service |
db8eaa |
int new = 0;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
snd_ctl_elem_info_t info = {0};
|
|
Packit Service |
db8eaa |
selem_none_t *simple;
|
|
Packit Service |
db8eaa |
const char *name1;
|
|
Packit Service |
db8eaa |
snd_ctl_elem_type_t ctype;
|
|
Packit Service |
db8eaa |
unsigned long values;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
err = snd_hctl_elem_info(helem, &info;;
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
ctype = snd_ctl_elem_info_get_type(&info;;
|
|
Packit Service |
db8eaa |
values = snd_ctl_elem_info_get_count(&info;;
|
|
Packit Service |
db8eaa |
switch (type) {
|
|
Packit Service |
db8eaa |
case CTL_SINGLE:
|
|
Packit Service |
db8eaa |
if (ctype == SND_CTL_ELEM_TYPE_ENUMERATED)
|
|
Packit Service |
db8eaa |
type = CTL_GLOBAL_ENUM;
|
|
Packit Service |
db8eaa |
else if (ctype != SND_CTL_ELEM_TYPE_BOOLEAN &&
|
|
Packit Service |
db8eaa |
ctype != SND_CTL_ELEM_TYPE_INTEGER)
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case CTL_GLOBAL_ROUTE:
|
|
Packit Service |
db8eaa |
case CTL_PLAYBACK_ROUTE:
|
|
Packit Service |
db8eaa |
case CTL_CAPTURE_ROUTE:
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
unsigned int n;
|
|
Packit Service |
db8eaa |
if (ctype == SND_CTL_ELEM_TYPE_ENUMERATED) {
|
|
Packit Service |
db8eaa |
if (type == CTL_PLAYBACK_ROUTE)
|
|
Packit Service |
db8eaa |
type = CTL_PLAYBACK_ENUM;
|
|
Packit Service |
db8eaa |
else if (type == CTL_CAPTURE_ROUTE)
|
|
Packit Service |
db8eaa |
type = CTL_CAPTURE_ENUM;
|
|
Packit Service |
db8eaa |
else
|
|
Packit Service |
db8eaa |
type = CTL_GLOBAL_ENUM;
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (ctype != SND_CTL_ELEM_TYPE_BOOLEAN)
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
#ifdef HAVE_SOFT_FLOAT
|
|
Packit Service |
db8eaa |
/* up to 256 channels */
|
|
Packit Service |
db8eaa |
for (n = 1; n < 256; n++)
|
|
Packit Service |
db8eaa |
if (n * n == values)
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
#else
|
|
Packit Service |
db8eaa |
n = sqrt((double)values);
|
|
Packit Service |
db8eaa |
#endif
|
|
Packit Service |
db8eaa |
if (n * n != values)
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
values = n;
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
case CTL_GLOBAL_SWITCH:
|
|
Packit Service |
db8eaa |
case CTL_PLAYBACK_SWITCH:
|
|
Packit Service |
db8eaa |
case CTL_CAPTURE_SWITCH:
|
|
Packit Service |
db8eaa |
if (ctype == SND_CTL_ELEM_TYPE_ENUMERATED) {
|
|
Packit Service |
db8eaa |
if (type == CTL_PLAYBACK_SWITCH)
|
|
Packit Service |
db8eaa |
type = CTL_PLAYBACK_ENUM;
|
|
Packit Service |
db8eaa |
else if (type == CTL_CAPTURE_SWITCH)
|
|
Packit Service |
db8eaa |
type = CTL_CAPTURE_ENUM;
|
|
Packit Service |
db8eaa |
else
|
|
Packit Service |
db8eaa |
type = CTL_GLOBAL_ENUM;
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (ctype != SND_CTL_ELEM_TYPE_BOOLEAN)
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case CTL_GLOBAL_VOLUME:
|
|
Packit Service |
db8eaa |
case CTL_PLAYBACK_VOLUME:
|
|
Packit Service |
db8eaa |
case CTL_CAPTURE_VOLUME:
|
|
Packit Service |
db8eaa |
if (ctype == SND_CTL_ELEM_TYPE_ENUMERATED) {
|
|
Packit Service |
db8eaa |
if (type == CTL_PLAYBACK_VOLUME)
|
|
Packit Service |
db8eaa |
type = CTL_PLAYBACK_ENUM;
|
|
Packit Service |
db8eaa |
else if (type == CTL_CAPTURE_VOLUME)
|
|
Packit Service |
db8eaa |
type = CTL_CAPTURE_ENUM;
|
|
Packit Service |
db8eaa |
else
|
|
Packit Service |
db8eaa |
type = CTL_GLOBAL_ENUM;
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (ctype != SND_CTL_ELEM_TYPE_INTEGER)
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case CTL_CAPTURE_SOURCE:
|
|
Packit Service |
db8eaa |
if (ctype != SND_CTL_ELEM_TYPE_ENUMERATED)
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case CTL_GLOBAL_ENUM:
|
|
Packit Service |
db8eaa |
case CTL_PLAYBACK_ENUM:
|
|
Packit Service |
db8eaa |
case CTL_CAPTURE_ENUM:
|
|
Packit Service |
db8eaa |
if (ctype != SND_CTL_ELEM_TYPE_ENUMERATED)
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
default:
|
|
Packit Service |
db8eaa |
assert(0);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
name1 = get_short_name(name);
|
|
Packit Service |
db8eaa |
if (snd_mixer_selem_id_malloc(&id))
|
|
Packit Service |
db8eaa |
return -ENOMEM;
|
|
Packit Service |
db8eaa |
snd_mixer_selem_id_set_name(id, name1);
|
|
Packit Service |
db8eaa |
snd_mixer_selem_id_set_index(id, snd_hctl_elem_get_index(helem));
|
|
Packit Service |
db8eaa |
melem = snd_mixer_find_selem(snd_mixer_class_get_mixer(class), id);
|
|
Packit Service |
db8eaa |
if (!melem) {
|
|
Packit Service |
db8eaa |
simple = calloc(1, sizeof(*simple));
|
|
Packit Service |
db8eaa |
if (!simple) {
|
|
Packit Service |
db8eaa |
snd_mixer_selem_id_free(id);
|
|
Packit Service |
db8eaa |
return -ENOMEM;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
simple->selem.id = id;
|
|
Packit Service |
db8eaa |
simple->selem.ops = &simple_none_ops;
|
|
Packit Service |
db8eaa |
err = snd_mixer_elem_new(&melem, SND_MIXER_ELEM_SIMPLE,
|
|
Packit Service |
db8eaa |
get_compare_weight(
|
|
Packit Service |
db8eaa |
snd_mixer_selem_id_get_name(simple->selem.id),
|
|
Packit Service |
db8eaa |
snd_mixer_selem_id_get_index(simple->selem.id)),
|
|
Packit Service |
db8eaa |
simple, selem_free);
|
|
Packit Service |
db8eaa |
if (err < 0) {
|
|
Packit Service |
db8eaa |
snd_mixer_selem_id_free(id);
|
|
Packit Service |
db8eaa |
free(simple);
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
new = 1;
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
db8eaa |
simple = snd_mixer_elem_get_private(melem);
|
|
Packit Service |
db8eaa |
snd_mixer_selem_id_free(id);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (simple->ctls[type].elem) {
|
|
Packit Service |
db8eaa |
SNDERR("helem (%s,'%s',%u,%u,%u) appears twice or more",
|
|
Packit Service |
db8eaa |
snd_ctl_elem_iface_name(
|
|
Packit Service |
db8eaa |
snd_hctl_elem_get_interface(helem)),
|
|
Packit Service |
db8eaa |
snd_hctl_elem_get_name(helem),
|
|
Packit Service |
db8eaa |
snd_hctl_elem_get_index(helem),
|
|
Packit Service |
db8eaa |
snd_hctl_elem_get_device(helem),
|
|
Packit Service |
db8eaa |
snd_hctl_elem_get_subdevice(helem));
|
|
Packit Service |
db8eaa |
err = -EINVAL;
|
|
Packit Service |
db8eaa |
goto __error;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
simple->ctls[type].elem = helem;
|
|
Packit Service |
db8eaa |
simple->ctls[type].type = snd_ctl_elem_info_get_type(&info;;
|
|
Packit Service |
db8eaa |
simple->ctls[type].inactive = snd_ctl_elem_info_is_inactive(&info;;
|
|
Packit Service |
db8eaa |
simple->ctls[type].values = values;
|
|
Packit Service |
db8eaa |
if ( (type == CTL_GLOBAL_ENUM) ||
|
|
Packit Service |
db8eaa |
(type == CTL_PLAYBACK_ENUM) ||
|
|
Packit Service |
db8eaa |
(type == CTL_CAPTURE_ENUM) ) {
|
|
Packit Service |
db8eaa |
simple->ctls[type].min = 0;
|
|
Packit Service |
db8eaa |
simple->ctls[type].max = snd_ctl_elem_info_get_items(&info;;
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
db8eaa |
if (ctype == SND_CTL_ELEM_TYPE_INTEGER) {
|
|
Packit Service |
db8eaa |
simple->ctls[type].min =
|
|
Packit Service |
db8eaa |
snd_ctl_elem_info_get_min(&info;;
|
|
Packit Service |
db8eaa |
simple->ctls[type].max =
|
|
Packit Service |
db8eaa |
snd_ctl_elem_info_get_max(&info;;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
switch (type) {
|
|
Packit Service |
db8eaa |
case CTL_CAPTURE_SOURCE:
|
|
Packit Service |
db8eaa |
simple->capture_item = value;
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
default:
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
err = snd_mixer_elem_attach(melem, helem);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
goto __error;
|
|
Packit Service |
db8eaa |
err = simple_update(melem);
|
|
Packit Service |
db8eaa |
if (err < 0) {
|
|
Packit Service |
db8eaa |
if (new)
|
|
Packit Service |
db8eaa |
goto __error;
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (new)
|
|
Packit Service |
db8eaa |
err = snd_mixer_elem_add(melem, class);
|
|
Packit Service |
db8eaa |
else
|
|
Packit Service |
db8eaa |
err = snd_mixer_elem_info(melem);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
err = selem_read(melem);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
if (err)
|
|
Packit Service |
db8eaa |
err = snd_mixer_elem_value(melem);
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
__error:
|
|
Packit Service |
db8eaa |
if (new)
|
|
Packit Service |
db8eaa |
snd_mixer_elem_free(melem);
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int simple_event_add(snd_mixer_class_t *class, snd_hctl_elem_t *helem)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
const char *name = snd_hctl_elem_get_name(helem);
|
|
Packit Service |
db8eaa |
size_t len;
|
|
Packit Service |
db8eaa |
selem_ctl_type_t type = CTL_SINGLE; /* to shut up warning */
|
|
Packit Service |
db8eaa |
if (snd_hctl_elem_get_interface(helem) != SND_CTL_ELEM_IFACE_MIXER)
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
if (strcmp(name, "Capture Source") == 0) {
|
|
Packit Service |
db8eaa |
snd_ctl_elem_info_t info = {0};
|
|
Packit Service |
db8eaa |
unsigned int k, items;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
err = snd_hctl_elem_info(helem, &info;;
|
|
Packit Service |
db8eaa |
assert(err >= 0);
|
|
Packit Service |
db8eaa |
if (snd_ctl_elem_info_get_type(&info) !=
|
|
Packit Service |
db8eaa |
SND_CTL_ELEM_TYPE_ENUMERATED)
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
items = snd_ctl_elem_info_get_items(&info;;
|
|
Packit Service |
db8eaa |
for (k = 0; k < items; ++k) {
|
|
Packit Service |
db8eaa |
const char *n;
|
|
Packit Service |
db8eaa |
snd_ctl_elem_info_set_item(&info, k);
|
|
Packit Service |
db8eaa |
err = snd_hctl_elem_info(helem, &info;;
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
n = snd_ctl_elem_info_get_item_name(&info;;
|
|
Packit Service |
db8eaa |
err = simple_add1(class, n, helem, CTL_CAPTURE_SOURCE,
|
|
Packit Service |
db8eaa |
k);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
len = base_len(name, &type);
|
|
Packit Service |
db8eaa |
if (len == 0) {
|
|
Packit Service |
db8eaa |
return simple_add1(class, name, helem, CTL_SINGLE, 0);
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
db8eaa |
char ename[128];
|
|
Packit Service |
db8eaa |
if (len >= sizeof(ename))
|
|
Packit Service |
db8eaa |
len = sizeof(ename) - 1;
|
|
Packit Service |
db8eaa |
memcpy(ename, name, len);
|
|
Packit Service |
db8eaa |
ename[len] = 0;
|
|
Packit Service |
db8eaa |
/* exception: Capture Volume and Capture Switch */
|
|
Packit Service |
db8eaa |
if (type == CTL_GLOBAL_VOLUME && !strcmp(ename, "Capture"))
|
|
Packit Service |
db8eaa |
type = CTL_CAPTURE_VOLUME;
|
|
Packit Service |
db8eaa |
else if (type == CTL_GLOBAL_SWITCH && !strcmp(ename, "Capture"))
|
|
Packit Service |
db8eaa |
type = CTL_CAPTURE_SWITCH;
|
|
Packit Service |
db8eaa |
return simple_add1(class, ename, helem, type, 0);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int simple_event_remove(snd_hctl_elem_t *helem,
|
|
Packit Service |
db8eaa |
snd_mixer_elem_t *melem)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
selem_none_t *simple = snd_mixer_elem_get_private(melem);
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
int k;
|
|
Packit Service |
db8eaa |
for (k = 0; k <= CTL_LAST; k++) {
|
|
Packit Service |
db8eaa |
if (simple->ctls[k].elem == helem)
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
assert(k <= CTL_LAST);
|
|
Packit Service |
db8eaa |
simple->ctls[k].elem = NULL;
|
|
Packit Service |
db8eaa |
err = snd_mixer_elem_detach(melem, helem);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
if (snd_mixer_elem_empty(melem))
|
|
Packit Service |
db8eaa |
return snd_mixer_elem_remove(melem);
|
|
Packit Service |
db8eaa |
err = simple_update(melem);
|
|
Packit Service |
db8eaa |
return snd_mixer_elem_info(melem);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int simple_event(snd_mixer_class_t *class, unsigned int mask,
|
|
Packit Service |
db8eaa |
snd_hctl_elem_t *helem, snd_mixer_elem_t *melem)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
if (mask == SND_CTL_EVENT_MASK_REMOVE)
|
|
Packit Service |
db8eaa |
return simple_event_remove(helem, melem);
|
|
Packit Service |
db8eaa |
if (mask & SND_CTL_EVENT_MASK_ADD) {
|
|
Packit Service |
db8eaa |
err = simple_event_add(class, helem);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (mask & SND_CTL_EVENT_MASK_INFO) {
|
|
Packit Service |
db8eaa |
err = simple_event_remove(helem, melem);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
err = simple_event_add(class, helem);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (mask & SND_CTL_EVENT_MASK_VALUE) {
|
|
Packit Service |
db8eaa |
err = selem_read(melem);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
if (err) {
|
|
Packit Service |
db8eaa |
err = snd_mixer_elem_value(melem);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief Register mixer simple element class - none abstraction
|
|
Packit Service |
db8eaa |
* \param mixer Mixer handle
|
|
Packit Service |
db8eaa |
* \param options Options container
|
|
Packit Service |
db8eaa |
* \param classp Pointer to returned mixer simple element class handle (or NULL)
|
|
Packit Service |
db8eaa |
* \return 0 on success otherwise a negative error code
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
int snd_mixer_simple_none_register(snd_mixer_t *mixer,
|
|
Packit Service |
db8eaa |
struct snd_mixer_selem_regopt *options ATTRIBUTE_UNUSED,
|
|
Packit Service |
db8eaa |
snd_mixer_class_t **classp)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_mixer_class_t *class;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (snd_mixer_class_malloc(&class))
|
|
Packit Service |
db8eaa |
return -ENOMEM;
|
|
Packit Service |
db8eaa |
snd_mixer_class_set_event(class, simple_event);
|
|
Packit Service |
db8eaa |
snd_mixer_class_set_compare(class, snd_mixer_selem_compare);
|
|
Packit Service |
db8eaa |
err = snd_mixer_class_register(class, mixer);
|
|
Packit Service |
db8eaa |
if (err < 0) {
|
|
Packit Service |
db8eaa |
free(class);
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
if (classp)
|
|
Packit Service |
db8eaa |
*classp = class;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|