blob: c0527b4b276eaf642aa673a9336dc918492d42f6 [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
28#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,
Haynes Mathew George98c95622014-06-20 19:14:25 -070036} section_t;
37
38typedef void (* section_process_fn)(const XML_Char **attr);
39
40static void process_acdb_id(const XML_Char **attr);
41static void process_pcm_id(const XML_Char **attr);
42static void process_backend_name(const XML_Char **attr);
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -070043static void process_config_params(const XML_Char **attr);
Haynes Mathew George98c95622014-06-20 19:14:25 -070044static void process_root(const XML_Char **attr);
45
46static 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,
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -070051 [CONFIG_PARAMS] = process_config_params,
Haynes Mathew George98c95622014-06-20 19:14:25 -070052};
53
54static section_t section;
55
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -070056struct platform_info {
57 void *platform;
58 struct str_parms *kvpairs;
59};
60
61static struct platform_info my_data;
62
Haynes Mathew George98c95622014-06-20 19:14:25 -070063/*
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>
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -070080 * <config_params>
81 * <param key="snd_card_name" value="msm8994-tomtom-mtp-snd-card"/>
82 * ...
83 * ...
84 * </config_params>
85 *
Haynes Mathew George98c95622014-06-20 19:14:25 -070086 * </audio_platform_info>
87 */
88
89static void process_root(const XML_Char **attr __unused)
90{
91}
92
93/* mapping from usecase to pcm dev id */
94static void process_pcm_id(const XML_Char **attr)
95{
96 int index;
97
98 if (strcmp(attr[0], "name") != 0) {
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -070099 ALOGE("%s: 'name' not found, no pcm_id set!", __func__);
Haynes Mathew George98c95622014-06-20 19:14:25 -0700100 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
139done:
140 return;
141}
142
143/* backend to be used for a device */
144static void process_backend_name(const XML_Char **attr)
145{
146 int index;
Ravi Kumar Alamandab7ea4f52015-06-08 16:44:05 -0700147 char *hw_interface = NULL;
Haynes Mathew George98c95622014-06-20 19:14:25 -0700148
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
Ravi Kumar Alamandab7ea4f52015-06-08 16:44:05 -0700167 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) {
Haynes Mathew George98c95622014-06-20 19:14:25 -0700176 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
181done:
182 return;
183}
184
185static void process_acdb_id(const XML_Char **attr)
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700186{
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
Haynes Mathew George98c95622014-06-20 19:14:25 -0700207 if (platform_set_snd_device_acdb_id(index, atoi((char *)attr[3])) < 0) {
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700208 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
213done:
214 return;
215}
216
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -0700217/* platform specific configuration key-value pairs */
218static 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]);
231done:
232 return;
233}
234
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700235static 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
Haynes Mathew George98c95622014-06-20 19:14:25 -0700242 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;
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -0700248 } else if (strcmp(tag_name, "config_params") == 0) {
249 section = CONFIG_PARAMS;
Haynes Mathew George98c95622014-06-20 19:14:25 -0700250 } 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);
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -0700267 } 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);
Haynes Mathew George98c95622014-06-20 19:14:25 -0700275 }
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700276
277 return;
278}
279
Haynes Mathew George98c95622014-06-20 19:14:25 -0700280static void end_tag(void *userdata __unused, const XML_Char *tag_name)
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700281{
Haynes Mathew George98c95622014-06-20 19:14:25 -0700282 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;
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -0700288 } else if (strcmp(tag_name, "config_params") == 0) {
289 section = ROOT;
290 platform_set_parameters(my_data.platform, my_data.kvpairs);
Haynes Mathew George98c95622014-06-20 19:14:25 -0700291 }
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700292}
293
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -0700294int platform_info_init(void *platform)
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700295{
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
Haynes Mathew George98c95622014-06-20 19:14:25 -0700303 section = ROOT;
304
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700305 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
Ravi Kumar Alamandac4f57312015-06-26 17:41:02 -0700320 my_data.platform = platform;
321 my_data.kvpairs = str_parms_create();
322
Haynes Mathew George5bc18842014-06-16 16:36:20 -0700323 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
352err_free_parser:
353 XML_ParserFree(parser);
354err_close_file:
355 fclose(file);
356done:
357 return ret;
358}