blob: a176177a0d10761a04314bfcdaf3ce1b521c116d [file] [log] [blame]
Ben Romberger55886882014-01-10 13:49:02 -08001/*
2 * Copyright (c) 2014, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
Ben Romberger61764e32014-01-10 13:49:02 -080030#define LOG_TAG "platform_info"
Ben Romberger55886882014-01-10 13:49:02 -080031#define LOG_NDDEBUG 0
32
33#include <errno.h>
34#include <stdio.h>
35#include <expat.h>
36#include <cutils/log.h>
37#include <audio_hw.h>
Ben Romberger61764e32014-01-10 13:49:02 -080038#include "platform_api.h"
39#include <platform.h>
Ben Romberger55886882014-01-10 13:49:02 -080040
Ben Romberger55886882014-01-10 13:49:02 -080041#define BUF_SIZE 1024
42
Haynes Mathew Georgef4da6fe2014-06-20 19:14:25 -070043typedef enum {
44 ROOT,
45 ACDB,
Amit Shekhar5a39c912014-10-14 15:39:30 -070046 BITWIDTH,
Haynes Mathew Georgef4da6fe2014-06-20 19:14:25 -070047 PCM_ID,
48 BACKEND_NAME,
49} section_t;
50
51typedef void (* section_process_fn)(const XML_Char **attr);
52
53static void process_acdb_id(const XML_Char **attr);
Amit Shekhar5a39c912014-10-14 15:39:30 -070054static void process_bit_width(const XML_Char **attr);
Haynes Mathew Georgef4da6fe2014-06-20 19:14:25 -070055static void process_pcm_id(const XML_Char **attr);
56static void process_backend_name(const XML_Char **attr);
57static void process_root(const XML_Char **attr);
58
59static section_process_fn section_table[] = {
60 [ROOT] = process_root,
61 [ACDB] = process_acdb_id,
Amit Shekhar5a39c912014-10-14 15:39:30 -070062 [BITWIDTH] = process_bit_width,
Haynes Mathew Georgef4da6fe2014-06-20 19:14:25 -070063 [PCM_ID] = process_pcm_id,
64 [BACKEND_NAME] = process_backend_name,
65};
66
67static section_t section;
68
69/*
70 * <audio_platform_info>
71 * <acdb_ids>
72 * <device name="???" acdb_id="???"/>
73 * ...
74 * ...
75 * </acdb_ids>
76 * <backend_names>
77 * <device name="???" backend="???"/>
78 * ...
79 * ...
80 * </backend_names>
81 * <pcm_ids>
82 * <usecase name="???" type="in/out" id="???"/>
83 * ...
84 * ...
85 * </pcm_ids>
86 * </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) {
99 ALOGE("%s: 'name' not found, no ACDB 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 not found!",
106 __func__, attr[1]);
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 type %d id %d was not set!",
135 __func__, attr[1], 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;
147
148 if (strcmp(attr[0], "name") != 0) {
149 ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
150 goto done;
151 }
152
153 index = platform_get_snd_device_index((char *)attr[1]);
154 if (index < 0) {
155 ALOGE("%s: Device %s not found, no ACDB ID set!",
156 __func__, attr[1]);
157 goto done;
158 }
159
160 if (strcmp(attr[2], "backend") != 0) {
161 ALOGE("%s: Device %s has no backend set!",
162 __func__, attr[1]);
163 goto done;
164 }
165
166 if (platform_set_snd_device_backend(index, attr[3]) < 0) {
167 ALOGE("%s: Device %s backend %s was not set!",
168 __func__, attr[1], attr[3]);
169 goto done;
170 }
171
172done:
173 return;
174}
175
176static void process_acdb_id(const XML_Char **attr)
Ben Romberger55886882014-01-10 13:49:02 -0800177{
Ben Romberger61764e32014-01-10 13:49:02 -0800178 int index;
Ben Romberger55886882014-01-10 13:49:02 -0800179
Ben Romberger61764e32014-01-10 13:49:02 -0800180 if (strcmp(attr[0], "name") != 0) {
181 ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
Ben Romberger55886882014-01-10 13:49:02 -0800182 goto done;
Ben Romberger61764e32014-01-10 13:49:02 -0800183 }
Ben Romberger55886882014-01-10 13:49:02 -0800184
Ben Romberger61764e32014-01-10 13:49:02 -0800185 index = platform_get_snd_device_index((char *)attr[1]);
186 if (index < 0) {
Helen Zeng6a16ad72014-02-23 22:04:44 -0800187 ALOGE("%s: Device %s in platform info xml not found, no ACDB ID set!",
188 __func__, attr[1]);
Ben Romberger55886882014-01-10 13:49:02 -0800189 goto done;
190 }
191
192 if (strcmp(attr[2], "acdb_id") != 0) {
Helen Zeng6a16ad72014-02-23 22:04:44 -0800193 ALOGE("%s: Device %s in platform info xml has no acdb_id, no ACDB ID set!",
194 __func__, attr[1]);
Ben Romberger55886882014-01-10 13:49:02 -0800195 goto done;
196 }
197
Haynes Mathew Georgef4da6fe2014-06-20 19:14:25 -0700198 if (platform_set_snd_device_acdb_id(index, atoi((char *)attr[3])) < 0) {
199 ALOGE("%s: Device %s, ACDB ID %d was not set!",
Helen Zeng6a16ad72014-02-23 22:04:44 -0800200 __func__, attr[1], atoi((char *)attr[3]));
Ben Romberger55886882014-01-10 13:49:02 -0800201 goto done;
Ben Romberger61764e32014-01-10 13:49:02 -0800202 }
Ben Romberger55886882014-01-10 13:49:02 -0800203
Ben Romberger55886882014-01-10 13:49:02 -0800204done:
205 return;
206}
207
Amit Shekhar5a39c912014-10-14 15:39:30 -0700208static void process_bit_width(const XML_Char **attr)
209{
210 int index;
211
212 if (strcmp(attr[0], "name") != 0) {
213 ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
214 goto done;
215 }
216
217 index = platform_get_snd_device_index((char *)attr[1]);
218 if (index < 0) {
219 ALOGE("%s: Device %s in platform info xml not found, no ACDB ID set!",
220 __func__, attr[1]);
221 goto done;
222 }
223
224 if (strcmp(attr[2], "bit_width") != 0) {
225 ALOGE("%s: Device %s in platform info xml has no bit_width, no ACDB ID set!",
226 __func__, attr[1]);
227 goto done;
228 }
229
230 if (platform_set_snd_device_bit_width(index, atoi((char *)attr[3])) < 0) {
231 ALOGE("%s: Device %s, ACDB ID %d was not set!",
232 __func__, attr[1], atoi((char *)attr[3]));
233 goto done;
234 }
235
236done:
237 return;
238}
239
Haynes Mathew Georgef4da6fe2014-06-20 19:14:25 -0700240static void start_tag(void *userdata __unused, const XML_Char *tag_name,
Ben Romberger55886882014-01-10 13:49:02 -0800241 const XML_Char **attr)
242{
243 const XML_Char *attr_name = NULL;
244 const XML_Char *attr_value = NULL;
245 unsigned int i;
246
Amit Shekhar5a39c912014-10-14 15:39:30 -0700247 if (strcmp(tag_name, "bit_width_configs") == 0) {
248 section = BITWIDTH;
249 } else if (strcmp(tag_name, "acdb_ids") == 0) {
Haynes Mathew Georgef4da6fe2014-06-20 19:14:25 -0700250 section = ACDB;
251 } else if (strcmp(tag_name, "pcm_ids") == 0) {
252 section = PCM_ID;
253 } else if (strcmp(tag_name, "backend_names") == 0) {
254 section = BACKEND_NAME;
255 } else if (strcmp(tag_name, "device") == 0) {
Amit Shekhar5a39c912014-10-14 15:39:30 -0700256 if ((section != ACDB) && (section != BACKEND_NAME) && (section != BITWIDTH)) {
Haynes Mathew Georgef4da6fe2014-06-20 19:14:25 -0700257 ALOGE("device tag only supported for acdb/backend names");
258 return;
259 }
260
261 /* call into process function for the current section */
262 section_process_fn fn = section_table[section];
263 fn(attr);
264 } else if (strcmp(tag_name, "usecase") == 0) {
265 if (section != PCM_ID) {
266 ALOGE("usecase tag only supported with PCM_ID section");
267 return;
268 }
269
270 section_process_fn fn = section_table[PCM_ID];
271 fn(attr);
272 }
Ben Romberger55886882014-01-10 13:49:02 -0800273
274 return;
275}
276
Haynes Mathew Georgef4da6fe2014-06-20 19:14:25 -0700277static void end_tag(void *userdata __unused, const XML_Char *tag_name)
Ben Romberger55886882014-01-10 13:49:02 -0800278{
Amit Shekhar5a39c912014-10-14 15:39:30 -0700279 if (strcmp(tag_name, "bit_width_configs") == 0) {
280 section = ROOT;
281 } else if (strcmp(tag_name, "acdb_ids") == 0) {
Haynes Mathew Georgef4da6fe2014-06-20 19:14:25 -0700282 section = ROOT;
283 } else if (strcmp(tag_name, "pcm_ids") == 0) {
284 section = ROOT;
285 } else if (strcmp(tag_name, "backend_names") == 0) {
286 section = ROOT;
287 }
Ben Romberger55886882014-01-10 13:49:02 -0800288}
289
Helen Zeng6a16ad72014-02-23 22:04:44 -0800290int platform_info_init(const char *filename)
Ben Romberger55886882014-01-10 13:49:02 -0800291{
292 XML_Parser parser;
293 FILE *file;
294 int ret = 0;
295 int bytes_read;
Ben Romberger55886882014-01-10 13:49:02 -0800296 void *buf;
297
Helen Zeng6a16ad72014-02-23 22:04:44 -0800298 file = fopen(filename, "r");
Haynes Mathew Georgef4da6fe2014-06-20 19:14:25 -0700299 section = ROOT;
300
Ben Romberger55886882014-01-10 13:49:02 -0800301 if (!file) {
302 ALOGD("%s: Failed to open %s, using defaults.",
Helen Zeng6a16ad72014-02-23 22:04:44 -0800303 __func__, filename);
Ben Romberger55886882014-01-10 13:49:02 -0800304 ret = -ENODEV;
305 goto done;
306 }
307
308 parser = XML_ParserCreate(NULL);
309 if (!parser) {
310 ALOGE("%s: Failed to create XML parser!", __func__);
311 ret = -ENODEV;
312 goto err_close_file;
313 }
314
Ben Romberger55886882014-01-10 13:49:02 -0800315 XML_SetElementHandler(parser, start_tag, end_tag);
316
317 while (1) {
318 buf = XML_GetBuffer(parser, BUF_SIZE);
319 if (buf == NULL) {
320 ALOGE("%s: XML_GetBuffer failed", __func__);
321 ret = -ENOMEM;
322 goto err_free_parser;
323 }
324
325 bytes_read = fread(buf, 1, BUF_SIZE, file);
326 if (bytes_read < 0) {
327 ALOGE("%s: fread failed, bytes read = %d", __func__, bytes_read);
328 ret = bytes_read;
329 goto err_free_parser;
330 }
331
332 if (XML_ParseBuffer(parser, bytes_read,
333 bytes_read == 0) == XML_STATUS_ERROR) {
334 ALOGE("%s: XML_ParseBuffer failed, for %s",
Helen Zeng6a16ad72014-02-23 22:04:44 -0800335 __func__, filename);
Ben Romberger55886882014-01-10 13:49:02 -0800336 ret = -EINVAL;
337 goto err_free_parser;
338 }
339
340 if (bytes_read == 0)
341 break;
342 }
343
Ben Romberger55886882014-01-10 13:49:02 -0800344err_free_parser:
345 XML_ParserFree(parser);
346err_close_file:
347 fclose(file);
348done:
349 return ret;
350}