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 28 #define PLATFORM_INFO_XML_PATH "/system/etc/audio_platform_info.xml" 29 30 typedef enum { 31 ROOT, 32 ACDB, 33 PCM_ID, 34 BACKEND_NAME, 35 CONFIG_PARAMS, 36 } section_t; 37 38 typedef void (* section_process_fn)(const XML_Char **attr); 39 40 static void process_acdb_id(const XML_Char **attr); 41 static void process_pcm_id(const XML_Char **attr); 42 static void process_backend_name(const XML_Char **attr); 43 static void process_config_params(const XML_Char **attr); 44 static void process_root(const XML_Char **attr); 45 46 static section_process_fn section_table[] = { 47 [ROOT] = process_root, 48 [ACDB] = process_acdb_id, 49 [PCM_ID] = process_pcm_id, 50 [BACKEND_NAME] = process_backend_name, 51 [CONFIG_PARAMS] = process_config_params, 52 }; 53 54 static section_t section; 55 56 struct platform_info { 57 void *platform; 58 struct str_parms *kvpairs; 59 }; 60 61 static struct platform_info my_data; 62 63 /* 64 * <audio_platform_info> 65 * <acdb_ids> 66 * <device name="???" acdb_id="???"/> 67 * ... 68 * ... 69 * </acdb_ids> 70 * <backend_names> 71 * <device name="???" backend="???"/> 72 * ... 73 * ... 74 * </backend_names> 75 * <pcm_ids> 76 * <usecase name="???" type="in/out" id="???"/> 77 * ... 78 * ... 79 * </pcm_ids> 80 * <config_params> 81 * <param key="snd_card_name" value="msm8994-tomtom-mtp-snd-card"/> 82 * ... 83 * ... 84 * </config_params> 85 * 86 * </audio_platform_info> 87 */ 88 89 static void process_root(const XML_Char **attr __unused) 90 { 91 } 92 93 /* mapping from usecase to pcm dev id */ 94 static void process_pcm_id(const XML_Char **attr) 95 { 96 int index; 97 98 if (strcmp(attr[0], "name") != 0) { 99 ALOGE("%s: 'name' not found, no pcm_id set!", __func__); 100 goto done; 101 } 102 103 index = platform_get_usecase_index((char *)attr[1]); 104 if (index < 0) { 105 ALOGE("%s: usecase %s in %s not found!", 106 __func__, attr[1], PLATFORM_INFO_XML_PATH); 107 goto done; 108 } 109 110 if (strcmp(attr[2], "type") != 0) { 111 ALOGE("%s: usecase type not mentioned", __func__); 112 goto done; 113 } 114 115 int type = -1; 116 117 if (!strcasecmp((char *)attr[3], "in")) { 118 type = 1; 119 } else if (!strcasecmp((char *)attr[3], "out")) { 120 type = 0; 121 } else { 122 ALOGE("%s: type must be IN or OUT", __func__); 123 goto done; 124 } 125 126 if (strcmp(attr[4], "id") != 0) { 127 ALOGE("%s: usecase id not mentioned", __func__); 128 goto done; 129 } 130 131 int id = atoi((char *)attr[5]); 132 133 if (platform_set_usecase_pcm_id(index, type, id) < 0) { 134 ALOGE("%s: usecase %s in %s, type %d id %d was not set!", 135 __func__, attr[1], PLATFORM_INFO_XML_PATH, type, id); 136 goto done; 137 } 138 139 done: 140 return; 141 } 142 143 /* backend to be used for a device */ 144 static void process_backend_name(const XML_Char **attr) 145 { 146 int index; 147 char *hw_interface = NULL; 148 149 if (strcmp(attr[0], "name") != 0) { 150 ALOGE("%s: 'name' not found, no ACDB ID set!", __func__); 151 goto done; 152 } 153 154 index = platform_get_snd_device_index((char *)attr[1]); 155 if (index < 0) { 156 ALOGE("%s: Device %s in %s not found, no ACDB ID set!", 157 __func__, attr[1], PLATFORM_INFO_XML_PATH); 158 goto done; 159 } 160 161 if (strcmp(attr[2], "backend") != 0) { 162 ALOGE("%s: Device %s in %s has no backed set!", 163 __func__, attr[1], PLATFORM_INFO_XML_PATH); 164 goto done; 165 } 166 167 if (attr[4] != NULL) { 168 if (strcmp(attr[4], "interface") != 0) { 169 hw_interface = NULL; 170 } else { 171 hw_interface = (char *)attr[5]; 172 } 173 } 174 175 if (platform_set_snd_device_backend(index, attr[3], hw_interface) < 0) { 176 ALOGE("%s: Device %s in %s, backend %s was not set!", 177 __func__, attr[1], PLATFORM_INFO_XML_PATH, attr[3]); 178 goto done; 179 } 180 181 done: 182 return; 183 } 184 185 static void process_acdb_id(const XML_Char **attr) 186 { 187 int index; 188 189 if (strcmp(attr[0], "name") != 0) { 190 ALOGE("%s: 'name' not found, no ACDB ID set!", __func__); 191 goto done; 192 } 193 194 index = platform_get_snd_device_index((char *)attr[1]); 195 if (index < 0) { 196 ALOGE("%s: Device %s in %s not found, no ACDB ID set!", 197 __func__, attr[1], PLATFORM_INFO_XML_PATH); 198 goto done; 199 } 200 201 if (strcmp(attr[2], "acdb_id") != 0) { 202 ALOGE("%s: Device %s in %s has no acdb_id, no ACDB ID set!", 203 __func__, attr[1], PLATFORM_INFO_XML_PATH); 204 goto done; 205 } 206 207 if (platform_set_snd_device_acdb_id(index, atoi((char *)attr[3])) < 0) { 208 ALOGE("%s: Device %s in %s, ACDB ID %d was not set!", 209 __func__, attr[1], PLATFORM_INFO_XML_PATH, atoi((char *)attr[3])); 210 goto done; 211 } 212 213 done: 214 return; 215 } 216 217 /* platform specific configuration key-value pairs */ 218 static void process_config_params(const XML_Char **attr) 219 { 220 if (strcmp(attr[0], "key") != 0) { 221 ALOGE("%s: 'key' not found", __func__); 222 goto done; 223 } 224 225 if (strcmp(attr[2], "value") != 0) { 226 ALOGE("%s: 'value' not found", __func__); 227 goto done; 228 } 229 230 str_parms_add_str(my_data.kvpairs, (char*)attr[1], (char*)attr[3]); 231 done: 232 return; 233 } 234 235 static void start_tag(void *userdata __unused, const XML_Char *tag_name, 236 const XML_Char **attr) 237 { 238 const XML_Char *attr_name = NULL; 239 const XML_Char *attr_value = NULL; 240 unsigned int i; 241 242 if (strcmp(tag_name, "acdb_ids") == 0) { 243 section = ACDB; 244 } else if (strcmp(tag_name, "pcm_ids") == 0) { 245 section = PCM_ID; 246 } else if (strcmp(tag_name, "backend_names") == 0) { 247 section = BACKEND_NAME; 248 } else if (strcmp(tag_name, "config_params") == 0) { 249 section = CONFIG_PARAMS; 250 } else if (strcmp(tag_name, "device") == 0) { 251 if ((section != ACDB) && (section != BACKEND_NAME)) { 252 ALOGE("device tag only supported for acdb/backend names"); 253 return; 254 } 255 256 /* call into process function for the current section */ 257 section_process_fn fn = section_table[section]; 258 fn(attr); 259 } else if (strcmp(tag_name, "usecase") == 0) { 260 if (section != PCM_ID) { 261 ALOGE("usecase tag only supported with PCM_ID section"); 262 return; 263 } 264 265 section_process_fn fn = section_table[PCM_ID]; 266 fn(attr); 267 } else if (strcmp(tag_name, "param") == 0) { 268 if (section != CONFIG_PARAMS) { 269 ALOGE("param tag only supported with CONFIG_PARAMS section"); 270 return; 271 } 272 273 section_process_fn fn = section_table[section]; 274 fn(attr); 275 } 276 277 return; 278 } 279 280 static void end_tag(void *userdata __unused, const XML_Char *tag_name) 281 { 282 if (strcmp(tag_name, "acdb_ids") == 0) { 283 section = ROOT; 284 } else if (strcmp(tag_name, "pcm_ids") == 0) { 285 section = ROOT; 286 } else if (strcmp(tag_name, "backend_names") == 0) { 287 section = ROOT; 288 } else if (strcmp(tag_name, "config_params") == 0) { 289 section = ROOT; 290 platform_set_parameters(my_data.platform, my_data.kvpairs); 291 } 292 } 293 294 int platform_info_init(void *platform) 295 { 296 XML_Parser parser; 297 FILE *file; 298 int ret = 0; 299 int bytes_read; 300 void *buf; 301 static const uint32_t kBufSize = 1024; 302 303 section = ROOT; 304 305 file = fopen(PLATFORM_INFO_XML_PATH, "r"); 306 if (!file) { 307 ALOGD("%s: Failed to open %s, using defaults.", 308 __func__, PLATFORM_INFO_XML_PATH); 309 ret = -ENODEV; 310 goto done; 311 } 312 313 parser = XML_ParserCreate(NULL); 314 if (!parser) { 315 ALOGE("%s: Failed to create XML parser!", __func__); 316 ret = -ENODEV; 317 goto err_close_file; 318 } 319 320 my_data.platform = platform; 321 my_data.kvpairs = str_parms_create(); 322 323 XML_SetElementHandler(parser, start_tag, end_tag); 324 325 while (1) { 326 buf = XML_GetBuffer(parser, kBufSize); 327 if (buf == NULL) { 328 ALOGE("%s: XML_GetBuffer failed", __func__); 329 ret = -ENOMEM; 330 goto err_free_parser; 331 } 332 333 bytes_read = fread(buf, 1, kBufSize, file); 334 if (bytes_read < 0) { 335 ALOGE("%s: fread failed, bytes read = %d", __func__, bytes_read); 336 ret = bytes_read; 337 goto err_free_parser; 338 } 339 340 if (XML_ParseBuffer(parser, bytes_read, 341 bytes_read == 0) == XML_STATUS_ERROR) { 342 ALOGE("%s: XML_ParseBuffer failed, for %s", 343 __func__, PLATFORM_INFO_XML_PATH); 344 ret = -EINVAL; 345 goto err_free_parser; 346 } 347 348 if (bytes_read == 0) 349 break; 350 } 351 352 err_free_parser: 353 XML_ParserFree(parser); 354 err_close_file: 355 fclose(file); 356 done: 357 return ret; 358 } 359