有些时候我们需要在WinCE下面直接对Nand进行一些操作,比如erase,mask bad block,unmask bad block,或者一些基于block的数据操作。
如果我们直接用Nand驱动去访问会造成一个问题,就是无法与系统的Nand驱动互斥访问,这样子很有可能会出现问题
所以我们可以实现FMD_OEMIoControl这个函数来给我们直接提供一个接口
由于通过DeviceIoControl去访问系统的Nand驱动,如DSK1,所以不存在访问冲突问题
为了确认调用DSK的DeviceIoControl会调用FMD_OEMIoControl,特意看了下CE6下FAL的代码(感谢鹏虾提供),在Falmain.cpp中有DSK_IOControl的源代码
BOOL
DSK_IOControl(
DWORD Handle,
DWORD dwIoControlCode,
PBYTE pInBuf,
DWORD nInBufSize,
PBYTE pOutBuf,
DWORD nOutBufSize,
PDWORD pBytesReturned)
{
BOOL fRet = FALSE;
EnterCriticalSection(&g_csMain);
EnterCriticalSection(&g_csFlashDevice);
__try
{
//----- 1. Check the function parameters to make sure we can handle the request... -----
switch (dwIoControlCode)
{
case DISK_IOCTL_INITIALIZED:
if(pInBuf == NULL)
{
goto PARAMETER_ERROR;
}
break;
case DISK_IOCTL_READ:case IOCTL_DISK_READ:
case DISK_IOCTL_WRITE:case IOCTL_DISK_WRITE:
if(pInBuf == NULL || nInBufSize < sizeof(SG_REQ))
{
goto PARAMETER_ERROR;
}
break;
case IOCTL_DISK_GETINFO:
if(pOutBuf == NULL || nOutBufSize != sizeof(DISK_INFO))
{
goto PARAMETER_ERROR;
}
break;
case DISK_IOCTL_GETINFO:
case DISK_IOCTL_SETINFO:case IOCTL_DISK_SETINFO:
if(pInBuf == NULL || nInBufSize != sizeof(DISK_INFO))
{
goto PARAMETER_ERROR;
}
break;
case DISK_IOCTL_GETNAME:case IOCTL_DISK_GETNAME:
if(pOutBuf == NULL || nOutBufSize == 0)
{
goto PARAMETER_ERROR;
}
break;
case DISK_IOCTL_FORMAT_MEDIA: case IOCTL_DISK_FORMAT_MEDIA:
break;
case IOCTL_DISK_DELETE_SECTORS:
case IOCTL_DISK_SET_SECURE_WIPE_FLAG:
if(pInBuf == NULL || nInBufSize != sizeof(DELETE_SECTOR_INFO))
{
goto PARAMETER_ERROR;
}
break;
case IOCTL_DISK_SECURE_WIPE:
if(pInBuf == NULL || nInBufSize != sizeof(DELETE_SECTOR_INFO))
{
goto PARAMETER_ERROR;
}
break;
case IOCTL_DISK_DEVICE_INFO:
if(pInBuf == NULL || nInBufSize != sizeof(STORAGEDEVICEINFO))
{
goto PARAMETER_ERROR;
}
break;
case IOCTL_DISK_GET_SECTOR_ADDR:
if(pInBuf == NULL || pOutBuf == NULL || nInBufSize != nOutBufSize)
{
goto PARAMETER_ERROR;
}
break;
case IOCTL_POWER_CAPABILITIES:
if(pOutBuf == NULL || nOutBufSize < sizeof(POWER_CAPABILITIES) || pBytesReturned == NULL)
{
goto PARAMETER_ERROR;
}
break;
case IOCTL_POWER_SET:
if(pOutBuf == NULL || nOutBufSize < sizeof(CEDEVICE_POWER_STATE) || pBytesReturned == NULL)
{
goto PARAMETER_ERROR;
}
break;
case IOCTL_POWER_GET:
if(pOutBuf == NULL || nOutBufSize < sizeof(CEDEVICE_POWER_STATE) || pBytesReturned == NULL)
{
goto PARAMETER_ERROR;
}
break;
default:
// Pass any other IOCTL through to the FMD.
fRet = FMD.pOEMIoControl(dwIoControlCode, pInBuf, nInBufSize, pOutBuf, nOutBufSize, pBytesReturned);
goto IO_EXIT;
}
//----- 2. Now handle the IOCTL request... -----
switch (dwIoControlCode)
{
case DISK_IOCTL_INITIALIZED:
break;
case DISK_IOCTL_READ:case IOCTL_DISK_READ:
DEBUGMSG(ZONE_FUNCTION,(TEXT("FLASHDRV.DLL:DSK_IOControl(DISK_IOCTL_READ)/r/n")));
//----- Service this scatter/gather READ request -----
if(!(fRet = ReadFromMedia((PSG_REQ)pInBuf)))
{
ReportError((TEXT("FLASHDRV.DLL:ReadFromMedia() failed./r/n")));
}
break;
case DISK_IOCTL_WRITE:case IOCTL_DISK_WRITE:
DEBUGMSG(ZONE_FUNCTION,(TEXT("FLASHDRV.DLL:DSK_IOControl(DISK_IOCTL_WRITE)/r/n")));
//----- Service this scatter/gather WRITE request -----
if(!(fRet = WriteToMedia((PSG_REQ)pInBuf)))
{
ReportError((TEXT("FLASHDRV.DLL:WriteToMedia() failed./r/n")));
}
break;
case DISK_IOCTL_GETINFO:case IOCTL_DISK_GETINFO:
DEBUGMSG(ZONE_FUNCTION,(TEXT("FLASHDRV.DLL:DSK_IOControl(DISK_IOCTL_GETINFO)/r/n")));
//----- Retrieve the storage information for this FLASH device -----
if(!(fRet = GetDiskInfo((PDISK_INFO)(dwIoControlCode!=IOCTL_DISK_GETINFO?pInBuf:pOutBuf))))
{
ReportError((TEXT("FLASHDRV.DLL:ERROR - Unable to get disk information from FMD!/r/n")));
goto IO_EXIT;
}
break;
case DISK_IOCTL_SETINFO: case IOCTL_DISK_SETINFO:
DEBUGMSG(ZONE_FUNCTION,(TEXT("FLASHDRV.DLL:DSK_IOControl(DISK_IOCTL_SETINFO)/r/n")));
//----- The FLASH media is a fixed size; hence, nothing needs to be done -----
break;
case DISK_IOCTL_GETNAME:case IOCTL_DISK_GETNAME:
SetLastError(ERROR_NOT_SUPPORTED);
break;
case DISK_IOCTL_FORMAT_MEDIA:case IOCTL_DISK_FORMAT_MEDIA:
DEBUGMSG(ZONE_FUNCTION,(TEXT("FLASHDRV.DLL:DSK_IOControl(DISK_IOCTL_FORMAT_MEDIA)/r/n")));
//----- Format the media on the FLASH device -----
if(!(fRet = FormatMedia()))
{
ReportError((TEXT("FLASHDRV.DLL:ERROR - Unable to format FLASH media!/r/n")));
goto IO_EXIT;
}
break;
case IOCTL_DISK_DEVICE_INFO:
{
fRet = GetDeviceInfo((PSTORAGEDEVICEINFO)pInBuf);
if (pBytesReturned)
*pBytesReturned = sizeof(STORAGEDEVICEINFO);
break;
}
case IOCTL_DISK_DELETE_SECTORS:
DEBUGMSG(ZONE_FUNCTION, (TEXT("FLASHDRV.DLL:DSK_IOControl(IOCTL_DISK_DELETE_SECTORS)/r/n")));
//----- Delete the requested sectors -----
if(!(fRet = DeleteSectors((PDELETE_SECTOR_INFO)pInBuf)))
{
ReportError((TEXT("FLASHDRV.DLL:ERROR - DeleteSectors() failed./r/n")));
goto IO_EXIT;
}
break;
case IOCTL_DISK_SECURE_WIPE:
DEBUGMSG(ZONE_FUNCTION, (TEXT("FLASHDRV.DLL:DSK_IOControl(IOCTL_DISK_SECURE_WIPE)/r/n")));
//----- Secure wipe the flash region -----
if(!(fRet = SecureWipe((PDELETE_SECTOR_INFO)pInBuf)))
{
ReportError((TEXT("FLASHDRV.DLL:ERROR - SecureWipe() failed./r/n")));
goto IO_EXIT;
}
break;
case IOCTL_DISK_SET_SECURE_WIPE_FLAG:
DEBUGMSG(ZONE_FUNCTION, (TEXT("FLASHDRV.DLL:DSK_IOControl(IOCTL_DISK_SET_SECURE_WIPE_FLAG)/r/n")));
//----- Set the secure wipe flag for the flash region -----
if(!(fRet = SetSecureWipeFlag((PDELETE_SECTOR_INFO)pInBuf)))
{
ReportError((TEXT("FLASHDRV.DLL:ERROR - SetSecureWipeFlag() failed./r/n")));
goto IO_EXIT;
}
break;
case IOCTL_DISK_GET_SECTOR_ADDR:
{
DEBUGMSG(ZONE_FUNCTION,(TEXT("FLASHDRV.DLL:DSK_IOControl(IOCTL_DISK_GET_SECTOR_ADDR)/r/n")));
//----- Service this scatter/gather READ request -----
if(!(fRet = GetPhysSectorAddr((PSECTOR_ADDR)pInBuf, (PSECTOR_ADDR)pOutBuf, nInBufSize / sizeof(SECTOR_ADDR))))
{
ReportError((TEXT("FLASHDRV.DLL:ReadFromMedia() failed./r/n")));
}
break;
}
case IOCTL_POWER_CAPABILITIES:
DEBUGMSG(ZONE_FUNCTION, (TEXT("FLASHDRV.DLL:DSK_IOControl(IOCTL_POWER_CAPABILITIES)/r/n")));
if(!(fRet = GetPowerCapabilities((PPOWER_CAPABILITIES)pOutBuf)))
{
ReportError((TEXT("FLASHDRV.DLL:ERROR - GetPowerCapabilities() failed./r/n")));
goto IO_EXIT;
}
*pBytesReturned = sizeof(POWER_CAPABILITIES);
break;
case IOCTL_POWER_SET:
DEBUGMSG(ZONE_FUNCTION, (TEXT("FLASHDRV.DLL:DSK_IOControl(IOCTL_POWER_SET)/r/n")));
if(!(fRet = SetPowerState((PCEDEVICE_POWER_STATE)pOutBuf)))
{
ReportError((TEXT("FLASHDRV.DLL:ERROR - SetPowerState() failed./r/n")));
goto IO_EXIT;
}
*pBytesReturned = sizeof(CEDEVICE_POWER_STATE);
break;
case IOCTL_POWER_GET:
DEBUGMSG(ZONE_FUNCTION, (TEXT("FLASHDRV.DLL:DSK_IOControl(IOCTL_POWER_GET)/r/n")));
if(!(fRet = GetPowerState((PCEDEVICE_POWER_STATE)pOutBuf)))
{
ReportError((TEXT("FLASHDRV.DLL:ERROR - GetPowerState() failed./r/n")));
goto IO_EXIT;
}
*pBytesReturned = sizeof(CEDEVICE_POWER_STATE);
break;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
SetLastError(ERROR_INVALID_PARAMETER);
}
IO_EXIT:
LeaveCriticalSection(&g_csFlashDevice);
LeaveCriticalSection(&g_csMain);
return fRet;
PARAMETER_ERROR:
SetLastError(ERROR_INVALID_PARAMETER);
LeaveCriticalSection(&g_csFlashDevice);
LeaveCriticalSection(&g_csMain);
return FALSE;
}
这里我们看到,进入函数就EnterCriticalSection,这样保证了驱动访问Nand不会产生冲突,然后如果不是系统的IOCTL代码,就会调用FMD.pOEMIoControl来处理,这里的FMD.pOEMIoControl就是通过FMDInterface结构体传递过来的FMD_OEMIoControl。
所以只要我们自定义了一个IOCTL,就会交由FMD_OEMIoControl来处理,这里可以做任何你想做的事情,不必考虑Nand访问冲突的问题。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/gooogleman/archive/2009/09/03/4513622.aspx