UCM: Implement ConflictingDevices, add device list to devices

Wherever SupportedDevice can appear, also allow ConflictingDevice. Only
one or the other (or neither) may be specified. When neither is
specified, allow anything. Sometimes, listing ConflictingDevices may
result in a shorter list than explicitly listing all SupportedDevices.

Add support for SupportedDevice and ConflictingDevice to SectionDevice.
This allows representing devices which are mutually exclusive, e.g. due
to a mux that switches between capturing from two different microphones,
without the possibility of mixing.

Enhance is_modifier_supported to allow ignoring SupportedDevice and
ConflictingDevice. This is useful when querying values from a
SectionModifier; there's no reason we shouldn't be able to query values
just because the current configuration would prevent enabling that
device. The new is_device_supported is implemented similarly.

Enhance switch_device to remove the old device from the current device
list before querying for the new device, and add it back immediately
afterwards. This allows the query for the new device to ignore any
conflicts caused solely by the old device.

Signed-off-by: Stephen Warren <swarren@nvidia.com>
Acked-by: Liam Girdwood <lrg@ti.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Stephen Warren 2011-06-03 14:56:31 -06:00 committed by Takashi Iwai
parent 866fa538d4
commit fc038149c5
4 changed files with 167 additions and 55 deletions

View file

@ -180,18 +180,25 @@ static int strip_legacy_dev_index(char *name)
}
/*
* 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;
@ -206,7 +213,7 @@ static int parse_supported_device(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
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);
@ -220,8 +227,11 @@ static int parse_supported_device(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
free(sdev);
return err;
}
list_add(&sdev->list, dlist);
list_add(&sdev->list, &dev_list->list);
}
dev_list->type = type;
return 0;
}
@ -413,11 +423,17 @@ static int parse_value(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
* SectionModifier."Capture Voice" {
*
* Comment "Record voice call"
*
* SupportedDevice [
* "x"
* "y"
* ]
*
* ConflictingDevice [
* "x"
* "y"
* ]
*
* EnableSequence [
* ....
* ]
@ -439,6 +455,9 @@ static int parse_value(snd_use_case_mgr_t *uc_mgr ATTRIBUTE_UNUSED,
* }
*
* }
*
* 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,
@ -469,7 +488,7 @@ static int parse_modifier(snd_use_case_mgr_t *uc_mgr,
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);
@ -490,7 +509,8 @@ static int parse_modifier(snd_use_case_mgr_t *uc_mgr,
}
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");
@ -498,6 +518,16 @@ static int parse_modifier(snd_use_case_mgr_t *uc_mgr,
}
}
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) {
@ -538,11 +568,6 @@ static int parse_modifier(snd_use_case_mgr_t *uc_mgr,
}
}
if (list_empty(&modifier->dev_list)) {
uc_error("error: %s: modifier missing supported device sequence", modifier->name);
return -EINVAL;
}
return 0;
}
@ -553,6 +578,16 @@ static int parse_modifier(snd_use_case_mgr_t *uc_mgr,
*SectionDevice."Headphones" {
* Comment "Headphones connected to 3.5mm jack"
*
* upportedDevice [
* "x"
* "y"
* ]
*
* ConflictingDevice [
* "x"
* "y"
* ]
*
* EnableSequence [
* ....
* ]
@ -599,6 +634,7 @@ static int parse_device(snd_use_case_mgr_t *uc_mgr,
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);
@ -618,6 +654,26 @@ static int parse_device(snd_use_case_mgr_t *uc_mgr,
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);