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)
-{
- return find(&verb->device_list,
- struct use_case_device, list, name,
- device_name);
-}
-
-static int is_modifier_supported(snd_use_case_mgr_t *uc_mgr,
- struct use_case_modifier *modifier)
+ find_device(snd_use_case_mgr_t *uc_mgr, const char *device_name,
+ int check_supported)
{
- struct dev_list *device;
- struct use_case_device *adev;
- struct list_head *pos, *pos1;
+ struct use_case_device *device;
+ struct use_case_verb *verb = uc_mgr->active_verb;
+ struct list_head *pos;
- list_for_each(pos, &modifier->dev_list) {
- device = list_entry(pos, struct dev_list, list);
+ list_for_each(pos, &verb->device_list) {
+ device = list_entry(pos, struct use_case_device, list);
- list_for_each(pos1, &uc_mgr->active_devices) {
- adev = list_entry(pos1, struct use_case_device,
- active_list);
+ if (strcmp(device_name, device->name))
+ continue;
- if (strcmp(adev->name, device->name))
- continue;
+ if (check_supported &&
+ !is_device_supported(uc_mgr, device))
+ continue;
- return 1;
- }
+ 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, const char *modifier_name,
+ int check_supported)
{
struct use_case_modifier *modifier;
struct use_case_verb *verb = uc_mgr->active_verb;
if (strcmp(modifier->name, modifier_name))
continue;
- if (is_modifier_supported(uc_mgr, modifier))
- return modifier;
+ if (check_supported &&
+ !is_modifier_supported(uc_mgr, modifier))
+ continue;
+
+ return modifier;
}
return NULL;
}
int err;
if (item != NULL) {
- mod = find_modifier(uc_mgr, item);
+ mod = find_modifier(uc_mgr, item, 0);
if (mod != NULL) {
err = get_value1(value, &mod->value_list, identifier);
if (err >= 0 || err != -ENOENT)
return err;
}
- dev = find_device(uc_mgr->active_verb, item);
+ dev = find_device(uc_mgr, item, 0);
if (dev != NULL) {
err = get_value1(value, &dev->value_list, identifier);
if (err >= 0 || err != -ENOENT)
if (uc_mgr->active_verb == NULL)
return -ENOENT;
- device = find_device(uc_mgr->active_verb, device_name);
+ device = find_device(uc_mgr, 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, modifier_name, 1);
if (modifier == NULL)
return -ENOENT;
return set_modifier(uc_mgr, modifier, enable);
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, 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, new_device, 1);
+ list_add_tail(&xold->active_list, &uc_mgr->active_devices);
if (xnew == NULL)
return -ENOENT;
err = 0;
uc_error("error: modifier %s already enabled", new_modifier);
return -EINVAL;
}
- xold = find_modifier(uc_mgr, old_modifier);
+ xold = find_modifier(uc_mgr, old_modifier, 1);
if (xold == NULL)
return -ENOENT;
- xnew = find_modifier(uc_mgr, new_modifier);
+ xnew = find_modifier(uc_mgr, new_modifier, 1);
if (xnew == NULL)
return -ENOENT;
err = 0;
}
/*
- * Parse transition
+ * Parse device list
*/
-static int parse_supported_device(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
- struct list_head *dlist,
- snd_config_t *cfg)
+static int parse_device_list(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
+ struct dev_list *dev_list,
+ enum dev_list_type type,
+ snd_config_t *cfg)
{
- struct dev_list *sdev;
+ struct dev_list_node *sdev;
const char *id;
snd_config_iterator_t i, next;
snd_config_t *n;
int err;
+ if (dev_list->type != DEVLIST_NONE) {
+ uc_error("error: multiple supported or"
+ " conflicting device lists");
+ return -EEXIST;
+ }
+
if (snd_config_get_id(cfg, &id) < 0)
return -EINVAL;
if (snd_config_get_id(n, &id) < 0)
return -EINVAL;
- sdev = calloc(1, sizeof(struct dev_list));
+ sdev = calloc(1, sizeof(struct dev_list_node));
if (sdev == NULL)
return -ENOMEM;
err = parse_string(n, &sdev->name);
free(sdev);
return err;
}
- list_add(&sdev->list, dlist);
+ list_add(&sdev->list, &dev_list->list);
}
+
+ dev_list->type = type;
+
return 0;
}
* SectionModifier."Capture Voice" {
*
* Comment "Record voice call"
+ *
* SupportedDevice [
* "x"
* "y"
* ]
*
+ * ConflictingDevice [
+ * "x"
+ * "y"
+ * ]
+ *
* EnableSequence [
* ....
* ]
* }
*
* }
+ *
+ * SupportedDevice and ConflictingDevice cannot be specified together.
+ * Both are optional.
*/
static int parse_modifier(snd_use_case_mgr_t *uc_mgr,
snd_config_t *cfg,
INIT_LIST_HEAD(&modifier->enable_list);
INIT_LIST_HEAD(&modifier->disable_list);
INIT_LIST_HEAD(&modifier->transition_list);
- INIT_LIST_HEAD(&modifier->dev_list);
+ INIT_LIST_HEAD(&modifier->dev_list.list);
INIT_LIST_HEAD(&modifier->value_list);
list_add_tail(&modifier->list, &verb->modifier_list);
modifier->name = strdup(name);
}
if (strcmp(id, "SupportedDevice") == 0) {
- err = parse_supported_device(uc_mgr, &modifier->dev_list, n);
+ err = parse_device_list(uc_mgr, &modifier->dev_list,
+ DEVLIST_SUPPORTED, n);
if (err < 0) {
uc_error("error: failed to parse supported"
" device list");
}
}
+ if (strcmp(id, "ConflictingDevice") == 0) {
+ err = parse_device_list(uc_mgr, &modifier->dev_list,
+ DEVLIST_CONFLICTING, n);
+ if (err < 0) {
+ uc_error("error: failed to parse conflicting"
+ " device list");
+ return err;
+ }
+ }
+
if (strcmp(id, "EnableSequence") == 0) {
err = parse_sequence(uc_mgr, &modifier->enable_list, n);
if (err < 0) {
}
}
- if (list_empty(&modifier->dev_list)) {
- uc_error("error: %s: modifier missing supported device sequence", modifier->name);
- return -EINVAL;
- }
-
return 0;
}
*SectionDevice."Headphones" {
* Comment "Headphones connected to 3.5mm jack"
*
+ * upportedDevice [
+ * "x"
+ * "y"
+ * ]
+ *
+ * ConflictingDevice [
+ * "x"
+ * "y"
+ * ]
+ *
* EnableSequence [
* ....
* ]
INIT_LIST_HEAD(&device->enable_list);
INIT_LIST_HEAD(&device->disable_list);
INIT_LIST_HEAD(&device->transition_list);
+ INIT_LIST_HEAD(&device->dev_list.list);
INIT_LIST_HEAD(&device->value_list);
list_add_tail(&device->list, &verb->device_list);
device->name = strdup(name);
continue;
}
+ if (strcmp(id, "SupportedDevice") == 0) {
+ err = parse_device_list(uc_mgr, &device->dev_list,
+ DEVLIST_SUPPORTED, n);
+ if (err < 0) {
+ uc_error("error: failed to parse supported"
+ " device list");
+ return err;
+ }
+ }
+
+ if (strcmp(id, "ConflictingDevice") == 0) {
+ err = parse_device_list(uc_mgr, &device->dev_list,
+ DEVLIST_CONFLICTING, n);
+ if (err < 0) {
+ uc_error("error: failed to parse conflicting"
+ " device list");
+ return err;
+ }
+ }
+
if (strcmp(id, "EnableSequence") == 0) {
uc_dbg("EnableSequence");
err = parse_sequence(uc_mgr, &device->enable_list, n);