blob: 45307b021b78ed6fb232e02835066727e8dd2806 [file] [log] [blame]
/*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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;
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;
err = snd_config_load(top, in);
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_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);
}