audio: extend platform parser

Extend platform parser with support for additional sections.
Supported sections now include acdb ids, pcm device ids and backend names.

Change-Id: Idfbc8a8bb490606686436c107db5b0c7d636ccbe
diff --git a/hal/platform_info.c b/hal/platform_info.c
index 409c396..832c0f0 100644
--- a/hal/platform_info.c
+++ b/hal/platform_info.c
@@ -27,7 +27,137 @@
 
 #define PLATFORM_INFO_XML_PATH      "/system/etc/audio_platform_info.xml"
 
-static void process_device(const XML_Char **attr)
+typedef enum {
+    ROOT,
+    ACDB,
+    PCM_ID,
+    BACKEND_NAME,
+} section_t;
+
+typedef void (* section_process_fn)(const XML_Char **attr);
+
+static void process_acdb_id(const XML_Char **attr);
+static void process_pcm_id(const XML_Char **attr);
+static void process_backend_name(const XML_Char **attr);
+static void process_root(const XML_Char **attr);
+
+static section_process_fn section_table[] = {
+    [ROOT] = process_root,
+    [ACDB] = process_acdb_id,
+    [PCM_ID] = process_pcm_id,
+    [BACKEND_NAME] = process_backend_name,
+};
+
+static section_t section;
+
+/*
+ * <audio_platform_info>
+ * <acdb_ids>
+ * <device name="???" acdb_id="???"/>
+ * ...
+ * ...
+ * </acdb_ids>
+ * <backend_names>
+ * <device name="???" backend="???"/>
+ * ...
+ * ...
+ * </backend_names>
+ * <pcm_ids>
+ * <usecase name="???" type="in/out" id="???"/>
+ * ...
+ * ...
+ * </pcm_ids>
+ * </audio_platform_info>
+ */
+
+static void process_root(const XML_Char **attr __unused)
+{
+}
+
+/* mapping from usecase to pcm dev id */
+static void process_pcm_id(const XML_Char **attr)
+{
+    int index;
+
+    if (strcmp(attr[0], "name") != 0) {
+        ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
+        goto done;
+    }
+
+    index = platform_get_usecase_index((char *)attr[1]);
+    if (index < 0) {
+        ALOGE("%s: usecase %s in %s not found!",
+              __func__, attr[1], PLATFORM_INFO_XML_PATH);
+        goto done;
+    }
+
+    if (strcmp(attr[2], "type") != 0) {
+        ALOGE("%s: usecase type not mentioned", __func__);
+        goto done;
+    }
+
+    int type = -1;
+
+    if (!strcasecmp((char *)attr[3], "in")) {
+        type = 1;
+    } else if (!strcasecmp((char *)attr[3], "out")) {
+        type = 0;
+    } else {
+        ALOGE("%s: type must be IN or OUT", __func__);
+        goto done;
+    }
+
+    if (strcmp(attr[4], "id") != 0) {
+        ALOGE("%s: usecase id not mentioned", __func__);
+        goto done;
+    }
+
+    int id = atoi((char *)attr[5]);
+
+    if (platform_set_usecase_pcm_id(index, type, id) < 0) {
+        ALOGE("%s: usecase %s in %s, type %d id %d was not set!",
+              __func__, attr[1], PLATFORM_INFO_XML_PATH, type, id);
+        goto done;
+    }
+
+done:
+    return;
+}
+
+/* backend to be used for a device */
+static void process_backend_name(const XML_Char **attr)
+{
+    int index;
+
+    if (strcmp(attr[0], "name") != 0) {
+        ALOGE("%s: 'name' not found, no ACDB ID set!", __func__);
+        goto done;
+    }
+
+    index = platform_get_snd_device_index((char *)attr[1]);
+    if (index < 0) {
+        ALOGE("%s: Device %s in %s not found, no ACDB ID set!",
+              __func__, attr[1], PLATFORM_INFO_XML_PATH);
+        goto done;
+    }
+
+    if (strcmp(attr[2], "backend") != 0) {
+        ALOGE("%s: Device %s in %s has no backed set!",
+              __func__, attr[1], PLATFORM_INFO_XML_PATH);
+        goto done;
+    }
+
+    if (platform_set_snd_device_backend(index, attr[3]) < 0) {
+        ALOGE("%s: Device %s in %s, backend %s was not set!",
+              __func__, attr[1], PLATFORM_INFO_XML_PATH, attr[3]);
+        goto done;
+    }
+
+done:
+    return;
+}
+
+static void process_acdb_id(const XML_Char **attr)
 {
     int index;
 
@@ -49,7 +179,7 @@
         goto done;
     }
 
-    if(platform_set_snd_device_acdb_id(index, atoi((char *)attr[3])) < 0) {
+    if (platform_set_snd_device_acdb_id(index, atoi((char *)attr[3])) < 0) {
         ALOGE("%s: Device %s in %s, ACDB ID %d was not set!",
               __func__, attr[1], PLATFORM_INFO_XML_PATH, atoi((char *)attr[3]));
         goto done;
@@ -66,15 +196,43 @@
     const XML_Char              *attr_value = NULL;
     unsigned int                i;
 
-    if (strcmp(tag_name, "device") == 0)
-        process_device(attr);
+    if (strcmp(tag_name, "acdb_ids") == 0) {
+        section = ACDB;
+    } else if (strcmp(tag_name, "pcm_ids") == 0) {
+        section = PCM_ID;
+    } else if (strcmp(tag_name, "backend_names") == 0) {
+        section = BACKEND_NAME;
+    } else if (strcmp(tag_name, "device") == 0) {
+        if ((section != ACDB) && (section != BACKEND_NAME)) {
+            ALOGE("device tag only supported for acdb/backend names");
+            return;
+        }
+
+        /* call into process function for the current section */
+        section_process_fn fn = section_table[section];
+        fn(attr);
+    } else if (strcmp(tag_name, "usecase") == 0) {
+        if (section != PCM_ID) {
+            ALOGE("usecase tag only supported with PCM_ID section");
+            return;
+        }
+
+        section_process_fn fn = section_table[PCM_ID];
+        fn(attr);
+    }
 
     return;
 }
 
-static void end_tag(void *userdata __unused, const XML_Char *tag_name __unused)
+static void end_tag(void *userdata __unused, const XML_Char *tag_name)
 {
-
+    if (strcmp(tag_name, "acdb_ids") == 0) {
+        section = ROOT;
+    } else if (strcmp(tag_name, "pcm_ids") == 0) {
+        section = ROOT;
+    } else if (strcmp(tag_name, "backend_names") == 0) {
+        section = ROOT;
+    }
 }
 
 int platform_info_init(void)
@@ -86,6 +244,8 @@
     void            *buf;
     static const uint32_t kBufSize = 1024;
 
+    section = ROOT;
+
     file = fopen(PLATFORM_INFO_XML_PATH, "r");
     if (!file) {
         ALOGD("%s: Failed to open %s, using defaults.",