fmd.cpp
资源名称:SMDK2440.rar [点击查看]
上传用户:qiulin1960
上传日期:2013-10-16
资源大小:2844k
文件大小:38k
源码类别:
Windows CE
开发平台:
Windows_Unix
- /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
- ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
- PARTICULAR PURPOSE.
- Copyright (c) 2002 Microsoft Corporation
- Module Name: FMD.CPP
- Abstract: FLASH Media Driver Interface Samsung K9F2808UOB NAND Flash Chip
- on AT-Rise development board.
- Notes: Currently, *only* the CE 3.0 (and earlier) power management logic
- is implemented (i.e. the PowerUp() and PowerDown() APIs).
- Environment: As noted, this media driver works on behalf of the FAL to directly
- access the underlying FLASH hardware. Consquently, this module
- needs to be linked with FAL.LIB to produce the device driver
- named FLASHDRV.DLL.
- -----------------------------------------------------------------------------*/
- #include <fmd.h>
- //#ifdef CEDAR_ONLY
- #ifndef NOSYSCALL
- // #include "utldrv.h"
- #include <nkintr.h>
- #include "oalintr.h"
- #endif
- //#endif // CEDAR_ONLY
- #ifdef NOBINFS
- #include "utldrv.h" // Still needed for driver->driver fast method calling in 4.x
- #endif
- #include <s2440.h>
- #include "cfnand.h"
- #include "loader.h"
- #ifndef NOSYSCALL
- #ifndef BOOT_LOADER
- // #define USENANDDMA 1
- // #define USESETKMODE 1
- // #define NAND_BUFFER_LENG 512
- #endif
- #endif
- #ifdef NOBINFS
- //#ifdef CEDAR_ONLY // Still needed in 4.x
- // Globals
- HANDLE g_hUTLObject = NULL;
- UTL_FASTCALL g_tblFastCall;
- //#endif // CEDAR_ONLY
- #endif
- // Globals needed for updatexip
- HANDLE g_hMutex = NULL;
- // BUGBUG: For now, we always will take the mutex
- BOOL g_bTakeMutex = TRUE;
- void GRABMUTEX();
- void RELEASEMUTEX();
- #ifdef NOSYSCALL
- #ifndef BOOT_LOADER
- // function prototypes for kernel functions
- extern "C"
- {
- HANDLE SC_CreateMutex(LPSECURITY_ATTRIBUTES lpsa, BOOL bInitialOwner, LPCTSTR lpName);
- DWORD SC_WaitForMultiple(DWORD cObjects, CONST HANDLE *lphObjects, BOOL fWaitAll, DWORD dwTimeout);
- BOOL SC_ReleaseMutex(HANDLE hMutex);
- BOOL SC_CloseHandle(HANDLE hObj);
- }
- #endif
- #endif
- // Use Macros here to avoid extra over head for c function calls
- #define READ_REGISTER_BYTE(p) (*(volatile PBYTE) (p))
- #define WRITE_REGISTER_BYTE(p, v) (*(volatile PBYTE)(p)) = (v)
- #define READ_REGISTER_USHORT(p) (*(volatile PUSHORT) (p))
- #define WRITE_REGISTER_USHORT(p, v) (*(volatile PUSHORT)(p)) = (v)
- #define READ_REGISTER_ULONG(p) (*(volatile PULONG) (p))
- #define WRITE_REGISTER_ULONG(p, v) (*(volatile PULONG)(p)) = (v)
- // Registers
- volatile PUSHORT pNFReg;
- volatile PUSHORT pNFCONF;
- volatile PUSHORT pNFCONT;
- volatile PUSHORT pNFCMD;
- volatile PUSHORT pNFADDR;
- volatile PULONG pNFDATA;
- volatile PUSHORT pNFSTAT;
- volatile PULONG pNFECC;
- volatile CLKPWRreg *v_s2440CLKPWR;
- volatile DMAreg *v_pDMAregs;
- volatile INTreg *v_pINTregs;
- #define NFDATA 0x4E000010
- // Event
- HANDLE gDMA3IntrEvent;
- PBYTE pDMABuffer;
- // Status bit pattern
- #define STATUS_READY 0x40
- #define STATUS_ERROR 0x01
- // HCLK=133Mhz
- #define TACLS 0
- #define TWRPH0 6
- #define TWRPH1 2
- // MACROS
- #define NF_CE_L() WRITE_REGISTER_USHORT(pNFCONT, (USHORT) (READ_REGISTER_USHORT(pNFCONT) & ~(1<<1)))
- #define NF_CE_H() WRITE_REGISTER_USHORT(pNFCONT, (USHORT) (READ_REGISTER_USHORT(pNFCONT) | (1<<1)))
- #define NF_CMD(cmd) WRITE_REGISTER_USHORT(pNFCMD, (USHORT) (cmd))
- #define NF_ADDR(addr) WRITE_REGISTER_USHORT(pNFADDR, (USHORT) (addr))
- #define NF_DATA_R() READ_REGISTER_BYTE(pNFDATA)
- #define NF_DATA_W(val) WRITE_REGISTER_BYTE(pNFDATA, (BYTE) (val))
- #define NF_DATA_R4() READ_REGISTER_ULONG(pNFDATA)
- #define NF_DATA_W4(val) WRITE_REGISTER_ULONG(pNFDATA, (ULONG) (val))
- #define NF_STAT() READ_REGISTER_USHORT(pNFSTAT)
- #define NF_MECC_UnLock() WRITE_REGISTER_USHORT(pNFCONT, (USHORT) (READ_REGISTER_USHORT(pNFCONT) & ~(1<<5)))
- #define NF_MECC_Lock() WRITE_REGISTER_USHORT(pNFCONT, (USHORT) (READ_REGISTER_USHORT(pNFCONT) | (1<<5)))
- #define NF_RSTECC() WRITE_REGISTER_USHORT(pNFCONT, (USHORT) (READ_REGISTER_USHORT(pNFCONT) | (1<<4)))
- #define NF_WAITRB() {while(!(NF_STAT() & (1<<1))) ;}
- #define NF_CLEAR_RB() WRITE_REGISTER_USHORT(pNFSTAT, (USHORT) (READ_REGISTER_USHORT(pNFSTAT) | (1<<2)))
- #define NF_DETECT_RB() {while(!(NF_STAT() & (1<<2)));}
- #define NF_ECC() READ_REGISTER_ULONG(pNFECC)
- // External function
- extern "C" {
- BOOL ECC_CorrectData(LPBYTE pData, LPBYTE pExistingECC, LPBYTE pNewECC);
- }
- // Flags and pointers
- #define BADBLOCKMARK 0x00
- // VALIDADDR is 5 << 8
- //
- // Explain: 5 means the 6th byte in spare area (517 byte in the sector)
- // Shift 8 bit to the left to form the correct address for 16bit port
- //
- #define VALIDADDR 0x05
- #define OEMADDR 0x04 // 5th byte in spare area
- #ifdef CEDAR_ONLY
- void PowerOnCallback()
- {
- DEBUGMSG(1, (TEXT("FlashDrv::FMD:: Come back form Power Off!n")));
- }
- #endif // CEDAR_ONLY
- // Reset the chip
- //
- void NF_Reset()
- {
- int i;
- GRABMUTEX();
- NF_CE_L();
- NF_CLEAR_RB();
- NF_CMD(CMD_RESET);
- for(i=0;i<10;i++); //tWB = 100ns. //??????
- NF_CE_H();
- RELEASEMUTEX();
- }
- /*
- Here is the statement from SamSung's K9F2808U0B datasheet:
- All device locations are erased (FFh) except location where the invalid block(s)
- information is written prior to shipping. The invalid block(s) status is defined
- by the 6th byte in the spare area. Samsung makes sure that either the 1st or 2nd
- page of every invalid block has non-FFh data at the column address of 517. Since
- the invalid block information is also erasable in most cases, it is impossible to
- recover the information once it has been erased.
- Here is the logic we are taking:
- If the block is invalid, non-FFh value in column address of 517, we don't use that
- block anyway. Otherwise, the whole spare area is subject to use by our program. If
- we found additional bad block later on, we don't necessary have to use column 517
- to represent invalid block. We could use any of the 16 byte spare area.
- But for simplicity, in our current implementation, we avoid to touch column 517. So
- the we allocate SectorInfo as following:
- - - - - - - - - - - - - - - - -
- |R|R|R|R|O|V|R|R|E|E|E|E|E|E|E|E|
- - - - - - - - - - - - - - - - -
- Where Rs are reserved bytes used by the FAL
- O is a byte for use by the OEM
- V is a byte indicating if the block is valid (a.k.a. bad)
- Es are bytes used for ECC
- */
- /*
- * NAND_ReadSectorInfo
- *
- * Read SectorInfo out of the spare area. The current implementation only handles
- * one sector at a time.
- */
- void NAND_ReadSectorInfo(SECTOR_ADDR sectorAddr, PSectorInfo pInfo)
- {
- // RETAILMSG(1, (TEXT("FlashDrv!FMD!NAND_ReadSectorInfo: rn")));
- GRABMUTEX();
- // Chip enable
- NF_CE_L();
- NF_CLEAR_RB();
- // Write the command
- NF_CMD(CMD_READ2);
- // Write the address
- NF_ADDR(0x00);
- NF_ADDR(sectorAddr & 0xff);
- NF_ADDR((sectorAddr >> 8) & 0xff);
- if (NEED_EXT_ADDR) {
- NF_ADDR((sectorAddr >> 16) & 0xff);
- }
- // RETAILMSG(1, (TEXT("sectorAddr : %x rn"), sectorAddr));
- // Wait for the Ready bit
- NF_DETECT_RB(); // Wait tR(max 12us)
- // Read the SectorInfo data (we only need to read first 8 bytes)
- pInfo->dwReserved1 = NF_DATA_R4();
- // RETAILMSG(1, (TEXT("pInfo->dwReserved1 = %xrn"), pInfo->dwReserved1));
- // OEM byte
- pInfo->bOEMReserved = (BYTE) NF_DATA_R();
- // RETAILMSG(1, (TEXT("pInfo->bOEMReserved = %xrn"), pInfo->bOEMReserved));
- // Read the bad block mark
- pInfo->bBadBlock = (BYTE) NF_DATA_R();
- // RETAILMSG(1, (TEXT("pInfo->bBadBlock = %xrn"), pInfo->bBadBlock));
- // Second reserved field (WORD)
- pInfo->wReserved2 = ((BYTE) NF_DATA_R() << 8);
- pInfo->wReserved2 |= ((BYTE) NF_DATA_R());
- // RETAILMSG(1, (TEXT("pInfo->wReserved2 = %xrn"), pInfo->wReserved2));
- // RETAILMSG(1, (TEXT("rn")));
- NF_CE_H();
- RELEASEMUTEX();
- }
- /*
- * NAND_WriteSectorInfo
- *
- * Write SectorInfo out to the spare area. The current implementation only handles
- * one sector at a time.
- */
- BOOL NAND_WriteSectorInfo(SECTOR_ADDR sectorAddr, PSectorInfo pInfo)
- {
- BOOL bRet = TRUE;
- // RETAILMSG(1, (TEXT("FlashDrv!FMD!NAND_WriteSectorInfo: rn")));
- GRABMUTEX();
- // Chip enable
- NF_CE_L();
- NF_CLEAR_RB();
- // Write the command
- // First, let's point to the spare area
- NF_CMD(CMD_READ2);
- NF_CMD(CMD_WRITE);
- // Write the address
- NF_ADDR(0x00);
- NF_ADDR(sectorAddr & 0xff);
- NF_ADDR((sectorAddr >> 8) & 0xff);
- if (NEED_EXT_ADDR) {
- NF_ADDR((sectorAddr >> 16) & 0xff);
- }
- // Now let's write the SectorInfo data
- //
- // Write the first reserved field (DWORD)
- NF_DATA_W4( pInfo->dwReserved1 );
- // Write OEM reserved flag
- NF_DATA_W( (pInfo->bOEMReserved) );
- // Write the bad block flag
- NF_DATA_W( (pInfo->bBadBlock) );
- // Write the second reserved field
- NF_DATA_W( (pInfo->wReserved2 >> 8) & 0xff );
- NF_DATA_W( (pInfo->wReserved2) );
- // Issue the write complete command
- NF_CMD(CMD_WRITE2);
- // Check ready bit
- NF_DETECT_RB(); // Wait tR(max 12us)
- // Check the status of program
- NF_CMD(CMD_STATUS);
- if(NF_DATA_R() & STATUS_ERROR) {
- RETAILMSG(1, (TEXT("NAND_WriteSectorInfo() ######## Error Programming page %d!n"), sectorAddr));
- bRet = FALSE;
- }
- NF_CE_H();
- RELEASEMUTEX();
- return bRet;
- }
- /*-----------------------------------------------------------------------------
- * FMD Interface functions
- *
- *----------------------------------------------------------------------------*/
- // FMD_Init
- //
- // Initialize the flash chip
- //
- // Note: Presently, the Flash size characteristics are hardcoded in CFNAND.H
- // and are NOT stored in the registry. Refer to the StratFlash FMD in
- // %WINCEROOT%PUBLICCOMMONOAKDRIVERSBLOCK... for an example of how
- // to use the registry for storing this information.
- //
- PVOID FMD_Init(LPCTSTR lpActiveReg, PPCI_REG_INFO pRegIn, PPCI_REG_INFO pRegOut)
- {
- RETAILMSG(1, (TEXT("FMD::FMD_Initrn")));
- // 0. Create the Mutex for shared access between the kernel and MSFLASH
- #ifndef BOOT_LOADER
- if (g_hMutex == NULL)
- {
- #ifdef NOSYSCALL
- #ifndef BOOT_LOADER
- g_hMutex = SC_CreateMutex(NULL, FALSE, TEXT("_FLASH_MUTEX_"));
- #endif
- #else
- g_hMutex = CreateMutex(NULL, FALSE, TEXT("_FLASH_MUTEX_"));
- #endif
- // was mutex creation successful?
- if (g_hMutex == NULL)
- {
- RETAILMSG(1,(TEXT("FlashDrv!FMD!FMD_Init: Unable to create mutexrn")));
- goto ErrExit;
- }
- }
- #endif
- #ifndef NOSYSCALL
- #ifdef NOBINFS
- DWORD dwBytes;
- // Initialize the FASTCALL structure to 0
- memset(&g_tblFastCall, 0, sizeof(UTL_FASTCALL));
- // 1. CreateFile to get the access to UTLDRV.
- //
- g_hUTLObject = CreateFile(TEXT("UTL0:"), GENERIC_READ|GENERIC_WRITE,
- FILE_SHARE_READ|FILE_SHARE_WRITE,
- NULL, OPEN_EXISTING, 0, 0);
- if(INVALID_HANDLE_VALUE == g_hUTLObject) {
- RETAILMSG(1, (TEXT("Failed CreateFile -- error = 0x%xn"), GetLastError()));
- goto ErrExit;
- }
- // 2. Call IOCTL to get the FAST CALL function pointer.
- //
- if(!DeviceIoControl(g_hUTLObject,
- IOCTL_UTL_GET_FASTCALL,
- NULL, 0,
- &g_tblFastCall, sizeof(g_tblFastCall),
- &dwBytes, NULL)) {
- RETAILMSG(1, (TEXT("Failed DeviceIoControl -- error = 0x%xn"), GetLastError()));
- goto ErrExit;
- }
- // 3. Call the fast call to get the PVA for the registers
- //
- // 3.1 Get the register for NAND controller
- if (ERROR_SUCCESS != g_tblFastCall.GetRegisterVA(g_tblFastCall.pContext, NFC_BASE,
- 32, FALSE, (DWORD *)&pNFReg) ) {
- RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_Init: Failed GetRegisterVA(NFC_BASE) call!n")));
- goto ErrExit;
- }
- // 3.2 Get the register for the CLKPWR register
- if (ERROR_SUCCESS != g_tblFastCall.GetRegisterVA(g_tblFastCall.pContext, CLKPWR_BASE,
- 32, FALSE, (DWORD *)&v_s2440CLKPWR) ) {
- RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_Init: Failed GetRegisterVA(CLKPWR_BASE) call!n")));
- goto ErrExit;
- }
- #ifdef CEDAR_ONLY
- // ++ CE 3.0 Specific Code. Not needed for 4.x +
- // 4. Register the Block driver to the Power On Monitor
- //
- if (ERROR_SUCCESS != g_tblFastCall.RegisterBlockDrv(g_tblFastCall.pContext,
- PowerOnCallback)) {
- RETAILMSG(1, (TEXT("Failed RegisterStorageDrv -- error = 0x%xn"), GetLastError()));
- goto ErrExit;
- }
- // -- CE 3.0 Specific Code. Not needed for 4.x +
- #endif // CEDAR_ONLY
- #else
- // RETAILMSG(1, (TEXT("FMD::FMD_Init:VirtualAlloc rn")));
- pNFReg = (PUSHORT) VirtualAlloc(0, 0x1000, MEM_RESERVE, PAGE_NOACCESS);
- if(!pNFReg) {
- RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_Init: Failed VirtualAlloc ... Bailing out!n")));
- goto ErrExit;
- }
- if(!VirtualCopy(pNFReg, (LPVOID) NFC_BASE, 0x1000,
- PAGE_READWRITE|PAGE_NOCACHE)) {
- RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_Init: Failed VirtualCopy for MemCtrl!n")));
- goto ErrExit;
- }
- // Allocate for the clock control register
- // Clock control register
- v_s2440CLKPWR = (CLKPWRreg *)VirtualAlloc(NULL, 0x1000, MEM_RESERVE, PAGE_NOACCESS);
- ASSERT(v_s2440CLKPWR);
- if (!VirtualCopy((LPVOID) v_s2440CLKPWR, (LPVOID) CLKPWR_BASE, 0x1000,
- PAGE_READWRITE | PAGE_NOCACHE)) {
- RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_Init: VirtualCopy (v_s2440CLKPWR) failed!rn")));
- goto ErrExit;
- }
- #ifdef USENANDDMA
- // From HMSEO
- // DMA Virtual alloc
- v_pDMAregs = (volatile DMAreg *) VirtualAlloc(0,sizeof(DMAreg),MEM_RESERVE, PAGE_NOACCESS);
- ASSERT(v_pDMAregs);
- if(!VirtualCopy((PVOID)v_pDMAregs,(PVOID)(DMA_BASE),sizeof(DMAreg),
- PAGE_READWRITE | PAGE_NOCACHE )) {
- ERRORMSG(1,(TEXT("For s2440DMA: VirtualCopy failed!rn")));
- goto ErrExit;
- }
- // Allocate DMA buffer
- pDMABuffer = (unsigned char *)VirtualAlloc(0, NAND_BUFFER_LENG, MEM_RESERVE, PAGE_NOACCESS);
- ASSERT(pDMABuffer);
- if(!VirtualCopy(pDMABuffer,
- (PVOID)NAND_DMA_BUFFER_BASE,
- NAND_BUFFER_LENG,
- PAGE_READWRITE | PAGE_NOCACHE) )
- {
- ERRORMSG(1,(TEXT("For s2440DMA: DMABuffer VirtualCopy failed!rn")));
- goto ErrExit;
- }
- #ifndef USESETKMODE
- // allocate the interrupt event for DMA
- gDMA3IntrEvent = CreateEvent(NULL, FALSE, FALSE,NULL);
- if (NULL == gDMA3IntrEvent) {
- ERRORMSG(1,(TEXT("For s2440DMA: CreateEvent failed!rn")));
- goto ErrExit;
- }
- if (!InterruptInitialize (SYSINTR_DMA3, gDMA3IntrEvent,NULL,0)) {
- ERRORMSG(1,(TEXT("For s2440DMA: InterruptInitialize failed!rn")));
- goto ErrExit;
- }
- #else
- v_pINTregs = (volatile INTreg *) VirtualAlloc(0,sizeof(INTreg),MEM_RESERVE, PAGE_NOACCESS);
- ASSERT(v_pINTregs);
- if(!VirtualCopy((PVOID)v_pINTregs,(PVOID)(INT_BASE),sizeof(INTreg),
- PAGE_READWRITE | PAGE_NOCACHE ))
- {
- ERRORMSG(1,(TEXT("For INTreg: VirtualCopy failed!rn")));
- goto ErrExit;
- }
- #endif USESETKMODE
- // End HMSEO
- #endif USENANDDMA
- #endif // NOBINFS
- #else
- pNFReg = (PUSHORT) (NFC_BASE | 0x20000000);
- v_s2440CLKPWR = (CLKPWRreg *) ( CLKPWR_BASE | 0x20000000 );
- #endif
- // Enable the clock to NAND controller
- v_s2440CLKPWR->rCLKCON |= (1<<4);
- // RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_Init: pNFReg = %x rn"), pNFReg));
- pNFCONF = pNFReg;
- pNFCONT = (PUSHORT) ((PBYTE) pNFReg + 0x04);
- pNFCMD = (PUSHORT) ((PBYTE) pNFReg + 0x08);
- pNFADDR = (PUSHORT) ((PBYTE) pNFReg + 0x0C);
- pNFDATA = (PULONG) ((PBYTE) pNFReg + 0x10);
- pNFSTAT = (PUSHORT) ((PBYTE) pNFReg + 0x20);
- pNFECC = (PULONG) ((PBYTE) pNFReg + 0x2C);
- // Now we need enable the NAND Flash controller
- GRABMUTEX();
- WRITE_REGISTER_USHORT(pNFCONF, (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0));
- WRITE_REGISTER_USHORT(pNFCONT, (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(1<<1)|(1<<0));
- WRITE_REGISTER_USHORT(pNFSTAT, 0);
- RELEASEMUTEX();
- // NF_Reset();
- RETAILMSG(1, (TEXT("FMD::FMD_Init Donern")));
- return (PVOID)pNFCONF;
- ErrExit:
- FMD_Deinit((PVOID)pNFCONF);
- return 0;
- }
- // FMD_Deinit
- //
- // De-initialize the flash chip
- //
- BOOL FMD_Deinit(PVOID hFMD)
- {
- if((DWORD)hFMD != (DWORD)pNFCONF)
- {
- return FALSE;
- }
- // destroy the mutex
- if (g_hMutex)
- {
- #ifdef NOSYSCALL
- #ifndef BOOT_LOADER
- SC_CloseHandle(g_hMutex);
- #endif
- #else
- CloseHandle(g_hMutex);
- #endif
- }
- #ifndef NOSYSCALL
- #ifdef NOBINFS
- // We don't have to free pNFReg and clock register.
- #ifdef CEDAR_ONLY
- // ++ CE 3.0 Specific Code. Not needed for 4.x +
- if (g_tblFastCall.UnRegisterBlockDrv) {
- g_tblFastCall.UnRegisterBlockDrv(g_tblFastCall.pContext, PowerOnCallback);
- }
- // -- CE 3.0 Specific Code. Not needed for 4.x +
- #endif // CEDAR_ONLY
- // Close the handle
- if (g_hUTLObject) {
- CloseHandle(g_hUTLObject);
- }
- #else
- if(pNFReg) {
- VirtualFree(pNFReg, 0, MEM_RELEASE);
- }
- if(v_s2440CLKPWR) {
- VirtualFree((LPVOID)v_s2440CLKPWR, 0, MEM_RELEASE);
- }
- #endif // NOBINFS
- #endif
- return TRUE;
- }
- // FMD_GetInfo
- //
- // Return the Flash information
- //
- BOOL FMD_GetInfo(PFlashInfo pFlashInfo)
- {
- pFlashInfo->flashType = NAND;
- // OK, instead of reading it from the chip, we use the hardcoded
- // numbers here.
- pFlashInfo->dwNumBlocks = NUM_BLOCKS;
- pFlashInfo->wSectorsPerBlock = PAGES_PER_BLOCK;
- pFlashInfo->wDataBytesPerSector = SECTOR_SIZE;
- return TRUE;
- }
- // FMD_ReadSector
- //
- // Read the content of the sector.
- //
- // startSectorAddr: Starting page address
- // pSectorBuff : Buffer for the data portion
- // pSectorInfoBuff: Buffer for Sector Info structure
- // dwNumSectors : Number of sectors
- //
- typedef union _ECCRegVal
- {
- DWORD dwECCVal;
- BYTE bECCBuf[4];
- } ECCRegVal;
- BOOL FMD_ReadSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff,
- PSectorInfo pSectorInfoBuff, DWORD dwNumSectors)
- {
- DWORD i;
- BYTE eccBuf[8];
- ECCRegVal eccRegVal;
- // RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_ReadSector: startSectorAddr = %x rn"), startSectorAddr));
- // Sanity check
- if (!pSectorBuff && !pSectorInfoBuff || dwNumSectors > 1) {
- #ifdef BOOT_LOADER
- EdbgOutputDebugString("Invalid parameters!rn");
- #else
- RETAILMSG(1, (TEXT("Invalid parameters!n")));
- #endif
- #ifndef NOSYSCALL
- SetLastError(ERROR_INVALID_PARAMETER);
- #endif
- return FALSE;
- }
- NF_Reset();
- if(!pSectorBuff) {
- // We are reading spare only
- NAND_ReadSectorInfo(startSectorAddr, pSectorInfoBuff);
- // There is no ECC for the sector info, so the read always succeed.
- return TRUE;
- }
- // RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_ReadSector: startSectorAddr = %x rn"), startSectorAddr));
- GRABMUTEX();
- // Initialize ECC register
- NF_RSTECC();
- NF_MECC_UnLock();
- // Enable the chip
- NF_CE_L();
- NF_CLEAR_RB();
- // Issue command
- NF_CMD(CMD_READ);
- // Set up address
- NF_ADDR(0x00);
- NF_ADDR((startSectorAddr) & 0xff);
- NF_ADDR((startSectorAddr >> 8) & 0xff);
- if (NEED_EXT_ADDR) {
- NF_ADDR((startSectorAddr >> 16) & 0xff);
- }
- NF_DETECT_RB(); // Wait tR(max 12us)
- // BUGBUG, because Media Player for Pocket PC sometimes pass us un-aligned buffer
- // we have to waste cycle here to work around this problem
- if( ((DWORD) pSectorBuff) & 0x3) {
- for(i=0; i<SECTOR_SIZE; i++) {
- pSectorBuff[i] = (BYTE) NF_DATA_R();
- }
- }
- else {
- // The right way.
- #ifndef USENANDDMA
- ReadPage512(pSectorBuff, pNFDATA);
- #else // USENANDDMA
- #ifdef USESETKMODE
- SetKMode(TRUE);
- v_pINTregs->rSRCPND=BIT_DMA3; // Init DMA src pending.
- #endif // USESETKMODE
- // Nand to memory dma setting
- v_pDMAregs->rDISRC3 = (unsigned int)NFDATA; // Nand flash data register
- v_pDMAregs->rDISRCC3 = (0<<1) | (1<<0); //arc=AHB,src_addr=fix
- v_pDMAregs->rDIDST3 = (int)NAND_DMA_BUFFER_PHYS;
- v_pDMAregs->rDIDSTC3 = (0<<1) | (0<<0); //dst=AHB,dst_addr=inc;
- v_pDMAregs->rDCON3 = (1<<31)|(1<<30)|(1<<29)|(1<<28)|(1<<27)|(0<<23)|(1<<22)|(2<<20)|(512/4/4);
- //Handshake,AHB,interrupt,(4-burst),whole,S/W,no_autoreload,word,count=128;
- // DMA on and start.
- v_pDMAregs->rDMASKTRIG3 = (1<<1)|(1<<0);
- #ifndef USESETKMODE
- WaitForSingleObject(gDMA3IntrEvent, INFINITE);
- InterruptDone(SYSINTR_DMA3);
- #else // USESETKMODE
- while(!(v_pINTregs->rSRCPND & BIT_DMA3)); // Wait until Dma transfer is done.
- v_pINTregs->rSRCPND=BIT_DMA3;
- SetKMode(FALSE);
- #endif // USESETKMODE
- memcpy(pSectorBuff, pDMABuffer, 512);
- #endif // USENANDDMA
- }
- /*
- for ( i = 0 ; i < 512; i++ )
- #ifdef BOOT_LOADER
- EdbgOutputDebugString("%x ", *(pSectorBuff+i));
- #else
- RETAILMSG(1, (TEXT("%x "), *(pSectorBuff+i)));
- #endif
- */
- // Do the ECC thing here
- // We read the ECC value from the ECC register pFNECC
- NF_MECC_Lock();
- eccRegVal.dwECCVal = NF_ECC();
- // Read the SectorInfo data
- if(pSectorInfoBuff) {
- // Read the SectorInfo data (we only need to read first 8 bytes)
- pSectorInfoBuff->dwReserved1 = NF_DATA_R4();
- // OEM byte
- pSectorInfoBuff->bOEMReserved = (BYTE) NF_DATA_R();
- // Read the bad block mark
- pSectorInfoBuff->bBadBlock = (BYTE) NF_DATA_R();
- // Second reserved field (WORD)
- pSectorInfoBuff->wReserved2 = ((BYTE) NF_DATA_R() << 8);
- pSectorInfoBuff->wReserved2 |= ((BYTE) NF_DATA_R());
- }
- else {
- // Advance the read pointer
- for(i=0; i<sizeof(SectorInfo); i++) {
- eccBuf[i] = (BYTE) NF_DATA_R();
- }
- }
- // Verify the ECC values
- //
- // Read the ECC buffer
- for(i=0; i<3; i++) {
- eccBuf[i] = (BYTE) NF_DATA_R();
- }
- NF_CE_H();
- // Copmare with the ECC generated from the HW
- if(eccBuf[0] != eccRegVal.bECCBuf[0] ||
- eccBuf[1] != eccRegVal.bECCBuf[1] ||
- eccBuf[2] != eccRegVal.bECCBuf[2] ) {
- #ifdef BOOT_LOADER
- EdbgOutputDebugString("FMD: ECC ERROR - Page #: %drn", startSectorAddr);
- EdbgOutputDebugString("(%x:%x %x:%x %x:%x)rn", eccBuf[0], eccRegVal.bECCBuf[0], eccBuf[1], eccRegVal.bECCBuf[1], eccBuf[2], eccRegVal.bECCBuf[2]);
- #else
- RETAILMSG(1, (TEXT("FMD: ECC ERROR - Page #: %drn"), startSectorAddr));
- #endif
- // Now try to correct them
- if(!ECC_CorrectData(pSectorBuff, eccBuf, eccRegVal.bECCBuf)) {
- RETAILMSG(1, (TEXT("FMD: Unable to correct the ECC error - Page #: %drn"),
- startSectorAddr));
- RELEASEMUTEX();
- return FALSE;
- }
- }
- RELEASEMUTEX();
- return TRUE;
- }
- //
- // IsBlockBad
- //
- // Check to see if the given block is bad. A block is bad if the 517th byte on
- // the first or second page is not 0xff.
- //
- // blockID: The block address. We need to convert this to page address
- //
- //
- BOOL IsBlockBad(BLOCK_ID blockID)
- {
- DWORD dwPageID = blockID << 5;
- BOOL bRet = FALSE;
- BYTE wFlag;
- GRABMUTEX();
- // Enable the chip
- NF_CE_L();
- NF_CLEAR_RB();
- // Issue the command
- NF_CMD(CMD_READ2);
- // Set up address
- NF_ADDR(VALIDADDR);
- NF_ADDR((dwPageID) & 0xff);
- NF_ADDR((dwPageID >> 8) & 0xff);
- if (NEED_EXT_ADDR) {
- NF_ADDR((dwPageID >> 16) & 0xff);
- }
- // Wait for Ready bit
- NF_DETECT_RB(); // Wait tR(max 12us)
- // Now get the byte we want
- wFlag = (BYTE) NF_DATA_R();
- if(wFlag != 0xff) {
- bRet = TRUE;
- }
- // Disable the chip
- NF_CE_H();
- RELEASEMUTEX();
- return bRet;
- }
- //
- // FMD_GetBlockStatus
- //
- // Returns the status of a block. The status information is stored in the spare area of the first sector for
- // the respective block.
- //
- // A block is BAD if the bBadBlock byte on the first page is not equal to 0xff.
- //
- DWORD FMD_GetBlockStatus(BLOCK_ID blockID)
- {
- SECTOR_ADDR sectorAddr = blockID << LOG_2_PAGES_PER_BLOCK;
- SectorInfo SI;
- DWORD dwResult = 0;
- if(!FMD_ReadSector(sectorAddr, NULL, &SI, 1))
- {
- return BLOCK_STATUS_UNKNOWN;
- }
- if(!(SI.bOEMReserved & OEM_BLOCK_READONLY))
- {
- dwResult |= BLOCK_STATUS_READONLY;
- }
- if(SI.bBadBlock != 0xFF)
- {
- dwResult |= BLOCK_STATUS_BAD;
- }
- return dwResult;
- }
- // FMD_EraseBlock
- //
- // Erase the given block
- //
- BOOL FMD_EraseBlock(BLOCK_ID blockID)
- {
- BOOL bRet = TRUE;
- DWORD dwPageID = blockID << 5;
- GRABMUTEX();
- #ifndef NOSYSCALL
- if(blockID < IMAGE_START_BLOCK)
- {
- bRet = FALSE;
- RELEASEMUTEX();
- return bRet;
- }
- #endif
- // Enable the chip
- NF_CE_L();
- NF_CLEAR_RB();
- // Issue command
- NF_CMD(CMD_ERASE);
- // Set up address
- NF_ADDR((dwPageID) & 0xff);
- NF_ADDR((dwPageID >> 8) & 0xff);
- if (NEED_EXT_ADDR) {
- NF_ADDR((dwPageID >> 16) & 0xff);
- }
- // Complete erase operation
- NF_CMD(CMD_ERASE2);
- // Wait for ready bit
- NF_DETECT_RB(); // Wait tR(max 12us)
- // Check the status
- NF_CMD(CMD_STATUS);
- if(NF_DATA_R() & STATUS_ERROR) {
- RETAILMSG(1, (TEXT("######## Error Erasing block %d!n"), blockID));
- bRet = FALSE;
- }
- NF_CE_H();
- RELEASEMUTEX();
- return bRet;
- }
- // FMD_WriteSector
- //
- // Write dwNumPages pages to the startSectorAddr
- //
- BOOL FMD_WriteSector(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff,
- DWORD dwNumSectors)
- {
- DWORD i;
- BOOL bRet = TRUE;
- DWORD dwECCVal;
- BYTE eccBuf[4];
- // RETAILMSG(1, (TEXT("FlashDrv!FMD!FMD_WriteSector: rn")));
- // Sanity check
- // BUGBUGBUG: I need to come back to support dwNumSectors > 1
- //
- if((!pSectorBuff && !pSectorInfoBuff) || dwNumSectors != 1) {
- #ifdef BOOT_LOADER
- EdbgOutputDebugString("Invalid parameters!rn");
- #else
- RETAILMSG(1, (TEXT("Invalid parameters!n")));
- #endif
- #ifndef NOSYSCALL
- SetLastError(ERROR_INVALID_PARAMETER);
- #endif
- return FALSE;
- }
- NF_Reset();
- if(!pSectorBuff) {
- // If we are asked just to write the SectorInfo, we will do that separately
- bRet = NAND_WriteSectorInfo(startSectorAddr, pSectorInfoBuff);
- return bRet; // Do not write the actual sector information...
- }
- GRABMUTEX();
- // Initialize ECC register
- NF_RSTECC();
- NF_MECC_UnLock();
- // Enable Chip
- NF_CE_L();
- // Issue command
- NF_CMD(CMD_READ);
- NF_CMD(CMD_WRITE);
- // Setup address
- NF_ADDR(0x00);
- NF_ADDR((startSectorAddr) & 0xff);
- NF_ADDR((startSectorAddr >> 8) & 0xff);
- if (NEED_EXT_ADDR) {
- NF_ADDR((startSectorAddr >> 16) & 0xff);
- }
- // Special case to handle un-aligned buffer pointer.
- //
- if( ((DWORD) pSectorBuff) & 0x3) {
- // Write the data
- for(i=0; i<SECTOR_SIZE; i++) {
- NF_DATA_W(pSectorBuff[i]);
- }
- }
- else {
- #ifndef USENANDDMA
- WritePage512(pSectorBuff, pNFDATA);
- #else // USENANDDMA
- #ifdef USESETKMODE
- SetKMode(TRUE);
- v_pINTregs->rSRCPND=BIT_DMA3; // Init DMA src pending.
- #endif // USESETKMODE
- memcpy(pDMABuffer, pSectorBuff, 512);
- // Nand to memory dma setting
- v_pDMAregs->rDISRC3 = (int)SDI_DMA_BUFFER_PHYS; // Nand flash data register
- v_pDMAregs->rDISRCC3 = (0<<1) | (0<<0); //arc=AHB,src_addr=inc
- v_pDMAregs->rDIDST3 = (int)NFDATA;
- v_pDMAregs->rDIDSTC3 = (0<<1) | (1<<0); //dst=AHB,dst_addr=fix;
- v_pDMAregs->rDCON3 = (1<<31)|(1<<30)|(1<<29)|(0<<28)|(1<<27)|(0<<23)|(1<<22)|(2<<20)|(512/4);
- // only unit transfer in writing!!!!
- //Handshake,AHB,interrupt,(unit),whole,S/W,no_autoreload,word,count=128;
- // DMA on and start.
- v_pDMAregs->rDMASKTRIG3 = (1<<1)|(1<<0);
- #ifndef USESETKMODE
- WaitForSingleObject(gDMA3IntrEvent, INFINITE);
- InterruptDone(SYSINTR_DMA3);
- #else // USESETKMODE
- while(!(v_pINTregs->rSRCPND & BIT_DMA3)); // Wait until Dma transfer is done.
- v_pINTregs->rSRCPND=BIT_DMA3;
- SetKMode(FALSE);
- #endif // USESETKMODE
- #endif // USENANDDMA
- }
- // Read out the ECC value generated by HW
- NF_MECC_Lock();
- dwECCVal = NF_ECC();
- // Write the SectorInfo data to the media
- // NOTE: This hardware is odd: only a byte can be written at a time and it must reside in the
- // upper byte of a USHORT.
- if(pSectorInfoBuff)
- {
- // Write the first reserved field (DWORD)
- NF_DATA_W4(pSectorInfoBuff->dwReserved1);
- // Write OEM reserved flag
- NF_DATA_W( (pSectorInfoBuff->bOEMReserved) );
- // Write the bad block flag
- NF_DATA_W( (pSectorInfoBuff->bBadBlock) );
- // Write the second reserved field
- NF_DATA_W( (pSectorInfoBuff->wReserved2 >> 8) & 0xff );
- NF_DATA_W( (pSectorInfoBuff->wReserved2) & 0xff );
- }else
- {
- // Make sure we advance the Flash's write pointer (even though we aren't writing the SectorInfo data)
- for(i=0; i<sizeof(SectorInfo); i++)
- {
- NF_DATA_W(0xff);
- }
- }
- // ECC stuff should be here
- eccBuf[0] = (BYTE) ((dwECCVal) & 0xff);
- eccBuf[1] = (BYTE) ((dwECCVal >> 8) & 0xff);
- eccBuf[2] = (BYTE) ((dwECCVal >> 16) & 0xff);
- // Write the ECC value to the flash
- for(i=0; i<3; i++) {
- NF_DATA_W(eccBuf[i]);
- }
- for(i=0; i<5; i++) {
- NF_DATA_W(0xff);
- }
- NF_CLEAR_RB();
- // Finish up the write operation
- NF_CMD(CMD_WRITE2);
- // Wait for RB
- NF_DETECT_RB(); // Wait tR(max 12us)
- // Check the status
- NF_CMD(CMD_STATUS);
- if(NF_DATA_R() & STATUS_ERROR) {
- #ifdef BOOT_LOADER
- EdbgOutputDebugString("FMD_WriteSector() ######## Error Programming page %d!rn", startSectorAddr);
- #else
- RETAILMSG(1, (TEXT("FMD_WriteSector() ######## Error Programming page %d!n"), startSectorAddr));
- #endif
- bRet = FALSE;
- }
- // Disable the chip
- NF_CE_H();
- RELEASEMUTEX();
- return bRet;
- }
- /*
- * MarkBlockBad
- *
- * Mark the block as a bad block. We need to write a 00 to the 517th byte
- */
- BOOL MarkBlockBad(BLOCK_ID blockID)
- {
- DWORD dwStartPage = blockID << 5;
- BOOL bRet = TRUE;
- GRABMUTEX();
- // Enable chip
- NF_CE_L();
- NF_CLEAR_RB();
- // Issue command
- // We are dealing with spare area
- NF_CMD(CMD_READ2);
- NF_CMD(CMD_WRITE);
- // Set up address
- NF_ADDR(VALIDADDR);
- NF_ADDR((dwStartPage) & 0xff);
- NF_ADDR((dwStartPage >> 8) & 0xff);
- if (NEED_EXT_ADDR) {
- NF_ADDR((dwStartPage >> 16) & 0xff);
- }
- NF_DATA_W(BADBLOCKMARK);
- // Copmlete the write
- NF_CMD(CMD_WRITE2);
- // Wait for RB
- NF_DETECT_RB(); // Wait tR(max 12us)
- // Get the status
- NF_CMD(CMD_STATUS);
- if(NF_DATA_R() & STATUS_ERROR) {
- RETAILMSG(1, (TEXT("######## Failed to mark the block bad!n")));
- bRet = FALSE;
- }
- // Disable chip select
- NF_CE_H();
- RELEASEMUTEX();
- return bRet;
- }
- //
- // FMD_SetBlockStatus
- //
- // Sets the status of a block. Only implement for bad blocks for now.
- // Returns TRUE if no errors in setting.
- //
- BOOL FMD_SetBlockStatus(BLOCK_ID blockID, DWORD dwStatus)
- {
- SECTOR_ADDR sectorAddr = blockID << LOG_2_PAGES_PER_BLOCK;
- BYTE bStatus = 0;
- if(dwStatus & BLOCK_STATUS_BAD)
- {
- if(!MarkBlockBad (blockID))
- {
- return FALSE;
- }
- }
- // We don't currently support setting a block to read-only, so fail if request is
- // for read-only and block is not currently read-only.
- if(dwStatus & BLOCK_STATUS_READONLY)
- {
- if(!(FMD_GetBlockStatus(blockID) & BLOCK_STATUS_READONLY))
- {
- return FALSE;
- }
- }
- return TRUE;
- }
- #ifndef NOSYSCALL
- // We don't have to build the following interface functions for the
- // bootloader.
- //
- // FMD_PowerUp
- //
- // Performs any necessary powerup procedures...
- //
- VOID FMD_PowerUp(VOID)
- {
- if (v_s2440CLKPWR && pNFCONF) {
- // Enable the clock to NAND controller
- v_s2440CLKPWR->rCLKCON |= (1<<4);
- // Reinit the NAND controller
- GRABMUTEX();
- WRITE_REGISTER_USHORT(pNFCONF, (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0));
- WRITE_REGISTER_USHORT(pNFCONT, (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(1<<1)|(1<<0));
- WRITE_REGISTER_USHORT(pNFSTAT, 0);
- RELEASEMUTEX();
- // Reset the controller
- NF_Reset();
- #ifdef CEDAR_ONLY
- // ++ CE 3.0 Specific Code. Not needed for 4.x +
- SetInterruptEvent(SYSINTR_POWERON);
- // -- CE 3.0 Specific Code. Not needed for 4.x +
- #endif // CEDAR_ONLY
- }
- }
- // FMD_PowerDown
- //
- // Performs any necessary powerdown procedures...
- //
- VOID FMD_PowerDown(VOID)
- {
- if (v_s2440CLKPWR) {
- // Disable the clock to NAND controller
- v_s2440CLKPWR->rCLKCON &= ~(1<<4);
- }
- }
- // FMD_OEMIoControl
- //
- // Used for any OEM defined IOCTL operations
- //
- BOOL FMD_OEMIoControl(DWORD dwIoControlCode, PBYTE pInBuf, DWORD nInBufSize,
- PBYTE pOutBuf, DWORD nOutBufSize, PDWORD pBytesReturned)
- {
- switch(dwIoControlCode)
- {
- case IOCTL_FMD_UPDATEXIP_BEGIN:
- g_bTakeMutex = TRUE;
- break;
- case IOCTL_FMD_UPDATEXIP_END:
- g_bTakeMutex = FALSE;
- break;
- default:
- RETAILMSG(1, (TEXT("FMD::FMD_OEMIoControl = 0x%xn"), dwIoControlCode));
- return FALSE;
- }
- return TRUE;
- }
- #endif // NOSYSCALL
- //------------------------------- Private Interface (NOT used by the FAL) --------------------------
- // FMD_GetOEMReservedByte
- //
- // Retrieves the OEM reserved byte (for metadata) for the specified physical sector.
- //
- //
- BOOL FMD_GetOEMReservedByte(SECTOR_ADDR physicalSectorAddr, PBYTE pOEMReserved)
- {
- GRABMUTEX();
- // Enable chip select
- NF_CE_L();
- NF_CLEAR_RB();
- // Issue command
- NF_CMD(CMD_READ2);
- // Set up address
- NF_ADDR(OEMADDR);
- NF_ADDR((physicalSectorAddr) & 0xff);
- NF_ADDR((physicalSectorAddr >> 8) & 0xff);
- if (NEED_EXT_ADDR) {
- NF_ADDR((physicalSectorAddr >> 16) & 0xff);
- }
- // Wait for the ready bit
- NF_DETECT_RB(); // Wait tR(max 12us)
- // Read the data
- *pOEMReserved = (BYTE) NF_DATA_R();
- // Disable chip select
- NF_CE_H();
- RELEASEMUTEX();
- return TRUE;
- }
- // FMD_SetOEMReservedByte
- //
- // Sets the OEM reserved byte (for metadata) for the specified physical sector.
- //
- BOOL FMD_SetOEMReservedByte(SECTOR_ADDR physicalSectorAddr, BYTE bOEMReserved)
- {
- BOOL bRet = TRUE;
- GRABMUTEX();
- // Enable chip select
- NF_CE_L();
- NF_CLEAR_RB();
- // Issue command
- NF_CMD(CMD_READ2);
- NF_CMD(CMD_WRITE);
- // Set up address
- NF_ADDR(OEMADDR);
- NF_ADDR((physicalSectorAddr) & 0xff);
- NF_ADDR((physicalSectorAddr >> 8) & 0xff);
- if (NEED_EXT_ADDR) {
- NF_ADDR((physicalSectorAddr >> 16) & 0xff);
- }
- // Write the data
- NF_DATA_W(bOEMReserved);
- // Complete the write
- NF_CMD(CMD_WRITE2);
- // Wait for the ready bit
- NF_DETECT_RB(); // Wait tR(max 12us)
- // Read the status
- NF_CMD(CMD_STATUS);
- // Check the status
- if(NF_DATA_R() & STATUS_ERROR) {
- RETAILMSG(1, (TEXT("######## Failed to set OEM Reserved byte!n")));
- bRet = FALSE;
- }
- // Disable chip select
- NF_CE_H();
- RELEASEMUTEX();
- return bRet;
- }
- //---------------------------------------- Helper Functions ----------------------------------------
- // Interface function for testing purpose.
- //
- BOOL FMD_ReadSpare(DWORD dwStartPage, LPBYTE pBuff, DWORD dwNumPages)
- {
- DWORD i, n;
- GRABMUTEX();
- // Enable chip select
- NF_CE_L();
- NF_CLEAR_RB();
- // Issue command
- NF_CMD(CMD_READ2);
- // Set up address
- NF_ADDR(0x00);
- NF_ADDR((dwStartPage) & 0xff);
- NF_ADDR((dwStartPage >> 8) & 0xff);
- if (NEED_EXT_ADDR) {
- NF_ADDR((dwStartPage >> 16) & 0xff);
- }
- // Wait for Ready bit
- NF_DETECT_RB(); // Wait tR(max 12us)
- // Now read out the data
- for(n=0; n<dwNumPages; n++) {
- // Read the spare area
- for(i=0; i<16; i++) {
- pBuff[n*16+i] = (BYTE) NF_DATA_R();
- }
- NF_DETECT_RB(); // Wait tR(max 12us)
- }
- NF_CE_H();
- RELEASEMUTEX();
- return TRUE;
- }
- void GRABMUTEX()
- {
- #ifdef NOSYSCALL
- #ifndef BOOT_LOADER
- // we're in the kernel - always SC_WaitForMultiple
- SC_WaitForMultiple(1, &g_hMutex, TRUE, INFINITE);
- #endif
- #else
- if (g_bTakeMutex) {
- // we can do a normal WaitForSingleObject
- WaitForSingleObject(g_hMutex, INFINITE);
- }
- #endif
- }
- void RELEASEMUTEX()
- {
- #ifdef NOSYSCALL
- #ifndef BOOT_LOADER
- SC_ReleaseMutex(g_hMutex);
- #endif
- #else
- if (g_bTakeMutex) {
- ReleaseMutex(g_hMutex);
- }
- #endif
- }