hal: add DSDA support on APQ targets

-This change adds DSDA support for APQ based targets
 where external modem is used for voice calls.
-Add new CSD API to support local call hold.

Change-Id: I7743a1df43dc1abac4e325ff104ec1bb64c9e12b
diff --git a/hal/Android.mk b/hal/Android.mk
index 73ae361..5f1c028 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -43,6 +43,8 @@
 
 LOCAL_SRC_FILES += audio_extn/audio_extn.c \
                    audio_extn/utils.c
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
 
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PCM_OFFLOAD)),true)
     LOCAL_CFLAGS += -DPCM_OFFLOAD_ENABLED
@@ -89,8 +91,7 @@
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_MULTI_VOICE_SESSIONS)),true)
     LOCAL_CFLAGS += -DMULTI_VOICE_SESSION_ENABLED
     LOCAL_SRC_FILES += voice_extn/voice_extn.c
-    LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
-    LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_INCALL_MUSIC)),true)
     LOCAL_CFLAGS += -DINCALL_MUSIC_ENABLED
 endif
@@ -108,8 +109,6 @@
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_SPKR_PROTECTION)),true)
     LOCAL_CFLAGS += -DSPKR_PROT_ENABLED
     LOCAL_SRC_FILES += audio_extn/spkr_protection.c
-    LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
-    LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
 endif
 
 ifdef MULTIPLE_HW_VARIANTS_ENABLED
@@ -124,8 +123,6 @@
 
 ifeq ($(strip $(DOLBY_DDP)),true)
     LOCAL_CFLAGS += -DDS1_DOLBY_DDP_ENABLED
-    LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
-    LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
     LOCAL_SRC_FILES += audio_extn/dolby.c
 endif
 
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index d10566d..bd1b235 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -628,6 +628,8 @@
 {
     snd_device_t out_snd_device = SND_DEVICE_NONE;
     snd_device_t in_snd_device = SND_DEVICE_NONE;
+    snd_device_t prev_out_snd_device = SND_DEVICE_NONE;
+    snd_device_t prev_in_snd_device = SND_DEVICE_NONE;
     struct audio_usecase *usecase = NULL;
     struct audio_usecase *vc_usecase = NULL;
     struct audio_usecase *voip_usecase = NULL;
@@ -723,7 +725,9 @@
      * and enable both RX and TX devices though one of them is same as current
      * device.
      */
-    if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) {
+    if ((usecase->type == VOICE_CALL) &&
+        (usecase->in_snd_device != SND_DEVICE_NONE) &&
+        (usecase->out_snd_device != SND_DEVICE_NONE)) {
         status = platform_switch_voice_call_device_pre(adev->platform);
     }
 
@@ -742,10 +746,13 @@
      * New device information should be sent to modem before enabling
      * the devices to reduce in-call device switch time.
      */
-    if (usecase->type == VOICE_CALL)
+    if ((usecase->type == VOICE_CALL) &&
+        (usecase->in_snd_device != SND_DEVICE_NONE) &&
+        (usecase->out_snd_device != SND_DEVICE_NONE)) {
         status = platform_switch_voice_call_enable_device_config(adev->platform,
                                                                  out_snd_device,
                                                                  in_snd_device);
+    }
 
     /* Enable new sound devices */
     if (out_snd_device != SND_DEVICE_NONE) {
@@ -764,6 +771,12 @@
                                                         out_snd_device,
                                                         in_snd_device);
 
+    /* Cache the current usecase devices. This is required to avoid
+     * sending device enable command to the external modem.
+     */
+    prev_in_snd_device = usecase->in_snd_device;
+    prev_out_snd_device = usecase->out_snd_device;
+
     usecase->in_snd_device = in_snd_device;
     usecase->out_snd_device = out_snd_device;
 
@@ -773,10 +786,13 @@
      * Enable device command should be sent to modem only after
      * enabling voice call mixer controls
      */
-    if (usecase->type == VOICE_CALL)
+    if ((usecase->type == VOICE_CALL) &&
+        (prev_in_snd_device != SND_DEVICE_NONE) &&
+        (prev_out_snd_device != SND_DEVICE_NONE)) {
         status = platform_switch_voice_call_usecase_route_post(adev->platform,
                                                                out_snd_device,
                                                                in_snd_device);
+    }
 
     ALOGD("%s: done",__func__);
 
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 6e52779..5bd37ee 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -23,6 +23,7 @@
 
 #include <stdlib.h>
 #include <dlfcn.h>
+#include <sys/ioctl.h>
 #include <cutils/log.h>
 #include <cutils/properties.h>
 #include <cutils/str_parms.h>
@@ -551,6 +552,14 @@
                   __func__, dlerror());
             goto error;
         }
+        csd->set_lch = (set_lch_t)dlsym(csd->csd_client, "csd_client_set_lch");
+        if (csd->set_lch == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_set_lch",
+                  __func__, dlerror());
+            /* Ignore the error as this is not mandatory function for
+             * basic voice call to work.
+             */
+        }
         csd->start_record = (start_record_t)dlsym(csd->csd_client,
                                              "csd_client_start_record");
         if (csd->start_record == NULL) {
@@ -1853,6 +1862,20 @@
     return ret;
 }
 
+int platform_update_lch(void *platform, struct voice_session *session,
+                        enum voice_lch_mode lch_mode)
+{
+    int ret = 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if ((my_data->csd != NULL) && (my_data->csd->set_lch != NULL))
+        ret = my_data->csd->set_lch(session->vsid, lch_mode);
+    else
+        ret = pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode);
+
+    return ret;
+}
+
 void platform_get_parameters(void *platform,
                             struct str_parms *query,
                             struct str_parms *reply)
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index f12697c..4ab5394 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -19,6 +19,7 @@
 
 #ifndef QCOM_AUDIO_PLATFORM_H
 #define QCOM_AUDIO_PLATFORM_H
+#include <sound/voice_params.h>
 
 enum {
     FLUENCE_NONE,
@@ -205,6 +206,7 @@
 typedef int (*stop_voice_t)(uint32_t);
 typedef int (*start_playback_t)(uint32_t);
 typedef int (*stop_playback_t)(uint32_t);
+typedef int (*set_lch_t)(uint32_t, enum voice_lch_mode);
 typedef int (*start_record_t)(uint32_t, int);
 typedef int (*stop_record_t)(uint32_t);
 /* CSD Client structure */
@@ -222,6 +224,7 @@
     stop_voice_t stop_voice;
     start_playback_t start_playback;
     stop_playback_t stop_playback;
+    set_lch_t set_lch;
     start_record_t start_record;
     stop_record_t stop_record;
 };
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 13f5473..fd62256 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -895,6 +895,14 @@
     return -ENOSYS;
 }
 
+int platform_update_lch(void *platform __unused,
+                        struct voice_session *session __unused,
+                        enum voice_lch_mode lch_mode __unused)
+{
+    LOGE("%s: Not implemented", __func__);
+    return -ENOSYS;
+}
+
 /* Delay in Us */
 int64_t platform_render_latency(audio_usecase_t usecase)
 {
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 52c6fec..9accd1b 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -23,6 +23,7 @@
 
 #include <stdlib.h>
 #include <dlfcn.h>
+#include <sys/ioctl.h>
 #include <cutils/log.h>
 #include <cutils/properties.h>
 #include <cutils/str_parms.h>
@@ -563,6 +564,14 @@
                   __func__, dlerror());
             goto error;
         }
+        csd->set_lch = (set_lch_t)dlsym(csd->csd_client, "csd_client_set_lch");
+        if (csd->set_lch == NULL) {
+            ALOGE("%s: dlsym error %s for csd_client_set_lch",
+                  __func__, dlerror());
+            /* Ignore the error as this is not mandatory function for
+             * basic voice call to work.
+             */
+        }
         csd->start_record = (start_record_t)dlsym(csd->csd_client,
                                              "csd_client_start_record");
         if (csd->start_record == NULL) {
@@ -2044,6 +2053,20 @@
     return ret;
 }
 
+int platform_update_lch(void *platform, struct voice_session *session,
+                        enum voice_lch_mode lch_mode)
+{
+    int ret = 0;
+    struct platform_data *my_data = (struct platform_data *)platform;
+
+    if ((my_data->csd != NULL) && (my_data->csd->set_lch != NULL))
+        ret = my_data->csd->set_lch(session->vsid, lch_mode);
+    else
+        ret = pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode);
+
+    return ret;
+}
+
 void platform_get_parameters(void *platform,
                             struct str_parms *query,
                             struct str_parms *reply)
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 956e395..19f37c7 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -19,6 +19,7 @@
 
 #ifndef QCOM_AUDIO_PLATFORM_H
 #define QCOM_AUDIO_PLATFORM_H
+#include <sound/voice_params.h>
 
 enum {
     FLUENCE_NONE,
@@ -190,13 +191,15 @@
 #define INCALL_MUSIC_UPLINK2_PCM_DEVICE 14
 #elif PLATFORM_MSM8x26
 #define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16
+#elif PLATFORM_APQ8084
+#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 34
 #else
 #define INCALL_MUSIC_UPLINK2_PCM_DEVICE 35
 #endif
 
 #define SPKR_PROT_CALIB_RX_PCM_DEVICE 5
 #ifdef PLATFORM_APQ8084
-#define SPKR_PROT_CALIB_TX_PCM_DEVICE 33
+#define SPKR_PROT_CALIB_TX_PCM_DEVICE 35
 #else
 #define SPKR_PROT_CALIB_TX_PCM_DEVICE 25
 #endif
@@ -302,6 +305,7 @@
 typedef int (*stop_voice_t)(uint32_t);
 typedef int (*start_playback_t)(uint32_t);
 typedef int (*stop_playback_t)(uint32_t);
+typedef int (*set_lch_t)(uint32_t, enum voice_lch_mode);
 typedef int (*start_record_t)(uint32_t, int);
 typedef int (*stop_record_t)(uint32_t);
 typedef int (*get_sample_rate_t)(uint32_t *);
@@ -320,6 +324,7 @@
     stop_voice_t stop_voice;
     start_playback_t start_playback;
     stop_playback_t stop_playback;
+    set_lch_t set_lch;
     start_record_t start_record;
     stop_record_t stop_record;
     get_sample_rate_t get_sample_rate;
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 66b090e..6c64073 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -19,6 +19,7 @@
 
 #ifndef AUDIO_PLATFORM_API_H
 #define AUDIO_PLATFORM_API_H
+#include <sound/voice_params.h>
 
 void *platform_init(struct audio_device *adev);
 void platform_deinit(void *platform);
@@ -63,6 +64,8 @@
 int platform_stop_incall_recording_usecase(void *platform);
 int platform_start_incall_music_usecase(void *platform);
 int platform_stop_incall_music_usecase(void *platform);
+int platform_update_lch(void *platform, struct voice_session *session,
+                        enum voice_lch_mode lch_mode);
 /* returns the latency for a usecase in Us */
 int64_t platform_render_latency(audio_usecase_t usecase);
 int platform_update_usecase_from_source(int source, audio_usecase_t usecase);
diff --git a/hal/voice_extn/voice_extn.c b/hal/voice_extn/voice_extn.c
index ea25a4b..b73eb31 100644
--- a/hal/voice_extn/voice_extn.c
+++ b/hal/voice_extn/voice_extn.c
@@ -187,11 +187,11 @@
             case CALL_LOCAL_HOLD:
                 ALOGD("%s: LOCAL_HOLD -> ACTIVE vsid:%x", __func__, session->vsid);
                 lch_mode = VOICE_LCH_STOP;
-                if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
-                    ALOGE("LOCAL_HOLD -> ACTIVE failed");
-                } else {
+                ret = platform_update_lch(adev->platform, session, lch_mode);
+                if (ret < 0)
+                    ALOGE("%s: lch mode update failed, ret = %d", __func__, ret);
+                else
                     session->state.current = session->state.new;
-                }
                 break;
 
             default:
@@ -239,11 +239,11 @@
             case CALL_LOCAL_HOLD:
                 ALOGD("%s: CALL_LOCAL_HOLD -> HOLD vsid:%x", __func__, session->vsid);
                 lch_mode = VOICE_LCH_STOP;
-                if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
-                    ALOGE("LOCAL_HOLD -> HOLD failed");
-                } else {
+                ret = platform_update_lch(adev->platform, session, lch_mode);
+                if (ret < 0)
+                    ALOGE("%s: lch mode update failed, ret = %d", __func__, ret);
+                else
                     session->state.current = session->state.new;
-                }
                 break;
 
             default:
@@ -261,11 +261,11 @@
                 ALOGD("%s: ACTIVE/CALL_HOLD -> LOCAL_HOLD vsid:%x", __func__,
                       session->vsid);
                 lch_mode = VOICE_LCH_START;
-                if (pcm_ioctl(session->pcm_tx, SNDRV_VOICE_IOCTL_LCH, &lch_mode) < 0) {
-                    ALOGE("LOCAL_HOLD -> HOLD failed");
-                } else {
+                ret = platform_update_lch(adev->platform, session, lch_mode);
+                if (ret < 0)
+                    ALOGE("%s: lch mode update failed, ret = %d", __func__, ret);
+                else
                     session->state.current = session->state.new;
-                }
                 break;
 
             default: