blob: 455629474fda98df01b37730cc687a293f0fe06c [file] [log] [blame]
Haynes Mathew George5bc18842014-06-16 16:36:20 -07001/*
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
Ed Tam70b5c142016-03-21 19:14:29 -070028#define PLATFORM_INFO_XML_PATH "/system/etc/audio_platform_info.xml"
29
Haynes Mathew George98c95622014-06-20 19:14:25 -070030typedef enum {
31 ROOT,
32 ACDB,
33 PCM_ID,
34 BACKEND_NAME,
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -070035 CONFIG_PARAMS,
keunhui.park2f7306a2015-07-16 16:48:06 +090036 OPERATOR_SPECIFIC,
Haynes Mathew George98c95622014-06-20 19:14:25 -070037} section_t;
38
39typedef void (* section_process_fn)(const XML_Char **attr);
40
41static void process_acdb_id(const XML_Char **attr);
42static void process_pcm_id(const XML_Char **attr);
43static void process_backend_name(const XML_Char **attr);
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -070044static void process_config_params(const XML_Char **attr);
Haynes Mathew George98c95622014-06-20 19:14:25 -070045static void process_root(const XML_Char **attr);
keunhui.park2f7306a2015-07-16 16:48:06 +090046static void process_operator_specific(const XML_Char **attr);
Haynes Mathew George98c95622014-06-20 19:14:25 -070047
48static section_process_fn section_table[] = {
49 [ROOT] = process_root,
50 [ACDB] = process_acdb_id,
51 [PCM_ID] = process_pcm_id,
52 [BACKEND_NAME] = process_backend_name,
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -070053 [CONFIG_PARAMS] = process_config_params,
keunhui.park2f7306a2015-07-16 16:48:06 +090054 [OPERATOR_SPECIFIC] = process_operator_specific,
Haynes Mathew George98c95622014-06-20 19:14:25 -070055};
56
57static section_t section;
58
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -070059struct platform_info {
60 void *platform;
61 struct str_parms *kvpairs;
62};
63
64static struct platform_info my_data;
65
Haynes Mathew George98c95622014-06-20 19:14:25 -070066/*
67 * <audio_platform_info>
68 * <acdb_ids>
69 * <device name="???" acdb_id="???"/>
70 * ...
71 * ...
72 * </acdb_ids>
73 * <backend_names>
74 * <device name="???" backend="???"/>
75 * ...
76 * ...
77 * </backend_names>
78 * <pcm_ids>
79 * <usecase name="???" type="in/out" id="???"/>
80 * ...
81 * ...
82 * </pcm_ids>
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -070083 * <config_params>
84 * <param key="snd_card_name" value="msm8994-tomtom-mtp-snd-card"/>
keunhui.park2f7306a2015-07-16 16:48:06 +090085 * <param key="operator_info" value="tmus;aa;bb;cc"/>
86 * <param key="operator_info" value="sprint;xx;yy;zz"/>
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -070087 * ...
88 * ...
89 * </config_params>
90 *
keunhui.park2f7306a2015-07-16 16:48:06 +090091 * <operator_specific>
92 * <device name="???" operator="???" mixer_path="???" acdb_id="???"/>
93 * ...
94 * ...
95 * </operator_specific>
96 *
Haynes Mathew George98c95622014-06-20 19:14:25 -070097 * </audio_platform_info>
98 */
99
100static void process_root(const XML_Char **attr __unused)
101{
102}
103
104/* mapping from usecase to pcm dev id */
105static void process_pcm_id(const XML_Char **attr)
106{
107 int index;
108
109 if (strcmp(attr[0], "name") != 0) {
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -0700110 ALOGE("%s: 'name' not found, no pcm_id set!", __func__);
Haynes Mathew George98c95622014-06-20 19:14:25 -0700111 goto done;
112 }
113
114 index = platform_get_usecase_index((char *)attr[1]);
115 if (index < 0) {
116 ALOGE("%s: usecase %s in %s not found!",
117 __func__, attr[1], PLATFORM_INFO_XML_PATH);
118 goto done;
119 }
120
121 if (strcmp(attr[2], "type") != 0) {
122 ALOGE("%s: usecase type not mentioned", __func__);
123 goto done;
124 }
125
126 int type = -1;
127
128 if (!strcasecmp((char *)attr[3], "in")) {
129 type = 1;
130 } else if (!strcasecmp((char *)attr[3], "out")) {
131 type = 0;
132 } else {
133 ALOGE("%s: type must be IN or OUT", __func__);
134 goto done;
135 }
136
137 if (strcmp(attr[4], "id") != 0) {
138 ALOGE("%s: usecase id not mentioned", __func__);
139 goto done;
140 }
141
142 int id = atoi((char *)attr[5]);
143
144 if (platform_set_usecase_pcm_id(index, type, id) < 0) {
145 ALOGE("%s: usecase %s in %s, type %d id %d was not set!",
146 __func__, attr[1], PLATFORM_INFO_XML_PATH, type, id);
147 goto done;
148 }
149
150done:
151 return;
152}
153
154/* backend to be used for a device */
155static void process_backend_name(const XML_Char **attr)
156{
157 int index;
Ravi Kumar Alamandab7ea4f52015-06-08 16:44:05 -0700158 char *hw_interface = NULL;
Haynes Mathew George98c95622014-06-20 19:14:25 -0700159
160 if (strcmp(attr[0], "name") != 0) {
161 ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
162 goto done;
163 }
164
165 index = platform_get_snd_device_index((char *)attr[1]);
166 if (index < 0) {
167 ALOGE("%s: Device %s in %s not found, no ACDB ID set!",
168 __func__, attr[1], PLATFORM_INFO_XML_PATH);
169 goto done;
170 }
171
172 if (strcmp(attr[2], "backend") != 0) {
173 ALOGE("%s: Device %s in %s has no backed set!",
174 __func__, attr[1], PLATFORM_INFO_XML_PATH);
175 goto done;
176 }
177
Ravi Kumar Alamandab7ea4f52015-06-08 16:44:05 -0700178 if (attr[4] != NULL) {
179 if (strcmp(attr[4], "interface") != 0) {
180 hw_interface = NULL;
181 } else {
182 hw_interface = (char *)attr[5];
183 }
184 }
185
186 if (platform_set_snd_device_backend(index, attr[3], hw_interface) < 0) {
Haynes Mathew George98c95622014-06-20 19:14:25 -0700187 ALOGE("%s: Device %s in %s, backend %s was not set!",
188 __func__, attr[1], PLATFORM_INFO_XML_PATH, attr[3]);
189 goto done;
190 }
191
192done:
193 return;
194}
195
196static void process_acdb_id(const XML_Char **attr)
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700197{
198 int index;
199
200 if (strcmp(attr[0], "name") != 0) {
201 ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
202 goto done;
203 }
204
205 index = platform_get_snd_device_index((char *)attr[1]);
206 if (index < 0) {
207 ALOGE("%s: Device %s in %s not found, no ACDB ID set!",
208 __func__, attr[1], PLATFORM_INFO_XML_PATH);
209 goto done;
210 }
211
212 if (strcmp(attr[2], "acdb_id") != 0) {
213 ALOGE("%s: Device %s in %s has no acdb_id, no ACDB ID set!",
214 __func__, attr[1], PLATFORM_INFO_XML_PATH);
215 goto done;
216 }
217
Haynes Mathew George98c95622014-06-20 19:14:25 -0700218 if (platform_set_snd_device_acdb_id(index, atoi((char *)attr[3])) < 0) {
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700219 ALOGE("%s: Device %s in %s, ACDB ID %d was not set!",
220 __func__, attr[1], PLATFORM_INFO_XML_PATH, atoi((char *)attr[3]));
221 goto done;
222 }
223
224done:
225 return;
226}
227
keunhui.park2f7306a2015-07-16 16:48:06 +0900228
229static void process_operator_specific(const XML_Char **attr)
230{
231 snd_device_t snd_device = SND_DEVICE_NONE;
232
233 if (strcmp(attr[0], "name") != 0) {
234 ALOGE("%s: 'name' not found", __func__);
235 goto done;
236 }
237
238 snd_device = platform_get_snd_device_index((char *)attr[1]);
239 if (snd_device < 0) {
240 ALOGE("%s: Device %s in %s not found, no ACDB ID set!",
241 __func__, (char *)attr[3], PLATFORM_INFO_XML_PATH);
242 goto done;
243 }
244
245 if (strcmp(attr[2], "operator") != 0) {
246 ALOGE("%s: 'operator' not found", __func__);
247 goto done;
248 }
249
250 if (strcmp(attr[4], "mixer_path") != 0) {
251 ALOGE("%s: 'mixer_path' not found", __func__);
252 goto done;
253 }
254
255 if (strcmp(attr[6], "acdb_id") != 0) {
256 ALOGE("%s: 'acdb_id' not found", __func__);
257 goto done;
258 }
259
260 platform_add_operator_specific_device(snd_device, (char *)attr[3], (char *)attr[5], atoi((char *)attr[7]));
261
262done:
263 return;
264}
265
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -0700266/* platform specific configuration key-value pairs */
267static void process_config_params(const XML_Char **attr)
268{
269 if (strcmp(attr[0], "key") != 0) {
270 ALOGE("%s: 'key' not found", __func__);
271 goto done;
272 }
273
274 if (strcmp(attr[2], "value") != 0) {
275 ALOGE("%s: 'value' not found", __func__);
276 goto done;
277 }
278
279 str_parms_add_str(my_data.kvpairs, (char*)attr[1], (char*)attr[3]);
keunhui.park2f7306a2015-07-16 16:48:06 +0900280 platform_set_parameters(my_data.platform, my_data.kvpairs);
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -0700281done:
282 return;
283}
284
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700285static void start_tag(void *userdata __unused, const XML_Char *tag_name,
286 const XML_Char **attr)
287{
288 const XML_Char *attr_name = NULL;
289 const XML_Char *attr_value = NULL;
290 unsigned int i;
291
Haynes Mathew George98c95622014-06-20 19:14:25 -0700292 if (strcmp(tag_name, "acdb_ids") == 0) {
293 section = ACDB;
294 } else if (strcmp(tag_name, "pcm_ids") == 0) {
295 section = PCM_ID;
296 } else if (strcmp(tag_name, "backend_names") == 0) {
297 section = BACKEND_NAME;
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -0700298 } else if (strcmp(tag_name, "config_params") == 0) {
299 section = CONFIG_PARAMS;
keunhui.park2f7306a2015-07-16 16:48:06 +0900300 } else if (strcmp(tag_name, "operator_specific") == 0) {
301 section = OPERATOR_SPECIFIC;
Haynes Mathew George98c95622014-06-20 19:14:25 -0700302 } else if (strcmp(tag_name, "device") == 0) {
keunhui.park2f7306a2015-07-16 16:48:06 +0900303 if ((section != ACDB) && (section != BACKEND_NAME) && (section != OPERATOR_SPECIFIC)) {
Haynes Mathew George98c95622014-06-20 19:14:25 -0700304 ALOGE("device tag only supported for acdb/backend names");
305 return;
306 }
307
308 /* call into process function for the current section */
309 section_process_fn fn = section_table[section];
310 fn(attr);
311 } else if (strcmp(tag_name, "usecase") == 0) {
312 if (section != PCM_ID) {
313 ALOGE("usecase tag only supported with PCM_ID section");
314 return;
315 }
316
317 section_process_fn fn = section_table[PCM_ID];
318 fn(attr);
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -0700319 } else if (strcmp(tag_name, "param") == 0) {
320 if (section != CONFIG_PARAMS) {
321 ALOGE("param tag only supported with CONFIG_PARAMS section");
322 return;
323 }
324
325 section_process_fn fn = section_table[section];
326 fn(attr);
Haynes Mathew George98c95622014-06-20 19:14:25 -0700327 }
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700328
329 return;
330}
331
Haynes Mathew George98c95622014-06-20 19:14:25 -0700332static void end_tag(void *userdata __unused, const XML_Char *tag_name)
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700333{
Haynes Mathew George98c95622014-06-20 19:14:25 -0700334 if (strcmp(tag_name, "acdb_ids") == 0) {
335 section = ROOT;
336 } else if (strcmp(tag_name, "pcm_ids") == 0) {
337 section = ROOT;
338 } else if (strcmp(tag_name, "backend_names") == 0) {
339 section = ROOT;
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -0700340 } else if (strcmp(tag_name, "config_params") == 0) {
341 section = ROOT;
keunhui.park2f7306a2015-07-16 16:48:06 +0900342 } else if (strcmp(tag_name, "operator_specific") == 0) {
343 section = ROOT;
Haynes Mathew George98c95622014-06-20 19:14:25 -0700344 }
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700345}
346
Ed Tam70b5c142016-03-21 19:14:29 -0700347int platform_info_init(void *platform)
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700348{
349 XML_Parser parser;
350 FILE *file;
351 int ret = 0;
352 int bytes_read;
353 void *buf;
354 static const uint32_t kBufSize = 1024;
Ed Tam70b5c142016-03-21 19:14:29 -0700355
Haynes Mathew George98c95622014-06-20 19:14:25 -0700356 section = ROOT;
357
Ed Tam70b5c142016-03-21 19:14:29 -0700358 file = fopen(PLATFORM_INFO_XML_PATH, "r");
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700359 if (!file) {
360 ALOGD("%s: Failed to open %s, using defaults.",
Ed Tam70b5c142016-03-21 19:14:29 -0700361 __func__, PLATFORM_INFO_XML_PATH);
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700362 ret = -ENODEV;
363 goto done;
364 }
365
366 parser = XML_ParserCreate(NULL);
367 if (!parser) {
368 ALOGE("%s: Failed to create XML parser!", __func__);
369 ret = -ENODEV;
370 goto err_close_file;
371 }
372
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -0700373 my_data.platform = platform;
374 my_data.kvpairs = str_parms_create();
375
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700376 XML_SetElementHandler(parser, start_tag, end_tag);
377
378 while (1) {
379 buf = XML_GetBuffer(parser, kBufSize);
380 if (buf == NULL) {
381 ALOGE("%s: XML_GetBuffer failed", __func__);
382 ret = -ENOMEM;
383 goto err_free_parser;
384 }
385
386 bytes_read = fread(buf, 1, kBufSize, file);
387 if (bytes_read < 0) {
388 ALOGE("%s: fread failed, bytes read = %d", __func__, bytes_read);
389 ret = bytes_read;
390 goto err_free_parser;
391 }
392
393 if (XML_ParseBuffer(parser, bytes_read,
394 bytes_read == 0) == XML_STATUS_ERROR) {
395 ALOGE("%s: XML_ParseBuffer failed, for %s",
Ed Tam70b5c142016-03-21 19:14:29 -0700396 __func__, PLATFORM_INFO_XML_PATH);
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700397 ret = -EINVAL;
398 goto err_free_parser;
399 }
400
401 if (bytes_read == 0)
402 break;
403 }
404
405err_free_parser:
406 XML_ParserFree(parser);
407err_close_file:
408 fclose(file);
409done:
410 return ret;
411}