st-hal : Add mixer based listen module interaction

Add mixer control support for configuring Listen Sound Model.
With this, we could use mixer controls, instead of IOCTL.
This also handles the 32bit-64bit complexity.

Change-Id: Iea81278201fc1da8e6e887dd32202790bd558924
diff --git a/Android.mk b/Android.mk
index 0fda1b1..d7c6632 100644
--- a/Android.mk
+++ b/Android.mk
@@ -17,6 +17,10 @@
 
 LOCAL_CFLAGS += -Wall -Werror
 
+ifeq ($(ENABLE_AUDIO_LEGACY_TECHPACK), true)
+  LOCAL_CFLAGS += -DENABLE_SVA_MIXER_CTL
+endif
+
 LOCAL_SRC_FILES := \
     sound_trigger_hw.c \
     sound_trigger_platform.c \
diff --git a/st_hw_session_lsm.c b/st_hw_session_lsm.c
index a5de07e..ba8154a 100644
--- a/st_hw_session_lsm.c
+++ b/st_hw_session_lsm.c
@@ -3,7 +3,7 @@
  * This file implements the hw session functionality specific to LSM HW
  *
  * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -58,6 +58,7 @@
 #include "sound_trigger_hw.h"
 #include "st_hw_common.h"
 
+#define LSM_LUT_CLEAR_INFO  _IOW('U', 0xF0, int)
 #define XSTR(x) STR(x)
 #define STR(x) #x
 
@@ -115,6 +116,14 @@
     int8_t polarActivityGUI[DOA_POLAR_ACTIVITY_INDICATORS];
 } st_ffv_doa_tracking_monitor_t;
 
+#ifdef ENABLE_SVA_MIXER_CTL
+struct st_lsm_cdev_info
+{
+    int fd;
+    int det_status;
+};
+#endif
+
 static struct pcm_config stdev_ape_pcm_config = {
     .channels = SOUND_TRIGGER_CHANNEL_MODE_MONO,
     .rate = SOUND_TRIGGER_SAMPLING_RATE_16000,
@@ -165,6 +174,26 @@
 typedef struct lsm_params_info_v2 lsm_param_info_t;
 typedef struct lsm_param_payload_v2 lsm_param_payload_t;
 
+#ifdef ENABLE_SVA_MIXER_CTL
+int lsm_set_session_data(struct mixer * st_mixer, void *ses_data)
+{
+    struct mixer_ctl *ctl = NULL;
+    const char *mixer_ctl_name = "LSM SESSION_DATA SET";
+
+    ctl = mixer_get_ctl_by_name(st_mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                __func__, mixer_ctl_name);
+    }
+
+    if (mixer_ctl_set_array(ctl, ses_data, sizeof(struct snd_lsm_session_data_v2)) < 0) {
+        ALOGE("%s: Could not set LSM load mixer control", __func__);
+    }
+
+    return 0;
+}
+#endif
+
 static int lsm_set_session_data_v2(st_hw_session_t *p_ses)
 {
     st_hw_session_lsm_t *p_lsm_ses = (st_hw_session_lsm_t*)p_ses;
@@ -194,7 +223,11 @@
     }
 
     ATRACE_BEGIN("sthal:lsm: pcm_ioctl sndrv_lsm_set_session_data_v2");
+#ifdef ENABLE_SVA_MIXER_CTL
+    status = lsm_set_session_data(p_ses->stdev->mixer, (void *)(&ses_data));
+#else
     status = pcm_ioctl(p_lsm_ses->pcm, SNDRV_LSM_SET_SESSION_DATA_V2, &ses_data);
+#endif
     ATRACE_END();
     if (status)
             ALOGE("%s: ERROR. SNDRV_LSM_SET_SESSION_DATA_V2 failed status(%d)",
@@ -252,6 +285,33 @@
     p_info->stage_idx = stage_idx;
 }
 
+#ifdef ENABLE_SVA_MIXER_CTL
+static int lsm_mixer_set_module_params
+(
+    st_hw_session_lsm_t *p_lsm_ses,
+    struct snd_lsm_module_params *lsm_params
+)
+{
+    const char *mixer_ctl_name = "LSM MODULE_PARAMS SET";
+    struct mixer_ctl *ctl = NULL;
+    st_hw_session_t p_ses = p_lsm_ses->common;
+    int ret = 0;
+
+    ctl = mixer_get_ctl_by_name(p_ses.stdev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                __func__, mixer_ctl_name);
+    }
+
+    ret = mixer_ctl_set_array(ctl, lsm_params, sizeof(struct snd_lsm_module_params));
+    if (ret < 0) {
+        ALOGE("%s: Could not set LSM set module params, ret = %d", __func__, ret);
+    }
+
+    return ret;
+}
+#endif
+
 static int lsm_set_module_params
 (
     st_hw_session_lsm_t *p_lsm_ses,
@@ -266,7 +326,11 @@
     }
 
     ATRACE_BEGIN("sthal:lsm: pcm_ioctl sndrv_lsm_set_module_params_v2");
+#ifdef ENABLE_SVA_MIXER_CTL
+    status = lsm_mixer_set_module_params(p_lsm_ses, lsm_params);
+#else
     status = pcm_ioctl(p_lsm_ses->pcm, SNDRV_LSM_SET_MODULE_PARAMS_V2, lsm_params);
+#endif
     ATRACE_END();
 
     if (status)
@@ -357,17 +421,46 @@
 #endif
 
 #ifdef LSM_EVENT_TIMESTAMP_MODE_SUPPORT
+
+#ifdef ENABLE_SVA_MIXER_CTL
+int lsm_set_fwk_mode_mixer_ctl(struct mixer * st_mixer, int buf_en)
+{
+    int ret = 0;
+    struct mixer_ctl *ctl = NULL;
+    const char *mixer_ctl_name = "LSM FWK_MODE SET";
+
+    ctl = mixer_get_ctl_by_name(st_mixer, mixer_ctl_name);
+     if (!ctl) {
+          ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                  __func__, mixer_ctl_name);
+     }
+
+    ret = mixer_ctl_set_value(ctl, 0, buf_en);
+    if (ret < 0) {
+         ALOGE("%s: Could not set LSM load mixer control", __func__);
+    }
+
+    return ret;
+}
+#endif
+
 static int set_lsm_fwk_mode(st_hw_session_lsm_t *p_lsm_ses)
 {
     int status;
     struct st_vendor_info *v_info = p_lsm_ses->common.vendor_uuid_info;
     unsigned int fwk_mode = LSM_EVENT_NON_TIME_STAMP_MODE;
+    st_hw_session_t p_ses;
 
     if (v_info && (v_info->fwk_mode == SOUND_TRIGGER_EVENT_TIME_STAMP_MODE))
         fwk_mode = LSM_EVENT_TIME_STAMP_MODE;
 
+    p_ses = p_lsm_ses->common;
+#ifdef ENABLE_SVA_MIXER_CTL
+    status = lsm_set_fwk_mode_mixer_ctl(p_ses.stdev->mixer, fwk_mode);
+#else
     status = pcm_ioctl(p_lsm_ses->pcm, SNDRV_LSM_SET_FWK_MODE_CONFIG,
                        &fwk_mode);
+#endif
     if (status)
         ALOGE("%s: SNDRV_LSM_SET_FWK_MODE_CONFIG status=%d", __func__, status);
 
@@ -431,9 +524,31 @@
 #endif
 
 #ifdef LSM_POLLING_ENABLE_SUPPORT
+
+#ifdef ENABLE_SVA_MIXER_CTL
+int lsm_set_port_mixer_ctl(struct mixer * st_mixer)
+{
+    int ret = 0;
+    struct mixer_ctl *ctl = NULL;
+    const char *mixer_ctl_name = "LSM PORT SET";
+
+    ctl = mixer_get_ctl_by_name(st_mixer, mixer_ctl_name);
+     if (!ctl) {
+          ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                  __func__, mixer_ctl_name);
+     }
+    ret = mixer_ctl_set_value(ctl, 0, 0);
+    if (ret < 0) {
+         ALOGE("%s: Could not set LSM load mixer control", __func__);
+    }
+    return ret;
+}
+#endif
+
 static int lsm_set_port(st_hw_session_lsm_t *p_lsm_ses)
 {
     int status = 0;
+    st_hw_session_t p_ses;
 
     if (p_lsm_ses->common.stdev->lpi_enable &&
         p_lsm_ses->common.vendor_uuid_info->lab_dam_cfg_payload.token_id) {
@@ -443,8 +558,12 @@
         if (status)
             return status;
     }
-
+    p_ses = p_lsm_ses->common;
+#ifdef ENABLE_SVA_MIXER_CTL
+    status = lsm_set_port_mixer_ctl(p_ses.stdev->mixer);
+#else
     status = pcm_ioctl(p_lsm_ses->pcm, SNDRV_LSM_SET_PORT);
+#endif
     if (status)
         ALOGE("%s: ERROR. SNDRV_LSM_SET_PORT, status=%d", __func__, status);
     return status;
@@ -487,6 +606,27 @@
 #endif
 
 #if (SNDRV_LSM_VERSION >= SNDRV_PROTOCOL_VERSION(0, 3, 0))
+
+#ifdef ENABLE_SVA_MIXER_CTL
+int lsm_set_input_hw_params_mixer_ctl(struct mixer * st_mixer, struct snd_lsm_input_hw_params *params)
+{
+    int ret = 0;
+    struct mixer_ctl *ctl = NULL;
+    const char *mixer_ctl_name = "LSM INPUT_HW_PARAMS SET";
+
+    ctl = mixer_get_ctl_by_name(st_mixer, mixer_ctl_name);
+     if (!ctl) {
+          ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                  __func__, mixer_ctl_name);
+     }
+    ret = mixer_ctl_set_array(ctl, params, sizeof(struct snd_lsm_input_hw_params));
+    if (ret < 0) {
+         ALOGE("%s: Could not set input hw params control", __func__);
+    }
+    return ret;
+}
+#endif
+
 static int send_lsm_input_hw_params(st_hw_session_t *p_ses)
 {
     struct st_vendor_info *v_info = p_ses->vendor_uuid_info;
@@ -504,8 +644,12 @@
     ALOGV("%s: set SNDRV_LSM_SET_INPUT_HW_PARAMS sr=%d bw=%d ch=%d ", __func__,
           params.sample_rate, params.bit_width, params.num_channels);
 
+#ifdef ENABLE_SVA_MIXER_CTL
+    status = lsm_set_input_hw_params_mixer_ctl(p_ses->stdev->mixer, &params);
+#else
     status = pcm_ioctl(p_lsm_ses->pcm, SNDRV_LSM_SET_INPUT_HW_PARAMS,
                        &params);
+#endif
     if (status) {
         ALOGE("%s: SNDRV_LSM_SET_INPUT_HW_PARAMS failed, status [%d] - %s",
               __func__, status, strerror(errno));
@@ -1108,6 +1252,28 @@
     return NULL;
 }
 
+#ifdef ENABLE_SVA_MIXER_CTL
+int lsm_get_det_event_info_control(struct mixer * st_mixer, void *arg)
+{
+    struct mixer_ctl *ctl = NULL;
+    const char *mixer_ctl_name = "LSM DET_EVENT_INFO GET";
+
+    struct snd_lsm_event_status *params = (struct snd_lsm_event_status *)arg;
+
+    ctl = mixer_get_ctl_by_name(st_mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                __func__, mixer_ctl_name);
+    }
+
+    if (mixer_ctl_get_array(ctl, params, params->payload_size + sizeof(*params)) < 0) {
+        ALOGE("%s: Could not get det event info", __func__);
+        return -EFAULT;
+    }
+
+    return 0;
+}
+#endif
 
 static void *callback_thread_loop(void *context)
 {
@@ -1117,9 +1283,27 @@
     char *st_lsm_event_cmd = NULL;
     unsigned int payload_alloc_size = SOUND_TRIGGER_MAX_EVNT_PAYLOAD_SIZE;
     int status = 0;
+    void *params_status = NULL;
     int event_status, request;
     st_hw_sess_event_t hw_sess_event; /* used to report event to st_session */
 
+#ifdef ENABLE_SVA_MIXER_CTL
+    struct mixer * st_mixer = NULL;
+    st_mixer = p_lsm_ses->common.stdev->mixer;
+    int lsm_cdev = 0;
+    struct st_lsm_cdev_info *cdev_query = NULL;
+
+    lsm_cdev = open("/dev/msm_lsm_cdev", O_RDONLY|O_WRONLY);
+    if (lsm_cdev < 0)
+        ALOGE("LSM CDEV open failed");
+
+    cdev_query =  calloc(1, sizeof(*cdev_query));
+    if (cdev_query == NULL) {
+        ALOGE("%s: ERROR. insufficient memory for cdev query", __func__);
+        goto exit;
+    }
+#endif
+
     if (p_lsm_ses == NULL) {
         ALOGE("%s: ERROR. null context.. exiting", __func__);
         return NULL;
@@ -1138,16 +1322,25 @@
 
     set_lsm_fwk_mode(p_lsm_ses);
     update_lsm_event_status_info(p_lsm_ses, &request, &st_lsm_event_cmd);
+    params_status = (void *)(&(params->status));
 
     while (!p_lsm_ses->exit_callback_thread) {
         params->payload_size = payload_alloc_size;
         ALOGI("%s:[%d] Waiting for %s",
                __func__, p_lsm_ses->common.sm_handle, st_lsm_event_cmd);
         pthread_mutex_unlock(&p_lsm_ses->callback_thread_lock);
+#ifdef ENABLE_SVA_MIXER_CTL
+        cdev_query->fd = p_lsm_ses->pcm_id;
+        status = ioctl(lsm_cdev, SNDRV_LSM_GENERIC_DET_EVENT, cdev_query);
+
+        if (cdev_query->det_status == LSM_VOICE_WAKEUP_STATUS_DETECTED)
+            status = lsm_get_det_event_info_control(st_mixer, params_status);
+#else
         if (p_lsm_ses->common.is_generic_event)
             status = pcm_ioctl(p_lsm_ses->pcm, request, &params->status);
         else
             status = pcm_ioctl(p_lsm_ses->pcm, request, params);
+#endif
         pthread_mutex_lock(&p_lsm_ses->callback_thread_lock);
 
         ALOGI("%s:[%d] Received %s status=%d",
@@ -1261,6 +1454,12 @@
         pthread_mutex_lock(&p_lsm_ses->callback_thread_lock);
     }
 
+#ifdef ENABLE_SVA_MIXER_CTL
+    //Before exiting the thread, intimate lut to clear the info.
+    status = ioctl(lsm_cdev, LSM_LUT_CLEAR_INFO, p_lsm_ses->pcm_id);
+    free(cdev_query);
+    close(lsm_cdev);
+#endif
     if (st_lsm_event_cmd)
         free(st_lsm_event_cmd);
 
@@ -1688,7 +1887,11 @@
            opens DSP LSM session with this ioctl cmd */
         ses_data.app_id = LSM_VOICE_WAKEUP_APP_ID_V2;
         ATRACE_BEGIN("sthal:lsm: pcm_ioctl sndrv_lsm_set_session_data");
+#ifdef ENABLE_SVA_MIXER_CTL
+    status = lsm_set_session_data(p_ses->stdev->mixer, (void *)(&ses_data));
+#else
         status = pcm_ioctl(p_lsm_ses->pcm, SNDRV_LSM_SET_SESSION_DATA, &ses_data);
+#endif
         ATRACE_END();
         if (status) {
             ALOGE("%s: ERROR. SNDRV_LSM_SET_SESSION_DATA failed status %d",
@@ -1828,6 +2031,24 @@
     return status;
 }
 
+#ifdef ENABLE_SVA_MIXER_CTL
+int lsm_send_lab_control_mixer_ctl(struct mixer * st_mixer, int buf_en)
+{
+    const char *mixer_ctl_name = "LSM LAB_CONTROL SET";
+    struct mixer_ctl *ctl = NULL;
+    ctl = mixer_get_ctl_by_name(st_mixer, mixer_ctl_name);
+     if (!ctl) {
+          ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                  __func__, mixer_ctl_name);
+     }
+    if (mixer_ctl_set_value(ctl, 0, buf_en) < 0) {
+         ALOGE("%s: Could not set LSM load mixer control", __func__);
+         return -EFAULT;
+    }
+    return 0;
+}
+#endif
+
 static int ape_dereg_sm(st_hw_session_t *p_ses, uint32_t model_id)
 {
     int status = 0, buf_en = 0;
@@ -1918,7 +2139,11 @@
             if ((p_lsm_ses->num_stages == 1) &&
                 !(p_lsm_ses->lsm_usecase.param_tag_tracker & PARAM_LAB_CONTROL_BIT)) {
                 ATRACE_BEGIN("sthal:lsm: pcm_ioctl sndrv_lsm_lab_control");
+#ifdef ENABLE_SVA_MIXER_CTL
+        status = lsm_send_lab_control_mixer_ctl(p_ses->stdev->mixer, buf_en);
+#else
                 status = pcm_ioctl(p_lsm_ses->pcm, SNDRV_LSM_LAB_CONTROL, &buf_en);
+#endif
                 ATRACE_END();
                 if (status)
                     ALOGE("%s: ERROR. SNDRV_LSM_LAB_CONTROL failed, status=%d",
@@ -2509,7 +2734,12 @@
         if (p_lsm_ses->num_stages == 1 &&
             !(p_lsm_ses->lsm_usecase.param_tag_tracker & PARAM_LAB_CONTROL_BIT)) {
             ATRACE_BEGIN("sthal:lsm: pcm_ioctl sndrv_lsm_lab_control");
+#ifdef ENABLE_SVA_MIXER_CTL
+        status = lsm_send_lab_control_mixer_ctl(p_ses->stdev->mixer, buf_en);
+#else
             status = pcm_ioctl(p_lsm_ses->pcm, SNDRV_LSM_LAB_CONTROL, &buf_en);
+#endif
+
             ATRACE_END();
             if (status) {
                 ALOGE("%s: ERROR. SNDRV_LSM_LAB_CONTROL failed, status=%d",
@@ -2571,6 +2801,25 @@
     return 0;
 }
 
+#ifdef ENABLE_SVA_MIXER_CTL
+int lsm_set_ape_control_mixer_ctl(struct mixer * st_mixer, int operation)
+{
+    struct mixer_ctl *ctl = NULL;
+    const char *mixer_ctl_name = "LSM APE_CONTROL CMD";
+
+    ctl = mixer_get_ctl_by_name(st_mixer, mixer_ctl_name);
+     if (!ctl) {
+          ALOGE("%s: Could not get ctl for mixer cmd - %s",
+                  __func__, mixer_ctl_name);
+     }
+    if (mixer_ctl_set_value(ctl, 0, operation) < 0) {
+         ALOGE("%s: Could not set LSM load mixer control", __func__);
+         return -EFAULT;
+    }
+    return 0;
+}
+#endif
+
 static int ape_start(st_hw_session_t* p_ses)
 {
     int status = 0;
@@ -2586,7 +2835,11 @@
     p_lsm_ses->exit_lab_processing = false;
 
     ATRACE_BEGIN("sthal:lsm: pcm_ioctl sndrv_lsm_start");
+#ifdef ENABLE_SVA_MIXER_CTL
+    status = lsm_set_ape_control_mixer_ctl(p_ses->stdev->mixer, ST_LSM_START);
+#else
     status = pcm_ioctl(p_lsm_ses->pcm, SNDRV_LSM_START);
+#endif
     ATRACE_END();
     if (status) {
         ALOGE("%s: ERROR. SNDRV_LSM_START failed, status=%d", __func__, status);
@@ -2610,7 +2863,11 @@
     }
 
     ATRACE_BEGIN("sthal:lsm: pcm_ioctl sndrv_lsm_stop");
+#ifdef ENABLE_SVA_MIXER_CTL
+    status = lsm_set_ape_control_mixer_ctl(p_ses->stdev->mixer, ST_LSM_STOP);
+#else
     status = pcm_ioctl(p_lsm_ses->pcm, SNDRV_LSM_STOP);
+#endif
     ATRACE_END();
     if (status)
         ALOGE("%s: ERROR. SNDDRV_LSM_STOP failed, status=%d", __func__, status);
@@ -2634,18 +2891,25 @@
     }
 
     ATRACE_BEGIN("sthal:lsm: pcm_ioctl sndrv_lsm_stop_lab");
+#ifdef ENABLE_SVA_MIXER_CTL
+    status = lsm_set_ape_control_mixer_ctl(p_ses->stdev->mixer, ST_LSM_STOP_LAB);
+#else
     status = pcm_ioctl(p_lsm_ses->pcm, SNDRV_LSM_STOP_LAB);
+#endif
     ATRACE_END();
     if (status) {
         ALOGE("%s: ERROR. SNDRV_LSM_STOP_BUFFERING failed status %d", __func__,
            status);
-    } else {
+    }
+#ifndef ENABLE_SVA_MIXER_CTL
+    else {
         ATRACE_BEGIN("sthal:lsm: pcm_ioctl sndrv_pcm_ioctl_reset");
         status = pcm_ioctl(p_lsm_ses->pcm, SNDRV_PCM_IOCTL_RESET);
         ATRACE_END();
         if (status) ALOGE("%s: ERROR. SNDRV_PCM_IOCTL_RESET failed status %d", __func__,
                status);
     }
+#endif
 
     ALOGD("%s:[%d] Exit, status=%d", __func__, p_ses->sm_handle, status);
     return status;
@@ -3075,7 +3339,9 @@
     int status;
     int wait_result;
     struct timespec timeout;
+    st_hw_session_t p_ses;
 
+    p_ses = p_lsm_ses->common;
     pthread_mutex_lock(&p_lsm_ses->callback_thread_lock);
     p_lsm_ses->exit_callback_thread = true;
     for (int i = 0; i < LSM_ABORT_RETRY_COUNT; i++) {
@@ -3085,7 +3351,11 @@
             pthread_mutex_unlock(&p_lsm_ses->callback_thread_lock);
             return;
         }
+#ifdef ENABLE_SVA_MIXER_CTL
+        status = lsm_set_ape_control_mixer_ctl(p_ses.stdev->mixer, ST_LSM_ABORT_EVENT);
+#else
         status = pcm_ioctl(p_lsm_ses->pcm, SNDRV_LSM_ABORT_EVENT);
+#endif
         ATRACE_END();
         GET_WAIT_TIMESPEC(timeout, LSM_ABORT_WAIT_TIMEOUT_NS);
         wait_result = pthread_cond_timedwait(&p_lsm_ses->callback_thread_cond,
diff --git a/st_hw_session_lsm.h b/st_hw_session_lsm.h
index c1326d9..cd9ea5c 100644
--- a/st_hw_session_lsm.h
+++ b/st_hw_session_lsm.h
@@ -1,6 +1,7 @@
 /* st_hw_session_lsm.h
  *
  * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -92,6 +93,13 @@
   typedef void* st_lsm_det_event_type_t;
 #endif
 
+enum st_lsm_ape_control {
+    ST_LSM_START = 1,
+    ST_LSM_STOP_LAB,
+    ST_LSM_ABORT_EVENT,
+    ST_LSM_STOP
+};
+
 struct multi_sm_conf_levels {
     uint32_t model_id;
     uint32_t num_conf_levels;