hal: add voice call support on apq8084
APQ8084 uses external modem to make voice calls.
APQ uses CSD QMI interface to communicate with external
modem. Add csd client apis to support voice calls
Change-Id: I11fe0cc614ee38c42e95b40d5cd5e2d8b3afd43a
diff --git a/hal/Android.mk b/hal/Android.mk
index 8bbfa69..58cf1c6 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -18,6 +18,9 @@
ifneq ($(filter msm8226,$(TARGET_BOARD_PLATFORM)),)
LOCAL_CFLAGS := -DPLATFORM_MSM8x26
endif
+ifneq ($(filter apq8084,$(TARGET_BOARD_PLATFORM)),)
+ LOCAL_CFLAGS := -DPLATFORM_APQ8084
+endif
endif
LOCAL_SRC_FILES := \
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index c9c59d7..532075c 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -71,6 +71,7 @@
int length;
};
+/* Audio calibration related functions */
typedef void (*acdb_deallocate_t)();
typedef int (*acdb_init_t)();
typedef void (*acdb_send_audio_cal_t)(int, int);
@@ -93,6 +94,7 @@
acdb_send_voice_cal_t acdb_send_voice_cal;
void *hw_info;
+ struct csd_data *csd;
};
static const int pcm_device_table[AUDIO_USECASE_MAX][2] = {
@@ -275,8 +277,133 @@
return 0;
}
+static struct csd_data *open_csd_client()
+{
+ struct csd_data *csd = calloc(1, sizeof(struct csd_data));
+
+ csd->csd_client = dlopen(LIB_CSD_CLIENT, RTLD_NOW);
+ if (csd->csd_client == NULL) {
+ ALOGE("%s: DLOPEN failed for %s", __func__, LIB_CSD_CLIENT);
+ goto error;
+ } else {
+ ALOGV("%s: DLOPEN successful for %s", __func__, LIB_CSD_CLIENT);
+
+ csd->deinit = (deinit_t)dlsym(csd->csd_client,
+ "csd_client_deinit");
+ if (csd->deinit == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_deinit", __func__,
+ dlerror());
+ goto error;
+ }
+ csd->disable_device = (disable_device_t)dlsym(csd->csd_client,
+ "csd_client_disable_device");
+ if (csd->disable_device == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_disable_device",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->enable_device = (enable_device_t)dlsym(csd->csd_client,
+ "csd_client_enable_device");
+ if (csd->enable_device == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_enable_device",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->start_voice = (start_voice_t)dlsym(csd->csd_client,
+ "csd_client_start_voice");
+ if (csd->start_voice == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_start_voice",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->stop_voice = (stop_voice_t)dlsym(csd->csd_client,
+ "csd_client_stop_voice");
+ if (csd->stop_voice == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_stop_voice",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->volume = (volume_t)dlsym(csd->csd_client,
+ "csd_client_volume");
+ if (csd->volume == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_volume",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->mic_mute = (mic_mute_t)dlsym(csd->csd_client,
+ "csd_client_mic_mute");
+ if (csd->mic_mute == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_mic_mute",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->slow_talk = (slow_talk_t)dlsym(csd->csd_client,
+ "csd_client_slow_talk");
+ if (csd->slow_talk == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_slow_talk",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->start_playback = (start_playback_t)dlsym(csd->csd_client,
+ "csd_client_start_playback");
+ if (csd->start_playback == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_start_playback",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->stop_playback = (stop_playback_t)dlsym(csd->csd_client,
+ "csd_client_stop_playback");
+ if (csd->stop_playback == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_stop_playback",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->start_record = (start_record_t)dlsym(csd->csd_client,
+ "csd_client_start_record");
+ if (csd->start_record == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_start_record",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->stop_record = (stop_record_t)dlsym(csd->csd_client,
+ "csd_client_stop_record");
+ if (csd->stop_record == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_stop_record",
+ __func__, dlerror());
+ goto error;
+ }
+ csd->init = (init_t)dlsym(csd->csd_client, "csd_client_init");
+
+ if (csd->init == NULL) {
+ ALOGE("%s: dlsym error %s for csd_client_init",
+ __func__, dlerror());
+ goto error;
+ } else {
+ csd->init();
+ }
+ }
+ return csd;
+
+error:
+ free(csd);
+ csd = NULL;
+ return csd;
+}
+
+void close_csd_client(struct csd_data *csd)
+{
+ if (csd != NULL) {
+ csd->deinit();
+ dlclose(csd->csd_client);
+ free(csd);
+ csd = NULL;
+ }
+}
+
void *platform_init(struct audio_device *adev)
{
+ char platform[PROPERTY_VALUE_MAX];
+ char baseband[PROPERTY_VALUE_MAX];
char value[PROPERTY_VALUE_MAX];
struct platform_data *my_data;
int retry_num = 0;
@@ -373,6 +500,17 @@
my_data->acdb_init();
}
+ /* If platform is apq8084 and baseband is MDM, load CSD Client specific
+ * symbols. Voice call is handled by MDM and apps processor talks to
+ * MDM through CSD Client
+ */
+ property_get("ro.board.platform", platform, "");
+ property_get("ro.baseband", baseband, "");
+ if (!strncmp("apq8084", platform, sizeof("apq8084")) &&
+ !strncmp("mdm", baseband, sizeof("mdm"))) {
+ my_data->csd = open_csd_client();
+ }
+
/* init usb */
audio_extn_usb_init(adev);
@@ -387,6 +525,8 @@
struct platform_data *my_data = (struct platform_data *)platform;
hw_info_deinit(my_data->hw_info);
+ close_csd_client(my_data->csd);
+
free(platform);
/* deinit usb */
audio_extn_usb_deinit();
@@ -481,7 +621,18 @@
int platform_switch_voice_call_device_pre(void *platform)
{
- return 0;
+ struct platform_data *my_data = (struct platform_data *)platform;
+ int ret = 0;
+
+ if (my_data->csd != NULL) {
+ /* This must be called before disabling mixer controls on APQ side */
+ ret = my_data->csd->disable_device();
+ if (ret < 0) {
+ ALOGE("%s: csd_client_disable_device, failed, error %d",
+ __func__, ret);
+ }
+ }
+ return ret;
}
int platform_switch_voice_call_device_post(void *platform,
@@ -490,13 +641,14 @@
{
struct platform_data *my_data = (struct platform_data *)platform;
int acdb_rx_id, acdb_tx_id;
+ int ret = 0;
+
+ acdb_rx_id = acdb_device_table[out_snd_device];
+ acdb_tx_id = acdb_device_table[in_snd_device];
if (my_data->acdb_send_voice_cal == NULL) {
ALOGE("%s: dlsym error for acdb_send_voice_call", __func__);
} else {
- acdb_rx_id = acdb_device_table[out_snd_device];
- acdb_tx_id = acdb_device_table[in_snd_device];
-
if (acdb_rx_id > 0 && acdb_tx_id > 0)
my_data->acdb_send_voice_cal(acdb_rx_id, acdb_tx_id);
else
@@ -504,17 +656,48 @@
acdb_rx_id, acdb_tx_id);
}
- return 0;
+ if (my_data->csd != NULL) {
+ if (acdb_rx_id > 0 || acdb_tx_id > 0) {
+ ret = my_data->csd->enable_device(acdb_rx_id, acdb_tx_id,
+ my_data->adev->acdb_settings);
+ if (ret < 0) {
+ ALOGE("%s: csd_enable_device, failed, error %d",
+ __func__, ret);
+ }
+ } else {
+ ALOGE("%s: Incorrect ACDB IDs (rx: %d tx: %d)", __func__,
+ acdb_rx_id, acdb_tx_id);
+ }
+ }
+ return ret;
}
-int platform_start_voice_call(void *platform)
+int platform_start_voice_call(void *platform, uint32_t vsid)
{
- return 0;
+ struct platform_data *my_data = (struct platform_data *)platform;
+ int ret = 0;
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->start_voice(vsid);
+ if (ret < 0) {
+ ALOGE("%s: csd_start_voice error %d\n", __func__, ret);
+ }
+ }
+ return ret;
}
-int platform_stop_voice_call(void *platform)
+int platform_stop_voice_call(void *platform, uint32_t vsid)
{
- return 0;
+ struct platform_data *my_data = (struct platform_data *)platform;
+ int ret = 0;
+
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->stop_voice(vsid);
+ if (ret < 0) {
+ ALOGE("%s: csd_stop_voice error %d\n", __func__, ret);
+ }
+ }
+ return ret;
}
int platform_set_voice_volume(void *platform, int volume)
@@ -523,7 +706,7 @@
struct audio_device *adev = my_data->adev;
struct mixer_ctl *ctl;
const char *mixer_ctl_name = "Voice Rx Gain";
- int vol_index = 0;
+ int vol_index = 0, ret = 0;
uint32_t set_values[ ] = {0,
ALL_SESSION_VSID,
DEFAULT_VOLUME_RAMP_DURATION_MS};
@@ -543,7 +726,13 @@
ALOGV("Setting voice volume index: %d", set_values[0]);
mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
- return 0;
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->volume(ALL_SESSION_VSID, volume);
+ if (ret < 0) {
+ ALOGE("%s: csd_volume error %d", __func__, ret);
+ }
+ }
+ return ret;
}
int platform_set_mic_mute(void *platform, bool state)
@@ -552,6 +741,7 @@
struct audio_device *adev = my_data->adev;
struct mixer_ctl *ctl;
const char *mixer_ctl_name = "Voice Tx Mute";
+ int ret = 0;
uint32_t set_values[ ] = {0,
ALL_SESSION_VSID,
DEFAULT_VOLUME_RAMP_DURATION_MS};
@@ -566,9 +756,15 @@
}
ALOGV("Setting voice mute state: %d", state);
mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
- }
- return 0;
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->mic_mute(ALL_SESSION_VSID, state);
+ if (ret < 0) {
+ ALOGE("%s: csd_mic_mute error %d", __func__, ret);
+ }
+ }
+ }
+ return ret;
}
snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices)
@@ -1017,6 +1213,13 @@
my_data->slowtalk = state;
}
+ if (my_data->csd != NULL) {
+ ret = my_data->csd->slow_talk(ALL_SESSION_VSID, state);
+ if (ret < 0) {
+ ALOGE("%s: csd_client_disable_device, failed, error %d",
+ __func__, ret);
+ }
+ }
return ret;
}
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 795c9f9..4cff959 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -148,27 +148,18 @@
#define AUDIO_CAPTURE_PERIOD_DURATION_MSEC 20
#define AUDIO_CAPTURE_PERIOD_COUNT 2
+#define DEVICE_NAME_MAX_SIZE 128
+#define HW_INFO_ARRAY_MAX_SIZE 32
+
#define DEEP_BUFFER_PCM_DEVICE 0
#define AUDIO_RECORD_PCM_DEVICE 0
#define MULTIMEDIA2_PCM_DEVICE 1
-#define VOICE_CALL_PCM_DEVICE 2
#define FM_PLAYBACK_PCM_DEVICE 5
#define FM_CAPTURE_PCM_DEVICE 6
#define INCALL_MUSIC_UPLINK_PCM_DEVICE 1
#define INCALL_MUSIC_UPLINK2_PCM_DEVICE 16
#define SPKR_PROT_CALIB_RX_PCM_DEVICE 5
#define SPKR_PROT_CALIB_TX_PCM_DEVICE 22
-
-#ifdef PLATFORM_MSM8x26
-#define VOICE2_CALL_PCM_DEVICE 14
-#define VOLTE_CALL_PCM_DEVICE 17
-#define QCHAT_CALL_PCM_DEVICE 18
-#else
-#define VOICE2_CALL_PCM_DEVICE 13
-#define VOLTE_CALL_PCM_DEVICE 14
-#define QCHAT_CALL_PCM_DEVICE 20
-#endif
-
#define PLAYBACK_OFFLOAD_DEVICE 9
#ifdef PLATFORM_MSM8610
@@ -177,6 +168,54 @@
#define LOWLATENCY_PCM_DEVICE 15
#endif
-#define DEVICE_NAME_MAX_SIZE 128
-#define HW_INFO_ARRAY_MAX_SIZE 32
+#ifdef PLATFORM_MSM8x26
+#define VOICE_CALL_PCM_DEVICE 2
+#define VOICE2_CALL_PCM_DEVICE 14
+#define VOLTE_CALL_PCM_DEVICE 17
+#define QCHAT_CALL_PCM_DEVICE 18
+#elif PLATFORM_APQ8084
+#define VOICE_CALL_PCM_DEVICE 20
+#define VOICE2_CALL_PCM_DEVICE 13
+#define VOLTE_CALL_PCM_DEVICE 21
+#define QCHAT_CALL_PCM_DEVICE 06
+#else
+#define VOICE_CALL_PCM_DEVICE 2
+#define VOICE2_CALL_PCM_DEVICE 13
+#define VOLTE_CALL_PCM_DEVICE 14
+#define QCHAT_CALL_PCM_DEVICE 20
+#endif
+
+#define LIB_CSD_CLIENT "libcsd-client.so"
+/* CSD-CLIENT related functions */
+typedef int (*init_t)();
+typedef int (*deinit_t)();
+typedef int (*disable_device_t)();
+typedef int (*enable_device_t)(int, int, uint32_t);
+typedef int (*volume_t)(uint32_t, int);
+typedef int (*mic_mute_t)(uint32_t, int);
+typedef int (*slow_talk_t)(uint32_t, uint8_t);
+typedef int (*start_voice_t)(uint32_t);
+typedef int (*stop_voice_t)(uint32_t);
+typedef int (*start_playback_t)(uint32_t);
+typedef int (*stop_playback_t)(uint32_t);
+typedef int (*start_record_t)(uint32_t, int);
+typedef int (*stop_record_t)(uint32_t, int);
+/* CSD Client structure */
+struct csd_data {
+ void *csd_client;
+ init_t init;
+ deinit_t deinit;
+ disable_device_t disable_device;
+ enable_device_t enable_device;
+ volume_t volume;
+ mic_mute_t mic_mute;
+ slow_talk_t slow_talk;
+ start_voice_t start_voice;
+ stop_voice_t stop_voice;
+ start_playback_t start_playback;
+ stop_playback_t stop_playback;
+ start_record_t start_record;
+ stop_record_t stop_record;
+};
+
#endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 856444d..b9919ae 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -32,8 +32,8 @@
int platform_switch_voice_call_device_post(void *platform,
snd_device_t out_snd_device,
snd_device_t in_snd_device);
-int platform_start_voice_call(void *platform);
-int platform_stop_voice_call(void *platform);
+int platform_start_voice_call(void *platform, uint32_t vsid);
+int platform_stop_voice_call(void *platform, uint32_t vsid);
int platform_set_voice_volume(void *platform, int volume);
int platform_set_mic_mute(void *platform, bool state);
snd_device_t platform_get_output_snd_device(void *platform, audio_devices_t devices);
diff --git a/hal/voice.c b/hal/voice.c
index 907ebc9..90b7a7e 100644
--- a/hal/voice.c
+++ b/hal/voice.c
@@ -81,7 +81,7 @@
session = (struct voice_session *)voice_get_session_from_use_case(adev, usecase_id);
session->state.current = CALL_INACTIVE;
- ret = platform_stop_voice_call(adev->platform);
+ ret = platform_stop_voice_call(adev->platform, session->vsid);
/* 1. Close the PCM devices */
if (session->pcm_rx) {
@@ -179,7 +179,7 @@
voice_set_volume(adev, adev->voice.volume);
- ret = platform_start_voice_call(adev->platform);
+ ret = platform_start_voice_call(adev->platform, session->vsid);
if (ret < 0) {
ALOGE("%s: platform_start_voice_call error %d\n", __func__, ret);
goto error_start_voice;