[Feature]Upload Modem source code

Change-Id: Id4294f30faced84d3e6fd6d5e61e1111bf287a37
diff --git a/mcu/driver/tty/src/excp_tty_ut.c b/mcu/driver/tty/src/excp_tty_ut.c
new file mode 100644
index 0000000..0dbaa4c
--- /dev/null
+++ b/mcu/driver/tty/src/excp_tty_ut.c
@@ -0,0 +1,767 @@
+/*****************************************************************************
+*  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) 2012
+*
+*  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:
+ * ---------
+ *   excp_tty_ut.c
+ *
+ * Project:
+ * --------
+ *   MOLY
+ *
+ * Description:
+ * ------------
+ *   TTY Core unit test file in exception mode - it needs Host Test Program to run test.
+ *   It works with enabling compile flag __EXCEPT_TTY_UT__.
+ *
+ * Author:
+ * -------
+ * -------
+ *
+ * ==========================================================================
+ * $Log$
+ *
+ * 03 11 2015 i-wei.tsai
+ * [MOLY00097392] [UMOLY] [TTY] Timer tick macro modification
+ * 	.
+ *
+ * 09 13 2013 i-wei.tsai
+ * [MOLY00037205] [CCCI Exception] CCCI exception mode 1st check-in.
+ * 	CCCI Exception IT
+ *
+ * 06 26 2013 i-wei.tsai
+ * [MOLY00027496] [TTYCore] Features check-in
+ * 1. add new TTY_CMD_MTU_SIZE support
+ * 2. add plug-in/plug-out indication
+ * 3. fix issue of flushing rx internal gpd
+ *
+ * 05 29 2013 haoren.kao
+ * [MOLY00024108] Support New USB Core
+ * Replace with New USB Core.
+ * We sync with the following codes from HaoRen MOLY CBr w1322:
+ * 1. USB Core
+ * 2. USB Class - acm/rndis/mbim
+ * 3. ipcore
+ * 4. ttycore
+ * 5. ethercore
+ *
+ * 11 12 2012 haoren.kao
+ * [MOLY00005322] TATAKA merge to MOLY
+ * * Shorten the busy loop time from about 5 ms to 10 us in order to avoid host test program SetCommState timeout.
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "dcl.h"
+#include "hmu.h"
+#include "kal_debug.h"
+#include "qmu_bm.h"
+#include "qmu_bm_util.h"
+#include "syscomp_config.h"
+
+#include "devdrv_ls.h"
+#include "drv_msgid.h"
+#include "md_drv_sap.h"
+#include "kal_public_defs.h"
+
+
+//#define __EXPT_CCCI_TTY_IT__
+
+#ifdef __EXPT_CCCI_TTY_IT__
+#define EXCEPTION_TEST_PORT     uart_port_dhl_sp_expt 
+//#define EXCEPTION_TEST_PORT     uart_port_dhl_ctrl_sp_expt
+#else
+#define EXCEPTION_TEST_PORT     uart_port_usb2
+#endif
+#define TX_BUF_NUM              500
+#define RX_BUF_NUM              499+1/*for tailed gpd*/
+#define TEST_LB_PKT_NUM         200
+#define EXCPT_TTY_UT_CHUNK_SIZE_DEFAULT  (QBM_TTY_XXX_DATA_LEN)
+
+#ifdef __EXPT_CCCI_TTY_IT__
+#define EXPT_TTY_TX_GPD_TYPE    QBM_TYPE_CCCI_COMM
+#define EXPT_TTY_RX_GPD_TYPE    QBM_TYPE_CCCI_COMM
+#else
+#define EXPT_TTY_TX_GPD_TYPE    QBM_TYPE_TTY_INT
+#define EXPT_TTY_RX_GPD_TYPE    QBM_TYPE_TTY_INT
+#endif
+
+#define EXCP_HALT()             while(1)
+
+#ifdef __EXPT_CCCI_TTY_IT__
+static DCL_UINT8 bm_buf_excp_tx[QBM_QUEUE_GET_MEM_SIZE(QBM_TYPE_CCCI_COMM, TX_BUF_NUM)];
+static DCL_UINT8 bm_buf_excp_rx[QBM_QUEUE_GET_MEM_SIZE(QBM_TYPE_CCCI_COMM, RX_BUF_NUM)];
+#else
+static DCL_UINT8 bm_buf_excp_tx[QBM_QUEUE_GET_MEM_SIZE(QBM_SIZE_TTY_INT, TX_BUF_NUM)];
+static DCL_UINT8 bm_buf_excp_rx[QBM_QUEUE_GET_MEM_SIZE(QBM_SIZE_TTY_INT, RX_BUF_NUM)];
+#endif
+
+static void *excp_tgpd_head = NULL;
+static void *excp_tgpd_tail = NULL;
+static void *excp_rgpd_head = NULL;
+static void *excp_rgpd_tail = NULL;
+
+static void *excp_tgpd_free_head = NULL;
+static void *excp_tgpd_free_tail = NULL;
+static void *excp_rgpd_free_head = NULL;
+static void *excp_rgpd_free_tail = NULL;
+
+typedef enum {
+    GPD_TYPE_TX,
+    GPD_TYPE_RX,
+} GPD_TYPE;
+
+
+#define BUSY_LOOP(_n) do{volatile int i; volatile int j=0; for (i=0; i<_n; i++) {j+=i*2;}}while(0)
+
+extern void dbg_print(char *fmt,...);
+
+#define TTYUT_DBG_PRINT(...)
+
+
+/*for debug only (CCCI)*/
+static volatile kal_uint32 DBG_LOCK = 1; 
+
+#define BUSY_STOP()                          \
+    do{                                      \
+        while(1){                            \
+            if(DBG_LOCK == 0) break;         \
+        }                                    \
+    }while(0)                                \
+
+void _excp_qbm_init(void)
+{
+    bm_queue_config conf;
+    kal_uint32 size;
+    kal_uint8 *pool;
+    
+    qbm_init();
+
+    /* Tx GPD queue init */
+    qbm_init_q_config(&conf);
+    size = QBM_QUEUE_GET_MEM_SIZE(EXPT_TTY_TX_GPD_TYPE, TX_BUF_NUM);
+    pool = &bm_buf_excp_tx[0];
+    conf.buff_num = TX_BUF_NUM;
+    conf.p_mem_pool_str = pool;
+    conf.p_mem_pool_end = pool + size;
+    qbm_init_queue_non_free(EXPT_TTY_TX_GPD_TYPE, &conf, &excp_tgpd_head, &excp_tgpd_tail);
+    
+    excp_tgpd_free_head = excp_tgpd_head;
+    excp_tgpd_free_tail = excp_tgpd_tail;
+
+    /* Rx GPD queue init */
+    qbm_init_q_config(&conf);
+    size = QBM_QUEUE_GET_MEM_SIZE(EXPT_TTY_RX_GPD_TYPE, RX_BUF_NUM);
+    pool = &bm_buf_excp_rx[0];
+    conf.buff_num = RX_BUF_NUM;
+    conf.p_mem_pool_str = pool;
+    conf.p_mem_pool_end = pool + size;
+    qbm_init_queue_non_free(EXPT_TTY_RX_GPD_TYPE, &conf, &excp_rgpd_head, &excp_rgpd_tail);
+
+    excp_rgpd_free_head = excp_rgpd_head;
+    excp_rgpd_free_tail = excp_rgpd_tail;
+
+}
+
+/**
+ *  @ return    gpd number allocated successfully
+ */
+static DCL_UINT16 _excp_alloc_gpd(
+        GPD_TYPE type,
+        kal_uint32 buff_num,
+        void **pp_head, 
+        void **pp_tail
+        )
+{
+    kal_uint16 alloc_num = 0;
+    void *free_head;
+    void *free_tail;
+    void *cur;
+    void *pre = NULL;
+
+    free_head = (type == GPD_TYPE_TX) ? excp_tgpd_free_head : excp_rgpd_free_head;
+    free_tail = (type == GPD_TYPE_TX) ? excp_tgpd_free_tail : excp_rgpd_free_tail;
+
+    cur = free_head;
+    
+    while (cur != NULL && buff_num > 0)
+    {
+        alloc_num ++;
+        buff_num --;
+        pre = cur;
+        cur = QBM_DES_GET_NEXT(cur);
+    }
+
+    *pp_head = free_head;
+    *pp_tail = pre;
+
+    if (type == GPD_TYPE_TX) {
+        excp_tgpd_free_head = cur;
+    } else {
+        excp_rgpd_free_head = cur;
+    }
+
+    return alloc_num;
+}
+
+static void _excp_free_gpd(
+        GPD_TYPE type,
+        void *p_head, 
+        void *p_tail
+        )
+{
+    void *free_head;
+    void *free_tail;
+
+    free_head = (type == GPD_TYPE_TX) ? excp_tgpd_free_head : excp_rgpd_free_head;
+    free_tail = (type == GPD_TYPE_TX) ? excp_tgpd_free_tail : excp_rgpd_free_tail;
+
+    if (free_head == NULL) {
+        free_head = p_head;
+    } else {
+        QBM_DES_SET_NEXT(free_tail, p_head);
+    }
+    free_tail = p_tail;
+
+    if (type == GPD_TYPE_TX) {
+        excp_tgpd_free_head = free_head;
+        excp_tgpd_free_tail = free_tail;
+    } else {
+        excp_rgpd_free_head = free_head;
+        excp_rgpd_free_tail = free_tail;
+    }
+}
+
+
+static kal_uint32 _excp_rst_gpd_list(kal_uint32 type,qbm_gpd* first_gpd, qbm_gpd* last_gpd)
+{
+    qbm_gpd*            current_gpd = NULL;
+    qbm_gpd*            next_gpd = NULL;
+    kal_uint32          num_gpd = 0;
+    
+    ASSERT(first_gpd && last_gpd);
+    current_gpd = first_gpd;
+
+    do {
+        next_gpd = QBM_DES_GET_NEXT(current_gpd);
+        qbm_reset_pd(type, (void*)current_gpd);
+        qbm_cal_set_checksum((kal_uint8 *)current_gpd);
+        QBM_CACHE_FLUSH(current_gpd, sizeof(qbm_gpd));
+        num_gpd ++;
+        if ( current_gpd == last_gpd )
+        {
+            break;
+        }        
+        current_gpd = next_gpd;
+    } while ( current_gpd != NULL );
+
+    return num_gpd;
+}
+
+static void* _excp_get_qbm_dataptr(void* gpd)
+{
+    void* bd = NULL;
+    void* data_ptr = NULL;
+    
+    ASSERT(NULL!=gpd);
+    if(0 != QBM_DES_GET_BDP(gpd)){
+        //4 <case 1> GPD->BD->BUFF
+        bd = QBM_DES_GET_DATAPTR(gpd);
+        ASSERT(NULL!=bd);
+        data_ptr = QBM_DES_GET_DATAPTR(bd);
+    }else{
+        //4 <case 2> GPD->BUFF        
+        data_ptr = QBM_DES_GET_DATAPTR(gpd);
+    }
+
+    ASSERT(NULL!=data_ptr);
+    return data_ptr;
+}
+
+static void _excp_set_qbm_datalen(void* gpd, kal_uint32 data_len)
+{
+    void* bd = NULL;
+
+    ASSERT(NULL != gpd);
+    /*QBM_TYPE_CCCI_COMM specific function*/
+    ASSERT(QBM_TYPE_CCCI_COMM == QBM_GET_TYPE(gpd));
+    /*Must have BD*/
+    ASSERT(0 != QBM_DES_GET_BDP(gpd));
+
+    bd = QBM_DES_GET_DATAPTR(gpd);
+    ASSERT(NULL!=bd);
+    QBM_DES_SET_DATALEN(bd, data_len);
+    qbm_cal_set_checksum((kal_uint8 *)bd);
+    
+    QBM_DES_SET_DATALEN(gpd, data_len);
+    qbm_cal_set_checksum((kal_uint8 *)gpd);
+}
+
+static void excp_loopback_test(DCL_HANDLE handle, kal_bool is_before_reset, kal_uint32 num)
+{
+    unsigned char *tx_buf_ptr;
+    unsigned char *rx_buf_ptr;
+    kal_char trigger_string[50] = {0};
+    kal_uint32 i;
+    kal_uint32 total_rx_num;
+    TTY_CTRL_EXCP_ASSIGN_RX_GPD_T ttyCtlAsnRxGpd;       
+    TTY_CTRL_EXCP_GET_RX_GPD_T ttyCtlGetRxGpd;
+    TTY_CTRL_EXCP_TX_GPD_T ttyCtlTxGpd;
+    TTY_CTRL_EXCP_TX_DONE_INFO_T ttyCtlTxDoneInfo;
+    TTY_CTRL_EXCP_HIF_STATE_T ttyCtlHifSt;
+    UART_CTRL_GET_CHUNK_SIZE_T ur_ctrl_get_chunk_size;
+
+    /*
+        Wait a period of time to let Host have enought time to open com port
+    */
+    for (i = 0; i < 500000; i ++)
+    {
+        if (!is_before_reset) {DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_HIF_POLL, NULL); }
+        BUSY_LOOP(100);
+    }
+
+    /* 
+        Send a packet to trigger Host start loopback test
+        #format: "exception num" (ex. "exception 50")
+    */
+    _excp_alloc_gpd(GPD_TYPE_TX, 1, &ttyCtlTxGpd.first_gpd, &ttyCtlTxGpd.last_gpd);
+    tx_buf_ptr = QBM_DES_GET_DATAPTR(ttyCtlTxGpd.first_gpd);
+    kal_mem_set(trigger_string, 0, sizeof(trigger_string));
+    sprintf(trigger_string, "exception %d", num);
+    kal_mem_cpy(tx_buf_ptr, trigger_string, strlen(trigger_string)+1);
+
+    // Set Tx GPD
+    QBM_CACHE_FLUSH(tx_buf_ptr, strlen(trigger_string)+1);
+    QBM_DES_SET_DATALEN(ttyCtlTxGpd.first_gpd, strlen(trigger_string)+1);
+    QBM_DES_SET_HWO(ttyCtlTxGpd.first_gpd);
+    qbm_cal_set_checksum(ttyCtlTxGpd.first_gpd);
+    QBM_CACHE_FLUSH(ttyCtlTxGpd.first_gpd, sizeof(qbm_gpd));
+    DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_TX_GPD, (DCL_CTRL_DATA_T*) &ttyCtlTxGpd);
+    // Polling Tx Done Info until all Tx GPD are sent and retrieved
+    do {
+        if (!is_before_reset) {DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_HIF_POLL, NULL); }
+        
+        DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_TX_DONE_INFO, (DCL_CTRL_DATA_T*) &ttyCtlTxDoneInfo);
+    
+        if (ttyCtlTxDoneInfo.num > 0) {
+            _excp_free_gpd(GPD_TYPE_TX, ttyCtlTxDoneInfo.first_gpd, ttyCtlTxDoneInfo.last_gpd);
+            break;
+        }
+    } while (1);
+
+    
+    /* Assign Rx GPD to driver */   
+    _excp_alloc_gpd(GPD_TYPE_RX, 2/*1 for tailed GPD*/, &ttyCtlAsnRxGpd.first_gpd, &ttyCtlAsnRxGpd.last_gpd);
+    DclSerialPort_Control(handle, TTY_CMD_GET_CHUNK_SIZE, (DCL_CTRL_DATA_T*)&ur_ctrl_get_chunk_size);
+    // first gpd
+    if(ur_ctrl_get_chunk_size.chunkSize == 1)
+    {
+        QBM_DES_SET_ALLOW_LEN(ttyCtlAsnRxGpd.first_gpd, EXCPT_TTY_UT_CHUNK_SIZE_DEFAULT);
+    }
+    else
+    {
+        QBM_DES_SET_ALLOW_LEN(ttyCtlAsnRxGpd.first_gpd, ur_ctrl_get_chunk_size.chunkSize);
+    }
+    QBM_DES_SET_HWO(ttyCtlAsnRxGpd.first_gpd);
+    qbm_cal_set_checksum(ttyCtlAsnRxGpd.first_gpd);
+    QBM_CACHE_FLUSH(ttyCtlAsnRxGpd.first_gpd, sizeof(qbm_gpd));
+    // last gpd
+    if(ur_ctrl_get_chunk_size.chunkSize == 1)
+    {
+        QBM_DES_SET_ALLOW_LEN(ttyCtlAsnRxGpd.first_gpd, EXCPT_TTY_UT_CHUNK_SIZE_DEFAULT);
+    }
+    else
+    {
+        QBM_DES_SET_ALLOW_LEN(ttyCtlAsnRxGpd.last_gpd, ur_ctrl_get_chunk_size.chunkSize);
+    }
+    QBM_DES_SET_HWO(ttyCtlAsnRxGpd.last_gpd);
+    qbm_cal_set_checksum(ttyCtlAsnRxGpd.last_gpd);
+    QBM_CACHE_FLUSH(ttyCtlAsnRxGpd.last_gpd, sizeof(qbm_gpd));
+    
+    DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_ASSIGN_RX_GPD, (DCL_CTRL_DATA_T*) &ttyCtlAsnRxGpd);
+    
+    total_rx_num = 0;
+    while (total_rx_num < num) // Polling Received Rx GPD and transmit the data to Host
+    {       
+        void *cur_tx;
+        void *cur_rx;
+        kal_uint16 rx_len;
+        kal_uint16 gpd_num;
+        
+        /* Get Rx GPD */
+        do {
+            if (!is_before_reset) {DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_HIF_POLL, NULL);}
+            DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_GET_RX_GPD, (DCL_CTRL_DATA_T*) &ttyCtlGetRxGpd);
+        } while (ttyCtlGetRxGpd.num == 0);
+        total_rx_num += ttyCtlGetRxGpd.num;
+        TTYUT_DBG_PRINT("[EXCEPT TTYUT] receive %d gpds, has received total %d gpds\r\n", ttyCtlGetRxGpd.num, total_rx_num);
+    
+        /* Allocate Tx GPD and re-transmit the rx data to Host */
+        gpd_num = ttyCtlGetRxGpd.num;
+        _excp_alloc_gpd(GPD_TYPE_TX, gpd_num, &ttyCtlTxGpd.first_gpd, &ttyCtlTxGpd.last_gpd);
+    
+        cur_rx = ttyCtlGetRxGpd.first_gpd;
+        cur_tx = ttyCtlTxGpd.first_gpd;
+        
+        for (i = 0; i < ttyCtlGetRxGpd.num; i ++)
+        {
+            rx_buf_ptr = QBM_DES_GET_DATAPTR(cur_rx);
+            rx_len = QBM_DES_GET_DATALEN(cur_rx);
+            tx_buf_ptr = QBM_DES_GET_DATAPTR(cur_tx);
+    
+            QBM_CACHE_INVALID(rx_buf_ptr, rx_len);
+            kal_mem_cpy(tx_buf_ptr, rx_buf_ptr, rx_len);
+            QBM_CACHE_FLUSH(tx_buf_ptr, rx_len);
+    
+            /* Set Tx GPD */
+            QBM_DES_SET_DATALEN(cur_tx, rx_len);
+            QBM_DES_SET_HWO(cur_tx);
+            qbm_cal_set_checksum(cur_tx);
+            QBM_CACHE_FLUSH(cur_tx, sizeof(qbm_gpd));
+    
+            /* Reset Rx GPD */
+            QBM_DES_SET_ALLOW_LEN(cur_rx, ur_ctrl_get_chunk_size.chunkSize);
+            QBM_DES_SET_HWO(cur_rx);
+            qbm_cal_set_checksum(cur_rx);
+            QBM_CACHE_FLUSH(cur_rx, sizeof(qbm_gpd));               
+    
+            cur_tx = QBM_DES_GET_NEXT(cur_tx);
+            cur_rx = QBM_DES_GET_NEXT(cur_rx);
+        }
+        DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_TX_GPD, (DCL_CTRL_DATA_T*) &ttyCtlTxGpd);
+
+        if (!is_before_reset) {DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_HIF_POLL, NULL); }
+        
+        /* Re-assign Rx GPD to driver */
+        ttyCtlAsnRxGpd.first_gpd = ttyCtlGetRxGpd.first_gpd;
+        ttyCtlAsnRxGpd.last_gpd = ttyCtlGetRxGpd.last_gpd;
+        DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_ASSIGN_RX_GPD, (DCL_CTRL_DATA_T*) &ttyCtlAsnRxGpd);
+    
+        /* Polling Tx Done Info until all Tx GPD are sent and retrieved */
+        do {
+            if (!is_before_reset) {DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_HIF_POLL, NULL);}
+            DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_TX_DONE_INFO, (DCL_CTRL_DATA_T*) &ttyCtlTxDoneInfo);
+    
+            if (ttyCtlTxDoneInfo.num > 0) {
+                _excp_free_gpd(GPD_TYPE_TX, ttyCtlTxDoneInfo.first_gpd, ttyCtlTxDoneInfo.last_gpd);
+                gpd_num -= ttyCtlTxDoneInfo.num;
+                TTYUT_DBG_PRINT("[EXCEPT TTYUT] has sent %d gpds\r\n", ttyCtlTxDoneInfo.num);
+            }
+        } while (gpd_num > 0);
+    
+        /* Check HIF state */
+        DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_HIF_STATE, (DCL_CTRL_DATA_T*) &ttyCtlHifSt);
+        if (ttyCtlHifSt.hif_state != HIF_STATE_NORMAL) {
+            EXCP_HALT();
+        }
+
+        if (!is_before_reset) {DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_HIF_POLL, NULL); }
+    }   
+
+}
+
+static void excp_ccci_loopback_test(DCL_HANDLE handle, kal_uint32 num)
+{
+    unsigned char *tx_buf_ptr;
+    unsigned char *rx_buf_ptr;
+    kal_char trigger_string[50] = {0};
+    kal_uint32 i;
+    kal_uint32 total_rx_num;
+    TTY_CTRL_EXCP_ASSIGN_RX_GPD_T ttyCtlAsnRxGpd;       
+    TTY_CTRL_EXCP_GET_RX_GPD_T ttyCtlGetRxGpd;
+    TTY_CTRL_EXCP_TX_GPD_T ttyCtlTxGpd;
+    TTY_CTRL_EXCP_TX_DONE_INFO_T ttyCtlTxDoneInfo;
+    TTY_CTRL_EXCP_HIF_STATE_T ttyCtlHifSt;
+    UART_CTRL_GET_MTU_SIZE_T ur_ctrl_get_mtu_size;
+    kal_uint32 tmp_num;
+
+    /*For debug test only*/
+    //BUSY_STOP();
+    
+    /* Assign Rx GPD to driver */
+    // TODO:Need to revise APIs. Because in exception mode(espicailly in HISR), some QBM APIs shall not be used. (ex:enhance mutex)
+    //tmp_num = _excp_alloc_gpd(GPD_TYPE_RX, 2/*1 for tailed GPD*/, &ttyCtlAsnRxGpd.first_gpd, &ttyCtlAsnRxGpd.last_gpd);
+    tmp_num = qbmt_alloc_q_no_tail(EXPT_TTY_RX_GPD_TYPE, 2, &ttyCtlAsnRxGpd.first_gpd, &ttyCtlAsnRxGpd.last_gpd);
+    if(tmp_num!= 2) while(1);
+    DclSerialPort_Control(handle, TTY_CMD_GET_MTU_SIZE, (DCL_CTRL_DATA_T*)&ur_ctrl_get_mtu_size);
+    QBM_DES_SET_ALLOW_LEN(ttyCtlAsnRxGpd.first_gpd, ur_ctrl_get_mtu_size.ulmtu_sz);
+    QBM_DES_SET_HWO(ttyCtlAsnRxGpd.first_gpd);
+    qbm_cal_set_checksum(ttyCtlAsnRxGpd.first_gpd);
+    QBM_CACHE_FLUSH(ttyCtlAsnRxGpd.first_gpd, sizeof(qbm_gpd));
+    // last gpd
+    QBM_DES_SET_ALLOW_LEN(ttyCtlAsnRxGpd.last_gpd, ur_ctrl_get_mtu_size.ulmtu_sz);
+    QBM_DES_SET_HWO(ttyCtlAsnRxGpd.last_gpd);
+    qbm_cal_set_checksum(ttyCtlAsnRxGpd.last_gpd);
+    QBM_CACHE_FLUSH(ttyCtlAsnRxGpd.last_gpd, sizeof(qbm_gpd));
+    
+    DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_ASSIGN_RX_GPD, (DCL_CTRL_DATA_T*) &ttyCtlAsnRxGpd);
+    
+    total_rx_num = 0;
+    //while (total_rx_num < num) // Polling Received Rx GPD and transmit the data to Host
+    while(1)
+    {       
+        void *cur_tx;
+        void *cur_rx;
+        kal_uint16 rx_len;
+        kal_uint16 gpd_num;
+        
+        /* Get Rx GPD */
+        do {
+            DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_HIF_POLL, NULL);
+            DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_GET_RX_GPD, (DCL_CTRL_DATA_T*) &ttyCtlGetRxGpd);
+        } while (ttyCtlGetRxGpd.num == 0);
+        total_rx_num += ttyCtlGetRxGpd.num;
+        TTYUT_DBG_PRINT("[EXCEPT TTYUT] receive %d gpds, has received total %d gpds\r\n", ttyCtlGetRxGpd.num, total_rx_num);
+    
+        /* Allocate Tx GPD and re-transmit the rx data to Host */
+        gpd_num = ttyCtlGetRxGpd.num;
+        //_excp_alloc_gpd(GPD_TYPE_TX, gpd_num, &ttyCtlTxGpd.first_gpd, &ttyCtlTxGpd.last_gpd);
+        tmp_num = qbmt_alloc_q_no_tail(EXPT_TTY_TX_GPD_TYPE, gpd_num, &ttyCtlTxGpd.first_gpd, &ttyCtlTxGpd.last_gpd);
+        if(tmp_num!= gpd_num) while(1);
+
+        cur_rx = ttyCtlGetRxGpd.first_gpd;
+        cur_tx = ttyCtlTxGpd.first_gpd;
+        
+        for (i = 0; i < ttyCtlGetRxGpd.num; i ++)
+        {
+            rx_buf_ptr = _excp_get_qbm_dataptr(cur_rx);
+            rx_len = QBM_DES_GET_DATALEN(cur_rx);
+            tx_buf_ptr = _excp_get_qbm_dataptr(cur_tx);
+    
+            QBM_CACHE_INVALID(rx_buf_ptr, rx_len);
+            kal_mem_cpy(tx_buf_ptr, rx_buf_ptr, rx_len);
+            QBM_CACHE_FLUSH(tx_buf_ptr, rx_len);
+    
+            /* Set Tx GPD */
+            _excp_set_qbm_datalen(cur_tx, rx_len);
+            QBM_DES_SET_HWO(cur_tx);
+            qbm_cal_set_checksum(cur_tx);
+            QBM_CACHE_FLUSH(cur_tx, sizeof(qbm_gpd));
+            
+            /* Reset Rx GPD */
+            _excp_rst_gpd_list(EXPT_TTY_RX_GPD_TYPE,cur_rx,cur_rx);
+            QBM_DES_SET_ALLOW_LEN(cur_rx, ur_ctrl_get_mtu_size.ulmtu_sz);
+            //QBM_DES_SET_HWO(cur_rx);
+            qbm_cal_set_checksum(cur_rx);
+            QBM_CACHE_FLUSH(cur_rx, sizeof(qbm_gpd));               
+    
+            cur_tx = QBM_DES_GET_NEXT(cur_tx);
+            cur_rx = QBM_DES_GET_NEXT(cur_rx);
+        }
+        DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_TX_GPD, (DCL_CTRL_DATA_T*) &ttyCtlTxGpd);
+
+        DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_HIF_POLL, NULL);
+        
+        /*Re-assign Rx GPD to driver */
+        ttyCtlAsnRxGpd.first_gpd = ttyCtlGetRxGpd.first_gpd;
+        ttyCtlAsnRxGpd.last_gpd = ttyCtlGetRxGpd.last_gpd;
+        DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_ASSIGN_RX_GPD, (DCL_CTRL_DATA_T*) &ttyCtlAsnRxGpd);
+    
+        /* Polling Tx Done Info until all Tx GPD are sent and retrieved */
+        do {
+            DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_HIF_POLL, NULL);
+
+            /*Debug only to check sdio interrupt status*/
+            //if((*SDIO_IRQ_DL_FTE0SR) & SDIO_INT_MASK) while(1);
+            
+            DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_TX_DONE_INFO, (DCL_CTRL_DATA_T*) &ttyCtlTxDoneInfo);
+    
+            if (ttyCtlTxDoneInfo.num > 0) {
+                //_excp_free_gpd(GPD_TYPE_TX, ttyCtlTxDoneInfo.first_gpd, ttyCtlTxDoneInfo.last_gpd);
+                qbmt_dest_q(ttyCtlTxDoneInfo.first_gpd, ttyCtlTxDoneInfo.last_gpd);
+                gpd_num -= ttyCtlTxDoneInfo.num;
+                TTYUT_DBG_PRINT("[EXCEPT TTYUT] has sent %d gpds\r\n", ttyCtlTxDoneInfo.num);
+            }
+        } while (gpd_num > 0);
+    
+        /* Check HIF state */
+        DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_HIF_STATE, (DCL_CTRL_DATA_T*) &ttyCtlHifSt);
+        if (ttyCtlHifSt.hif_state != HIF_STATE_NORMAL) {
+            EXCP_HALT();
+        }
+
+        DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_HIF_POLL, NULL);
+    }   
+
+}
+
+DCL_STATUS excp_ttyut(void)
+{
+    DCL_HANDLE handle;
+
+    //for debug only
+    //BUSY_STOP();
+    
+    hmu_except_init();
+
+    TTYUT_DBG_PRINT("[EXCEPT TTYUT] excp_ttyut start\r\n");
+
+    handle = DclSerialPort_Open(EXCEPTION_TEST_PORT, 0);
+
+    /* Init QBM for exception */
+    _excp_qbm_init();
+
+    /* Test Case 1: Loopback before RESET */
+        /* HIF init and Clear channel */
+    DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_HIF_INIT, NULL);
+    DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_CLEAR_CHANNEL, NULL);
+
+#ifdef __EXPT_CCCI_TTY_IT__
+    excp_ccci_loopback_test(handle, TEST_LB_PKT_NUM);
+#else
+    //BUSY_LOOP(60000000);
+    TTYUT_DBG_PRINT("[EXCEPT TTYUT] excp_ttyut case 1\r\n");
+    {
+        excp_loopback_test(handle, KAL_TRUE, TEST_LB_PKT_NUM);
+    }
+
+    /* Test Case 2: RESET */
+    TTYUT_DBG_PRINT("[EXCEPT TTYUT] excp_ttyut case 2\r\n");
+    {
+        DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_RESET, NULL);
+    }
+
+    /* Test Case 3: Loopback after RESET */
+        /* HIF init */
+    DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_HIF_INIT, NULL);
+    //BUSY_LOOP(60000000);
+    TTYUT_DBG_PRINT("[EXCEPT TTYUT] excp_ttyut case 3\r\n");
+    {
+        excp_loopback_test(handle, KAL_FALSE, TEST_LB_PKT_NUM);
+    }
+
+    /* Test Case 4: HIF_STATE return TXERROR */
+    TTYUT_DBG_PRINT("[EXCEPT TTYUT] excp_ttyut case 4\r\n");
+    {
+        TTY_CTRL_EXCP_TX_GPD_T ttyCtlTxGpd;
+        TTY_CTRL_EXCP_TX_DONE_INFO_T ttyCtlTxDoneInfo;
+        TTY_CTRL_EXCP_HIF_STATE_T ttyCtlHifSt;
+        kal_uint16 gpd_num;
+        kal_uint16 count;
+
+        BUSY_LOOP(50000);
+        while (1)
+        {
+            gpd_num = _excp_alloc_gpd(GPD_TYPE_TX, 1, &ttyCtlTxGpd.first_gpd, &ttyCtlTxGpd.last_gpd);
+            TTYUT_DBG_PRINT("[EXCEPT TTYUT] allocate %d gpd\r\n", gpd_num);
+            if (gpd_num == 0) {
+                break;
+            }
+            QBM_DES_SET_DATALEN(ttyCtlTxGpd.first_gpd, 100);
+            QBM_DES_SET_HWO(ttyCtlTxGpd.first_gpd);
+            qbm_cal_set_checksum(ttyCtlTxGpd.first_gpd);
+            QBM_CACHE_FLUSH(ttyCtlTxGpd.first_gpd, sizeof(qbm_gpd));
+
+            BUSY_LOOP(300000);
+            DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_TX_GPD, (DCL_CTRL_DATA_T*) &ttyCtlTxGpd);
+            DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_HIF_POLL, NULL);
+        }
+
+        count = 10000;
+        while (count-- > 0)
+        {
+            BUSY_LOOP(30000);
+            DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_TX_DONE_INFO, (DCL_CTRL_DATA_T*) &ttyCtlTxDoneInfo);
+        }
+        
+        DclSerialPort_Control(handle, TTY_CMD_EXCEPTION_HIF_STATE, (DCL_CTRL_DATA_T*) &ttyCtlHifSt);
+        if (ttyCtlHifSt.hif_state != HIF_STATE_TXERROR) {
+            TTYUT_DBG_PRINT("[EXCEPT TTYUT] ERROR!! HIF_STATE return NORMAL\r\n");
+            EXCP_HALT();
+        } else {
+            TTYUT_DBG_PRINT("[EXCEPT TTYUT] HIF_STATE return HIF_STATE_TXERROR\r\n");
+        }
+    }
+
+    TTYUT_DBG_PRINT("[EXCEPT TTYUT] excp_ttyut end\r\n");
+#endif
+    return STATUS_OK;
+}
+
+static kal_bool excp_ttyut_task_init(void)
+{
+    return KAL_TRUE;
+}
+
+static void excp_ttyut_task_main(task_entry_struct *task_entry_ptr)
+{
+    DCL_HANDLE handle;
+    UART_CTRL_PUT_BYTES_T ur_ctrl_putbytes;
+    char *dummy_string = "DUMMYdummyDummY";
+    DCL_STATUS status;
+    UART_CTRL_GET_DRV_STATE_T getDrvState;
+
+    handle = DclSerialPort_Open(EXCEPTION_TEST_PORT, 0);
+
+    DclSerialPort_UpModuleInit(handle, MOD_EXCP_TTYUT, 0); // conventional init
+
+    /*If taking CCCI exception IT test, task will be blocked here. Because, driver is attached when exception init*/
+    getDrvState.u4OwnerId = MOD_EXCP_TTYUT;
+    do {
+        kal_sleep_task(KAL_TICKS_100_MSEC);
+        status = DclSerialPort_Control(handle, TTY_CMD_GET_DRV_STATE, (DCL_CTRL_DATA_T*) &getDrvState);
+    } while ((getDrvState.drv_state != DRV_ST_ATTACHED) || (status != STATUS_OK)); 
+
+    kal_sleep_task(KAL_TICKS_5_SEC);
+
+    /* Transmit a dummy packet */
+    ur_ctrl_putbytes.u4OwenrId = MOD_EXCP_TTYUT;
+    ur_ctrl_putbytes.puBuffaddr = (DCL_UINT8*)dummy_string;
+    ur_ctrl_putbytes.u2Length = strlen(dummy_string);
+    DclSerialPort_Control(handle, SIO_CMD_PUT_BYTES, (DCL_CTRL_DATA_T*) &ur_ctrl_putbytes);
+
+    kal_sleep_task(KAL_TICKS_5_SEC);
+
+    /* Trigger an assert to enter exception mode */
+    ASSERT(0);
+}
+
+kal_bool excp_ttyut_create(comptask_handler_struct **handle)
+{
+    static const comptask_handler_struct excp_ttyut_handler_info =
+    {
+        excp_ttyut_task_main,        /* task entry function */
+        excp_ttyut_task_init,        /* task initialization function */
+        NULL        /* task reset handler */
+    };
+
+    TTYUT_DBG_PRINT("=========>excp_ttyut_create\r\n");
+
+    *handle = (comptask_handler_struct *)&excp_ttyut_handler_info;
+    return KAL_TRUE;
+}
+