ucm: switch to ucm2 directory and v2 format, keep backward compatibility

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
Jaroslav Kysela 2019-11-09 11:53:32 +01:00
parent f600310954
commit aba2260ae7
3 changed files with 134 additions and 37 deletions

View file

@ -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;

View file

@ -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"

View file

@ -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;