/*
Description:
AT command handler, handle command AT commands at*maudvol=P1,P2,P3
Parameters:
	pChip -- Pointer to chip data structure
	ParamCount -- Count of parameter array
	Params  --- P1,P2,...,P6
*/
int AtMaudVol(brcm_alsa_chip_t *pChip, Int32 ParamCount, Int32 *Params)
{
	int *pVolume;
	int mode, vol;

	aTrace(LOG_AUDIO_DRIVER, "%s P1-P6=%ld %ld %ld %ld %ld %ld cnt=%ld\n",
			__func__, Params[0], Params[1], Params[2],
			Params[3], Params[4], Params[5], ParamCount);

	csl_caph_ControlHWClock(TRUE);

	switch (Params[0]) {
	case 6:		/*at*maudvol=6 */
		mode = AUDCTRL_GetAudioMode();
		/*Get volume. Range -36 ~ 0 dB in Driver and DSP: */
		Params[0] =
		    AUDCTRL_GetTelephonySpkrVolume(AUDIO_GAIN_FORMAT_mB);
		Params[0] = Params[0] / 100;	/* dB */
		Params[0] += AudParmP()[mode].voice_volume_max;
		/* Range 0~36 dB shown in PCG */
		/*
		pVolume = pChip->streamCtl[
		CTL_STREAM_PANEL_VOICECALL -1].ctlLine[mode].iVolume;
		Params[0] = pVolume[0];
		*/
		aTrace(LOG_AUDIO_DRIVER,
				"%s pVolume[0] %ld\n", __func__, Params[0]);
		return 0;

	case 7:		/* at*maudvol=7,x    Range 0~36 dB in PCG */
		mode = AUDCTRL_GetAudioMode();
		/*
		   mode = pChip->streamCtl[
		   CTL_STREAM_PANEL_VOICECALL-1].iLineSelect[1];
		 */
		pVolume =
		    pChip->streamCtl[CTL_STREAM_PANEL_VOICECALL -
				     1].ctlLine[mode].iVolume;
		pVolume[0] = Params[1];
		pVolume[1] = Params[1];
		vol = Params[1];
		vol -= AudParmP()[mode].voice_volume_max;
		/* Range -36 ~ 0 dB in DSP */
		AUDCTRL_SetTelephonySpkrVolume(AUDIO_SINK_UNDEFINED,
					       (vol * 100),
					       AUDIO_GAIN_FORMAT_mB);

		aTrace(LOG_AUDIO_DRIVER, "%s pVolume[0] %d mode=%d vol %d\n",
				__func__, pVolume[0], mode, vol);
		return 0;

	default:
		aWarn("%s Unsupported cmd %ld\n", __func__,
				Params[0]);
		break;
	}
	return -1;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//AUDIO_Policy_Get_Mode
//	Identifies the mode to be applied.
//----------------------------------------------------------------
UInt32 AUDIO_Policy_Get_Mode(UInt32 mode)
{
    AudioMode_t  new_mode, cur_mode;

    cur_mode = AUDCTRL_GetAudioMode();

    if ( cur_mode >= AUDIO_MODE_NUMBER )
        cur_mode = (AudioMode_t) (cur_mode - AUDIO_MODE_NUMBER);

    if(tState == BRCM_STATE_INCALL)
        new_mode = cur_mode;
    else 
        new_mode = mode;

    return new_mode;
}
int AtMaudMode(brcm_alsa_chip_t *pChip, Int32 ParamCount, Int32 *Params)
{
	AUDIO_SOURCE_Enum_t mic = AUDIO_SOURCE_ANALOG_MAIN;
	AUDIO_SINK_Enum_t spk = AUDIO_SINK_HANDSET;
	AudioMode_t mode = AUDIO_SINK_HANDSET;
	AudioApp_t app = AUDIO_APP_VOICE_CALL, currapp;
	int rtn = 0;		/* 0 means Ok */
	static UInt8 loopback_status = 0, loopback_input = 0, loopback_output =
	    0, sidetone_mode = 0;
	static UInt8 loopback_api_input, loopback_api_output;
	Int32 pCurSel[2];

	aTrace(LOG_AUDIO_DRIVER, "%s P1-P6=%ld %ld %ld %ld %ld %ld cnt=%ld\n",
			__func__, Params[0], Params[1], Params[2],
			Params[3], Params[4], Params[5], ParamCount);

	csl_caph_ControlHWClock(TRUE);

	switch (Params[0]) {

	case 0:		/* at*maudmode 0 */
		break;

	case 1:		/* at*maudmode 1 mode */
		break;

	case 8:		/* at*maudmode=8 */
		Params[0] = loopback_status;
		aTrace(LOG_AUDIO_DRIVER,
				" %s loopback status is %d\n", __func__,
				loopback_status);
		DEBUG(" %s loopback status is %d\n", __func__, loopback_status);
		break;

	case 9:		/* at*maudmode=9,x.  x = 0 --> disable; x =1 enable */
		loopback_status = Params[1];
		if (loopback_status > 1)
			loopback_status = 1;

		aTrace(LOG_AUDIO_DRIVER,
				" %s set loopback status %d (1:ena 0:dis)\n",
				__func__, loopback_status);

		break;

	case 10:		/* at*maudmode=10  --> get loopback path */
		/* Per PCG request
		   if (loopback_output > 2) loopback_output = 2; */

		Params[0] = loopback_input;
		Params[1] = loopback_output;
		aTrace(LOG_AUDIO_DRIVER,
				"%s loopback path is from src %d to sink %d\n",
				__func__, loopback_input, loopback_output);
		break;

		/* at*maudmode=11,x,y  --> set loopback path. */
		/* mic: 0 = default mic, 1 = main mic */
		/* spk: 0 = handset, 1 = headset, 2 = loud speaker */
	case 11:
		loopback_input = loopback_api_input = Params[1];
		loopback_output = loopback_api_output = Params[2];
		sidetone_mode = Params[3];

		if (((loopback_input > 6) && (loopback_input != 11)) ||
		    ((loopback_output > 2) && (loopback_output != 9) &&
		     (loopback_output != 4))) {
			aError(
					"%s srr/sink exceeds its range.\n",
					__func__);
			rtn = -1;
			break;
		}
		if (loopback_output == 2)	/* use IHF */
			loopback_api_output = 4;
		if (loopback_input == 0)	/* default mic: use main mic */
			loopback_api_input = 1;

		loopback_status = 1;
		/* enable the HW loopback without DSP. */
		AUDCTRL_SetAudioLoopback(TRUE, loopback_api_input,
					 loopback_api_output, sidetone_mode);

		aTrace(LOG_AUDIO_DRIVER,
				"%s ena lpback: src %d sink %d sidetone %d\n",
				__func__, loopback_api_input,
			loopback_api_output, sidetone_mode);
		break;

	case 12:		/* at*maudmode=12  --> disable loopback path */
		loopback_status = 0;
		AUDCTRL_SetAudioLoopback(FALSE, loopback_api_input,
			loopback_api_output, sidetone_mode);
		aTrace(LOG_AUDIO_DRIVER,
				"%s dis lpback: src %d sink %d sidetone %d\n",
				__func__, loopback_api_input,
			loopback_api_output, sidetone_mode);
		break;

	case 13:		/* at*maudmode=13  --> Get call ID */
		aError(
				"%s get call ID is not supported\n", __func__);
		rtn = -1;
		break;
		/* at*maudmode=14  --> read current mode and app */
	case 14:
		Params[0] = AUDCTRL_GetAudioApp();
		Params[1] = AUDCTRL_GetAudioMode();
		aTrace(LOG_AUDIO_DRIVER, "%s app %ld mode %ld\n",
				__func__, Params[0], Params[1]);
		break;
		/* at*maudmode=15  --> set current mode and app */
	case 15:
		app = Params[1];
		mode = Params[2];
		AUDCTRL_GetSrcSinkByMode(mode, &mic, &spk);
		pCurSel[0] =
		    pChip->streamCtl[CTL_STREAM_PANEL_VOICECALL -
				     1].iLineSelect[0];
		/* save current setting */
		pCurSel[1] = pChip->
		    streamCtl[CTL_STREAM_PANEL_VOICECALL - 1].iLineSelect[1];

		/* Update 'VC-SEL' -- */
		pChip->streamCtl[CTL_STREAM_PANEL_VOICECALL - 1].
		    iLineSelect[0] = mic;
		pChip->streamCtl[CTL_STREAM_PANEL_VOICECALL - 1].
		    iLineSelect[1] = spk;
#ifdef CONFIG_BCM_MODEM
		RPC_SetProperty(RPC_PROP_AUDIO_MODE,
			(UInt32)(app * AUDIO_MODE_NUMBER + mode));
#endif
		/* for PCG to set new app */
		currapp = AUDCTRL_GetAudioApp();
		if (currapp != app) {
			/* Remove the current app
			before setting the new app */
			AUDCTRL_RemoveAudioApp(currapp);
			AUDCTRL_SaveAudioApp(app);
		}

		if (app == AUDIO_APP_VOICE_CALL
		    || app == AUDIO_APP_VOICE_CALL_WB
		    || app == AUDIO_APP_VT_CALL
		    || app == AUDIO_APP_VT_CALL_WB) {
			AUDCTRL_SetTelephonyMicSpkr(mic, spk, false);
			AUDCTRL_SetAudioMode(mode, app);
		} else if (app == AUDIO_APP_MUSIC) {
			if (AUDCTRL_InVoiceCall() == FALSE) {
				AUDCTRL_SwitchPlaySpk_forTuning(mode);
				AUDCTRL_SaveAudioMode(mode);
				AUDCTRL_SaveAudioApp(app);
			}
		} else {
			/* Handling all other apps cases */
			/* For PCG to set new Mode */
			AUDCTRL_SetAudioMode(mode, app);
		}

		aTrace(LOG_AUDIO_DRIVER, "%s mic %d spk %d mode %ld app %ld\n",
			__func__, mic, spk, Params[2],
			Params[1]);
		break;

	/* read back AUDIO_APP_NUMBER and AUDIO_APP_MM_NUMBER */
	/* needs to match to enum AudioTuneCommand_t in at_audtune.c */
	case 16:
		Params[0] = AUDIO_APP_NUMBER;
		Params[1] = AUDIO_APP_MM_NUMBER;
		break;

	case 99:		/* at*maudmode=99  --> stop tuning */
		break;

		/* at*maudmode=100  --> set external audio
		   amplifer gain in PMU */
		/* PCG and loadcal currently use Q13p2 gain format */
	case 100:
		{
		short gain;

		gain = (short)Params[3];

		if (Params[1] == 3) {
			aTrace(LOG_AUDIO_DRIVER, "Params[2] = %d, "
				"Params[3] %d, audio mode %d\n",
				(int)Params[2], (int)Params[3],
				AUDCTRL_GetAudioMode());
			if ((Params[2] == PARAM_PMU_SPEAKER_PGA_LEFT_CHANNEL)
			|| (Params[2] == PARAM_PMU_SPEAKER_PGA_RIGHT_CHANNEL)) {
				if (AUDCTRL_GetAudioMode() == AUDIO_MODE_HEADSET
					|| AUDCTRL_GetAudioMode() ==
					AUDIO_MODE_TTY) {
						aTrace(LOG_AUDIO_DRIVER,
						"%s ext headset "
						"speaker gain = %d\n",
						__func__, gain);

					if (Params[2] ==
					PARAM_PMU_SPEAKER_PGA_LEFT_CHANNEL)
						extern_hs_set_gain(gain*25,
						AUDIO_HS_LEFT);
					else if (Params[2] ==
					PARAM_PMU_SPEAKER_PGA_RIGHT_CHANNEL)
						extern_hs_set_gain(gain*25,
						AUDIO_HS_RIGHT);
				} else if (AUDCTRL_GetAudioMode() ==
					AUDIO_MODE_SPEAKERPHONE) {
					aTrace(LOG_AUDIO_DRIVER, "%s ext IHF "
						"speaker gain = %d\n",
						__func__, gain);
					extern_ihf_set_gain(gain*25);
				}

			}
			/* Params[2] checking */
			aTrace(LOG_AUDIO_DRIVER,
				    "Params[2] = %d, Params[3] %d,"
				     " audio mode %d\n",
				     (int)Params[2], (int)Params[3],
				     AUDCTRL_GetAudioMode());

			if (Params[2] == PARAM_PMU_HIGH_GAIN_MODE_FLAG) {
				if (AUDCTRL_GetAudioMode() ==
					AUDIO_MODE_SPEAKERPHONE) {
					aTrace(LOG_AUDIO_DRIVER,
						"ext IHF high gain "
						"mode = %d\n",
						(int)Params[3]);
					extern_ihf_en_hi_gain_mode(
						(int)Params[3]);
				} else if (AUDCTRL_GetAudioMode() ==
					AUDIO_MODE_HEADSET ||
					AUDCTRL_GetAudioMode() ==
					AUDIO_MODE_TTY) {
					aTrace(LOG_AUDIO_DRIVER,
						"ext HS high gain "
						"mode = %d\n",
						(int)Params[3]);
					extern_hs_en_hi_gain_mode(
						(int)Params[3]);
				}
			}
		}	/* if (Params[1] == 3) */
		}		/* case 100 */

		break;

	default:
		aWarn("%s Unsupported cmd %ld\n", __func__,
				Params[0]);
		rtn = -1;
		break;
	}

	return rtn;
}
static long voip_ioctl(struct file *hw, unsigned int cmd, unsigned long arg)
{
	bcm_caph_hwdep_voip_t *pvoip;
	voipdev *pvoipchrdevpvtdata;
	long ret = 0;
	Boolean enable = FALSE;
	Int32 size = 0;
	int data;
	voip_codec_type_data_t val;
	static UserCtrl_data_t *dataptr;
	brcm_alsa_chip_t *pchip = NULL;
	struct treq_sysparm_t *eq;
	struct snd_card *pcard = NULL;
	int rc;
	pvoipchrdevpvtdata = (voipdev *)hw->private_data;
	pvoip = (bcm_caph_hwdep_voip_t *)pvoipchrdevpvtdata->pvoip;
	pcard =  (struct snd_card *)pvoipchrdevpvtdata->card;
	pchip = (brcm_alsa_chip_t *)pcard->private_data;
	aTrace(LOG_ALSA_INTERFACE, "ALSA-CAPH hwdep_ioctl cmd=%08X\n", cmd);
	switch (cmd) {
	case VoIP_Ioctl_GetVersion:
		/* ret = put_user(BrcmAACEncVersion, (int __user *)arg); */
		break;
	case VoIP_Ioctl_Start:
		get_user(data, (int __user *)arg);
		aTrace(LOG_ALSA_INTERFACE, "VoIP_Ioctl_Start type=%d (2==UL)"
			"voipinstcnt=%u\n", data, voipinstcnt);
		rc = down_interruptible(&sVoipAction);
		if (rc)		
			return rc;
		
		aTrace(LOG_ALSA_INTERFACE,"VoIP_Ioctl_Start: acquired sVoipAction\n");
		if (voipinstcnt == 0) { /* start VoIP only once */
			BRCM_AUDIO_Param_RateChange_t param_rate_change;
			BRCM_AUDIO_Param_Open_t param_open;
			BRCM_AUDIO_Param_Prepare_t parm_prepare;
			BRCM_AUDIO_Param_Start_t param_start;
			voipinstcnt++;
			aTrace(LOG_ALSA_INTERFACE,"voipinstcnt=%d\n", voipinstcnt);
#if 0
			hw->private_data =
			    kzalloc(sizeof(bcm_caph_hwdep_voip_t), GFP_KERNEL);
			CAPH_ASSERT(hw->private_data);
			pvoip = (bcm_caph_hwdep_voip_t *) hw->private_data;
#endif
			pvoipchrdevpvtdata->pvoip =
			    kzalloc(sizeof(bcm_caph_hwdep_voip_t), GFP_KERNEL);
			pvoip = pvoipchrdevpvtdata->pvoip;
			CAPH_ASSERT(pvoip);
			init_waitqueue_head(&pvoip->sleep);
			pvoip->buffer_handle =
			    (audio_voip_driver_t *)
			    kzalloc(sizeof(audio_voip_driver_t), GFP_KERNEL);

			aTrace(LOG_ALSA_INTERFACE,"pvoip->buffer_handle=0x%x",pvoip->buffer_handle);
			
			if (pvoip->buffer_handle)
				memset((u8 *) pvoip->buffer_handle, 0,
				       sizeof(audio_voip_driver_t));
			else {
				pvoip->buffer_handle = NULL;
				voipinstcnt--;
				up(&sVoipAction);
				aError("voip_ioctl failed with ENOMEM 1");
				return -ENOMEM;
			}
/*ul data*/
			if (pchip->voip_data.codec_type_ul == VoIP_Codec_None)
			{
				if (pchip->voip_data.codec_type_dl != VoIP_Codec_None)
					pchip->voip_data.codec_type_ul = pchip->voip_data.codec_type_dl;
				else
					pchip->voip_data.codec_type_ul = VoIP_Codec_PCM_16K; // by default

				aTrace(LOG_ALSA_INTERFACE, "VoIP_Ioctl_Start: VoIPCmd forced UL codec [0x%x]\n",
					pchip->voip_data.codec_type_ul);
			}
			pvoip->codec_type_ul = pchip->voip_data.codec_type_ul;
			pvoip->frame_size_ul = svoipframelen[pvoip->
								codec_type_ul - 1];
			pvoip->buffer_size_ul = pvoip->frame_size_ul *
							VOIP_FRAMES_IN_BUFFER;
			pvoip->buffer_handle->voip_data_ul_buf_ptr =
			kzalloc(pvoip->buffer_size_ul, GFP_KERNEL);

			aTrace(LOG_ALSA_INTERFACE, "VoIP_Ioctl_Start: voip_data_ul_buf_ptr=0x%x,"
				"buffer_size_ul=%d\n",
			pvoip->buffer_handle->voip_data_ul_buf_ptr,
			pvoip->buffer_size_ul);
			
			if (pvoip->buffer_handle->voip_data_ul_buf_ptr)
				memset(pvoip->buffer_handle->
				       voip_data_ul_buf_ptr, 0,
				       pvoip->buffer_size_ul);
			else {
				if (pvoip->buffer_handle->
					voip_data_dl_buf_ptr) {
					kfree(pvoip->buffer_handle->
						voip_data_dl_buf_ptr);
					pvoip->buffer_handle->
						voip_data_dl_buf_ptr = NULL;
				}
				pvoip->buffer_handle->voip_data_ul_buf_ptr =
									NULL;
				kfree(pvoip->buffer_handle);
				pvoip->buffer_handle = NULL;
				voipinstcnt--;
				up(&sVoipAction);
				aError("voip_ioctl failed with ENOMEM 2");
				return -ENOMEM;
			}
/*dl data*/
			if (pchip->voip_data.codec_type_dl == VoIP_Codec_None)
			{
				if (pchip->voip_data.codec_type_ul != VoIP_Codec_None)
					pchip->voip_data.codec_type_dl = pchip->voip_data.codec_type_ul;
				else
					pchip->voip_data.codec_type_dl = VoIP_Codec_PCM_16K; // by default
				aTrace(LOG_ALSA_INTERFACE, "VoIP_Ioctl_Start: VoIPCmd forced DL codec [0x%x]\n",
					pchip->voip_data.codec_type_dl);
			}
			pvoip->codec_type_dl = pchip->voip_data.codec_type_dl;
			pvoip->frame_size_dl = svoipframelen[pvoip->
								codec_type_dl - 1];
			pvoip->buffer_size_dl = pvoip->frame_size_dl *
							VOIP_FRAMES_IN_BUFFER;
			pvoip->buffer_handle->voip_data_dl_buf_ptr =
				kzalloc(pvoip->buffer_size_dl, GFP_KERNEL);
			if (pvoip->buffer_handle->voip_data_dl_buf_ptr) {
				memset(pvoip->buffer_handle->
				       voip_data_dl_buf_ptr, 0,
				       pvoip->buffer_size_dl);
			} else {
				if (pvoip->buffer_handle->
					voip_data_ul_buf_ptr) {
					kfree(pvoip->buffer_handle->
						voip_data_ul_buf_ptr);
					pvoip->buffer_handle->
						voip_data_ul_buf_ptr = NULL;
				}
				pvoip->buffer_handle->voip_data_dl_buf_ptr =
									NULL;
				kfree(pvoip->buffer_handle);
				pvoip->buffer_handle = NULL;
				voipinstcnt--;
				up(&sVoipAction);
				aError("voip_ioctl failed with ENOMEM 3");
				return -ENOMEM;
			}
			param_open.drv_handle = NULL;
			param_open.drv_type = AUDIO_DRIVER_VOIP;
			AUDIO_Ctrl_Trigger(ACTION_AUD_OpenVoIP,
				&param_open, NULL, 1);
			pvoip->buffer_handle->drv_handle =
				param_open.drv_handle;
			if (!pvoip->buffer_handle->drv_handle) {
				kfree(pvoip->buffer_handle->
				      voip_data_dl_buf_ptr);
				pvoip->buffer_handle->
				      voip_data_dl_buf_ptr = NULL;
				kfree(pvoip->buffer_handle->
				      voip_data_ul_buf_ptr);
				pvoip->buffer_handle->
				      voip_data_ul_buf_ptr = NULL;
				kfree(pvoip->buffer_handle);
				pvoip->buffer_handle = NULL;
				voipinstcnt--;
				up(&sVoipAction);
				aError("voip_ioctl failed with ENOMEM 4");
				return -ENOMEM;
			}
			/* set UL callback */
			parm_prepare.drv_handle =
				pvoip->buffer_handle->drv_handle;
			parm_prepare.cbParams.voipULCallback =
				HWDEP_VOIP_DumpUL_CB;
			parm_prepare.cbParams.pPrivateData = (void *)pvoip;
			AUDIO_Ctrl_Trigger(
				ACTION_AUD_SET_VOIP_UL_CB,
				&parm_prepare, NULL, 0);
			/* set DL callback */
			parm_prepare.drv_handle =
				pvoip->buffer_handle->drv_handle;
			parm_prepare.cbParams.voipDLCallback =
				HWDEP_VOIP_FillDL_CB;
			parm_prepare.cbParams.pPrivateData = (void *)pvoip;
			AUDIO_Ctrl_Trigger(
				ACTION_AUD_SET_VOIP_DL_CB,
				&parm_prepare, NULL, 0);
			/* VoIP is always 16K.
			No need to set the codec type here*/
			if (isvolte) {
				if (((data == VoIP_UL) &&
					((pvoip->codec_type_ul == VoIP_Codec_PCM_16K) ||
					(pvoip->codec_type_ul == VOIP_Codec_AMR_WB_7K)))
				|| ((data == VoIP_DL) &&
					((pvoip->codec_type_dl == VoIP_Codec_PCM_16K) ||
					(pvoip->codec_type_dl == VOIP_Codec_AMR_WB_7K)))) {
					/* VOIP_PCM_16K or
					VOIP_AMR_WB_MODE_7k */
				param_rate_change.codecID = 0x0A;
			} else
				param_rate_change.codecID = 0x06;
			AUDIO_Ctrl_Trigger(ACTION_AUD_RateChange,
					&param_rate_change, NULL, 0);
			}
			param_start.drv_handle =
				pvoip->buffer_handle->drv_handle;
			param_start.data = (void *)&pchip->voip_data;
			AUDIO_Ctrl_Trigger(ACTION_AUD_StartVoIP,
				&param_start, NULL, 0);
			pvoip->writecount = VOIP_FRAMES_IN_BUFFER;
			pvoip->status = voip_hwdep_status_started;
			aTrace(LOG_ALSA_INTERFACE, "Status made to voip_hwdep_status_started");
		} else {
			voipinstcnt++;
			/*Limit Voip instance to two*/
			if (voipinstcnt > 2)
				voipinstcnt = 2;
			aTrace(LOG_ALSA_INTERFACE,
					"VoIP_Ioctl_Start -> just increment "
					"the count, voip already started voipinstcnt=%d\n", voipinstcnt);
		}
		if (pvoip != NULL) {
			if (data == VoIP_UL)
				pvoip->ulstarted = 1;
			else
				pvoip->dlstarted = 1;
		}
		up(&sVoipAction);
		aTrace(LOG_ALSA_INTERFACE, "VoIP_Ioctl_Start END voipinstcnt=%d\n",voipinstcnt);
		break;
	case VoIP_Ioctl_Stop:
		get_user(data, (int __user *)arg);
		aTrace(LOG_ALSA_INTERFACE, "VoIP_Ioctl_Stop type=%d (2==UL) "
			"voipinstcnt=%u\n", data, voipinstcnt);
		rc = down_interruptible(&sVoipAction);
		if (rc)		
			return rc;
		aTrace(LOG_ALSA_INTERFACE, "VoIP_Ioctl_Stop acquired sVoipAction");
		if (data == VoIP_UL)
			pvoip->ulstarted = 0;
		else
			pvoip->dlstarted = 0;
		if (voipinstcnt >= 2)
		{
			voipinstcnt--;
			aTrace(LOG_ALSA_INTERFACE, "VoIP_Ioctl_Stop--1--voipinstcnt=%d\n", voipinstcnt);
		}	
		else if ((voipinstcnt < 2) ||
				(pvoip->ulstarted == 0 &&
					pvoip->dlstarted == 0)) {
			BRCM_AUDIO_Param_Stop_t param_stop;
			BRCM_AUDIO_Param_Close_t param_close;
			voipinstcnt = 0;
			aTrace(LOG_ALSA_INTERFACE, "VoIP_Ioctl_Stop--2--voipinstcnt=%d\n", voipinstcnt);
			if (pvoip->buffer_handle)
			param_stop.drv_handle =
				pvoip->buffer_handle->drv_handle;
			else
				param_stop.drv_handle = NULL;
			AUDIO_Ctrl_Trigger(ACTION_AUD_StopVoIP,
				&param_stop, NULL, 0);
			if (pvoip->buffer_handle)
			param_close.drv_handle =
				pvoip->buffer_handle->drv_handle;
			else
				param_close.drv_handle = NULL;
			AUDIO_Ctrl_Trigger(ACTION_AUD_CloseVoIP,
				&param_close, NULL, 1);
			if (pvoip->buffer_handle) {
			kfree(pvoip->buffer_handle->voip_data_dl_buf_ptr);
			pvoip->buffer_handle->voip_data_dl_buf_ptr = NULL;
			kfree(pvoip->buffer_handle->voip_data_ul_buf_ptr);
			pvoip->buffer_handle->voip_data_ul_buf_ptr = NULL;
			kfree(pvoip->buffer_handle);
			pvoip->buffer_handle = NULL;
			}
			pvoip->status = voip_hwdep_status_stopped;
			wake_up(&pvoip->sleep);
		}
		up(&sVoipAction);
		break;
	case VoIP_Ioctl_SetSource:
		aTrace(LOG_ALSA_INTERFACE ,
				" Warning: VoIP_Ioctl_SetSource"
				"is depreciated , please"
				"use mixer control VC-SEL instead\n");
		break;
	case VoIP_Ioctl_SetSink:
		aTrace(LOG_ALSA_INTERFACE ,
				" Warning: VoIP_Ioctl_SetSink"
				"is depreciated, please"
				"use mixer control VC-SEL instead\n");
		break;
	case VoIP_Ioctl_SetCodecType:
		aTrace(LOG_ALSA_INTERFACE, "VoIP_Ioctl_SetCodecType\n");
		copy_from_user(&val, (int __user *)arg,
				   sizeof(voip_codec_type_data_t));
		if (val.ul_dl_type == VoIP_UL) {
			pchip->voip_data.codec_type_ul = val.codec_type;
			aTrace(LOG_ALSA_INTERFACE,
				" VoIP_Ioctl_SetCodecType (UL) codec_type %ld\n",
				pchip->voip_data.codec_type_ul);
		/*pvoip = (bcm_caph_hwdep_voip_t *) hw->private_data;*/
			if (!pvoip)
				break;
			pvoip->codec_type_ul = pchip->voip_data.codec_type_ul;
		} else {
			pchip->voip_data.codec_type_dl = val.codec_type;
			aTrace(LOG_ALSA_INTERFACE,
				" VoIP_Ioctl_SetCodecType (DL) codec_type %ld\n",
				pchip->voip_data.codec_type_dl);
		/*pvoip = (bcm_caph_hwdep_voip_t *) hw->private_data;*/
			if (!pvoip)
				break;
			pvoip->codec_type_dl = pchip->voip_data.codec_type_dl;
		}
		/*Check whether in a VoLTE call*/
		/*If no, do nothing.*/
		/*If yes, do the NB<->WB switching*/
		if (isvolte) {
			BRCM_AUDIO_Param_RateChange_t param_rate_change;
			if (pvoip->ulstarted == 0 && pvoip->dlstarted == 0)
				break;
			if (!(pvoip->buffer_handle))
				break;
			if (!(pvoip->buffer_handle->drv_handle))
				break;
			AUDIO_DRIVER_Ctrl(pvoip->buffer_handle->drv_handle,
				AUDIO_DRIVER_SET_AMR, &pchip->voip_data);
			if (((val.ul_dl_type == VoIP_UL) &&
				((pvoip->codec_type_ul == VoIP_Codec_PCM_16K) ||
				(pvoip->codec_type_ul == VOIP_Codec_AMR_WB_7K)))
			|| ((val.ul_dl_type == VoIP_DL) &&
				((pvoip->codec_type_dl == VoIP_Codec_PCM_16K) ||
				(pvoip->codec_type_dl == VOIP_Codec_AMR_WB_7K))))
				/* VOIP_PCM_16K or VOIP_AMR_WB_MODE_7k */
					param_rate_change.codecID = 0x0A;
			else
					param_rate_change.codecID = 0x06;
			AUDIO_Ctrl_Trigger(ACTION_AUD_RateChange,
					&param_rate_change, NULL, 0);
		}
		break;
	case VoIP_Ioctl_SetBitrate:
		get_user(data, (int __user *)arg);
		pchip->voip_data.bitrate_index = (u32) data;
		aTrace(LOG_ALSA_INTERFACE,
				" VoIP_Ioctl_SetBitrate bitrate_index %ld,\n",
				pchip->voip_data.bitrate_index);
		/*pvoip = (bcm_caph_hwdep_voip_t *) hw->private_data;*/
		if (!pvoip)
			break;
		if (isvolte) {
			if (pvoip->ulstarted == 0 && pvoip->dlstarted == 0)
				break;
			if (!(pvoip->buffer_handle))
				break;
			if (!(pvoip->buffer_handle->drv_handle))
				break;
			AUDIO_DRIVER_Ctrl(pvoip->buffer_handle->drv_handle,
				AUDIO_DRIVER_SET_AMR, &pchip->voip_data);
		}
		break;
	case VoIP_Ioctl_GetSource:
		{
		s32 *psel;
		psel = pchip->streamCtl[CTL_STREAM_PANEL_VOICECALL - 1]
			.iLineSelect;
		data = (int)psel[0];
		put_user(data, (int __user *)arg);
		}
		break;
	case VoIP_Ioctl_GetSink:
		{
		s32 *psel;
		psel = pchip->streamCtl[CTL_STREAM_PANEL_VOICECALL - 1]
			.iLineSelect;
		data = (int)psel[1];
		put_user(data, (int __user *)arg);
		}
		break;
	case VoIP_Ioctl_GetCodecType:
		aTrace(LOG_ALSA_INTERFACE, "voip_ioctl in VoIP_Ioctl_GetCodecType");
		copy_from_user(&val, (int __user *)arg,
				   sizeof(voip_codec_type_data_t));
		if (val.ul_dl_type == VoIP_UL)
			val.codec_type = (int)pchip->voip_data.codec_type_ul;
		else
			val.codec_type = (int)pchip->voip_data.codec_type_dl;
		aTrace(LOG_ALSA_INTERFACE,
			" VoIP_Ioctl_GetCodecType (UL:DL) codec_type %ld:%ld\n",
			pchip->voip_data.codec_type_ul, pchip->voip_data.codec_type_dl);
		copy_to_user((int __user *)arg, &val,
				   sizeof(voip_codec_type_data_t));
		break;
	case VoIP_Ioctl_GetBitrate:
		data = (int)pchip->voip_data.bitrate_index;
		put_user(data, (int __user *)arg);
		break;
	case VoIP_Ioctl_GetMode:
		{
			AudioMode_t mode = AUDCTRL_GetAudioMode();
			put_user((int)mode, (int __user *)arg);
			aTrace(LOG_ALSA_INTERFACE,
					" VoIP_Ioctl_GetMode mode %d,\n",
					mode);
		}
		break;
	case VoIP_Ioctl_SetMode:
		aTrace(LOG_ALSA_INTERFACE ,
				" Warning: VoIP_Ioctl_SetMode"
				"is depreciated, please "
				"use mixer control VC-SEL instead\n");
		break;
	case VoIP_Ioctl_SetVoLTEDTX:
		get_user(data, (int __user *)arg);
		pchip->voip_data.isDTXEnabled = (u8) data;
		aTrace(LOG_ALSA_INTERFACE, " VoIP_Ioctl_SetVoLTEDTX %d,\n",
				pchip->voip_data.isDTXEnabled);
		/*pvoip = (bcm_caph_hwdep_voip_t *) hw->private_data;*/
		if (!pvoip)
			break;
		if (!(pvoip->buffer_handle))
			break;
		if (!(pvoip->buffer_handle->drv_handle))
			break;
		AUDIO_DRIVER_Ctrl(pvoip->buffer_handle->drv_handle,
				AUDIO_DRIVER_SET_DTX, &pchip->voip_data);
		break;
	case VoIP_Ioctl_SetVoLTEFlag:
		get_user(data, (int __user *)arg);
		pchip->voip_data.isVoLTE = (u8) data;
		aTrace(LOG_ALSA_INTERFACE, " VoIP_Ioctl_SetFlag isVoLTE %d,\n",
				pchip->voip_data.isVoLTE);
		isvolte = pchip->voip_data.isVoLTE;
		break;
	case VoIP_Ioctl_GetVoLTEFlag:
		data = (int)pchip->voip_data.isVoLTE;
		put_user(data, (int __user *)arg);
		break;
	case DSPCtrl_Ioctl_SPCtrl:
		if (dataptr == NULL)
			dataptr = kzalloc(sizeof(UserCtrl_data_t), GFP_KERNEL);
		else
			memset(dataptr, 0, sizeof(UserCtrl_data_t));
		if (!dataptr)
			return -ENOMEM;
		ret =
		    copy_from_user(dataptr, (int __user *)arg,
				   sizeof(UserCtrl_data_t));
		enable = (Boolean) dataptr->data[0];
		size = dataptr->data[1];
		ret =
		    AUDDRV_User_CtrlDSP(AUDDRV_USER_SP_CTRL, enable, size,
					(void *)&(dataptr->data[2]));
		if (!enable) {
			kfree(dataptr);
			dataptr = NULL;
		}
		break;
	case DSPCtrl_Ioctl_SPSetVar:
		/*
		 * Will move this part later after we separate the voip and
		 * dspctrl connections.
		 */
		if (dataptr == NULL)
			dataptr = kzalloc(sizeof(UserCtrl_data_t), GFP_KERNEL);
		else
			memset(dataptr, 0, sizeof(UserCtrl_data_t));
		if (!dataptr)
			return -ENOMEM;
		ret =
		    copy_from_user(dataptr, (int __user *)arg,
				   sizeof(UserCtrl_data_t));
		size = dataptr->data[0];
		ret =
		    AUDDRV_User_CtrlDSP(AUDDRV_USER_SP_VAR, enable, size,
					(void *)&(dataptr->data[2]));
		break;
	case DSPCtrl_Ioctl_SPQuery:
		if (dataptr == NULL)
			dataptr = kzalloc(sizeof(UserCtrl_data_t), GFP_KERNEL);
		else
			memset(dataptr, 0, sizeof(UserCtrl_data_t));
		if (!dataptr)
			return -ENOMEM;
		ret =
		    AUDDRV_User_CtrlDSP(AUDDRV_USER_SP_QUERY, enable, size,
					(void *)dataptr);
		if (ret < 0)
			return ret;
		if (copy_to_user
		    ((int __user *)arg, dataptr, sizeof(UserCtrl_data_t)))
			return -EFAULT;
		break;
	case DSPCtrl_Ioctl_EQCtrl:
		if (dataptr == NULL)
			dataptr = kzalloc(sizeof(UserCtrl_data_t), GFP_KERNEL);
		else
			memset(dataptr, 0, sizeof(UserCtrl_data_t));
		if (!dataptr)
			return -ENOMEM;
		if (copy_from_user
		    (dataptr, (int __user *)arg, sizeof(UserCtrl_data_t)))
			return -EFAULT;
		enable = (Boolean) dataptr->data[0];
		ret =
		    AUDDRV_User_CtrlDSP(AUDDRV_USER_EQ_CTRL, enable, size,
					(void *)&(dataptr->data[2]));
		if (!enable) {
			kfree(dataptr);
			dataptr = NULL;
		}
		break;
	case Ctrl_Ioctl_SWEQParm:
		aTrace(LOG_ALSA_INTERFACE,
			"ALSA-CAPH hwdep_ioctl Ctrl_Ioctl_SWEQParm");
		eq = kzalloc(sizeof(*eq), GFP_KERNEL);
		if (eq == NULL) {
			aError("treq_sysparm_t mem alloc failed");
			return -ENOMEM;
		}
		/* get the sysparm from driver
		 SW EQ is only for music playback for now*/
		if (copy_from_user(eq, (int __user *)arg,
			sizeof(struct treq_sysparm_t))) {
			if (eq != NULL) {
				kfree(eq);
				eq = NULL;
			}
			return -EFAULT;
		}
		ret = AUDDRV_Get_TrEqParm((void *)eq,
			sizeof(*eq), AUDIO_APP_MUSIC,
			(eq->data)[TREQ_DATA_SIZE-1]);
		if (!ret) {
			if (copy_to_user((void __user *)arg, eq,
			sizeof(*eq))) {
				if (eq != NULL) {
					kfree(eq);
					eq = NULL;
				}
				return -EFAULT;
			}
		}
		if (eq != NULL) {
			kfree(eq);
			eq = NULL;
		}
		break;
	default:
		ret = -ENOTTY;
		break;
	}
	return ret;
}
void AUDIO_Ctrl_Process(
	BRCM_AUDIO_ACTION_en_t action_code,
	void *arg_param,
	void *callback,
    int  block
	)
{
   	TMsgAudioCtrl	msgAudioCtrl;
	unsigned int	len;
	AUDIO_DRIVER_TYPE_t drv_type;
    UInt32 app_profile = 0 ;
	static AudioApp_t prev_app_profile = 0;
	static AudioMode_t prev_mode_profile = 0;
	static bool mode_restore = FALSE;

	if(arg_param == NULL)
	{
		DEBUG("AUDIO_Ctrl_Process: arg_param is NULL \n");
		return;
	}
    switch (action_code)
    {
        case ACTION_AUD_StartPlay:
        {
            BRCM_AUDIO_Param_Start_t* param_start = (BRCM_AUDIO_Param_Start_t*) arg_param;
            
		//20110905 	//prev_app_profile = AUDDRV_GetAudioApp();
            app_profile = AUDIO_Policy_Get_Profile(AUDIO_APP_MUSIC);

            AUDIO_DRIVER_Ctrl(param_start->drv_handle,AUDIO_DRIVER_START,NULL);

            AUDIO_DRIVER_Ctrl(param_start->drv_handle,AUDIO_DRIVER_GET_DRV_TYPE,(void*)&drv_type);

            if (AUDIO_Policy_GetState() == BRCM_STATE_INCALL)
            {
                DEBUG("Play Music During Voice call \n");
                musicduringcall = TRUE;
                if ( sgTableIDChannelOfDev[param_start->substream_number].speaker == AUDCTRL_SPK_HEADSET ||
                     sgTableIDChannelOfDev[param_start->substream_number].speaker == AUDCTRL_SPK_BTM )
                {
                    DEBUG("Play Music During Voice call to HEADSET or BTM\n");
                    if ( app_profile == AUDIO_APP_VOICE_CALL )
                    {
                        DEBUG(" Play music during Voice call with BT Tap at 8k \r\n");
                        AUDCTRL_EnableTap (AUDIO_HW_TAP_VOICE, AUDCTRL_SPK_BTM, 8000);
                    }
                    else
                    {
                        DEBUG(" Play music during Voice call with BT Tap at 16k \r\n");
                        if ( sgTableIDChannelOfDev[param_start->substream_number].speaker == AUDCTRL_SPK_BTM )
                        {
                            AUDCTRL_EnableTap (AUDIO_HW_TAP_VOICE, AUDCTRL_SPK_BTM, 8000);
                        }
                        else
                        {
                            AUDCTRL_EnableTap (AUDIO_HW_TAP_VOICE, AUDCTRL_SPK_BTM, 16000);
                        }
                    }

                    AUDCTRL_EnablePlay(AUDIO_HW_NONE,
                                       sgTableIDChannelOfDev[param_start->substream_number].hw_id,
                                       AUDIO_HW_TAP_VOICE,
                                       AUDCTRL_SPK_BTM,
                                       param_start->channels,
                                       param_start->rate
                                      );
                }
                else
                {
                    DEBUG("Play Music During Voice call to HANDSET or LOUDSPEAKER\n");
                    if ( app_profile == AUDIO_APP_VOICE_CALL )
                    {
                        DEBUG(" Play music during Voice call with BT Tap at 8k \r\n");
                        AUDCTRL_EnableTap (AUDIO_HW_TAP_VOICE, AUDCTRL_SPK_HEADSET, 8000);
                    }
                    else
                    {
                        DEBUG(" Play music during Voice call with BT Tap at 16k \r\n");
                        AUDCTRL_EnableTap (AUDIO_HW_TAP_VOICE, AUDCTRL_SPK_HEADSET, 16000);
                    }

                    AUDCTRL_EnablePlay(AUDIO_HW_NONE,
                                       sgTableIDChannelOfDev[param_start->substream_number].hw_id,
                                       AUDIO_HW_TAP_VOICE,
                                       AUDCTRL_SPK_HEADSET,
                                       param_start->channels,
                                       param_start->rate
                                      );
                }
            }
            else
            {
               	AUDCTRL_SaveAudioModeFlag( sgTableIDChannelOfDev[param_start->substream_number].speaker,app_profile);
            
                if( sgTableIDChannelOfDev[param_start->substream_number].speaker == AUDCTRL_SPK_BTM )
                {
                    AUDCTRL_EnableTap (AUDIO_HW_TAP_VOICE, sgTableIDChannelOfDev[param_start->substream_number].speaker, 8000);

                    // Enable the playback the path
                    AUDCTRL_EnablePlay(AUDIO_HW_NONE,
                                       sgTableIDChannelOfDev[param_start->substream_number].hw_id,
                                       AUDIO_HW_TAP_VOICE,
                                       sgTableIDChannelOfDev[param_start->substream_number].speaker,
                                       param_start->channels,
                                       param_start->rate
				      );
                }
                else
                {
                    // Enable the playback the path
                    AUDCTRL_EnablePlay(AUDIO_HW_NONE,
                                       sgTableIDChannelOfDev[param_start->substream_number].hw_id,
                                       AUDIO_HW_NONE,
                                       sgTableIDChannelOfDev[param_start->substream_number].speaker,
                                       param_start->channels,
                                       param_start->rate
                                      );

                    //if (param_start->substream_number == 5)  // Ring case
                    if(extra_speaker)
                    {
                        DEBUG("Play to speaker as well \n");
                        AUDCTRL_AddPlaySpk(sgTableIDChannelOfDev[param_start->substream_number].hw_id, //		AUDIO_HW_ID_t			sink,
                                           AUDCTRL_SPK_LOUDSPK                 //          AUDCTRL_SPEAKER_t		spk
                                          );
                    }
                }
            }

            // set the slopgain register to max value
            AUDCTRL_SetPlayVolume(sgTableIDChannelOfDev[param_start->substream_number].hw_id,
                                  sgTableIDChannelOfDev[param_start->substream_number].speaker,
                                  AUDIO_GAIN_FORMAT_VOL_LEVEL,
                                  AUDIO_VOLUME_MAX,
                                  AUDIO_VOLUME_MAX
                                 );

            // start DMA now
            AUDIO_DRIVER_Ctrl(param_start->drv_handle,AUDIO_DRIVER_RESUME,NULL);

            playback_prev_time = 0;
            playback_triggered = 1;

        }
        break;
        case ACTION_AUD_StopPlay:
        {
            BRCM_AUDIO_Param_Stop_t* param_stop = (BRCM_AUDIO_Param_Stop_t*) arg_param;

            // stop DMA first
            AUDIO_DRIVER_Ctrl(param_stop->drv_handle,AUDIO_DRIVER_PAUSE,NULL);

            AUDIO_DRIVER_Ctrl(param_stop->drv_handle,AUDIO_DRIVER_GET_DRV_TYPE,(void*)&drv_type);
            //if (param_stop->substream_number == 5)  // Ring case
            if(extra_speaker)
            {
		            DEBUG(" REMOVING  LOUDSPK  \n");				  
                    AUDCTRL_RemovePlaySpk(sgTableIDChannelOfDev[param_stop->substream_number].hw_id, //		AUDIO_HW_ID_t			sink,
									  AUDCTRL_SPK_LOUDSPK				  //		  AUDCTRL_SPEAKER_t 	spk
                    );
            }

		//20110905	//AUDCTRL_SaveAudioModeFlag( AUDDRV_GetAudioMode(), prev_app_profile );

            //disable the playback path
            if (AUDIO_Policy_GetState() == BRCM_STATE_INCALL)
            {
                musicduringcall = FALSE;
                if ( sgTableIDChannelOfDev[param_stop->substream_number].speaker == AUDCTRL_SPK_HEADSET ||
                     sgTableIDChannelOfDev[param_stop->substream_number].speaker == AUDCTRL_SPK_BTM )
                {
                    AUDCTRL_DisablePlay(AUDIO_HW_NONE,
                                        sgTableIDChannelOfDev[param_stop->substream_number].hw_id,
                                        AUDCTRL_SPK_BTM
                                       );
                }
                else
                {
                    AUDCTRL_DisablePlay(AUDIO_HW_NONE,
                                        sgTableIDChannelOfDev[param_stop->substream_number].hw_id,
                                        AUDCTRL_SPK_HEADSET
                                       );
                }
                AUDCTRL_DisableTap (AUDIO_HW_TAP_VOICE);
            }
            else
            {
                if( sgTableIDChannelOfDev[param_stop->substream_number].speaker == AUDCTRL_SPK_BTM )
                {
                    AUDCTRL_DisablePlay(AUDIO_HW_NONE,
                                        sgTableIDChannelOfDev[param_stop->substream_number].hw_id,
                                        sgTableIDChannelOfDev[param_stop->substream_number].speaker
                                       );

                    AUDCTRL_DisableTap (AUDIO_HW_TAP_VOICE);
                }
                else
                {
                    AUDCTRL_DisablePlay(AUDIO_HW_NONE,
                                        sgTableIDChannelOfDev[param_stop->substream_number].hw_id,
                                        sgTableIDChannelOfDev[param_stop->substream_number].speaker
                                       );
                }
            }
            AUDIO_DRIVER_Ctrl(param_stop->drv_handle,AUDIO_DRIVER_STOP,NULL);

            playback_prev_time = 0;
            playback_triggered = 0;

            

        }
        break;
        case ACTION_AUD_PausePlay:
        {
            BRCM_AUDIO_Param_Pause_t* param_pause = (BRCM_AUDIO_Param_Pause_t*) arg_param;

            AUDIO_DRIVER_Ctrl(param_pause->drv_handle,AUDIO_DRIVER_GET_DRV_TYPE,(void*)&drv_type);

            //disable the playback path
             AUDCTRL_DisablePlay(AUDIO_HW_NONE,
                        sgTableIDChannelOfDev[param_pause->substream_number].hw_id,
                        sgTableIDChannelOfDev[param_pause->substream_number].speaker
                    );

            if( sgTableIDChannelOfDev[param_pause->substream_number].speaker == AUDCTRL_SPK_BTM )
            {
                AUDCTRL_DisableTap (AUDIO_HW_TAP_VOICE);
            }
            AUDIO_DRIVER_Ctrl(param_pause->drv_handle,AUDIO_DRIVER_PAUSE,NULL);
        }
        break;

        case ACTION_AUD_ResumePlay:
        {
            BRCM_AUDIO_Param_Resume_t* param_resume = (BRCM_AUDIO_Param_Resume_t*) arg_param;

            AUDIO_DRIVER_Ctrl(param_resume->drv_handle,AUDIO_DRIVER_GET_DRV_TYPE,(void*)&drv_type);

            AUDIO_DRIVER_Ctrl(param_resume->drv_handle,AUDIO_DRIVER_RESUME,NULL);

            if( sgTableIDChannelOfDev[param_resume->substream_number].speaker == AUDCTRL_SPK_BTM )
            {
                AUDCTRL_EnableTap (AUDIO_HW_TAP_VOICE, sgTableIDChannelOfDev[param_resume->substream_number].speaker, param_resume->rate);

                // Enable the playback the path
                AUDCTRL_EnablePlay(AUDIO_HW_NONE,
                                   sgTableIDChannelOfDev[param_resume->substream_number].hw_id,
                                   AUDIO_HW_TAP_VOICE,
                                   sgTableIDChannelOfDev[param_resume->substream_number].speaker,
				                   param_resume->channels,
                                   param_resume->rate
				    );
            }
            else
            {
                // Enable the playback the path
                AUDCTRL_EnablePlay(AUDIO_HW_NONE,
                                   sgTableIDChannelOfDev[param_resume->substream_number].hw_id,
                                   AUDIO_HW_NONE,
                                   sgTableIDChannelOfDev[param_resume->substream_number].speaker,
				                   param_resume->channels,
                                   param_resume->rate
				    );
            }
        }
        break;
        case ACTION_AUD_StartRecord:
        {
            AudioApp_t app_prof = AUDIO_APP_RECORDING;
            AudioMode_t  new_mode = AUDIO_MODE_SPEAKERPHONE;
            AudioMode_t cur_mode;

            BRCM_AUDIO_Param_Start_t* param_start = (BRCM_AUDIO_Param_Start_t*) arg_param;
            DEBUG("ACTION_AUD_StartRecord : param_start->substream_number -  %d \n",param_start->substream_number);

			prev_app_profile = AUDDRV_GetAudioApp();
            cur_mode = AUDCTRL_GetAudioMode();

            if ( cur_mode >= AUDIO_MODE_NUMBER )
                cur_mode = (AudioMode_t) (cur_mode - AUDIO_MODE_NUMBER);

            if (param_start->substream_number == 6 || param_start->substream_number == 7) // record request with Google voice search profile
			{
                app_prof = AUDIO_APP_RECORDING_GVS;
				mode_restore = TRUE;
				prev_mode_profile = cur_mode;
				DEBUG("ACTION_AUD_StartRecord : [%d, %d]", prev_app_profile, prev_mode_profile);
			}

            if (param_start->substream_number == 9 || param_start->substream_number == 10) // record request with voip profile
            {
				app_prof = AUDIO_APP_VOIP;
                new_mode = cur_mode; // use current mode based on earpiece or speaker
            }
            
            if (param_start->substream_number == 11 || param_start->substream_number == 12) // record request with voip incomm profile
            {
				app_prof = AUDIO_APP_VOIP_INCOMM;
                new_mode = cur_mode; // use current mode based on earpiece or speaker
            }

            if (param_start->substream_number == 1 || param_start->substream_number == 7  || param_start->substream_number == 8 
                || param_start->substream_number == 10 || param_start->substream_number == 12) // record request with auxilary mic
                new_mode = AUDIO_MODE_HEADSET;

            app_profile = AUDIO_Policy_Get_Profile(app_prof);
            new_mode = AUDIO_Policy_Get_Mode(new_mode);
            AUDCTRL_SaveAudioModeFlag(new_mode,app_profile);

            AUDCTRL_EnableRecord(sgTableIDChannelOfCaptDev[param_start->substream_number].hw_id,
				                     AUDIO_HW_NONE,
                                     sgTableIDChannelOfCaptDev[param_start->substream_number].mic,
				                     param_start->channels,
                                     param_start->rate);

            AUDIO_DRIVER_Ctrl(param_start->drv_handle,AUDIO_DRIVER_START,NULL);

             AUDIO_Policy_SetState(BRCM_STATE_RECORD);

        }
        break;
        case ACTION_AUD_StopRecord:
        {
            BRCM_AUDIO_Param_Stop_t* param_stop = (BRCM_AUDIO_Param_Stop_t*) arg_param;
               
            AUDIO_DRIVER_Ctrl(param_stop->drv_handle,AUDIO_DRIVER_STOP,NULL);

			if (mode_restore)
			{
				mode_restore = FALSE;
				AUDCTRL_SaveAudioModeFlag( prev_mode_profile, prev_app_profile );
				DEBUG("ACTION_AUD_StartRecord : [%d, %d]", prev_app_profile, prev_mode_profile);
			}
			else
			{
				AUDCTRL_SaveAudioModeFlag( AUDDRV_GetAudioMode(), prev_app_profile );
			}

            AUDCTRL_DisableRecord(sgTableIDChannelOfCaptDev[param_stop->substream_number].hw_id,
                                      AUDIO_HW_NONE,
                                      sgTableIDChannelOfCaptDev[param_stop->substream_number].mic);

            AUDIO_Policy_RestoreState();

        }
	break;
        case ACTION_AUD_OpenPlay:
        {
            BRCM_AUDIO_Param_Open_t* param_open = (BRCM_AUDIO_Param_Open_t*) arg_param;

            param_open->drv_handle = AUDIO_DRIVER_Open(sgTableIDChannelOfDev[param_open->substream_number].drv_type);

            DEBUG("param_open->drv_handle -  0x%x \n",param_open->drv_handle);

        }
        break;
        case ACTION_AUD_ClosePlay:
        {
            BRCM_AUDIO_Param_Close_t* param_close = (BRCM_AUDIO_Param_Close_t*) arg_param;

            DEBUG("param_close->drv_handle -  0x%x \n",param_close->drv_handle);

            AUDIO_DRIVER_Close(param_close->drv_handle);

        }
        break;

	case ACTION_AUD_OpenRecord:
        {
            BRCM_AUDIO_Param_Open_t* param_open = (BRCM_AUDIO_Param_Open_t*) arg_param;

            param_open->drv_handle = AUDIO_DRIVER_Open(sgTableIDChannelOfCaptDev[param_open->substream_number].drv_type);

            DEBUG("param_open->drv_handle -  0x%x \n",param_open->drv_handle);

        }
        break;

        case ACTION_AUD_CloseRecord:
        {
            BRCM_AUDIO_Param_Close_t* param_close = (BRCM_AUDIO_Param_Close_t*) arg_param;

            DEBUG("param_close->drv_handle -  0x%x \n",param_close->drv_handle);

            AUDIO_DRIVER_Close(param_close->drv_handle);

        }
        break;


        case ACTON_VOICECALL_START:
        {
            BRCM_VOICE_Param_Start_t* param_voice_start = (BRCM_VOICE_Param_Start_t*)arg_param;
            int vol_level;

            telephony_stream_number = param_voice_start->substream_number;

            if ( telephony_codecId == 10 )
            {
                DEBUG("Enable telephony WB Call \r\n");
                app_profile = AUDIO_Policy_Get_Profile(AUDIO_APP_VOICE_CALL_WB);
                AUDCTRL_SaveAudioModeFlag( sgTableIDChannelOfVoiceCallDev[telephony_stream_number-VOICE_CALL_SUB_DEVICE].speaker + AUDIO_MODE_NUMBER,app_profile);
            }
            else if ( telephony_codecId == 6 )
            {
                DEBUG("Enable telephony NB Call \r\n");
                app_profile = AUDIO_Policy_Get_Profile(AUDIO_APP_VOICE_CALL);
                AUDCTRL_SaveAudioModeFlag( sgTableIDChannelOfVoiceCallDev[telephony_stream_number-VOICE_CALL_SUB_DEVICE].speaker,app_profile);
            }
            else
            {
                DEBUG("Enable telephony Invalid Codec : Setting as NB \r\n");
                app_profile = AUDIO_Policy_Get_Profile(AUDIO_APP_VOICE_CALL);
                AUDCTRL_SaveAudioModeFlag( sgTableIDChannelOfVoiceCallDev[telephony_stream_number-VOICE_CALL_SUB_DEVICE].speaker,app_profile);
            }

            if ( (telephony_stream_number-VOICE_CALL_SUB_DEVICE) == 4 )
            {
		if ( telephony_codecId == 10 )
            	{
                	DEBUG("Enable telephony WB Call for BT NREC \r\n");
                	app_profile = AUDIO_Policy_Get_Profile(AUDIO_APP_VOICE_CALL_WB);
                	AUDCTRL_SaveAudioModeFlag(AUDCTRL_SPK_HANDSFREE, app_profile);
            	}
            	else if ( telephony_codecId == 6 )
            	{
                	DEBUG("Enable telephony NB Call BT NREC \r\n");
                	app_profile = AUDIO_Policy_Get_Profile(AUDIO_APP_VOICE_CALL);
                	AUDCTRL_SaveAudioModeFlag(AUDCTRL_SPK_HANDSFREE, app_profile);
            	}

                DEBUG(" Telephony : Turning Off EC and NS \r\n");
                //AUDCTRL_EC(FALSE, 0);
                //AUDCTRL_NS(FALSE);
            }
            else
            {
                DEBUG(" Telephony : Turning On EC and NS \r\n");
                //AUDCTRL_EC(TRUE, 0);
                //AUDCTRL_NS(TRUE);
            }

            vol_level= GetCtrlValue(BRCM_CTL_EAR_Playback_Volume);
            if(vol_level > 5)
                vol_level = 5;
            AUDCTRL_SetPlayVolume(AUDIO_HW_VOICE_OUT,AUDCTRL_SPK_HANDSET,AUDIO_GAIN_FORMAT_DSP_VOICE_VOL_GAIN,vol_level,vol_level);

            AUDCTRL_RateChangeTelephony();
            AUDCTRL_EnableTelephony(AUDIO_HW_VOICE_IN,AUDIO_HW_VOICE_OUT,sgTableIDChannelOfVoiceCallDev[telephony_stream_number-VOICE_CALL_SUB_DEVICE].mic,sgTableIDChannelOfVoiceCallDev[telephony_stream_number-VOICE_CALL_SUB_DEVICE].speaker);
            telephony_started = 1;

	        if(TRUE==GetCtrlValue(BRCM_CTL_Mic_Capture_Mute))
            {
                DEBUG("Muting device \r\n");
			    AUDCTRL_SetTelephonyMicMute(AUDIO_HW_VOICE_OUT,AUDCTRL_MIC_MAIN,TRUE);;
            }
            AUDIO_Policy_SetState(BRCM_STATE_INCALL);


        }
        break;

        case ACTON_VOICECALL_STOP:
        {
            BRCM_VOICE_Param_Stop_t* param_voice_stop = (BRCM_VOICE_Param_Stop_t*)arg_param;

            telephony_stream_number = param_voice_stop->substream_number;

            DEBUG("DISABLE TELEPHONY substream = %d \r\n", telephony_stream_number);
            AUDCTRL_DisableTelephony(AUDIO_HW_VOICE_IN,AUDIO_HW_VOICE_OUT,sgTableIDChannelOfVoiceCallDev[telephony_stream_number-VOICE_CALL_SUB_DEVICE].mic,sgTableIDChannelOfVoiceCallDev[telephony_stream_number-VOICE_CALL_SUB_DEVICE].speaker);
            telephony_started = 0;
             AUDIO_Policy_RestoreState();
        }
        break;

        case ACTON_VOICECALL_UPDATE:
        {
            int local_sub_stream_number = 0;
            BRCM_VOICE_Param_Update_t* param_voice_update = (BRCM_VOICE_Param_Update_t*)arg_param;

            DEBUG("TELEPHONY UPDATE codecId = %d \r\n", param_voice_update->voicecall_codecId);

            if ( telephony_codecId != param_voice_update->voicecall_codecId )
            {
                telephony_codecId = param_voice_update->voicecall_codecId;

                if (telephony_started)
                {
                    if ( telephony_codecId == 10 )
                    {
                        app_profile = AUDIO_Policy_Get_Profile(AUDIO_APP_VOICE_CALL_WB);
                        DEBUG("call_CodedId_hander : changing Mode to AMR-WB ===>\r\n");
                        AUDCTRL_SaveAudioModeFlag( sgTableIDChannelOfVoiceCallDev[telephony_stream_number - VOICE_CALL_SUB_DEVICE].speaker + AUDIO_MODE_NUMBER,app_profile);
                        DEBUG("call_CodedId_hander : changing Mode to AMR-WB <===\r\n");
                    }
                    else
                    {
                        app_profile = AUDIO_Policy_Get_Profile(AUDIO_APP_VOICE_CALL);
                        DEBUG("call_CodedId_hander : changing Mode to AMR-NB ===>\r\n");
                        AUDCTRL_SaveAudioModeFlag( sgTableIDChannelOfVoiceCallDev[telephony_stream_number - VOICE_CALL_SUB_DEVICE].speaker,app_profile );
                        DEBUG("call_CodedId_hander : changing Mode to AMR-NB <===\r\n");
                    }
                    DEBUG("call_CodedId_hander : AUDCTRL_RateChangeTelephony ===>\r\n");
                    if ( musicduringcall == TRUE )
                    {
                        local_sub_stream_number = (telephony_stream_number - VOICE_CALL_SUB_DEVICE)*2;
                        // wired headphone
                        if(telephony_stream_number == 17)
                        {
                            // set the substream number to same as headset
                            local_sub_stream_number = 4;
                        }

                        AUDCTRL_DisableTap (AUDIO_HW_TAP_VOICE);
                        if ( app_profile == AUDIO_APP_VOICE_CALL )
                        {
                            
                            AUDCTRL_RateChangeTelephony();
                            if( sgTableIDChannelOfDev[local_sub_stream_number].speaker == AUDCTRL_SPK_HEADSET ||
                                sgTableIDChannelOfDev[local_sub_stream_number].speaker == AUDCTRL_SPK_BTM )
                            {
                                AUDCTRL_EnableTap (AUDIO_HW_TAP_VOICE, AUDCTRL_SPK_BTM, 8000);
                            }
                            else
                            {
                                AUDCTRL_EnableTap (AUDIO_HW_TAP_VOICE, AUDCTRL_SPK_HEADSET, 8000);
                            }
                        }
                        else
                        {
                            AUDCTRL_RateChangeTelephony();
                            if( sgTableIDChannelOfDev[local_sub_stream_number].speaker == AUDCTRL_SPK_HEADSET )
                            {
                                AUDCTRL_EnableTap (AUDIO_HW_TAP_VOICE, AUDCTRL_SPK_BTM, 16000);
                            }
                            else if ( sgTableIDChannelOfDev[local_sub_stream_number].speaker == AUDCTRL_SPK_BTM )
                            {
                                AUDCTRL_EnableTap (AUDIO_HW_TAP_VOICE, AUDCTRL_SPK_BTM, 8000);
                            }
                            else
                            {
                                AUDCTRL_EnableTap (AUDIO_HW_TAP_VOICE, AUDCTRL_SPK_HEADSET, 16000);
                            }
                        }
                    }
                    else
                    {
                        AUDCTRL_RateChangeTelephony();
                    }
                    DEBUG("call_CodedId_hander : AUDCTRL_RateChangeTelephony <===\r\n");
                }
            }
        }
        break;
		
        case ACTON_FM_START:
        {
	    BRCM_FM_Param_Start_t* param_start = (BRCM_FM_Param_Start_t*) arg_param;
        app_profile = AUDIO_Policy_Get_Profile(AUDIO_APP_FM);
			
      	    AUDCTRL_SaveAudioModeFlag( sgTableIDChannelOfDev[param_start->substream_number].speaker,app_profile);
                			
	        // Enable the FM playback the path
            AUDCTRL_EnablePlay(AUDIO_HW_I2S_IN,
				sgTableIDChannelOfDev[param_start->substream_number].hw_id,
				AUDIO_HW_NONE,
				sgTableIDChannelOfDev[param_start->substream_number].speaker,
				param_start->channels,
				param_start->rate
						);
            // set the slopgain register to max value
            // 20110530 FM radio volume is controlled by FM radio chip.
            AUDCTRL_SetPlayVolume(sgTableIDChannelOfDev[param_start->substream_number].hw_id,
				  sgTableIDChannelOfDev[param_start->substream_number].speaker,
				  AUDIO_GAIN_FORMAT_FM_RADIO_DIGITAL_VOLUME_TABLE,
				  AUDIO_VOLUME_MAX,
				  AUDIO_VOLUME_MAX 
						);

            AUDIO_Policy_SetState(BRCM_STATE_FM);

	    }
        break;
		
        case ACTON_FM_STOP:
        {

            BRCM_FM_Param_Stop_t* param_fm_stop = (BRCM_FM_Param_Stop_t*)arg_param;
	
            //disable the FM playback path
            AUDCTRL_DisablePlay(AUDIO_HW_I2S_IN,
				  sgTableIDChannelOfDev[param_fm_stop->substream_number].hw_id,
				  sgTableIDChannelOfDev[param_fm_stop->substream_number].speaker
						 );
            AUDIO_Policy_RestoreState();
        }
        break;
        case  ACTON_ROUTE:
            {
                BRCM_AUDIO_Param_Route_t* parm_route = (BRCM_AUDIO_Param_Route_t*)arg_param;
                 DEBUG("ACTON_ROUTE  \n");			
                

                if(playback_triggered == 1){

                    if(parm_route->command == 1)
                    {
                        DEBUG(" ADDING  SPK - %d  \n",parm_route->speaker);				  
                        AUDCTRL_AddPlaySpk(AUDIO_HW_PLR_OUT,
                                               parm_route->speaker
                                              );
                        extra_speaker = 1;

                    }
                    else if (parm_route->command == 0)
                    {
             
                        DEBUG(" REMOVING  SPK - %d  \n",parm_route->speaker);				  
                        AUDCTRL_RemovePlaySpk(AUDIO_HW_PLR_OUT, 
									      parm_route->speaker	
                        );

                        extra_speaker = 0;
                    }
                }
                else
                {
                    if(parm_route->command == 1)
                        extra_speaker = 1;
                    else if (parm_route->command == 0)
                        extra_speaker = 0;
                }
            }
            break;
        default:
            DEBUG("Error AUDIO_Ctrl_Process Invalid acction command \n");
    }
    if(block)
    {
        // put the message in output fifo if waiting
        msgAudioCtrl.action_code = action_code;
	    if(arg_param)
		    memcpy(&msgAudioCtrl.param, arg_param, sizeof(BRCM_AUDIO_Control_Params_un_t));
	    else
		    memset(&msgAudioCtrl.param, 0, sizeof(BRCM_AUDIO_Control_Params_un_t));
	    msgAudioCtrl.pCallBack = callback;
        msgAudioCtrl.block = block;

        len = kfifo_in_locked(&sgThreadData.m_pkfifo_out, (unsigned char *)&msgAudioCtrl, sizeof(TMsgAudioCtrl), &sgThreadData.m_lock_out);
        if(len != sizeof(TMsgAudioCtrl))
		    DEBUG("Error AUDIO_Ctrl_Process len=%d expected %d \n", len, sizeof(TMsgAudioCtrl));
#if 1        
        // release the semaphore 
        DEBUG("Semaphore released - %d \n",action_code);
        OSSEMAPHORE_Release(sgThreadData.action_complete);
#endif
    }

}