blob: ace57ea99bd684ada8d3d7b5d94455326e8ff5ee [file] [log] [blame]
Haynes Mathew George5bc18842014-06-16 16:36:20 -07001/*
Haynes Mathew George569b7482017-05-08 14:44:27 -07002 * Copyright (C) 2014 The Android Open Source Project
Haynes Mathew George5bc18842014-06-16 16:36:20 -07003 *
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>
Haynes Mathew Georgee6e2d442018-02-22 18:51:56 -080023#include <log/log.h>
Haynes Mathew George5bc18842014-06-16 16:36:20 -070024#include <audio_hw.h>
25#include "platform_api.h"
26#include <platform.h>
vivek mehtaa8d7c922016-05-25 14:40:44 -070027#include <math.h>
Haynes Mathew George5bc18842014-06-16 16:36:20 -070028
Haynes Mathew George98c95622014-06-20 19:14:25 -070029typedef enum {
30 ROOT,
31 ACDB,
32 PCM_ID,
33 BACKEND_NAME,
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -070034 CONFIG_PARAMS,
keunhui.park2f7306a2015-07-16 16:48:06 +090035 OPERATOR_SPECIFIC,
vivek mehtaa8d7c922016-05-25 14:40:44 -070036 GAIN_LEVEL_MAPPING,
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -080037 APP_TYPE,
jiabin8962a4d2018-03-19 18:21:24 -070038 MICROPHONE_CHARACTERISTIC,
Haynes Mathew George98c95622014-06-20 19:14:25 -070039} section_t;
40
41typedef void (* section_process_fn)(const XML_Char **attr);
42
43static void process_acdb_id(const XML_Char **attr);
44static void process_pcm_id(const XML_Char **attr);
45static void process_backend_name(const XML_Char **attr);
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -070046static void process_config_params(const XML_Char **attr);
Haynes Mathew George98c95622014-06-20 19:14:25 -070047static void process_root(const XML_Char **attr);
keunhui.park2f7306a2015-07-16 16:48:06 +090048static void process_operator_specific(const XML_Char **attr);
vivek mehtaa8d7c922016-05-25 14:40:44 -070049static void process_gain_db_to_level_map(const XML_Char **attr);
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -080050static void process_app_type(const XML_Char **attr);
jiabin8962a4d2018-03-19 18:21:24 -070051static void process_microphone_characteristic(const XML_Char **attr);
Haynes Mathew George98c95622014-06-20 19:14:25 -070052
53static section_process_fn section_table[] = {
54 [ROOT] = process_root,
55 [ACDB] = process_acdb_id,
56 [PCM_ID] = process_pcm_id,
57 [BACKEND_NAME] = process_backend_name,
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -070058 [CONFIG_PARAMS] = process_config_params,
keunhui.park2f7306a2015-07-16 16:48:06 +090059 [OPERATOR_SPECIFIC] = process_operator_specific,
vivek mehtaa8d7c922016-05-25 14:40:44 -070060 [GAIN_LEVEL_MAPPING] = process_gain_db_to_level_map,
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -080061 [APP_TYPE] = process_app_type,
jiabin8962a4d2018-03-19 18:21:24 -070062 [MICROPHONE_CHARACTERISTIC] = process_microphone_characteristic,
Haynes Mathew George98c95622014-06-20 19:14:25 -070063};
64
vivek mehta0fb11312017-05-15 19:35:32 -070065static set_parameters_fn set_parameters = &platform_set_parameters;
66
Haynes Mathew George98c95622014-06-20 19:14:25 -070067static section_t section;
68
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -070069struct platform_info {
vivek mehta0fb11312017-05-15 19:35:32 -070070 bool do_full_parse;
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -070071 void *platform;
72 struct str_parms *kvpairs;
73};
74
vivek mehta0fb11312017-05-15 19:35:32 -070075static struct platform_info my_data = {true, NULL, NULL};
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -070076
jiabin8962a4d2018-03-19 18:21:24 -070077struct audio_string_to_enum {
78 const char* name;
79 unsigned int value;
80};
81
82static const struct audio_string_to_enum mic_locations[AUDIO_MICROPHONE_LOCATION_CNT] = {
83 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_LOCATION_UNKNOWN),
84 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_LOCATION_MAINBODY),
85 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_LOCATION_MAINBODY_MOVABLE),
86 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_LOCATION_PERIPHERAL),
87};
88
89static const struct audio_string_to_enum mic_directionalities[AUDIO_MICROPHONE_DIRECTIONALITY_CNT] = {
90 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_DIRECTIONALITY_OMNI),
91 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_DIRECTIONALITY_BI_DIRECTIONAL),
92 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_DIRECTIONALITY_UNKNOWN),
93 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_DIRECTIONALITY_CARDIOID),
94 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_DIRECTIONALITY_HYPER_CARDIOID),
95 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_MICROPHONE_DIRECTIONALITY_SUPER_CARDIOID),
96};
97
98static const struct audio_string_to_enum device_in_types[] = {
99 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_AMBIENT),
100 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_COMMUNICATION),
101 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC),
102 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
103 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_WIRED_HEADSET),
104 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_AUX_DIGITAL),
105 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_HDMI),
106 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_VOICE_CALL),
107 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_TELEPHONY_RX),
108 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BACK_MIC),
109 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_REMOTE_SUBMIX),
110 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
111 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
112 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_USB_ACCESSORY),
113 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_USB_DEVICE),
114 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_FM_TUNER),
115 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_TV_TUNER),
116 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_LINE),
117 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_SPDIF),
118 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_A2DP),
119 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_LOOPBACK),
120 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_IP),
121 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BUS),
122 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_PROXY),
123 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_USB_HEADSET),
124 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_BLE),
125 AUDIO_MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_DEFAULT),
126};
127
128static bool find_enum_by_string(const struct audio_string_to_enum * table, const char * name,
129 int32_t len, unsigned int *value)
130{
131 if (table == NULL) {
132 ALOGE("%s: table is NULL", __func__);
133 return false;
134 }
135
136 if (name == NULL) {
137 ALOGE("null key");
138 return false;
139 }
140
141 for (int i = 0; i < len; i++) {
142 if (!strcmp(table[i].name, name)) {
143 *value = table[i].value;
144 return true;
145 }
146 }
147 return false;
148}
149
Haynes Mathew George98c95622014-06-20 19:14:25 -0700150/*
151 * <audio_platform_info>
152 * <acdb_ids>
153 * <device name="???" acdb_id="???"/>
154 * ...
155 * ...
156 * </acdb_ids>
157 * <backend_names>
158 * <device name="???" backend="???"/>
159 * ...
160 * ...
161 * </backend_names>
162 * <pcm_ids>
163 * <usecase name="???" type="in/out" id="???"/>
164 * ...
165 * ...
166 * </pcm_ids>
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -0700167 * <config_params>
168 * <param key="snd_card_name" value="msm8994-tomtom-mtp-snd-card"/>
keunhui.park2f7306a2015-07-16 16:48:06 +0900169 * <param key="operator_info" value="tmus;aa;bb;cc"/>
170 * <param key="operator_info" value="sprint;xx;yy;zz"/>
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -0700171 * ...
172 * ...
173 * </config_params>
174 *
keunhui.park2f7306a2015-07-16 16:48:06 +0900175 * <operator_specific>
176 * <device name="???" operator="???" mixer_path="???" acdb_id="???"/>
177 * ...
178 * ...
179 * </operator_specific>
180 *
Haynes Mathew George98c95622014-06-20 19:14:25 -0700181 * </audio_platform_info>
182 */
183
184static void process_root(const XML_Char **attr __unused)
185{
186}
187
188/* mapping from usecase to pcm dev id */
189static void process_pcm_id(const XML_Char **attr)
190{
191 int index;
192
193 if (strcmp(attr[0], "name") != 0) {
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -0700194 ALOGE("%s: 'name' not found, no pcm_id set!", __func__);
Haynes Mathew George98c95622014-06-20 19:14:25 -0700195 goto done;
196 }
197
198 index = platform_get_usecase_index((char *)attr[1]);
199 if (index < 0) {
200 ALOGE("%s: usecase %s in %s not found!",
201 __func__, attr[1], PLATFORM_INFO_XML_PATH);
202 goto done;
203 }
204
205 if (strcmp(attr[2], "type") != 0) {
206 ALOGE("%s: usecase type not mentioned", __func__);
207 goto done;
208 }
209
210 int type = -1;
211
212 if (!strcasecmp((char *)attr[3], "in")) {
213 type = 1;
214 } else if (!strcasecmp((char *)attr[3], "out")) {
215 type = 0;
216 } else {
217 ALOGE("%s: type must be IN or OUT", __func__);
218 goto done;
219 }
220
221 if (strcmp(attr[4], "id") != 0) {
222 ALOGE("%s: usecase id not mentioned", __func__);
223 goto done;
224 }
225
226 int id = atoi((char *)attr[5]);
227
228 if (platform_set_usecase_pcm_id(index, type, id) < 0) {
229 ALOGE("%s: usecase %s in %s, type %d id %d was not set!",
230 __func__, attr[1], PLATFORM_INFO_XML_PATH, type, id);
231 goto done;
232 }
233
234done:
235 return;
236}
237
238/* backend to be used for a device */
239static void process_backend_name(const XML_Char **attr)
240{
241 int index;
Ravi Kumar Alamandab7ea4f52015-06-08 16:44:05 -0700242 char *hw_interface = NULL;
Haynes Mathew George98c95622014-06-20 19:14:25 -0700243
244 if (strcmp(attr[0], "name") != 0) {
245 ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
246 goto done;
247 }
248
249 index = platform_get_snd_device_index((char *)attr[1]);
250 if (index < 0) {
251 ALOGE("%s: Device %s in %s not found, no ACDB ID set!",
252 __func__, attr[1], PLATFORM_INFO_XML_PATH);
253 goto done;
254 }
255
256 if (strcmp(attr[2], "backend") != 0) {
257 ALOGE("%s: Device %s in %s has no backed set!",
258 __func__, attr[1], PLATFORM_INFO_XML_PATH);
259 goto done;
260 }
261
Ravi Kumar Alamandab7ea4f52015-06-08 16:44:05 -0700262 if (attr[4] != NULL) {
263 if (strcmp(attr[4], "interface") != 0) {
264 hw_interface = NULL;
265 } else {
266 hw_interface = (char *)attr[5];
267 }
268 }
269
270 if (platform_set_snd_device_backend(index, attr[3], hw_interface) < 0) {
Haynes Mathew George98c95622014-06-20 19:14:25 -0700271 ALOGE("%s: Device %s in %s, backend %s was not set!",
272 __func__, attr[1], PLATFORM_INFO_XML_PATH, attr[3]);
273 goto done;
274 }
275
276done:
277 return;
278}
279
vivek mehtaa8d7c922016-05-25 14:40:44 -0700280static void process_gain_db_to_level_map(const XML_Char **attr)
281{
282 struct amp_db_and_gain_table tbl_entry;
283
284 if ((strcmp(attr[0], "db") != 0) ||
285 (strcmp(attr[2], "level") != 0)) {
286 ALOGE("%s: invalid attribute passed %s %sexpected amp db level",
287 __func__, attr[0], attr[2]);
288 goto done;
289 }
290
291 tbl_entry.db = atof(attr[1]);
292 tbl_entry.amp = exp(tbl_entry.db * 0.115129f);
293 tbl_entry.level = atoi(attr[3]);
294
vivek mehta40125092017-08-21 18:48:51 -0700295 //custome level should be > 0. Level 0 is fixed for default
296 CHECK(tbl_entry.level > 0);
297
vivek mehtaa8d7c922016-05-25 14:40:44 -0700298 ALOGV("%s: amp [%f] db [%f] level [%d]", __func__,
299 tbl_entry.amp, tbl_entry.db, tbl_entry.level);
300 platform_add_gain_level_mapping(&tbl_entry);
301
302done:
303 return;
304}
305
Haynes Mathew George98c95622014-06-20 19:14:25 -0700306static void process_acdb_id(const XML_Char **attr)
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700307{
308 int index;
309
310 if (strcmp(attr[0], "name") != 0) {
311 ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
312 goto done;
313 }
314
315 index = platform_get_snd_device_index((char *)attr[1]);
316 if (index < 0) {
317 ALOGE("%s: Device %s in %s not found, no ACDB ID set!",
318 __func__, attr[1], PLATFORM_INFO_XML_PATH);
319 goto done;
320 }
321
322 if (strcmp(attr[2], "acdb_id") != 0) {
323 ALOGE("%s: Device %s in %s has no acdb_id, no ACDB ID set!",
324 __func__, attr[1], PLATFORM_INFO_XML_PATH);
325 goto done;
326 }
327
Haynes Mathew George98c95622014-06-20 19:14:25 -0700328 if (platform_set_snd_device_acdb_id(index, atoi((char *)attr[3])) < 0) {
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700329 ALOGE("%s: Device %s in %s, ACDB ID %d was not set!",
330 __func__, attr[1], PLATFORM_INFO_XML_PATH, atoi((char *)attr[3]));
331 goto done;
332 }
333
334done:
335 return;
336}
337
keunhui.park2f7306a2015-07-16 16:48:06 +0900338
339static void process_operator_specific(const XML_Char **attr)
340{
341 snd_device_t snd_device = SND_DEVICE_NONE;
342
343 if (strcmp(attr[0], "name") != 0) {
344 ALOGE("%s: 'name' not found", __func__);
345 goto done;
346 }
347
348 snd_device = platform_get_snd_device_index((char *)attr[1]);
349 if (snd_device < 0) {
350 ALOGE("%s: Device %s in %s not found, no ACDB ID set!",
351 __func__, (char *)attr[3], PLATFORM_INFO_XML_PATH);
352 goto done;
353 }
354
355 if (strcmp(attr[2], "operator") != 0) {
356 ALOGE("%s: 'operator' not found", __func__);
357 goto done;
358 }
359
360 if (strcmp(attr[4], "mixer_path") != 0) {
361 ALOGE("%s: 'mixer_path' not found", __func__);
362 goto done;
363 }
364
365 if (strcmp(attr[6], "acdb_id") != 0) {
366 ALOGE("%s: 'acdb_id' not found", __func__);
367 goto done;
368 }
369
370 platform_add_operator_specific_device(snd_device, (char *)attr[3], (char *)attr[5], atoi((char *)attr[7]));
371
372done:
373 return;
374}
375
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -0700376/* platform specific configuration key-value pairs */
377static void process_config_params(const XML_Char **attr)
378{
379 if (strcmp(attr[0], "key") != 0) {
380 ALOGE("%s: 'key' not found", __func__);
381 goto done;
382 }
383
384 if (strcmp(attr[2], "value") != 0) {
385 ALOGE("%s: 'value' not found", __func__);
386 goto done;
387 }
388
389 str_parms_add_str(my_data.kvpairs, (char*)attr[1], (char*)attr[3]);
vivek mehta0fb11312017-05-15 19:35:32 -0700390 set_parameters(my_data.platform, my_data.kvpairs);
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -0700391done:
392 return;
393}
394
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -0800395static void process_app_type(const XML_Char **attr)
396{
397 if (strcmp(attr[0], "uc_type")) {
398 ALOGE("%s: uc_type not found", __func__);
399 goto done;
400 }
401
vivek mehtaa68fea62017-06-08 19:04:02 -0700402 if (strcmp(attr[2], "mode")) {
403 ALOGE("%s: mode not found", __func__);
404 goto done;
405 }
406
407 if (strcmp(attr[4], "bit_width")) {
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -0800408 ALOGE("%s: bit_width not found", __func__);
409 goto done;
410 }
411
vivek mehtaa68fea62017-06-08 19:04:02 -0700412 if (strcmp(attr[6], "id")) {
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -0800413 ALOGE("%s: id not found", __func__);
414 goto done;
415 }
416
vivek mehtaa68fea62017-06-08 19:04:02 -0700417 if (strcmp(attr[8], "max_rate")) {
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -0800418 ALOGE("%s: max rate not found", __func__);
419 goto done;
420 }
421
vivek mehtaa68fea62017-06-08 19:04:02 -0700422 platform_add_app_type(attr[1], attr[3], atoi(attr[5]), atoi(attr[7]),
423 atoi(attr[9]));
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -0800424done:
425 return;
426}
427
jiabin8962a4d2018-03-19 18:21:24 -0700428static void process_microphone_characteristic(const XML_Char **attr) {
429 struct audio_microphone_characteristic_t microphone;
430 uint32_t curIdx = 0;
431
432 if (strcmp(attr[curIdx++], "valid_mask")) {
433 ALOGE("%s: valid_mask not found", __func__);
434 goto done;
435 }
436 microphone.valid_mask = atoi(attr[curIdx++]);
437
438 if (strcmp(attr[curIdx++], "device_id")) {
439 ALOGE("%s: device_id not found", __func__);
440 goto done;
441 }
442 if (strlen(attr[curIdx]) > AUDIO_MICROPHONE_ID_MAX_LEN) {
443 ALOGE("%s: device_id %s is too long", __func__, attr[curIdx]);
444 goto done;
445 }
446 strcpy(microphone.device_id, attr[curIdx++]);
447
448 if (strcmp(attr[curIdx++], "type")) {
449 ALOGE("%s: device not found", __func__);
450 goto done;
451 }
452 if (!find_enum_by_string(device_in_types, (char*)attr[curIdx++],
453 ARRAY_SIZE(device_in_types), &microphone.device)) {
454 ALOGE("%s: type %s in %s not found!",
455 __func__, attr[--curIdx], PLATFORM_INFO_XML_PATH);
456 goto done;
457 }
458
459 if (strcmp(attr[curIdx++], "address")) {
460 ALOGE("%s: address not found", __func__);
461 goto done;
462 }
463 if (strlen(attr[curIdx]) > AUDIO_DEVICE_MAX_ADDRESS_LEN) {
464 ALOGE("%s, address %s is too long", __func__, attr[curIdx]);
465 goto done;
466 }
467 strcpy(microphone.address, attr[curIdx++]);
468 if (strlen(microphone.address) == 0) {
469 // If the address is empty, populate the address according to device type.
470 if (microphone.device == AUDIO_DEVICE_IN_BUILTIN_MIC) {
471 strcpy(microphone.address, AUDIO_BOTTOM_MICROPHONE_ADDRESS);
472 } else if (microphone.device == AUDIO_DEVICE_IN_BACK_MIC) {
473 strcpy(microphone.address, AUDIO_BACK_MICROPHONE_ADDRESS);
474 }
475 }
476
477 if (strcmp(attr[curIdx++], "location")) {
478 ALOGE("%s: location not found", __func__);
479 goto done;
480 }
481 if (!find_enum_by_string(mic_locations, (char*)attr[curIdx++],
482 AUDIO_MICROPHONE_LOCATION_CNT, &microphone.location)) {
483 ALOGE("%s: location %s in %s not found!",
484 __func__, attr[--curIdx], PLATFORM_INFO_XML_PATH);
485 goto done;
486 }
487
488 if (strcmp(attr[curIdx++], "group")) {
489 ALOGE("%s: group not found", __func__);
490 goto done;
491 }
492 microphone.group = atoi(attr[curIdx++]);
493
494 if (strcmp(attr[curIdx++], "index_in_the_group")) {
495 ALOGE("%s: index_in_the_group not found", __func__);
496 goto done;
497 }
498 microphone.index_in_the_group = atoi(attr[curIdx++]);
499
500 if (strcmp(attr[curIdx++], "directionality")) {
501 ALOGE("%s: directionality not found", __func__);
502 goto done;
503 }
504 if (!find_enum_by_string(mic_directionalities, (char*)attr[curIdx++],
505 AUDIO_MICROPHONE_DIRECTIONALITY_CNT, &microphone.directionality)) {
506 ALOGE("%s: directionality %s in %s not found!",
507 __func__, attr[--curIdx], PLATFORM_INFO_XML_PATH);
508 goto done;
509 }
510
511 if (strcmp(attr[curIdx++], "num_frequency_responses")) {
512 ALOGE("%s: num_frequency_responses not found", __func__);
513 goto done;
514 }
515 microphone.num_frequency_responses = atoi(attr[curIdx++]);
516 if (microphone.num_frequency_responses > AUDIO_MICROPHONE_MAX_FREQUENCY_RESPONSES) {
517 ALOGE("%s: num_frequency_responses is too large", __func__);
518 goto done;
519 }
520 if (microphone.num_frequency_responses > 0) {
521 if (strcmp(attr[curIdx++], "frequencies")) {
522 ALOGE("%s: frequencies not found", __func__);
523 goto done;
524 }
525 char *token = strtok((char *)attr[curIdx++], ",");
526 uint32_t num_frequencies = 0;
527 while (token) {
528 microphone.frequency_responses[0][num_frequencies++] = atof(token);
529 if (num_frequencies > AUDIO_MICROPHONE_MAX_FREQUENCY_RESPONSES) {
530 ALOGE("%s: num %u of frequency is too large", __func__, num_frequencies);
531 goto done;
532 }
533 token = strtok(NULL, ",");
534 }
535
536 if (strcmp(attr[curIdx++], "responses")) {
537 ALOGE("%s: responses not found", __func__);
538 goto done;
539 }
540 token = strtok((char *)attr[curIdx++], ",");
541 uint32_t num_responses = 0;
542 while (token) {
543 microphone.frequency_responses[1][num_responses++] = atof(token);
544 if (num_responses > AUDIO_MICROPHONE_MAX_FREQUENCY_RESPONSES) {
545 ALOGE("%s: num %u of response is too large", __func__, num_responses);
546 goto done;
547 }
548 token = strtok(NULL, ",");
549 }
550
551 if (num_frequencies != num_responses
552 || num_frequencies != microphone.num_frequency_responses) {
553 ALOGE("%s: num of frequency and response not match: %u, %u, %u",
554 __func__, num_frequencies, num_responses, microphone.num_frequency_responses);
555 goto done;
556 }
557 }
558
559 if (microphone.valid_mask & AUDIO_MICROPHONE_CHARACTERISTIC_SENSITIVITY) {
560 if (strcmp(attr[curIdx++], "sensitivity")) {
561 ALOGE("%s: sensitivity not found", __func__);
562 goto done;
563 }
564 microphone.sensitivity = atof(attr[curIdx++]);
565 } else {
566 microphone.sensitivity = AUDIO_MICROPHONE_SENSITIVITY_UNKNOWN;
567 }
568
569 if (microphone.valid_mask & AUDIO_MICROPHONE_CHARACTERISTIC_MAX_SPL) {
570 if (strcmp(attr[curIdx++], "max_spl")) {
571 ALOGE("%s: max_spl not found", __func__);
572 goto done;
573 }
574 microphone.max_spl = atof(attr[curIdx++]);
575 } else {
576 microphone.max_spl = AUDIO_MICROPHONE_SPL_UNKNOWN;
577 }
578
579 if (microphone.valid_mask & AUDIO_MICROPHONE_CHARACTERISTIC_MIN_SPL) {
580 if (strcmp(attr[curIdx++], "min_spl")) {
581 ALOGE("%s: min_spl not found", __func__);
582 goto done;
583 }
584 microphone.min_spl = atof(attr[curIdx++]);
585 } else {
586 microphone.min_spl = AUDIO_MICROPHONE_SPL_UNKNOWN;
587 }
588
589 if (microphone.valid_mask & AUDIO_MICROPHONE_CHARACTERISTIC_ORIENTATION) {
590 if (strcmp(attr[curIdx++], "orientation")) {
591 ALOGE("%s: orientation not found", __func__);
592 goto done;
593 }
594 char *token = strtok((char *)attr[curIdx++], ",");
595 float orientation[3];
596 uint32_t idx = 0;
597 while (token) {
598 orientation[idx++] = atof(token);
599 if (idx > 3) {
600 ALOGE("%s: orientation invalid", __func__);
601 goto done;
602 }
603 token = strtok(NULL, ",");
604 }
605 if (idx != 3) {
606 ALOGE("%s: orientation invalid", __func__);
607 goto done;
608 }
609 microphone.orientation.x = orientation[0];
610 microphone.orientation.y = orientation[1];
611 microphone.orientation.z = orientation[2];
612 } else {
613 microphone.orientation.x = 0.0f;
614 microphone.orientation.y = 0.0f;
615 microphone.orientation.z = 0.0f;
616 }
617
618 if (microphone.valid_mask & AUDIO_MICROPHONE_CHARACTERISTIC_GEOMETRIC_LOCATION) {
619 if (strcmp(attr[curIdx++], "geometric_location")) {
620 ALOGE("%s: geometric_location not found", __func__);
621 goto done;
622 }
623 char *token = strtok((char *)attr[curIdx++], ",");
624 float geometric_location[3];
625 uint32_t idx = 0;
626 while (token) {
627 geometric_location[idx++] = atof(token);
628 if (idx > 3) {
629 ALOGE("%s: geometric_location invalid", __func__);
630 goto done;
631 }
632 token = strtok(NULL, ",");
633 }
634 if (idx != 3) {
635 ALOGE("%s: geometric_location invalid", __func__);
636 goto done;
637 }
638 microphone.geometric_location.x = geometric_location[0];
639 microphone.geometric_location.y = geometric_location[1];
640 microphone.geometric_location.z = geometric_location[2];
641 } else {
642 microphone.geometric_location.x = AUDIO_MICROPHONE_COORDINATE_UNKNOWN;
643 microphone.geometric_location.y = AUDIO_MICROPHONE_COORDINATE_UNKNOWN;
644 microphone.geometric_location.z = AUDIO_MICROPHONE_COORDINATE_UNKNOWN;
645 }
646
647 platform_set_microphone_characteristic(my_data.platform, microphone);
648done:
649 return;
650}
651
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700652static void start_tag(void *userdata __unused, const XML_Char *tag_name,
653 const XML_Char **attr)
654{
655 const XML_Char *attr_name = NULL;
656 const XML_Char *attr_value = NULL;
657 unsigned int i;
658
Haynes Mathew George98c95622014-06-20 19:14:25 -0700659
vivek mehta0fb11312017-05-15 19:35:32 -0700660 if (my_data.do_full_parse) {
661 if (strcmp(tag_name, "acdb_ids") == 0) {
662 section = ACDB;
663 } else if (strcmp(tag_name, "pcm_ids") == 0) {
664 section = PCM_ID;
665 } else if (strcmp(tag_name, "backend_names") == 0) {
666 section = BACKEND_NAME;
667 } else if (strcmp(tag_name, "config_params") == 0) {
668 section = CONFIG_PARAMS;
669 } else if (strcmp(tag_name, "operator_specific") == 0) {
670 section = OPERATOR_SPECIFIC;
671 } else if (strcmp(tag_name, "gain_db_to_level_mapping") == 0) {
672 section = GAIN_LEVEL_MAPPING;
673 } else if (strcmp(tag_name, "app_types") == 0) {
674 section = APP_TYPE;
jiabin8962a4d2018-03-19 18:21:24 -0700675 } else if (strcmp(tag_name, "microphone_characteristics") == 0) {
676 section = MICROPHONE_CHARACTERISTIC;
vivek mehta0fb11312017-05-15 19:35:32 -0700677 } else if (strcmp(tag_name, "device") == 0) {
678 if ((section != ACDB) && (section != BACKEND_NAME) && (section != OPERATOR_SPECIFIC)) {
679 ALOGE("device tag only supported for acdb/backend names");
680 return;
681 }
Haynes Mathew George98c95622014-06-20 19:14:25 -0700682
vivek mehta0fb11312017-05-15 19:35:32 -0700683 /* call into process function for the current section */
684 section_process_fn fn = section_table[section];
685 fn(attr);
686 } else if (strcmp(tag_name, "usecase") == 0) {
687 if (section != PCM_ID) {
688 ALOGE("usecase tag only supported with PCM_ID section");
689 return;
690 }
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -0700691
vivek mehta0fb11312017-05-15 19:35:32 -0700692 section_process_fn fn = section_table[PCM_ID];
693 fn(attr);
694 } else if (strcmp(tag_name, "param") == 0) {
695 if (section != CONFIG_PARAMS) {
696 ALOGE("param tag only supported with CONFIG_PARAMS section");
697 return;
698 }
vivek mehtaa8d7c922016-05-25 14:40:44 -0700699
vivek mehta0fb11312017-05-15 19:35:32 -0700700 section_process_fn fn = section_table[section];
701 fn(attr);
702 } else if (strcmp(tag_name, "gain_level_map") == 0) {
703 if (section != GAIN_LEVEL_MAPPING) {
jiabin8962a4d2018-03-19 18:21:24 -0700704 ALOGE("gain_level_map tag only supported with GAIN_LEVEL_MAPPING section");
vivek mehta0fb11312017-05-15 19:35:32 -0700705 return;
706 }
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -0800707
vivek mehta0fb11312017-05-15 19:35:32 -0700708 section_process_fn fn = section_table[GAIN_LEVEL_MAPPING];
709 fn(attr);
710 } else if (!strcmp(tag_name, "app")) {
711 if (section != APP_TYPE) {
712 ALOGE("app tag only valid in section APP_TYPE");
713 return;
714 }
715
716 section_process_fn fn = section_table[APP_TYPE];
717 fn(attr);
jiabin8962a4d2018-03-19 18:21:24 -0700718 } else if (strcmp(tag_name, "microphone") == 0) {
719 if (section != MICROPHONE_CHARACTERISTIC) {
720 ALOGE("microphone tag only supported with MICROPHONE_CHARACTERISTIC section");
721 return;
722 }
723 section_process_fn fn = section_table[MICROPHONE_CHARACTERISTIC];
724 fn(attr);
vivek mehta0fb11312017-05-15 19:35:32 -0700725 }
726 } else {
727 if(strcmp(tag_name, "config_params") == 0) {
728 section = CONFIG_PARAMS;
729 } else if (strcmp(tag_name, "param") == 0) {
730 if (section != CONFIG_PARAMS) {
731 ALOGE("param tag only supported with CONFIG_PARAMS section");
732 return;
733 }
734
735 section_process_fn fn = section_table[section];
736 fn(attr);
737 }
Haynes Mathew George98c95622014-06-20 19:14:25 -0700738 }
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700739
740 return;
741}
742
Haynes Mathew George98c95622014-06-20 19:14:25 -0700743static void end_tag(void *userdata __unused, const XML_Char *tag_name)
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700744{
Haynes Mathew George98c95622014-06-20 19:14:25 -0700745 if (strcmp(tag_name, "acdb_ids") == 0) {
746 section = ROOT;
747 } else if (strcmp(tag_name, "pcm_ids") == 0) {
748 section = ROOT;
749 } else if (strcmp(tag_name, "backend_names") == 0) {
750 section = ROOT;
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -0700751 } else if (strcmp(tag_name, "config_params") == 0) {
752 section = ROOT;
keunhui.park2f7306a2015-07-16 16:48:06 +0900753 } else if (strcmp(tag_name, "operator_specific") == 0) {
754 section = ROOT;
vivek mehtaa8d7c922016-05-25 14:40:44 -0700755 } else if (strcmp(tag_name, "gain_db_to_level_mapping") == 0) {
756 section = ROOT;
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -0800757 } else if (strcmp(tag_name, "app_types") == 0) {
758 section = ROOT;
jiabin8962a4d2018-03-19 18:21:24 -0700759 } else if (strcmp(tag_name, "microphone_characteristics") == 0) {
760 section = ROOT;
Haynes Mathew George98c95622014-06-20 19:14:25 -0700761 }
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700762}
763
vivek mehta0fb11312017-05-15 19:35:32 -0700764int snd_card_info_init(const char *filename, void *platform, set_parameters_fn fn)
765{
766 set_parameters = fn;
767 my_data.do_full_parse = false;
768 return platform_info_init(filename, platform);
769}
770
vivek mehtade4849c2016-03-03 17:23:38 -0800771int platform_info_init(const char *filename, void *platform)
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700772{
773 XML_Parser parser;
774 FILE *file;
775 int ret = 0;
776 int bytes_read;
777 void *buf;
778 static const uint32_t kBufSize = 1024;
vivek mehtade4849c2016-03-03 17:23:38 -0800779 char platform_info_file_name[MIXER_PATH_MAX_LENGTH]= {0};
Haynes Mathew George98c95622014-06-20 19:14:25 -0700780 section = ROOT;
781
vivek mehtade4849c2016-03-03 17:23:38 -0800782 if (filename == NULL) {
783 strlcpy(platform_info_file_name, PLATFORM_INFO_XML_PATH, MIXER_PATH_MAX_LENGTH);
784 } else {
785 strlcpy(platform_info_file_name, filename, MIXER_PATH_MAX_LENGTH);
786 }
787
788 ALOGV("%s: platform info file name is %s", __func__, platform_info_file_name);
789
790 file = fopen(platform_info_file_name, "r");
791
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700792 if (!file) {
793 ALOGD("%s: Failed to open %s, using defaults.",
vivek mehtade4849c2016-03-03 17:23:38 -0800794 __func__, platform_info_file_name);
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700795 ret = -ENODEV;
796 goto done;
797 }
798
799 parser = XML_ParserCreate(NULL);
800 if (!parser) {
801 ALOGE("%s: Failed to create XML parser!", __func__);
802 ret = -ENODEV;
803 goto err_close_file;
804 }
805
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -0700806 my_data.platform = platform;
807 my_data.kvpairs = str_parms_create();
808
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700809 XML_SetElementHandler(parser, start_tag, end_tag);
810
811 while (1) {
812 buf = XML_GetBuffer(parser, kBufSize);
813 if (buf == NULL) {
814 ALOGE("%s: XML_GetBuffer failed", __func__);
815 ret = -ENOMEM;
816 goto err_free_parser;
817 }
818
819 bytes_read = fread(buf, 1, kBufSize, file);
820 if (bytes_read < 0) {
821 ALOGE("%s: fread failed, bytes read = %d", __func__, bytes_read);
822 ret = bytes_read;
823 goto err_free_parser;
824 }
825
826 if (XML_ParseBuffer(parser, bytes_read,
827 bytes_read == 0) == XML_STATUS_ERROR) {
828 ALOGE("%s: XML_ParseBuffer failed, for %s",
vivek mehtade4849c2016-03-03 17:23:38 -0800829 __func__, platform_info_file_name);
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700830 ret = -EINVAL;
831 goto err_free_parser;
832 }
833
834 if (bytes_read == 0)
835 break;
836 }
837
vivek mehta0fb11312017-05-15 19:35:32 -0700838 set_parameters = &platform_set_parameters;
839 my_data.do_full_parse = true;
840
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700841err_free_parser:
842 XML_ParserFree(parser);
843err_close_file:
844 fclose(file);
845done:
846 return ret;
847}