* 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.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Support for the verb/device/modifier core logic and API,
* command line tool and file parser was kindly sponsored by
{
struct list_head *pos;
int count = 0;
-
+
list_for_each(pos, list) {
count += 1;
}
{
char **res;
int cnt;
-
+
cnt = list_count(list) * mult;
- if (cnt == 0)
+ if (cnt == 0) {
+ *result = NULL;
return cnt;
+ }
res = calloc(mult, cnt * sizeof(char *));
if (res == NULL)
return -ENOMEM;
free(uc_mgr->ctl_dev);
uc_mgr->ctl_dev = NULL;
snd_ctl_close(uc_mgr->ctl);
-
+
}
err = snd_ctl_open(ctl, ctl_dev, 0);
if (err < 0)
pos = strrchr(cset, ' ');
if (pos == NULL) {
uc_error("undefined value for cset >%s<", cset);
- return -EINVAL;
+ err = -EINVAL;
+ goto __fail;
}
*pos = '\0';
err = snd_ctl_ascii_elem_id_parse(id, cset);
goto __fail;
err = 0;
__fail:
- *pos = ' ';
+ if (pos != NULL)
+ *pos = ' ';
+
+ if (id != NULL)
+ free(id);
+ if (value != NULL)
+ free(value);
+ if (info != NULL)
+ free(info);
+
return err;
}
usleep(s->data.sleep);
break;
case SEQUENCE_ELEMENT_TYPE_EXEC:
- err = system(s->data.exec);
+ /* Remove because security issues */
+ /* err = system(s->data.exec);
if (err < 0)
- goto __fail;
+ goto __fail; */
+ uc_error("unsupported known sequence command %i", s->type);
break;
default:
uc_error("unknown sequence command %i", s->type);
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;
verb_name);
}
+static int is_devlist_supported(snd_use_case_mgr_t *uc_mgr,
+ struct dev_list *dev_list)
+{
+ struct dev_list_node *device;
+ struct use_case_device *adev;
+ struct list_head *pos, *pos1;
+ int found_ret;
+
+ switch (dev_list->type) {
+ case DEVLIST_NONE:
+ default:
+ return 1;
+ case DEVLIST_SUPPORTED:
+ found_ret = 1;
+ break;
+ case DEVLIST_CONFLICTING:
+ found_ret = 0;
+ break;
+ }
+
+ list_for_each(pos, &dev_list->list) {
+ device = list_entry(pos, struct dev_list_node, list);
+
+ list_for_each(pos1, &uc_mgr->active_devices) {
+ adev = list_entry(pos1, struct use_case_device,
+ active_list);
+ if (!strcmp(device->name, adev->name))
+ return found_ret;
+ }
+ }
+ return 1 - found_ret;
+}
+
+static inline int is_modifier_supported(snd_use_case_mgr_t *uc_mgr,
+ struct use_case_modifier *modifier)
+{
+ return is_devlist_supported(uc_mgr, &modifier->dev_list);
+}
+
+static inline int is_device_supported(snd_use_case_mgr_t *uc_mgr,
+ struct use_case_device *device)
+{
+ return is_devlist_supported(uc_mgr, &device->dev_list);
+}
+
/**
* \brief Find device
* \param verb Use case verb
* \return structure on success, otherwise a NULL (not found)
*/
static inline struct use_case_device *
- find_device(struct use_case_verb *verb,
- const char *device_name)
+ find_device(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb,
+ const char *device_name, int check_supported)
{
- return find(&verb->device_list,
- struct use_case_device, list, name,
- device_name);
-}
+ struct use_case_device *device;
+ struct list_head *pos;
-static int is_modifier_supported(snd_use_case_mgr_t *uc_mgr,
- struct use_case_modifier *modifier)
-{
- struct dev_list *device;
- struct use_case_device *adev;
- struct list_head *pos, *pos1;
- char *cpos;
- int dlen, len;
-
- list_for_each(pos, &modifier->dev_list) {
- device = list_entry(pos, struct dev_list, list);
- cpos = strchr(device->name, '.');
- if (cpos) {
- if (find(&uc_mgr->active_devices,
- struct use_case_device, active_list,
- name, device->name))
- return 1;
- } else {
- dlen = strlen(device->name);
- list_for_each(pos1, &uc_mgr->active_devices) {
- adev = list_entry(pos1, struct use_case_device,
- active_list);
- cpos = strchr(adev->name, '.');
- if (cpos)
- len = cpos - adev->name;
- else
- len = strlen(adev->name);
- if (len != dlen)
- continue;
- if (memcmp(adev->name, device->name, len))
- continue;
- return 1;
- }
- }
+ list_for_each(pos, &verb->device_list) {
+ device = list_entry(pos, struct use_case_device, list);
+
+ if (strcmp(device_name, device->name))
+ continue;
+
+ if (check_supported &&
+ !is_device_supported(uc_mgr, device))
+ continue;
+
+ return device;
}
- return 0;
+ return NULL;
}
/**
* \return structure on success, otherwise a NULL (not found)
*/
static struct use_case_modifier *
- find_modifier(snd_use_case_mgr_t *uc_mgr, const char *modifier_name)
+ find_modifier(snd_use_case_mgr_t *uc_mgr, struct use_case_verb *verb,
+ const char *modifier_name, int check_supported)
{
struct use_case_modifier *modifier;
- struct use_case_verb *verb = uc_mgr->active_verb;
struct list_head *pos;
- char name[64], *cpos;
list_for_each(pos, &verb->modifier_list) {
modifier = list_entry(pos, struct use_case_modifier, list);
- strncpy(name, modifier->name, sizeof(name));
- name[sizeof(name)-1] = '\0';
- cpos = strchr(name, '.');
- if (!cpos)
+ if (strcmp(modifier->name, modifier_name))
continue;
- *cpos= '\0';
- if (strcmp(name, modifier_name))
+ if (check_supported &&
+ !is_modifier_supported(uc_mgr, modifier))
continue;
- if (is_modifier_supported(uc_mgr, modifier))
- return modifier;
+ return modifier;
}
return NULL;
}
err = execute_sequence(uc_mgr, &uc_mgr->default_list,
&uc_mgr->value_list, NULL, NULL);
-
+
return err;
}
char *verbname)
{
struct use_case_verb *verb;
-
+
if (verbname) {
verb = find_verb(uc_mgr, verbname);
} else {
char *verbname)
{
struct use_case_verb *verb;
-
+
if (verbname) {
verb = find_verb(uc_mgr, verbname);
} else {
name, comment);
}
+/**
+ * \brief Get list of supported/conflicting devices
+ * \param list Returned list
+ * \param name Name of modifier or verb to query
+ * \param type Type of device list entries to return
+ * \return Number of list entries if success, otherwise a negative error code
+ */
+static int get_supcon_device_list(snd_use_case_mgr_t *uc_mgr,
+ const char **list[], char *name,
+ enum dev_list_type type)
+{
+ char *str;
+ struct use_case_verb *verb;
+ struct use_case_modifier *modifier;
+ struct use_case_device *device;
+
+ if (!name)
+ return -ENOENT;
+
+ str = strchr(name, '/');
+ if (str) {
+ *str = '\0';
+ verb = find_verb(uc_mgr, str + 1);
+ }
+ else {
+ verb = uc_mgr->active_verb;
+ }
+ if (!verb)
+ return -ENOENT;
+
+ modifier = find_modifier(uc_mgr, verb, name, 0);
+ if (modifier) {
+ if (modifier->dev_list.type != type)
+ return 0;
+ return get_list(&modifier->dev_list.list, list,
+ struct dev_list_node, list,
+ name);
+ }
+
+ device = find_device(uc_mgr, verb, name, 0);
+ if (device) {
+ if (device->dev_list.type != type)
+ return 0;
+ return get_list(&device->dev_list.list, list,
+ struct dev_list_node, list,
+ name);
+ }
+
+ return -ENOENT;
+
+}
+
+/**
+ * \brief Get list of supported devices
+ * \param list Returned list
+ * \param name Name of verb or modifier to query
+ * \return Number of list entries if success, otherwise a negative error code
+ */
+static int get_supported_device_list(snd_use_case_mgr_t *uc_mgr,
+ const char **list[], char *name)
+{
+ return get_supcon_device_list(uc_mgr, list, name, DEVLIST_SUPPORTED);
+}
+
+/**
+ * \brief Get list of conflicting devices
+ * \param list Returned list
+ * \param name Name of verb or modifier to query
+ * \return Number of list entries if success, otherwise a negative error code
+ */
+static int get_conflicting_device_list(snd_use_case_mgr_t *uc_mgr,
+ const char **list[], char *name)
+{
+ return get_supcon_device_list(uc_mgr, list, name, DEVLIST_CONFLICTING);
+}
+
struct myvalue {
struct list_head list;
char *value;
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)) {
val = malloc(sizeof(struct myvalue));
if (val == NULL)
return -ENOMEM;
+ val->value = v->data;
list_add_tail(&val->list, list);
}
}
struct use_case_modifier *mod;
char **res;
int err;
-
+
if (verbname) {
verb = find_verb(uc_mgr, verbname);
} else {
goto __fail;
}
err = alloc_str_list(&mylist, 1, &res);
- *list = (const char **)res;
if (err >= 0) {
+ *list = (const char **)res;
list_for_each(pos, &mylist) {
val = list_entry(pos, struct myvalue, list);
*res = strdup(val->value);
err = get_device_list(uc_mgr, list, str);
else if (check_identifier(identifier, "_modifiers"))
err = get_modifier_list(uc_mgr, list, str);
+ else if (check_identifier(identifier, "_supporteddevs"))
+ err = get_supported_device_list(uc_mgr, list, str);
+ else if (check_identifier(identifier, "_conflictingdevs"))
+ err = get_conflicting_device_list(uc_mgr, list, str);
+ else if (identifier[0] == '_')
+ err = -ENOENT;
else
err = get_value_list(uc_mgr, identifier, list, str);
if (str)
{
struct ucm_value *val;
struct list_head *pos;
-
+
if (!value_list)
return -ENOENT;
* \param uc_mgr Use case manager
* \param identifier Value identifier (string)
* \param value Returned value string
- * \param modifier modifier name (string)
+ * \param item Modifier or Device name (string)
* \return Zero on success (value is filled), 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)
+ const char *identifier,
+ const char **value,
+ const char *mod_dev_name,
+ const char *verb_name,
+ int exact)
{
- struct use_case_modifier *mod;
+ struct use_case_verb *verb;
+ struct use_case_modifier *mod;
+ struct use_case_device *dev;
int err;
- if (modifier != NULL) {
- mod = find_modifier(uc_mgr, modifier);
- if (mod != NULL) {
- err = get_value1(value, &mod->value_list, identifier);
+ if (mod_dev_name || verb_name || !exact) {
+ if (verb_name && strlen(verb_name)) {
+ verb = find_verb(uc_mgr, verb_name);
+ } else {
+ verb = uc_mgr->active_verb;
+ }
+ if (verb) {
+ if (mod_dev_name) {
+ mod = find_modifier(uc_mgr, verb,
+ mod_dev_name, 0);
+ if (mod) {
+ err = get_value1(value,
+ &mod->value_list,
+ identifier);
+ if (err >= 0 || err != -ENOENT)
+ return err;
+ }
+
+ dev = find_device(uc_mgr, verb,
+ mod_dev_name, 0);
+ if (dev) {
+ err = get_value1(value,
+ &dev->value_list,
+ identifier);
+ if (err >= 0 || err != -ENOENT)
+ return err;
+ }
+
+ if (exact)
+ return -ENOENT;
+ }
+
+ err = get_value1(value, &verb->value_list, identifier);
if (err >= 0 || err != -ENOENT)
return err;
}
+
+ if (exact)
+ return -ENOENT;
}
- err = get_value1(value, &uc_mgr->active_verb->value_list, identifier);
- if (err >= 0 || err != -ENOENT)
- return err;
+
err = get_value1(value, &uc_mgr->value_list, identifier);
if (err >= 0 || err != -ENOENT)
return err;
+
return -ENOENT;
}
/**
* \brief Get current - string
* \param uc_mgr Use case manager
- * \param identifier
+ * \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;
+ const char *slash1, *slash2, *mod_dev_after;
+ const char *ident, *mod_dev, *verb;
+ int exact = 0;
int err;
pthread_mutex_lock(&uc_mgr->mutex);
}
err = 0;
} else if (strcmp(identifier, "_verb") == 0) {
- if (uc_mgr->active_verb == NULL)
- return -ENOENT;
+ if (uc_mgr->active_verb == NULL) {
+ err = -ENOENT;
+ goto __end;
+ }
*value = strdup(uc_mgr->active_verb->name);
if (*value == NULL) {
err = -ENOMEM;
goto __end;
}
err = 0;
+ } else if (identifier[0] == '_') {
+ err = -ENOENT;
+ goto __end;
} 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);
+ if (identifier[0] == '=') {
+ exact = 1;
+ identifier++;
+ }
+
+ slash1 = strchr(identifier, '/');
+ if (slash1) {
+ ident = strndup(identifier, slash1 - identifier);
+
+ slash2 = strchr(slash1 + 1, '/');
+ if (slash2) {
+ mod_dev_after = slash2;
+ verb = slash2 + 1;
+ }
+ else {
+ mod_dev_after = slash1 + strlen(slash1);
+ verb = NULL;
+ }
+
+ if (mod_dev_after == slash1 + 1)
+ mod_dev = NULL;
+ else
+ mod_dev = strndup(slash1 + 1,
+ mod_dev_after - (slash1 + 1));
+ }
+ else {
+ ident = identifier;
+ mod_dev = NULL;
+ verb = NULL;
+ }
+
+ err = get_value(uc_mgr, ident, value, mod_dev, verb, exact);
+ if (ident != identifier)
+ free((void *)ident);
+ if (mod_dev)
+ free((void *)mod_dev);
}
__end:
pthread_mutex_unlock(&uc_mgr->mutex);
{
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)
{
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)
/**
* \brief Get current - integer
* \param uc_mgr Use case manager
- * \param identifier
- * \return Value if success, otherwise a negative error code
+ * \param identifier
+ * \return Value if success, otherwise a negative error code
*/
int snd_use_case_geti(snd_use_case_mgr_t *uc_mgr,
const char *identifier,
*value = err;
err = 0;
}
+#if 0
+ /*
+ * enable this block if the else clause below is expanded to query
+ * user-supplied values
+ */
+ } else if (identifier[0] == '_')
+ err = -ENOENT;
+#endif
} else
- err = -EINVAL;
+ err = -ENOENT;
if (str)
free(str);
}
if (uc_mgr->active_verb == NULL)
return -ENOENT;
- device = find_device(uc_mgr->active_verb, device_name);
+ device = find_device(uc_mgr, uc_mgr->active_verb, device_name, 1);
if (device == NULL)
return -ENOENT;
return set_device(uc_mgr, device, enable);
if (uc_mgr->active_verb == NULL)
return -ENOENT;
- modifier = find_modifier(uc_mgr, modifier_name);
+ modifier = find_modifier(uc_mgr, uc_mgr->active_verb, modifier_name, 1);
if (modifier == NULL)
return -ENOENT;
return set_modifier(uc_mgr, modifier, enable);
struct transition_sequence *trans;
struct list_head *pos;
int err, seq_found = 0;
-
+
if (uc_mgr->active_verb == NULL)
return -ENOENT;
if (device_status(uc_mgr, old_device) == 0) {
uc_error("error: device %s already enabled", new_device);
return -EINVAL;
}
- xold = find_device(uc_mgr->active_verb, old_device);
+ xold = find_device(uc_mgr, uc_mgr->active_verb, old_device, 1);
if (xold == NULL)
return -ENOENT;
- xnew = find_device(uc_mgr->active_verb, new_device);
+ list_del(&xold->active_list);
+ xnew = find_device(uc_mgr, uc_mgr->active_verb, new_device, 1);
+ list_add_tail(&xold->active_list, &uc_mgr->active_devices);
if (xnew == NULL)
return -ENOENT;
err = 0;
struct transition_sequence *trans;
struct list_head *pos;
int err, seq_found = 0;
-
+
if (uc_mgr->active_verb == NULL)
return -ENOENT;
if (modifier_status(uc_mgr, old_modifier) == 0) {
uc_error("error: modifier %s already enabled", new_modifier);
return -EINVAL;
}
- xold = find_modifier(uc_mgr, old_modifier);
+ xold = find_modifier(uc_mgr, uc_mgr->active_verb, old_modifier, 1);
if (xold == NULL)
return -ENOENT;
- xnew = find_modifier(uc_mgr, new_modifier);
+ xnew = find_modifier(uc_mgr, uc_mgr->active_verb, new_modifier, 1);
if (xnew == NULL)
return -ENOENT;
err = 0;
if (err < 0)
return err;
}
- return err;
+ return err;
}
/**