Nandflash 驱动移植 (四)
Nandflash驱动移植系列文章导航: Nandflash 驱动移植 (一) Nandflash 驱动移植 (二) Nandflash 驱动移植 (三) Nandflash 驱动移植 (四) Nandflash 驱动移植 (五) Nandflash 驱动移植 (六) 一共六篇 ? ? ? 接着上一篇,这一篇介绍cpp部分 fmd.cpp,这里将逐个函数进行分析讲解: // // Copyright (c) Microsoft Corporation. All rights reserved. // // // Use of this sample source code is subject to the terms of the Microsoft // license agreement under which you licensed this sample source code. If // you did not accept the terms of the license agreement,you are not // authorized to use this sample source code. For the terms of the license,// please see the license agreement between you and Microsoft or,if applicable,// see the LICENSE.RTF on your install media or the root of your tools installation. // THE SAMPLE SOURCE CODE IS PROVIDED "AS IS",WITH NO WARRANTIES. // #include <fmd.h> #include <nkintr.h> #include <oal.h> // BSP Configuration Files #include "bsp_cfg.h" #include "bsp_base_reg_cfg.h" // Base Definitions #include "s3c6410_base_regs.h" #include "s3c6410_nand.h" #include "s3c6410_syscon.h" //#include <ethdbg.h> #include "Cfnand.h" //#include <kitl.h> //#define SYNC_OP #define CHECK_SPAREECC (0) // 1 gjl #define NAND_DEBUG (0) #define NAND_BASE (0xB0200000) // PA:0x70200000 #define SYSCON_BASE (0xB2A0F000) // PA:0x7E00F000 #ifdef SYNC_OP CRITICAL_SECTION g_csNandFlash; #endif #ifdef __cplusplus // gjl extern "C" { int iSighForSlcMlc; // gjl } #endif static volatile S3C6410_NAND_REG *g_pNFConReg = NULL; static volatile S3C6410_SYSCON_REG *g_pSysConReg = NULL; #define DEBUG_WRITE_READ_EQUAL 0 #if DEBUG_WRITE_READ_EQUAL DWORD g_MECCBuf[8]; DWORD g_MECCBuf_R[8]; DWORD g_SECCBuf[2]; DWORD g_SECCBuf_R[2]; #endif extern "C" { void RdPage512(unsigned char *bufPt); void RdPage512Unalign(unsigned char *bufPt); void WrPage512(unsigned char *bufPt); void WrPage512Unalign(unsigned char *bufPt); void WrPageInfo(PBYTE pBuff); void RdPageInfo(PBYTE pBuff); } NANDDeviceInfo GetNandInfo(void) { return stDeviceInfo; } 引用头文件这部分不需要更改 1、读取Flash的ID: /* @func DWORD | ReadFlashID | Reads the flash manufacturer and device codes. @rdesc Manufacturer and device codes. @comm @xref */ static DWORD ReadFlashID(void) { BYTE Mfg,Dev,Nouse,Infoma,Planesize; int i; NF_nFCE_L(); // Deselect the flash chip. NF_CMD(CMD_READID); // Send flash ID read command. NF_ADDR(0); for (i=0; i<10; i++) { Mfg = NF_RDDATA_BYTE(); if (Mfg == 0xEC || Mfg == 0x98) break; } Dev = NF_RDDATA_BYTE(); Nouse = NF_RDDATA_BYTE(); Infoma = NF_RDDATA_BYTE(); Planesize = NF_RDDATA_BYTE(); //RETAILMSG(1,(TEXT("[FMD:ERR] FMD_Init() : page info = 0x%08x,0x%08x,0x%08xn"),Planesize)); //According to the read ID from flash,Nouse=0x14,Infoma=0xa5,planesize=0x64,the page size is 2K,block size is 256KB //there are 4096 blocks,plane num=2,plane size=4Gbit //So we should change the cfnand.h nandflash information. NF_nFCE_H(); return ((DWORD)(Mfg<<8)+Dev); }这个也不需要修改,具体请参照手册 2、flash初始化: /* @func PVOID | FMD_Init | Initializes the Smart Media NAND flash controller. @rdesc Pointer to S3C2410 NAND controller registers. @comm @xref */ PVOID FMD_Init(LPCTSTR lpActiveReg,PPCI_REG_INFO pRegIn,PPCI_REG_INFO pRegOut) { volatile DWORD nNandID; UINT8 nMID,nDID; UINT32 nCnt; BOOL bNandExt = FALSE; RETAILMSG(1,(TEXT("[FMD] ++FMD_Init() *######rn"))); if (pRegIn && pRegIn->MemBase.Num && pRegIn->MemBase.Reg[0]) { g_pNFConReg = (S3C6410_NAND_REG *)(pRegIn->MemBase.Reg[0]); } else { g_pNFConReg = (S3C6410_NAND_REG *)NAND_BASE; } g_pSysConReg = (S3C6410_SYSCON_REG *)SYSCON_BASE; #ifdef SYNC_OP InitializeCriticalSection(&g_csNandFlash); EnterCriticalSection(&g_csNandFlash); #endif // Configure BUS Width and Chip Select for NAND Flash g_pSysConReg->MEM_SYS_CFG &= ~(1<<12); // NAND Flash BUS Width -> 8 bit g_pSysConReg->MEM_SYS_CFG &= ~(0x1<<1); // Xm0CS2 -> NFCON CS0 // Set up initial flash controller configuration. g_pNFConReg->NFCONF = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4); NF_ECCTYPE_4BIT(); g_pNFConReg->NFCONT = (0<<17)|(0<<16)|(0<<10)|(0<<9)|(0<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<4)|(0x3<<1)|(1<<0); g_pNFConReg->NFSTAT = (1<<4); nNandID = ReadFlashID(); #ifdef SYNC_OP LeaveCriticalSection(&g_csNandFlash); #endif nMID = (UINT8)(nNandID >> 8); nDID = (UINT8)(nNandID & 0xff); RETAILMSG(1,(TEXT("[FMD:INF] FMD_Init() : Read ID = 0x%08xn"),nNandID)); for (nCnt = 0; astNandSpec[nCnt].nMID != 0; nCnt++) { if (nDID == astNandSpec[nCnt].nDID) { bNandExt = TRUE; break; } } if (!bNandExt) { RETAILMSG(1,(TEXT("[FMD:ERR] FMD_Init() : Unknown ID = 0x%08xn"),nNandID)); return NULL; } NUM_OF_BLOCKS = astNandSpec[nCnt].nNumOfBlks; PAGES_PER_BLOCK = astNandSpec[nCnt].nPgsPerBlk; SECTORS_PER_PAGE = astNandSpec[nCnt].nSctsPerPg; RETAILMSG(1,(TEXT("[FMD] FMD_Init() : NUM_OF_BLOCKS = %dn"),NUM_OF_BLOCKS)); RETAILMSG(1,(TEXT("[FMD] FMD_Init() : PAGES_PER_BLOCK = %dn"),PAGES_PER_BLOCK)); RETAILMSG(1,(TEXT("[FMD] FMD_Init() : SECTORS_PER_PAGE = %dn"),SECTORS_PER_PAGE)); // gjl if(iSighForSlcMlc == 1) { NUM_OF_BLOCKS = 8192; PAGES_PER_BLOCK = 8; SECTORS_PER_PAGE = 4; } else { NUM_OF_BLOCKS = astNandSpec[nCnt].nNumOfBlks; PAGES_PER_BLOCK = astNandSpec[nCnt].nPgsPerBlk; SECTORS_PER_PAGE = astNandSpec[nCnt].nSctsPerPg; } RETAILMSG(1,(TEXT("[FMD] --FMD_Init()n"))); return((PVOID)g_pNFConReg); } 上面这个代码是原BSP中的,这个初始化函数里面,有些东西需要修改一下 // Set up initial flash controller configuration. 这个我们对照手册看一下 g_pNFConReg->NFCONF = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4) | (1<<2) | (0<<0); 这一句接下来,原代码中使用的是NF_ECCTYPE_4BIT(); ?4bit的ECC,这里我们将使用8bit的ECC,修改为 NF_ECCTYPE_8BIT(); // use 8bit ECC 原: g_pNFConReg->NFCONT = (0<<17)|(0<<16)|(0<<10)|(0<<9)|(0<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<4)|(0x3<<1)|(1<<0); 参照手册修改为: g_pNFConReg->NFCONT = (0<<13)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0); 接下来直接看到 // gjl if(iSighForSlcMlc == 1) { NUM_OF_BLOCKS = 8192; PAGES_PER_BLOCK = 8; SECTORS_PER_PAGE = 4; } else { NUM_OF_BLOCKS = astNandSpec[nCnt].nNumOfBlks; PAGES_PER_BLOCK = astNandSpec[nCnt].nPgsPerBlk; SECTORS_PER_PAGE = astNandSpec[nCnt].nSctsPerPg; }这里if中的NUM_OF_BLOCKS = 8192;这个定死了,不大好,咱改成(修改之后,可以同时兼容K9GAG08U0D 2G和K9LBG08U0D 4G的Nandflash) NUM_OF_BLOCKS = astNandSpec[nCnt].nNumOfBlks; 到此,FMD_Init()函数就基本上搞掂了。 3、FMD_ReadSector() /* @func BOOL | FMD_ReadSector | Reads the specified sector(s) from NAND flash. @rdesc TRUE = Success,FALSE = Failure. @comm @xref */ BOOL FMD_ReadSector(SECTOR_ADDR startSectorAddr,LPBYTE pSectorBuff,PSectorInfo pSectorInfoBuff,DWORD dwNumSectors) { BOOL bRet; //RETAILMSG(1,(TEXT("[R:0x%08x] n"),startSectorAddr)); #if (NAND_DEBUG) RETAILMSG(1,(TEXT("[FMD] ++FMD_ReadSector(0x%08x) n"),startSectorAddr)); #endif #ifdef SYNC_OP EnterCriticalSection(&g_csNandFlash); #endif if ( IS_LB ) { bRet = FMD_LB_ReadSector(startSectorAddr,pSectorBuff,pSectorInfoBuff,dwNumSectors); } else { bRet = FMD_SB_ReadSector(startSectorAddr,dwNumSectors); } #ifdef SYNC_OP LeaveCriticalSection(&g_csNandFlash); #endif #if (NAND_DEBUG) RETAILMSG(1,(TEXT("[FMD] --FMD_ReadSector()n"))); #endif return bRet; }这里我们不需要做修改,不过其中调用的FMD_LB_ReadSector()函数待会需要修改一下(FMD_LB_ReadSector()是针对Nandflash,4bit或8bit的ECC;而FMD_SB_ReadSector()是针对Norflash,1bit的ecc校验) 4、FMD_EraseBlock() ?擦除块 /* @func BOOL | FMD_EraseBlock | Erases the specified flash block. @rdesc TRUE = Success,FALSE = Failure. @comm @xref */ BOOL FMD_EraseBlock(BLOCK_ID blockID) { BOOL bRet = TRUE; #if (NAND_DEBUG) RETAILMSG(1,(TEXT("[FMD] ++FMD_EraseBlock(0x%08x) n"),blockID)); #endif #ifdef SYNC_OP EnterCriticalSection(&g_csNandFlash); #endif if ( IS_LB ) { bRet = FMD_LB_EraseBlock(blockID); } else { bRet = FMD_SB_EraseBlock(blockID); } #ifdef SYNC_OP LeaveCriticalSection(&g_csNandFlash); #endif #if (NAND_DEBUG) RETAILMSG(1,(TEXT("[FMD] --FMD_EraseBlock()n"))); #endif return bRet; } 这个函数也没有什么需要修改的,其中调用到的FMD_LB_EraseBlock()待会会讲到。 5、FMD_WriteSector() /* @func BOOL | FMD_WriteSector | Writes the specified data to the specified NAND flash sector/page. @rdesc TRUE = Success,FALSE = Failure. @comm @xref */ BOOL FMD_WriteSector(SECTOR_ADDR startSectorAddr,DWORD dwNumSectors) { BOOL bRet = TRUE; #if DEBUG_WRITE_READ_EQUAL BYTE pSectorBuffRead[4096]; // gjl 2048 SectorInfo SectorInfoBuffRead; PSectorInfo pSectorInfoBuffRead = &SectorInfoBuffRead; BYTE *temp = (BYTE*)pSectorInfoBuff; BYTE *temp1 = (BYTE*)pSectorInfoBuffRead; UINT16 nSectorLoop,j=40; #endif #if (NAND_DEBUG) RETAILMSG(1,(TEXT("[FMD] ++FMD_WriteSector(0x%08x) n"),startSectorAddr)); #endif #ifdef SYNC_OP EnterCriticalSection(&g_csNandFlash); #endif if ( IS_LB ) { bRet = FMD_LB_WriteSector(startSectorAddr,dwNumSectors); #if DEBUG_WRITE_READ_EQUAL FMD_LB_ReadSector(startSectorAddr,pSectorBuffRead,pSectorInfoBuffRead,dwNumSectors); for (nSectorLoop = 0; nSectorLoop < 2048; nSectorLoop++) { if(pSectorBuff[nSectorLoop] != pSectorBuffRead[nSectorLoop]) break; } RETAILMSG(1,(TEXT("[FMD] ++FMD_WriteSector equal number = %x n"),nSectorLoop)); for (nSectorLoop = 0; nSectorLoop < 8; nSectorLoop++) { if(temp1[nSectorLoop] != temp[nSectorLoop]) break; } RETAILMSG(1,(TEXT("[FMD] ++FMD_WriteSector informationequal equal number = %x n"),nSectorLoop)); RETAILMSG(1,(TEXT("[FMD] ++FMD_WriteSector sector bytes:n"))); for (nSectorLoop = 0; nSectorLoop < 2048; nSectorLoop++) { if(j--==0) { j=40; RETAILMSG(1,(TEXT("n"))); } RETAILMSG(1,(TEXT("%x "),pSectorBuff[nSectorLoop])); } RETAILMSG(1,(TEXT("n endn"))); RETAILMSG(1,(TEXT("[FMD] ++FMD_ReadSector sector bytes:n"))); for (nSectorLoop = 0; nSectorLoop < 2048; nSectorLoop++) { if(j--==0) { j=40; RETAILMSG(1,pSectorBuffRead[nSectorLoop])); } RETAILMSG(1,(TEXT("n endn"))); for (nSectorLoop = 0; nSectorLoop < 8; nSectorLoop++) { if(g_MECCBuf_R[nSectorLoop] != g_MECCBuf[nSectorLoop]) break; } RETAILMSG(1,(TEXT("[FMD] ++FMD_WriteSector MECC data equal number = %x n"),nSectorLoop)); for (nSectorLoop = 0; nSectorLoop < 8; nSectorLoop++) { if(g_SECCBuf_R[nSectorLoop] != g_SECCBuf[nSectorLoop]) break; } RETAILMSG(1,(TEXT("[FMD] ++FMD_WriteSector SECC data equal number = %x n"),nSectorLoop)); #endif } else { bRet = FMD_SB_WriteSector(startSectorAddr,(TEXT("[FMD] --FMD_WriteSector()n"))); #endif return bRet; } 该函数也没有什么地方需要修改的。 6、FMD_PowerUp() VOID FMD_PowerUp(VOID) { #if (NAND_DEBUG) RETAILMSG(1,(TEXT("[FMD] FMD_PowerUp() n"))); #endif // Set up initial flash controller configuration. g_pNFConReg->NFCONF = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4); g_pNFConReg->NFCONT = (0<<17)|(0<<16)|(0<<10)|(0<<9)|(0<<8)|(1<<7)|(1<<6)|(1<<5)|(1<<4)|(0x3<<1)|(1<<0); g_pNFConReg->NFSTAT = (1<<4); } 这里我们参照之前在FMD_Init()的配置,修改其中的NFCONF和NFCONT的配置为: g_pNFConReg->NFCONF = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4) | (1<<2) | (0<<0); g_pNFConReg->NFCONT = (0<<13)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0); 7、FMD_PowerDown() VOID FMD_PowerDown(VOID) { #if (NAND_DEBUG) RETAILMSG(1,(TEXT("[FMD] FMD_PowerDown() n"))); #endif } 该函数不需要修改什么。 接下来的这几个函数都不需要修改: BOOL FMD_OEMIoControl(DWORD dwIoControlCode,PBYTE pInBuf,DWORD nInBufSize,PBYTE pOutBuf,DWORD nOutBufSize,PDWORD pBytesReturned) { switch(dwIoControlCode) { case IOCTL_FMD_GET_INTERFACE: { RETAILMSG(1,(TEXT("[FMD] FMD_OEMIoControl() : IOCTL_FMD_GET_INTERFACEn"))); if (!pOutBuf || nOutBufSize < sizeof(FMDInterface)) { DEBUGMSG(1,(TEXT("FMD_OEMIoControl: IOCTL_FMD_GET_INTERFACE bad parameter(s).n"))); return(FALSE); } PFMDInterface pInterface = (PFMDInterface)pOutBuf; pInterface->cbSize = sizeof(FMDInterface); pInterface->pInit = FMD_Init; pInterface->pDeInit = FMD_Deinit; pInterface->pGetInfo = FMD_GetInfo; pInterface->pGetInfoEx = NULL; //FMD_GetInfoEx; pInterface->pGetBlockStatus = FMD_GetBlockStatus; pInterface->pSetBlockStatus = FMD_SetBlockStatus; pInterface->pReadSector = FMD_ReadSector; pInterface->pWriteSector = FMD_WriteSector; pInterface->pEraseBlock = FMD_EraseBlock; pInterface->pPowerUp = FMD_PowerUp; pInterface->pPowerDown = FMD_PowerDown; pInterface->pGetPhysSectorAddr = NULL; break; } case IOCTL_FMD_LOCK_BLOCKS: RETAILMSG(1,(TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_LOCK_BLOCKS Not Supportedn"))); return FALSE; case IOCTL_FMD_UNLOCK_BLOCKS: RETAILMSG(1,(TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_UNLOCK_BLOCKS Not Supportedn"))); return FALSE; case IOCTL_FMD_READ_RESERVED: RETAILMSG(1,(TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_READ_RESERVEDn"))); return FALSE; case IOCTL_FMD_WRITE_RESERVED: RETAILMSG(1,(TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_WRITE_RESERVEDn"))); return FALSE; case IOCTL_FMD_GET_RESERVED_TABLE: RETAILMSG(1,(TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_GET_RESERVED_TABLEn"))); return FALSE; case IOCTL_FMD_SET_REGION_TABLE: RETAILMSG(1,(TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_SET_REGION_TABLEn"))); return FALSE; case IOCTL_FMD_SET_SECTORSIZE: RETAILMSG(1,(TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_SET_SECTORSIZEn"))); return FALSE; case IOCTL_FMD_RAW_WRITE_BLOCKS: RETAILMSG(1,(TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_RAW_WRITE_BLOCKSn"))); return FALSE; case IOCTL_FMD_GET_RAW_BLOCK_SIZE: RETAILMSG(1,(TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_GET_RAW_BLOCK_SIZEn"))); return FALSE; case IOCTL_FMD_GET_INFO: RETAILMSG(1,(TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_GET_INFOn"))); return FALSE; case IOCTL_FMD_SET_XIPMODE : RETAILMSG(1,(TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_SET_XIPMODEn"))); return FALSE; case IOCTL_FMD_GET_XIPMODE: RETAILMSG(1,(TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_FMD_GET_XIPMODEn"))); return FALSE; case IOCTL_DISK_FLUSH_CACHE: //RETAILMSG(1,(TEXT("[FMD:ERR] FMD_OEMIoControl() : IOCTL_DISK_FLUSH_CACHEn"))); return TRUE; default: RETAILMSG(1,(TEXT("[FMD:ERR] FMD_OEMIoControl() : Unknown IOCTL (0x%08x)n"),dwIoControlCode)); return FALSE; } return TRUE; } BOOL FMD_Deinit(PVOID hFMD) { #if (NAND_DEBUG) RETAILMSG(1,(TEXT("[FMD] FMD_Deinit() n"))); #endif return(TRUE); } /* @func BOOL | FMD_GetInfo | Provides information on the NAND flash. @rdesc TRUE = Success,FALSE = Failure. @comm @xref */ BOOL FMD_GetInfo(PFlashInfo pFlashInfo) { // Add by AlexLee RunNo[5] UINT32 nCnt; UINT32 nNandID; UINT8 nMID,nDID; if (pFlashInfo == NULL) { RETAILMSG(1,(TEXT("[FMD:ERR] FMD_GetInfo() : Invalid Parametern"))); return(FALSE); } pFlashInfo->flashType = NAND; #ifdef SYNC_OP EnterCriticalSection(&g_csNandFlash); #endif nNandID = ReadFlashID(); #ifdef SYNC_OP LeaveCriticalSection(&g_csNandFlash); #endif nMID = nNandID >> 8; nDID = nNandID & 0xff; for (nCnt = 0; astNandSpec[nCnt].nMID != 0; nCnt++) { if (nDID == astNandSpec[nCnt].nDID) { break; } } // OK,instead of reading it from the chip,we use the hardcoded // numbers here. pFlashInfo->dwNumBlocks = NUM_OF_BLOCKS; pFlashInfo->wSectorsPerBlock = PAGES_PER_BLOCK; pFlashInfo->wDataBytesPerSector = NAND_SECTOR_SIZE; pFlashInfo->dwBytesPerBlock = (PAGES_PER_BLOCK * NAND_SECTOR_SIZE); //RETAILMSG(1,(TEXT("[FMD] FMD_GetInfo() : NUMBLOCKS = %d(0x%x),SECTORSPERBLOCK = %d(0x%x),BYTESPERSECTOR = %d(0x%x) n"),pFlashInfo->dwNumBlocks,pFlashInfo->wSectorsPerBlock,pFlashInfo->wDataBytesPerSector,pFlashInfo->wDataBytesPerSector)); // del by alexlee return TRUE; } /* @func DWORD | FMD_GetBlockStatus | Returns the status of the specified block. @rdesc Block status (see fmd.h). @comm @xref */ DWORD FMD_GetBlockStatus(BLOCK_ID blockID) { DWORD dwResult = 0; #if (NAND_DEBUG) RETAILMSG(1,(TEXT("[FMD] ++FMD_GetBlockStatus(0x%08x) n"),blockID)); #endif #ifdef SYNC_OP EnterCriticalSection(&g_csNandFlash); #endif if ( IS_LB ) { dwResult = FMD_LB_GetBlockStatus(blockID); } else { dwResult = FMD_SB_GetBlockStatus(blockID); } #ifdef SYNC_OP LeaveCriticalSection(&g_csNandFlash); #endif #if (NAND_DEBUG) RETAILMSG(1,(TEXT("[FMD] --FMD_GetBlockStatus()n"))); #endif return dwResult; } /* @func BOOL | FMD_SetBlockStatus | Marks the block with the specified block status. @rdesc TRUE = Success,FALSE = Failure. @comm @xref */ BOOL FMD_SetBlockStatus(BLOCK_ID blockID,DWORD dwStatus) { BOOL bRet = TRUE; #if (NAND_DEBUG) RETAILMSG(1,(TEXT("[FMD] ++FMD_SetBlockStatus(0x%08x,0x%08x) n"),blockID,dwStatus)); #endif #ifdef SYNC_OP EnterCriticalSection(&g_csNandFlash); #endif if ( IS_LB ) { bRet = FMD_LB_SetBlockStatus(blockID,dwStatus); } else { bRet = FMD_SB_SetBlockStatus(blockID,dwStatus); } #ifdef SYNC_OP LeaveCriticalSection(&g_csNandFlash); #endif #if (NAND_DEBUG) RETAILMSG(1,(TEXT("[FMD] --FMD_SetBlockStatus()n"))); #endif return bRet; } 文章有点长,先到这里了,关键点将在下一篇介绍 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |