⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 华程电子 - 分类应用(usb开发)软件篇.htm

📁 usb的协议的详细说明
💻 HTM
📖 第 1 页 / 共 3 页
字号:
            
               
&nbsp;&nbsp; &nbsp;&nbsp; 写输出缓冲区或丢弃输入缓冲区 <BR>FlushFileBuffers 
<BR>FlushConsoleInputBuffer <BR>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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp; 系统关闭InitialSystemShutdown 
<BR><BR>和上面的驱动程序支持的功能代码相对应,一般的驱动程序看起来就象下面的样子。 <BR>DriverEntry(…) // 驱动程序入口 <BR>{ 
<BR>… <BR>DeviceObject-&gt;MajorFunction[IRP_MJ_CREATE] = XXDriverCreateClose; 
//XX对应的是你自己给你的驱动程序的命名<BR>DeviceObject-&gt;MajorFunction[IRP_MJ_CLOSE] = 
XXDriverCreateClose; <BR>DeviceObject-&gt;MajorFunction[IRP_MJ_READ] = 
XXDriverReadWrite; <BR>DeviceObject-&gt;MajorFunction[IRP_MJ_WRITE] = 
XXDriverReadWrite; <BR>… <BR>} <BR>XXDriverCreateClose(…) // 
对应IRP_MJ_CREATE和IRP_MJ_CLOSE的例程 <BR>{ <BR>//………. <BR>} 
<BR>XXDriverDeviceControl(…)// 对应IRP_MJ_DEVICE_CONTROL的例程 <BR>{ <BR>//………. <BR>} 
<BR>XXDriverReadWrite(…) // 对应IRP_MJ_READ和IRP_MJ_WRITE的例程 <BR>{ <BR>//………. <BR>} 
<BR><BR>一个驱动程序并不需要支持所有的功能代码,比如如果一个驱动程序根本就不必要与用户模式客户程序交互,那么就不用支持IRP_MJ_CREATE和IRP_MJ_CLOSE。又如设备不支持设备读写,就不用支持IRP_MJ_READ和IRP_MJ_WRITE。 
驱动程序对象是在操作系统启动驱动程序、在调用驱动程序 入口DriverEntry之前就已经创建好了的,并且作为DriverEntry 
函数的参数传递给驱动程序。如果驱动程序启动失败,操作 
系统将删除该对象。该对象的数据结构如下。注意下表并不是完整地列出了ntddk.h中的DEVICE_OBJECT结构体的所有数 
据项,这里仅列出了一般驱动程序可能使用到的数据项。 </FONT></P>
<TABLE width="100%" border=1>
  <TBODY>
  <TR>
    <TD width="50%"><FONT face=宋体>Driver对象数据项 &nbsp;</FONT></TD>
    <TD width="50%"><FONT face=宋体>说明 </FONT></TD></TR>
  <TR>
    <TD width="50%"><FONT face=宋体>PDEVICE_OBJECT&nbsp; DeviceObject </FONT></TD>
    <TD width="50%"><FONT face=宋体>&nbsp; 由本驱动程序创建的Device对象的链表</FONT></TD></TR>
  <TR>
    <TD width="50%"><FONT face=宋体>ULONG Flags&nbsp;&nbsp;&nbsp;&nbsp; 
      PDRIVER_INITIALIZE DriverInit &nbsp;&nbsp;&nbsp;</FONT></TD>
    <TD width="50%"><FONT face=宋体>驱动程序初始化例程(一般较少用) </FONT></TD></TR>
  <TR>
    <TD width="50%"><FONT face=宋体>PDRIVER_STARTIO DriverStartIo 
      &nbsp;&nbsp;&nbsp;&nbsp;</FONT></TD>
    <TD width="50%"><FONT face=宋体>&nbsp; StartIo例程入口,一般该例程对低层设备驱动程序用得较多, 
      高层驱动程序较少使用本例程。</FONT></TD></TR>
  <TR>
    <TD width="50%"><FONT face=宋体>PDRIVER_UNLOAD&nbsp; DriverUnload 
      &nbsp;</FONT></TD>
    <TD width="50%"><FONT 
  face=宋体>卸载驱动程序例程,如果想在控制面版的设备里停止该设备,应该提供本例程。</FONT></TD></TR>
  <TR>
    <TD width="50%"><FONT face=宋体>PDRIVER_DISPATCH 
      MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1] </FONT></TD>
    <TD width="50%"><FONT face=宋体>&nbsp;&nbsp;&nbsp; 驱动程序的Dispatch例程表 
    </FONT></TD></TR></TBODY></TABLE>
<P><FONT face=宋体>在上面提到过驱动程序是管理同类型的所有设备,所以上面的 
结构中DeviceObject指向的就不是单个的设备对象,而是一个对象链表,这个链表的维护在下面介绍Device对象时可以看到。 Device对象与Device 
Extension 驱动程序在调用IoCreateDevice函数成功后就创建了一个Device 
对象。下面对Device对象几个比较重要的数据做一介绍。</FONT></P>
<TABLE width="100%" border=1>
  <TBODY>
  <TR>
    <TD width="25%"><FONT face=宋体>Device对象数据项 
      &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</FONT></TD>
    <TD width="75%"><FONT face=宋体>说明 </FONT></TD></TR>
  <TR>
    <TD width="25%"><FONT face=宋体>PVOID DeviceExtension &nbsp;</FONT></TD>
    <TD width="75%"><FONT face=宋体>指向Device Extension结构的指针</FONT></TD></TR>
  <TR>
    <TD width="25%"><FONT face=宋体>PDRIVER_OBJECT DriverObject</FONT></TD>
    <TD width="75%"><FONT face=宋体>指向这个设备的Driver对象的指针,IoCreateDevice会 
      自动填写本数据。</FONT></TD></TR>
  <TR>
    <TD width="25%"><FONT face=宋体>ULONG Flags </FONT></TD>
    <TD width="75%"><FONT face=宋体>指定这个设备的缓冲策略</FONT></TD></TR>
  <TR>
    <TD width="25%"><FONT face=宋体>PDEVICE_OBJECT NextDevice </FONT></TD>
    <TD width="75%"><FONT 
  face=宋体>指向属于这个驱动程序的下一个设备对象,依靠本数据来维护设备对象链表</FONT></TD></TR>
  <TR>
    <TD width="25%"><FONT face=宋体>CCHAR StackSize &nbsp;</FONT></TD>
    <TD width="75%"><FONT 
      face=宋体>发送到这个设备的IRP需要的I/O堆栈单元的最小数目,一般对分层驱动程序来说,本数据应该比其下层设备的大1</FONT></TD></TR>
  <TR>
    <TD width="25%"><FONT face=宋体>ULONG AlignmentRequirement</FONT></TD>
    <TD width="75%"><FONT face=宋体>缓冲区要求的内存对齐,一般对分层驱动程序来说,本值应该 
      和其下层设备的对齐一致</FONT></TD></TR></TBODY></TABLE>
<P><FONT 
face=宋体>Device记录着设备的特徵和状态信息,对系统上的每个虚拟的、逻辑的和物理的设备都有一个Device对象。例如对一个硬盘驱动程序,对一个物理硬盘有一个名称为Partition0的Device对象,对应整个物理磁盘,同时对硬盘的每个分区,也都有一个Device对象,它们的名称分别为PartitionX(X从1开始,每个分区对应一个数字)。 
<BR>Device Extension是连接到Device对象的一个很重要的数据结构,它的数据结构是由驱动程序设计者自己来确定的,在 
调用IoCreateDevice的时候应该指定它的大小,Device Extension其实是由操作系统在非份页内存池中为每个Device 
对象分配的一块内存。由于驱动程序必须是完全可重入的, 因此使用任何全局变量和静态变量都不是好的办法,一般来 
说和设备有关的任何需要保持的信息都应该放到Device Extension里去。 <BR>设备的缓冲策略也必须提一下,这里的Flag的缓冲策略主要 
决定设备读写(功能代码IRP_MJ_READ和IRP_MJ_WRITE)时候的 缓冲策略,另外功能代码IRP_MJ_DEVICE_CONTROL时候的缓冲 
策略是由IOCTL控制代码本身来决定的。两者不能混为一谈。 在下面我将专门用一节来讨论I/O的缓冲策略。 <BR>I/O请求包(IRP) 
<BR>在上面的结构里面已经出现了IRP了,在这里对它做一说明。 
在NT中,几乎所有的I/O都是包驱动的,可以说驱动程序和操作系统其他部份都是通过I/O请求包来进行交互的。我们 来看看一个I/O请求的执行过程。 <BR>(1) 
操作系统的I/O管理器从非分页内存分配一个IRP,响应一个I/O请求。基于由客户指定的I/O函数,I/O管理器将该 
IRP传递给合适的驱动程序的Dispatch例程。 <BR>(2) 
Dispatch例程检查请求的参数是否有效,如果有效,驱动程序根据请求的内容进行一系列的操作。否则设置错 误状态信息直接返回。 <BR>(3) 
操作完成时,将数据(如果有)和状态信息存放到IRP中 并返回给I/O管理器。 <BR>(4) I/O管理器对返回的IRP进行适当的处理后将最后状态和 
数据(如果有)返回给用户。 <BR><BR>一个IRP的主要数据项如下表所示。 <BR>IRP包括一个IRP头和一个IRP stack 
的区域。由于WDM的模式下都是包驱动的,所里IRP可以说是一个非常重要的东东。还有那个该死的URB(God damn URB!)<FONT 
color=#c0c0c0>[人一辈子真的很过瘾,有些人或有些事你明明不喜欢或做不来,可是有时侯你又不得不硬着头皮去做,就像一大堆球迷围着一堆狗屎般的中国足球,那班傻儿真是要钱不要脸,丢咱中国人的脸]</FONT><BR></FONT></P>
<TABLE width="100%" border=1>
  <TBODY>
  <TR>
    <TD width="28%"><FONT face=宋体>IRP主要数据项</FONT></TD>
    <TD width="72%"><FONT face=宋体>说明 </FONT></TD></TR>
  <TR>
    <TD width="28%"><FONT face=宋体>IO_STATUS_BLOCK IoStatus</FONT></TD>
    <TD width="72%"><FONT face=宋体>存放I/O请求的状态</FONT></TD></TR>
  <TR>
    <TD width="28%"><FONT face=宋体>PVOID AssociatedIrp.SystemBuffer</FONT></TD>
    <TD width="72%"><FONT face=宋体>如果设备执行缓冲I/O,则为指向系统空间缓冲区的指针。 
  否则为NULL</FONT></TD></TR>
  <TR>
    <TD width="28%"><FONT face=宋体>PMDL MdlAddress </FONT></TD>
    <TD width="72%"><FONT face=宋体>如果设备执行直接I/O,指向用户空间缓冲区的内存描述表的指针</FONT></TD></TR>
  <TR>
    <TD width="28%"><FONT face=宋体>PVOID UserBuffer</FONT></TD>
    <TD width="72%"><FONT face=宋体>I/O缓冲区的用户空间地址 </FONT></TD></TR>
  <TR>
    <TD width="28%"><FONT face=宋体>BOOLEAN Cancel</FONT></TD>
    <TD width="72%"><FONT face=宋体>&nbsp;&nbsp; 指示IRP已被取消 
</FONT></TD></TR></TBODY></TABLE>
<P><FONT face=宋体>关于AssociatedIrp.SystemBuffer、MdlAddress和UserBuffer将在 
下面的I/O缓冲区策略里面更详细地讨论。 
<BR><BR>NT还有更多其他的对象,例如中断对象、Controller对象、定时器对象等等,但在我们开发的驱动程序中并没有用到,因此在这里不做介绍。 
<BR>I/O缓冲策略 
<BR>很明显的,驱动程序和客户应用程序经常需要进行数据交换,但我们知道驱动程序和客户应用程序可能不在同一个地址空间,因此操作系统必须解决两者之间的数据交换。这就就设计到设备的I/O缓冲策略。<BR>读写请求的I/O缓冲策略 
<BR>前面说到通过设置Device对象的Flag可以选择控制处理读写请求的I/O缓冲策略。下面对这些缓冲策略分别做一介绍。 
<BR>1、缓冲I/O(DO_BUFFERED_IO) 
<BR>在读写请求的一开始,I/O管理器检查用户缓冲区的可访问性,然后分配与调用者的缓冲区一样大的非分页池,并把它的地址放在IRP的AssociatedIrp.SystemBuffer域中。驱动程序就利用这个域来进行实际数据的传输。 
<BR>对于IRP_MJ_READ读请求,I/O管理器还把IRP的UserBuffer域设置 成调用者缓冲区的用户空间地址。当请求完成时,I/O管理器利用 
这个地址将数据从驱动程序的系统空间拷贝回调用者的缓冲区。对 于IRP_MJ_WRITE写请求,UserBuffer被设置为NULL,并把用户缓冲 
区的数据拷贝到系统缓冲区中。 <BR>2、 直接I/O(DO_DIRECT_IO) 
<BR>I/O管理器首先检查用户缓冲区的可访问性,并在物理内存中锁定它。然后它为该缓冲区创建一个内存描述表(MDL),并把MDL的地址 
存放在IRP的MdlAddress域中。AssociatedIrp.SystemBuffer和 UserBuffer都被设置为NULL。驱动程序可以调用函数 
MmGetSystemAddressForMdl得到用户缓冲区的系统空间地址,从而 进行数据操作。这个函数将调用者的缓冲区映射到非份页的地址空 
间。驱动程序完成I/O请求后,系统自动从系统空间解除缓冲区的映射。 <BR>3、 这两种方法都不是 
<BR>这种情况比较少用,因为这需要驱动程序自己来处理缓冲问题。 I/O管理器仅把调用者缓冲区的用户空间地址放到IRP的UserBuffer 
域中。我们并不推荐这种方式。 <BR></FONT></P>
<P><FONT face=宋体>IOCTL缓冲区的缓冲策略 <BR>IOCTL请求涉及来自调用者的输入缓冲区和返回到调用者的输出 
缓冲区。为了理解IOCTL请求,我们先来看看WIN32 API DeviceIoControl函数的原型。 <BR>BOOL DeviceIoControl ( 
<BR>HANDLE hDevice, // 设备句柄 <BR>DWORD dwIoControlCode, // IOCTL请求操作代码 <BR>LPVOID 
lpInBuffer, // 输入缓冲区地址 <BR>DWORD nInBufferSize, // 输入缓冲区大小 <BR>LPVOID 
lpOutBuffer, // 输出缓冲区地址 <BR>DWORD nOutBufferSize, // 输出缓冲区大小 <BR>LPDWORD 
lpBytesReturned, // 存放返回字节数的指针 <BR>LPOVERLAPPED lpOverlapped // 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -