|  | /* | 
|  | *  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); | 
|  | } |