mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-29 05:40:25 -04:00
ucm: add LibraryConfig support
This commit allows to define private alsa-lib's configuration. When
the configuration is present, the device values ("PlaybackCTL",
"CaptureCTL", "PlaybackMixer", "CaptureMixer", "CapturePCM")
are prefixed with '_ucmHEXA.' string where HEXA is replaced by the
unique hexadecimal number identifying the opened ucm manager handle.
Syntax 4
LibraryConfig.a_label.SubstiConfig {
# substituted library configuration like:
usr_share_dir "${ConfLibDir}"
}
LibraryConfig.b_label.Config {
# non-substituted library configuration like:
usr_share_dir "/usr/share/alsa"
}
The File counterparts:
LibraryConfig.c_label.SubstiFile "/some/path"
LibraryConfig.d_label.File "/some/path"
Note that for files the contents is substituted on the request,
but the file name is always substituted (useful for ${ConfDir} etc.).
The private configuration is not saved or preserved. It's life time
belongs to the opened ucm manager handle.
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
parent
3e0140088c
commit
8f5779eb3f
11 changed files with 400 additions and 36 deletions
|
|
@ -374,4 +374,11 @@ int _snd_config_load_with_include(snd_config_t *config, snd_input_t *in,
|
|||
void *INTERNAL(snd_dlopen)(const char *name, int mode, char *errbuf, size_t errbuflen);
|
||||
#endif
|
||||
|
||||
const char *uc_mgr_alibcfg_by_device(snd_config_t **config, const char *name);
|
||||
|
||||
static inline int _snd_is_ucm_device(const char *name)
|
||||
{
|
||||
return name && name[0] == '_' && name[1] == 'u' && name[2] == 'c' && name[3] == 'm';
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -257,6 +257,7 @@ int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr,
|
|||
* - NULL - return current card
|
||||
* - _verb - return current verb
|
||||
* - _file - return configuration file loaded for current card
|
||||
* - _alibcfg - return private alsa-lib's configuration for current card
|
||||
*
|
||||
* - [=]{NAME}[/[{modifier}|{/device}][/{verb}]]
|
||||
* - value identifier {NAME}
|
||||
|
|
|
|||
|
|
@ -1520,9 +1520,15 @@ int snd_ctl_open(snd_ctl_t **ctlp, const char *name, int mode)
|
|||
int err;
|
||||
|
||||
assert(ctlp && name);
|
||||
if (_snd_is_ucm_device(name)) {
|
||||
name = uc_mgr_alibcfg_by_device(&top, name);
|
||||
if (name == NULL)
|
||||
return -ENODEV;
|
||||
} else {
|
||||
err = snd_config_update_ref(&top);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
err = snd_ctl_open_noupdate(ctlp, top, name, mode, 0);
|
||||
snd_config_unref(top);
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -2686,9 +2686,15 @@ int snd_pcm_open(snd_pcm_t **pcmp, const char *name,
|
|||
int err;
|
||||
|
||||
assert(pcmp && name);
|
||||
if (_snd_is_ucm_device(name)) {
|
||||
name = uc_mgr_alibcfg_by_device(&top, name);
|
||||
if (name == NULL)
|
||||
return -ENODEV;
|
||||
} else {
|
||||
err = snd_config_update_ref(&top);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
err = snd_pcm_open_noupdate(pcmp, top, name, stream, mode, 0);
|
||||
snd_config_unref(top);
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -304,9 +304,15 @@ int snd_rawmidi_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
|
|||
int err;
|
||||
|
||||
assert((inputp || outputp) && name);
|
||||
if (_snd_is_ucm_device(name)) {
|
||||
name = uc_mgr_alibcfg_by_device(&top, name);
|
||||
if (name == NULL)
|
||||
return -ENODEV;
|
||||
} else {
|
||||
err = snd_config_update_ref(&top);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
err = snd_rawmidi_open_noupdate(inputp, outputp, top, name, mode);
|
||||
snd_config_unref(top);
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -978,9 +978,15 @@ int snd_seq_open(snd_seq_t **seqp, const char *name,
|
|||
int err;
|
||||
|
||||
assert(seqp && name);
|
||||
if (_snd_is_ucm_device(name)) {
|
||||
name = uc_mgr_alibcfg_by_device(&top, name);
|
||||
if (name == NULL)
|
||||
return -ENODEV;
|
||||
} else {
|
||||
err = snd_config_update_ref(&top);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
err = snd_seq_open_noupdate(seqp, top, name, streams, mode, 0);
|
||||
snd_config_unref(top);
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -205,9 +205,15 @@ int snd_timer_open(snd_timer_t **timer, const char *name, int mode)
|
|||
int err;
|
||||
|
||||
assert(timer && name);
|
||||
if (_snd_is_ucm_device(name)) {
|
||||
name = uc_mgr_alibcfg_by_device(&top, name);
|
||||
if (name == NULL)
|
||||
return -ENODEV;
|
||||
} else {
|
||||
err = snd_config_update_ref(&top);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
err = snd_timer_open_noupdate(timer, top, name, mode);
|
||||
snd_config_unref(top);
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -570,6 +570,38 @@ static int execute_sysw(const char *sysw)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int rewrite_device_value(snd_use_case_mgr_t *uc_mgr, const char *name, char **value)
|
||||
{
|
||||
char *sval;
|
||||
size_t l;
|
||||
static const char **s, *_prefix[] = {
|
||||
"PlaybackCTL",
|
||||
"CaptureCTL",
|
||||
"PlaybackMixer",
|
||||
"CaptureMixer",
|
||||
"PlaybackPCM",
|
||||
"CapturePCM",
|
||||
NULL
|
||||
};
|
||||
|
||||
for (s = _prefix; *s && *value; s++) {
|
||||
if (strcmp(*s, name) != 0)
|
||||
continue;
|
||||
l = strlen(*value) + 9 + 1;
|
||||
sval = malloc(l);
|
||||
if (sval == NULL) {
|
||||
free(*value);
|
||||
*value = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
snprintf(sval, l, "_ucm%04X.%s", uc_mgr->ucm_card_number, *value);
|
||||
free(*value);
|
||||
*value = sval;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Execute the sequence
|
||||
* \param uc_mgr Use case manager
|
||||
|
|
@ -596,6 +628,8 @@ static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
|
|||
cdev = strdup(s->data.cdev);
|
||||
if (cdev == NULL)
|
||||
goto __fail_nomem;
|
||||
if (rewrite_device_value(uc_mgr, "PlaybackCTL", &cdev))
|
||||
goto __fail_nomem;
|
||||
break;
|
||||
case SEQUENCE_ELEMENT_TYPE_CSET:
|
||||
case SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE:
|
||||
|
|
@ -1259,10 +1293,18 @@ int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr,
|
|||
INIT_LIST_HEAD(&mgr->variable_list);
|
||||
pthread_mutex_init(&mgr->mutex, NULL);
|
||||
|
||||
err = uc_mgr_card_open(mgr);
|
||||
if (err < 0)
|
||||
goto _err;
|
||||
|
||||
err = snd_config_top(&mgr->local_config);
|
||||
if (err < 0)
|
||||
goto _err;
|
||||
|
||||
mgr->card_name = strdup(card_name);
|
||||
if (mgr->card_name == NULL) {
|
||||
free(mgr);
|
||||
return -ENOMEM;
|
||||
err = -ENOMEM;
|
||||
goto _err;
|
||||
}
|
||||
|
||||
/* get info on use_cases and verify against card */
|
||||
|
|
@ -1321,6 +1363,7 @@ int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr)
|
|||
*/
|
||||
int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr)
|
||||
{
|
||||
uc_mgr_card_close(uc_mgr);
|
||||
uc_mgr_free(uc_mgr);
|
||||
|
||||
return 0;
|
||||
|
|
@ -1868,6 +1911,7 @@ static int get_value1(snd_use_case_mgr_t *uc_mgr, char **value,
|
|||
{
|
||||
struct ucm_value *val;
|
||||
struct list_head *pos;
|
||||
int err;
|
||||
|
||||
if (!value_list)
|
||||
return -ENOENT;
|
||||
|
|
@ -1881,7 +1925,10 @@ static int get_value1(snd_use_case_mgr_t *uc_mgr, char **value,
|
|||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
return uc_mgr_get_substituted_value(uc_mgr, value, val->data);
|
||||
err = uc_mgr_get_substituted_value(uc_mgr, value, val->data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return rewrite_device_value(uc_mgr, val->name, value);
|
||||
}
|
||||
}
|
||||
return -ENOENT;
|
||||
|
|
@ -1976,6 +2023,31 @@ static int get_value(snd_use_case_mgr_t *uc_mgr,
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get private alsa-lib configuration (ASCII)
|
||||
* \param uc_mgr Use case manager
|
||||
* \param str Returned value string
|
||||
* \return Zero on success (value is filled), otherwise a negative error code
|
||||
*/
|
||||
static int get_alibcfg(snd_use_case_mgr_t *uc_mgr, char **str)
|
||||
{
|
||||
snd_output_t *out;
|
||||
size_t size;
|
||||
int err;
|
||||
|
||||
err = snd_output_buffer_open(&out);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_config_save(uc_mgr->local_config, out);
|
||||
if (err >= 0) {
|
||||
size = snd_output_buffer_steal(out, str);
|
||||
if (*str)
|
||||
(*str)[size] = '\0';
|
||||
}
|
||||
snd_output_close(out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get current - string
|
||||
* \param uc_mgr Use case manager
|
||||
|
|
@ -2029,9 +2101,10 @@ int snd_use_case_get(snd_use_case_mgr_t *uc_mgr,
|
|||
}
|
||||
err = 0;
|
||||
|
||||
} else if (strcmp(identifier, "_alibcfg") == 0) {
|
||||
err = get_alibcfg(uc_mgr, (char **)value);
|
||||
} else if (identifier[0] == '_') {
|
||||
err = -ENOENT;
|
||||
goto __end;
|
||||
} else {
|
||||
if (identifier[0] == '=') {
|
||||
exact = 1;
|
||||
|
|
|
|||
145
src/ucm/parser.c
145
src/ucm/parser.c
|
|
@ -31,6 +31,7 @@
|
|||
*/
|
||||
|
||||
#include "ucm_local.h"
|
||||
#include <stdbool.h>
|
||||
#include <dirent.h>
|
||||
#include <limits.h>
|
||||
|
||||
|
|
@ -420,6 +421,128 @@ int uc_mgr_evaluate_inplace(snd_use_case_mgr_t *uc_mgr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse one item for alsa-lib config
|
||||
*/
|
||||
static int parse_libconfig1(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
|
||||
{
|
||||
snd_config_iterator_t i, next;
|
||||
snd_config_t *n, *config = NULL;
|
||||
const char *id, *file = NULL;
|
||||
bool substfile = false, substconfig = false;
|
||||
int err;
|
||||
|
||||
if (snd_config_get_id(cfg, &id) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
|
||||
uc_error("compound type expected for %s", id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_config_for_each(i, next, cfg) {
|
||||
n = snd_config_iterator_entry(i);
|
||||
|
||||
if (snd_config_get_id(n, &id) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (strcmp(id, "File") == 0 ||
|
||||
strcmp(id, "SubstiFile") == 0) {
|
||||
substfile = id[0] == 'S';
|
||||
err = snd_config_get_string(n, &file);
|
||||
if (err < 0)
|
||||
return err;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(id, "Config") == 0 ||
|
||||
strcmp(id, "SubstiConfig") == 0) {
|
||||
substconfig = id[0] == 'S';
|
||||
if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND)
|
||||
return -EINVAL;
|
||||
config = n;
|
||||
continue;
|
||||
}
|
||||
|
||||
uc_error("unknown field %s", id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (file) {
|
||||
if (substfile) {
|
||||
snd_config_t *cfg;
|
||||
err = uc_mgr_config_load(uc_mgr->conf_format, file, &cfg);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = uc_mgr_substitute_tree(uc_mgr, cfg);
|
||||
if (err < 0) {
|
||||
snd_config_delete(config);
|
||||
return err;
|
||||
}
|
||||
err = snd_config_merge(uc_mgr->local_config, cfg, 1);
|
||||
if (err < 0) {
|
||||
snd_config_delete(cfg);
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
char filename[PATH_MAX];
|
||||
|
||||
ucm_filename(filename, sizeof(filename), uc_mgr->conf_format,
|
||||
file[0] == '/' ? NULL : uc_mgr->conf_dir_name,
|
||||
file);
|
||||
err = uc_mgr_config_load_into(uc_mgr->conf_format, filename, uc_mgr->local_config);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (config) {
|
||||
if (substconfig) {
|
||||
err = uc_mgr_substitute_tree(uc_mgr, config);
|
||||
if (err < 0) {
|
||||
snd_config_delete(config);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
err = snd_config_merge(uc_mgr->local_config, config, 1);
|
||||
if (err < 0) {
|
||||
snd_config_delete(config);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse alsa-lib config
|
||||
*/
|
||||
static int parse_libconfig(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
|
||||
{
|
||||
snd_config_iterator_t i, next;
|
||||
snd_config_t *n;
|
||||
const char *id;
|
||||
int err;
|
||||
|
||||
if (snd_config_get_id(cfg, &id) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
|
||||
uc_error("compound type expected for %s", id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_config_for_each(i, next, cfg) {
|
||||
n = snd_config_iterator_entry(i);
|
||||
|
||||
err = parse_libconfig1(uc_mgr, n);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse transition
|
||||
*/
|
||||
|
|
@ -1644,6 +1767,7 @@ static int parse_verb_file(snd_use_case_mgr_t *uc_mgr,
|
|||
file);
|
||||
goto _err;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* device remove */
|
||||
|
|
@ -1654,6 +1778,17 @@ static int parse_verb_file(snd_use_case_mgr_t *uc_mgr,
|
|||
file);
|
||||
goto _err;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* alsa-lib configuration */
|
||||
if (uc_mgr->conf_format > 3 && strcmp(id, "LibraryConfig") == 0) {
|
||||
err = parse_libconfig(uc_mgr, n);
|
||||
if (err < 0) {
|
||||
uc_error("error: failed to parse LibConfig");
|
||||
return err;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1962,6 +2097,16 @@ static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
|
|||
continue;
|
||||
}
|
||||
|
||||
/* alsa-lib configuration */
|
||||
if (uc_mgr->conf_format > 3 && strcmp(id, "LibraryConfig") == 0) {
|
||||
err = parse_libconfig(uc_mgr, n);
|
||||
if (err < 0) {
|
||||
uc_error("error: failed to parse LibraryConfig");
|
||||
return err;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* error */
|
||||
if (strcmp(id, "Error") == 0)
|
||||
return error_node(uc_mgr, n);
|
||||
|
|
|
|||
|
|
@ -222,6 +222,10 @@ struct snd_use_case_mgr {
|
|||
char *conf_dir_name;
|
||||
char *comment;
|
||||
int conf_format;
|
||||
unsigned int ucm_card_number;
|
||||
|
||||
/* UCM cards list */
|
||||
struct list_head cards_list;
|
||||
|
||||
/* use case verb, devices and modifier configs parsed from files */
|
||||
struct list_head verb_list;
|
||||
|
|
@ -253,6 +257,9 @@ struct snd_use_case_mgr {
|
|||
/* list of opened control devices */
|
||||
struct list_head ctl_list;
|
||||
|
||||
/* local library configuration */
|
||||
snd_config_t *local_config;
|
||||
|
||||
/* Components don't define cdev, the card device. When executing
|
||||
* a sequence of a component device, ucm manager enters component
|
||||
* domain and needs to provide cdev to the component. This cdev
|
||||
|
|
@ -275,6 +282,7 @@ void uc_mgr_stdout(const char *fmt, ...);
|
|||
|
||||
const char *uc_mgr_sysfs_root(void);
|
||||
const char *uc_mgr_config_dir(int format);
|
||||
int uc_mgr_config_load_into(int format, const char *file, snd_config_t *cfg);
|
||||
int uc_mgr_config_load(int format, const char *file, snd_config_t **cfg);
|
||||
int uc_mgr_config_load_file(snd_use_case_mgr_t *uc_mgr, const char *file, snd_config_t **cfg);
|
||||
int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr);
|
||||
|
|
@ -291,6 +299,14 @@ void uc_mgr_free_transition_element(struct transition_sequence *seq);
|
|||
void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr);
|
||||
void uc_mgr_free(snd_use_case_mgr_t *uc_mgr);
|
||||
|
||||
static inline int uc_mgr_has_local_config(snd_use_case_mgr_t *uc_mgr)
|
||||
{
|
||||
return uc_mgr && snd_config_iterator_first(uc_mgr->local_config);
|
||||
}
|
||||
|
||||
int uc_mgr_card_open(snd_use_case_mgr_t *uc_mgr);
|
||||
void uc_mgr_card_close(snd_use_case_mgr_t *uc_mgr);
|
||||
|
||||
int uc_mgr_open_ctl(snd_use_case_mgr_t *uc_mgr,
|
||||
struct ctl_list **ctl_list,
|
||||
const char *device,
|
||||
|
|
|
|||
132
src/ucm/utils.c
132
src/ucm/utils.c
|
|
@ -341,50 +341,55 @@ const char *uc_mgr_config_dir(int format)
|
|||
return path;
|
||||
}
|
||||
|
||||
int uc_mgr_config_load(int format, const char *file, snd_config_t **cfg)
|
||||
int uc_mgr_config_load_into(int format, const char *file, snd_config_t *top)
|
||||
{
|
||||
FILE *fp;
|
||||
snd_input_t *in;
|
||||
snd_config_t *top;
|
||||
const char *default_paths[2];
|
||||
int err;
|
||||
|
||||
fp = fopen(file, "r");
|
||||
if (!fp) {
|
||||
err = -errno;
|
||||
__err0:
|
||||
__err_open:
|
||||
uc_error("could not open configuration file %s", file);
|
||||
return err;
|
||||
}
|
||||
err = snd_input_stdio_attach(&in, fp, 1);
|
||||
if (err < 0)
|
||||
goto __err0;
|
||||
err = snd_config_top(&top);
|
||||
if (err < 0)
|
||||
goto __err1;
|
||||
goto __err_open;
|
||||
|
||||
default_paths[0] = uc_mgr_config_dir(format);
|
||||
default_paths[1] = NULL;
|
||||
err = _snd_config_load_with_include(top, in, 0, default_paths);
|
||||
if (err < 0) {
|
||||
uc_error("could not load configuration file %s", file);
|
||||
goto __err2;
|
||||
}
|
||||
err = snd_input_close(in);
|
||||
if (err < 0) {
|
||||
in = NULL;
|
||||
goto __err2;
|
||||
}
|
||||
*cfg = top;
|
||||
return 0;
|
||||
|
||||
__err2:
|
||||
snd_config_delete(top);
|
||||
__err1:
|
||||
if (in)
|
||||
snd_input_close(in);
|
||||
return err;
|
||||
}
|
||||
err = snd_input_close(in);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int uc_mgr_config_load(int format, const char *file, snd_config_t **cfg)
|
||||
{
|
||||
snd_config_t *top;
|
||||
int err;
|
||||
|
||||
err = snd_config_top(&top);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = uc_mgr_config_load_into(format, file, top);
|
||||
if (err < 0) {
|
||||
snd_config_delete(top);
|
||||
return err;
|
||||
}
|
||||
*cfg = top;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uc_mgr_free_value(struct list_head *base)
|
||||
{
|
||||
|
|
@ -725,8 +730,95 @@ void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr)
|
|||
|
||||
void uc_mgr_free(snd_use_case_mgr_t *uc_mgr)
|
||||
{
|
||||
snd_config_delete(uc_mgr->local_config);
|
||||
uc_mgr_free_verb(uc_mgr);
|
||||
uc_mgr_free_ctl_list(uc_mgr);
|
||||
free(uc_mgr->card_name);
|
||||
free(uc_mgr);
|
||||
}
|
||||
|
||||
/*
|
||||
* UCM card list stuff
|
||||
*/
|
||||
|
||||
static pthread_mutex_t ucm_cards_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static LIST_HEAD(ucm_cards);
|
||||
static unsigned int ucm_card_assign;
|
||||
|
||||
static snd_use_case_mgr_t *uc_mgr_card_find(unsigned int card_number)
|
||||
{
|
||||
struct list_head *pos;
|
||||
snd_use_case_mgr_t *uc_mgr;
|
||||
|
||||
list_for_each(pos, &ucm_cards) {
|
||||
uc_mgr = list_entry(pos, snd_use_case_mgr_t, cards_list);
|
||||
if (uc_mgr->ucm_card_number == card_number)
|
||||
return uc_mgr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int uc_mgr_card_open(snd_use_case_mgr_t *uc_mgr)
|
||||
{
|
||||
unsigned int prev;
|
||||
|
||||
pthread_mutex_lock(&ucm_cards_mutex);
|
||||
prev = ucm_card_assign++;
|
||||
while (uc_mgr_card_find(ucm_card_assign)) {
|
||||
ucm_card_assign++;
|
||||
ucm_card_assign &= 0xffff;
|
||||
if (ucm_card_assign == prev) {
|
||||
pthread_mutex_unlock(&ucm_cards_mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
uc_mgr->ucm_card_number = ucm_card_assign;
|
||||
list_add(&uc_mgr->cards_list, &ucm_cards);
|
||||
pthread_mutex_unlock(&ucm_cards_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uc_mgr_card_close(snd_use_case_mgr_t *uc_mgr)
|
||||
{
|
||||
pthread_mutex_lock(&ucm_cards_mutex);
|
||||
list_del(&uc_mgr->cards_list);
|
||||
pthread_mutex_unlock(&ucm_cards_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get library configuration based on the private ALSA device name
|
||||
* \param name[in] ALSA device name
|
||||
* \retval config A configuration tree or NULL
|
||||
*
|
||||
* The returned configuration (non-NULL) should be unreferenced using
|
||||
* snd_config_unref() call.
|
||||
*/
|
||||
const char *uc_mgr_alibcfg_by_device(snd_config_t **top, const char *name)
|
||||
{
|
||||
char buf[5];
|
||||
long card_num;
|
||||
snd_config_t *config;
|
||||
snd_use_case_mgr_t *uc_mgr;
|
||||
int err;
|
||||
|
||||
if (strncmp(name, "_ucm", 4) || strlen(name) < 12 || name[8] != '.')
|
||||
return NULL;
|
||||
strncpy(buf, name + 4, 4);
|
||||
buf[4] = '\0';
|
||||
err = safe_strtol(buf, &card_num);
|
||||
if (err < 0 || card_num < 0 || card_num > 0xffff)
|
||||
return NULL;
|
||||
config = NULL;
|
||||
pthread_mutex_lock(&ucm_cards_mutex);
|
||||
uc_mgr = uc_mgr_card_find(card_num);
|
||||
/* non-empty configs are accepted only */
|
||||
if (uc_mgr_has_local_config(uc_mgr)) {
|
||||
config = uc_mgr->local_config;
|
||||
snd_config_ref(config);
|
||||
}
|
||||
pthread_mutex_unlock(&ucm_cards_mutex);
|
||||
if (!config)
|
||||
return NULL;
|
||||
*top = config;
|
||||
return name + 9;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue