1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "platform_info" 18 #define LOG_NDDEBUG 0 19 20 #include <errno.h> 21 #include <stdio.h> 22 #include <expat.h> 23 #include <cutils/log.h> 24 #include <audio_hw.h> 25 #include "platform_api.h" 26 #include <platform.h> 27 #include <math.h> 28 29 typedef enum { 30 ROOT, 31 ACDB, 32 PCM_ID, 33 BACKEND_NAME, 34 CONFIG_PARAMS, 35 OPERATOR_SPECIFIC, 36 GAIN_LEVEL_MAPPING, 37 APP_TYPE, 38 } section_t; 39 40 typedef void (* section_process_fn)(const XML_Char **attr); 41 42 static void process_acdb_id(const XML_Char **attr); 43 static void process_pcm_id(const XML_Char **attr); 44 static void process_backend_name(const XML_Char **attr); 45 static void process_config_params(const XML_Char **attr); 46 static void process_root(const XML_Char **attr); 47 static void process_operator_specific(const XML_Char **attr); 48 static void process_gain_db_to_level_map(const XML_Char **attr); 49 static void process_app_type(const XML_Char **attr); 50 51 static section_process_fn section_table[] = { 52 [ROOT] = process_root, 53 [ACDB] = process_acdb_id, 54 [PCM_ID] = process_pcm_id, 55 [BACKEND_NAME] = process_backend_name, 56 [CONFIG_PARAMS] = process_config_params, 57 [OPERATOR_SPECIFIC] = process_operator_specific, 58 [GAIN_LEVEL_MAPPING] = process_gain_db_to_level_map, 59 [APP_TYPE] = process_app_type, 60 }; 61 62 static set_parameters_fn set_parameters = &platform_set_parameters; 63 64 static section_t section; 65 66 struct platform_info { 67 bool do_full_parse; 68 void *platform; 69 struct str_parms *kvpairs; 70 }; 71 72 static struct platform_info my_data = {true, NULL, NULL}; 73 74 /* 75 * <audio_platform_info> 76 * <acdb_ids> 77 * <device name="???" acdb_id="???"/> 78 * ... 79 * ... 80 * </acdb_ids> 81 * <backend_names> 82 * <device name="???" backend="???"/> 83 * ... 84 * ... 85 * </backend_names> 86 * <pcm_ids> 87 * <usecase name="???" type="in/out" id="???"/> 88 * ... 89 * ... 90 * </pcm_ids> 91 * <config_params> 92 * <param key="snd_card_name" value="msm8994-tomtom-mtp-snd-card"/> 93 * <param key="operator_info" value="tmus;aa;bb;cc"/> 94 * <param key="operator_info" value="sprint;xx;yy;zz"/> 95 * ... 96 * ... 97 * </config_params> 98 * 99 * <operator_specific> 100 * <device name="???" operator="???" mixer_path="???" acdb_id="???"/> 101 * ... 102 * ... 103 * </operator_specific> 104 * 105 * </audio_platform_info> 106 */ 107 108 static void process_root(const XML_Char **attr __unused) 109 { 110 } 111 112 /* mapping from usecase to pcm dev id */ 113 static void process_pcm_id(const XML_Char **attr) 114 { 115 int index; 116 117 if (strcmp(attr[0], "name") != 0) { 118 ALOGE("%s: 'name' not found, no pcm_id set!", __func__); 119 goto done; 120 } 121 122 index = platform_get_usecase_index((char *)attr[1]); 123 if (index < 0) { 124 ALOGE("%s: usecase %s in %s not found!", 125 __func__, attr[1], PLATFORM_INFO_XML_PATH); 126 goto done; 127 } 128 129 if (strcmp(attr[2], "type") != 0) { 130 ALOGE("%s: usecase type not mentioned", __func__); 131 goto done; 132 } 133 134 int type = -1; 135 136 if (!strcasecmp((char *)attr[3], "in")) { 137 type = 1; 138 } else if (!strcasecmp((char *)attr[3], "out")) { 139 type = 0; 140 } else { 141 ALOGE("%s: type must be IN or OUT", __func__); 142 goto done; 143 } 144 145 if (strcmp(attr[4], "id") != 0) { 146 ALOGE("%s: usecase id not mentioned", __func__); 147 goto done; 148 } 149 150 int id = atoi((char *)attr[5]); 151 152 if (platform_set_usecase_pcm_id(index, type, id) < 0) { 153 ALOGE("%s: usecase %s in %s, type %d id %d was not set!", 154 __func__, attr[1], PLATFORM_INFO_XML_PATH, type, id); 155 goto done; 156 } 157 158 done: 159 return; 160 } 161 162 /* backend to be used for a device */ 163 static void process_backend_name(const XML_Char **attr) 164 { 165 int index; 166 char *hw_interface = NULL; 167 168 if (strcmp(attr[0], "name") != 0) { 169 ALOGE("%s: 'name' not found, no ACDB ID set!", __func__); 170 goto done; 171 } 172 173 index = platform_get_snd_device_index((char *)attr[1]); 174 if (index < 0) { 175 ALOGE("%s: Device %s in %s not found, no ACDB ID set!", 176 __func__, attr[1], PLATFORM_INFO_XML_PATH); 177 goto done; 178 } 179 180 if (strcmp(attr[2], "backend") != 0) { 181 ALOGE("%s: Device %s in %s has no backed set!", 182 __func__, attr[1], PLATFORM_INFO_XML_PATH); 183 goto done; 184 } 185 186 if (attr[4] != NULL) { 187 if (strcmp(attr[4], "interface") != 0) { 188 hw_interface = NULL; 189 } else { 190 hw_interface = (char *)attr[5]; 191 } 192 } 193 194 if (platform_set_snd_device_backend(index, attr[3], hw_interface) < 0) { 195 ALOGE("%s: Device %s in %s, backend %s was not set!", 196 __func__, attr[1], PLATFORM_INFO_XML_PATH, attr[3]); 197 goto done; 198 } 199 200 done: 201 return; 202 } 203 204 static void process_gain_db_to_level_map(const XML_Char **attr) 205 { 206 struct amp_db_and_gain_table tbl_entry; 207 208 if ((strcmp(attr[0], "db") != 0) || 209 (strcmp(attr[2], "level") != 0)) { 210 ALOGE("%s: invalid attribute passed %s %sexpected amp db level", 211 __func__, attr[0], attr[2]); 212 goto done; 213 } 214 215 tbl_entry.db = atof(attr[1]); 216 tbl_entry.amp = exp(tbl_entry.db * 0.115129f); 217 tbl_entry.level = atoi(attr[3]); 218 219 //custome level should be > 0. Level 0 is fixed for default 220 CHECK(tbl_entry.level > 0); 221 222 ALOGV("%s: amp [%f] db [%f] level [%d]", __func__, 223 tbl_entry.amp, tbl_entry.db, tbl_entry.level); 224 platform_add_gain_level_mapping(&tbl_entry); 225 226 done: 227 return; 228 } 229 230 static void process_acdb_id(const XML_Char **attr) 231 { 232 int index; 233 234 if (strcmp(attr[0], "name") != 0) { 235 ALOGE("%s: 'name' not found, no ACDB ID set!", __func__); 236 goto done; 237 } 238 239 index = platform_get_snd_device_index((char *)attr[1]); 240 if (index < 0) { 241 ALOGE("%s: Device %s in %s not found, no ACDB ID set!", 242 __func__, attr[1], PLATFORM_INFO_XML_PATH); 243 goto done; 244 } 245 246 if (strcmp(attr[2], "acdb_id") != 0) { 247 ALOGE("%s: Device %s in %s has no acdb_id, no ACDB ID set!", 248 __func__, attr[1], PLATFORM_INFO_XML_PATH); 249 goto done; 250 } 251 252 if (platform_set_snd_device_acdb_id(index, atoi((char *)attr[3])) < 0) { 253 ALOGE("%s: Device %s in %s, ACDB ID %d was not set!", 254 __func__, attr[1], PLATFORM_INFO_XML_PATH, atoi((char *)attr[3])); 255 goto done; 256 } 257 258 done: 259 return; 260 } 261 262 263 static void process_operator_specific(const XML_Char **attr) 264 { 265 snd_device_t snd_device = SND_DEVICE_NONE; 266 267 if (strcmp(attr[0], "name") != 0) { 268 ALOGE("%s: 'name' not found", __func__); 269 goto done; 270 } 271 272 snd_device = platform_get_snd_device_index((char *)attr[1]); 273 if (snd_device < 0) { 274 ALOGE("%s: Device %s in %s not found, no ACDB ID set!", 275 __func__, (char *)attr[3], PLATFORM_INFO_XML_PATH); 276 goto done; 277 } 278 279 if (strcmp(attr[2], "operator") != 0) { 280 ALOGE("%s: 'operator' not found", __func__); 281 goto done; 282 } 283 284 if (strcmp(attr[4], "mixer_path") != 0) { 285 ALOGE("%s: 'mixer_path' not found", __func__); 286 goto done; 287 } 288 289 if (strcmp(attr[6], "acdb_id") != 0) { 290 ALOGE("%s: 'acdb_id' not found", __func__); 291 goto done; 292 } 293 294 platform_add_operator_specific_device(snd_device, (char *)attr[3], (char *)attr[5], atoi((char *)attr[7])); 295 296 done: 297 return; 298 } 299 300 /* platform specific configuration key-value pairs */ 301 static void process_config_params(const XML_Char **attr) 302 { 303 if (strcmp(attr[0], "key") != 0) { 304 ALOGE("%s: 'key' not found", __func__); 305 goto done; 306 } 307 308 if (strcmp(attr[2], "value") != 0) { 309 ALOGE("%s: 'value' not found", __func__); 310 goto done; 311 } 312 313 str_parms_add_str(my_data.kvpairs, (char*)attr[1], (char*)attr[3]); 314 set_parameters(my_data.platform, my_data.kvpairs); 315 done: 316 return; 317 } 318 319 static void process_app_type(const XML_Char **attr) 320 { 321 if (strcmp(attr[0], "uc_type")) { 322 ALOGE("%s: uc_type not found", __func__); 323 goto done; 324 } 325 326 if (strcmp(attr[2], "mode")) { 327 ALOGE("%s: mode not found", __func__); 328 goto done; 329 } 330 331 if (strcmp(attr[4], "bit_width")) { 332 ALOGE("%s: bit_width not found", __func__); 333 goto done; 334 } 335 336 if (strcmp(attr[6], "id")) { 337 ALOGE("%s: id not found", __func__); 338 goto done; 339 } 340 341 if (strcmp(attr[8], "max_rate")) { 342 ALOGE("%s: max rate not found", __func__); 343 goto done; 344 } 345 346 platform_add_app_type(attr[1], attr[3], atoi(attr[5]), atoi(attr[7]), 347 atoi(attr[9])); 348 done: 349 return; 350 } 351 352 static void start_tag(void *userdata __unused, const XML_Char *tag_name, 353 const XML_Char **attr) 354 { 355 const XML_Char *attr_name = NULL; 356 const XML_Char *attr_value = NULL; 357 unsigned int i; 358 359 360 if (my_data.do_full_parse) { 361 if (strcmp(tag_name, "acdb_ids") == 0) { 362 section = ACDB; 363 } else if (strcmp(tag_name, "pcm_ids") == 0) { 364 section = PCM_ID; 365 } else if (strcmp(tag_name, "backend_names") == 0) { 366 section = BACKEND_NAME; 367 } else if (strcmp(tag_name, "config_params") == 0) { 368 section = CONFIG_PARAMS; 369 } else if (strcmp(tag_name, "operator_specific") == 0) { 370 section = OPERATOR_SPECIFIC; 371 } else if (strcmp(tag_name, "gain_db_to_level_mapping") == 0) { 372 section = GAIN_LEVEL_MAPPING; 373 } else if (strcmp(tag_name, "app_types") == 0) { 374 section = APP_TYPE; 375 } else if (strcmp(tag_name, "device") == 0) { 376 if ((section != ACDB) && (section != BACKEND_NAME) && (section != OPERATOR_SPECIFIC)) { 377 ALOGE("device tag only supported for acdb/backend names"); 378 return; 379 } 380 381 /* call into process function for the current section */ 382 section_process_fn fn = section_table[section]; 383 fn(attr); 384 } else if (strcmp(tag_name, "usecase") == 0) { 385 if (section != PCM_ID) { 386 ALOGE("usecase tag only supported with PCM_ID section"); 387 return; 388 } 389 390 section_process_fn fn = section_table[PCM_ID]; 391 fn(attr); 392 } else if (strcmp(tag_name, "param") == 0) { 393 if (section != CONFIG_PARAMS) { 394 ALOGE("param tag only supported with CONFIG_PARAMS section"); 395 return; 396 } 397 398 section_process_fn fn = section_table[section]; 399 fn(attr); 400 } else if (strcmp(tag_name, "gain_level_map") == 0) { 401 if (section != GAIN_LEVEL_MAPPING) { 402 ALOGE("usecase tag only supported with GAIN_LEVEL_MAPPING section"); 403 return; 404 } 405 406 section_process_fn fn = section_table[GAIN_LEVEL_MAPPING]; 407 fn(attr); 408 } else if (!strcmp(tag_name, "app")) { 409 if (section != APP_TYPE) { 410 ALOGE("app tag only valid in section APP_TYPE"); 411 return; 412 } 413 414 section_process_fn fn = section_table[APP_TYPE]; 415 fn(attr); 416 } 417 } else { 418 if(strcmp(tag_name, "config_params") == 0) { 419 section = CONFIG_PARAMS; 420 } else if (strcmp(tag_name, "param") == 0) { 421 if (section != CONFIG_PARAMS) { 422 ALOGE("param tag only supported with CONFIG_PARAMS section"); 423 return; 424 } 425 426 section_process_fn fn = section_table[section]; 427 fn(attr); 428 } 429 } 430 431 return; 432 } 433 434 static void end_tag(void *userdata __unused, const XML_Char *tag_name) 435 { 436 if (strcmp(tag_name, "acdb_ids") == 0) { 437 section = ROOT; 438 } else if (strcmp(tag_name, "pcm_ids") == 0) { 439 section = ROOT; 440 } else if (strcmp(tag_name, "backend_names") == 0) { 441 section = ROOT; 442 } else if (strcmp(tag_name, "config_params") == 0) { 443 section = ROOT; 444 } else if (strcmp(tag_name, "operator_specific") == 0) { 445 section = ROOT; 446 } else if (strcmp(tag_name, "gain_db_to_level_mapping") == 0) { 447 section = ROOT; 448 } else if (strcmp(tag_name, "app_types") == 0) { 449 section = ROOT; 450 } 451 } 452 453 int snd_card_info_init(const char *filename, void *platform, set_parameters_fn fn) 454 { 455 set_parameters = fn; 456 my_data.do_full_parse = false; 457 return platform_info_init(filename, platform); 458 } 459 460 int platform_info_init(const char *filename, void *platform) 461 { 462 XML_Parser parser; 463 FILE *file; 464 int ret = 0; 465 int bytes_read; 466 void *buf; 467 static const uint32_t kBufSize = 1024; 468 char platform_info_file_name[MIXER_PATH_MAX_LENGTH]= {0}; 469 section = ROOT; 470 471 if (filename == NULL) { 472 strlcpy(platform_info_file_name, PLATFORM_INFO_XML_PATH, MIXER_PATH_MAX_LENGTH); 473 } else { 474 strlcpy(platform_info_file_name, filename, MIXER_PATH_MAX_LENGTH); 475 } 476 477 ALOGV("%s: platform info file name is %s", __func__, platform_info_file_name); 478 479 file = fopen(platform_info_file_name, "r"); 480 481 if (!file) { 482 ALOGD("%s: Failed to open %s, using defaults.", 483 __func__, platform_info_file_name); 484 ret = -ENODEV; 485 goto done; 486 } 487 488 parser = XML_ParserCreate(NULL); 489 if (!parser) { 490 ALOGE("%s: Failed to create XML parser!", __func__); 491 ret = -ENODEV; 492 goto err_close_file; 493 } 494 495 my_data.platform = platform; 496 my_data.kvpairs = str_parms_create(); 497 498 XML_SetElementHandler(parser, start_tag, end_tag); 499 500 while (1) { 501 buf = XML_GetBuffer(parser, kBufSize); 502 if (buf == NULL) { 503 ALOGE("%s: XML_GetBuffer failed", __func__); 504 ret = -ENOMEM; 505 goto err_free_parser; 506 } 507 508 bytes_read = fread(buf, 1, kBufSize, file); 509 if (bytes_read < 0) { 510 ALOGE("%s: fread failed, bytes read = %d", __func__, bytes_read); 511 ret = bytes_read; 512 goto err_free_parser; 513 } 514 515 if (XML_ParseBuffer(parser, bytes_read, 516 bytes_read == 0) == XML_STATUS_ERROR) { 517 ALOGE("%s: XML_ParseBuffer failed, for %s", 518 __func__, platform_info_file_name); 519 ret = -EINVAL; 520 goto err_free_parser; 521 } 522 523 if (bytes_read == 0) 524 break; 525 } 526 527 set_parameters = &platform_set_parameters; 528 my_data.do_full_parse = true; 529 530 err_free_parser: 531 XML_ParserFree(parser); 532 err_close_file: 533 fclose(file); 534 done: 535 return ret; 536 } 537