From: Ranjani Sridharan Date: Mon, 26 Apr 2021 18:19:31 +0000 (-0700) Subject: topology: pre-process-object: Add support for processing Manifest object X-Git-Tag: v1.2.5~18 X-Git-Url: https://git.alsa-project.org/?a=commitdiff_plain;h=d999c267d3acf08211e10416ee3dfcb66619304b;p=alsa-utils.git topology: pre-process-object: Add support for processing Manifest object 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 Signed-off-by: Jaroslav Kysela --- diff --git a/topology/pre-process-object.c b/topology/pre-process-object.c index 3793ab5..609e1ec 100644 --- a/topology/pre-process-object.c +++ b/topology/pre-process-object.c @@ -30,6 +30,58 @@ #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 */ diff --git a/topology/pre-processor.h b/topology/pre-processor.h index 5cb1727..5599ca2 100644 --- a/topology/pre-processor.h +++ b/topology/pre-processor.h @@ -23,16 +23,44 @@ #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);