作者:ARM-WINCE
在网上的很多论坛中都看到有人提问:应用程序如何直接读写Flash的扇区,或者是类似的问题。总之,就是希望应用程序能够直接访问Flash设备,直接读写扇区的数据,或者作其他的操作。这几天没事,就尝试着做了一下,把我的方法介绍给大家。
先做个简单的介绍。WinCE支持Flash设备,一般指Nandflash或者是NORFlash,采用的架构一般是FAL+FMD架构,我们实现FMD相关的接口函数,Flash的驱动就算完成了。当WinCE启动以后,我们能够看到Flash设备的磁盘。我们可以操作磁盘上面的文件,但是不能直接操作flash设备,对Flash设备的操作无非就是:读,写,擦除,读ID。
现在开始介绍实现的方法。我们如果想在应用程序中直接调用FMD中的FMD_ReadSector(..),FMD_WriteSector(..),FMD_EraseBlock(..)是不太现实的。这里再补充一下,这三个函数分别是Flash的读扇区,写扇区,擦除块的函数。好像有点罗嗦了。但是我们可以在应用程序中调用到FMD_OEMIoControl(..)函数,这个是可以做到的。所以我们需要改一下Flash设备的驱动程序,也就是改Flash设备驱动中的FMD_OEMIoControl(..)这个函数。我的改动如下:
BOOL FMD_OEMIoControl(DWORD dwIoControlCode, PBYTE pInBuf, DWORD nInBufSize, PBYTE pOutBuf, DWORD nOutBufSize, PDWORD pBytesReturned)
{
PFMDInterface pInterface = (PFMDInterface)pOutBuf;
RETAILMSG(1, (TEXT("FMD_OEMIoControl: control code is 0x%x/r/n"), dwIoControlCode));
switch(dwIoControlCode)
{
case IOCTL_FMD_GET_INTERFACE:
if (!pOutBuf || nOutBufSize < sizeof(FMDInterface))
{
DEBUGMSG(1, (TEXT("FMD_OEMIoControl: IOCTL_FMD_GET_INTERFACE bad parameter(s)./r/n")));
return(FALSE);
}
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;
pInterface->pOEMIoControl = FMD_OEMIoControl;
break;
case 0xff123456:
FMD_ReadSector(..); //调用读Sector函数
break;
case 0xff654321:
FMD_WriteSector(..); //调用写Sector函数
break;
case 0xff123457:
FMD_EraseBlock(..); //调用擦除Block函数
break;
default:
DEBUGMSG(1, (TEXT("FMD_OEMIoControl: unrecognized IOCTL (0x%x)./r/n"), dwIoControlCode));
return(FALSE);
}
return(TRUE);
}
在FMD_OEMIoControl(..)函数里面增加了3个case,这3个case里面调用了读/写/擦除函数。至于Case的值,我是随便定义的。这样Flash设备的驱动部分就改完了。
在改完Flash驱动以后,我下面会提供两种方法,每一种方法都和Flash设备的注册表配置有关:
1. 以Nandflash为例,当然对于NORFlash来说大同小异,注册表配置如下:
[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/NANDFlash]
"Dll"="ep94xxnandflash.dll"
"Prefix"="DSK"
"Order"=dword:4
;"Ioctl"=dword:4
"Profile"="NSFlash"
"IClass"="{A4E7EDDA-E575-4252-9D6B-4195D48BB865}"
; Override names in default profile
[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/NSFlash]
"Name"="Ep94xx NAND Flash"
"Folder"="NANDFlash"
"PartitionDriver"="MSPart.dll"
"AutoMount"=dword:1
"AutoPart"=dword:1
"AutoFormat"=dword:1
[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/NSFlash/FATFS]
"EnableCache"=dword:1
"CacheSize"=dword:1000
"MountBootable"=dword:1
"Flags"=dword:00000024
"CheckForFormat"=dword:1
然后编写应用程序,主要就是通过CreateFile来打开DSK1:设备,然后通过DeviceIoControl(..)函数来调用FMD_OEMIoControl(..)函数,来达到直接读/写/擦除Flash设备的目的。应用程序代码如下:
HANDLE hFirm;
hFirm = CreateFile(TEXT("DSK1:"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if(hFirm == INVALID_HANDLE_VALUE)
{
printf("Open Flash Device Failed");
return 0;
}
iRet = DeviceIoControl(hFirm, 0xff123456, para1, para2, para3, para4, para5, para6); //Read Flash Sector
iRet = DeviceIoControl(hFirm, 0xff654321, para1, para2, para3, para4, para5, para6); //Write Flash Sector
iRet = DeviceIoControl(hFirm, 0xff123457, para1, para2, para3, para4, para5, para6); //Erase Flash Block
printf("DeviceIoControl OK/r/n");
while(1)
;
通过上面的应用程序,就能够调用到Flash设备驱动中的FMD_OEMIoControl(..)函数,这样根据不同的case就可以调用读/写/擦除函数了。
2. 以Nandflash为例,当然对于NORFlash来说大同小异,注册表配置如下:
[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/NANDFlash]
"Dll"="ep94xxnandflash.dll"
"Prefix"="DSK"
"Order"=dword:4
;"Ioctl"=dword:4
"Profile"="NSFlash"
"IClass"="{A4E7EDDA-E575-4252-9D6B-4195D48BB865}"
; Override names in default profile
[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/NSFlash]
"Name"="Ep94xx NAND Flash"
"Folder"="NANDFlash"
"PartitionDriver"="MSPart.dll"
"AutoMount"=dword:1
"AutoPart"=dword:1
"AutoFormat"=dword:1
[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/NSFlash/FATFS]
"EnableCache"=dword:1
"CacheSize"=dword:1000
"MountBootable"=dword:1
"Flags"=dword:00000024
"CheckForFormat"=dword:1
[HKEY_LOCAL_MACHINE/System/StorageManager/AutoLoad/NSFlash]
"DriverPath"="Drivers//BuiltIn//NANDFlash"
"LoadFlags"=dword:0
"BootPhase"=dword:1
然后编写应用程序,主要就是通过OpenStore来打开NSFlash,然后通过DeviceIoControl(..)函数来调用FMD_OEMIoControl(..)函数,来达到直接读/写/擦除Flash设备的目的。应用程序代码如下:
HANDLE hFirm;
hFirm = OpenStore(L"NSFlash");
if(hFirm == INVALID_HANDLE_VALUE)
{
printf("Open Flash Device Failed");
return 0;
}
iRet = DeviceIoControl(hFirm, 0xff123456, para1, para2, para3, para4, para5, para6);
iRet = DeviceIoControl(hFirm, 0xff654321, para1, para2, para3, para4, para5, para6);
iRet = DeviceIoControl(hFirm, 0xff123457, para1, para2, para3, para4, para5, para6);
printf("DeviceIoControl OK/r/n");
while(1)
;
通过这种方法,也可以在应用程序中调用到FMD_OEMIoControl(..)函数,从而达到直接访问Flash设备的目的。
总结一下,上面的两种方法大致原理其实是一样的,都是通过DeviceIoControl函数来调用FMD_OEMIoControl函数,然后达到直接访问Flash驱动的目的,这样就可以在应用程序中直接读/写/擦除Flash设备了。
最后需要注意的是:你的Flash驱动里面需要对读/写/擦除等直接操作Flash硬件的函数进行保护,因为Flash设备应该是由WinCE的文件系统来管理的,而现在你的应用程序也可以直接访问它了,所以保险起见,添加互斥量保护避免访问冲突。
上面的所有实现,都是在WinCE6.0上面做得,相信在WinCE5.0上面应该差不多。
28楼 suzhbruce 2010-09-13 17:30发表 [回复]
请问版主nanjianhui:
感谢你的分享, 现要写入数据到NandFlash, 那你上面提到的那个 iRet = DeviceIoControl(hFirm, 0xff123456, para1, para2, para3, para4, para5, para6)调用中, para1的写入数据具体格式是怎样的啊..? 难道是SG_REQ格式? 还是其它 ?
可否举例说明一下? 感谢!!
27楼 nanjianhui 2009-09-15 17:22发表 [回复]
我认为也是可以的,不过我没有试过。你的问题好像是因为你的驱动中没有识别出正确的IOcontrol操作码。
26楼 ashazhuang 2009-09-09 11:19发表 [回复]
WINCE5.0 无法用楼主的方法吧。我在fmd_iocontrol()添加自己的case. 出现错误提示“DSK_iocontrol unknown code (.....)”
25楼 nanjianhui 2008-11-13 09:50发表 [回复]
这里有Nandflash的参考代码,你可以看一下:
/WINCE600/PUBLIC/COMMON/OAK/DRIVERS/BLOCK/MSFLASHFMD/SDNPCI
24楼 redeg 2008-11-09 21:29发表 [回复]
楼主,在PB的MSFLASHFMD目录下哪个是NAND FLASH的驱动?FASL目录好像是NOR的驱动对吗?
23楼 lskymate 2008-11-07 18:18发表 [回复]
版主.謝謝您
小弟目前改用deviceIoControl
來取代readFile,writeFile已可成功
對flash存取.
感激
22楼 lskymate 2008-11-06 17:43发表 [回复]
(接續上篇)
flashReadBuffer,
512,
&flashReadCounter,
NULL);
if (readFlashOk == FALSE)
{RETAILMSG(1, (L" Read Mounted Volume Failure!! /n" )); exit(-1);}
// ReadFile - END
真的不曉得為什麼會出問題..
可以在為小弟指點一下嗎?
非常感激
而關於 註冊表的資訊如下
[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/SKYFMD]
@=""
"Prefix"="DSK"
"Dll"="SKYFMD.dll"
"Index"=dword:2
"IClass"=multi_sz:"{A4E7EDDA-E575-4252-9D6B-4195D48BB865}"
"Profile"="SKYFMD"
[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/SKYFMD]
"DefaultFileSystem"="FATFS"
"PartitionDriver"="mspart.dll"
"Name"="SKYFALFMD"
"AutoMount"=dword:1
"AutoPart"=dword:1
"AutoFormat"=dword:1
"Ioctl"=dword:4
感激
21楼 lskymate 2008-11-06 17:43发表 [回复]
(接續上篇)
flashReadBuffer,
512,
&flashReadCounter,
NULL);
if (readFlashOk == FALSE)
{RETAILMSG(1, (L" Read Mounted Volume Failure!! /n" )); exit(-1);}
// ReadFile - END
真的不曉得為什麼會出問題..
可以在為小弟指點一下嗎?
非常感激
而關於 註冊表的資訊如下
[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/SKYFMD]
@=""
"Prefix"="DSK"
"Dll"="SKYFMD.dll"
"Index"=dword:2
"IClass"=multi_sz:"{A4E7EDDA-E575-4252-9D6B-4195D48BB865}"
"Profile"="SKYFMD"
[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/SKYFMD]
"DefaultFileSystem"="FATFS"
"PartitionDriver"="mspart.dll"
"Name"="SKYFALFMD"
"AutoMount"=dword:1
"AutoPart"=dword:1
"AutoFormat"=dword:1
"Ioctl"=dword:4
感激
20楼 lskymate 2008-11-06 17:39发表 [回复]
版主您好
目前小弟希望可以透過File System來對Flash存取.
也就是說寫一支AP.利用Logical Sector Address去
對Flash做讀寫的動作.
目前是計畫用 writeFile及readFile來寫入及讀取.
但會發生exception.
目前 CreateFile 的程式如下
//----------------- CreateFile -----------------
#define FLASHPATH TEXT("//Mounted Volume//Vol:")
hFlash = CreateFile (FLASHPATH,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFlash == INVALID_HANDLE_VALUE)
{ RETAILMSG(1, (L"Open Mounted Volume Failure!!/n" )); exit(-1); }
// CreateFile - END
讀取資料 ReadFile 的程式如下
//----------------- ReadFile -----------------
flashReadBuffer = (char *) malloc (sizeof(char)*512); //接收資料的buffer
memset (flashReadBuffer, 0, sizeof(char)*512);
flashAddress = SetFilePointer (hFlash,
0,
NULL,
FILE_BEGIN);
readFlashOk = ReadFile (hFlash, //執行到這裡時將會發生錯誤(First - chance exception)
19楼 lskymate 2008-09-16 20:36发表 [回复]
謝謝版主.
我在Storage Manager Control Panel Applet有看到了.
非常感激
18楼 nanjianhui 2008-09-16 12:38发表 [回复]
你可以在控制面板里面,看看有没有一个Storage的Manager,在里面应该可以看到,并且作mount。
17楼 lskymate 2008-09-12 19:28发表 [回复]
版主您好.
我發現,C:/WINCE600/PUBLIC/COMMON/OAK/DRIVERS/BLOCK/MSFLASHFMD/RAM 下有一個用 virtualalloc 的作法來產生2M的ram Flash.
但我不知如何使用.所以把他拉出來
放到DEVICEEMULATOR(BSP)下將他當成driver
並BUILD成功.然後attach Emulator時.也可以順利
看到自己在FMD.c加的資訊.
但在EMULATOR上.並沒有看到關於這個 flash device .的相關資訊.請問我要如何像 linux 那樣 mount這個
flash device 呢?
非常感激
16楼 eagle1597 2008-09-10 16:33发表 [回复]
1: "因为在WinCE6.0中限制了IOControl的访问"
这个我不了解, 我的确只在5.0中做过. 谢谢你的指出.
2: 如果你把srctor留出不给ce管理, 当然也就没有必要写额外信息了.
15楼 nanjianhui 2008-09-10 12:53发表 [回复]
你的方法可行,但是有个问题,在WinCE5.0下可以,但是在WinCE6.0下就不行了。因为在WinCE6.0中限制了IOControl的访问,只有有限的几个case是可以被应用层访问的,所以你的方法就不适用了,关于这个问题,我以前写过一篇blog叫“WinCE BSP中d的OEMIoControl介绍”,你可以看一下。你要是非要通过IOControl来访问,你就需要改public目录下的代码,这样好像不太好啊,你怎么release BSP给你的客户呢?
关于你说的要往Sector的额外信息写数据的问题,我认为没有什么必要,这块区域应该不属于WinCE可见的磁盘区域,所以你在FMD_GetInfo中,设置总共有多少个block的时候,把这块区域预留出来就可以了。
14楼 eagle1597 2008-09-10 10:40发表 [回复]
我来发表看法吧.
楼主的做法是可行的, 我也提供另一种做法, 那就是在oal层增加ioctl.
大家知道, 在ioctl_tab.h 中有KernelIOControl的一些OEM增加的额外IOCTL, 我们完全可以在这里增加一个例如IOCTL_HAL_READFLASE等的Oal函数, 在oal层中, 诸如调用FMD_ReadSecotr等是很方便的. 增加后, 应用层就可以通过KernelIOControl来这行flash的读写了.
还应该指出的是, 在对Flash的某个sector进行物理写后, 还应该对该sector的额外信息块写一定的数据以指示该flash存在数据,以至于不会被fal层把这个sector当作空闲而重写该sector.
Sector后的sector_info结构如下:
typedef struct _SectorMappingInfo
{
SECTOR_ADDR logicalSectorAddr;
BYTE bOEMReserved; // For use by OEM
BYTE bBadBlock; // Indicates if block is BAD
WORD fDataStatus;
} SectorMappingInfo, *PSectorMappingInfo;
而当我们对这个sector进行写后(不通过fal层),我们应该把上面结构体中的fDataStatus置一定的值, 以下值供参考:
#define FREE_SECTOR 0xFFFF // Indicates sector is free (erased)
#define DIRTY_SECTOR 0x0001 // Indicates sector is ready to erase
#define SECTOR_WRITE_IN_PROGRESS 0x0002 // Indicates sector write is in progress
#define SECTOR_WRITE_COMPLETED 0x0004 // Indicates sector write completed (data is valid)
#define COMPACTION_IN_PROGRESS 0x0008 // Indicates previous block is being compacted
#define COMPACTION_COMPLETED 0x0010 // Indicates previous block compaction completed
#define SECURE_WIPE_IN_
13楼 nanjianhui 2008-09-04 09:34发表 [回复]
在仿真的环境下,你最好在你的BSP中重写一个NandFlash的驱动,但是在实现驱动的FMD层中的函数的时候,你可以不对硬件操作,只对一块内存进行操作。也就是相当于一块RamDisk,但是使用NandFlash驱动来实现的。这样应该是可行的。
12楼 lskymate 2008-09-03 05:05发表 [回复]
看了版主這篇文章.真是收穫良多.
真的十分抱歉.在這裡很唐突的請教版主ㄧ些問題
如果版主方便的話.不知可否為小弟解惑..
非常感激.
小弟目前使用Wince 6.0
想在Emulator上.模擬Flash裝置(沒有板子..)
目前使用的BSP是DEVICEEMULATOR
而另外勾選的Catalog Item有
Binary Rom Image file System,
FAT File System
Storage Manager Control Panel Applet
Registry Storage-RAM-based Registry
RAM and ROM File System
Storage Device(全部選項).
PCI NAND Flash Driver.
在Build時成功.但attach target時會停住..
出現訊息如下.
4294784275 PID:400002 TID:10e0002 DEVICE!RegReadActivationValues RegQueryValueEx(Notify/BusPrefix) returned 2
4294784289 PID:400002 TID:1070002 Unknown: DEBUGCHK failed in file C:/ymzki/private/winceos/DRIVERS/msflash/src/./falmain.cpp at line 1409
想請問版主.Emulator下如何模擬像flash 這類的block driver.呢?
非常非常感激.
詩凱上
11楼 nanjianhui 2008-08-28 10:09发表 [回复]
你可以开一个Buffer,每次调用FMD_ReadSector的时候,把数据读到Buffer中,然后把该Bufffer的首地址传回,就可以了。
10楼 nanjianhui 2008-08-28 10:03发表 [回复]
你可以开一个Buffer,每次调用FMD_ReadSector的时候,把数据读到Buffer中,然后把该Bufffer的首地址传回,就可以了。
9楼 nanjianhui 2008-08-28 10:02发表 [回复]
你可以开一个Buffer,每次调用FMD_ReadSector的时候,把数据读到Buffer中,然后把该Bufffer的首地址传回,就可以了。
8楼 redeg 2008-08-27 10:35发表 [回复]
楼主,在调用FMD_ReadSector时如何逐一读取每块数据?该如何传递参数,我是新手,还希望楼主能解答.谢谢.
7楼 nanjianhui 2008-08-19 09:37发表 [回复]
楼上的,没错你是可以得到。问题是你在什么地方得到呢?是在应用程序中得到么,那你应该是得到了驱动函数的指针,你能在应用程序中直接调用么?
我没有试过,但是我认为不行。如果你实现了,请你写出具体步骤,谢谢。
6楼 slj0998 2008-08-07 18:09发表 [回复]
IOCTL_FMD_GET_INTERFACE:
用这个不就可以直接得到
PFMDInterface pInterface
读写直接用
pInterface->pReadSector = FMD_ReadSector;pInterface->pWriteSector = FMD_WriteSector;
难道不行吗?
5楼 nanjianhui 2008-08-06 12:32发表 [回复]
NandFlash驱动在WinCE6.0下是运行在内核模式的,所以应用程序想要直接调用内核下的驱动的API因该是不可能的。如果楼上有什么好的方法,并且已经实现了,欢迎指点。
4楼 freasy 2008-08-05 21:17发表 [回复]
只要暴露的足够多,应用程序什么事都可以做了
3楼 freasy 2008-08-05 21:15发表 [回复]
只要暴露的足够多,应用程序什么事都可以做了
2楼 nanjianhui 2008-07-30 17:54发表 [回复]
呵呵,你的方法在WinCE6.0上可行么??
1楼 guopeixin 2008-07-27 15:49发表 [回复]
1. 首先要说,你这样的方法很是巧妙,但是要修改驱动的代码,这样可能会引起一些未知的问题.
2. 你可以直接将fmd层的lib连接到ap中,然后直接在ap中对lib暴露出的接口对flash进行操作就可以了.
在网上的很多论坛中都看到有人提问:应用程序如何直接读写Flash的扇区,或者是类似的问题。总之,就是希望应用程序能够直接访问Flash设备,直接读写扇区的数据,或者作其他的操作。这几天没事,就尝试着做了一下,把我的方法介绍给大家。
先做个简单的介绍。WinCE支持Flash设备,一般指Nandflash或者是NORFlash,采用的架构一般是FAL+FMD架构,我们实现FMD相关的接口函数,Flash的驱动就算完成了。当WinCE启动以后,我们能够看到Flash设备的磁盘。我们可以操作磁盘上面的文件,但是不能直接操作flash设备,对Flash设备的操作无非就是:读,写,擦除,读ID。
现在开始介绍实现的方法。我们如果想在应用程序中直接调用FMD中的FMD_ReadSector(..),FMD_WriteSector(..),FMD_EraseBlock(..)是不太现实的。这里再补充一下,这三个函数分别是Flash的读扇区,写扇区,擦除块的函数。好像有点罗嗦了。但是我们可以在应用程序中调用到FMD_OEMIoControl(..)函数,这个是可以做到的。所以我们需要改一下Flash设备的驱动程序,也就是改Flash设备驱动中的FMD_OEMIoControl(..)这个函数。我的改动如下:
BOOL FMD_OEMIoControl(DWORD dwIoControlCode, PBYTE pInBuf, DWORD nInBufSize, PBYTE pOutBuf, DWORD nOutBufSize, PDWORD pBytesReturned)
{
PFMDInterface pInterface = (PFMDInterface)pOutBuf;
RETAILMSG(1, (TEXT("FMD_OEMIoControl: control code is 0x%x/r/n"), dwIoControlCode));
switch(dwIoControlCode)
{
case IOCTL_FMD_GET_INTERFACE:
if (!pOutBuf || nOutBufSize < sizeof(FMDInterface))
{
DEBUGMSG(1, (TEXT("FMD_OEMIoControl: IOCTL_FMD_GET_INTERFACE bad parameter(s)./r/n")));
return(FALSE);
}
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;
pInterface->pOEMIoControl = FMD_OEMIoControl;
break;
case 0xff123456:
FMD_ReadSector(..); //调用读Sector函数
break;
case 0xff654321:
FMD_WriteSector(..); //调用写Sector函数
break;
case 0xff123457:
FMD_EraseBlock(..); //调用擦除Block函数
break;
default:
DEBUGMSG(1, (TEXT("FMD_OEMIoControl: unrecognized IOCTL (0x%x)./r/n"), dwIoControlCode));
return(FALSE);
}
return(TRUE);
}
在FMD_OEMIoControl(..)函数里面增加了3个case,这3个case里面调用了读/写/擦除函数。至于Case的值,我是随便定义的。这样Flash设备的驱动部分就改完了。
在改完Flash驱动以后,我下面会提供两种方法,每一种方法都和Flash设备的注册表配置有关:
1. 以Nandflash为例,当然对于NORFlash来说大同小异,注册表配置如下:
[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/NANDFlash]
"Dll"="ep94xxnandflash.dll"
"Prefix"="DSK"
"Order"=dword:4
;"Ioctl"=dword:4
"Profile"="NSFlash"
"IClass"="{A4E7EDDA-E575-4252-9D6B-4195D48BB865}"
; Override names in default profile
[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/NSFlash]
"Name"="Ep94xx NAND Flash"
"Folder"="NANDFlash"
"PartitionDriver"="MSPart.dll"
"AutoMount"=dword:1
"AutoPart"=dword:1
"AutoFormat"=dword:1
[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/NSFlash/FATFS]
"EnableCache"=dword:1
"CacheSize"=dword:1000
"MountBootable"=dword:1
"Flags"=dword:00000024
"CheckForFormat"=dword:1
然后编写应用程序,主要就是通过CreateFile来打开DSK1:设备,然后通过DeviceIoControl(..)函数来调用FMD_OEMIoControl(..)函数,来达到直接读/写/擦除Flash设备的目的。应用程序代码如下:
HANDLE hFirm;
hFirm = CreateFile(TEXT("DSK1:"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if(hFirm == INVALID_HANDLE_VALUE)
{
printf("Open Flash Device Failed");
return 0;
}
iRet = DeviceIoControl(hFirm, 0xff123456, para1, para2, para3, para4, para5, para6); //Read Flash Sector
iRet = DeviceIoControl(hFirm, 0xff654321, para1, para2, para3, para4, para5, para6); //Write Flash Sector
iRet = DeviceIoControl(hFirm, 0xff123457, para1, para2, para3, para4, para5, para6); //Erase Flash Block
printf("DeviceIoControl OK/r/n");
while(1)
;
通过上面的应用程序,就能够调用到Flash设备驱动中的FMD_OEMIoControl(..)函数,这样根据不同的case就可以调用读/写/擦除函数了。
2. 以Nandflash为例,当然对于NORFlash来说大同小异,注册表配置如下:
[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/NANDFlash]
"Dll"="ep94xxnandflash.dll"
"Prefix"="DSK"
"Order"=dword:4
;"Ioctl"=dword:4
"Profile"="NSFlash"
"IClass"="{A4E7EDDA-E575-4252-9D6B-4195D48BB865}"
; Override names in default profile
[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/NSFlash]
"Name"="Ep94xx NAND Flash"
"Folder"="NANDFlash"
"PartitionDriver"="MSPart.dll"
"AutoMount"=dword:1
"AutoPart"=dword:1
"AutoFormat"=dword:1
[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/NSFlash/FATFS]
"EnableCache"=dword:1
"CacheSize"=dword:1000
"MountBootable"=dword:1
"Flags"=dword:00000024
"CheckForFormat"=dword:1
[HKEY_LOCAL_MACHINE/System/StorageManager/AutoLoad/NSFlash]
"DriverPath"="Drivers//BuiltIn//NANDFlash"
"LoadFlags"=dword:0
"BootPhase"=dword:1
然后编写应用程序,主要就是通过OpenStore来打开NSFlash,然后通过DeviceIoControl(..)函数来调用FMD_OEMIoControl(..)函数,来达到直接读/写/擦除Flash设备的目的。应用程序代码如下:
HANDLE hFirm;
hFirm = OpenStore(L"NSFlash");
if(hFirm == INVALID_HANDLE_VALUE)
{
printf("Open Flash Device Failed");
return 0;
}
iRet = DeviceIoControl(hFirm, 0xff123456, para1, para2, para3, para4, para5, para6);
iRet = DeviceIoControl(hFirm, 0xff654321, para1, para2, para3, para4, para5, para6);
iRet = DeviceIoControl(hFirm, 0xff123457, para1, para2, para3, para4, para5, para6);
printf("DeviceIoControl OK/r/n");
while(1)
;
通过这种方法,也可以在应用程序中调用到FMD_OEMIoControl(..)函数,从而达到直接访问Flash设备的目的。
总结一下,上面的两种方法大致原理其实是一样的,都是通过DeviceIoControl函数来调用FMD_OEMIoControl函数,然后达到直接访问Flash驱动的目的,这样就可以在应用程序中直接读/写/擦除Flash设备了。
最后需要注意的是:你的Flash驱动里面需要对读/写/擦除等直接操作Flash硬件的函数进行保护,因为Flash设备应该是由WinCE的文件系统来管理的,而现在你的应用程序也可以直接访问它了,所以保险起见,添加互斥量保护避免访问冲突。
上面的所有实现,都是在WinCE6.0上面做得,相信在WinCE5.0上面应该差不多。
28楼 suzhbruce 2010-09-13 17:30发表 [回复]
请问版主nanjianhui:
感谢你的分享, 现要写入数据到NandFlash, 那你上面提到的那个 iRet = DeviceIoControl(hFirm, 0xff123456, para1, para2, para3, para4, para5, para6)调用中, para1的写入数据具体格式是怎样的啊..? 难道是SG_REQ格式? 还是其它 ?
可否举例说明一下? 感谢!!
27楼 nanjianhui 2009-09-15 17:22发表 [回复]
我认为也是可以的,不过我没有试过。你的问题好像是因为你的驱动中没有识别出正确的IOcontrol操作码。
26楼 ashazhuang 2009-09-09 11:19发表 [回复]
WINCE5.0 无法用楼主的方法吧。我在fmd_iocontrol()添加自己的case. 出现错误提示“DSK_iocontrol unknown code (.....)”
25楼 nanjianhui 2008-11-13 09:50发表 [回复]
这里有Nandflash的参考代码,你可以看一下:
/WINCE600/PUBLIC/COMMON/OAK/DRIVERS/BLOCK/MSFLASHFMD/SDNPCI
24楼 redeg 2008-11-09 21:29发表 [回复]
楼主,在PB的MSFLASHFMD目录下哪个是NAND FLASH的驱动?FASL目录好像是NOR的驱动对吗?
23楼 lskymate 2008-11-07 18:18发表 [回复]
版主.謝謝您
小弟目前改用deviceIoControl
來取代readFile,writeFile已可成功
對flash存取.
感激
22楼 lskymate 2008-11-06 17:43发表 [回复]
(接續上篇)
flashReadBuffer,
512,
&flashReadCounter,
NULL);
if (readFlashOk == FALSE)
{RETAILMSG(1, (L" Read Mounted Volume Failure!! /n" )); exit(-1);}
// ReadFile - END
真的不曉得為什麼會出問題..
可以在為小弟指點一下嗎?
非常感激
而關於 註冊表的資訊如下
[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/SKYFMD]
@=""
"Prefix"="DSK"
"Dll"="SKYFMD.dll"
"Index"=dword:2
"IClass"=multi_sz:"{A4E7EDDA-E575-4252-9D6B-4195D48BB865}"
"Profile"="SKYFMD"
[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/SKYFMD]
"DefaultFileSystem"="FATFS"
"PartitionDriver"="mspart.dll"
"Name"="SKYFALFMD"
"AutoMount"=dword:1
"AutoPart"=dword:1
"AutoFormat"=dword:1
"Ioctl"=dword:4
感激
21楼 lskymate 2008-11-06 17:43发表 [回复]
(接續上篇)
flashReadBuffer,
512,
&flashReadCounter,
NULL);
if (readFlashOk == FALSE)
{RETAILMSG(1, (L" Read Mounted Volume Failure!! /n" )); exit(-1);}
// ReadFile - END
真的不曉得為什麼會出問題..
可以在為小弟指點一下嗎?
非常感激
而關於 註冊表的資訊如下
[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/SKYFMD]
@=""
"Prefix"="DSK"
"Dll"="SKYFMD.dll"
"Index"=dword:2
"IClass"=multi_sz:"{A4E7EDDA-E575-4252-9D6B-4195D48BB865}"
"Profile"="SKYFMD"
[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/SKYFMD]
"DefaultFileSystem"="FATFS"
"PartitionDriver"="mspart.dll"
"Name"="SKYFALFMD"
"AutoMount"=dword:1
"AutoPart"=dword:1
"AutoFormat"=dword:1
"Ioctl"=dword:4
感激
20楼 lskymate 2008-11-06 17:39发表 [回复]
版主您好
目前小弟希望可以透過File System來對Flash存取.
也就是說寫一支AP.利用Logical Sector Address去
對Flash做讀寫的動作.
目前是計畫用 writeFile及readFile來寫入及讀取.
但會發生exception.
目前 CreateFile 的程式如下
//----------------- CreateFile -----------------
#define FLASHPATH TEXT("//Mounted Volume//Vol:")
hFlash = CreateFile (FLASHPATH,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFlash == INVALID_HANDLE_VALUE)
{ RETAILMSG(1, (L"Open Mounted Volume Failure!!/n" )); exit(-1); }
// CreateFile - END
讀取資料 ReadFile 的程式如下
//----------------- ReadFile -----------------
flashReadBuffer = (char *) malloc (sizeof(char)*512); //接收資料的buffer
memset (flashReadBuffer, 0, sizeof(char)*512);
flashAddress = SetFilePointer (hFlash,
0,
NULL,
FILE_BEGIN);
readFlashOk = ReadFile (hFlash, //執行到這裡時將會發生錯誤(First - chance exception)
19楼 lskymate 2008-09-16 20:36发表 [回复]
謝謝版主.
我在Storage Manager Control Panel Applet有看到了.
非常感激
18楼 nanjianhui 2008-09-16 12:38发表 [回复]
你可以在控制面板里面,看看有没有一个Storage的Manager,在里面应该可以看到,并且作mount。
17楼 lskymate 2008-09-12 19:28发表 [回复]
版主您好.
我發現,C:/WINCE600/PUBLIC/COMMON/OAK/DRIVERS/BLOCK/MSFLASHFMD/RAM 下有一個用 virtualalloc 的作法來產生2M的ram Flash.
但我不知如何使用.所以把他拉出來
放到DEVICEEMULATOR(BSP)下將他當成driver
並BUILD成功.然後attach Emulator時.也可以順利
看到自己在FMD.c加的資訊.
但在EMULATOR上.並沒有看到關於這個 flash device .的相關資訊.請問我要如何像 linux 那樣 mount這個
flash device 呢?
非常感激
16楼 eagle1597 2008-09-10 16:33发表 [回复]
1: "因为在WinCE6.0中限制了IOControl的访问"
这个我不了解, 我的确只在5.0中做过. 谢谢你的指出.
2: 如果你把srctor留出不给ce管理, 当然也就没有必要写额外信息了.
15楼 nanjianhui 2008-09-10 12:53发表 [回复]
你的方法可行,但是有个问题,在WinCE5.0下可以,但是在WinCE6.0下就不行了。因为在WinCE6.0中限制了IOControl的访问,只有有限的几个case是可以被应用层访问的,所以你的方法就不适用了,关于这个问题,我以前写过一篇blog叫“WinCE BSP中d的OEMIoControl介绍”,你可以看一下。你要是非要通过IOControl来访问,你就需要改public目录下的代码,这样好像不太好啊,你怎么release BSP给你的客户呢?
关于你说的要往Sector的额外信息写数据的问题,我认为没有什么必要,这块区域应该不属于WinCE可见的磁盘区域,所以你在FMD_GetInfo中,设置总共有多少个block的时候,把这块区域预留出来就可以了。
14楼 eagle1597 2008-09-10 10:40发表 [回复]
我来发表看法吧.
楼主的做法是可行的, 我也提供另一种做法, 那就是在oal层增加ioctl.
大家知道, 在ioctl_tab.h 中有KernelIOControl的一些OEM增加的额外IOCTL, 我们完全可以在这里增加一个例如IOCTL_HAL_READFLASE等的Oal函数, 在oal层中, 诸如调用FMD_ReadSecotr等是很方便的. 增加后, 应用层就可以通过KernelIOControl来这行flash的读写了.
还应该指出的是, 在对Flash的某个sector进行物理写后, 还应该对该sector的额外信息块写一定的数据以指示该flash存在数据,以至于不会被fal层把这个sector当作空闲而重写该sector.
Sector后的sector_info结构如下:
typedef struct _SectorMappingInfo
{
SECTOR_ADDR logicalSectorAddr;
BYTE bOEMReserved; // For use by OEM
BYTE bBadBlock; // Indicates if block is BAD
WORD fDataStatus;
} SectorMappingInfo, *PSectorMappingInfo;
而当我们对这个sector进行写后(不通过fal层),我们应该把上面结构体中的fDataStatus置一定的值, 以下值供参考:
#define FREE_SECTOR 0xFFFF // Indicates sector is free (erased)
#define DIRTY_SECTOR 0x0001 // Indicates sector is ready to erase
#define SECTOR_WRITE_IN_PROGRESS 0x0002 // Indicates sector write is in progress
#define SECTOR_WRITE_COMPLETED 0x0004 // Indicates sector write completed (data is valid)
#define COMPACTION_IN_PROGRESS 0x0008 // Indicates previous block is being compacted
#define COMPACTION_COMPLETED 0x0010 // Indicates previous block compaction completed
#define SECURE_WIPE_IN_
13楼 nanjianhui 2008-09-04 09:34发表 [回复]
在仿真的环境下,你最好在你的BSP中重写一个NandFlash的驱动,但是在实现驱动的FMD层中的函数的时候,你可以不对硬件操作,只对一块内存进行操作。也就是相当于一块RamDisk,但是使用NandFlash驱动来实现的。这样应该是可行的。
12楼 lskymate 2008-09-03 05:05发表 [回复]
看了版主這篇文章.真是收穫良多.
真的十分抱歉.在這裡很唐突的請教版主ㄧ些問題
如果版主方便的話.不知可否為小弟解惑..
非常感激.
小弟目前使用Wince 6.0
想在Emulator上.模擬Flash裝置(沒有板子..)
目前使用的BSP是DEVICEEMULATOR
而另外勾選的Catalog Item有
Binary Rom Image file System,
FAT File System
Storage Manager Control Panel Applet
Registry Storage-RAM-based Registry
RAM and ROM File System
Storage Device(全部選項).
PCI NAND Flash Driver.
在Build時成功.但attach target時會停住..
出現訊息如下.
4294784275 PID:400002 TID:10e0002 DEVICE!RegReadActivationValues RegQueryValueEx(Notify/BusPrefix) returned 2
4294784289 PID:400002 TID:1070002 Unknown: DEBUGCHK failed in file C:/ymzki/private/winceos/DRIVERS/msflash/src/./falmain.cpp at line 1409
想請問版主.Emulator下如何模擬像flash 這類的block driver.呢?
非常非常感激.
詩凱上
11楼 nanjianhui 2008-08-28 10:09发表 [回复]
你可以开一个Buffer,每次调用FMD_ReadSector的时候,把数据读到Buffer中,然后把该Bufffer的首地址传回,就可以了。
10楼 nanjianhui 2008-08-28 10:03发表 [回复]
你可以开一个Buffer,每次调用FMD_ReadSector的时候,把数据读到Buffer中,然后把该Bufffer的首地址传回,就可以了。
9楼 nanjianhui 2008-08-28 10:02发表 [回复]
你可以开一个Buffer,每次调用FMD_ReadSector的时候,把数据读到Buffer中,然后把该Bufffer的首地址传回,就可以了。
8楼 redeg 2008-08-27 10:35发表 [回复]
楼主,在调用FMD_ReadSector时如何逐一读取每块数据?该如何传递参数,我是新手,还希望楼主能解答.谢谢.
7楼 nanjianhui 2008-08-19 09:37发表 [回复]
楼上的,没错你是可以得到。问题是你在什么地方得到呢?是在应用程序中得到么,那你应该是得到了驱动函数的指针,你能在应用程序中直接调用么?
我没有试过,但是我认为不行。如果你实现了,请你写出具体步骤,谢谢。
6楼 slj0998 2008-08-07 18:09发表 [回复]
IOCTL_FMD_GET_INTERFACE:
用这个不就可以直接得到
PFMDInterface pInterface
读写直接用
pInterface->pReadSector = FMD_ReadSector;pInterface->pWriteSector = FMD_WriteSector;
难道不行吗?
5楼 nanjianhui 2008-08-06 12:32发表 [回复]
NandFlash驱动在WinCE6.0下是运行在内核模式的,所以应用程序想要直接调用内核下的驱动的API因该是不可能的。如果楼上有什么好的方法,并且已经实现了,欢迎指点。
4楼 freasy 2008-08-05 21:17发表 [回复]
只要暴露的足够多,应用程序什么事都可以做了
3楼 freasy 2008-08-05 21:15发表 [回复]
只要暴露的足够多,应用程序什么事都可以做了
2楼 nanjianhui 2008-07-30 17:54发表 [回复]
呵呵,你的方法在WinCE6.0上可行么??
1楼 guopeixin 2008-07-27 15:49发表 [回复]
1. 首先要说,你这样的方法很是巧妙,但是要修改驱动的代码,这样可能会引起一些未知的问题.
2. 你可以直接将fmd层的lib连接到ap中,然后直接在ap中对lib暴露出的接口对flash进行操作就可以了.