hal: enable form factor based configuration

- for 8996 enable form factor based mixer path configuration

Change-Id: Ib3cc1bdb2b0427c9d98cfaa9cbae21b91dc38bd2
diff --git a/hal/msm8974/hw_info.c b/hal/msm8974/hw_info.c
new file mode 100644
index 0000000..6723362
--- /dev/null
+++ b/hal/msm8974/hw_info.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2016 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 "hardware_info"
+/*#define LOG_NDEBUG 0*/
+#define LOG_NDDEBUG 0
+
+#include <stdlib.h>
+#include <cutils/log.h>
+#include "audio_hw.h"
+#include "platform.h"
+#include "audio_extn.h"
+
+struct hardware_info {
+    char name[HW_INFO_ARRAY_MAX_SIZE];
+    char type[HW_INFO_ARRAY_MAX_SIZE];
+    /* variables for handling target variants */
+    uint32_t num_snd_devices;
+    char dev_extn[HW_INFO_ARRAY_MAX_SIZE];
+    snd_device_t  *snd_devices;
+};
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+
+static const snd_device_t tasha_db_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER
+};
+
+static const snd_device_t tasha_fluid_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_AND_HDMI,
+    SND_DEVICE_OUT_SPEAKER_PROTECTED,
+    SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED,
+};
+
+static const snd_device_t tasha_liquid_variant_devices[] = {
+    SND_DEVICE_OUT_SPEAKER,
+    SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES,
+    SND_DEVICE_IN_SPEAKER_MIC,
+    SND_DEVICE_IN_HEADSET_MIC,
+    SND_DEVICE_IN_VOICE_DMIC,
+    SND_DEVICE_IN_VOICE_SPEAKER_DMIC,
+    SND_DEVICE_IN_VOICE_REC_DMIC_STEREO,
+    SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE,
+    SND_DEVICE_IN_QUAD_MIC,
+};
+
+static void  update_hardware_info_8996(struct hardware_info *hw_info)
+{
+    struct snd_card_split *tmp_handle = audio_extn_get_snd_card_split();
+    ALOGV("%s: device %s snd_card %s form_factor %s",
+               __func__, tmp_handle->device, tmp_handle->snd_card, tmp_handle->form_factor);
+
+    strlcpy(hw_info->name, tmp_handle->device, sizeof(hw_info->name));
+    snprintf(hw_info->type, sizeof(hw_info->type), " %s", tmp_handle->form_factor);
+    snprintf(hw_info->dev_extn, sizeof(hw_info->dev_extn), "-%s", tmp_handle->form_factor);
+
+    if (!strncmp(tmp_handle->form_factor, "fluid", sizeof("fluid"))) {
+        hw_info->snd_devices = (snd_device_t *)tasha_fluid_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(tasha_fluid_variant_devices);
+    } else if (!strncmp(tmp_handle->form_factor, "liquid", sizeof("liquid"))) {
+        hw_info->snd_devices = (snd_device_t *)tasha_liquid_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(tasha_liquid_variant_devices);
+    } else if (!strncmp(tmp_handle->form_factor, "db", sizeof("db"))) {
+        hw_info->snd_devices = (snd_device_t *)tasha_db_variant_devices;
+        hw_info->num_snd_devices = ARRAY_SIZE(tasha_db_variant_devices);
+    } else {
+        ALOGW("%s: %s form factor doesnt need mixer path over ride", __func__, tmp_handle->form_factor);
+    }
+
+    ALOGV("name %s type %s dev_extn %s", hw_info->name, hw_info->type, hw_info->dev_extn);
+}
+
+
+void *hw_info_init(const char *snd_card_name)
+{
+    struct hardware_info *hw_info = NULL;
+    bool hw_supported = false;
+
+    if (strstr(snd_card_name, "msm8996")) {
+        ALOGD("8996 - variant soundcard");
+        hw_supported = true;
+    } else {
+        ALOGE("%s: Unsupported target %s:",__func__, snd_card_name);
+    }
+
+    if (hw_supported) {
+        hw_info = malloc(sizeof(struct hardware_info));
+        if (!hw_info) {
+            ALOGE("failed to allocate mem for hardware info");
+            goto on_finish;
+        }
+
+        hw_info->snd_devices = NULL;
+        hw_info->num_snd_devices = 0;
+        strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
+        strlcpy(hw_info->type, "", sizeof(hw_info->type));
+        strlcpy(hw_info->name, "", sizeof(hw_info->name));
+        update_hardware_info_8996(hw_info);
+    }
+
+on_finish:
+    return hw_info;
+}
+
+void hw_info_deinit(void *hw_info)
+{
+    free(hw_info);
+}
+
+void hw_info_append_hw_type(void *hw_info, snd_device_t snd_device,
+                            char *device_name)
+{
+    struct hardware_info *my_data = (struct hardware_info*) hw_info;
+    uint32_t i = 0;
+
+    if (my_data == NULL)
+        return;
+
+    snd_device_t *snd_devices =
+            (snd_device_t *) my_data->snd_devices;
+
+    if (snd_devices != NULL) {
+        for (i = 0; i <  my_data->num_snd_devices; i++) {
+            if (snd_device == (snd_device_t)snd_devices[i]) {
+                ALOGV("extract dev_extn device %d, device_name %s extn = %s ",
+                        (snd_device_t)snd_devices[i], device_name,  my_data->dev_extn);
+                CHECK(strlcat(device_name,  my_data->dev_extn,
+                        DEVICE_NAME_MAX_SIZE) < DEVICE_NAME_MAX_SIZE);
+                break;
+            }
+        }
+    }
+    ALOGD("%s : device_name = %s", __func__,device_name);
+}
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index d0260f5..4af0c04 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -129,6 +129,8 @@
     char *snd_card_name;
     int max_vol_index;
     int max_mic_count;
+
+    void *hw_info;
 };
 
 static int pcm_device_table[AUDIO_USECASE_MAX][2] = {
@@ -932,7 +934,8 @@
     char *snd_internal_name = NULL;
     char *tmp = NULL;
     char mixer_xml_file[MIXER_PATH_MAX_LENGTH]= {0};
-
+    char platform_info_file[MIXER_PATH_MAX_LENGTH]= {0};
+    struct snd_card_split *snd_split_handle = NULL;
     my_data = calloc(1, sizeof(struct platform_data));
 
     my_data->adev = adev;
@@ -941,9 +944,6 @@
 
     set_platform_defaults(my_data);
 
-    /* Initialize platform specific ids and/or backends*/
-    platform_info_init(my_data);
-
     while (snd_card_num < MAX_SND_CARD) {
         adev->mixer = mixer_open(snd_card_num);
 
@@ -962,52 +962,89 @@
         }
 
         snd_card_name = mixer_get_name(adev->mixer);
+        my_data->hw_info = hw_info_init(snd_card_name);
 
-        /* validate the sound card name */
-        if (my_data->snd_card_name != NULL &&
-                strncmp(snd_card_name, my_data->snd_card_name, MAX_SND_CARD_NAME_LEN) != 0) {
-            ALOGI("%s: found valid sound card %s, but not primary sound card %s",
-                   __func__, snd_card_name, my_data->snd_card_name);
-            retry_num = 0;
-            snd_card_num++;
-            continue;
-        }
+        audio_extn_set_snd_card_split(snd_card_name);
+        snd_split_handle = audio_extn_get_snd_card_split();
 
-        if ((snd_internal_name = strtok_r(snd_card_name, "-", &tmp)) != NULL) {
-           /* Get the codec internal name from the sound card name
-            * and form the mixer paths file name dynamically. This
-            * is generic way of picking any codec name based mixer
-            * files in future with no code change. This code
-            * assumes mixer files are formed with format as
-            * mixer_paths_internalcodecname.xml
+        /* 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.
 
-            * If this dynamically read mixer files fails to open then it
-            * falls back to default mixer file i.e mixer_paths.xml. This is
-            * done to preserve backward compatibility but not mandatory as
-            * long as the mixer files are named as per above assumption.
-            */
+         * current code extends and looks for any of the exteneded mixer path and
+         * platform info file present based on codec and form factor.
 
-            if ((snd_internal_name = strtok_r(NULL, "-", &tmp)) != NULL) {
-                // need to carryforward old file name
-                if (!strncmp(snd_card_name, TOMTOM_8226_SND_CARD_NAME,
+         * 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,
                              sizeof(TOMTOM_8226_SND_CARD_NAME))) {
-                    snprintf(mixer_xml_file, sizeof(mixer_xml_file), "%s_%s.xml",
+            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.xml",
-                             MIXER_XML_BASE_STRING, snd_internal_name);
-                }
+        } else {
 
-                if (F_OK == access(mixer_xml_file, 0)) {
-                    use_default_mixer_path = false;
+            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 (F_OK != access(mixer_xml_file, 0)) {
+                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 (F_OK != access(mixer_xml_file, 0)) {
+                    memset(mixer_xml_file, 0, sizeof(mixer_xml_file));
+                    strlcpy(mixer_xml_file, MIXER_XML_DEFAULT_PATH, MIXER_PATH_MAX_LENGTH);
+                }
+            }
+
+            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 (F_OK != access(platform_info_file, 0)) {
+                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 (F_OK != access(platform_info_file, 0)) {
+                    memset(platform_info_file, 0, sizeof(platform_info_file));
+                    strlcpy(platform_info_file, PLATFORM_INFO_XML_PATH, MIXER_PATH_MAX_LENGTH);
                 }
             }
         }
 
-        if (use_default_mixer_path) {
-            memset(mixer_xml_file, 0, sizeof(mixer_xml_file));
-            strlcpy(mixer_xml_file, MIXER_XML_DEFAULT_PATH, MIXER_PATH_MAX_LENGTH);
+        /* 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
+         * so use length of my_data->snd_card_name for comparision
+         */
+
+        if (my_data->snd_card_name != NULL &&
+                strncmp(snd_card_name, my_data->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);
+            retry_num = 0;
+            snd_card_num++;
+            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);
@@ -1195,6 +1232,8 @@
     struct platform_data *my_data = (struct platform_data *)platform;
     close_csd_client(my_data->csd);
 
+    hw_info_deinit(my_data->hw_info);
+
     for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
         if (backend_tag_table[dev])
             free(backend_tag_table[dev]);
@@ -1239,6 +1278,29 @@
         return "none";
 }
 
+int platform_get_snd_device_name_extn(void *platform, snd_device_t snd_device,
+                                      char *device_name)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if (platform == NULL || device_name == NULL) {
+        ALOGW("%s: something wrong, use legacy get_snd_device name", __func__);
+        device_name = platform_get_snd_device_name(snd_device);
+    } else if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX) {
+        if (operator_specific_device_table[snd_device] != NULL) {
+            strlcpy(device_name, get_operator_specific_device_mixer_path(snd_device),
+                    DEVICE_NAME_MAX_SIZE);
+        } else {
+            strlcpy(device_name, device_table[snd_device], DEVICE_NAME_MAX_SIZE);
+        }
+        hw_info_append_hw_type(my_data->hw_info, snd_device, device_name);
+    } else {
+        strlcpy(device_name, "none", DEVICE_NAME_MAX_SIZE);
+    }
+
+    return 0;
+}
+
 void platform_add_backend_name(void *platform, char *mixer_path,
                                snd_device_t snd_device)
 {
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index d6c9e8e..53474f6 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -149,6 +149,9 @@
 
 };
 
+#define DEVICE_NAME_MAX_SIZE   128
+#define HW_INFO_ARRAY_MAX_SIZE 32
+
 #define DEFAULT_OUTPUT_SAMPLING_RATE 48000
 
 #define ALL_SESSION_VSID                0xFFFFFFFF
@@ -303,4 +306,6 @@
     get_sample_rate_t get_sample_rate;
 };
 
+#define PLATFORM_INFO_XML_PATH          "/system/etc/audio_platform_info.xml"
+#define PLATFORM_INFO_XML_BASE_STRING   "/system/etc/audio_platform_info"
 #endif // QCOM_AUDIO_PLATFORM_H