1/* 2 Copyright(c) 2021 Intel Corporation 3 All rights reserved. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of version 2 of the GNU General Public License as 7 published by the Free Software Foundation. 8 9 This program is distributed in the hope that it will be useful, but 10 WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program; if not, write to the Free Software 16 Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 17 The full GNU General Public License is included in this distribution 18 in the file called LICENSE.GPL. 19*/ 20#include "aconfig.h" 21#include <assert.h> 22#include <errno.h> 23#include <limits.h> 24#include <stdio.h> 25#include <alsa/asoundlib.h> 26#include "topology.h" 27#include "pre-processor.h" 28 29bool tplg_class_is_attribute_check(const char *attr, snd_config_t *class_cfg, char *category) 30{ 31 snd_config_iterator_t i, next; 32 snd_config_t *cfg, *n; 33 int ret; 34 35 ret = snd_config_search(class_cfg, category, &cfg); 36 if (ret < 0) 37 return false; 38 39 snd_config_for_each(i, next, cfg) { 40 const char *id, *s; 41 42 n = snd_config_iterator_entry(i); 43 if (snd_config_get_id(n, &id) < 0) 44 continue; 45 46 if (snd_config_get_string(n, &s) < 0) 47 continue; 48 49 if (!strcmp(attr, s)) 50 return true; 51 } 52 53 return false; 54} 55 56/* check if attribute is mandatory */ 57bool tplg_class_is_attribute_mandatory(const char *attr, snd_config_t *class_cfg) 58{ 59 return tplg_class_is_attribute_check(attr, class_cfg, "attributes.mandatory"); 60} 61 62/* check if attribute is immutable */ 63bool tplg_class_is_attribute_immutable(const char *attr, snd_config_t *class_cfg) 64{ 65 return tplg_class_is_attribute_check(attr, class_cfg, "attributes.immutable"); 66} 67 68/* check if attribute is unique */ 69bool tplg_class_is_attribute_unique(const char *attr, snd_config_t *class_cfg) 70{ 71 snd_config_t *unique; 72 const char *s; 73 int ret; 74 75 ret = snd_config_search(class_cfg, "attributes.unique", &unique); 76 if (ret < 0) 77 return false; 78 79 if (snd_config_get_string(unique, &s) < 0) 80 return false; 81 82 if (!strcmp(attr, s)) 83 return true; 84 85 return false; 86} 87 88/* 89 * Helper function to look up class definition from the Object config. 90 * ex: For an object declaration, Object.Widget.pga.0{}, return the config correspdonding to 91 * Class.Widget.pga{}. Note that input config , "cfg" does not include the "Object" node. 92 */ 93snd_config_t *tplg_class_lookup(struct tplg_pre_processor *tplg_pp, snd_config_t *cfg) 94{ 95 snd_config_iterator_t first, end; 96 snd_config_t *class, *class_cfg = NULL; 97 const char *class_type, *class_name; 98 char *class_config_id; 99 int ret; 100 101 if (snd_config_get_id(cfg, &class_type) < 0) 102 return NULL; 103 104 first = snd_config_iterator_first(cfg); 105 end = snd_config_iterator_end(cfg); 106 107 if (first == end) { 108 SNDERR("No class name provided for object type: %s\n", class_type); 109 return NULL; 110 } 111 112 class = snd_config_iterator_entry(first); 113 114 if (snd_config_get_id(class, &class_name) < 0) 115 return NULL; 116 117 class_config_id = tplg_snprintf("Class.%s.%s", class_type, class_name); 118 if (!class_config_id) 119 return NULL; 120 121 ret = snd_config_search(tplg_pp->input_cfg, class_config_id, &class_cfg); 122 if (ret < 0) 123 SNDERR("No Class definition found for %s\n", class_config_id); 124 125 free(class_config_id); 126 return class_cfg; 127} 128 129/* find the attribute config by name in the class definition */ 130snd_config_t *tplg_class_find_attribute_by_name(struct tplg_pre_processor *tplg_p ATTRIBUTE_UNUSED, 131 snd_config_t *class, const char *name) 132{ 133 snd_config_t *attr = NULL; 134 const char *class_id; 135 char *attr_str; 136 int ret; 137 138 if (snd_config_get_id(class, &class_id) < 0) 139 return NULL; 140 141 attr_str = tplg_snprintf("DefineAttribute.%s", name); 142 if (!attr_str) 143 return NULL; 144 145 ret = snd_config_search(class, attr_str, &attr); 146 if (ret < 0) 147 SNDERR("No definition for attribute '%s' in class '%s'\n", 148 name, class_id); 149 150 free(attr_str); 151 return attr; 152} 153 154/* get the name of the attribute that must have a unique value in the object instance */ 155const char *tplg_class_get_unique_attribute_name(struct tplg_pre_processor *tplg_pp ATTRIBUTE_UNUSED, 156 snd_config_t *class) 157{ 158 snd_config_t *unique; 159 const char *unique_name, *class_id; 160 int ret; 161 162 if (snd_config_get_id(class, &class_id) < 0) 163 return NULL; 164 165 ret = snd_config_search(class, "attributes.unique", &unique); 166 if (ret < 0) { 167 SNDERR("No unique attribute in class '%s'\n", class_id); 168 return NULL; 169 } 170 171 if (snd_config_get_string(unique, &unique_name) < 0) { 172 SNDERR("Invalid name for unique attribute in class '%s'\n", class_id); 173 return NULL; 174 } 175 176 return unique_name; 177} 178 179/* get attribute type from the definition */ 180snd_config_type_t tplg_class_get_attribute_type(struct tplg_pre_processor *tplg_pp ATTRIBUTE_UNUSED, 181 snd_config_t *attr) 182{ 183 snd_config_t *type; 184 const char *s; 185 int ret; 186 187 /* default to integer if no type is given */ 188 ret = snd_config_search(attr, "type", &type); 189 if (ret < 0) 190 return SND_CONFIG_TYPE_INTEGER; 191 192 ret = snd_config_get_string(type, &s); 193 assert(ret >= 0); 194 195 if (!strcmp(s, "string")) 196 return SND_CONFIG_TYPE_STRING; 197 198 if (!strcmp(s, "compound")) 199 return SND_CONFIG_TYPE_COMPOUND; 200 201 if (!strcmp(s, "real")) 202 return SND_CONFIG_TYPE_REAL; 203 204 if (!strcmp(s, "integer64")) 205 return SND_CONFIG_TYPE_INTEGER64; 206 207 return SND_CONFIG_TYPE_INTEGER; 208} 209 210/* get token_ref for attribute with name attr_name in the class */ 211const char *tplg_class_get_attribute_token_ref(struct tplg_pre_processor *tplg_pp ATTRIBUTE_UNUSED, 212 snd_config_t *class, const char *attr_name) 213{ 214 snd_config_t *attributes, *attr, *token_ref; 215 const char *token; 216 int ret; 217 218 ret = snd_config_search(class, "DefineAttribute", &attributes); 219 if (ret < 0) 220 return NULL; 221 222 ret = snd_config_search(attributes, attr_name, &attr); 223 if (ret < 0) 224 return NULL; 225 226 ret = snd_config_search(attr, "token_ref", &token_ref); 227 if (ret < 0) 228 return NULL; 229 230 ret = snd_config_get_string(token_ref, &token); 231 if (ret < 0) 232 return NULL; 233 234 return token; 235} 236 237/* convert a valid attribute string value to the corresponding tuple value */ 238long tplg_class_attribute_valid_tuple_value(struct tplg_pre_processor *tplg_pp ATTRIBUTE_UNUSED, 239 snd_config_t *class, snd_config_t *attr) 240{ 241 242 snd_config_t *attributes, *cfg, *valid, *tuples, *n; 243 snd_config_iterator_t i, next; 244 const char *attr_name, *attr_value; 245 int ret; 246 247 ret = snd_config_get_id(attr, &attr_name); 248 if (ret < 0) 249 return -EINVAL; 250 251 ret = snd_config_get_string(attr, &attr_value); 252 if (ret < 0) 253 return -EINVAL; 254 255 /* find attribute definition in class */ 256 ret = snd_config_search(class, "DefineAttribute", &attributes); 257 if (ret < 0) 258 return -EINVAL; 259 260 261 ret = snd_config_search(attributes, attr_name, &cfg); 262 if (ret < 0) 263 return -EINVAL; 264 265 /* check if it has valid values */ 266 ret = snd_config_search(cfg, "constraints.valid_values", &valid); 267 if (ret < 0) 268 return -EINVAL; 269 270 ret = snd_config_search(cfg, "constraints.tuple_values", &tuples); 271 if (ret < 0) 272 return -EINVAL; 273 274 /* find and return the tuple value matching the attribute value id */ 275 snd_config_for_each(i, next, valid) { 276 const char *s, *id; 277 278 n = snd_config_iterator_entry(i); 279 if (snd_config_get_string(n, &s) < 0) 280 continue; 281 if (snd_config_get_id(n, &id) < 0) 282 continue; 283 284 if (!strcmp(attr_value, s)) { 285 snd_config_t *tuple; 286 long tuple_value; 287 288 ret = snd_config_search(tuples, id, &tuple); 289 if (ret < 0) 290 return -EINVAL; 291 292 ret = snd_config_get_integer(tuple, &tuple_value); 293 if (ret < 0) 294 return ret; 295 296 return tuple_value; 297 } 298 } 299 300 return -EINVAL; 301} 302