hal: add support for automotive audio hal extension

Add support for automotive audio HAL extension to
handle automotive specific feature enablement and
interface implementation.
Move hostless setup into auto hal module.

Change-Id: I5032433263b3cacc579da6a8a40389d1f783e49c
diff --git a/hal/Android.mk b/hal/Android.mk
index 7cab96f..ee13fad 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -509,6 +509,11 @@
     LOCAL_STATIC_LIBRARIES += libprofile_rt
 endif
 
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_AUTO_HAL)),true)
+    LOCAL_CFLAGS += -DAUDIO_EXTN_AUTO_HAL_ENABLED
+    LOCAL_SRC_FILES += audio_extn/auto_hal.c
+endif
+
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_EXT_HW_PLUGIN)),true)
     LOCAL_CFLAGS += -DEXT_HW_PLUGIN_ENABLED
     LOCAL_SRC_FILES += audio_extn/ext_hw_plugin.c
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 3503fd6..d58f0ea 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -1146,6 +1146,18 @@
 
 int audio_extn_utils_get_license_params(const struct audio_device *adev,  struct audio_license_params *lic_params);
 
+#ifndef AUDIO_EXTN_AUTO_HAL_ENABLED
+#define audio_extn_auto_hal_init(adev)                (0)
+#define audio_extn_auto_hal_deinit()                  (0)
+#define audio_extn_auto_hal_enable_hostless()         (0)
+#define audio_extn_auto_hal_disable_hostless()        (0)
+#else
+int32_t audio_extn_auto_hal_init(struct audio_device *adev);
+void audio_extn_auto_hal_deinit(void);
+int32_t audio_extn_auto_hal_enable_hostless(void);
+void audio_extn_auto_hal_disable_hostless(void);
+#endif
+
 #ifndef EXT_HW_PLUGIN_ENABLED
 #define audio_extn_ext_hw_plugin_init(adev)                (0)
 #define audio_extn_ext_hw_plugin_deinit(plugin)              (0)
diff --git a/hal/audio_extn/auto_hal.c b/hal/audio_extn/auto_hal.c
new file mode 100644
index 0000000..9f88d86
--- /dev/null
+++ b/hal/audio_extn/auto_hal.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2019 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#define LOG_TAG "auto_hal_extn"
+/*#define LOG_NDEBUG 0*/
+
+#include <errno.h>
+#include <pthread.h>
+#include <cutils/log.h>
+#include <math.h>
+#include <audio_hw.h>
+#include "audio_extn.h"
+#include "platform_api.h"
+#include "platform.h"
+#include "audio_hal_plugin.h"
+
+#ifdef DYNAMIC_LOG_ENABLED
+#include <log_xml_parser.h>
+#define LOG_MASK HAL_MOD_FILE_AUTO_HAL
+#include <log_utils.h>
+#endif
+
+#ifdef AUDIO_EXTN_AUTO_HAL_ENABLED
+
+struct hostless_config {
+    struct pcm *pcm_tx;
+    struct pcm *pcm_rx;
+};
+
+typedef struct auto_hal_module {
+    struct audio_device *adev;
+    struct hostless_config hostless;
+} auto_hal_module_t;
+
+/* Auto hal module struct */
+static struct auto_hal_module *auto_hal = NULL;
+
+/* Note: Due to ADP H/W design, SoC TERT/SEC TDM CLK and FSYNC lines are
+ * both connected with CODEC and a single master is needed to provide
+ * consistent CLK and FSYNC to slaves, hence configuring SoC TERT TDM as
+ * single master and bring up a dummy hostless from TERT to SEC to ensure
+ * both slave SoC SEC TDM and CODEC are driven upon system boot. */
+int32_t audio_extn_auto_hal_enable_hostless(void)
+{
+    int32_t ret = 0;
+    char mixer_path[MIXER_PATH_MAX_LENGTH];
+
+    ALOGD("%s: Enable TERT -> SEC Hostless", __func__);
+
+    if (auto_hal == NULL) {
+        ALOGE("%s: Invalid device", __func__);
+        return -EINVAL;
+    }
+
+    strlcpy(mixer_path, "dummy-hostless", MIXER_PATH_MAX_LENGTH);
+    ALOGD("%s: apply mixer and update path: %s", __func__, mixer_path);
+    if (audio_route_apply_and_update_path(auto_hal->adev->audio_route,
+            mixer_path)) {
+        ALOGD("%s: %s not supported, continue", __func__, mixer_path);
+        return ret;
+    }
+
+    /* TERT TDM TX 7 HOSTLESS to SEC TDM RX 7 HOSTLESS */
+    int pcm_dev_rx = 48, pcm_dev_tx = 49;
+    struct pcm_config pcm_config_lb = {
+        .channels = 1,
+        .rate = 48000,
+        .period_size = 240,
+        .period_count = 2,
+        .format = PCM_FORMAT_S16_LE,
+        .start_threshold = 0,
+        .stop_threshold = INT_MAX,
+        .avail_min = 0,
+    };
+
+    auto_hal->hostless.pcm_tx = pcm_open(auto_hal->adev->snd_card,
+                                   pcm_dev_tx,
+                                   PCM_IN, &pcm_config_lb);
+    if (auto_hal->hostless.pcm_tx &&
+        !pcm_is_ready(auto_hal->hostless.pcm_tx)) {
+        ALOGE("%s: %s", __func__,
+            pcm_get_error(auto_hal->hostless.pcm_tx));
+        ret = -EIO;
+        goto error;
+    }
+    auto_hal->hostless.pcm_rx = pcm_open(auto_hal->adev->snd_card,
+                                   pcm_dev_rx,
+                                   PCM_OUT, &pcm_config_lb);
+    if (auto_hal->hostless.pcm_rx &&
+        !pcm_is_ready(auto_hal->hostless.pcm_rx)) {
+        ALOGE("%s: %s", __func__,
+            pcm_get_error(auto_hal->hostless.pcm_rx));
+        ret = -EIO;
+        goto error;
+    }
+
+    if (pcm_start(auto_hal->hostless.pcm_tx) < 0) {
+        ALOGE("%s: pcm start for pcm tx failed", __func__);
+        ret = -EIO;
+        goto error;
+    }
+    if (pcm_start(auto_hal->hostless.pcm_rx) < 0) {
+        ALOGE("%s: pcm start for pcm rx failed", __func__);
+        ret = -EIO;
+        goto error;
+    }
+    return ret;
+
+error:
+    if (auto_hal->hostless.pcm_rx)
+        pcm_close(auto_hal->hostless.pcm_rx);
+    if (auto_hal->hostless.pcm_tx)
+        pcm_close(auto_hal->hostless.pcm_tx);
+    return ret;
+}
+
+void audio_extn_auto_hal_disable_hostless(void)
+{
+    ALOGD("%s: Disable TERT -> SEC Hostless", __func__);
+
+    if (auto_hal == NULL) {
+        ALOGE("%s: Invalid device", __func__);
+        return;
+    }
+
+    if (auto_hal->hostless.pcm_tx) {
+        pcm_close(auto_hal->hostless.pcm_tx);
+        auto_hal->hostless.pcm_tx = NULL;
+    }
+    if (auto_hal->hostless.pcm_rx) {
+        pcm_close(auto_hal->hostless.pcm_rx);
+        auto_hal->hostless.pcm_rx = NULL;
+    }
+}
+
+int32_t audio_extn_auto_hal_init(struct audio_device *adev)
+{
+    int32_t ret = 0;
+
+    if (auto_hal != NULL) {
+        ALOGD("%s: Auto hal module already exists",
+                __func__);
+        return ret;
+    }
+
+    auto_hal = calloc(1, sizeof(struct auto_hal_module));
+
+    if (auto_hal == NULL) {
+        ALOGE("%s: Memory allocation failed for auto hal module",
+                __func__);
+        return -ENOMEM;
+    }
+
+    auto_hal->adev = adev;
+
+    return ret;
+}
+
+void audio_extn_auto_hal_deinit(void)
+{
+    if (auto_hal == NULL) {
+        ALOGE("%s: Auto hal module is NULL, cannot deinitialize",
+                __func__);
+        return;
+    }
+
+    free(auto_hal);
+
+    return;
+}
+#endif /* AUDIO_EXTN_AUTO_HAL_ENABLED */
diff --git a/hal/audio_extn/ext_hw_plugin.c b/hal/audio_extn/ext_hw_plugin.c
index a24f5c6..a99f71b 100644
--- a/hal/audio_extn/ext_hw_plugin.c
+++ b/hal/audio_extn/ext_hw_plugin.c
@@ -47,11 +47,6 @@
 typedef int32_t (*audio_hal_plugin_send_msg_t)(audio_hal_plugin_msg_type_t,
                                            void *, uint32_t);
 
-struct hostless_module {
-    struct pcm *pcm_tx;
-    struct pcm *pcm_rx;
-};
-
 struct ext_hw_plugin_data {
     struct audio_device           *adev;
     void                          *plugin_handle;
@@ -62,91 +57,11 @@
     snd_device_t                   out_snd_dev[AUDIO_HAL_PLUGIN_USECASE_MAX];
     snd_device_t                   in_snd_dev[AUDIO_HAL_PLUGIN_USECASE_MAX];
     bool                           mic_mute;
-    struct hostless_module         adev_hostless;
 };
 
 /* This can be defined in platform specific file or use compile flag */
 #define LIB_PLUGIN_DRIVER "libaudiohalplugin.so"
 
-/* Note: Due to ADP H/W design, SoC TERT/SEC TDM CLK and FSYNC lines are 
- * both connected with CODEC and a single master is needed to provide
- * consistent CLK and FSYNC to slaves, hence configuring SoC TERT TDM as
- * single master and bring up a dummy hostless from TERT to SEC to ensure
- * both slave SoC SEC TDM and CODEC are driven upon system boot. */
-static void audio_extn_ext_hw_plugin_enable_adev_hostless(void *plugin)
-{
-    struct ext_hw_plugin_data *my_plugin =
-        (struct ext_hw_plugin_data *)plugin;
-    char mixer_path[MIXER_PATH_MAX_LENGTH];
-
-    ALOGI("%s: Enable TERT -> SEC Hostless", __func__);
-
-    strlcpy(mixer_path, "dummy-hostless", MIXER_PATH_MAX_LENGTH);
-    ALOGD("%s: apply mixer and update path: %s", __func__, mixer_path);
-    if (audio_route_apply_and_update_path(my_plugin->adev->audio_route,
-            mixer_path)) {
-        ALOGE("%s: %s not supported, continue", __func__, mixer_path);
-        return;
-    }
-
-    /* TERT TDM TX 7 HOSTLESS to SEC TDM RX 7 HOSTLESS */
-    int pcm_dev_rx = 48, pcm_dev_tx = 49;
-    struct pcm_config pcm_config_lb = {
-        .channels = 1,
-        .rate = 48000,
-        .period_size = 240,
-        .period_count = 2,
-        .format = PCM_FORMAT_S16_LE,
-        .start_threshold = 0,
-        .stop_threshold = INT_MAX,
-        .avail_min = 0,
-    };
-
-    my_plugin->adev_hostless.pcm_tx = pcm_open(my_plugin->adev->snd_card,
-                                   pcm_dev_tx,
-                                   PCM_IN, &pcm_config_lb);
-    if (my_plugin->adev_hostless.pcm_tx &&
-        !pcm_is_ready(my_plugin->adev_hostless.pcm_tx)) {
-        ALOGE("%s: %s", __func__,
-            pcm_get_error(my_plugin->adev_hostless.pcm_tx));
-        return;
-    }
-    my_plugin->adev_hostless.pcm_rx = pcm_open(my_plugin->adev->snd_card,
-                                   pcm_dev_rx,
-                                   PCM_OUT, &pcm_config_lb);
-    if (my_plugin->adev_hostless.pcm_rx &&
-        !pcm_is_ready(my_plugin->adev_hostless.pcm_rx)) {
-        ALOGE("%s: %s", __func__,
-            pcm_get_error(my_plugin->adev_hostless.pcm_rx));
-        return;
-    }
-
-    if (pcm_start(my_plugin->adev_hostless.pcm_tx) < 0) {
-        ALOGE("%s: pcm start for pcm tx failed", __func__);
-        return;
-    }
-    if (pcm_start(my_plugin->adev_hostless.pcm_rx) < 0) {
-        ALOGE("%s: pcm start for pcm rx failed", __func__);
-        return;
-    }
-}
-
-static void audio_extn_ext_hw_plugin_disable_adev_hostless(void *plugin)
-{
-    struct ext_hw_plugin_data *my_plugin = (struct ext_hw_plugin_data *)plugin;
-
-    ALOGI("%s: Disable TERT -> SEC Hostless", __func__);
-
-    if (my_plugin->adev_hostless.pcm_tx) {
-        pcm_close(my_plugin->adev_hostless.pcm_tx);
-        my_plugin->adev_hostless.pcm_tx = NULL;
-    }
-    if (my_plugin->adev_hostless.pcm_rx) {
-        pcm_close(my_plugin->adev_hostless.pcm_rx);
-        my_plugin->adev_hostless.pcm_rx = NULL;
-    }
-}
-
 void* audio_extn_ext_hw_plugin_init(struct audio_device *adev)
 {
     int32_t ret = 0;
@@ -161,6 +76,8 @@
 
     my_plugin->adev = adev;
 
+    (void)audio_extn_auto_hal_enable_hostless();
+
     my_plugin->plugin_handle = dlopen(LIB_PLUGIN_DRIVER, RTLD_NOW);
     if (my_plugin->plugin_handle == NULL) {
         ALOGE("%s: DLOPEN failed for %s", __func__, LIB_PLUGIN_DRIVER);
@@ -199,8 +116,6 @@
         }
     }
 
-    audio_extn_ext_hw_plugin_enable_adev_hostless(my_plugin);
-
     my_plugin->mic_mute = false;
     return my_plugin;
 
@@ -221,8 +136,6 @@
         return -EINVAL;
     }
 
-    audio_extn_ext_hw_plugin_disable_adev_hostless(my_plugin);
-
     if (my_plugin->audio_hal_plugin_deinit) {
         ret = my_plugin->audio_hal_plugin_deinit();
         if (ret) {
@@ -233,6 +146,8 @@
     if(my_plugin->plugin_handle != NULL)
         dlclose(my_plugin->plugin_handle);
 
+    audio_extn_auto_hal_disable_hostless();
+
     free(my_plugin);
     return ret;
 }
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index cf7c9f5..652c2f3 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -8286,6 +8286,7 @@
         }
         if(adev->ext_hw_plugin)
             audio_extn_ext_hw_plugin_deinit(adev->ext_hw_plugin);
+        audio_extn_auto_hal_deinit();
         free(device);
         adev = NULL;
     }
@@ -8546,6 +8547,7 @@
         adev->device.close_output_stream = audio_extn_qaf_close_output_stream;
     }
 
+    audio_extn_auto_hal_init(adev);
     adev->ext_hw_plugin = audio_extn_ext_hw_plugin_init(adev);
 
     if (access(VISUALIZER_LIBRARY_PATH, R_OK) == 0) {