alsa-lib/src/ucm/main.c

1002 lines
28 KiB
C
Raw Normal View History

/*
* 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"
#include <stdarg.h>
#include <pthread.h>
/*
* misc
*/
static int check_identifier(const char *identifier, const char *prefix)
{
int len;
if (strcmp(identifier, prefix) == 0)
return 1;
len = strlen(prefix);
if (memcmp(identifier, prefix, len) == 0 && identifier[len] == '/')
return 1;
return 0;
}
static int list_count(struct list_head *list)
{
struct list_head *pos;
int count = 0;
list_for_each(pos, list) {
count += 1;
}
return count;
}
static int alloc_str_list(struct list_head *list, int mult, char **result[])
{
char **res;
int cnt;
cnt = list_count(list) * mult;
if (cnt == 0)
return cnt;
res = calloc(mult, cnt * sizeof(char *));
if (res == NULL)
return -ENOMEM;
*result = res;
return cnt;
}
/**
* \brief Create an identifier
* \param fmt Format (sprintf like)
* \param ... Optional arguments for sprintf like format
* \return Allocated string identifier or NULL on error
*/
char *snd_use_case_identifier(const char *fmt, ...)
{
char *str, *res;
int size = strlen(fmt) + 512;
va_list args;
str = malloc(size);
if (str == NULL)
return NULL;
va_start(args, fmt);
vsnprintf(str, size, fmt, args);
va_end(args);
str[size-1] = '\0';
res = realloc(str, strlen(str) + 1);
if (res)
return res;
return str;
}
/**
* \brief Free a string list
* \param list The string list to free
* \param items Count of strings
* \return Zero if success, otherwise a negative error code
*/
int snd_use_case_free_list(const char *list[], int items)
{
int i;
if (list == NULL)
return 0;
for (i = 0; i < items; i++)
free((void *)list[i]);
free(list);
return 0;
}
/**
* \brief Execute the sequence
* \param uc_mgr Use case manager
* \param seq Sequence
* \return zero on success, otherwise a negative error code
*/
static int execute_sequence(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
struct list_head *seq)
{
struct list_head *pos;
struct sequence_element *s;
list_for_each(pos, seq) {
s = list_entry(pos, struct sequence_element, list);
switch (s->type) {
case SEQUENCE_ELEMENT_TYPE_CSET:
uc_error("cset not yet implemented: '%s'", s->data.cset);
break;
case SEQUENCE_ELEMENT_TYPE_SLEEP:
usleep(s->data.sleep);
break;
case SEQUENCE_ELEMENT_TYPE_EXEC:
uc_error("exec not yet implemented: '%s'", s->data.exec);
break;
default:
uc_error("unknown sequence command %i", s->type);
break;
}
}
return 0;
}
/**
* \brief Import master config and execute the default sequence
* \param uc_mgr Use case manager
* \return zero on success, otherwise a negative error code
*/
static int import_master_config(snd_use_case_mgr_t *uc_mgr)
{
int err;
err = uc_mgr_import_master_config(uc_mgr);
if (err < 0)
return err;
err = execute_sequence(uc_mgr, &uc_mgr->default_list);
if (err < 0)
uc_error("Unable to execute default sequence");
return err;
}
/**
* \brief Universal find - string in a list
* \param list List of structures
* \param offset Offset of list structure
* \param soffset Offset of string structure
* \param match String to match
* \return structure on success, otherwise a NULL (not found)
*/
static void *find0(struct list_head *list,
unsigned long offset,
unsigned long soffset,
const char *match)
{
struct list_head *pos;
char *ptr, *str;
list_for_each(pos, list) {
ptr = list_entry_offset(pos, char, offset);
str = *((char **)(ptr + soffset));
if (strcmp(str, match) == 0)
return ptr;
}
return NULL;
}
#define find(list, type, member, value, match) \
find0(list, (unsigned long)(&((type *)0)->member), \
(unsigned long)(&((type *)0)->value), match)
/**
* \brief Universal string list
* \param list List of structures
* \param result Result list
* \param offset Offset of list structure
* \param s1offset Offset of string structure
* \return count of items on success, otherwise a negative error code
*/
static int get_list0(struct list_head *list,
const char **result[],
unsigned long offset,
unsigned long s1offset)
{
char **res;
int cnt;
struct list_head *pos;
char *ptr, *str1;
cnt = alloc_str_list(list, 1, &res);
if (cnt <= 0)
return cnt;
*result = (const char **)res;
list_for_each(pos, list) {
ptr = list_entry_offset(pos, char, offset);
str1 = *((char **)(ptr + s1offset));
if (str1 != NULL) {
*res = strdup(str1);
if (*res == NULL)
goto __fail;
} else {
*res = NULL;
}
res++;
}
return cnt;
__fail:
snd_use_case_free_list((const char **)res, cnt);
return -ENOMEM;
}
#define get_list(list, result, type, member, s1) \
get_list0(list, result, \
(unsigned long)(&((type *)0)->member), \
(unsigned long)(&((type *)0)->s1))
/**
* \brief Universal string list - pair of strings
* \param list List of structures
* \param result Result list
* \param offset Offset of list structure
* \param s1offset Offset of string structure
* \param s1offset Offset of string structure
* \return count of items on success, otherwise a negative error code
*/
static int get_list20(struct list_head *list,
const char **result[],
unsigned long offset,
unsigned long s1offset,
unsigned long s2offset)
{
char **res;
int cnt;
struct list_head *pos;
char *ptr, *str1, *str2;
cnt = alloc_str_list(list, 2, &res);
if (cnt <= 0)
return cnt;
*result = (const char **)res;
list_for_each(pos, list) {
ptr = list_entry_offset(pos, char, offset);
str1 = *((char **)(ptr + s1offset));
if (str1 != NULL) {
*res = strdup(str1);
if (*res == NULL)
goto __fail;
} else {
*res = NULL;
}
res++;
str2 = *((char **)(ptr + s2offset));
if (str2 != NULL) {
*res = strdup(str2);
if (*res == NULL)
goto __fail;
} else {
*res = NULL;
}
res++;
}
return cnt;
__fail:
snd_use_case_free_list((const char **)res, cnt);
return -ENOMEM;
}
#define get_list2(list, result, type, member, s1, s2) \
get_list20(list, result, \
(unsigned long)(&((type *)0)->member), \
(unsigned long)(&((type *)0)->s1), \
(unsigned long)(&((type *)0)->s2))
/**
* \brief Find verb
* \param uc_mgr Use case manager
* \param verb_name verb to find
* \return structure on success, otherwise a NULL (not found)
*/
static inline struct use_case_verb *find_verb(snd_use_case_mgr_t *uc_mgr,
const char *verb_name)
{
return find(&uc_mgr->verb_list,
struct use_case_verb, list, name,
verb_name);
}
/**
* \brief Find modifier
* \param verb Use case verb
* \param modifier_name modifier to find
* \return structure on success, otherwise a NULL (not found)
*/
static inline struct use_case_modifier *
find_modifier(struct use_case_verb *verb,
const char *modifier_name)
{
return find(&verb->modifier_list,
struct use_case_modifier, list, name,
modifier_name);
}
/**
* \brief Set verb
* \param uc_mgr Use case manager
* \param verb verb to set
* \param enable nonzero = enable, zero = disable
* \return zero on success, otherwise a negative error code
*/
static int set_verb(snd_use_case_mgr_t *uc_mgr,
struct use_case_verb *verb,
int enable)
{
struct list_head *seq;
int err;
if (enable) {
seq = &verb->enable_list;
} else {
seq = &verb->disable_list;
}
err = execute_sequence(uc_mgr, seq);
if (enable && err >= 0)
uc_mgr->active_verb = verb;
return err;
}
/**
* \brief Set modifier
* \param uc_mgr Use case manager
* \param modifier modifier to set
* \param enable nonzero = enable, zero = disable
* \return zero on success, otherwise a negative error code
*/
static int set_modifier(snd_use_case_mgr_t *uc_mgr,
struct use_case_modifier *modifier,
int enable)
{
struct list_head *seq;
int err;
if (enable) {
seq = &modifier->enable_list;
} else {
seq = &modifier->disable_list;
}
err = execute_sequence(uc_mgr, seq);
if (enable && err >= 0) {
list_add_tail(&modifier->active_list, &uc_mgr->active_modifiers);
} else if (!enable) {
list_del(&modifier->active_list);
}
return err;
}
/**
* \brief Set device
* \param uc_mgr Use case manager
* \param device device to set
* \param enable nonzero = enable, zero = disable
* \return zero on success, otherwise a negative error code
*/
static int set_device(snd_use_case_mgr_t *uc_mgr,
struct use_case_device *device,
int enable)
{
struct list_head *seq;
int err;
if (enable) {
seq = &device->enable_list;
} else {
seq = &device->disable_list;
}
err = execute_sequence(uc_mgr, seq);
if (enable && err >= 0) {
list_add_tail(&device->active_list, &uc_mgr->active_devices);
} else if (!enable) {
list_del(&device->active_list);
}
return err;
}
/**
* \brief Init sound card use case manager.
* \param uc_mgr Returned use case manager pointer
* \param card_name name of card to open
* \return zero on success, otherwise a negative error code
*/
int snd_use_case_mgr_open(snd_use_case_mgr_t **mgr,
const char *card_name)
{
snd_use_case_mgr_t *uc_mgr;
int err;
/* create a new UCM */
uc_mgr = calloc(1, sizeof(snd_use_case_mgr_t));
if (uc_mgr == NULL)
return -ENOMEM;
INIT_LIST_HEAD(&uc_mgr->verb_list);
INIT_LIST_HEAD(&uc_mgr->default_list);
pthread_mutex_init(&uc_mgr->mutex, NULL);
uc_mgr->card_name = strdup(card_name);
if (uc_mgr->card_name == NULL) {
free(uc_mgr);
return -ENOMEM;
}
/* get info on use_cases and verify against card */
err = import_master_config(uc_mgr);
if (err < 0) {
uc_error("error: failed to import %s use case configuration %d",
card_name, err);
goto err;
}
*mgr = uc_mgr;
return 0;
err:
uc_mgr_free(uc_mgr);
return err;
}
/**
* \brief Reload and reparse all use case files.
* \param uc_mgr Use case manager
* \return zero on success, otherwise a negative error code
*/
int snd_use_case_mgr_reload(snd_use_case_mgr_t *uc_mgr)
{
int err;
pthread_mutex_lock(&uc_mgr->mutex);
uc_mgr_free_verb(uc_mgr);
/* reload all use cases */
err = import_master_config(uc_mgr);
if (err < 0) {
uc_error("error: failed to reload use cases\n");
pthread_mutex_unlock(&uc_mgr->mutex);
return -EINVAL;
}
pthread_mutex_unlock(&uc_mgr->mutex);
return err;
}
/**
* \brief Close use case manager.
* \param uc_mgr Use case manager
* \return zero on success, otherwise a negative error code
*/
int snd_use_case_mgr_close(snd_use_case_mgr_t *uc_mgr)
{
uc_mgr_free(uc_mgr);
return 0;
}
/**
* \brief Reset sound card controls to default values.
* \param uc_mgr Use case manager
* \return zero on success, otherwise a negative error code
*/
int snd_use_case_mgr_reset(snd_use_case_mgr_t *uc_mgr)
{
struct list_head *pos, *npos;
struct use_case_modifier *modifier;
struct use_case_device *device;
int err;
pthread_mutex_lock(&uc_mgr->mutex);
list_for_each_safe(pos, npos, &uc_mgr->active_modifiers) {
modifier = list_entry(pos, struct use_case_modifier,
active_list);
err = set_modifier(uc_mgr, modifier, 0);
if (err < 0)
uc_error("Unable to disable modifier %s", modifier->name);
}
INIT_LIST_HEAD(&uc_mgr->active_modifiers);
list_for_each_safe(pos, npos, &uc_mgr->active_devices) {
device = list_entry(pos, struct use_case_device,
active_list);
err = set_device(uc_mgr, device, 0);
if (err < 0)
uc_error("Unable to disable device %s", device->name);
}
INIT_LIST_HEAD(&uc_mgr->active_devices);
err = set_verb(uc_mgr, uc_mgr->active_verb, 0);
if (err < 0) {
uc_error("Unable to disable verb %s", uc_mgr->active_verb->name);
return err;
}
uc_mgr->active_verb = NULL;
err = execute_sequence(uc_mgr, &uc_mgr->default_list);
pthread_mutex_unlock(&uc_mgr->mutex);
return err;
}
/**
* \brief Get list of cards in pair cardname+comment
* \param list Returned list
* \return Number of list entries if success, otherwise a negative error code
*/
static int get_card_list(const char **list[])
{
return -ENXIO; /* Not Yet Implemented */
}
/**
* \brief Get list of verbs in pair verbname+comment
* \param list Returned list
* \param verbname For verb (NULL = current)
* \return Number of list entries if success, otherwise a negative error code
*/
static int get_verb_list(snd_use_case_mgr_t *uc_mgr, const char **list[])
{
return get_list2(&uc_mgr->verb_list, list,
struct use_case_verb, list,
name, comment);
}
/**
* \brief Get list of devices in pair devicename+comment
* \param list Returned list
* \param verbname For verb (NULL = current)
* \return Number of list entries if success, otherwise a negative error code
*/
static int get_device_list(snd_use_case_mgr_t *uc_mgr, const char **list[],
char *verbname)
{
struct use_case_verb *verb;
if (verbname) {
verb = find_verb(uc_mgr, verbname);
} else {
verb = uc_mgr->active_verb;
}
if (verb == NULL)
return -ENOENT;
return get_list2(&verb->device_list, list,
struct use_case_device, list,
name, comment);
return 0;
}
/**
* \brief Get list of modifiers in pair devicename+comment
* \param list Returned list
* \param verbname For verb (NULL = current)
* \return Number of list entries if success, otherwise a negative error code
*/
static int get_modifier_list(snd_use_case_mgr_t *uc_mgr, const char **list[],
char *verbname)
{
struct use_case_verb *verb;
if (verbname) {
verb = find_verb(uc_mgr, verbname);
} else {
verb = uc_mgr->active_verb;
}
if (verb == NULL)
return -ENOENT;
return get_list2(&verb->modifier_list, list,
struct use_case_modifier, list,
name, comment);
return 0;
}
struct myvalue {
struct list_head list;
char *value;
};
static int add_values(struct list_head *list,
const char *identifier,
struct list_head *source)
{
struct ucm_value *v;
struct myvalue *val;
struct list_head *pos, *pos1;
int match;
list_for_each(pos, source) {
v = list_entry(pos, struct ucm_value, list);
if (check_identifier(identifier, v->name)) {
match = 0;
list_for_each(pos1, list) {
val = list_entry(pos1, struct myvalue, list);
if (strcmp(val->value, v->data) == 0) {
match = 1;
break;
}
}
if (!match) {
val = malloc(sizeof(struct myvalue));
if (val == NULL)
return -ENOMEM;
list_add_tail(&val->list, list);
}
}
}
return 0;
}
/**
* \brief Get list of values
* \param list Returned list
* \param verbname For verb (NULL = current)
* \return Number of list entries if success, otherwise a negative error code
*/
static int get_value_list(snd_use_case_mgr_t *uc_mgr,
const char *identifier,
const char **list[],
char *verbname)
{
struct list_head mylist, *pos, *npos;
struct myvalue *val;
struct use_case_verb *verb;
struct use_case_device *dev;
struct use_case_modifier *mod;
char **res;
int err;
if (verbname) {
verb = find_verb(uc_mgr, verbname);
} else {
verb = uc_mgr->active_verb;
}
if (verb == NULL)
return -ENOENT;
INIT_LIST_HEAD(&mylist);
err = add_values(&mylist, identifier, &verb->value_list);
if (err < 0)
goto __fail;
list_for_each(pos, &verb->device_list) {
dev = list_entry(pos, struct use_case_device, list);
err = add_values(&mylist, identifier, &dev->value_list);
if (err < 0)
goto __fail;
}
list_for_each(pos, &verb->modifier_list) {
mod = list_entry(pos, struct use_case_modifier, list);
err = add_values(&mylist, identifier, &mod->value_list);
if (err < 0)
goto __fail;
}
err = alloc_str_list(&mylist, 1, &res);
*list = (const char **)res;
if (err >= 0) {
list_for_each(pos, &mylist) {
val = list_entry(pos, struct myvalue, list);
*res = strdup(val->value);
if (*res == NULL) {
snd_use_case_free_list((const char **)res, err);
err = -ENOMEM;
goto __fail;
}
res++;
}
}
__fail:
list_for_each_safe(pos, npos, &mylist) {
val = list_entry(pos, struct myvalue, list);
list_del(&val->list);
free(val);
}
return err;
}
/**
* \brief Get list of enabled devices
* \param list Returned list
* \param verbname For verb (NULL = current)
* \return Number of list entries if success, otherwise a negative error code
*/
static int get_enabled_device_list(snd_use_case_mgr_t *uc_mgr,
const char **list[])
{
if (uc_mgr->active_verb == NULL)
return -EINVAL;
return get_list(&uc_mgr->active_devices, list,
struct use_case_device, active_list,
name);
}
/**
* \brief Get list of enabled modifiers
* \param list Returned list
* \param verbname For verb (NULL = current)
* \return Number of list entries if success, otherwise a negative error code
*/
static int get_enabled_modifier_list(snd_use_case_mgr_t *uc_mgr,
const char **list[])
{
if (uc_mgr->active_verb == NULL)
return -EINVAL;
return get_list(&uc_mgr->active_modifiers, list,
struct use_case_modifier, active_list,
name);
}
/**
* \brief Obtain a list of entries
* \param uc_mgr Use case manager (may be NULL - card list)
* \param identifier (may be NULL - card list)
* \param list Returned allocated list
* \return Number of list entries if success, otherwise a negative error code
*/
int snd_use_case_get_list(snd_use_case_mgr_t *uc_mgr,
const char *identifier,
const char **list[])
{
char *str, *str1;
int err;
if (uc_mgr == NULL || identifier == NULL)
return get_card_list(list);
pthread_mutex_lock(&uc_mgr->mutex);
if (strcmp(identifier, "_verbs") == 0)
err = get_verb_list(uc_mgr, list);
else if (strcmp(identifier, "_enadevs"))
err = get_enabled_device_list(uc_mgr, list);
else if (strcmp(identifier, "_enamods"))
err = get_enabled_modifier_list(uc_mgr, list);
else {
str1 = strchr(identifier, '/');
if (str1) {
str = strdup(str1 + 1);
if (str == NULL) {
err = -ENOMEM;
goto __end;
}
} else {
str = NULL;
}
if (check_identifier(identifier, "_devices"))
err = get_device_list(uc_mgr, list, str);
else if (check_identifier(identifier, "_modifiers"))
err = get_modifier_list(uc_mgr, list, str);
else
err = get_value_list(uc_mgr, identifier, list, str);
if (str)
free(str);
}
__end:
pthread_mutex_unlock(&uc_mgr->mutex);
return err;
}
static int get_value1(const char **value, struct list_head *value_list,
const char *identifier)
{
struct ucm_value *val;
struct list_head *pos;
list_for_each(pos, value_list) {
val = list_entry(pos, struct ucm_value, list);
if (check_identifier(identifier, val->name)) {
*value = strdup(val->data);
if (*value == NULL)
return -ENOMEM;
return 0;
}
}
return 0;
}
/**
* \brief Get value
* \param list Returned list
* \param verbname For verb (NULL = current)
* \return Number of list entries if success, otherwise a negative error code
*/
static int get_value(snd_use_case_mgr_t *uc_mgr,
const char *identifier,
const char **value,
const char *modifier)
{
struct use_case_modifier *mod;
if (uc_mgr->active_verb == NULL)
return -ENOENT;
if (modifier == NULL)
return get_value1(value, &uc_mgr->active_verb->value_list,
identifier);
mod = find_modifier(uc_mgr->active_verb, modifier);
if (mod == NULL)
return -EINVAL;
return get_value1(value, &mod->value_list, identifier);
}
/**
* \brief Get current - string
* \param uc_mgr Use case manager
* \param identifier
* \param value Value pointer
* \return Zero if success, otherwise a negative error code
*
* Note: String is dynamically allocated, use free() to
* deallocate this string.
*/
int snd_use_case_get(snd_use_case_mgr_t *uc_mgr,
const char *identifier,
const char **value)
{
char *str, *str1;
int err;
pthread_mutex_lock(&uc_mgr->mutex);
if (identifier == NULL) {
*value = strdup(uc_mgr->card_name);
if (*value == NULL) {
err = -ENOMEM;
goto __end;
}
err = 0;
} else if (strcmp(identifier, "_verb") == 0) {
if (uc_mgr->active_verb == NULL)
return -ENOENT;
*value = strdup(uc_mgr->active_verb->name);
if (*value == NULL) {
err = -ENOMEM;
goto __end;
}
err = 0;
} else {
str1 = strchr(identifier, '/');
if (str1) {
str = strdup(str1 + 1);
if (str == NULL) {
err = -ENOMEM;
goto __end;
}
} else {
str = NULL;
}
err = get_value(uc_mgr, identifier, value, str);
if (str)
free(str);
}
__end:
pthread_mutex_unlock(&uc_mgr->mutex);
return err;
}
long device_status(snd_use_case_mgr_t *uc_mgr,
const char *device_name)
{
struct use_case_device *dev;
struct list_head *pos;
list_for_each(pos, &uc_mgr->active_devices) {
dev = list_entry(pos, struct use_case_device, active_list);
if (strcmp(dev->name, device_name) == 0)
return 1;
}
return 0;
}
long modifier_status(snd_use_case_mgr_t *uc_mgr,
const char *modifier_name)
{
struct use_case_modifier *mod;
struct list_head *pos;
list_for_each(pos, &uc_mgr->active_modifiers) {
mod = list_entry(pos, struct use_case_modifier, active_list);
if (strcmp(mod->name, modifier_name) == 0)
return 1;
}
return 0;
}
/**
* \brief Get current - integer
* \param uc_mgr Use case manager
* \param identifier
* \return Value if success, otherwise a negative error code
*/
long snd_use_case_geti(snd_use_case_mgr_t *uc_mgr,
const char *identifier)
{
char *str, *str1;
long err;
pthread_mutex_lock(&uc_mgr->mutex);
if (0) {
/* nothing here - prepared for fixed identifiers */
} else {
str1 = strchr(identifier, '/');
if (str1) {
str = strdup(str1 + 1);
if (str == NULL) {
err = -ENOMEM;
goto __end;
}
} else {
str = NULL;
}
if (check_identifier(identifier, "_devstatus"))
err = device_status(uc_mgr, str);
else if (check_identifier(identifier, "_modstatus"))
err = modifier_status(uc_mgr, str);
else
err = -EINVAL;
if (str)
free(str);
}
__end:
pthread_mutex_unlock(&uc_mgr->mutex);
return err;
}
/**
* \brief Set new
* \param uc_mgr Use case manager
* \param identifier
* \param value Value
* \return Zero if success, otherwise a negative error code
*/
int snd_use_case_set(snd_use_case_mgr_t *uc_mgr,
const char *identifier,
const char *value)
{
char *str, *str1;
int err;
pthread_mutex_lock(&uc_mgr->mutex);
if (strcmp(identifier, "_verb") == 0)
err = set_verb_user(uc_mgr, value);
else if (strcmp(identifier, "_enadev") == 0)
err = set_device_user(uc_mgr, value, 1);
else if (strcmp(identifier, "_disdev") == 0)
err = set_device_user(uc_mgr, value, 0);
else if (strcmp(identifier, "_enamod") == 0)
err = set_modifier_user(uc_mgr, value, 1);
else if (strcmp(identifier, "_dismod") == 0)
err = set_modifier_user(uc_mgr, value, 0);
else {
str1 = strchr(identifier, '/');
if (str1) {
str = strdup(str1 + 1);
if (str == NULL) {
err = -ENOMEM;
goto __end;
}
} else {
str = NULL;
}
if (check_identifier(identifier, "_swdev"))
err = switch_device(uc_mgr, str, value);
else if (check_identifier(identifier, "_swmod"))
err = switch_modifier(uc_mgr, str, value);
else
err = -EINVAL;
if (str)
free(str);
}
__end:
pthread_mutex_unlock(&uc_mgr->mutex);
return err;
}