/******************************************************************************
 *
 * Copyright 2013, Silicon Image, Inc.  All rights reserved.
 * No part of this work may be reproduced, modified, distributed, transmitted,
 * transcribed, or translated into any language or computer format, in any form
 * or by any means without written permission of
 * Silicon Image, Inc., 1140 East Arques Avenue, Sunnyvale, California 94085
 *
 *****************************************************************************/
/**
 * @file Sii977xLib.c
 *
 * @brief Defines the exported functions for the DLL application.
 *
 *****************************************************************************/
//#define SII_DEBUG 2

/***** #include statements ***************************************************/

/***** Register Module name **************************************************/

/***** local macro definitions ***********************************************/

/***** local type definitions ************************************************/

/***** local prototypes ******************************************************/

static void sResourcesDelete( Obj_t* pObj );
static SiiRetVal_t sHandle( Obj_t* pObj );
static void sHandleFlashProg( Obj_t* pObj );
static void sHandleIpcInterrupts( Obj_t* pObj );
static void sHandleIspInterrupts( Obj_t* pObj );
static void sRequestMessageInit( Obj_t* pObj, SiiDrvIpcOpCode_t opCode );
static void sRequestMessageSend( Obj_t* pObj );
static SiiRetVal_t sWaitForValidIpcResponseMessage( Obj_t* pObj, SiiDrvIpcOpCode_t opCode );
#if( SII9777_USER_DEF__MULTI_THREAD )
#if( SII9777_USER_DEF__IPC_SEMAPHORE )
static SiiRetVal_t sSemaphoreIpcTake( Obj_t* pObj );
static void sSemaphoreIpcGive( Obj_t* pObj );
static SiiRetVal_t sMutexHandleTake( Obj_t* pObj );
static void sMutexHandleGive( Obj_t* pObj );
#endif
static SiiRetVal_t sMutexApiTake( Obj_t* pObj );
static void sMutexApiGive( Obj_t* pObj );
#endif
static void sDeviceRestart( Obj_t* pObj );
static bool_t sDevicePing( Obj_t* pObj );
static void sInterruptsEnableSet( Obj_t* pObj, bool_t bEnable );

/***** local data objects ****************************************************/

/***** call-back functions ***************************************************/

void SiiDrvIpcCallBack( SiiDrvIpcInst_t ipcInst, SiiDrvIpcEvent_t ipcEvent )
{     
    SiiInst_t inst = SII_SYS_OBJ_PARENT_INST_GET(ipcInst);
    Obj_t*    pObj = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);

    if( ipcEvent & SII_DRV_IPC_EVENT__MESSAGE_RECEIVED )
    {
        SiiDrvIpcMesInst_t mesInst = SiiDrvIpcMessageCreate();

        SiiDrvIpcMessageReceive(pObj->ipcInst, mesInst);
        if( SII_DRV_IPC_TYPE__NOTIFY == SiiDrvIpcTypeGet(mesInst) )
        {
            Sii9777EventFlags_t eventFlags = (Sii9777EventFlags_t)SiiDrvIpcLongPop(mesInst);

            if( eventFlags & SII9777_EVENT_FLAGS__BOOT_DONE )
            {
                pObj->bootStat = SII9777_BOOT_STAT__SUCCESS;
            }
            pObj->eventFlagsUser |= eventFlags;
            SII_LOG1A("SII_DRV_IPC_TYPE__NOTIFY", pObj, ("\n"));
        }
        else if( SII_DRV_IPC_TYPE__RESPONSE == SiiDrvIpcTypeGet(mesInst) )
        {
            SII_LOG1A("SII_DRV_IPC_TYPE__RESPONSE", pObj, ("\n"));
            SiiDrvIpcMessageCopy(pObj->mesAckInst, mesInst);

#if( SII9777_USER_DEF__MULTI_THREAD && SII9777_USER_DEF__IPC_SEMAPHORE )
            /* Don't give IPC semaphore if IPC request was initiated through Sii9777Handle */
            if( !pObj->bFromUserCallBack )
            {
                sSemaphoreIpcGive(pObj);
            }
#endif
        }
        SiiDrvIpcMessageDelete(mesInst);
    }
}

/***** public functions ******************************************************/

SiiRetVal_t Sii9777Handle( SiiInst_t inst )
{
    Obj_t*       pObj   = NULL;
    SiiRetVal_t  retVal = 0;

    if( SII_INST_NULL == inst )
    {
        /* Handle multi host driver instantiations */
        pObj = (Obj_t*)SiiSysObjFirstGet(sObjListInst);

        while( pObj && !retVal )
        {
            retVal = sHandle(pObj);

            /* Go to next timer instance */
            pObj = (Obj_t*)SiiSysObjNextGet(pObj);
        }
    }
    else
    {
        /* Handle single host driver instantiation */
        pObj = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);

        retVal = sHandle(pObj);
    }
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777StandbySet( SiiInst_t inst, bool_t* pbOn )
{
    Obj_t*              pObj    = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t         retVal  = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777StandbySet", pObj, ("%d", (uint16_t)*pbOn));

        sRequestMessageInit(pObj, SII9777_STANDBY_SET);
        SiiDrvIpcBoolPush(pObj->mesReqInst, *pbOn);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_STANDBY_SET);
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777StandbyGet( SiiInst_t inst, bool_t* pbOn )
{
    Obj_t*              pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t         retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777StandbyGet", pObj, (""));

        sRequestMessageInit(pObj, SII9777_STANDBY_GET);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_STANDBY_GET);
        if( !retVal )
        {
            *pbOn = SiiDrvIpcBoolPop(pObj->mesAckInst);
            SII_LOG1B(("%d", (uint16_t)*pbOn));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777ChipIdQuery( SiiInst_t inst, uint32_t* pChipIdStat )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777ChipIdQuery", pObj, (""));

        sRequestMessageInit(pObj, SII9777_CHIPID_QUERY);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_CHIPID_QUERY);
        if( !retVal )
        {
            *pChipIdStat = SiiDrvIpcLongPop(pObj->mesAckInst);
            SII_LOG1B(("%08lX", *pChipIdStat));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777ChipRevisionQuery( SiiInst_t inst, uint32_t* pChipRevStat )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777ChipRevisionQuery", pObj, (""));

        sRequestMessageInit(pObj, SII9777_CHIPREVISION_QUERY);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_CHIPREVISION_QUERY);
        if( !retVal )
        {
            *pChipRevStat = SiiDrvIpcLongPop(pObj->mesAckInst);
            SII_LOG1B(("%08lX", *pChipRevStat));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777ProductIdQuery( SiiInst_t inst, uint32_t* pProdIdStat )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777ProductIdQuery", pObj, (""));

        sRequestMessageInit(pObj, SII9777_PRODUCTID_QUERY);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_PRODUCTID_QUERY);
        if( !retVal )
        {
            *pProdIdStat = SiiDrvIpcLongPop(pObj->mesAckInst);
            SII_LOG1B(("%08lX", *pProdIdStat));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777FirmwareVersionQuery( SiiInst_t inst, uint32_t* pVersionStat )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777FirmwareVersionQuery", pObj, (""));

        sRequestMessageInit(pObj, SII9777_FIRMWAREVERSION_QUERY);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_FIRMWAREVERSION_QUERY);
        if( !retVal )
        {
            *pVersionStat = SiiDrvIpcLongPop(pObj->mesAckInst);
            SII_LOG1B(("%08lX", *pVersionStat));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777ReleaseTimeStampQuery( SiiInst_t inst, uint32_t* pTimeStamp )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777ReleaseTimeStampQuery", pObj, (""));

        sRequestMessageInit(pObj, SII9777_RELEASETIMESTAMP_QUERY);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_RELEASETIMESTAMP_QUERY);
        if( !retVal )
        {
            *pTimeStamp = SiiDrvIpcLongPop(pObj->mesAckInst);
            SII_LOG1B(("%08lX", *pTimeStamp));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777BootStatusQuery( SiiInst_t inst, Sii9777BootStat_t* pBootStat )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;
    
    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777BootStatusQuery", pObj, (""));

        if( SII9777_BOOT_STAT__IN_PROGRESS == pObj->bootStat )
        {
            /* Ping device */
            if( sDevicePing(pObj) )
            {
                pObj->bootStat = SII9777_BOOT_STAT__SUCCESS;
            }
            else
            {
                if( SiiSysTimeOutMilliIs(&pObj->bootTimeOut) )
                {
                    pObj->bootStat = SII9777_BOOT_STAT__FAILURE;
                }
            }
        }

        *pBootStat = pObj->bootStat;
        SII_LOG1B(("%d", (uint16_t)*pBootStat));
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777EventFlagsMaskSet( SiiInst_t inst, Sii9777EventFlags_t* pFlags )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    
    if( !retVal )
    {
        SII_LOG1A("Sii9777EventFlagsMaskSet", pObj, ("%08lX", *pFlags));

        if( SII9777_BOOT_STAT__SUCCESS == pObj->bootStat )
        {
            sRequestMessageInit(pObj, SII9777_EVENTFLAGSMASK_SET);
            SiiDrvIpcLongPush(pObj->mesReqInst, (*pFlags) & EVENT_MASK_EXTERNAL);
            sRequestMessageSend(pObj);

            retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_EVENTFLAGSMASK_SET);
            if( !retVal )
            {
                pObj->eventFlagsMask =  *pFlags;
            }
        }
        else
        {
            pObj->eventFlagsMask = (*pFlags) & EVENT_MASK_INTERNAL;
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777EventFlagsMaskGet( SiiInst_t inst, Sii9777EventFlags_t* pFlags )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777EventFlagsMaskGet", pObj, (""));

        *pFlags = pObj->eventFlagsMask;
        SII_LOG1B(("%08lX", *pFlags));
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777EventFlagsQuery( SiiInst_t inst, Sii9777EventFlags_t* pFlags )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777EventFlagsQuery", pObj, (""));

        sRequestMessageInit(pObj, SII9777_EVENTFLAGS_QUERY);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_EVENTFLAGS_QUERY);
        if( !retVal )
        {
            *pFlags = (SiiDrvIpcLongPop(pObj->mesAckInst) & EVENT_MASK_EXTERNAL) | (pObj->eventFlagsStat & EVENT_MASK_INTERNAL);
            SII_LOG1B(("%08lX", *pFlags));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777EventFlagsStatusClear( SiiInst_t inst, Sii9777EventFlags_t* pFlags )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777EventFlagsStatusClear", pObj, ("%08lX", *pFlags));

        pObj->eventFlagsStat &= (~(*pFlags));
        sRequestMessageInit(pObj, SII9777_EVENTFLAGSSTATUS_CLEAR);
        SiiDrvIpcLongPush(pObj->mesReqInst, *pFlags);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_EVENTFLAGSSTATUS_CLEAR);
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777GpioConfigSet( SiiInst_t inst, uint16_t *pGpioPins )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777GpioConfigSet", pObj, ("%04X", *pGpioPins));

        sRequestMessageInit(pObj, SII9777_GPIOCONFIG_SET);
        SiiDrvIpcWordPush(pObj->mesReqInst, *pGpioPins);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_GPIOCONFIG_SET);
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777GpioConfigGet( SiiInst_t inst, uint16_t *pGpioPins )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777GpioConfigGet", pObj, (""));

        sRequestMessageInit(pObj, SII9777_GPIOCONFIG_GET);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_GPIOCONFIG_GET);
        if( !retVal )
        {
            *pGpioPins = SiiDrvIpcWordPop(pObj->mesAckInst);
            SII_LOG1B(("%04X", *pGpioPins));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777GpioOutputSet( SiiInst_t inst, uint16_t* pGpioPins )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777GpioOutputSet", pObj, ("%04X", *pGpioPins));

        sRequestMessageInit(pObj, SII9777_GPIOOUTPUT_SET);
        SiiDrvIpcWordPush(pObj->mesReqInst, *pGpioPins);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_GPIOOUTPUT_SET);
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777GpioOutputClr( SiiInst_t inst, uint16_t* pGpioPins )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777GpioOutputClr", pObj, ("%04X", *pGpioPins));

        sRequestMessageInit(pObj, SII9777_GPIOOUTPUT_CLR);
        SiiDrvIpcWordPush(pObj->mesReqInst, *pGpioPins);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_GPIOOUTPUT_CLR);
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777GpioQuery( SiiInst_t inst, uint16_t* pGpioPins )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777GpioQuery", pObj, (""));

        sRequestMessageInit(pObj, SII9777_GPIO_QUERY);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_GPIO_QUERY);
        if( !retVal )
        {
            *pGpioPins = SiiDrvIpcWordPop(pObj->mesAckInst);
            SII_LOG1B(("%04X", *pGpioPins));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777GpioEventMaskSet( SiiInst_t inst, uint16_t*  pGpioPins )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777GpioEventMaskSet", pObj, ("%04X", *pGpioPins));

        sRequestMessageInit(pObj, SII9777_GPIOEVENTMASK_SET);
        SiiDrvIpcWordPush(pObj->mesReqInst, *pGpioPins);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_GPIOEVENTMASK_SET);
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777GpioEventMaskGet( SiiInst_t inst, uint16_t*  pGpioPins )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777GpioEventMaskGet", pObj, (""));

        sRequestMessageInit(pObj, SII9777_GPIOEVENTMASK_GET);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_GPIOEVENTMASK_GET);
        if( !retVal )
        {
            *pGpioPins = SiiDrvIpcWordPop(pObj->mesAckInst);
            SII_LOG1B(("%04X", *pGpioPins));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

/* Obsoleted */
SiiRetVal_t Sii9777FirmwareInit( SiiInst_t inst )
{
    return Sii9777FlashInit(inst, SII9777_FLASH_OPERATION__WRITE, SII9777_FLASH_TARGET__FULL_DEVICE);
}

SiiRetVal_t Sii9777FlashInit( SiiInst_t inst, Sii9777FlashOperation_t operation, Sii9777FlashTarget_t target )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777FlashInit", pObj, (""));

        /* Check flash Operation request code */
        switch( operation )
        {
            case SII9777_FLASH_OPERATION__READ :
                pObj->bFlashRead   = true;
                SiiDrvIspReadInit(pObj->devId);
                break;

            case SII9777_FLASH_OPERATION__WRITE :
                pObj->bFlashRead   = false;
                break;

            case SII9777_FLASH_OPERATION__WRITE_VERIFY :
                pObj->bFlashRead   = false;
                break;

            default: retVal = 1; break;
        }

        if( !retVal )
        {
            switch( target )
            {
                case SII9777_FLASH_TARGET__FULL_DEVICE:
                    pObj->flashAddr    = 0x00000;
                    pObj->flashSize    = 0x80000; /* Full size of 4Mbit flash */
                    if( SII9777_FLASH_OPERATION__READ != operation )
                    {
                        SiiDrvIspChipErase(pObj->devId);
                    }
                    break;

                case SII9777_FLASH_TARGET__EDID_TABLES:
                    pObj->flashAddr    = 0x05000;
                    pObj->flashSize    = 0x00400; /* Size of power-up default EDID tables */
                    if( SII9777_FLASH_OPERATION__READ != operation )
                    {
                        SiiDrvIspSectorErase(pObj->devId, 0x05000);
                    }
                    break;

                case SII9777_FLASH_TARGET__FIRMWARE:
                default: retVal = 1; break;
            }
        }

        if( !retVal )
        {
#if( SII9777_FLASH_BUFFER_SIZE )
            if( pObj->pFlashPacket )
            {
                 SiiSysMallocDelete(pObj->pFlashPacket);
            }
#endif
            pObj->pFlashPacket = NULL;
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777FirmwareUpdate( SiiInst_t inst, const uint8_t* pData, uint16_t length )
{
    return Sii9777FlashUpdate(inst, (uint8_t *)pData, length);
}

SiiRetVal_t Sii9777FlashUpdate( SiiInst_t inst, uint8_t* pData, uint16_t length )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777FlashUpdate", pObj, ("length=%d\n", length));

        if( NULL == pData )
        {
            retVal = 1;
        }
        else if( 0 == length )
        {
            retVal = 2;
        }
        else if( 0 == pObj->flashSize )
        {
            /* Flash is already programmed, don't expect more data */
            retVal = 3;
        }
        else
        {
            if( pObj->bFlashRead )
            {
                SiiDrvIspBurstRead(pObj->devId, pObj->flashAddr, pData, length);
                pObj->flashAddr += length;
            }
            else /* Writing Flash */
            {
                if( pObj->pFlashPacket )
                {
                    /* Previous buffer has not been emptied */
                    retVal = 4;
                }

#if( SII9777_FLASH_BUFFER_SIZE )
                if( !retVal && (length > SII9777_FLASH_BUFFER_SIZE) )
                {
                    /* Rquested packet size is bigger than maximum allowed packet size */
                    retVal = 5;
                }
#endif

#if( !SII9777_FLASH_BUFFER_SIZE )
                if( !retVal && (length != 256) )
                {
                    /* Rquested packet size is bigger than maximum allowed packet size */
                    retVal = 6;
                }
#endif

                if( !retVal )
                {
#if( SII9777_FLASH_BUFFER_SIZE )
                     /* Create data flash packet */
                     pObj->pFlashPacket = (uint8_t*)SiiSysMallocCreate(length);
                     SII_ASSERT(pObj->pFlashPacket);

                     if( pObj->pFlashPacket )
                     {
                         /* Copy data into flash packet */
                         SII_MEMCPY(pObj->pFlashPacket, pData, length);

                         /* Initialize packet pointer and size */
                         pObj->pPacketPntr  = pObj->pFlashPacket;
                         pObj->packetSize   = length;

                         /* Start flashing packet (interrupt driven) */
                         sHandleFlashProg(pObj);
                     }
                     else
                     {
                         retVal = 7;
                     }
#else
                    pObj->pFlashPacket = (uint8_t*)pData;

                    /* Start flashing packet (interrupt driven) */
                    sHandleFlashProg(pObj);
#endif
                }
            }

            if( !retVal )
            {
                /* Update total number of bytes programmed */
                if( pObj->flashSize < length )
                {
                    pObj->flashSize = 0;
                }
                else
                {
                    pObj->flashSize -= length;
                }
            }
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777FirmwareStatusQuery( SiiInst_t inst, Sii9777FlashStat_t* poStatus )
{
    return Sii9777FlashStatusQuery(inst, poStatus);
}

SiiRetVal_t Sii9777FlashStatusQuery( SiiInst_t inst, Sii9777FlashStat_t* poStatus )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777FlashStatusQuery", pObj, (""));

        if( pObj->bFlashRead || SiiDrvIspOperationDone(pObj->devId) )
        {
            *poStatus = SII9777_FIRMWARE_STAT__READY;
        }
        else
        {
            *poStatus = SII9777_FIRMWARE_STAT__IN_PROGRESS;
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777FirmwareRestart( SiiInst_t inst )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777FirmwareRestart", pObj, (""));

        sDeviceRestart(pObj);
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777DualLinkModeSet( SiiInst_t inst, Sii9777DualLinkMode_t* pDualLinkMode )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777DualLinkModeSet", pObj, ("%d", *pDualLinkMode));

        sRequestMessageInit(pObj, SII9777_DUALLINKMODE_SET);
        SiiDrvIpcBytePush(pObj->mesReqInst, *pDualLinkMode);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_DUALLINKMODE_SET);
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777DualLinkModeGet( SiiInst_t inst, Sii9777DualLinkMode_t* pDualLinkMode )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777DualLinkModeGet", pObj, (""));

        sRequestMessageInit(pObj, Sii9777_DUALLINKMODE_GET);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, Sii9777_DUALLINKMODE_GET);
        if( !retVal )
        {
            *pDualLinkMode = (Sii9777DualLinkMode_t)SiiDrvIpcBytePop(pObj->mesAckInst);
            SII_LOG1B(("%d", *pDualLinkMode));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777TmdsEnableSet( SiiInst_t inst, Sii9777TxPort_t port, bool_t* pbOn )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777TmdsEnableSet", pObj, ("port=%d : %d", (uint16_t)port, (uint16_t)*pbOn));

        sRequestMessageInit(pObj, SII9777_TMDSENABLE_SET);
        SiiDrvIpcBytePush(pObj->mesReqInst, (uint8_t)port);
        SiiDrvIpcBoolPush(pObj->mesReqInst, *pbOn);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_TMDSENABLE_SET);
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777TmdsEnableGet( SiiInst_t inst, Sii9777TxPort_t port, bool_t* pbOn )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777TmdsEnableGet", pObj, ("port=%d : ", (uint16_t)port));

        sRequestMessageInit(pObj, SII9777_TMDSENABLE_GET);
        SiiDrvIpcBytePush(pObj->mesReqInst, (uint8_t)port);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_TMDSENABLE_GET);
        if( !retVal )
        {
            *pbOn = SiiDrvIpcBoolPop(pObj->mesAckInst);
            SII_LOG1B(("%d", *pbOn));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777AudioSourceSet( SiiInst_t inst, Sii9777TxPort_t port, Sii9777AudioSource_t* pAudioSrc )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("AudioSourceSet", pObj, ("%d", (int16_t)*pAudioSrc));

        sRequestMessageInit(pObj, SII9777_AUDIOSOURCE_SET);
        SiiDrvIpcBytePush(pObj->mesReqInst, (uint8_t)port);
        SiiDrvIpcBytePush(pObj->mesReqInst, (uint8_t)*pAudioSrc);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_AUDIOSOURCE_SET);
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777AudioSourceGet( SiiInst_t inst, Sii9777TxPort_t port, Sii9777AudioSource_t* pAudioSrc )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("AudioSourceGet", pObj, (""));

        sRequestMessageInit(pObj, SII9777_AUDIOSOURCE_GET);
        SiiDrvIpcBytePush(pObj->mesReqInst, (uint8_t)port);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_AUDIOSOURCE_GET);
        if( !retVal )
        {
            *pAudioSrc = (Sii9777AudioSource_t)SiiDrvIpcBytePop(pObj->mesAckInst);
            SII_LOG1B(("%d", (int16_t)*pAudioSrc));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777I2sSpdifAudioFormatSet( SiiInst_t inst, Sii9777AudioFmt_t *pAudioFmt )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777I2sSpdifAudioFormatSet", pObj, (""));

        sRequestMessageInit(pObj, SII9777_I2SSPDIFAUDIOFORMAT_SET);
        SiiDrvIpcArrayPush(pObj->mesReqInst, pAudioFmt->aifData, 10);
        SiiDrvIpcArrayPush(pObj->mesReqInst, pAudioFmt->csData, 7);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_I2SSPDIFAUDIOFORMAT_SET);
        if( !retVal )
        {
            SII_LOG1B(("Audio Info Frame : "));
            SII_LOG1B_ARRAY(pAudioFmt->aifData, 10);
            SII_LOG1B(("channel status   : "));
            SII_LOG1B_ARRAY(pAudioFmt->csData, 7);
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777I2sSpdifAudioFormatGet( SiiInst_t inst, Sii9777AudioFmt_t *pAudioFmt )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777I2sSpdifAudioFormatGet", pObj, (""));

        sRequestMessageInit(pObj, SII9777_I2SSPDIFAUDIOFORMAT_GET);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_I2SSPDIFAUDIOFORMAT_GET);
        if( !retVal )
        {
            SiiDrvIpcArrayPop(pObj->mesAckInst, pAudioFmt->aifData, 10);
            SiiDrvIpcArrayPop(pObj->mesAckInst, pAudioFmt->csData, 7);

            SII_LOG1B(("Audio Info Frame : "));
            SII_LOG1B_ARRAY(pAudioFmt->aifData, 10);
            SII_LOG1B(("channel status   : "));
            SII_LOG1B_ARRAY(pAudioFmt->csData, 7);
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777PixelFormatConversionSet( SiiInst_t inst, bool_t* pEnable )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777PixelFormatConversionSet", pObj, ("%d", (int16_t)*pEnable));

        sRequestMessageInit(pObj, SII9777_PIXELFORMATCONVERSION_SET);
        SiiDrvIpcBoolPush(pObj->mesReqInst, *pEnable);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_PIXELFORMATCONVERSION_SET);
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777PixelFormatConversionGet( SiiInst_t inst, bool_t* pEnable )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777PixelFormatConversionGet", pObj, (""));

        sRequestMessageInit(pObj, SII9777_PIXELFORMATCONVERSION_GET);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_PIXELFORMATCONVERSION_GET);
        if( !retVal )
        {
            *pEnable = SiiDrvIpcBoolPop(pObj->mesAckInst);
            SII_LOG1B(("%d", (int16_t)*pEnable));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777PixelFormatConversionQuery( SiiInst_t inst, Sii9777PixFmtConv_t* pStatus )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777PixelFormatConversionQuery", pObj, (""));

        sRequestMessageInit(pObj, SII9777_PIXELFORMATCONVERSION_QUERY);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_PIXELFORMATCONVERSION_QUERY);
        if( !retVal )
        {
            *pStatus = (Sii9777PixFmtConv_t)SiiDrvIpcBytePop(pObj->mesAckInst);
            SII_LOG1B(("%d", (int16_t)*pStatus));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777Smpte4kSet( SiiInst_t inst, Sii9777Smpte4k_t* smpte4k )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777Smpte4kSet", pObj, ("%d", (int16_t)*smpte4k));

        sRequestMessageInit(pObj, SII9777_SMPTE4K_SET);
        SiiDrvIpcBytePush(pObj->mesReqInst, (uint8_t)*smpte4k);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_SMPTE4K_SET);
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777Smpte4kGet( SiiInst_t inst, Sii9777Smpte4k_t* smpte4k )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777Smpte4kGet", pObj, (""));

        sRequestMessageInit(pObj, SII9777_SMPTE4K_GET);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_SMPTE4K_GET);
        if( !retVal )
        {
            *smpte4k = (Sii9777Smpte4k_t)SiiDrvIpcBytePop(pObj->mesAckInst);
            SII_LOG1B(("%d", (int16_t)*smpte4k));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777TpgEnableSet( SiiInst_t inst, bool_t* pbOn )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777TpgEnableSet", pObj, ("%d", (int16_t)*pbOn));

        sRequestMessageInit(pObj, SII9777_TPGENABLE_SET);
        SiiDrvIpcBoolPush(pObj->mesReqInst, *pbOn);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_TPGENABLE_SET);
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777TpgEnableGet( SiiInst_t inst, bool_t* pbOn )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777TpgEnableGet", pObj, (""));

        sRequestMessageInit(pObj, SII9777_TPGENABLE_GET);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_TPGENABLE_GET);
        if( !retVal )
        {
            *pbOn = SiiDrvIpcBoolPop(pObj->mesAckInst);
            SII_LOG1B(("%d", (int16_t)*pbOn));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777TpgPatternSet( SiiInst_t inst, Sii9777TpgPattern_t* pPattern )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777TpgPatternSet", pObj, ("%d", (int16_t)*pPattern));

        sRequestMessageInit(pObj, SII9777_TPGPATTERN_SET);
        SiiDrvIpcBytePush(pObj->mesReqInst, (uint8_t)*pPattern);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_TPGPATTERN_SET);
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777TpgPatternGet( SiiInst_t inst, Sii9777TpgPattern_t* pPattern )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777TpgPatternGet", pObj, (""));

        sRequestMessageInit(pObj, SII9777_TPGPATTERN_GET);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_TPGPATTERN_GET);
        if( !retVal )
        {
            *pPattern = (Sii9777TpgPattern_t)SiiDrvIpcBytePop(pObj->mesAckInst);
            SII_LOG1B(("%d", (int16_t)*pPattern));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777TpgVidResSet( SiiInst_t inst, Sii9777VidRes_t* pVidRes )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777TpgVidResSet", pObj, ("%d", (int16_t)*pVidRes));

        sRequestMessageInit(pObj, SII9777_TPGVIDRES_SET);
        SiiDrvIpcBytePush(pObj->mesReqInst, (uint8_t)*pVidRes);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_TPGVIDRES_SET);
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777TpgVidResGet( SiiInst_t inst, Sii9777VidRes_t* pVidRes )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777TpgVidResGet", pObj, (""));

        sRequestMessageInit(pObj, SII9777_TPGVIDRES_GET);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_TPGVIDRES_GET);
        if( !retVal )
        {
            *pVidRes = (Sii9777VidRes_t)SiiDrvIpcBytePop(pObj->mesAckInst);
            SII_LOG1B(("%d", (int16_t)*pVidRes));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777CmsBypassSet( SiiInst_t inst, bool_t* pbOn )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777CmsBypassSet", pObj, ("%d", (int16_t)*pbOn));

        sRequestMessageInit(pObj, SII9777_CMSBYPASS_SET);
        SiiDrvIpcBoolPush(pObj->mesReqInst, *pbOn);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_CMSBYPASS_SET);
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777CmsBypassGet( SiiInst_t inst, bool_t* pbOn )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777CmsBypassGet", pObj, (""));

        sRequestMessageInit(pObj, SII9777_CMSBYPASS_GET);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_CMSBYPASS_GET);
        if( !retVal )
        {
            *pbOn = SiiDrvIpcBoolPop(pObj->mesAckInst);
            SII_LOG1B(("%d", (int16_t)*pbOn));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777CmsSaturationSet( SiiInst_t inst, Sii9777CmsColor_t clr, int8_t* pSat )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777CmsSaturationSet", pObj, ("%d", (int16_t)*pSat));

        sRequestMessageInit(pObj, SII9777_CMSSATURATION_SET);
        SiiDrvIpcBytePush(pObj->mesReqInst, (uint8_t)clr);
        SiiDrvIpcBytePush(pObj->mesReqInst, (uint8_t)*pSat);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_CMSSATURATION_SET);
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777CmsSaturationGet( SiiInst_t inst, Sii9777CmsColor_t clr, int8_t* pSat )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777CmsSaturationGet", pObj, (""));

        sRequestMessageInit(pObj, SII9777_CMSSATURATION_GET);
        SiiDrvIpcBytePush(pObj->mesReqInst, (uint8_t)clr);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_CMSSATURATION_GET);
        if( !retVal )
        {
            *pSat = (int8_t)SiiDrvIpcBytePop(pObj->mesAckInst);
            SII_LOG1B(("%d", (int16_t)*pSat));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777CmsHueSet( SiiInst_t inst, Sii9777CmsColor_t clr, int8_t* pHue )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777CmsHueSet", pObj, ("%d", (int16_t)*pHue));

        sRequestMessageInit(pObj, SII9777_CMSHUE_SET);
        SiiDrvIpcBytePush(pObj->mesReqInst, (uint8_t)clr);
        SiiDrvIpcBytePush(pObj->mesReqInst, (uint8_t)*pHue);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_CMSHUE_SET);
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777CmsHueGet( SiiInst_t inst, Sii9777CmsColor_t clr, int8_t* pHue )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777CmsHueGet", pObj, (""));

        sRequestMessageInit(pObj, SII9777_CMSHUE_GET);
        SiiDrvIpcBytePush(pObj->mesReqInst, (uint8_t)clr);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_CMSHUE_GET);
        if( !retVal )
        {
            *pHue = (int8_t)SiiDrvIpcBytePop(pObj->mesAckInst);
            SII_LOG1B(("%d", (int16_t)*pHue));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777CmsWhitePointTempSet( SiiInst_t inst, Sii9777CmsColor_t clr, int16_t* pTemperature )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777CmsWhitePointTempSet", pObj, ("%d", (int16_t)*pTemperature));

        sRequestMessageInit(pObj, SII9777_CMSWHITEPOINTTEMP_SET);
        SiiDrvIpcBytePush(pObj->mesReqInst, (uint8_t)clr);
        SiiDrvIpcWordPush(pObj->mesReqInst, (uint8_t)*pTemperature);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_CMSWHITEPOINTTEMP_SET);
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777CmsWhitePointTempGet( SiiInst_t inst, Sii9777CmsColor_t clr, int16_t* pTemperature )
{
    Obj_t*      pObj   = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG1A("Sii9777CmsWhitePointTempGet", pObj, (""));

        sRequestMessageInit(pObj, SII9777_CMSWHITEPOINTTEMP_GET);
        SiiDrvIpcBytePush(pObj->mesReqInst, (uint8_t)clr);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_CMSWHITEPOINTTEMP_GET);
        if( !retVal )
        {
            *pTemperature = (int16_t)SiiDrvIpcWordPop(pObj->mesAckInst);
            SII_LOG1B(("%d", (int16_t)*pTemperature));
        }
    }
    MUTEX_API_GIVE(pObj);
    RETURN_API(retVal);
}

SiiRetVal_t Sii9777ChipRegWrite( SiiInst_t inst, uint16_t addr, uint8_t* pData, uint8_t len)
{
    Obj_t*              pObj    = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t         retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);

    if( !retVal )
    {
        SII_LOG1A("Sii9777ChipRegWrite", pObj, ("addr=%04X, len=%d, data : ", addr, (uint16_t)len));
        SII_LOG1B_ARRAY(pData, len);

        sRequestMessageInit(pObj, SII9777_CHIPREG_WRITE);
        SiiDrvIpcWordPush(pObj->mesReqInst, addr);
        SiiDrvIpcBytePush(pObj->mesReqInst, len);
        SiiDrvIpcArrayPush(pObj->mesReqInst, pData, len);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_CHIPREG_WRITE);
    }

    MUTEX_API_GIVE(pObj);

    RETURN_API(retVal);
}

SiiRetVal_t Sii9777ChipRegRead( SiiInst_t inst, uint16_t addr, uint8_t* pData, uint8_t len )
{
    Obj_t*              pObj    = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t         retVal = 0;

    retVal = MUTEX_API_TAKE(pObj);

    if( !retVal )
    {
        SII_LOG1A("Sii9777ChipRegRead", pObj, ("addr=%04X, len=%d, data : ", addr, (uint16_t)len));

        sRequestMessageInit(pObj, SII9777_CHIPREG_READ);
        SiiDrvIpcWordPush(pObj->mesReqInst, addr);
        SiiDrvIpcBytePush(pObj->mesReqInst, len);
        sRequestMessageSend(pObj);

        retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_CHIPREG_READ);
        if( !retVal )
        {
            SiiDrvIpcArrayPop(pObj->mesAckInst, pData, len);
            SII_LOG1B_ARRAY(pData, len);
        }
    }

    MUTEX_API_GIVE(pObj);

    RETURN_API(retVal);
}

SiiRetVal_t Sii9777ServiceModeSet( SiiInst_t inst, bool_t bOn )
{
    Obj_t*      pObj    = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);
    SiiRetVal_t retVal = 0;

    SiiDrvCraWrite8(pObj->devId, 0x7205, (bOn) ? (0x01) : (0x00));
    pObj->servDatPntr = 0;
    RETURN_API(retVal);
}

uint16_t Sii9777ServiceDataGet( SiiInst_t inst, uint8_t* pData, uint16_t len )
{
    Obj_t* pObj = (Obj_t*)SII_SYS_OBJ_CHECK(sObjListInst, inst);

    if( 0x8000 > pObj->servDatPntr )
    {
        uint16_t x = 0x8000 - pObj->servDatPntr; 

        if( x < len )
        {
            len = x;
        }
    }
    else
    {
        len = 0;
    }
    if( len )
    {
        SiiDrvCraBlockRead8(pObj->devId, pObj->servDatPntr, pData, len);
        pObj->servDatPntr += len;
    }
    return len;
}

/***** local functions *******************************************************/

static void sResourcesDelete( Obj_t* pObj )
{
    if( pObj->mesAckInst )
    {
        SiiDrvIpcMessageDelete(pObj->mesAckInst);
    }

    if( pObj->mesReqInst )
    {
        SiiDrvIpcMessageDelete(pObj->mesReqInst);
    }

    if( pObj->ipcInst )
    {
        SiiDrvIpcDelete(pObj->ipcInst);
    }

#if( SII9777_USER_DEF__MULTI_THREAD )
  #if( SII9777_USER_DEF__IPC_SEMAPHORE )
    if( pObj->semaphoreHandle )
    {
        SiiPlatformSemaphoreDelete(pObj->semaphoreHandle);
    }

    if( pObj->semaphoreIpc )
    {
        SiiPlatformSemaphoreDelete(pObj->semaphoreIpc);
    }
  #endif
    if( pObj->semaphoreApi )
    {
        SiiPlatformSemaphoreDelete(pObj->semaphoreApi);
    }
#endif

    SiiSysObjInstanceDelete(pObj);
    if( !SiiSysObjFirstGet(sObjListInst) )
    {
        /* Delete list of objects */
        SiiSysObjListDelete(sObjListInst);
        sObjListInst = SII_INST_NULL;
    }
}

static SiiRetVal_t sHandle( Obj_t* pObj )
{
    SiiRetVal_t         retVal = 0;
    Sii9777EventFlags_t flags  = 0;

    retVal = MUTEX_HANDLE_TAKE(pObj);
    if( !retVal )
    {
        SII_LOG2A("sHandle", pObj, ("\n"));

        /* Temperarily disable all interrupts to force INT signal to go low */
        sInterruptsEnableSet(pObj, false);

        /* Handle IPC interrupts */
        sHandleIpcInterrupts(pObj);

        /* Handle ISP interrupts */
        sHandleIspInterrupts(pObj);

        /* Release INT force low condition to allow level triggered ISR to be invoked in case some interrupt bits still were set */
        sInterruptsEnableSet(pObj, true);

        /* Update Event status */
        pObj->eventFlagsStat |= pObj->eventFlagsUser;
        pObj->eventFlagsUser = 0x00000000;
        flags = pObj->eventFlagsStat & pObj->eventFlagsMask;
        pObj->eventFlagsStat &= (~pObj->eventFlagsMask);
    }
    
    /* Release Mutex before calling user call-back handler so that user application can call APIs from call-back handler */
    MUTEX_HANDLE_GIVE(pObj);

    if( !retVal )
    {
        if( flags )
        {
            if( pObj->siiLibEvtCbFunc )
            {
#if( SII9777_USER_DEF__MULTI_THREAD && SII9777_USER_DEF__IPC_SEMAPHORE )
                /* Set flag to allow API calls indentify if they were called from user call-back */
                pObj->bFromUserCallBack = true;
#endif

                /* Call notification handler */
                pObj->siiLibEvtCbFunc(SII_OBJ2INST(pObj), flags);

#if( SII9777_USER_DEF__MULTI_THREAD && SII9777_USER_DEF__IPC_SEMAPHORE )
                pObj->bFromUserCallBack = false;
#endif
            }
        }
    }
    return retVal;
}

static void sHandleFlashProg( Obj_t* pObj )
{
    /* Make sure previous flashing operation is done */
    SII_ASSERT(SiiDrvIspOperationDone(pObj->devId));

    if( pObj->pFlashPacket )
    {
        uint16_t pageSize = 256;

#if( SII9777_FLASH_BUFFER_SIZE )
        /* Detemine maximum page size based on absolute flashing address                 */
        /* Maximum page size is 256 bytes if LSByte of absolute flashing address is zero */
        pageSize = 256 - (pObj->flashAddr%256); 

        /* Check if packet size is smaller than maximum page size */
        if( pObj->packetSize < pageSize )
        {
            pageSize = pObj->packetSize;
        }
#endif

        SII_LOG2A("sHandleFlashProg", pObj, ("Offset=0x%lX, length=0x%x\n", pObj->flashAddr, pageSize));
#if( SII9777_FLASH_BUFFER_SIZE )
        /* Program page of bytes */
        SiiDrvIspBurstWrite(pObj->flashAddr, pObj->pPacketPntr, pageSize);

        pObj->pPacketPntr   += pageSize;
        pObj->packetSize    -= pageSize;

        /* Check if entire packet has been programmed */
        if( 0 == pObj->packetSize )
        {
            /* Delete flash packet */ 
            SiiSysMallocDelete(pObj->pFlashPacket);
            pObj->pFlashPacket = NULL;

            /* Assert notification to indicate that packet has been flashed */ 
            pObj->eventFlagsUser |= SII9777_EVENT_FLAGS__FLASH_DONE;
        }
#else
        /* Program page of bytes */
        SiiDrvIspBurstWrite(pObj->devId, pObj->flashAddr, pObj->pFlashPacket, pageSize);

        /* Clear packet pointer to indicate packet is programmed */
        pObj->pFlashPacket = NULL;

        /* Assert notification to indicate that packet has been flashed */ 
        pObj->eventFlagsUser |= SII9777_EVENT_FLAGS__FLASH_DONE;
#endif

        pObj->flashAddr     += pageSize;
    }
    else
    {
        /* Assert notification to indicate erase cyle has been finished */ 
        pObj->eventFlagsUser |= SII9777_EVENT_FLAGS__FLASH_DONE;
    }
}

static void sHandleIpcInterrupts( Obj_t* pObj )
{
    uint8_t ipcFlags = 0;

    /* Read IPC interrupt status flags */
    ipcFlags = SiiDrvCraRead8(pObj->devId, 0x7062);
    if( ipcFlags )
    {
        /* Clear IPC interrupt status flags */
        SiiDrvCraWrite8(pObj->devId, 0x7062, ipcFlags);

        if( ipcFlags & 0x7 )
        {
            /* Handle IPC interrupts */
            SiiDrvIpcHandler(pObj->ipcInst, (SiiDrvIpcIsrFlags_t)ipcFlags);
        }
    }

    SII_LOG2A("sHandleIpcInterrupts", pObj, ("%02X\n", (uint16_t)ipcFlags));
}

static void sHandleIspInterrupts( Obj_t* pObj )
{
    uint8_t ispFlags = 0;

    /* Read ISP interrupt status flags */
    ispFlags = SiiDrvCraRead8(pObj->devId, 0x00f3);
    if( ispFlags )
    {
        /* Clear ISP interrupt status flag */
        SiiDrvCraWrite8(pObj->devId, 0x00f3, ispFlags);

        /* Handle ISP interrupts */
        sHandleFlashProg(pObj);  /* Flash program handler */
    }

    SII_LOG2A("sHandleIspInterrupts", pObj, ("%02X\n", (uint16_t)ispFlags));
}

static void sRequestMessageInit( Obj_t* pObj, SiiDrvIpcOpCode_t opCode )
{
    SiiDrvIpcMessageClear(pObj->mesReqInst);
    SiiDrvIpcTypeSet(pObj->mesReqInst, SII_DRV_IPC_TYPE__REQUEST);
    SiiDrvIpcOpCodeSet(pObj->mesReqInst, opCode);
    pObj->tagCode++;
    SiiDrvIpcTagCodeSet(pObj->mesReqInst, pObj->tagCode);

    /* Clear previous acknowledge message before new request message is initiated */
    SiiDrvIpcMessageClear(pObj->mesAckInst);
}

static void sRequestMessageSend( Obj_t* pObj )
{
    SiiDrvIpcMessageSend(pObj->ipcInst, pObj->mesReqInst);
}

static SiiRetVal_t sWaitForValidIpcResponseMessage( Obj_t* pObj, SiiDrvIpcOpCode_t opCode )
{
    SiiRetVal_t retVal = 0;

    SII_LOG2A("sWaitForValidIpcResponseMessage", pObj, (""));
#if( SII9777_USER_DEF__MULTI_THREAD && SII9777_USER_DEF__IPC_SEMAPHORE )
    /* First check if API call was initiated through user call back. */
    /* Response message polling is required when called through user call-back, since Sii9777Handle is still blocked */
    if( pObj->bFromUserCallBack )
#endif
    {   /* Poll and wait until response message is received */
        
        SiiSysTimeMilli_t timeOut;

        /* Wait for respondse message from slave */
        SiiSysTimeOutMilliSet(&timeOut, IPC_COMPLETION_TIMEOUT);
        while( opCode != SiiDrvIpcOpCodeGet(pObj->mesAckInst) ) /* Check if responding message has been received. */
        {
            SiiPlatformSleepMsec(10);
            sHandleIpcInterrupts(pObj);

            if( SiiSysTimeOutMilliIs(&timeOut) ) /* Check for time-out */
            {
                retVal = SII9777_RETVAL__IPC_NO_RESPONSE;
                break;
            }
        }
        if( retVal == SII9777_RETVAL__IPC_NO_RESPONSE ) {
            printk("** TIMEOUT SII9777 OpCODE %d time %d\n", opCode);
        }
    }
#if( SII9777_USER_DEF__MULTI_THREAD && SII9777_USER_DEF__IPC_SEMAPHORE )
    else
    {
        /* Wait for Sii9777Handle() to receive response message */
        /* sSemaphoreIpcTake returns false if released through timeout */
        retVal = sSemaphoreIpcTake(pObj);
        if( !retVal )
        {
            if( opCode != SiiDrvIpcOpCodeGet(pObj->mesAckInst) )
            {
                retVal = SII9777_RETVAL__IPC_NO_RESPONSE;
            }
        }
    }
#endif

    if( pObj->eventFlagsUser )
    {
        /* bit 3 is used to invoke user application to call Sii9777Handle() to ensure handling of remaining event flags */
        SiiDrvCraWrite8(pObj->devId, 0x7060, 0x08);
    }

    /* Clear IPC Tx-queue in case it wasn't cleared due to time out or latency of SiiDrvIpcHandler() call. */
    SiiDrvIpcTxReset(pObj->ipcInst);

    if( !retVal )
    {
        /* Check Tag Code */
        if( pObj->tagCode != SiiDrvIpcTagCodeGet(pObj->mesAckInst) )
        {
            retVal = SII9777_RETVAL__IPC_WRONG_TAG_CODE;
        }
    }

    if( !retVal )
    {
        /* Read result code */
        retVal = (SiiRetVal_t)SiiDrvIpcBytePop(pObj->mesAckInst);
    }

    return retVal;
}

#if( SII9777_USER_DEF__MULTI_THREAD )
#if( SII9777_USER_DEF__IPC_SEMAPHORE )
static SiiRetVal_t sSemaphoreIpcTake( Obj_t* pObj )
{
    SiiRetVal_t retVal = 0;

    SII_ASSERT(pObj->semaphoreHandle);
    SII_ASSERT(pObj->semaphoreIpc);

    SII_LOG2A("sSemaphoreIpcTake", pObj, (""));

    /* Ipc semaphore should not be given at this point. If still given then take ipc semaphore to clear */
    if( pObj->bIpcGiven )
    {
        /* Take IPC Semaphore */
        if( SII_PLATFORM_STATUS__SUCCESS != SiiPlatformSemaphoreTake(pObj->semaphoreIpc, 1) )
        {
            SII_ASSERT(0);
        }

        pObj->bIpcGiven = false;
    }

    /* Give Handle Semaphore */
    SiiPlatformSemaphoreGive(pObj->semaphoreHandle);

    if( !retVal )
    {
        if( SII_PLATFORM_STATUS__SUCCESS != SiiPlatformSemaphoreTake(pObj->semaphoreIpc, IPC_COMPLETION_TIMEOUT) )
        {
            retVal = SII9777_RETVAL__SEMAPHORE_IPC_EXPIRE;
        }
        else
        {
            /* Clear IPC given flag because IPC take did not get expired */
            pObj->bIpcGiven = false;
        }
    }
    if( !retVal && (SII_PLATFORM_STATUS__SUCCESS != SiiPlatformSemaphoreTake(pObj->semaphoreHandle, IPC_COMPLETION_TIMEOUT)) )
    {
        retVal = SII9777_RETVAL__SEMAPHORE_HANDLE_EXPIRE;
    }
    return retVal;
}

static void sSemaphoreIpcGive( Obj_t* pObj )
{
    SII_ASSERT(pObj->semaphoreIpc);

    SII_LOG2A("sSemaphoreIpcGive", pObj, (""));

    /* Set Ipc given flag so that later we can still determine if IPC semaphore was still given after it was released through expiration */
    pObj->bIpcGiven = true;

    SiiPlatformSemaphoreGive(pObj->semaphoreIpc);
}

static SiiRetVal_t sMutexHandleTake( Obj_t* pObj )
{
    SiiRetVal_t retVal = 0;

    SII_ASSERT(pObj->semaphoreHandle);

    SII_LOG2A("sMutexHandleTake", pObj, (""));

    if( !retVal && (SII_PLATFORM_STATUS__SUCCESS != SiiPlatformSemaphoreTake(pObj->semaphoreHandle, IPC_COMPLETION_TIMEOUT)) )
    {
        retVal = SII9777_RETVAL__SEMAPHORE_HANDLE_EXPIRE;
    }
    return retVal;
}

static void sMutexHandleGive( Obj_t* pObj )
{
    SII_ASSERT(pObj->semaphoreHandle);

    SII_LOG2A("sMutexHandleGive", pObj, (""));

    SiiPlatformSemaphoreGive(pObj->semaphoreHandle);
}
#endif

static SiiRetVal_t sMutexApiTake( Obj_t* pObj )
{
    SiiRetVal_t retVal = 0;

    SII_ASSERT(pObj->semaphoreApi);

    SII_LOG2A("sMutexApiTake", pObj, (""));

    if( !retVal && (SII_PLATFORM_STATUS__SUCCESS != SiiPlatformSemaphoreTake(pObj->semaphoreApi, IPC_COMPLETION_TIMEOUT)) )
    {
        retVal = SII9777_RETVAL__SEMAPHORE_API_EXPIRE;
    }
#if( SII9777_USER_DEF__IPC_SEMAPHORE )
    SII_ASSERT(pObj->semaphoreHandle);
    if( !retVal && (SII_PLATFORM_STATUS__SUCCESS != SiiPlatformSemaphoreTake(pObj->semaphoreHandle, IPC_COMPLETION_TIMEOUT)) )
    {
        retVal = SII9777_RETVAL__SEMAPHORE_HANDLE_EXPIRE;
    }
#endif
    return retVal;
}

static void sMutexApiGive( Obj_t* pObj )
{
    SII_ASSERT(pObj->semaphoreApi);

    SII_LOG2A("sMutexApiGive", pObj, (""));

#if( SII9777_USER_DEF__IPC_SEMAPHORE )
    SII_ASSERT(pObj->semaphoreHandle);
    SiiPlatformSemaphoreGive(pObj->semaphoreHandle);
#endif
    SiiPlatformSemaphoreGive(pObj->semaphoreApi);
}
#endif

static void sDeviceRestart( Obj_t* pObj )
{
    /* Re-fetch firmware from flash and restart firmware */
    pObj->bootStat = SII9777_BOOT_STAT__IN_PROGRESS;

    /* SW reset SiI9777 device */
    SiiPlatformDeviceResetSet(pObj->devId, true);
    SiiPlatformDeviceResetSet(pObj->devId, false);

    /* Set boot timeout timer */
    SiiSysTimeOutMilliSet(&pObj->bootTimeOut, BOOT_TIME_MAX);
}

static bool_t sDevicePing( Obj_t* pObj )
{
    SiiRetVal_t retVal = 0;

    /* Ping device */
    sRequestMessageInit(pObj, SII9777_FIRMWAREVERSION_QUERY);
    sRequestMessageSend(pObj);

    /* wait for response from 8051 firmware and check result */
    retVal = sWaitForValidIpcResponseMessage(pObj, SII9777_FIRMWAREVERSION_QUERY);

    return (retVal) ? (false) : (true);
}

static void sInterruptsEnableSet( Obj_t* pObj, bool_t bEnable )
{
    if( bEnable )
    {
        /* Set interrupt mask bits to allow invokation of INT signal */
        SiiDrvCraWrite8(pObj->devId, 0x7061, 0x0F);
        SiiDrvCraWrite8(pObj->devId, 0x00f2, 0x01);
    }
    else
    {
        /* Clear interrupt mask bits to avoid invokation of INT signal */
        SiiDrvCraWrite8(pObj->devId, 0x7061, 0x00);
        SiiDrvCraWrite8(pObj->devId, 0x00f2, 0x00);
    }
}

/***** end of file ***********************************************************/
