//******************************************************************************
//
// Function Name:  VoIP_StopTelephony()
//
// Description:	This function stops full duplex telephony session
//
// Notes:	The full duplex DSP interface is in sharedmem, not vsharedmem.
//		But since its function is closely related to voice processing,
//		we put it here.
//
//******************************************************************************
Boolean VoIP_StopTelephony(void)
{
    int ret;

    Telephony_DumpVPFramesCB=NULL;
    Telephony_FillVPFramesCB=NULL;
    flush_workqueue(intr_workqueue);
    destroy_workqueue(intr_workqueue);

    intr_workqueue = NULL;

#ifdef USE_HR_TIMER
    OSTASK_Sleep( 40 );			// To make sure the timer is not running anymore
    ret = hrtimer_cancel( &hr_timer );
    if (ret) printk("The timer was still in use...\n");

     printk("HR Timer module uninstalling\n");

#else
    gpt_stop(VT_USE_GPT_INDEX);
    gpt_free(VT_USE_GPT_INDEX);
#endif

    return TRUE;
}
//******************************************************************************
//
// Function Name:  VoIP_StopTelephony()
//
// Description:	This function stops full duplex telephony session
//
// Notes:	The full duplex DSP interface is in sharedmem, not vsharedmem.
//		But since its function is closely related to voice processing,
//		we put it here.
//
//******************************************************************************
Boolean VoIP_StopTelephony(void)
{
    int ret;

    Telephony_DumpVPFramesCB=NULL;
    Telephony_FillVPFramesCB=NULL;

/* [email protected] 2011.12.02 start */
/* add patch CSP 476896 for audio loop */
/* review by liubing */
#ifdef USE_WORK_QUEUE_FOR_DL    
	flush_workqueue(intr_workqueue);
    destroy_workqueue(intr_workqueue);

    intr_workqueue = NULL;
#else	
	tasklet_kill(&(voip_task));
#endif	
/* [email protected] 2011.12.02 end */
	

#ifdef USE_HR_TIMER
    OSTASK_Sleep( 40 );			// To make sure the timer is not running anymore
    ret = hrtimer_cancel( &hr_timer );
    if (ret) printk("The timer was still in use...\n");

     printk("HR Timer module uninstalling\n");

#else
    gpt_stop(VT_USE_GPT_INDEX);
    gpt_free(VT_USE_GPT_INDEX);
#endif

    return TRUE;
}
static ssize_t
timer_test_show(struct device *dev, struct device_attribute *attr,
		const char *buf, size_t n)
{
	uint32_t test_time, num, index, tick_time, mode, clk;
	struct gpt_cfg timer_tst;
	
	/* test_time: The ticks for which the timer needs to run
	 *       num: Number of times the timer has to run (On each 
	 *            instance it would interrupt after test_time.
	 *     index: Index of the GPT to test
	 *      mode: Non-zero value for oneshot, 0 for periodic
	 */
	if (sscanf(buf, "%d %d %d %d %d", &test_time, &num,
				&index, &mode, &clk) == 5) {
		if (gpt_request(index) == GPT_ERR_INVALID_INDEX) {
			pr_err("Error configuring CE timer exit\n");
			return -EINVAL;
		}

		/* Disable Pedestral mode */
		timer_tst.gctrl = SW_PEDEMODE;
		/* Set the clock to 32Khz */
		timer_tst.gclk = clk;
		/* Configure the timer mode oneshot/periodic */
		if (mode)
			timer_tst.gmode = GPT_MODE_ONESHOT;
		else
			timer_tst.gmode = GPT_MODE_PERIODIC;

		/* Global variable to keep track */
		g_gptdev[index].gpt_count = 0;
		g_gptdev[index].gpt_mode = timer_tst.gmode;
		g_gptdev[index].gpt_num_times = num;
		g_gptdev[index].gpt_index = index;

		/* Configure the timer for the above configration */
		gpt_config(index, &timer_tst, gpt_isr, &g_gptdev[index]);

		/* Get tick count before start for ref */
		tick_time = timer_get_tick_count();
		/* The timer starts here */
		gpt_start(index, test_time);

		/* Wait here until the timer completes the test */
		while (g_gptdev[index].gpt_count < g_gptdev[index].gpt_num_times)
			msleep(10);

		/* Print start and end time */
		pr_info("Tick time taken for gpt index %d start:%u end:%u\n",
				index, tick_time, timer_get_tick_count());

		/* Free timer here */
		gpt_free(index);
		return n;
	}

	return -EINVAL;
}
//******************************************************************************
//
// Function Name:  VoIP_StartTelephony()
//
// Description:	This function starts full duplex telephony session
//
// Notes:	The full duplex DSP interface is in sharedmem, not vsharedmem.
//		But since its function is closely related to voice processing,
//		we put it here.
//
//******************************************************************************
Boolean VoIP_StartTelephony(
VPUDumpFramesCB_t telephony_dump_cb,
VPUDumpFramesCB_t telephony_fill_cb,
UInt16	 voip_codec_type,  	// codec mode for encoding the next speech frame
Boolean	       dtx_mode,	// Turn DTX on (TRUE) or off (FALSE): this is obsolete. contained in voip_codec_type
Boolean	     amr_if2_enable	// Select AMR IF1 (FALSE) or IF2 (TRUE) format: obsolete
)
{
#ifdef USE_HR_TIMER
    unsigned long delay_in_ms = 20L;

    intr_workqueue = create_workqueue("vt-gpt");
    if (!intr_workqueue)
    {
        return TRUE;
    }

    INIT_WORK(&intr_work, VoIP_Task_Entry);

    ktime = ktime_set( 0, (delay_in_ms*1000000) );

    hrtimer_init( &hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL );

    hr_timer.function = &hrtimer_callback;

    hrtimer_start( &hr_timer, ktime, HRTIMER_MODE_REL );

#else
    struct gpt_cfg gptimer_config;

    intr_workqueue = create_workqueue("vt-gpt");
    if (!intr_workqueue)
    {
        return TRUE;
    }

    INIT_WORK(&intr_work, VoIP_Task_Entry);

    if ( gpt_request(VT_USE_GPT_INDEX) != VT_USE_GPT_INDEX )
        return TRUE;

    /* Disable Pedestral mode */
    gptimer_config.gctrl = SW_PEDEMODE;
    /* Set the clock to 1 Mhz */
    gptimer_config.gclk = 1024*1024;
    /* Configure the timer mode oneshot/periodic */
    gptimer_config.gmode = GPT_MODE_PERIODIC;

    /* Configure the timer for the above configration */
    if ( gpt_config(VT_USE_GPT_INDEX, &gptimer_config, gptimer_callback, NULL) != GPT_SUCCESS )
    {
        gpt_free(VT_USE_GPT_INDEX);
        return TRUE;
    }

    /* The timer starts here */
    if ( gpt_start(VT_USE_GPT_INDEX, 1000*20) != GPT_SUCCESS )
    {
        gpt_free(VT_USE_GPT_INDEX);
        return TRUE;
    }
#endif
    Telephony_DumpVPFramesCB=telephony_dump_cb;
    Telephony_FillVPFramesCB=telephony_fill_cb;

    return FALSE;
}