mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-11-02 09:01:48 -05:00
ucm: switch to ucm2 directory and v2 format, keep backward compatibility
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
parent
f600310954
commit
aba2260ae7
3 changed files with 134 additions and 37 deletions
149
src/ucm/parser.c
149
src/ucm/parser.c
|
|
@ -61,6 +61,65 @@ static int parse_sequence(snd_use_case_mgr_t *uc_mgr,
|
|||
struct list_head *base,
|
||||
snd_config_t *cfg);
|
||||
|
||||
/*
|
||||
* compose configuration file
|
||||
*/
|
||||
static void configuration_filename2(char *fn, size_t fn_len, int format,
|
||||
const char *dir, const char *file,
|
||||
const char *suffix)
|
||||
{
|
||||
snprintf(fn, fn_len, "%s/ucm%s/%s/%s%s",
|
||||
snd_config_topdir(), format >= 2 ? "2" : "",
|
||||
dir, file, suffix);
|
||||
fn[fn_len-1] = '\0';
|
||||
}
|
||||
|
||||
static void configuration_filename(snd_use_case_mgr_t *uc_mgr,
|
||||
char *fn, size_t fn_len,
|
||||
const char *file, const char *suffix)
|
||||
{
|
||||
const char *env, *dir;
|
||||
|
||||
if (uc_mgr->conf_format > 0) {
|
||||
/* known format */
|
||||
env = getenv(uc_mgr->conf_format >= 2 ? ALSA_CONFIG_UCM2_VAR :
|
||||
ALSA_CONFIG_UCM_VAR);
|
||||
} else {
|
||||
/* auto-detect */
|
||||
env = getenv(ALSA_CONFIG_UCM2_VAR);
|
||||
if (env == NULL) {
|
||||
env = getenv(ALSA_CONFIG_UCM_VAR);
|
||||
} else {
|
||||
uc_mgr->conf_format = 2;
|
||||
}
|
||||
}
|
||||
if (env) {
|
||||
snprintf(fn, fn_len, "%s/%s/%s%s",
|
||||
env, uc_mgr->conf_file_name, file, suffix);
|
||||
fn[fn_len-1] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
dir = uc_mgr->conf_file_name;
|
||||
if (uc_mgr->conf_format > 0) {
|
||||
__format:
|
||||
configuration_filename2(fn, fn_len, uc_mgr->conf_format,
|
||||
dir, file, suffix);
|
||||
return;
|
||||
}
|
||||
|
||||
configuration_filename2(fn, fn_len, 2, dir, file, suffix);
|
||||
if (access(fn, R_OK) == 0)
|
||||
return;
|
||||
|
||||
configuration_filename2(fn, fn_len, 0, dir, file, suffix);
|
||||
if (access(fn, R_OK)) {
|
||||
/* make sure that the error message refers to the new path */
|
||||
uc_mgr->conf_format = 2;
|
||||
goto __format;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse string
|
||||
*/
|
||||
|
|
@ -1052,7 +1111,6 @@ static int parse_verb_file(snd_use_case_mgr_t *uc_mgr,
|
|||
struct use_case_verb *verb;
|
||||
snd_config_t *cfg;
|
||||
char filename[MAX_FILE];
|
||||
char *env = getenv(ALSA_CONFIG_UCM_VAR);
|
||||
int err;
|
||||
|
||||
/* allocate verb */
|
||||
|
|
@ -1080,15 +1138,8 @@ static int parse_verb_file(snd_use_case_mgr_t *uc_mgr,
|
|||
}
|
||||
|
||||
/* open Verb file for reading */
|
||||
if (env)
|
||||
snprintf(filename, sizeof(filename), "%s/%s/%s",
|
||||
env, uc_mgr->conf_file_name, file);
|
||||
else
|
||||
snprintf(filename, sizeof(filename), "%s/ucm/%s/%s",
|
||||
snd_config_topdir(), uc_mgr->conf_file_name, file);
|
||||
filename[sizeof(filename)-1] = '\0';
|
||||
|
||||
err = uc_mgr_config_load(filename, &cfg);
|
||||
configuration_filename(uc_mgr, filename, sizeof(filename), file, "");
|
||||
err = uc_mgr_config_load(uc_mgr->conf_format, filename, &cfg);
|
||||
if (err < 0) {
|
||||
uc_error("error: failed to open verb file %s : %d",
|
||||
filename, -errno);
|
||||
|
|
@ -1283,6 +1334,7 @@ static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
|
|||
snd_config_iterator_t i, next;
|
||||
snd_config_t *n;
|
||||
const char *id;
|
||||
long l;
|
||||
int err;
|
||||
|
||||
if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
|
||||
|
|
@ -1290,6 +1342,23 @@ static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (uc_mgr->conf_format >= 2) {
|
||||
err = snd_config_search(cfg, "Syntax", &n);
|
||||
if (err < 0) {
|
||||
uc_error("Syntax field not found in %s", uc_mgr->conf_file_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
err = snd_config_get_integer(n, &l);
|
||||
if (err < 0) {
|
||||
uc_error("Syntax field is invalid in %s", uc_mgr->conf_file_name);
|
||||
return err;
|
||||
}
|
||||
if (l < 2 || l > SYNTAX_VERSION_MAX) {
|
||||
uc_error("Incompatible syntax %d in %s", l, uc_mgr->conf_file_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* parse master config sections */
|
||||
snd_config_for_each(i, next, cfg) {
|
||||
|
||||
|
|
@ -1297,6 +1366,9 @@ static int parse_master_file(snd_use_case_mgr_t *uc_mgr, snd_config_t *cfg)
|
|||
if (snd_config_get_id(n, &id) < 0)
|
||||
continue;
|
||||
|
||||
if (uc_mgr->conf_format >= 2 && strcmp(id, "Syntax") == 0)
|
||||
continue;
|
||||
|
||||
if (strcmp(id, "Comment") == 0) {
|
||||
err = parse_string(n, &uc_mgr->comment);
|
||||
if (err < 0) {
|
||||
|
|
@ -1400,10 +1472,10 @@ next_card:
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int load_master_config(const char *card_name, snd_config_t **cfg)
|
||||
static int load_master_config(snd_use_case_mgr_t *uc_mgr,
|
||||
const char *card_name, snd_config_t **cfg)
|
||||
{
|
||||
char filename[MAX_FILE];
|
||||
char *env = getenv(ALSA_CONFIG_UCM_VAR);
|
||||
int err;
|
||||
|
||||
if (strnlen(card_name, MAX_CARD_LONG_NAME) == MAX_CARD_LONG_NAME) {
|
||||
|
|
@ -1412,16 +1484,9 @@ static int load_master_config(const char *card_name, snd_config_t **cfg)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (env)
|
||||
snprintf(filename, sizeof(filename)-1,
|
||||
"%s/%s/%s.conf", env, card_name, card_name);
|
||||
else
|
||||
snprintf(filename, sizeof(filename)-1,
|
||||
"%s/ucm/%s/%s.conf", snd_config_topdir(),
|
||||
card_name, card_name);
|
||||
filename[MAX_FILE-1] = '\0';
|
||||
|
||||
err = uc_mgr_config_load(filename, cfg);
|
||||
configuration_filename(uc_mgr, filename, sizeof(filename),
|
||||
card_name, ".conf");
|
||||
err = uc_mgr_config_load(uc_mgr->conf_format, filename, cfg);
|
||||
if (err < 0) {
|
||||
uc_error("error: could not parse configuration for card %s",
|
||||
card_name);
|
||||
|
|
@ -1452,7 +1517,7 @@ int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr)
|
|||
|
||||
err = get_card_long_name(uc_mgr);
|
||||
if (err == 0) /* load file that maches the card long name */
|
||||
err = load_master_config(uc_mgr->card_long_name, &cfg);
|
||||
err = load_master_config(uc_mgr, uc_mgr->card_long_name, &cfg);
|
||||
|
||||
if (err == 0) {
|
||||
/* got device-specific file that matches the card long name */
|
||||
|
|
@ -1462,7 +1527,7 @@ int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr)
|
|||
* either short name or long name (users may open a card by
|
||||
* its name or long name).
|
||||
*/
|
||||
err = load_master_config(uc_mgr->card_name, &cfg);
|
||||
err = load_master_config(uc_mgr, uc_mgr->card_name, &cfg);
|
||||
if (err < 0)
|
||||
return err;
|
||||
strncpy(uc_mgr->conf_file_name, uc_mgr->card_name, MAX_CARD_LONG_NAME);
|
||||
|
|
@ -1512,26 +1577,27 @@ static int is_component_directory(const char *dir)
|
|||
*
|
||||
* Cards are defined by machines. Each card/machine installs its UCM
|
||||
* configuration files in a subdirectory with the same name as the sound
|
||||
* card under /usr/share/alsa/ucm. This function will scan all the card
|
||||
* card under /usr/share/alsa/ucm2. This function will scan all the card
|
||||
* directories and skip the component directories defined in the array
|
||||
* component_dir.
|
||||
*/
|
||||
int uc_mgr_scan_master_configs(const char **_list[])
|
||||
{
|
||||
char filename[MAX_FILE], dfl[MAX_FILE];
|
||||
char *env = getenv(ALSA_CONFIG_UCM_VAR);
|
||||
const char **list;
|
||||
char *env = getenv(ALSA_CONFIG_UCM2_VAR);
|
||||
const char **list, *d_name;
|
||||
snd_config_t *cfg, *c;
|
||||
int i, j, cnt, err;
|
||||
long l;
|
||||
ssize_t ss;
|
||||
struct dirent **namelist;
|
||||
|
||||
if (env)
|
||||
snprintf(filename, sizeof(filename)-1, "%s", env);
|
||||
else
|
||||
snprintf(filename, sizeof(filename)-1, "%s/ucm",
|
||||
snprintf(filename, sizeof(filename)-1, "%s/ucm2",
|
||||
snd_config_topdir());
|
||||
filename[MAX_FILE-1] = '\0';
|
||||
filename[sizeof(filename)-1] = '\0';
|
||||
|
||||
#if defined(_GNU_SOURCE) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__sun) && !defined(ANDROID)
|
||||
#define SORTFUNC versionsort
|
||||
|
|
@ -1569,13 +1635,32 @@ int uc_mgr_scan_master_configs(const char **_list[])
|
|||
|
||||
for (i = j = 0; i < cnt; i++) {
|
||||
|
||||
d_name = namelist[i]->d_name;
|
||||
|
||||
/* Skip the directories for component devices */
|
||||
if (is_component_directory(namelist[i]->d_name))
|
||||
if (is_component_directory(d_name))
|
||||
continue;
|
||||
|
||||
err = load_master_config(namelist[i]->d_name, &cfg);
|
||||
|
||||
configuration_filename2(filename, sizeof(filename), 2,
|
||||
d_name, d_name, ".conf");
|
||||
err = uc_mgr_config_load(2, filename, &cfg);
|
||||
if (err < 0)
|
||||
goto __err;
|
||||
err = snd_config_search(cfg, "Syntax", &c);
|
||||
if (err < 0) {
|
||||
uc_error("Syntax field not found in %s", d_name);
|
||||
continue;
|
||||
}
|
||||
err = snd_config_get_integer(c, &l);
|
||||
if (err < 0) {
|
||||
uc_error("Syntax field is invalid in %s", d_name);
|
||||
goto __err;
|
||||
}
|
||||
if (l < 2 || l > SYNTAX_VERSION_MAX) {
|
||||
uc_error("Incompatible syntax %d in %s", l, d_name);
|
||||
goto __err;
|
||||
}
|
||||
err = snd_config_search(cfg, "Comment", &c);
|
||||
if (err >= 0) {
|
||||
err = parse_string(c, (char **)&list[j+1]);
|
||||
|
|
@ -1585,7 +1670,7 @@ int uc_mgr_scan_master_configs(const char **_list[])
|
|||
}
|
||||
}
|
||||
snd_config_delete(cfg);
|
||||
list[j] = strdup(namelist[i]->d_name);
|
||||
list[j] = strdup(d_name);
|
||||
if (list[j] == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto __err;
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@
|
|||
#include <pthread.h>
|
||||
#include "use-case.h"
|
||||
|
||||
#define SYNTAX_VERSION_MAX 2
|
||||
|
||||
#define MAX_FILE 256
|
||||
#define MAX_CARD_LONG_NAME 80
|
||||
|
||||
|
|
@ -193,6 +195,7 @@ struct snd_use_case_mgr {
|
|||
char card_long_name[MAX_CARD_LONG_NAME];
|
||||
char conf_file_name[MAX_CARD_LONG_NAME];
|
||||
char *comment;
|
||||
int conf_format;
|
||||
|
||||
/* use case verb, devices and modifier configs parsed from files */
|
||||
struct list_head verb_list;
|
||||
|
|
@ -235,7 +238,7 @@ struct snd_use_case_mgr {
|
|||
void uc_mgr_error(const char *fmt, ...);
|
||||
void uc_mgr_stdout(const char *fmt, ...);
|
||||
|
||||
int uc_mgr_config_load(const char *file, snd_config_t **cfg);
|
||||
int uc_mgr_config_load(int format, const char *file, snd_config_t **cfg);
|
||||
int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr);
|
||||
int uc_mgr_scan_master_configs(const char **_list[]);
|
||||
|
||||
|
|
@ -246,3 +249,6 @@ void uc_mgr_free(snd_use_case_mgr_t *uc_mgr);
|
|||
|
||||
/** The name of the environment variable containing the UCM directory */
|
||||
#define ALSA_CONFIG_UCM_VAR "ALSA_CONFIG_UCM"
|
||||
|
||||
/** The name of the environment variable containing the UCM directory (new syntax) */
|
||||
#define ALSA_CONFIG_UCM2_VAR "ALSA_CONFIG_UCM2"
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ void uc_mgr_stdout(const char *fmt,...)
|
|||
va_end(va);
|
||||
}
|
||||
|
||||
int uc_mgr_config_load(const char *file, snd_config_t **cfg)
|
||||
int uc_mgr_config_load(int format, const char *file, snd_config_t **cfg)
|
||||
{
|
||||
FILE *fp;
|
||||
snd_input_t *in;
|
||||
|
|
@ -71,9 +71,15 @@ int uc_mgr_config_load(const char *file, snd_config_t **cfg)
|
|||
if (err < 0)
|
||||
goto __err1;
|
||||
|
||||
path = getenv(ALSA_CONFIG_UCM_VAR);
|
||||
if (!path || path[0] == '\0')
|
||||
path = ALSA_CONFIG_DIR "/ucm";
|
||||
if (format >= 2) {
|
||||
path = getenv(ALSA_CONFIG_UCM2_VAR);
|
||||
if (!path || path[0] == '\0')
|
||||
path = ALSA_CONFIG_DIR "/ucm2";
|
||||
} else {
|
||||
path = getenv(ALSA_CONFIG_UCM_VAR);
|
||||
if (!path || path[0] == '\0')
|
||||
path = ALSA_CONFIG_DIR "/ucm";
|
||||
}
|
||||
|
||||
default_paths[0] = path;
|
||||
default_paths[1] = NULL;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue