wince FAL+FMD的简单分析
creator
sz111@126.com
1.首先弄清楚FAL中的设备驱动,物理设备数据类型如下:
typedef struct _DEVICE
{
DWORD dwID;
PVOID hFMD;
PVOID hFMDHook;
} DEVICE , *PDEVICE;
有一个公共变量g_pDevice来保存这个。pDevice指向g_pDevice
2.在DSK_Init初始化化中,会通过GetFMDInterface(pDevice)获得FMD。
VOID GetFMDInterface(PDEVICE pDevice)
{
FMD.cbSize = sizeof(FMDInterface);
// query FMD intrface from the FMD
FMD.pOEMIoControl = FMD_OEMIoControl;
if (!FMD_OEMIoControl (IOCTL_FMD_GET_INTERFACE, NULL, 0, (PBYTE)&FMD, sizeof(FMDInterface), NULL))
{
// FMD does not support IOCTL_FMD_GET_INTERFACE, so build the FMDInterface
// structure using the legacy FMD functions
FMD.pInit = FMD_Init;
FMD.pDeInit = FMD_Deinit;
FMD.pGetInfo = FMD_GetInfo;
FMD.pGetBlockStatus = FMD_GetBlockStatus;
FMD.pSetBlockStatus = FMD_SetBlockStatus;
FMD.pReadSector = FMD_ReadSector;
FMD.pWriteSector = FMD_WriteSector;
FMD.pEraseBlock = FMD_EraseBlock;
FMD.pPowerUp = FMD_PowerUp;
FMD.pPowerDown = FMD_PowerDown;
}
// query hook library in case any FMD functions need to be shimmed
pDevice->hFMDHook = FMDHOOK_HookInterface(&FMD);
}
其中FMD_OEMIoControl是在Fmd.cpp中定义的。通过这个函数把msflash.dll和nandflash.dll联系起来。
通过它获得FMD,是一个函数指针接口,以后就通过FMD来执行FMD中的实际函数了。
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_INTERFACE\r\n")));
if (!pOutBuf || nOutBufSize < sizeof(FMDInterface))
{
DEBUGMSG(1, (TEXT("FMD_OEMIoControl: IOCTL_FMD_GET_INTERFACE bad parameter(s).\r\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;
}
.....
}
3.获得FMD之后,首先调用FMD.pInit, 对FMD设备进行初始化。主要是控制器的配置,读ID得到nandflash的容量,
等信息。
4.调用FMD.pGetInfo(&oldFlashInfo)获得nandflash的信息。最终也是调用BOOL FMD_GetInfo(PFlashInfo pFlashInfo)
pFlashInfo->dwNumBlocks = NUM_OF_BLOCKS;
pFlashInfo->wSectorsPerBlock = PAGES_PER_BLOCK;
pFlashInfo->wDataBytesPerSector = NAND_SECTOR_SIZE;
pFlashInfo->dwBytesPerBlock = (PAGES_PER_BLOCK * NAND_SECTOR_SIZE);
把相关信息读到oldFlashInfo中。然后把相关数据写入公共变量g_pFlashMediaInfo
5.然后通过调用CalculateLogicalRange来统计nandflash的区域大小和可以用的block
BOOL CalculateLogicalRange(PFlashRegion pRegion)
{
DWORD dwBlockID;
DWORD dwNumLogicalBlocks = 0;
for (dwBlockID = pRegion->dwStartPhysBlock; dwBlockID < pRegion->dwStartPhysBlock + pRegion->dwNumPhysBlocks; dwBlockID++)
{
DWORD dwStatus = FMD.pGetBlockStatus (dwBlockID);
if (!(dwStatus & (BLOCK_STATUS_RESERVED | BLOCK_STATUS_BAD)))
{
dwNumLogicalBlocks++;
}
}
//pRegion->dwCompactBlocks=MINIMUM_FLASH_BLOCKS_TO_RESERVE最少的block为2,如果wince发现少于2个block的可用块,就会返回error。
if (dwNumLogicalBlocks <= pRegion->dwCompactBlocks)
{
ReportError((TEXT("FLASHDRV.DLL:CalculateLogicalRange() - Invalid number of logical blocks %d\r\n"), dwNumLogicalBlocks));
return FALSE;
}
// Account for compaction blocks
dwNumLogicalBlocks -= pRegion->dwCompactBlocks;
pRegion->dwNumLogicalBlocks = dwNumLogicalBlocks;
return TRUE;
}
最终也是调用FMD_GetBlockStatus函数。