audio: Add ACDB INIT extension

- Add an audio extension for ACDB
- ACDB Init from AHAL and STHAL are routed via this extension

Test:  verify audio playback and captrue

Change-Id: I5ee568d360651d6db7d351fb8aae1b508bf99589
Signed-off-by: David Lin <dtwlin@google.com>
diff --git a/hal/Android.mk b/hal/Android.mk
index 2b27e64..2de6c16 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -67,7 +67,8 @@
 	audio_extn/ext_speaker.c \
 	audio_extn/audio_extn.c \
 	audio_extn/utils.c \
-	$(AUDIO_PLATFORM)/platform.c
+	$(AUDIO_PLATFORM)/platform.c \
+        acdb.c
 
 ifdef MULTIPLE_HW_VARIANTS_ENABLED
   LOCAL_CFLAGS += -DHW_VARIANTS_ENABLED
diff --git a/hal/acdb.c b/hal/acdb.c
new file mode 100644
index 0000000..1614cc9
--- /dev/null
+++ b/hal/acdb.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audio_hw_acdb"
+//#define LOG_NDEBUG 0
+#define LOG_NDDEBUG 0
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <dlfcn.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include <system/audio.h>
+#include <tinyalsa/asoundlib.h>
+#include "acdb.h"
+#include <platform_api.h>
+
+#define PLATFORM_CONFIG_KEY_SOUNDCARD_NAME "snd_card_name"
+#define PLATFORM_INFO_XML_PATH          "audio_platform_info.xml"
+
+int acdb_init(int snd_card_num)
+{
+
+    int result = -1;
+    char *cvd_version = NULL;
+
+    char *snd_card_name = NULL;
+    struct mixer *mixer = NULL;
+    struct acdb_platform_data *my_data = NULL;
+
+    if(snd_card_num < 0) {
+        ALOGE("invalid sound card number");
+        return result;
+    }
+
+    mixer = mixer_open(snd_card_num);
+    if (!mixer) {
+        ALOGE("%s: Unable to open the mixer card: %d", __func__,
+               snd_card_num);
+        goto cleanup;
+    }
+
+    my_data = calloc(1, sizeof(struct acdb_platform_data));
+    if (!my_data) {
+        ALOGE("failed to allocate acdb platform data");
+        goto cleanup;
+    }
+
+    list_init(&my_data->acdb_meta_key_list);
+
+    /* Extract META KEY LIST INFO */
+    //platform_info_init(PLATFORM_INFO_XML_PATH, my_data);
+
+    my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW);
+    if (my_data->acdb_handle == NULL) {
+        ALOGE("%s: DLOPEN failed for %s", __func__, LIB_ACDB_LOADER);
+        goto cleanup;
+    }
+
+    ALOGV("%s: DLOPEN successful for %s", __func__, LIB_ACDB_LOADER);
+
+    my_data->acdb_init_v3 = (acdb_init_v3_t)dlsym(my_data->acdb_handle,
+                                                     "acdb_loader_init_v3");
+    if (my_data->acdb_init_v3 == NULL)
+        ALOGE("%s: dlsym error %s for acdb_loader_init_v3", __func__, dlerror());
+
+    my_data->acdb_init_v2 = (acdb_init_v2_cvd_t)dlsym(my_data->acdb_handle,
+                                                     "acdb_loader_init_v2");
+    if (my_data->acdb_init_v2 == NULL)
+        ALOGE("%s: dlsym error %s for acdb_loader_init_v2", __func__, dlerror());
+
+    my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
+                                                 "acdb_loader_init_ACDB");
+    if (my_data->acdb_init == NULL && my_data->acdb_init_v2 == NULL
+        && my_data->acdb_init_v3 == NULL) {
+        ALOGE("%s: dlsym error %s for acdb_loader_init_ACDB", __func__, dlerror());
+        goto cleanup;
+    }
+
+    /* Get CVD version */
+    cvd_version = calloc(1, MAX_CVD_VERSION_STRING_SIZE);
+    if (!cvd_version) {
+        ALOGE("%s: Failed to allocate cvd version", __func__);
+        goto cleanup;
+    } else {
+        struct mixer_ctl *ctl = NULL;
+        int count = 0;
+
+        ctl = mixer_get_ctl_by_name(mixer, CVD_VERSION_MIXER_CTL);
+        if (!ctl) {
+            ALOGE("%s: Could not get ctl for mixer cmd - %s",  __func__, CVD_VERSION_MIXER_CTL);
+            goto cleanup;
+        }
+        mixer_ctl_update(ctl);
+
+        count = mixer_ctl_get_num_values(ctl);
+        if (count > MAX_CVD_VERSION_STRING_SIZE)
+            count = MAX_CVD_VERSION_STRING_SIZE;
+
+        result = mixer_ctl_get_array(ctl, cvd_version, count);
+        if (result != 0) {
+            ALOGE("%s: ERROR! mixer_ctl_get_array() failed to get CVD Version", __func__);
+            goto cleanup;
+        }
+    }
+
+    /* Get Sound card name */
+    snd_card_name = strdup(mixer_get_name(mixer));
+    if (!snd_card_name) {
+        ALOGE("failed to allocate memory for snd_card_name");
+        result = -1;
+        goto cleanup;
+    }
+
+    int key = 0;
+    struct listnode *node = NULL;
+    struct meta_key_list *key_info = NULL;
+
+    if (my_data->acdb_init_v3) {
+        result = my_data->acdb_init_v3(snd_card_name, cvd_version,
+                                       &my_data->acdb_meta_key_list);
+    } else if (my_data->acdb_init_v2) {
+        node = list_head(&my_data->acdb_meta_key_list);
+        key_info = node_to_item(node, struct meta_key_list, list);
+        key = key_info->cal_info.nKey;
+        result = my_data->acdb_init_v2(snd_card_name, cvd_version, key);
+    } else {
+        result = my_data->acdb_init();
+    }
+
+cleanup:
+    if (NULL != my_data) {
+        if (my_data->acdb_handle)
+            dlclose(my_data->acdb_handle);
+
+        struct listnode *node;
+        struct meta_key_list *key_info;
+        list_for_each(node, &my_data->acdb_meta_key_list) {
+            key_info = node_to_item(node, struct meta_key_list, list);
+            free(key_info);
+        }
+        free(my_data);
+    }
+
+    mixer_close(mixer);
+    free(cvd_version);
+    free(snd_card_name);
+
+    return result;
+}
+
+int acdb_set_metainfo_key(void *platform, char *name, int key) {
+
+    struct meta_key_list *key_info = (struct meta_key_list *)
+                                        calloc(1, sizeof(struct meta_key_list));
+    struct acdb_platform_data *pdata = (struct acdb_platform_data *)platform;
+    if (!key_info) {
+        ALOGE("%s: Could not allocate memory for key %d", __func__, key);
+        return -ENOMEM;
+    }
+
+    key_info->cal_info.nKey = key;
+    strlcpy(key_info->name, name, sizeof(key_info->name));
+    list_add_tail(&pdata->acdb_meta_key_list, &key_info->list);
+
+    ALOGD("%s: successfully added module %s and key %d to the list", __func__,
+               key_info->name, key_info->cal_info.nKey);
+
+    return 0;
+}
+
+int acdb_set_parameters(void *platform, struct str_parms *parms)
+{
+    struct acdb_platform_data *my_data = (struct acdb_platform_data *)platform;
+    char value[128];
+    char *kv_pairs = str_parms_to_str(parms);
+    int ret = 0;
+
+    if (kv_pairs == NULL) {
+        ret = -EINVAL;
+        ALOGE("%s: key-value pair is NULL",__func__);
+        goto done;
+    }
+
+    ret = str_parms_get_str(parms, PLATFORM_CONFIG_KEY_SOUNDCARD_NAME,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        str_parms_del(parms, PLATFORM_CONFIG_KEY_SOUNDCARD_NAME);
+        my_data->snd_card_name = strdup(value);
+        ALOGV("%s: sound card name %s", __func__, my_data->snd_card_name);
+    }
+
+done:
+    free(kv_pairs);
+
+    return ret;
+}
diff --git a/hal/acdb.h b/hal/acdb.h
new file mode 100644
index 0000000..08026fb
--- /dev/null
+++ b/hal/acdb.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ACDB_H
+#define ACDB_H
+
+#include <cutils/list.h>
+#include <linux/msm_audio_calibration.h>
+
+#define MAX_CVD_VERSION_STRING_SIZE 100
+#define LIB_ACDB_LOADER "libacdbloader.so"
+#define CVD_VERSION_MIXER_CTL "CVD Version"
+#define ACDB_METAINFO_KEY_MODULE_NAME_LEN 100
+
+/* Audio calibration related functions */
+typedef void (*acdb_deallocate_t)();
+typedef int  (*acdb_init_v3_t)(const char *, char *, struct listnode *);
+typedef int  (*acdb_init_v2_cvd_t)(char *, char *, int);
+typedef int  (*acdb_init_v2_t)(char *);
+typedef int  (*acdb_init_t)();
+typedef void (*acdb_send_audio_cal_t)(int, int);
+typedef void (*acdb_send_voice_cal_t)(int, int);
+typedef int (*acdb_reload_vocvoltable_t)(int);
+typedef int (*acdb_send_gain_dep_cal_t)(int, int, int, int, int);
+typedef int (*acdb_send_custom_top_t) (void);
+
+struct meta_key_list {
+    struct listnode list;
+    struct audio_cal_info_metainfo cal_info;
+    char name[ACDB_METAINFO_KEY_MODULE_NAME_LEN];
+};
+
+struct acdb_platform_data {
+    /* Audio calibration related functions */
+    void                       *acdb_handle;
+    acdb_init_t                acdb_init;
+    acdb_init_v2_cvd_t         acdb_init_v2;
+    acdb_init_v3_t             acdb_init_v3;
+    char *snd_card_name;
+    struct listnode acdb_meta_key_list;
+};
+
+int acdb_init(int);
+
+int acdb_set_metainfo_key(void *platform, char *name, int key);
+int acdb_set_parameters(void *platform, struct str_parms *parms);
+#endif //ACDB_H
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index ae71fe0..85a5881 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -186,4 +186,8 @@
 int audio_extn_snd_mon_unregister_listener(void *stream);
 #endif
 
+bool audio_extn_utils_resolve_config_file(char[]);
+void audio_extn_utils_get_platform_info(const char* snd_card_name,
+                                        char* platform_info_file);
+int audio_extn_utils_get_snd_card_num();
 #endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index 6e0004f..e41af96 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -26,6 +26,7 @@
 #include <cutils/log.h>
 #include <cutils/misc.h>
 
+#include "acdb.h"
 #include "audio_hw.h"
 #include "platform.h"
 #include "platform_api.h"
@@ -293,3 +294,150 @@
         platform_send_audio_calibration_v2(adev->platform, usecase, app_type, 48000);
     }
 }
+
+#define MAX_SND_CARD 8
+#define RETRY_US 500000
+#define RETRY_NUMBER 10
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+static const char *kConfigLocationList[] =
+        {"/odm/etc", "/vendor/etc", "/system/etc"};
+static const int kConfigLocationListSize =
+        (sizeof(kConfigLocationList) / sizeof(kConfigLocationList[0]));
+
+bool audio_extn_utils_resolve_config_file(char file_name[MIXER_PATH_MAX_LENGTH])
+{
+    char full_config_path[MIXER_PATH_MAX_LENGTH];
+    for (int i = 0; i < kConfigLocationListSize; i++) {
+        snprintf(full_config_path,
+                 MIXER_PATH_MAX_LENGTH,
+                 "%s/%s",
+                 kConfigLocationList[i],
+                 file_name);
+        if (F_OK == access(full_config_path, 0)) {
+            strcpy(file_name, full_config_path);
+            return true;
+        }
+    }
+    return false;
+}
+
+/* platform_info_file should be size 'MIXER_PATH_MAX_LENGTH' */
+void audio_extn_utils_get_platform_info(const char* snd_card_name, char* platform_info_file)
+{
+    if (NULL == snd_card_name) {
+        return;
+    }
+
+    struct snd_card_split *snd_split_handle = NULL;
+
+    audio_extn_set_snd_card_split(snd_card_name);
+    snd_split_handle = audio_extn_get_snd_card_split();
+
+    snprintf(platform_info_file, MIXER_PATH_MAX_LENGTH, "%s_%s_%s.xml",
+                     PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card,
+                     snd_split_handle->form_factor);
+
+    if (!audio_extn_utils_resolve_config_file(platform_info_file)) {
+        memset(platform_info_file, 0, MIXER_PATH_MAX_LENGTH);
+        snprintf(platform_info_file, MIXER_PATH_MAX_LENGTH, "%s_%s.xml",
+                     PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card);
+
+        if (!audio_extn_utils_resolve_config_file(platform_info_file)) {
+            memset(platform_info_file, 0, MIXER_PATH_MAX_LENGTH);
+            strlcpy(platform_info_file, PLATFORM_INFO_XML_PATH, MIXER_PATH_MAX_LENGTH);
+            audio_extn_utils_resolve_config_file(platform_info_file);
+        }
+    }
+}
+
+int audio_extn_utils_get_snd_card_num()
+{
+
+    void *hw_info = NULL;
+    struct mixer *mixer = NULL;
+    int retry_num = 0;
+    int snd_card_num = 0;
+    const char* snd_card_name = NULL;
+    char platform_info_file[MIXER_PATH_MAX_LENGTH]= {0};
+
+    struct acdb_platform_data *my_data = calloc(1, sizeof(struct acdb_platform_data));
+
+    bool card_verifed[MAX_SND_CARD] = {0};
+    const int retry_limit = property_get_int32("audio.snd_card.open.retries", RETRY_NUMBER);
+
+    for (;;) {
+        if (snd_card_num >= MAX_SND_CARD) {
+            if (retry_num++ >= retry_limit) {
+                ALOGE("%s: Unable to find correct sound card, aborting.", __func__);
+                snd_card_num = -1;
+                goto done;
+            }
+
+            snd_card_num = 0;
+            usleep(RETRY_US);
+            continue;
+        }
+
+        if (card_verifed[snd_card_num]) {
+            ++snd_card_num;
+            continue;
+        }
+
+        mixer = mixer_open(snd_card_num);
+
+        if (!mixer) {
+            ALOGE("%s: Unable to open the mixer card: %d", __func__,
+               snd_card_num);
+            ++snd_card_num;
+            continue;
+        }
+
+        card_verifed[snd_card_num] = true;
+
+        snd_card_name = mixer_get_name(mixer);
+        hw_info = hw_info_init(snd_card_name);
+
+        audio_extn_utils_get_platform_info(snd_card_name, platform_info_file);
+
+        /* Initialize snd card name specific ids and/or backends*/
+        snd_card_info_init(platform_info_file, my_data, &acdb_set_parameters);
+
+        /* validate the sound card name
+         * my_data->snd_card_name can contain
+         *     <a> complete sound card name, i.e. <device>-<codec>-<form_factor>-snd-card
+         *         example: msm8994-tomtom-mtp-snd-card
+         *     <b> or sub string of the card name, i.e. <device>-<codec>
+         *         example: msm8994-tomtom
+         * snd_card_name is truncated to 32 charaters as per mixer_get_name() implementation
+         * so use min of my_data->snd_card_name and snd_card_name length for comparison
+         */
+
+        if (my_data->snd_card_name != NULL &&
+                strncmp(snd_card_name, my_data->snd_card_name,
+                        min(strlen(snd_card_name), strlen(my_data->snd_card_name))) != 0) {
+            ALOGI("%s: found valid sound card %s, but not primary sound card %s",
+                   __func__, snd_card_name, my_data->snd_card_name);
+            ++snd_card_num;
+            mixer_close(mixer);
+            mixer = NULL;
+            hw_info_deinit(hw_info);
+            hw_info = NULL;
+            continue;
+        }
+
+        ALOGI("%s: found sound card %s, primary sound card expeted is %s",
+              __func__, snd_card_name, my_data->snd_card_name);
+        break;
+    }
+
+done:
+    mixer_close(mixer);
+    hw_info_deinit(hw_info);
+
+    if (my_data)
+        free(my_data);
+
+    return snd_card_num;
+}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index db54f5d..a43c3b1 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -24,6 +24,7 @@
 #include <cutils/properties.h>
 #include <audio_hw.h>
 #include <platform_api.h>
+#include "acdb.h"
 #include "platform.h"
 #include "audio_extn.h"
 #include <linux/msm_audio.h>
@@ -54,11 +55,6 @@
 /* EDID format ID for LPCM audio */
 #define EDID_FORMAT_LPCM    1
 
-/* Retry for delay in FW loading*/
-#define RETRY_NUMBER 10
-#define RETRY_US 500000
-#define MAX_SND_CARD 8
-
 #define MAX_SND_CARD_NAME_LEN 31
 
 #define DEFAULT_APP_TYPE_RX_PATH  69936
@@ -104,18 +100,8 @@
 static struct listnode *operator_specific_device_table[SND_DEVICE_MAX];
 
 /* Audio calibration related functions */
-typedef void (*acdb_deallocate_t)();
-typedef int  (*acdb_init_v2_cvd_t)(char *, char *, int);
-typedef int  (*acdb_init_v2_t)(char *);
-typedef int  (*acdb_init_t)();
-typedef void (*acdb_send_audio_cal_t)(int, int);
 typedef void (*acdb_send_audio_cal_v3_t)(int, int, int, int, int);
-typedef void (*acdb_send_voice_cal_t)(int, int);
-typedef int (*acdb_reload_vocvoltable_t)(int);
-typedef int (*acdb_send_gain_dep_cal_t)(int, int, int, int, int);
-typedef int (*acdb_send_custom_top_t) (void);
 
-/* Audio calibration related functions */
 struct platform_data {
     struct audio_device *adev;
     bool fluence_in_spkr_mode;
@@ -1137,28 +1123,6 @@
             strdup("USB_AUDIO_RX Channels");
 }
 
-// Treblized config files will be located in /odm/etc or /vendor/etc.
-static const char *kConfigLocationList[] =
-        {"/odm/etc", "/vendor/etc", "/system/etc"};
-static const int kConfigLocationListSize =
-        (sizeof(kConfigLocationList) / sizeof(kConfigLocationList[0]));
-
-bool resolveConfigFile(char file_name[MIXER_PATH_MAX_LENGTH]) {
-    char full_config_path[MIXER_PATH_MAX_LENGTH];
-    for (int i = 0; i < kConfigLocationListSize; i++) {
-        snprintf(full_config_path,
-                 MIXER_PATH_MAX_LENGTH,
-                 "%s/%s",
-                 kConfigLocationList[i],
-                 file_name);
-        if (F_OK == access(full_config_path, 0)) {
-            strcpy(file_name, full_config_path);
-            return true;
-        }
-    }
-    return false;
-}
-
 static int
 platform_backend_app_type_cfg_init(struct platform_data *pdata,
                                    struct mixer *mixer)
@@ -1227,142 +1191,83 @@
     list_init(&app_type_entry_list);
 
     set_platform_defaults(my_data);
-    bool card_verifed[MAX_SND_CARD] = {0};
-    const int retry_limit = property_get_int32("audio.snd_card.open.retries", RETRY_NUMBER);
 
-    for (;;) {
-        if (snd_card_num >= MAX_SND_CARD) {
-            if (retry_num++ >= retry_limit) {
-                ALOGE("%s: Unable to find correct sound card, aborting.", __func__);
-                goto init_failed;
-            }
+    // audio_extn_utils_get_snd_card_num does
+    // - open mixer and get snd card name
+    // - parse platform info xml file and check for valid snd card name
+    // - on failure loop through all the active snd card
 
-            snd_card_num = 0;
-            usleep(RETRY_US);
-            continue;
-        }
-
-        if (card_verifed[snd_card_num]) {
-            ++snd_card_num;
-            continue;
-        }
-
-        adev->mixer = mixer_open(snd_card_num);
-
-        if (!adev->mixer) {
-            ALOGE("%s: Unable to open the mixer card: %d", __func__,
-               snd_card_num);
-            ++snd_card_num;
-            continue;
-        }
-
-        card_verifed[snd_card_num] = true;
-
-        snd_card_name = mixer_get_name(adev->mixer);
-        my_data->hw_info = hw_info_init(snd_card_name);
-
-        audio_extn_set_snd_card_split(snd_card_name);
-        snd_split_handle = audio_extn_get_snd_card_split();
-
-        /* Get the codec internal name from the sound card and/or form factor
-         * name and form the mixer paths and platfor info file name dynamically.
-         * This is generic way of picking any codec and forma factor name based
-         * mixer and platform info files in future with no code change.
-
-         * current code extends and looks for any of the exteneded mixer path and
-         * platform info file present based on codec and form factor.
-
-         * order of picking appropriate file is
-         * <i>   mixer_paths_<codec_name>_<form_factor>.xml, if file not present
-         * <ii>  mixer_paths_<codec_name>.xml, if file not present
-         * <iii> mixer_paths.xml
-
-         * same order is followed for audio_platform_info.xml as well
-         */
-
-        // need to carryforward old file name
-        if (!strncmp(snd_card_name, TOMTOM_8226_SND_CARD_NAME,
-                     min(strlen(TOMTOM_8226_SND_CARD_NAME), strlen(snd_card_name)))) {
-            snprintf(mixer_xml_file, sizeof(mixer_xml_file), "%s_%s.xml",
-                             MIXER_XML_BASE_STRING, TOMTOM_MIXER_FILE_SUFFIX );
-        } else {
-
-            snprintf(mixer_xml_file, sizeof(mixer_xml_file), "%s_%s_%s.xml",
-                             MIXER_XML_BASE_STRING, snd_split_handle->snd_card,
-                             snd_split_handle->form_factor);
-            if (!resolveConfigFile(mixer_xml_file)) {
-                memset(mixer_xml_file, 0, sizeof(mixer_xml_file));
-                snprintf(mixer_xml_file, sizeof(mixer_xml_file), "%s_%s.xml",
-                             MIXER_XML_BASE_STRING, snd_split_handle->snd_card);
-
-                if (!resolveConfigFile(mixer_xml_file)) {
-                    memset(mixer_xml_file, 0, sizeof(mixer_xml_file));
-                    strlcpy(mixer_xml_file, MIXER_XML_DEFAULT_PATH, MIXER_PATH_MAX_LENGTH);
-                    resolveConfigFile(mixer_xml_file);
-                }
-            }
-
-            snprintf(platform_info_file, sizeof(platform_info_file), "%s_%s_%s.xml",
-                             PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card,
-                             snd_split_handle->form_factor);
-
-            if (!resolveConfigFile(platform_info_file)) {
-                memset(platform_info_file, 0, sizeof(platform_info_file));
-                snprintf(platform_info_file, sizeof(platform_info_file), "%s_%s.xml",
-                             PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card);
-
-                if (!resolveConfigFile(platform_info_file)) {
-                    memset(platform_info_file, 0, sizeof(platform_info_file));
-                    strlcpy(platform_info_file, PLATFORM_INFO_XML_PATH, MIXER_PATH_MAX_LENGTH);
-                    resolveConfigFile(platform_info_file);
-                }
-            }
-        }
-
-        /* Initialize platform specific ids and/or backends*/
-        platform_info_init(platform_info_file, my_data);
-
-        /* validate the sound card name
-         * my_data->snd_card_name can contain
-         *     <a> complete sound card name, i.e. <device>-<codec>-<form_factor>-snd-card
-         *         example: msm8994-tomtom-mtp-snd-card
-         *     <b> or sub string of the card name, i.e. <device>-<codec>
-         *         example: msm8994-tomtom
-         * snd_card_name is truncated to 32 charaters as per mixer_get_name() implementation
-         * so use min of my_data->snd_card_name and snd_card_name length for comparison
-         */
-
-        if (my_data->snd_card_name != NULL &&
-                strncmp(snd_card_name, my_data->snd_card_name,
-                        min(strlen(snd_card_name), strlen(my_data->snd_card_name))) != 0) {
-            ALOGI("%s: found valid sound card %s, but not primary sound card %s",
-                   __func__, snd_card_name, my_data->snd_card_name);
-            ++snd_card_num;
-            mixer_close(adev->mixer);
-            adev->mixer = NULL;
-            hw_info_deinit(my_data->hw_info);
-            my_data->hw_info = NULL;
-            continue;
-        }
-        ALOGI("%s: found sound card %s, primary sound card expeted is %s",
-              __func__, snd_card_name, my_data->snd_card_name);
-
-        ALOGD("%s: Loading mixer file: %s", __func__, mixer_xml_file);
-        adev->audio_route = audio_route_init(snd_card_num, mixer_xml_file);
-
-        if (!adev->audio_route) {
-            ALOGE("%s: Failed to init audio route controls, aborting.", __func__);
-            mixer_close(adev->mixer);
-            adev->mixer = NULL;
-            hw_info_deinit(my_data->hw_info);
-            my_data->hw_info = NULL;
-            goto init_failed;
-        }
-        adev->snd_card = snd_card_num;
-        ALOGD("%s: Opened sound card:%d", __func__, snd_card_num);
-        break;
+    snd_card_num = audio_extn_utils_get_snd_card_num();
+    if (-1 == snd_card_num) {
+        ALOGE("%s: invalid sound card number (-1), bailing out ", __func__);
+        goto init_failed;
     }
 
+    adev->mixer = mixer_open(snd_card_num);
+    snd_card_name = mixer_get_name(adev->mixer);
+    my_data->hw_info = hw_info_init(snd_card_name);
+
+    audio_extn_set_snd_card_split(snd_card_name);
+    snd_split_handle = audio_extn_get_snd_card_split();
+
+    /* Get the codec internal name from the sound card and/or form factor
+     * name and form the mixer paths and platfor info file name dynamically.
+     * This is generic way of picking any codec and forma factor name based
+     * mixer and platform info files in future with no code change.
+
+     * current code extends and looks for any of the exteneded mixer path and
+     * platform info file present based on codec and form factor.
+
+     * order of picking appropriate file is
+     * <i>   mixer_paths_<codec_name>_<form_factor>.xml, if file not present
+     * <ii>  mixer_paths_<codec_name>.xml, if file not present
+     * <iii> mixer_paths.xml
+
+     * same order is followed for audio_platform_info.xml as well
+     */
+
+    // need to carryforward old file name
+    if (!strncmp(snd_card_name, TOMTOM_8226_SND_CARD_NAME,
+                 min(strlen(TOMTOM_8226_SND_CARD_NAME), strlen(snd_card_name)))) {
+        snprintf(mixer_xml_file, sizeof(mixer_xml_file), "%s_%s.xml",
+                         MIXER_XML_BASE_STRING, TOMTOM_MIXER_FILE_SUFFIX );
+    } else {
+
+        snprintf(mixer_xml_file, sizeof(mixer_xml_file), "%s_%s_%s.xml",
+                         MIXER_XML_BASE_STRING, snd_split_handle->snd_card,
+                         snd_split_handle->form_factor);
+        if (!audio_extn_utils_resolve_config_file(mixer_xml_file)) {
+            memset(mixer_xml_file, 0, sizeof(mixer_xml_file));
+            snprintf(mixer_xml_file, sizeof(mixer_xml_file), "%s_%s.xml",
+                         MIXER_XML_BASE_STRING, snd_split_handle->snd_card);
+
+            if (!audio_extn_utils_resolve_config_file(mixer_xml_file)) {
+                memset(mixer_xml_file, 0, sizeof(mixer_xml_file));
+                strlcpy(mixer_xml_file, MIXER_XML_DEFAULT_PATH, MIXER_PATH_MAX_LENGTH);
+                audio_extn_utils_resolve_config_file(mixer_xml_file);
+            }
+        }
+    }
+
+    audio_extn_utils_get_platform_info(snd_card_name, platform_info_file);
+
+    /* Initialize platform specific ids and/or backends*/
+    platform_info_init(platform_info_file, my_data);
+
+    ALOGD("%s: Loading mixer file: %s", __func__, mixer_xml_file);
+    adev->audio_route = audio_route_init(snd_card_num, mixer_xml_file);
+
+    if (!adev->audio_route) {
+        ALOGE("%s: Failed to init audio route controls, aborting.", __func__);
+        mixer_close(adev->mixer);
+        adev->mixer = NULL;
+        hw_info_deinit(my_data->hw_info);
+        my_data->hw_info = NULL;
+        goto init_failed;
+    }
+    adev->snd_card = snd_card_num;
+    ALOGD("%s: Opened sound card:%d", __func__, snd_card_num);
+
     //set max volume step for voice call
     property_get("ro.config.vc_call_vol_steps", value, TOSTRING(MAX_VOL_INDEX));
     my_data->max_vol_index = atoi(value);
@@ -1476,30 +1381,30 @@
                   __func__, LIB_ACDB_LOADER);
 
 #if defined (PLATFORM_MSM8994) || (PLATFORM_MSM8996) || (PLATFORM_MSM8998)
-        acdb_init_v2_cvd_t acdb_init;
-        acdb_init = (acdb_init_v2_cvd_t)dlsym(my_data->acdb_handle,
+        acdb_init_v2_cvd_t acdb_init_local;
+        acdb_init_local = (acdb_init_v2_cvd_t)dlsym(my_data->acdb_handle,
                                               "acdb_loader_init_v2");
-        if (acdb_init == NULL)
+        if (acdb_init_local == NULL)
             ALOGE("%s: dlsym error %s for acdb_loader_init_v2", __func__,
                   dlerror());
 
 #elif defined (PLATFORM_MSM8084)
-        acdb_init_v2_t acdb_init;
-        acdb_init = (acdb_init_v2_t)dlsym(my_data->acdb_handle,
+        acdb_init_v2_t acdb_init_local;
+        acdb_init_local = (acdb_init_v2_t)dlsym(my_data->acdb_handle,
                                           "acdb_loader_init_v2");
-        if (acdb_init == NULL)
+        if (acdb_init_local == NULL)
             ALOGE("%s: dlsym error %s for acdb_loader_init_v2", __func__,
                   dlerror());
 
 #else
-        acdb_init_t acdb_init;
-        acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
+        acdb_init_t acdb_init_local;
+        acdb_init_local = (acdb_init_t)dlsym(my_data->acdb_handle,
                                                     "acdb_loader_init_ACDB");
-        if (acdb_init == NULL)
+        if (acdb_init_local == NULL)
             ALOGE("%s: dlsym error %s for acdb_loader_init_ACDB", __func__,
                   dlerror());
 #endif
-        my_data->acdb_init = acdb_init;
+        my_data->acdb_init = acdb_init_local;
 
         my_data->acdb_send_custom_top = (acdb_send_custom_top_t)
                                         dlsym(my_data->acdb_handle,
@@ -1509,7 +1414,14 @@
             ALOGE("%s: Could not find the symbol acdb_get_default_app_type from %s",
                   __func__, LIB_ACDB_LOADER);
 
-        platform_acdb_init(my_data);
+        int result = acdb_init(adev->snd_card);
+        if (!result) {
+            my_data->acdb_initialized = true;
+            ALOGD("ACDB initialized");
+        } else {
+            my_data->acdb_initialized = false;
+            ALOGD("ACDB initialization failed");
+        }
     }
 
     /* init usb */
diff --git a/hal/platform_api.h b/hal/platform_api.h
index e3bcc1a..c51c492 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -107,6 +107,9 @@
 /* From platform_info.c */
 int platform_info_init(const char *filename, void *);
 
+typedef int (*set_parameters_fn)(void *platform, struct str_parms *parms);
+int snd_card_info_init(const char *filename, void *, set_parameters_fn);
+
 int platform_get_usecase_index(const char * usecase);
 int platform_set_usecase_pcm_id(audio_usecase_t usecase, int32_t type, int32_t pcm_id);
 void platform_set_echo_reference(struct audio_device *adev, bool enable, audio_devices_t out_device);
diff --git a/hal/platform_info.c b/hal/platform_info.c
index 952fc68..c63f244 100644
--- a/hal/platform_info.c
+++ b/hal/platform_info.c
@@ -59,14 +59,17 @@
     [APP_TYPE] = process_app_type,
 };
 
+static set_parameters_fn set_parameters = &platform_set_parameters;
+
 static section_t section;
 
 struct platform_info {
+    bool              do_full_parse;
     void             *platform;
     struct str_parms *kvpairs;
 };
 
-static struct platform_info my_data;
+static struct platform_info my_data = {true, NULL, NULL};
 
 /*
  * <audio_platform_info>
@@ -305,7 +308,7 @@
     }
 
     str_parms_add_str(my_data.kvpairs, (char*)attr[1], (char*)attr[3]);
-    platform_set_parameters(my_data.platform, my_data.kvpairs);
+    set_parameters(my_data.platform, my_data.kvpairs);
 done:
     return;
 }
@@ -344,61 +347,76 @@
     const XML_Char              *attr_value = NULL;
     unsigned int                i;
 
-    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, "config_params") == 0) {
-        section = CONFIG_PARAMS;
-    } else if (strcmp(tag_name, "operator_specific") == 0) {
-        section = OPERATOR_SPECIFIC;
-    } else if (strcmp(tag_name, "gain_db_to_level_mapping") == 0) {
-        section = GAIN_LEVEL_MAPPING;
-    } else if (strcmp(tag_name, "app_types") == 0) {
-        section = APP_TYPE;
-    } else if (strcmp(tag_name, "device") == 0) {
-        if ((section != ACDB) && (section != BACKEND_NAME) && (section != OPERATOR_SPECIFIC)) {
-            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;
-        }
+    if (my_data.do_full_parse) {
+        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, "config_params") == 0) {
+            section = CONFIG_PARAMS;
+        } else if (strcmp(tag_name, "operator_specific") == 0) {
+            section = OPERATOR_SPECIFIC;
+        } else if (strcmp(tag_name, "gain_db_to_level_mapping") == 0) {
+            section = GAIN_LEVEL_MAPPING;
+        } else if (strcmp(tag_name, "app_types") == 0) {
+            section = APP_TYPE;
+        } else if (strcmp(tag_name, "device") == 0) {
+            if ((section != ACDB) && (section != BACKEND_NAME) && (section != OPERATOR_SPECIFIC)) {
+                ALOGE("device tag only supported for acdb/backend names");
+                return;
+            }
 
-        section_process_fn fn = section_table[PCM_ID];
-        fn(attr);
-    } else if (strcmp(tag_name, "param") == 0) {
-        if (section != CONFIG_PARAMS) {
-            ALOGE("param tag only supported with CONFIG_PARAMS section");
-            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[section];
-        fn(attr);
-    } else if (strcmp(tag_name, "gain_level_map") == 0) {
-        if (section != GAIN_LEVEL_MAPPING) {
-            ALOGE("usecase tag only supported with GAIN_LEVEL_MAPPING section");
-            return;
-        }
+            section_process_fn fn = section_table[PCM_ID];
+            fn(attr);
+        } else if (strcmp(tag_name, "param") == 0) {
+            if (section != CONFIG_PARAMS) {
+                ALOGE("param tag only supported with CONFIG_PARAMS section");
+                return;
+            }
 
-        section_process_fn fn = section_table[GAIN_LEVEL_MAPPING];
-        fn(attr);
-    } else if (!strcmp(tag_name, "app")) {
-        if (section != APP_TYPE) {
-            ALOGE("app tag only valid in section APP_TYPE");
-            return;
-        }
+            section_process_fn fn = section_table[section];
+            fn(attr);
+        } else if (strcmp(tag_name, "gain_level_map") == 0) {
+            if (section != GAIN_LEVEL_MAPPING) {
+                ALOGE("usecase tag only supported with GAIN_LEVEL_MAPPING section");
+                return;
+            }
 
-        section_process_fn fn = section_table[APP_TYPE];
-        fn(attr);
+            section_process_fn fn = section_table[GAIN_LEVEL_MAPPING];
+            fn(attr);
+        } else if (!strcmp(tag_name, "app")) {
+            if (section != APP_TYPE) {
+                ALOGE("app tag only valid in section APP_TYPE");
+                return;
+            }
+
+            section_process_fn fn = section_table[APP_TYPE];
+            fn(attr);
+        }
+    } else {
+        if(strcmp(tag_name, "config_params") == 0) {
+            section = CONFIG_PARAMS;
+        } else if (strcmp(tag_name, "param") == 0) {
+            if (section != CONFIG_PARAMS) {
+                ALOGE("param tag only supported with CONFIG_PARAMS section");
+                return;
+            }
+
+            section_process_fn fn = section_table[section];
+            fn(attr);
+        }
     }
 
     return;
@@ -423,6 +441,13 @@
     }
 }
 
+int snd_card_info_init(const char *filename, void *platform, set_parameters_fn fn)
+{
+    set_parameters = fn;
+    my_data.do_full_parse = false;
+    return platform_info_init(filename, platform);
+}
+
 int platform_info_init(const char *filename, void *platform)
 {
     XML_Parser      parser;
@@ -490,6 +515,9 @@
             break;
     }
 
+    set_parameters = &platform_set_parameters;
+    my_data.do_full_parse = true;
+
 err_free_parser:
     XML_ParserFree(parser);
 err_close_file: