mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-11-09 13:30:03 -05:00
Merge branch 'ucm'
This commit is contained in:
commit
916a203d94
18 changed files with 3840 additions and 5 deletions
|
|
@ -38,6 +38,10 @@ if BUILD_SEQ
|
|||
SUBDIRS += seq
|
||||
libasound_la_LIBADD += seq/libseq.la
|
||||
endif
|
||||
if BUILD_UCM
|
||||
SUBDIRS += ucm
|
||||
libasound_la_LIBADD += ucm/libucm.la
|
||||
endif
|
||||
if BUILD_ALISP
|
||||
SUBDIRS += alisp
|
||||
libasound_la_LIBADD += alisp/libalisp.la
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
EXTRA_LTLIBRARIES = libcontrol.la
|
||||
|
||||
libcontrol_la_SOURCES = cards.c tlv.c namehint.c hcontrol.c \
|
||||
control.c control_hw.c setup.c control_symbols.c
|
||||
control.c control_hw.c setup.c ctlparse.c \
|
||||
control_symbols.c
|
||||
if BUILD_CTL_PLUGIN_SHM
|
||||
libcontrol_la_SOURCES += control_shm.c
|
||||
endif
|
||||
|
|
|
|||
351
src/control/ctlparse.c
Normal file
351
src/control/ctlparse.c
Normal file
|
|
@ -0,0 +1,351 @@
|
|||
/**
|
||||
* \file control/control.c
|
||||
* \brief CTL interface - parse ASCII identifiers and values
|
||||
* \author Jaroslav Kysela <perex@perex.cz>
|
||||
* \date 2010
|
||||
*/
|
||||
/*
|
||||
* Control Interface - ASCII parser
|
||||
* Copyright (c) 2010 by Jaroslav Kysela <perex@perex.cz>
|
||||
*
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include "control_local.h"
|
||||
|
||||
/* Function to convert from percentage to volume. val = percentage */
|
||||
|
||||
#define convert_prange1(val, min, max) \
|
||||
ceil((val) * ((max) - (min)) * 0.01 + (min))
|
||||
|
||||
#define check_range(val, min, max) \
|
||||
((val < min) ? (min) : ((val > max) ? (max) : (val)))
|
||||
|
||||
static long get_integer(const char **ptr, long min, long max)
|
||||
{
|
||||
long val = min;
|
||||
char *p = (char *)*ptr, *s;
|
||||
|
||||
if (*p == ':')
|
||||
p++;
|
||||
if (*p == '\0' || (!isdigit(*p) && *p != '-'))
|
||||
goto out;
|
||||
|
||||
s = p;
|
||||
val = strtol(s, &p, 10);
|
||||
if (*p == '.') {
|
||||
p++;
|
||||
strtol(p, &p, 10);
|
||||
}
|
||||
if (*p == '%') {
|
||||
val = (long)convert_prange1(strtod(s, NULL), min, max);
|
||||
p++;
|
||||
}
|
||||
val = check_range(val, min, max);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
out:
|
||||
*ptr = p;
|
||||
return val;
|
||||
}
|
||||
|
||||
static long long get_integer64(const char **ptr, long long min, long long max)
|
||||
{
|
||||
long long val = min;
|
||||
char *p = (char *)*ptr, *s;
|
||||
|
||||
if (*p == ':')
|
||||
p++;
|
||||
if (*p == '\0' || (!isdigit(*p) && *p != '-'))
|
||||
goto out;
|
||||
|
||||
s = p;
|
||||
val = strtol(s, &p, 10);
|
||||
if (*p == '.') {
|
||||
p++;
|
||||
strtol(p, &p, 10);
|
||||
}
|
||||
if (*p == '%') {
|
||||
val = (long long)convert_prange1(strtod(s, NULL), min, max);
|
||||
p++;
|
||||
}
|
||||
val = check_range(val, min, max);
|
||||
if (*p == ',')
|
||||
p++;
|
||||
out:
|
||||
*ptr = p;
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief return ASCII CTL element identifier name
|
||||
* \param id CTL identifier
|
||||
* \return ascii identifier of CTL element
|
||||
*
|
||||
* The string is allocated using strdup().
|
||||
*/
|
||||
char *snd_ctl_ascii_elem_id_get(snd_ctl_elem_id_t *id)
|
||||
{
|
||||
unsigned int index, device, subdevice;
|
||||
char buf[256], buf1[32];
|
||||
|
||||
snprintf(buf, sizeof(buf), "numid=%u,iface=%s,name='%s'",
|
||||
snd_ctl_elem_id_get_numid(id),
|
||||
snd_ctl_elem_iface_name(
|
||||
snd_ctl_elem_id_get_interface(id)),
|
||||
snd_ctl_elem_id_get_name(id));
|
||||
buf[sizeof(buf)-1] = '\0';
|
||||
index = snd_ctl_elem_id_get_index(id);
|
||||
device = snd_ctl_elem_id_get_device(id);
|
||||
subdevice = snd_ctl_elem_id_get_subdevice(id);
|
||||
if (index) {
|
||||
snprintf(buf1, sizeof(buf1), ",index=%i", index);
|
||||
if (strlen(buf) + strlen(buf1) < sizeof(buf))
|
||||
strcat(buf, buf1);
|
||||
}
|
||||
if (device) {
|
||||
snprintf(buf1, sizeof(buf1), ",device=%i", device);
|
||||
if (strlen(buf) + strlen(buf1) < sizeof(buf))
|
||||
strcat(buf, buf1);
|
||||
}
|
||||
if (subdevice) {
|
||||
snprintf(buf1, sizeof(buf1), ",subdevice=%i", subdevice);
|
||||
if (strlen(buf) + strlen(buf1) < sizeof(buf))
|
||||
strcat(buf, buf1);
|
||||
}
|
||||
return strdup(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief parse ASCII string as CTL element identifier
|
||||
* \param dst destination CTL identifier
|
||||
* \param str source ASCII string
|
||||
* \return zero on success, otherwise a negative error code
|
||||
*/
|
||||
int snd_ctl_ascii_elem_id_parse(snd_ctl_elem_id_t *dst, const char *str)
|
||||
{
|
||||
int c, size, numid;
|
||||
char *ptr;
|
||||
|
||||
while (*str == ' ' || *str == '\t')
|
||||
str++;
|
||||
if (!(*str))
|
||||
return -EINVAL;
|
||||
snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_MIXER); /* default */
|
||||
while (*str) {
|
||||
if (!strncasecmp(str, "numid=", 6)) {
|
||||
str += 6;
|
||||
numid = atoi(str);
|
||||
if (numid <= 0) {
|
||||
fprintf(stderr, "amixer: Invalid numid %d\n", numid);
|
||||
return -EINVAL;
|
||||
}
|
||||
snd_ctl_elem_id_set_numid(dst, atoi(str));
|
||||
while (isdigit(*str))
|
||||
str++;
|
||||
} else if (!strncasecmp(str, "iface=", 6)) {
|
||||
str += 6;
|
||||
if (!strncasecmp(str, "card", 4)) {
|
||||
snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_CARD);
|
||||
str += 4;
|
||||
} else if (!strncasecmp(str, "mixer", 5)) {
|
||||
snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_MIXER);
|
||||
str += 5;
|
||||
} else if (!strncasecmp(str, "pcm", 3)) {
|
||||
snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_PCM);
|
||||
str += 3;
|
||||
} else if (!strncasecmp(str, "rawmidi", 7)) {
|
||||
snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_RAWMIDI);
|
||||
str += 7;
|
||||
} else if (!strncasecmp(str, "timer", 5)) {
|
||||
snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_TIMER);
|
||||
str += 5;
|
||||
} else if (!strncasecmp(str, "sequencer", 9)) {
|
||||
snd_ctl_elem_id_set_interface(dst, SND_CTL_ELEM_IFACE_SEQUENCER);
|
||||
str += 9;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (!strncasecmp(str, "name=", 5)) {
|
||||
char buf[64];
|
||||
str += 5;
|
||||
ptr = buf;
|
||||
size = 0;
|
||||
if (*str == '\'' || *str == '\"') {
|
||||
c = *str++;
|
||||
while (*str && *str != c) {
|
||||
if (size < (int)sizeof(buf)) {
|
||||
*ptr++ = *str;
|
||||
size++;
|
||||
}
|
||||
str++;
|
||||
}
|
||||
if (*str == c)
|
||||
str++;
|
||||
} else {
|
||||
while (*str && *str != ',') {
|
||||
if (size < (int)sizeof(buf)) {
|
||||
*ptr++ = *str;
|
||||
size++;
|
||||
}
|
||||
str++;
|
||||
}
|
||||
}
|
||||
*ptr = '\0';
|
||||
snd_ctl_elem_id_set_name(dst, buf);
|
||||
} else if (!strncasecmp(str, "index=", 6)) {
|
||||
str += 6;
|
||||
snd_ctl_elem_id_set_index(dst, atoi(str));
|
||||
while (isdigit(*str))
|
||||
str++;
|
||||
} else if (!strncasecmp(str, "device=", 7)) {
|
||||
str += 7;
|
||||
snd_ctl_elem_id_set_device(dst, atoi(str));
|
||||
while (isdigit(*str))
|
||||
str++;
|
||||
} else if (!strncasecmp(str, "subdevice=", 10)) {
|
||||
str += 10;
|
||||
snd_ctl_elem_id_set_subdevice(dst, atoi(str));
|
||||
while (isdigit(*str))
|
||||
str++;
|
||||
}
|
||||
if (*str == ',') {
|
||||
str++;
|
||||
} else {
|
||||
if (*str)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_ctl_enum_item_index(snd_ctl_t *handle,
|
||||
snd_ctl_elem_info_t *info,
|
||||
const char **ptrp)
|
||||
{
|
||||
char *ptr = (char *)*ptrp;
|
||||
int items, i, len;
|
||||
const char *name;
|
||||
|
||||
items = snd_ctl_elem_info_get_items(info);
|
||||
if (items <= 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < items; i++) {
|
||||
snd_ctl_elem_info_set_item(info, i);
|
||||
if (snd_ctl_elem_info(handle, info) < 0)
|
||||
return -1;
|
||||
name = snd_ctl_elem_info_get_item_name(info);
|
||||
len = strlen(name);
|
||||
if (! strncmp(name, ptr, len)) {
|
||||
if (! ptr[len] || ptr[len] == ',' || ptr[len] == '\n') {
|
||||
ptr += len;
|
||||
*ptrp = ptr;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief parse ASCII string as CTL element value
|
||||
* \param dst destination CTL element value
|
||||
* \param info CTL element info structure
|
||||
* \param value source ASCII string
|
||||
* \return zero on success, otherwise a negative error code
|
||||
*/
|
||||
int snd_ctl_ascii_value_parse(snd_ctl_t *handle,
|
||||
snd_ctl_elem_value_t *dst,
|
||||
snd_ctl_elem_info_t *info,
|
||||
const char *value)
|
||||
{
|
||||
const char *ptr = value;
|
||||
snd_ctl_elem_id_t *myid;
|
||||
snd_ctl_elem_type_t type;
|
||||
unsigned int idx, count;
|
||||
long tmp;
|
||||
long long tmp64;
|
||||
|
||||
snd_ctl_elem_id_alloca(&myid);
|
||||
snd_ctl_elem_info_get_id(info, myid);
|
||||
type = snd_ctl_elem_info_get_type(info);
|
||||
count = snd_ctl_elem_info_get_count(info);
|
||||
snd_ctl_elem_value_set_id(dst, myid);
|
||||
|
||||
for (idx = 0; idx < count && idx < 128 && ptr && *ptr; idx++) {
|
||||
switch (type) {
|
||||
case SND_CTL_ELEM_TYPE_BOOLEAN:
|
||||
tmp = 0;
|
||||
if (!strncasecmp(ptr, "on", 2) ||
|
||||
!strncasecmp(ptr, "up", 2)) {
|
||||
tmp = 1;
|
||||
ptr += 2;
|
||||
} else if (!strncasecmp(ptr, "yes", 3)) {
|
||||
tmp = 1;
|
||||
ptr += 3;
|
||||
} else if (!strncasecmp(ptr, "toggle", 6)) {
|
||||
tmp = snd_ctl_elem_value_get_boolean(dst, idx);
|
||||
tmp = tmp > 0 ? 0 : 1;
|
||||
ptr += 6;
|
||||
} else if (isdigit(*ptr)) {
|
||||
tmp = atoi(ptr) > 0 ? 1 : 0;
|
||||
while (isdigit(*ptr))
|
||||
ptr++;
|
||||
} else {
|
||||
while (*ptr && *ptr != ',')
|
||||
ptr++;
|
||||
}
|
||||
snd_ctl_elem_value_set_boolean(dst, idx, tmp);
|
||||
break;
|
||||
case SND_CTL_ELEM_TYPE_INTEGER:
|
||||
tmp = get_integer(&ptr,
|
||||
snd_ctl_elem_info_get_min(info),
|
||||
snd_ctl_elem_info_get_max(info));
|
||||
snd_ctl_elem_value_set_integer(dst, idx, tmp);
|
||||
break;
|
||||
case SND_CTL_ELEM_TYPE_INTEGER64:
|
||||
tmp64 = get_integer64(&ptr,
|
||||
snd_ctl_elem_info_get_min64(info),
|
||||
snd_ctl_elem_info_get_max64(info));
|
||||
snd_ctl_elem_value_set_integer64(dst, idx, tmp64);
|
||||
break;
|
||||
case SND_CTL_ELEM_TYPE_ENUMERATED:
|
||||
tmp = get_ctl_enum_item_index(handle, info, &ptr);
|
||||
if (tmp < 0)
|
||||
tmp = get_integer(&ptr, 0,
|
||||
snd_ctl_elem_info_get_items(info) - 1);
|
||||
snd_ctl_elem_value_set_enumerated(dst, idx, tmp);
|
||||
break;
|
||||
case SND_CTL_ELEM_TYPE_BYTES:
|
||||
tmp = get_integer(&ptr, 0, 255);
|
||||
snd_ctl_elem_value_set_byte(dst, idx, tmp);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!strchr(value, ','))
|
||||
ptr = value;
|
||||
else if (*ptr == ',')
|
||||
ptr++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
10
src/ucm/Makefile.am
Normal file
10
src/ucm/Makefile.am
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
EXTRA_LTLIBRARIES = libucm.la
|
||||
|
||||
libucm_la_SOURCES = utils.c parser.c main.c
|
||||
|
||||
noinst_HEADERS = ucm_local.h
|
||||
|
||||
all: libucm.la
|
||||
|
||||
|
||||
INCLUDES=-I$(top_srcdir)/include
|
||||
1437
src/ucm/main.c
Normal file
1437
src/ucm/main.c
Normal file
File diff suppressed because it is too large
Load diff
1180
src/ucm/parser.c
Normal file
1180
src/ucm/parser.c
Normal file
File diff suppressed because it is too large
Load diff
208
src/ucm/ucm_local.h
Normal file
208
src/ucm/ucm_local.h
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Support for the verb/device/modifier core logic and API,
|
||||
* command line tool and file parser was kindly sponsored by
|
||||
* Texas Instruments Inc.
|
||||
* Support for multiple active modifiers and devices,
|
||||
* transition sequences, multiple client access and user defined use
|
||||
* cases was kindly sponsored by Wolfson Microelectronics PLC.
|
||||
*
|
||||
* Copyright (C) 2008-2010 SlimLogic Ltd
|
||||
* Copyright (C) 2010 Wolfson Microelectronics PLC
|
||||
* Copyright (C) 2010 Texas Instruments Inc.
|
||||
* Copyright (C) 2010 Red Hat Inc.
|
||||
* Authors: Liam Girdwood <lrg@slimlogic.co.uk>
|
||||
* Stefan Schmidt <stefan@slimlogic.co.uk>
|
||||
* Justin Xu <justinx@slimlogic.co.uk>
|
||||
* Jaroslav Kysela <perex@perex.cz>
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
#define UC_MGR_DEBUG
|
||||
#endif
|
||||
|
||||
#include "local.h"
|
||||
#include "use-case.h"
|
||||
|
||||
#define MAX_FILE 256
|
||||
#define ALSA_USE_CASE_DIR ALSA_CONFIG_DIR "/ucm"
|
||||
|
||||
#define SEQUENCE_ELEMENT_TYPE_CDEV 1
|
||||
#define SEQUENCE_ELEMENT_TYPE_CSET 2
|
||||
#define SEQUENCE_ELEMENT_TYPE_SLEEP 3
|
||||
#define SEQUENCE_ELEMENT_TYPE_EXEC 4
|
||||
|
||||
struct ucm_value {
|
||||
struct list_head list;
|
||||
char *name;
|
||||
char *data;
|
||||
};
|
||||
|
||||
struct sequence_element {
|
||||
struct list_head list;
|
||||
unsigned int type;
|
||||
union {
|
||||
long sleep; /* Sleep time in msecs if sleep element, else 0 */
|
||||
char *cdev;
|
||||
char *cset;
|
||||
char *exec;
|
||||
} data;
|
||||
};
|
||||
|
||||
/*
|
||||
* Transition sequences. i.e. transition between one verb, device, mod to another
|
||||
*/
|
||||
struct transition_sequence {
|
||||
struct list_head list;
|
||||
char *name;
|
||||
struct list_head transition_list;
|
||||
};
|
||||
|
||||
/*
|
||||
* Modifier Supported Devices.
|
||||
*/
|
||||
struct dev_list {
|
||||
struct list_head list;
|
||||
char *name;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Describes a Use Case Modifier and it's enable and disable sequences.
|
||||
* A use case verb can have N modifiers.
|
||||
*/
|
||||
struct use_case_modifier {
|
||||
struct list_head list;
|
||||
struct list_head active_list;
|
||||
|
||||
char *name;
|
||||
char *comment;
|
||||
|
||||
/* modifier enable and disable sequences */
|
||||
struct list_head enable_list;
|
||||
struct list_head disable_list;
|
||||
|
||||
/* modifier transition list */
|
||||
struct list_head transition_list;
|
||||
|
||||
/* list of supported devices per modifier */
|
||||
struct list_head dev_list;
|
||||
|
||||
/* values */
|
||||
struct list_head value_list;
|
||||
};
|
||||
|
||||
/*
|
||||
* Describes a Use Case Device and it's enable and disable sequences.
|
||||
* A use case verb can have N devices.
|
||||
*/
|
||||
struct use_case_device {
|
||||
struct list_head list;
|
||||
struct list_head active_list;
|
||||
|
||||
char *name;
|
||||
char *comment;
|
||||
|
||||
/* device enable and disable sequences */
|
||||
struct list_head enable_list;
|
||||
struct list_head disable_list;
|
||||
|
||||
/* device transition list */
|
||||
struct list_head transition_list;
|
||||
|
||||
/* value list */
|
||||
struct list_head value_list;
|
||||
};
|
||||
|
||||
/*
|
||||
* Describes a Use Case Verb and it's enable and disable sequences.
|
||||
* A use case verb can have N devices and N modifiers.
|
||||
*/
|
||||
struct use_case_verb {
|
||||
struct list_head list;
|
||||
|
||||
unsigned int active: 1;
|
||||
|
||||
char *name;
|
||||
char *comment;
|
||||
|
||||
/* verb enable and disable sequences */
|
||||
struct list_head enable_list;
|
||||
struct list_head disable_list;
|
||||
|
||||
/* verb transition list */
|
||||
struct list_head transition_list;
|
||||
|
||||
/* hardware devices that can be used with this use case */
|
||||
struct list_head device_list;
|
||||
|
||||
/* modifiers that can be used with this use case */
|
||||
struct list_head modifier_list;
|
||||
|
||||
/* value list */
|
||||
struct list_head value_list;
|
||||
};
|
||||
|
||||
/*
|
||||
* Manages a sound card and all its use cases.
|
||||
*/
|
||||
struct snd_use_case_mgr {
|
||||
char *card_name;
|
||||
char *comment;
|
||||
|
||||
/* use case verb, devices and modifier configs parsed from files */
|
||||
struct list_head verb_list;
|
||||
|
||||
/* default settings - sequence */
|
||||
struct list_head default_list;
|
||||
|
||||
/* default settings - value list */
|
||||
struct list_head value_list;
|
||||
|
||||
/* current status */
|
||||
struct use_case_verb *active_verb;
|
||||
struct list_head active_devices;
|
||||
struct list_head active_modifiers;
|
||||
|
||||
/* locking */
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
/* change to list of ctl handles */
|
||||
snd_ctl_t *ctl;
|
||||
char *ctl_dev;
|
||||
};
|
||||
|
||||
#define uc_error SNDERR
|
||||
|
||||
#ifdef UC_MGR_DEBUG
|
||||
#define uc_dbg SNDERR
|
||||
#else
|
||||
#define uc_dbg(fmt, arg...)
|
||||
#endif
|
||||
|
||||
void uc_mgr_error(const char *fmt, ...);
|
||||
void uc_mgr_stdout(const char *fmt, ...);
|
||||
|
||||
int uc_mgr_config_load(const char *file, snd_config_t **cfg);
|
||||
int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr);
|
||||
int uc_mgr_scan_master_configs(const char **_list[]);
|
||||
|
||||
void uc_mgr_free_sequence_element(struct sequence_element *seq);
|
||||
void uc_mgr_free_transition_element(struct transition_sequence *seq);
|
||||
void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr);
|
||||
void uc_mgr_free(snd_use_case_mgr_t *uc_mgr);
|
||||
236
src/ucm/utils.c
Normal file
236
src/ucm/utils.c
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Support for the verb/device/modifier core logic and API,
|
||||
* command line tool and file parser was kindly sponsored by
|
||||
* Texas Instruments Inc.
|
||||
* Support for multiple active modifiers and devices,
|
||||
* transition sequences, multiple client access and user defined use
|
||||
* cases was kindly sponsored by Wolfson Microelectronics PLC.
|
||||
*
|
||||
* Copyright (C) 2008-2010 SlimLogic Ltd
|
||||
* Copyright (C) 2010 Wolfson Microelectronics PLC
|
||||
* Copyright (C) 2010 Texas Instruments Inc.
|
||||
* Copyright (C) 2010 Red Hat Inc.
|
||||
* Authors: Liam Girdwood <lrg@slimlogic.co.uk>
|
||||
* Stefan Schmidt <stefan@slimlogic.co.uk>
|
||||
* Justin Xu <justinx@slimlogic.co.uk>
|
||||
* Jaroslav Kysela <perex@perex.cz>
|
||||
*/
|
||||
|
||||
#include "ucm_local.h"
|
||||
|
||||
void uc_mgr_error(const char *fmt,...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
fprintf(stderr, "ucm: ");
|
||||
vfprintf(stderr, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void uc_mgr_stdout(const char *fmt,...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
vfprintf(stdout, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
int uc_mgr_config_load(const char *file, snd_config_t **cfg)
|
||||
{
|
||||
FILE *fp;
|
||||
snd_input_t *in;
|
||||
snd_config_t *top;
|
||||
int err;
|
||||
|
||||
fp = fopen(file, "r");
|
||||
if (fp == NULL) {
|
||||
err = -errno;
|
||||
goto __err;
|
||||
}
|
||||
err = snd_input_stdio_attach(&in, fp, 1);
|
||||
if (err < 0) {
|
||||
__err:
|
||||
uc_error("could not open configuration file %s", file);
|
||||
return err;
|
||||
}
|
||||
err = snd_config_top(&top);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = snd_config_load(top, in);
|
||||
if (err < 0) {
|
||||
uc_error("could not load configuration file %s", file);
|
||||
snd_config_delete(top);
|
||||
return err;
|
||||
}
|
||||
err = snd_input_close(in);
|
||||
if (err < 0) {
|
||||
snd_config_delete(top);
|
||||
return err;
|
||||
}
|
||||
*cfg = top;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uc_mgr_free_value(struct list_head *base)
|
||||
{
|
||||
struct list_head *pos, *npos;
|
||||
struct ucm_value *val;
|
||||
|
||||
list_for_each_safe(pos, npos, base) {
|
||||
val = list_entry(pos, struct ucm_value, list);
|
||||
free(val->name);
|
||||
free(val->data);
|
||||
list_del(&val->list);
|
||||
free(val);
|
||||
}
|
||||
}
|
||||
|
||||
void uc_mgr_free_dev_list(struct list_head *base)
|
||||
{
|
||||
struct list_head *pos, *npos;
|
||||
struct dev_list *dlist;
|
||||
|
||||
list_for_each_safe(pos, npos, base) {
|
||||
dlist = list_entry(pos, struct dev_list, list);
|
||||
free(dlist->name);
|
||||
list_del(&dlist->list);
|
||||
free(dlist);
|
||||
}
|
||||
}
|
||||
|
||||
void uc_mgr_free_sequence_element(struct sequence_element *seq)
|
||||
{
|
||||
if (seq == NULL)
|
||||
return;
|
||||
switch (seq->type) {
|
||||
case SEQUENCE_ELEMENT_TYPE_CSET:
|
||||
case SEQUENCE_ELEMENT_TYPE_EXEC:
|
||||
free(seq->data.exec);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(seq);
|
||||
}
|
||||
|
||||
void uc_mgr_free_sequence(struct list_head *base)
|
||||
{
|
||||
struct list_head *pos, *npos;
|
||||
struct sequence_element *seq;
|
||||
|
||||
list_for_each_safe(pos, npos, base) {
|
||||
seq = list_entry(pos, struct sequence_element, list);
|
||||
list_del(&seq->list);
|
||||
uc_mgr_free_sequence_element(seq);
|
||||
}
|
||||
}
|
||||
|
||||
void uc_mgr_free_transition_element(struct transition_sequence *tseq)
|
||||
{
|
||||
free(tseq->name);
|
||||
uc_mgr_free_sequence(&tseq->transition_list);
|
||||
free(tseq);
|
||||
}
|
||||
|
||||
void uc_mgr_free_transition(struct list_head *base)
|
||||
{
|
||||
struct list_head *pos, *npos;
|
||||
struct transition_sequence *tseq;
|
||||
|
||||
list_for_each_safe(pos, npos, base) {
|
||||
tseq = list_entry(pos, struct transition_sequence, list);
|
||||
list_del(&tseq->list);
|
||||
uc_mgr_free_transition_element(tseq);
|
||||
}
|
||||
}
|
||||
|
||||
void uc_mgr_free_modifier(struct list_head *base)
|
||||
{
|
||||
struct list_head *pos, *npos;
|
||||
struct use_case_modifier *mod;
|
||||
|
||||
list_for_each_safe(pos, npos, base) {
|
||||
mod = list_entry(pos, struct use_case_modifier, list);
|
||||
free(mod->name);
|
||||
free(mod->comment);
|
||||
uc_mgr_free_sequence(&mod->enable_list);
|
||||
uc_mgr_free_sequence(&mod->disable_list);
|
||||
uc_mgr_free_transition(&mod->transition_list);
|
||||
uc_mgr_free_dev_list(&mod->dev_list);
|
||||
uc_mgr_free_value(&mod->value_list);
|
||||
list_del(&mod->list);
|
||||
free(mod);
|
||||
}
|
||||
}
|
||||
|
||||
void uc_mgr_free_device(struct list_head *base)
|
||||
{
|
||||
struct list_head *pos, *npos;
|
||||
struct use_case_device *dev;
|
||||
|
||||
list_for_each_safe(pos, npos, base) {
|
||||
dev = list_entry(pos, struct use_case_device, list);
|
||||
free(dev->name);
|
||||
free(dev->comment);
|
||||
uc_mgr_free_sequence(&dev->enable_list);
|
||||
uc_mgr_free_sequence(&dev->disable_list);
|
||||
uc_mgr_free_transition(&dev->transition_list);
|
||||
uc_mgr_free_value(&dev->value_list);
|
||||
list_del(&dev->list);
|
||||
free(dev);
|
||||
}
|
||||
}
|
||||
|
||||
void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr)
|
||||
{
|
||||
struct list_head *pos, *npos;
|
||||
struct use_case_verb *verb;
|
||||
|
||||
list_for_each_safe(pos, npos, &uc_mgr->verb_list) {
|
||||
verb = list_entry(pos, struct use_case_verb, list);
|
||||
free(verb->name);
|
||||
free(verb->comment);
|
||||
uc_mgr_free_sequence(&verb->enable_list);
|
||||
uc_mgr_free_sequence(&verb->disable_list);
|
||||
uc_mgr_free_transition(&verb->transition_list);
|
||||
uc_mgr_free_value(&verb->value_list);
|
||||
uc_mgr_free_device(&verb->device_list);
|
||||
uc_mgr_free_modifier(&verb->modifier_list);
|
||||
list_del(&verb->list);
|
||||
free(verb);
|
||||
}
|
||||
uc_mgr_free_sequence(&uc_mgr->default_list);
|
||||
uc_mgr_free_value(&uc_mgr->value_list);
|
||||
free(uc_mgr->comment);
|
||||
uc_mgr->comment = NULL;
|
||||
uc_mgr->active_verb = NULL;
|
||||
INIT_LIST_HEAD(&uc_mgr->active_devices);
|
||||
INIT_LIST_HEAD(&uc_mgr->active_modifiers);
|
||||
if (uc_mgr->ctl != NULL) {
|
||||
snd_ctl_close(uc_mgr->ctl);
|
||||
uc_mgr->ctl = NULL;
|
||||
}
|
||||
free(uc_mgr->ctl_dev);
|
||||
uc_mgr->ctl_dev = NULL;
|
||||
}
|
||||
|
||||
void uc_mgr_free(snd_use_case_mgr_t *uc_mgr)
|
||||
{
|
||||
uc_mgr_free_verb(uc_mgr);
|
||||
free(uc_mgr->card_name);
|
||||
free(uc_mgr);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue