??xml version="1.0" encoding="utf-8" standalone="yes"?>色综合久久综精品,波多野结衣中文字幕久久,国产精品免费久久http://www.shnenglu.com/milkyway/category/3375.html多看,多想,多实?/description>zh-cnTue, 20 May 2008 03:36:23 GMTTue, 20 May 2008 03:36:23 GMT60VirtualCopy in WinCE6.0 http://www.shnenglu.com/milkyway/articles/22195.html相思酸中有?/dc:creator>相思酸中有?/author>Wed, 18 Apr 2007 02:56:00 GMThttp://www.shnenglu.com/milkyway/articles/22195.htmlhttp://www.shnenglu.com/milkyway/comments/22195.htmlhttp://www.shnenglu.com/milkyway/articles/22195.html#Feedback1http://www.shnenglu.com/milkyway/comments/commentRss/22195.htmlhttp://www.shnenglu.com/milkyway/services/trackbacks/22195.htmlhttp://blog.csdn.net/fredzeng/archive/2007/04/04/1551898.aspx

在CE4.2/5.0里面滚打多年的兄弟应该经常用q个函数吧。这个函数方侉K动和应用E序范围M的物理地址Q包括物理内存啊Q设备控制器的寄存器啊,甚至GPIO也可以在AP里面随便拉上拉下?/font>

q个函数虽然方便Q但是ƈ不安全,你想你好不容易把一个功能完善的imagelbuild出来了,l果到了一个写AP?#8220;高手”Q把你的寄存器和׃n内存中的数据修改得一塌糊涂,最后报出bug来说你驱动的你会不会晕倒!

q好从CE6.0开始我们可以安枕无忧了Q因为AP再也不能调用VirtualCopy函数来直接访问物理地址了,但因此带来了一些应用上的不ѝ?/font>

VirtualCopy的限制来源于CE6.0之后kernel的巨大变革,在CE5.0之前的Windows CE操作pȝ中,kenrel׃仅是kern.exeQnk.exeQ,q个exe其实是OAL、KITL和Kernel三个的合体,nk.exe是运行于内核模式Qkernel modeQ,也就h了访问特D地址的权限,然后除此之外的代码默认都是运行于用户模式Quser modeQ,所以它们的驱动和AP都是{的,都在用户模式q行Q要q行在kernel模式也可以,调用一个API SetKmodeQ)p了。因为驱动是肯定要访问物理地址的,所以CE5.0以前的OS都是q行用户模式的程式访问物理地址的,然后又ؓ了方便做从物理地址到虚拟地址的映,提供了一pd的帮助函敎ͼvirtualcopy是最常用的函C一?/font>

CE6.0开始,kernel模式变得比较正规Q类g台式Z的windowspȝ了,驱动和ap的权限是严格区分的,大部分的驱动E序q行在kernel模式Q它们可以用virtualcopyd物理地址对应的物理设备,但用h式的AP从此没有直接访问物理地址的权限,virtualcopy每次调用都会p|q回?/font>

在这里还要注意的是,其实q不是用h式就不能使用virtualcopyQvirtualcopy只是不能在用h式的AP中用,但是却还可以在用h式的驱动使用Q但是在用户模式的驱动中使用也有条gQ那是必须在对应的注册表中讄可以讉K的内存地址的范围才行?/font>

在某些场合,一些特D功能的AP实需要访问物理地址的,比如讄保存物理内存指定位置的全局变量Q开发读写GPIO的测试工L{。在q种情况下一U简单的Ҏ是实C个最单的跑在kernel模式的流驱动Q提供一个deviceiocontrol的接口来帮助AP甌对应于物理内存地址的虚拟内存地址?/font>

除了virtualcopy之外QCE6下还有很多API是AP和user模式的驱动不能调用的Q给大家参考一下,大家要把CE50下的APUL?.0下一定要注意扑ֈ替代

Virtual Memory APIs
CeVirtualSharedAlloc
LockPages
LockPagesEx
UnlockPages
UnlockPagesEx
VirtualAllocCopyEx
VirtualCopyEx
VirtualSetAttributes
CreateStaticMapping
NKDeleteStaticMapping
VirtualCopy

File System APIs
ReadRegistryFromOEM
SetStoreQueueBase
WriteRegistryToOEM

Power APIs
PowerOffSystem Q很多测试AP用到Q?/font>

Miscellaneous APIs
SetOOMEvent



]]>
Windows CE6 新特?/title><link>http://www.shnenglu.com/milkyway/articles/22191.html</link><dc:creator>相思酸中有?/dc:creator><author>相思酸中有?/author><pubDate>Wed, 18 Apr 2007 01:57:00 GMT</pubDate><guid>http://www.shnenglu.com/milkyway/articles/22191.html</guid><wfw:comment>http://www.shnenglu.com/milkyway/comments/22191.html</wfw:comment><comments>http://www.shnenglu.com/milkyway/articles/22191.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/milkyway/comments/commentRss/22191.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/milkyway/services/trackbacks/22191.html</trackback:ping><description><![CDATA[来自 <a >http://www.winbile.net/BBS/1015270/ShowPost.aspx</a><br><br>重新设计了KernelQ支持的q程C32个扩展到32000 <br>每个q程的地址I间?2MB扩展?GB <br>很多pȝ模块Q如文gpȝ和设备管理器Q将q行在kernel模式QOAL也从kernel独立出来Qdriver可以q行在kernel模式和user模式 <br>Visual Studio 2005专业版将包括一个被UCؓPlatform Builder的功能强大的插gQ它是一个专门ؓ嵌入式^台提供的“集成开发环?#8221;。这个集成开发环境得整个开发链融ؓ一体,q提供了一个从讑֤到应用都易于使用的工P极大地加速了讑֤开发的上市 <br>Windows Embedded CE 6.0加入了新的单元核心数据和语音lg <br>Windows Embedded CE 6.0包含的组件更便于开发者创建通过Windows Vista™内置功能无线q接到远E桌面共享体验的投媄?br><br>来自 <a >http://develop.csai.cn/ebd/200702031135001231.htm</a><br><br><a target=_blank><u><font color=#356299>Windows</font></u></a> CE 6.0大幅改变了核心定址以及<a target=_blank><u><font color=#356299>资源</font></u></a>分配的机Ӟ旧版CE同时间只能有32个程序执行于各自分配?2MB虚拟存储器空间中Q?.0版则是大q放宽了限制Q最大可同时执行32,000个程序,而且每个E序可拥有独立分配的2GB虚拟存储器,在此同时Q核心服务、硬件装|的驱动E序、视H绘图以及事件子pȝ、档案系l等服务都被转移到系l核心保留空间中。不q这L改变也会带给使用者疑虑,毕竟q去NT 4.0曾l上演过cM的戏码,驱动程序从使用者模式{Ud核心模式Q虽然可以大q改q应用的速度Q但是一个体质不良的驱动E序Q可能就会拖垮整个系l,因此在硬仉动程序的开发上Q就必需要有个有?a target=_blank><u><font color=#356299>标准</font></u></a>来规范,最好还要导入如WHQL之类的驱动程序验证服务,以避免媄响整个系l的E_性? <p>  <a target=_blank><u><font color=#356299>Windows</font></u></a> CE 6.0的新变革</p> <p>  <a target=_blank><u><font color=#356299>Windows</font></u></a> CE 6.0依旧把眼光投注在ARM架构中,新的BSP与编译器也都支持了ARM的最Cp,但是其它<a target=_blank><u><font color=#356299>嵌入?/font></u></a>处理器的支持也没有被忽视Q威盛公司最新的处理器也在不久前宣称支持?a target=_blank><u><font color=#356299>Windows</font></u></a> CE 6.0<a target=_blank><u><font color=#356299>操作pȝ</font></u></a>。?.0版也?a target=_blank><u><font color=#356299>微Y</font></u></a>首个导入ơ世代档案系lExFAT?a target=_blank><u><font color=#356299>操作pȝ</font></u></a>Q虽然到目前为止其细节还不明了,但是Ҏ已有的信息指出,ExFAT?a target=_blank><u><font color=#356299>Windows</font></u></a> CE 6.0中,担当了ȝ所有外接储存媒体的中界层的角色Q广Z业界所U赞的是Q这能够解除q去传统FAT档案pȝ?2GB单一定w限制。ExFAT同样也解除了单一档案只能?GB以下的限Ӟq对于硬件厂商以<a target=_blank><u><font color=#356299>Windows</font></u></a> CE发展大容量储存管理伺服架构,有著相当大的帮助。加上一些安全机Ӟ我们可以把ExFAT视ؓ<a target=_blank><u><font color=#356299>Windows</font></u></a> CE 6.0上的NTFS加强版?/p> <p>  VoIP也是<a target=_blank><u><font color=#356299>Windows</font></u></a> CE 6.0另一个持l加强的重点Q除了在应用E序层的整合更进一步以外,<a target=_blank><u><font color=#356299>操作pȝ</font></u></a>核心也具备直接支持的能力Q因此硬件开发上可以更容易的?a target=_blank><u><font color=#356299>Windows</font></u></a> CE环境上进行各U网l的语音通讯服务。而因应这L势Q?.0版自然也把过?.0版的~失补正q来Q在|络堆叠协定斚wQ直接支持了802.11i、WAP2?02.11eQ无UQoSQ、蓝牙A2DP/AVRCP的AES加密{等Qؓ无线通讯建立了一个稳定、安全以及可靠的应用环境?/p> <p>  而从使用者观Ҏ看,<a target=_blank><u><font color=#356299>Windows</font></u></a> CE 6.0扩展了超以往版本d的承诺,q些功能包括了最新的多媒体能力,诸如<a target=_blank><u><font color=#356299>Windows</font></u></a> Media 10/11的支持、,对于|络多媒体装|的原生整合能力Q在Platform Builder开发工具中Q甚至也加入了行动媒体中心的支持Q可以藉?a target=_blank><u><font color=#356299>Windows</font></u></a> Media Connect 2.0大幅强化多媒体应用的支持能力Qƈ且可以与其它<a target=_blank><u><font color=#356299>微Y</font></u></a>?a target=_blank><u><font color=#356299>操作pȝ</font></u></a>或硬件装|做同步l合的动作。这些功能包含了以下目Q?/p> <p>  ?TIFF~解码器的支?br>  ?HD-DVD的解码器支持<br>  ?MPEG-2解码?br>  ?更多的媄音编码与格式支持<br>  ?UDF 2.5格式的支?br>  ?虚拟环绕声道的支?br>  ?多轨x的支?br>  ?强化DirectDrawQ可支持电视使用的交错显C模?br>  ?USB OTG功能加入Q可作ؓUSB的控制端</p> <p>  虽然在核心部分做么大的更斎ͼ但是<a target=_blank><u><font color=#356299>Windows</font></u></a> CE 6.0的储存上q没有如<a target=_blank><u><font color=#356299>微Y</font></u></a>其它<a target=_blank><u><font color=#356299>操作pȝ</font></u></a>般的飞涨QVista甚至需要超q?0GB的初始储存安装空_Q,相较?.0版,6.0在体U上也不q增加了5Q左叻I虽然q对<a target=_blank><u><font color=#356299>嵌入?/font></u></a>pȝ产业来说是理所当然Q但对于<a target=_blank><u><font color=#356299>微Y</font></u></a>可以说是另一奇qV?/p> <p>  <a target=_blank><u><font color=#356299>Windows</font></u></a> CE 6.0带给开发者的好处</p> <p>  在开攑֎始码的历史中Q?a target=_blank><u><font color=#356299>微Y</font></u></a>要写下另一个新的里E碑Q?00Q对产品开发者释攑և原始码,且可允许厂商q行自订的变更或订做Q而无释攑ևl过修改的程序码Q虽然在q义上ƈ不能视ؓ真正开放,但是些喜Ƣ藏U留一手的厂商来说Q无疑是增加竞争力的最xD之一。而作为开发工LVisual Studio 2005 PRO会作ؓ<a target=_blank><u><font color=#356299>Windows</font></u></a> CE 6.0的整体套件之一Q内建的许多开发工具与定义对于开发者来说相对便利许多?/p> <p>  <a target=_blank><u><font color=#356299>Windows</font></u></a> CE 6.0支持?a target=_blank><u><font color=#356299>Windows</font></u></a> <a target=_blank><u><font color=#356299>.NET</font></u></a> Compact Framework 2.0作ؓ应用E序理开发以及Win32?MFC?ATL?WTL和STL{?a target=_blank><u><font color=#356299>E序开?/font></u></a>界面提供l开发原生应用程序的开发者用。具备了如此势力庞大以及完整的开发环境作为支持,开发者与刉商也可保后箋的支持不虞匮乏?/p> <p>  而在g斚wQ根?a target=_blank><u><font color=#356299>微Y</font></u></a>斚w的说法,在不变更原有的硬件架构之下,导入<a target=_blank><u><font color=#356299>Windows</font></u></a> CE 6.0可以大幅改善原有E序的执行效率,q且也容许同旉有更多程序同步执行,׃每个E序都具备有独立的执行空_特定E序当掉Q也不会影响到其它应用程序或pȝ执行Q提供给使用者比起以往旧版pȝ更强的稳固性与更大的弹性。而目前逐渐风行的多核心处理架构上,<a target=_blank><u><font color=#356299>Windows</font></u></a> CE 6.0也可以在不变?a target=_blank><u><font color=#356299>E序开?/font></u></a>者原有程序模型的状况之下Q提供最佛_的核心工作自动分配与指定Q当Ӟ如果有需求的话,<a target=_blank><u><font color=#356299>E序开?/font></u></a>者依然可以自行决定指定核心的方式?/p> <p>  市场上的实际应用与结?/p> <p>  截至目前为止Q台湑ַl有研华U技在针对物、仓储管理、公共服务以及领域维护方面的应用Q进行基?a target=_blank><u><font color=#356299>Windows</font></u></a> CE 6.0<a target=_blank><u><font color=#356299>操作pȝ</font></u></a>下的工业U掌上型l端机的开发,而精技计算机则是开发了可应用于搜集资料、RFID、BarCode理的垂直市场PDAQ采?a target=_blank><u><font color=#356299>Windows</font></u></a> CE 6.0中的cell core元gQ羃短GPRS端的资料传输设计时程。而各大手持式装置的开发者也都已l在着手导?a target=_blank><u><font color=#356299>Windows</font></u></a> CE 6.0Q实际品预计将会于2007q第二季之后逐渐现台面?/p> <p>  100Q开攑֎始码的创丑֯?a target=_blank><u><font color=#356299>微Y</font></u></a>来说是个相当大的H破Q虽然这有一大部分是因ؓ<a target=_blank><u><font color=#356299>嵌入?/font></u></a><a target=_blank><u><font color=#356299>Linux</font></u></a>所带来的竞争挑战所_但是鹬蚌怺的结果,带给开发伙伴的好处也远大于q去采用闭模式的流E,而gl过?a target=_blank><u><font color=#356299>Windows</font></u></a> CE 5.0的成果,<a target=_blank><u><font color=#356299>Windows</font></u></a> CE 6.0也将会l在<a target=_blank><u><font color=#356299>嵌入?/font></u></a>应用、行动装|、GPS、智能型<a target=_blank><u><font color=#356299>手机</font></u></a>{市场l攻城掠圎ͼ不过在面对市Z诸多Ҏ的竞争,<a target=_blank><u><font color=#356299>微Y</font></u></a>仍须做出更多的改q。比如在修正漏洞斚w可以更快速的反应、ƈ且提供给开发者更大的支持力度{等Q当开发者甜头吃的够多,自然也会?a target=_blank><u><font color=#356299>Windows</font></u></a> CE<a target=_blank><u><font color=#356299>Windows</font></u></a> CE架构更ؓ忠诚Q出现在市面上的产品自然也会更ؓ成熟?br></p> <br> <img src ="http://www.shnenglu.com/milkyway/aggbug/22191.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/milkyway/" target="_blank">相思酸中有?/a> 2007-04-18 09:57 <a href="http://www.shnenglu.com/milkyway/articles/22191.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VirtualAlloc/Copy and MmMapIospacehttp://www.shnenglu.com/milkyway/articles/22123.html相思酸中有?/dc:creator>相思酸中有?/author>Tue, 17 Apr 2007 05:38:00 GMThttp://www.shnenglu.com/milkyway/articles/22123.htmlhttp://www.shnenglu.com/milkyway/comments/22123.htmlhttp://www.shnenglu.com/milkyway/articles/22123.html#Feedback0http://www.shnenglu.com/milkyway/comments/commentRss/22123.htmlhttp://www.shnenglu.com/milkyway/services/trackbacks/22123.htmlKurt Kennett

VirtualCopy can be a bit confusing to use.

http://msdn2.microsoft.com/en-us/library/aa908789.aspx

Let's look at the parameters.  I've commented with -- after each of them.

lpvDest

[in] Pointer to the destination memory, which must be reserved.

-- This means that the destination range of VIRTUAL memory must already be reserved by a call to VirtualAlloc().  You must have allocated a range of virtual memory that you are going to map to some physical range.

lpvSrc

[in] Pointer to committed memory.

-- This is the range of *either* VIRTUAL *or* PHYSICAL memory that you want to map the range specified by the 'lpvDest' parameter to.  

If you specify a VIRTUAL address and omit the PAGE_PHYSICAL flag from the fdwProtect parameter, then you are simply saying "Copy the mapping at the lpvSrc address to the lpvDest address".  This just means that there will be two ranges of virtual memory that point to the same physical range.

If you specify a PHYSICAL address (shifted right 8 bits) and include the PAGE_PHYSICAL flag in the fdwProtect parameter, then you are saying "Map the range at the lpvDest address to this specific physical address".  This sets your new range of virtual memory to point to a piece of physical memory.

cbSize

[in] Size, in bytes, of the region. The allocated pages include all pages containing one or more bytes in the range from lpAddress to lpAddress+cbSize. This means that a 2-byte range straddling a page boundary causes both pages to be included in the allocated region.

-- pretty straight forward here.

fdwProtect

[in] Type of access protection. If the pages are being committed, any one of a number of flags can be specified, along with the PAGE_GUARD and PAGE_NOCACHE, protection modifier flags. The following table shows the flags that can be specified.

-- 'Reserving' a page means you're allocating a range of virtual memory but not pointing it at anything yet.  'Commiting' a page means you are actually taking up physical storage somewhere - be it in RAM or in physical addres space.  For the purposes of our discussion here, you would normally map registers and i/o space with PAGE_NOCACHE.  If you used a physical address (shifted right 8 bits) in the lpvSrc parameter, then you would also specify the PAGE_PHYSICAL flag.


quetion:

If I want to access some physical memory in my driver,  can I do like these way?

Method (1) define static map relationship in OEMAddressTable and reserve difined virtual address in config.bib first, then use VirtualAlloc() and VirtualCopy() without the page_physical parameter.

or (2)  directly use MmMapIoSpace() or VirtualAlloc+Copy() with the page_physical parameter

answer:
Yes, either of those would work I believe.  #2 is the preferred/recommended method


Monday, March 26, 2007 12:07 PM by Kurt Kennett

Wow!  Lots of interest in VirtualCopy!  Ok, I'll try to be super-clear here.

VirtualCopy *copies* or *sets* a range of virtual addresses.  

   - You use it to *copy* an existing Virtual->Physical mapping (no matter where it is).  

OR

   - You use it to *set* a mapping to a range of physical addresses.

In *either* case, the virtual memory you want to create the new map in must already be allocated (via VirtualAlloc()).

OEMAddressTable is a static (unchanging, available at startup without doing any work or setup) table of virtual -> physical mappings.  The kernel is the only thing that has default access to the resources mapped by this table.  If you are operating outside the OAL (i.e. in any kind of driver or application), you must use VirtualCopy() to copy or create memory page mappings.  As mentioned above, you can copy any existing mapping as long as you have access to it.  This includes a static mapping done by the OEMAddressTable.  Some people will map all resources in the OEMAddressTable (so the kernel has access to everything), then just copy those mappings in drivers when they need to.  This is not a best practice because it makes driver code less portable -- it is better to read the physical address of a component from the registry, then use the value found there to map to it. If you do this your driver code does not have to change if it is moved to a different platform or extended to use multiple components in different physical locations.

A mapping does not have to exist in OEMAddressTable in order for you to access the physical resources mapped.  You can create a new mapping unknown to the OEMAddressTable by using VirtualCopy with the PAGE_PHYSICAL flag.

MmMapIoSpace is a CEDDK function -- it simply does the appropriate calls to VirtualAlloc/VirtualCopy.  You could write your own MmMapIoSpace if you wanted to.  Some people have in the past - calling the function "VirtualMemCopyPhysical" or something like that.  Some platforms need to modify the MmMapIoSpace to set Virtual mapping attributes when pages are mapped (hence the original purpose for this blog entry).

Using flags like PAGE_EXECUTE_READWRITE with VirtualCopy are a 'request'.  If the platform/CPU does not have a differentiation between executable pages and non-executable pages, the EXECUTE property will not be able to be set.  For example, the X86 CPUs can explicitly state that memory is executable, but can't be read or written to.  The ARM processors have no notion of this - you can read it or read and write it.



In Windows CE 5.0 and earlier, virtual allocations below 2MB come out of the address space of the process calling it, while allocations above 2MB come out of the shared address space.

Sue




]]>
ce内存映射的点Ҏ?/title><link>http://www.shnenglu.com/milkyway/articles/18270.html</link><dc:creator>相思酸中有?/dc:creator><author>相思酸中有?/author><pubDate>Fri, 02 Feb 2007 01:27:00 GMT</pubDate><guid>http://www.shnenglu.com/milkyway/articles/18270.html</guid><wfw:comment>http://www.shnenglu.com/milkyway/comments/18270.html</wfw:comment><comments>http://www.shnenglu.com/milkyway/articles/18270.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/milkyway/comments/commentRss/18270.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/milkyway/services/trackbacks/18270.html</trackback:ping><description><![CDATA[ <table style="TABLE-LAYOUT: fixed; WORD-BREAK: break-all" cellspacing="1" cellpadding="3" width="98%" bgcolor="#cccccc" border="0"> <tbody> <tr bgcolor="#f8f8f8"> <td>wy12218 发表?2006-11-9 18:17:00 </td> </tr> <tr bgcolor="#ffffff"> <td height="0"> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td> <p>OEMAddressTable里定义的映射关系是给ARM MMU用的,是在KernelStart(source code参考wince420private目录)时徏立的,只要WINCEq在?׃会解? <br />OEMAddressTable里的Virtual Addr和Physical Addr是对ARM来说? 其实对于WINCE,只能访问到它的Virtual address. 也就是说,OEMAddressTable里的Virtual address对WINCE pȝ来说才是Physical Address. <br /><br />l过OEMAddressTable映射后的pȝ的物理地址,?x80000000~0x9fffffff之间.是caching and buffering的地址,q个地址加上0x20000000,是它的cache & buffering disabled地址.所有的g寄存器的地址都在q个地址D上,受MMU保护? <br /><br />上面讲的pȝ的物理地址,?x80000000~0xbfffffff,在Kernel Mode下都可以直接讉K. ISR是在KERNEL?也就可以直接讉Kq些pȝ的物理地址.无所?因ؓISR只能讉K静态映的虚拟地址". <br /><br />上面说过,对于ARM来说,有虚拟地址和物理地址之分,对于WINCE来说,也有虚拟地址和物理地址之分. 可以q么?ARM的虚拟地址是WINCEpȝ的物理地址. <br />32位的OSd?G的虚拟地址I间,WINCE也不例外. 其中,0x00000000~0x80000000是Application Space; 0x80000000~0xffffffff是System Reserved. pȝ的物理地址在System Reserved的这D?只能在KERNEL MODE讉K. 那么,当APPLICATION和DRIVER(都是q行在USER MODE)要访问这些在System Reserved地址D늚g寄存器或MEMORY怎么办呢? 只好再徏立一层映关p?在Application Space里分配一D늩?把它映射到System Reserved里的地址?q就是VirtualAlloc/Copy和MmMapIoSpaceq的事情.</p> <p>如果你的地址是这样声明的: <br />#define RTC_COUNTER *((volatile unsigned *)0x91000000) <br />那么直接d可以了,比如: <br />int nRtc = RTC_COUNTER; <br />RTC_COUNTER = nRtc; <br /><br />否则,可以? <br />int nRtc = READ_REGISTER_ULONG(0x91000000); <br />WRITE_REGISTER_ULONG(0X91000000, nRtc); <br /><br />其实q两U方式的本质是一L,都是把地址声明成某个数据类?然后可以直接读写了.下面是READ_REGISTER_ULONG()和WRITE_REGISTER_ULONG()的定? <br />#define READ_REGISTER_ULONG(reg) (*(volatile unsigned long * const)(reg)) <br />#define WRITE_REGISTER_ULONG(reg, val) (*(volatile unsigned long * const)(reg)) = (val)</p> <p> </p> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <img src ="http://www.shnenglu.com/milkyway/aggbug/18270.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/milkyway/" target="_blank">相思酸中有?/a> 2007-02-02 09:27 <a href="http://www.shnenglu.com/milkyway/articles/18270.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>wince中断问题http://www.shnenglu.com/milkyway/articles/18268.html相思酸中有?/dc:creator>相思酸中有?/author>Fri, 02 Feb 2007 01:25:00 GMThttp://www.shnenglu.com/milkyway/articles/18268.htmlhttp://www.shnenglu.com/milkyway/comments/18268.htmlhttp://www.shnenglu.com/milkyway/articles/18268.html#Feedback0http://www.shnenglu.com/milkyway/comments/commentRss/18268.htmlhttp://www.shnenglu.com/milkyway/services/trackbacks/18268.html阅读全文

]]>
WinCE中OEM适配层编E点滴之创徏OALhttp://www.shnenglu.com/milkyway/articles/18267.html相思酸中有?/dc:creator>相思酸中有?/author>Fri, 02 Feb 2007 01:23:00 GMThttp://www.shnenglu.com/milkyway/articles/18267.htmlhttp://www.shnenglu.com/milkyway/comments/18267.htmlhttp://www.shnenglu.com/milkyway/articles/18267.html#Feedback0http://www.shnenglu.com/milkyway/comments/commentRss/18267.htmlhttp://www.shnenglu.com/milkyway/services/trackbacks/18267.html  2001q计机专业毕业。从毕业起一直从事Y件开发工作。目前从?Windows CE 下操作系l内核定制和应用E序开发。在实际工作中积累了CE下开发的一些经验。希望和 CE 下开发者交、探讨,更希望你们能不吝赐教。我的EMailQwindowsce@tom.com

  如果您有技术问题向我咨询,L?a target="_blank">天极|嵌入式开发论?/font>Q本人将在此论坛回复您的问题。在论坛上交会更方便些Q其它网友也可以回答参与QI补了我的不?/p>

  q入作者专?/font>

  正文

  正如CE的帮助文档所aQ创建OAL是一个非常复杂的dQ而通常的办法是复制原有的相同^台的OAL代码Q然后修Ҏ适应q_的特D要求。也是说对于没有特D要求的q_Q复制原有相同^台的OAL代码p够了。由于OAL的复杂性在q篇文章中我只讲解常用的部分?

  一、实现ISR

  1. ISR的概?br />
  ISRQinterrupt service routineQ是处理IRQsQinterrupt request lineQ的E序。Windows CE用一个ISR来处理所有的IRQh。当一个中断发生时Q内核的异常处理E序先调用内核ISRQ内核ISR用所有具有相同优先和较低优先的中断,然后调用已经注册的OAL ISRE序Q一般ISR有下列特征:

  1) 执行最的中断处理Q最的中断处理指能够检验、答复生中断的gQ而把更多的处理工作留lISTQinterrupt service threadQ?br />
  2) 当ISR完成时返回中断IDQ中断ID大部分是预定义的Q?br />
  2. X86q_的ISRl构

  X86q_的ISR保存?_WINCEROOT%\PUBLIC\COMMON\OAK\CSP\I486\OAL\fwpc.c中,函数名ؓPeRPISR。下面分析一下此函数的主要代码:

ULONG PeRPISR(void)
{
 ULONG ulRet = SYSINTR_NOP; ///q回|既中断IDQ以SYSINTR_为前~Q?br /> UCHAR ucCurrentInterrupt; ///当前中断?br /> if (fIntrTime) ////// fIntrTime 用于试SR和IST的g时时_试工具为ILTiming.exe?br />  ......
  ucCurrentInterrupt = PICGetCurrentInterrupt(); ////q回当前中断IRQ
 if (ucCurrentInterrupt == INTR_TIMER0) ///IRQ0QIRQ0为系l时钟(system tickQ中断,具体见“二、实现系l时钟?br /> ......
 if (dwRebootAddress) ////是否需要重启动
  RebootHandler();
  ......
 if(ucCurrentInterrupt == INTR_RTC) ////IRQ8Qreal-time clock的中?br />  ......
 else if (ucCurrentInterrupt <= INTR_MAXIMUM) ///如果中断于 INTR_MAXIMUM
 {
  ulRet = NKCallIntChain(ucCurrentInterrupt); ////调用中断?br />  if (ulRet == SYSINTR_CHAIN) ///如果中断链未包含中断
   ulRet = OEMTranslateIrq(ucCurrentInterrupt); ////在IRQ 和SYSINTR之间转换Q此函数q回IRQ对应的SYSINTR
   ......
   PICEnableInterrupt(ucCurrentInterrupt, FALSE); ///启用除当前中断以外的所有中?br /> } ///else if
 OEMIndicateIntSource(ulRet); ///通知内核已经发生SYSINTR中断
}

  从以上代码不隄出ISR的Q务就是返回以“SYSINTR_”ؓ前缀的中断IDQ如果不需要进一步执行ISTQ那么就q回SYSINTR_NOP?br />
  3. 中断注册步骤

  参考X86q_的代码,中断注册步骤如下Q?br />
  1) 用SETUP_INTERRUPT_MAP宏关联SYSINTR和IRQ。以“SYSINTR_”ؓ前缀的常量由内核使用Q用于唯一标识发生中断的硬件。在Nkintr.h文g中预定义了一些SYSINTRQOEM可以在Oalintr.h文g中自定义SYSINTR?br />
  2) 用HookInterrupt函数兌g中断号和ISR。这里的g中断号ؓ物理中断P而非逻辑中断号IRQ。在InitPICs函数Q和上述ISR位于同一文gQ的最后调用了HookInterrupt函数Q如下:

for (i = 64; i < 80; i++)
 HookInterrupt(i, (void *)PeRPISR); ///用ISR兌16个中断号

  4. 中断处理步骤

  1) 调用InterruptInitialize函数兌SYSINTR和ISTQ具体是兌IST{待的事件。一般在驱动E序中按如下~写Q?br />
hEvent = CreateEvent(...) ///创徏一个事件对?br />InterruptInitialize(SYSINTR_SERIAL, hEvent, ...) ///兌一个串口中断ID和这个事?br />hThd = CreateThread(..., MyISTRoutine, hEvent, ...) ///创徏一个线E(ISTQ?br />CeSetThreadPriority(hThd, 152); ///提高此线E的优先U?/td>

  2) IST执行I/O操作Q一般IST按如下编写:

for(;;) ///驱动E序一直处于服务状?br />{
 WaitForSingleObject(hEvent, INFINITE); ////无限{待事g
 ...... //// I/O操作
 InterruptDone(InterruptId); ///l束当前中断处理
}

  3) ISR和IST之间数据传输

  假如我们要从一个设备频J的d数据而每ơ读取量非常,那么每次d都要调用IST会降低性能。作x案,ISR可以做读取工作(存放到缓冲区Q,q在~冲区存放满后由IST到缓冲区d。因为ISRq行在内核模式而ISTq行在用h式,IST不能L地访问ISR的缓冲区Qؓ此CE提供了一个办法(参见标题为“Passing Data between an ISR and an IST”的帮助文档Q,您也可以?a target="_blank">天极|嵌入式开发论?/font>询问?br />
  二、实现系l时?/b>

  1. pȝ旉Qsystem tickQ概?br />
  pȝ旉是内栔R要的唯一中断QIRQ0Q,pȝ旉每毫U生一个中断,当发生中断时内核在ISR中篏计,?000的倍数是q了一U钟。在处理pȝ旉的ISR中不仅要累计计数Q还要决定是否通知内核开始重新调度当前所有的U程。要实现一个OALQ系l时钟是W一个必d的事?br />
  2. X86q_pȝ旉中断的处理工?pȝ旉由InitClock函数负责初始化工作,一般是在OEMInit函数中调用。当发生中断ӞISR首先用下列语句篏计计敎ͼ

CurMSec += SYSTEM_TICK_MS; /////SYSTEM_TICK_MS = 1

  然后Ҏ下列语句判断应该q回什么|

if ((int) (dwReschedTime ?CurMSec) >= 0)
 return SYSINTR_RESCHED; ///重新调度
else
 return SYSINTR_NOP; ///不再执行M操作

  上述代码中全局变量dwReschedTime在schedule.c中定义,也就是由内核的调度模块决定在何时开始重新调度线E。CurMSec累计了从WindowsCE启动到当前d产生了多个system tick。实现系l时钟后q要实现OEMIdle函数Q当没有U程准备q行时OEMIdle被调用,OEMIdle函数CPU|于I闲模式Q但在空闲模式下仍然要篏计系l时钟?br />
  三、I/O控制代码

  1. I/O控制代码作用

  应用软g或者驱动程序可以调用KernelIoControl函数与OAL层通信Q而KernelIoControl在内部调用OEMIoControl函数。OEMIoControl是一个OAL APIQOEM可以在OEMIoControl中编写自qI/O控制代码实现一些功能,或者说与应用Y仉信。I/O控制代码常用的例子如重启计算机、得到系l信息、设|RTC、得到设备ID{。还有一些系l程序用的Ҏ的I/O控制代码。在q里说明一下,我经q实验证实CE提供的得到设备IDҎq有效?br />
  2. ~写自己的I/O控制代码步骤

  1) 在pkfuncs.h或者新~写一?h文g中按如下格式定义Q?br />
#define IOCTL_MY_CONTROL CTL_CODE(FILE_DEVICE_HAL, 3000, METHOD_NEITHER, FILE_ANY_ACCESS)

  2) 在oemioctl.c中修改OEMIoControl函数Q添加如下代码:

case IOCTL_MY_CONTROL:

......

  3) 在应用程序中调用KernelIoControl函数Q具体参数参见帮助文?img src ="http://www.shnenglu.com/milkyway/aggbug/18267.html" width = "1" height = "1" />

]]>
NAND and NOR and XIPhttp://www.shnenglu.com/milkyway/articles/18266.html相思酸中有?/dc:creator>相思酸中有?/author>Fri, 02 Feb 2007 01:20:00 GMThttp://www.shnenglu.com/milkyway/articles/18266.htmlhttp://www.shnenglu.com/milkyway/comments/18266.htmlhttp://www.shnenglu.com/milkyway/articles/18266.html#Feedback0http://www.shnenglu.com/milkyway/comments/commentRss/18266.htmlhttp://www.shnenglu.com/milkyway/services/trackbacks/18266.htmlhttp://www.student.buct.edu.cn/snc/blog/blog.asp?name=wy12218&month=2003-9

NOR和NAND是现在市Z两种主要的非易失闪存技术。Intel?988q首先开发出NOR flash技术,d改变了原先由EPROM和EEPROM一l天下的局面。紧接着Q?989q_东芝公司发表了NAND flashl构Q强调降低每比特的成本,更高的性能Qƈ且象盘一样可以通过接口L升。但是经q了十多q之后,仍然有相当多的硬件工E师分不清NOR和NAND闪存?
相“flash存储器”经常可以与相“NOR存储器”互换用。许多业内h士也搞不清楚NAND闪存技术相对于NOR技术的优越之处Q因为大多数情况下闪存只是用来存储少量的代码Q这时NOR闪存更适合一些。而NAND则是高数据存储密度的理想解决Ҏ?
NOR的特Ҏ芯片内执?XIP, eXecute In Place)Q这样应用程序可以直接在flash闪存内运行,不必再把代码dpȝRAM中。NOR的传输效率很高,??MB的小定w时具有很高的成本效益Q但是很低的写入和擦除速度大大影响了它的性能?
NANDl构能提供极高的单元密度Q可以达到高存储密度Qƈ且写入和擦除的速度也很快。应用NAND的困隑֜于flash的管理和需要特D的pȝ接口?

性能比较
flash闪存是非易失存储器,可以对称为块的存储器单元块进行擦写和再编E。Q何flash器g的写入操作只能在I或已擦除的单元内进行,所以大多数情况下,在进行写入操作之前必d执行擦除。NAND器g执行擦除操作是十分简单的Q而NOR则要求在q行擦除前先要将目标块内所有的位都写ؓ0?
׃擦除NOR器g时是?4?28KB的块q行的,执行一个写?擦除操作的时间ؓ5sQ与此相反,擦除NAND器g是以8?2KB的块q行的,执行相同的操作最多只需?ms?
执行擦除时块寸的不同进一步拉大了NOR和NADN之间的性能差距Q统计表明,对于l定的一套写入操?其是更新小文g?Q更多的擦除操作必须在基于NOR的单元中q行。这P当选择存储解决ҎӞ设计师必L衡以下的各项因素?
?NOR的读速度比NANDE快一些?
?NAND的写入速度比NOR快很多?
?NAND?ms擦除速度q比NOR?s快?
?大多数写入操作需要先q行擦除操作?
?NAND的擦除单元更,相应的擦除电路更?

接口差别
NOR flash带有SRAM接口Q有_的地址引脚来寻址Q可以很Ҏ地存取其内部的每一个字节?
NAND器g使用复杂的I/O口来串行地存取数据,各个产品或厂商的Ҏ可能各不相同?个引脚用来传送控制、地址和数据信息?
NANDd写操作采?12字节的块Q这一Ҏ点像盘理此类操作Q很自然圎ͼZNAND的存储器可以取代硬盘或其他块设备?

定w和成?
NAND flash的单元尺寸几乎是NOR器g的一半,׃生q程更ؓ单,NANDl构可以在给定的模具寸内提供更高的定wQ也q应地降低了h根{?
NOR flash占据了容量ؓ1?6MB闪存市场的大部分Q而NAND flash只是用在8?28MB的品当中,q也说明NOR主要应用在代码存储介质中QNAND适合于数据存储,NAND在CompactFlash、Secure Digital、PC Cards和MMC存储卡市Z所占䆾额最大?

?性和耐用?
采用flahs介质时一个需要重点考虑的问题是?性。对于需要扩展MTBF的系l来_Flash是非常合适的存储Ҏ。可以从寿命(耐用?、位交换和坏块处理三个方面来比较NOR和NAND的可*性?
寿命(耐用?
在NAND闪存中每个块的最大擦写次数是一百万ơ,而NOR的擦写次数是十万ơ。NAND存储器除了具?0?的块擦除周期优势Q典型的NAND块尺寸要比NOR器g?倍,每个NAND存储器块在给定的旉内的删除ơ数要少一些?
位交?
所有flash器g都受位交换现象的困扰。在某些情况?很少见,NAND发生的次数要比NOR?Q一个比特位会发生反转或被报告反转了?
一位的变化可能不很明显Q但是如果发生在一个关键文件上Q这个小的故障可能Dpȝ停机。如果只是报告有问题Q多dơ就可能解决了?
当然Q如果这个位真的改变了,必采用错误探?错误更正(EDC/ECC)法。位反{的问题更多见于NAND闪存QNAND的供应商使用NAND闪存的时候,同时使用EDC/ECC法?
q个问题对于用NAND存储多媒体信息时倒不是致命的。当Ӟ如果用本地存储设备来存储操作pȝ、配|文件或其他敏感信息Ӟ必须使用EDC/ECCpȝ以确保可*性?
坏块处理
NAND器g中的坏块是随机分布的。以前也曾有q消除坏块的努力Q但发现成品率太低,代h太高Q根本不划算?
NAND器g需要对介质q行初始化扫描以发现坏块Qƈ坏块标Cؓ不可用。在已制成的器g中,如果通过?的方法不能进行这处理,导致高故障率?

易于使用
可以非常直接C用基于NOR的闪存,可以像其他存储器那样q接Qƈ可以在上面直接运行代码?
׃需要I/O接口QNAND要复杂得多。各UNAND器g的存取方法因厂家而异?
在用NAND器gӞ必须先写入驱动程序,才能l箋执行其他操作。向NAND器g写入信息需要相当的技巧,因ؓ设计师绝不能向坏块写入,q就意味着在NAND器g上自始至l都必须q行虚拟映射?

软g支持
当讨Y件支持的时候,应该区别基本的读/?擦操作和高一U的用于盘仿真和闪存管理算法的软gQ包括性能优化?
在NOR器g上运行代码不需要Q何的软g支持Q在NAND器g上进行同h作时Q通常需要驱动程序,也就是内存技术驱动程?MTD)QNAND和NOR器g在进行写入和擦除操作旉需要MTD?
使用NOR器g时所需要的MTD要相对少一些,许多厂商都提供用于NOR器g的更高软gQ这其中包括M-System的TrueFFS驱动Q该驱动被Wind River System、Microsoft、QNX Software System、Symbian和Intel{厂商所采用?
驱动q用于对DiskOnChip产品q行仿真和NAND闪存的管理,包括U错、坏块处理和损耗^?img src ="http://www.shnenglu.com/milkyway/aggbug/18266.html" width = "1" height = "1" />

]]>
WINCE的内存配|?/title><link>http://www.shnenglu.com/milkyway/articles/17845.html</link><dc:creator>相思酸中有?/dc:creator><author>相思酸中有?/author><pubDate>Sat, 20 Jan 2007 13:25:00 GMT</pubDate><guid>http://www.shnenglu.com/milkyway/articles/17845.html</guid><wfw:comment>http://www.shnenglu.com/milkyway/comments/17845.html</wfw:comment><comments>http://www.shnenglu.com/milkyway/articles/17845.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/milkyway/comments/commentRss/17845.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/milkyway/services/trackbacks/17845.html</trackback:ping><description><![CDATA[ <p>by  microsun<br /><br />WINCE的内存(包括SDRAM及FLASHQ的配置包含两个斚wQ源代码(包括C和汇~?中的定义,及系l配|文件CONFIG.BIB中的定义。源代码中需要定义内存的物理及虚拟地址Q大,q初始化名ؓOEMAddressTable的结构数l,以告知系l物理地址与虚拟地址的对应关p,pȝҎ其设|生成MMU表。而CONFIG.BIB中一般会内存定义成不同的段Q各D는作不同的用途?br /><br />CONFIG.BIB文g<br />CONFIG.BIB文g分两个部分,我们且称之ؓD,MEMORYD和CONFIGDcMEMORYD定义内存的分片ҎQCONFIGD定义系l其它的一些属性。以下是一个CONFIG。BIB文gMEMORYD늚例子Q?br />MEMORY<br />Q?名称 起始地址 大小 属?br />RESERVED 80000000 00008000 RESERVED<br />DRV_GLB 80008000 00001000 RESERVED<br />CS8900 80010000 00030000 RESERVED<br />EDBG 80040000 00080000 RESERVED<br />NK 800C0000 00740000 RAMIMAGE<br />RAM 81000000 00800000 RAM<br /><br />名称原则上可以取L字符ԌROMIMAGE通过一个内存片的属性来判断它的用途。RESERVE属性表明该片内存是BSP自己使用的,pȝ不必兛_其用途;RAMIMAGE说明它是一片存放OS IMAGE的内存;而RAM则表CZ片内存ؓRAMQ系l可以在其中分配I间Q运行程序?br />但存放ROM的这片内存的名称Q即NK一般不要改动。因为BIB文g中定义将一个文件加入到哪个ROM片(WINCE支持ROM IMAGE存放在不q箋的几个内存片中)中时会用到这个名Uͼ如下现这行BIB文g就定义touch.dll攑֜名称为NKq片ROM中,<br />touch.dll $(_FLATRELEASEDIR)\touch.dll NK SH<br />因而,如果NK改ؓ其它名称Q则pȝ中所有的BIB文g中的q个NK串都需要改动?br />注意Q保证各片内存不要重叠;而且中间不要留空z,以节U内存;两种讑֤如果不能同时被加载,应该只为其保留一片从而节U内存,例如Q本例中的CS8950是ؓ|卡驱动E序保留的,EDBG是ؓ|卡作调试(KITLQ用时保留的Q而系l设计成q两个程序不会同时加载(CS8950在启动时判断如果EDBG在运行就会自动退出)Q这样ؓq两个驱动程序各保留一片内存实在浪费而且也没有必要?br />RAM片必d物理上是q箋的,如果pȝ的物理内存被分成了几片,则在RAM片只能声明一片,其它的内存在启动阶段由OEMGetExtensionDRAM报告l系l,如果有多于一个的内存片,应该用OEMEnumExtensionDRAM报告。NK片则没有此限Ӟ只是NK跨越两个以上物理内存片时Q系l启动时会显C个OS包跨了多个物理内存片,认ؓ是个错误Q但q不影响pȝ的执行与E_性,因ؓpȝ启动之时便会打开MMU而用虚拟地址Q从而看到连l的内存I间。当Ӟ如果内核自己都被攑֜了两个内存片上,那系l应该就无法启动了。而其它保留v来的内存片是一般是l驱动程序DMA用,应该保证它们在物理上的连l性,因ؓDMA是直接用物理地址的?br />CONFIGD中以下几个需要格外注意:<br />ROMSTARTQ它定义ROM的v始位|,应该和NK片的起始位置相同?br />ROMSIZEQ定义ROM的大,应该和NK片的大小相同?br />如果不需要NK。BIN文gQ则可以不设q两个倹{?br />ROMWIDTHQ它只是定义ROMIMAG生成ROM包时如何l织文gQ而非其字面含义:ROM的宽度,所以一般都应该?2<br />COMPRESSIONQ一般定义ؓONQ以打开压羃功能Q从而减BIN文g的尺寸?br />AUTOSIZEQ一般应该设为ONQ以使系l将定义lROM但没有用掉的内存当做RAM使用Q而提高RAM的用率。注意,如果ROM是FLASHQ则不能设ؓONQ因为FLASH不能当作RAM使用?br />ROMOFFSETQ它定义OS起始位置Q即ROMSTARTQ的物理地址和虚拟地址的差|有些BSP中ƈ没有使用q个定义?br />OEMAddressTable及其?br />OEMAddressTable用来初始化系l中各种讑֤的虚拟地址与物理地址的对映关pR在我用的BSP中,它是q样定义q初始化的:<br />typedef struct<br />{<br />ULONG ulVirtualAddress;<br />ULONG ulPhysicalAddress;<br />ULONG ulSizeInMegs;<br />} AddressTableStruct;<br /><br />#define MEG(A) (((A - 1)>>20) + 1)<br /><br />const AddressTableStruct OEMAddressTable[] =<br />{<br />{ SDRAM_VIRTUAL_MEMORY, //虚拟地址<br />PHYSICAL_ADDR_SDRAM_MAIN, //物理地址<br />MEG(SDRAM_MAIN_BLOCK_SIZE) //q段I间的大,以M?br />},<br />……………………?br />{<br />0,<br />0,<br />0<br />}<br />}Q?br />如例子所C,OEMAddressTableZ个结构数l,每项的第一个成员ؓ虚拟地址Q第二个成员为对应的物理地址Q最后一个成员ؓ该段I间的大。这个数l的最后一必d部ؓ0Q以C整个数l的l束。内核启动时会读取这个数l的内容以初始化MMU表Q启用MMUQ从ɽE序可以用虚拟地址来访问设备。当ӞOEMAddressTable中所用到的每个物理地址及虚拟地址都需要在头文件中定义Q每个BSP中定义这些值的文g不尽相同Q所以,在此不能说明具体在哪个文Ӟ读者朋友可以参考具体BSP的文档及代码?br /><br />不连l内存的处理<br />如果内存在物理上是连l的Q则OEMAddressTable中只需要一就可以完成对内存的地址映射。但如果BSPq行在SDRAM物理上不q箋的系l上ӞOEMAddressTable中需要更多的ҎSDRAM映射到连l的虚拟地址上,当然也可以将它们映射Cq箋的虚拟地址上,但似乎没有理由那么做。而且Q当其物理地址不连l时pȝ需要做更多的工作。例如,我有q样一个系l:32M SDRAMQ?6M FLASHQSDRAM在物理上不连l,被分成了4?M的内存块Q我的SDRAM的用情况如下图所C:<br /><br /><br /><br />CONFIG。BIB文g的MEMORYD如下所C:<br />MEMORY<br />RESERVED 80000000 00008000 RESERVED<br />DRV_GLB 80008000 00001000 RESERVED<br />CS8900 80010000 00030000 RESERVED<br />EDBG 80040000 00080000 RESERVED<br />NK 800C0000 00940000 RAMIMAGE<br />RAM 81800000 00800000 RAM<br /><br />在这32M的空间中QBSP保留了前0x80000字节Q接下来是NKQ它占用?x940000字节Q而且它跨了两个内存?q些和其它BSP的设|都没有多大差别,接下来看RAM?它只占用了最后的8MI间,前面说过Q在q种物理内存不连l的pȝ中,RAM片不能跨两个物理内存块Q所以它被设计成只占用该pȝ中的最后一个物理内存片Q而其它两片则由OEMEnumExtensionDRAM在运行时L告给pȝQ该函数的内容如?<br /><br />pMemSections[0].dwFlags=0;<br />pMemSections[0].dwStart=(SDRAM_VIRTUAL_MEMORY + 0x1000000);<br />pMemSections[0].dwLen=0x800000;<br /><br />pMemSections[1].dwFlags=0;<br />pMemSections[1].dwStart=(SDRAM_VIRTUAL_MEMORY + 0x0A00000);<br />pMemSections[1].dwLen=0x600000;<br />return 2;<br />q样,pȝ所有的内存都被Ȁz?pȝ可用内存变成了8+8+6=24MQ可以将RAM定义三片中的L一片,而在OEMEnumExtensionDRAM中报告其它两片。但把RAM攑֜最后一片物理内存上有一个很大的好处Q即如果NK变大Q例如编译一个DEBUG版的pȝӞq时Q只需要将OEMEnumExtensionDRAM中的内容注释掉,CONFIG.BIB文g不用做Q何改动,pȝ可q行Q只是在MAKEIMG时会有一个警告说pȝ包太大,可能无法q行Q但实际不会影响pȝ的执行与E_性,因ؓNK之后的那D内存ƈ没有被用,正好被涨大的pȝ占用Q这在调试时极其方便?br />而如果系l物理内存是q箋的,那将变得单的多,q以上面的设|ؓ例,如果q?2M的SDRAM是物理上q箋的,内存的用情况就可以表示如下图:<br /><br /><br />所有者系l可用内存都可以定义在RAM片中?br />对硬件知识了解不多的朋友h意:SDRAM是否在物理上q箋Q与我们的板上有几片SDRAM没有关系Q应该向g工程师了解SDRAM的地址分布情况?/p> <img src ="http://www.shnenglu.com/milkyway/aggbug/17845.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/milkyway/" target="_blank">相思酸中有?/a> 2007-01-20 21:25 <a href="http://www.shnenglu.com/milkyway/articles/17845.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ARM开发过E中最最需要注意的问题http://www.shnenglu.com/milkyway/articles/17844.html相思酸中有?/dc:creator>相思酸中有?/author>Sat, 20 Jan 2007 13:24:00 GMThttp://www.shnenglu.com/milkyway/articles/17844.htmlhttp://www.shnenglu.com/milkyway/comments/17844.htmlhttp://www.shnenglu.com/milkyway/articles/17844.html#Feedback0http://www.shnenglu.com/milkyway/comments/commentRss/17844.htmlhttp://www.shnenglu.com/milkyway/services/trackbacks/17844.html
qx大家接触最多的可能是X86q_Q在q种pȝ上写E序几乎不需要考虑太多问题Q但ARM上就不一样了Q最常见也最Ҏ被忽略的问题可能是字节的对齐,即像我q样有六七年E序开发经验的才手也时帔R于提Ԍ最q就有一个BUGQ花了一天时间最l发现是寚w引发的,在此与大家分享,但愿大家能够注意到?br />
  我在EBOOT中读取存在HARD DISK上的nk.bin文gQ从而从HARD DISK上LOAD WINCEpȝQ在q个q程中L有check sum错误Q但从ethernet下蝲时不会有错,所以问题应该还是在我加的这部分代码上,而且同样的代码在PC上能正常q行。经q检查代码的逻辑关系是正的。接着我在出错时将那些数据全部用调试信息打出来Q发C文g开始算L4096个字节被丢掉了,而其它的字节都是对的。初步判断是寚w引发的问题,所以去查每一个BUFFERQ最l发现是在读取硬盘数据时BUFFERRq没有按双字节对齐,而硬盘以16BITd数据Q而引发了错误?br />
实际上,q类问题在ARMpȝ上很常见Q让人防不胜Ԍ以下是我的一些例子?br />
1Q解析数据流时应该时L意。如果需要把一个数据流QBUFFERQ{化成l构q行取|应该把q个l构定义为按字节存取.考虑如下l构Q?br />
struct a{

char a;
short b;
long c;
};
如果某个数据中包含q样的结构,而且我们要直接将数据的指针转化成该l构的指针,然后直接取结构成员的|我们应该将q个l构定义成按字节讉KQ即其夹在语句
#pragma pack(push,1)
...

#pragma pack(pop)
之中。如果我们不q样做,~译器会成员b的地址寚w到short指针的地址Q即在a之后加上一个char?位的成员Q将C寚w到LONGQ即在B之后再加一个char成员。如此一来,成员B和成员C得不到正确的g?br />
如果我们定义一个普通的l构用来存放一些数据,则不用定义成按字节存取,~译器会加上一些占位成员,但ƈ不会影响E序的运行。从q个意义上讲Q在ARM中,结构成员定义成CHAR和SHORT来节U内存是没有意义的?br />
一个典型的例子文件系l的驱动E序Q文件是以一些已l定义好的结构存攑֜存储介质上的Q它们被dC个BUFFER中,而具体取某个文g、目录结构时Q我们会地址转化成结构而读取其中的倹{?br />

2Q访问外设时?br />例如Q磁盘驱动通常?6BIT的方式存取数据,xơ存取两个字节,q样p求传l它的BUFFER是双字节寚w的,驱动E序应该至上层传来的指针做出正确的处理以保证数据的正性?br />

3.有时Q我们没有将数据指针{化ؓl构指针取|但如果我们读取的是双字节或者是四字节的数据Q同样需要注意对齐的问题Q例如,如果从一个BUFFER的偏U?0处读取一个四字节|则实际得到的值是偏移8处的
地址上的DWORD倹{?img src ="http://www.shnenglu.com/milkyway/aggbug/17844.html" width = "1" height = "1" />

]]>
加速CE的编译过E?/title><link>http://www.shnenglu.com/milkyway/articles/17842.html</link><dc:creator>相思酸中有?/dc:creator><author>相思酸中有?/author><pubDate>Sat, 20 Jan 2007 13:22:00 GMT</pubDate><guid>http://www.shnenglu.com/milkyway/articles/17842.html</guid><wfw:comment>http://www.shnenglu.com/milkyway/comments/17842.html</wfw:comment><comments>http://www.shnenglu.com/milkyway/articles/17842.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/milkyway/comments/commentRss/17842.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/milkyway/services/trackbacks/17842.html</trackback:ping><description><![CDATA[ <p>来自<a >http://winceblog.blogspot.com/2006_11_01_archive.html</a><br /><br />一个常见的办法是执行菜单命oQBuild->Open Release DirectoryL开一个命令行H口Q然后在q个H口中EQ到惛_~译的目录,执行Build.如果要重新编译就q行Build -c,<br />然后扑ֈ生成的DQL文gQ将其拷到Release 目录下,再执行makeimgp了.</p> <img src ="http://www.shnenglu.com/milkyway/aggbug/17842.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/milkyway/" target="_blank">相思酸中有?/a> 2007-01-20 21:22 <a href="http://www.shnenglu.com/milkyway/articles/17842.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>windowsCE常用~译参数 及编译器列表 http://www.shnenglu.com/milkyway/articles/17674.html相思酸中有?/dc:creator>相思酸中有?/author>Tue, 16 Jan 2007 02:13:00 GMThttp://www.shnenglu.com/milkyway/articles/17674.htmlhttp://www.shnenglu.com/milkyway/comments/17674.htmlhttp://www.shnenglu.com/milkyway/articles/17674.html#Feedback0http://www.shnenglu.com/milkyway/comments/commentRss/17674.htmlhttp://www.shnenglu.com/milkyway/services/trackbacks/17674.htmlhttp://www.cnblogs.com/nasiry/archive/2004/11/09/61958.aspx

---------------by nasiry 

RELEASETYPE
指定发布的类?实际上就是编译后的文件的存放位置可选项?
SDK|DDK|PLATFORM|LOCAL|CUSTOM 其余选项{效OAK

DLLENTRY|EXEENTRY|NODLLENTRY
指定入口?

_TGTCPUFAMILY 

指定处理器所属家族可选x86|MIPS|SH|ARM


LINT_TYPE
可选all | lob | ind

TARGETEXEFILES
控制输出文g 可选NOLINK---不链?


 

TARGETTYPE
输出文g的类?可选DYNLINK|PROGRAM|LIBRARY

WINCEDEBUG
文g发布cd 可选retail|debug I?debug

CDEBUG_DEFINES
调试~译选项 WINCE_LMEM_DEBUG|DISABLE_OPTIMIZER|WINCESHIP|WINCE_OVERRIDE_CFLAGS

TARGET_PDB_NAME
PDB文g?

WINCEPROFILE
可?|1

TGTCPUISANAME
处理器名U?


~译?
x86

cxx cl386 -nologo
asm ml -nologo
-machine:iX86

SH3

cxx clsh -nologo
asm shasm
-machine:sh3

SH4
cxx clsh -nologo
asm shasm
-machine:sh4

MIPSII
cxx clmips -nologo
asm mipsasm
-machine:mips /-machine:-machine:mipsfpu

ARMV4                :

cxx clarm -nologo
asm armasm -coff
-machine:arm

ARMV4T
ARMV4I
clthumb -nologo
asm armasm -coff
-machine:thumb



]]>
Kitl是怎样工作的?http://www.shnenglu.com/milkyway/articles/17673.html相思酸中有?/dc:creator>相思酸中有?/author>Tue, 16 Jan 2007 02:08:00 GMThttp://www.shnenglu.com/milkyway/articles/17673.htmlhttp://www.shnenglu.com/milkyway/comments/17673.htmlhttp://www.shnenglu.com/milkyway/articles/17673.html#Feedback1http://www.shnenglu.com/milkyway/comments/commentRss/17673.htmlhttp://www.shnenglu.com/milkyway/services/trackbacks/17673.html     来自 http://www.cnblogs.com/nasiry/archive/2004/09/22/45473.aspx                                
---------------------------------
注:׃我们主要是分析kitl的工作原理我们就甉|理的代码不做分析,以加电启动的E序进行分析?
part1.
kitl初始?
-------------
Kitl的加载于其他调试服务之前Q以提供些调试服务发布调试信息和接收L调试命o的的通道。通常kitl在系lHAL初始化工作完成后q行加蝲QMS在OEMInit中启动kitl。这样就可以使用NIC或者是serial/Pal作ؓkitl的物理传输介质?
kitl的初始化由KitlInit完成Q这部分代码主要负责Q?to be fill later)
下面我们来看看kitl的具体代码,q些代码位于%CEROOT%\PRIVATE\WINCEOS\COREOS\NK\KITL下?
BOOL KitlInit (BOOL fStartKitl)
{
    // just initialize function pointers
    pKITLRegisterDfltClient  = KITLRegisterDfltClient;
    pKITLIoCtl = KITLIoctl;
    pfnIsDesktopDbgrExist = IsDesktopDbgrExist;

    // Initialize default clients
    NewClient (KITL_SVC_DBGMSG, KITL_SVCNAME_DBGMSG, FALSE);
    NewClient (KITL_SVC_PPSH,   KITL_SVCNAME_PPSH,   FALSE);
    NewClient (KITL_SVC_KDBG,   KITL_SVCNAME_KDBG,   FALSE);


    return fStartKitl? StartKitl (TRUE) : TRUE;
}
q段代码主要完成两个动作Q?
1.装蝲函数指针Qؓ后箋代码的执行装载入口点?
2.注册kitl客户端,q些客户端实C输层以后是我们所需要的调试界面?
输入参数军_是否立即启动KITL服务Q如果false的话׃仅进行初始化{待后箋动作使用startKitl来启动kitl.

我们再来看看NewClient的原?
static PKITL_CLIENT NewClient (UCHAR uId, LPCSTR pszSvcName, BOOL fAlloc)
{
    DEBUGCHK(IS_VALID_ID(uId));
    DEBUGCHK (!KITLClients[uId]);
    if (!fAlloc) {
        DEBUGCHK(IS_DFLT_SVC(uId));
        KITLClients[uId] = &DfltClnts[uId];
    } else if (!(KITLClients[uId] = (PKITL_CLIENT) AllocMem (HEAP_KITLCLIENT))) {
        return NULL;
    }
    memset (KITLClients[uId], 0, sizeof(KITL_CLIENT));
    KITLClients[uId]->ServiceId = uId;
    strcpy (KITLClients[uId]->ServiceName, pszSvcName);

    return KITLClients[uId];
}
q个被称为NewClient的函数所完成的功能十分的单,先检查所需要创建的l构是否是系l默认服务所需要的Q如果是的话q接将该结构的指针指向全局l构DfltClntsq初始化l构Q如果不是就甌相应的空间完成该l构的初始化。默认的服务?KITL_SVCNAME_DBGMSGQ?KITL_SVCNAME_PPSHQ?KITL_SVCNAME_KDBG分别对应Debug信息的发布通道(Debug message)Q文本控制台界面(PPshell)Q和内核调试界面(kernel debug),在这里大家可能会问:Z么不l一使用固定的全局l构来存放这些服务的信息呢?原因很简单,因ؓq些"client"在WindowSCE下是可以注册扩充和注销的,q样用AllocMem所分配的内存空间在不再需要这些服务的时候可以释放掉Q就可以避免不必要的费。另外KITLClients是这样定义的PKITL_CLIENT KITLClients[MAX_KITL_CLIENTS];所以kitl所能注册的clientq同3个默认的服务一共最多可以有MAX_KITL_CLIENTS--128个?

下面l箋沿着E序往下看吧,kitlInit完成最基本的初始化动作卛_启动kitl服务了。再看一下这个函数的原型?
static BOOL StartKitl (BOOL fInit)
{
    // KITL already started?
    if (!fInit && (KITLGlobalState & KITL_ST_DESKTOP_CONNECTED)) {
        return TRUE;
    }

    /*
     * When this function is called, the kernel hasn't yet been initialized,
     * so can't make any system calls.  Once the system has come up far
     * enough to handle system calls, KITLInitializeInterrupt() is called to complete
     * initialization.  This is indicated by the KITL_ST_MULTITHREADED flag in KITLGlobalState.
     */
    // Detect/initialize ethernet hardware, and return address information
    if (!OEMKitlInit (&Kitl))
        return FALSE;

    // verify that the Kitl structure is initialized.
    if (!Kitl.pfnDecode || !Kitl.pfnEncode || !Kitl.pfnEnableInt || !Kitl.pfnRecv || !Kitl.pfnSend
        || !Kitl.dwPhysBuffer || !Kitl.dwPhysBufLen || !Kitl.WindowSize || !Kitl.pfnGetDevCfg || !Kitl.pfnSetHostCfg) {
        return FALSE;
    }

    // Validate that address is not in free RAM area - the HAL should put it in a reserved
    // section of memory conditional on some environment var.
    if ((pTOC->ulRAMStart < Kitl.dwPhysBuffer + Kitl.dwPhysBufLen)
        && (pTOC->ulRAMEnd > Kitl.dwPhysBuffer)) {
        KITLOutputDebugString("\r\n!Debug Ethernet packet buffers in free RAM area - must set IMGEBOOT=1\r\n");
        return FALSE;
    }

    if (Kitl.dwPhysBufLen < (DWORD) 3 * KITL_BUFFER_POOL_SIZE) {
        KITLOutputDebugString("\r\n!Debug Ethernet buffer size too small, must be at least 0x%x bytes (3 * WindowSize * 2 * KITL_MTU)\r\n",
            3 * KITL_BUFFER_POOL_SIZE);
        return FALSE;
    }

    KITLGlobalState |= KITL_ST_KITLSTARTED; // indicate (to kdstub) that KITL has started

    // If the initialized flag is already set, we are being called from the power on routine,
    // so reinit the HW, but not any state.
    if (!(KITLGlobalState & KITL_ST_ADAPTER_INITIALIZED)) {
        // perform the initial handshake with the desktop
        if (!KITLConnectToDesktop ()) {
            KITLOutputDebugString ("\r\n!Unable to establish KITL connection with desktop!\r\n");
            return FALSE;
        }
       
        // Set up kernel function pointers
        pKITLInitializeInterrupt = KITLInitializeInterrupt;
        pKITLSend = KITLSend;
        pKITLRecv = KITLRecv;

        KITLGlobalState |= KITL_ST_ADAPTER_INITIALIZED;

        if (Kitl.dwBootFlags & KITL_FL_DBGMSG)
            SetKernelCommDev (KERNEL_SVC_DBGMSG, KERNEL_COMM_ETHER);
        if (Kitl.dwBootFlags & KITL_FL_PPSH)
            SetKernelCommDev (KERNEL_SVC_PPSH, KERNEL_COMM_ETHER);
        if (Kitl.dwBootFlags & KITL_FL_KDBG)
            SetKernelCommDev (KERNEL_SVC_KDBG, KERNEL_COMM_ETHER);

        // only perform cleanboot if it's connected at boot. Cleanboot flag is
        // ignored if it's started dynamically.
        if (fInit && (Kitl.dwBootFlags & KITL_FL_CLEANBOOT)) {
            extern ROMHDR *const volatile pTOC;     // Gets replaced by RomLoader with real address
            // just clear the magic nOEMKitlInitumber (see SC_SetCleanRebootFlag)
            // NOTE: We can NOT call SC_SetCleanRebootFlag here since logPtr isn't
            // initialized yet.
            ((fslog_t *)((pTOC->ulRAMFree + MemForPT) | 0x20000000))->magic1 = 0;
        }
        // if OEM calls KitlInit (FALSE), KITLInitializeInterrupt will
        // not be called in SystemStartupFuc. We need to initialize
        // interrupt here (when RegisterClient is called)
        if (fKITLcsInitialized && !InSysCall ()) {
            KITLInitializeInterrupt ();
        }
    }

    LOG (KITLGlobalState);
    return TRUE;
}
启动代码首先判断是否已经启动kitl服务Q之后调用OEMKitlInitQ该函数q不在private目录下实玎ͼ通常windowsCE需要用户定制的代码都是q种l构---MS提供的代码接口,用户自己完成相应的OEM部分Q通常q些代码都是与具体的gq_相关的代码。kitl的OEM代码在HAL中实玎ͼ通常在platform\kernel\hal\.下,q部分的代码我们先蟩q,看完startkitl的全貌再回过头逐个说明。OEMkitlInit为kitl初始化硬件传输介质,同时分配初始化一些kitl所需要的全局l构。随后startkitll箋查OEMkitlInit所分配和初始化的KITLl构和内存区域是否有效后讄kitl的全局标示KITL_ST_KITLSTARTEDQ之后设|终端服务程序以及接收和发送程序的入口点后讄全局标示KITL_ST_ADAPTER_INITIALIZED。现在传输介质已l全部就l,通过SetKernelCommDev讄kernel通过ethernet传送调试信息,调试输入Q以及CESH控制台。再后调用KITLInitializeInterrupt完成中断的初始化kitl启动的过E就l束了?
   紧接着我们来看看,OEMkitlInit都须要我们干什么。下面用SMDK2440的kitl为实例来q行分析Q?
BOOL OEMKitlInit (PKITLTRANSPORT pKitl)
{
    KITLOutputDebugString ("+OEMKitlInit\n");
    RETAILMSG(1, (_T("+OEMKitlInit\r\n")));
    // try to find a transport available
    if (!InitEther (pKitl)
        && !InitParallelSerial (pKitl)) {
        KITLOutputDebugString ("Unable to initialize KITL Transports!\n");
        return FALSE;
    }

    gpKitl = pKitl;
    KITLOutputDebugString ("-OEMKitlInit\n");
    RETAILMSG(1, (_T("-OEMKitlInit\r\n")));
    return TRUE;
}

事实上工作很单,调用InitEther (pKitl) ?!InitParallelSerial (pKitl)初始化网卡直接把初始化的KITL全局l构q回是所有的工作。这儿的InitParallelSerial是一个dummy永远q回false,也就是说q里没有对serial&parallel transportq行支持。真正的工作量集中在InitEther之后。事实上InitEther ?InitParallelSerial只要L的实C个就可以辑ֈ建立传输界面的目?下面Q我们l看后面的代码?
BOOL InitEther(PKITLTRANSPORT pKitl)
{
    EDBG_ADAPTER adp;
    DWORD dwDHCPLeaseTime;
    DWORD dwSubnetMask;

    KITLOutputDebugString ("+InitEther\n");

    memset (&adp, 0, sizeof(adp));
    memset (pKitl, 0, sizeof (KITLTRANSPORT));

    // use existing code for ether initialization
    if (!OEMEthInit (&adp))
        return FALSE;

    // we are going to completely ignore the info in bootargs and the adaptor info
    // returned from OEMEthInit, except MAC address. Just to prove that KITL will connect standalone

    // get the MAC address
    MyAddr.wMAC[0] = adp.Addr.wMAC[0];
    MyAddr.wMAC[1] = adp.Addr.wMAC[1];
    MyAddr.wMAC[2] = adp.Addr.wMAC[2];
    //MyAddr = adp.Addr;
   
    CreateDeviceName(&MyAddr, pKitl->szName);
    KITLOutputDebugString ("Using device name: %s\n", pKitl->szName);

    // If we haven't been given an IP address from our loader (or if we're not using static IP), get an IP address
    // from a DHCP server.
    if (adp.Addr.dwIP)
    {
        // Static IP or we got the IP from our bootloader...
        MyAddr.dwIP     = adp.Addr.dwIP;
        dwSubnetMask    = 0;    // Don't care about subnet mask...
        dwDHCPLeaseTime = adp.DHCPLeaseTime;
    }
    else
    {
        // Get a DHCP address...
        if (!EbootGetDHCPAddr (&MyAddr, &dwSubnetMask, &dwDHCPLeaseTime))
            return FALSE;
    }
   
    MyAddr.wPort = htons (EDBG_SVC_PORT);
    KITLOutputDebugString ("Device %s, IP %s, Port %d\n", pKitl->szName, inet_ntoa (MyAddr.dwIP), htons (MyAddr.wPort));

    // initialize KITL Ethernet transport layer
    if (!KitlEtherInit (&MyAddr, dwDHCPLeaseTime)) {
        KITLOutputDebugString ("Unable to initialize KITL Ether transport\n");
        return FALSE;
    }
   
    // fill in the blanks in KITLTRANSPORT structure.
    pKitl->FrmHdrSize = KitlEtherGetFrameHdrSize ();
    pKitl->Interrupt = (UCHAR) adp.SysIntrVal;
    pKitl->dwPhysBuffer = EDBG_PHYSICAL_MEMORY_START;
    pKitl->dwPhysBufLen = 0x20000;                      // 128K of buffer available
    pKitl->dwBootFlags = 0;
    pKitl->WindowSize = EDBG_WINDOW_SIZE;
    pKitl->pfnDecode = KitlEtherDecodeUDP;
    pKitl->pfnEncode = KitlEtherEncodeUDP;
    pKitl->pfnSend = EthSend;
    pKitl->pfnRecv = OEMEthGetFrame;
    pKitl->pfnEnableInt = KitlEthEnableInts;
    pKitl->pfnSetHostCfg = SetHostCfg;
    pKitl->pfnGetDevCfg = GetDevCfg;

    KITLOutputDebugString ("-InitEther\n");


    return TRUE;
}
q个函数完成的工作主要是调用OEMEthInit初始化网卡的服务E序及获得相应的IP和MACQ如果IP无效则用DHCP动态获得IP.通过MACg生一个标C,q个标示用来lPB的IDE使用。刚才的我们在kitlInit中看到除了检查OEMkitlInit的返回g外还查了KITLl构Q该l构的这些特征值正是在q儿讄的。在q儿可以看到pKitl->pfnDecode pKitl->pfnEncode pKitl->pfnSetHostCfg pKitl->pfnGetDevCfg 以及kitl所用的中断可些都是OEM代码Q也是用于传输的编码和解码形式以及配置函数都是可以自己定义的,q样一来也无所谓用什么传输介质作为KITK
的transport了,q就Z?394或者是USBq一cȝ传输链\也能充当传输界面作了准备?OEMEthInit函数是用于初始化传输介质--以太|卡。这部分代码直接是硬件控制代码,我们来简单的看一下?
BOOL
OEMEthInit(EDBG_ADAPTER *pAdapter)
{
 PBYTE pBaseIOAddress;

 // Driver globals from the bootloader.
 //
 if (pDriverGlobals->eth.EbootMagicNum == EBOOT_MAGIC_NUM)
 {
  memcpy(pAdapter, &pDriverGlobals->eth.TargetAddr, sizeof(EDBG_ADAPTER));

  switch(pDriverGlobals->misc.EbootDevice)
  {
  case(DOWNLOAD_DEVICE_PCMCIA): // NE2000 CF card.
   pBaseIOAddress  = (PBYTE)PCMCIA_Init();
   if (pBaseIOAddress)
   {
    // Initialize the built-in Ethenet controller.
    //
    if (!NE2000Init((PBYTE)pBaseIOAddress, 1, pAdapter->Addr.wMAC))
    {
     EdbgOutputDebugString("ERROR: OEMEthInit: Failed to initialize Ethernet controller.\r\n");
     return(FALSE);
    }
   }
   pfnEDbgInit            = NE2000Init;
   pfnEDbgEnableInts      = NE2000EnableInts;
   pfnEDbgDisableInts     = NE2000DisableInts;
   pfnEDbgGetPendingInts  = NE2000GetPendingInts;
   pfnEDbgGetFrame        = NE2000GetFrame;
   pfnEDbgSendFrame       = NE2000SendFrame;
   pfnEDbgReadEEPROM      = NE2000ReadEEPROM;
   pfnEDbgWriteEEPROM     = NE2000WriteEEPROM;
   pfnEDbgSetOptions      = NE2000SetOptions;
  #ifdef IMGSHAREETH
   pfnCurrentPacketFilter = Ne2000CurrentPacketFilter;
   pfnMulticastList  = NE2000MulticastList;
  #endif // IMGSHAREETH.
   break;
  case(DOWNLOAD_DEVICE_CS8900): // CS8900A.
   // Initialize the CS8900.
   //
   if (!CS8900DBG_Init((PBYTE)CS8900DBG_IOBASE, CS8900DBG_MEMBASE, pAdapter->Addr.wMAC))
   {
    EdbgOutputDebugString("ERROR: OEMEthInit: CS8900 initialization failed.\r\n");
    return(FALSE);
   }

   pfnEDbgInit  = CS8900DBG_Init;
   pfnEDbgEnableInts      = CS8900DBG_EnableInts;
   pfnEDbgDisableInts     = CS8900DBG_DisableInts;
   pfnEDbgGetFrame  = CS8900DBG_GetFrame;
   pfnEDbgSendFrame = CS8900DBG_SendFrame;
   pfnEDbgGetPendingInts  = CS8900DBG_GetPendingInts;
  #ifdef IMGSHAREETH
   pfnCurrentPacketFilter = CS8900DBG_CurrentPacketFilter;
   pfnMulticastList = CS8900DBG_MulticastList;
  #endif // IMGSHAREETH.
   break;
  default:
   EdbgOutputDebugString("ERROR: OEMInit: Unknown download NIC (0x%x).\r\n", pDriverGlobals->misc.EbootDevice);
   return(FALSE);
 
 }}
 else
 {
  // TODO - retrieve CS8900 MAC address from flash...
  // TODO - intialize the CS8900 from scratch...
 }

 EdbgOutputDebugString("::: OEMEthInit() IP Address : %s\r\n", inet_ntoa(pAdapter->Addr.dwIP));
 EdbgOutputDebugString("::: OEMEthInit() Netmask    : %s\r\n", inet_ntoa(pDriverGlobals->eth.SubnetMask));

 if (pDriverGlobals->misc.EbootDevice == DOWNLOAD_DEVICE_PCMCIA)
  pAdapter->SysIntrVal    = SYSINTR_PCMCIA_LEVEL;
 else
  pAdapter->SysIntrVal    = SYSINTR_ETHER;

 pAdapter->DHCPLeaseTime = DEFAULT_DHCP_LEASE;
 pAdapter->EdbgFlags     = pDriverGlobals->eth.EdbgFlags;
  
#ifdef IMGSHAREETH
    VBridgeInit();
    VBridgeKSetLocalMacAddress((char *)pAdapter->Addr.wMAC);
#endif // IMGSHAREETH.

 return(TRUE);
}
   
q个函数看v来很复杂其实真正的工作ƈ不多Q首先判断是不是由eboot启动的,如果已经eboot中已l完成了对以太网卡的初始化动作就直接使用|卡q装?挂接|卡所需的函数和|卡信息Q否则就需要自p|网卡的MAC地址和初始化|卡(事实上以上函数ƈ没有对这部分代码q行实现Q这是很多使用2410/2440的用户在不用eboot启动的情况下L不能使用kitl的原?-找不到eboot在DriverGlobal中留下的magic NUMBER)。这儿之所以有NE2000和Cs8900的区分是因ؓSMDK2440可以使用PCMICA挂接Ne2000兼容的NIC或板载CS8900Q后面设|中断标C有两个分支也是q个原因?
IMGSHAREETH的部分是Vbridge的部?Z么要使用q个叫vbridge的东西呢Q我们看看下面的假设?
Z建立kitl占用了一个网卡资源,而该资源如果在windowsCE下复?该设备同时被两个驱动使用1.kitl 2.windowsCE NIC driver)的话会不会导致问题呢Q看看下面的两个函数?
    VBridgeInit();
    VBridgeKSetLocalMacAddress((char *)pAdapter->Addr.wMAC);
    该函数在内核调试传输通道和tcp/ip&windsock之间建立一个虚拟的|桥v-bridgeQ在外部看来vbridge像在mac层一Pvbridge一斚w和硬仉讯建立传输的物理界面,另一斚w和调试所需的EDBG和vmini.dll提供相同的逻辑界面Q在更高的层面vmini.dll像一个专门的|卡一h持NDIS以至于tcp/ip协议栈。这h们就可以一斚w使用|卡做调试另外一斚w仍然能让windowsCE使用|卡通讯Q对于windowCE而言所使用的网卡不在是与底层对应的|络讑֤Q而是通过vbridge虚拟出来的网l设备,所以在直接使用SMDK24XX的bsp~译出来的系l网卡显CZؓvmini是q个原因。这个时候网卡驱动怎么配置呢?{案很简单,是不要|卡驱动Q因为我们已l从vbridge中抽?虚拟---用一个网?Z个网卡了Q原来的|卡驱动也就不在需要了?
   
从上面的OemKitlInit到InitEther都是OEM代码Q目的在于Kitl与相应的transport的物理介质联pv来,也就是构建kitl的硬件抽象层Q在一个kitl初始化代码中中只有这部分工作(OEM代码)是必要的Q其余的代码直接使用MS~译好的lib可以了。尽如此我们还是l看下面的代码,虽然q对我们来说不是必须的不q对一个程序要有全面的认识Q框架上的重要模块都是需要了解和认识的?


看完了这一pd的OEM代码Ql看看StartKitl里面我们没有看完的部分在讄启动标示位之前做?个检查分别是查buffer的位|是否在~译pȝ的时候预留下来以及是否有_的长度可用。这个内存区域不是动态分配的Q而是在bsp的内存配|文件中指定q保留下来的(见bsp file目录下的config.bib)。再下来q行一个KITLConnectToDesktop的动作,q个看名字就知道作用了。就是和PCq接。同L看代码:
static BOOL KITLConnectToDesktop (void)
{
    // we'll use the PpfsFmtBuf for send buffer since ppfs can't be started yet at this stage
    //
    PKITL_HDR pHdr = (PKITL_HDR) (PpfsFmtBuf + Kitl.FrmHdrSize);
    PKITL_DEV_TRANSCFG pCfg = (PKITL_DEV_TRANSCFG) KITLDATA(pHdr);
    USHORT cbData = sizeof (PpfsFmtBuf) - Kitl.FrmHdrSize - sizeof (KITL_HDR) - sizeof (KITL_DEV_TRANSCFG);

    if (!Kitl.pfnGetDevCfg ((LPBYTE) (pCfg+1), &cbData))
        return FALSE;

    memset (pHdr, 0, sizeof (KITL_HDR));
    pHdr->Id = KITL_ID;
    pHdr->Service = KITL_SVC_ADMIN;
    pHdr->Cmd = KITL_CMD_TRAN_CONFIG;
    cbData += sizeof (KITL_DEV_TRANSCFG);
    pCfg->wLen = cbData;
    pCfg->wCpuId = KITL_CPUID;
    memcpy (pCfg->szDevName, Kitl.szName, KITL_MAX_DEV_NAMELEN);
    cbData += sizeof (KITL_HDR);

    return KitlSendFrame (PpfsFmtBuf, cbData)
        && KITLPollResponse (FALSE, ChkCnxDsktp, TranCnxDsktp, (LPVOID) cbData);
}
l构PKITL_HDR是kilt的传输头格式Q而PKITL_DEV_TRANSCFG信息则是传输讑֤的设|。首先通过调用Kitl.pfnGetDevCfg得到传输讑֤的信息,Kitl.pfnGetDevCfg是函数指针,在对以太|卡初始化的时候指向OEM代码中的GetDevCfg函数。通过q个函数得到讑֤信息(smdk2410的bsp中这儿返回的是IP地址)。然后再l箋讄传输头的标示Q类型,命o{等信息Q然后就是发送数据了Q具体的动作是调用KitlSendFrame?To be continue...)

BOOL KitlSendFrame (LPBYTE pbFrame, WORD cbData)
{
    if (!Kitl.pfnEncode (pbFrame, cbData)) {
        KITLOutputDebugString ("!KitlSendFrame: transport failed to encode the data frame\r\n");
        return FALSE;
    }

    return KitlSendRawData (pbFrame, (USHORT) (cbData + Kitl.FrmHdrSize + Kitl.FrmTlrSize));
}
q个函数首先调用KitlEtherEncodeUDPҎ据q行~码为UDP协议需要的格式。然后调?KitlSendRawData数据送出至PC.
BOOL KitlSendRawData (LPBYTE pbData, WORD wLength)
{
    BOOL fRet;
    if (!(KITLGlobalState & KITL_ST_MULTITHREADED) || InSysCall())
        fRet = Kitl.pfnSend (pbData, wLength);
    else if (IsDesktopDbgrExist ())
        fRet = KCall((PKFN) Kitl.pfnSend, pbData, wLength);
    else {
        EnterCriticalSection (&KITLKCallcs);
        fRet = Kitl.pfnSend (pbData, wLength);
        LeaveCriticalSection (&KITLKCallcs);
    }
    return fRet;
}
首先判定pȝ没有在调度中且当前代码在不可剥夺状态状态运行,通过EthSend调用OEMEthSendFrame数据送出完成了工作。另外两个分支与我们分析的程序流没有关系先放一下?
BOOL
OEMEthSendFrame(
    BYTE *pData,     // IN - Data buffer
    DWORD dwLength)  // IN - Length of buffer
{
    int retries = 0;

    while (retries++ < 4) {
        if (!pfnEDbgSendFrame(pData, dwLength))
  {
#ifdef IMGSHAREETH
   ProcessVMiniSend();
#endif //IMGSHAREETH
            return TRUE;
  }
        else
            EdbgOutputDebugString("!OEMEthSendFrame failure, retry %u\n",retries);
    }
    return FALSE;
}
在发送数据的过E中专门有处理vMini发送的q程。由于kitl本n׃是很单我们以后后面再用专门的文章说明vbridge的工作过E。完成了发送,我们l箋下面的过E?
BOOL KITLPollResponse (BOOL fUseSysCalls, PFN_CHECK pfnCheck, PFN_TRANSMIT pfnTransmit, LPVOID pData)
{
    DWORD dwLoopCnt = 0, dwLoopMax = MIN_POLL_ITER;
    DWORD dwStartTime = CurMSec;
    int   nTimeMax = MIN_POLL_TIME;  // start with 1 sec
    BOOL  fUseIter = FALSE, fUseTick = FALSE;

    while (!pfnCheck (pData)) {
        //
        // if we've already connected with desktop, use the desktop
        // "Retransmit" package to determine if we need to retransmit
        //
        if (!(KITLGlobalState & KITL_ST_DESKTOP_CONNECTED)) {
            if (fUseTick) {
                if ((int) (CurMSec - dwStartTime) > nTimeMax) {
                    // retransmit
                    if (!pfnTransmit (pData, fUseSysCalls))
                        return FALSE;
                    dwStartTime = CurMSec;
                    if (nTimeMax < MAX_POLL_TIME)
                        nTimeMax <<= 1;
                }
            } else if (fUseIter || (dwStartTime == CurMSec)) {
                // if time isn't moving for a while, we'll
                // use iteration.
                if (dwLoopCnt ++ > dwLoopMax) {
                    if (!pfnTransmit (pData, fUseSysCalls))
                        return FALSE;
                    if (dwLoopMax < MAX_POLL_ITER)
                        dwLoopMax <<= 1;
                    dwLoopCnt = 0;
                    fUseIter = TRUE;
                }
            } else {
                // time is moving, just use tick from here
                fUseTick = TRUE;
            }
        }
        if (!KITLPollData(fUseSysCalls, pfnTransmit, pData)) {
            return FALSE;
        }
    }
    return TRUE;
}
static BOOL TranCnxDsktp (LPVOID pParam, BOOL fUseSysCalls)
{
    return KitlSendFrame (PpfsFmtBuf, (WORD) (DWORD) pParam);
}
q个函数的主体是一个@环,l止的条件是!pfnCheck (pData)Q这个函数是由前面传递进来的Q返回gؓKITLGlobalState & KITL_ST_DESKTOP_CONNECTEDQ也是说在得到桌面q接之前是不会返回的也就是说启动kitl以后不与桌面计算接windowsCE的是无法启动的。由于从dwStartTime定义到dwStartTime == CurMSec的判定仅仅需要很的旉可以完成这D|间内CurMSec是不会被改写的就可以通过循环q行时?
q过TranCnxDsktp重新发送数据,直到KITLPollData讄KITLGlobalState?
static BOOL KITLPollData(BOOL fUseSysCalls, PFN_TRANSMIT pfnTransmit, LPVOID pData)
{
    LPBYTE pRecvBuf = PollRecvBuf;
   
    if (fUseSysCalls && (KITLGlobalState & KITL_ST_MULTITHREADED)
        && !(pRecvBuf = _alloca(KITL_MTU))) {
        KITLOutputDebugString("!KITLPollData: STACK OVERFLOW!\r\n");
        return FALSE;
    }
    HandleRecvInterrupt(pRecvBuf, fUseSysCalls, pfnTransmit, pData);
    return TRUE;
}
׃我们上面传来的fUseSysCalls参数为false所以前一D|查操作ƈ不进行。直接调?HandleRecvInterrupt?

void HandleRecvInterrupt(UCHAR *pRecvBuf, BOOL fUseSysCalls, PFN_TRANSMIT pfnTransmit, LPVOID pData)
{
    WORD wLen = KITL_MTU;
    BOOL fFrameRecvd;

    // Receive data into buffer
    do {
        if (!fUseSysCalls)
            fFrameRecvd = Kitl.pfnRecv (pRecvBuf, &wLen);
        else if (IsDesktopDbgrExist ())
            fFrameRecvd = KCall((PKFN) Kitl.pfnRecv, pRecvBuf, &wLen);
        else {
            EnterCriticalSection (&KITLKCallcs);
            fFrameRecvd = Kitl.pfnRecv (pRecvBuf, &wLen);
            LeaveCriticalSection (&KITLKCallcs);
        }
        if (fFrameRecvd) {
            ProcessRecvFrame (pRecvBuf,wLen,fUseSysCalls, pfnTransmit, pData);
            wLen = KITL_MTU;
        }
    } while (fFrameRecvd);
}
通过Kitl.pfnRecv调用pfnEDbgGetFrame指向的CS8900DBG_GetFramed当前的数据送交ProcessRecvFrame处理。注意,q儿的pfnEDbgGetFrameq不是通过DMA或者是|卡传来的中断启动的而是使用查询的方法进行的Q这是Z么这儿ƈ没有启动中断仍然能够使用以太|卡q行数据传输数据的原因。随后,我们计机端送来的数据送交ProcessRecvFrame处理?

static BOOL ProcessRecvFrame(UCHAR *pFrame, WORD wMsgLen, BOOL fUseSysCalls, PFN_TRANSMIT pfnTransmit, LPVOID pData)
{
    KITL_HDR *pMsg;
    KITL_CLIENT *pClient = NULL;
    BOOL fRet = TRUE;
    UCHAR RxBufOffset;
    WORD  wDataLen;
    UCHAR ClientIdx;
    // let the transport layer decode the frame
    if (!(pMsg = (KITL_HDR *) Kitl.pfnDecode (pFrame, &wMsgLen))) {
        KITL_DEBUGMSG(ZONE_RECV, ("ProcessRecvFrame: Received Unhandled frame\n"));
        return FALSE;
    }

    // is it a valid KITL message?
    if (pMsg->Id != KITL_ID) {
        KITL_DEBUGMSG(ZONE_WARNING,("KITL: Got unrecognized Id: %X\r\n",pMsg->Id));
        return FALSE;
    }
   
    // Validate length
    if (wMsgLen < KITL_DATA_OFFSET) {
        KITL_DEBUGMSG(ZONE_WARNING,("KITL: Invalid length %u\n",wMsgLen));
        return FALSE;
    }
    if (KITLDebugZone & ZONE_FRAMEDUMP)
        KITLDecodeFrame("<<KITLRecv",pMsg, wMsgLen);
   
    // Check for administrative messages
    if (pMsg->Service == KITL_SVC_ADMIN)
        return ProcessAdminMsg(pMsg, wMsgLen, fUseSysCalls, pfnTransmit, pData);

    // Service Id is index into KITLClients array
    ClientIdx = pMsg->Service;
    if (ClientIdx >= MAX_KITL_CLIENTS) {
        KITL_DEBUGMSG(ZONE_WARNING,("!ProcessKITLMsg: Invalid ServiceId: %u\n",pMsg->Service));
        return FALSE;
    }

    pClient = KITLClients[ClientIdx];
   
    // Until we complete registering, only handle administrative messages
    if (!pClient || !(pClient->State & KITL_CLIENT_REGISTERED)) {
        KITL_DEBUGMSG(ZONE_WARNING,("!ProcessKITLMsg: Client %u not registered\n",ClientIdx));
        return FALSE;
    }
    if (pMsg->Service != pClient->ServiceId) {
        KITL_DEBUGMSG(ZONE_WARNING,("!ProcessKITLMsg: Mismatch in service Id for Client %u (Got %u, expect %u)\n",
                                    ClientIdx,pMsg->Service,pClient->ServiceId));
        return FALSE;
    }

    if (pClient->State & KITL_USE_SYSCALLS) {
        if (fUseSysCalls) 
            EnterCriticalSection(&pClient->ClientCS);
        else if (pClient->ClientCS.OwnerThread) {
            // We can't get the client CS, and it is owned - just toss frame
            KITL_DEBUGMSG(ZONE_WARNING,("!KITL(%u) tossing msg %u (Can't get CS)\n",ClientIdx, pMsg->SeqNum));
            return FALSE;
        }
    }

    // we've being in sync with the desktop
    pClient->State |= KITL_SYNCED;
   
    // Put flags and seq # to LEDs
    KITL_DEBUGLED(LED_PEM_SEQ, ((DWORD) pMsg->Flags << 24) | pMsg->SeqNum);
   
    // OK, valid message, see if it's an ACK
    if (pMsg->Flags & KITL_FL_ACK) {
        KITL_DEBUGMSG(ZONE_RECV,("KITL(%u): Received ack for msg %u, Tx window: %u,%u\n",
                                 ClientIdx,pMsg->SeqNum, pClient->AckExpected,pClient->TxSeqNum));
        // ACKs acknowledge all data up to the ACK sequence #
        while (SEQ_BETWEEN(pClient->AckExpected, pMsg->SeqNum, pClient->TxSeqNum)) {       
            if ((pClient->State & KITL_USE_SYSCALLS) &&
                ((pClient->CfgFlags & KITL_CFGFL_STOP_AND_WAIT) ||
                 (SEQ_DELTA(pClient->AckExpected, pClient->TxSeqNum) >= pClient->WindowSize-1) ||
                 !(KITLGlobalState & KITL_ST_INT_ENABLED))) {
                if (fUseSysCalls)
                    SetClientEvent(pClient,pClient->evTxFull);
                else {
                    // Can't process message at this time...
                    KITL_DEBUGMSG(ZONE_WARNING,("!KITL(%u): Tossing ACK %u (Can't set event)\n",
                                                ClientIdx, pMsg->SeqNum));
                    return FALSE;
                }
            }
            // Stop retransmission timer.
            TimerStop(pClient, (UCHAR)(pClient->AckExpected % pClient->WindowSize),fUseSysCalls);
            SEQ_INC(pClient->AckExpected);
        }
        goto ProcessKITLMsg_exit;
    }

    // Handle NACKs - retransmit requested frame if it is in our Tx window
    if (pMsg->Flags & KITL_FL_NACK) {
        KITL_DEBUGMSG(ZONE_WARNING,("KITL(%u): Received NACK for msg %u, Tx window: %u,%u\n",
                                    ClientIdx,pMsg->SeqNum, pClient->AckExpected,pClient->TxSeqNum));
        if (SEQ_BETWEEN(pClient->AckExpected, pMsg->SeqNum, pClient->TxSeqNum)) {
            UCHAR Index = pMsg->SeqNum % pClient->WindowSize;
            if (pClient->TxFrameLen[Index]) {
                // Restart retransmission timer (note we can't start timers if syscalls
                // are disabled, but this shouldn't screw us up, we'll just potentially
                // retransmit an extra frame if the timer fires before we get the ACK)
                if (fUseSysCalls)
                    TimerStop(pClient,Index,fUseSysCalls);
                RetransmitFrame(pClient, Index, fUseSysCalls);
                if (fUseSysCalls)
                    TimerStart(pClient,Index,KITL_RETRANSMIT_INTERVAL_MS,fUseSysCalls);
            }
            else
                KITL_DEBUGMSG(ZONE_WARNING,("!KITL(%u): NACK in window, but TxFrameLen empty!\n",ClientIdx));
        }
        else
            KITL_DEBUGMSG(ZONE_WARNING,("!KITL(%u): Received NACK outside of TX window: Seq: %u, Window: %u,%u\n",
                                        ClientIdx,pMsg->SeqNum,pClient->AckExpected,pClient->TxSeqNum));
        goto ProcessKITLMsg_exit;
    }
   
    // Data frame.  Place in appropriate slot in Rx buffer pool. Note that we defer acking
    // received frames until they are read from the buffer, in KITLRecv.
    RxBufOffset = pMsg->SeqNum % pClient->WindowSize;

    if (! SEQ_BETWEEN(pClient->RxSeqNum, pMsg->SeqNum, pClient->RxWinEnd)) {
        UCHAR uLastACK = (UCHAR) (pClient->RxWinEnd - pClient->WindowSize - 1);

        KITL_DEBUGMSG (ZONE_WARNING, ("KITL(%u): Received msg outside window: Seq:%u, Win:%u,%u\n",
                              ClientIdx,pMsg->SeqNum,pClient->RxSeqNum,pClient->RxWinEnd));

        // Special case to handle lost ACKs - if an ack is dropped, our Rx window will have
        // advanced beyond the seq # of the retransmitted frame.  Since ACKs ack all messages
        // up to the ack #, we only need to check the last frame.
        if (pMsg->SeqNum == uLastACK) {
            KITL_DEBUGMSG(ZONE_WARNING,("KITL(%u): Lost ACK (seq: %u, win: %u,%u)\n",ClientIdx,
                                        pMsg->SeqNum,uLastACK,pClient->RxWinEnd));
            SendAckNack (TRUE, pClient, uLastACK);
        }
    } else if (pClient->RxFrameLen[RxBufOffset] != 0) {
        // If all our buffers are full, toss frame (will be acked when data is read in KITLRecv)
        KITL_DEBUGMSG(ZONE_WARNING,("KITL(%u): Received duplicate (Seq:%u), slot %u already full. Win: %u,%u\n",
                                    ClientIdx,pMsg->SeqNum,RxBufOffset,pClient->RxSeqNum,pClient->RxWinEnd));
    } else {
        DWORD OldProcPerms;

        // If we're in non-preemptible mode, can't set the receive event, so just toss message
        // and wait for retry.
        if (!fUseSysCalls && (pClient->State & KITL_USE_SYSCALLS)) {
            KITL_DEBUGMSG(ZONE_WARNING,("KITL(%u): Tossing frame %u (Can't signal Rx event)\n",
                                        ClientIdx,pMsg->SeqNum));
            return FALSE;
        }

        KITL_DEBUGMSG(ZONE_RECV,("KITL(%u): Received frame Seq: %u, len: %u, putting in slot %u\n",
                                 ClientIdx, pMsg->SeqNum, wMsgLen, RxBufOffset));
        // If frames were dropped, send NACK (only allow one outstanding NACK)
        if (pMsg->SeqNum != pClient->RxSeqNum) {
            KITL_DEBUGMSG(ZONE_WARNING,("!KITL(%u): Dropped frame (seq: %u, win: %u,%u)\n",
                                        ClientIdx,pMsg->SeqNum,pClient->RxSeqNum, pClient->RxWinEnd));

            if (!(pClient->State & KITL_NACK_SENT)) {
                SendAckNack(FALSE, pClient, pClient->RxSeqNum);
                pClient->State |= KITL_NACK_SENT;          
            }
        }
        else
            pClient->State &= ~KITL_NACK_SENT;
       
        // Copy data to receive buffer, unblock anyone waiting, and close receive window
        wDataLen = wMsgLen - (WORD)KITL_DATA_OFFSET;
        if (wDataLen == 0)
            KITL_DEBUGMSG(ZONE_WARNING,("!KITL: Received data message with 0 length!\n"));
        if (pClient->ProcPerms) {
            // acquire permission of pClient and add it to current thread
            ACCESSKEY aKey = GETCURKEY() | pClient->ProcPerms;
            SWITCHKEY (OldProcPerms, aKey);
        }
        memcpy(pClient->pRxBufferPool + RxBufOffset*KITL_MTU,KITLDATA(pMsg), wDataLen);
        if (pClient->ProcPerms) {
            SETCURKEY (OldProcPerms);           
        }
        pClient->RxFrameLen[RxBufOffset] = wDataLen;

        if (pClient->State & KITL_USE_SYSCALLS)
            // If we get here, we know that fUseSysCalls is TRUE
            SetClientEvent(pClient,pClient->evRecv);
       
        // Close receive window
        while (pClient->RxFrameLen[pClient->RxSeqNum % pClient->WindowSize] &&
               (SEQ_DELTA(pClient->RxSeqNum, pClient->RxWinEnd) >= 1)) {
            KITL_DEBUGMSG(ZONE_RECV,("Rx win: %u,%u, usesyscalls: %u\n",pClient->RxSeqNum, pClient->RxWinEnd, fUseSysCalls));
            SEQ_INC(pClient->RxSeqNum);
        }
    }
   
ProcessKITLMsg_exit:

    if (fUseSysCalls && (pClient->State & KITL_USE_SYSCALLS))
        LeaveCriticalSection(&pClient->ClientCS);
   
    return fRet;
}
ProcessRecvFramed是一个近200行的函数Q样子很吓h。它是数据的解析和处理模块的主体。我们从上到下看看都q了些什么。先调用KitlEtherDecodeUDP来自主机的数据帧解码ؓKITL_HDRl构Q然后效验魔法数KITL_IDQ确认该帧的信息的有效性以及数据长度是否有效,如果ZONE_FRAMEDUMP标签是打开的则需要则解析Frame的内容ƈ记录下来(输出到调试界面,初始化流Eƈ不包含该信息)Q然后判定该数据帧描q的信息是否属于理命o(q接桌面Q新建client{等),如果是则调用ProcessAdminMsgq行处理?
static BOOL ProcessAdminMsg(KITL_HDR *pHdr, WORD wMsgLen, BOOL fUseSysCalls, PFN_TRANSMIT pfnTransmit, LPVOID pData)
{
    KITL_CLIENT *pClient = NULL;   
   
    switch (pHdr->Cmd)
    {
        case KITL_CMD_SVC_CONFIG:
        {
            KITL_SVC_CONFIG_DATA *pCfg = (KITL_SVC_CONFIG_DATA *) KITLDATA (pHdr);
            int i, iStart;
           
            if (wMsgLen != (KITL_DATA_OFFSET + sizeof(KITL_SVC_CONFIG_DATA))) {
                KITL_DEBUGMSG(ZONE_WARNING,("!ProcessAdminMsg: Invalid legnth for CONFIG msg: %u\n",wMsgLen));
                return FALSE;
            }

            // Find client struct
            if ((i = ChkDfltSvc (pCfg->ServiceName)) < 0)
                i = HASH(pCfg->ServiceName[0]);

            iStart = i;

            while (KITLClients[i]) {
                // For multi instanced services, skip clients that are already registered
                if (!strcmp(KITLClients[i]->ServiceName,pCfg->ServiceName) &&
                    (!(KITLClients[i]->State & KITL_CLIENT_REGISTERED) || !(KITLClients[i]->CfgFlags & KITL_CFGFL_MULTIINST))) {
                    pClient = KITLClients[i];
                    break;
                }
                if (i < NUM_DFLT_KITL_SERVICES)
                    // no dups for default services
                    break;

                if (MAX_KITL_CLIENTS == ++ i)
                    i = NUM_DFLT_KITL_SERVICES;

                if (iStart == i)
                    break;  // couldn't find a client
            }

            if (!pClient || !(pClient->State & (KITL_CLIENT_REGISTERING|KITL_CLIENT_REGISTERED))) {
                KITL_DEBUGMSG(ZONE_WARNING,("!Received config for unrecognized service %s\n",
                                            pCfg->ServiceName));
                return TRUE;
            }

            if (fUseSysCalls)
                EnterCriticalSection(&pClient->ClientCS);

            // Send config to peer, unless this was a response to our cmd
            if (!(pHdr->Flags & KITL_FL_ADMIN_RESP)) {
                // ack this config message
                SendConfig(pClient,TRUE);

                // Stop any pending transfers, reset sequence #s, etc

                // WARNING - can cause lost transmit data if the other side doesn't get
                // our config, and retries the config command.
                if (pClient->State & KITL_SYNCED) {
                    ResetClientState(pClient);
                }
            }

            //
            // we got the response from desktop, connecting the client
            //
            KITL_DEBUGMSG(ZONE_INIT, ("ProcessAdminMsg: Receive Config message for service %s\n", pClient->ServiceName));
            pClient->State &= ~(KITL_WAIT_CFG|KITL_CLIENT_REGISTERING);
            pClient->State |= KITL_CLIENT_REGISTERED;
            // Set our event in case anyone is waiting for config info
            if (fUseSysCalls)
                SetClientEvent(pClient,pClient->evCfg);

           
            if (fUseSysCalls)           
                LeaveCriticalSection(&pClient->ClientCS);
            break;
        }
        case KITL_CMD_RESET:
            {
                KITL_RESET_DATA *pResetData =  (KITL_RESET_DATA *) KITLDATA (pHdr);

                KITLOutputDebugString("KITL: Got RESET command\n");

                // Set for clean boot if requested
                if (pResetData->Flags & KITL_RESET_CLEAN)
                    SC_SetCleanRebootFlag();
               
                // This function never returns
                KernelIoctl(IOCTL_HAL_REBOOT, NULL,0,NULL,0,NULL);
                KITLOutputDebugString("KITL: IOCTL_HAL_REBOOT not supported on this platform\n");
                break;
            }

        case KITL_CMD_DEBUGBREAK:
            if (fUseSysCalls && IsDesktopDbgrExist ())
                DebugBreak ();
            break;

        case KITL_CMD_TRAN_CONFIG:
            {
                int i;
               
                PKITL_HOST_TRANSCFG pCfg = (PKITL_HOST_TRANSCFG) KITLDATA(pHdr);
                wMsgLen -= KITL_DATA_OFFSET;
                if (pCfg->dwLen != wMsgLen) {
                    KITLOutputDebugString ("!Host config message size mismatch %d, %d\r\n", pCfg->dwLen, wMsgLen);
                    return FALSE;
                }
                wMsgLen -= sizeof (KITL_HOST_TRANSCFG);
                if (!Kitl.pfnSetHostCfg ((LPBYTE) (pCfg+1), wMsgLen))
                    return FALSE;
                Kitl.dwBootFlags = pCfg->dwFlags;

                if (pCfg->dwKeySig == HOST_TRANSCFG_KEYSIG) {
                    for (i = 0; i < HOST_TRANSCFG_NUM_REGKEYS; i++) {
                        g_dwKeys[i] = pCfg->dwKeys[i];
                        KITL_DEBUGMSG (ZONE_INIT, (" KeyIndex %d = %d \n", i, g_dwKeys[i]));
                    }
                }   
                KITLGlobalState |= KITL_ST_DESKTOP_CONNECTED;
            }
            break;

        // in case we're polling (pfnTransmit && pData only set to non-null if we're polling)
        // we'll use desktop as our timer (desktop sends a retransmit packet to us every 2 seconds).
        case KITL_CMD_RETRASMIT:
            if (pfnTransmit && pData) {
                // KITLOutputDebugString ("Retrasmitting packets....\n");
                pfnTransmit (pData, fUseSysCalls);
            }
            break;
        default:
            KITL_DEBUGMSG(ZONE_WARNING,("!ProcessAdminMsg: Unhandled command 0x%X\n",pHdr->Cmd));
            return FALSE;
    }
    return TRUE;
}
我们直接看KITL_CMD_TRAN_CONFIG分支Q目前我们的主要工作仍然是配|连接。首先得到PKITL_HOST_TRANSCFGl构指针Qƈ送SetHostCfg讄L信息之后Q读入从L送出?个key值后讄以及kitl启动选项和KITL_ST_DESKTOP_CONNECTED标示位。绕了这么大一圈也干了个初始化连接的工作Q现在我们l回到startKitl。首先先是设|三个函数指针供后面E序调用Qƈ讄标示位KITL_ST_ADAPTER_INITIALIZED;然后通过SetKernelCommDev从定位KERNEL_SVC_DBGMSG,KERNEL_SVC_PPSHQKERNEL_SVC_KDBG的transportQ注意:q个函数q不是kitl的函敎ͼ而是windowsCE kernel的系l函数在WINCE420\PRIVATE\WINCEOS\COREOS\NK\KERNELkwin32.c?作用是从定位pȝ调试信息的发布通道Q有兴趣可以自己看看。之后StartKitl的过E就l束了,q个时候你肯定想问那kitl的中断初始化函数是什么时候才q行呢?没有中断的支持kitl是如何通讯和工作的呢,事实上KITLInitializeInterruptp责这部分的工作,但是׃pȝ内核q没有完成初始化的动作,所以这个时候v动kitl的中断是会媄响kernel的工作。因此在后面由SystemStartupFunc()调用KITLInitializeInterrupt来完成初始化的动作?
BOOL
KITLInitializeInterrupt()
{

    int i;
    if (!(KITLGlobalState & KITL_ST_ADAPTER_INITIALIZED))
        return FALSE;
   
    // Check if we are coming up for the first time, or resuming interrupts (e.g. when coming
    // back from OEMPowerOff)
    if (KITLGlobalState & KITL_ST_MULTITHREADED) {
        // Just enable interrupt and return
        EnableInts();
        return TRUE;
    }
   
    KITLOutputDebugString("KITL: Leaving polling mode...\n");

    InitializeCriticalSection(&KITLODScs);
    InitializeCriticalSection(&KITLKCallcs);

    KITLGlobalState |= KITL_ST_MULTITHREADED;
   
    KITL_DEBUGMSG(ZONE_INIT,("KITL Checking client registrations\n"));
    // Some clients may have registered already, finish initialization now that
    // the system is up. KDBG continues to run in polling mode.
    for (i=0; i< MAX_KITL_CLIENTS; i++) {
        if (KITLClients[i] && (i != KITL_SVC_KDBG)
            && (KITLClients[i]->State & (KITL_CLIENT_REGISTERED|KITL_CLIENT_REGISTERING))) {
            if (!RegisterClientPart2((UCHAR)i))
                return FALSE;
        }
    }

    // Start interrupt thread. If we have clients registered, also turn on receive interrupts
    // from the ethernet controller, otherwise leave them disabled.
    if ((UCHAR) KITL_SYSINTR_NOINTR != Kitl.Interrupt) {
        KITL_DEBUGMSG(ZONE_INIT,("KITL Creating IST\n"));
        if ((hIntrThread = CreateKernelThread((LPTHREAD_START_ROUTINE)KITLInterruptThread,
                                              NULL, (WORD)g_dwKITLThreadPriority, 0)) == NULL) {
            KITLOutputDebugString("Error creating interrupt thread\n");
            return FALSE;
        }
    }

    return TRUE;
}
׃会有IST为kitl专门服务Q所以也需要界区来完成线E的操作Q这儿创ZKITLODScs\KITLKCallcs两个临界区。之后标?KITL_ST_MULTITHREADED。检查注册了的服务,完成后就创徏IST.

kitl的初始化Q启动的大致q程是如此Qstart-->注册服务-〉初始化transport->创徏IST

最后我们来看看IST里面我们都干些什?
static DWORD KITLInterruptThread (DWORD Dummy)
{
    HANDLE hIntEvent;
    DWORD dwRet;

    KITL_DEBUGMSG(ZONE_INIT,("KITL Interrupt thread started (hTh: 0x%X, pTh: 0x%X), using SYSINTR %u\n",
                             hCurThread,pCurThread, Kitl.Interrupt));

    pCurThread->bDbgCnt = 1;   // no entry messages
   
    if ((hIntEvent = CreateEvent(0,FALSE,FALSE,EDBG_INTERRUPT_EVENT)) == NULL) {
        KITLOutputDebugString("KITL CreateEvent failed!\n");
        return 0;
    }
    if (!SC_InterruptInitialize(Kitl.Interrupt, hIntEvent, NULL,0)) {
        CloseHandle(hIntEvent);
        KITLOutputDebugString("KITL InterruptInitialize failed\n");
        return 0;
    }

    // always enable interrupt as long as OEM told us so
    EnableInts();
   
    KITLGlobalState |= KITL_ST_IST_STARTED;
   
    while ((dwRet = SC_WaitForMultiple (1,&hIntEvent,0,INFINITE)) == WAIT_OBJECT_0) {

        KITL_DEBUGLED(LED_IST_ENTRY,0);
        KITL_DEBUGMSG(ZONE_INTR,("KITL Interrupt event\n"));

        // no need to check pending, just call HandleRecvInterrupts because it'll
        // just return if there is no interrupt pending
        HandleRecvInterrupt(ISTRecvBuf,TRUE, NULL, NULL);

        SC_InterruptDone(Kitl.Interrupt);
       
        KITL_DEBUGMSG(ZONE_INTR,("Processed Interrupt event\n"));
    }
    KITLOutputDebugString("!KITL Interrupt thread got error in WaitForMultipleObjects: dwRet:%u, GLE:%u\n",
                          dwRet,GetLastError());
    return 0;
}
首先是创IST所属的事gQƈ该事g与所属的中断联系hQ再后自然是启动中断了。设定KITL_ST_IST_STARTED标记后的代码是IST的实际内容,当中断发生,交付HandleRecvInterrupt处理Q返回中断。和多数IST一栯调用永远不会q回Q除非结束该U程Q所以后面的调试信息输出的是错误?

void HandleRecvInterrupt(UCHAR *pRecvBuf, BOOL fUseSysCalls, PFN_TRANSMIT pfnTransmit, LPVOID pData)
{
    WORD wLen = KITL_MTU;
    BOOL fFrameRecvd;

    // Receive data into buffer
    do {
        if (!fUseSysCalls)
            fFrameRecvd = Kitl.pfnRecv (pRecvBuf, &wLen);
        else if (IsDesktopDbgrExist ())
            fFrameRecvd = KCall((PKFN) Kitl.pfnRecv, pRecvBuf, &wLen);
        else {
            EnterCriticalSection (&KITLKCallcs);
            fFrameRecvd = Kitl.pfnRecv (pRecvBuf, &wLen);
            LeaveCriticalSection (&KITLKCallcs);
        }
        if (fFrameRecvd) {
            ProcessRecvFrame (pRecvBuf,wLen,fUseSysCalls, pfnTransmit, pData);
            wLen = KITL_MTU;
        }
    } while (fFrameRecvd);
}
HandleRecvInterrupt是中断处理程序的实体Q将transport送来的数据填入缓冲区待处理。上面所提到的中断在OEM代码中指定,在SMDK2440bsp中该中断对应以太|卡中断?



]]>
解读WINCE 5.0 KITL代码程 http://www.shnenglu.com/milkyway/articles/17671.html相思酸中有?/dc:creator>相思酸中有?/author>Tue, 16 Jan 2007 02:00:00 GMThttp://www.shnenglu.com/milkyway/articles/17671.htmlhttp://www.shnenglu.com/milkyway/comments/17671.htmlhttp://www.shnenglu.com/milkyway/articles/17671.html#Feedback1http://www.shnenglu.com/milkyway/comments/commentRss/17671.htmlhttp://www.shnenglu.com/milkyway/services/trackbacks/17671.html

作者:Walzer
日期Q?005.3.19

摘要QKITL是PLATFORM BUILDER中的一个亮点,提供了和本地调试cM的断炏V变量跟t、内存查看等手段Q如果没有KITLQ嵌入式调试应该只能用串口打印消息来看了Q工作效率大大下降。本文以实现最单的SERIAL KITL为目的,其实现代码q行跟踪调试Q这些代码跨了WINCE的PLATFORM、PUBLIC、PRIVATE三大主要目录Q有些烦琐,不过只要能调通,一切工作和弯\都是值得的。我把调试经验和个h理解写下来,希望能帮助别人少走弯路。如果文章中有理解失当的地方Q请不吝赐教?br />
正文Q?br />
一.void OEMInit()  [platform\project\src\kernel\oal\init.c]
    首先从OEMInit()函数看v。。在依次初始化Branch-Target Buffer、KERNEL函数、初始化中断、TIMER之后Q就轮到KITL了。调用了q个函数OALKitlStart()。此时有个编译的分支Q如果是RELEASE版本Q那么在kernel\kern\stubs.c里面的OALKitlStart()函数是个STUBQ只是return TRUEQ?如果是DEBUG版本Q那p到kernel\oal\kitl.c里面的OALKitlStart().

?BOOL OALKitlStart()  [platform\myproject\src\kernel\oal]
    在OALKitlStart()里面Q首先试图从0xA00FF00处读取bootloader里面留下的kitl参量Q如果读不到东西则用该函数里的默认配置。由于原来用了ethernet同时作ؓdownload和kitl途径Q所以在InitSpecifiedEthDevice函数里给pKitlArgsl构体赋g。现在想把两者划分清楚,首先把dbootloader里面的kitl参量一句干掉,使用我们在下面的默认配置。主要就是填充三个参?/p>

1.首先是这个结构体
OAL_KITL_ARGS pKITLArgs
{
 UINT32 flags;  //讑֥ENABLED标志Q按需要设POLL标志Q但注意一定不要设PASSIVE标志
 DEVICE_LOCATION  devLoc;
 {
  DWORD  IfcType;  //不论etherq是serialQ都是internal type =0;
  DWORD  BusNumber; // =0
  DWORD  LogicalLoc; //物理地址
  PVOID     PhysicalLoc; //留做后面=OALPAtoVA(LogicalLoc, FALSE). 真见? 感觉应该和上面的LogicalLoc作用调过来看着比较吧?
  DWORD  Pin;  //Ethernet才用的东?br /> }
 union
 {
  struct
  {
   UINT32  baudRate; //不用解释?br />   UINT32  dataBits;
   UINT32  stopBits;
   UINT32  parity;
  }
  struct
  {
   UINT16  mac[3]; //q个也不用解释了
   UINT32  ipAddress;
   UINT32  ipMask;
   UINT32  ipRoute
  }
 }
}
2. pszDeviceID.  感觉q名字就是v了好? 赋成Walzer应该比较?不过q是保留原来赋的AMOISOFT好了, 免得被打.
3. 全局变量OAL_KITL_DEVICE g_kitlDevices. q个东东在kitl.c开头包含的kitl_cfg.h中被赋?  最主要是修改g_kitlDevices.pDriver.  q个pDrvier指向一个函数指针列表的l构体,该列表定义了用做kitl模块的初始化、读写、中断、流控制{函数?g_kitlDevices本n是个二维数组, 可以定义许多讑֤用做kitl时提供的参数讄, 后面会用一个for来@环判断pKITLArgs的参数和g_kilDevices里面哪个一l数l成员相匚w.

q三个参量填充好以后Q就可以q到OALKitlInit(pszDeviceID, pKITLArgs, g_kitlDevices)里面?

?BOOL OALKitlInit( deviceId, pArgs, pDevice)    [platform\common\src\common\kitl\kitl.c]
    q个函数先把输入的参量全部用OALMSG打印出来Q这个不?br />    重要的是引入了g_kitlState全局变量Q开头一?br />    g_kitlState.pDevice = OALKitlFindDevice(&pArgs->devLoc, pDevice) q个是上面所说的从g_kitlDevices里可用设备列表里循环判断Q找到选用的设备的匚w函数指针?br />    接着把输入参量devicdId和前面填充好的OAL_KITL_ARGSl构COPY到g_kitlState里面
    然后可以调用KItlInit(TRUE)了,如果前面在FLAG里面设了PASSSIVE标志Q现在就是KitlInit(FALSE)了,嘿嘿爽到了吧?/p>

?BOOL KitlInit(BOOL fStartKitl)    [private\winceos\coreos\nk\kitl\ethdbg.c]
    太猥琐了Q我要用串口Q它居然叫ethdbg.cQ不l面子。不q是private里面的东东,可远观而不可亵玩焉~~
    q个函数q了三g事:
1. 装蝲了三个全局的函数指?br />2. 用NewClient注册了三个KITL客户端:
    KITL_SVCNAME_DBGMSG   //debug message, Debug信息发布通道
    KITL_SVCNAME_PPSH  //PPshell, 文本控制台界?
    KITL_SVCNAME_KDBG //kernel debug, 内核调试界面

3.由fStartKitl来决定是否启动StartKitl()函数. (q里Z提一下,按照匈牙利命名法, BOOL变量前面加个b, 但MS的做法我觉得很合? BOOL变量是个FLAG? 前面加个f, 把小b留着lBYTEcd?)

?static BOOL StartKitl(BOOL fInit)    [private\winceos\coreos\nk\kitl\ethdbg.c]
    q又是prviate里面的东东。最痛苦的地方开始了。这函数及其子函数将W一ơ调用OEM自己写的KITL模块初始化、读写程序。是骡子是马Q拉出来溜溜q道啦~
    按顺序看下来Q首先判断输入参量是否要启动KITLQƈ且如果KITLGlobalState里面被打上KITL_ST_DESKTOP_CONNECTED标记的话Q那下面的步骤就全免了。当然我们是W一ơ运行到q里Q若q么p出的话,俺就马加爵了?/p>

    W一?
    q的W一件正事就是调用OEMKitlInit(&Kitl). q个后面详述. l箋把这个函数看?
    OEMKitlInit初始化KITL的硬件抽象层后ƈ把相x针数据填充给全局变量KITLTRANSPORT Kitl (有没有搞错,Z么不叫g_kitl), q些工作做完p回了
     StartKitl收货后把Kitll构整个查一?保证没错? 马上买单, 把全局变量KITLGlobalState打上个KITL_ST_KITLSTARTED标记. q才KITL启动的第一步OK?

    W二?
    接下来就是KITLConnectToDesktop(), q这个函数后是W一ơ用了前面KITL传输介质g抽象层里的读写函C, q时候就需要调试了. q个ConnectToDesktop大致是先Send了一个kITL.....的frameq去,然后polling{待PC端的response, 那边再发个kITL.....的frameq来, 搞得跟地下党打暗号似? 其实也没什么玄乎的Q就是普通的数据包前面加个KTIL专用的HEADER而已. q个CONNECT成功?KITLGlobalState里面加个KITL_ST_DESKTOP_CONNECTED标记?

    W三?
    set up kernel function pointers, 也没什?׃个函数指? 赋完后就KITL_ST_ADAPTER_INITIALIZED? 其实q个KITLGolbalSate的d?个标?分别?br />KITL_STARTED,  (OK)
DESKTOP_CONNECTED,   (OK)
TIMER_INIT, (?)
INT_ENABLED,  (POLLING)
IST_STARTED,  (POLLING)
MULTITHREADED,   (?)
ADAPTER_INITIALIZED. (OK)
后面括号里打上OK是到q里已经完成的, 打问L我还不太清楚什么作? INT和IST两项,我们用的POLLING所以肯定是不需要了.

    W四?
    调用SetKernelCommDev讄kernel通过何种介质传送DBGMSG, PPSH和KDBG.
    OHYEAH, 我的SERIAL KITL夭折在q里. q到SerKernelCommDev(service, CommDevice)函数里看, 它只认CommDevice=KERNEL_COMM_ETHER的情况,而屏蔽了与ETHERq列的SERIAL和PARALLER,直接return FALSE, 下面的事情都不用q了. 而在MS提供的WinCE Documantation里面Q这个SetKernelCommDev函数的说明上写着"This function is obsolete and should not be used". 若想改嘛,q个是在private里面的还动它不得. NND, 感觉被MS raped?
     如果使用ETHER在这里成功的? 下面q有两个函数NKForceCleanBoot()和KITLInitializeInterrupt()走过? qKITL初始化就全部l束? 我估计KITLGolbalSate里面的INIT_ENABLED和IST_STARTED是在这个函数过E中被标C?
    
   
?BOOL OEMKitlInit(PKITLTRANSPORT pKitl)    [platform\common\src\common\kitl\kitl.c]
    前面提到StartKItlh后,首要的就是调用OEMKitlInit. q个函数在WinCE4.2?.0里差别很? 4.2里的做法是  ?if (!InitEther (pKitl) && !InitParallelSerial (pKitl)), 把ETHER, SERIAL, PARALLEL都初始化了一?运气看哪个用得上,?.0里是q来后就一个很明显的分支剧?由g_kitlState.pDevice->type来决定是调用OALKitlEthInitq是OALKitlSerialInit. 典型的种族歧? 居然没有OALKitlParallelinit. q好我们用的是SERIAL.
    q里有个选择~译的地?是#ifdef KITL_ETHER?ifdef KITL_SERIAL, 具体定义的地Ҏ该目录下的sources文g里面一?CDEFINES=$(CDEFINES) -DKITL_SERIAL -DKITL_ETHER, 猥琐啊找了半? 其实我觉得既然有ifl构来选了Q那么选择~译也是可有可无的了.
    好,下面p到OALKItlSerialInit()里面.

?BOOL OALKitlSerialInit(LPSTR deviceId, OAL_KITL_DEVICE *pDevice, OAL_KITL_ARGS *pArgs, KITLTRANSPORT *pKitl)
    [platform\common\src\common\kitl\kitlserial.c]
    我自己往q个kitlserial.c文g里写了六个函?
    BOOL KitlSerialInit(KITL_SERIAL_INTFO *pSerInfo)
    UINT16 KitlSerialWriteData(UINT8 *pch, UINT16 length)
    UINT16 KitlSerialReadData(UINT8 *pch, UINT16 length)
    void KitlSerialFlowControl  //stub, 我所用的FFUART只有TXD和RXD两根U? RTS{都没有, 所以FlowControl自然也应该是STUB?br />    void KitlSerialEnableInt(void)   //stub, use polling
    void KitlSerialDisableInt(void)  //stub, use polling
    否则前面的g_kitlDevices里面没有相应的硬件抽象层来填?
    上面的SerialRecv, Encode, Decode{就意思都很明显了,不用多说. OK现在已经走到最底层? 文章也可以结束了.

八、记录一下调试经?br />    虽然q是我第三次调串口了Q由于没ȝ前面的经验,q是耗了两天才到private里面夭折的地斏V实际上应该一天就能走C。问题出?br />1. W一天调试器Ҏ用不上手。调试器软g、PB不断ȝQ经帔R启Y件甚至重启电脑,W一天有3/4以上的时间耗在q些问题? 不断重启?br />2. 在UART初始化函数的最后,居然忘记了在interrupt controller register里面enable uart unit, q么乌龙的事?br />3. KitlSerialFlowControl的问? 写的时候照搬了X86下的函数, 没想明白到底要Control什? 调试时死在这里后,  一开始把指向q个函数的指针设|成NULL, 但这样PRIVATE里面有些要IF判断的函数就q不M. 后来换成STUBOK?
4. receive函数里面, 在收每个BYTE之前先去判断了Line Status Register里面的Data Ready bit, 如果该ؓ? 则返回失? 但这里是有问题的Q具体也没太x? 反正在调试debug serial的时候就把这个判断从MS提供的源码里头删MQ现在做KITL serial时又手痒加进? 果然q是不行. q可能是MS或INTEL的一处BUG, 但按照INTEL CPU MANUL UPDATE里面l的LE? 一开始只判断LSR里面的ERROR, 没有判断DR位就开始读W一个BYTE? 读过后再判断如果DR位ؓ1,则l读下一BYTE.
5. 在receive函数里加通过debugger加break point, l果receive buffer register里面的数据被debugger扫描M后,变零了QCPU上却什么都收不? q事情耗了大半个下午,最后还是Jeffery发现的这个问?

参考文章:
KITL解析 by Nasiry  (http://nasiry.cnblogs.com/archive/2004/09/22/45473.html)



]]>
"Out of Memory" and Required components for ActiveSync http://www.shnenglu.com/milkyway/articles/17670.html相思酸中有?/dc:creator>相思酸中有?/author>Tue, 16 Jan 2007 01:51:00 GMThttp://www.shnenglu.com/milkyway/articles/17670.htmlhttp://www.shnenglu.com/milkyway/comments/17670.htmlhttp://www.shnenglu.com/milkyway/articles/17670.html#Feedback2http://www.shnenglu.com/milkyway/comments/commentRss/17670.htmlhttp://www.shnenglu.com/milkyway/services/trackbacks/17670.html 来自 http://www.cnblogs.com/walzer/archive/2006/02/05/325574.html
Author: Walzer
Date:    2005.5.20

摘要: WINCE 5.0中关于ActiveSync的Dependence没有做好Q这肯定是MS的一处BUG。我们必L动地dq些相关的组Ӟ?个)Q否则就会在启动ActiveSyncq接时出现Out of Memory的让人匪h思的错误。文章的最后给Z如何在注册表中注册一个USBq接作ؓActiveSync默认q接的做法?br />
    At first I was so puzzled by this problem for several days. I connected my target to PC by usb and wana enable ActiveSync, the usb serial function seems work well and  repllog.exe is autoloaded. But on the target, there jumps out a  warning window with the title "Out of Memory", and the descriptions are "Cannot connect to PC. No program memory available. Stop some programs, and try again. If the problem persist, reset your device according to the owner's manual".
    This platform have 32MB flash  and 32MB SDRAM. I burn nk.nb0 (20M) into the flash and use XIP, so the memory must be enough for this application. But what's the problem?
    The debug messages are shown below.
 
0x83f21000: [NOTIFY] HandleSystemEvent 9 none
0x83f21000: [NOTIFY] HandleSystemEvent found repllog.exe for event 9
0x83f21000: [NOTIFY] HandleSystemEvent schedules immediate notify for repllog.exe AppRunAtRs232Detect
0x83f21000: [NOTIFY] SetUserNotification (or replacing 00000000)
0x83f21000: [NOTIFY] SetUserNotification::Setting event semaphore
0x83f21000: [NOTIFY] ProcessDatabase::started at local time 01/01/2003 12:00:42
0x83f24434: NOTIFICATION::NewPacket attempt to exec 0000073e:repllog.exe AppRunAtRs232Detect
0x83d14000: >>> Loading module coredll.dll at address 0x03F40000-0x03FF4000 (RW data at 0x01FFE000-0x01FFF145)
0x83d14000: >>> Loading module ws2.dll at address 0x03BB0000-0x03BC4000 (RW data at 0x01FCD000-0x01FCDB24)
0x83d14000: >>> Loading module winsock.dll at address 0x03BD0000-0x03BD6000 (RW data at 0x01FCF000-0x01FCF08C)
Loaded symbols for 'D:\SOURCE_CODE\WINCE500\PBWORKSPACES\WINDOWTV\RELDIR\WINDOWTV_ARMV4I_DEBUG\WINSOCK.DLL'
0x83d14000: >>> Loading module repllog.exe at address 0x0E010000-0x0E02E000
Loaded symbols for 'D:\SOURCE_CODE\WINCE500\PBWORKSPACES\WINDOWTV\RELDIR\WINDOWTV_ARMV4I_DEBUG\REPLLOG.EXE'
0x83d14000: RLOG: [0x43F24D0E] Started with cmdline: AppRunAtRs232Detect
0x83d14000: AddToProcessInputLocaleTable: Added process to ProcessInputLocale table, hProcess = 0x43D3A242
0x83d14000: RLOG: [0x43F24D0E] Using '`USB' connection
0x83d14000: RLOG: [0x43F24D0E] Welcome to repllog. Port in use: Dccman: 5679; RRA: 5678
0x83d14000: RLOG: [0x43F24D0E] WM_WINDOWREADY
0x83d14000: RLOG: [0x43F24D0E] About to run rapisrv.exe
0x83f24434: [NOTIFY] DeleteUserNotification 0000073e
0x83f24434: [NOTIFY] DeleteUserNotification: 0000073e deleted
0x83e84bb4: >>> Loading module coredll.dll at address 0x03F40000-0x03FF4000 (RW data at 0x01FFE000-0x01FFF145)
0x83e84bb4: >>> Loading module ws2.dll at address 0x03BB0000-0x03BC4000 (RW data at 0x01FCD000-0x01FCDB24)
0x83e84bb4: >>> Loading module winsock.dll at address 0x03BD0000-0x03BD6000 (RW data at 0x01FCF000-0x01FCF08C)
0x83e84bb4: >>> Loading module rapisrv.exe at address 0x10010000-0x10031000
Loaded symbols for 'D:\SOURCE_CODE\WINCE500\PBWORKSPACES\WINDOWTV\RELDIR\WINDOWTV_ARMV4I_DEBUG\RAPISRV.EXE'
0x83e84bb4: AddToProcessInputLocaleTable: Added process to ProcessInputLocale table, hProcess = 0xE3D4A1BE
RpcSrv: Rapi Server running on DeviceType: 2
0x83d14000: RLOG: [0x43F24D0E] Using '`USB' connection
0x83d14000: RLOG: [0x43F24D0E] About to run rnaapp.exe -n -m -e"`USB"
RpcSrv: Winsock Started version 1.1
0x83d01000: >>> Loading module wspm.dll at address 0x03B90000-0x03B97000 (RW data at 0x01FC9000-0x01FC9154)
Loaded symbols for 'D:\SOURCE_CODE\WINCE500\PBWORKSPACES\WINDOWTV\RELDIR\WINDOWTV_ARMV4I_DEBUG\WSPM.DLL'
RpcSrv: SocketBufSize=16384 bytes
0x83d01000: <RPC:RESLIST> 
0x83d01000: CResList::CResList()
0x83d01928: CreateNewProc failure on rnaapp.exe!
0x83d14000: RLOG: [0x43F24D0E] CreateProcess rnaapp.exe failed. GetLastError: 2

0x83d14000: Grow Gdi handle table from 448 to 512
0x83d14000: DlgMgr: FindDlgItem id 1 returning NULL.
 
BTW, the source code of rapllog.exe is at private\datasync\apps\conn31\rep\repllog\ . But Microsoft haven't publish these codes yet.
 
----------------------------------------------------------------------------------------------------------------
 
In fact, "out of memory" is a fake message. I asked it on the newsgroup and someone tell me they have seen a similar message when missing a required OS component. I am so sorry to say that, the dependency checks on ActiveSync in WinCE5.0 are not very good, so we have to add them into our OSDesign manually.
 
The required and relative components are:
  (1) Core OS->Applications - End User->ActiveSync->File Sync
  (2) Core OS->Communication Services and Networking->Networking - Wide Area Network (WAN)->Dial Up Networking (RAS/PPP) 
  (3) Core OS->Communication Services and Networking->Networking - Wide Area Network (WAN)->Telephony API (TAPI 2.0)->Unimodem Support
  (4) Core OS->Shell and User Interface->User Interface->Network User Interface
 
----------------------------------------------------------------------------------------------------------------
 
After the system completely booted, we need to creat a new connection in control pannel -> Dial Up Networking. Select USB direct connection then OK, for example use the default name "My Connection".  In the other hand, set PC connection to the newly created "My Connection". Now connect the USB cable, and the ActiveSync on desktop will sound a dulcet tune~~~
 
But these two steps we can wirte them into registry before. To take an easy way, I compare the registry on traget device before these settings and after it, and these are the changes:
 
[HKEY_CURRENT_USER\Comm\RasBook\USB Connection]
"Entry"=hex:\
      08,02,40,00,00,00,00,00,00,00,00,00,00,00,00,00,f4,db,04,12,d0,77,01,7c,01,\
      00,00,00,01,00,00,00,01,00,00,00,1c,e3,04,12,0a,00,00,00,74,dc,04,12,01,00,\
      00,00,18,dc,04,12,68,53,03,00,f0,4b,01,7c,18,dc,04,12,d8,55,03,00,20,dc,04,\
      12,ca,1b,05,12,00,00,00,00,00,00,00,00,00,00,00,00,f0,4b,01,7c,00,00,00,00,\
      0a,00,00,00,00,00,00,00,ec,3b,37,03,54,dc,04,12,f0,4b,01,7c,00,1c,1a,00,00,\
      00,00,00,07,18,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
      00,00,b8,dd,04,12,00,00,00,00,f0,aa,00,00,08,00,00,00,00,00,00,00,0a,00,00,\
      00,00,00,00,00,4c,f7,f6,03,00,00,00,00,6c,02,00,00,00,00,00,00,4a,c0,d7,83,\
      00,00,00,00,a4,dc,04,12,00,00,00,00,f0,4b,01,7c,01,00,00,00,04,6e,f6,03,b0,\
      dc,04,12,b8,c5,14,80,38,22,05,00,c0,71,01,7c,38,22,05,00,38,22,05,00,b0,dc,\
      04,12,c0,71,01,7c,f0,4b,01,7c,01,00,00,00,4a,c0,d7,83,74,dc,04,12,74,dc,04,\
      12,0a,00,00,00,01,00,00,00,eb,ff,ff,ff,4a,cf,d7,83,00,00,00,00,00,00,00,00,\
      00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,01,00,00,00,64,00,69,00,72,\
      00,65,00,63,00,74,00,00,00,04,12,00,00,00,00,00,00,00,00,0a,00,00,00,f0,4b,\
      01,7c,f0,4b,55,00,53,00,42,00,20,00,43,00,61,00,62,00,6c,00,65,00,3a,00,00,\
      00,00,00,00,00,a0,6f,fe,80,00,00,00,00,01,00,00,00,0a,00,00,00,02,00,00,00,\
      00,00,00,00,78,dd,04,12,b4,df,0f,00,d0,77,01,7c,89,01,00,00,00,00,00,00,ca,\
      1b,05,12,0a,00,00,00,7c,09,f6,03,00,00,00,00,0a,00,00,00,00,00,00,00,0a,00,\
      00,00,0a,00,00,00,ca,1b,05,12,b0,dd,04,12,b8,af,0f,00,00,ca,2a,0a,81,00,00,\
      00,ca,1b,05,12,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,ca,2a,0a,\
      ca,1b,05,12,50,18,00,00,03,00,00,00,05,00,00,00,74,66,2a,0a,df,fd,ff,ff,00,\
      00,00,00,4a,c0,d7,83,ca,1b,05,12,88,01,00,00,7c,fd,ff,ff,84,02,00,00,94,66,\
      2a,0a,00,de,04,12,00,00,00,00,0c,de,04,12,0c,de,04,12,04,6e,f6,03,0c,de,04,\
      12,9c,66,2a,0a,80,12,05,00,a0,5f,01,7c,80,12,05,00,80,12,05,00,0c,de,04,12,\
      a0,5f,01,7c,80,22,05,00,80,22,05,00,00,00,00,00,44,e0,04,12,18,08,e3,03,00,\
      00,00,00,d4,e1,e2,03,08,00,00,00,0a,00,00,00,01,00,00,00,01,00,00,00,38,22,\
      05,00,00,ca,2a,0a,4a,c0,d7,83,ca,1b,05,12,ca,1b,05,00,ca,1b,05,00,0c,00,00,\
      00,7c,09,f6,03,00,00,00,00,0a,00,00,00,88,de,04,12,cc,f3,f6,03,88,de,04,12,\
      4c,f7,f6,03,4a,c0,d7,83,4a,c0,d7,83,e4,b9,14,80,4a,c0,d7,83,a8,de,04,12,fc,\
      5c,08,00,ca,1b,05,12,ac,de,04,12,4a,c0,d7,83,4a,c0,d7,83,00,00,00,00,4a,c0,\
      d7,83,d6,9a,f9,e3,01,00,00,00,4a,c0,d7,83,00,ff,04,12,f0,4b,01,7c,f0,4b,01,\
      7c,64,aa,0f,00,4a,cf,d7,83,01,00,00,00,01,00,00,00,00,00,00,00,f4,de,04,12,\
      58,bf,02,00,00,00,00,00,f0,4b,01,7c,04,df,04,12,b4,5b,08,00,18,df,04,12,28,\
      df,04,12,10,df,04,12,01,00,00,00,00,00,00,00,ca,1b,05,12,00,00,00,00,00,87,\
      03,00,d6,9a,f9,e3,0a,00,00,00,00,00,00,00,d0,76,01,7c,00,4b,01,7c,64,aa,0f,\
      00,ca,1b,05,12,01,00,00,00,0a,00,00,00,00,00,00,00,d0,76,01,7c,01,00,00,00,\
      01,4b,01,7c,38,df,04,12,01,df,04,12,60,c1,02,00,d0,76,01,7c,01,00,00,00,01,\
      00,00,00,01,00,00,00,1c,e3,04,12,0a,00,00,00,f4,df,04,12,01,00,00,00,98,df,\
      04,12,68,53,03,00,f0,4b,01,7c,98,df,04,12,d8,55,03,00,a0,df,04,12,ca,1b,05,\
      12,00,00,00,00,00,00,00,00,00,00,00,12,00,00,00,00,00,00,00,00,01,00,00,00,\
      fc,82,cb,03,20,8f,d4,83,a0,6f,fe,80,a0,6f,fe,80,02,00,00,00,00,00,00,12,dc,\
      df,04,12,bc,0a,12,80,e4,fc,d3,83,01,00,00,00,20,8f,d4,83,a0,6f,fe,80,a0,6f,\
      fe,80,02,00,00,00,e4,fc,d3,83,a0,e0,04,12,00,00,00,00,20,8f,d4,83,d0,1f,f7,\
      83,00,00,00,00,00,00,00,00,fc,82,cb,03,00,00,00,00,0f,00,00,00,f0,6a,fe,80,\
      fc,82,cb,03,20,8f,d4,83,00,00,00,00,00,00,00,00,ec,df,04,12,01,d2,06,00,01,\
      00,00,00,23,00,00,00,00,00,00,00
 
[HKEY_CURRENT_USER\ControlPanel\Comm]
    "Cnct"="USB Connection"
 
I can't understand what does the table of hexes mean, but it did work well in the registry. So, after the system booted, we can conntect usb cable and enable ActiveSync automatically without any manual settings.


]]>
WinCE中划分Storage Memory和Program Memory http://www.shnenglu.com/milkyway/articles/17669.html相思酸中有?/dc:creator>相思酸中有?/author>Tue, 16 Jan 2007 01:49:00 GMThttp://www.shnenglu.com/milkyway/articles/17669.htmlhttp://www.shnenglu.com/milkyway/comments/17669.htmlhttp://www.shnenglu.com/milkyway/articles/17669.html#Feedback0http://www.shnenglu.com/milkyway/comments/commentRss/17669.htmlhttp://www.shnenglu.com/milkyway/services/trackbacks/17669.htmlhttp://www.cnblogs.com/walzer/archive/2006/04/21/380851.html

首先解释下这两个东东

The RAM on a Windows CE–based device is divided into two areas: the object store and the program memory.

The object store resembles a permanent, virtual RAM disk. Data in the object store is retained when you suspend or perform a soft reset operation on the system. Devices typically have a backup power supply for the RAM to preserve data if the main power supply is interrupted temporarily. When operation resumes, the system looks for a previously created object store in RAM and uses it, if one is found. Devices that do not have battery-backed RAM can use the hive-based registry to preserve data during multiple boot processes.

The program memory consists of the remaining RAM. Program memory works like the RAM in personal computers ?it stores the heaps and stacks for the applications that are running.

我承认我很懒Q上面一D话的URL是ms-help://MS.WindowsCE.500/wcecoreos5/html/wce50conMemoryArchitecture.htm

具体的设|可以在pȝ启动后,Control Panel -> System -> Memory 里面看到。默认的是把内存五五开Q一半给Storage MemoryQ?一半给Program Memory用。这h然是不合的。以64M的RAMZ, 启动后Storage Memory 32M, 而因为没有留出界面让用户往里面拷东? M时候in use都不会超q?0M; Program Memory也是32M, 但启动后q?7M, 实际上应用程序可用的内存只有5M, 一旦达C上限, 那么每前q一步都要很艰难地去释放几十K内存Q然后用掉,再去释放几十K内存Q如此@环,此时应用E序的运行速度狂慢无比.

划分的方法也很简? 只不q可能没人注意到而已.

说明在ms-help://MS.WindowsCE.500/wceosdev5/html/wce50lrfFSRAMPERCENT.htm  懒得看英文的人就l箋往下看

其实说白了就一句话, 在BSP的config.bib?CONFIG 区添加这个变?FSRAMPERCENT = 0xXXXXXX, 但注意两点,

(1) 必须写在config.bib的CONFIG区里, 不是plagform.bib不是config.reg{其他文件而是config.bibQ也不是config.bib文g的Q意地方而一定要在CONFIG REGION?
(2) FSRAMPERCENTq个变量一定得写ؓFSRAMPERCENT, 不能写成FSROMPERCENT不能写成ILOVEU, 或者阿猫阿狗什么的.

写下q两句的时候本人已l打开无敌光环, 免疫一切鸡蛋和西红?

FSRAMPERCENT是一?byte长度的十六进制数, 我们用代数假?FSRAMPERCENT = 0xQXYZ, 其中Q,X,Y,Z都是十六q制?/p>

那么最l划分给Storage Memory的大?=  ( Q + X + Y +  Z ) / 0x400 * TOTAL_RAM_SIZE

以文中的例子来算, FSRAMPERCENT=0x10203040, 假设TOTAL_RAM_SIZE=64M, 那么StorageMemory= (0x10 + 0x20 + 0x30 + 0x40) / 0x400 * 64M = 10M.



]]>
RAPI初始化算法和SAMPLE CODEhttp://www.shnenglu.com/milkyway/articles/17667.html相思酸中有?/dc:creator>相思酸中有?/author>Tue, 16 Jan 2007 01:42:00 GMThttp://www.shnenglu.com/milkyway/articles/17667.htmlhttp://www.shnenglu.com/milkyway/comments/17667.htmlhttp://www.shnenglu.com/milkyway/articles/17667.html#Feedback1http://www.shnenglu.com/milkyway/comments/commentRss/17667.htmlhttp://www.shnenglu.com/milkyway/services/trackbacks/17667.htmlhttp://www.cnblogs.com/walzer/archive/2006/02/05/325605.html

作者:Walzer
日期Q?005.12.12

RAPI全写为Remote Application Interface, 是PC端调用这lAPI, 通过ActiveSync来操作TARGET端WindowsCE作业. q个功能估计以后在WINCE或WIN MOBILE的应用上会用到许?/p>

我今天修改了同事留下的Updateboot.exe的代? 改进蓝牙d的模? q个地方我们用到了RAPI, 看一下他们在E序中初始化RAPI的做?/p>

 HRESULT hRapiResult;
 hRapiResult = CeRapiInit();
 if(hRapiResult != S_OK)
 {
     m_ValueEdit.SetWindowText((LPCTSTR)"初始化RAPIp|");
     return;
 }

看v来是qxE无奇, 实际上单步一下就可以发现q行到CeRapiInit()? E序BLOCK在这里了Q死z走不下? q没有达刊Wif(hRapiResult != S_OK)的预期目? 我查了一下CeRapiInit()的说?

A call to CeRapiInit does not return until the connection is made, an error occurs, or another thread calls CeRapiUninit.

也就是说像我现在q没有把板子和PC相连q启动ACTIVE SYNC? q个CeRapiInit()是肯定赖着不走? E序会死在这? (鄙视一下谁写的代码Q这个坑好大?  因此惛_了重新创立个{待q程调用CeRapiUninit来干掉它. 不过q样做显然不厚道, 创立q程需要占用更多的内存. 所以用了上句说明的下半D?

The CeRapiInitEx function does not block the calling thread. Instead, it uses an event to signal when initialization is complete.

建立个事? 用WaitForSingleObject来等? 时BYEBYE? 贡献自己写的如下代码, 以后RAPI INIT可以参?br />

BOOL RapiInitialzation()
{
    RAPIINIT struRapiInit;   
//q个是CeRapiInitEx函数要求的入口参?/span>
    DWORD dwWaitResult = 0;  //{待初始化完成事件的变量
    HRESULT hRapiResult = NULL; //CeRapiInitEx的返回HANDLE

    
if ( m_bRapiInitFlag == FALSE ) //全局的一个FLAG,如果初始化过׃再重复了
    {
        struRapiInit.cbSize 
= sizeof(RAPIINIT);  //填满该结构体仅有的三个成?/span>
        struRapiInit.hrRapiInit = NULL;  //明知是输出参C手填一? 我以前吃q亏, 惊弓之鸟
        struRapiInit.heRapiInit = NULL;

        hRapiResult 
= CeRapiInitEx(&struRapiInit);  //关键?/span>

        m_ValueEdit.SetWindowText((LPCTSTR)
"Wait 2 second for RapiInit"); //后面2U程序要一下了, 得告诉用?  m_ValutEdit和对话框里一个IDC_STATIC兌?
        dwWaitResult = WaitForSingleObject(struRapiInit.heRapiInit, 2000);  //关键?/span>

        
if( hRapiResult == S_OK && 
            struRapiInit.hrRapiInit 
== S_OK &&
            dwWaitResult 
!= WAIT_TIMEOUT)    //保守赯, 三个q回值都判断
        {
           m_bRapiInitFlag 
= TRUE;
           
return TRUE;
        }
        
else
        {
            m_ValueEdit.SetWindowText((LPCTSTR)
"The initialization of RAPI falied, you need to install an ActiveSync or connect the IPTV to PC");   //一般是没连接导? 当然也可能用h装ActiveSync
           return FALSE;
        }
    }
    
else
    {
         m_bRapiInitFlag 
= TRUE;
         
return TRUE;
    }
}


]]>
multi-xip的实?http://www.shnenglu.com/milkyway/articles/17664.html相思酸中有?/dc:creator>相思酸中有?/author>Tue, 16 Jan 2007 01:29:00 GMThttp://www.shnenglu.com/milkyway/articles/17664.htmlhttp://www.shnenglu.com/milkyway/comments/17664.htmlhttp://www.shnenglu.com/milkyway/articles/17664.html#Feedback0http://www.shnenglu.com/milkyway/comments/commentRss/17664.htmlhttp://www.shnenglu.com/milkyway/services/trackbacks/17664.htmlhttp://www.cnblogs.com/yakin/archive/2005/07/20/196572.aspx
作? yakin

multi-xip实际上很有用Q但是现在有一个ؓ隄事情Q就是OSh之后无法写flashQ这个很让h苦恼。所以这也导致升U程序无法设|标志位。只能用GPIO口?/p>

Multi-xip的实玎ͼ
1) Bib文g的修改:
   MEMORY

    RSVD     80000000  000FF000  RESERVED
    ARGS     800FF000  00001000  RESERVED
    NK       9C600000  01000000   RAMIMAGE
    APP      9D600000  00500000   RAMIMAGE
    CHAIN    9DB00000  00002000   RESERVED
    RAM      80100000  01F00000  RAM
    pdwXIPLoc 00000000 9DB00000  FIXUPVAR

CONFIG

    AUTOSIZE=ON
    ROM_AUTOSIZE=OFF
    RAM_AUTOSIZE=OFF
    DLLADDR_AUTOSIZE=ON
    XIPSCHAIN=9DB00000
    ROMSTART=9C600000
    ROMWIDTH=32
    ROMSIZE=01600000

    KERNELFIXUPS=ON

2) 在OEMInit加一个连接各个bin的函敎ͼ
void InitRomChain()
{
 // Added for MultiXIP stuff
 static  ROMChain_t s_pNextRom[MAX_ROM] = {0};
 DWORD  dwRomCount = 0;
    DWORD       dwChainCount = 0;
    DWORD *     pdwCurXIP;
    DWORD       dwNumXIPs;
    PXIPCHAIN_ENTRY pChainEntry = NULL;
    if(pdwXIPLoc == NOT_FIXEDUP){
        return;  // no chain or not fixed up properly
    }
    // set the top bit to mark it as a virtual address
    pdwCurXIP = (DWORD*)(((DWORD)pdwXIPLoc) | 0x80000000);
    // first DWORD is number of XIPs
    dwNumXIPs = (*pdwCurXIP);
   if(dwNumXIPs > MAX_ROM){
      OALMSG(TRUE, (L"ERROR: Number of XIPs exceeds MAX\r\n"));
      //lpWriteDebugStringFunc(TEXT("ERROR: Number of XIPs exceeds MAX\n"));
      return;
    }
    pChainEntry = (PXIPCHAIN_ENTRY)(pdwCurXIP + 1);
    while(dwChainCount < dwNumXIPs)
    {
        if ((pChainEntry->usFlags & ROMXIP_OK_TO_LOAD) &&  // flags indicates valid XIP
            *(LPDWORD)(((DWORD)(pChainEntry->pvAddr)) + ROM_SIGNATURE_OFFSET) == ROM_SIGNATURE)
        {
            s_pNextRom[dwRomCount].pTOC = *(ROMHDR **)(((DWORD)(pChainEntry->pvAddr)) + ROM_SIGNATURE_OFFSET + 4);
            s_pNextRom[dwRomCount].pNext = NULL;
            if (dwRomCount != 0)
            {
                s_pNextRom[dwRomCount-1].pNext = &s_pNextRom[dwRomCount];
            }
            else
            {
                OEMRomChain = s_pNextRom;
            }
            dwRomCount++;
        }
        else
        {
            OALMSG(TRUE, (L"Invalid XIP found\r\n"));
            //lpWriteDebugStringFunc( _T("Invalid XIP found\n") );
        }
        ++pChainEntry;
  dwChainCount++;
 }
}
  q是从CEPC中拷贝过来的?/p>


通过上面的设|,romimage会生?个binQnk.binQapp.binQchain.binQ还有一个xip.binQ是上面三个bin的集合体。我们download是要download xip.binQ这样就可以实现multibin。通过调试发现QInitRomChain是利用chain.bin来连接各个bin的?br />q样我们也理解了bib文g中这个语句的含义Q?br />pdwXIPLoc 00000000 9DB00000  FIXUPVAR
也就是FIXUPVAR的含义。我们看到在代码中我们同样定义了pdwXIPLocQ这样romimageӞ将9DB00000赋给pdwXIPLoc。这是FIXUPVAR的作用。正如pTOC也是由romimage赋g栗?/p>

]]>
CE中将PC上指定文件加入NK, q放到目标机上指定目?/title><link>http://www.shnenglu.com/milkyway/articles/17662.html</link><dc:creator>相思酸中有?/dc:creator><author>相思酸中有?/author><pubDate>Tue, 16 Jan 2007 01:14:00 GMT</pubDate><guid>http://www.shnenglu.com/milkyway/articles/17662.html</guid><wfw:comment>http://www.shnenglu.com/milkyway/comments/17662.html</wfw:comment><comments>http://www.shnenglu.com/milkyway/articles/17662.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/milkyway/comments/commentRss/17662.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/milkyway/services/trackbacks/17662.html</trackback:ping><description><![CDATA[来自 <a >http://www.cnblogs.com/walzer/archive/2006/02/05/325604.html</a><br /><div id="fp9h79t" class="postbody"><p>作者:Walzer<br />日期Q?005.9.29<br /><br />以这ơ要加入PC上事先做好的bookmark.htm, 攑ֈ板上DiskOnChip/Documents and Settings/Walzer/ 目录下ؓ?</p><p>首先把bookmark.htm拯到ie.bib的同U目录public\ie\oak\files\下,然后在bib里包?br />bookmark.htm    $(_FLATRELEASEDIR)\bookmark.htm             NK SH<br />x该文件放到NK里,DOWNLOAD下去后是pȝ隐藏文g。由于我们用了Multi-Bin的做法,所以还得在PLATFORM下的xip.cfg里指定新加入文g攑ֈ哪个BIN里面.</p><p>q个地球人都知道了。重Ҏ下面的如何把文g在DOWNLOAD后放到指定目录里?/p><p>扑ֈie.dat, 里面的语法格式参考ms-help://MS.WindowsCE.500/wceosdev5/html/wce50conFileSystemFile.htm<br />我在里面加了一D?br />Directory("\DiskOnChip"):-Directory("Documents and Settings")<br />Directory("\DiskOnChip\Documents and Settings"):-Directory("Walzer")<br />Directory("\DiskOnChip\Documents and Settings\Amoi"):-File("bookmark.htm","\Windows\bookmark.htm")<br />先徏立两层子目录Q然后把ROM里面的bookmark.htm拯到目录里。值得一提的是第三行的最后一个参量,\Windows\bookmark.htm 下蝲后的文g都在ROM里面Q\windows是指ROM里的文g?/p><p>cM的dat文gq很多,SYSGEN的时候就在PBWorkspace的相应RELEASE目录里胜利会? 合ƈ为initobj.tmp, q个文g和合q前零散的都为ASCII码,然后要{成UNICODE生成initobj.datQ最后我们可以看到ce.bib里包含了initobj.datq个文gQƈ入最l生成的BIN文g里?/p></div><img src ="http://www.shnenglu.com/milkyway/aggbug/17662.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/milkyway/" target="_blank">相思酸中有?/a> 2007-01-16 09:14 <a href="http://www.shnenglu.com/milkyway/articles/17662.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何为Win CEpȝ开发应用程?/title><link>http://www.shnenglu.com/milkyway/articles/17589.html</link><dc:creator>相思酸中有?/dc:creator><author>相思酸中有?/author><pubDate>Sat, 13 Jan 2007 08:34:00 GMT</pubDate><guid>http://www.shnenglu.com/milkyway/articles/17589.html</guid><wfw:comment>http://www.shnenglu.com/milkyway/comments/17589.html</wfw:comment><comments>http://www.shnenglu.com/milkyway/articles/17589.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/milkyway/comments/commentRss/17589.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/milkyway/services/trackbacks/17589.html</trackback:ping><description><![CDATA[ <p class="MsoNormal"> <span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #666666; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">To write applications for Windows CE, Microsoft offers a rich set of languages for creating managed (.NET) or native applications. You can use Visual Studio .NET to write managed code or use eMbedded Visual C ++ to write native code.<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /?><o:p></o:p></span> </p> <p class="MsoNormal"> <span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #666666; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt"> <o:p> </o:p> </span> </p> <p class="MsoNormal"> <span lang="EN-US" style="FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"> <span style="mso-tab-count: 1">    </span> </span> <span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">在什么情况下应该?/span> <span lang="EN-US" style="FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">Visual Studio .NET</span> <span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">而不?/span> <span lang="EN-US" style="FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">eMbedded Visual C++</span> <span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">来ؓ</span> <span lang="EN-US" style="FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">Win CE</span> <span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">pȝ开发应用程序?</span> <span lang="EN-US" style="FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"> <o:p> </o:p> </span> </p> <p class="MsoNormal"> <span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #666666; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">The type of application that you want to create will dictate the choice between native and managed code (.NET). When performance and control are the highest priorities, developers should turn to eMbedded Visual C++ or native code. When a consistent programming model and time-to-market are the primary considerations, the advantages offered by Visual Studio .NET are unparalleled.<o:p></o:p></span> </p> <p class="MsoNormal"> <span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #666666; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt"> <o:p> </o:p> </span> </p> <p class="MsoNormal"> <span lang="EN-US" style="FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">.NET Compact Framework</span> <span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">应用E序的运行性能是否?/span> <span lang="EN-US" style="FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">eMbedded Visual C++</span> <span style="FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt">应用E序一P</span> <span lang="EN-US" style="FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 10.5pt"> <o:p> </o:p> </span> </p> <p class="MsoNormal"> <span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #666666; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">In most cases, applications that you write with eMbedded Visual C++ will run faster than those that you write by using Microsoft Visual Basic .NET or Microsoft Visual C# .NET. However, for computationally-intensive portions of an application, you will see a substantial improvement of your Visual Basic .NET applications over their eMbedded Visual Basic .NET equivalents.<o:p></o:p></span> </p> <p class="MsoNormal"> <span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #666666; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt"> <o:p> </o:p> </span> </p> <img src ="http://www.shnenglu.com/milkyway/aggbug/17589.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/milkyway/" target="_blank">相思酸中有?/a> 2007-01-13 16:34 <a href="http://www.shnenglu.com/milkyway/articles/17589.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Pocket PC的应用程序是否可以直接在Windows CE讑֤上运?/title><link>http://www.shnenglu.com/milkyway/articles/17588.html</link><dc:creator>相思酸中有?/dc:creator><author>相思酸中有?/author><pubDate>Sat, 13 Jan 2007 08:32:00 GMT</pubDate><guid>http://www.shnenglu.com/milkyway/articles/17588.html</guid><wfw:comment>http://www.shnenglu.com/milkyway/comments/17588.html</wfw:comment><comments>http://www.shnenglu.com/milkyway/articles/17588.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/milkyway/comments/commentRss/17588.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/milkyway/services/trackbacks/17588.html</trackback:ping><description><![CDATA[来自<a >http://www.advantech.com.cn/microsoft/shownews.asp?id=79</a><br /><br /><p class="MsoNormal"><span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #666666; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">Running an application natively refers to running an application without recompiling it for a different environment. Windows CE .NET 4.2 and Windows CE 5.0 devices can run Pocket PC applications if both of the following are true: <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /?><o:p></o:p></span></p><p class="MsoNormal"><span style="FONT-SIZE: 9pt; COLOR: #666666; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">?/span><span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #666666; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">      </span>The application is designed for the same CPU architecture <o:p></o:p></span></p><p class="MsoNormal"><span style="FONT-SIZE: 9pt; COLOR: #666666; FONT-FAMILY: 宋体; mso-ascii-font-family: Verdana; mso-hansi-font-family: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">?/span><span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #666666; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt"><span style="mso-tab-count: 1">      </span>The application calls the same API set as the Pocket PC 2003 SDK. Windows CE .NET 4.2 and Windows CE 5.0 support the same SDK APIs from CESHELL and AYGSHELL. <o:p></o:p></span></p><p class="MsoNormal"><span lang="EN-US" style="FONT-SIZE: 9pt; COLOR: #666666; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">For more information, visit the Windows CE Application Development page.<o:p></o:p></span></p><img src ="http://www.shnenglu.com/milkyway/aggbug/17588.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/milkyway/" target="_blank">相思酸中有?/a> 2007-01-13 16:32 <a href="http://www.shnenglu.com/milkyway/articles/17588.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 怎样d驱动到CE的CATALOG中去http://www.shnenglu.com/milkyway/articles/17247.html相思酸中有?/dc:creator>相思酸中有?/author>Thu, 04 Jan 2007 08:18:00 GMThttp://www.shnenglu.com/milkyway/articles/17247.htmlhttp://www.shnenglu.com/milkyway/comments/17247.htmlhttp://www.shnenglu.com/milkyway/articles/17247.html#Feedback0http://www.shnenglu.com/milkyway/comments/commentRss/17247.htmlhttp://www.shnenglu.com/milkyway/services/trackbacks/17247.htmltry:
1,create a new catalog,and save it to WINCE PLATFORM BUILDER\4.00\cepc\cec\ directory.
2,create a new feature group for the catalog,define the "name" and "group".
3,add a new feature for the feature group.define the "name" and "locale:0409".
4,add some new build method for the feature,select from "step".
5,add a new action for the build method.
6,if u have *.bib file,and a new bib file and location the bib file to the NK.BIN whatever bib section defined to modules or files
7,save it and add it to catalog,can use pb or cec edit.
the important is:
select the correct build method to using and the correct action to using.
build method include:PreSYSGEN,SYSGEN,PostSYSGEN,PreBSP,BSP,PostBSP,PreBuildRel,BuildRel,PostBuildRel,PreMakeImg,MakeImg,PostMakeImg.
action include:Build,Copy,Custom,Environment,Source Browse.
if the drvier have source file(*.c,*.h),must select BSP and Source Browse.
if the driver have no source file and have *.dll file please select any build method and "Copy" action.


]]>
如何防止Windows CE .NET盗用COM1端口http://www.shnenglu.com/milkyway/articles/17246.html相思酸中有?/dc:creator>相思酸中有?/author>Thu, 04 Jan 2007 08:01:00 GMThttp://www.shnenglu.com/milkyway/articles/17246.htmlhttp://www.shnenglu.com/milkyway/comments/17246.htmlhttp://www.shnenglu.com/milkyway/articles/17246.html#Feedback0http://www.shnenglu.com/milkyway/comments/commentRss/17246.htmlhttp://www.shnenglu.com/milkyway/services/trackbacks/17246.html 在缺省状态下QWindows CE .NETCOM1端口用于调试目的。如果您在自q讑֤上还拥有其它COM端口Q那么,Windows CE .NET则会它们划归应用程序用(物理意义上的COM2端口成为逻辑意义上的COM1端口Q依此类推)。然而,某些特定目可能需要将全部COM端口划归应用E序使用?

为此Q请遵@下列处理步骤Q?

通过修改OEMInitDebugSerial()Q可在OAL的debug.c文g中找刎ͼ函数的方式告知操作系l不要将COM端口用于调试目的
if ( ! pBootArgs->ucBaudDivisor ) {
pBootArgs->ucBaudDevisor = 6; // Default to 19.2 if nothing specified.
}

pBootArgs->ucComPort = 0; // ADD THIS LINE

switch ( pBootArgs->ucComPort ) {

通过Ҏ册表文gplatform.reg加以修改来调整COM端口映射关系?
举例来说Q将现有注册表项Q?
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Serial]
"SysIntr"=dword:13 ; NOTE: This is physical COM2 (subtract 10 for IRQ)
"IoBase"=dword:02F8 ; NOTE: This is physical COM2
...
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Serial2]
"SysIntr"=dword:14 ; NOTE: This is physical COM3 (subtract 10 for IRQ)
"IoBase"=dword:03E8 ; NOTE: This is physical COM3
...

修改为:

[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Serial]
"SysIntr"=dword:14 ; NOTE: This is physical COM1 (subtract 10 for IRQ)
"IoBase"=dword:03F8 ; NOTE: This is physical COM1
...
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\Serial2]
"SysIntr"=dword:13 ; NOTE: This is physical COM2 (subtract 10 for IRQ)
"IoBase"=dword:02F8 ; NOTE: This is physical COM2
...

说明Q您所看到的结果可能有所不同。如果您的系l针对COM端口使用了不同的IoBase/IRQ讄Q则请对注册表文件platform.regq行适当配置?

另一U替代方法就是在您的BIOS中对COM端口的IoBase/IRQ讄q行修改。Windows CE .NET已就?F8/4Q典型的COM1Q留作自用进行了性规定(针对CEPCQ。D例来_如果您将此类讄指派lCOM4Q那么,Windows CE .NET调试信息便会路由至物理端口?/font>


]]>
如何在Windows CE.NET下用大?56MB内存http://www.shnenglu.com/milkyway/articles/17240.html相思酸中有?/dc:creator>相思酸中有?/author>Thu, 04 Jan 2007 07:11:00 GMThttp://www.shnenglu.com/milkyway/articles/17240.htmlhttp://www.shnenglu.com/milkyway/comments/17240.htmlhttp://www.shnenglu.com/milkyway/articles/17240.html#Feedback0http://www.shnenglu.com/milkyway/comments/commentRss/17240.htmlhttp://www.shnenglu.com/milkyway/services/trackbacks/17240.html首先Q你必须安装Windows CE .NET Platform Builder 4.0Q以下简UPB4Q?假设你安装的Windows CE.NET位于D:\WINCE目录下,那么Q首先找到文件oeminit.asm,位于D:\Wince\Public\Common\Oak\Csp\I486\Oal,q个文g是提供给OEM厂商做一些特定的配置的?
打开oeminit.asm文g,然后扑ֈ“_OEMAddressTable:”,_OEMAddressTable是一个非常关键的内存映射描述表,主要描述物理内存和虚拟内存之间的映射Q表的每一条目?个DWORD,依次是(VAQPAQcbSizeQ,其中VA是虚拟内存的开始地址Q一般ؓ80000000h,PA是物理内存的开始地址Q一般ؓ0QcbSize是CE内核支持物理内存的大,q个DWORD是我们最最兛_?其单位是BYTE。需要注意的是,cbSize,一定要?M Byte的倍数Q因为Windows CE.NET内核中检内存大,是以4M Byte为单位来的。cbSizepȝ默认?4000000h,其大ؓ64M,我们可以其修改?0000000h,可以支?56M内存了,当然Q你如果x持更大的内存Q也可以增大cbSize,只要?M的倍数卛_?
另外需要修改一个文件是Q,打开pc.h,查找刎ͼ
#define CEPC_EXTRA_RAM_START 0x81C00000 // 28 MB is default top of RAM for auto-detectQ这里规定Windows CE.NET内核内存的开始地址Q默认从28M Byte开始?
#define CEPC_EXTRA_RAM_SIZE 0x02400000 // Potentially add another 36 MB q里规定了内怸探测内存定w的最大尺寸,0x02400000 ,表示最大探?6MQ这L话,28MB+36MB正好?4MB?
我们需要支?56MB内存Q只需要修改CEPC_EXTRA_RAM_SIZE卛_Q将其改修改Q?
#define CEPC_EXTRA_RAM_SIZE 0x02400000+0x0C000000 // Potentially add another 36 + 128 + 64MB
修改ZqC个文件后Q需要重新编译系l内核,打开PB4.0,打开Build->Open Build Release Directory,q入一个DOS操作界面,然后q入D:\Wince\Public\Common\Oak\Csp\I486\目录下,执行“Build –cfs?重新~译内核,然后重新建立一个新的PlatformQ编译后卛_?/font>


]]>
串行通讯 http://www.shnenglu.com/milkyway/articles/17239.html相思酸中有?/dc:creator>相思酸中有?/author>Thu, 04 Jan 2007 07:09:00 GMThttp://www.shnenglu.com/milkyway/articles/17239.htmlhttp://www.shnenglu.com/milkyway/comments/17239.htmlhttp://www.shnenglu.com/milkyway/articles/17239.html#Feedback0http://www.shnenglu.com/milkyway/comments/commentRss/17239.htmlhttp://www.shnenglu.com/milkyway/services/trackbacks/17239.html

串行通讯实际上将被所有的Windows CE讑֤所支持Q在g水^上,通过늼和红外传送器q行串行通讯是很普通的。调制解调器也支持串行通讯?

1.PC和Windows CE的通信pȝ

Win32的通信pȝ Win32提供l用户一个模块化?2位的保护模式的通信pȝ。在Win32中,各种通信资源的函数做了很大的改进和标准化Q得它们的操作如同文件的操作一栗?

在串口读写操作中QWin32引入了超时概c超时直接媄响读和写的操作行为。当过预先讑֮的超旉隔时QReadFile、WriteFile操作仍未l束Q那么将无条件结束读写操作,而不论是否已d或写入指定数量的字符?

Windows CE的通信pȝ Windows CE驱动程序分ZU:本地讑֤驱动E序和流讑֤驱动E序。本地设备驱动程序,也称为“内|驱动程序”,q些讑֤驱动E序是一些硬件所必需的,是由原始讑֤刉商创徏的,用以驱动如键盘、触摸屏、音频设备等Q往往在设备售出后׃会再更换。另一斚wQ流接口讑֤驱动E序Q指可安装的启动E序Q可以由W三方生产商提供Q以支持d到系l中的设备。Windows CE下的讑֤驱动E序在与应用E序相同的保护上工作。当pȝ启动Ӟ大多数驱动程序是p备管理进E(DEVICE.EXEQ加载的Q所有的q些驱动E序共享同一个进E地址I间?

本地讑֤驱动E序一般都被紧紧地限制在Windows CE的操作系l中Q往往在设备售出后׃会再更换。因为Windows CE没有像ISA或PCI那样的用于附加插卡的ȝQ附加的g通常是通过PCMCIA或“小型快闪槽”安装的Q例如串?是通过PCMCIA卡实现的。观察注册表中的HKEY_LOCAL_MACHINE下的\Drivers\Active键中的内容,可以了解在Windows CE中加载了什么驱动程序。 

通信q程 包括Q?Q打开通信资源。在q程使用串口之前Q首先应使用CreateFile函数打开通信资源Q返回一个标识该资源的句柄。在CreateFile函数打开串口通信资源Ӟpȝ根据上ơ打开资源时的数值初始化和配|资源;Q?Q读写串口资源。通过ReadFile和WriteFile函数来读写串口。读和写的超时时间由SetCommTimeouts函数讄Q(3Q关闭通信资源。在使用通信资源l束后,应调用CloseHandle函数来关闭通信句柄Q释放资源?

基本的串行通信~程 串行讑֤被视为用于打开、关闭、读和写串口的常规、可安装的流讑֤。Win32 API提供了一l通信函数QWindows CE支持了其中的大多数通信函数?

打开和关闭串行端口:在所有的设备都可以使用CreateFile来打开串行端口讑֤。一般的调用Ҏ如下Q?

hSer=CreateFile(TEXT(“COM1:?,

GENERIC_READ|GENERIC_WRITE,

0,

NULL,

OPEN_EXISTING,

0,

NULL);

 

׃Windows CE不支持设备的重叠I/OQ因此不能传递FILE_FLAG_OVERLAPPED标志。当不成功时Q返回句柄INVALILD_HANDLE_VALUEQ反之返回打开的串行端口句柄?

调用CloseHandle可以关闭一个串行端?

CloseHandle(hSer);

d串行端口Q可以用ReadFile和WriteFile来读写串行端口。从串口d数据只需如下调用Q?

int rc;

DWORD cBytes;

BYTE ch;

rc=ReadFile(hSer,&ch,1,&cBytes,NULL);

调用成功Q则变量ch读入一个字节,cBytes被讄取的字节的数量?

从串口写入数据只需如下调用Q?

int rc;

DWORD cBytes;

BYTE ch;

ch=TEXT(‘A?;

rc=WriteFile(hSer , &ch , 1 , &cBytes , NULL );

上面的代码将字母A写入已经打开的端口,成功的话QReadFile和WriteFile都将q回TRUE?


http://palmheart.net/modules.php?op=modload&name=Sections&file=index&req=viewarticle&artid=154

每一个串行设备都匚w有一个COM口,例如“COM1”。Windows CE为打开串口和管理接收设备上的连接提供了一个API。一旦连接成功,用相同的函数进行数据传送,q些函数用以M个文件或者写一个文件。数据只是简单的从一个设备传送到另一个设备。不支持同步和异步I/O?/font>


]]>WinCE下直接启动自己应用程序的Ҏhttp://www.shnenglu.com/milkyway/articles/17170.html相思酸中有?/dc:creator>相思酸中有?/author>Wed, 03 Jan 2007 02:20:00 GMThttp://www.shnenglu.com/milkyway/articles/17170.htmlhttp://www.shnenglu.com/milkyway/comments/17170.htmlhttp://www.shnenglu.com/milkyway/articles/17170.html#Feedback1http://www.shnenglu.com/milkyway/comments/commentRss/17170.htmlhttp://www.shnenglu.com/milkyway/services/trackbacks/17170.htmlhttp://jkflyfox.spaces.live.com/?_c11_blogpart_blogpart=blogview&_c=blogpart&partqs=cat%3d%25e7%25a8%258b%25e5%25ba%258f%25e6%258a%2580%25e5%25b7%25a7

其实让一个程序在wince里启动和windows里差不多Q直接设|其为启动项Q这个有几个Ҏ。一个就是制作一个快h式,指向我们的应用程序如app.exeQ然后将快捷方式攑ֈ\windows\startup下面?
    步骤如下Q(假设app.exe已经拯到windows下面Q?br />    1 在pb中创Z个文Ӟ文gcd选txtQ然后命名ؓ.lnk后缀Q假讑֐字ؓtest.lnk 
    2 ~辑其内容ؓ: 16#\windows\app.exe。备注:前面?6? 后面所有字W的dQ包括空根{Wince的帮助文档上说这么定义就行,但是我尝试后Q最后down到目标机上面时提C找不到文gQ在wince里查看这么创建的test.lnk的属性,发现其指向\windows\app.exe后面q有两个ҎQ因此不对,我的解决Ҏ是修改test.lnk的内容ؓ16#"\Windows\app.exe" 
    3 ~辑好lnk文g内容后在pb中修改project.bib。在filesD后面添加下面一行:(和添加别的文件到image中类|见我的《WinCE中如何向image中添加文件》,也要在pb的flatform菜单的setting下添加build语句Q不再赘q?
        test.lnk $(_FLATRELEASEDIR)\test.lnk NK S
    在project.dat中增加下面一行:
         Directory("\Windows\startup"):-File("test.lnk","\Windows\test.lnk")
    q样后系l启动后׃自动启动我们的程序了?
   
    另外一U方法是~辑注册表:在project.reg中添加如下内?
        [HKEY_LOCAL_MACHINE\init]
        "Launch80"="app.exe"
        "Depend80"=hex:14,00,1e,00
    q个是设定启动顺序,launch后面的数字越大的是后启动,Depend80后面的指定依赖项Qؓ16q制Q上面的语句表明依赖ؓlaunch20定义的device.exe和launch30中定义的gwes.exeQ?注意Launch后面的数字范围ؓ0?9 Q此范围之外的将不会有效果?
    q样两种Ҏ的效果都是系l都是系l先启动资源理器explorer.exeQ就是看到的默认桌面Q,然后启动我们的程序,Q如果利用taskman shell然后Ld栏那么效果更好)但是q样q不够,我们如何不显C桌面,直接昄我们的程序呢Q?
    |上有h介绍的方法是Lstandard shellQ但是我~译L报错。我采用的方法是替换注册表中lauch50中的explorer.exe为我的app.exeQ即搞定?
    修改注册表的ҎQ先把带KITL的系l跑hQ在PB的TOOLS->Remote registry editor里修?验证有效?再去修改platfrom.reg, 或者自己写个REG文gQ然后在platform.reg里INCLUDEq来 SYSGEN后确认PBWORKSPACE里相关项目的REL目录里reginit.ini文g里包含了自己做的修改后make image然后DOWNLOAD下去OK了?
    值得补充的是Q我们前面介l的步骤中那个修改^台settingQ添加语句的Q是因ؓ我每ơ都是重新sysgen和buildQ如果只是简单的make image的话Q都是pb中的build OS菜单下的命oQ,那么直接用release中的内容Q因此也可以直接文件放到release文g夹,然后改project.bib{实现往image中添加文件?同样Q也可以直接修改release中的shell.reg中的launch50gؓ我们自己的程序(或者类g改reginit.ini文gQreginit.ini文g存放有所有wince的静态注册表Q来辑ֈL桌面Q直接启动我们程序的效果Q?
注意Q这么启动的E序Q如果点d闭,׃L的,因ؓ没有H口q行了。实际运用中Q当然不会让用户关闭我们的程序,除非他一起关闭系l?
如果也需要build的话Q可以通过往image中添加文件的Ҏ我们改好的shell.regd到release目录。?/div>

]]>WinCE中如何向image中添加文?/title><link>http://www.shnenglu.com/milkyway/articles/17169.html</link><dc:creator>相思酸中有?/dc:creator><author>相思酸中有?/author><pubDate>Wed, 03 Jan 2007 02:19:00 GMT</pubDate><guid>http://www.shnenglu.com/milkyway/articles/17169.html</guid><wfw:comment>http://www.shnenglu.com/milkyway/comments/17169.html</wfw:comment><comments>http://www.shnenglu.com/milkyway/articles/17169.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/milkyway/comments/commentRss/17169.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/milkyway/services/trackbacks/17169.html</trackback:ping><description><![CDATA[来自<a >http://jkflyfox.spaces.live.com/?_c11_blogpart_blogpart=blogview&_c=blogpart&partqs=cat%3d%25e7%25a8%258b%25e5%25ba%258f%25e6%258a%2580%25e5%25b7%25a7</a><br /><br />?U情冉|说明如何d <p>W一U,是image已经在CEPC或者终端上跑v来了Q那么这个时候要x加文件可以通过PB或者EVC提供的remote file viewerQ这个比较简单,看着界面操作p了? </p><p>W二U,是对定制的image已经buildq了Q现在想往里面d文g的话Q可以在你对应^台的release文g多w面直接添加文Ӟ然后修改q_配置文gproject.bibQ然后再make imageQ也可以文件添加到image中去Q将image启动后,会出现在windows文g夹下? </p><p>比如你想test.txtd到image中,则首先需要将此文件拷贝到q_release目录下面 </p><p>Q^台release目录也就是环境变量_FLATRELEASEDIR的|_FLATRELEASEDIR?= %_WINCEROOT%\PBWorkspaces\%_TGTPROJ%\RelDir\%_TGTPLAT%\%_TGTCPUFAMILY%_ReleaseQ也是realease目录Q(_TGTPLAT为^台名Q_TGTCPUFAMILY为CPU名)。我新徏的^CؓshellTestQ其gؓE:\WINCE500\PBWorkspaces\ShellTest\RelDir\MyCEPC_x86_Release Q? </p><p>然后按照以下修改project.bibQ? </p><p>在其中添加类D样一? </p><p>test.txt$(_FLATRELEASEDIR)\test.txt NK S </p><p>q句话的意思是说将q_release文g夹下面的test.txt文gd到image中,文g属性ؓpȝ文gQ关于bib文g的格式,h阅WinCE的帮?/p><p>修改好project.bib后,保存Q然后在pb的bulid菜单下选择make imageQ成功后下蝲到终端或CEPCQ就可以看到d的文件了?/p><p>W三U,是q_定制都没做好Q或者做好了需要修改,那么如果你直接按照第二种来做Q然后选择build菜单的sysgen and build的话Q你会发现根本不会讲test.txt拯到image中,q个也是我的惨痛教训Q花了好些时间才知道原因?/p><p>Z么呢Q从build image时的outputH口Q我每次都可以看到clean up目release目录的输出,看来我直接把文g复制到release目录是不行的Q因为在sysgen and build的过E中此文件夹会被清空Q自然我的test.txt也被清掉了。那该怎么办呢Q?<br />q里~少一个步骤,那就是要在^台设|中Q作一些配|,从而让Release目录在被清空以后能将目标文g从本地硬盘动态复制到release目录</p><p>修改配置以便拯文g到Release目录的主要步骤如下: <br />1 pb中从platform菜单选setting <br />2 在弹出对话框中Configuration一确保正,一般默认就是正的?<br />3 Custom Build Actions选项卡中的Build step下拉框,选择Pre-Make Image (有四个选项Q分别ؓPre-SysgenQPost-SysgenQPre-Make ImageQPost-Make ImageQ意思如其名) Q然后NewQ在弹出的Custom Build Action对话框中输入cM以下的语句: <br />copy <Path>\<File name> %_FLATRELEASEDIR%\<File name> </p><p>比如test.txt攑֜我电脑上的e盘根目录下,那么语句是这LQ?/p><p>copy E:\test.txt %_FLATRELEASEDIR%\test.txt <br /></p><p>加上q个步骤后,再按W二U方法就可以辑ֈ目的了?/p><img src ="http://www.shnenglu.com/milkyway/aggbug/17169.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/milkyway/" target="_blank">相思酸中有?/a> 2007-01-03 10:19 <a href="http://www.shnenglu.com/milkyway/articles/17169.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.shnenglu.com/" title="精品视频久久久久">精品视频久久久久</a> <div class="friend-links"> </div> </div> </footer> <a href="http://www.yyfeixiang.cn" target="_blank">avþþþþòվ </a>| <a href="http://www.vbnj.cn" target="_blank">þùƷһ</a>| <a href="http://www.zjuny.cn" target="_blank">ԭۺϾþô˾Ʒ</a>| <a href="http://www.gljqk.cn" target="_blank">Ʒþþþþþþþ</a>| <a href="http://www.jxfic.org.cn" target="_blank">ձձȾþþƷ</a>| <a href="http://www.668j.cn" target="_blank">þԭƷ</a>| <a href="http://www.szltw.cn" target="_blank">޹ƷۺϾþһ</a>| <a href="http://www.etxf.cn" target="_blank">ƷþþþӰԺɫ</a>| <a href="http://www.cqzmz.cn" target="_blank">ùƷӰ˾þ</a>| <a href="http://www.youxi011.cn" target="_blank">þ÷׾Ʒ</a>| <a href="http://www.fylmbd.cn" target="_blank">þƵ6</a>| <a href="http://www.co1txk.cn" target="_blank">99þùۺϾƷ鶹</a>| <a href="http://www.jxlbw.cn" target="_blank">Ӱ7777þþƷˬ</a>| <a href="http://www.r7831.cn" target="_blank">99þĻ</a>| <a href="http://www.upboss.cn" target="_blank">޾Ʒþþþþ</a>| <a href="http://www.pingpangq.cn" target="_blank">aëƬþѲ</a>| <a href="http://www.yt-tongyong.cn" target="_blank">ھƷþ</a>| <a href="http://www.ncysjz.cn" target="_blank">ŷ˾þþƷ</a>| <a href="http://www.jtm0513.cn" target="_blank">þþƷ99Ʒ</a>| <a href="http://www.semtmtw.cn" target="_blank">Ʒþþþþ</a>| <a href="http://www.bbdhtex.cn" target="_blank">þù</a>| <a href="http://www.3743.com.cn" target="_blank">˾Ʒþ޸岻 </a>| <a href="http://www.sd2sc.com.cn" target="_blank">þþۺ</a>| <a href="http://www.baidudianying.cn" target="_blank">˾Ʒһþ</a>| <a href="http://www.o33k.cn" target="_blank">Ʒ18þþ⺾</a>| <a href="http://www.wshoponlinet.cn" target="_blank">þݺҹҹ2014</a>| <a href="http://www.club-biz.cn" target="_blank">þùƷ</a>| <a href="http://www.qcqxzx.cn" target="_blank">þþþþһ</a>| <a href="http://www.ksszzyy.cn" target="_blank">þþþþþAv</a>| <a href="http://www.jhcplm.cn" target="_blank">˾þþAV츾ɫ</a>| <a href="http://www.ksjhyt.cn" target="_blank">Ʒþþþþþþ</a>| <a href="http://www.itsidekick.cn" target="_blank">þþþۺϹŷһ </a>| <a href="http://www.uzhp.cn" target="_blank">99þþƷһ </a>| <a href="http://www.bb657.cn" target="_blank">.Ʒþþ鶹Ʒ</a>| <a href="http://www.4neq.cn" target="_blank">þþþþþ</a>| <a href="http://www.lsjtht.cn" target="_blank">ŷɫ۾þþƷ</a>| <a href="http://www.uzxin.cn" target="_blank">þþƷþþþùۿ99ˮ</a>| <a href="http://www.odostudio.cn" target="_blank">һɫƵþվ</a>| <a href="http://www.vxe49.cn" target="_blank">þþŷղAV</a>| <a href="http://www.qhcl233.cn" target="_blank">91鶹Ʒ91þþ</a>| <a href="http://www.k2938.cn" target="_blank">þó˹Ʒ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>