//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//------------------------------------------------------------------------------
//
//  File: ioctl.c
//
//  This file implements the OEM's IO Control (IOCTL) functions and declares
//  global variables used by the IOCTL component.
//
#include <windows.h>
#include <oal.h>
#include <bsp.h>
#include <Pkfuncs.h>
#include <Storemgr.h>
#include <pmplatform.h>
#include <drvmsg.h>
#ifdef BSP_POCKETSTORE
#include <FSR_PartitionID.h>
#endif
#include "loader.h"
#include <fmd.h>
#ifdef BSP_POCKETSTORE
#include <FSR.h>
#include <FSR_LLD_OneNAND.h>
#include <FSR_LLD_4K_OneNAND.h>
#endif
#include <clkinfo.h>
#include "power.h"

//------------------------------------------------------------------------------
//
//  Global: g_oalIoctlPlatformType/OEM
//
//  Platform Type/OEM
//
LPCWSTR g_oalIoCtlPlatformType = L"";
LPCWSTR g_oalIoCtlPlatformOEM  = IOCTL_PLATFORM_OEM;

LPCWSTR g_oalIoCtlPlatformName  = IOCTL_PLATFORM_NAME;
LPCWSTR g_oalIoCtlPlatformManufacturer  = IOCTL_PLATFORM_MANUFACTURER;
//------------------------------------------------------------------------------
//
//  Global: g_oalIoctlProcessorVendor/Name/Core
//
//  Processor information
//
LPCWSTR g_oalIoCtlProcessorVendor = IOCTL_PROCESSOR_VENDOR;
LPCWSTR g_oalIoCtlProcessorName   = IOCTL_PROCESSOR_NAME;
LPCWSTR g_oalIoCtlProcessorCore   = IOCTL_PROCESSOR_CORE;

const UINT8 g_oalIoCtlVendorId[6] = { 0x00, 0x50, 0xBF, 0x43, 0x39, 0xBF };

//------------------------------------------------------------------------------
//
// Global: g_oalIoctlPlatformManufacturer/Name
//
// if the platform supports SPI_GETPLATFORMMANUFACTURER and SPI_GETPLATFORMNAME
// initialize these globals here and 
// copy them to g_oalIoCtlPlatformManufacturer/g_oalIoCtlPlatformName in OEMInit() 
//

LPCWSTR g_pPlatformManufacturer = IOCTL_PLATFORM_MANUFACTURER;
LPCWSTR g_pPlatformName = IOCTL_PLATFORM_NAME;


//------------------------------------------------------------------------------
//
//  Global:  g_oalIoctlInstructionSet
//
//  Processor instruction set identifier and maximal CPU speed
//
UINT32 g_oalIoCtlInstructionSet = IOCTL_PROCESSOR_INSTRUCTION_SET;
UINT32 g_oalIoCtlClockSpeed = IOCTL_PROCESSOR_CLOCK_SPEED;





//------------------------------------------------------------------------------
//
//  Function:  OALIoCtlHalGetHWEntropy
//
//  Implements the IOCTL_HAL_GET_HWENTROPY handler. This function creates a
//  64-bit value which is unique to the hardware.  This value never changes.
//
static BOOL OALIoCtlHalGetHWEntropy(
        UINT32 dwIoControlCode, VOID *lpInBuf, UINT32 nInBufSize, VOID *lpOutBuf,
        UINT32 nOutBufSize, UINT32* lpBytesReturned)
{
    volatile DWORD *pChipId;
    UINT32 HWEntropy[2] = {0, 0};
    DWORD dwErr = 0;

    OALMSG(OAL_IOCTL&&OAL_FUNC, (L"+OALIoCtlHalGetHWEntropy\r\n"));

    // Check buffer size
    if (lpBytesReturned != NULL)
    {
    *lpBytesReturned = sizeof(HWEntropy);
    }

    if (lpOutBuf == NULL || nOutBufSize < sizeof(HWEntropy))
    {
        NKSetLastError(ERROR_INSUFFICIENT_BUFFER);
        OALMSG(OAL_WARN, (L"WARN: OALIoCtlHalGetHWEntropy: Buffer too small\r\n"));
    }
    else
    {
        __try
        {
            pChipId = (volatile DWORD *)OALPAtoVA(BASE_REG_PA_CHIPID, FALSE);
            if (pChipId == NULL)
            {
                OALMSG(OAL_ERROR, (TEXT("[OALIoCtl] ChipID is *NOT* mapped.\n")));
                return FALSE;
            }
            else
            {
                // Get ChipId ids
                HWEntropy[0] = *pChipId;
                HWEntropy[1] = *pChipId;

                // Copy pattern to output buffer
                memcpy(lpOutBuf, HWEntropy, sizeof(HWEntropy));
            }
        }
        __except (EXCEPTION_EXECUTE_HANDLER)
        {
            dwErr = ERROR_INVALID_PARAMETER;
        }

    }

    if (dwErr)
    {
        OALMSG(OAL_ERROR, (TEXT("[OAL:ERR] OALIoCtlHalGetHWEntropy() Failed dwErr = 0x%08x\r\n"), dwErr));
        NKSetLastError(dwErr);
    }

    // Indicate status
    OALMSG(OAL_IOCTL&&OAL_FUNC, (L"-OALIoCtlHalGetHWEntropy(rc = %d)\r\n", dwErr));
    OALMSG(1, (L"-OALIoCtlHalGetHWEntropy(rc = %d)\r\n", dwErr));
    return !dwErr;
}


//------------------------------------------------------------------------------
//
//  Function:  OALIoCtlHalGetHiveCleanFlag
//
//  Implements the IOCTL_HAL_GET_HIVE_CLEAN_FLAG handler. 
//  This IOCTL is used by Filesys.exe to query the OEM to determine if the registry hives and user profiles should be deleted and recreated.

BOOL OALIoCtlHalGetHiveCleanFlag ( 
    UINT32 code, VOID *pInpBuffer, UINT32 inpSize, VOID *pOutBuffer, 
    UINT32 outSize, UINT32 *pOutSize) 
{
	BOOL bRet = FALSE;

    DWORD *pdwFlags = (DWORD*)pInpBuffer;
	BOOL *pfClean  = (BOOL*)pOutBuffer;
	BOOL *bCleanSysHiveFlag = (BOOL*) OALArgsQuery(OAL_ARGS_QUERY_SYS_HIVE_CLEAN);
	BOOL *bCleanUserHiveFlag = (BOOL*) OALArgsQuery(OAL_ARGS_QUERY_USER_HIVE_CLEAN);   
    
    OALMSG(OAL_IOCTL&&OAL_OEM_FUNC, (TEXT("IOCTL_HAL_GET_HIVE_CLEAN_FLAG called. = 0x%x\r\n"), code));

	if (!pInpBuffer || (inpSize != sizeof(DWORD)) || !pOutBuffer || (outSize != sizeof(BOOL)))
	{
		NKSetLastError(ERROR_INVALID_PARAMETER);
	    OALMSG(OAL_WARN, (L"ERROR: OALIoCtlHalHiveCleanFlag: Invalid input buffer\r\n"));
        goto cleanUp;
 	} 

	OALMSG(OAL_DEBUG, (TEXT("OALIoCtlHalGetHiveCleanFlag :: pArgs->bClearSystemHiveReg = 0x%x\r\n"), *bCleanSysHiveFlag ));
	OALMSG(OAL_DEBUG, (TEXT("OALIoCtlHalGetHiveCleanFlag :: pArgs->bClearUserHiveReg = 0x%x\r\n"), *bCleanUserHiveFlag));

	if (*pdwFlags == HIVECLEANFLAG_SYSTEM) 
	{
	    if(*bCleanSysHiveFlag)
        {  
		    OALMSG(OAL_INFO, (TEXT("OEM: Cleaning system hive\r\n")));
		    *pfClean = TRUE;
		    
        }
        else
        {
  	        OALMSG(OAL_INFO, (TEXT("OEM: No Cleaning system hive\r\n")));
		    *pfClean = FALSE;
        }
                
		}
	else if(*pdwFlags == HIVECLEANFLAG_USERS)
	{
	    if(*bCleanUserHiveFlag)
        {
	        OALMSG(OAL_INFO, (TEXT("OEM: Cleaning user hive\r\n")));
		    *pfClean = TRUE;
            *bCleanSysHiveFlag = FALSE;
		    *bCleanUserHiveFlag = FALSE;            
        }
        else
        {
  	        OALMSG(OAL_INFO, (TEXT("OEM: No Cleaning user hive\r\n")));
		    *pfClean = FALSE;
        }
       

	}
        
    bRet = TRUE;

cleanUp:
    return bRet;
}


BOOL OALIoCtlHalQueryFormatPartition(
    UINT32 code, VOID *pInpBuffer, UINT32 inpSize, VOID *pOutBuffer, 
    UINT32 outSize, UINT32 *pOutSize) 
{
	BOOL bRet = FALSE;

    STORAGECONTEXT* pContext = (STORAGECONTEXT*)pInpBuffer;
	BOOL *pfClean = (BOOL*)pOutBuffer;
    
	BOOL *bCleanBootFlag = (BOOL*) OALArgsQuery(OAL_ARGS_QUERY_CLEANBOOT);
	BOOL *bFormatStorageFlag = (BOOL*) OALArgsQuery(OAL_ARGS_QUERY_FORMATPART);
    
	if (sizeof(STORAGECONTEXT) != inpSize || !pInpBuffer || sizeof(BOOL) != outSize || !pOutBuffer)
	{
		NKSetLastError(ERROR_INVALID_PARAMETER);
		goto cleanUp;
	}    

    OALMSG(OAL_OEM_FUNC, (TEXT("OALIoCtlHalQueryFormatPartition\r\n")));
	OALMSG(OAL_DEBUG, (TEXT("pArgs->bCleanBoot = %d \r\n"),*bCleanBootFlag));	
	OALMSG(OAL_DEBUG, (TEXT("pArgs->bFormatStorage = %d \r\n"),*bFormatStorageFlag));	
 
    if(AFS_FLAG_ROOTFS & pContext->dwFlags)
	{
        if(*bCleanBootFlag || *bFormatStorageFlag)
        {    
            OALMSG(OAL_DEBUG, (TEXT("[NK:OAL] Clearing RootFS\r\n")));
            *pfClean = TRUE;
            *bCleanBootFlag = FALSE;
            *bFormatStorageFlag = FALSE;
		}
        else
        {
            OALMSG(OAL_DEBUG, (TEXT("[NK:OAL] No Clearing RootFS\r\n")));
        }
    }
    else if(AFS_FLAG_BOOTABLE & pContext->dwFlags)
    {
        if(*bCleanBootFlag)
        {
           OALMSG(OAL_DEBUG, (TEXT("[NK:OAL] Clearing BootableFS\r\n")));
           *pfClean = TRUE;
           *bCleanBootFlag = FALSE;
        }
        else
        {
           OALMSG(OAL_DEBUG, (TEXT("[NK:OAL] No Clearing BootableFS\r\n")));
        }
    }

    bRet = TRUE;
    
cleanUp:
    return bRet;
}

BOOL OALIoCtlHalQueryDisplaySettings (
    UINT32 dwIoControlCode, VOID *lpInBuf, UINT32 nInBufSize, VOID *lpOutBuf, 
    UINT32 nOutBufSize, UINT32* lpBytesReturned)
{
    DWORD dwErr = 0;

    RETAILMSG(0, (TEXT("In OALIoCtlHalQueryDisplaySettings^^^^^\r\n")));

    if (lpBytesReturned) {
        *lpBytesReturned = 0;
    }

    if (!lpOutBuf) {
        dwErr = ERROR_INVALID_PARAMETER;
    } else if (sizeof(DWORD)*3 > nOutBufSize) {
        dwErr = ERROR_INSUFFICIENT_BUFFER;
    } else {
        // Check the boot arg structure for the default display settings.
        __try {

            // TBD, jylee
            ((PDWORD)lpOutBuf)[0] = (DWORD)LCD_WIDTH;
            ((PDWORD)lpOutBuf)[1] = (DWORD)LCD_HEIGHT;
            ((PDWORD)lpOutBuf)[2] = (DWORD)LCD_BPP;

            if (lpBytesReturned) {
                *lpBytesReturned = sizeof (DWORD) * 3;
            }

        } __except (EXCEPTION_EXECUTE_HANDLER) {
            dwErr = ERROR_INVALID_PARAMETER;
        }
    }

    if (dwErr) {
        NKSetLastError (dwErr);
    }

    return !dwErr;
}


//------------------------------------------------------------------------------
//
//  Function: OALIoCtlHalReboot
//  This function make a Warm Boot of the target device
//
static BOOL OALIoCtlHalReboot(
        UINT32 code, VOID *pInpBuffer, UINT32 inpSize,
        VOID *pOutBuffer, UINT32 outSize, UINT32 *pOutSize)
{
    BSP_ARGS *pBSPArgs = ((BSP_ARGS *) IMAGE_SHARE_ARGS_UA_START);
    volatile PMU_MISC_REG *pPMUMISCReg = (PMU_MISC_REG *)OALPAtoVA(BASE_REG_PA_PMU_MISC, FALSE);
	TOC BootCfg;
    DWORD tmp=0;

    OALMSG(OAL_IOCTL&&OAL_FUNC, (TEXT("[OAL] ++OALIoCtlHalReboot()\r\n")));

    if(!OALIoCtlGetEbootCfg(IOCTL_GET_EBOOT_CONFIG, NULL, 0, &BootCfg, sizeof(BootCfg), &tmp)){
		OALMSG(OAL_ERROR, (L"OALIoCtlGetEbootCfg Failed\r\n"));
    }
	if (pBSPArgs->fUpdateMode != BootCfg.BootCfg.fUpdateMode)
	{
	    OALMSG(OAL_INFO,(L"OALIoCtlHalReboot :: bULDRBoot set (%x -> %x)\r\n\r\n", BootCfg.BootCfg.fUpdateMode, pBSPArgs->fUpdateMode));
        BootCfg.BootCfg.fUpdateMode = pBSPArgs->fUpdateMode;
		if(!OALIoCtlSetEbootCfg(IOCTL_SET_EBOOT_CONFIG, (PBYTE)&BootCfg, sizeof(TOC), NULL, 0, &tmp))
			OALMSG(OAL_ERROR, (L"OALIoCtlSetEbootCfg Failed\r\n"));
	}

    if(pBSPArgs->fUpdateMode == TRUE){
        pPMUMISCReg->MISC_REG.INFORM2 = ULDR_RESET; // Reset Reason
    }        
#ifdef BSP_IMGULDR
        pPMUMISCReg->MISC_REG.INFORM2 = ULDR_RESET; // Reset Reason
#endif


    OEMSWReset();

    OALMSG(OAL_IOCTL&&OAL_FUNC, (TEXT("[OAL] --OALIoCtlHalReboot()\r\n")));

    return TRUE;
}

BOOL OALIoCtlHalProfile(UINT32 dwIoControlCode, VOID *lpInBuf, UINT32 nInBufSize, VOID *lpOutBuf, UINT32 nOutBufSize, UINT32* lpBytesReturned)
{
    RETAILMSG(0, (TEXT("<<<< OALIoCtlHalProfile .>>>>\n")));
    return(TRUE);
}

//------------------------------------------------------------------------------
//
//  Function:  OALIoCtlHalSetSystemLevel
//
//  For Testing DVFS level manually
//  NOTE!!! Remove UpdateDVFS() in the OALTimerIntrHandler() function
//
static BOOL OALIoCtlHalSetSystemLevel(
        UINT32 dwIoControlCode, VOID *lpInBuf, UINT32 nInBufSize,
        VOID *lpOutBuf, UINT32 nOutBufSize, UINT32* lpBytesReturned)
{

    OALMSG(TRUE, (TEXT("[OAL:ERR] OALIoCtlHalSetSystemLevel() : This IOCTL is deprecatd !!!\r\n")));
    return TRUE;

}

//------------------------------------------------------------------------------
//
//  Function:  OALIoCtlHalProfileDVFS
//
//  For Profiling DVFS transition and CPU idle/active rate
//  NOTE!!! Enable #define DVFS_LEVEL_PROFILE in DVFS.c
//
static BOOL OALIoCtlHalProfileDVFS(
        UINT32 dwIoControlCode, VOID *lpInBuf, UINT32 nInBufSize,
        VOID *lpOutBuf, UINT32 nOutBufSize, UINT32* lpBytesReturned)
{
    OALMSG(TRUE, (TEXT("[OAL:ERR] OALIoCtlHalProfileDVFS() is deprecated !!!\r\n")));

    return TRUE;

}


static BOOL OALIoCtlHalGetCPUID(
        UINT32 dwIoControlCode, VOID *lpInBuf, UINT32 nInBufSize,
        VOID *lpOutBuf, UINT32 nOutBufSize, UINT32* lpBytesReturned)
{
    DWORD dwErr = 0;
    volatile DWORD *pChipId;

    OALMSG(OAL_IOCTL&&OAL_FUNC, (TEXT("++OALIoCtlHalGetCPUID()\r\n")));

    if (lpBytesReturned)
    {
        *lpBytesReturned = 0;
    }

    if (lpInBuf == NULL)
    {
        dwErr = ERROR_INVALID_PARAMETER;
    }
    else if (sizeof(DWORD) > nInBufSize)
    {
        dwErr = ERROR_INSUFFICIENT_BUFFER;
    }
    else
    {
        __try
        {
            pChipId = (volatile DWORD *)OALPAtoVA(BASE_REG_PA_CHIPID, FALSE);
            if (pChipId == NULL)
            {
                OALMSG(OAL_ERROR, (TEXT("[OALIoCtl] ChipID is *NOT* mapped.\n")));
                return FALSE;
            }
            else
            {
                *(DWORD *)lpOutBuf = *pChipId;
            }
        }
        __except (EXCEPTION_EXECUTE_HANDLER)
        {
            dwErr = ERROR_INVALID_PARAMETER;
        }
    }

    if (dwErr)
    {
        OALMSG(OAL_ERROR, (TEXT("[OAL:ERR] OALIoCtlHalGetCPUID() Failed dwErr = 0x%08x\r\n"), dwErr));
        NKSetLastError(dwErr);
    }

    OALMSG(OAL_IOCTL&&OAL_FUNC, (TEXT("--OALIoCtlHalGetCPUID()\r\n")));

    return !dwErr;
}

//------------------------------------------------------------------------------
//
//  Function:  OALIoCtlHalCheckLPAudio
//
//  This function is called for configuration LP Audio Mode in Application and Driver.

BOOL OALIoCtlHalCheckLPAudio(
        UINT32 dwIoControlCode, VOID *lpInBuf, UINT32 nInBufSize,
        VOID *lpOutBuf, UINT32 nOutBufSize, UINT32* lpBytesReturned
) {
    BOOL dwErr = FALSE;

    BSP_ARGS *pArgs=(BSP_ARGS*)IMAGE_SHARE_ARGS_UA_START;

    OALMSG(1, (TEXT("++OALIoCtlHalCheckLPAudio(bLPAudioEn=%d)\r\n"),pArgs->bLPAudioEn));
    if (lpBytesReturned)
    {
        *lpBytesReturned = 0;
    }  

    if (lpInBuf == NULL)
    {
        dwErr = ERROR_INVALID_PARAMETER;
    }
    else if (sizeof(BOOL) > nInBufSize)
    {
        dwErr = ERROR_INSUFFICIENT_BUFFER;
    }
    else
    {
        __try
        {
            pArgs->bLPAudioEn = *(BOOL*)lpInBuf;
        }
        __except (EXCEPTION_EXECUTE_HANDLER)
        {
            dwErr = ERROR_INVALID_PARAMETER;
        }
    }

    if (dwErr)
    {
        OALMSG(OAL_ERROR, (TEXT("[OAL:ERR] v() Failed dwErr = 0x%08x\r\n"), dwErr));
        NKSetLastError(dwErr);
    }
    OALMSG(1, (TEXT("--OALIoCtlHalCheckLPAudio(bLPAudioEn=%d)\r\n"),pArgs->bLPAudioEn));

    return !dwErr;
}

BOOL OALIoCtlHalQueryDriverLog(
    UINT32 code, VOID *lpInBuf, UINT32 nInBufSize, VOID *lpOutBuf,
    UINT32 nOutBufSize, UINT32 *pOutSize)
{
	OALMSG(OAL_IOCTL&&OAL_OEM_FUNC, (TEXT("OALIoCtlHalQueryDriverLog\r\n")));

    if (lpInBuf || nInBufSize || !lpOutBuf || (nOutBufSize != sizeof(BOOL)))
    {
		OALMSG(OAL_WARN, (TEXT("OALIoCtlHalQueryDriverLog: wrong arg size!\r\n")));
        NKSetLastError(ERROR_INVALID_PARAMETER);
		return FALSE;
    }
    else
    {
		BOOL  *pfEnableDrvmask  = (BOOL*)lpOutBuf;
		OALMSG(OAL_DEBUG, (TEXT("OALArgsQuery(OAL_ARGS_QUERY_DRVMASKENABLE)!\r\n")));
		*pfEnableDrvmask = *((BOOL *) OALArgsQuery(OAL_ARGS_QUERY_DRVMASKENABLE));
    }

	return TRUE;
}

BOOL OALIoCtlHalQueryDriverMask(
    UINT32 code, VOID *lpInBuf, UINT32 nInBufSize, VOID *lpOutBuf,
    UINT32 nOutBufSize, UINT32 *pOutSize)
{
	if (lpInBuf || nInBufSize || !lpOutBuf || (nOutBufSize < (sizeof(DWORD)*12)))	//12 = DRVLOG_PART_NUM
	{
		OALMSG(OAL_WARN, (TEXT("OALIoCtlHalQueryDriverMask: wrong arg size!\r\n")));
        NKSetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
	} else	
    {
		UCHAR *cp = lpOutBuf, *ap;
		ap = (UCHAR *) OALArgsQuery(OAL_ARGS_QUERY_DRVMASK);
		memcpy(cp, ap, nOutBufSize);

		if(pOutSize)
		  *pOutSize = sizeof(DWORD)*12;	//12 = DRVLOG_PART_NUM

		OALMSG(OAL_IOCTL&&OAL_OEM_FUNC, (TEXT("OALIoCtlHalQueryDriverMask\r\n")));
    }
	
	return TRUE;
}

BOOL OALIoCtlHalGetSystemClock(    
    UINT32 code, VOID *lpInBuf, UINT32 nInBufSize, VOID *lpOutBuf,
    UINT32 nOutBufSize, UINT32 *pOutSize)
{
	if (lpInBuf || nInBufSize || !lpOutBuf || (nOutBufSize < (sizeof(SYSTEM_CLOCK))))	
	{
		OALMSG(OAL_WARN, (TEXT("OALIoCtlHalGetSystemClock: wrong arg size!\r\n")));
        NKSetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
	} else	
    {
		SYSTEM_CLOCK *dstSystemClock = (SYSTEM_CLOCK*)lpOutBuf;
        SYSTEM_CLOCK *srcSystemClock;
		srcSystemClock = (SYSTEM_CLOCK *) OALArgsQuery(OAL_ARGS_QUERY_SYSTEMCLOCKS);
        
		memcpy(dstSystemClock, srcSystemClock, nOutBufSize);
		
		OALMSG(OAL_IOCTL&&OAL_OEM_FUNC, (TEXT("OALIoCtlHalGetSystemClock\r\n")));
    }
    
        return TRUE;
		
}


BOOL OALIoCtlHalChangeDriverMask(
    UINT32 code, VOID *lpInBuf, UINT32 nInBufSize, VOID *lpOutBuf,
    UINT32 nOutBufSize, UINT32 *pOutSize)
{
	OALMSG(OAL_IOCTL&&OAL_OEM_FUNC, (TEXT("OALIoCtlHalChangeDriverMask\r\n")));

    if (!lpInBuf || (nInBufSize < (sizeof(DWORD)*12)) || lpOutBuf || nOutBufSize)
    {
		OALMSG(OAL_WARN, (TEXT("OALIoCtlHalChangeDriverMask: wrong arg size!\r\n")));
		OALMSG(OAL_WARN, (TEXT("size InBufSize = %d\r\n"),sizeof(DWORD)*12));
        NKSetLastError(ERROR_INVALID_PARAMETER);
		return FALSE;
    }
    else
    {
    	OALMSG(OAL_DEBUG, (TEXT("CALL OALArgsChange!!!\r\n")));
		OALArgsChange(lpInBuf, nInBufSize);
    }

	return TRUE;
}

CRITICAL_SECTION csPocketStoreBML;

BOOL OALIoCtlGetEbootCfg(UINT32 code,VOID *pInpBuffer,UINT32 inpSize,VOID *pOutBuffer,UINT32 outSize,UINT32 *pOutSize)
{

	UINT32			nVol = 0;
	UINT32          nStartVsn;
#ifdef BSP_POCKETSTORE    
	FSRPartEntry    pstPartEntry;
	FSRVolSpec      pstVolSpec;
    UINT32          n1stVpn = 0;
    UINT32          nPgsPerUnit;    
#endif    

	UINT8			pData[2048];

	UINT32          nBlkNum;
	UINT32			nRet;	
	PTOC    		pBootCfg;
    UINT32          i;

    if ( !pOutBuffer )
    {
        NKSetLastError(ERROR_INSUFFICIENT_BUFFER);
		OALMSG(OAL_ERROR, (_T("OALIoCtlGetEbootCfg :: Invlid Buffer!!\r\n")));
        goto ClearReturn;
    }

	pBootCfg = (PTOC)pData;
#ifdef BSP_POCKETSTORE
	OALMSG(OAL_IOCTL&&OAL_OEM_FUNC, (_T("OALIoCtlGetEbootCfg ++\r\n")));
	EnterCriticalSection(&csPocketStoreBML);
	
    nRet = FSR_BML_Init(FSR_BML_FLAG_NONE);
    if (nRet != FSR_BML_SUCCESS && nRet != FSR_BML_ALREADY_INITIALIZED)
    {
        OALMSG(OAL_ERROR, (_T("FSR_BML_Init error\r\n")));
        goto ClearReturn;
    }
    
    /* Open Device */
    nRet = FSR_BML_Open(nVol,FSR_BML_FLAG_NONE);    
    if (nRet!=FSR_BML_SUCCESS)
    {
        OALMSG(OAL_ERROR, (TEXT("FMD_GetInfo : FSR_BML_Open is failed 0x%x.\r\n"), nRet));
        goto ClearReturn; 
    }
    
	// get volume info
	if(FSR_BML_GetVolSpec(0,&pstVolSpec,FSR_BML_FLAG_NONE) != FSR_BML_SUCCESS)
    {
	    OALMSG(OAL_ERROR, (_T("Faild to get voulume info....\r\n")));
	    goto ClearReturn;
	}

    // get partition info
  	if(FSR_BML_LoadPIEntry(0, FSR_PARTID_EBOOTCFG, &n1stVpn, &nPgsPerUnit, &pstPartEntry) != FSR_BML_SUCCESS)
	{
	    OALMSG(OAL_ERROR, (_T("Faild to get partition info....\r\n")));
	    goto ClearReturn;
	}

	nStartVsn   = pstPartEntry.n1stVun    * (pstVolSpec.nPgsPerSLCUnit) * (pstVolSpec.nSctsPerPg >> 2);     // 4 sector = 1 page (2KB)

	nBlkNum		= pstPartEntry.n1stVun;
	
	OALMSG(OAL_IOCTL&&OAL_DEBUG, (_T("OALIoCtlGetEbootCfg :: nStartVsn = 0x%x, nBlkNum = 0x%x\r\n"), nStartVsn, nBlkNum));

	// Read config block
    if (FSR_BML_Read(0, nStartVsn, 1, pData, NULL, FSR_BML_FLAG_ECC_ON) != FSR_BML_SUCCESS) {
		OALMSG(OAL_ERROR, (_T("OALIoCtlGetEbootCfg : Failed to read bootcfg ...\r\n")));
        goto ClearReturn;
    }
    
    if (FSR_BML_Close(0, FSR_BML_FLAG_NONE) != FSR_BML_SUCCESS) 
    {
        OALMSG(OAL_ERROR, (_T("OALIoCtlGetEbootCfg : Failed to FSR_BML_Close ...\r\n")));
        goto ClearReturn;
    }
        
    /*
    // For Debugging
    OALMSG(OAL_IOCTL&&OAL_DEBUG, (_T("OALIoCtlGetEbootCfg :: Magic Number ==> 0x%x\r\n"), pBootCfg->BootCfg.ConfigMagicNumber ));
    OALMSG(OAL_IOCTL&&OAL_DEBUG, (_T("OALIoCtlGetEbootCfg :: dwSignature ==> 0x%x\r\n"), pBootCfg->dwSignature ));
    
    RETAILMSG(1, (TEXT("\r\n =============================================================")));
	for (i=0;i<4096;i++)
	{
		if ((i%16)==0)
			RETAILMSG(1, (TEXT("\r\n 0x%04x_%04x |"), (i + 0x800*nStartVsn)>>16, (i + 0x800*nStartVsn)&0xffff));
		
		RETAILMSG(1, (TEXT(" %02x"), pData[i]));

		if ((i%512)==511)
			RETAILMSG(1, (TEXT("\r\n -------------------------------------------------------------")));
	}
    */
	memcpy(pOutBuffer, &pData, sizeof(TOC));

	if (pOutSize)
	{
		*pOutSize = sizeof(TOC);
	}
	
	LeaveCriticalSection(&csPocketStoreBML);
#endif    
	OALMSG(OAL_IOCTL&&OAL_OEM_FUNC, (_T("OALIoCtlGetEbootCfg --\r\n")));
	return TRUE;

ClearReturn:
	LeaveCriticalSection(&csPocketStoreBML);
	OALMSG(OAL_ERROR, (_T("OALIoCtlGetEbootCfg Failed\r\n")));
	return FALSE;


}

BOOL OALIoCtlSetEbootCfg(UINT32 code, VOID *pInpBuffer,UINT32 inpSize,VOID *pOutBuffer,UINT32 outSize,UINT32 *pOutSize)
{

	UINT32			nVol = 0;
    UINT32          n1stVpn = 0;
    UINT32          nPgsPerUnit;     
	UINT32          nStartVsn;
#ifdef BSP_POCKETSTORE
	FSRPartEntry    pstPartEntry;
	FSRVolSpec      pstVolSpec;
#endif 
	UINT32          nBlkNum;
	UINT32			nRet;	
	PTOC		pBootCfg;
   
    if(!pInpBuffer )
    {
        NKSetLastError(ERROR_INSUFFICIENT_BUFFER);
		OALMSG(OAL_ERROR, (_T("OALIoCtlSetEbootCfg :: Invlid Buffer!!\r\n")));
        goto ClearReturn;
    }

	pBootCfg = (PTOC)pInpBuffer;
#ifdef BSP_POCKETSTORE
	OALMSG(OAL_IOCTL&&OAL_OEM_FUNC, (_T("OALIoCtlSetEbootCfg :: Magic Number ==> 0x%x  0x%x\r\n"), pBootCfg->dwSignature, TOC_SIGNATURE ));

	if ( pBootCfg->dwSignature != TOC_SIGNATURE && pBootCfg->dwSignature != 0x434F544E)
	{
		OALMSG(OAL_ERROR, (TEXT("OALIoCtlSetEbootCfg :: Invalid Eboot Config Setting!! Incorrect Magic Number!!==> 0x%x  0x%x\r\n"), pBootCfg->dwSignature, TOC_SIGNATURE));
		goto ClearReturn;
	}		
	
	OALMSG(OAL_IOCTL&&OAL_OEM_FUNC, (_T("OALIoCtlSetEbootCfg ++\r\n")));
	EnterCriticalSection(&csPocketStoreBML);

    nRet = FSR_BML_Init(FSR_BML_FLAG_NONE);
    if (nRet != FSR_BML_SUCCESS && nRet != FSR_BML_ALREADY_INITIALIZED)
    {
        OALMSG(OAL_ERROR, (_T("FSR_BML_Init error\r\n")));
        goto ClearReturn;
    }
    
    /* Open Device */
    nRet = FSR_BML_Open(nVol,FSR_BML_FLAG_NONE);    
    if (nRet!=FSR_BML_SUCCESS)
    {
        OALMSG(OAL_ERROR, (TEXT("FMD_GetInfo : FSR_BML_Open is failed 0x%x.\r\n"), nRet));
        goto ClearReturn;
    }
    
	// get volume info
	if(FSR_BML_GetVolSpec(0,&pstVolSpec,FSR_BML_FLAG_NONE) != FSR_BML_SUCCESS)
    {
	    OALMSG(OAL_ERROR, (_T("Faild to get voulume info....\r\n")));
	    goto ClearReturn;
	}

    // get partition info
  	if(FSR_BML_LoadPIEntry(0, FSR_PARTID_EBOOTCFG, &n1stVpn, &nPgsPerUnit, &pstPartEntry) != FSR_BML_SUCCESS)
	{
	    OALMSG(OAL_ERROR, (_T("Faild to get partition info....\r\n")));
	    goto ClearReturn;
	}
    
	nStartVsn   = pstPartEntry.n1stVun    * (pstVolSpec.nPgsPerSLCUnit) * (pstVolSpec.nSctsPerPg >> 2);     // 4 sector = 1 page (2KB)

	nBlkNum		= pstPartEntry.n1stVun;

	OALMSG(OAL_IOCTL&&OAL_DEBUG, (_T("OALIoCtlSetEbootCfg :: nStartVsn = 0x%x, nBlkNum = 0x%x\r\n"), nStartVsn, nBlkNum));

	// Erase config block
    if (FSR_BML_Erase(0,(UINT32 *)&nBlkNum, 1, FSR_BML_FLAG_NONE)!=FSR_BML_SUCCESS) {
		OALMSG(OAL_ERROR, (_T("OALIoCtlSetEbootCfg : Failed to erase bootcfg block ...\r\n")));
		goto ClearReturn;
    }
    
	// Write Bootblock
    if (FSR_BML_Write(0, nStartVsn, 1, (PUCHAR)pBootCfg, NULL, FSR_BML_FLAG_ECC_ON)!=FSR_BML_SUCCESS) {
		OALMSG(OAL_ERROR, (_T("OALIoCtlSetEbootCfg : Failed to write bootcfg ...\r\n")));
		goto ClearReturn;
    }
    
    if (FSR_BML_Close(0, FSR_BML_FLAG_NONE) != FSR_BML_SUCCESS) 
    {
        OALMSG(OAL_ERROR, (_T("OALIoCtlSetEbootCfg : Failed to FSR_BML_Close ...\r\n")));
        goto ClearReturn;
    }   
    
	LeaveCriticalSection(&csPocketStoreBML);
#endif
	OALMSG(OAL_IOCTL&&OAL_OEM_FUNC, (_T("OALIoCtlSetEbootCfg --\r\n")));
	return TRUE;

ClearReturn:
	LeaveCriticalSection(&csPocketStoreBML);
	OALMSG(OAL_ERROR, (_T("OALIoCtlSetEbootCfg Failed\r\n")));
	return FALSE;

}


//------------------------------------------------------------------------------
//
//  Global: g_oalIoCtlTable[]
//
//  IOCTL handler table. This table includes the IOCTL code/handler pairs
//  defined in the IOCTL configuration file. This global array is exported
//  via oal_ioctl.h and is used by the OAL IOCTL component.
//
const OAL_IOCTL_HANDLER g_oalIoCtlTable[] = {
#include "ioctl_tab.h"
};

//------------------------------------------------------------------------------

