/* SPDX-License-Identifier: LGPL-2.1-only OR BSD-3-Clause */
/******************************************************************************
 *
 * This file is provided under a dual license.  When you use or
 * distribute this software, you may choose to be licensed under
 * version 2.1 of the GNU Lesser General Public License
 * ("LGPLv2.1 License") or BSD License.
 *
 * LGPLv2.1 License
 *
 * Copyright(C) 2019 MediaTek Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2.1 of the GNU Lesser General Public
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html for more
 * details.
 *
 * BSD LICENSE
 *
 * Copyright(C) 2019 MediaTek Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *****************************************************************************/

/*-----------------------------------------------------------------------------
 * $RCSfile: io_mtdmx.c,v $
 * $Revision: #3 $
 * $Author: danning.wang $
 * $SWAuthor: wen han $
 * $MD5HEX:  $
 *---------------------------------------------------------------------------*/

/** @file io_mtdmx.c
 */

//-----------------------------------------------------------------------------
// Include files
//-----------------------------------------------------------------------------
#include "mtdmx.h"
#include "dmx_if.h"
#include "gcpu_if.h"
#include "dmx_mm_if.h"
#include "fbm_drvif.h"
#include "mpv_drvif.h"
#include "vdec_drvif.h"
#include "aud_drvif.h"
#include "stc_drvif.h"
#include "cb_data.h"
#include "cb_low.h"
#include <linux/mtal_ioctl.h>
#ifdef CC_TRUSTZONE_SUPPORT
#include "tz_if.h"
#endif
#include "x_assert.h"
#include "x_util.h"
#include "x_bim.h"
#include "dmx_drm_drvif.h"
#include "x_hal_arm.h"
#include "x_os.h"

extern int mtal_ioctl_mttsrec(unsigned int cmd, unsigned long arg);
#ifdef TIME_SHIFT_SUPPORT
extern int mtal_ioctl_mtdrec(unsigned int cmd, unsigned long arg);
#endif
extern MT_RESULT_T MTDMX_MWIF_Call(unsigned long arg);
//-----------------------------------------------------------------------------
// Constant definitions
//-----------------------------------------------------------------------------
#define MAX_SECTION_SIZE            32768

#define MAX_PES_SIZE                65536

#define MTAL_DMX_MULTIPLE_INVALID_INSTANCE 0xFF
#define MTAL_DMX_MULTIPLE_INVALID_PIDX     0xFF
#define MTAL_DMX_MULTIPLE_INVALID_FILTERX  0xFF

#define MTAL_DMX_EXPECTED_SIZE              (0x500000)
//-----------------------------------------------------------------------------
// Type definitions
//-----------------------------------------------------------------------------
typedef struct
{
    BOOL fgValid;
    DMX_CONN_TYPE_T eConType;
    UINT8 u1VirtualPidx;
} MTAL_DMX_PID_INFO_T;

typedef struct
{
    BOOL fgValid;
    DMX_CONN_TYPE_T eConType;
    UINT8 u1VirtualFilterIdx;
} MTAL_DMX_FILTER_INFO_T;

//-----------------------------------------------------------------------------
// Public functions
//-----------------------------------------------------------------------------
extern BOOL _MTPVR_QueryPlayMode(UCHAR ucPvrId);
extern BOOL _MTPVR_VideoCallback(const DMX_PES_MSG_T* prPes);
extern BOOL _MTPVR_AudioCallback(const DMX_AUDIO_PES_T* prPes);

//-----------------------------------------------------------------------------
// Macro definitions
//-----------------------------------------------------------------------------

#define DATASIZE(rp, wp, size)      \
    (((rp) <= (wp)) ? ((wp) - (rp)) : (((wp) + (size)) - (rp)))


#define USR_SPACE_ACCESS_VALIDATE_1ARG(arg)                 \
    if (!access_ok(VERIFY_READ, (void __user *)arg,         \
                   sizeof(INT32)))                            \
    {                                                       \
        printk("mtal_ioctl_mtdmx access argument error\n");     \
        return MTR_ERR_INV;                                          \
    }                                                       \

#define COPY_FROM_USER_ARG_SIZE(ArgUsr, ArgKernel, size)       \
    if (copy_from_user(ArgKernel, (void __user *)ArgUsr,   \
                       (size)))                             \
    {                                                       \
        printk("mtal_ioctl_mtdmx copy argument error\n");      \
        return MTR_ERR_INV;                                          \
    }                                                       \

#define COPY_FROM_USER_1ARG(ArgUsr, ArgKernel)              \
    if (copy_from_user(&ArgKernel, (void __user *)ArgUsr,   \
                       sizeof(INT32)))                        \
    {                                                       \
        printk("mtal_ioctl_mtdmx copy argument error\n");      \
        return MTR_ERR_INV;                                          \
    }                                                       \

#define USR_SPACE_ACCESS_VALIDATE_2ARG(arg)                 \
    if (!access_ok(VERIFY_READ, (void __user *)arg,         \
                   sizeof(MTAL_IOCTL_2ARG_T)))              \
    {                                                       \
        printk("mtal_ioctl_mtdmx access argument error\n");     \
        return MTR_ERR_INV;                                          \
    }                                                       \

#define COPY_FROM_USER_2ARG(ArgUsr, ArgKernel)              \
    if (copy_from_user(&ArgKernel, (void __user *)ArgUsr,   \
                       sizeof(MTAL_IOCTL_2ARG_T)))          \
    {                                                       \
        printk("mtal_ioctl_mtdmx copy argument error\n");      \
        return MTR_ERR_INV;                                          \
    }     \

#define USR_SPACE_ACCESS_VALIDATE_3ARG(arg)                 \
    if (!access_ok(VERIFY_READ, (void __user *)arg,         \
                   sizeof(MTAL_IOCTL_3ARG_T)))              \
    {                                                       \
        printk("mtal_ioctl_mtdmx access argument error\n");     \
        return MTR_ERR_INV;                                          \
    }                                                       \

#define COPY_FROM_USER_3ARG(ArgUsr, ArgKernel)              \
    if (copy_from_user(&ArgKernel, (void __user *)ArgUsr,   \
                       sizeof(MTAL_IOCTL_3ARG_T)))          \
    {                                                       \
        printk("mtal_ioctl_mtdmx copy argument error\n");      \
        return MTR_ERR_INV;                                          \
    }     \

#define USR_SPACE_ACCESS_VALIDATE_4ARG(arg)                 \
    if (!access_ok(VERIFY_READ, (void __user *)arg,         \
                   sizeof(MTAL_IOCTL_4ARG_T)))              \
    {                                                       \
        printk("mtal_ioctl_mtdmx access argument error\n");     \
        return MTR_ERR_INV;                                          \
    }                                                       \

#define COPY_FROM_USER_4ARG(ArgUsr, ArgKernel)              \
    if (copy_from_user(&ArgKernel, (void __user *)ArgUsr,   \
                       sizeof(MTAL_IOCTL_4ARG_T)))          \
    {                                                       \
        printk("mtal_ioctl_mtdmx copy argument error\n");      \
        return MTR_ERR_INV;                                          \
    }     \

#define USR_SPACE_ACCESS_VALIDATE_5ARG(arg)                 \
    if (!access_ok(VERIFY_READ, (void __user *)arg,         \
                   sizeof(MTAL_IOCTL_5ARG_T)))              \
    {                                                       \
        printk("mtal_ioctl_mtdmx access argument error\n");     \
        return MTR_ERR_INV;                                          \
    }                                                       \

#define COPY_FROM_USER_5ARG(ArgUsr, ArgKernel)              \
    if (copy_from_user(&ArgKernel, (void __user *)ArgUsr,   \
                       sizeof(MTAL_IOCTL_5ARG_T)))          \
    {                                                       \
        printk("mtal_ioctl_mtdmx copy argument error\n");      \
        return MTR_ERR_INV;                                          \
    }     \

#define USR_SPACE_ACCESS_VALIDATE_6ARG(arg)                 \
    if (!access_ok(VERIFY_READ, (void __user *)arg,         \
                   sizeof(MTAL_IOCTL_6ARG_T)))              \
    {                                                       \
        printk("mtal_ioctl_mtdmx access argument error\n");     \
        return MTR_ERR_INV;                                          \
    }                                                       \

#define COPY_FROM_USER_6ARG(ArgUsr, ArgKernel)              \
    if (copy_from_user(&ArgKernel, (void __user *)ArgUsr,   \
                       sizeof(MTAL_IOCTL_6ARG_T)))          \
    {                                                       \
        printk("mtal_ioctl_mtdmx copy argument error\n");      \
        return MTR_ERR_INV;                                          \
    }     \

#define USR_SPACE_ACCESS_VALIDATE_7ARG(arg)                 \
		if (!access_ok(VERIFY_READ, (void __user *)arg, 		\
					   sizeof(MTAL_IOCTL_7ARG_T)))				\
		{														\
			printk("mtal_ioctl_mtdmx access argument error\n");	 \
			return MTR_ERR_INV; 										 \
		}														\
	
#define COPY_FROM_USER_7ARG(ArgUsr, ArgKernel)              \
		if (copy_from_user(&ArgKernel, (void __user *)ArgUsr,	\
						   sizeof(MTAL_IOCTL_7ARG_T)))			\
		{														\
			printk("mtal_ioctl_mtdmx copy argument error\n");	  \
			return MTR_ERR_INV; 										 \
		}	  \

#define USR_SPACE_ACCESS_VALIDATE_8ARG(arg)                 \
    if (!access_ok(VERIFY_READ, (void __user *)arg,         \
                   sizeof(MTAL_IOCTL_8ARG_T)))              \
    {                                                       \
        printk("mtal_ioctl_mtdmx access argument error\n");     \
        return MTR_ERR_INV;                                          \
    }                                                       \

#define COPY_FROM_USER_8ARG(ArgUsr, ArgKernel)              \
    if (copy_from_user(&ArgKernel, (void __user *)ArgUsr,   \
                       sizeof(MTAL_IOCTL_8ARG_T)))          \
    {                                                       \
        printk("mtal_ioctl_mtdmx copy argument error\n");      \
        return MTR_ERR_INV;                                          \
    }     \

#define USR_SPACE_ACCESS_VALIDATE_9ARG(arg)                 \
		if (!access_ok(VERIFY_READ, (void __user *)arg, 		\
					   sizeof(MTAL_IOCTL_9ARG_T)))				\
		{														\
			printk("mtal_ioctl_mtdmx access argument error\n");	 \
			return MTR_ERR_INV; 										 \
		}														\
	
#define COPY_FROM_USER_9ARG(ArgUsr, ArgKernel)              \
		if (copy_from_user(&ArgKernel, (void __user *)ArgUsr,	\
						   sizeof(MTAL_IOCTL_9ARG_T)))			\
		{														\
			printk("mtal_ioctl_mtdmx copy argument error\n");	  \
			return MTR_ERR_INV; 										 \
		}	  \

#define USR_SPACE_ACCESS_VALIDATE_11ARG(arg)                 \
		if (!access_ok(VERIFY_READ, (void __user *)arg, 		\
					   sizeof(MTAL_IOCTL_11ARG_T)))				\
		{														\
			printk("mtal_ioctl_mtdmx access argument error\n");	 \
			return MTR_ERR_INV; 										 \
		}														\
	
#define COPY_FROM_USER_11ARG(ArgUsr, ArgKernel)              \
		if (copy_from_user(&ArgKernel, (void __user *)ArgUsr,	\
						   sizeof(MTAL_IOCTL_11ARG_T)))			\
		{														\
			printk("mtal_ioctl_mtdmx copy argument error\n");	  \
			return MTR_ERR_INV; 										 \
		}	  \

#define USR_SPACE_ACCESS_VALIDATE_12ARG(arg)                 \
				if (!access_ok(VERIFY_READ, (void __user *)arg, 		\
							   sizeof(MTAL_IOCTL_12ARG_T))) 			\
				{														\
					printk("mtal_ioctl_mtdmx access argument error\n");	 \
					return MTR_ERR_INV; 										 \
				}														\
			
#define COPY_FROM_USER_12ARG(ArgUsr, ArgKernel)              \
				if (copy_from_user(&ArgKernel, (void __user *)ArgUsr,	\
								   sizeof(MTAL_IOCTL_12ARG_T))) 		\
				{														\
					printk("mtal_ioctl_mtdmx copy argument error\n");	  \
					return MTR_ERR_INV; 										 \
				}	  \


#define COPY_FROM_USER_ARG(ArgUsr, ArgKernel,type)              \
    if (copy_from_user(&ArgKernel, (void __user *)ArgUsr,   \
                       sizeof(type)))          \
    {                                                       \
        printk("mtal_ioctl_mtdmx copy argument error\n");      \
        return MTR_ERR_INV;                                          \
    }     \

#define USR_SPACE_ACCESS_VALIDATE_ARG(arg,type)                 \
    if (!access_ok(VERIFY_READ, (void __user *)arg,         \
                   sizeof(type)))              \
    {                                                       \
        printk("mtal_ioctl_mtdmx access argument error\n");     \
        return MTR_ERR_INV;                                          \
    }                                                       \

#define USR_SPACE_ACCESS_VALIDATE_ARG_SIZE(arg,size)                 \
    if (!access_ok(VERIFY_READ, (void __user *)arg,         \
                   size))              \
    {                                                       \
        printk("mtal_ioctl_mtdmx access argument error\n");     \
        return MTR_ERR_INV;                                          \
    }                                                       \

#define COPY_TO_USER_ARG(ArgUsr, ArgKernel,type)              \
    if (copy_to_user((void __user *)ArgUsr, &ArgKernel,   \
                       sizeof(type)))          \
    {                                                       \
        printk("mtal_ioctl_mtdmx copy argument error\n");      \
        return MTR_ERR_INV;                                          \
    } \

#define COPY_TO_USER_ARG_SIZE(ArgUsr, ArgKernel,size)              \
    if (copy_to_user((void __user *)ArgUsr, ArgKernel,   \
                       size))          \
    {                                                       \
        printk("mtal_ioctl_mtdmx copy argument error\n");      \
        return MTR_ERR_INV;                                          \
    } \

#ifdef MTDMX_PRINT_SCHAR
#undef MTDMX_PRINT_SCHAR
#endif
#define MTDMX_PRINT_SCHAR(func,str)   do{\
                                            if(IS_MTDMX_LOG_ENABLE)\
                                            {\
                                                UINT8 i=0;\
                                                do\
                                                {\
                                                    printf("%s[%d] = %d, "func,i,str[i]);\
                                                }while(str[i++] != 0);\
                                                printf("\n");\
                                            }\
                                        }while(0)

#ifdef MTDMX_PRINT_CHAR
#undef MTDMX_PRINT_CHAR
#endif
#define MTDMX_PRINT_CHAR(func,str)   do{\
                                            if(IS_MTDMX_LOG_ENABLE)\
                                            {\
                                                UINT8 i=0;\
                                                do\
                                                {\
                                                    printf("%s[%d] = %d, "func,i,str[i]);\
                                                }while(str[i++] != 0);\
                                                printf("");\
                                            }\
                                        }while(0)

#ifdef MTDMX_PRINT_ARRAY
#undef MTDMX_PRINT_ARRAY
#endif
#define MTDMX_PRINT_ARRAY(func,typeinfo,str,length) do{\
                                                            if(IS_MTDMX_LOG_ENABLE)\
                                                            {\
                                                                UINT8 i=0;\
                                                                while(length > i)\
                                                                {\
                                                                    printf("%s%s[%d] = %d\n",func,typeinfo,i,str[i]);\
                                                                    i++;\
                                                                }\
                                                                printf("\n");\
                                                            }\
                                                        }while(0)

#ifdef MTDMX_PRINT_SEC
#undef MTDMX_PRINT_SEC
#endif
#define MTDMX_PRINT_SEC(func ,rsec)  do{\
                                            if(IS_MTDMX_LOG_ENABLE)\
                                            {printf("%s u1TableID = 0x%x,\n",func,(rsec).u1TableID);\
                                                printf("%s u2SecLen = 0x%x,\n",func,(rsec).u2SecLen);\
                                                  printf("%s u1VerNum = 0x%x,\n",func,(rsec).u1VerNum);\
                                                   printf("%s u4CRC = 0x%x\n",func,(rsec).u4CRC);\
                                                }\
                                        }while(0)

#ifdef MTDMX_PID_CNT
#undef MTDMX_PID_CNT
#endif
#define MTDMX_PID_CNT(func,rcnt) do{\
                                        if(IS_MTDMX_LOG_ENABLE)\
                                        {printf("%s u4PesCount = 0x%x,\n",func,(rcnt).u4PesCount);\
                                            printf("%s u4PicCount = 0x%x,\n",func,(rcnt).u4PicCount);\
                                               printf("%s u4SecCount = 0x%x\n",func,(rcnt).u4SecCount);\
                                            }\
                                    }while(0)


#ifdef MTDMX_PRINT_P_PID
#undef  MTDMX_PRINT_P_PID
#endif
#define MTDMX_PRINT_P_PID(str,rpid)    do{\
                                        if(IS_MTDMX_LOG_ENABLE)\
                                        {printf("%s fgEnable = %u,\n",str,(rpid).fgEnable);\
                                            printf("%s fgAllocateBuffer = %u,\n",str,(rpid).fgAllocateBuffer);\
                                              printf("%s u2Pid = 0x%x,\n",str,(rpid).u2Pid);\
                                               printf("%s u4BufAddr = 0x%x,\n",str,(rpid).u4BufAddr);\
                                                 printf("%s u4BufSize = 0x%x,\n",str,(rpid).u4BufSize);\
                                                  printf("%s ePidType = 0x%x,\n",str,(rpid).ePidType);\
                                                   printf("%s pvNotifyTag = 0x%x,\n",str,(UINT32)((rpid).pvNotifyTag));\
                                                    printf("%s pfnScramble = 0x%x,\n",str,(UINT32)(rpid).pfnScramble);\
                                                     printf("%s pvScrambleTag = 0x%x\n",str,(UINT32)((rpid).pvScrambleTag));\
                                            }\
                                        }while(0)

#ifdef MTDMX_PRINT_FTR
#undef MTDMX_PRINT_FTR
#endif
#define MTDMX_PRINT_FTR(func,rftr)    do{\
                                            if(IS_MTDMX_LOG_ENABLE)\
                                            {printf("%s fgEnable = %d,\n",func,(rftr).fgEnable);\
                                                printf("%s fgCheckCrc = %d,\n",func,(rftr).fgCheckCrc);\
                                                  printf("%s u1Pidx = 0x%x,\n",func,(rftr).u1Pidx);\
                                                   printf("%s u1Offset = 0x%x,\n",func,(rftr).u1Offset);\
                                                     MTDMX_PRINT_ARRAY(func,"au1Data", (rftr).au1Data, 16);\
                                                      MTDMX_PRINT_ARRAY(func,"au1Mask", (rftr).au1Mask, 16);\
                                                }\
                                        }while(0)


//-----------------------------------------------------------------------------
// Static variables
//-----------------------------------------------------------------------------

/// Temporary Section buffer
static UINT8 *_pu1SecBuf = NULL;
static HANDLE_T _hSecBufSem = NULL_HANDLE;

static BOOL _afgPidCreated[MTDMX_NUM_PID_INDEX];
static BOOL _afgSectionPid[MTDMX_NUM_PID_INDEX];


static BOOL _fgVdecEs1Used = FALSE;

/// Demux API critical
static BOOL _fgIoDmxLocking = FALSE;
static CRIT_STATE_T _rIoDmxLock;

#define MAX_ALLOC_BUFFER_COUNT 128
// stored buffer pointer
static UINT32 u4PsiBufAddr[MAX_ALLOC_BUFFER_COUNT] = {0};
static UINT32 u4PesBufAddr[MAX_ALLOC_BUFFER_COUNT] = {0};

static BOOL fgFbmDmx1Used = FALSE;
static BOOL fgFbmDmx2Used = FALSE;
static FBM_POOL_T* prFbmPool = NULL;

//-----------------------------------------------------------------------------
// Macro definitions
//-----------------------------------------------------------------------------

MTAL_DMX_PID_INFO_T _arDmxInfo[DMX_NUM_PID_INDEX];
MTAL_DMX_FILTER_INFO_T _arDmxFilterInfo[DMX_NUM_FILTER_INDEX];

static MT_RESULT_T SafeCopyFromUserArgSize(void *pArgUsr, void *pArgKernel, UINT32 u4Size)
{
    USR_SPACE_ACCESS_VALIDATE_ARG_SIZE(pArgUsr, u4Size);
    COPY_FROM_USER_ARG_SIZE(pArgUsr, pArgKernel, u4Size);

    return MTR_OK;
}

static MT_RESULT_T SafeCopyToUserArgSize(void *pArgUsr, void *pArgKernel, UINT32 u4Size)
{
    USR_SPACE_ACCESS_VALIDATE_ARG_SIZE(pArgUsr, u4Size);
    COPY_TO_USER_ARG_SIZE(pArgUsr, pArgKernel, u4Size);

    return MTR_OK;
}

static BOOL _MTAL_DMX_VirtualFilterBitmap(const UINT32 *pu4PhyBitmap, UINT32 *pu4VirBitmap, UINT32 u4Size);

//-----------------------------------------------------------------------------
/** Enter demux API critical section
 *
 *  @retval void
 */
//-----------------------------------------------------------------------------
static void _IoMtDmx_Lock(void)
{
    _rIoDmxLock = x_crit_start();

    ASSERT(!_fgIoDmxLocking);
    _fgIoDmxLocking = TRUE;

    UNUSED(_fgIoDmxLocking);          // Make Lint happy
}

//-----------------------------------------------------------------------------
/** Leave demux API critical section
 *
 *  @retval void
 */
//-----------------------------------------------------------------------------

static void _IoMtDmx_Unlock(void)
{
    ASSERT(_fgIoDmxLocking);
    _fgIoDmxLocking = FALSE;

    x_crit_end(_rIoDmxLock);

    UNUSED(_fgIoDmxLocking);          // Make Lint happy
}


//-----------------------------------------------------------------------------
// Static functions
//-----------------------------------------------------------------------------
static BOOL _MtDmxCallback(UINT8 u1Pidx, DMX_NOTIFY_CODE_T eCode,
                           UINT32 u4Data, const void* pvNotifyTag)
{
    DMX_NOTIFY_INFO_PSI_T* prPSIInfo;
    DMX_NOTIFY_INFO_PES_T* prPESInfo;
    DMX_NOTIFY_INFO_RAW_TS_T* prRawTsInfo;
    DMX_MTAL_CB_T rCB;
    UINT8 u1VirPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;
    UINT32 au4VirtMatchBitmap[MTSEC_CNT];

    // Check if PID is really active
    ASSERT(u1Pidx < DMX_NUM_PID_INDEX);

    _IoMtDmx_Lock();
    u1VirPidx = _arDmxInfo[u1Pidx].u1VirtualPidx;
    _IoMtDmx_Unlock();

    if (u1VirPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1VirPidx error\n");
        return FALSE;
    }
    else
    {
        rCB.u1Pidx = u1VirPidx;
    }
    rCB.type = eCode;
    //rCB.u1Pidx = u1Pidx;

    // Check notification code
    switch (eCode)
    {
    case DMX_NOTIFY_CODE_OVERFLOW:
        rCB.u4Data0 = u4Data;
        break;

    case DMX_NOTIFY_CODE_SCRAMBLE_STATE:
        rCB.u4Data0 = u4Data;
        break;
    case DMX_NOTIFY_CODE_RAW_SCRAMBLE_STATE:
        rCB.u4Data0 = u4Data;
        break;
    case DMX_NOTIFY_CODE_PSI:
        prPSIInfo = (DMX_NOTIFY_INFO_PSI_T*)u4Data;
        ASSERT(prPSIInfo != NULL);

        rCB.u4Data0 = prPSIInfo->u1SerialNumber;
        rCB.u4Data1 = prPSIInfo->u4SecAddr;
        rCB.u4Data2 = prPSIInfo->u4SecLen;
        // make klocwork happy
        //x_memcpy(&rCB.u4Data3, prPSIInfo->au4MatchBitmap, SEC_CNT * sizeof(UINT32));
        if (!_MTAL_DMX_VirtualFilterBitmap(prPSIInfo->au4MatchBitmap, au4VirtMatchBitmap, sizeof(au4VirtMatchBitmap)))
        {
            Printf("invalid bitmap.\n");
            return FALSE;
        }

        if (MTSEC_CNT >= 1)
        {
            rCB.u4Data3 = au4VirtMatchBitmap[0];
        }
        if (MTSEC_CNT >= 2)
        {
            rCB.u4Data4 = au4VirtMatchBitmap[1];
        }
        if (MTSEC_CNT >= 3)
        {
            rCB.u4Data5 = au4VirtMatchBitmap[2];
        }
        if (MTSEC_CNT >= 4)
        {
            rCB.u4Data6 = au4VirtMatchBitmap[3];
        }
        if (MTSEC_CNT >= 5)
        {
            rCB.u4Data7 = au4VirtMatchBitmap[4];
        }
        if (MTSEC_CNT >= 6)
        {
            rCB.u4Data8 = au4VirtMatchBitmap[5];
        }
        if (MTSEC_CNT >= 7)
        {
            rCB.u4Data9 = au4VirtMatchBitmap[6];
        }
        if (MTSEC_CNT >= 8)
        {
            rCB.u4Data10 = au4VirtMatchBitmap[7];
        }
        break;

    case DMX_NOTIFY_CODE_PES:
        prPESInfo = (DMX_NOTIFY_INFO_PES_T*)u4Data;
        ASSERT(prPESInfo != NULL);

        rCB.u4Data0 = prPESInfo->u1SerialNumber;
        rCB.u4Data1 = prPESInfo->u4DataAddr;
        rCB.u4Data2 = prPESInfo->u4DataSize;
        //some pvr playback, need notify audio pes pts
        #ifdef CC_DMX_DILIVER_AUDIO_PTS_FOR_PES_NOTIFY
        rCB.u4Data3 = prPESInfo->u4Pts;
        #endif
        break;

    case DMX_NOTIFY_CODE_AV_PES:
        prPESInfo = (DMX_NOTIFY_INFO_PES_T*)u4Data;
        ASSERT(prPESInfo != NULL);

        rCB.u4Data0 = prPESInfo->u1SerialNumber;
        rCB.u4Data1 = prPESInfo->u4DataAddr;
        rCB.u4Data2 = prPESInfo->u4DataSize;
        break;

    case DMX_NOTIFY_CODE_RAW_TS:
        prRawTsInfo = (DMX_NOTIFY_INFO_RAW_TS_T*)u4Data;
        ASSERT(prRawTsInfo != NULL);

        rCB.u4Data0 = prRawTsInfo->u1SerialNumber;
        rCB.u4Data1 = prRawTsInfo->u4DataAddr;
        rCB.u4Data2 = prRawTsInfo->u4DataSize;
        break;

    default:
        // Unexpected notification
        ASSERT(0);
        break;
    }

    UNUSED(_CB_PutEvent(CB_MTAL_DMX_TRIGGER, sizeof (DMX_MTAL_CB_T), &rCB));

    return TRUE;
}


//-----------------------------------------------------------------------------
/** _MwMPEGVideoCallback
 *  Callback handler of video PES
 *
 *  @param  prPes           PES message
 *
 *  @retval TRUE            Succeed
 *  @retval FALSE           Fail
 */
//-----------------------------------------------------------------------------
static BOOL _MwMPEGVideoCallback(const DMX_PES_MSG_T* prPes)
{
    VDEC_PES_INFO_T rMpvPes;

    ASSERT(prPes != NULL);

    x_memset((void*)&rMpvPes, 0, sizeof(VDEC_PES_INFO_T));

    switch (prPes->u4FrameType)
    {
    case PIC_TYPE_I:
        rMpvPes.ucPicType = MPV_I_TYPE;
        break;

    case PIC_TYPE_P:
        rMpvPes.ucPicType = MPV_P_TYPE;
        break;

    case PIC_TYPE_B:
        rMpvPes.ucPicType = MPV_B_TYPE;
        break;

    default:
        return TRUE;
    }

    rMpvPes.ucMpvId = prPes->u1DeviceId;
    rMpvPes.ucEsId = prPes->u1Channel;
    rMpvPes.u4FifoStart = prPes->u4BufStart;
    rMpvPes.u4FifoEnd = prPes->u4BufEnd;
    rMpvPes.u4VldReadPtr = prPes->u4FrameAddr;
    rMpvPes.u4PTS = prPes->u4Pts;
    rMpvPes.u4DTS = prPes->u4Dts;
    rMpvPes.fgDtsValid = prPes->fgPtsDts;
    rMpvPes.fgSeqHdr = prPes->fgSeqHeader;
    rMpvPes.fgGop = prPes->fgGop;
    rMpvPes.fgEos = prPes->fgEOS;
    rMpvPes.u4VideoType = prPes->eVideoType;
    
    if (prPes->fgEOS)
    {
        MTDMX_PRINT("MPEG-2 VideoCallback EOS.\n");
    }

    return (VDEC_SendEs(&rMpvPes) == 1);
}


//-----------------------------------------------------------------------------
/** _MwH264VideoCallback
 *  Callback handler of video PES
 */
//-----------------------------------------------------------------------------
static BOOL _MwH264VideoCallback(const DMX_PES_MSG_T* prPes)
{
    VDEC_PES_INFO_T  rMpvPes;
    UINT32 u4Addr;

    ASSERT(prPes != NULL);

    x_memset((void*)&rMpvPes, 0, sizeof(VDEC_PES_INFO_T));

    if (!H264_PIC_VALID_TYPE(prPes->u4FrameType))
    {
        return TRUE;
    }
    rMpvPes.ucPicType = prPes->ucPicType;
    rMpvPes.ucMpvId = prPes->u1DeviceId;
    rMpvPes.ucEsId = prPes->u1Channel;
    rMpvPes.u4FifoStart = prPes->u4BufStart;
    rMpvPes.u4FifoEnd = prPes->u4BufEnd;

    u4Addr = prPes->u4FrameAddr + 4;
    if (u4Addr >= prPes->u4BufEnd)
    {
        u4Addr -= (prPes->u4BufEnd - prPes->u4BufStart);
    }
    rMpvPes.u4VldReadPtr = u4Addr;

    rMpvPes.u4PTS = prPes->u4Pts;
    rMpvPes.u4DTS = prPes->u4Dts;
    rMpvPes.fgDtsValid = prPes->fgPtsDts;
    //rMpvPes.fgSeqHdr = prPes->fgSeqHeader;
    //rMpvPes.fgGop = prPes->fgGop;

    rMpvPes.fgEos = prPes->fgEOS;
    rMpvPes.u1SliceCount = prPes->u1SliceCount;
    rMpvPes.u4VideoType = prPes->eVideoType;

    if (prPes->fgEOS)
    {
        MTDMX_PRINT("h264 VideoCallback EOS.\n");
    }

    return (VDEC_SendEs((void *)&rMpvPes) == 1);
}

//-----------------------------------------------------------------------------
/** _MwH265VideoCallback
 *  Callback handler of video PES
 */
//-----------------------------------------------------------------------------
static BOOL _MwH265VideoCallback(const DMX_PES_MSG_T* prPes)
{
    VDEC_PES_INFO_T  rMpvPes;
    UINT32 u4Addr;

    ASSERT(prPes != NULL);

    x_memset((void*)&rMpvPes, 0, sizeof(VDEC_PES_INFO_T));

    if (!H265_PIC_VALID_TYPE(prPes->u4FrameType))
    {
        return TRUE;
    }

    rMpvPes.ucPicType = prPes->u4FrameType;
    rMpvPes.ucMpvId = prPes->u1DeviceId;
    rMpvPes.ucEsId = prPes->u1Channel;
    rMpvPes.u4FifoStart = prPes->u4BufStart;
    rMpvPes.u4FifoEnd = prPes->u4BufEnd;

    u4Addr = prPes->u4FrameAddr + 3;
    if (u4Addr >= prPes->u4BufEnd)
    {
        u4Addr -= (prPes->u4BufEnd - prPes->u4BufStart);
    }
    rMpvPes.u4VldReadPtr = u4Addr;

    rMpvPes.u4PTS = prPes->u4Pts;
    rMpvPes.u4DTS = prPes->u4Dts;
    rMpvPes.fgDtsValid = prPes->fgPtsDts;
    //rMpvPes.fgSeqHdr = prPes->fgSeqHeader;
    //rMpvPes.fgGop = prPes->fgGop;

    rMpvPes.fgEos = prPes->fgEOS;
    rMpvPes.u1SliceCount = prPes->u1SliceCount;
    rMpvPes.u4VideoType = prPes->eVideoType;

    if (prPes->fgEOS)
    {
        MTDMX_PRINT("h265 VideoCallback EOS.\n");
    }

    return (VDEC_SendEs((void *)&rMpvPes) == 1);
}

//-----------------------------------------------------------------------------
/** _AVSVideoCallback
 *  Callback handler of video PES
 */
//-----------------------------------------------------------------------------
static BOOL _AVSVideoCallback(const DMX_PES_MSG_T* prPes)
{
    VDEC_PES_INFO_T  rMpvPes;
#if defined(CC_TRUSTZONE_SUPPORT) && defined(CC_SVP_SUPPORT)

#else
    UINT32 u4Addr;
#endif

    ASSERT(prPes != NULL);

    x_memset((void*)&rMpvPes, 0, sizeof(rMpvPes));

#if defined(CC_TRUSTZONE_SUPPORT) && defined(CC_SVP_SUPPORT)
    //u4Addr = (UINT32)prPes->au1PicInfo;
     rMpvPes.ucPicType = prPes->ucPicType;
#else
    u4Addr = prPes->u4FrameAddr + 3;
    if (u4Addr >= prPes->u4BufEnd)
    {
        u4Addr -= (prPes->u4BufEnd - prPes->u4BufStart);
    }    
    rMpvPes.ucPicType = *(UINT8*)VIRTUAL(u4Addr);    
#endif


    rMpvPes.ucMpvId = prPes->u1DeviceId;
    rMpvPes.ucEsId = prPes->u1Channel;
    rMpvPes.u4FifoStart = prPes->u4BufStart;
    rMpvPes.u4FifoEnd = prPes->u4BufEnd;

    rMpvPes.u4VldReadPtr = prPes->u4FrameAddr;

    rMpvPes.u4PTS = prPes->u4Pts;
    rMpvPes.u4DTS = prPes->u4Dts;
    rMpvPes.fgDtsValid = prPes->fgPtsDts;
    rMpvPes.u4VideoType = prPes->eVideoType;

    rMpvPes.fgEos = prPes->fgEOS;

    if (prPes->fgEOS)
    {
        MTDMX_PRINT("AVS VideoCallback EOS.\n");
    }

    return (VDEC_SendEs((void *)&rMpvPes) == 1);
}


//-----------------------------------------------------------------------------
/** _MwDmxVideoCallback
 *  Callback handler of video PES
 *
 *  @param  prPes           PES message
 *
 *  @retval TRUE            Succeed
 *  @retval FALSE           Fail
 */
//-----------------------------------------------------------------------------
static BOOL _MwDmxVideoCallback(const DMX_PES_MSG_T* prPes)
{

    switch (prPes->eVideoType)
    {
    case DMX_VIDEO_MPEG:
        return _MwMPEGVideoCallback(prPes);

    case DMX_VIDEO_H264:
        return _MwH264VideoCallback(prPes);

    case DMX_VIDEO_AVS:
        return _AVSVideoCallback(prPes);

    case DMX_VIDEO_H265:
        return _MwH265VideoCallback(prPes);

    default:
        return FALSE;
    }

    return TRUE;
}



//-----------------------------------------------------------------------------
/** _MTDMX_SetDecoderEx
 */
//-----------------------------------------------------------------------------
void _MTDMX_SetDecoderEx(UINT8 u1InstId)
{
    DMX_DECODER_CALLBACKS_T rDecoderCallbacks;

    MTDMX_PRINT("dmx video, audio callback setting ------\n");

    // play 192 ts
#ifdef CC_DMX_A1
    if (_MTPVR_QueryPlayMode(0))
#endif
    {
        MTDMX_PRINT("============ callback for Play 192 ===========\n");
        rDecoderCallbacks.pfnSendVideoPes = _MwDmxVideoCallback;
        rDecoderCallbacks.pfnUpdateVideoWp = VDEC_SetWptr;
        rDecoderCallbacks.pfnSendAudioPes = AUD_SendAudioPes;
    }
#ifdef CC_DMX_A1
    else // play 188 ts
    {
        MTDMX_PRINT("============= callback for Play 188 ===========\n");
        rDecoderCallbacks.pfnSendVideoPes = _MTPVR_VideoCallback;
        rDecoderCallbacks.pfnUpdateVideoWp = VDEC_SetWptr;
        rDecoderCallbacks.pfnSendAudioPes = _MTPVR_AudioCallback;
    }
#endif

    DMX_MUL_SetDecoderCallbacks(u1InstId, &rDecoderCallbacks);
}


//-----------------------------------------------------------------------------
/** _MTAL_DMX_PhysicalPidx
 *
 *  @param  u1VirtualPidx          Virtual PID index
 *
 */
//-----------------------------------------------------------------------------
UINT8 _MTAL_DMX_PhysicalPidx(UINT8 u1VirtualPidx)
{
    UINT8 i;

    _IoMtDmx_Lock();
    for (i = 0; i < DMX_NUM_PID_INDEX; i++)
    {
        if ((_arDmxInfo[i].fgValid == TRUE) && (_arDmxInfo[i].u1VirtualPidx == u1VirtualPidx))
        {
            break;
        }
    }
    _IoMtDmx_Unlock();

    if (i >= DMX_NUM_PID_INDEX)
    {
        return MTAL_DMX_MULTIPLE_INVALID_PIDX;
    }

    return i;
}

//-----------------------------------------------------------------------------
/** _MTAL_DMX_PhysicalFilterx
 *
 *  @param  u1VirtualFilterx          Virtual Filter index
 *
 */
//-----------------------------------------------------------------------------
UINT8 _MTAL_DMX_PhysicalFilterx(UINT8 u1VirFilterx)
{
    UINT8 i;
    
    _IoMtDmx_Lock();
    for (i = 0; i < DMX_NUM_FILTER_INDEX; i++)
    {
        if (_arDmxFilterInfo[i].fgValid && (_arDmxFilterInfo[i].u1VirtualFilterIdx == u1VirFilterx))
        {
            break;
        }
    }
    _IoMtDmx_Unlock();

    if (i >= DMX_NUM_FILTER_INDEX)
    {
        return MTAL_DMX_MULTIPLE_INVALID_FILTERX;
    }

    return i;
}

//-----------------------------------------------------------------------------
/** _MTAL_DMX_VirtualFilterBitmap
 *
 */
//-----------------------------------------------------------------------------
static BOOL _MTAL_DMX_VirtualFilterBitmap(const UINT32 *pu4PhyBitmap, UINT32 *pu4VirBitmap, UINT32 u4Size)
{
    UINT8 i;
    UINT8 u1VirFilterx = 0;
    BOOL fgValid;

    if((pu4PhyBitmap == NULL) || (pu4VirBitmap == NULL))
    {
        return FALSE;
    }

    x_memset((void*)pu4VirBitmap, 0, u4Size);
    for (i = 0; i < DMX_NUM_FILTER_INDEX; i++)
    {
        _IoMtDmx_Lock();
        fgValid = _arDmxFilterInfo[i].fgValid;
        u1VirFilterx = _arDmxFilterInfo[i].u1VirtualFilterIdx;
        _IoMtDmx_Unlock();

        if (fgValid)
        {
            if (pu4PhyBitmap[SEC_NUM(i)] & (1 << FILTERINDEX(i)))
            {
                if (u1VirFilterx < MTDMX_NUM_EXTEND_FILTER_INDEX)
                {
                    pu4VirBitmap[MTSEC_NUM(u1VirFilterx)] |= (1 << MTFILTERINDEX(u1VirFilterx));
                }
                else
                {
                    Printf("invalid virtual filter index.\n");
                    return FALSE;
                }
            }
        }
    }

    return TRUE;
}

//-----------------------------------------------------------------------------
/** _MtdmxInitConntype
 *
 *  @param  eConnType           connection type
 *  @return  u1Inst             instance ID
 *
 */
//-----------------------------------------------------------------------------
static UINT8 _MtdmxInitConntype(DMX_CONN_TYPE_T eConnType)
{
    UINT8 u1Inst = 0;

    u1Inst = DMX_MUL_GetAvailableInst(eConnType);

    if (u1Inst == MTAL_DMX_MULTIPLE_INVALID_INSTANCE)
    {
        MTDMX_PRINT("Instances are all occupied.\n");
        return u1Inst;
    }

    //just for dtv case
    if (eConnType < DMX_CONN_TYPE_TUNER_MAX)
    {
        if (!DMX_MUL_SetInstType(u1Inst, DMX_IN_BROADCAST_TS))
        {
            MTDMX_PRINT("SetInstType fail.\n");
        }

        if (!DMX_MUL_SetTSIdx(u1Inst))
        {
            MTDMX_PRINT("SetTsIdx fail.\n");
        }

        //set dtv av decoder callback;
        _MTDMX_SetDecoderEx(u1Inst);
    }

    return u1Inst;
}

//-----------------------------------------------------------------------------
/*
 *  _MTDMX_DisConnectInfo
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_ConnectInfo(unsigned long arg)
{
    MTAL_IOCTL_2ARG_T    rArg;
    MTDMX_PID_INFO_T    rPidInfo;
    MTDMX_PID_INFO_T*   prPidInfo = NULL;
    UINT8 u1VirtualPidx;
    UINT8 u1PhysicalPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;
    UINT8 u1Inst = 0;
    DMX_CONN_TYPE_T eConnType = DMX_CONN_TYPE_NONE;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u1VirtualPidx = (UINT8)rArg.ai4Arg[0];
    prPidInfo = (MTDMX_PID_INFO_T*)rArg.ai4Arg[1];

    USR_SPACE_ACCESS_VALIDATE_ARG(prPidInfo, MTDMX_PID_INFO_T);
    COPY_FROM_USER_ARG(prPidInfo, rPidInfo, MTDMX_PID_INFO_T);

    MTDMX_PRINT(" _MTDMX_ConnectInfo u1Pidx = %d \n",u1VirtualPidx);

    if (u1VirtualPidx >= MTDMX_NUM_PID_INDEX)
    {
        return MTR_NOT_OK;
    }

    eConnType = (DMX_CONN_TYPE_T)rPidInfo.eConType;

    if (eConnType == DMX_CONN_TYPE_NONE)
    {
        return MTR_NOT_OK;
    }

    u1Inst = _MtdmxInitConntype(eConnType);

    if (u1Inst == MTAL_DMX_MULTIPLE_INVALID_INSTANCE)
    {
        MTDMX_PRINT("Instances are all occupied.\n");
        return MTR_NOT_OK;
    }

    u1PhysicalPidx = DMX_MUL_GetAvailablePidx(u1Inst);

    if (u1PhysicalPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Pidx are all occupied.\n");
        return MTR_NOT_OK;
    }

    _IoMtDmx_Lock();
    _arDmxInfo[u1PhysicalPidx].fgValid = TRUE;
    _arDmxInfo[u1PhysicalPidx].eConType = (DMX_CONN_TYPE_T)rPidInfo.eConType;
    _arDmxInfo[u1PhysicalPidx].u1VirtualPidx = u1VirtualPidx;
    _IoMtDmx_Unlock();

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  _MTDMX_ConnectAvailablePidx
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_ConnectAvailablePidx(unsigned long arg)
{
    MTAL_IOCTL_2ARG_T    rArg;
    MTDMX_PID_INFO_T    rPidInfo;
    MTDMX_PID_INFO_T*   prPidInfo = NULL;
    UINT8 *pu1VirtualPidx;
    UINT8 u1VirtualPidx;
    UINT8 u1PhysicalPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;
    UINT8 u1Inst = 0;
    DMX_CONN_TYPE_T eConnType = DMX_CONN_TYPE_NONE;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);
    
    prPidInfo = (MTDMX_PID_INFO_T*)rArg.ai4Arg[0];
    pu1VirtualPidx = (UINT8*)rArg.ai4Arg[1];

    USR_SPACE_ACCESS_VALIDATE_ARG(prPidInfo, MTDMX_PID_INFO_T);
    COPY_FROM_USER_ARG(prPidInfo, rPidInfo, MTDMX_PID_INFO_T);

    eConnType = (DMX_CONN_TYPE_T)rPidInfo.eConType;

    if (eConnType == DMX_CONN_TYPE_NONE)
    {
        return MTR_NOT_OK;
    }

    u1Inst = _MtdmxInitConntype(eConnType);

    if (u1Inst == MTAL_DMX_MULTIPLE_INVALID_INSTANCE)
    {
        MTDMX_PRINT("Instances are all occupied.\n");
        return MTR_NOT_OK;
    }

    u1PhysicalPidx = DMX_MUL_GetAvailablePidx(u1Inst);

    if (u1PhysicalPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Pidx are all occupied.\n");
        return MTR_NOT_OK;
    }

    u1VirtualPidx = u1PhysicalPidx + MTDMX_EXTEND_PID_START; 
    
    _IoMtDmx_Lock();
    _arDmxInfo[u1PhysicalPidx].fgValid = TRUE;
    _arDmxInfo[u1PhysicalPidx].eConType = (DMX_CONN_TYPE_T)rPidInfo.eConType;
    _arDmxInfo[u1PhysicalPidx].u1VirtualPidx = u1VirtualPidx;
    _IoMtDmx_Unlock();

    USR_SPACE_ACCESS_VALIDATE_ARG(pu1VirtualPidx, UINT8);
    COPY_TO_USER_ARG(pu1VirtualPidx, u1VirtualPidx, UINT8);

    MTDMX_PRINT(" -u1VirtualPidx = %d\n", u1VirtualPidx);
    
    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  _MTDMX_DisConnectInfo
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_DisConnectInfo(unsigned long arg)
{
    INT32 Arg;
    UINT8 u1Pidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;
    UINT8 u1VirtualPidx, i;
    BOOL fgTheLastPidxOfInst = FALSE;
    DMX_CONN_TYPE_T eConnType;

    USR_SPACE_ACCESS_VALIDATE_ARG(arg, INT32);
    COPY_FROM_USER_1ARG(arg, Arg);

    u1VirtualPidx = (UINT8)Arg;

    MTDMX_PRINT(" -u1Pidx = %d \n",u1VirtualPidx);

    u1Pidx = _MTAL_DMX_PhysicalPidx(u1VirtualPidx);

    if (u1Pidx >= DMX_NUM_PID_INDEX)
    {
        MTDMX_PRINT("Pidx are all occupied.\n");
        return MTR_NOT_OK;
    }

    _IoMtDmx_Lock();
    // check if this is the last pidx of the inst
    eConnType = _arDmxInfo[u1Pidx].eConType;
    for (i = 0; i < DMX_NUM_PID_INDEX; i++)
    {
        if ((i != u1Pidx) && (_arDmxInfo[i].eConType == eConnType) &&
                (_arDmxInfo[i].fgValid == TRUE))
        {
            break;
        }
    }

    if (i == DMX_NUM_PID_INDEX)
    {
        fgTheLastPidxOfInst = TRUE;
    }

    _arDmxInfo[u1Pidx].fgValid = FALSE;
    _arDmxInfo[u1Pidx].eConType = DMX_CONN_TYPE_BUFAGENT_0;
    _arDmxInfo[u1Pidx].u1VirtualPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;
    _IoMtDmx_Unlock();

    UNUSED(DMX_MUL_FreePidx(u1Pidx));

    if (fgTheLastPidxOfInst)
    {
        //just for dtv case, swdmx will free mm inst
        if (eConnType < DMX_CONN_TYPE_TUNER_MAX)
        {
            UINT8 u1Inst;
            u1Inst = DMX_MUL_GetAvailableInst(eConnType);
            UNUSED(DMX_MUL_FreeInst(u1Inst));
        }
    }

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/** _MTAL_DMX_IsES1Used
 *
 *  @param  u1VirtualPidx          Virtual PID index
 *
 */
//-----------------------------------------------------------------------------
BOOL _MTAL_DMX_IsES1Used(void)
{
    BOOL fgUsed = FALSE;

    _IoMtDmx_Lock();
    fgUsed = _fgVdecEs1Used;
    _IoMtDmx_Unlock();

    return fgUsed;
}

//-----------------------------------------------------------------------------
/** _MtdmxSetPid
 */
//-----------------------------------------------------------------------------
static BOOL _MtdmxSetPid(UINT8 u1Pidx, UINT32 u4Flags, const DMX_PID_T* prPid)
{
    DMX_PID_T rPid;

    x_memset((void *)&rPid, 0, sizeof(DMX_PID_T));

    rPid = *prPid;

    //if(u4Flags & DMX_PID_FLAG_TS_INDEX)
    //{
    //    rPid.u1TsIndex = DMX_GetFramerIndex();
    //}

    return DMX_SetPid(u1Pidx, u4Flags, &rPid);
}

//-----------------------------------------------------------------------------
/*
 *  Init demux driver
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_Init(unsigned long arg)
{
    UINT32 i;
    UINT8 u1Inst = MTAL_DMX_MULTIPLE_INVALID_INSTANCE;
    BOOL fgAllocateSecBuf = FALSE;
    static BOOL _fgDmxInit = FALSE;

    MTDMX_PRINT(" - void\n");

    if (_fgDmxInit)
    {
        return MTR_OK;
    }

    if (!DMX_Init())
    {
        return MTR_NOT_OK;
    }

    _IoMtDmx_Lock();
    for (i=0; i<MTDMX_NUM_PID_INDEX; i++)
    {
        _afgPidCreated[i] = FALSE;
        _afgSectionPid[i] = FALSE;
    }

    if (!_pu1SecBuf)
    {
        fgAllocateSecBuf = TRUE;
    }
    _IoMtDmx_Unlock();


	if (_hSecBufSem == NULL_HANDLE)
	{
		if (x_sema_create(&_hSecBufSem, X_SEMA_TYPE_BINARY, X_SEMA_STATE_UNLOCK) != OSR_OK)
		{
			MTDMX_PRINT("create _hSecBufSem fail\n");
			return MTR_NOT_OK;
		}
	}

    if (fgAllocateSecBuf)
    {
        _pu1SecBuf = (UINT8 *)x_mem_alloc_virtual(MAX_SECTION_SIZE);

        if (!_pu1SecBuf)
        {
            MTDMX_PRINT("alloc temp section buffer error\n");
            return MTR_NOT_OK;
        }
    }

    /*Tuner 0 connection initializaiton for backward compability purpose.
      New MW will initial it by _MTDMX_ConnectInfo()*/
    u1Inst =  _MtdmxInitConntype(DMX_CONN_TYPE_TUNER_0);
    if (u1Inst == MTAL_DMX_MULTIPLE_INVALID_INSTANCE)
    {
        MTDMX_PRINT("Instances are all occupied.\n");
        return MTR_NOT_OK;
    }

    _fgDmxInit = TRUE;

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/*
 *  Reset demux driver
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_Reset(unsigned long arg)
{
    MTDMX_PRINT(" - void\n");

    if (!DMX_Reset())
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Start demux
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_Start (unsigned long arg)
{
    MTDMX_PRINT(" - void\n");

    if (!DMX_Start())
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Stop demux
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_Stop(unsigned long arg)
{
    MTDMX_PRINT(" - void\n");

    if (!DMX_Stop())
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/*
 *  Set Front end type
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetFrontEndEx(unsigned long arg)
{
    MTAL_IOCTL_2ARG_T    rArg;
    UINT8 u1TsIdx;
    DMX_FRONTEND_T eFrontEnd;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u1TsIdx = (UINT8)rArg.ai4Arg[0];
    eFrontEnd = (DMX_FRONTEND_T)rArg.ai4Arg[1];

    MTDMX_PRINT(" - Ts: %d eFE: %d\n", u1TsIdx, (UINT32)eFrontEnd);

    if (!DMX_SetFrontEndEx(u1TsIdx, eFrontEnd))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Set Video type by ts_idx
 */
//-----------------------------------------------------------------------------

static MT_RESULT_T _MTDMX_SetVideoTypeEx(unsigned long arg)
{
    MTAL_IOCTL_2ARG_T    rArg;
    UINT8 u1TsIdx;
    DMX_VIDEO_TYPE_T eType;

    UINT8 u1Instance = 0;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u1TsIdx = (UINT8)rArg.ai4Arg[0];
    eType = (DMX_VIDEO_TYPE_T)rArg.ai4Arg[1];

    u1Instance = DMX_MUL_GetDtvInstFromTsIdx(u1TsIdx);

    if (!DMX_MUL_SetVideoType(u1Instance, eType))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}

static MT_RESULT_T _DMX_SetVideoTypeByPidx(unsigned long arg)
{
    MTAL_IOCTL_2ARG_T    rArg;
    UINT8 u1VirtualPidx;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;
    DMX_VIDEO_TYPE_T eType;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u1VirtualPidx = (UINT8)rArg.ai4Arg[0];
    eType = (DMX_VIDEO_TYPE_T)rArg.ai4Arg[1];

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1VirtualPidx);
    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }

    if (!DMX_SetVideoTypeByPidx(u1PhyPidx, eType))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/*
 *  Set  packet framer size by ts_idx
 */
//-----------------------------------------------------------------------------

static MT_RESULT_T _MTDMX_SetFramerPkt(unsigned long arg)
{
    MTAL_IOCTL_2ARG_T    rArg;
    UINT8 u1TsIdx;
    UINT8 u1Size;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u1TsIdx = (UINT8)rArg.ai4Arg[0];
    u1Size = (UINT8)rArg.ai4Arg[1];

    if (!DMX_SetPacketSizeEx(u1TsIdx, u1Size))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Set Video type
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetVideoType(unsigned long arg)
{
    DMX_VIDEO_TYPE_T eType;
    INT32 Arg;
    UINT8 u1Instance = 0;

    USR_SPACE_ACCESS_VALIDATE_ARG(arg, INT32);
    COPY_FROM_USER_1ARG(arg, Arg);

    MTDMX_PRINT(" - eType: %lu\n", Arg);

    eType = (DMX_VIDEO_TYPE_T)Arg;


    u1Instance = DMX_MUL_GetDtvInstFromTsIdx(0); // this old API always use TS index 0


    if (!DMX_MUL_SetVideoType(u1Instance, eType))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/*
 *  Set a PID
 *
 *  @param  u1Pidx          PID index, 0 ~ 31
 *  @param  u4Flags         Function flags
 *  @param  prPid           The PID structure of the PES
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetPid(unsigned long arg)
{
    MTAL_IOCTL_3ARG_T    rArg;
    UINT8 u1Pidx ;
    UINT32 u4Flags ;
    MTDMX_PID_T* prPid =NULL;
    MTDMX_PID_T rPid;
    DMX_PID_T rDrvPid;
    //FBM_POOL_T* prFbmPool;
    UINT8 u4AudDeviceID;
    UINT32 au4BufStart[3], au4BufEnd[3];
    UINT32 u4VfifoAddr = 0, u4VfifoSize = 0;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;

    x_memset((void *)&rPid,0,sizeof(MTDMX_PID_T));
    x_memset((void *)&rDrvPid,0,sizeof(DMX_PID_T));

    USR_SPACE_ACCESS_VALIDATE_3ARG(arg);
    COPY_FROM_USER_3ARG(arg, rArg);

    u1Pidx = (UINT8)rArg.ai4Arg[0];
    u4Flags = (UINT32)rArg.ai4Arg[1];
    prPid = (MTDMX_PID_T*)rArg.ai4Arg[2];

    USR_SPACE_ACCESS_VALIDATE_ARG(prPid, MTDMX_PID_T);
    COPY_FROM_USER_ARG(prPid, rPid, MTDMX_PID_T);

    MTDMX_PRINT(" -u1Pidx = %u, u4Flags = 0x%x\n ", u1Pidx, u4Flags);
    MTDMX_PRINT_P_PID("rPid.", rPid);

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);
    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }

#if 1
    // Only enable/disable PID
    if (u4Flags == MTDMX_PID_FLAG_VALID)
    {
        rDrvPid.fgEnable = rPid.fgEnable;
        if (!_MtdmxSetPid(u1PhyPidx, u4Flags, &rDrvPid))
        {
            return MTR_NOT_OK;
        }

        return MTR_OK;
    }
#endif
    // Get from MW
    rDrvPid.fgEnable = rPid.fgEnable;
    rDrvPid.fgAllocateBuffer = rPid.fgAllocateBuffer;
    rDrvPid.u4BufAddr = rPid.u4BufAddr;
    rDrvPid.u4BufSize = rPid.u4BufSize;
    rDrvPid.u1DeviceId = 0;
    rDrvPid.ePidType = rPid.ePidType;
#ifdef CC_DMX_A1
    rDrvPid.u1ContainAD = (rPid.ePidType == MTDMX_PID_TYPE_ES_AUDIO) ? rPid.u1ContainAD : 0;
#else
    rDrvPid.u1ContainAD = 2;
#endif

    if (rPid.ePidType == MTDMX_PID_TYPE_ES_VIDEO)
    {
        // Allocate video buffer from FBM
        if((!fgFbmDmx1Used) && (!fgFbmDmx2Used))
        {
#if defined(CC_TRUSTZONE_SUPPORT) && defined(CC_SVP_SUPPORT)
            prFbmPool = FBM_Alloc(FBM_TYPE_TZ_DMX);
#else
            prFbmPool = FBM_Alloc(FBM_TYPE_DMX);
#endif
            ASSERT(prFbmPool != NULL);
            if (!prFbmPool)
            {
                Printf("Fail to get VFIFO!\n");
                return MTR_NOT_OK;
            }
        }

        if(rPid.u1ChannelId == 0)
        {
        	_IoMtDmx_Lock();
            fgFbmDmx1Used = TRUE;
			_IoMtDmx_Unlock();
        }
        else
        {
        	_IoMtDmx_Lock();
            fgFbmDmx2Used = TRUE;
			_IoMtDmx_Unlock();
        }

        u4VfifoAddr = prFbmPool->u4Addr;
        u4VfifoSize = prFbmPool->u4Size;
        
        ASSERT(u4VfifoAddr != 0);
        if(u4VfifoSize < MTAL_DMX_EXPECTED_SIZE)
        {
            MTDMX_PRINT("DMX buffer size is too smaler: 0x%x!\n", u4VfifoSize);
        }

        // Setup buffer attributes
        rDrvPid.fgAllocateBuffer = FALSE;
#if defined(CC_DMX_A1) || defined(CC_DUAL_TUNER_SUPPORT)

        if (rPid.u1ChannelId == 0)
        {
            rDrvPid.u4BufAddr = u4VfifoAddr;
            rDrvPid.u4BufSize = u4VfifoSize / 2;
        }
        else
        {
            rDrvPid.u4BufAddr = u4VfifoAddr + (u4VfifoSize / 2);
            rDrvPid.u4BufSize = u4VfifoSize / 2;
            Printf("Free VDEC1 for DDI playing 3D content or background recording\n");

            _IoMtDmx_Lock();
            _fgVdecEs1Used = TRUE;
            _IoMtDmx_Unlock();

        }
#else
        rDrvPid.u4BufAddr = u4VfifoAddr;
        rDrvPid.u4BufSize = u4VfifoSize;
#endif
        Printf("Vdec ID=%d,VFifo Start=0x%08X,Vfifo BufferSize=0x%08X.\r\n",rPid.u1ChannelId,rDrvPid.u4BufAddr,
        rDrvPid.u4BufSize);
    }
    else if ((rPid.ePidType == MTDMX_PID_TYPE_ES_AUDIO) && (u4Flags & MTDMX_PID_FLAG_DEVICE_ID))
    {
#ifdef AUD_OLDFIFO_INTF
        if (AUD_GetAudFifo(&au4BufStart[0], &au4BufEnd[0], &au4BufStart[1],
                           &au4BufEnd[1]) != AUD_OK)
#else
        if ((AUD_GetAudFifo(0, &au4BufStart[0], &au4BufEnd[0]) != AUD_OK) ||
                (AUD_GetAudFifo(1, &au4BufStart[1], &au4BufEnd[1]) != AUD_OK)
                || (AUD_GetAudFifo(2, &au4BufStart[2], &au4BufEnd[2]) != AUD_OK)
           )
#endif
        {
            return MTR_NOT_OK;
        }
        if ((au4BufStart[0] == 0) || (au4BufStart[1] == 0)
                ||  (au4BufStart[2] == 0)
           )
        {
            return MTR_NOT_OK;
        }

        rDrvPid.fgAllocateBuffer = FALSE;
        /*Get the Audio device id from mw*/
        u4AudDeviceID = rPid.u1DeviceId;

#if defined(CC_DMX_A1)
        if(u4AudDeviceID > 2)
        {
            MTDMX_PRINT("The audio device id is wrong %d\n ",rPid.u1DeviceId);
            return MTR_NOT_OK;
        }
#elif !defined(CC_MT5391_AUD_3_DECODER)
        if (u4AudDeviceID >= 2)
        {
            MTDMX_PRINT("The audio device id from mw is wrong %d\n ", rPid.u1DeviceId);
            return FALSE;
        }
#elif defined(CC_MT5391_AUD_MW_AUTO_CTRL)
        if (u4AudDeviceID == 0)
        {
            u4AudDeviceID = 1;
        }

#ifdef CC_DUAL_AUD_DEC_SUPPORT
        //if (u4AudDeviceID == AUD_DEC_SUB)
        {
            u4AudDeviceID = AUD_Check_Dual_DecId(u4AudDeviceID);    
        }
#endif


        if (u4AudDeviceID > 2)
        {
            MTDMX_PRINT("The audio device id from mw is wrong %d\n ",rPid.u1DeviceId);
            return FALSE;
        }
#endif
        rDrvPid.u4BufAddr = au4BufStart[u4AudDeviceID];
        rDrvPid.u4BufSize = au4BufEnd[u4AudDeviceID] - au4BufStart[u4AudDeviceID];
        rDrvPid.u1DeviceId = u4AudDeviceID;
    }

    if ((rPid.pfnNotify != NULL) && (u4Flags & MTDMX_PID_FLAG_CALLBACK))
    {
        rDrvPid.pfnNotify = _MtDmxCallback;
    }
    else
    {
        rDrvPid.pfnNotify = NULL;
    }

    if ((rPid.pfnScramble != NULL) && (u4Flags & DMX_PID_FLAG_SCRAMBLE_STATE))
    {
        rDrvPid.pfnScramble = _MtDmxCallback;
    }
    else
    {
        rDrvPid.pfnScramble = NULL;
    }

    rDrvPid.pvNotifyTag = NULL;
    rDrvPid.pvScrambleTag = NULL;
	rDrvPid.u1ChannelId = rPid.u1ChannelId;
    rDrvPid.u1TsIndex = rPid.u1TsIndex;
    u4Flags |= DMX_PID_FLAG_TS_INDEX;

    // Set by driver only
     if (u4Flags & MTDMX_PID_FLAG_PID)
    {
     rDrvPid.u2Pid = rPid.u2Pid;
     rDrvPid.fgPrimary = TRUE;
     rDrvPid.u1KeyIndex = 0x0;
     rDrvPid.u1SteerMode = DMX_STEER_TO_FTUP;
     rDrvPid.ePcrMode = DMX_PCR_MODE_NONE;
     rDrvPid.eDescMode = DMX_DESC_MODE_NONE;
     u4Flags |= (DMX_PID_FLAG_PRIMARY | DMX_PID_FLAG_KEY_INDEX | DMX_PID_FLAG_STEER | 
                    DMX_PID_FLAG_PCR | DMX_PID_FLAG_DESC_MODE);
    }

    // This is config for scramble check case
    if (u4Flags & MTDMX_PID_FLAG_DISABLE_OUTPUT)
    {
        rDrvPid.fgDisableFifoOutput = rPid.fgDisableOutput;
        u4Flags |= DMX_PID_FLAG_DISABLE_OUTPUT;
        if (!DMX_SetScrambleCheckPid(u1PhyPidx, u4Flags, &rDrvPid))
        {
            return MTR_NOT_OK;
        }
    }
    else
    {
        if (!_MtdmxSetPid(u1PhyPidx, u4Flags, &rDrvPid))
        {
            return MTR_NOT_OK;
        }
    }

#ifdef CC_KR_3DDTV_HARDCODE
    // set another h264 pid by hardcode
    if (rPid.ePidType == MTDMX_PID_TYPE_ES_VIDEO)
    {
        UINT8 u1SpecificPidx;
        u1SpecificPidx = 30;  //special case, how to avoid
        rDrvPid.u2Pid = 259;
        rDrvPid.u4BufAddr = u4VfifoAddr + (u4VfifoSize / 2);
        rDrvPid.u4BufSize = u4VfifoSize / 2;
        rDrvPid.u1ChannelId = 1;
        if (!_MtdmxSetPid(u1SpecificPidx, u4Flags, &rDrvPid))
        {
            return MTR_NOT_OK;
        }
    }
#endif

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/*
 *  Set a PID
 *
 *  @param  u1Pidx          PID index, 0 ~ 31
 *  @param  u4Flags         Function flags
 *  @param  prPid           The PID structure of the PES
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetFilePid(unsigned long arg)
{
    MTAL_IOCTL_3ARG_T    rArg;
    UINT8 u1Pidx ;
    UINT32 u4Flags ;
    MTDMX_PID_T* prPid =NULL;
    MTDMX_PID_T rPid;
    DMX_PID_T rDrvPid;
    //FBM_POOL_T* prFbmPool;
    UINT8 u4AudDeviceID;
    UINT32 au4BufStart[3], au4BufEnd[3];
    UINT32 u4VfifoAddr = 0, u4VfifoSize = 0;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;

    x_memset((void *)&rPid,0,sizeof(MTDMX_PID_T));
    x_memset((void *)&rDrvPid,0,sizeof(DMX_PID_T));

    USR_SPACE_ACCESS_VALIDATE_3ARG(arg);
    COPY_FROM_USER_3ARG(arg, rArg);

    u1Pidx = (UINT8)rArg.ai4Arg[0];
    u4Flags = (UINT32)rArg.ai4Arg[1];
    prPid = (MTDMX_PID_T*)rArg.ai4Arg[2];

    USR_SPACE_ACCESS_VALIDATE_ARG(prPid, MTDMX_PID_T);
    COPY_FROM_USER_ARG(prPid, rPid, MTDMX_PID_T);

    MTDMX_PRINT(" -u1Pidx = %u, u4Flags = 0x%x\n ", u1Pidx, u4Flags);
    MTDMX_PRINT_P_PID("rPid.", rPid);

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }

#if 1
    // Only enable/disable PID
    if (u4Flags == MTDMX_PID_FLAG_VALID)
    {
        rDrvPid.fgEnable = rPid.fgEnable;
        if (!DMX_SetFilePid(u1PhyPidx, u4Flags, &rDrvPid))
        {
            return MTR_NOT_OK;
        }

        return MTR_OK;
    }
#endif
    // Get from MW
    rDrvPid.fgEnable = rPid.fgEnable;
    rDrvPid.fgAllocateBuffer = rPid.fgAllocateBuffer;
    rDrvPid.u2Pid = rPid.u2Pid;
    rDrvPid.u4BufAddr = rPid.u4BufAddr;
    rDrvPid.u4BufSize = rPid.u4BufSize;
    rDrvPid.u1DeviceId = 0;
    rDrvPid.ePidType = rPid.ePidType;

    if (rPid.ePidType == MTDMX_PID_TYPE_ES_VIDEO)
    {
        // Allocate video buffer from FBM
        if((!fgFbmDmx1Used) && (!fgFbmDmx2Used))
        {
#if defined(CC_TRUSTZONE_SUPPORT) && defined(CC_SVP_SUPPORT)
            prFbmPool = FBM_Alloc(FBM_TYPE_TZ_DMX);
#else
            prFbmPool = FBM_Alloc(FBM_TYPE_DMX);
#endif
            ASSERT(prFbmPool != NULL);
            if (!prFbmPool)
            {
                Printf("Fail to get VFIFO!\n");
                return MTR_NOT_OK;
            }
        }

        if(rPid.u1ChannelId == 0)
        {
        	_IoMtDmx_Lock();
            fgFbmDmx1Used = TRUE;
			_IoMtDmx_Unlock();
        }
        else
        {
        	_IoMtDmx_Lock();
            fgFbmDmx2Used = TRUE;
			_IoMtDmx_Unlock();
        }

        u4VfifoAddr = prFbmPool->u4Addr;
        u4VfifoSize = prFbmPool->u4Size;
        
        ASSERT(u4VfifoAddr != 0);
        if(u4VfifoSize < MTAL_DMX_EXPECTED_SIZE)
        {
            MTDMX_PRINT("DMX buffer size is too smaler: 0x%x!\n", u4VfifoSize);
        }

        // Setup buffer attributes
        rDrvPid.fgAllocateBuffer = FALSE;
#if defined(CC_DMX_A1) || defined(CC_DUAL_TUNER_SUPPORT)
        if (rPid.u1ChannelId == 0)
        {
            rDrvPid.u4BufAddr = u4VfifoAddr;
            rDrvPid.u4BufSize = u4VfifoSize / 2;
        }
        else
        {
            rDrvPid.u4BufAddr = u4VfifoAddr + (u4VfifoSize / 2);
            rDrvPid.u4BufSize = u4VfifoSize / 2;
            Printf("Free VDEC1 for DDI playing 3D content or background recording\n");

            _IoMtDmx_Lock();
            _fgVdecEs1Used = TRUE;
            _IoMtDmx_Unlock();

        }
#else
        rDrvPid.u4BufAddr = u4VfifoAddr;
        rDrvPid.u4BufSize = u4VfifoSize;
#endif
        //rDrvPid.u1DeviceId = rPid.u1DeviceId;
    }
    else if (rPid.ePidType == MTDMX_PID_TYPE_ES_AUDIO && (u4Flags & MTDMX_PID_FLAG_DEVICE_ID))
    {
#ifdef AUD_OLDFIFO_INTF
        if (AUD_GetAudFifo(&au4BufStart[0], &au4BufEnd[0], &au4BufStart[1],
                           &au4BufEnd[1]) != AUD_OK)
#else
        if ((AUD_GetAudFifo(0, &au4BufStart[0], &au4BufEnd[0]) != AUD_OK) ||
                (AUD_GetAudFifo(1, &au4BufStart[1], &au4BufEnd[1]) != AUD_OK)
                || (AUD_GetAudFifo(2, &au4BufStart[2], &au4BufEnd[2]) != AUD_OK)
           )
#endif
        {
            return MTR_NOT_OK;
        }
        if ((au4BufStart[0] == 0) || (au4BufStart[1] == 0)
                ||  (au4BufStart[2] == 0)
           )
        {
            return MTR_NOT_OK;
        }

        rDrvPid.fgAllocateBuffer = FALSE;
        /*Get the Audio device id from mw*/
        u4AudDeviceID = rPid.u1DeviceId;

#ifndef CC_MT5391_AUD_3_DECODER
        if (u4AudDeviceID >= 2)
        {
            MTDMX_PRINT("The audio device id from mw is wrong %d\n ", rPid.u1DeviceId);
            return FALSE;
        }
#else
#ifdef CC_MT5391_AUD_MW_AUTO_CTRL
        if (u4AudDeviceID == 0)
        {
            u4AudDeviceID = 1;
        }
        
#ifdef CC_DUAL_AUD_DEC_SUPPORT
        //if (u4AudDeviceID == AUD_DEC_SUB)
        {
            u4AudDeviceID = AUD_Check_Dual_DecId(u4AudDeviceID);    
        }
#endif

        if (u4AudDeviceID > 2)
        {
            MTDMX_PRINT("The audio device id from mw is wrong %d\n ",rPid.u1DeviceId);
            return FALSE;
        }
#endif
#endif

        rDrvPid.u4BufAddr = au4BufStart[u4AudDeviceID];
        rDrvPid.u4BufSize = au4BufEnd[u4AudDeviceID] - au4BufStart[u4AudDeviceID];
        rDrvPid.u1DeviceId = u4AudDeviceID;
    }

    if ((rPid.pfnNotify != NULL) && (u4Flags & MTDMX_PID_FLAG_CALLBACK))
    {
        rDrvPid.pfnNotify = _MtDmxCallback;
    }
    else
    {
        rDrvPid.pfnNotify = NULL;
    }

    if ((rPid.pfnScramble != NULL) && (u4Flags & DMX_PID_FLAG_SCRAMBLE_STATE))
    {
        rDrvPid.pfnScramble = _MtDmxCallback;
    }
    else
    {
        rDrvPid.pfnScramble = NULL;
    }

    rDrvPid.pvNotifyTag = NULL;
    rDrvPid.pvScrambleTag = NULL;

    // Set by driver only
    rDrvPid.fgPrimary = TRUE;
    rDrvPid.u1TsIndex = rPid.u1TsIndex;
    rDrvPid.u1KeyIndex = 0x0;
    rDrvPid.u1SteerMode = DMX_STEER_TO_FTUP;
    rDrvPid.ePcrMode = DMX_PCR_MODE_NONE;
    rDrvPid.eDescMode = DMX_DESC_MODE_NONE;
    rDrvPid.u1ChannelId = rPid.u1ChannelId;

    u4Flags |= (DMX_PID_FLAG_PRIMARY | DMX_PID_FLAG_TS_INDEX | DMX_PID_FLAG_KEY_INDEX |
                DMX_PID_FLAG_DEVICE_ID | DMX_PID_FLAG_STEER | DMX_PID_FLAG_PCR |
                DMX_PID_FLAG_DESC_MODE);

    // This is config for scramble check case
    if (u4Flags & MTDMX_PID_FLAG_DISABLE_OUTPUT)
    {
        rDrvPid.fgDisableFifoOutput = rPid.fgDisableOutput;
        u4Flags |= DMX_PID_FLAG_DISABLE_OUTPUT;
        if (!DMX_SetScrambleCheckPid(u1PhyPidx, u4Flags, &rDrvPid))
        {
            return MTR_NOT_OK;
        }
    }
    else
    {
        if (!DMX_SetFilePid(u1PhyPidx, u4Flags, &rDrvPid))
        {
            return MTR_NOT_OK;
        }
    }

#ifdef CC_KR_3DDTV_HARDCODE
    // set another h264 pid by hardcode
    if (rPid.ePidType == MTDMX_PID_TYPE_ES_VIDEO)
    {
        UINT8 u1SpecificPidx;
        u1SpecificPidx = 30;  //special case, how to avoid
        rDrvPid.u2Pid = 259;
        rDrvPid.u4BufAddr = u4VfifoAddr + (u4VfifoSize / 2);
        rDrvPid.u4BufSize = u4VfifoSize / 2;
        rDrvPid.u1ChannelId = 1;
        if (!DMX_SetFilePid(u1SpecificPidx, u4Flags, &rDrvPid))
        {
            return MTR_NOT_OK;
        }
    }
#endif

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/*
 *  Get a PID
 *
 *  @param  u1Pidx          PID index, 0 ~ 31
 *  @param  u4Flags         Function flags
 *  @param  prPid           The PID structure of the PES
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_GetPid (unsigned long arg)
{
    MTAL_IOCTL_3ARG_T    rArg;
    UINT8 u1Pidx;
    UINT32 u4Flags;
    MTDMX_PID_T * prPid = NULL;
    MTDMX_PID_T rPid;
    DMX_PID_T rDrvPid;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;

    x_memset(&rDrvPid, 0, sizeof(rDrvPid));
    x_memset((void *)&rPid,0,sizeof(MTDMX_PID_T));

    USR_SPACE_ACCESS_VALIDATE_3ARG(arg);
    COPY_FROM_USER_3ARG(arg, rArg);

    u1Pidx = (UINT8)rArg.ai4Arg[0];
    u4Flags = (UINT32)rArg.ai4Arg[1];
    prPid = (MTDMX_PID_T*)rArg.ai4Arg[2];

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    //This is special for getpid, MW want traverse serch all pidx ,Then in most of
    //case u1PhyPidx is 0xff.
    //so in mach case, we return the right value to mw.
    //in not mach case, we return all zero back to mw. this will need glue layer judge enable status.
    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error, u1Pidx=0x%x\n", u1Pidx);
        //return MTR_NOT_OK;
    }
    else //match case
    {
        if (!DMX_GetPid(u1PhyPidx, u4Flags, &rDrvPid))
        {
            return MTR_NOT_OK;
        }

	    rPid.ePidType = rDrvPid.ePidType;
	    rPid.fgAllocateBuffer = rDrvPid.fgAllocateBuffer;
	    rPid.fgEnable = rDrvPid.fgEnable;
	    rPid.pfnNotify = (PFN_MTDMX_NOTIFY)rDrvPid.pfnNotify;
	    rPid.pfnScramble = (PFN_MTDMX_NOTIFY)rDrvPid.pfnScramble;
	    rPid.pvNotifyTag = rDrvPid.pvNotifyTag;
	    rPid.pvScrambleTag = rDrvPid.pvScrambleTag;
	    rPid.u2Pid = rDrvPid.u2Pid;
	    rPid.u4BufAddr = rDrvPid.u4BufAddr;
	    rPid.u4BufSize = rDrvPid.u4BufSize;
	    rPid.u1TsIndex = rDrvPid.u1TsIndex;
	    rPid.u1DeviceId = rDrvPid.u1DeviceId;
	    rPid.u1ChannelId = rDrvPid.u1ChannelId;
	    rPid.fgDisableOutput = rDrvPid.fgDisableFifoOutput;
		rPid.u1LocalTsIndex = rDrvPid.u1LocalTsIndex;

	    MTDMX_PRINT(" -u1PhyPidx = %u , u4Flags = 0x%x\n ", u1PhyPidx, u4Flags);// log for virtual address
	    MTDMX_PRINT_P_PID("rPid.", rPid);
	}

	USR_SPACE_ACCESS_VALIDATE_ARG(prPid, MTDMX_PID_T);
	COPY_TO_USER_ARG(prPid, rPid, MTDMX_PID_T);

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Free a PID
 *
 *  @param  u1Pidx          PID index, 0 ~ 31
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_FreePid(unsigned long arg)
{
    DMX_PID_T rDrvPid;
    INT32 Arg;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;
    UINT8 u1VirtualPidx;

    USR_SPACE_ACCESS_VALIDATE_ARG(arg, INT32);
    COPY_FROM_USER_1ARG(arg, Arg);

    u1VirtualPidx = (UINT8)Arg;

    MTDMX_PRINT(" - u1Pidx = %d \n",u1VirtualPidx);

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1VirtualPidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }

    if (!DMX_GetPid(u1PhyPidx, DMX_PID_FLAG_BUFFER | DMX_PID_FLAG_DEVICE_ID, &rDrvPid))
    {
        return MTR_NOT_OK;
    }

#ifndef CC_DMX_A1
    if (rDrvPid.ePidType == DMX_PID_TYPE_ES_AUDIO)
    {
        DMX_TraceLog((UINT32)_MTDMX_FreePid, "_MTDMX_FreePid",
                     (UINT32)AUD_WaitDspFlush, "AUD_WaitDspFlush",
                     DMX_TRACE_FUNCTION_CALL);

        AUD_WaitDspFlush(rDrvPid.u1DeviceId);

        DMX_TraceLog((UINT32)_MTDMX_FreePid, "_MTDMX_FreePid",
                     (UINT32)AUD_WaitDspFlush, "AUD_WaitDspFlush",
                     DMX_TRACE_FUNCTION_RETURN);
    }
#endif

    _IoMtDmx_Lock();
    _afgPidCreated[u1PhyPidx] = FALSE;
    _afgSectionPid[u1PhyPidx] = FALSE;
    _IoMtDmx_Unlock();

    if (!DMX_FreePid(u1PhyPidx))
    {
        return MTR_NOT_OK;
    }

    if(rDrvPid.ePidType == (DMX_PID_TYPE_T)MTDMX_PID_TYPE_ES_VIDEO)
    {
        if(rDrvPid.u1ChannelId == 0)
        {
        	_IoMtDmx_Lock();
            fgFbmDmx1Used = FALSE;
			_IoMtDmx_Unlock();
        }
        else if(rDrvPid.u1ChannelId == 1)
        {
        	_IoMtDmx_Lock();
            fgFbmDmx2Used = FALSE;
			_IoMtDmx_Unlock();
        }

        if((!fgFbmDmx1Used) && (!fgFbmDmx2Used))
        {
			_IoMtDmx_Lock();
            UNUSED(FBM_Free(prFbmPool));
			_IoMtDmx_Unlock();
            prFbmPool = NULL;
        }
    }

#ifdef CC_DMX_A1
    if(rDrvPid.ePidType == (DMX_PID_TYPE_T)MTDMX_PID_TYPE_ES_VIDEO)
    {
        if (rDrvPid.u1ChannelId == 1)
        {
            _IoMtDmx_Lock();
            _fgVdecEs1Used = FALSE;
            _IoMtDmx_Unlock();
        }
    }
#endif

    //UNUSED(_MTAL_DMX_DisConnectInfo(u1VirtualPidx)); //disconnect information

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Find PID index for a given PID value
 *
 *  @param  u2Pid           PID
 *  @param  pu1PidIndex [out]
 *                          The PID index if found
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_GetPidIndex(unsigned long arg)
{
    MTAL_IOCTL_2ARG_T    rArg;
    UINT16 u2Pid;
    UINT8 *pu1PidIndex = NULL;
    UINT8 u1PidIndex;
    UINT8 u1VirPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u2Pid = (UINT16)rArg.ai4Arg[0];
    pu1PidIndex = (UINT8*)rArg.ai4Arg[1];

    if (!DMX_GetPidIndex(u2Pid, &u1PidIndex))
    {
        return MTR_NOT_OK;
    }

    _IoMtDmx_Lock();
    u1VirPidx = _arDmxInfo[u1PidIndex].u1VirtualPidx;
    _IoMtDmx_Unlock();

    if (u1VirPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1VirPidx error\n");
        return MTR_NOT_OK;
    }

    USR_SPACE_ACCESS_VALIDATE_ARG(pu1PidIndex, UINT8);
    COPY_TO_USER_ARG(pu1PidIndex, u1VirPidx, UINT8);

    MTDMX_PRINT(" -u2Pid = 0x%x, u1PidIndex = %d\n",u2Pid,u1VirPidx);

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Set a Video Pid
 *
 *  @param  u1PidIndex      PID index (0 - 31)
 *  @param  u2PidNum        Video PID number
 *  @param  fgEnable        Enable video pid or not
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetVideoPid(unsigned long arg)
{
    MTAL_IOCTL_3ARG_T    rArg;
    UINT8 u1Pidx ;
    UINT16 u2PidNum;
    BOOL fgEnable;
    DMX_PID_T rPid;
    //FBM_POOL_T* prFbmPool;
    UINT32 u4VfifoAddr = 0, u4VfifoSize = 0;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;
    BOOL fgPidCreated = FALSE;
    UINT8 u1Instance;

    x_memset((void *)&rPid,0,sizeof(DMX_PID_T));

    USR_SPACE_ACCESS_VALIDATE_3ARG(arg);
    COPY_FROM_USER_3ARG(arg, rArg);

    u1Pidx = (UINT8)rArg.ai4Arg[0];
    u2PidNum = (UINT16)rArg.ai4Arg[1];
    fgEnable = (BOOL)rArg.ai4Arg[2];

    MTDMX_PRINT(" -u1VitruePidx =%d, u2PidNum = 0x%x, fgEnable  =%d\n ",u1Pidx,u2PidNum,fgEnable);


    if (u1Pidx >= MTDMX_NUM_PID_INDEX)
    {
        return MTR_NOT_OK;
    }

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }



    // If callback is used by MM, setup callback again to make sure we have correct callback registration
    u1Instance = DMX_MUL_GetPidxInstId(u1PhyPidx);
    _MTDMX_SetDecoderEx(u1Instance);

    _IoMtDmx_Lock();
    fgPidCreated = _afgPidCreated[u1PhyPidx];
    _IoMtDmx_Unlock();

    if (fgPidCreated)
    {
        rPid.fgEnable = fgEnable;
        if (!_MtdmxSetPid(u1PhyPidx, DMX_PID_FLAG_VALID, &rPid))
        {
            return MTR_NOT_OK;
        }

        return MTR_OK;
    }

    // Allocate video buffer from FBM
    if((!fgFbmDmx1Used) && (!fgFbmDmx2Used))
    {
#if defined(CC_TRUSTZONE_SUPPORT) && defined(CC_SVP_SUPPORT)
        prFbmPool = FBM_Alloc(FBM_TYPE_TZ_DMX);
#else
        prFbmPool = FBM_Alloc(FBM_TYPE_DMX);
#endif
        ASSERT(prFbmPool != NULL);
        if (!prFbmPool)
        {
            Printf("Fail to get VFIFO!\n");
            return MTR_NOT_OK;
        }
    }

    if(rPid.u1ChannelId == 0)
    {
      	_IoMtDmx_Lock();
        fgFbmDmx1Used = TRUE;
		_IoMtDmx_Unlock();
    }
    else
    {
       	_IoMtDmx_Lock();
        fgFbmDmx2Used = TRUE;
		_IoMtDmx_Unlock();
    }

    u4VfifoAddr = prFbmPool->u4Addr;
    u4VfifoSize = prFbmPool->u4Size;
    
    ASSERT(u4VfifoAddr != 0);
    if(u4VfifoSize < MTAL_DMX_EXPECTED_SIZE)
    {
        MTDMX_PRINT("DMX buffer size is too smaler: 0x%x!\n", u4VfifoSize);
    }

    // Setup buffer attributes
    rPid.fgAllocateBuffer = FALSE;
    rPid.u4BufAddr = u4VfifoAddr;
    rPid.u4BufSize = u4VfifoSize;
    rPid.ePidType = DMX_PID_TYPE_ES_VIDEO;
    rPid.u1TsIndex = 0x0;
    rPid.pfnNotify = NULL;
    rPid.fgPrimary = TRUE;
    rPid.u2Pid = u2PidNum;
    rPid.fgEnable = fgEnable;
    rPid.u1ChannelId = 0x0;
    rPid.pfnScramble = NULL;
    rPid.pvScrambleTag = NULL;

    // Set by driver only
    rPid.fgPrimary = TRUE;
    rPid.u1TsIndex = 0;
    rPid.u1KeyIndex = 0x0;
    rPid.u1DeviceId = 0;
    rPid.u1SteerMode = DMX_STEER_TO_FTUP;
    rPid.ePcrMode = DMX_PCR_MODE_NONE;
    rPid.eDescMode = DMX_DESC_MODE_NONE;

    if (!_MtdmxSetPid(u1PhyPidx, DMX_PID_FLAG_ALL, &rPid))
    {
        return MTR_NOT_OK;
    }

    _IoMtDmx_Lock();
    _afgPidCreated[u1PhyPidx] = TRUE;
    _IoMtDmx_Unlock();

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Set a Audio Pid
 *
 *  @param  u1PidIndex      PID index (0 - 31)
 *  @param  u2PidNum        Video PID number
 *  @param  fgEnable        Enable audio pid or not
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetAudioPid (unsigned long arg)
{
    MTAL_IOCTL_3ARG_T    rArg;
    UINT8 u1Pidx ;
    UINT16 u2PidNum;
    BOOL fgEnable;
    DMX_PID_T rPid;
    UINT32 au4BufStart[3], au4BufEnd[3];
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;
    BOOL fgPidCreated = FALSE;
    UINT8 u1Instance;
    x_memset((void *)&rPid,0,sizeof(DMX_PID_T));

    USR_SPACE_ACCESS_VALIDATE_3ARG(arg);
    COPY_FROM_USER_3ARG(arg, rArg);

    u1Pidx = (UINT8)rArg.ai4Arg[0];
    u2PidNum = (UINT16)rArg.ai4Arg[1];
    fgEnable = (BOOL)rArg.ai4Arg[2];

    MTDMX_PRINT(" -u1ViturePidx =%d, u2PidNum = 0x%x, fgEnable  =%d\n ",u1Pidx,u2PidNum,fgEnable);

    if (u1Pidx >= MTDMX_NUM_PID_INDEX)
    {
        return MTR_NOT_OK;
    }

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }


	// If callback is used by MM, setup callback again to make sure we have correct callback registration
	 u1Instance = DMX_MUL_GetPidxInstId(u1PhyPidx);
	 _MTDMX_SetDecoderEx(u1Instance);
    _IoMtDmx_Lock();
    fgPidCreated = _afgPidCreated[u1PhyPidx];
    _IoMtDmx_Unlock();

    if (fgPidCreated)
    {
        rPid.fgEnable = fgEnable;
        if (!_MtdmxSetPid(u1PhyPidx, DMX_PID_FLAG_VALID, &rPid))
        {
            return MTR_NOT_OK;
        }

        return MTR_OK;
    }

#ifdef AUD_OLDFIFO_INTF
    if (AUD_GetAudFifo(&au4BufStart[0], &au4BufEnd[0], &au4BufStart[1],
                       &au4BufEnd[1]) != AUD_OK)
#else
    if ((AUD_GetAudFifo(0, &au4BufStart[0], &au4BufEnd[0]) != AUD_OK) ||
            (AUD_GetAudFifo(1, &au4BufStart[1], &au4BufEnd[1]) != AUD_OK)
            || (AUD_GetAudFifo(2, &au4BufStart[2], &au4BufEnd[2]) != AUD_OK)
       )
#endif
    {
        return MTR_NOT_OK;
    }

    if ((au4BufStart[0] == 0) || (au4BufStart[1] == 0)
            ||  (au4BufStart[2] == 0)
       )
    {
        return MTR_NOT_OK;
    }

    if (GetTargetCountry() == COUNTRY_US)
    {
        rPid.u1DeviceId = 0;        // Audio Device ID
    }
    else
    {
        rPid.u1DeviceId = 1;        // Audio Device ID
    }

    rPid.u4BufAddr = au4BufStart[rPid.u1DeviceId];
    rPid.u4BufSize = au4BufEnd[rPid.u1DeviceId] -
                     au4BufStart[rPid.u1DeviceId];
    rPid.fgAllocateBuffer = FALSE;

    rPid.ePidType = DMX_PID_TYPE_ES_AUDIO;
    rPid.u1TsIndex = 0x0;
    rPid.pfnNotify = NULL;
    rPid.fgPrimary = TRUE;
    rPid.u2Pid = u2PidNum;
    rPid.fgEnable = fgEnable;

    rPid.pfnScramble = NULL;
    rPid.pvScrambleTag = NULL;

    // Set by driver only
    rPid.fgPrimary = TRUE;
    rPid.u1TsIndex = 0;
    rPid.u1KeyIndex = 0x0;
    rPid.u1SteerMode = DMX_STEER_TO_FTUP;
    rPid.ePcrMode = DMX_PCR_MODE_NONE;
    rPid.eDescMode = DMX_DESC_MODE_NONE;

    if (!_MtdmxSetPid(u1PhyPidx, DMX_PID_FLAG_ALL, &rPid))
    {
        return MTR_NOT_OK;
    }

    _IoMtDmx_Lock();
    _afgPidCreated[u1PhyPidx] = TRUE;
    _IoMtDmx_Unlock();

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/*
 *  Set a Audio description Pid
 *
 *  @param  u1PidIndex      PID index (0 - 31)
 *  @param  u2PidNum        Video PID number
 *  @param  fgEnable        Enable audio pid or not
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetAudioDescPid (unsigned long arg)
{
    MTAL_IOCTL_3ARG_T    rArg;
    UINT8 u1Pidx ;
    UINT16 u2PidNum;
    BOOL fgEnable;
    DMX_PID_T rPid;
    UINT32 au4BufStart[3], au4BufEnd[3];
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;
    BOOL fgPidCreated = FALSE;
    UINT8 u1Instance;

    x_memset((void *)&rPid,0,sizeof(DMX_PID_T));

    USR_SPACE_ACCESS_VALIDATE_3ARG(arg);
    COPY_FROM_USER_3ARG(arg, rArg);

    u1Pidx = (UINT8)rArg.ai4Arg[0];
    u2PidNum = (UINT16)rArg.ai4Arg[1];
    fgEnable = (BOOL)rArg.ai4Arg[2];

    MTDMX_PRINT(" -u1VirtualPidx =%d, u2PidNum = 0x%x, fgEnable  =%d\n ",u1Pidx,u2PidNum,fgEnable);



    if (u1Pidx >= MTDMX_NUM_PID_INDEX)
    {
        return MTR_NOT_OK;
    }

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }


	// If callback is used by MM, setup callback again to make sure we have correct callback registration
    u1Instance = DMX_MUL_GetPidxInstId(u1PhyPidx);
	 _MTDMX_SetDecoderEx(u1Instance);
    _IoMtDmx_Lock();
    fgPidCreated = _afgPidCreated[fgPidCreated];
    _IoMtDmx_Unlock();

    if (fgPidCreated)
    {
        rPid.fgEnable = fgEnable;
        if (!_MtdmxSetPid(u1PhyPidx, DMX_PID_FLAG_VALID, &rPid))
        {
            return MTR_NOT_OK;
        }

        return MTR_OK;
    }

#ifdef AUD_OLDFIFO_INTF
    if (AUD_GetAudFifo(&au4BufStart[0], &au4BufEnd[0], &au4BufStart[1],
                       &au4BufEnd[1]) != AUD_OK)
#else
    if ((AUD_GetAudFifo(0, &au4BufStart[0], &au4BufEnd[0]) != AUD_OK) ||
            (AUD_GetAudFifo(1, &au4BufStart[1], &au4BufEnd[1]) != AUD_OK)
            || (AUD_GetAudFifo(2, &au4BufStart[2], &au4BufEnd[2]) != AUD_OK)
       )
#endif
    {
        return MTR_NOT_OK;
    }
    if ((au4BufStart[0] == 0) || (au4BufStart[1] == 0)
            ||  (au4BufStart[2] == 0)
       )
    {
        return MTR_NOT_OK;
    }

    rPid.u1DeviceId = 2;        // Audio Description Device ID
    rPid.u4BufAddr = au4BufStart[rPid.u1DeviceId];
    rPid.u4BufSize = au4BufEnd[rPid.u1DeviceId] -
                     au4BufStart[rPid.u1DeviceId];
    rPid.fgAllocateBuffer = FALSE;

    rPid.ePidType = DMX_PID_TYPE_ES_AUDIO;
    rPid.u1TsIndex = 0x0;
    rPid.pfnNotify = NULL;
    rPid.fgPrimary = TRUE;
    rPid.u2Pid = u2PidNum;
    rPid.fgEnable = fgEnable;

    // Set by driver only
    rPid.fgPrimary = TRUE;
    rPid.u1TsIndex = 0;
    rPid.u1KeyIndex = 0x0;
    rPid.u1SteerMode = DMX_STEER_TO_FTUP;
    rPid.ePcrMode = DMX_PCR_MODE_NONE;
    rPid.eDescMode = DMX_DESC_MODE_NONE;

    if (!_MtdmxSetPid(u1PhyPidx, DMX_PID_FLAG_ALL, &rPid))
    {
        return MTR_NOT_OK;
    }

    _IoMtDmx_Lock();
    _afgPidCreated[u1PhyPidx] = TRUE;
    _IoMtDmx_Unlock();

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/*
 *  Set a PCR Pid to one PID index
 *
 *  @param  u1TsIdx         TS index (0 - 3)
 *  @param  u1PidIndex      PID index (0 - 31)
 *  @param  u1PidIndex      Stc set (0 - 1)
 *  @param  fgEnable        Enable PCR of the PID or not
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetPcrPidEx  (unsigned long arg)
{
    MTAL_IOCTL_4ARG_T    rArg;
    UINT8 u1TsIdx;
    UINT8 u1Pidx;
    UINT8 u1StcSet;
    UINT16 u2PcrPid;
    DMX_PID_T rDrvPid;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;

    USR_SPACE_ACCESS_VALIDATE_4ARG(arg);
    COPY_FROM_USER_4ARG(arg, rArg);

    u1TsIdx = (UINT8)rArg.ai4Arg[0];
    u1Pidx = (UINT8)rArg.ai4Arg[1];
    u1StcSet = (UINT8)rArg.ai4Arg[2];
    u2PcrPid = (UINT16)rArg.ai4Arg[3];

    MTDMX_PRINT(" - u1VitrualPidx = %d, u2PcrPid = 0x%x, u1StcSet =  0x%x\n", u1Pidx, u2PcrPid, u1StcSet);

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }

    if ((u1TsIdx >= DMX_FRAMER_COUNT) || (u1StcSet >= DMX_NUM_STC_NUM))
    {
        MTDMX_PRINT(" wrong parameter - u1TsIdx = %d, u1StcSet = 0x%x\n", u1TsIdx, u1StcSet);
        return MTR_NOT_OK;
    }

    x_memset((VOID*)&rDrvPid, 0, sizeof(DMX_PID_T));
    rDrvPid.fgEnable = TRUE;
    rDrvPid.fgAllocateBuffer = FALSE;
    rDrvPid.u2Pid = u2PcrPid;
    rDrvPid.ePidType = DMX_PID_TYPE_NONE;
    rDrvPid.fgPrimary = FALSE;
    rDrvPid.u1TsIndex = u1TsIdx;
    rDrvPid.ePcrMode = DMX_PCR_MODE_NEW;
    rDrvPid.eDescMode = DMX_DESC_MODE_NONE;
    rDrvPid.u1DeviceId = u1StcSet;

    if (!_MtdmxSetPid(u1PhyPidx, DMX_PID_FLAG_ALL & ~DMX_PID_FLAG_BUFFER, &rDrvPid))
    {
        return MTR_NOT_OK;
    }

    if (DMX_SetStcSrc(u1PhyPidx, u1StcSet) != 0)
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/*
 *  Set a PCR
 *
 *  @param  u1PidIndex      PID index (0 - 31)
 *  @param  fgEnable        Enable PCR of the PID or not
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetPcr  (unsigned long arg)
{
    MTAL_IOCTL_2ARG_T    rArg;
    UINT8 u1Pidx ;
    BOOL fgEnable;
    DMX_PID_T rDrvPid;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;
    UINT8 u1StcSet;

    x_memset((void *)&rDrvPid,0,sizeof(DMX_PID_T));

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u1Pidx = (UINT8)rArg.ai4Arg[0];
    fgEnable = (BOOL)rArg.ai4Arg[1];

    MTDMX_PRINT(" - u1VirtualPidx = %d, fgEnable = %d\n",u1Pidx,fgEnable);

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }

    rDrvPid.fgEnable = fgEnable;

    if (!_MtdmxSetPid(u1PhyPidx, DMX_PID_FLAG_VALID, &rDrvPid))
    {
        return MTR_NOT_OK;
    }

    /* get STC Id from device ID */
    if (!DMX_GetPid(u1PhyPidx, DMX_PID_FLAG_DEVICE_ID, &rDrvPid))
    {
        return MTR_NOT_OK;
    }

    u1StcSet = rDrvPid.u1DeviceId;

    if (fgEnable)
    {
        if (DMX_SetStcSrc(u1PhyPidx, u1StcSet) != 0)
        {
            return MTR_NOT_OK;
        }
    }
    else
    {
        if (DMX_SetStcSrc(u1PhyPidx, STC_SRC_NS) != 0)   // Set to other PCR to disable
        {
            return MTR_NOT_OK;
        }
    }

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/*
 *  Setup a section filter
 *
 *  @param  u1FilterIndex   Filter index (0 - 31)
 *  @param  u4Flags         Function flags
 *  @param  prFilter        Filter structure
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetFilter (unsigned long arg)
{
    MTAL_IOCTL_3ARG_T    rArg;
    UINT8 u1FilterIndex, u1PhyFilterx;
    UINT32 u4Flags;
    MTDMX_FILTER_T *prFilter =NULL;
    MTDMX_FILTER_T rFilter;
    DMX_FILTER_T rDrvFilter;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;
    x_memset(&rDrvFilter, 0, sizeof(rDrvFilter));

    USR_SPACE_ACCESS_VALIDATE_3ARG(arg);
    COPY_FROM_USER_3ARG(arg, rArg);

    u1FilterIndex = (UINT8)rArg.ai4Arg[0];
    u4Flags = (UINT32)rArg.ai4Arg[1];
    prFilter = (MTDMX_FILTER_T*)rArg.ai4Arg[2];

    USR_SPACE_ACCESS_VALIDATE_ARG(prFilter, MTDMX_FILTER_T);
    COPY_FROM_USER_ARG(prFilter, rFilter, MTDMX_FILTER_T);
    
    MTDMX_PRINT(" -u1VirtFilterx = %u, u4Flags = 0x%x\n ", u1FilterIndex, u4Flags);
    MTDMX_PRINT_FTR("rFilter.", rFilter);

    u1PhyFilterx = _MTAL_DMX_PhysicalFilterx(u1FilterIndex);
    if(u1PhyFilterx == MTAL_DMX_MULTIPLE_INVALID_FILTERX)
    {
        MTDMX_PRINT("Get Phy Filterx error\n");
        return MTR_NOT_OK;
    }

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(rFilter.u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }

    // Driver here
    rDrvFilter.fgEnable = rFilter.fgEnable;
    rDrvFilter.fgCheckCrc = rFilter.fgCheckCrc;
    rDrvFilter.u1Pidx = u1PhyPidx;
    rDrvFilter.u1Offset = rFilter.u1Offset;
    rDrvFilter.au4Data[0] = (rFilter.au1Data[0] << 24) | (rFilter.au1Data[1] << 16) |
                            (rFilter.au1Data[2] << 8) | rFilter.au1Data[3];
    rDrvFilter.au4Data[1] = (rFilter.au1Data[4] << 24) | (rFilter.au1Data[5] << 16) |
                            (rFilter.au1Data[6] << 8) | rFilter.au1Data[7];
    rDrvFilter.au4Mask[0] = (rFilter.au1Mask[0] << 24) | (rFilter.au1Mask[1] << 16) |
                            (rFilter.au1Mask[2] << 8) | rFilter.au1Mask[3];
    rDrvFilter.au4Mask[1] = (rFilter.au1Mask[4] << 24) | (rFilter.au1Mask[5] << 16) |
                            (rFilter.au1Mask[6] << 8) | rFilter.au1Mask[7];


    //rDrvFilter.eMode = DMX_FILTER_MODE_GENERIC;
    rDrvFilter.eMode = DMX_FILTER_MODE_POS_NEG;

    u4Flags |= DMX_FILTER_FLAG_MODE;
    if (!DMX_SetFilter(u1PhyFilterx, 0, u4Flags, &rDrvFilter))
    {
        return MTR_NOT_OK;
    }

    rDrvFilter.u1Offset = 1;
    rDrvFilter.au4Data[0] = (rFilter.au1Data[8] << 24) | (rFilter.au1Data[9] << 16) |
                            (rFilter.au1Data[10] << 8) | rFilter.au1Data[11];
    rDrvFilter.au4Data[1] = (rFilter.au1Data[12] << 24) | (rFilter.au1Data[13] << 16) |
                            (rFilter.au1Data[14] << 8) | rFilter.au1Data[15];
    rDrvFilter.au4Mask[0] = (rFilter.au1Mask[8] << 24) | (rFilter.au1Mask[9] << 16) |
                            (rFilter.au1Mask[10] << 8) | rFilter.au1Mask[11];
    rDrvFilter.au4Mask[1] = (rFilter.au1Mask[12] << 24) | (rFilter.au1Mask[13] << 16) |
                            (rFilter.au1Mask[14] << 8) | rFilter.au1Mask[15];
    if (!DMX_SetFilter(u1PhyFilterx, 1, u4Flags, &rDrvFilter))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Get a section filter
 *
 *  @param  u1FilterIndex   Filter index (0 - 31)
 *  @param  u4Flags         Function flags
 *  @param  prFilter        Filter structure
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_GetFilter (unsigned long arg)
{
    MTAL_IOCTL_3ARG_T    rArg;
    UINT8 u1FilterIndex, u1PhyFilterx;
    UINT32 u4Flags;
    MTDMX_FILTER_T *prFilter = NULL;
    MTDMX_FILTER_T rFilter;
    DMX_FILTER_T rDrvFilter;
    UINT8 u1VirPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;
    x_memset(&rDrvFilter, 0, sizeof(rDrvFilter));

    USR_SPACE_ACCESS_VALIDATE_3ARG(arg);
    COPY_FROM_USER_3ARG(arg, rArg);

    u1FilterIndex = (UINT8)rArg.ai4Arg[0];
    u4Flags = (UINT32)rArg.ai4Arg[1];
    prFilter = (MTDMX_FILTER_T*)rArg.ai4Arg[2];

    u1PhyFilterx = _MTAL_DMX_PhysicalFilterx(u1FilterIndex);
    if(u1PhyFilterx == MTAL_DMX_MULTIPLE_INVALID_FILTERX)
    {
        MTDMX_PRINT("Get Phy Filterx error\n");
        return MTR_NOT_OK;
    }

    if (!DMX_GetFilter(u1PhyFilterx, 0, u4Flags, &rDrvFilter))
    {
        return MTR_NOT_OK;
    }

    _IoMtDmx_Lock();
    u1VirPidx = _arDmxInfo[rDrvFilter.u1Pidx].u1VirtualPidx;
    _IoMtDmx_Unlock();

    if (u1VirPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1VirPidx error\n");
    }


    rFilter.fgEnable = rDrvFilter.fgEnable;
    rFilter.fgCheckCrc = rDrvFilter.fgEnable;
    rFilter.u1Pidx = u1VirPidx;
    rFilter.u1Offset = rDrvFilter.u1Offset;
    rFilter.au1Data[0] = (UINT8)((rDrvFilter.au4Data[0] >> 24) & 0xFF);
    rFilter.au1Data[1] = (UINT8)((rDrvFilter.au4Data[0] >> 16) & 0xFF);
    rFilter.au1Data[2] = (UINT8)((rDrvFilter.au4Data[0] >> 8) & 0xFF);
    rFilter.au1Data[3] = (UINT8)(rDrvFilter.au4Data[0] & 0xFF);
    rFilter.au1Data[4] = (UINT8)((rDrvFilter.au4Data[1] >> 24) & 0xFF);
    rFilter.au1Data[5] = (UINT8)((rDrvFilter.au4Data[1] >> 16) & 0xFF);
    rFilter.au1Data[6] = (UINT8)((rDrvFilter.au4Data[1] >> 8) & 0xFF);
    rFilter.au1Data[7] = (UINT8)(rDrvFilter.au4Data[1] & 0xFF);
    rFilter.au1Mask[0] = (UINT8)((rDrvFilter.au4Mask[0] >> 24) & 0xFF);
    rFilter.au1Mask[1] = (UINT8)((rDrvFilter.au4Mask[0] >> 16) & 0xFF);
    rFilter.au1Mask[2] = (UINT8)((rDrvFilter.au4Mask[0] >> 8) & 0xFF);
    rFilter.au1Mask[3] = (UINT8)(rDrvFilter.au4Mask[0] & 0xFF);
    rFilter.au1Mask[4] = (UINT8)((rDrvFilter.au4Mask[1] >> 24) & 0xFF);
    rFilter.au1Mask[5] = (UINT8)((rDrvFilter.au4Mask[1] >> 16) & 0xFF);
    rFilter.au1Mask[6] = (UINT8)((rDrvFilter.au4Mask[1] >> 8) & 0xFF);
    rFilter.au1Mask[7] = (UINT8)(rDrvFilter.au4Mask[1] & 0xFF);

    if (!DMX_GetFilter(u1PhyFilterx, 1, u4Flags, &rDrvFilter))
    {
        return MTR_NOT_OK;
    }
    rFilter.au1Data[8] = (UINT8)((rDrvFilter.au4Data[0] >> 24) & 0xFF);
    rFilter.au1Data[9] = (UINT8)((rDrvFilter.au4Data[0] >> 16) & 0xFF);
    rFilter.au1Data[10] = (UINT8)((rDrvFilter.au4Data[0] >> 8) & 0xFF);
    rFilter.au1Data[11] = (UINT8)(rDrvFilter.au4Data[0] & 0xFF);
    rFilter.au1Data[12] = (UINT8)((rDrvFilter.au4Data[1] >> 24) & 0xFF);
    rFilter.au1Data[13] = (UINT8)((rDrvFilter.au4Data[1] >> 16) & 0xFF);
    rFilter.au1Data[14] = (UINT8)((rDrvFilter.au4Data[1] >> 8) & 0xFF);
    rFilter.au1Data[15] = (UINT8)(rDrvFilter.au4Data[1] & 0xFF);
    rFilter.au1Mask[8] = (UINT8)((rDrvFilter.au4Mask[0] >> 24) & 0xFF);
    rFilter.au1Mask[9] = (UINT8)((rDrvFilter.au4Mask[0] >> 16) & 0xFF);
    rFilter.au1Mask[10] = (UINT8)((rDrvFilter.au4Mask[0] >> 8) & 0xFF);
    rFilter.au1Mask[11] = (UINT8)(rDrvFilter.au4Mask[0] & 0xFF);
    rFilter.au1Mask[12] = (UINT8)((rDrvFilter.au4Mask[1] >> 24) & 0xFF);
    rFilter.au1Mask[13] = (UINT8)((rDrvFilter.au4Mask[1] >> 16) & 0xFF);
    rFilter.au1Mask[14] = (UINT8)((rDrvFilter.au4Mask[1] >> 8) & 0xFF);
    rFilter.au1Mask[15] = (UINT8)(rDrvFilter.au4Mask[1] & 0xFF);

    USR_SPACE_ACCESS_VALIDATE_ARG(prFilter, MTDMX_FILTER_T);
    COPY_TO_USER_ARG(prFilter, rFilter, MTDMX_FILTER_T);

    MTDMX_PRINT(" -u1FilterIndex = %u, u4Flags = 0x%x\n ",u1PhyFilterx,u4Flags);
    MTDMX_PRINT_FTR("rFilter.", rFilter);

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Allocate section buffer pool
 *
 *  @param  u4Size          Buffer size
 *  @param  pu4Addr         Return kernel address
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_PSI_AllocateBuffer (unsigned long arg)
{
    MTAL_IOCTL_2ARG_T    rArg;
    UINT32 u4Size;
    UINT32 *pu4Addr = NULL;
    UINT32 u4Addr;
    UINT32 u4Loop = 0;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u4Size = (UINT32)rArg.ai4Arg[0];
    pu4Addr = (UINT32*)rArg.ai4Arg[1];

    for(u4Loop = 0; u4Loop < MAX_ALLOC_BUFFER_COUNT; u4Loop++)
    {
        if(u4PsiBufAddr[u4Loop] == 0)
        {
            break;
        }
    }
    
    if(u4Loop >= MAX_ALLOC_BUFFER_COUNT)
    {
        Printf("_MTDMX_PES_AllocateBuffer u4PesBufAddr size overflow\n");
        return MTR_PARAMETER_ERROR;
    }

    u4Addr = (UINT32)x_mem_alloc(u4Size);
    if (u4Addr == 0)
    {
        return MTR_NOT_OK;
    }
    
    u4PsiBufAddr[u4Loop] = u4Addr;
    
    USR_SPACE_ACCESS_VALIDATE_ARG(pu4Addr, UINT32);
    COPY_TO_USER_ARG(pu4Addr, u4Addr, UINT32);

    MTDMX_PRINT(" - u4Size = 0x%x, u4Addr = 0x%x\n", u4Size, u4Addr);
    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Free a section buffer pool
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_PSI_FreeBuffer(unsigned long arg)
{
    UINT32 u4Addr;
    INT32 Arg;
    UINT32 u4Loop = 0;

    USR_SPACE_ACCESS_VALIDATE_ARG(arg, INT32);
    COPY_FROM_USER_1ARG(arg, Arg);

    u4Addr = (UINT32)Arg;

    if (u4Addr == 0)
    {
        return MTR_NOT_OK;
    }

    for(u4Loop = 0; u4Loop < MAX_ALLOC_BUFFER_COUNT;  u4Loop++)
    {
        if(u4PsiBufAddr[u4Loop] == u4Addr)
        {
            u4PsiBufAddr[u4Loop] = 0;
            break;
        }
    }
    
    if(u4Loop >= MAX_ALLOC_BUFFER_COUNT)
    {
        Printf("_MTDMX_PES_FreeBuffer u4Addr:0x%p not found.\n", u4Addr);
        return MTR_PARAMETER_ERROR;
    }
    
    x_mem_free((VOID*)u4Addr);

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Copy data from a section buffer
 *
 *  @param  u1Pidx          PID index, 0 ~ 31
 *  @param  u1SerialNumber  The serial number
 *  @param  u4FrameAddr     Frame address (Kernel address)
 *  @param  u4SkipSize      Skip size before copying
 *  @param  u4CopySize      Data size to copy
 *  @param  pu1Dest         Destination buffer (User address)
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_PSI_GetBuffer(unsigned long arg)
{
    MTAL_IOCTL_6ARG_T    rArg;
    UINT8 u1Pidx;
    UINT8 u1SerialNumber;
    UINT32 u4FrameAddr;
    UINT32 u4SkipSize;
    UINT32 u4CopySize;
    UCHAR* pu1Dest =NULL;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;

    USR_SPACE_ACCESS_VALIDATE_6ARG(arg);
    COPY_FROM_USER_6ARG(arg, rArg);

    u1Pidx = (UINT8)rArg.ai4Arg[0];
    u1SerialNumber = (UINT8)rArg.ai4Arg[1];
    u4FrameAddr = (UINT32)rArg.ai4Arg[2];
    u4SkipSize = (UINT32)rArg.ai4Arg[3];
    u4CopySize = (UINT32)rArg.ai4Arg[4];
    pu1Dest = (UCHAR*)rArg.ai4Arg[5];

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }

    if (!_pu1SecBuf)
    {
        MTDMX_PRINT("PSI_GetBuffer: null section buffer\n");
        return MTR_NOT_OK;
    }

    if (u4CopySize > MAX_SECTION_SIZE)
    {
        MTDMX_PRINT("PSI_GetBuffer: invalid size %u\n", u4CopySize);
        return MTR_NOT_OK;
    }

	VERIFY(x_sema_lock(_hSecBufSem, X_SEMA_OPTION_WAIT) == OSR_OK);

    if (!DMX_PSI_GetBuffer(u1PhyPidx, u1SerialNumber, u4FrameAddr,
                          u4SkipSize, u4CopySize, _pu1SecBuf))
    {
		VERIFY(x_sema_unlock(_hSecBufSem) == OSR_OK);
        MTDMX_PRINT("DMX_PSI_GetBuffer fail.\n");
        return MTR_NOT_OK;
    }

    USR_SPACE_ACCESS_VALIDATE_ARG_SIZE(pu1Dest, u4CopySize);
    COPY_TO_USER_ARG_SIZE(pu1Dest, _pu1SecBuf, u4CopySize);

	VERIFY(x_sema_unlock(_hSecBufSem) == OSR_OK);

    MTDMX_PRINT(" - u1PhyPidx = %u\n"
                "u1SerialNumber = 0x%x\n"
                "u4FrameAddr = 0x%x\n"
                "u4SkipSize = 0x%x\n"
                "u4CopySize = 0x%x\n",
                u1PhyPidx,
                u1SerialNumber,
                u4FrameAddr,
                u4SkipSize,
                u4CopySize);

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Unlock a section buffer
 *
 *  @param  u1Pidx          PID index, 0 ~ 31
 *  @param  u1SerialNumber  The serial number
 *  @param  u4Size          Unlocked data size
 *  @param  u4FrameAddr     Original frame address (Kernel address)
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_PSI_UnlockBuffer(unsigned long arg)
{
    MTAL_IOCTL_4ARG_T    rArg;
    UINT8 u1Pidx;
    UINT8 u1SerialNumber;
    UINT32 u4Size;
    UINT32 u4FrameAddr;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;

    USR_SPACE_ACCESS_VALIDATE_4ARG(arg);
    COPY_FROM_USER_4ARG(arg, rArg);

    u1Pidx = (UINT8)rArg.ai4Arg[0];
    u1SerialNumber = (UINT8)rArg.ai4Arg[1];
    u4Size = (UINT32)rArg.ai4Arg[2];
    u4FrameAddr = (UINT32)rArg.ai4Arg[3];

    MTDMX_PRINT(" - u1VirtualPidx = %u\n"
                "u1SerialNumber = 0x%x\n"
                "u4Size = 0x%x\n"
                "u4FrameAddr = 0x%x\n",
                u1Pidx,
                u1SerialNumber,
                u4Size,
                u4FrameAddr);

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }

    if (!DMX_PSI_UnlockBuffer(u1PhyPidx, u1SerialNumber, u4Size, u4FrameAddr))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/*
 *  Flush a section buffer
 *
 *  @param  u1Pidx          PID index, 0 ~ 31
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_PSI_FlushBuffer (unsigned long arg)
{
    UINT8 u1Pidx;
    INT32 Arg;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;

    USR_SPACE_ACCESS_VALIDATE_ARG(arg, INT32);
    COPY_FROM_USER_1ARG(arg, Arg);

    u1Pidx = (UINT8)Arg;

    MTDMX_PRINT(" - u1VirtualPidx = %d\n",u1Pidx);

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
    }

    //add driver implementation code here
    if (!DMX_PSI_FlushBuffer(u1PhyPidx))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Get section header and CRC
 *
 *  @param  u1Pidx          PID index, 0 ~ 31
 *  @param  u1SerialNumber  The serial number
 *  @param  prHeaderCRC     Section header/CRC structure
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_PSI_GetBufferSectionHeader(unsigned long arg)
{
    MTAL_IOCTL_6ARG_T rArg;
    UINT8 u1Pidx;
    UINT8 u1SerialNumber;
    UINT32 u4FrameAddr;
    UINT32 u4SkipSize;
    UINT32 u4CopySize;
    MTDMX_SECTION_HEADER_T *prHeader = NULL;
    MTDMX_SECTION_HEADER_T rHeader;
    UINT32 u4Offset;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;

    USR_SPACE_ACCESS_VALIDATE_6ARG(arg);
    COPY_FROM_USER_6ARG(arg, rArg);

    u1Pidx = (UINT8)rArg.ai4Arg[0];
    u1SerialNumber = (UINT8)rArg.ai4Arg[1];
    u4FrameAddr = (UINT32)rArg.ai4Arg[2];
    u4SkipSize = (UINT32)rArg.ai4Arg[3];
    u4CopySize = (UINT32)rArg.ai4Arg[4];
    prHeader = (MTDMX_SECTION_HEADER_T *)rArg.ai4Arg[5];

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }

    if (!_pu1SecBuf)
    {
        MTDMX_PRINT("PSI_GetBufferSectionHeader: null section buffer\n");
        return MTR_NOT_OK;
    }

    if (u4CopySize > MAX_SECTION_SIZE)
    {
        MTDMX_PRINT("PSI_GetBufferSectionHeader: invalid size %u\n", u4CopySize);
        return MTR_NOT_OK;
    }

	VERIFY(x_sema_lock(_hSecBufSem, X_SEMA_OPTION_WAIT) == OSR_OK);

    if (!DMX_PSI_GetBuffer(u1PhyPidx, u1SerialNumber, u4FrameAddr,
                          u4SkipSize, u4CopySize, _pu1SecBuf))
    {
		VERIFY(x_sema_unlock(_hSecBufSem) == OSR_OK);
        return MTR_NOT_OK;
    }

    rHeader.u1TableID = _pu1SecBuf[0];
    rHeader.u2SecLen = ((_pu1SecBuf[1] & 0xf) << 8) | _pu1SecBuf[2];
    rHeader.u1VerNum = (_pu1SecBuf[5] & 0x3e) >> 1;
    u4Offset = (UINT32)rHeader.u2SecLen + 3;

    if (u4Offset > MAX_SECTION_SIZE)
    {
    	VERIFY(x_sema_unlock(_hSecBufSem) == OSR_OK);
        return MTR_NOT_OK;
    }

    rHeader.u4CRC = (UINT32)_pu1SecBuf[u4Offset - 1] |
                    ((UINT32)_pu1SecBuf[u4Offset - 2] << 8) |
                    ((UINT32)_pu1SecBuf[u4Offset - 3] << 16) |
                    ((UINT32)_pu1SecBuf[u4Offset - 4] << 24);

	VERIFY(x_sema_unlock(_hSecBufSem) == OSR_OK);

    USR_SPACE_ACCESS_VALIDATE_ARG(prHeader, MTDMX_SECTION_HEADER_T);
    COPY_TO_USER_ARG(prHeader, rHeader, MTDMX_SECTION_HEADER_T);

    MTDMX_PRINT(" - u1PhyPidx = %u\n"
                "u1SerialNumber = 0x%x\n",
                u1PhyPidx,
                u1SerialNumber);
    MTDMX_PRINT_SEC("rHeader.",rHeader);
    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Allocate PES buffer pool
 *
 *  @param  u4Size          Buffer size
 *  @param  pu4Addr         Return allocated buffer address (Kernel address)
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_PES_AllocateBuffer(unsigned long arg)
{
    MTAL_IOCTL_2ARG_T    rArg;
    UINT32 u4Size;
    UINT32 *pu4Addr = NULL;
    UINT32 u4Addr;
    UINT32 u4Loop = 0;
    
    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u4Size = (UINT32)rArg.ai4Arg[0];
    pu4Addr = (UINT32*)rArg.ai4Arg[1];

    for(u4Loop = 0; u4Loop < MAX_ALLOC_BUFFER_COUNT; u4Loop++)
    {
        if(u4PesBufAddr[u4Loop] == 0)
        {
            break;
        }
    }
    
    if(u4Loop >= MAX_ALLOC_BUFFER_COUNT)
    {
        Printf("_MTDMX_PES_AllocateBuffer u4PesBufAddr size overflow\n");
        return MTR_PARAMETER_ERROR;
    }
    
    u4Addr = (UINT32)x_mem_alloc_virtual(u4Size);
    
    if (u4Addr == 0)
    {
        return MTR_NOT_OK;
    }
    
    u4PesBufAddr[u4Loop] = u4Addr;
    
    USR_SPACE_ACCESS_VALIDATE_ARG(pu4Addr, UINT32);
    COPY_TO_USER_ARG(pu4Addr, u4Addr, UINT32);

    MTDMX_PRINT(" - u4Size = 0x%x, u4Addr = 0x%x\n", u4Size, u4Addr);
    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Free a PES buffer pool
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_PES_FreeBuffer(unsigned long arg)
{
    UINT32 u4Addr;
    INT32 Arg;
    UINT32 u4Loop = 0;
    
    USR_SPACE_ACCESS_VALIDATE_ARG(arg, INT32);
    COPY_FROM_USER_1ARG(arg, Arg);

    u4Addr =(UINT32)Arg;

    if (u4Addr == 0)
    {
        return MTR_NOT_OK;
    }

    for(u4Loop = 0; u4Loop < MAX_ALLOC_BUFFER_COUNT;  u4Loop++)
    {
        if(u4PesBufAddr[u4Loop] == u4Addr)
        {
            u4PesBufAddr[u4Loop] = 0;
            break;
        }
    }
    
    if(u4Loop >= MAX_ALLOC_BUFFER_COUNT)
    {
        Printf("_MTDMX_PES_FreeBuffer u4Addr:0x%p not found.\n", u4Addr);
        return MTR_PARAMETER_ERROR;
    }
    
    x_mem_free((VOID*)u4Addr);

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/*
 *  Unlock a PES buffer
 *
 *  @param  u1Pidx          PID index, 0 ~ 31
 *  @param  u1SerialNumber  The serial number
 *  @param  u4Size          Unlocked data size
 *  @param  u4FrameAddr     Original frame address (Kernel address)
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_PES_UnlockBuffer(unsigned long arg)
{
    MTAL_IOCTL_4ARG_T    rArg;
    UINT8 u1Pidx;
    UINT8 u1SerialNumber;
    UINT32 u4Size;
    UINT32 u4FrameAddr;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;

    USR_SPACE_ACCESS_VALIDATE_4ARG(arg);
    COPY_FROM_USER_4ARG(arg, rArg);

    u1Pidx = (UINT8)rArg.ai4Arg[0];
    u1SerialNumber = (UINT8)rArg.ai4Arg[1];
    u4Size = (UINT32)rArg.ai4Arg[2];
    u4FrameAddr = (UINT32)rArg.ai4Arg[3];

    MTDMX_PRINT(" - u1VirtualPidx = %u\n"
                "u1SerialNumber = 0x%x\n"
                "u4Size = 0x%x\n"
                "u4FrameAddr = 0x%x\n",
                u1Pidx,
                u1SerialNumber,
                u4Size,
                u4FrameAddr);

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }

    if (!DMX_PES_UnlockBuffer(u1PhyPidx, u1SerialNumber, u4Size, u4FrameAddr))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Flush a PES buffer
 *
 *  @param  u1Pidx          PID index, 0 ~ 31
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_PES_FlushBuffer(unsigned long arg)
{
    UINT8 u1Pidx;
    INT32 Arg;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;

    USR_SPACE_ACCESS_VALIDATE_ARG(arg, INT32);
    COPY_FROM_USER_1ARG(arg, Arg);

    u1Pidx = (UINT8)Arg;

    MTDMX_PRINT(" - u1VirtualPidx = %d\n",u1Pidx);

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }

    if (!DMX_PES_FlushBuffer(u1PhyPidx))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Copy data from a PES buffer
 *
 *  @param  u1Pidx          PID index, 0 ~ 31
 *  @param  u1SerialNumber  The serial number
 *  @param  u4FrameAddr     Frame address (Kernel mode address)
 *  @param  u4SkipSize      Skip size before copying
 *  @param  u4CopySize      Data size to copy
 *  @param  pu1Dest         Destination buffer (User mode address)
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_PES_GetBuffer (unsigned long arg)
{
    MTAL_IOCTL_6ARG_T    rArg;
    UINT8 u1Pidx;
    UINT8 u1SerialNumber;
    UINT32 u4FrameAddr;
    UINT32 u4SkipSize;
    UINT32 u4CopySize;
    UCHAR* pu1Dest =NULL;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;
    UINT32 u4Addr;
    UCHAR* pu1Tmp =NULL;

    USR_SPACE_ACCESS_VALIDATE_6ARG(arg);
    COPY_FROM_USER_6ARG(arg, rArg);

    u1Pidx = (UINT8)rArg.ai4Arg[0];
    u1SerialNumber = (UINT8)rArg.ai4Arg[1];
    u4FrameAddr = (UINT32)rArg.ai4Arg[2];
    u4SkipSize = (UINT32)rArg.ai4Arg[3];
    u4CopySize = (UINT32)rArg.ai4Arg[4];
    pu1Dest = (UCHAR*)rArg.ai4Arg[5];

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }

    u4Addr = (UINT32)x_mem_alloc_virtual(u4CopySize);
    if (u4Addr == 0)
    {
        MTDMX_PRINT("alloc Pes temp buffer error\n");
        return MTR_NOT_OK;
    }
    pu1Tmp = (UINT8 *)u4Addr;

    if (!DMX_PES_GetBuffer(u1PhyPidx, u1SerialNumber, u4FrameAddr,
                           u4SkipSize, u4CopySize, pu1Tmp))
    {
        x_mem_free((VOID*)u4Addr);
        return MTR_NOT_OK;
    }

    if(SafeCopyToUserArgSize((void *)pu1Dest, (void *)pu1Tmp, u4CopySize) != MTR_OK)
    {
        x_mem_free((VOID*)u4Addr);
        return MTR_NOT_OK;
    }

    x_mem_free((VOID*)u4Addr);

    MTDMX_PRINT(" - u1PhyPidx = %u\n"
                "u1SerialNumber = 0x%x\n"
                "u4FrameAddr = 0x%x\n"
                "u4SkipSize = 0x%x\n"
                "u4CopySize = 0x%x\n",
                u1PhyPidx,
                u1SerialNumber,
                u4FrameAddr,
                u4SkipSize,
                u4CopySize);

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/*
 *  Copy data from a raw TS buffer
 *
 *  @param  u1Pidx          PID index, 0 ~ 31
 *  @param  u1SerialNumber  The serial number
 *  @param  u4FrameAddr     Frame address (Kernel mode address)
 *  @param  u4SkipSize      Skip size before copying
 *  @param  u4CopySize      Data size to copy
 *  @param  pu1Dest         Destination buffer (User mode address)
 
 *  Sony use MTDMX_RawTs_GetBuffer() API for getting PCR data. 
 *  The purpose of getting PCR data is for the following workaround, STC(System Time Clock) 32bit -> 33bit workaround solution.
 */
 
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_RawTs_GetBuffer (unsigned long arg)
{
    MTAL_IOCTL_6ARG_T    rArg;
    UINT8 u1Pidx;
    UINT8 u1SerialNumber;
    UINT32 u4FrameAddr;
    UINT32 u4SkipSize;
    UINT32 u4CopySize;
    UCHAR* pu1Dest =NULL;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;
    UCHAR* pu1Tmp =NULL;

    USR_SPACE_ACCESS_VALIDATE_6ARG(arg);
    COPY_FROM_USER_6ARG(arg, rArg);

    u1Pidx = (UINT8)rArg.ai4Arg[0];
    u1SerialNumber = (UINT8)rArg.ai4Arg[1];
    u4FrameAddr = (UINT32)rArg.ai4Arg[2];
    u4SkipSize = (UINT32)rArg.ai4Arg[3];
    u4CopySize = (UINT32)rArg.ai4Arg[4];
    pu1Dest = (UCHAR*)rArg.ai4Arg[5];

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }

    pu1Tmp = (UCHAR *)x_mem_alloc_virtual(u4CopySize);
    if (!pu1Tmp)
    {
        MTDMX_PRINT("alloc RawTs temp buffer error\n");
        return MTR_NOT_OK;
    }

    if (!DMX_RawTs_GetBuffer(u1PhyPidx, u1SerialNumber, u4FrameAddr,
                             u4SkipSize, u4CopySize, pu1Tmp))
    {
        x_mem_free((VOID*)pu1Tmp);
        return MTR_NOT_OK;
    }

    if(SafeCopyToUserArgSize((void *)pu1Dest, (void *)pu1Tmp, u4CopySize) != MTR_OK)
    {
        x_mem_free((VOID*)pu1Tmp);
        return MTR_NOT_OK;
    }

    x_mem_free((VOID*)pu1Tmp);

    MTDMX_PRINT(" - u1PhyPidx = %u\n"
                "u1SerialNumber = 0x%x\n"
                "u4FrameAddr = 0x%x\n"
                "u4SkipSize = 0x%x\n"
                "u4CopySize = 0x%x\n",
                u1PhyPidx,
                u1SerialNumber,
                u4FrameAddr,
                u4SkipSize,
                u4CopySize);

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Unlock a raw TS buffer
 *
 *  @param  u1Pidx          PID index, 0 ~ 31
 *  @param  u1SerialNumber  The serial number
 *  @param  u4Size          Unlocked data size
 *  @param  u4FrameAddr     Original frame address (Kernel address)
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_RawTs_UnlockBuffer(unsigned long arg)
{
    MTAL_IOCTL_4ARG_T    rArg;
    UINT8 u1Pidx;
    UINT8 u1SerialNumber;
    UINT32 u4Size;
    UINT32 u4FrameAddr;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;

    USR_SPACE_ACCESS_VALIDATE_4ARG(arg);
    COPY_FROM_USER_4ARG(arg, rArg);

    u1Pidx = (UINT8)rArg.ai4Arg[0];
    u1SerialNumber = (UINT8)rArg.ai4Arg[1];
    u4Size = (UINT32)rArg.ai4Arg[2];
    u4FrameAddr = (UINT32)rArg.ai4Arg[3];

    MTDMX_PRINT(" - u1VirtualPidx = %u\n"
                "u1SerialNumber = 0x%x\n"
                "u4Size = 0x%x\n"
                "u4FrameAddr = 0x%x\n",
                u1Pidx,
                u1SerialNumber,
                u4Size,
                u4FrameAddr);

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }

    if (!DMX_RawTs_UnlockBuffer(u1PhyPidx, u1SerialNumber, u4Size, u4FrameAddr))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Get the counter structure of a given pid index
 *
 *  @param  u1Pidx          PID index, 0 ~ 31
 *  @param  prCounters [output]
 *                          Pointer to the PID counter structure
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_GetPidCounters (unsigned long arg)
{
    MTAL_IOCTL_2ARG_T    rArg;
    UINT8 u1Pidx;
    MTDMX_PID_COUNTERS_T * prCounters =NULL;
    MTDMX_PID_COUNTERS_T rCounters;
    DMX_PID_COUNTERS_T rDrvCounters;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u1Pidx = (UINT8)rArg.ai4Arg[0];
    prCounters = (MTDMX_PID_COUNTERS_T*)rArg.ai4Arg[1];

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }

    if (!DMX_GetPidCounters(u1PhyPidx, &rDrvCounters))
    {
        return MTR_NOT_OK;
    }

    rCounters.u4PesCount = rDrvCounters.u4PesCount;
    rCounters.u4PicCount = rDrvCounters.u4PicCount;
    rCounters.u4SecCount = rDrvCounters.u4SecCount;

    USR_SPACE_ACCESS_VALIDATE_ARG(prCounters, MTDMX_PID_COUNTERS_T);
    COPY_TO_USER_ARG(prCounters, rCounters, MTDMX_PID_COUNTERS_T);

    MTDMX_PRINT(" -u1PhyPidx = %u ", u1PhyPidx);
    MTDMX_PID_CNT("rCounters.", rCounters);

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/** MTDMX_ResetPidCounters
 *  Reset counters of a given pid index
 *
 *  @param  u1Pidx          PID index, 0 ~ 31
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_ResetPidCounters (unsigned long arg)
{
    UINT8 u1Pidx;
    INT32 Arg;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;

    USR_SPACE_ACCESS_VALIDATE_ARG(arg, INT32);
    COPY_FROM_USER_1ARG(arg, Arg);

    u1Pidx = (UINT8)Arg;

    MTDMX_PRINT(" -u1VirtualPidx = %u \n",u1Pidx);

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }

    if (!DMX_ResetPidCounters(u1PhyPidx))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Get lock state
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_GetLockState(unsigned long arg)
{
    MTAL_IOCTL_2ARG_T    rArg;
    UINT8 u1TsIdx;
    BOOL *pfgLock = NULL;
    BOOL fgLock;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u1TsIdx = (UINT8)rArg.ai4Arg[0];
    pfgLock = (BOOL*)rArg.ai4Arg[1];

    fgLock = DMX_GetLockState(u1TsIdx);

    USR_SPACE_ACCESS_VALIDATE_ARG(pfgLock, BOOL);
    COPY_TO_USER_ARG(pfgLock, fgLock, BOOL);

    MTDMX_PRINT("-- Tsidx : %d, -fgLock = %d\n", u1TsIdx, fgLock);

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Get scramble state
 *
 *  @param  u1Pidx          PID index, 0 ~ 31
 *  @return     The scramble state
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_GetScrambleState(unsigned long arg)
{
    MTAL_IOCTL_2ARG_T    rArg;
    UINT8 u1Pidx ;
    MTDMX_SCRAMBLE_STATE_T* peScramble_State = NULL;
    MTDMX_SCRAMBLE_STATE_T eScramble_State;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u1Pidx = (UINT8)rArg.ai4Arg[0];
    peScramble_State = (MTDMX_SCRAMBLE_STATE_T*)rArg.ai4Arg[1];

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }

    eScramble_State = (MTDMX_SCRAMBLE_STATE_T)DMX_GetScrambleState(u1PhyPidx);

    USR_SPACE_ACCESS_VALIDATE_ARG(peScramble_State, MTDMX_SCRAMBLE_STATE_T);
    COPY_TO_USER_ARG(peScramble_State, eScramble_State, MTDMX_SCRAMBLE_STATE_T);

    MTDMX_PRINT(" -u1PhyPidx = %d, eScramble_State = %d\n",u1PhyPidx,eScramble_State);
    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Get raw scramble state
 *
 *  @param  u1Pidx          PID index, 0 ~ 31
 *  @return     The scramble state
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_GetRawScrambleState(unsigned long arg)
{
    MTAL_IOCTL_2ARG_T    rArg;
    UINT8 u1Pidx ;
    MTDMX_SCRAMBLE_STATE_T* peScramble_State = NULL;
    MTDMX_SCRAMBLE_STATE_T eScramble_State;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u1Pidx = (UINT8)rArg.ai4Arg[0];
    peScramble_State = (MTDMX_SCRAMBLE_STATE_T*)rArg.ai4Arg[1];

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }

    eScramble_State = (MTDMX_SCRAMBLE_STATE_T)DMX_GetRawScrambleState(u1PhyPidx);

    USR_SPACE_ACCESS_VALIDATE_ARG(peScramble_State, MTDMX_SCRAMBLE_STATE_T);
    COPY_TO_USER_ARG(peScramble_State, eScramble_State, MTDMX_SCRAMBLE_STATE_T);

    MTDMX_PRINT(" -u1PhyPidx = %d, RawScramble_State = %d\n",u1PhyPidx,eScramble_State);
    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Get front end state
 *
 *  @param  u1TsIdx          ts index
 *  @return     The front end state
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_GetFrontEndEx(unsigned long arg)
{
    MTAL_IOCTL_2ARG_T    rArg;
    UINT8 u1TsIdx ;
    MTDMX_FRONTEND_T* peFe = NULL;
    MTDMX_FRONTEND_T eFe;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u1TsIdx= (UINT8)rArg.ai4Arg[0];
    peFe = (MTDMX_FRONTEND_T*)rArg.ai4Arg[1];

    eFe = (MTDMX_FRONTEND_T)DMX_GetFrontEndEx(u1TsIdx);

    USR_SPACE_ACCESS_VALIDATE_ARG(peFe, MTDMX_FRONTEND_T);
    COPY_TO_USER_ARG(peFe, eFe, MTDMX_FRONTEND_T);

    MTDMX_PRINT(" -u1TsIdx = %d, eFe = %d\n",u1TsIdx,eFe);
    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Get current STC
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_GetCurSTC(unsigned long arg)
{
    MTAL_IOCTL_3ARG_T    rArg;
    STC_CLOCK rClk;
    UINT32 u4StcHi, u4StcLo;
    UINT32 *pu4StcHi, *pu4StcLo;
    UINT8 u1StcSet;
    USR_SPACE_ACCESS_VALIDATE_3ARG(arg);
    COPY_FROM_USER_3ARG(arg, rArg);

    u1StcSet = (UINT8)rArg.ai4Arg[0];
    pu4StcHi = (UINT32*)rArg.ai4Arg[1];
    pu4StcLo = (UINT32*)rArg.ai4Arg[2];

    if (u1StcSet >= DMX_NUM_STC_NUM)
    {
        return MTR_NOT_OK;
    }

    if (STC_GetSrc(u1StcSet, &rClk) != 0)
    {
        return MTR_NOT_OK;
    }

    u4StcLo = rClk.u4Base;
    u4StcHi = (UINT32)rClk.ucBaseHi | ((UINT32)rClk.u2Ext << 1);

    USR_SPACE_ACCESS_VALIDATE_ARG(pu4StcHi, UINT32);
    COPY_TO_USER_ARG(pu4StcHi, u4StcHi, UINT32);

    USR_SPACE_ACCESS_VALIDATE_ARG(pu4StcLo, UINT32);
    COPY_TO_USER_ARG(pu4StcLo, u4StcLo, UINT32);

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Set generic section filter
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetGenericFilter(unsigned long arg)
{
    MTAL_IOCTL_3ARG_T    rArg;
    UINT8 i, u1VirFilterx, u1PhyFilterx;
    UINT32 u4Flags;
    MTDMX_GENERIC_FILTER_T *prFilter =NULL;
    MTDMX_GENERIC_FILTER_T rFilter;
    DMX_FILTER_GENERIC_T rDrvFilter;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;
    #ifdef CC_MT5399
    DMX_PID_T rDrvPid;
    #endif

    x_memset(&rDrvFilter, 0, sizeof(rDrvFilter));

    USR_SPACE_ACCESS_VALIDATE_3ARG(arg);
    COPY_FROM_USER_3ARG(arg, rArg);

    u1VirFilterx = (UINT8)rArg.ai4Arg[0];
    u4Flags = (UINT32)rArg.ai4Arg[1];
    prFilter = (MTDMX_GENERIC_FILTER_T*)rArg.ai4Arg[2];

    USR_SPACE_ACCESS_VALIDATE_ARG(prFilter, MTDMX_GENERIC_FILTER_T);
    COPY_FROM_USER_ARG(prFilter, rFilter, MTDMX_GENERIC_FILTER_T);
    MTDMX_PRINT(" -u1FilterIndex = %u, u4Flags = 0x%x\n ",u1VirFilterx,u4Flags);
    MTDMX_PRINT_FTR("rFilter.", rFilter);

    //Virtual Filterx Convert to Physics
    u1PhyFilterx = _MTAL_DMX_PhysicalFilterx(u1VirFilterx);
    if(u1PhyFilterx == MTAL_DMX_MULTIPLE_INVALID_FILTERX)
    {
        MTDMX_PRINT("Get Phy Filterx error\n");
        return MTR_NOT_OK;
    }
    MTDMX_PRINT(" -u1PhyFilterx = %u\n ",u1PhyFilterx);

#ifdef CC_MT5399
    //find phypidx according vitual pidx
    u1PhyPidx = _MTAL_DMX_PhysicalPidx(rFilter.u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }
    else
    {
        rFilter.u1Pidx = u1PhyPidx;
    }

    //Only mt5399 need set tsindx
    x_memset(&rDrvPid, 0, sizeof(rDrvPid));

    //Get Ts index
    if (!DMX_GetPid(u1PhyPidx, DMX_PID_FLAG_TS_INDEX, &rDrvPid))
    {
        return MTR_NOT_OK;
    }

    rDrvFilter.u1Tsidx = rDrvPid.u1TsIndex;
    //rvFilter.u1Tsidx = DMX_MUL_GetTsIdx(DMX_MUL_GetPidxInstId(rDrvFilter.u1Pidx));
#else
    //if don't set pidx ,so we need not set virtual and physical pidx
    if ((u4Flags & DMX_FILTER_FLAG_PIDX) != 0)
    {
        u1PhyPidx = _MTAL_DMX_PhysicalPidx(rFilter.u1Pidx);

        if(u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
        {
            MTDMX_PRINT("Get u1PhyPidx error\n");
            return MTR_NOT_OK;
        }
        else
        {
            rFilter.u1Pidx = u1PhyPidx ;
        }
    }
#endif

    // Driver here
    rDrvFilter.fgEnable = rFilter.fgEnable;
    rDrvFilter.fgCheckCrc = rFilter.fgCheckCrc;
    rDrvFilter.u1Pidx = rFilter.u1Pidx;
    rDrvFilter.u1Offset = rFilter.u1Offset;
    rDrvFilter.fgShiftHwFilter = rFilter.fgShiftHwFilter;

    for (i=0; i<16; i++)
    {
        rDrvFilter.au1Data[i] = rFilter.au1Data[i];
        rDrvFilter.au1Mask[i] = rFilter.au1Mask[i];
        rDrvFilter.au1PosNeg[i] = rFilter.au1PosNeg[i];
    }

    if (!DMX_SetGenFilter(u1PhyFilterx, u4Flags, &rDrvFilter))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/*
 *  Get generic section filter setting
 *
 *  @param  u1FilterIndex   Filter index (0 - 31)
 *  @param  u4Flags         Function flags
 *  @param  prFilter        Filter structure
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_GetGenFilter (unsigned long arg)
{
    MTAL_IOCTL_3ARG_T    rArg;
    UINT8 u1VirFilterx, u1PhyFilterx, i;
    UINT32 u4Flags;
    MTDMX_GENERIC_FILTER_T *prFilter = NULL;
    MTDMX_GENERIC_FILTER_T rFilter;
    DMX_FILTER_GENERIC_T rDrvFilter;
    UINT8 u1VirPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;
    #ifdef CC_MT5399
    DMX_PID_T rDrvPid;
    #endif

    x_memset(&rFilter, 0, sizeof(rFilter));

    USR_SPACE_ACCESS_VALIDATE_3ARG(arg);
    COPY_FROM_USER_3ARG(arg, rArg);

    //Virtual Filterx Convert to Physics
    u1VirFilterx = (UINT8)rArg.ai4Arg[0];
    u1PhyFilterx = _MTAL_DMX_PhysicalFilterx(u1VirFilterx);
    if(u1PhyFilterx == MTAL_DMX_MULTIPLE_INVALID_FILTERX)
    {
        MTDMX_PRINT("Get Phy Filterx error\n");
        return MTR_NOT_OK;
    }
    MTDMX_PRINT(" -u1PhyFilterx = %u\n ",u1VirFilterx);
    
    u4Flags = (UINT32)rArg.ai4Arg[1];
    prFilter = (MTDMX_GENERIC_FILTER_T*)rArg.ai4Arg[2];

    USR_SPACE_ACCESS_VALIDATE_ARG(prFilter, MTDMX_GENERIC_FILTER_T);
    COPY_FROM_USER_ARG(prFilter, rFilter, MTDMX_GENERIC_FILTER_T);


    //find phy pidx according virtual pidx
    u1PhyPidx = _MTAL_DMX_PhysicalPidx(rFilter.u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }
    else
    {
        rDrvFilter.u1Pidx = u1PhyPidx ;
    }

    //Only mt5399 need set tsindx
    #ifdef CC_MT5399
    x_memset(&rDrvPid, 0, sizeof(rDrvPid));

    //Get Ts index
    if (!DMX_GetPid(u1PhyPidx, DMX_PID_FLAG_TS_INDEX, &rDrvPid))
    {
        return MTR_NOT_OK;
    }

    rDrvFilter.u1Tsidx = rDrvPid.u1TsIndex;
    #endif

    if (!DMX_GetGenFilter(u1PhyFilterx, u4Flags, (DMX_FILTER_GENERIC_T*)&rDrvFilter))
    {
        return MTR_NOT_OK;
    }

    _IoMtDmx_Lock();
    u1VirPidx = _arDmxInfo[rDrvFilter.u1Pidx].u1VirtualPidx;
    _IoMtDmx_Unlock();

    if (u1VirPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1VirPidx error\n");
        return MTR_NOT_OK;
    }
    else
    {
        rFilter.u1Pidx = u1VirPidx;
    }

    //
    rFilter.fgEnable= rDrvFilter.fgEnable;
    rFilter.fgCheckCrc = rDrvFilter.fgCheckCrc;
    rFilter.u1Offset = rDrvFilter.u1Offset;

    for (i=0; i<16; i++)
    {
         rFilter.au1Data[i]= rDrvFilter.au1Data[i];
         rFilter.au1Mask[i] = rDrvFilter.au1Mask[i];
         rFilter.au1PosNeg[i] = rDrvFilter.au1PosNeg[i];
    }

    USR_SPACE_ACCESS_VALIDATE_ARG(prFilter, MTDMX_GENERIC_FILTER_T);
    COPY_TO_USER_ARG(prFilter, rFilter, MTDMX_GENERIC_FILTER_T);

    MTDMX_PRINT(" -u1PhyFilterx = %u, u4Flags = 0x%x\n ",u1PhyFilterx,u4Flags);
    MTDMX_PRINT_FTR("rFilter.", rFilter);

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  _MTDMX_ConnectFilter
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_ConnectFilter(unsigned long arg)
{
    MTAL_IOCTL_2ARG_T    rArg;
    UINT8 u1Inst = 0;
    DMX_CONN_TYPE_T eConType;
    UINT8 u1VirFilterx, u1PhyFilterx;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u1VirFilterx = (UINT8)rArg.ai4Arg[0];
    eConType = (DMX_CONN_TYPE_T)rArg.ai4Arg[1];

    if (u1VirFilterx >= MTDMX_EXTEND_FILTER_START)
    {
        return MTR_NOT_OK;
    }

    if (eConType == DMX_CONN_TYPE_NONE)
    {
        return MTR_NOT_OK;
    }

    u1Inst = DMX_MUL_GetAvailableInst(eConType);

    if (u1Inst == DMX_MULTIPLE_NULL_INSTANCE)
    {
        MTDMX_PRINT("Instances are all occupied.\n");
        return u1Inst;
    }

    u1PhyFilterx = DMX_MUL_GetAvailableFilter(u1Inst);
    if (u1PhyFilterx == DMX_MULTIPLE_NULL_FILTER)
    {
        MTDMX_PRINT("Filterx are all occupied.\n");
        return MTR_NOT_OK;
    }

    _IoMtDmx_Lock();
    _arDmxFilterInfo[u1PhyFilterx].fgValid = TRUE;
    _arDmxFilterInfo[u1PhyFilterx].eConType = eConType;
    _arDmxFilterInfo[u1PhyFilterx].u1VirtualFilterIdx = u1VirFilterx;
    _IoMtDmx_Unlock();

    MTDMX_PRINT(" -u1PhyFilterx = %d, u1VirFilterx = %d\n", u1PhyFilterx, u1VirFilterx);

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  _MTDMX_ConnectAvailableFilterx
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_ConnectAvailableFilterx(unsigned long arg)
{
    MTAL_IOCTL_2ARG_T    rArg;
    UINT8 u1Inst = 0;
    DMX_CONN_TYPE_T eConType;
    UINT8 *pu1VirFilterx;
    UINT8 u1VirFilterx, u1PhyFilterx;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);
    
    eConType = (DMX_CONN_TYPE_T)rArg.ai4Arg[0];
    pu1VirFilterx = (UINT8*)rArg.ai4Arg[1];

    if (eConType == DMX_CONN_TYPE_NONE)
    {
        return MTR_NOT_OK;
    }

    u1Inst = DMX_MUL_GetAvailableInst(eConType);

    if (u1Inst == DMX_MULTIPLE_NULL_INSTANCE)
    {
        MTDMX_PRINT("Instances are all occupied.\n");
        return u1Inst;
    }

    u1PhyFilterx = DMX_MUL_GetAvailableFilter(u1Inst);
    if (u1PhyFilterx == DMX_MULTIPLE_NULL_FILTER)
    {
        MTDMX_PRINT("Filterx are all occupied.\n");
        return MTR_NOT_OK;
    }

    u1VirFilterx = u1PhyFilterx + MTDMX_EXTEND_FILTER_START;

    _IoMtDmx_Lock();
    _arDmxFilterInfo[u1PhyFilterx].fgValid = TRUE;
    _arDmxFilterInfo[u1PhyFilterx].eConType = eConType;
    _arDmxFilterInfo[u1PhyFilterx].u1VirtualFilterIdx = u1VirFilterx;
    _IoMtDmx_Unlock();

    USR_SPACE_ACCESS_VALIDATE_ARG(pu1VirFilterx, UINT8);
    COPY_TO_USER_ARG(pu1VirFilterx, u1VirFilterx, UINT8);

    MTDMX_PRINT(" -u1PhyFilterx = %d, u1VirFilterx = %d\n", u1PhyFilterx, u1VirFilterx);

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  _MTDMX_DisConnectFilter
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_DisConnectFilter(unsigned long arg)
{
    INT32 Arg;
    UINT8 u1VirFilterx, u1PhyFilterx;

    USR_SPACE_ACCESS_VALIDATE_ARG(arg, INT32);
    COPY_FROM_USER_1ARG(arg, Arg);

    u1VirFilterx = (UINT8)Arg;

    //Virtual Filterx Convert to Physics
    u1PhyFilterx = _MTAL_DMX_PhysicalFilterx(u1VirFilterx);
    if(u1PhyFilterx == MTAL_DMX_MULTIPLE_INVALID_FILTERX)
    {
        MTDMX_PRINT("Get Phy Filterx error\n");
        return MTR_NOT_OK;
    }
    
    _IoMtDmx_Lock();
    _arDmxFilterInfo[u1PhyFilterx].fgValid = FALSE;
    _arDmxFilterInfo[u1PhyFilterx].eConType = DMX_CONN_TYPE_BUFAGENT_0;
    _arDmxFilterInfo[u1PhyFilterx].u1VirtualFilterIdx = MTAL_DMX_MULTIPLE_INVALID_FILTERX;
    _IoMtDmx_Unlock();

    UNUSED(DMX_MUL_FreeFilter(u1PhyFilterx));

    MTDMX_PRINT(" -u1Filterx = %d \n",u1VirFilterx);

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/** Set DES desrambler key
 *
 *  @param  u1Index         The key index
 *  @param  fg3Des          TRUE: 3DES, FALSE: DES
 *  @param  fgEven          TRUE: even key, FALSE: odd key
 *  @param  au4Key          The key
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetDesKey(unsigned long arg)
{
    MTAL_IOCTL_4ARG_T    rArg;
    UINT8 u1KeyIdx;
    BOOL fg3Des;
    BOOL fgEven;
    UINT32* pu4Key;
    UINT32 au4Key[6];

    USR_SPACE_ACCESS_VALIDATE_4ARG(arg);
    COPY_FROM_USER_4ARG(arg, rArg);

    u1KeyIdx = (UINT8)rArg.ai4Arg[0];
    fg3Des = (BOOL)rArg.ai4Arg[1];
    fgEven = (BOOL)rArg.ai4Arg[2];
    pu4Key = (UINT32*)rArg.ai4Arg[3];

    USR_SPACE_ACCESS_VALIDATE_ARG_SIZE(pu4Key, 24);
    COPY_FROM_USER_ARG_SIZE(pu4Key, au4Key, 24);

    MTDMX_PRINT(" -u1Index=%d, fg3Des=%d, fgEven=%d\n", u1KeyIdx, (int)fg3Des, (int)fgEven);

    if (!DMX_SetDesKey(u1KeyIdx, fg3Des, fgEven, au4Key))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/** Set the initial vector of DES
 *
 *  @param  u4IvHi          The high word of the initial vector
 *  @param  u4IvLo          The low word of the initial vector
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetDesOddEvenIV(unsigned long arg)
{
    MTAL_IOCTL_4ARG_T    rArg;
    UINT8 u1Idx;
    UINT32 u4IvHi;
    UINT32 u4IvLo;
    BOOL fgEven;

    USR_SPACE_ACCESS_VALIDATE_4ARG(arg);
    COPY_FROM_USER_4ARG(arg, rArg);

    u1Idx = (UINT8)rArg.ai4Arg[0];
    fgEven = (BOOL)rArg.ai4Arg[1];
    u4IvHi = (UINT32)rArg.ai4Arg[2];
    u4IvLo = (UINT32)rArg.ai4Arg[3];

    MTDMX_PRINT(" -u4IvHi=0x%x, u4IvLo=0x%x\n", (unsigned int)u4IvHi,
                (unsigned int)u4IvLo);

    DMX_SetDesIV(u1Idx, u4IvHi, u4IvLo, fgEven);

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/** Set RTB mode of DES
 *
 *  @param  eMode          MTDMX_DESC_RTB_MODE_T
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetRtbMode(unsigned long arg)
{
    UINT8 u1Idx;
    DMX_DESC_RTB_MODE_T eMode;
    MTAL_IOCTL_2ARG_T rArg;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u1Idx = (UINT8)rArg.ai4Arg[0];
    eMode = (DMX_DESC_RTB_MODE_T)rArg.ai4Arg[1];

    MTDMX_PRINT(" - u1Pidx = %d \n", eMode);

    DMX_SetRtbMode(u1Idx, eMode);

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/** Set AES key len
 *
 *  @param  u4KeyLen        The key length
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetAesKeyLen(unsigned long arg)
{
    MTAL_IOCTL_2ARG_T rArg;
    UINT8 u1Idx;
    UINT32 u4KeyLen;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u1Idx = (UINT8)rArg.ai4Arg[0];
    u4KeyLen = (UINT32)rArg.ai4Arg[1];

    MTDMX_PRINT(" - KeyLen=%d\n", (int)u4KeyLen);

    DMX_SetAesKeyLen(u1Idx, u4KeyLen);

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/** Set AES key
 *
 *  @param  u1Index         The key index
 *  @param  fgEven          If fgEven=TRUE means set even key
 *  @param  au4Key          The key value
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetAesKey(unsigned long arg)
{
    MTAL_IOCTL_3ARG_T    rArg;
    UINT8 u1KeyIdx;
    BOOL fgEven;
    UINT32* pu4Key;
    UINT32 au4Key[8];

    USR_SPACE_ACCESS_VALIDATE_3ARG(arg);
    COPY_FROM_USER_3ARG(arg, rArg);

    u1KeyIdx = (UINT8)rArg.ai4Arg[0];
    fgEven = (BOOL)rArg.ai4Arg[1];
    pu4Key = (UINT32*)rArg.ai4Arg[2];

    USR_SPACE_ACCESS_VALIDATE_ARG_SIZE(pu4Key, 32);
    COPY_FROM_USER_ARG_SIZE(pu4Key, au4Key, 32);

    MTDMX_PRINT(" - u1Index=%d, fgEven=%d\n", (int)u1KeyIdx, (int)fgEven);

    if (!DMX_SetAesKey(u1KeyIdx, fgEven, au4Key))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/** Set the odd/even initial vector
 *
 *  @param  au4Iv           The initial vector
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetAesOddEvenIV(unsigned long arg)
{
    MTAL_IOCTL_3ARG_T  rArg;
    UINT8 u1Idx;
    BOOL fgEven;
    UINT32* pu4Iv;
    UINT32 au4Iv[4];

    USR_SPACE_ACCESS_VALIDATE_3ARG(arg);
    COPY_FROM_USER_3ARG(arg, rArg);

    u1Idx = (UINT8)rArg.ai4Arg[0];
    fgEven = (BOOL)rArg.ai4Arg[1];
    pu4Iv = (UINT32*)rArg.ai4Arg[2];

    USR_SPACE_ACCESS_VALIDATE_ARG_SIZE(pu4Iv, 16);
    COPY_FROM_USER_ARG_SIZE(pu4Iv, au4Iv, 16);

    DMX_SetAesIV(u1Idx, au4Iv, fgEven);

    UNUSED(fgEven);
    UNUSED(au4Iv);

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/** Set the initial vector of AES
 *
 *  @param  u1Pidx           PID index value
 *  @param  eDescMode        Descramble mode
 *  @param  u1KyeIndex       Key index value
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetDescramblPid(unsigned long arg)
{
    MTAL_IOCTL_3ARG_T    rArg;
    UINT8 u1Pidx;
    MTDMX_DESC_MODE_T eDescMode;
    UINT8 u1KeyIndex;
    DMX_PID_T rPid;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;

    USR_SPACE_ACCESS_VALIDATE_3ARG(arg);
    COPY_FROM_USER_3ARG(arg, rArg);

    u1Pidx = (UINT8)rArg.ai4Arg[0];
    eDescMode = (MTDMX_DESC_MODE_T)rArg.ai4Arg[1];
    u1KeyIndex = (UINT8)rArg.ai4Arg[2];

    MTDMX_PRINT(" - u1VirtualPidx=%d, eDescMode=%d, u1KeyIndex=%d\n",
                (int)u1Pidx, (int)eDescMode, (int)u1KeyIndex);

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }

    rPid.eDescMode = (DMX_DESC_MODE_T)eDescMode;
    rPid.u1KeyIndex = u1KeyIndex;
    if (!DMX_SetPid(u1PhyPidx, DMX_PID_FLAG_DESC_MODE | DMX_PID_FLAG_KEY_INDEX, &rPid))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/** Set the initial vector of AES
 *
 *  @param  u1Pidx           PID index value
 *  @param  eDescMode        Descramble mode
 *  @param  u1KyeIndex       Key index value
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetFileDescramblPid(unsigned long arg)
{
    MTAL_IOCTL_3ARG_T    rArg;
    UINT8 u1Pidx;
    MTDMX_DESC_MODE_T eDescMode;
    UINT8 u1KeyIndex;
    DMX_PID_T rPid;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;

    USR_SPACE_ACCESS_VALIDATE_3ARG(arg);
    COPY_FROM_USER_3ARG(arg, rArg);

    u1Pidx = (UINT8)rArg.ai4Arg[0];
    eDescMode = (MTDMX_DESC_MODE_T)rArg.ai4Arg[1];
    u1KeyIndex = (UINT8)rArg.ai4Arg[2];

    MTDMX_PRINT(" - u1VirtualPidx=%d, eDescMode=%d, u1KeyIndex=%d\n",
                (int)u1Pidx, (int)eDescMode, (int)u1KeyIndex);

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }

    rPid.eDescMode = (DMX_DESC_MODE_T)eDescMode;
    rPid.u1KeyIndex = u1KeyIndex;
    if (!DMX_SetFilePid(u1PhyPidx, DMX_PID_FLAG_DESC_MODE | DMX_PID_FLAG_KEY_INDEX, &rPid))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/** _MTDMX_SetDVBKey
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetDVBKey(unsigned long arg)
{
    MTAL_IOCTL_3ARG_T rArg;
    UINT8 u1Index;
    BOOL fgEven;
    UINT32 *pu4Key;
    UINT32 au4Key[2];

    USR_SPACE_ACCESS_VALIDATE_3ARG(arg);
    COPY_FROM_USER_3ARG(arg, rArg);

    u1Index = (UINT8)rArg.ai4Arg[0];
    fgEven = (BOOL)rArg.ai4Arg[1];
    pu4Key = (UINT32*)rArg.ai4Arg[2];

    USR_SPACE_ACCESS_VALIDATE_ARG_SIZE(pu4Key, 8);
    COPY_FROM_USER_ARG_SIZE(pu4Key, au4Key, 8);

    if (!DMX_SetDVBKey(u1Index, fgEven, au4Key))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/** Set the initial vector of DVB
 *
 *  @param  u4IvHi          The high word of the initial vector
 *  @param  u4IvLo          The low word of the initial vector
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetDVBIV(unsigned long arg)
{
    MTAL_IOCTL_4ARG_T    rArg;
    UINT8 u1Idx;
    UINT32 u4IvHi;
    UINT32 u4IvLo;
    BOOL fgEven;

    USR_SPACE_ACCESS_VALIDATE_4ARG(arg);
    COPY_FROM_USER_4ARG(arg, rArg);

    u1Idx = (UINT8)rArg.ai4Arg[0];
    fgEven = (BOOL)rArg.ai4Arg[1];
    u4IvHi = (UINT32)rArg.ai4Arg[2];
    u4IvLo = (UINT32)rArg.ai4Arg[3];

    MTDMX_PRINT(" -u4IvHi=0x%x, u4IvLo=0x%x\n", (unsigned int)u4IvHi,
                (unsigned int)u4IvLo);

    DMX_SetDVBIV(u1Idx, u4IvHi, u4IvLo, fgEven);

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/** Set crypto key
 *
 *  @param  u1KeyIdx        The key index
 *  @param  fgEven          If fgEven=TRUE means set even key
 *  @param  eKeyType        The key type 
 *  @param  pu1Key          Pointer to the key value
 *  @param  u4KeyLen        The key length 
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetCryptoKey(unsigned long arg)
{
    MTAL_IOCTL_5ARG_T    rArg;
    UINT8 u1KeyIdx;
    BOOL fgEven;
    DMX_CRYPTO_KEY_TYPE_T eKeyType;
    UINT8 *pu1UserKey, *pu1Key;
    UINT32 u4KeyLen;

    USR_SPACE_ACCESS_VALIDATE_5ARG(arg);
    COPY_FROM_USER_5ARG(arg, rArg);

    u1KeyIdx = (UINT8)rArg.ai4Arg[0];
    fgEven = (BOOL)rArg.ai4Arg[1];
    eKeyType = (DMX_CRYPTO_KEY_TYPE_T)rArg.ai4Arg[2];
    pu1UserKey = (UINT8*)rArg.ai4Arg[3];
    u4KeyLen = (UINT32)rArg.ai4Arg[4]; 
    

    pu1Key = (UINT8 *)x_mem_alloc_virtual(u4KeyLen);
    if (!pu1Key)
    {
        MTDMX_PRINT("alloc key buffer error, size=%u\n", u4KeyLen);
        return MTR_NOT_OK;
    }

    if(SafeCopyFromUserArgSize((void *)pu1UserKey, (void *)pu1Key, u4KeyLen) != MTR_OK)
    {
        x_mem_free((VOID*)pu1Key);
        return MTR_NOT_OK;
    }

    if (!DMX_SetCryptoKey(u1KeyIdx, fgEven, eKeyType, pu1Key, u4KeyLen))
    {
        x_mem_free((VOID*)pu1Key);
        return MTR_NOT_OK;
    }
				
    x_mem_free((VOID*)pu1Key);
    
    MTDMX_PRINT(" - u1KeyIdx=%d, fgEven=%d, eKeyType=%u, u4KeyLen=%u\n", 
                (int)u1KeyIdx, (int)fgEven, (UINT32)eKeyType, u4KeyLen);

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  Get ES fifo data size
 *
 *  @param  u1Pidx          PID index, 0 ~ 79
 *  @param  pu4Size [out]
 *                          The ES fifo Size
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_Get_ESFifoSize(unsigned long arg)
{
    MTAL_IOCTL_2ARG_T    rArg;
    UINT8 u1Pidx;
    UINT32* pu4Size;
    UINT32 u4Size;
    DMX_PID_T rPid;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u1Pidx = (UINT8)rArg.ai4Arg[0];
    pu4Size = (UINT32*)rArg.ai4Arg[1];

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }

    if (!DMX_GetPid(u1PhyPidx, DMX_PID_FLAG_DATA_POINTERS | DMX_PID_FLAG_BUFFER, &rPid))
    {
        return MTR_NOT_OK;
    }

    u4Size = DATASIZE(rPid.u4Rp, rPid.u4Wp, rPid.u4BufSize);

    USR_SPACE_ACCESS_VALIDATE_ARG(pu4Size, UINT32);
    COPY_TO_USER_ARG(pu4Size, u4Size, UINT32);

    MTDMX_PRINT("u1PhyPidIndex = %d , Size = %d.\n",u1PhyPidx,u4Size);

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/*
 *  _MTDMX_GetPacketStatus
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_GetPacketStatus(unsigned long arg)
{
    MTAL_IOCTL_4ARG_T rArg;
    UINT8 u1Tsidx;
    UINT32 u4MsTime;
    UINT32 u4RcvCount, u4DropCount;
    UINT32 *pu4RcvCount, *pu4DropCount;

    USR_SPACE_ACCESS_VALIDATE_4ARG(arg);
    COPY_FROM_USER_4ARG(arg, rArg);

    u1Tsidx  = (UINT8)rArg.ai4Arg[0];
    u4MsTime = (UINT32)rArg.ai4Arg[1];
    pu4RcvCount = (UINT32*)rArg.ai4Arg[2];
    pu4DropCount = (UINT32*)rArg.ai4Arg[3];

    DMX_GetPacketStatus(u1Tsidx, u4MsTime, &u4RcvCount, &u4DropCount);

    USR_SPACE_ACCESS_VALIDATE_ARG(pu4RcvCount, UINT32);
    COPY_TO_USER_ARG(pu4RcvCount, u4RcvCount, UINT32);

    USR_SPACE_ACCESS_VALIDATE_ARG(pu4DropCount, UINT32);
    COPY_TO_USER_ARG(pu4DropCount, u4DropCount, UINT32);

    MTDMX_PRINT("Tsindex: %u, Period: %u ms, receive %u pkt, drop %u pkt\n",
                u1Tsidx, u4MsTime, u4RcvCount, u4DropCount);
    return MTR_OK;
}


#ifdef ENABLE_MULTIMEDIA
static MT_RESULT_T _MTDMX_AES_SetDecryptInfo(unsigned long arg)
{
    MTAL_IOCTL_2ARG_T    rArg;
    UINT8 i;
    UINT32 u4Flags;
    MTDMX_DRM_AES_T* prDrm =NULL;
    MTDMX_DRM_AES_T rDrm;
    DMX_MM_DRM_AES_T rDrvDrm;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u4Flags = (UINT32)rArg.ai4Arg[0];
    prDrm = (MTDMX_DRM_AES_T*)rArg.ai4Arg[1];

    USR_SPACE_ACCESS_VALIDATE_ARG(prDrm, MTDMX_DRM_AES_T);
    COPY_FROM_USER_ARG(prDrm, rDrm, MTDMX_DRM_AES_T);

    rDrvDrm.fgCBC = rDrm.fgCBC;
    rDrvDrm.u4KeyBitLen = rDrm.u4KeyBitLen;
    rDrvDrm.u4Offset = rDrm.u4Offset;
    rDrvDrm.u4EncryLen = rDrm.u4EncryLen;
    rDrvDrm.fgEncrypt = rDrm.fgEncrypt;

    for (i=0; i <16; i++)
    {
        rDrvDrm.au1IV[i] = rDrm.au1IV[i];
    }

    for (i=0; i <32; i++)
    {
        rDrvDrm.au1Key[i] = rDrm.au1Key[i];
    }

    if (!DMX_AES_SetDecryptInfo(u4Flags, &rDrvDrm))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}


static MT_RESULT_T _MTDMX_AES_MoveBlockData(unsigned long arg)
{
    INT32    Arg;
    MTDMX_DRM_AES_BLKDATA_T* prBlkData =NULL;
    MTDMX_DRM_AES_BLKDATA_T rBlkData;
    //DMX_AES_BLKDATA_T rDrvBlkData;

    USR_SPACE_ACCESS_VALIDATE_ARG(arg, INT32);
    COPY_FROM_USER_1ARG(arg, Arg);

    prBlkData = (MTDMX_DRM_AES_BLKDATA_T*)Arg;

    USR_SPACE_ACCESS_VALIDATE_ARG(prBlkData, MTDMX_DRM_AES_BLKDATA_T);
    COPY_FROM_USER_ARG(prBlkData, rBlkData, MTDMX_DRM_AES_BLKDATA_T);

    if (!DMX_AES_MoveBlockData((DMX_AES_BLKDATA_T*)&rBlkData))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}


static MT_RESULT_T _MTDMX_AES_SetDecryptInfoEx(unsigned long arg)
{
    MTAL_IOCTL_3ARG_T    rArg;
    UINT8 i;
    UINT32 u4Flags;
    MTDMX_DRM_AES_T* prDrm =NULL;
    MTDMX_DRM_AES_T rDrm;
    DMX_MM_DRM_AES_T rDrvDrm;
    UINT8 u1Idx;

    USR_SPACE_ACCESS_VALIDATE_3ARG(arg);
    COPY_FROM_USER_3ARG(arg, rArg);

    u1Idx = (UINT8)rArg.ai4Arg[0];
    u4Flags = (UINT32)rArg.ai4Arg[1];
    prDrm = (MTDMX_DRM_AES_T*)rArg.ai4Arg[2];

    USR_SPACE_ACCESS_VALIDATE_ARG(prDrm, MTDMX_DRM_AES_T);
    COPY_FROM_USER_ARG(prDrm, rDrm, MTDMX_DRM_AES_T);

    rDrvDrm.fgCBC = rDrm.fgCBC;
    rDrvDrm.u4KeyBitLen = rDrm.u4KeyBitLen;
    rDrvDrm.u4Offset = rDrm.u4Offset;
    rDrvDrm.u4EncryLen = rDrm.u4EncryLen;
    rDrvDrm.fgEncrypt = rDrm.fgEncrypt;

    for (i=0; i <16; i++)
    {
        rDrvDrm.au1IV[i] = rDrm.au1IV[i];
    }

    for (i=0; i <32; i++)
    {
        rDrvDrm.au1Key[i] = rDrm.au1Key[i];
    }

    if (!DMX_AES_SetDecryptInfoEx(u1Idx, u4Flags, &rDrvDrm))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}

static MT_RESULT_T _MTDMX_AES_AllocEngine(unsigned long arg)
{
    INT32    Arg;
    UINT8 u1Idx;
    UINT8 *pu1Idx;

    USR_SPACE_ACCESS_VALIDATE_ARG(arg, INT32);
    COPY_FROM_USER_1ARG(arg, Arg);

    pu1Idx = (UINT8 *)Arg;

    u1Idx = DMX_AES_AllocEngine();

    USR_SPACE_ACCESS_VALIDATE_ARG(pu1Idx, UINT8);
    COPY_TO_USER_ARG(pu1Idx, u1Idx, UINT8);

    return MTR_OK;
}


static MT_RESULT_T _MTDMX_AES_FreeEngine(unsigned long arg)
{
    INT32    Arg;
    UINT8 u1Idx;
    //UINT8 *pu1Idx;

    USR_SPACE_ACCESS_VALIDATE_ARG(arg, INT32);
    COPY_FROM_USER_1ARG(arg, Arg);

    u1Idx = (UINT8)Arg;

    if (!DMX_AES_FreeEngine(u1Idx))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}


static MT_RESULT_T _MTDMX_AES_MoveBlockDataEx(unsigned long arg)
{
    MTAL_IOCTL_2ARG_T    rArg;
    UINT8 u1Idx;
    MTDMX_DRM_AES_BLKDATA_T* prBlkData =NULL;
    MTDMX_DRM_AES_BLKDATA_T rBlkData;
    //DMX_AES_BLKDATA_T rDrvBlkData;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u1Idx = (UINT32)rArg.ai4Arg[0];
    prBlkData = (MTDMX_DRM_AES_BLKDATA_T*)rArg.ai4Arg[1];

    USR_SPACE_ACCESS_VALIDATE_ARG(prBlkData, MTDMX_DRM_AES_BLKDATA_T);
    COPY_FROM_USER_ARG(prBlkData, rBlkData, MTDMX_DRM_AES_BLKDATA_T);

    if (!DMX_AES_MoveBlockDataEx(u1Idx, (DMX_AES_BLKDATA_T*)&rBlkData))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}

#endif //ENABLE_MULTIMEDIA


static MT_RESULT_T _MTDMX_GCPU_Cmd(unsigned long arg)
{
    MTAL_IOCTL_5ARG_T    rArg;
    UINT32 u4Handle;
    UINT32 u4Cmd;
    void* pvUserParam = NULL;
    void* pvParam = NULL;
    UINT32 u4Size;
    BOOL fgIommu;
    UINT8 au1Param[sizeof(TSDESC_PARAM_T)]; // the max size of GCPU parameter

    USR_SPACE_ACCESS_VALIDATE_5ARG(arg);
    COPY_FROM_USER_5ARG(arg, rArg);

    u4Handle = (UINT32)rArg.ai4Arg[0];
    u4Cmd = (UINT32)rArg.ai4Arg[1];
    pvUserParam = (void *)rArg.ai4Arg[2];
    u4Size = (UINT32)rArg.ai4Arg[3];
    fgIommu = (BOOL)rArg.ai4Arg[4];

    if (u4Size > sizeof(TSDESC_PARAM_T))
    {
        MTDMX_PRINT("The parameter size: %d is over reserved size: %d\n", u4Size, (int)sizeof(TSDESC_PARAM_T));
        return MTR_NOT_OK;
    }

    pvParam = au1Param;
    USR_SPACE_ACCESS_VALIDATE_ARG_SIZE(pvUserParam, u4Size);
    COPY_FROM_USER_ARG_SIZE(pvUserParam, pvParam, u4Size);

    MTDMX_PRINT(" -u4Handle=%d, u4Cmd=%d, u4ParamSize=%d\n", u4Handle, (int)u4Cmd, (int)u4Size);

    if (GCPU_CmdEx(u4Handle, u4Cmd, pvParam, fgIommu) != S_GCPU_OK)
    {
        return MTR_NOT_OK;
    }

    USR_SPACE_ACCESS_VALIDATE_ARG_SIZE(pvUserParam, u4Size);
    COPY_TO_USER_ARG_SIZE(pvUserParam, pvParam, u4Size);

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/** Set PID input source type
 *
 *  @param  u1Pidx           PID index value
 *  @param  eType            PID input source type
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetPidInputSource(unsigned long arg)
{
    MTAL_IOCTL_2ARG_T    rArg;
    UINT8 u1Pidx ;
    MTDMX_PID_INSRC_T eType;
    DMX_PID_T rPid;
    DMX_SOURCE_T eSource;
    UINT8 u1PhyPidx = MTAL_DMX_MULTIPLE_INVALID_PIDX;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u1Pidx = (UINT8)rArg.ai4Arg[0];
    eType = (MTDMX_PID_INSRC_T)rArg.ai4Arg[1];

    u1PhyPidx = _MTAL_DMX_PhysicalPidx(u1Pidx);

    if (u1PhyPidx == MTAL_DMX_MULTIPLE_INVALID_PIDX)
    {
        MTDMX_PRINT("Get u1PhyPidx error\n");
        return MTR_NOT_OK;
    }


    if (eType == MTDMX_PID_INSRC_DTV)
    {
        eSource = DMX_SOURCE_DTV0;
    }
    else if ((eType == MTDMX_PID_INSRC_TIMESHIFT_PLAY) || (eType == MTDMX_PID_INSRC_MM))
    {
        eSource = DMX_SOURCE_TSFILE0;
    }
    else
    {
        return MTR_NOT_OK;
    }

    if (!DMX_SetPidEx(u1PhyPidx, DMX_PID_FLAG_NONE, &rPid, eSource))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}

static MT_RESULT_T _MTDMX_ReloadSecureKey(unsigned long arg)
{
    MTAL_IOCTL_3ARG_T    rArg;
    UINT8 u1DmxKeyIdx;
    UINT32 u4SecureKeyIdx;
    DMX_CRYPTO_KEY_TYPE_T eKeyType;

    USR_SPACE_ACCESS_VALIDATE_3ARG(arg);
    COPY_FROM_USER_3ARG(arg, rArg);

    u1DmxKeyIdx = (UINT8)rArg.ai4Arg[0];
    u4SecureKeyIdx = (UINT8)rArg.ai4Arg[1];
    eKeyType = (DMX_CRYPTO_KEY_TYPE_T)rArg.ai4Arg[2];

    if (!DMX_ReloadSecureKey(u1DmxKeyIdx, u4SecureKeyIdx, eKeyType))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}

#ifdef CC_DMX_SUPPORT_MULTI2
//-----------------------------------------------------------------------------
/** _MTDMX_SetMulti2Config
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetMulti2Config(unsigned long arg)
{
    MTAL_IOCTL_3ARG_T rArg;
    BOOL fgOfbFreeRun;
    UINT16 u2Iteration;
    UINT8 u1Index;

    USR_SPACE_ACCESS_VALIDATE_3ARG(arg);
    COPY_FROM_USER_3ARG(arg, rArg);

    u1Index = (UINT8)rArg.ai4Arg[0];
    fgOfbFreeRun = (BOOL)rArg.ai4Arg[1];
    u2Iteration = (UINT16)rArg.ai4Arg[2];

    DMX_SetMulti2Config(u1Index,fgOfbFreeRun, u2Iteration);

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/** _MTDMX_SetMulti2Key
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetMulti2Key(unsigned long arg)
{
    MTAL_IOCTL_3ARG_T rArg;
    UINT8 u1Index;
    BOOL fgEven;
    UINT32 *pu4Key;
    UINT32 au4Key[2];

    USR_SPACE_ACCESS_VALIDATE_3ARG(arg);
    COPY_FROM_USER_3ARG(arg, rArg);

    u1Index = (UINT8)rArg.ai4Arg[0];
    fgEven = (BOOL)rArg.ai4Arg[1];
    pu4Key = (UINT32*)rArg.ai4Arg[2];

    USR_SPACE_ACCESS_VALIDATE_ARG_SIZE(pu4Key, 8);
    COPY_FROM_USER_ARG_SIZE(pu4Key, au4Key, 8);

    if (!DMX_SetMulti2Key(u1Index, fgEven, au4Key))
    {
        return MTR_NOT_OK;
    }

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/** _MTDMX_SetMulti2CbcIV
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetMulti2CbcIV(unsigned long arg)
{
    MTAL_IOCTL_3ARG_T rArg;
    UINT32 u4IvHi;
    UINT32 u4IvLo;
    UINT8 u1Index;

    USR_SPACE_ACCESS_VALIDATE_3ARG(arg);
    COPY_FROM_USER_3ARG(arg, rArg);

    u1Index = (UINT8)rArg.ai4Arg[0];
    u4IvHi = (UINT32)rArg.ai4Arg[1];
    u4IvLo = (UINT32)rArg.ai4Arg[2];

    DMX_SetMulti2CbcIV(u1Index,u4IvHi, u4IvLo);

    return MTR_OK;
}


//-----------------------------------------------------------------------------
/** _MTDMX_SetMulti2OfbIV
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetMulti2OfbIV(unsigned long arg)
{
    MTAL_IOCTL_3ARG_T rArg;
    UINT32 u4IvHi;
    UINT32 u4IvLo;
    UINT8 u1Index;

    USR_SPACE_ACCESS_VALIDATE_3ARG(arg);
    COPY_FROM_USER_3ARG(arg, rArg);

    u1Index = (UINT8)rArg.ai4Arg[0];
    u4IvHi = (UINT32)rArg.ai4Arg[1];
    u4IvLo = (UINT32)rArg.ai4Arg[2];

    DMX_SetMulti2OfbIV(u1Index,u4IvHi, u4IvLo);

    return MTR_OK;
}

//-----------------------------------------------------------------------------
/** _MTDMX_SetMulti2SysKey
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetMulti2SysKey(unsigned long arg)
{
    MTAL_IOCTL_2ARG_T rArg;
    UINT32 *pu4Key;
    UINT32 au4Key[8];
    UINT8 u1Index;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u1Index = (UINT8)rArg.ai4Arg[0];
    pu4Key = (UINT32*)rArg.ai4Arg[1];

    USR_SPACE_ACCESS_VALIDATE_ARG_SIZE(pu4Key, 32);
    COPY_FROM_USER_ARG_SIZE(pu4Key, au4Key, 32);

    DMX_SetMulti2SysKey(u1Index,au4Key);

    return MTR_OK;
}
#else
//-----------------------------------------------------------------------------
/** _MTDMX_SetMulti2Config
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetMulti2Config(unsigned long arg)
{
    return MTR_OK;
}


//-----------------------------------------------------------------------------
/** _MTDMX_SetMulti2Key
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetMulti2Key(unsigned long arg)
{
    return MTR_OK;
}


//-----------------------------------------------------------------------------
/** _MTDMX_SetMulti2CbcIV
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetMulti2CbcIV(unsigned long arg)
{
    return MTR_OK;
}


//-----------------------------------------------------------------------------
/** _MTDMX_SetMulti2OfbIV
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetMulti2OfbIV(unsigned long arg)
{
    return MTR_OK;
}

//-----------------------------------------------------------------------------
/** _MTDMX_SetMulti2SysKey
 */
//-----------------------------------------------------------------------------
static MT_RESULT_T _MTDMX_SetMulti2SysKey(unsigned long arg)
{
    return MTR_OK;
}

#endif

#define DEVICE_DATA_LEN                    (128)
#define DM_KEY_LEN                         (16)
#define ULPK_LEN                           (32)
#define ROMKEY_LEN                         (32)


static MT_RESULT_T _MTDRM_BimGetDeviceData(unsigned long arg)
{
    return MTR_NOT_OK;
}

static MT_RESULT_T _MTDRM_BimGetDmKey(unsigned long arg)
{
    return MTR_NOT_OK;
}

static MT_RESULT_T _MTDRM_BimGetULPK(unsigned long arg)
{
    return MTR_NOT_OK;
}

static MT_RESULT_T _MTDRM_BimGetRomKey(unsigned long arg)
{
    return MTR_NOT_OK;
}

/**
Input parameter
    pu1KeyBuf : Output key buffer
    pu4OutSize : Output size pointer
Output
    Success/Failure
Operation
    Read DivX DRM HW Secret key
**/
extern VOID DRV_DIVX_GetHWSecretKeyEx(UINT8 *pu1KeyBuf);
static MT_RESULT_T  _MTDRM_DivX_GetHWSecretKeyEx(unsigned long arg)
{
    MTAL_IOCTL_8ARG_T    rArg;

    //DRV_DIVX_GetHWSecretKeyEx((UINT8 *)&rArg.ai4Arg[0]);
    USR_SPACE_ACCESS_VALIDATE_8ARG(arg);
    COPY_TO_USER_ARG(arg, rArg,MTAL_IOCTL_8ARG_T);

    return MTR_OK;
}

static MT_RESULT_T _MTDMX_SetTsOut(unsigned long arg)
{
#ifdef CC_DMX_ENABLE_TSOUT
    DMX_TSOUT_PATH_T ePath;
    UINT8 u1TsIdx;
    MTAL_IOCTL_2ARG_T rArg;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    u1TsIdx = (UINT8)rArg.ai4Arg[0];
    ePath = (DMX_TSOUT_PATH_T)rArg.ai4Arg[1];

    if (!DMX_SetTsOut(u1TsIdx, ePath))
    {
        return MTR_NOT_OK;
    }
#endif
    return MTR_OK;
}

static MT_RESULT_T _MTDMX_SetPTSDrift(unsigned long arg)
{
    UCHAR ucStcId;
    INT32 i4Drift;
    MTAL_IOCTL_2ARG_T rArg;

    USR_SPACE_ACCESS_VALIDATE_2ARG(arg);
    COPY_FROM_USER_2ARG(arg, rArg);

    ucStcId = (UCHAR)rArg.ai4Arg[0];
    i4Drift = (INT32)rArg.ai4Arg[1];

    if (STC_SetPtsDrift(ucStcId, i4Drift) == STC_VALID)
    {
        return MTR_OK;
    }
    else
    {
        return MTR_NOT_OK;
    }
}

static MT_RESULT_T _MTDMX_GetHwInfo(unsigned long arg)
{
    MTDMX_HW_INFO_T *prHwInfo = NULL;
    MTDMX_HW_INFO_T rHwInfo;
    UINT32 u4Arg = 0;
    x_memset(&rHwInfo, 0, sizeof(rHwInfo));

    USR_SPACE_ACCESS_VALIDATE_1ARG(arg);
    COPY_FROM_USER_1ARG(arg,u4Arg);

    prHwInfo = (MTDMX_HW_INFO_T *)u4Arg;

    rHwInfo.u1PbPidFilterNum = DMX_NUM_PID_INDEX;
    rHwInfo.u1PbSecFilterNum = DMX_NUM_FILTER_INDEX;
    rHwInfo.u1RecPidFilterNum = FVR_NUM_PID_INDEX;
    rHwInfo.u1CaKeyNum = DMX_DMEM_CA_KEY_NUM;
    rHwInfo.u1FramerNum = DMX_FRAMER_COUNT;
    rHwInfo.u1StcNum = DMX_NUM_STC_NUM;

    USR_SPACE_ACCESS_VALIDATE_ARG(prHwInfo, MTDMX_HW_INFO_T);
    COPY_TO_USER_ARG(prHwInfo, rHwInfo, MTDMX_HW_INFO_T);

    return MTR_OK;
}

static MT_RESULT_T _MTDRM_DIVX_GetHwSecretKey0(unsigned long arg)
{
    INT32    Arg;
    UINT8 *pu1Buf;
    UINT8 au1Data[ROMKEY_LEN];

    USR_SPACE_ACCESS_VALIDATE_ARG(arg, INT32);
    COPY_FROM_USER_1ARG(arg, Arg);

    pu1Buf = (UINT8 *)Arg;

    HalFlushInvalidateDCacheMultipleLine((UINT32)au1Data, ROMKEY_LEN);

    #if defined(CC_TRUSTZONE_SUPPORT)
    if (!TZ_DRM_Divx_GetHwSecretKey0(au1Data))
    {
        return MTR_NOT_OK;
    }
    #else
    x_memcpy(pu1Buf, (void *)(0xf4003c00), ROMKEY_LEN);
    #endif

    USR_SPACE_ACCESS_VALIDATE_ARG_SIZE(pu1Buf, ROMKEY_LEN);
    COPY_TO_USER_ARG_SIZE(pu1Buf, au1Data, ROMKEY_LEN);

    return MTR_OK;
}

static MT_RESULT_T _MTDRM_DIVX_GetHwSecretKey1(unsigned long arg)
{
    INT32    Arg;
    UINT8 *pu1Buf;
    UINT8 au1Data[ROMKEY_LEN];

    USR_SPACE_ACCESS_VALIDATE_ARG(arg, INT32);
    COPY_FROM_USER_1ARG(arg, Arg);

    pu1Buf = (UINT8 *)Arg;

    HalFlushInvalidateDCacheMultipleLine((UINT32)au1Data, ROMKEY_LEN);

    #if defined(CC_TRUSTZONE_SUPPORT)
    if (!TZ_DRM_Divx_GetHwSecretKey1(au1Data))
    {
        return MTR_NOT_OK;
    }
    #else
    x_memcpy(pu1Buf, (void *)(0xf4003c20), ROMKEY_LEN);
    #endif

    USR_SPACE_ACCESS_VALIDATE_ARG_SIZE(pu1Buf, ROMKEY_LEN);
    COPY_TO_USER_ARG_SIZE(pu1Buf, au1Data, ROMKEY_LEN);

    return MTR_OK;
}

#ifdef CC_EIT_SECTION_FILTER
static MT_RESULT_T _MTDMX_SetEITSection(unsigned long arg)
{
    MTDMX_SECTION_KEY_SET_T rMtSetSection;
    SECTION_KEY_SET_T rSetSection;
    
    USR_SPACE_ACCESS_VALIDATE_ARG(arg,MTDMX_SECTION_KEY_SET_T);
    COPY_FROM_USER_ARG(arg,rMtSetSection,MTDMX_SECTION_KEY_SET_T);

    rSetSection.eSetType = rMtSetSection.eSetType;
    rSetSection.fgSet = rMtSetSection.fgSet;
    rSetSection.tSecKey.e_key.ui2_onid = rMtSetSection.tSecKey.e_key.ui2_onid;
    rSetSection.tSecKey.e_key.ui2_svcid = rMtSetSection.tSecKey.e_key.ui2_svcid;
    rSetSection.tSecKey.e_key.ui2_tsid = rMtSetSection.tSecKey.e_key.ui2_tsid;
    rSetSection.tSecKey.ui1_tableid = rMtSetSection.tSecKey.ui1_tableid;
    rSetSection.tSecKey.ui1_version = rMtSetSection.tSecKey.ui1_version;
    rSetSection.tSecKey.ui1_secnum = rMtSetSection.tSecKey.ui1_secnum;

    if(!DMX_SetEITSection(&rSetSection))
    {
        return MTR_NOT_OK;
    }
    return MTR_OK;
}
#endif


//-----------------------------------------------------------------------------
// Public functions
//-----------------------------------------------------------------------------
int mtal_ioctl_mtdmx(struct inode *inode, struct file *file, unsigned int cmd,
                     unsigned long arg)
{
    INT32 i4Ret = MTR_OK;

#ifdef TIME_SHIFT_SUPPORT
    if ((i4Ret = mtal_ioctl_mtdrec(cmd, arg)) != MTR_NOT_SUPPORTED)
    {
        return i4Ret;
    }
#endif

    switch (cmd)
    {
    case MTAL_IO_DMX_INIT:
        i4Ret = _MTDMX_Init(arg);
        break;

    case MTAL_IO_DMX_RESET:
        i4Ret = _MTDMX_Reset(arg);
        break;

    case MTAL_IO_DMX_SETFRONTENDEX:
        i4Ret = _MTDMX_SetFrontEndEx(arg);
        break;

    case MTAL_IO_DMX_SETVIDEOTYPE:
        i4Ret = _MTDMX_SetVideoType(arg);
        break;
    case MTAL_IO_DMX_SETVIDEOTYPEEX:
        i4Ret = _MTDMX_SetVideoTypeEx(arg);
        break;
    case MTAL_IO_DMX_SETVIDEOTYPEBYPIDX:
        i4Ret = _DMX_SetVideoTypeByPidx(arg);
        break;
    case MTAL_IO_DMX_SETPKTSIZE:
        i4Ret = _MTDMX_SetFramerPkt(arg);
        break;
    case MTAL_IO_DMX_START:
        i4Ret = _MTDMX_Start(arg);
        break;

    case MTAL_IO_DMX_STOP:
        i4Ret = _MTDMX_Stop(arg);
        break;

    case MTAL_IO_DMX_SETPID:
        i4Ret = _MTDMX_SetPid(arg);
        break;

    case MTAL_IO_DMX_SETFILEPID:
        i4Ret = _MTDMX_SetFilePid(arg);
        break;

    case MTAL_IO_DMX_GETPID:
        i4Ret = _MTDMX_GetPid(arg);
        break;

    case MTAL_IO_DMX_FREEPID:
        i4Ret = _MTDMX_FreePid(arg);
        break;

    case MTAL_IO_DMX_GETPIDIDX:
        i4Ret = _MTDMX_GetPidIndex(arg);
        break;

    case MTAL_IO_DMX_GETESFIFO:
        i4Ret = _MTDMX_Get_ESFifoSize(arg);
        break;

    case MTAL_IO_DMX_GETPACKETSTATUS:
        i4Ret = _MTDMX_GetPacketStatus(arg);
        break;

    case MTAL_IO_DMX_SETVDEPID:
        i4Ret = _MTDMX_SetVideoPid(arg);
        break;

    case MTAL_IO_DMX_SETAUDPID:
        i4Ret = _MTDMX_SetAudioPid(arg);
        break;

    case MTAL_IO_DMX_SETAUDDESPID:
        i4Ret = _MTDMX_SetAudioDescPid(arg);
        break;

    case MTAL_IO_DMX_SETPCRPIDEX:
        i4Ret = _MTDMX_SetPcrPidEx(arg);
        break;

    case MTAL_IO_DMX_SETPCR:
        i4Ret = _MTDMX_SetPcr(arg);
        break;

    case MTAL_IO_DMX_SETFTR:
        i4Ret = _MTDMX_SetFilter(arg);
        break;

    case MTAL_IO_DMX_GETFTR:
        i4Ret = _MTDMX_GetFilter(arg);
        break;

    case MTAL_IO_DMX_PSI_ALCBFR:
        i4Ret = _MTDMX_PSI_AllocateBuffer(arg);
        break;

    case MTAL_IO_DMX_PSI_FREEBFR:
        i4Ret = _MTDMX_PSI_FreeBuffer(arg);
        break;

    case MTAL_IO_DMX_PSI_GETBFR:
        i4Ret = _MTDMX_PSI_GetBuffer(arg);
        break;

    case MTAL_IO_DMX_PSI_ULKBFR:
        i4Ret = _MTDMX_PSI_UnlockBuffer(arg);
        break;

    case MTAL_IO_DMX_PSI_FLSBFR:
        i4Ret = _MTDMX_PSI_FlushBuffer(arg);
        break;

    case MTAL_IO_DMX_PSI_GETBFRSECHEAD:
        i4Ret = _MTDMX_PSI_GetBufferSectionHeader(arg);
        break;

    case MTAL_IO_DMX_PES_ALKBFR:
        i4Ret = _MTDMX_PES_AllocateBuffer(arg);
        break;

    case MTAL_IO_DMX_PES_FREEBFR:
        i4Ret = _MTDMX_PES_FreeBuffer(arg);
        break;

    case MTAL_IO_DMX_PES_ULKBFR:
        i4Ret = _MTDMX_PES_UnlockBuffer(arg);
        break;

    case MTAL_IO_DMX_PES_FLSBFR:
        i4Ret = _MTDMX_PES_FlushBuffer(arg);
        break;

    case MTAL_IO_DMX_PES_GETBFR:
        i4Ret = _MTDMX_PES_GetBuffer(arg);
        break;

    case MTAL_IO_DMX_RAWTS_GETBFR:
        i4Ret = _MTDMX_RawTs_GetBuffer(arg);
        break;

    case MTAL_IO_DMX_RAWTS_ULKBFR:
        i4Ret = _MTDMX_RawTs_UnlockBuffer(arg);
        break;

    case MTAL_IO_DMX_GETPIDCNT:
        i4Ret = _MTDMX_GetPidCounters(arg);
        break;

    case MTAL_IO_DMX_RSTPIDCNT:
        i4Ret = _MTDMX_ResetPidCounters(arg);
        break;

    case MTAL_IO_DMX_GETLOKSTE:
        i4Ret = _MTDMX_GetLockState(arg);
        break;

    case MTAL_IO_DMX_GETSCRMSTE:
        i4Ret = _MTDMX_GetScrambleState(arg);
        break;

    case MTAL_IO_DMX_GETFRONTEND:
        i4Ret = _MTDMX_GetFrontEndEx(arg);
        break;

    case MTAL_IO_DMX_GETRAWSCRMSTE:
        i4Ret = _MTDMX_GetRawScrambleState(arg);
        break;

    case MTAL_IO_DMX_GETCURSTC:
        i4Ret = _MTDMX_GetCurSTC(arg);
        break;

    case MTAL_IO_DMX_SETGENERICFILTER:
        i4Ret = _MTDMX_SetGenericFilter(arg);
        break;

    case MTAL_IO_DMX_GETGENERICFILTER:
        i4Ret = _MTDMX_GetGenFilter(arg);
        break;

    case MTAL_IO_DMX_CONNECT_FILTER:
        i4Ret = _MTDMX_ConnectFilter(arg);
        break;
        
    case MTAL_IO_DMX_CONNECT_AVAILABLEFILTER:
        i4Ret = _MTDMX_ConnectAvailableFilterx(arg);
        break;
        
    case MTAL_IO_DMX_DISCONNECT_FILTER:
        i4Ret = _MTDMX_DisConnectFilter(arg);
        break;
        
    case MTAL_IO_DMX_SETDESKEY:
        i4Ret = _MTDMX_SetDesKey(arg);
        break;

    case MTAL_IO_DMX_SETDESEVENODDIV:
        i4Ret = _MTDMX_SetDesOddEvenIV(arg);
        break;

    case MTAL_IO_DMX_SETRTBMODE:
        i4Ret = _MTDMX_SetRtbMode(arg);
        break;

    case MTAL_IO_DMX_SETAESKEYLEN:
        i4Ret = _MTDMX_SetAesKeyLen(arg);
        break;

    case MTAL_IO_DMX_SETAESKEY:
        i4Ret = _MTDMX_SetAesKey(arg);
        break;

        //DVB key and IV
    case MTAL_IO_DMX_DVB_KEY:
        i4Ret = _MTDMX_SetDVBKey(arg);
        break;

    case MTAL_IO_DMX_DVB_IV:
        i4Ret = _MTDMX_SetDVBIV(arg);
        break;

    case MTAL_IO_DMX_SETCRYPTOKEY:
        i4Ret = _MTDMX_SetCryptoKey(arg);
        break;

    case MTAL_IO_DMX_SETAESEVENODDIV:
        i4Ret = _MTDMX_SetAesOddEvenIV(arg);
        break;

    case MTAL_IO_DMX_SETDESCPID:
        i4Ret = _MTDMX_SetDescramblPid(arg);
        break;

    case MTAL_IO_DMX_SETFILEDESCPID:
        i4Ret = _MTDMX_SetFileDescramblPid(arg);
        break;

#ifdef ENABLE_MULTIMEDIA
    case MTAL_IO_DMX_AES_SETDCRINFO:
        i4Ret = _MTDMX_AES_SetDecryptInfo(arg);
        break;
#endif

#ifdef ENABLE_MULTIMEDIA
    case MTAL_IO_DMX_AES_MVBLKDATA:
        i4Ret = _MTDMX_AES_MoveBlockData(arg);
        break;

    case MTAL_IO_DMX_AES_ALLOCENGINE:
        i4Ret = _MTDMX_AES_AllocEngine(arg);
        break;

    case MTAL_IO_DMX_AES_FREEENGINE:
        i4Ret = _MTDMX_AES_FreeEngine(arg);
        break;

    case MTAL_IO_DMX_AES_SETDCRINFOEX:
        i4Ret = _MTDMX_AES_SetDecryptInfoEx(arg);
        break;

    case MTAL_IO_DMX_AES_MVBLKDATAEX:
        i4Ret = _MTDMX_AES_MoveBlockDataEx(arg);
        break;
#endif

    case MTAL_IO_DMX_GCPU_CMD:
        i4Ret = _MTDMX_GCPU_Cmd(arg);
        break;

    case MTAL_IO_DMX_SETPID_INSRC:
        i4Ret = _MTDMX_SetPidInputSource(arg);
        break;

    case MTAL_IO_DMX_MULTI2_CFG:
        i4Ret = _MTDMX_SetMulti2Config(arg);
        break;

    case MTAL_IO_DMX_MULTI2_KEY:
        i4Ret = _MTDMX_SetMulti2Key(arg);
        break;

    case MTAL_IO_DMX_MULTI2_CBCIV:
        i4Ret = _MTDMX_SetMulti2CbcIV(arg);
        break;

    case MTAL_IO_DMX_MULTI2_OFBIV:
        i4Ret = _MTDMX_SetMulti2OfbIV(arg);
        break;

    case MTAL_IO_DMX_MULTI2_SYSKEY:
        i4Ret = _MTDMX_SetMulti2SysKey(arg);
        break;

    case MTAL_IO_DRM_DIVX_GET_HW_SECRET_KEY_EX:
        i4Ret = _MTDRM_DivX_GetHWSecretKeyEx(arg);
        break;

    case MTAL_IO_BIM_GET_DEVICE_DATA:
        i4Ret = _MTDRM_BimGetDeviceData(arg);
        break;

    case MTAL_IO_BIM_DM_GET_KEY:
        i4Ret = _MTDRM_BimGetDmKey(arg);
        break;

    case MTAL_IO_BIM_GET_ULPK:
        i4Ret = _MTDRM_BimGetULPK(arg);
        break;

    case MTAL_IO_BIM_GET_ROMKEY:
        i4Ret = _MTDRM_BimGetRomKey(arg);
        break;

    case MTAL_IO_DMX_SETTSOUT:
        i4Ret = _MTDMX_SetTsOut(arg);
        break;

    case MTAL_IO_DMX_SETPTSDRIFT:
        i4Ret = _MTDMX_SetPTSDrift(arg);
        break;

    case MTAL_IO_DMX_MWIF_CALL:
        i4Ret = MTDMX_MWIF_Call(arg);
        break;

    case MTAL_IO_DMX_CONNECT:
        i4Ret = _MTDMX_ConnectInfo(arg);
        break;

    case MTAL_IO_DMX_CONNECT_AVAILABLEPID:
        i4Ret = _MTDMX_ConnectAvailablePidx(arg);
        break;

    case MTAL_IO_DMX_DISCONNECT:
        i4Ret = _MTDMX_DisConnectInfo(arg);
        break;

    case MTAL_IO_DMX_GETHWINFO:
           i4Ret = _MTDMX_GetHwInfo(arg);
           break;

    case MTAL_IO_DRM_DIVX_GET_HW_SECRET_KEY0:
        i4Ret = _MTDRM_DIVX_GetHwSecretKey0(arg);
        break;
    case MTAL_IO_DRM_DIVX_GET_HW_SECRET_KEY1:
        i4Ret = _MTDRM_DIVX_GetHwSecretKey1(arg);
        break;
    case  MTAL_IO_DMX_RELOADSECUREKEY:
        i4Ret = _MTDMX_ReloadSecureKey(arg);
        break;

#ifdef CC_EIT_SECTION_FILTER
    case MTAL_IO_DMX_SET_EITSECTION:
        i4Ret = _MTDMX_SetEITSection(arg);
        break;
#endif

#ifdef TIME_SHIFT_SUPPORT
    default:
        i4Ret = mtal_ioctl_mttsrec(cmd, arg);
        break;
#endif

    }

    return i4Ret;
}


//-----------------------------------------------------------------------------
/** MTDMX_SetPCR
 */
//-----------------------------------------------------------------------------
BOOL MTDMX_SetPCR(UINT8 u1Pidx, UINT16 u2PidNum, MTDMX_PID_INSRC_T eInType, BOOL fgEnable)
{
    DMX_PID_T rPid;

    x_memset((VOID*)&rPid, 0, sizeof(DMX_PID_T));
    rPid.fgAllocateBuffer = FALSE;
    rPid.u2Pid = u2PidNum;
    //rPid.u4BufAddr = 0x0;
    //rPid.u4BufSize = 0x0;
    rPid.ePidType = DMX_PID_TYPE_NONE;
    rPid.fgPrimary = FALSE;
    rPid.ePcrMode = DMX_PCR_MODE_NEW;
    rPid.eDescMode = DMX_DESC_MODE_NONE;
    rPid.fgEnable = fgEnable;

    if (eInType == MTDMX_PID_INSRC_DTV)
    {
        if (!_MtdmxSetPid(u1Pidx, DMX_PID_FLAG_ALL & (~DMX_PID_FLAG_BUFFER), &rPid))
        {
            return FALSE;
        }
    }
    else if (eInType == MTDMX_PID_INSRC_TIMESHIFT_PLAY)
    {
        rPid.u1TsIndex = 2;
        if (!DMX_SetPid(u1Pidx, DMX_PID_FLAG_ALL & (~DMX_PID_FLAG_BUFFER), &rPid))
        {
            return FALSE;
        }
    }
    else if (eInType == MTDMX_PID_INSRC_MM)
    {
        rPid.u1TsIndex = 0;
        if (!DMX_SetPid(u1Pidx, DMX_PID_FLAG_ALL & (~DMX_PID_FLAG_BUFFER), &rPid))
        {
            return FALSE;
        }
    }
    else
    {
        return  FALSE;
    }

    if (fgEnable)
    {
        if (DMX_SetStcSrc(u1Pidx, 0) != 0)   // Force use STC 0
        {
            return MTR_NOT_OK;
        }
    }
    else
    {
        if (DMX_SetStcSrc(u1Pidx, STC_SRC_NS) != 0)   // Set to other PCR to disable
        {
            return MTR_NOT_OK;
        }
    }

    return TRUE;
}

//-----------------------------------------------------------------------------
/** MTDMX_SetSecondVideoPid
 */
//-----------------------------------------------------------------------------
BOOL MTDMX_SetSecondVideoPid(UINT8 u1Pidx, UINT32 u4Flags, MTDMX_PID_T* prPid)
{
    MTDMX_PID_T rPid;
    DMX_PID_T rDrvPid;
    //FBM_POOL_T* prFbmPool;
    UINT32 u4VfifoAddr = 0, u4VfifoSize = 0;

    rPid = *prPid;

    // Only enable/disable PID
    if (u4Flags == MTDMX_PID_FLAG_VALID)
    {
        rDrvPid.fgEnable = rPid.fgEnable;
        if (!_MtdmxSetPid(u1Pidx, u4Flags, &rDrvPid))
        {
            return FALSE;
        }

        return TRUE;
    }

    // Get from MW
    rDrvPid.fgEnable = rPid.fgEnable;
    rDrvPid.fgAllocateBuffer = rPid.fgAllocateBuffer;
    rDrvPid.u2Pid = rPid.u2Pid;
    rDrvPid.u4BufAddr = rPid.u4BufAddr;
    rDrvPid.u4BufSize = rPid.u4BufSize;
    rDrvPid.u1DeviceId = 0;
    rDrvPid.ePidType = rPid.ePidType;

    if (rPid.ePidType == MTDMX_PID_TYPE_ES_VIDEO)
    {
        // Allocate video buffer from FBM
        if((!fgFbmDmx1Used) && (!fgFbmDmx2Used))
        {
#if defined(CC_TRUSTZONE_SUPPORT) && defined(CC_SVP_SUPPORT)
            prFbmPool = FBM_Alloc(FBM_TYPE_TZ_DMX);
#else
            prFbmPool = FBM_Alloc(FBM_TYPE_DMX);
#endif
            ASSERT(prFbmPool != NULL);
            if (!prFbmPool)
            {
                Printf("Fail to get VFIFO!\n");
                return MTR_NOT_OK;
            }
        }

        if(rPid.u1ChannelId == 0)
        {
        	_IoMtDmx_Lock();
            fgFbmDmx1Used = TRUE;
			_IoMtDmx_Unlock();
        }
        else
        {
        	_IoMtDmx_Lock();
            fgFbmDmx2Used = TRUE;
			_IoMtDmx_Unlock();
        }

        u4VfifoAddr = prFbmPool->u4Addr;
        u4VfifoSize = prFbmPool->u4Size;
        
        ASSERT(u4VfifoAddr != 0);
        if(u4VfifoSize < MTAL_DMX_EXPECTED_SIZE)
        {
            MTDMX_PRINT("DMX buffer size is too smaler: 0x%x!\n", u4VfifoSize);
        }

        // Setup buffer attributes
        rDrvPid.fgAllocateBuffer = FALSE;
        rDrvPid.u4BufAddr = u4VfifoAddr + (u4VfifoSize / 2);
        rDrvPid.u4BufSize = u4VfifoSize / 2;
        //rDrvPid.u1DeviceId = rPid.u1DeviceId;
    }

    if ((rPid.pfnNotify != NULL) && (u4Flags & MTDMX_PID_FLAG_CALLBACK))
    {
        rDrvPid.pfnNotify = _MtDmxCallback;
    }
    else
    {
        rDrvPid.pfnNotify = NULL;
    }

    if ((rPid.pfnScramble != NULL) && (u4Flags & DMX_PID_FLAG_SCRAMBLE_STATE))
    {
        rDrvPid.pfnScramble = _MtDmxCallback;
    }
    else
    {
        rDrvPid.pfnScramble = NULL;
    }

    rDrvPid.pvNotifyTag = NULL;
    rDrvPid.pvScrambleTag = NULL;

    // Set by driver only
    rDrvPid.fgPrimary = TRUE;
    rDrvPid.u1TsIndex = rPid.u1TsIndex;
    rDrvPid.u1KeyIndex = 0x0;
    rDrvPid.u1SteerMode = DMX_STEER_TO_FTUP;
    rDrvPid.ePcrMode = DMX_PCR_MODE_NONE;
    rDrvPid.eDescMode = DMX_DESC_MODE_NONE;
    rDrvPid.u1ChannelId = 0x1;

    u4Flags |= (DMX_PID_FLAG_PRIMARY | DMX_PID_FLAG_TS_INDEX | DMX_PID_FLAG_KEY_INDEX |
                DMX_PID_FLAG_DEVICE_ID | DMX_PID_FLAG_STEER | DMX_PID_FLAG_PCR |
                DMX_PID_FLAG_DESC_MODE | DMX_PID_FLAG_SCRAMBLE_STATE);

    if (!_MtdmxSetPid(u1Pidx, u4Flags, &rDrvPid))
    {
        return FALSE;
    }

    return TRUE;
}


