﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-binghuo-随笔分类-驱动开发</title><link>http://www.cppblog.com/binghuo/category/9761.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 16 Mar 2009 21:46:38 GMT</lastBuildDate><pubDate>Mon, 16 Mar 2009 21:46:38 GMT</pubDate><ttl>60</ttl><item><title>PCI9052接口芯片的配置及驱动程序开发</title><link>http://www.cppblog.com/binghuo/archive/2009/03/12/76363.html</link><dc:creator>冰火</dc:creator><author>冰火</author><pubDate>Thu, 12 Mar 2009 11:46:00 GMT</pubDate><guid>http://www.cppblog.com/binghuo/archive/2009/03/12/76363.html</guid><wfw:comment>http://www.cppblog.com/binghuo/comments/76363.html</wfw:comment><comments>http://www.cppblog.com/binghuo/archive/2009/03/12/76363.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/binghuo/comments/commentRss/76363.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/binghuo/services/trackbacks/76363.html</trackback:ping><description><![CDATA[<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan" align=left><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">0 </span><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">引言<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">如果把<span lang=EN-US>PC</span>机作为控制系统的操作平台，<span lang=EN-US>PCI</span>总线作为一种先进的高性能<span lang=EN-US>32</span>／<span lang=EN-US>64</span>位局部总线正迅速取代原来的<span lang=EN-US>ISA</span>总线的主导地位，以用于高速外设，并成为微型计算机系统的主流系统，因而也成为工程开发人员用于工业控制的首选。为了缩短开发周期，一般都采用专用的接口器件。本文就是采用<span lang=EN-US>PLX</span>公司的<span lang=EN-US><a title=PCI9052货源和PDF资料 href="http://www.ic37.com/PCI9052-p.htm" target=_blank><span style="COLOR: #00007f; TEXT-DECORATION: none; mso-bidi-font-size: 12.0pt; text-underline: none">PCI9052</span></a></span>来把<span lang=EN-US>PCI</span>总线上的操作转换为对局部总线的操作，同时通过双口<span lang=EN-US>RAM</span>实现和下位机的存储转接。针对一般<span lang=EN-US>PCI</span>总线开发时由于软硬件分离使开发的软硬件不能很好结合的现象，本文结合实例介绍了应用程序并给出了如何通过<span lang=EN-US>DriverStudio</span>开发的<span lang=EN-US>PCI</span>设备驱动程序来访问<span lang=EN-US>PCI</span>设备卡硬件资源的具体程序。<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><strong><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">1 PCI</span></strong><strong><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">的配置空间及其配置</span></strong><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt"> <o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">PCI</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">总线支持存储器地址空间、<span lang=EN-US>I</span>／<span lang=EN-US>O</span>地址空间和配置空间等三个物理空间。其中，配置空间是<span lang=EN-US>PCI</span>总线所特有的一个空间，<span lang=EN-US>PCI</span>总线能实现即插即用的功能，正是通过它特有的配置空间来实现的。<span lang=EN-US>PCI</span>配置空间的大小为<span lang=EN-US>256</span>字节，分为头标区和设备有关区。直接影响设备特性的配置寄存器在头标区，其他部分则因设备而异。<span lang=EN-US>PCI</span>总线的配置空间通常与<span lang=EN-US>PCI</span>接口芯片相关。该配置空间包括一系列的<span lang=EN-US>PCI</span>配置寄存器。本文采用的<span lang=EN-US><a title=PCI9052货源和PDF资料 href="http://www.ic37.com/PCI9052-p.htm" target=_blank><span style="COLOR: #00007f; TEXT-DECORATION: none; mso-bidi-font-size: 12.0pt; text-underline: none">PCI9052</span></a></span>芯片的配置寄存器分为<span lang=EN-US>PCI</span>配置寄存器和局部配置寄存器，二者都可以由<span lang=EN-US>PCI</span>总线和串行<span lang=EN-US><a title=EEPROM货源和PDF资料 href="http://www.ic37.com/EEPROM-p.htm" target=_blank><span style="COLOR: #00007f; TEXT-DECORATION: none; mso-bidi-font-size: 12.0pt; text-underline: none">EEPROM</span></a></span>访问。<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">在<span lang=EN-US>PCI</span>配置寄存器中的设备<span lang=EN-US>ID</span>、制造商<span lang=EN-US>ID</span>、版本号、首区类代码、类别代码、指令寄存器和状态寄存器等寄存器在所有的<span lang=EN-US>PCI</span>设备中都必须实现，具体设置可参考文献<span lang=EN-US>[1]</span>。通常情况下，操作系统可使用这些寄存器的内容来决定该<span lang=EN-US>PCI</span>设备的加载其驱动程序。<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">PCI</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">总线最重要的功能之一是通过基地址寄存器和局部配置寄存器在地址空间重定位<span lang=EN-US>PCI</span>设备。系统上电时，通过上层应用软件能判断系统中存在那些设备，并建立协调的地址映射。所以，基地址寄存器和局部配置寄存器是实现驱动程序的关键。<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">PCI</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">配置寄存器提供有<span lang=EN-US>6</span>个基地址寄存器<span lang=EN-US>(BASE0</span>～<span lang=EN-US>BASE5)</span>这些基地址都是系统中的物理地址，其中<span lang=EN-US>BASE0</span>和<span lang=EN-US>BASE1</span>是用来访问局部配置寄存器的基地址，<span lang=EN-US>BASE0</span>是映射到内存的基地址，<span lang=EN-US>BASE1</span>是映射到<span lang=EN-US>I</span>／<span lang=EN-US>O</span>的基地址，可用于通过内存和<span lang=EN-US>I</span>／<span lang=EN-US>O</span>来访问局部配置寄存器。这两个基地址可固定用于<span lang=EN-US><a title=PCI9052货源和PDF资料 href="http://www.ic37.com/PCI9052-p.htm" target=_blank><span style="COLOR: #00007f; TEXT-DECORATION: none; mso-bidi-font-size: 12.0pt; text-underline: none">PCI9052</span></a></span>芯片的寄存器操作。<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">通过<span lang=EN-US>BASE2</span>～<span lang=EN-US>BASE5</span>四个空间最多可以访问局部端所接的<span lang=EN-US>4</span>个芯片，实现<span lang=EN-US>4</span>个局部地址空间<span lang=EN-US>(</span>局部空间<span lang=EN-US>0</span>～<span lang=EN-US>3)</span>的<span lang=EN-US>PCI</span>总线访问。<span lang=EN-US>PCI</span>总线对局部端所接芯片的局部地址映射是通过<span lang=EN-US>4</span>个寄存器组<span lang=EN-US>(PCI</span>基地址寄存器，局部范围寄存器，局部基地址寄存器，局部总线区域描述符<span lang=EN-US>)</span>来实现的。这个组定义了每个空间以及相应局部空间的特性。它们将局部端的芯片通过局部端地址<span lang=EN-US>(</span>在局部配置寄存器中设置<span lang=EN-US>)</span>翻译成<span lang=EN-US>PCI</span>总线地址，也就是将本地的芯片映射到系统的内存或<span lang=EN-US>I</span>／<span lang=EN-US>O</span>口。而片选信号寄存器则是用来选定这些局部端所接的芯片的。这样，用程序操作这一段内存<span lang=EN-US>(</span>或<span lang=EN-US>I</span>／<span lang=EN-US>O)</span>实际上就是对本地芯片的操作。其映射关系如图<span lang=EN-US>1</span>所示。这些寄存器的内容必须在芯片复位时通过串行<span lang=EN-US>E2PROM</span>进行加载，而正确配置<span lang=EN-US>E2PROM</span>的内容则是使用<span lang=EN-US><a title=PCI9052货源和PDF资料 href="http://www.ic37.com/PCI9052-p.htm" target=_blank><span style="COLOR: #00007f; TEXT-DECORATION: none; mso-bidi-font-size: 12.0pt; text-underline: none">PCI9052</span></a></span>的关键。<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">本设计选取<span lang=EN-US>LAS0(Local Address Space 0)</span>来访问局部端的双口<span lang=EN-US>RAM</span>芯片中的<span lang=EN-US>2 KB</span>寻址空间，与其有关的寄存器有四个：<span lang=EN-US>LAS0</span>范围寄存器、<span lang=EN-US>LAS0</span>局部基址寄存器、<span lang=EN-US>LAS0</span>局部总线区域描述符和片选<span lang=EN-US>0</span>基址寄存器。<span lang=EN-US>LAS0</span>范围寄存器规定了地址空间的大小。由于需要<span lang=EN-US>2 KB</span>的内存空间，而计算机预留了<span lang=EN-US>32 KB</span>空间<span lang=EN-US>(</span>即<span lang=EN-US>8000H)</span>，所以其寄存器值为<span lang=EN-US>0xFFFF8000H</span>，而类型则是不可预取的；<span lang=EN-US>LAS0</span>局部基地址寄存器定义了设备卡资源上所占用的基地址，它的最终目的是将这个基地址重新映射到<span lang=EN-US>PCI</span>地址空间。由于基地址必须是<span lang=EN-US>32KB</span>的整数倍，因此，为方便起见，可以将基地址定为<span lang=EN-US>00000000H</span>，又由于位<span lang=EN-US>0</span>为空间使能位，所以，寄存器的值为<span lang=EN-US>00000001H</span>；<span lang=EN-US>LAS0</span>局部总线区域描述符用来定义地址空间<span lang=EN-US>0</span>的具体工作特性。<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">该总线采用<span lang=EN-US>16</span>位总线宽度，工作方式定义为不使能突发和不预取，因此，该寄存器的数值初步确定为<span lang=EN-US>4043A1C0H</span>，最终的值则需要不断测试才能确定；片选<span lang=EN-US>0</span>基址寄存器使用<span lang=EN-US><a title=PCI9052货源和PDF资料 href="http://www.ic37.com/PCI9052-p.htm" target=_blank><span style="COLOR: #00007f; TEXT-DECORATION: none; mso-bidi-font-size: 12.0pt; text-underline: none">PCI9052</span></a></span>的<span lang=EN-US>CS0#</span>作为双口<span lang=EN-US>RAM</span>的片选信号，<span lang=EN-US>CS0#</span>片选信号的起始地址和地址范围由片选<span lang=EN-US>0</span>基址寄存器设置，局部总线的容量是<span lang=EN-US>2 KB</span>，第<span lang=EN-US>11</span>位为<span lang=EN-US>1</span>，基地址是该范围的<span lang=EN-US>16</span>倍，一般将倍数放置在范围位之后，所以寄存器值设置为<span lang=EN-US>0xO008401</span>。当从局部空间<span lang=EN-US>0</span>基址开始的<span lang=EN-US>2 KB</span>空间范围落在<span lang=EN-US>CS0</span>基地址寄存器所设置的范围内，<span lang=EN-US>CS0</span>端有效，这种方式可减少地址译码得到的片选逻辑。<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">用<span lang=EN-US>PLX9052</span>可将<span lang=EN-US>PCI</span>总线上的操作转换为对局部总线的操作，即通过<span lang=EN-US>LAD0</span>～<span lang=EN-US>LAD7</span>、<span lang=EN-US>RD</span>、<span lang=EN-US>WR</span>、<span lang=EN-US>CS</span>等对局部端芯片访问。如果系统分配给本卡的存储空间为<span lang=EN-US>FFFF0000H</span>～<span lang=EN-US>FFFF7FFFFH</span>。那么，当系统通过<span lang=EN-US>PCI</span>总线访问这个区域时，<span lang=EN-US>PLX9052</span>就会应答，并将其转换为局部地址<span lang=EN-US>0x0000H</span>～<span lang=EN-US>0x07FFH</span>，另外，<span lang=EN-US>PLX9052</span>自身也有一些内部寄存器，它们被自动映射到另一片内存区域，可通过<span lang=EN-US>PCI</span>总线直接访问。<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt"><a title=PCI9052货源和PDF资料 href="http://www.ic37.com/PCI9052-p.htm" target=_blank><span style="COLOR: #00007f; TEXT-DECORATION: none; mso-bidi-font-size: 12.0pt; text-underline: none">PCI9052</span></a></span><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">提供了两种类型的中断源<span lang=EN-US>(</span>硬件中断和软件中断<span lang=EN-US>)</span>。中断可通过<span lang=EN-US><a title=PCI9052货源和PDF资料 href="http://www.ic37.com/PCI9052-p.htm" target=_blank><span style="COLOR: #00007f; TEXT-DECORATION: none; mso-bidi-font-size: 12.0pt; text-underline: none">PCI9052</span></a></span>中断控制／状态寄存器来<span lang=EN-US>(INTCSR)</span>允许和禁止。<span lang=EN-US><a title=PCI9052货源和PDF资料 href="http://www.ic37.com/PCI9052-p.htm" target=_blank><span style="COLOR: #00007f; TEXT-DECORATION: none; mso-bidi-font-size: 12.0pt; text-underline: none">PCI9052</span></a></span>通过<span lang=EN-US>2</span>个局部中断引脚来实现硬件中断，它们支持边缘和电平触发中断，可以通过对<span lang=EN-US>INTCSR</span>寄存器的编程来实现局部中断，然后产生<span lang=EN-US>PCI</span>中断<span lang=EN-US>(INTA)</span>，并生成<span lang=EN-US>PCI</span>中断<span lang=EN-US>INTA#</span>方式。<span lang=EN-US><a title=PCI9052货源和PDF资料 href="http://www.ic37.com/PCI9052-p.htm" target=_blank><span style="COLOR: #00007f; TEXT-DECORATION: none; mso-bidi-font-size: 12.0pt; text-underline: none">PCI9052</span></a></span>可以软件方式产生中断，设计时只需要将<span lang=EN-US>INTCSR</span>寄存器的软件中断位设置为<span lang=EN-US>1</span>即可。<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><strong><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">2 </span></strong><strong><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">驱动程序的开发</span></strong><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt"> <o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">在开发<span lang=EN-US>PCI</span>板卡功能驱动程序之前，首先要明白所需的<span lang=EN-US>PCI</span>硬件资源，并针对设备卡的硬件资源来处理<span lang=EN-US>PCI</span>设备的内存、端口的读写，以及中断处理，从而实现<span lang=EN-US>PCI</span>设备功能。<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><strong><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">2.1 </span></strong><strong><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">驱动程序在操作系统体系结构中的位置</span></strong><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt"> <o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">操作系统结构可分为五层模型：<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">(1)</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">用户应用程序；<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">(2)IO</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">管理层；<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">(3)</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">驱动程序；<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">(4)HAL(</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">硬件抽象层<span lang=EN-US>)</span>；<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">(5)</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">硬件。<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">图<span lang=EN-US>2</span>给出了<span lang=EN-US>Windows2000</span>操作系统驱动程序开发者所关心的特征，一般情况下，软件要么在用户模式中执行，要么在内核模式下执行。从驱动开发的角度上看，<span lang=EN-US>WDM</span>模型为存在于<span lang=EN-US>Win-dows2000</span>系统中的驱动程序提供了一个参考框架。作为<span lang=EN-US>Windows2000</span>系统结构开发人员，由于操作系统为应用程序，而在驱动程序和硬件之间提供有系统服务接口和平台相关操作，因此，设计时只需要关注应用程序和设备驱动程序的开发。<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><strong><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">2.2 </span></strong><strong><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">设备资源</span></strong><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt"> <o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">PCI</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">设备的硬件资源分配与管理是驱动程序很重要的部分，设备的硬件资源包括内存空间、<span lang=EN-US>I</span>／<span lang=EN-US>O</span>空间和中断。由于<span lang=EN-US>PCI</span>总线为<span lang=EN-US>PnP</span>总线，<span lang=EN-US>PCI</span>设备的硬件资源是由<span lang=EN-US>PCI</span>配置机构动态分配给<span lang=EN-US>PCI</span>配置寄存器的，因此，驱动程序首先需要取得这些资源才能操作硬件。当<span lang=EN-US>PnP</span>管理器检测到<span lang=EN-US>PCI</span>设备时，系统就会发送<span lang=EN-US>IRP_MN_START_DEVICE</span>的<span lang=EN-US>IRP</span>给驱动程序，驱动程序调用<span lang=EN-US>OnStartDevice</span>以启动例程处理，并在启动例程里获取该<span lang=EN-US>IRP</span>栈，同时把它包含的系统分配给该设备的资源信息。<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">用<span lang=EN-US>DriverStudio</span>开发驱动程序时，应在<span lang=EN-US>Wizard</span>中设置好<span lang=EN-US>PCI</span>设备的资源。对于实际的<span lang=EN-US><a title=PCI9052货源和PDF资料 href="http://www.ic37.com/PCI9052-p.htm" target=_blank><span style="COLOR: #00007f; TEXT-DECORATION: none; mso-bidi-font-size: 12.0pt; text-underline: none">PCI9052</span></a></span>设备卡，其基地址寄存器<span lang=EN-US>0</span>和<span lang=EN-US>1</span>分别固定用于<span lang=EN-US><a title=PCI9052货源和PDF资料 href="http://www.ic37.com/PCI9052-p.htm" target=_blank><span style="COLOR: #00007f; TEXT-DECORATION: none; mso-bidi-font-size: 12.0pt; text-underline: none">PCI9052</span></a></span>局部寄存器的内存映射地址和<span lang=EN-US>I</span>／<span lang=EN-US>O</span>映射地址，基地址寄存器<span lang=EN-US>2</span>则用于设备卡的内存映射地址，并使用局部中断引脚来产生<span lang=EN-US>PCI</span>中断，以分别生成对应的<span lang=EN-US>KIoRange</span>类、<span lang=EN-US>KMemoryRange</span>类和<span lang=EN-US>KInterrupt</span>类。这些配置信息由配置管理器发送到<span lang=EN-US>OnStartDevice</span>中重载该成员函数，而开发者则不必再处理。在一般情况下，驱动程序无需再访问<span lang=EN-US>PCI</span>设备的配置空间，如果需要访问，则可通过类<span lang=EN-US>KPciConfiguration</span>，该类包含了通过向<span lang=EN-US>PCI</span>总线发送渎写配置空间的<span lang=EN-US>IRP</span>操作。也可定义类<span lang=EN-US>KRe-sourceAssignment</span>来获取<span lang=EN-US>PCI</span>的端口地址和中断号以及内存地址和大小，并把得到的资源放在用户自己定义的变量中。<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><strong><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">2.3 WDM</span></strong><strong><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">驱动程序对硬件资源的访问</span></strong><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt"> <o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">获取设备的硬件资源以后，就可以对硬件资源进行访问了。对硬件的访问一般包括<span lang=EN-US>I</span>／<span lang=EN-US>O</span>端口访问和内存访问，它们分别对应<span lang=EN-US>PCI</span>配置空间的<span lang=EN-US>I</span>／<span lang=EN-US>O</span>空间和内存空间。从图<span lang=EN-US>2</span>可以看出，当应用程序需要访问设备时，它就会调用<span lang=EN-US>Win32API</span>函数<span lang=EN-US>(</span>如<span lang=EN-US>ReadFile)</span>。<span lang=EN-US>Win32</span>子系统模块通过调用平台相关的系统服务接口实现该<span lang=EN-US>API</span>，而平台相关的系统服务则调用内核模式来支持例程。即在调用<span lang=EN-US>ReadFile</span>函数时，首先到达系统的人口点，然后调用系统服务接口，最后由系统调用内核模式的服务例程。执行时首先检查传递给它们的参数，然后创建一个<span lang=EN-US>&#8220;I</span>／<span lang=EN-US>O</span>请求包<span lang=EN-US>(IRP)&#8221;</span>的数据结构，并把这个数据结构送到某个驱动程序的入口点执行<span lang=EN-US>IRP</span>设备驱动程序，最后再访问硬件。对于<span lang=EN-US>PIO</span>方式的设备，一个<span lang=EN-US>IRP_MJ_READ</span>操作将直接读取设备的端口或设备的内存寄存器。一般会使用硬件抽象层<span lang=EN-US>(HAL)</span>来访问硬件。<span lang=EN-US>IRP</span>贯穿于驱动程序之间，它在应用程序、驱动程序和设备之间起着桥梁作用，可称之为内核态的<span lang=EN-US>&#8220;</span>消息<span lang=EN-US>&#8221;</span>。驱动程序完成一个<span lang=EN-US>I</span>／<span lang=EN-US>O</span>操作后，可通过调用一个特殊内核模式服务例程来完成该<span lang=EN-US>IRP</span>，完成操作时再处理<span lang=EN-US>IRP</span>的最后工作，以它使等待的应用程序恢复运行。<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">用<span lang=EN-US>DriverStudio</span>开发驱动程序时，可根据配置声明<span lang=EN-US>KIoRange</span>类、<span lang=EN-US>KMemoryRange</span>类和<span lang=EN-US>KInterrupt</span>类来实现对内存空间、<span lang=EN-US>I</span>／<span lang=EN-US>O</span>空间、中断的操作。在本例中，基地址寄存器<span lang=EN-US>0</span>和<span lang=EN-US>1</span>固定用于<span lang=EN-US><a title=PCI9052货源和PDF资料 href="http://www.ic37.com/PCI9052-p.htm" target=_blank><span style="COLOR: #00007f; TEXT-DECORATION: none; mso-bidi-font-size: 12.0pt; text-underline: none">PCI9052</span></a></span>芯片的操作寄存器内存映射地址和<span lang=EN-US>I</span>／<span lang=EN-US>O</span>映射地址，基地址寄存器<span lang=EN-US>2</span>则用于双口<span lang=EN-US>RAM</span>的内存映射。通过一个外部引脚即可产生中断。标识两个<span lang=EN-US>KMem-oryRange</span>类实例、一个<span lang=EN-US>KIoRange</span>类实例和一个<span lang=EN-US>KInterrupt</span>类实例的具体实现细节如下：<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">(1) I</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">／<span lang=EN-US>O</span>端口的访问<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">I</span><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">／<span lang=EN-US>O</span>端口的访问流程如图<span lang=EN-US>3</span>所示，应用程序通过<span lang=EN-US>API</span>函数<span lang=EN-US>DeviceIoControl</span>的调用，并调用驱动程序的分发例程<span lang=EN-US>DeviceControl</span>，同时通过<span lang=EN-US>KIoRange</span>类来实现对<span lang=EN-US>I</span>／<span lang=EN-US>O</span>映射空间的访问。需要注意的是，当<span lang=EN-US>DeviceloControl</span>异步调用的时候，必须在驱动程序中添加取消例程，并在<span lang=EN-US>DeviceControl</span>例程中阻止一个应用程序对其的多次调用。<span lang=EN-US>KIoRange</span>类的成员函数<span lang=EN-US>outb</span>、<span lang=EN-US>inb</span>、<span lang=EN-US>outw</span>、<span lang=EN-US>inw</span>、<span lang=EN-US>ind</span>、<span lang=EN-US>outd</span>可分别用于从端口读或写一个字节、字和双字数据。在<span lang=EN-US>WDM</span>中，对于<span lang=EN-US>I</span>／<span lang=EN-US>O</span>端口，系统可将其看成寄存器，一般用于数字传输量比较小的地方。在对<span lang=EN-US>PCI</span>设备的访问中，<span lang=EN-US>I</span>／<span lang=EN-US>O</span>端口的访问通常比较频繁。<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">(2) </span><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">内存的访问<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">在基于<span lang=EN-US>DriverStudio</span>开发的驱动程序中，向存储器空间读写大量数据一般选用<span lang=EN-US>Write</span>／<span lang=EN-US>Read</span>函数，但对于一个实际存在的物理设备的访问，在某一时刻只能进行一个操作，因而在访问内存对象的时候，一般都要求一个<span lang=EN-US>IRP</span>排队的队列，可通过设备类的成员函数<span lang=EN-US>QueueIrp</span>将<span lang=EN-US>IRP</span>插入队列。<span lang=EN-US>DriverWorks</span>提供有<span lang=EN-US>KDeviceQueue</span>类，其成员函数<span lang=EN-US>StartIo</span>用于处理设备对象的<span lang=EN-US>IRP</span>队列。具体的操作是通过<span lang=EN-US>KMemoryRange</span>类来实现对设备内存映射空间的访问。其访问流程见图<span lang=EN-US>4</span>所示。需要注意的是，当<span lang=EN-US>IRP</span>队列为空时，调用<span lang=EN-US>QueueIrp</span>时，系统将同步调用<span lang=EN-US>StartIo</span>函数。<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">(3) </span><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">中断处理<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">驱动程序的中断处理编程涉及到内核机制比较多的一种驱动程序，因而相对复杂。首先用中断服务程序提升系统的<span lang=EN-US>IRQL</span>，但不能进行大多数有用的内核调用。另外，提升<span lang=EN-US>IRQL</span>运行代码需要尽可能快地运行。所以，中断处理一般和在<span lang=EN-US>DIS-PATCH_LEVEL</span>级运行的延迟调用<span lang=EN-US>(DPC)</span>例程相配合可解决以上两个问题。在<span lang=EN-US>DriverWorks</span>中，通常通过<span lang=EN-US>KInterrupt</span>类和<span lang=EN-US>KDeferredCall</span>类来实现，并通过向导来在中断服务例程和<span lang=EN-US>DPC</span>中增加功能代码。<span lang=EN-US>KDeferredCall</span>类封装有<span lang=EN-US>DPC</span>的操作。<span lang=EN-US>KInter-rupt</span>类用于实现硬件中断的处理，其成员函数包括中断初始化，以及将一个中断服务例程连接到另一个中断和解除其连接等。在中断服务例程中把<span lang=EN-US>IRP</span>交给<span lang=EN-US>DPC</span>例程，可在<span lang=EN-US>DPC</span>处理完后结束该<span lang=EN-US>IRP</span>。需要注意的是，中断服务例程不是<span lang=EN-US>KInter-rupt</span>类的成员函数，它的主要作用是减少中断延迟时间。<span lang=EN-US> <o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; WORD-BREAK: break-all; TEXT-INDENT: 24pt; LINE-HEIGHT: 18pt; TEXT-ALIGN: left; mso-pagination: widow-orphan; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto" align=left><strong><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">3 </span></strong><strong><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">结束语</span></strong><span lang=EN-US style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt"> <o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span style="FONT-FAMILY: 宋体; mso-bidi-font-size: 10.5pt; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt">本文主要从访问设备硬件资源的角度介绍了<span lang=EN-US>PCI</span>配置空间的配置和驱动程序的开发方法。利用该方法可对<span lang=EN-US>PCI</span>板卡的配置空间和所需的硬件资源进行正确设置，然后通过<span lang=EN-US>DriverStudio</span>的驱动程序向导生成工具在程序框架里添加适当的代码，最后借助于<span lang=EN-US>DriverStudio</span>开发包提供的调试工具<span lang=EN-US>SoftICE</span>和<span lang=EN-US>DriverMonitor</span>以及由<span lang=EN-US>Wizard</span>产生的控制台应用程序，来快速开发出基于<span lang=EN-US>PCI</span>总线的设备驱动程序。</span></p>
<img src ="http://www.cppblog.com/binghuo/aggbug/76363.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/binghuo/" target="_blank">冰火</a> 2009-03-12 19:46 <a href="http://www.cppblog.com/binghuo/archive/2009/03/12/76363.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>驱动版Hello World</title><link>http://www.cppblog.com/binghuo/archive/2009/03/10/76091.html</link><dc:creator>冰火</dc:creator><author>冰火</author><pubDate>Tue, 10 Mar 2009 03:04:00 GMT</pubDate><guid>http://www.cppblog.com/binghuo/archive/2009/03/10/76091.html</guid><description><![CDATA[<p>我们学习程序设计，都是从&#8220;Hello World&#8221;开始的，驱动程序也不例外，今天我就写一个驱动版的&#8220;Hello World&#8221;来热热身，目的希望大家能对驱动程序的基本框架有所了解。</p>
<p>驱动程序分为2类，一个是Kernel模式驱动，另一个是Windows模式驱动，2种模式本质是相同，但细节不同，本文介绍的是内核模式驱动和驱动程序的安装、使用。</p>
<p>驱动程序同普通的EXE，DLL一样，都属于PE文件，而且都有一个入口函数。但EXE中，入口函数是main()/WinMain()和Unicode的wmain()/wWinmain()，DLL的入口函数则可有可无，它是DllMain()。驱动程序也有入口函数，而且是必须的，它是DriverEntry()，再次提示，它是必须的，因为I/O管理器会首先调用驱动程序的DriverEntry()，它的作用就像DllMain()--完成一些初始化工作。DriverEntry()一共有2个参数：1PDRIVER_OBJECT DriverObject，指向驱动程序对象的指针，我们操作驱动程序，全靠它，它是由I/O管理器传递进来的；2）PUNICODE_STRING RegistryPath，驱动程序的服务主键，这个参数的使用并不多，但要注意，在DriverEntry()返回后，它可能会消失，所以如果需要使用，记住先要保存下来。DriverEntry()的返回一个NTSTATUS值，它是一个ULONG值，具体的定义，请参见DDK中的NTSTATUS.H头文件，里边有详细的定义。</p>
<p>既然要写驱动版的&#8220;Hello World&#8221;，就需要确定如何来与驱动程序通信，常用的共享内存，共享事件，IOCTL宏，或者直接用ReadFile()或WriteFile()进行读写，在本文里我就采用一种简单的、但又很常用的IOCTL宏，它依赖的IRP派遣例程是IRP_MJ_DEVICE_CONTROL，Win32程序使用DeviceIoControl()与驱动进行通信，根据不同的IOCTL宏，输出不同的调试信息。为了简便，我并没有使用ReadFile()将信息读出来，而是直接用DbgPrint()输出，所以需要使用DbgView查看，其他调试工具也可以。PS：偷懒！</p>
<p>驱动程序与I/O管理器通信，使用的是IRP，即I/O请求包。IRP分为2部分：1）IRP首部；2）IRP堆栈。IRP首部信息如下：</p>
<p>IRP首部：</p>
<p>IO_STATUS_BLOCK IoStatus&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 包含I/O请求的状态 <br>PVOID AssociatedIrp.SystemBuffer 如果执行缓冲区I/O，这个指针指向系统缓冲区 <br>PMDL MdlAddress&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果直接I/O，这个指针指向用户缓冲区的存储器描述符表 <br>PVOID UserBuffer&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; I/O缓冲区的用户空间地址</p>
<p>IRP堆栈：</p>
<p>UCHAR MajorFunction&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 指示IRP_MJ_XXX派遣例程 <br>UCHAR MinorFunction&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 同上，一般文件系统和SCSI驱动程序使用它 <br>&nbsp;<br>union Parameters&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MajorFunction的联合类型 <br>{ <br>struct Read&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IRP_MJ_READ的参数 <br>ULONG Length <br>ULONG Key <br>LARGE_INTEGER ByteOffset <br>&nbsp;<br>struct Write&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IRP_MJ_WRITE的参数 <br>ULONG Length <br>ULONG Key <br>LARGE_INTEGER ByteOffset <br>&nbsp;<br>struct DeviceIoControl&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IRP_MJ_DEVICE_CONTROL参数<br>ULONG OutputBufferLength <br>ULONG InputBufferLength <br>ULONG IoControlCode <br>PVOID Type3InputBuffer <br>}&nbsp; <br>PDEVICE_OBJECT DeviceObject&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 请求的目标设备对象的指针 <br>PFILE_OBJECT FileObject&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 请求的目标文件对象的指针，如果有的话</p>
<p>操作IRP。对于不同的IRP函数，操作也是不同的：有的只操作IRP首部；有的只操作IRP堆栈；还有操作IRP整体，下面是一些常用的函数：</p>
<p>IRP整体：</p>
<p>&nbsp;&nbsp;&nbsp; 名称&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 描述&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 调用者<br>IoStartPacket&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 发送IRP到Start I/O例程&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dispatch <br>IoCompleteRequest&nbsp;&nbsp;&nbsp;&nbsp; 表示所有的处理完成&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DpcForIsr <br>IoStartNextPacket&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 发送下一个IRP到Start I/O例程&nbsp;&nbsp;&nbsp;&nbsp; DpcForIsr <br>IoCallDriver&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 发送IRP请求&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dispatch <br>IoAllocateIrp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 请求另外的IRP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dispatch <br>IoFreeIrp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 释放驱动程序分配的IRP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; I/O Completion</p>
<p>IRP堆栈：</p>
<p>&nbsp;&nbsp;&nbsp; 名称&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 描述&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 调用者<br>IoGetCurrentIrpStackLocation&nbsp;&nbsp; 得到调用者堆栈的指针&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dispatch <br>IoMarkIrpPending&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 为进一步的处理标记调用者I/O堆栈&nbsp; Dispatch <br>IoGetNextIrpStackLocation 得到下一个驱动程序的I/O堆栈的指针 Dispatch <br>IoSetNextIrpStackLocation&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将I/O堆栈指针压入堆栈&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Dispatc</p>
<p>在驱动程序，IRP派遣例程起着很重要的作用，每个IRP派遣例程，几乎都有对应的Win32函数，下面是几个常用的：</p>
<p>IRP派遣例程：</p>
<p>&nbsp;&nbsp;&nbsp; 名称&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 描述&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 调用者<br>IRP_MJ_CREATE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 请求一个句柄&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CreateFile <br>IRP_MJ_CLEANUP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在关闭句柄时取消悬挂的IRP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CloseHandle <br>IRP_MJ_CLOSE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 关闭句柄&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CloseHandle <br>IRP_MJ_READ&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 从设备得到数据&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ReadFile <br>IRP_MJ_WRITE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 传送数据到设备&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WriteFile <br>IRP_MJ_DEVICE_CONTROL&nbsp;&nbsp;&nbsp; 控制操作（利用IOCTL宏）&nbsp;&nbsp; DeviceIoControl <br>IRP_MJ_INTERNAL_DEVICE_CONTROL&nbsp; 控制操作(只能被内核调用)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; N/A <br>IRP_MJ_QUERY_INFORMATION&nbsp;&nbsp;&nbsp; 得到文件的长度&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GetFileSize <br>IRP_MJ_SET_INFORMATION&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 设置文件的长度&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SetFileSize <br>IRP_MJ_FLUSH_BUFFERS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 写输出缓冲区或者丢弃输入缓冲区&nbsp; FlushFileBuffers FlushConsoleInputBuffer PurgeComm <br>IRP_MJ_SHUTDOWN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 系统关闭&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InitiateSystemShutdown</p>
<p>====================================================================================================</p>
<p>下面开始写我们的驱动版的&#8220;Hello World&#8221;，程序很简单，先介绍一下流程：</p>
<p>1，调用IoCreateDevice()创建一个设备，并返回一个设备对象。<br>2，调用IoCreateSynbolicLink()创建一个符号连接，使Win32程序可以使用驱动程序<br>3，设置IRP_MJ_DEVICE_CONTROL派遣例程HelloWorldDispatch()和卸载例程HelloWorldUnLoad()。</p>
<p>如果Win32程序使用DeviceIoControl()，则执行HelloWorldDispatch()函数<br>4，调用IoGetCurrentIrpStackLocation()得到当前调用者的IRP指针<br>5，取得IO控制代码，完成后使用IoCompleteRequest()完成IRP操作</p>
<p>如果使用ControlService()停止驱动程序，则执行HelloWorldUnLoad()函数<br>4，调用IoDeleteSymbolicLink()删除符号连接<br>5，调用IoDeleteDevice()删除已建立的设备</p>
<p>驱动入口DriverEntry()</p>
<p>//创建设备<br>IoCreateDevice(DriverObject,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //驱动程序对象<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //扩展设备的大小，由于不需要，所以置0<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;DeviceNameString,&nbsp;&nbsp; //设备名称<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FILE_DEVICE_UNKNOWN, //设备类型<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //指示设备允许的操作<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FALSE,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //如果为TRUE，表示只能有一个线程使用该设备，为FALSE，则没有限制<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;lpDeviceObject);&nbsp;&nbsp;&nbsp; //返回的设备对象</p>
<p>//创建符号连接<br>IoCreateSymbolicLink(&amp;DeviceLinkString,&nbsp;&nbsp; //存放符号连接的UNICODE_STRING<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;DeviceNameString);&nbsp; //设备名称</p>
<p>//派遣例程和卸载例程<br>DriverObject-&gt;MajorFunction[IRP_MJ_DEVICE_CONTROL]=HelloWorldDispatch;吧<br>DriverObject-&gt;DriverUnload=HelloWorldUnLoad;</p>
<p>IRP派遣例程HelloWorldDispatch()</p>
<p>IrpStack=IoGetCurrentIrpStackLocation(pIrp);&nbsp;&nbsp; //得到当前调用者的IRP堆栈</p>
<p>//获取IO控制代码，并执行指定操作，这里只是DbgPrint()<br>IoControlCodes=IrpStack-&gt;Parameters.DeviceIoControl.IoControlCode;<br>switch (IoControlCodes)&nbsp; {<br>......</p>
<p>IoCompleteRequest(pIrp,IO_NO_INCREMENT);&nbsp;&nbsp; //完成IRP操作</p>
<p>卸载例程HelloWorldUnLoad()</p>
<p>//删除符号连接和设备<br>IoDeleteSymbolicLink(&amp;DeviceLinkString);<br>IoDeleteDevice(DriverObject-&gt;DeviceObject);</p>
<p>====================================================================================================完整代码：</p>
<p>#ifndef __HELLOWORLD_C__<br>#define __HELLOWORLD_C__</p>
<p>#define DEBUGMSG</p>
<p>#include "HelloWorld.h"</p>
<p>//驱动入口<br>NTSTATUS DriverEntry (IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)<br>{<br>&nbsp;&nbsp;&nbsp; NTSTATUS ntStatus=STATUS_SUCCESS;<br>&nbsp;&nbsp;&nbsp; PDEVICE_OBJECT lpDeviceObject=NULL;&nbsp;&nbsp; //指向设备对象的指针<br>&nbsp;&nbsp;&nbsp; UNICODE_STRING DeviceNameString;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //设备名称<br>&nbsp;&nbsp;&nbsp; UNICODE_STRING DeviceLinkString;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //符号连接</p>
<p>&nbsp;&nbsp;&nbsp; //调试信息<br>&nbsp;&nbsp;&nbsp; #ifdef DEBUGMSG<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DbgPrint("Starting DriverEntry()\n");<br>&nbsp;&nbsp;&nbsp; #endif</p>
<p>&nbsp;&nbsp;&nbsp; RtlInitUnicodeString(&amp;DeviceNameString,NT_DEVICE_NAME);&nbsp; //初始化Unicode字符串</p>
<p>&nbsp;&nbsp;&nbsp; //创建设备<br>&nbsp;&nbsp;&nbsp; ntStatus=IoCreateDevice(DriverObject,0,&amp;DeviceNameString,FILE_DEVICE_UNKNOWN,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0,FALSE,&amp;lpDeviceObject);</p>
<p>&nbsp;&nbsp;&nbsp; //使用NT_SUCCESS宏检测函数调用是否成功<br>&nbsp;&nbsp;&nbsp; if (!NT_SUCCESS(ntStatus))<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #ifdef DEBUGMSG<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DbgPrint("Error IoCreateDevice()\n");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #endif<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto Error;<br>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; RtlInitUnicodeString(&amp;DeviceLinkString,DOS_DEVICE_NAME);</p>
<p>&nbsp;&nbsp;&nbsp; //创建符号连接<br>&nbsp;&nbsp;&nbsp; ntStatus=IoCreateSymbolicLink(&amp;DeviceLinkString,&amp;DeviceNameString);</p>
<p>&nbsp;&nbsp;&nbsp; if (!NT_SUCCESS(ntStatus))<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #ifdef DEBUGMSG<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DbgPrint("Error IoCreateSymbolicLink()\n");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #endif<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto Error;<br>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; //设置IRP派遣例程和卸载例程<br>&nbsp;&nbsp;&nbsp; DriverObject-&gt;MajorFunction[IRP_MJ_CREATE]=//HelloWorldDispatch;<br>&nbsp;&nbsp;&nbsp; DriverObject-&gt;MajorFunction[IRP_MJ_CLOSE]=//HelloWorldDispatch;<br>&nbsp;&nbsp;&nbsp; DriverObject-&gt;MajorFunction[IRP_MJ_DEVICE_CONTROL]=HelloWorldDispatch;<br>&nbsp;&nbsp;&nbsp; DriverObject-&gt;DriverUnload=HelloWorldUnLoad;</p>
<p>&nbsp;&nbsp;&nbsp; return ntStatus;</p>
<p>&nbsp;&nbsp;&nbsp; Error:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #ifdef DEBUGMSG<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DbgPrint("Error DriverEntry()\n");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #endif</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ntStatus;<br>}</p>
<p>NTSTATUS HelloWorldDispatch (IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp)<br>{<br>&nbsp;&nbsp;&nbsp; NTSTATUS ntStatus=STATUS_SUCCESS;<br>&nbsp;&nbsp;&nbsp; ULONG IoControlCodes=0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //I/O控制代码<br>&nbsp;&nbsp;&nbsp; PIO_STACK_LOCATION IrpStack=NULL;&nbsp;&nbsp; //IRP堆栈</p>
<p>&nbsp;&nbsp;&nbsp; //设置IRP状态<br>&nbsp;&nbsp;&nbsp; pIrp-&gt;IoStatus.Status=STATUS_SUCCESS;<br>&nbsp;&nbsp;&nbsp; pIrp-&gt;IoStatus.Information=0;</p>
<p>&nbsp;&nbsp;&nbsp; #ifdef DEBUGMSG<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DbgPrint("Starting HelloWorldDispatch()\n");<br>&nbsp;&nbsp;&nbsp; #endif</p>
<p>&nbsp;&nbsp;&nbsp; IrpStack=IoGetCurrentIrpStackLocation(pIrp);&nbsp;&nbsp;&nbsp; //得到当前调用者的IRP</p>
<p>&nbsp;&nbsp;&nbsp; switch (IrpStack-&gt;MajorFunction)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case IRP_MJ_CREATE:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #ifdef DEBUGMSG<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DbgPrint("IRP_MJ_CREATE\n");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #endif<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case IRP_MJ_CLOSE:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #ifdef DEBUGMSG<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DbgPrint("IRP_MJ_CLOSE\n");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #endif<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case IRP_MJ_DEVICE_CONTROL:</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #ifdef DEBUGMSG<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DbgPrint("IRP_MJ_DEVICE_CONTROL\n");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #endif</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //取得I/O控制代码<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IoControlCodes=IrpStack-&gt;Parameters.DeviceIoControl.IoControlCode;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; switch (IoControlCodes)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //启动<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case START_HELLPWORLD:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DbgPrint("Starting \"Hello World\"\n");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; break;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //停止<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case STOP_HELLPWORLD:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DbgPrint("Stoping \"Hello World\"\n");<br>&nbsp;&nbsp;% </p>
<img src ="http://www.cppblog.com/binghuo/aggbug/76091.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/binghuo/" target="_blank">冰火</a> 2009-03-10 11:04 <a href="http://www.cppblog.com/binghuo/archive/2009/03/10/76091.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SOURCES文件详解 </title><link>http://www.cppblog.com/binghuo/archive/2009/03/10/76079.html</link><dc:creator>冰火</dc:creator><author>冰火</author><pubDate>Tue, 10 Mar 2009 01:00:00 GMT</pubDate><guid>http://www.cppblog.com/binghuo/archive/2009/03/10/76079.html</guid><wfw:comment>http://www.cppblog.com/binghuo/comments/76079.html</wfw:comment><comments>http://www.cppblog.com/binghuo/archive/2009/03/10/76079.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/binghuo/comments/commentRss/76079.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/binghuo/services/trackbacks/76079.html</trackback:ping><description><![CDATA[<p class=MsoNormal><span lang=EN-US>SOURCES</span><span style="FONT-FAMILY: 宋体">文件是</span><span lang=EN-US>WINCE</span><span style="FONT-FAMILY: 宋体">底层开发中最重要的文件之一</span><span lang=EN-US>,</span><span style="FONT-FAMILY: 宋体">主要的配置项如下</span><span lang=EN-US>:</span></p>
<p class=MsoNormal><span lang=EN-US><o:p></o:p></span></p>
<p class=MsoNormal><span lang=EN-US><o:p></o:p>TARGETNAME,</span><span style="FONT-FAMILY: 宋体">定义模块名称</span><span lang=EN-US>.<br>TARGETTYPE,</span><span style="FONT-FAMILY: 宋体">模块的种类</span><span lang=EN-US>,</span><span style="FONT-FAMILY: 宋体">可以是</span><span lang=EN-US>DYNLINK, LIBRARY,EXE.<br></span><span style="FONT-FAMILY: 宋体">如果</span><span lang=EN-US>TARGETTYPE</span><span style="FONT-FAMILY: 宋体">是</span><span lang=EN-US>DLL,</span><span style="FONT-FAMILY: 宋体">则可以定义</span><span lang=EN-US>DLLENTRY,</span><span style="FONT-FAMILY: 宋体">将</span><span lang=EN-US>Dll</span><span style="FONT-FAMILY: 宋体">入口定义成别的不是</span><span lang=EN-US>DLLMain</span><span style="FONT-FAMILY: 宋体">的函数</span><span lang=EN-US>,</span><span style="FONT-FAMILY: 宋体">如果</span><span lang=EN-US>DLL</span><span style="FONT-FAMILY: 宋体">的入口是</span><span lang=EN-US>DllMain</span><span style="FONT-FAMILY: 宋体">，则不需要别的定义。</span><span lang=EN-US><br></span><span style="FONT-FAMILY: 宋体">如果</span><span lang=EN-US>TARGETTYPE</span><span style="FONT-FAMILY: 宋体">是</span><span lang=EN-US>EXE,</span><span style="FONT-FAMILY: 宋体">则可以定义</span><span lang=EN-US>EXEENTRY,</span><span style="FONT-FAMILY: 宋体">用于指定</span><span lang=EN-US>EXE</span><span style="FONT-FAMILY: 宋体">的入口函数</span><span lang=EN-US>. </span></p>
<p class=MsoNormal><span style="FONT-FAMILY: 宋体">如果</span><span lang=EN-US>TARGETTYPE</span><span style="FONT-FAMILY: 宋体">是</span><span lang=EN-US>LIBRARY,</span><span style="FONT-FAMILY: 宋体">则不需要定义入口函数。</span></p>
<p class=MsoNormal><span lang=EN-US><o:p></o:p><br>INCLUDES</span><span style="FONT-FAMILY: 宋体">，如果一个模块需要使用非标准路径下的头文件时</span><span lang=EN-US>,</span><span style="FONT-FAMILY: 宋体">需要定义</span><span lang=EN-US>INCLUDES,</span><span style="FONT-FAMILY: 宋体">用于包含更多的头文件路径</span><span lang=EN-US>,</span><span style="FONT-FAMILY: 宋体">用法如下</span><span lang=EN-US>:<br><br>INCLUDES=$(INCLUDES);\new directory\...,</span><span style="FONT-FAMILY: 宋体">注意定义新的</span><span lang=EN-US>INCLUDES</span><span style="FONT-FAMILY: 宋体">时</span><span lang=EN-US>,</span><span style="FONT-FAMILY: 宋体">需要包含</span><span lang=EN-US>INCLUDES</span><span style="FONT-FAMILY: 宋体">原来的值，否则就需要包含所有可能的目录。</span><span lang=EN-US><br><br>TARGETLIBS,SOURCELIBS</span><span style="FONT-FAMILY: 宋体">用于定义该模块需要链接哪些库文件</span><span lang=EN-US>.</span></p>
<p class=MsoNormal><span lang=EN-US><o:p></o:p><br>TARGETLIBS</span><span style="FONT-FAMILY: 宋体">，如果一个库以</span><span lang=EN-US>DLL</span><span style="FONT-FAMILY: 宋体">的形式提供给调用者，就需要用</span><span lang=EN-US>TARGETLIBS</span><span style="FONT-FAMILY: 宋体">，它只链接一个函数地址，系统执行时会将被链接的库加载。比如</span><span lang=EN-US>coredll.lib</span><span style="FONT-FAMILY: 宋体">就是这样的库文件。即动态链接。</span></p>
<p class=MsoNormal><span lang=EN-US>SOURCELIBS</span><span style="FONT-FAMILY: 宋体">，将库中的函数实体链接进来。即静态链接，用到的函数会在我们的文件中形成一份拷贝。</span></p>
<p class=MsoNormal><span lang=EN-US><o:p></o:p></span><br><span style="FONT-FAMILY: 宋体">注意，内核这个执行文件是没有</span><span lang=EN-US>TARGETLIBS</span><span style="FONT-FAMILY: 宋体">的，</span><span lang=EN-US>GIISR.DLL</span><span style="FONT-FAMILY: 宋体">也不能有</span><span lang=EN-US>TARGETLIBS</span><span style="FONT-FAMILY: 宋体">。</span></p>
<p class=MsoNormal><span lang=EN-US><br>WINCECOD,</span><span style="FONT-FAMILY: 宋体">如果将其定义为</span><span lang=EN-US>1,</span><span style="FONT-FAMILY: 宋体">则编译器会为每一个文件生成</span><span lang=EN-US>.cod</span><span style="FONT-FAMILY: 宋体">文件</span><span lang=EN-US>,</span><span style="FONT-FAMILY: 宋体">它是一个汇编文件，调试时查看汇编代码也是一种很好的办法。</span><span lang=EN-US><br><br>SOURCES,</span><span style="FONT-FAMILY: 宋体">定义该模块需要哪些源文件</span><span lang=EN-US>.</span></p>
<img src ="http://www.cppblog.com/binghuo/aggbug/76079.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/binghuo/" target="_blank">冰火</a> 2009-03-10 09:00 <a href="http://www.cppblog.com/binghuo/archive/2009/03/10/76079.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用I/O命令访问PCI总线设备配置空间</title><link>http://www.cppblog.com/binghuo/archive/2009/03/10/76077.html</link><dc:creator>冰火</dc:creator><author>冰火</author><pubDate>Tue, 10 Mar 2009 00:52:00 GMT</pubDate><guid>http://www.cppblog.com/binghuo/archive/2009/03/10/76077.html</guid><wfw:comment>http://www.cppblog.com/binghuo/comments/76077.html</wfw:comment><comments>http://www.cppblog.com/binghuo/archive/2009/03/10/76077.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/binghuo/comments/commentRss/76077.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/binghuo/services/trackbacks/76077.html</trackback:ping><description><![CDATA[<font size=2><strong>关键词</strong>：PCI总线 配置空间 操作系统<br>转自：</font><a href="http://topdzh.byethost4.com/viewthread.php?tid=48&amp;extra=page%3D1"><u><font color=#0000ff size=2>http://topdzh.byethost4.com/viewthread.php?tid=48&amp;extra=page%3D1</font></u></a><br><br><font size=2>PCI总线推出以来，以其独有的特性受到众多厂商的青睐，已经成为计算机扩展总线的主流。目前，国内的许多技术人员已经具备开发PCI总线接口设备的能 力。但是PCI总线的编程技术，也就是对PCI总线设备的操作技术，一直是一件让技术人员感到头疼的事情。PCI总线编程的核心技术是对相应板卡配置空间 的理解和访问。一般软件编程人员基于对硬件设备原理的生疏，很难理解并操作配置空间，希望硬件开发人员直接告诉他们怎样操作；而PCI总线硬件开发人员虽 深刻地理解了其意义，在没有太多编程经验地前提下，也难于轻易地操作PCI板卡。结果大多是硬件技术人员花费大量时间和精力去学习DDK、 WINDRVER等驱动程序开发软件。<br><br>作者在开发PCI总线接口设备时，经过对PCI总线协议的深入研究，从协议本身的角度出发，找到一种方面而快捷的PCI配置空间操作方法，只使用简单的 I/O命令即可找到特定的PCI总线设备并对其所有的配置空间进行读写操作。一旦读得其配置空间的内容，即可中得到担任系统对该PCI总线设备的资源分 配。<br><br>1 PCI总线配置空间及配置机制<br><br>为避免各PCI设备在资源的占用上发生冲突，PCI总线采用即插即用协议。即在系统建立时由操作系统按照各设备的要求统一分配资源，资源分配的信息由系统 写入各PCI设备的配置空间寄存器，并在操作系统内部备份。各PCI设备有其独自的配置空间，设计者通过对积压设备（或插槽）的ISDEL引脚的驱动区分 不同设备的配置空间。配置空间的前64个字节称为配置空间的预定自区，它对每个设备都具有相同的定义且必须被支持；共后的空间称为设备关联区，由设备制造 商根据需要定义。与编程有关的配置空间信息主要有：<br><br>（1）设备号（Device ID）及销售商号（Vendor ID），配置空间偏移量为00h，用于对各PCI设备的区分和查找。为了保证其唯一性，Vendor ID应当向PCI特别兴趣小组（PCI SIG）申请而得到。<br><br>（2）PCI基地址（PCI Base Address），配置空间偏移量为10～24h，设备通过设定可读写的高位数值来向操作系统指示所需资源空间的大小。比如，某设备需要64K字节的内存 空间，可以将配置空间的某基地址寄存器的高16位设成可读写的，而将低16位置为0（只可读）。操作系统在建立时，先向所有位写1，实际上只有高16位被 接收而被置成了1，低16位仍为0.这样操作系统读取该寄存器时，返回值为FFFF0000h，据此操作系统可以断定其需要的空间大小是64K字节，然后 分配一段空闲的内存空间并向该寄存器的高16位填写其地址。<br><br>其它可能与编程有关的配置空间的定义及地址请参阅参考文献[1]。<br><br>由于PC-AT兼容系统CPU只有内存和I/O两种空间，没有专用的配置空间，PCI协议规定利用特定的I/O空间操作驱动PCI桥路转换成配置空间的操 作。目前存在两种转换机制，即配置机制1#和配置机制2#。配置机制2#在新的设计中将不再被采用，新的设计应使用配置机制1#来产生配置空间的物理操 作。这种机制使用了两个特定的32位I/O空间，即CF8h和CFCh。这两个空间对应于PCI桥路的两个寄存器，当桥路看到CPU在局部总线对这两个 I/O空间进行双字操作时，就将该I/O操作转变为PCI总线的配置操作。寄存器CF8h用于产生配置空间的地址（CONFIG-ADDRESS），寄存 器CFCh用于保存配置空间的读写数据（CONFIG-DATA）。<br><br>配置空间地址寄存器的格式如图1。<br><img alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/fengyv/2a.gif"><br><br></font><span style="FONT-SIZE: 12px"><font color=#000000><font size=2>CF8H（局部总线）：<br><br>当CPU发出对I/O空间CFCh的操作时，PCI桥路将检查配置空间地址寄存器CF8h的31位。如果为1，就在PCI总线上产生一个相应的配置空间读或写操作，其地址由PCI桥路根据配置空间地址寄存器的内容作如图2所示的转换。<br><br>CFCh (局部总线)：<br><br>设备号被PCI桥路译码产生PCI总线地址的高位地址，它们被设计者用作IDSEL信号来区分相应的PCI设备。6位寄存器号用于寻址该PCI设备配置空 间62个双字的配置寄存器（256字节）。功能号用于区分多功能设备的某特定功能的配置空间，对常用的单功能设备为000。某中PCI插槽的总线号随系统 （主板）的不同稍有区别，大多数PC机为1，工控机可能为2或3。为了找到某设备，应在系统的各个总线号上查找，直到定位。如果在0～5号总线上不能发现 该设备，即可认为该设备不存在。<br><br>理解了上述PCI协议里的配置机制后，就可以直接对CF8h和CFCh两个双字的I/O空间进行操作，查找某个PCI设备并访问其配置空间，从而得到操作系统对该PCI设备的资源分配。<br><script type=text/javascript><!--google_ad_client = "pub-2299987709779770";google_ad_width = 468;google_ad_height = 60;google_ad_format = "468x60_as";google_ad_type = "image";google_ad_channel ="";google_color_border = "FFFFFF";google_color_bg = "FFFFFF";google_color_link = "0000FF";google_color_url = "008000";google_color_text = "000000";//--></script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type=text/javascript></script><script src="http://googleads.g.doubleclick.net/pagead/test_domain.js"></script><script src="http://pagead2.googlesyndication.com/pagead/render_ads.js"></script><script>window.google_render_ad();</script></font><iframe name=google_ads_frame marginWidth=0 marginHeight=0 src="http://googleads.g.doubleclick.net/pagead/ads?client=undefined&amp;dt=1236646225562&amp;lmt=1236646225&amp;format=undefinedxundefined&amp;output=html&amp;correlator=1236646225562&amp;url=http%3A%2F%2Fwww.cppblog.com%2Fmilkyway%2Farticles%2F17138.html&amp;ea=0&amp;ref=http%3A%2F%2Fwww.google.cn%2Fcustom%3Fhl%3Dzh-CN%26inlang%3Dzh-CN%26safe%3Dactive%26client%3Dpub-4210569241504288%26channel%3D7748181296%26cof%3DFORID%253A1%253BGL%253A1%253BS%253Ahttp%253A%252F%252Fwww.cppblog.com%252F%253BL%253Ahttp%253A%252F%252Fwww.cppblog.com%252Fimages%252Flogo.gif%253BLH%253A29%253BLW%253A149%253BLBGC%253AFFFFFF%253BLC%253A%25230000ff%253BVLC%253A%2523663399%253BGFNT%253A%25230000ff%253BGIMP%253A%25230000ff%253B%26domains%3Dcppblog.com%253Bblogjava.net%253Bcnblogs.com%26newwindow%3D1%26ie%3DGB2312%26oe%3DGB2312%26q%3Dpci%2B%25C7%25FD%25B6%25AF%26sitesearch%3Dcppblog.com%26meta%3D&amp;frm=0&amp;ga_vid=1059142221.1236646226&amp;ga_sid=1236646226&amp;ga_hid=1922644332&amp;flash=9.0.115.0&amp;u_h=768&amp;u_w=1024&amp;u_ah=738&amp;u_aw=1024&amp;u_cd=32&amp;u_tz=480&amp;u_java=true&amp;dtd=63" frameBorder=0 scrolling=no allowTransparency></iframe><iframe name=google_ads_frame marginWidth=0 marginHeight=0 src="http://pagead2.googlesyndication.com/pagead/ads?client=ca-pub-2299987709779770&amp;dt=1167720266531&amp;lmt=1167720266&amp;prev_fmts=160x600_as%2C120x60&amp;format=120x60&amp;output=html&amp;url=http%3A%2F%2Fblog.csdn.net%2Ffengyv%2Farchive%2F2006%2F06%2F30%2F856621.aspx&amp;ref=http%3A%2F%2Fblog.csdn.net%2Ffengyv%2Fcategory%2F192281.aspx%3FPageNumber%3D2&amp;cc=31&amp;u_h=800&amp;u_w=1280&amp;u_ah=772&amp;u_aw=1280&amp;u_cd=32&amp;u_tz=480&amp;u_java=true" frameBorder=0 width=120 scrolling=no height=60 allowTransparency></iframe><br><font size=2>2 用I/O命令访问PCI总线配置空间<br><br><img alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/fengyv/2b.gif"><br><br></font></font></span><span style="FONT-SIZE: 12px"><font color=#000000><font size=2>要访问PCI总线设备的配置空间，必须先查找该设备。查找的基本根据是各PCI设备的配置空间里都存有特定的设备号（Device ID）及销售商号（Vendor ID），它们占用配置空间的00h地址。而查找的目的是获得该设备的总线号和设备号。查找的基本过程如下：用I/O命令写配置空间的地址寄存器CF8h， 使其最高位为1，总线号及设备为0，功能号及寄存器号为0，即往I/O端口CF8h80000000h；然后用I/O命令读取配置空间的数据寄存器 CFCh。如果该寄存器值与该PCI设备的Device ID及Vendor ID不相符，则依次递增设备号/总线号，重复上述操作直到找到该设备为止。如果查完所有的设备号/总线号（1～5）仍不能找到该设备，则应当考虑硬件上的 问题。对于多功能设备，只要设备配置寄存器相应的功能号值，其余步骤与单功能设备一样。<br><br>如查找设备号为9054h，销售商号为10b5的单功能PCI设备，编写的程序如下：<br><br></font></font></span>
<div class=postText><span style="FONT-SIZE: 12px"><font color=#000000><font size=2><font color=#000000>
<div class=smalltxt style="FONT-WEIGHT: bold; MARGIN-LEFT: 2em; MARGIN-RIGHT: 2em">
<div style="FLOAT: left">CODE:</div>
</div>
<div class=altbg2 id=code0 style="CLEAR: both; BORDER-RIGHT: rgb(105,140,195) 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: rgb(105,140,195) 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; MARGIN: 3px 2em 2em; BORDER-LEFT: rgb(105,140,195) 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: rgb(105,140,195) 1px solid">char bus;char device;<br><br>unsigned int ioa0,iod;<br><br>int scan( )<br><br>{<br><br>bus=0;device=0;<br><br>for(char i=0;i&lt;5;i++) {<br><br>for(char j=0;j&lt;32;j++) {<br><br>bus=i; device=j;<br><br>ioa0=0x80000000+bus*0x10000<br><br>+(device*8)*0x100;<br><br>_outpd(0xcf8,ioa0);<br><br>iod=_inpd(0xcfc);<br><br>if (iod0= =0x905410b5) return 0;<br><br>}<br><br>}<br><br>retrn -1<br><br>}</div>
</font></font></font></span><span style="FONT-SIZE: 12px"><font color=#000000><font size=2>调用子程序scan( )，如果返回值为-1，则没有找到该PCI设备。如果返回值为0，则找到了该PCI设备。该设备的总线号和设备号分别在全局变量bus和device中， 利用这两个变量即可轻易对该设备的配置空间进行访问，从而得到分配的资源信息。假设该PCI设备占用了4个资源空间，分别对应于配置空间10h～1ch， 其中前两个为I/O空间，后两个为内存空间，若定义其基地址分别为ioaddr1,ioaddr2,memaddr1,memaddr2,相应的程序如 下：<br><br></font></font></span><span style="FONT-SIZE: 12px"><font color=#000000><font size=2><font color=#000000>
<div class=smalltxt style="FONT-WEIGHT: bold; MARGIN-LEFT: 2em; MARGIN-RIGHT: 2em">
<div style="FLOAT: left">CODE:</div>
</div>
<div class=altbg2 id=code1 style="CLEAR: both; BORDER-RIGHT: rgb(105,140,195) 1px solid; PADDING-RIGHT: 10px; BORDER-TOP: rgb(105,140,195) 1px solid; PADDING-LEFT: 10px; PADDING-BOTTOM: 10px; MARGIN: 3px 2em 2em; BORDER-LEFT: rgb(105,140,195) 1px solid; PADDING-TOP: 5px; BORDER-BOTTOM: rgb(105,140,195) 1px solid">unsigned short ioaddr1,ioaddr2;<br><br>unsigned int memaddr1,memaddr2;<br><br>unsigned int iobase,ioa;<br><br>void getbaseaddr(char bus,char device);<br><br>{<br><br>iobase=0x80000000+bus*0x10000+(device*8)*0x100;<br><br>ioa=iobase+0x10;/*寻址基地址寄存器0*/<br><br>_outpd(0xcf8,ioa);<br><br>ioaddr1=(unsigned short)_inpd(0xcfc)&amp;0xfffc;<br><br>/*屏蔽低两位和高16位*/<br><br>ioa=iobase+0x14; /*寻址基地址寄存器1*/<br><br>_outpd(0xcf8,ioa);<br><br>ioaddr2=(unsigned short)_inpd(0xcfc)&amp;0xfffc;<br><br>ioa=iobase+0x18;/*寻址基地寄存器2*/<br><br>_outpd(0xcf8,ioa);<br><br>memaddr1=_inpd(0xcfc) &amp; 0xfffffff0;<br><br>/*屏蔽低4位*/<br><br>ioa=iobase+0x1c; /*寻址基地址寄存器3*/<br><br>_outpd(0xcf8,ioa);<br><br>memaddr2=_inpd(0xcfc) &amp; 0xfffffff0;<br><br>}</div>
</font></font></font></span><span style="FONT-SIZE: 12px"><font color=#000000><font size=2>对于I/O基地址，最低两位D0、D1固定为01，对地址本身无效，应当被屏蔽。对PC-AT兼容机，I/O有效地址为16位，因此高位也应被屏蔽。对于 内存地址，最低位D0固定为0，而D1～D3用于指示该地址的一些物理特性[1]，因此其低4位地址应当被屏蔽。需要指出的是该内存地址是系统的物理地 址，在WINDOWS运行于保护模式时，需要经过转换得到相应的线性地址才能对该内存空间进行直接读写。介绍该转换方法的相关文章较为常见，此处不再赘 述。<br><br>上述程序给出了读取配置空间里的基地址的方法。另有相当多PCI设备通过配置空间的设备关联区来设置该设备的工作状态，可轻易地用I/O命令进行相应的设置，无须编写繁杂的驱动程序。在开发PCI视频图像采集卡的过程中，该方法得到了实际应用。</font></font></span></div>
<img src ="http://www.cppblog.com/binghuo/aggbug/76077.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/binghuo/" target="_blank">冰火</a> 2009-03-10 08:52 <a href="http://www.cppblog.com/binghuo/archive/2009/03/10/76077.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>驱动调试的一般性技巧</title><link>http://www.cppblog.com/binghuo/archive/2009/03/10/76076.html</link><dc:creator>冰火</dc:creator><author>冰火</author><pubDate>Tue, 10 Mar 2009 00:48:00 GMT</pubDate><guid>http://www.cppblog.com/binghuo/archive/2009/03/10/76076.html</guid><wfw:comment>http://www.cppblog.com/binghuo/comments/76076.html</wfw:comment><comments>http://www.cppblog.com/binghuo/archive/2009/03/10/76076.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/binghuo/comments/commentRss/76076.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/binghuo/services/trackbacks/76076.html</trackback:ping><description><![CDATA[<span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">一般性调试技巧包括打印调试信息、查看</span><span lang=EN-US>dump</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">文件等。这些方法在调试驱动中比较常见，使用也比较简单。</span>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>1</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">．打印调试信息</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">对于开发驱动程序来说，最简单的调试方法就是打印出调试信息。因为驱动程序很难像应用程序那样由一般的调试器调试，因此，打印调试信息是运用最为广泛的调试技巧。</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">打印调试信息需要使用</span><span lang=EN-US>DbgPrint</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">函数，使用方法类似于</span><span lang=EN-US>c</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">函数</span><span lang=EN-US>printf</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。另外，还有一个宏</span><span lang=EN-US>KdPrint</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">，在</span><span lang=EN-US>checked</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">版本中，它对应着</span><span lang=EN-US>DbgPrint</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">函数，而在</span><span lang=EN-US>free</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">版本中，它不做任何操作。</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如果希望不管是在</span><span lang=EN-US>checked</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">版本还是</span><span lang=EN-US>free</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">版本，都希望自己可以控制调试信息的输出，那我们可以这样的方式实现，通过宏开关定义，如下所示：</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: green; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">//</span><span style="FONT-SIZE: 9pt; COLOR: green; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">打印错误信息<span lang=EN-US><o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">#define</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: #010001">FLAG_DEBUG_ERROR<o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: green; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">//</span><span style="FONT-SIZE: 9pt; COLOR: green; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">打印函数进入退出信息<span lang=EN-US><o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">#define</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: #010001">FLAG_DEBUG_FUNC<o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: green; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">//</span><span style="FONT-SIZE: 9pt; COLOR: green; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">打印其它信息<span lang=EN-US><o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">#define</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes"><span style="mso-tab-count: 2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: #010001">FLAG_DEBUG_INFO<o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: #010001; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes"><o:p>&nbsp;</o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">#if</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes"> <span style="COLOR: blue">defined</span> (<span style="COLOR: #010001">FLAG_DEBUG_ERROR</span>)<o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">#define</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes"><span style="mso-spacerun: yes">&nbsp; </span><span style="COLOR: #010001">DEBUG_ERROR</span>(<span style="COLOR: #010001">fmt</span>)<span style="mso-tab-count: 1">&nbsp;&nbsp; </span>{ <span style="COLOR: #010001">DbgPrint</span> <span style="COLOR: #010001">fmt</span> ;}<o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">#else<o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: gray; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">#define<span style="mso-spacerun: yes">&nbsp; </span>DEBUG_ERROR(fmt)<o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">#endif<o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes"><o:p>&nbsp;</o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">#if</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes"> <span style="COLOR: blue">defined</span> (<span style="COLOR: #010001">FLAG_DEBUG_FUNC</span>)<o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">#define</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes"><span style="mso-spacerun: yes">&nbsp; </span><span style="COLOR: #010001">DEBUG_FUNC</span>(<span style="COLOR: #010001">fmt</span>)<span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span>{ <span style="COLOR: #010001">DbgPrint</span> <span style="COLOR: #010001">fmt</span> ;}<o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">#else<o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: gray; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">#define<span style="mso-spacerun: yes">&nbsp; </span>DEBUG_FUNC(fmt)<o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">#endif<o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes"><o:p>&nbsp;</o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">#if</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes"> <span style="COLOR: blue">defined</span> (<span style="COLOR: #010001">FLAG_DEBUG_INFO</span>)<o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">#define</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes"><span style="mso-spacerun: yes">&nbsp; </span><span style="COLOR: #010001">DEBUG_INFO</span>(<span style="COLOR: #010001">fmt</span>)<span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp; </span>{ <span style="COLOR: #010001">DbgPrint</span> <span style="COLOR: #010001">fmt</span> ;}<o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">#else<o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: gray; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">#define<span style="mso-spacerun: yes">&nbsp; </span>DEBUG_INFO(fmt)<o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">#endif<o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes"><o:p>&nbsp;</o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes"><o:p>&nbsp;</o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-layout-grid-align: none" align=left><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">#define</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes"> <span style="COLOR: #010001">INTO_FUNC</span><span style="mso-tab-count: 1">&nbsp; </span><span style="COLOR: #010001">DEBUG_FUNC</span>((<span style="COLOR: #a31515">"===&gt;&gt;&gt; %s\n"</span>, <span style="COLOR: #010001">__FUNCTION__</span>))<o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US style="FONT-SIZE: 9pt; COLOR: blue; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">#define</span><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes"> <span style="COLOR: #010001">OUT_FUNC</span><span style="mso-tab-count: 1">&nbsp;&nbsp; </span><span style="COLOR: #010001">DEBUG_FUNC</span>((<span style="COLOR: #a31515">"&lt;&lt;&lt;=== %s\n"</span>, <span style="COLOR: #010001">__FUNCTION__</span>))<o:p></o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes"><o:p>&nbsp;</o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes"><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes">查看调试信息，一般使用<span lang=EN-US>DbgView</span>工具软件。<span lang=EN-US><o:p></o:p></span></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US style="FONT-SIZE: 9pt; FONT-FAMILY: 新宋体; mso-font-kerning: 0pt; mso-hansi-font-family: 'Times New Roman'; mso-no-proof: yes"><o:p>&nbsp;</o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>2</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">．存储</span><span lang=EN-US>dump</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">信息</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">打印调试信息，可以满足大部分的调试需要，然后有时驱动经常导致蓝屏死机的情况，这样即使打印了调试信息，也没办法看到，这种情况下，可以设置</span><span lang=EN-US>dump</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">信息。所谓的</span><span lang=EN-US>dump</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">信息就是在系统崩溃之前，操作系统会将当前的调用堆栈记录成一个</span><span lang=EN-US>dump</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">文件，这个文件对以后的分析极为有用。</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">设置存储</span><span lang=EN-US>dump</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">信息的方法如下。</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">右键单击&#8220;我的电脑&#8221;，选择&#8220;属性&#8221;，弹出&#8220;系统属性&#8221;对话框。选择&#8220;高级&#8221;选项卡，然后在&#8220;启动和故障恢复&#8221;栏内，单击&#8220;设置&#8221;按钮，弹出&#8220;启动和故障恢复&#8221;对话框，在&#8220;系统失败&#8221;栏内，设置写入调试信息，如下图所示。</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><span lang=EN-US><v:shapetype id=_x0000_t75 coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></v:path><o:lock v:ext="edit" aspectratio="t"><img height=497 alt="" src="http://www.cppblog.com/images/cppblog_com/aurain/1.GIF" width=512 border=0></o:lock></v:shapetype></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: center" align=center><span lang=EN-US><img height=487 alt="" src="http://www.cppblog.com/images/cppblog_com/aurain/2.GIF" width=512 border=0></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US><o:p>&nbsp;</o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>3</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">．使用</span><span lang=EN-US>WinDbg</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">调试工具查看</span><span lang=EN-US>dump</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">信息</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Dump</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">信息，必须用专用的工具软件查看，一般使用</span><span lang=EN-US>WinDbg</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">工具，这个需要下载符号表（具体使用参看这篇文章</span><span lang=EN-US><a href="http://www.cppblog.com/aurain/archive/2009/01/04/71138.html"><u><font color=#800080>http://www.cppblog.com/aurain/archive/2009/01/04/71138.html</font></u></a></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">）。</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">打开</span><span lang=EN-US>WinDbg</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">软件后，选择菜单&#8220;</span><span lang=EN-US>File|Open Crash Dump</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">&#8221;或&#8220;</span><span lang=EN-US>Ctrl+D</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">&#8221;，然后选择</span><span lang=EN-US>dump</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">文件，这些文件一般存在在</span><span lang=EN-US>c:\windows\</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">目录下，</span><span lang=EN-US>.dmp</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">格式。打开完毕后，在命令框内输入</span><span lang=EN-US>!analyze &#8211;v</span><span style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">后回车，回显示崩溃前内核堆栈调用说明，因此可以分析出是什么地方出了问题。如下图所提示的分析信息：</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>*******************************************************************************</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>*<span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>*</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>*<span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>Bugcheck Analysis<span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>*</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>*<span style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>*</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>*******************************************************************************</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US><o:p>&nbsp;</o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS (ce)</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>A driver unloaded without cancelling timers, DPCs, worker threads, etc.</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>The broken driver's name is displayed on the screen.</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>Arguments:</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>Arg1: f76cf820, memory referenced</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>Arg2: 00000008, value 0 = read operation, 1 = write operation</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>Arg3: f76cf820, If non-zero, the instruction address which referenced the bad memory</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US><span style="mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>address.</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>Arg4: 00000000, Mm internal code.</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US><o:p>&nbsp;</o:p></span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>Debugging Details:</span></p>
<p class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><span lang=EN-US>------------------</span></p>
<img src ="http://www.cppblog.com/binghuo/aggbug/76076.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/binghuo/" target="_blank">冰火</a> 2009-03-10 08:48 <a href="http://www.cppblog.com/binghuo/archive/2009/03/10/76076.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>驱动程序开发入门（转自驱动程序开发网） </title><link>http://www.cppblog.com/binghuo/archive/2009/03/10/76075.html</link><dc:creator>冰火</dc:creator><author>冰火</author><pubDate>Tue, 10 Mar 2009 00:42:00 GMT</pubDate><guid>http://www.cppblog.com/binghuo/archive/2009/03/10/76075.html</guid><wfw:comment>http://www.cppblog.com/binghuo/comments/76075.html</wfw:comment><comments>http://www.cppblog.com/binghuo/archive/2009/03/10/76075.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/binghuo/comments/commentRss/76075.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/binghuo/services/trackbacks/76075.html</trackback:ping><description><![CDATA[<p>&nbsp;</p>
&nbsp;
<p><span>近一个多月以来一直在看驱动方面的东西，把马少华翻译的</span><span>Programming the Microsoft Windows Drivers Model</span><span>的第一版算是过了一遍，但一直没有动手写一行代码。每个人的学习方式不同，对于我来说，一样东西如果没有一个框架上的大体把握，就象新到一个城市，一下还找不到方位感，说起一个地方，根本不知道处于自己所在位置的哪个方向，因而相当长的一段时间内会感觉到特别别扭。当然，也只是别扭而已，你知道这需要时间的，时间够了，有些东西会自然地沉积在你的身体里，然后可以不假思索地说出东西南北来，这么多年了，你多少对自己还保留着一点信心吧！呵呵。</span></p>
<p>&nbsp;</p>
<p><span>老马翻译的是第一版，我机器上也有</span><span>Walter Oney</span><span>的第二版（</span><span>E</span><span>文），内容扩充了不少，我曾经试图直接看二版的，东西总要新一些吧。唉！看了一段时间，进度太慢了，</span><span>E</span><span>文的水准还处于边读边翻译的阶段，每句话都要过到脑子里先变成中文再理解，如果看自己已经熟悉的东西，可能还能好点，对于驱动新手来说，很多概念是新的，再这么折腾绕一回，老费劲了。想一想，还是别为难自己了，先对整体框架有了一个大体的把握，回头再看</span><span>E</span><span>文的也行吧。也不记得在哪找到了老马的中文版（好像� </span></p>
<img src ="http://www.cppblog.com/binghuo/aggbug/76075.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/binghuo/" target="_blank">冰火</a> 2009-03-10 08:42 <a href="http://www.cppblog.com/binghuo/archive/2009/03/10/76075.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>