]> git.alsa-project.org Git - alsa-utils.git/commitdiff
topology: pre-process-object: Add support for processing Manifest object
authorRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Mon, 26 Apr 2021 18:19:31 +0000 (11:19 -0700)
committerJaroslav Kysela <perex@perex.cz>
Tue, 25 May 2021 16:26:51 +0000 (18:26 +0200)
The pre-processor converts the Topology2.0 objects into
the relevant sections by looking for attributes defined
in the template config for the section and reading the
attribute values from the object instance config.

The structure struct build_function_map contains the
mapping of the build function to use for each object
based on the type and name for the class that the object
belongs to. The manifest object is the simplest with
no attributes. So, the build function simply creates
a new Section called SectionManifest which will be
populated with the data section in the following patches.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
topology/pre-process-object.c
topology/pre-processor.h

index 3793ab5e90a54e83ebe53c6f5c5dc1f7bcb71379..609e1ec125d29741f3a969f057708297e0be8fc7 100644 (file)
 #include "topology.h"
 #include "pre-processor.h"
 
+static int tplg_create_config_template(struct tplg_pre_processor *tplg_pp,
+                                      snd_config_t **template,
+                                      const struct config_template_items *items)
+{
+       snd_config_t *top, *child;
+       int ret, i;
+
+       ret = snd_config_make(&top, "template", SND_CONFIG_TYPE_COMPOUND);
+       if (ret < 0)
+               return ret;
+
+       /* add integer configs */
+       if (items->int_config_ids)
+               for (i = 0; i < MAX_CONFIGS_IN_TEMPLATE; i++)
+                       if (items->int_config_ids[i]) {
+                               ret = tplg_config_make_add(&child, items->int_config_ids[i],
+                                                          SND_CONFIG_TYPE_INTEGER, top);
+                               if (ret < 0)
+                                       goto err;
+                       }
+
+       /* add string configs */
+       if (items->string_config_ids)
+               for (i = 0; i < MAX_CONFIGS_IN_TEMPLATE; i++)
+                       if (items->string_config_ids[i]) {
+                               ret = tplg_config_make_add(&child, items->string_config_ids[i],
+                                                          SND_CONFIG_TYPE_STRING, top);
+                               if (ret < 0)
+                                       goto err;
+                       }
+
+       /* add compound configs */
+       if (items->compound_config_ids)
+               for (i = 0; i < MAX_CONFIGS_IN_TEMPLATE; i++) {
+                       if (items->compound_config_ids[i]) {
+                               ret = tplg_config_make_add(&child, items->compound_config_ids[i],
+                                                          SND_CONFIG_TYPE_COMPOUND, top);
+                               if (ret < 0)
+                                       goto err;
+                       }
+               }
+
+err:
+       if (ret < 0) {
+               snd_config_delete(top);
+               return ret;
+       }
+
+       *template = top;
+       return ret;
+}
+
 static void tplg_attribute_print_valid_values(snd_config_t *valid_values, const char *name)
 {
        snd_config_iterator_t i, next;
@@ -221,6 +273,25 @@ min_max_check:
        return tplg_object_is_attribute_min_max_valid(attr, obj_attr, false);
 }
 
+/* get object's name attribute value */
+const char *tplg_object_get_name(struct tplg_pre_processor *tplg_pp,
+                                snd_config_t *object)
+{
+       snd_config_t *cfg;
+       const char *name;
+       int ret;
+
+       ret = snd_config_search(object, "name", &cfg);
+       if (ret < 0)
+               return NULL;
+
+       ret = snd_config_get_string(cfg, &name);
+       if (ret < 0)
+               return NULL;
+
+       return name;
+}
+
 /* look up the instance of object in a config */
 static snd_config_t *tplg_object_lookup_in_config(struct tplg_pre_processor *tplg_pp,
                                                  snd_config_t *class, const char *type,
@@ -238,6 +309,180 @@ static snd_config_t *tplg_object_lookup_in_config(struct tplg_pre_processor *tpl
        return obj_cfg;
 }
 
+/* search for all template configs in the source config and copy them to the destination */
+static int tplg_object_add_attributes(snd_config_t *dst, snd_config_t *template,
+                                     snd_config_t *src)
+{
+       snd_config_iterator_t i, next;
+       snd_config_t *n;
+       int ret;
+
+       snd_config_for_each(i, next, template) {
+               snd_config_t *attr, *new;
+               const char *id;
+       
+               n = snd_config_iterator_entry(i);
+               if (snd_config_get_id(n, &id) < 0)
+                       continue;
+
+               ret = snd_config_search(src, id, &attr);
+               if (ret < 0)
+                       continue;
+
+               /* skip if attribute is already set */
+               ret = snd_config_search(dst, id, &new);
+               if (ret >= 0)
+                       continue;
+
+               ret = snd_config_copy(&new, attr);
+               if (ret < 0) {
+                       SNDERR("failed to copy attribute %s\n", id);
+                       return ret;
+               }
+
+               ret = snd_config_add(dst, new);
+               if (ret < 0) {
+                       snd_config_delete(new);
+                       SNDERR("failed to add attribute %s\n", id);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static const struct build_function_map *tplg_object_get_map(struct tplg_pre_processor *tplg_pp,
+                                                           snd_config_t *obj);
+
+/*
+ * Function to create a new "section" config based on the template. The new config will be
+ * added to the output_cfg or the top_config input parameter.
+ */
+int tplg_build_object_from_template(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
+                                   snd_config_t **wtop, snd_config_t *top_config,
+                                   bool skip_name)
+{
+       snd_config_t *top, *template, *obj;
+       const struct build_function_map *map;
+       const char *object_name;
+       int ret;
+
+       /* look up object map */
+       map = tplg_object_get_map(tplg_pp, obj_cfg);
+       if (!map) {
+               SNDERR("unknown object type or class name\n");
+               return -EINVAL;
+       }
+
+       obj = tplg_object_get_instance_config(tplg_pp, obj_cfg);
+
+       /* look up or create the corresponding section config for object */
+       if (!top_config)
+               top_config = tplg_pp->output_cfg;
+
+       ret = snd_config_search(top_config, map->section_name, &top);
+       if (ret < 0) {
+               ret = tplg_config_make_add(&top, map->section_name, SND_CONFIG_TYPE_COMPOUND,
+                                          top_config);
+               if (ret < 0) {
+                       SNDERR("Error creating %s config\n", map->section_name);
+                       return ret;
+               }
+       }
+
+       /* get object name */
+       object_name = tplg_object_get_name(tplg_pp, obj);
+       if (!object_name) {
+               ret = snd_config_get_id(obj, &object_name);
+               if (ret < 0) {
+                       SNDERR("Invalid ID for %s\n", map->section_name);
+                       return ret;
+               }
+       }
+
+       tplg_pp_debug("Building object: '%s' ...", object_name);
+
+       /* create and add new object config with name, if needed */
+       if (skip_name) {
+               *wtop = top;
+       } else {
+               *wtop = tplg_find_config(top, object_name);
+               if (!(*wtop)) {
+                       ret = tplg_config_make_add(wtop, object_name, SND_CONFIG_TYPE_COMPOUND,
+                                                  top);
+                       if (ret < 0) {
+                               SNDERR("Error creating config for %s\n", object_name);
+                               return ret;
+                       }
+               }
+       }
+
+       /* create template config */
+       if (!map->template_items)
+               return 0;
+
+       ret = tplg_create_config_template(tplg_pp, &template, map->template_items);
+       if (ret < 0) {
+               SNDERR("Error creating template config for %s\n", object_name);
+               return ret;
+       }
+
+       /* update section config based on template and the attribute values in the object */
+       ret = tplg_object_add_attributes(*wtop, template, obj);
+       snd_config_delete(template);
+       if (ret < 0)
+               SNDERR("Error adding attributes for object '%s'\n", object_name);
+
+       return ret;
+}
+
+static int tplg_build_generic_object(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
+                                    snd_config_t *parent)
+{
+       snd_config_t *wtop;
+
+       return tplg_build_object_from_template(tplg_pp, obj_cfg, &wtop, NULL, false);
+}
+
+const struct build_function_map object_build_map[] = {
+       {"Base", "manifest", "SectionManifest", &tplg_build_generic_object, NULL},
+};
+
+static const struct build_function_map *tplg_object_get_map(struct tplg_pre_processor *tplg_pp,
+                                                           snd_config_t *obj)
+{
+       snd_config_iterator_t first;
+       snd_config_t *class;
+       const char *class_type, *class_name;
+       unsigned int i;
+
+       first = snd_config_iterator_first(obj);
+       class = snd_config_iterator_entry(first);
+
+       if (snd_config_get_id(class, &class_name) < 0)
+               return NULL;
+
+       if (snd_config_get_id(obj, &class_type) < 0)
+               return NULL;
+
+       for (i = 0; i < ARRAY_SIZE(object_build_map); i++) {
+               if (!strcmp(class_type, "Widget") &&
+                   !strcmp(object_build_map[i].class_type, "Widget"))
+                       return &object_build_map[i];
+
+               if (!strcmp(class_type, "Dai") &&
+                   !strcmp(object_build_map[i].class_type, "Dai"))
+                       return &object_build_map[i];
+
+               /* for other type objects, also match the object class_name */
+               if (!strcmp(class_type, object_build_map[i].class_type) &&
+                   !strcmp(object_build_map[i].class_name, class_name))
+                       return &object_build_map[i];
+       }
+
+       return NULL;
+}
+
 /* return 1 if attribute not found in search_config, 0 on success and negative value on error */
 static int tplg_object_copy_and_add_param(struct tplg_pre_processor *tplg_pp,
                                          snd_config_t *obj,
@@ -619,6 +864,8 @@ static int tplg_build_object(struct tplg_pre_processor *tplg_pp, snd_config_t *n
                              snd_config_t *parent)
 {
        snd_config_t *obj_local, *class_cfg;
+       const struct build_function_map *map;
+       build_func builder;
        const char *id, *class_id;
        int ret;
 
@@ -652,10 +899,21 @@ static int tplg_build_object(struct tplg_pre_processor *tplg_pp, snd_config_t *n
 
        /* construct object name using class constructor */
        ret = tplg_construct_object_name(tplg_pp, obj_local, class_cfg);
-       if (ret < 0)
+       if (ret < 0) {
                SNDERR("Failed to construct object name for %s\n", id);
+               return ret;
+       }
 
-       return ret;
+       tplg_pp_config_debug(tplg_pp, obj_local);
+
+       /* nothing to do if object is not supported */
+       map = tplg_object_get_map(tplg_pp, new_obj);
+       if (!map)
+               return 0;
+
+       /* build the object and save the sections to the output config */
+       builder = map->builder;
+       return builder(tplg_pp, new_obj, parent);
 }
 
 /* create top-level topology objects */
index 5cb1727d15e328f8e723f630e36698e35608b974..5599ca2f04ffd639f9ca12087dfc2eaea541d429 100644 (file)
 #include "topology.h"
 
 #define DEBUG_MAX_LENGTH       256
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof (a)[0])
+
+#define MAX_CONFIGS_IN_TEMPLATE        32
+struct config_template_items {
+       char *int_config_ids[MAX_CONFIGS_IN_TEMPLATE];
+       char *string_config_ids[MAX_CONFIGS_IN_TEMPLATE];
+       char *compound_config_ids[MAX_CONFIGS_IN_TEMPLATE];
+};
+
+typedef int (*build_func)(struct tplg_pre_processor *tplg_pp, snd_config_t *obj,
+                         snd_config_t *parent);
+
+struct build_function_map {
+       char *class_type;
+       char *class_name;
+       char *section_name;
+       build_func builder;
+       const struct config_template_items *template_items;
+};
+
+extern const struct build_function_map object_build_map[];
 
 /* debug helpers */
 void tplg_pp_debug(char *fmt, ...);
 void tplg_pp_config_debug(struct tplg_pre_processor *tplg_pp, snd_config_t *cfg);
 
+/* object build helpers */
+int tplg_build_object_from_template(struct tplg_pre_processor *tplg_pp, snd_config_t *obj_cfg,
+                                   snd_config_t **wtop, snd_config_t *top_config,
+                                   bool skip_name);
+
 /* object helpers */
 int tplg_pre_process_objects(struct tplg_pre_processor *tplg_pp, snd_config_t *cfg,
                             snd_config_t *parent);
 snd_config_t *tplg_object_get_instance_config(struct tplg_pre_processor *tplg_pp,
                                        snd_config_t *class_type);
+const char *tplg_object_get_name(struct tplg_pre_processor *tplg_pp,
+                                snd_config_t *object);
 
 /* class helpers */
 snd_config_t *tplg_class_lookup(struct tplg_pre_processor *tplg_pp, snd_config_t *cfg);