mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-29 05:40:25 -04:00
Many UCM profiles include the UCM profile components under ucm/* subdirectories and thusly put <searchdir:ucm> at each place. This is rather cumbersome. This patch makes the UCM parser to set the default include path, so that each profile no longer needs to set searchdir. All the <searchdir:ucm> lines currently found in the profiles are removed gracefully, too. For the needed implementation, a new helper, _snd_config_load_with_include() is introduced. It's not exported, only for the use inside alsa-lib. Signed-off-by: Takashi Iwai <tiwai@suse.de>
243 lines
6.2 KiB
C
243 lines
6.2 KiB
C
/*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* Support for the verb/device/modifier core logic and API,
|
|
* command line tool and file parser was kindly sponsored by
|
|
* Texas Instruments Inc.
|
|
* Support for multiple active modifiers and devices,
|
|
* transition sequences, multiple client access and user defined use
|
|
* cases was kindly sponsored by Wolfson Microelectronics PLC.
|
|
*
|
|
* Copyright (C) 2008-2010 SlimLogic Ltd
|
|
* Copyright (C) 2010 Wolfson Microelectronics PLC
|
|
* Copyright (C) 2010 Texas Instruments Inc.
|
|
* Copyright (C) 2010 Red Hat Inc.
|
|
* Authors: Liam Girdwood <lrg@slimlogic.co.uk>
|
|
* Stefan Schmidt <stefan@slimlogic.co.uk>
|
|
* Justin Xu <justinx@slimlogic.co.uk>
|
|
* Jaroslav Kysela <perex@perex.cz>
|
|
*/
|
|
|
|
#include "ucm_local.h"
|
|
|
|
void uc_mgr_error(const char *fmt,...)
|
|
{
|
|
va_list va;
|
|
va_start(va, fmt);
|
|
fprintf(stderr, "ucm: ");
|
|
vfprintf(stderr, fmt, va);
|
|
va_end(va);
|
|
}
|
|
|
|
void uc_mgr_stdout(const char *fmt,...)
|
|
{
|
|
va_list va;
|
|
va_start(va, fmt);
|
|
vfprintf(stdout, fmt, va);
|
|
va_end(va);
|
|
}
|
|
|
|
int uc_mgr_config_load(const char *file, snd_config_t **cfg)
|
|
{
|
|
FILE *fp;
|
|
snd_input_t *in;
|
|
snd_config_t *top;
|
|
const char *default_path;
|
|
int err;
|
|
|
|
fp = fopen(file, "r");
|
|
if (fp == NULL) {
|
|
err = -errno;
|
|
goto __err;
|
|
}
|
|
err = snd_input_stdio_attach(&in, fp, 1);
|
|
if (err < 0) {
|
|
__err:
|
|
uc_error("could not open configuration file %s", file);
|
|
return err;
|
|
}
|
|
err = snd_config_top(&top);
|
|
if (err < 0)
|
|
return err;
|
|
|
|
default_path = getenv(ALSA_CONFIG_UCM_VAR);
|
|
if (!default_path || !*default_path)
|
|
default_path = ALSA_CONFIG_DIR "/ucm";
|
|
err = _snd_config_load_with_include(top, in, default_path);
|
|
if (err < 0) {
|
|
uc_error("could not load configuration file %s", file);
|
|
snd_config_delete(top);
|
|
return err;
|
|
}
|
|
err = snd_input_close(in);
|
|
if (err < 0) {
|
|
snd_config_delete(top);
|
|
return err;
|
|
}
|
|
*cfg = top;
|
|
return 0;
|
|
}
|
|
|
|
void uc_mgr_free_value(struct list_head *base)
|
|
{
|
|
struct list_head *pos, *npos;
|
|
struct ucm_value *val;
|
|
|
|
list_for_each_safe(pos, npos, base) {
|
|
val = list_entry(pos, struct ucm_value, list);
|
|
free(val->name);
|
|
free(val->data);
|
|
list_del(&val->list);
|
|
free(val);
|
|
}
|
|
}
|
|
|
|
void uc_mgr_free_dev_list(struct dev_list *dev_list)
|
|
{
|
|
struct list_head *pos, *npos;
|
|
struct dev_list_node *dlist;
|
|
|
|
list_for_each_safe(pos, npos, &dev_list->list) {
|
|
dlist = list_entry(pos, struct dev_list_node, list);
|
|
free(dlist->name);
|
|
list_del(&dlist->list);
|
|
free(dlist);
|
|
}
|
|
}
|
|
|
|
void uc_mgr_free_sequence_element(struct sequence_element *seq)
|
|
{
|
|
if (seq == NULL)
|
|
return;
|
|
switch (seq->type) {
|
|
case SEQUENCE_ELEMENT_TYPE_CSET:
|
|
case SEQUENCE_ELEMENT_TYPE_EXEC:
|
|
free(seq->data.exec);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
free(seq);
|
|
}
|
|
|
|
void uc_mgr_free_sequence(struct list_head *base)
|
|
{
|
|
struct list_head *pos, *npos;
|
|
struct sequence_element *seq;
|
|
|
|
list_for_each_safe(pos, npos, base) {
|
|
seq = list_entry(pos, struct sequence_element, list);
|
|
list_del(&seq->list);
|
|
uc_mgr_free_sequence_element(seq);
|
|
}
|
|
}
|
|
|
|
void uc_mgr_free_transition_element(struct transition_sequence *tseq)
|
|
{
|
|
free(tseq->name);
|
|
uc_mgr_free_sequence(&tseq->transition_list);
|
|
free(tseq);
|
|
}
|
|
|
|
void uc_mgr_free_transition(struct list_head *base)
|
|
{
|
|
struct list_head *pos, *npos;
|
|
struct transition_sequence *tseq;
|
|
|
|
list_for_each_safe(pos, npos, base) {
|
|
tseq = list_entry(pos, struct transition_sequence, list);
|
|
list_del(&tseq->list);
|
|
uc_mgr_free_transition_element(tseq);
|
|
}
|
|
}
|
|
|
|
void uc_mgr_free_modifier(struct list_head *base)
|
|
{
|
|
struct list_head *pos, *npos;
|
|
struct use_case_modifier *mod;
|
|
|
|
list_for_each_safe(pos, npos, base) {
|
|
mod = list_entry(pos, struct use_case_modifier, list);
|
|
free(mod->name);
|
|
free(mod->comment);
|
|
uc_mgr_free_sequence(&mod->enable_list);
|
|
uc_mgr_free_sequence(&mod->disable_list);
|
|
uc_mgr_free_transition(&mod->transition_list);
|
|
uc_mgr_free_dev_list(&mod->dev_list);
|
|
uc_mgr_free_value(&mod->value_list);
|
|
list_del(&mod->list);
|
|
free(mod);
|
|
}
|
|
}
|
|
|
|
void uc_mgr_free_device(struct list_head *base)
|
|
{
|
|
struct list_head *pos, *npos;
|
|
struct use_case_device *dev;
|
|
|
|
list_for_each_safe(pos, npos, base) {
|
|
dev = list_entry(pos, struct use_case_device, list);
|
|
free(dev->name);
|
|
free(dev->comment);
|
|
uc_mgr_free_sequence(&dev->enable_list);
|
|
uc_mgr_free_sequence(&dev->disable_list);
|
|
uc_mgr_free_transition(&dev->transition_list);
|
|
uc_mgr_free_dev_list(&dev->dev_list);
|
|
uc_mgr_free_value(&dev->value_list);
|
|
list_del(&dev->list);
|
|
free(dev);
|
|
}
|
|
}
|
|
|
|
void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr)
|
|
{
|
|
struct list_head *pos, *npos;
|
|
struct use_case_verb *verb;
|
|
|
|
list_for_each_safe(pos, npos, &uc_mgr->verb_list) {
|
|
verb = list_entry(pos, struct use_case_verb, list);
|
|
free(verb->name);
|
|
free(verb->comment);
|
|
uc_mgr_free_sequence(&verb->enable_list);
|
|
uc_mgr_free_sequence(&verb->disable_list);
|
|
uc_mgr_free_transition(&verb->transition_list);
|
|
uc_mgr_free_value(&verb->value_list);
|
|
uc_mgr_free_device(&verb->device_list);
|
|
uc_mgr_free_device(&verb->cmpt_device_list);
|
|
uc_mgr_free_modifier(&verb->modifier_list);
|
|
list_del(&verb->list);
|
|
free(verb);
|
|
}
|
|
uc_mgr_free_sequence(&uc_mgr->default_list);
|
|
uc_mgr_free_value(&uc_mgr->value_list);
|
|
free(uc_mgr->comment);
|
|
uc_mgr->comment = NULL;
|
|
uc_mgr->active_verb = NULL;
|
|
INIT_LIST_HEAD(&uc_mgr->active_devices);
|
|
INIT_LIST_HEAD(&uc_mgr->active_modifiers);
|
|
if (uc_mgr->ctl != NULL) {
|
|
snd_ctl_close(uc_mgr->ctl);
|
|
uc_mgr->ctl = NULL;
|
|
}
|
|
free(uc_mgr->ctl_dev);
|
|
uc_mgr->ctl_dev = NULL;
|
|
}
|
|
|
|
void uc_mgr_free(snd_use_case_mgr_t *uc_mgr)
|
|
{
|
|
uc_mgr_free_verb(uc_mgr);
|
|
free(uc_mgr->card_name);
|
|
free(uc_mgr);
|
|
}
|