WINCE4.2到5.0(3)
差不多完成了全部工作,系统也能正常运行。还是记录下遇到的一些问题,以备将来查找。
- NK.bin 文件大小的问题,如果使用中文环境,最后生成的NK.bin大小应该在30M左右,使能默认的英文环境,大小在17M左右。事实上增加了catalog, 并不会另nk.bin文件级数增长,大多数都是几十K大小。如增加对standard sdk的支持,并不会增大多少容量的flash。
- CS8900 驱动,将4.2的拿来用,编译排错后,发现只是可以在nk.bin烧录进flash并启动后,可以正常使用,下电重启后,连cs8900网卡都找不到。这 个问题费了我太多的时间,几乎都想放弃了,后来终于解决了:在是cs8900初始化的时候,先进行读取cs8900的id等硬件信息,然后再初始化 8900用到的总线(bank5)。这个的顺序应该反一下,先进行对总线的初始化,再读ID与初始化8900的硬件信息。具体在驱动的cs8900.c文 件的CS8900Initialize()函数内,将对CSInit()的调用放在总线与寄存器初始化之后进行即可。那为什么在4.2下,即使是这样的反 序调用也是可以的呢,因为4.2的内核在启动时,我就对cs8900用到的总线进行了初始化,而5.0的内核我没有去处理,这样层次、结构清晰了然。
- CS8900中断,接上次写的一篇日记。5.0的中断处理与4.2有很大的不同。我用的是EINT11中断,需要做的工作是:
1>在网卡驱动中对8900用到的EINT11进行初始化。
2>在BSPIntrInit()函数中,对EINT11与SYSINTR_ETHERNET进行静态映射。
3> 修改cs8900相关的注册表信息,将键值SysIntr和InterruptNumber赋值为SYSINTR_ETHERNET对应的十六进制值。这 里为什么有两个键值,实际上SysIntr是5.0的,而InterruptNumber是4.2下的,我为了节省时间,写了两个。不知道是pdd层还是 mdd层使用了这个键值,查起来也方便。
4>修改cs8900注册表中的IoBaseAddress键值
5>做到以上四个步 骤后,已经可以将cs8900驱动起来了。要稳定工作,还不够,因为这里有个特定的bug。cs8900中断后,将会产生一个中断标志,然后内核产生中断 后去读数据,读完后再去清除cs8900的这个中断标志。如果内核不清除这个标志,cs8900下次再有数据传输时,将不会产生中断给内核。了解这点后, 再看内核的操作流程。内核在接到中断并读取数据后并清除cs8900的中断标志后,将会调用OEMInterruptEnable()函数,以再次开放 cs8900对应的中断,而这个OEMInterruptEnable()会依次清除SRCPND,INTPND,INTMSK,EINTMSK等寄存 器。那么如果内核在中断并读取CS8900数据并清除8900的中断标志,与,调用OEMInterruptEnable()函数之间这时cs8900接 收数据并产生中断这样一种非典型性的情况下,在这种情况下,由于8900产生了中断标志,然后OEMInterruptEnable()函数清除了 SRCPND,INTPND对应的标志,使得内核无法知道有中断产生了,而cs8900的中断标志又一直存在,这样的由于cs8900的这一特性,将会导 致cs8900不能工作了。事实证明,这种情况并不是不常见,而是很常见,经常会发生这样的情况。解决方法是在OEMInterruptEnable() 函数中不要每次对都SRCPND,INTPND进行清除。由于是5.0的系统,跟4.2有很大的不一样,在5.0中 OEMInterruptEnable()会调用OalIntrEnableIrqs(),这个函数里,会调用BSPIntrEnableIrq()函数 给BSP一个操作的机会,那就可以在BSPIntrEnableIrq()里更改,我把它改造成了这样:(原来的函数就是打印两个信息)BOOL g_EthInited = FALSE;
UINT32 BSPIntrEnableIrq(UINT32 irq)
{
UINT32 msk;
S3C2410X_INTR_REG * pIntrRegs;
S3C2410X_IOPORT_REG * pPortRegs;
pIntrRegs = (S3C2410X_INTR_REG*)OALPAtoVA(S3C2410X_BASE_REG_PA_INTR,FALSE);
pPortRegs = (S3C2410X_IOPORT_REG*)OALPAtoVA(S3C2410X_BASE_REG_PA_IOPORT,FALSE);
if (irq == IRQ_EINT11)
{
if (g_EthInited == FALSE)
{
RETAILMSG(1,(TEXT("ethernet irq enable... by xiaoyunsoft 2008-09-25/r/n")));
msk = 1 << (irq - IRQ_EINT4 + 4);
OUTREG32(&pPortRegs->EINTPEND, msk);
msk = 1 << IRQ_EINT8_23;
OUTREG32(&pIntrRegs->SRCPND,msk);
if ((INREG32(&pIntrRegs->INTPND) & msk) != 0)
{
OUTREG32(&pIntrRegs->INTPND, msk);
}
g_EthInited = TRUE;
}
msk = 1<<(irq-IRQ_EINT4+4);
CLRREG32(&pPortRegs->EINTMASK, msk);
CLRREG32(&pIntrRegs->INTMSK, 1 << IRQ_EINT8_23);
return OAL_INTR_IRQ_UNDEFINED ;
}
OALMSG(OAL_INTR&&OAL_VERBOSE, (L"-BSPIntrEnableIrq(irq = %d)/r/n", irq));return irq;
}
一定要注意上面的那个粗体部份的返回值,这里是根据此函数的调用者OalIntrEnableIrqs()功能写的 :BOOL OALIntrEnableIrqs(UINT32 count, const UINT32 *pIrqs)
{
BOOL rc = TRUE;
UINT32 i, mask, irq;OALMSG(OAL_INTR&&OAL_FUNC, (
L"+OALIntrEnableIrqs(%d, 0x%08x)/r/n", count, pIrqs
));for (i = 0; i < count; i++) {
#ifndef OAL_BSP_CALLBACKS
irq = pIrqs[i];
#else
// Give BSP chance to enable irq on subordinate interrupt controller
irq = BSPIntrEnableIrq(pIrqs[i]);
#endif
if (irq == OAL_INTR_IRQ_UNDEFINED) continue;
// Depending on IRQ number use internal or external mask register
if (irq <= IRQ_ADC) {
// Use interrupt mask register
CLRREG32(&g_pIntrRegs->INTMSK, 1 << irq);
} else if (irq <= IRQ_EINT7) {
// Use external mask register
CLRREG32(&g_pIntrRegs->INTMSK, 1 << IRQ_EINT4_7);
CLRREG32(&g_pPortRegs->EINTMASK, 1 << (irq - IRQ_EINT4 + 4));
} else if (irq <= IRQ_EINT23) {
// Use external mask register
mask = 1 << (irq - IRQ_EINT4 + 4);
OUTREG32(&g_pPortRegs->EINTPEND, mask);
CLRREG32(&g_pPortRegs->EINTMASK, mask);
mask = 1 << IRQ_EINT8_23;
if ((INREG32(&g_pIntrRegs->INTPND) & mask) != 0) {
OUTREG32(&g_pIntrRegs->INTPND, mask);
}
CLRREG32( &g_pIntrRegs->INTMSK, 1 << IRQ_EINT8_23);
} else {
rc = FALSE;
}
}OALMSG(OAL_INTR&&OAL_FUNC, (L"-OALIntrEnableIrqs(rc = %d)/r/n", rc));
return rc;
} - 上次留下的问题,关于cs8900能生成lib,而不是dll文件,解决办法是像4.2的增加cs8900r一样,以对nmake命令的支持。但是我没有用这个方法,因为太麻烦,有更简单的方法:在cs8900r目录中找到source文件,对其进行更改:
PREPROCESSDEFFILE=1
DEFFILE=cs8900.def
TARGETDEFNAME=cs8900
TARGETNAME=cs8900
TARGETTYPE=DYNLINK
RELEASETYPE=PLATFORM
…
TARGETLIBS= /
$(_COMMONSDKROOT)/lib/$(_CPUINDPATH)/coredll.lib /
$(_COMMONSDKROOT)/lib/$(_CPUINDPATH)/ndis.lib /
$(_COMMONOAKROOT)/lib/$(_CPUINDPATH)/ceddk.lib /
SOURCELIBS= /
$(_PROJECTROOT)/cesysgen/sdk/lib/armv4i/retail/ndis.lib /
DLLENTRY=DllEntry
…
像这样的source文件在每个需要编译的目录下都会有一个,是为了给make提供编译“内容”的,很重要。从它的一些关键字也可以看出大概意思,具体可以参改相关的文档,make这样的命令在linux下应用很广。 - NandFlash的移植
我 发现在5.0自带的bsp中的nandflash不能正常运行,也可能是我没有花更多的时间去测试。nandflash的驱动在4.2是位于bsp中的 drivers目录内,由于nandflash的驱动是eboot与kernel共享的,所以在5.0下,此驱动被移动到了bsp/src/common /下面。我把4.2的驱动拷贝到了5.0的drivers目录下,更改drivers目录下的dirs文件,将nandflsh目录加入其内,使得在 drivers目录执行build命令时,编译器也会编译nandflsh目录下的文件。编译后发现不行,有好些语法错误,大概是volatile关键 字、还有两个重复定义的宏,排除后编译还是不行,查了下,是source文件也需要调整,注释掉不必要的预编译条件,就OK了。注意你的 nandflash驱动生成最终的dll文件名,因为在实现注册表永久保存时需要用到。 - 注册表永久保存
对当前pb工程加入必要的catalog,如“基于永久保存的注册表” ,binfs文件系统的支持等,这个图是5.0实现永久保存:
然后就是对platform.reg进行修改,跟4.2下的差不多,贴上相关代码:; HIVE BOOT SECTION
[HKEY_LOCAL_MACHINE/Drivers/Resources/IRQ]
"Identifier"=dword:1
"Minimum"=dword:1
"Space"=dword:20
"Ranges"="1-0x20"
; "Shared"=""[HKEY_LOCAL_MACHINE/Drivers/Resources/IO]
"Identifier"=dword:2
"Minimum"=dword:0
"Space"=dword:10000
"Ranges"="0-0xFFFF"
; END HIVE BOOT SECTION; @CESYSGEN IF FILESYS_FSREGHIVE
; HIVE BOOT SECTION; Valid Bits for Flags registry value
; If no flags are set, the hive will be stored in the object store.
;
; 0x00000001 Start storage manager in boot phase 1 for hive-based registry
; 0x00000002 Start device manager in boot phase 1 for hive-based registry
; 0x00000004 Start storage manager in boot phase 1 for registry in
; external ROM (such as BINFS)
; 0x00000008 Start device manager in boot phase 1 for registry in
; external ROM (such as BINFS)[HKEY_LOCAL_MACHINE/init/BootVars]
; "SystemHive"="Documents and Settings//system.hv"
; "ProfileDir"="Documents and Settings"
; "Flags"=dword:3
"SYSTEMHIVE"="system.hv"
"Start DevMgr"=dword:1
"RegistryFlags"=dword:1
"Flags"=dword:1000
"DefaultUser"="default"; END HIVE BOOT SECTION
; @CESYSGEN ENDIF FILESYS_FSREGHIVE; @CESYSGEN IF FILESYS_FSREGHIVE
; HIVE BOOT SECTION
;[HKEY_LOCAL_MACHINE/Drivers/BuiltIn/FlashDisk]
; "Profile"="FlashDisk"
; "IClass"=multi_sz:"{A4E7EDDA-E575-4252-9D6B-4195D48BB865}"
; "Order"=dword:0
; "FriendlyName"="xiaoyunsoft NAND Flash Driver"
; "Dll"="flashdisk.dll"
; "Prefix"="DSK"
; "Ioctl"=dword:4
; "MountFlags"=dword:11
; "BootPhase"=dword:0
; "Flags"=dword:1000[HKEY_LOCAL_MACHINE/System/StorageManager/PartitionTable]
"21"="BINFS"[HKEY_LOCAL_MACHINE/System/StorageManager/BINFS]
"Folder"="BINFS"
"FriendlyName"="Bin FileSystem"
"Dll"="binfs.dll"
"MountFlags"=dword:11
"BootPhase"=dword:0
"Flags"=dword:1000[HKEY_LOCAL_MACHINE/System/StorageManager/AutoLoad/FlashDrv]
"DriverPath"="Drivers//BlockDevice//FlashDrv"
"LoadFlags"=dword:1
"MountFlags"=dword:11
"BootPhase"=dword:0
"Flags"=dword:1000[HKEY_LOCAL_MACHINE/Drivers/BlockDevice/FlashDrv]
"Prefix"="DSK"
"Dll"="FlashDrv.dll"
"Order"=dword:0
"Ioctl"=dword:4
"Profile"="FlashDrv"
"FriendlyName"="MS Flash Driver"
"MountFlags"=dword:11
"BootPhase"=dword:0
"Flags"=dword:1000[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/FlashDrv]
"DefaultFileSystem"="BINFS"
"PartitionDriver"="mspart.dll"
"AutoMount"=dword:1
"AutoPart"=dword:1
"AutoFormat"=dword:1
"Folder"="ResidentFlash"
"Name"="xiaoyunsoft Flash Disk"
"BootPhase"=dword:0
"Flags"=dword:1000
"MountHidden"=dword:0[HKEY_LOCAL_MACHINE/System/StorageManager/Profiles/FlashDrv/FATFS]
"MountFlags"=dword:2
"Flags"=dword:1000[HKEY_LOCAL_MACHINE/System/StorageManager/FATFS]
"MountFlags"=dword:0
"Flags"=dword:1000; END HIVE BOOT SECTION
IF BSP_NOETHER !
IF SYSGEN_ETHERNET
#include "$(_TARGETPLATROOT)/src/drivers/cs8900r/cs8900.reg"
ENDIF
ENDIF
注意看最后几行,它跟永久保存注册表没有关系,只是通过#include来包函一个外部的cs8900相关的驱动。 - 关于将空闲flash做为分区。我觉得还是跟eboot有关系,我用的还是4.2下的eboot,里面有我增加的新建分区功能代码,而且在4.2也是可以正常工作的。主要还是对catalog的操作,具体也可以参照上面一张图示。