[Feature]Upload Modem source code

Change-Id: Id4294f30faced84d3e6fd6d5e61e1111bf287a37
diff --git a/mcu/driver/audio/src/v1/eCall_drv.c b/mcu/driver/audio/src/v1/eCall_drv.c
new file mode 100644
index 0000000..787dfda
--- /dev/null
+++ b/mcu/driver/audio/src/v1/eCall_drv.c
@@ -0,0 +1,1312 @@
+/*****************************************************************************
+*  Copyright Statement:
+*  --------------------
+*  This software is protected by Copyright and the information contained
+*  herein is confidential. The software may not be copied and the information
+*  contained herein may not be used or disclosed except with the written
+*  permission of MediaTek Inc. (C) 2011
+*
+*  BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+*  THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+*  RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON
+*  AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+*  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+*  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+*  NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+*  SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+*  SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH
+*  THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
+*  NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
+*  SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
+*
+*  BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE
+*  LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+*  AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+*  OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO
+*  MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. 
+*
+*  THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
+*  WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
+*  LAWS PRINCIPLES.  ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
+*  RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
+*  THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
+*
+*****************************************************************************/
+
+/*******************************************************************************
+ *
+ * Filename:
+ * ---------
+ * eCall_drv.c
+ *
+ * Project:
+ * --------
+ *   MAUI
+ *
+ * Description:
+ * ------------
+ *   eCall Modem Driver  
+ *
+ * Author:
+ * -------
+ * -------
+ *
+ *==============================================================================
+ *             HISTORY
+ * Below this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
+ *------------------------------------------------------------------------------
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ *------------------------------------------------------------------------------
+ * Upper this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
+ *==============================================================================
+ *******************************************************************************/
+
+#include <stdio.h>
+#include "ecall_defines.h"
+#include "ecall_control.h"
+#include "modemx.h"
+
+#include "kal_public_api.h"
+#include "kal_trace.h"
+#include "l1sp_trc.h"
+#include "l1audio.h"
+#include "pcm4way.h"
+#include "am.h"
+#include "media.h"
+#include "sp_enhance.h"
+#include "bli_exp.h"
+#include "spc_drv.h"
+#include "sal_def.h"
+#include "sal_exp.h"
+
+
+Int16 eCall_TX_CTRL_SEQ_State[800];
+Int16 eCall_TX_CTRL_SEQ_dlData[800];
+Int16 eCall_TX_CTRL_SEQ_dlMetric[800];
+Int16 eCall_RX_CTRL_SEQ_State[800];
+Int16 eCall_RX_CTRL_SEQ_dlData[800];
+Int16 eCall_RX_CTRL_SEQ_dlMetric[800];
+Int16 eCall_RX_Ctrl_Index;
+
+#define PCM_FIFO_LEN 2   // could be 1 ~ N
+#define ECALL_SWB_BUF_LEN 640 // 32k*20ms = 640
+#define ECALL_WB_BUF_LEN  320 // 16k*20ms = 320
+#define ECALL_NB_BUF_LEN  160 //  8k*20ms = 160
+
+typedef enum {
+   Udef = -1, Ivs, IvsRx, IvsTx, Psap, PsapRx, PsapTx
+} RunMode;
+
+typedef struct {
+   RunMode mode;
+
+   kal_bool  ivsPush;
+   kal_bool  msdReceived;
+   kal_bool  msdSet;
+   kal_uint8 aud_id;
+   kal_uint8 Ctrl_Par_Switch;
+   kal_bool  TxRx;
+
+   int frameStartHlack;
+   int frameStartHlackCur;
+   
+   Ord8  NewMsd[ECALL_MSD_MAX_LENGTH];
+   Ord8  CurMsd[ECALL_MSD_MAX_LENGTH];
+   
+   // For PCM4Way
+   kal_uint16 pcm_fifo_read;
+   kal_uint16 pcm_fifo_write;
+   kal_uint16 next_to_process;
+   kal_uint16 reserve_2byte;
+
+   // speech-channel PCM  buffer
+   // Input from PCM4WAY
+   kal_uint16 ul_pcm_input[2*PCM_FIFO_LEN][ECALL_SWB_BUF_LEN]; // input buffer size = 640
+   kal_uint16 dl_pcm_input[2*PCM_FIFO_LEN][ECALL_SWB_BUF_LEN];
+
+   kal_uint16 ul_pcm_input_len[2*PCM_FIFO_LEN];
+   kal_uint16 dl_pcm_input_len[2*PCM_FIFO_LEN];
+
+   // SRC temp buffer (NB 8k only)
+   kal_uint16 ul_pcm_fifo[2*PCM_FIFO_LEN][ECALL_NB_BUF_LEN];   // input buffer size = 160
+   kal_uint16 dl_pcm_fifo[2*PCM_FIFO_LEN][ECALL_NB_BUF_LEN];
+
+   // Output to PCM4WAY
+   kal_uint16 ul_pcm_output_nb[2*PCM_FIFO_LEN][ECALL_NB_BUF_LEN];   //160
+   kal_uint16 ul_pcm_output_wb[2*PCM_FIFO_LEN][ECALL_WB_BUF_LEN];   //320
+   kal_uint16 ul_pcm_output_swb[2*PCM_FIFO_LEN][ECALL_SWB_BUF_LEN]; //640
+
+   kal_bool isUpdateUL[2*PCM_FIFO_LEN];
+
+   // SRC handler internal buffer
+   // 32k <-> 8k
+   kal_uint8 internal_buf_ul_out[2184]; // internal buffer for src
+   kal_uint8 internal_buf_dl_in[2184]; // internal buffer for src
+   // 16k <-> 8k
+   kal_uint8 internal_buf_ul_out2[2184]; // internal buffer for src
+   kal_uint8 internal_buf_dl_in2[2184]; // internal buffer for src
+
+
+   BLI_HANDLE * dl_downsample_16_8;
+   BLI_HANDLE * dl_downsample_32_8;
+   BLI_HANDLE * ul_upsample_8_16;
+   BLI_HANDLE * ul_upsample_8_32;
+
+   // For HRT
+   kal_uint16 HRT_status;
+   kal_uint16 HRT_status_backup; 
+   
+   eCall_Callback handler;
+   
+   void *allocMem;
+} EcallShell;
+
+static EcallShell *eCallModemIVS;
+static EcallShell *eCallModemPSAP;
+
+kal_enhmutexid eCall_mutex;
+
+/*------------------------------------------------*/
+/* The private functions of eCall modem driver.   */
+/*------------------------------------------------*/
+//#pragma arm section code="SECONDARY_ROCODE"
+void eCall_Init(void)  
+{
+	eCall_mutex= kal_create_enh_mutex( "ECALL_MUTEX" );	
+}
+
+static void eCall_HRT_Set(void)
+{
+   eCallModemIVS->HRT_status = 1;
+}
+
+static void eCall_HRT_Clean(void)
+{
+   eCallModemIVS->HRT_status = 0;
+}
+
+static void eCall_IVS_hisr(void)
+{
+   kal_uint16 read_idx, write_idx;
+   
+   if (eCallModemIVS == NULL)
+      return;
+   
+   read_idx  = eCallModemIVS->pcm_fifo_read;
+   write_idx = eCallModemIVS->pcm_fifo_write;
+   
+   if (eCallModemIVS->pcm_fifo_read == eCallModemIVS->next_to_process) {
+      // Processed data isn't enough
+      	if(spc_Get_Ecall_Lib_Status()==SPC_ECALL_ENABLE ){
+         PCM4WAY_FillSE(0); 
+         PCM4WAY_FillSpk(0);
+      	}
+
+   } else {
+       if(spc_Get_Ecall_Lib_Status()==SPC_ECALL_ENABLE ) {
+           // uplink-path
+           if (eCallModemIVS->isUpdateUL[read_idx] == KAL_FALSE) {
+               PCM4WAY_PutToSE((const uint16*)(eCallModemIVS->ul_pcm_input[read_idx]));
+
+           } else {
+               uint16 bufLen = SAL_PcmEx_GetBufLen(SAL_PCMEX_PNW_BUF_M2D_UL1);
+               if(ECALL_NB_BUF_LEN == bufLen) {
+                   PCM4WAY_PutToSE((const uint16*)(eCallModemIVS->ul_pcm_output_nb[read_idx]));
+
+               } else if(ECALL_WB_BUF_LEN == bufLen) {
+                   PCM4WAY_PutToSE((const uint16*)(eCallModemIVS->ul_pcm_output_wb[read_idx]));
+
+               } else {
+                  PCM4WAY_PutToSE((const uint16*)(eCallModemIVS->ul_pcm_output_swb[read_idx]));
+               }
+
+               eCallModemIVS->isUpdateUL[read_idx] = KAL_FALSE;
+               MD_TRC_ECALL_IVS_PCM_UPDATE_PUTTOSE(read_idx, bufLen);
+            }
+
+           // downlink-path no change
+           PCM4WAY_PutToSpk((const uint16*)(eCallModemIVS->dl_pcm_input[read_idx]));
+       }
+
+      // Update index
+      eCallModemIVS->pcm_fifo_write++;
+      if (eCallModemIVS->pcm_fifo_write == 2*PCM_FIFO_LEN) {
+         eCallModemIVS->pcm_fifo_write = 0;
+      }
+   }
+   if (read_idx != write_idx) {
+      // There is enough space to write data from microphone
+      eCallModemIVS->ul_pcm_input_len[write_idx] = PCM4WAY_GetFromMic((uint16*)(eCallModemIVS->ul_pcm_input[write_idx]));
+      eCallModemIVS->dl_pcm_input_len[write_idx] = PCM4WAY_GetFromSD((uint16*)(eCallModemIVS->dl_pcm_input[write_idx]));
+      MD_TRC_ECALL_IVS_PCM_INPUT_LEN(write_idx, eCallModemIVS->ul_pcm_input_len[write_idx], write_idx, eCallModemIVS->dl_pcm_input_len);
+
+      // Update index
+      eCallModemIVS->pcm_fifo_read++; 
+      if (eCallModemIVS->pcm_fifo_read == 2*PCM_FIFO_LEN) {
+         eCallModemIVS->pcm_fifo_read = 0;
+      }
+   }
+   
+   eCallModemIVS->HRT_status_backup = eCallModemIVS->HRT_status;
+   eCall_HRT_Set();
+                   
+   L1Audio_SetEvent(eCallModemIVS->aud_id, (void*)0);
+}
+//#pragma arm section
+
+static void eCall_IVS_ProcessFrame(void)
+{
+   kal_uint32 proc_idx;
+
+   // Here we only do DL downsample, UL upsample
+   kal_uint32 dl_ds_inLen, dl_ds_outLen;
+   kal_uint32 ul_us_inLen, ul_us_outLen;
+
+   kal_uint16 *p_dl_ds_inBuf, *p_dl_ds_outBuf;
+   kal_uint16 *p_ul_us_inBuf, *p_ul_us_outBuf;
+
+   if (eCallModemIVS == NULL)
+      return;
+
+   proc_idx = eCallModemIVS->next_to_process;
+
+   switch (eCallModemIVS->mode) {
+      case Ivs:
+         if (eCallModemIVS->ivsPush == KAL_TRUE) {
+            IvsSendStart();
+            eCallModemIVS->ivsPush = KAL_FALSE;
+         }
+
+         /******************************************************
+         *  dl_pcm_input  -> dl_pcm_fifo    -> dl_pcm_output   *
+         *     32k               8k            32k             *
+         *                [BAUDOT] -> [ECALLLIB]                    * 
+         ******************************************************/
+
+         /* [ECALL blisrc] DL downsample start */
+         p_dl_ds_inBuf = eCallModemIVS->dl_pcm_input[proc_idx];
+         p_dl_ds_outBuf = eCallModemIVS->dl_pcm_fifo[proc_idx];
+
+         if(ECALL_WB_BUF_LEN == eCallModemIVS->dl_pcm_input_len[proc_idx]) {
+             dl_ds_inLen  = ECALL_WB_BUF_LEN << 1;  
+             dl_ds_outLen = ECALL_NB_BUF_LEN << 1; 
+             BLI_Convert(eCallModemIVS->dl_downsample_16_8, (short *)p_dl_ds_inBuf, &dl_ds_inLen, (short *)p_dl_ds_outBuf, &dl_ds_outLen);
+
+         } else if(ECALL_SWB_BUF_LEN ==eCallModemIVS->dl_pcm_input_len[proc_idx]) {
+             dl_ds_inLen  = ECALL_SWB_BUF_LEN << 1;  
+             dl_ds_outLen = ECALL_NB_BUF_LEN << 1; 
+             BLI_Convert(eCallModemIVS->dl_downsample_32_8, (short *)p_dl_ds_inBuf, &dl_ds_inLen, (short *)p_dl_ds_outBuf, &dl_ds_outLen);
+
+         } else{
+             memcpy(p_dl_ds_outBuf, p_dl_ds_inBuf, ECALL_NB_BUF_LEN << 1);
+         }
+         /* [ECALL blisrc] DL downsample end */
+
+#if 1
+         {
+            IvsState preRxState = IvsRxGetState();
+            IvsState curState;
+
+            IvsProcess((Int16 *)eCallModemIVS->dl_pcm_fifo[proc_idx]);
+
+            curState = IvsTxGetState();
+            if ((curState == IvsTrigger) || (curState == IvsStart) || (curState == IvsSendMsd) || (preRxState != IvsIdle) || (IvsRxGetState() != IvsIdle)) {
+                memcpy(eCallModemIVS->ul_pcm_fifo[proc_idx], eCallModemIVS->dl_pcm_fifo[proc_idx], ECALL_NB_BUF_LEN*sizeof(kal_uint16));
+
+                /*****************************************************
+                 *  dl_pcm_output  <- dl_pcm_fifo  <- dl_pcm_input    *
+                 *     32k               8k            32k            *
+                 *                 [ECALLLIB] <- [BAUDOT]                  *
+                 *****************************************************/
+
+                /* [ECALL blisrc] UL up sampling start */
+                //NB output
+                p_ul_us_inBuf = eCallModemIVS->ul_pcm_fifo[proc_idx];
+                p_ul_us_outBuf = eCallModemIVS->ul_pcm_output_nb[proc_idx];
+                memcpy(p_ul_us_outBuf, p_ul_us_inBuf, ECALL_NB_BUF_LEN << 1);
+
+                //WB output
+                ul_us_inLen = ECALL_NB_BUF_LEN << 1; 
+                ul_us_outLen = ECALL_WB_BUF_LEN << 1;
+                p_ul_us_outBuf = eCallModemIVS->ul_pcm_output_wb[proc_idx];
+                BLI_Convert(eCallModemIVS->ul_upsample_8_16, (short *)p_ul_us_inBuf, &ul_us_inLen, (short *)p_ul_us_outBuf, &ul_us_outLen);
+
+                //SWB output
+                ul_us_inLen = ECALL_NB_BUF_LEN << 1; 
+                ul_us_outLen = ECALL_SWB_BUF_LEN << 1;
+                p_ul_us_outBuf = eCallModemIVS->ul_pcm_output_swb[proc_idx];
+                BLI_Convert(eCallModemIVS->ul_upsample_8_32, (short *)p_ul_us_inBuf, &ul_us_inLen, (short *)p_ul_us_outBuf, &ul_us_outLen);
+                /* [ECALL blisrc] UL up sampling end */
+
+                eCallModemIVS->isUpdateUL[proc_idx] = KAL_TRUE;
+                MD_TRC_ECALL_IVS_PCM_UPDATE_UL(proc_idx, curState, proc_idx, eCallModemIVS->isUpdateUL[proc_idx]);
+            }
+         }
+
+#else         
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+#endif
+         
+         break;
+      case IvsRx:
+         if (eCallModemIVS->ivsPush == KAL_TRUE) {
+            IvsSendStart();
+            eCallModemIVS->ivsPush = KAL_FALSE;
+         }
+
+         /******************************************************
+         *  dl_pcm_input  -> dl_pcm_fifo    -> dl_pcm_output   *
+         *     32k               8k            32k             *
+         *                [BAUDOT] -> [ECALLLIB]                    * 
+         ******************************************************/
+
+         /* [ECALL blisrc] DL downsample start */
+         p_dl_ds_inBuf = eCallModemIVS->dl_pcm_input[proc_idx];
+         p_dl_ds_outBuf = eCallModemIVS->dl_pcm_fifo[proc_idx];
+
+         if(ECALL_WB_BUF_LEN == eCallModemIVS->dl_pcm_input_len[proc_idx]) {
+            dl_ds_inLen  = ECALL_WB_BUF_LEN << 1;  
+            dl_ds_outLen = ECALL_NB_BUF_LEN << 1; 
+            BLI_Convert(eCallModemIVS->dl_downsample_16_8, (short *)p_dl_ds_inBuf, &dl_ds_inLen, (short *)p_dl_ds_outBuf, &dl_ds_outLen);
+
+         } else if(ECALL_SWB_BUF_LEN ==eCallModemIVS->dl_pcm_input_len[proc_idx]) {
+            dl_ds_inLen  = ECALL_SWB_BUF_LEN << 1;  
+            dl_ds_outLen = ECALL_NB_BUF_LEN << 1; 
+            BLI_Convert(eCallModemIVS->dl_downsample_32_8, (short *)p_dl_ds_inBuf, &dl_ds_inLen, (short *)p_dl_ds_outBuf, &dl_ds_outLen);
+
+         } else{
+           memcpy(p_dl_ds_outBuf, p_dl_ds_inBuf, ECALL_NB_BUF_LEN << 1);
+         }
+         /* [ECALL blisrc] DL downsample end */
+
+#if 1
+         {
+            IvsState preRxState = IvsRxGetState();
+            IvsState curState;
+
+            IvsProcess((Int16 *)eCallModemIVS->dl_pcm_fifo[proc_idx]);
+
+            curState = IvsTxGetState();
+            if ((curState == IvsTrigger) || (curState == IvsStart) || (curState == IvsSendMsd) || (preRxState != IvsIdle) || (IvsRxGetState() != IvsIdle)) {
+                memcpy(eCallModemIVS->ul_pcm_fifo[proc_idx], eCallModemIVS->dl_pcm_fifo[proc_idx], ECALL_NB_BUF_LEN*sizeof(kal_uint16));
+
+                /*****************************************************
+                 *  dl_pcm_output  <- dl_pcm_fifo  <- dl_pcm_input    *
+                 *     32k               8k            32k            *
+                 *                 [ECALLLIB] <- [BAUDOT]                  *
+                 *****************************************************/
+
+                /* [ECALL blisrc] UL up sampling start */
+                //NB output
+                p_ul_us_inBuf = eCallModemIVS->ul_pcm_fifo[proc_idx];
+                p_ul_us_outBuf = eCallModemIVS->ul_pcm_output_nb[proc_idx];
+                memcpy(p_ul_us_outBuf, p_ul_us_inBuf, ECALL_NB_BUF_LEN << 1);
+
+                //WB output
+                ul_us_inLen = ECALL_NB_BUF_LEN << 1; 
+                ul_us_outLen = ECALL_WB_BUF_LEN << 1;
+                p_ul_us_outBuf = eCallModemIVS->ul_pcm_output_wb[proc_idx];
+                BLI_Convert(eCallModemIVS->ul_upsample_8_16, (short *)p_ul_us_inBuf, &ul_us_inLen, (short *)p_ul_us_outBuf, &ul_us_outLen);
+
+                //SWB output
+                ul_us_inLen = ECALL_NB_BUF_LEN << 1; 
+                ul_us_outLen = ECALL_SWB_BUF_LEN << 1;
+                p_ul_us_outBuf = eCallModemIVS->ul_pcm_output_swb[proc_idx];
+                BLI_Convert(eCallModemIVS->ul_upsample_8_32, (short *)p_ul_us_inBuf, &ul_us_inLen, (short *)p_ul_us_outBuf, &ul_us_outLen);
+                /* [ECALL blisrc] UL up sampling end */
+
+                eCallModemIVS->isUpdateUL[proc_idx] = KAL_TRUE;
+                MD_TRC_ECALL_IVS_PCM_UPDATE_UL(proc_idx, curState, proc_idx, eCallModemIVS->isUpdateUL[proc_idx]);
+            }
+         }
+#else          
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+#endif
+         
+         break;
+      default:
+         ASSERT(0);
+         break;
+   }
+}
+
+static void eCall_IVS_ProcessTask(void *data)
+{
+   kal_take_enh_mutex( eCall_mutex);
+   if (eCallModemIVS == NULL) {
+       kal_give_enh_mutex( eCall_mutex);  	
+      return;
+   }
+   
+   if (eCallModemIVS->HRT_status_backup != 0)
+   {
+       MD_TRC_ECALL_IVS_HRT_STATUS(eCallModemIVS->HRT_status_backup);  
+   }
+   
+   while (eCallModemIVS->next_to_process != eCallModemIVS->pcm_fifo_write) {
+      // Process each frame
+      eCall_IVS_ProcessFrame();
+      
+      // Update index
+      eCallModemIVS->next_to_process++;
+      if (eCallModemIVS->next_to_process == 2 * PCM_FIFO_LEN) {
+         eCallModemIVS->next_to_process = 0;
+      }
+      
+      eCall_HRT_Clean();
+   }
+  kal_give_enh_mutex( eCall_mutex); 
+}
+
+static void eCall_IVS_OnHandler( void *data ) 
+{
+   (void)data;
+   if(spc_Get_Ecall_Lib_Status()==SPC_ECALL_ENABLE )
+   {
+
+   	PCM4WAY_Start(eCall_IVS_hisr, 0);
+   }
+   else
+   {
+   	PCM4WAY_Start(eCall_IVS_hisr, 4);	
+   }
+}
+
+static void eCall_IVS_OffHandler( void *data ) 
+{      
+   (void)data;
+   
+   PCM4WAY_Stop(0);
+}
+
+/*------------------------------------------------*/
+/* The public functions of eCall modem driver.    */
+/*------------------------------------------------*/
+eCall_Modem_Status eCall_IVS_Open(eCall_Callback handler)
+{
+   ASSERT( handler != NULL );
+
+   MD_TRC_ECALL_IVS_DRV_OPEN(spc_Get_Ecall_Lib_Status());
+   
+   if (eCallModemPSAP != NULL) {
+      return eCALL_OPERATION_FAIL;
+   }
+   
+   if ( eCallModemIVS != NULL ) {
+      return eCALL_OPERATION_ALREADY_OPEN;
+   }
+   
+   //L1SP_EnableSpeechEnhancement(KAL_FALSE);
+   
+   //eCallModemIVS = (EcallShell *)audio_alloc_mem_cacheable( sizeof(EcallShell) );
+   eCallModemIVS = (EcallShell *)get_ctrl_buffer( sizeof(EcallShell) );
+   ASSERT( eCallModemIVS != NULL );
+   memset(eCallModemIVS, 0, sizeof(EcallShell));
+   
+   // Allocate for IVS internal structure
+   {
+      kal_uint32 reqSize;
+      
+      reqSize = (kal_uint32) IvsGetMemSize();
+     // eCallModemIVS->allocMem = (void *)audio_alloc_mem_cacheable( reqSize ); 
+      eCallModemIVS->allocMem = (void *)get_ctrl_buffer( reqSize );
+      memset(eCallModemIVS->allocMem, 0, sizeof(reqSize));
+      IvsInit( eCallModemIVS->allocMem );
+
+      if (eCallModemIVS->allocMem == NULL) {
+          MD_TRC_ECALL_IVS_DRV_ALLOCMEM_NULL();
+      }
+   }
+
+   // open BLI Src for ecall
+   // 32k <-> 8k
+   eCallModemIVS->dl_downsample_32_8 = BLI_Open(32000, 1, 8000, 1, (signed char*)eCallModemIVS->internal_buf_dl_in, 0); // open DL down sampling src
+   eCallModemIVS->ul_upsample_8_32 = BLI_Open(8000, 1, 32000, 1, (signed char*)eCallModemIVS->internal_buf_ul_out, 0); // open UL up sampling src
+   // 16k <-> 8k
+   eCallModemIVS->dl_downsample_16_8 = BLI_Open(16000, 1, 8000, 1, (signed char*)eCallModemIVS->internal_buf_dl_in2, 0); // open DL down sampling src
+   eCallModemIVS->ul_upsample_8_16 = BLI_Open(8000, 1, 16000, 1, (signed char*)eCallModemIVS->internal_buf_ul_out2, 0); // open UL up sampling src
+
+   eCallModemIVS->aud_id = L1Audio_GetAudioID();
+   L1Audio_SetEventHandler(eCallModemIVS->aud_id , eCall_IVS_ProcessTask);
+   L1Audio_SetFlag(eCallModemIVS->aud_id);
+   
+   IvsRxReset();
+   
+   eCallModemIVS->mode = IvsRx;
+   eCallModemIVS->pcm_fifo_read = 0;
+   eCallModemIVS->pcm_fifo_write = PCM_FIFO_LEN;
+   eCallModemIVS->next_to_process = PCM_FIFO_LEN;
+   eCallModemIVS->handler = handler;
+
+   for (int i=0; i<2*PCM_FIFO_LEN; i++) {
+       eCallModemIVS->isUpdateUL[i] = KAL_FALSE;
+   }
+
+   //Init eCall RX ctrl seq 
+    memset(eCall_RX_CTRL_SEQ_State, 0, 800*sizeof(Int16));
+    memset(eCall_RX_CTRL_SEQ_dlData, 0, 800*sizeof(Int16));
+    memset(eCall_RX_CTRL_SEQ_dlMetric, 0, 800*sizeof(Int16));
+    eCall_RX_Ctrl_Index = 1;
+    eCall_RX_CTRL_SEQ_dlMetric[0] = 0xFF;
+    eCall_RX_CTRL_SEQ_State[0] = 0xDD;
+    eCall_RX_CTRL_SEQ_dlData[0] = 0xEE;
+
+   if(spc_Get_Ecall_Lib_Status()==SPC_ECALL_SDT_ONLY ){
+	Ivs_Set_Ecall_Lib_Status(Ivs_ECALL_SDT_ONLY);   
+   }else if(spc_Get_Ecall_Lib_Status()==SPC_ECALL_ENABLE){
+	Ivs_Set_Ecall_Lib_Status(Ivs_ECALL_ENABLE);   
+   }else {
+	return eCALL_OPERATION_FAIL;   
+   }
+   
+   if ( AM_IsSpeechOn() ) {
+      eCall_IVS_OnHandler( (void *)0 );
+   }
+   
+   // Hook service to L1SP
+   L1SP_Register_Pcm4WayService( eCall_IVS_OnHandler, eCall_IVS_OffHandler );
+   
+   return eCALL_OPERATION_SUCCESS;
+}
+
+eCall_Modem_Status eCall_IVS_Close(void)
+{
+   MD_TRC_ECALL_IVS_DRV_CLOSE();
+   kal_take_enh_mutex( eCall_mutex);
+   if ( eCallModemIVS == NULL ) {
+	  kal_give_enh_mutex( eCall_mutex);
+      return eCALL_OPERATION_ALREADY_CLOSE;
+   }
+
+   if (eCallModemPSAP != NULL) {
+	  kal_give_enh_mutex( eCall_mutex);
+      return eCALL_OPERATION_FAIL;
+   }
+
+   if(spc_Get_Ecall_Lib_Status()==SPC_ECALL_DISABLE){
+   	   kal_give_enh_mutex( eCall_mutex);   	
+	   return eCALL_OPERATION_FAIL;   	
+   }   
+   // Unhook service to L1SP
+   L1SP_UnRegister_Pcm4Way_Service();
+   
+   if ( AM_IsSpeechOn() ) {
+      eCall_IVS_OffHandler( (void *)0 );
+   }
+   
+   L1Audio_ClearFlag(eCallModemIVS->aud_id);
+   L1Audio_FreeAudioID(eCallModemIVS->aud_id);
+
+   BLI_Close(eCallModemIVS->dl_downsample_16_8, 0); // Close DL down sampling src
+   BLI_Close(eCallModemIVS->dl_downsample_32_8, 0); // Close DL down sampling src
+   BLI_Close(eCallModemIVS->ul_upsample_8_16, 0); // Close UL up sampling src
+   BLI_Close(eCallModemIVS->ul_upsample_8_32, 0); // Close UL up sampling src
+
+   // Deallocate for IVS internal structure
+   {
+      IvsDeinit();
+      if (eCallModemIVS->allocMem == NULL) {
+          MD_TRC_ECALL_IVS_DRV_ALLOCMEM_NULL();
+
+      } else {
+          free_ctrl_buffer( (void *) eCallModemIVS->allocMem );
+      }
+   }
+
+   free_ctrl_buffer( (void *) eCallModemIVS );
+   //L1SP_EnableSpeechEnhancement(KAL_TRUE);
+   eCallModemIVS = NULL;
+
+   //transfer ctrl data to AP
+   spc_eCall_RX_CTRL_Data(0xDD);
+   spc_eCall_RX_CTRL_Data(0xEE);
+   spc_eCall_RX_CTRL_Data(0xFF);
+
+   kal_give_enh_mutex( eCall_mutex);
+   return eCALL_OPERATION_SUCCESS;
+}
+
+eCall_Modem_Status eCall_IVS_PutMSD(const kal_uint8 *pMSD, const kal_uint32 uLen, kal_uint8 from)
+{   
+    kal_uint8 i=0;
+   if (eCallModemPSAP != NULL) {
+      return eCALL_OPERATION_FAIL;
+   }
+
+   if ( eCallModemIVS == NULL ) {
+      return eCALL_OPERATION_FAIL;
+   }
+   if(spc_Get_Ecall_Lib_Status()==SPC_ECALL_SDT_ONLY)
+   {
+	return eCALL_OPERATION_STOP;
+   }
+   ASSERT( pMSD != NULL );
+   ASSERT( uLen <= ECALL_MSD_MAX_LENGTH);
+   
+   memset(eCallModemIVS->NewMsd, 0, ECALL_MSD_MAX_LENGTH*sizeof(Ord8));
+   memcpy(eCallModemIVS->NewMsd, pMSD, uLen*sizeof(Ord8));
+//   for(i=0;i<140;i=i+7)
+//   {
+//    MD_TRC_ECALL_IVS_DRV_PUT_MSD(pMSD[i],pMSD[i+1],pMSD[i+2],pMSD[i+3],pMSD[i+4],pMSD[i+5],pMSD[i+6]);	  	
+//   }    
+   // Check status and copy to current MSD
+   //if ( IvsTxGetState() == IvsIdle ) {
+      memcpy(eCallModemIVS->CurMsd, eCallModemIVS->NewMsd, ECALL_MSD_MAX_LENGTH*sizeof(Ord8));
+   //}
+   for(i=0;i<140;i=i+7)
+   {
+     MD_TRC_ECALL_IVS_DRV_PUT_MSD(eCallModemIVS->CurMsd[i],eCallModemIVS->CurMsd[i+1],eCallModemIVS->CurMsd[i+2],eCallModemIVS->CurMsd[i+3],eCallModemIVS->CurMsd[i+4],eCallModemIVS->CurMsd[i+5],eCallModemIVS->CurMsd[i+6]);
+   }   
+
+   // 0: Internal, 1:L5
+   if (from == 1) {
+       eCallModemIVS->msdSet = KAL_TRUE;
+   }
+   MD_TRC_ECALL_IVS_DRV_MSD_SET(from, eCallModemIVS->msdSet);
+
+   IvsTxReset(eCallModemIVS->CurMsd, ECALL_MSD_MAX_LENGTH);
+   
+   return eCALL_OPERATION_SUCCESS;
+}
+
+eCall_Modem_Status eCall_IVS_SendStart(void)
+{
+   MD_TRC_ECALL_IVS_DRV_SEND_START();
+   if (eCallModemPSAP != NULL) {
+      return eCALL_OPERATION_FAIL;
+   }
+
+   if ( eCallModemIVS == NULL ) {
+      return eCALL_OPERATION_FAIL;
+   }
+   
+   // Check state
+   if ( IvsTxGetState() != IvsIdle ) {
+      return eCALL_OPERATION_DURING_TRANSMISSION;
+   }
+   if(spc_Get_Ecall_Lib_Status()==SPC_ECALL_DISABLE){
+	   return eCALL_OPERATION_FAIL;   	
+   }   
+   eCallModemIVS->TxRx = KAL_TRUE;
+   IvsRxReset();
+   
+   if (eCallModemIVS->msdSet) {
+      eCallModemIVS->mode = Ivs;
+   }
+   
+   eCallModemIVS->ivsPush = KAL_TRUE;
+   
+   return eCALL_OPERATION_SUCCESS;
+}
+
+
+#if 1
+/*------------------------------------------------*/
+/* The unit test code for callback.               */
+/*------------------------------------------------*/
+
+void IvsCatchEvent(IvsEvent ie)
+{
+   ASSERT(eCallModemIVS);
+   
+   MD_TRC_ECALL_IVS_DRV_CATCH_EVENT(ie);
+   
+   /* custom event handlers to be implemented here... */
+   /* see modemx.h for a list of possible events (enum IvsEvent) */
+   switch (ie) {
+      case IVSEVENT_SENDINGMSD:
+		#if defined(__L5_SUPPORT__)
+        if (eCallModemIVS->msdSet) {
+		    spc_L5ECALL_Status_Info_Callback(0xE1,0);
+        } else {
+            MD_TRC_ECALL_IVS_DRV_MSD_NOT_SET();
+        }
+		#else
+		spc_eCall_Handshake_Info_Notify(0xE1,0);
+		#endif 
+       break;
+      case IVSEVENT_CONTROLLOCK:
+         eCallModemIVS->mode = Ivs;
+         eCallModemIVS->TxRx = KAL_TRUE;
+         eCallModemIVS->handler( eCALL_EVENT_RECV_START, NULL);
+         break;
+      case IVSEVENT_NACKRECEIVED:
+         eCallModemIVS->handler( eCALL_EVENT_RECV_NACK, NULL);
+         break;
+      case IVSEVENT_LLACKRECEIVED:
+		#if defined(__L5_SUPPORT__)
+		spc_L5ECALL_Status_Info_Callback(0xE2,0);
+		#else
+		spc_eCall_Handshake_Info_Notify(0xE2,0);
+		#endif 
+         eCallModemIVS->handler( eCALL_EVENT_RECV_LL_ACK, NULL);
+         break;
+      case IVSEVENT_HLACKRECEIVED:
+         eCallModemIVS->mode = IvsRx;
+         break;
+      case IVSEVENT_RECEIVESTART:
+		#if defined(__L5_SUPPORT__)
+		spc_L5ECALL_Status_Info_Callback(0xE4,0);
+		#else
+		spc_eCall_Handshake_Info_Notify(0xE4,0);
+		#endif 
+         break;		 
+      default:
+         break;
+   }
+}
+
+void IvsReceiveHlack(const Ord8 data)
+{
+   MD_TRC_ECALL_IVS_DRV_HLACK((eCallModemIVS->CurMsd[0] & 0x0F), (data & 0x0F));
+   	#if defined(__L5_SUPPORT__)
+	spc_L5ECALL_Status_Info_Callback(0xE3,data);
+	#else
+	spc_eCall_Handshake_Info_Notify(0xE3,data);
+	#endif 	
+	
+   if ((eCallModemIVS->CurMsd[0] & 0x0F) == (data & 0x0F)) {
+      //eCallModemIVS->handler( eCALL_EVENT_RECV_HL_ACK_CORRECT, (void *)data); //NEED TO CHECK
+   } else {
+      //eCallModemIVS->handler( eCALL_EVENT_RECV_HL_ACK_MISMATCH, (void *)data);
+   }
+   IvsRxReset();
+   IvsTxReset(eCallModemIVS->CurMsd, ECALL_MSD_MAX_LENGTH);
+   eCallModemIVS->TxRx = KAL_FALSE;
+}
+
+void PsapCatchEvent(PsapEvent pe)
+{
+   MD_TRC_ECALL_PSAP_DRV_CATCH_EVENT(pe);
+   
+   switch (pe) {
+      /* custom event handlers to be implemented here... */
+      /* see modemx.h for a list of possible events (enum PsapEvent) */
+      case PSAPEVENT_CONTROLLOCK:
+         eCallModemPSAP->TxRx = KAL_TRUE;
+         break;
+      case PSAPEVENT_IDLEPOSTHLACK:
+         PsapReset();
+         eCallModemPSAP->frameStartHlackCur = 0;
+         eCallModemPSAP->msdReceived = KAL_FALSE;
+         eCallModemPSAP->ivsPush = KAL_TRUE;
+         eCallModemPSAP->TxRx = KAL_FALSE;
+         break;
+      default:
+         break;
+   }
+}
+
+#endif
+
+#if defined(__ECALL_PSAP_SUPPORT__)
+
+/*------------------------------------------------*/
+/* The unit test code for PSAP.                   */
+/*------------------------------------------------*/
+
+void PsapReceiveMsd(const Ord8 *msd, int length) {
+   int n;
+   
+   MD_TRC_ECALL_PSAP_DRV_RECEIVE_MSD();
+   
+   for (n = 0; n < ECALL_MSD_MAX_LENGTH; n++) {
+      eCallModemPSAP->CurMsd[n] = msd[n];
+   }
+   eCallModemPSAP->msdReceived = KAL_TRUE;
+
+   for (n=0; n<20; n++) {
+      kal_uint32 base = 7*n;
+      
+      MD_TRC_ECALL_PSAP_DRV_MSD_DATA(
+         msd[base], msd[base+1], msd[base+2], msd[base+3], msd[base+4], msd[base+5], msd[base+6]);
+   }
+   
+   eCallModemPSAP->handler( eCALL_EVENT_PSAP_RECV_MSD, eCallModemPSAP->CurMsd);
+}
+
+//#pragma arm section code="SECONDARY_ROCODE"
+static void eCall_PSAP_hisr(void)
+{
+   kal_uint16 read_idx, write_idx;
+   
+   read_idx  = eCallModemPSAP->pcm_fifo_read;
+   write_idx = eCallModemPSAP->pcm_fifo_write;
+   
+   if (eCallModemPSAP->pcm_fifo_read == eCallModemPSAP->next_to_process) {
+      // Processed data isn't enough
+      PCM4WAY_FillSE(0);
+      PCM4WAY_FillSpk(0);
+   } else {
+      // uplink-path
+      if (eCallModemPSAP->isUpdateUL[read_idx] == KAL_FALSE) {
+          PCM4WAY_PutToSE((const uint16*)(eCallModemPSAP->ul_pcm_input[read_idx]));
+
+      } else {
+          uint16 bufLen = SAL_PcmEx_GetBufLen(SAL_PCMEX_PNW_BUF_M2D_UL1);
+          if(ECALL_NB_BUF_LEN == bufLen) {
+              PCM4WAY_PutToSE((const uint16*)(eCallModemPSAP->ul_pcm_output_nb[read_idx]));
+
+          } else if(ECALL_WB_BUF_LEN == bufLen) {
+              PCM4WAY_PutToSE((const uint16*)(eCallModemPSAP->ul_pcm_output_wb[read_idx]));
+
+          } else {
+             PCM4WAY_PutToSE((const uint16*)(eCallModemPSAP->ul_pcm_output_swb[read_idx]));
+          }
+
+          eCallModemPSAP->isUpdateUL[read_idx] = KAL_FALSE;
+          MD_TRC_ECALL_PSAP_PCM_UPDATE_PUTTOSE(read_idx, bufLen);
+      }
+
+      // downlink-path no change
+      PCM4WAY_PutToSpk((const uint16*)(eCallModemPSAP->dl_pcm_input[read_idx]));
+      
+      // Update index
+      eCallModemPSAP->pcm_fifo_write++;
+      if (eCallModemPSAP->pcm_fifo_write == 2*PCM_FIFO_LEN) {
+         eCallModemPSAP->pcm_fifo_write = 0;
+      }
+   }
+   if (read_idx != write_idx) {
+      // There is enough space to write data from microphone
+      eCallModemPSAP->ul_pcm_input_len[write_idx] = PCM4WAY_GetFromMic((uint16*)(eCallModemPSAP->ul_pcm_input[write_idx]));
+      eCallModemPSAP->dl_pcm_input_len[write_idx] = PCM4WAY_GetFromSD((uint16*)(eCallModemPSAP->dl_pcm_input[write_idx]));
+      MD_TRC_ECALL_PSAP_PCM_INPUT_LEN(write_idx, eCallModemPSAP->ul_pcm_input_len[write_idx], write_idx, eCallModemPSAP->dl_pcm_input_len);
+      
+      // Update index
+      eCallModemPSAP->pcm_fifo_read++; 
+      if (eCallModemPSAP->pcm_fifo_read == 2*PCM_FIFO_LEN) {
+         eCallModemPSAP->pcm_fifo_read = 0;
+      }
+   }
+                        
+   L1Audio_SetEvent(eCallModemPSAP->aud_id, (void*)0);
+}
+//#pragma arm section
+
+static void eCall_PSAP_ProcessFrame(void)
+{
+   kal_uint32 proc_idx = eCallModemPSAP->next_to_process;
+
+   // Here we only do DL downsample, UL upsample
+   kal_uint32 dl_ds_inLen, dl_ds_outLen;
+   kal_uint32 ul_us_inLen, ul_us_outLen;
+
+   kal_uint16 *p_dl_ds_inBuf, *p_dl_ds_outBuf;
+   kal_uint16 *p_ul_us_inBuf, *p_ul_us_outBuf;
+
+   switch (eCallModemPSAP->mode) {
+      case Psap:
+         if (eCallModemPSAP->ivsPush == KAL_FALSE) {
+            PsapSendStart();
+            eCallModemPSAP->ivsPush = KAL_TRUE;
+         }
+         if (eCallModemPSAP->msdReceived == KAL_TRUE) {
+            if ( ++eCallModemPSAP->frameStartHlackCur == eCallModemPSAP->frameStartHlack)
+               PsapSendHlack(eCallModemPSAP->CurMsd[0] & 0x0F);
+         }
+
+         /******************************************************
+         *  dl_pcm_input  -> dl_pcm_fifo    -> dl_pcm_output   *
+         *     32k               8k            32k             *
+         *                [BAUDOT] -> [ECALLLIB]                    * 
+         ******************************************************/
+
+         /* [ECALL blisrc] DL downsample start */
+         p_dl_ds_inBuf = eCallModemPSAP->dl_pcm_input[proc_idx];
+         p_dl_ds_outBuf = eCallModemPSAP->dl_pcm_fifo[proc_idx];
+
+         if(ECALL_WB_BUF_LEN == eCallModemPSAP->dl_pcm_input_len[proc_idx]) {
+             dl_ds_inLen  = ECALL_WB_BUF_LEN << 1;  
+             dl_ds_outLen = ECALL_NB_BUF_LEN << 1; 
+             BLI_Convert(eCallModemPSAP->dl_downsample_16_8, (short *)p_dl_ds_inBuf, &dl_ds_inLen, (short *)p_dl_ds_outBuf, &dl_ds_outLen);
+
+         } else if(ECALL_SWB_BUF_LEN ==eCallModemPSAP->dl_pcm_input_len[proc_idx]) {
+             dl_ds_inLen  = ECALL_SWB_BUF_LEN << 1;  
+             dl_ds_outLen = ECALL_NB_BUF_LEN << 1; 
+             BLI_Convert(eCallModemPSAP->dl_downsample_32_8, (short *)p_dl_ds_inBuf, &dl_ds_inLen, (short *)p_dl_ds_outBuf, &dl_ds_outLen);
+
+         } else{
+             memcpy(p_dl_ds_outBuf, p_dl_ds_inBuf, ECALL_NB_BUF_LEN << 1);
+         }
+         /* [ECALL blisrc] DL downsample end */
+
+         PsapProcess( (Int16 *)eCallModemPSAP->dl_pcm_fifo[proc_idx]);
+
+         if (eCallModemPSAP->TxRx) {
+            memcpy(eCallModemPSAP->ul_pcm_fifo[proc_idx], eCallModemPSAP->dl_pcm_fifo[proc_idx], ECALL_NB_BUF_LEN*sizeof(kal_uint16));
+
+            /*****************************************************
+             *  dl_pcm_output  <- dl_pcm_fifo  <- dl_pcm_input    *
+             *     32k               8k            32k            *
+             *                 [ECALLLIB] <- [BAUDOT]                  *
+             *****************************************************/
+
+            /* [ECALL blisrc] UL up sampling start */
+            //NB output
+            p_ul_us_inBuf = eCallModemPSAP->ul_pcm_fifo[proc_idx];
+            p_ul_us_outBuf = eCallModemPSAP->ul_pcm_output_nb[proc_idx];
+            memcpy(p_ul_us_outBuf, p_ul_us_inBuf, ECALL_NB_BUF_LEN << 1);
+
+            //WB output
+            ul_us_inLen = ECALL_NB_BUF_LEN << 1; 
+            ul_us_outLen = ECALL_WB_BUF_LEN << 1;
+            p_ul_us_outBuf = eCallModemPSAP->ul_pcm_output_wb[proc_idx];
+            BLI_Convert(eCallModemPSAP->ul_upsample_8_16, (short *)p_ul_us_inBuf, &ul_us_inLen, (short *)p_ul_us_outBuf, &ul_us_outLen);
+
+            //SWB output
+            ul_us_inLen = ECALL_NB_BUF_LEN << 1; 
+            ul_us_outLen = ECALL_SWB_BUF_LEN << 1;
+            p_ul_us_outBuf = eCallModemPSAP->ul_pcm_output_swb[proc_idx];
+            BLI_Convert(eCallModemPSAP->ul_upsample_8_32, (short *)p_ul_us_inBuf, &ul_us_inLen, (short *)p_ul_us_outBuf, &ul_us_outLen);
+            /* [ECALL blisrc] UL up sampling end */
+
+            eCallModemPSAP->isUpdateUL[proc_idx] = KAL_TRUE;
+            MD_TRC_ECALL_PSAP_PCM_UPDATE_UL(proc_idx, eCallModemPSAP->TxRx, proc_idx, eCallModemPSAP->isUpdateUL[proc_idx]);
+         }
+
+         break;
+      case PsapRx:
+         if (eCallModemPSAP->ivsPush == KAL_FALSE) {
+            PsapSendStart();
+            eCallModemPSAP->ivsPush = KAL_TRUE;
+         }
+         if (eCallModemPSAP->msdReceived == KAL_TRUE) {
+            if ( ++eCallModemPSAP->frameStartHlackCur == eCallModemPSAP->frameStartHlack)
+               PsapSendHlack(eCallModemPSAP->CurMsd[0] & 0x0F);
+         }
+
+         /******************************************************
+         *  dl_pcm_input  -> dl_pcm_fifo    -> dl_pcm_output   *
+         *     32k               8k            32k             *
+         *                [BAUDOT] -> [ECALLLIB]                    * 
+         ******************************************************/
+
+         /* [ECALL blisrc] DL downsample start */
+         p_dl_ds_inBuf = eCallModemPSAP->dl_pcm_input[proc_idx];
+         p_dl_ds_outBuf = eCallModemPSAP->dl_pcm_fifo[proc_idx];
+
+         if(ECALL_WB_BUF_LEN == eCallModemPSAP->dl_pcm_input_len[proc_idx]) {
+             dl_ds_inLen  = ECALL_WB_BUF_LEN << 1;  
+             dl_ds_outLen = ECALL_NB_BUF_LEN << 1; 
+             BLI_Convert(eCallModemPSAP->dl_downsample_16_8, (short *)p_dl_ds_inBuf, &dl_ds_inLen, (short *)p_dl_ds_outBuf, &dl_ds_outLen);
+
+         } else if(ECALL_SWB_BUF_LEN ==eCallModemPSAP->dl_pcm_input_len[proc_idx]) {
+             dl_ds_inLen  = ECALL_SWB_BUF_LEN << 1;  
+             dl_ds_outLen = ECALL_NB_BUF_LEN << 1; 
+             BLI_Convert(eCallModemPSAP->dl_downsample_32_8, (short *)p_dl_ds_inBuf, &dl_ds_inLen, (short *)p_dl_ds_outBuf, &dl_ds_outLen);
+
+         } else{
+             memcpy(p_dl_ds_outBuf, p_dl_ds_inBuf, ECALL_NB_BUF_LEN << 1);
+         }
+         /* [ECALL blisrc] DL downsample end */
+
+         PsapRxProcess( (Int16 *)eCallModemPSAP->dl_pcm_fifo[proc_idx] );
+
+         if (eCallModemPSAP->TxRx) {
+            memcpy(eCallModemPSAP->ul_pcm_fifo[proc_idx], eCallModemPSAP->dl_pcm_fifo[proc_idx], ECALL_NB_BUF_LEN*sizeof(kal_uint16));
+
+            /*****************************************************
+             *  dl_pcm_output  <- dl_pcm_fifo  <- dl_pcm_input    *
+             *     32k               8k            32k            *
+             *                 [ECALLLIB] <- [BAUDOT]                  *
+             *****************************************************/
+
+            /* [ECALL blisrc] UL up sampling start */
+            //NB output
+            p_ul_us_inBuf = eCallModemPSAP->ul_pcm_fifo[proc_idx];
+            p_ul_us_outBuf = eCallModemPSAP->ul_pcm_output_nb[proc_idx];
+            memcpy(p_ul_us_outBuf, p_ul_us_inBuf, ECALL_NB_BUF_LEN << 1);
+
+            //WB output
+            ul_us_inLen = ECALL_NB_BUF_LEN << 1; 
+            ul_us_outLen = ECALL_WB_BUF_LEN << 1;
+            p_ul_us_outBuf = eCallModemPSAP->ul_pcm_output_wb[proc_idx];
+            BLI_Convert(eCallModemPSAP->ul_upsample_8_16, (short *)p_ul_us_inBuf, &ul_us_inLen, (short *)p_ul_us_outBuf, &ul_us_outLen);
+
+            //SWB output
+            ul_us_inLen = ECALL_NB_BUF_LEN << 1; 
+            ul_us_outLen = ECALL_SWB_BUF_LEN << 1;
+            p_ul_us_outBuf = eCallModemPSAP->ul_pcm_output_swb[proc_idx];
+            BLI_Convert(eCallModemPSAP->ul_upsample_8_32, (short *)p_ul_us_inBuf, &ul_us_inLen, (short *)p_ul_us_outBuf, &ul_us_outLen);
+            /* [ECALL blisrc] UL up sampling end */
+
+            eCallModemPSAP->isUpdateUL[proc_idx] = KAL_TRUE;
+            MD_TRC_ECALL_PSAP_PCM_UPDATE_UL(proc_idx, eCallModemPSAP->TxRx, proc_idx, eCallModemPSAP->isUpdateUL[proc_idx]);
+         }
+
+         break;
+      default:
+         ASSERT(0);
+         break;
+   }
+}
+
+static void eCall_PSAP_ProcessTask(void *data)
+{
+   if (eCallModemPSAP == NULL) {
+      return;
+   }
+   
+   while (eCallModemPSAP->next_to_process != eCallModemPSAP->pcm_fifo_write) {
+      // Process each frame
+      eCall_PSAP_ProcessFrame();
+      
+      // Update index
+      eCallModemPSAP->next_to_process++;
+      if (eCallModemPSAP->next_to_process == 2 * PCM_FIFO_LEN) {
+         eCallModemPSAP->next_to_process = 0;
+      }
+   }
+}
+
+static void eCall_PSAP_OnHandler( void *data ) 
+{
+   (void)data;
+   
+   PCM4WAY_Start(eCall_PSAP_hisr, 0);
+}
+
+static void eCall_PSAP_OffHandler( void *data ) 
+{      
+   (void)data;
+   
+   PCM4WAY_Stop(0);
+}
+
+eCall_Modem_Status eCall_PSAP_Open(eCall_Callback handler)
+{
+   ASSERT( handler != NULL );
+
+   if ( eCallModemIVS != NULL ) {
+      return eCALL_OPERATION_FAIL;
+   }
+
+   if ( eCallModemPSAP != NULL ) {
+      return eCALL_OPERATION_ALREADY_OPEN;
+   }
+   
+   //L1SP_EnableSpeechEnhancement(KAL_FALSE);
+   
+   //eCallModemPSAP = (EcallShell *)audio_alloc_mem_cacheable( sizeof(EcallShell) );
+   eCallModemPSAP = (EcallShell *)get_ctrl_buffer( sizeof(EcallShell) );
+   ASSERT( eCallModemPSAP != NULL );
+   memset(eCallModemPSAP, 0, sizeof(EcallShell));
+   
+   // Allocate for PSAP internal structure
+   {
+      kal_uint32 reqSize;
+      
+      reqSize = (kal_uint32) PsapGetMemSize();
+      //eCallModemPSAP->allocMem = (void *)audio_alloc_mem_cacheable( reqSize );
+	  eCallModemPSAP->allocMem = (void *)get_ctrl_buffer( reqSize );
+      memset(eCallModemPSAP->allocMem, 0, sizeof(reqSize));
+      PsapInit( eCallModemPSAP->allocMem );
+   }
+
+   // open BLI Src for ecall
+   // 32k <-> 8k
+   eCallModemPSAP->dl_downsample_32_8 = BLI_Open(32000, 1, 8000, 1, (signed char*)eCallModemPSAP->internal_buf_dl_in, 0); // open DL down sampling src
+   eCallModemPSAP->ul_upsample_8_32 = BLI_Open(8000, 1, 32000, 1, (signed char*)eCallModemPSAP->internal_buf_ul_out, 0); // open UL up sampling src
+   // 16k <-> 8k
+   eCallModemPSAP->dl_downsample_16_8 = BLI_Open(16000, 1, 8000, 1, (signed char*)eCallModemPSAP->internal_buf_dl_in2, 0); // open DL down sampling src
+   eCallModemPSAP->ul_upsample_8_16 = BLI_Open(8000, 1, 16000, 1, (signed char*)eCallModemPSAP->internal_buf_ul_out2, 0); // open UL up sampling src
+
+   eCallModemPSAP->aud_id = L1Audio_GetAudioID();
+   L1Audio_SetEventHandler(eCallModemPSAP->aud_id , eCall_PSAP_ProcessTask);
+   L1Audio_SetFlag(eCallModemPSAP->aud_id);
+   
+   PsapReset();
+   
+   eCallModemPSAP->mode = Psap; //PsapRx;
+   eCallModemPSAP->ivsPush = KAL_TRUE; //KAL_FALSE;
+   eCallModemPSAP->msdReceived = KAL_FALSE;
+   eCallModemPSAP->frameStartHlack = 10;
+   eCallModemPSAP->pcm_fifo_read = 0;
+   eCallModemPSAP->pcm_fifo_write = PCM_FIFO_LEN;
+   eCallModemPSAP->next_to_process = PCM_FIFO_LEN;
+   eCallModemPSAP->frameStartHlackCur = 0;
+   eCallModemPSAP->handler = handler;
+
+   for (int i=0; i<2*PCM_FIFO_LEN; i++) {
+       eCallModemPSAP->isUpdateUL[i] = KAL_FALSE;
+   }
+
+   if ( AM_IsSpeechOn() ) {
+      eCall_PSAP_OnHandler( (void *)0 );
+   }
+   
+   // Hook service to L1SP
+   L1SP_Register_Pcm4WayService( eCall_PSAP_OnHandler, eCall_PSAP_OffHandler );
+   
+   return eCALL_OPERATION_SUCCESS;
+}
+
+eCall_Modem_Status eCall_PSAP_Close(void)
+{
+   if( eCallModemPSAP == NULL ) {
+      return eCALL_OPERATION_ALREADY_CLOSE;
+   }
+   
+   if ( eCallModemIVS != NULL ) {
+      return eCALL_OPERATION_FAIL;
+   }
+   
+   // Unhook service to L1SP
+   L1SP_UnRegister_Pcm4Way_Service();
+   
+   if ( AM_IsSpeechOn() ) {
+      eCall_PSAP_OffHandler( (void *)0 );
+   }
+   
+   L1Audio_ClearFlag(eCallModemPSAP->aud_id);
+   L1Audio_FreeAudioID(eCallModemPSAP->aud_id);
+
+   BLI_Close(eCallModemPSAP->dl_downsample_16_8, 0); // Close DL down sampling src
+   BLI_Close(eCallModemPSAP->dl_downsample_32_8, 0); // Close DL down sampling src
+   BLI_Close(eCallModemPSAP->ul_upsample_8_16, 0); // Close UL up sampling src
+   BLI_Close(eCallModemPSAP->ul_upsample_8_32, 0); // Close UL up sampling src
+
+   // Deallocate for PSAP internal structure
+   {
+      PsapDeinit();
+      free_ctrl_buffer( (void *) eCallModemPSAP->allocMem );
+   }
+   
+   free_ctrl_buffer( (void *) eCallModemPSAP ); 
+   //L1SP_EnableSpeechEnhancement(KAL_TRUE);
+   eCallModemPSAP = NULL;
+   
+   return eCALL_OPERATION_SUCCESS;
+}
+
+eCall_Modem_Status eCall_PSAP_SendStart(void)
+{
+   if (eCallModemPSAP == NULL) {
+      return eCALL_OPERATION_FAIL;
+   }
+   
+   if ( eCallModemIVS != NULL ) {
+      return eCALL_OPERATION_FAIL;
+   }
+   
+   eCallModemPSAP->TxRx = KAL_TRUE;
+   eCallModemPSAP->mode = Psap;
+   eCallModemPSAP->ivsPush = KAL_FALSE;
+   
+   return eCALL_OPERATION_SUCCESS;
+}
+
+#else
+
+// Provide dummy function to support feature switchable
+void PsapReceiveMsd(const Ord8 *msd, int length) { }
+eCall_Modem_Status eCall_PSAP_Open(eCall_Callback handler) {return eCALL_OPERATION_FAIL;}
+eCall_Modem_Status eCall_PSAP_Close(void) {return eCALL_OPERATION_FAIL;}
+eCall_Modem_Status eCall_PSAP_SendStart(void) {return eCALL_OPERATION_FAIL;}
+
+#endif