Blame src/ucm/main.c

Packit Service db8eaa
/*
Packit Service db8eaa
 *  This library is free software; you can redistribute it and/or
Packit Service db8eaa
 *  modify it under the terms of the GNU Lesser General Public
Packit Service db8eaa
 *  License as published by the Free Software Foundation; either
Packit Service db8eaa
 *  version 2 of the License, or (at your option) any later version.
Packit Service db8eaa
 *
Packit Service db8eaa
 *  This library is distributed in the hope that it will be useful,
Packit Service db8eaa
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service db8eaa
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service db8eaa
 *  Lesser General Public License for more details.
Packit Service db8eaa
 *
Packit Service db8eaa
 *  You should have received a copy of the GNU Lesser General Public
Packit Service db8eaa
 *  License along with this library; if not, write to the Free Software  
Packit Service db8eaa
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit Service db8eaa
 *
Packit Service db8eaa
 *  Support for the verb/device/modifier core logic and API,
Packit Service db8eaa
 *  command line tool and file parser was kindly sponsored by
Packit Service db8eaa
 *  Texas Instruments Inc.
Packit Service db8eaa
 *  Support for multiple active modifiers and devices,
Packit Service db8eaa
 *  transition sequences, multiple client access and user defined use
Packit Service db8eaa
 *  cases was kindly sponsored by Wolfson Microelectronics PLC.
Packit Service db8eaa
 *
Packit Service db8eaa
 *  Copyright (C) 2008-2010 SlimLogic Ltd
Packit Service db8eaa
 *  Copyright (C) 2010 Wolfson Microelectronics PLC
Packit Service db8eaa
 *  Copyright (C) 2010 Texas Instruments Inc.
Packit Service db8eaa
 *  Copyright (C) 2010 Red Hat Inc.
Packit Service db8eaa
 *  Authors: Liam Girdwood <lrg@slimlogic.co.uk>
Packit Service db8eaa
 *	         Stefan Schmidt <stefan@slimlogic.co.uk>
Packit Service db8eaa
 *	         Justin Xu <justinx@slimlogic.co.uk>
Packit Service db8eaa
 *               Jaroslav Kysela <perex@perex.cz>
Packit Service db8eaa
 */
Packit Service db8eaa
Packit Service db8eaa
#include "ucm_local.h"
Packit Service db8eaa
#include <ctype.h>
Packit Service db8eaa
#include <stdarg.h>
Packit Service db8eaa
#include <pthread.h>
Packit Service db8eaa
#include <sys/stat.h>
Packit Service db8eaa
#include <limits.h>
Packit Service db8eaa
Packit Service db8eaa
/*
Packit Service db8eaa
 * misc
Packit Service db8eaa
 */
Packit Service db8eaa
Packit Service db8eaa
static int get_value(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
			const char *identifier,
Packit Service db8eaa
			char **value,
Packit Service db8eaa
			const char *mod_dev_name,
Packit Service db8eaa
			const char *verb_name,
Packit Service db8eaa
			int exact);
Packit Service db8eaa
static int get_value1(snd_use_case_mgr_t *uc_mgr, char **value,
Packit Service db8eaa
                      struct list_head *value_list, const char *identifier);
Packit Service db8eaa
static int get_value3(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
                      char **value,
Packit Service db8eaa
		      const char *identifier,
Packit Service db8eaa
		      struct list_head *value_list1,
Packit Service db8eaa
		      struct list_head *value_list2,
Packit Service db8eaa
		      struct list_head *value_list3);
Packit Service db8eaa
Packit Service db8eaa
static int execute_component_seq(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
				 struct component_sequence *cmpt_seq,
Packit Service db8eaa
				 struct list_head *value_list1,
Packit Service db8eaa
				 struct list_head *value_list2,
Packit Service db8eaa
				 struct list_head *value_list3,
Packit Service db8eaa
				 char *cdev);
Packit Service db8eaa
Packit Service db8eaa
static int check_identifier(const char *identifier, const char *prefix)
Packit Service db8eaa
{
Packit Service db8eaa
	int len;
Packit Service db8eaa
Packit Service db8eaa
	len = strlen(prefix);
Packit Service db8eaa
	if (strncmp(identifier, prefix, len) != 0)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
Packit Service db8eaa
	if (identifier[len] == 0 || identifier[len] == '/')
Packit Service db8eaa
		return 1;
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int list_count(struct list_head *list)
Packit Service db8eaa
{
Packit Service db8eaa
        struct list_head *pos;
Packit Service db8eaa
        int count = 0;
Packit Service db8eaa
        
Packit Service db8eaa
        list_for_each(pos, list) {
Packit Service db8eaa
                count += 1;
Packit Service db8eaa
        }
Packit Service db8eaa
        return count;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int alloc_str_list(struct list_head *list, int mult, char **result[])
Packit Service db8eaa
{
Packit Service db8eaa
        char **res;
Packit Service db8eaa
        int cnt;
Packit Service db8eaa
        
Packit Service db8eaa
        cnt = list_count(list) * mult;
Packit Service db8eaa
        if (cnt == 0) {
Packit Service db8eaa
		*result = NULL;
Packit Service db8eaa
                return cnt;
Packit Service db8eaa
	}
Packit Service db8eaa
        res = calloc(mult, cnt * sizeof(char *));
Packit Service db8eaa
        if (res == NULL)
Packit Service db8eaa
                return -ENOMEM;
Packit Service db8eaa
        *result = res;
Packit Service db8eaa
        return cnt;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Create an identifier
Packit Service db8eaa
 * \param fmt Format (sprintf like)
Packit Service db8eaa
 * \param ... Optional arguments for sprintf like format
Packit Service db8eaa
 * \return Allocated string identifier or NULL on error
Packit Service db8eaa
 */
Packit Service db8eaa
char *snd_use_case_identifier(const char *fmt, ...)
Packit Service db8eaa
{
Packit Service db8eaa
	char *str, *res;
Packit Service db8eaa
	int size = strlen(fmt) + 512;
Packit Service db8eaa
	va_list args;
Packit Service db8eaa
Packit Service db8eaa
	str = malloc(size);
Packit Service db8eaa
	if (str == NULL)
Packit Service db8eaa
		return NULL;
Packit Service db8eaa
	va_start(args, fmt);
Packit Service db8eaa
	vsnprintf(str, size, fmt, args);
Packit Service db8eaa
	va_end(args);
Packit Service db8eaa
	str[size-1] = '\0';
Packit Service db8eaa
	res = realloc(str, strlen(str) + 1);
Packit Service db8eaa
	if (res)
Packit Service db8eaa
		return res;
Packit Service db8eaa
	return str;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Free a string list
Packit Service db8eaa
 * \param list The string list to free
Packit Service db8eaa
 * \param items Count of strings
Packit Service db8eaa
 * \return Zero if success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_use_case_free_list(const char *list[], int items)
Packit Service db8eaa
{
Packit Service db8eaa
        int i;
Packit Service db8eaa
	if (list == NULL)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
        for (i = 0; i < items; i++)
Packit Service db8eaa
		free((void *)list[i]);
Packit Service db8eaa
        free(list);
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int read_tlv_file(unsigned int **res,
Packit Service db8eaa
			 const char *filepath)
Packit Service db8eaa
{
Packit Service db8eaa
	int err = 0;
Packit Service db8eaa
	int fd;
Packit Service db8eaa
	struct stat st;
Packit Service db8eaa
	size_t sz;
Packit Service db8eaa
	ssize_t sz_read;
Packit Service db8eaa
	struct snd_ctl_tlv *tlv;
Packit Service db8eaa
Packit Service db8eaa
	fd = open(filepath, O_RDONLY);
Packit Service db8eaa
	if (fd < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (fstat(fd, &st) == -1) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		goto __fail;
Packit Service db8eaa
	}
Packit Service db8eaa
	sz = st.st_size;
Packit Service db8eaa
	if (sz > 16 * 1024 * 1024 || sz < 8 || sz % 4) {
Packit Service db8eaa
		uc_error("File size should be less than 16 MB "
Packit Service db8eaa
			 "and multiple of 4");
Packit Service db8eaa
		err = -EINVAL;
Packit Service db8eaa
		goto __fail;
Packit Service db8eaa
	}
Packit Service db8eaa
	*res = malloc(sz);
Packit Service db8eaa
	if (res == NULL) {
Packit Service db8eaa
		err = -ENOMEM;
Packit Service db8eaa
		goto __fail;
Packit Service db8eaa
	}
Packit Service db8eaa
	sz_read = read(fd, *res, sz);
Packit Service db8eaa
	if (sz_read < 0 || (size_t)sz_read != sz) {
Packit Service db8eaa
		err = -EIO;
Packit Service db8eaa
		free(*res);
Packit Service db8eaa
		*res = NULL;
Packit Service db8eaa
	}
Packit Service db8eaa
	/* Check if the tlv file specifies valid size. */
Packit Service db8eaa
	tlv = (struct snd_ctl_tlv *)(*res);
Packit Service db8eaa
	if (tlv->length + 2 * sizeof(unsigned int) != sz) {
Packit Service db8eaa
		uc_error("Invalid tlv size: %d", tlv->length);
Packit Service db8eaa
		err = -EINVAL;
Packit Service db8eaa
		free(*res);
Packit Service db8eaa
		*res = NULL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
__fail:
Packit Service db8eaa
	close(fd);
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int binary_file_parse(snd_ctl_elem_value_t *dst,
Packit Service db8eaa
			      snd_ctl_elem_info_t *info,
Packit Service db8eaa
			      const char *filepath)
Packit Service db8eaa
{
Packit Service db8eaa
	int err = 0;
Packit Service db8eaa
	int fd;
Packit Service db8eaa
	struct stat st;
Packit Service db8eaa
	size_t sz;
Packit Service db8eaa
	ssize_t sz_read;
Packit Service db8eaa
	char *res;
Packit Service db8eaa
	snd_ctl_elem_type_t type;
Packit Service db8eaa
	unsigned int idx, count;
Packit Service db8eaa
Packit Service db8eaa
	type = snd_ctl_elem_info_get_type(info);
Packit Service db8eaa
	if (type != SND_CTL_ELEM_TYPE_BYTES) {
Packit Service db8eaa
		uc_error("only support byte type!");
Packit Service db8eaa
		err = -EINVAL;
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	fd = open(filepath, O_RDONLY);
Packit Service db8eaa
	if (fd < 0) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (stat(filepath, &st) == -1) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		goto __fail;
Packit Service db8eaa
	}
Packit Service db8eaa
	sz = st.st_size;
Packit Service db8eaa
	count = snd_ctl_elem_info_get_count(info);
Packit Service db8eaa
	if (sz != count || sz > sizeof(dst->value.bytes)) {
Packit Service db8eaa
		uc_error("invalid parameter size %d!", sz);
Packit Service db8eaa
		err = -EINVAL;
Packit Service db8eaa
		goto __fail;
Packit Service db8eaa
	}
Packit Service db8eaa
	res = malloc(sz);
Packit Service db8eaa
	if (res == NULL) {
Packit Service db8eaa
		err = -ENOMEM;
Packit Service db8eaa
		goto __fail;
Packit Service db8eaa
	}
Packit Service db8eaa
	sz_read = read(fd, res, sz);
Packit Service db8eaa
	if (sz_read < 0 || (size_t)sz_read != sz) {
Packit Service db8eaa
		err = -errno;
Packit Service db8eaa
		goto __fail_read;
Packit Service db8eaa
	}
Packit Service db8eaa
	for (idx = 0; idx < sz; idx++)
Packit Service db8eaa
		snd_ctl_elem_value_set_byte(dst, idx, *(res + idx));
Packit Service db8eaa
      __fail_read:
Packit Service db8eaa
	free(res);
Packit Service db8eaa
      __fail:
Packit Service db8eaa
	close(fd);
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
extern int __snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst,
Packit Service db8eaa
					 const char *str,
Packit Service db8eaa
					 const char **ret_ptr);
Packit Service db8eaa
Packit Service db8eaa
static int execute_cset(snd_ctl_t *ctl, const char *cset, unsigned int type)
Packit Service db8eaa
{
Packit Service db8eaa
	const char *pos;
Packit Service db8eaa
	int err;
Packit Service db8eaa
	snd_ctl_elem_id_t *id;
Packit Service db8eaa
	snd_ctl_elem_value_t *value;
Packit Service db8eaa
	snd_ctl_elem_info_t *info;
Packit Service db8eaa
	unsigned int *res = NULL;
Packit Service db8eaa
Packit Service db8eaa
	snd_ctl_elem_id_malloc(&id;;
Packit Service db8eaa
	snd_ctl_elem_value_malloc(&value);
Packit Service db8eaa
	snd_ctl_elem_info_malloc(&info;;
Packit Service db8eaa
Packit Service db8eaa
	err = __snd_ctl_ascii_elem_id_parse(id, cset, &pos;;
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		goto __fail;
Packit Service db8eaa
	while (*pos && isspace(*pos))
Packit Service db8eaa
		pos++;
Packit Service db8eaa
	if (!*pos) {
Packit Service db8eaa
		uc_error("undefined value for cset >%s<", cset);
Packit Service db8eaa
		err = -EINVAL;
Packit Service db8eaa
		goto __fail;
Packit Service db8eaa
	}
Packit Service db8eaa
	snd_ctl_elem_info_set_id(info, id);
Packit Service db8eaa
	err = snd_ctl_elem_info(ctl, info);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		goto __fail;
Packit Service db8eaa
	if (type == SEQUENCE_ELEMENT_TYPE_CSET_TLV) {
Packit Service db8eaa
		if (!snd_ctl_elem_info_is_tlv_writable(info)) {
Packit Service db8eaa
			err = -EINVAL;
Packit Service db8eaa
			goto __fail;
Packit Service db8eaa
		}
Packit Service db8eaa
		err = read_tlv_file(&res, pos);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			goto __fail;
Packit Service db8eaa
		err = snd_ctl_elem_tlv_write(ctl, id, res);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			goto __fail;
Packit Service db8eaa
	} else {
Packit Service db8eaa
		snd_ctl_elem_value_set_id(value, id);
Packit Service db8eaa
		err = snd_ctl_elem_read(ctl, value);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			goto __fail;
Packit Service db8eaa
		if (type == SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE)
Packit Service db8eaa
			err = binary_file_parse(value, info, pos);
Packit Service db8eaa
		else
Packit Service db8eaa
			err = snd_ctl_ascii_value_parse(ctl, value, info, pos);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			goto __fail;
Packit Service db8eaa
		err = snd_ctl_elem_write(ctl, value);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			goto __fail;
Packit Service db8eaa
	}
Packit Service db8eaa
	err = 0;
Packit Service db8eaa
      __fail:
Packit Service db8eaa
	if (id != NULL)
Packit Service db8eaa
		free(id);
Packit Service db8eaa
	if (value != NULL)
Packit Service db8eaa
		free(value);
Packit Service db8eaa
	if (info != NULL)
Packit Service db8eaa
		free(info);
Packit Service db8eaa
	if (res != NULL)
Packit Service db8eaa
		free(res);
Packit Service db8eaa
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Execute the sequence
Packit Service db8eaa
 * \param uc_mgr Use case manager
Packit Service db8eaa
 * \param seq Sequence
Packit Service db8eaa
 * \return zero on success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int execute_sequence(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
			    struct list_head *seq,
Packit Service db8eaa
			    struct list_head *value_list1,
Packit Service db8eaa
			    struct list_head *value_list2,
Packit Service db8eaa
			    struct list_head *value_list3)
Packit Service db8eaa
{
Packit Service db8eaa
	struct list_head *pos;
Packit Service db8eaa
	struct sequence_element *s;
Packit Service db8eaa
	char *cdev = NULL;
Packit Service db8eaa
	snd_ctl_t *ctl = NULL;
Packit Service db8eaa
	struct ctl_list *ctl_list;
Packit Service db8eaa
	int err = 0;
Packit Service db8eaa
Packit Service db8eaa
	list_for_each(pos, seq) {
Packit Service db8eaa
		s = list_entry(pos, struct sequence_element, list);
Packit Service db8eaa
		switch (s->type) {
Packit Service db8eaa
		case SEQUENCE_ELEMENT_TYPE_CDEV:
Packit Service db8eaa
			cdev = strdup(s->data.cdev);
Packit Service db8eaa
			if (cdev == NULL)
Packit Service db8eaa
				goto __fail_nomem;
Packit Service db8eaa
			break;
Packit Service db8eaa
		case SEQUENCE_ELEMENT_TYPE_CSET:
Packit Service db8eaa
		case SEQUENCE_ELEMENT_TYPE_CSET_BIN_FILE:
Packit Service db8eaa
		case SEQUENCE_ELEMENT_TYPE_CSET_TLV:
Packit Service db8eaa
			if (cdev == NULL && uc_mgr->in_component_domain) {
Packit Service db8eaa
				/* For sequence of a component device, use
Packit Service db8eaa
				 * its parent's cdev stored by ucm manager.
Packit Service db8eaa
				 */
Packit Service db8eaa
				if (uc_mgr->cdev == NULL) {
Packit Service db8eaa
					uc_error("cdev is not defined!");
Packit Service db8eaa
					return err;
Packit Service db8eaa
				}
Packit Service db8eaa
Packit Service db8eaa
				cdev = strndup(uc_mgr->cdev, PATH_MAX);
Packit Service db8eaa
				if (!cdev)
Packit Service db8eaa
					return -ENOMEM;
Packit Service db8eaa
			} else if (cdev == NULL) {
Packit Service db8eaa
				char *playback_ctl = NULL;
Packit Service db8eaa
				char *capture_ctl = NULL;
Packit Service db8eaa
Packit Service db8eaa
				err = get_value3(uc_mgr, &playback_ctl, "PlaybackCTL",
Packit Service db8eaa
						 value_list1,
Packit Service db8eaa
						 value_list2,
Packit Service db8eaa
						 value_list3);
Packit Service db8eaa
				if (err < 0 && err != -ENOENT) {
Packit Service db8eaa
					uc_error("cdev is not defined!");
Packit Service db8eaa
					return err;
Packit Service db8eaa
				}
Packit Service db8eaa
				err = get_value3(uc_mgr, &capture_ctl, "CaptureCTL",
Packit Service db8eaa
						 value_list1,
Packit Service db8eaa
						 value_list2,
Packit Service db8eaa
						 value_list3);
Packit Service db8eaa
				if (err < 0 && err != -ENOENT) {
Packit Service db8eaa
					free(playback_ctl);
Packit Service db8eaa
					uc_error("cdev is not defined!");
Packit Service db8eaa
					return err;
Packit Service db8eaa
				}
Packit Service db8eaa
				if (playback_ctl == NULL &&
Packit Service db8eaa
				    capture_ctl == NULL) {
Packit Service db8eaa
					uc_error("cdev is not defined!");
Packit Service db8eaa
					return -EINVAL;
Packit Service db8eaa
				}
Packit Service db8eaa
				if (playback_ctl != NULL &&
Packit Service db8eaa
				    capture_ctl != NULL &&
Packit Service db8eaa
				    strcmp(playback_ctl, capture_ctl) != 0) {
Packit Service db8eaa
					free(playback_ctl);
Packit Service db8eaa
					free(capture_ctl);
Packit Service db8eaa
					uc_error("cdev is not equal for playback and capture!");
Packit Service db8eaa
					return -EINVAL;
Packit Service db8eaa
				}
Packit Service db8eaa
				if (playback_ctl != NULL) {
Packit Service db8eaa
					cdev = playback_ctl;
Packit Service db8eaa
					free(capture_ctl);
Packit Service db8eaa
				} else {
Packit Service db8eaa
					cdev = capture_ctl;
Packit Service db8eaa
				}
Packit Service db8eaa
			}
Packit Service db8eaa
			if (ctl == NULL) {
Packit Service db8eaa
				err = uc_mgr_open_ctl(uc_mgr, &ctl_list, cdev, 1);
Packit Service db8eaa
				if (err < 0) {
Packit Service db8eaa
					uc_error("unable to open ctl device '%s'", cdev);
Packit Service db8eaa
					goto __fail;
Packit Service db8eaa
				}
Packit Service db8eaa
				ctl = ctl_list->ctl;
Packit Service db8eaa
			}
Packit Service db8eaa
			err = execute_cset(ctl, s->data.cset, s->type);
Packit Service db8eaa
			if (err < 0) {
Packit Service db8eaa
				uc_error("unable to execute cset '%s'", s->data.cset);
Packit Service db8eaa
				goto __fail;
Packit Service db8eaa
			}
Packit Service db8eaa
			break;
Packit Service db8eaa
		case SEQUENCE_ELEMENT_TYPE_SLEEP:
Packit Service db8eaa
			usleep(s->data.sleep);
Packit Service db8eaa
			break;
Packit Service db8eaa
		case SEQUENCE_ELEMENT_TYPE_EXEC:
Packit Service db8eaa
			err = system(s->data.exec);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				goto __fail;
Packit Service db8eaa
			break;
Packit Service db8eaa
		case SEQUENCE_ELEMENT_TYPE_CMPT_SEQ:
Packit Service db8eaa
			/* Execute enable or disable sequence of a component
Packit Service db8eaa
			 * device. Pass the cdev defined by the machine device.
Packit Service db8eaa
			 */
Packit Service db8eaa
			err = execute_component_seq(uc_mgr,
Packit Service db8eaa
						    &s->data.cmpt_seq,
Packit Service db8eaa
						    value_list1,
Packit Service db8eaa
						    value_list2,
Packit Service db8eaa
						    value_list3,
Packit Service db8eaa
						    cdev);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				goto __fail;
Packit Service db8eaa
			break;
Packit Service db8eaa
		default:
Packit Service db8eaa
			uc_error("unknown sequence command %i", s->type);
Packit Service db8eaa
			break;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
	free(cdev);
Packit Service db8eaa
	return 0;
Packit Service db8eaa
      __fail_nomem:
Packit Service db8eaa
	err = -ENOMEM;
Packit Service db8eaa
      __fail:
Packit Service db8eaa
	free(cdev);
Packit Service db8eaa
	return err;
Packit Service db8eaa
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/* Execute enable or disable sequence of a component device.
Packit Service db8eaa
 *
Packit Service db8eaa
 * For a component device (a codec or embedded DSP), its sequence doesn't
Packit Service db8eaa
 * specify the sound card device 'cdev', because a component can be reused
Packit Service db8eaa
 * by different sound cards (machines). So when executing its sequence, a
Packit Service db8eaa
 * parameter 'cdev' is used to pass cdev defined by the sequence of its
Packit Service db8eaa
 * parent, the machine device. UCM manger will store the cdev when entering
Packit Service db8eaa
 * the component domain.
Packit Service db8eaa
 */
Packit Service db8eaa
static int execute_component_seq(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
				 struct component_sequence *cmpt_seq,
Packit Service db8eaa
				 struct list_head *value_list1 ATTRIBUTE_UNUSED,
Packit Service db8eaa
				 struct list_head *value_list2 ATTRIBUTE_UNUSED,
Packit Service db8eaa
				 struct list_head *value_list3 ATTRIBUTE_UNUSED,
Packit Service db8eaa
				 char *cdev)
Packit Service db8eaa
{
Packit Service db8eaa
	struct use_case_device *device = cmpt_seq->device;
Packit Service db8eaa
	struct list_head *seq;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	/* enter component domain and store cdev for the component */
Packit Service db8eaa
	uc_mgr->in_component_domain = 1;
Packit Service db8eaa
	uc_mgr->cdev = cdev;
Packit Service db8eaa
Packit Service db8eaa
	/* choose enable or disable sequence of the component device */
Packit Service db8eaa
	if (cmpt_seq->enable)
Packit Service db8eaa
		seq = &device->enable_list;
Packit Service db8eaa
	else
Packit Service db8eaa
		seq = &device->disable_list;
Packit Service db8eaa
Packit Service db8eaa
	/* excecute the sequence of the component dev */
Packit Service db8eaa
	err = execute_sequence(uc_mgr, seq,
Packit Service db8eaa
			       &device->value_list,
Packit Service db8eaa
			       &uc_mgr->active_verb->value_list,
Packit Service db8eaa
			       &uc_mgr->value_list);
Packit Service db8eaa
Packit Service db8eaa
	/* exit component domain and clear cdev */
Packit Service db8eaa
	uc_mgr->in_component_domain = 0;
Packit Service db8eaa
	uc_mgr->cdev = NULL;
Packit Service db8eaa
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int add_auto_value(snd_use_case_mgr_t *uc_mgr, const char *key, char *value)
Packit Service db8eaa
{
Packit Service db8eaa
	char *s;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	err = get_value1(uc_mgr, &value, &uc_mgr->value_list, key);
Packit Service db8eaa
	if (err == -ENOENT) {
Packit Service db8eaa
		s = strdup(value);
Packit Service db8eaa
		if (s == NULL)
Packit Service db8eaa
			return -ENOMEM;
Packit Service db8eaa
		return uc_mgr_add_value(&uc_mgr->value_list, key, s);
Packit Service db8eaa
	} else if (err < 0) {
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	free(value);
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int add_auto_values(snd_use_case_mgr_t *uc_mgr)
Packit Service db8eaa
{
Packit Service db8eaa
	struct ctl_list *ctl_list;
Packit Service db8eaa
	const char *id;
Packit Service db8eaa
	char buf[40];
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	ctl_list = uc_mgr_get_master_ctl(uc_mgr);
Packit Service db8eaa
	if (ctl_list) {
Packit Service db8eaa
		id = snd_ctl_card_info_get_id(ctl_list->ctl_info);
Packit Service db8eaa
		snprintf(buf, sizeof(buf), "hw:%s", id);
Packit Service db8eaa
		err = add_auto_value(uc_mgr, "PlaybackCTL", buf);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		err = add_auto_value(uc_mgr, "CaptureCTL", buf);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief execute default commands
Packit Service db8eaa
 * \param uc_mgr Use case manager
Packit Service db8eaa
 * \return zero on success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int set_defaults(snd_use_case_mgr_t *uc_mgr)
Packit Service db8eaa
{
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	if (uc_mgr->default_list_executed)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
	err = execute_sequence(uc_mgr, &uc_mgr->default_list,
Packit Service db8eaa
			       &uc_mgr->value_list, NULL, NULL);
Packit Service db8eaa
	if (err < 0) {
Packit Service db8eaa
		uc_error("Unable to execute default sequence");
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	uc_mgr->default_list_executed = 1;
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Import master config and execute the default sequence
Packit Service db8eaa
 * \param uc_mgr Use case manager
Packit Service db8eaa
 * \return zero on success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int import_master_config(snd_use_case_mgr_t *uc_mgr)
Packit Service db8eaa
{
Packit Service db8eaa
	int err;
Packit Service db8eaa
	
Packit Service db8eaa
	err = uc_mgr_import_master_config(uc_mgr);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
	return add_auto_values(uc_mgr);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Check, if the UCM configuration is empty
Packit Service db8eaa
 * \param uc_mgr Use case Manager
Packit Service db8eaa
 * \return zero on success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int check_empty_configuration(snd_use_case_mgr_t *uc_mgr)
Packit Service db8eaa
{
Packit Service db8eaa
	int err;
Packit Service db8eaa
	char *value;
Packit Service db8eaa
Packit Service db8eaa
	err = get_value(uc_mgr, "Linked", &value, NULL, NULL, 1);
Packit Service db8eaa
	if (err >= 0) {
Packit Service db8eaa
		err = strcasecmp(value, "true") == 0 ||
Packit Service db8eaa
		      strcmp(value, "1") == 0;
Packit Service db8eaa
		free(value);
Packit Service db8eaa
		if (err)
Packit Service db8eaa
			return 0;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (!list_empty(&uc_mgr->verb_list))
Packit Service db8eaa
		return 0;
Packit Service db8eaa
	if (!list_empty(&uc_mgr->boot_list))
Packit Service db8eaa
		return 0;
Packit Service db8eaa
	return -ENXIO;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Universal find - string in a list
Packit Service db8eaa
 * \param list List of structures
Packit Service db8eaa
 * \param offset Offset of list structure
Packit Service db8eaa
 * \param soffset Offset of string structure
Packit Service db8eaa
 * \param match String to match
Packit Service db8eaa
 * \return structure on success, otherwise a NULL (not found)
Packit Service db8eaa
 */
Packit Service db8eaa
static void *find0(struct list_head *list,
Packit Service db8eaa
		   unsigned long offset,
Packit Service db8eaa
		   unsigned long soffset,
Packit Service db8eaa
		   const char *match)
Packit Service db8eaa
{
Packit Service db8eaa
	struct list_head *pos;
Packit Service db8eaa
	char *ptr, *str;
Packit Service db8eaa
Packit Service db8eaa
	list_for_each(pos, list) {
Packit Service db8eaa
		ptr = list_entry_offset(pos, char, offset);
Packit Service db8eaa
		str = *((char **)(ptr + soffset));
Packit Service db8eaa
		if (strcmp(str, match) == 0)
Packit Service db8eaa
			return ptr;
Packit Service db8eaa
	}
Packit Service db8eaa
	return NULL;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
#define find(list, type, member, value, match) \
Packit Service db8eaa
	find0(list, (unsigned long)(&((type *)0)->member), \
Packit Service db8eaa
		    (unsigned long)(&((type *)0)->value), match)
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Universal string list
Packit Service db8eaa
 * \param list List of structures
Packit Service db8eaa
 * \param result Result list
Packit Service db8eaa
 * \param offset Offset of list structure
Packit Service db8eaa
 * \param s1offset Offset of string structure
Packit Service db8eaa
 * \return count of items on success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int get_list0(struct list_head *list,
Packit Service db8eaa
                     const char **result[],
Packit Service db8eaa
                     unsigned long offset,
Packit Service db8eaa
                     unsigned long s1offset)
Packit Service db8eaa
{
Packit Service db8eaa
        char **res;
Packit Service db8eaa
        int cnt;
Packit Service db8eaa
	struct list_head *pos;
Packit Service db8eaa
	char *ptr, *str1;
Packit Service db8eaa
Packit Service db8eaa
	cnt = alloc_str_list(list, 1, &res;;
Packit Service db8eaa
	if (cnt <= 0) {
Packit Service db8eaa
		*result = NULL;
Packit Service db8eaa
	        return cnt;
Packit Service db8eaa
	}
Packit Service db8eaa
	*result = (const char **)res;
Packit Service db8eaa
	list_for_each(pos, list) {
Packit Service db8eaa
		ptr = list_entry_offset(pos, char, offset);
Packit Service db8eaa
		str1 = *((char **)(ptr + s1offset));
Packit Service db8eaa
		if (str1 != NULL) {
Packit Service db8eaa
		        *res = strdup(str1);
Packit Service db8eaa
		        if (*res == NULL)
Packit Service db8eaa
		                goto __fail;
Packit Service db8eaa
                } else {
Packit Service db8eaa
                        *res = NULL;
Packit Service db8eaa
                }
Packit Service db8eaa
                res++;
Packit Service db8eaa
	}
Packit Service db8eaa
	return cnt;
Packit Service db8eaa
      __fail:
Packit Service 45dc4a
        snd_use_case_free_list((const char **)res, cnt);
Packit Service db8eaa
        return -ENOMEM;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
#define get_list(list, result, type, member, s1) \
Packit Service db8eaa
	get_list0(list, result, \
Packit Service db8eaa
	            (unsigned long)(&((type *)0)->member), \
Packit Service db8eaa
		    (unsigned long)(&((type *)0)->s1))
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Universal string list - pair of strings
Packit Service db8eaa
 * \param list List of structures
Packit Service db8eaa
 * \param result Result list
Packit Service db8eaa
 * \param offset Offset of list structure
Packit Service db8eaa
 * \param s1offset Offset of string structure
Packit Service db8eaa
 * \param s1offset Offset of string structure
Packit Service db8eaa
 * \return count of items on success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int get_list20(struct list_head *list,
Packit Service db8eaa
                      const char **result[],
Packit Service db8eaa
                      unsigned long offset,
Packit Service db8eaa
                      unsigned long s1offset,
Packit Service db8eaa
                      unsigned long s2offset)
Packit Service db8eaa
{
Packit Service db8eaa
        char **res;
Packit Service db8eaa
        int cnt;
Packit Service db8eaa
	struct list_head *pos;
Packit Service db8eaa
	char *ptr, *str1, *str2;
Packit Service db8eaa
Packit Service db8eaa
	cnt = alloc_str_list(list, 2, &res;;
Packit Service db8eaa
	if (cnt <= 0) {
Packit Service db8eaa
		*result = NULL;
Packit Service db8eaa
	        return cnt;
Packit Service db8eaa
	}
Packit Service db8eaa
        *result = (const char **)res;
Packit Service db8eaa
	list_for_each(pos, list) {
Packit Service db8eaa
		ptr = list_entry_offset(pos, char, offset);
Packit Service db8eaa
		str1 = *((char **)(ptr + s1offset));
Packit Service db8eaa
		if (str1 != NULL) {
Packit Service db8eaa
		        *res = strdup(str1);
Packit Service db8eaa
		        if (*res == NULL)
Packit Service db8eaa
		                goto __fail;
Packit Service db8eaa
                } else {
Packit Service db8eaa
                        *res = NULL;
Packit Service db8eaa
                }
Packit Service db8eaa
                res++;
Packit Service db8eaa
		str2 = *((char **)(ptr + s2offset));
Packit Service db8eaa
		if (str2 != NULL) {
Packit Service db8eaa
		        *res = strdup(str2);
Packit Service db8eaa
		        if (*res == NULL)
Packit Service db8eaa
		                goto __fail;
Packit Service db8eaa
                } else {
Packit Service db8eaa
                        *res = NULL;
Packit Service db8eaa
                }
Packit Service db8eaa
                res++;
Packit Service db8eaa
	}
Packit Service db8eaa
	return cnt;
Packit Service db8eaa
      __fail:
Packit Service 45dc4a
        snd_use_case_free_list((const char **)res, cnt);
Packit Service db8eaa
        return -ENOMEM;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
#define get_list2(list, result, type, member, s1, s2) \
Packit Service db8eaa
	get_list20(list, result, \
Packit Service db8eaa
	            (unsigned long)(&((type *)0)->member), \
Packit Service db8eaa
		    (unsigned long)(&((type *)0)->s1), \
Packit Service db8eaa
		    (unsigned long)(&((type *)0)->s2))
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Find verb
Packit Service db8eaa
 * \param uc_mgr Use case manager
Packit Service db8eaa
 * \param verb_name verb to find
Packit Service db8eaa
 * \return structure on success, otherwise a NULL (not found)
Packit Service db8eaa
 */
Packit Service db8eaa
static inline struct use_case_verb *find_verb(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
					      const char *verb_name)
Packit Service db8eaa
{
Packit Service db8eaa
	return find(&uc_mgr->verb_list,
Packit Service db8eaa
		    struct use_case_verb, list, name,
Packit Service db8eaa
		    verb_name);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int is_devlist_supported(snd_use_case_mgr_t *uc_mgr, 
Packit Service db8eaa
	struct dev_list *dev_list)
Packit Service db8eaa
{
Packit Service db8eaa
	struct dev_list_node *device;
Packit Service db8eaa
	struct use_case_device *adev;
Packit Service db8eaa
	struct list_head *pos, *pos1;
Packit Service db8eaa
	int found_ret;
Packit Service db8eaa
Packit Service db8eaa
	switch (dev_list->type) {
Packit Service db8eaa
	case DEVLIST_NONE:
Packit Service db8eaa
	default:
Packit Service db8eaa
		return 1;
Packit Service db8eaa
	case DEVLIST_SUPPORTED:
Packit Service db8eaa
		found_ret = 1;
Packit Service db8eaa
		break;
Packit Service db8eaa
	case DEVLIST_CONFLICTING:
Packit Service db8eaa
		found_ret = 0;
Packit Service db8eaa
		break;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	list_for_each(pos, &dev_list->list) {
Packit Service db8eaa
		device = list_entry(pos, struct dev_list_node, list);
Packit Service db8eaa
Packit Service db8eaa
		list_for_each(pos1, &uc_mgr->active_devices) {
Packit Service db8eaa
			adev = list_entry(pos1, struct use_case_device,
Packit Service db8eaa
					    active_list);
Packit Service db8eaa
			if (!strcmp(device->name, adev->name))
Packit Service db8eaa
				return found_ret;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
	return 1 - found_ret;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static inline int is_modifier_supported(snd_use_case_mgr_t *uc_mgr, 
Packit Service db8eaa
	struct use_case_modifier *modifier)
Packit Service db8eaa
{
Packit Service db8eaa
	return is_devlist_supported(uc_mgr, &modifier->dev_list);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static inline int is_device_supported(snd_use_case_mgr_t *uc_mgr, 
Packit Service db8eaa
	struct use_case_device *device)
Packit Service db8eaa
{
Packit Service db8eaa
	return is_devlist_supported(uc_mgr, &device->dev_list);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Find device
Packit Service db8eaa
 * \param verb Use case verb
Packit Service db8eaa
 * \param device_name device to find
Packit Service db8eaa
 * \return structure on success, otherwise a NULL (not found)
Packit Service db8eaa
 */
Packit Service db8eaa
static inline struct use_case_device *
Packit Service db8eaa
        find_device(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb,
Packit Service db8eaa
		    const char *device_name, int check_supported)
Packit Service db8eaa
{
Packit Service db8eaa
	struct use_case_device *device;
Packit Service db8eaa
	struct list_head *pos;
Packit Service db8eaa
Packit Service db8eaa
	list_for_each(pos, &verb->device_list) {
Packit Service db8eaa
		device = list_entry(pos, struct use_case_device, list);
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(device_name, device->name))
Packit Service db8eaa
			continue;
Packit Service db8eaa
Packit Service db8eaa
		if (check_supported &&
Packit Service db8eaa
		    !is_device_supported(uc_mgr, device))
Packit Service db8eaa
			continue;
Packit Service db8eaa
Packit Service db8eaa
		return device;
Packit Service db8eaa
	}
Packit Service db8eaa
	return NULL;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Find modifier
Packit Service db8eaa
 * \param verb Use case verb
Packit Service db8eaa
 * \param modifier_name modifier to find
Packit Service db8eaa
 * \return structure on success, otherwise a NULL (not found)
Packit Service db8eaa
 */
Packit Service db8eaa
static struct use_case_modifier *
Packit Service db8eaa
        find_modifier(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb,
Packit Service db8eaa
		      const char *modifier_name, int check_supported)
Packit Service db8eaa
{
Packit Service db8eaa
	struct use_case_modifier *modifier;
Packit Service db8eaa
	struct list_head *pos;
Packit Service db8eaa
Packit Service db8eaa
	list_for_each(pos, &verb->modifier_list) {
Packit Service db8eaa
		modifier = list_entry(pos, struct use_case_modifier, list);
Packit Service db8eaa
Packit Service db8eaa
		if (strcmp(modifier->name, modifier_name))
Packit Service db8eaa
			continue;
Packit Service db8eaa
Packit Service db8eaa
		if (check_supported &&
Packit Service db8eaa
		    !is_modifier_supported(uc_mgr, modifier))
Packit Service db8eaa
			continue;
Packit Service db8eaa
Packit Service db8eaa
		return modifier;
Packit Service db8eaa
	}
Packit Service db8eaa
	return NULL;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
long device_status(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
                   const char *device_name)
Packit Service db8eaa
{
Packit Service db8eaa
        struct use_case_device *dev;
Packit Service db8eaa
        struct list_head *pos;
Packit Service db8eaa
Packit Service db8eaa
        list_for_each(pos, &uc_mgr->active_devices) {
Packit Service db8eaa
                dev = list_entry(pos, struct use_case_device, active_list);
Packit Service db8eaa
                if (strcmp(dev->name, device_name) == 0)
Packit Service db8eaa
                        return 1;
Packit Service db8eaa
        }
Packit Service db8eaa
        return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
long modifier_status(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
                     const char *modifier_name)
Packit Service db8eaa
{
Packit Service db8eaa
        struct use_case_modifier *mod;
Packit Service db8eaa
        struct list_head *pos;
Packit Service db8eaa
Packit Service db8eaa
        list_for_each(pos, &uc_mgr->active_modifiers) {
Packit Service db8eaa
                mod = list_entry(pos, struct use_case_modifier, active_list);
Packit Service db8eaa
                if (strcmp(mod->name, modifier_name) == 0)
Packit Service db8eaa
                        return 1;
Packit Service db8eaa
        }
Packit Service db8eaa
        return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Set verb
Packit Service db8eaa
 * \param uc_mgr Use case manager
Packit Service db8eaa
 * \param verb verb to set
Packit Service db8eaa
 * \param enable nonzero = enable, zero = disable
Packit Service db8eaa
 * \return zero on success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int set_verb(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
		    struct use_case_verb *verb,
Packit Service db8eaa
		    int enable)
Packit Service db8eaa
{
Packit Service db8eaa
	struct list_head *seq;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	if (enable) {
Packit Service db8eaa
		err = set_defaults(uc_mgr);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
		seq = &verb->enable_list;
Packit Service db8eaa
	} else {
Packit Service db8eaa
		seq = &verb->disable_list;
Packit Service db8eaa
	}
Packit Service db8eaa
	err = execute_sequence(uc_mgr, seq,
Packit Service db8eaa
			       &verb->value_list,
Packit Service db8eaa
			       &uc_mgr->value_list,
Packit Service db8eaa
			       NULL);
Packit Service db8eaa
	if (enable && err >= 0)
Packit Service db8eaa
		uc_mgr->active_verb = verb;
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Set modifier
Packit Service db8eaa
 * \param uc_mgr Use case manager
Packit Service db8eaa
 * \param modifier modifier to set
Packit Service db8eaa
 * \param enable nonzero = enable, zero = disable
Packit Service db8eaa
 * \return zero on success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int set_modifier(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
			struct use_case_modifier *modifier,
Packit Service db8eaa
			int enable)
Packit Service db8eaa
{
Packit Service db8eaa
	struct list_head *seq;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	if (modifier_status(uc_mgr, modifier->name) == enable)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
Packit Service db8eaa
	if (enable) {
Packit Service db8eaa
		seq = &modifier->enable_list;
Packit Service db8eaa
	} else {
Packit Service db8eaa
		seq = &modifier->disable_list;
Packit Service db8eaa
	}
Packit Service db8eaa
	err = execute_sequence(uc_mgr, seq,
Packit Service db8eaa
			       &modifier->value_list,
Packit Service db8eaa
			       &uc_mgr->active_verb->value_list,
Packit Service db8eaa
			       &uc_mgr->value_list);
Packit Service db8eaa
	if (enable && err >= 0) {
Packit Service db8eaa
		list_add_tail(&modifier->active_list, &uc_mgr->active_modifiers);
Packit Service db8eaa
	} else if (!enable) {
Packit Service db8eaa
		list_del(&modifier->active_list);
Packit Service db8eaa
	}
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Set device
Packit Service db8eaa
 * \param uc_mgr Use case manager
Packit Service db8eaa
 * \param device device to set
Packit Service db8eaa
 * \param enable nonzero = enable, zero = disable
Packit Service db8eaa
 * \return zero on success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int set_device(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
		      struct use_case_device *device,
Packit Service db8eaa
		      int enable)
Packit Service db8eaa
{
Packit Service db8eaa
	struct list_head *seq;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
        if (device_status(uc_mgr, device->name) == enable)
Packit Service db8eaa
		return 0;
Packit Service db8eaa
Packit Service db8eaa
	if (enable) {
Packit Service db8eaa
		seq = &device->enable_list;
Packit Service db8eaa
	} else {
Packit Service db8eaa
		seq = &device->disable_list;
Packit Service db8eaa
	}
Packit Service db8eaa
	err = execute_sequence(uc_mgr, seq,
Packit Service db8eaa
			       &device->value_list,
Packit Service db8eaa
			       &uc_mgr->active_verb->value_list,
Packit Service db8eaa
			       &uc_mgr->value_list);
Packit Service db8eaa
	if (enable && err >= 0) {
Packit Service db8eaa
		list_add_tail(&device->active_list, &uc_mgr->active_devices);
Packit Service db8eaa
	} else if (!enable) {
Packit Service db8eaa
		list_del(&device->active_list);
Packit Service db8eaa
	}
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Init sound card use case manager.
Packit Service db8eaa
 * \param uc_mgr Returned use case manager pointer
Packit Service db8eaa
 * \param card_name name of card to open
Packit Service db8eaa
 * \return zero on success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_use_case_mgr_open(snd_use_case_mgr_t **uc_mgr,
Packit Service db8eaa
			  const char *card_name)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_use_case_mgr_t *mgr;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	/* create a new UCM */
Packit Service db8eaa
	mgr = calloc(1, sizeof(snd_use_case_mgr_t));
Packit Service db8eaa
	if (mgr == NULL)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
	INIT_LIST_HEAD(&mgr->verb_list);
Packit Service db8eaa
	INIT_LIST_HEAD(&mgr->boot_list);
Packit Service db8eaa
	INIT_LIST_HEAD(&mgr->default_list);
Packit Service db8eaa
	INIT_LIST_HEAD(&mgr->value_list);
Packit Service db8eaa
	INIT_LIST_HEAD(&mgr->active_modifiers);
Packit Service db8eaa
	INIT_LIST_HEAD(&mgr->active_devices);
Packit Service db8eaa
	INIT_LIST_HEAD(&mgr->ctl_list);
Packit Service db8eaa
	INIT_LIST_HEAD(&mgr->variable_list);
Packit Service db8eaa
	pthread_mutex_init(&mgr->mutex, NULL);
Packit Service db8eaa
Packit Service db8eaa
	mgr->card_name = strdup(card_name);
Packit Service db8eaa
	if (mgr->card_name == NULL) {
Packit Service db8eaa
		free(mgr);
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	/* get info on use_cases and verify against card */
Packit Service db8eaa
	err = import_master_config(mgr);
Packit Service db8eaa
	if (err < 0) {
Packit Service db8eaa
		uc_error("error: failed to import %s use case configuration %d",
Packit Service db8eaa
			 card_name, err);
Packit Service db8eaa
		goto _err;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	err = check_empty_configuration(mgr);
Packit Service db8eaa
	if (err < 0) {
Packit Service db8eaa
		uc_error("error: failed to import %s (empty configuration)", card_name);
Packit Service db8eaa
		goto _err;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	*uc_mgr = mgr;
Packit Service db8eaa
	return 0;
Packit Service db8eaa
Packit Service db8eaa
_err:
Packit Service db8eaa
	uc_mgr_free(mgr);
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Reload and reparse all use case files.
Packit Service db8eaa
 * \param uc_mgr Use case manager
Packit Service db8eaa
 * \return zero on success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr)
Packit Service db8eaa
{
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	pthread_mutex_lock(&uc_mgr->mutex);
Packit Service db8eaa
Packit Service db8eaa
	uc_mgr_free_verb(uc_mgr);
Packit Service db8eaa
Packit Service db8eaa
	uc_mgr->default_list_executed = 0;
Packit Service db8eaa
Packit Service db8eaa
	/* reload all use cases */
Packit Service db8eaa
	err = import_master_config(uc_mgr);
Packit Service db8eaa
	if (err < 0) {
Packit Service db8eaa
		uc_error("error: failed to reload use cases");
Packit Service db8eaa
		pthread_mutex_unlock(&uc_mgr->mutex);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	pthread_mutex_unlock(&uc_mgr->mutex);
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Close use case manager.
Packit Service db8eaa
 * \param uc_mgr Use case manager
Packit Service db8eaa
 * \return zero on success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr)
Packit Service db8eaa
{
Packit Service db8eaa
	uc_mgr_free(uc_mgr);
Packit Service db8eaa
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/*
Packit Service db8eaa
 * Tear down current use case verb, device and modifier.
Packit Service db8eaa
 */
Packit Service db8eaa
static int dismantle_use_case(snd_use_case_mgr_t *uc_mgr)
Packit Service db8eaa
{
Packit Service db8eaa
	struct list_head *pos, *npos;
Packit Service db8eaa
	struct use_case_modifier *modifier;
Packit Service db8eaa
	struct use_case_device *device;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	list_for_each_safe(pos, npos, &uc_mgr->active_modifiers) {
Packit Service db8eaa
		modifier = list_entry(pos, struct use_case_modifier,
Packit Service db8eaa
				      active_list);
Packit Service db8eaa
		err = set_modifier(uc_mgr, modifier, 0);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			uc_error("Unable to disable modifier %s", modifier->name);
Packit Service db8eaa
	}
Packit Service db8eaa
	INIT_LIST_HEAD(&uc_mgr->active_modifiers);
Packit Service db8eaa
Packit Service db8eaa
	list_for_each_safe(pos, npos, &uc_mgr->active_devices) {
Packit Service db8eaa
		device = list_entry(pos, struct use_case_device,
Packit Service db8eaa
				    active_list);
Packit Service db8eaa
		err = set_device(uc_mgr, device, 0);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			uc_error("Unable to disable device %s", device->name);
Packit Service db8eaa
	}
Packit Service db8eaa
	INIT_LIST_HEAD(&uc_mgr->active_devices);
Packit Service db8eaa
Packit Service db8eaa
	err = set_verb(uc_mgr, uc_mgr->active_verb, 0);
Packit Service db8eaa
	if (err < 0) {
Packit Service db8eaa
		uc_error("Unable to disable verb %s", uc_mgr->active_verb->name);
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	uc_mgr->active_verb = NULL;
Packit Service db8eaa
Packit Service db8eaa
	err = execute_sequence(uc_mgr, &uc_mgr->default_list,
Packit Service db8eaa
			       &uc_mgr->value_list, NULL, NULL);
Packit Service db8eaa
	
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Reset sound card controls to default values.
Packit Service db8eaa
 * \param uc_mgr Use case manager
Packit Service db8eaa
 * \return zero on success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
Packit Service db8eaa
{
Packit Service db8eaa
        int err;
Packit Service db8eaa
Packit Service db8eaa
	pthread_mutex_lock(&uc_mgr->mutex);
Packit Service db8eaa
	err = execute_sequence(uc_mgr, &uc_mgr->default_list,
Packit Service db8eaa
			       &uc_mgr->value_list, NULL, NULL);
Packit Service db8eaa
	INIT_LIST_HEAD(&uc_mgr->active_modifiers);
Packit Service db8eaa
	INIT_LIST_HEAD(&uc_mgr->active_devices);
Packit Service db8eaa
	uc_mgr->active_verb = NULL;
Packit Service db8eaa
	pthread_mutex_unlock(&uc_mgr->mutex);
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get list of verbs in pair verbname+comment
Packit Service db8eaa
 * \param list Returned list
Packit Service db8eaa
 * \return Number of list entries if success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int get_verb_list(snd_use_case_mgr_t *uc_mgr, const char **list[])
Packit Service db8eaa
{
Packit Service db8eaa
        return get_list2(&uc_mgr->verb_list, list,
Packit Service db8eaa
                         struct use_case_verb, list,
Packit Service db8eaa
                         name, comment);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get list of devices in pair devicename+comment
Packit Service db8eaa
 * \param list Returned list
Packit Service db8eaa
 * \param verbname For verb (NULL = current)
Packit Service db8eaa
 * \return Number of list entries if success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int get_device_list(snd_use_case_mgr_t *uc_mgr, const char **list[],
Packit Service db8eaa
                           char *verbname)
Packit Service db8eaa
{
Packit Service db8eaa
        struct use_case_verb *verb;
Packit Service db8eaa
        
Packit Service db8eaa
        if (verbname) {
Packit Service db8eaa
                verb = find_verb(uc_mgr, verbname);
Packit Service db8eaa
        } else {
Packit Service db8eaa
                verb = uc_mgr->active_verb;
Packit Service db8eaa
        }
Packit Service db8eaa
        if (verb == NULL)
Packit Service db8eaa
                return -ENOENT;
Packit Service db8eaa
        return get_list2(&verb->device_list, list,
Packit Service db8eaa
                         struct use_case_device, list,
Packit Service db8eaa
                         name, comment);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get list of modifiers in pair devicename+comment
Packit Service db8eaa
 * \param list Returned list
Packit Service db8eaa
 * \param verbname For verb (NULL = current)
Packit Service db8eaa
 * \return Number of list entries if success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int get_modifier_list(snd_use_case_mgr_t *uc_mgr, const char **list[],
Packit Service db8eaa
                             char *verbname)
Packit Service db8eaa
{
Packit Service db8eaa
        struct use_case_verb *verb;
Packit Service db8eaa
        
Packit Service db8eaa
        if (verbname) {
Packit Service db8eaa
                verb = find_verb(uc_mgr, verbname);
Packit Service db8eaa
        } else {
Packit Service db8eaa
                verb = uc_mgr->active_verb;
Packit Service db8eaa
        }
Packit Service db8eaa
        if (verb == NULL)
Packit Service db8eaa
                return -ENOENT;
Packit Service db8eaa
        return get_list2(&verb->modifier_list, list,
Packit Service db8eaa
                         struct use_case_modifier, list,
Packit Service db8eaa
                         name, comment);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get list of supported/conflicting devices
Packit Service db8eaa
 * \param list Returned list
Packit Service db8eaa
 * \param name Name of modifier or verb to query
Packit Service db8eaa
 * \param type Type of device list entries to return
Packit Service db8eaa
 * \return Number of list entries if success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int get_supcon_device_list(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
				  const char **list[], char *name,
Packit Service db8eaa
				  enum dev_list_type type)
Packit Service db8eaa
{
Packit Service db8eaa
	char *str;
Packit Service db8eaa
	struct use_case_verb *verb;
Packit Service db8eaa
	struct use_case_modifier *modifier;
Packit Service db8eaa
	struct use_case_device *device;
Packit Service db8eaa
Packit Service db8eaa
	if (!name)
Packit Service db8eaa
		return -ENOENT;
Packit Service db8eaa
Packit Service db8eaa
	str = strchr(name, '/');
Packit Service db8eaa
	if (str) {
Packit Service db8eaa
		*str = '\0';
Packit Service db8eaa
		verb = find_verb(uc_mgr, str + 1);
Packit Service db8eaa
	}
Packit Service db8eaa
	else {
Packit Service db8eaa
		verb = uc_mgr->active_verb;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (!verb)
Packit Service db8eaa
		return -ENOENT;
Packit Service db8eaa
Packit Service db8eaa
	modifier = find_modifier(uc_mgr, verb, name, 0);
Packit Service db8eaa
	if (modifier) {
Packit Service db8eaa
		if (modifier->dev_list.type != type) {
Packit Service db8eaa
			*list = NULL;
Packit Service db8eaa
			return 0;
Packit Service db8eaa
		}
Packit Service db8eaa
		return get_list(&modifier->dev_list.list, list,
Packit Service db8eaa
				struct dev_list_node, list,
Packit Service db8eaa
				name);
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	device = find_device(uc_mgr, verb, name, 0);
Packit Service db8eaa
	if (device) {
Packit Service db8eaa
		if (device->dev_list.type != type) {
Packit Service db8eaa
			*list = NULL;
Packit Service db8eaa
			return 0;
Packit Service db8eaa
		}
Packit Service db8eaa
		return get_list(&device->dev_list.list, list,
Packit Service db8eaa
				struct dev_list_node, list,
Packit Service db8eaa
				name);
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	return -ENOENT;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get list of supported devices
Packit Service db8eaa
 * \param list Returned list
Packit Service db8eaa
 * \param name Name of verb or modifier to query
Packit Service db8eaa
 * \return Number of list entries if success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int get_supported_device_list(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
				     const char **list[], char *name)
Packit Service db8eaa
{
Packit Service db8eaa
	return get_supcon_device_list(uc_mgr, list, name, DEVLIST_SUPPORTED);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get list of conflicting devices
Packit Service db8eaa
 * \param list Returned list
Packit Service db8eaa
 * \param name Name of verb or modifier to query
Packit Service db8eaa
 * \return Number of list entries if success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int get_conflicting_device_list(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
				       const char **list[], char *name)
Packit Service db8eaa
{
Packit Service db8eaa
	return get_supcon_device_list(uc_mgr, list, name, DEVLIST_CONFLICTING);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
#ifndef DOC_HIDDEN
Packit Service db8eaa
struct myvalue {
Packit Service db8eaa
	struct list_head list;
Packit Service db8eaa
	const char *text;
Packit Service db8eaa
};
Packit Service db8eaa
#endif
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Convert myvalue list string list
Packit Service db8eaa
 * \param list myvalue list
Packit Service db8eaa
 * \param res string list
Packit Service db8eaa
 * \retval Number of list entries if success, otherwise a negativer error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int myvalue_to_str_list(struct list_head *list, char ***res)
Packit Service db8eaa
{
Packit Service db8eaa
	struct list_head *pos;
Packit Service db8eaa
	struct myvalue *value;
Packit Service db8eaa
	char **p;
Packit Service db8eaa
	int cnt;
Packit Service db8eaa
Packit Service db8eaa
	cnt = alloc_str_list(list, 1, res);
Packit Service db8eaa
	if (cnt < 0)
Packit Service db8eaa
		return cnt;
Packit Service db8eaa
	p = *res;
Packit Service db8eaa
	list_for_each(pos, list) {
Packit Service db8eaa
		value = list_entry(pos, struct myvalue, list);
Packit Service db8eaa
		*p = strdup(value->text);
Packit Service db8eaa
		if (*p == NULL) {
Packit Service db8eaa
			snd_use_case_free_list((const char **)p, cnt);
Packit Service db8eaa
			return -ENOMEM;
Packit Service db8eaa
		}
Packit Service db8eaa
		p++;
Packit Service db8eaa
	}
Packit Service db8eaa
	return cnt;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Free myvalue list
Packit Service db8eaa
 * \param list myvalue list
Packit Service db8eaa
 */
Packit Service db8eaa
static void myvalue_list_free(struct list_head *list)
Packit Service db8eaa
{
Packit Service db8eaa
	struct list_head *pos, *npos;
Packit Service db8eaa
	struct myvalue *value;
Packit Service db8eaa
Packit Service db8eaa
	list_for_each_safe(pos, npos, list) {
Packit Service db8eaa
		value = list_entry(pos, struct myvalue, list);
Packit Service db8eaa
		list_del(&value->list);
Packit Service db8eaa
		free(value);
Packit Service db8eaa
	}
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Merge one value to the myvalue list
Packit Service db8eaa
 * \param list The list with values
Packit Service db8eaa
 * \param value The value to be merged (without duplicates)
Packit Service db8eaa
 * \return 1 if dup, 0 if success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int merge_value(struct list_head *list, const char *text)
Packit Service db8eaa
{
Packit Service db8eaa
	struct list_head *pos;
Packit Service db8eaa
	struct myvalue *value;
Packit Service db8eaa
Packit Service db8eaa
	list_for_each(pos, list) {
Packit Service db8eaa
		value = list_entry(pos, struct myvalue, list);
Packit Service db8eaa
		if (strcmp(value->text, text) == 0)
Packit Service db8eaa
			return 1;
Packit Service db8eaa
	}
Packit Service db8eaa
	value = malloc(sizeof(*value));
Packit Service db8eaa
	if (value == NULL)
Packit Service db8eaa
		return -ENOMEM;
Packit Service db8eaa
	value->text = text;
Packit Service db8eaa
	list_add_tail(&value->list, list);
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Find all values for given identifier
Packit Service db8eaa
 * \param list Returned list
Packit Service db8eaa
 * \param source Source list with ucm_value structures
Packit Service db8eaa
 * \return Zero if success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int add_identifiers(struct list_head *list,
Packit Service db8eaa
			   struct list_head *source)
Packit Service db8eaa
{
Packit Service db8eaa
	struct ucm_value *v;
Packit Service db8eaa
	struct list_head *pos;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	list_for_each(pos, source) {
Packit Service db8eaa
		v = list_entry(pos, struct ucm_value, list);
Packit Service db8eaa
		err = merge_value(list, v->name);
Packit Service db8eaa
		if (err < 0)
Packit Service db8eaa
			return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Find all values for given identifier
Packit Service db8eaa
 * \param list Returned list
Packit Service db8eaa
 * \param identifier Identifier
Packit Service db8eaa
 * \param source Source list with ucm_value structures
Packit Service db8eaa
 */
Packit Service db8eaa
static int add_values(struct list_head *list,
Packit Service db8eaa
                      const char *identifier,
Packit Service db8eaa
                      struct list_head *source)
Packit Service db8eaa
{
Packit Service db8eaa
	struct ucm_value *v;
Packit Service db8eaa
	struct list_head *pos;
Packit Service db8eaa
	int err;
Packit Service db8eaa
        
Packit Service db8eaa
	list_for_each(pos, source) {
Packit Service db8eaa
		v = list_entry(pos, struct ucm_value, list);
Packit Service db8eaa
		if (check_identifier(identifier, v->name)) {
Packit Service db8eaa
			err = merge_value(list, v->data);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				return err;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief compare two identifiers
Packit Service db8eaa
 */
Packit Service db8eaa
static int identifier_cmp(const void *_a, const void *_b)
Packit Service db8eaa
{
Packit Service db8eaa
	const char * const *a = _a;
Packit Service db8eaa
	const char * const *b = _b;
Packit Service db8eaa
	return strcmp(*a, *b);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get list of available identifiers
Packit Service db8eaa
 * \param list Returned list
Packit Service db8eaa
 * \param name Name of verb or modifier to query
Packit Service db8eaa
 * \return Number of list entries if success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int get_identifiers_list(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
				const char **list[], char *name)
Packit Service db8eaa
{
Packit Service db8eaa
	struct use_case_verb *verb;
Packit Service db8eaa
	struct use_case_modifier *modifier;
Packit Service db8eaa
	struct use_case_device *device;
Packit Service db8eaa
	struct list_head mylist;
Packit Service db8eaa
	struct list_head *value_list;
Packit Service db8eaa
	char *str, **res;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	if (!name)
Packit Service db8eaa
		return -ENOENT;
Packit Service db8eaa
Packit Service db8eaa
	str = strchr(name, '/');
Packit Service db8eaa
	if (str) {
Packit Service db8eaa
		*str = '\0';
Packit Service db8eaa
		verb = find_verb(uc_mgr, str + 1);
Packit Service db8eaa
	}
Packit Service db8eaa
	else {
Packit Service db8eaa
		verb = uc_mgr->active_verb;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (!verb)
Packit Service db8eaa
		return -ENOENT;
Packit Service db8eaa
Packit Service db8eaa
	value_list = NULL;
Packit Service db8eaa
	modifier = find_modifier(uc_mgr, verb, name, 0);
Packit Service db8eaa
	if (modifier) {
Packit Service db8eaa
		value_list = &modifier->value_list;
Packit Service db8eaa
	} else {
Packit Service db8eaa
		device = find_device(uc_mgr, verb, name, 0);
Packit Service db8eaa
		if (device)
Packit Service db8eaa
			value_list = &device->value_list;
Packit Service db8eaa
	}
Packit Service db8eaa
	if (value_list == NULL)
Packit Service db8eaa
		return -ENOENT;
Packit Service db8eaa
Packit Service db8eaa
	INIT_LIST_HEAD(&mylist);
Packit Service db8eaa
	err = add_identifiers(&mylist, &uc_mgr->value_list);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		goto __fail;
Packit Service db8eaa
	err = add_identifiers(&mylist, &verb->value_list);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		goto __fail;
Packit Service db8eaa
	err = add_identifiers(&mylist, value_list);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		goto __fail;
Packit Service db8eaa
	err = myvalue_to_str_list(&mylist, &res;;
Packit Service db8eaa
	if (err > 0)
Packit Service db8eaa
		*list = (const char **)res;
Packit Service db8eaa
	else if (err == 0)
Packit Service db8eaa
		*list = NULL;
Packit Service db8eaa
__fail:
Packit Service db8eaa
	myvalue_list_free(&mylist);
Packit Service db8eaa
	if (err <= 0)
Packit Service db8eaa
		return err;
Packit Service db8eaa
	qsort(*list, err, sizeof(char *), identifier_cmp);
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get list of values
Packit Service db8eaa
 * \param list Returned list
Packit Service db8eaa
 * \param verbname For verb (NULL = current)
Packit Service db8eaa
 * \return Number of list entries if success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int get_value_list(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
                          const char *identifier,
Packit Service db8eaa
                          const char **list[],
Packit Service db8eaa
                          char *verbname)
Packit Service db8eaa
{
Packit Service db8eaa
	struct list_head mylist, *pos;
Packit Service db8eaa
        struct use_case_verb *verb;
Packit Service db8eaa
        struct use_case_device *dev;
Packit Service db8eaa
        struct use_case_modifier *mod;
Packit Service db8eaa
        char **res;
Packit Service db8eaa
        int err;
Packit Service db8eaa
        
Packit Service db8eaa
        if (verbname) {
Packit Service db8eaa
                verb = find_verb(uc_mgr, verbname);
Packit Service db8eaa
        } else {
Packit Service db8eaa
                verb = uc_mgr->active_verb;
Packit Service db8eaa
        }
Packit Service db8eaa
        if (verb == NULL)
Packit Service db8eaa
                return -ENOENT;
Packit Service db8eaa
        INIT_LIST_HEAD(&mylist);
Packit Service db8eaa
	err = add_values(&mylist, identifier, &uc_mgr->value_list);
Packit Service db8eaa
	if (err < 0)
Packit Service db8eaa
		goto __fail;
Packit Service db8eaa
        err = add_values(&mylist, identifier, &verb->value_list);
Packit Service db8eaa
        if (err < 0)
Packit Service db8eaa
                goto __fail;
Packit Service db8eaa
        list_for_each(pos, &verb->device_list) {
Packit Service db8eaa
                dev = list_entry(pos, struct use_case_device, list);
Packit Service db8eaa
                err = add_values(&mylist, identifier, &dev->value_list);
Packit Service db8eaa
                if (err < 0)
Packit Service db8eaa
                        goto __fail;
Packit Service db8eaa
        }
Packit Service db8eaa
        list_for_each(pos, &verb->modifier_list) {
Packit Service db8eaa
                mod = list_entry(pos, struct use_case_modifier, list);
Packit Service db8eaa
                err = add_values(&mylist, identifier, &mod->value_list);
Packit Service db8eaa
                if (err < 0)
Packit Service db8eaa
                        goto __fail;
Packit Service db8eaa
        }
Packit Service db8eaa
	err = myvalue_to_str_list(&mylist, &res;;
Packit Service db8eaa
	if (err > 0)
Packit Service db8eaa
	        *list = (const char **)res;
Packit Service db8eaa
	else if (err == 0)
Packit Service db8eaa
		*list = NULL;
Packit Service db8eaa
      __fail:
Packit Service db8eaa
	myvalue_list_free(&mylist);
Packit Service db8eaa
        return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get list of enabled devices
Packit Service db8eaa
 * \param list Returned list
Packit Service db8eaa
 * \param verbname For verb (NULL = current)
Packit Service db8eaa
 * \return Number of list entries if success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int get_enabled_device_list(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
                                   const char **list[])
Packit Service db8eaa
{
Packit Service db8eaa
        if (uc_mgr->active_verb == NULL)
Packit Service db8eaa
                return -EINVAL;
Packit Service db8eaa
        return get_list(&uc_mgr->active_devices, list,
Packit Service db8eaa
                        struct use_case_device, active_list,
Packit Service db8eaa
                        name);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get list of enabled modifiers
Packit Service db8eaa
 * \param list Returned list
Packit Service db8eaa
 * \param verbname For verb (NULL = current)
Packit Service db8eaa
 * \return Number of list entries if success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int get_enabled_modifier_list(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
                                     const char **list[])
Packit Service db8eaa
{
Packit Service db8eaa
        if (uc_mgr->active_verb == NULL)
Packit Service db8eaa
                return -EINVAL;
Packit Service db8eaa
        return get_list(&uc_mgr->active_modifiers, list,
Packit Service db8eaa
                        struct use_case_modifier, active_list,
Packit Service db8eaa
                        name);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Obtain a list of entries
Packit Service db8eaa
 * \param uc_mgr Use case manager (may be NULL - card list)
Packit Service db8eaa
 * \param identifier (may be NULL - card list)
Packit Service db8eaa
 * \param list Returned allocated list
Packit Service db8eaa
 * \return Number of list entries if success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
			  const char *identifier,
Packit Service db8eaa
			  const char **list[])
Packit Service db8eaa
{
Packit Service db8eaa
	char *str, *str1;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	if (uc_mgr == NULL || identifier == NULL)
Packit Service db8eaa
		return uc_mgr_scan_master_configs(list);
Packit Service db8eaa
	pthread_mutex_lock(&uc_mgr->mutex);
Packit Service db8eaa
	if (strcmp(identifier, "_verbs") == 0)
Packit Service db8eaa
		err = get_verb_list(uc_mgr, list);
Packit Service db8eaa
        else if (strcmp(identifier, "_enadevs") == 0)
Packit Service db8eaa
        	err = get_enabled_device_list(uc_mgr, list);
Packit Service db8eaa
        else if (strcmp(identifier, "_enamods") == 0)
Packit Service db8eaa
                err = get_enabled_modifier_list(uc_mgr, list);
Packit Service db8eaa
        else {
Packit Service db8eaa
                str1 = strchr(identifier, '/');
Packit Service db8eaa
                if (str1) {
Packit Service db8eaa
                        str = strdup(str1 + 1);
Packit Service db8eaa
                	if (str == NULL) {
Packit Service db8eaa
                  		err = -ENOMEM;
Packit Service db8eaa
                		goto __end;
Packit Service db8eaa
                        }
Packit Service db8eaa
                } else {
Packit Service db8eaa
                        str = NULL;
Packit Service db8eaa
                }
Packit Service db8eaa
		if (check_identifier(identifier, "_devices"))
Packit Service db8eaa
			err = get_device_list(uc_mgr, list, str);
Packit Service db8eaa
                else if (check_identifier(identifier, "_modifiers"))
Packit Service db8eaa
			err = get_modifier_list(uc_mgr, list, str);
Packit Service db8eaa
		else if (check_identifier(identifier, "_identifiers"))
Packit Service db8eaa
			err = get_identifiers_list(uc_mgr, list, str);
Packit Service db8eaa
		else if (check_identifier(identifier, "_supporteddevs"))
Packit Service db8eaa
			err = get_supported_device_list(uc_mgr, list, str);
Packit Service db8eaa
		else if (check_identifier(identifier, "_conflictingdevs"))
Packit Service db8eaa
			err = get_conflicting_device_list(uc_mgr, list, str);
Packit Service db8eaa
		else if (identifier[0] == '_')
Packit Service db8eaa
			err = -ENOENT;
Packit Service db8eaa
		else
Packit Service db8eaa
			err = get_value_list(uc_mgr, identifier, list, str);
Packit Service db8eaa
		if (str)
Packit Service db8eaa
			free(str);
Packit Service db8eaa
	}
Packit Service db8eaa
      __end:
Packit Service db8eaa
	pthread_mutex_unlock(&uc_mgr->mutex);
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int get_value1(snd_use_case_mgr_t *uc_mgr, char **value,
Packit Service db8eaa
		      struct list_head *value_list, const char *identifier)
Packit Service db8eaa
{
Packit Service db8eaa
        struct ucm_value *val;
Packit Service db8eaa
        struct list_head *pos;
Packit Service db8eaa
        
Packit Service db8eaa
	if (!value_list)
Packit Service db8eaa
		return -ENOENT;
Packit Service db8eaa
Packit Service db8eaa
        list_for_each(pos, value_list) {
Packit Service db8eaa
		val = list_entry(pos, struct ucm_value, list);
Packit Service db8eaa
		if (check_identifier(identifier, val->name)) {
Packit Service db8eaa
			if (uc_mgr->conf_format < 2) {
Packit Service db8eaa
				*value = strdup(val->data);
Packit Service db8eaa
				if (*value == NULL)
Packit Service db8eaa
					return -ENOMEM;
Packit Service db8eaa
				return 0;
Packit Service db8eaa
			}
Packit Service db8eaa
			return uc_mgr_get_substituted_value(uc_mgr, value, val->data);
Packit Service db8eaa
		}
Packit Service db8eaa
        }
Packit Service db8eaa
        return -ENOENT;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int get_value3(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
		      char **value,
Packit Service db8eaa
		      const char *identifier,
Packit Service db8eaa
		      struct list_head *value_list1,
Packit Service db8eaa
		      struct list_head *value_list2,
Packit Service db8eaa
		      struct list_head *value_list3)
Packit Service db8eaa
{
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	err = get_value1(uc_mgr, value, value_list1, identifier);
Packit Service db8eaa
	if (err >= 0 || err != -ENOENT)
Packit Service db8eaa
		return err;
Packit Service db8eaa
	err = get_value1(uc_mgr, value, value_list2, identifier);
Packit Service db8eaa
	if (err >= 0 || err != -ENOENT)
Packit Service db8eaa
		return err;
Packit Service db8eaa
	err = get_value1(uc_mgr, value, value_list3, identifier);
Packit Service db8eaa
	if (err >= 0 || err != -ENOENT)
Packit Service db8eaa
		return err;
Packit Service db8eaa
	return -ENOENT;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get value
Packit Service db8eaa
 * \param uc_mgr Use case manager
Packit Service db8eaa
 * \param identifier Value identifier (string)
Packit Service db8eaa
 * \param value Returned value string
Packit Service db8eaa
 * \param item Modifier or Device name (string)
Packit Service db8eaa
 * \return Zero on success (value is filled), otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
static int get_value(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
			const char *identifier,
Packit Service db8eaa
			char **value,
Packit Service db8eaa
			const char *mod_dev_name,
Packit Service db8eaa
			const char *verb_name,
Packit Service db8eaa
			int exact)
Packit Service db8eaa
{
Packit Service db8eaa
	struct use_case_verb *verb;
Packit Service db8eaa
	struct use_case_modifier *mod;
Packit Service db8eaa
	struct use_case_device *dev;
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	if (mod_dev_name || verb_name || !exact) {
Packit Service db8eaa
		if (verb_name && strlen(verb_name)) {
Packit Service db8eaa
			verb = find_verb(uc_mgr, verb_name);
Packit Service db8eaa
		} else {
Packit Service db8eaa
			verb = uc_mgr->active_verb;
Packit Service db8eaa
		}
Packit Service db8eaa
		if (verb) {
Packit Service db8eaa
			if (mod_dev_name) {
Packit Service db8eaa
				mod = find_modifier(uc_mgr, verb,
Packit Service db8eaa
						    mod_dev_name, 0);
Packit Service db8eaa
				if (mod) {
Packit Service db8eaa
					err = get_value1(uc_mgr, value,
Packit Service db8eaa
							 &mod->value_list,
Packit Service db8eaa
							 identifier);
Packit Service db8eaa
					if (err >= 0 || err != -ENOENT)
Packit Service db8eaa
						return err;
Packit Service db8eaa
				}
Packit Service db8eaa
Packit Service db8eaa
				dev = find_device(uc_mgr, verb,
Packit Service db8eaa
						  mod_dev_name, 0);
Packit Service db8eaa
				if (dev) {
Packit Service db8eaa
					err = get_value1(uc_mgr, value,
Packit Service db8eaa
							 &dev->value_list,
Packit Service db8eaa
							 identifier);
Packit Service db8eaa
					if (err >= 0 || err != -ENOENT)
Packit Service db8eaa
						return err;
Packit Service db8eaa
				}
Packit Service db8eaa
Packit Service db8eaa
				if (exact)
Packit Service db8eaa
					return -ENOENT;
Packit Service db8eaa
			}
Packit Service db8eaa
Packit Service db8eaa
			err = get_value1(uc_mgr, value, &verb->value_list, identifier);
Packit Service db8eaa
			if (err >= 0 || err != -ENOENT)
Packit Service db8eaa
				return err;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (exact)
Packit Service db8eaa
			return -ENOENT;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	err = get_value1(uc_mgr, value, &uc_mgr->value_list, identifier);
Packit Service db8eaa
	if (err >= 0 || err != -ENOENT)
Packit Service db8eaa
		return err;
Packit Service db8eaa
Packit Service db8eaa
	return -ENOENT;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get current - string
Packit Service db8eaa
 * \param uc_mgr Use case manager
Packit Service db8eaa
 * \param identifier 
Packit Service db8eaa
 * \param value Value pointer
Packit Service db8eaa
 * \return Zero if success, otherwise a negative error code
Packit Service db8eaa
 *
Packit Service db8eaa
 * Note: String is dynamically allocated, use free() to
Packit Service db8eaa
 * deallocate this string.
Packit Service db8eaa
 */      
Packit Service db8eaa
int snd_use_case_get(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
		     const char *identifier,
Packit Service db8eaa
		     const char **value)
Packit Service db8eaa
{
Packit Service db8eaa
	const char *slash1, *slash2, *mod_dev_after;
Packit Service db8eaa
	const char *ident, *mod_dev, *verb;
Packit Service db8eaa
	int exact = 0;
Packit Service db8eaa
        int err;
Packit Service db8eaa
Packit Service db8eaa
	pthread_mutex_lock(&uc_mgr->mutex);
Packit Service db8eaa
	if (identifier == NULL) {
Packit Service db8eaa
	        *value = strdup(uc_mgr->card_name);
Packit Service db8eaa
	        if (*value == NULL) {
Packit Service db8eaa
	                err = -ENOMEM;
Packit Service db8eaa
	                goto __end;
Packit Service db8eaa
                }
Packit Service db8eaa
                err = 0;
Packit Service db8eaa
        } else if (strcmp(identifier, "_verb") == 0) {
Packit Service db8eaa
                if (uc_mgr->active_verb == NULL) {
Packit Service db8eaa
                        err = -ENOENT;
Packit Service db8eaa
			goto __end;
Packit Service db8eaa
		}
Packit Service db8eaa
                *value = strdup(uc_mgr->active_verb->name);
Packit Service db8eaa
                if (*value == NULL) {
Packit Service db8eaa
                        err = -ENOMEM;
Packit Service db8eaa
                        goto __end;
Packit Service db8eaa
                }
Packit Service db8eaa
	        err = 0;
Packit Service db8eaa
	} else if (strcmp(identifier, "_file") == 0) {
Packit Service db8eaa
		/* get the conf file name of the opened card */
Packit Service db8eaa
		if ((uc_mgr->card_name == NULL) ||
Packit Service db8eaa
		    (uc_mgr->conf_file_name == NULL) ||
Packit Service db8eaa
		    (uc_mgr->conf_file_name[0] == '\0')) {
Packit Service db8eaa
			err = -ENOENT;
Packit Service db8eaa
			goto __end;
Packit Service db8eaa
		}
Packit Service db8eaa
		*value = strdup(uc_mgr->conf_file_name);
Packit Service db8eaa
		if (*value == NULL) {
Packit Service db8eaa
			err = -ENOMEM;
Packit Service db8eaa
			goto __end;
Packit Service db8eaa
		}
Packit Service db8eaa
		err = 0;
Packit Service db8eaa
Packit Service db8eaa
	} else if (identifier[0] == '_') {
Packit Service db8eaa
		err = -ENOENT;
Packit Service db8eaa
		goto __end;
Packit Service db8eaa
        } else {
Packit Service db8eaa
		if (identifier[0] == '=') {
Packit Service db8eaa
			exact = 1;
Packit Service db8eaa
			identifier++;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		slash1 = strchr(identifier, '/');
Packit Service db8eaa
		if (slash1) {
Packit Service db8eaa
			ident = strndup(identifier, slash1 - identifier);
Packit Service db8eaa
Packit Service db8eaa
			slash2 = strchr(slash1 + 1, '/');
Packit Service db8eaa
			if (slash2) {
Packit Service db8eaa
				mod_dev_after = slash2;
Packit Service db8eaa
				verb = slash2 + 1;
Packit Service db8eaa
			}
Packit Service db8eaa
			else {
Packit Service db8eaa
				mod_dev_after = slash1 + strlen(slash1);
Packit Service db8eaa
				verb = NULL;
Packit Service db8eaa
			}
Packit Service db8eaa
Packit Service db8eaa
			if (mod_dev_after == slash1 + 1)
Packit Service db8eaa
				mod_dev = NULL;
Packit Service db8eaa
			else
Packit Service db8eaa
				mod_dev = strndup(slash1 + 1,
Packit Service db8eaa
						  mod_dev_after - (slash1 + 1));
Packit Service db8eaa
		}
Packit Service db8eaa
		else {
Packit Service db8eaa
			ident = identifier;
Packit Service db8eaa
			mod_dev = NULL;
Packit Service db8eaa
			verb = NULL;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		err = get_value(uc_mgr, ident, (char **)value, mod_dev, verb,
Packit Service db8eaa
		                exact);
Packit Service db8eaa
		if (ident != identifier)
Packit Service db8eaa
			free((void *)ident);
Packit Service db8eaa
		if (mod_dev)
Packit Service db8eaa
			free((void *)mod_dev);
Packit Service db8eaa
        }
Packit Service db8eaa
      __end:
Packit Service db8eaa
	pthread_mutex_unlock(&uc_mgr->mutex);
Packit Service db8eaa
        return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Get current - integer
Packit Service db8eaa
 * \param uc_mgr Use case manager
Packit Service db8eaa
 * \param identifier 
Packit Service db8eaa
 * \return Value if success, otherwise a negative error code 
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
		      const char *identifier,
Packit Service db8eaa
		      long *value)
Packit Service db8eaa
{
Packit Service db8eaa
        char *str, *str1;
Packit Service db8eaa
        long err;
Packit Service db8eaa
Packit Service db8eaa
	pthread_mutex_lock(&uc_mgr->mutex);
Packit Service db8eaa
        if (0) {
Packit Service db8eaa
                /* nothing here - prepared for fixed identifiers */
Packit Service db8eaa
        } else {
Packit Service db8eaa
                str1 = strchr(identifier, '/');
Packit Service db8eaa
                if (str1) {
Packit Service db8eaa
                        str = strdup(str1 + 1);
Packit Service db8eaa
                	if (str == NULL) {
Packit Service db8eaa
                  		err = -ENOMEM;
Packit Service db8eaa
                		goto __end;
Packit Service db8eaa
                        }
Packit Service db8eaa
                } else {
Packit Service db8eaa
                        str = NULL;
Packit Service db8eaa
                }
Packit Service db8eaa
                if (check_identifier(identifier, "_devstatus")) {
Packit Service db8eaa
			if (!str) {
Packit Service db8eaa
				err = -EINVAL;
Packit Service db8eaa
				goto __end;
Packit Service db8eaa
			}
Packit Service db8eaa
                        err = device_status(uc_mgr, str);
Packit Service db8eaa
			if (err >= 0) {
Packit Service db8eaa
				*value = err;
Packit Service db8eaa
				err = 0;
Packit Service db8eaa
			}
Packit Service db8eaa
		} else if (check_identifier(identifier, "_modstatus")) {
Packit Service db8eaa
			if (!str) {
Packit Service db8eaa
				err = -EINVAL;
Packit Service db8eaa
				goto __end;
Packit Service db8eaa
			}
Packit Service db8eaa
                        err = modifier_status(uc_mgr, str);
Packit Service db8eaa
			if (err >= 0) {
Packit Service db8eaa
				*value = err;
Packit Service db8eaa
				err = 0;
Packit Service db8eaa
			}
Packit Service db8eaa
#if 0
Packit Service db8eaa
		/*
Packit Service db8eaa
		 * enable this block if the else clause below is expanded to query
Packit Service db8eaa
		 * user-supplied values
Packit Service db8eaa
		 */
Packit Service db8eaa
		} else if (identifier[0] == '_')
Packit Service db8eaa
			err = -ENOENT;
Packit Service db8eaa
#endif
Packit Service db8eaa
		} else
Packit Service db8eaa
                        err = -ENOENT;
Packit Service db8eaa
                if (str)
Packit Service db8eaa
                        free(str);
Packit Service db8eaa
        }
Packit Service db8eaa
      __end:
Packit Service db8eaa
	pthread_mutex_unlock(&uc_mgr->mutex);
Packit Service db8eaa
        return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int set_boot_user(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
			 const char *value)
Packit Service db8eaa
{
Packit Service db8eaa
	int err;
Packit Service db8eaa
Packit Service db8eaa
	if (value != NULL && *value) {
Packit Service db8eaa
		uc_error("error: wrong value for _boot (%s)", value);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
	err = execute_sequence(uc_mgr, &uc_mgr->boot_list,
Packit Service db8eaa
			       &uc_mgr->value_list, NULL, NULL);
Packit Service db8eaa
	if (err < 0) {
Packit Service db8eaa
		uc_error("Unable to execute boot sequence");
Packit Service db8eaa
		return err;
Packit Service db8eaa
	}
Packit Service db8eaa
	return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int set_defaults_user(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
			     const char *value)
Packit Service db8eaa
{
Packit Service db8eaa
	if (value != NULL && *value) {
Packit Service db8eaa
		uc_error("error: wrong value for _defaults (%s)", value);
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	}
Packit Service db8eaa
	return set_defaults(uc_mgr);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int handle_transition_verb(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
                                  struct use_case_verb *new_verb)
Packit Service db8eaa
{
Packit Service db8eaa
        struct list_head *pos;
Packit Service db8eaa
        struct transition_sequence *trans;
Packit Service db8eaa
        int err;
Packit Service db8eaa
Packit Service db8eaa
        list_for_each(pos, &uc_mgr->active_verb->transition_list) {
Packit Service db8eaa
                trans = list_entry(pos, struct transition_sequence, list);
Packit Service db8eaa
                if (strcmp(trans->name, new_verb->name) == 0) {
Packit Service db8eaa
                        err = execute_sequence(uc_mgr, &trans->transition_list,
Packit Service db8eaa
					       &uc_mgr->active_verb->value_list,
Packit Service db8eaa
					       &uc_mgr->value_list,
Packit Service db8eaa
					       NULL);
Packit Service db8eaa
                        if (err >= 0)
Packit Service db8eaa
                                return 1;
Packit Service db8eaa
                        return err;
Packit Service db8eaa
                }
Packit Service db8eaa
        }
Packit Service db8eaa
        return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int set_verb_user(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
                         const char *verb_name)
Packit Service db8eaa
{
Packit Service db8eaa
        struct use_case_verb *verb;
Packit Service db8eaa
        int err = 0;
Packit Service db8eaa
Packit Service db8eaa
        if (uc_mgr->active_verb &&
Packit Service db8eaa
            strcmp(uc_mgr->active_verb->name, verb_name) == 0)
Packit Service db8eaa
                return 0;
Packit Service db8eaa
        if (strcmp(verb_name, SND_USE_CASE_VERB_INACTIVE) != 0) {
Packit Service db8eaa
                verb = find_verb(uc_mgr, verb_name);
Packit Service db8eaa
                if (verb == NULL)
Packit Service db8eaa
                        return -ENOENT;
Packit Service db8eaa
        } else {
Packit Service db8eaa
                verb = NULL;
Packit Service db8eaa
        }
Packit Service db8eaa
        if (uc_mgr->active_verb) {
Packit Service db8eaa
                err = handle_transition_verb(uc_mgr, verb);
Packit Service db8eaa
                if (err == 0) {
Packit Service db8eaa
                        err = dismantle_use_case(uc_mgr);
Packit Service db8eaa
                        if (err < 0)
Packit Service db8eaa
                                return err;
Packit Service db8eaa
                } else if (err == 1) {
Packit Service db8eaa
                        uc_mgr->active_verb = verb;
Packit Service db8eaa
                        verb = NULL;
Packit Service db8eaa
                } else {
Packit Service db8eaa
                        verb = NULL; /* show error */
Packit Service db8eaa
                }
Packit Service db8eaa
        }
Packit Service db8eaa
        if (verb) {
Packit Service db8eaa
                err = set_verb(uc_mgr, verb, 1);
Packit Service db8eaa
                if (err < 0)
Packit Service db8eaa
                        uc_error("error: failed to initialize new use case: %s",
Packit Service db8eaa
                                 verb_name);
Packit Service db8eaa
        }
Packit Service db8eaa
        return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
Packit Service db8eaa
static int set_device_user(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
                           const char *device_name,
Packit Service db8eaa
                           int enable)
Packit Service db8eaa
{
Packit Service db8eaa
        struct use_case_device *device;
Packit Service db8eaa
Packit Service db8eaa
        if (uc_mgr->active_verb == NULL)
Packit Service db8eaa
                return -ENOENT;
Packit Service db8eaa
        device = find_device(uc_mgr, uc_mgr->active_verb, device_name, 1);
Packit Service db8eaa
        if (device == NULL)
Packit Service db8eaa
                return -ENOENT;
Packit Service db8eaa
        return set_device(uc_mgr, device, enable);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int set_modifier_user(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
                             const char *modifier_name,
Packit Service db8eaa
                             int enable)
Packit Service db8eaa
{
Packit Service db8eaa
        struct use_case_modifier *modifier;
Packit Service db8eaa
Packit Service db8eaa
        if (uc_mgr->active_verb == NULL)
Packit Service db8eaa
                return -ENOENT;
Packit Service db8eaa
Packit Service db8eaa
        modifier = find_modifier(uc_mgr, uc_mgr->active_verb, modifier_name, 1);
Packit Service db8eaa
        if (modifier == NULL)
Packit Service db8eaa
                return -ENOENT;
Packit Service db8eaa
        return set_modifier(uc_mgr, modifier, enable);
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int switch_device(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
                         const char *old_device,
Packit Service db8eaa
                         const char *new_device)
Packit Service db8eaa
{
Packit Service db8eaa
        struct use_case_device *xold, *xnew;
Packit Service db8eaa
        struct transition_sequence *trans;
Packit Service db8eaa
        struct list_head *pos;
Packit Service db8eaa
        int err, seq_found = 0;
Packit Service db8eaa
        
Packit Service db8eaa
        if (uc_mgr->active_verb == NULL)
Packit Service db8eaa
                return -ENOENT;
Packit Service db8eaa
        if (device_status(uc_mgr, old_device) == 0) {
Packit Service db8eaa
                uc_error("error: device %s not enabled", old_device);
Packit Service db8eaa
                return -EINVAL;
Packit Service db8eaa
        }
Packit Service db8eaa
        if (device_status(uc_mgr, new_device) != 0) {
Packit Service db8eaa
                uc_error("error: device %s already enabled", new_device);
Packit Service db8eaa
                return -EINVAL;
Packit Service db8eaa
        }
Packit Service db8eaa
        xold = find_device(uc_mgr, uc_mgr->active_verb, old_device, 1);
Packit Service db8eaa
        if (xold == NULL)
Packit Service db8eaa
                return -ENOENT;
Packit Service db8eaa
        list_del(&xold->active_list);
Packit Service db8eaa
        xnew = find_device(uc_mgr, uc_mgr->active_verb, new_device, 1);
Packit Service db8eaa
        list_add_tail(&xold->active_list, &uc_mgr->active_devices);
Packit Service db8eaa
        if (xnew == NULL)
Packit Service db8eaa
                return -ENOENT;
Packit Service db8eaa
        err = 0;
Packit Service db8eaa
        list_for_each(pos, &xold->transition_list) {
Packit Service db8eaa
                trans = list_entry(pos, struct transition_sequence, list);
Packit Service db8eaa
                if (strcmp(trans->name, new_device) == 0) {
Packit Service db8eaa
                        err = execute_sequence(uc_mgr, &trans->transition_list,
Packit Service db8eaa
					       &xold->value_list,
Packit Service db8eaa
					       &uc_mgr->active_verb->value_list,
Packit Service db8eaa
					       &uc_mgr->value_list);
Packit Service db8eaa
                        if (err >= 0) {
Packit Service db8eaa
                                list_del(&xold->active_list);
Packit Service db8eaa
                                list_add_tail(&xnew->active_list, &uc_mgr->active_devices);
Packit Service db8eaa
                        }
Packit Service db8eaa
                        seq_found = 1;
Packit Service db8eaa
                        break;
Packit Service db8eaa
                }
Packit Service db8eaa
        }
Packit Service db8eaa
        if (!seq_found) {
Packit Service db8eaa
                err = set_device(uc_mgr, xold, 0);
Packit Service db8eaa
                if (err < 0)
Packit Service db8eaa
                        return err;
Packit Service db8eaa
                err = set_device(uc_mgr, xnew, 1);
Packit Service db8eaa
                if (err < 0)
Packit Service db8eaa
                        return err;
Packit Service db8eaa
        }
Packit Service db8eaa
        return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int switch_modifier(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
                           const char *old_modifier,
Packit Service db8eaa
                           const char *new_modifier)
Packit Service db8eaa
{
Packit Service db8eaa
        struct use_case_modifier *xold, *xnew;
Packit Service db8eaa
        struct transition_sequence *trans;
Packit Service db8eaa
        struct list_head *pos;
Packit Service db8eaa
        int err, seq_found = 0;
Packit Service db8eaa
        
Packit Service db8eaa
        if (uc_mgr->active_verb == NULL)
Packit Service db8eaa
                return -ENOENT;
Packit Service db8eaa
        if (modifier_status(uc_mgr, old_modifier) == 0) {
Packit Service db8eaa
                uc_error("error: modifier %s not enabled", old_modifier);
Packit Service db8eaa
                return -EINVAL;
Packit Service db8eaa
        }
Packit Service db8eaa
        if (modifier_status(uc_mgr, new_modifier) != 0) {
Packit Service db8eaa
                uc_error("error: modifier %s already enabled", new_modifier);
Packit Service db8eaa
                return -EINVAL;
Packit Service db8eaa
        }
Packit Service db8eaa
        xold = find_modifier(uc_mgr, uc_mgr->active_verb, old_modifier, 1);
Packit Service db8eaa
        if (xold == NULL)
Packit Service db8eaa
                return -ENOENT;
Packit Service db8eaa
        xnew = find_modifier(uc_mgr, uc_mgr->active_verb, new_modifier, 1);
Packit Service db8eaa
        if (xnew == NULL)
Packit Service db8eaa
                return -ENOENT;
Packit Service db8eaa
        err = 0;
Packit Service db8eaa
        list_for_each(pos, &xold->transition_list) {
Packit Service db8eaa
                trans = list_entry(pos, struct transition_sequence, list);
Packit Service db8eaa
                if (strcmp(trans->name, new_modifier) == 0) {
Packit Service db8eaa
                        err = execute_sequence(uc_mgr, &trans->transition_list,
Packit Service db8eaa
					       &xold->value_list,
Packit Service db8eaa
					       &uc_mgr->active_verb->value_list,
Packit Service db8eaa
					       &uc_mgr->value_list);
Packit Service db8eaa
                        if (err >= 0) {
Packit Service db8eaa
                                list_del(&xold->active_list);
Packit Service db8eaa
                                list_add_tail(&xnew->active_list, &uc_mgr->active_modifiers);
Packit Service db8eaa
                        }
Packit Service db8eaa
                        seq_found = 1;
Packit Service db8eaa
                        break;
Packit Service db8eaa
                }
Packit Service db8eaa
        }
Packit Service db8eaa
        if (!seq_found) {
Packit Service db8eaa
                err = set_modifier(uc_mgr, xold, 0);
Packit Service db8eaa
                if (err < 0)
Packit Service db8eaa
                        return err;
Packit Service db8eaa
                err = set_modifier(uc_mgr, xnew, 1);
Packit Service db8eaa
                if (err < 0)
Packit Service db8eaa
                        return err;
Packit Service db8eaa
        }
Packit Service db8eaa
        return err;        
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Set new
Packit Service db8eaa
 * \param uc_mgr Use case manager
Packit Service db8eaa
 * \param identifier
Packit Service db8eaa
 * \param value Value
Packit Service db8eaa
 * \return Zero if success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_use_case_set(snd_use_case_mgr_t *uc_mgr,
Packit Service db8eaa
                     const char *identifier,
Packit Service db8eaa
                     const char *value)
Packit Service db8eaa
{
Packit Service db8eaa
	char *str, *str1;
Packit Service db8eaa
	int err = 0;
Packit Service db8eaa
Packit Service db8eaa
	pthread_mutex_lock(&uc_mgr->mutex);
Packit Service db8eaa
	if (strcmp(identifier, "_boot") == 0)
Packit Service db8eaa
		err = set_boot_user(uc_mgr, value);
Packit Service db8eaa
	else if (strcmp(identifier, "_defaults") == 0)
Packit Service db8eaa
		err = set_defaults_user(uc_mgr, value);
Packit Service db8eaa
	else if (strcmp(identifier, "_verb") == 0)
Packit Service db8eaa
	        err = set_verb_user(uc_mgr, value);
Packit Service db8eaa
        else if (strcmp(identifier, "_enadev") == 0)
Packit Service db8eaa
                err = set_device_user(uc_mgr, value, 1);
Packit Service db8eaa
        else if (strcmp(identifier, "_disdev") == 0)
Packit Service db8eaa
                err = set_device_user(uc_mgr, value, 0);
Packit Service db8eaa
        else if (strcmp(identifier, "_enamod") == 0)
Packit Service db8eaa
                err = set_modifier_user(uc_mgr, value, 1);
Packit Service db8eaa
        else if (strcmp(identifier, "_dismod") == 0)
Packit Service db8eaa
                err = set_modifier_user(uc_mgr, value, 0);
Packit Service db8eaa
        else {
Packit Service db8eaa
                str1 = strchr(identifier, '/');
Packit Service db8eaa
                if (str1) {
Packit Service db8eaa
                        str = strdup(str1 + 1);
Packit Service db8eaa
                	if (str == NULL) {
Packit Service db8eaa
                  		err = -ENOMEM;
Packit Service db8eaa
                		goto __end;
Packit Service db8eaa
                        }
Packit Service db8eaa
                } else {
Packit Service db8eaa
                        err = -EINVAL;
Packit Service db8eaa
                        goto __end;
Packit Service db8eaa
                }
Packit Service db8eaa
                if (check_identifier(identifier, "_swdev"))
Packit Service db8eaa
                        err = switch_device(uc_mgr, str, value);
Packit Service db8eaa
                else if (check_identifier(identifier, "_swmod"))
Packit Service db8eaa
                        err = switch_modifier(uc_mgr, str, value);
Packit Service db8eaa
                else
Packit Service db8eaa
                        err = -EINVAL;
Packit Service db8eaa
                if (str)
Packit Service db8eaa
                        free(str);
Packit Service db8eaa
        }
Packit Service db8eaa
      __end:
Packit Service db8eaa
	pthread_mutex_unlock(&uc_mgr->mutex);
Packit Service db8eaa
        return err;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Parse control element identifier
Packit Service db8eaa
 * \param elem_id Element identifier
Packit Service db8eaa
 * \param ucm_id Use case identifier
Packit Service db8eaa
 * \param value String value to be parsed
Packit Service db8eaa
 * \return Zero if success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_use_case_parse_ctl_elem_id(snd_ctl_elem_id_t *dst,
Packit Service db8eaa
				   const char *ucm_id,
Packit Service db8eaa
				   const char *value)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_ctl_elem_iface_t iface;
Packit Service db8eaa
	int jack_control;
Packit Service db8eaa
Packit Service db8eaa
	jack_control = strcmp(ucm_id, "JackControl") == 0;
Packit Service db8eaa
	if (!jack_control &&
Packit Service db8eaa
	    strcmp(ucm_id, "PlaybackVolume") &&
Packit Service db8eaa
	    strcmp(ucm_id, "PlaybackSwitch") &&
Packit Service db8eaa
	    strcmp(ucm_id, "CaptureVolume") &&
Packit Service db8eaa
	    strcmp(ucm_id, "CaptureSwitch"))
Packit Service db8eaa
		return -EINVAL;
Packit Service db8eaa
	snd_ctl_elem_id_clear(dst);
Packit Service db8eaa
	if (strcasestr(ucm_id, "name="))
Packit Service db8eaa
		return __snd_ctl_ascii_elem_id_parse(dst, value, NULL);
Packit Service db8eaa
	iface = SND_CTL_ELEM_IFACE_MIXER;
Packit Service db8eaa
	if (jack_control)
Packit Service db8eaa
		iface = SND_CTL_ELEM_IFACE_CARD;
Packit Service db8eaa
	snd_ctl_elem_id_set_interface(dst, iface);
Packit Service db8eaa
	snd_ctl_elem_id_set_name(dst, value);
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
/**
Packit Service db8eaa
 * \brief Parse mixer element identifier
Packit Service db8eaa
 * \param dst Simple mixer element identifier
Packit Service db8eaa
 * \param ucm_id Use case identifier
Packit Service db8eaa
 * \param value String value to be parsed
Packit Service db8eaa
 * \return Zero if success, otherwise a negative error code
Packit Service db8eaa
 */
Packit Service db8eaa
int snd_use_case_parse_selem_id(snd_mixer_selem_id_t *dst,
Packit Service db8eaa
				const char *ucm_id,
Packit Service db8eaa
				const char *value)
Packit Service db8eaa
{
Packit Service db8eaa
#ifdef BUILD_MIXER
Packit Service db8eaa
	if (strcmp(ucm_id, "PlaybackMixerId") == 0 ||
Packit Service db8eaa
	    strcmp(ucm_id, "CaptureMixerId") == 0)
Packit Service db8eaa
		return snd_mixer_selem_id_parse(dst, value);
Packit Service db8eaa
#endif
Packit Service db8eaa
	return -EINVAL;
Packit Service db8eaa
}