mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-11-03 09:01:52 -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