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