return 0;
}
+/*
+ * Parse Device Rename/Delete Command
+ *
+ * # The devices might be renamed to allow the better conditional runtime
+ * # evaluation. Bellow example renames Speaker1 device to Speaker and
+ * # removes Speaker2 device.
+ * RenameDevice."Speaker1" "Speaker"
+ * RemoveDevice."Speaker2" "Speaker2"
+ */
+static int parse_dev_name_list(snd_config_t *cfg,
+ struct list_head *list)
+{
+ snd_config_t *n;
+ snd_config_iterator_t i, next;
+ const char *id, *name1;
+ char *name2;
+ struct ucm_dev_name *dev;
+ snd_config_iterator_t pos;
+ int err;
+
+ if (snd_config_get_id(cfg, &id) < 0)
+ return -EINVAL;
+
+ if (snd_config_get_type(cfg) != SND_CONFIG_TYPE_COMPOUND) {
+ uc_error("compound type expected for %s", id);
+ return -EINVAL;
+ }
+
+ snd_config_for_each(i, next, cfg) {
+ n = snd_config_iterator_entry(i);
+
+ if (snd_config_get_id(n, &name1) < 0)
+ return -EINVAL;
+
+ err = parse_string(n, &name2);
+ if (err < 0) {
+ uc_error("error: failed to get target device name for '%s'", name1);
+ return err;
+ }
+
+ /* skip duplicates */
+ list_for_each(pos, list) {
+ dev = list_entry(pos, struct ucm_dev_name, list);
+ if (strcmp(dev->name1, name1) == 0) {
+ free(name2);
+ return 0;
+ }
+ }
+
+ dev = calloc(1, sizeof(*dev));
+ if (dev == NULL)
+ return -ENOMEM;
+ dev->name1 = strdup(name1);
+ if (dev->name1 == NULL) {
+ free(dev);
+ free(name2);
+ return -ENOMEM;
+ }
+ dev->name2 = name2;
+ list_add_tail(&dev->list, list);
+ }
+
+ return 0;
+}
+
static int parse_compound_check_legacy(snd_use_case_mgr_t *uc_mgr,
snd_config_t *cfg,
int (*fcn)(snd_use_case_mgr_t *, snd_config_t *, void *, void *),
void *data1,
void *data2 ATTRIBUTE_UNUSED)
{
- return parse_compound_check_legacy(uc_mgr, cfg, parse_modifier, data1);
+ return parse_compound(uc_mgr, cfg, parse_modifier, data1, data2);
+}
+
+static int verb_device_management(struct use_case_verb *verb)
+{
+ struct list_head *pos;
+ struct ucm_dev_name *dev;
+ int err;
+
+ /* rename devices */
+ list_for_each(pos, &verb->rename_list) {
+ dev = list_entry(pos, struct ucm_dev_name, list);
+ err = uc_mgr_rename_device(verb, dev->name1, dev->name2);
+ if (err < 0) {
+ uc_error("error: cannot rename device '%s' to '%s'", dev->name1, dev->name2);
+ return err;
+ }
+ }
+
+ /* remove devices */
+ list_for_each(pos, &verb->rename_list) {
+ dev = list_entry(pos, struct ucm_dev_name, list);
+ err = uc_mgr_remove_device(verb, dev->name2);
+ if (err < 0) {
+ uc_error("error: cannot remove device '%s'", dev->name2);
+ return err;
+ }
+ }
+
+ /* those lists are no longer used */
+ uc_mgr_free_dev_name_list(&verb->rename_list);
+ uc_mgr_free_dev_name_list(&verb->remove_list);
+ return 0;
}
/*
INIT_LIST_HEAD(&verb->cmpt_device_list);
INIT_LIST_HEAD(&verb->modifier_list);
INIT_LIST_HEAD(&verb->value_list);
+ INIT_LIST_HEAD(&verb->rename_list);
+ INIT_LIST_HEAD(&verb->remove_list);
list_add_tail(&verb->list, &uc_mgr->verb_list);
if (use_case_name == NULL)
return -EINVAL;
}
continue;
}
+
+ /* device renames */
+ if (strcmp(id, "RenameDevice") == 0) {
+ err = parse_dev_name_list(n, &verb->rename_list);
+ if (err < 0) {
+ uc_error("error: %s failed to parse device rename",
+ file);
+ goto _err;
+ }
+ }
+
+ /* device remove */
+ if (strcmp(id, "RemoveDevice") == 0) {
+ err = parse_dev_name_list(n, &verb->remove_list);
+ if (err < 0) {
+ uc_error("error: %s failed to parse device remove",
+ file);
+ goto _err;
+ }
+ }
}
snd_config_delete(cfg);
uc_error("error: no use case device defined", file);
return -EINVAL;
}
+
+ /* do device rename and delete */
+ err = verb_device_management(verb);
+ if (err < 0) {
+ uc_error("error: device management error in verb '%s'", verb->name);
+ return err;
+ }
+
return 0;
_err:
snd_ctl_card_info_t *ctl_info;
};
+struct ucm_dev_name {
+ struct list_head list;
+ char *name1;
+ char *name2;
+};
+
/*
* Describes a Use Case Modifier and it's enable and disable sequences.
* A use case verb can have N modifiers.
/* value list */
struct list_head value_list;
+
+ /* temporary modifications lists */
+ struct list_head rename_list;
+ struct list_head remove_list;
};
/*
int uc_mgr_import_master_config(snd_use_case_mgr_t *uc_mgr);
int uc_mgr_scan_master_configs(const char **_list[]);
+int uc_mgr_remove_device(struct use_case_verb *verb, const char *name);
+int uc_mgr_rename_device(struct use_case_verb *verb, const char *src,
+ const char *dst);
+
+void uc_mgr_free_dev_name_list(struct list_head *base);
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);
}
}
+int uc_mgr_rename_in_dev_list(struct dev_list *dev_list, const char *src,
+ const char *dst)
+{
+ struct list_head *pos;
+ struct dev_list_node *dlist;
+ char *dst1;
+
+ list_for_each(pos, &dev_list->list) {
+ dlist = list_entry(pos, struct dev_list_node, list);
+ if (strcmp(dlist->name, src) == 0) {
+ dst1 = strdup(dst);
+ if (dst1 == NULL)
+ return -ENOMEM;
+ free(dlist->name);
+ dlist->name = dst1;
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+int uc_mgr_remove_from_dev_list(struct dev_list *dev_list, const char *name)
+{
+ struct list_head *pos;
+ struct dev_list_node *dlist;
+
+ list_for_each(pos, &dev_list->list) {
+ dlist = list_entry(pos, struct dev_list_node, list);
+ if (strcmp(dlist->name, name) == 0) {
+ free(dlist->name);
+ list_del(&dlist->list);
+ free(dlist);
+ return 0;
+ }
+ }
+ return -ENODEV;
+}
+
void uc_mgr_free_sequence_element(struct sequence_element *seq)
{
if (seq == NULL)
}
}
+void uc_mgr_free_dev_name_list(struct list_head *base)
+{
+ struct list_head *pos, *npos;
+ struct ucm_dev_name *dev;
+
+ list_for_each_safe(pos, npos, base) {
+ dev = list_entry(pos, struct ucm_dev_name, list);
+ list_del(&dev->list);
+ free(dev->name1);
+ free(dev->name2);
+ free(dev);
+ }
+}
+
void uc_mgr_free_modifier(struct list_head *base)
{
struct list_head *pos, *npos;
}
}
-void uc_mgr_free_device(struct list_head *base)
+void uc_mgr_free_device(struct use_case_device *dev)
+{
+ 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_dev_list(&dev->dev_list);
+ uc_mgr_free_value(&dev->value_list);
+ list_del(&dev->list);
+ free(dev);
+}
+
+void uc_mgr_free_device_list(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_dev_list(&dev->dev_list);
- uc_mgr_free_value(&dev->value_list);
- list_del(&dev->list);
- free(dev);
+ uc_mgr_free_device(dev);
+ }
+}
+
+int uc_mgr_rename_device(struct use_case_verb *verb, const char *src,
+ const char *dst)
+{
+ struct use_case_device *device;
+ struct list_head *pos, *npos;
+ char *dst1;
+
+ /* no errors when device is not found */
+ list_for_each_safe(pos, npos, &verb->device_list) {
+ device = list_entry(pos, struct use_case_device, list);
+ if (strcmp(device->name, src) == 0) {
+ dst1 = strdup(dst);
+ if (dst1 == NULL)
+ return -ENOMEM;
+ free(device->name);
+ device->name = dst1;
+ continue;
+ }
+ uc_mgr_rename_in_dev_list(&device->dev_list, src, dst);
+ }
+ return 0;
+}
+
+int uc_mgr_remove_device(struct use_case_verb *verb, const char *name)
+{
+ struct use_case_device *device;
+ struct list_head *pos, *npos;
+
+ list_for_each_safe(pos, npos, &verb->device_list) {
+ device = list_entry(pos, struct use_case_device, list);
+ if (strcmp(device->name, name) == 0) {
+ uc_mgr_free_device(device);
+ continue;
+ }
+ uc_mgr_remove_from_dev_list(&device->dev_list, name);
+ return 0;
}
+ return -ENOENT;
}
void uc_mgr_free_verb(snd_use_case_mgr_t *uc_mgr)
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_device(&verb->cmpt_device_list);
+ uc_mgr_free_device_list(&verb->device_list);
+ uc_mgr_free_device_list(&verb->cmpt_device_list);
uc_mgr_free_modifier(&verb->modifier_list);
+ uc_mgr_free_dev_name_list(&verb->rename_list);
+ uc_mgr_free_dev_name_list(&verb->remove_list);
list_del(&verb->list);
free(verb);
}