(1)用户应用程序:用户编写的,通过驱动程序与硬件打交道的可执行文件:
(2)I/0管理层:负责用户应用程序和驱动程序之间的数据交换,并通过IRP(IO请求包)来完成; (3)驱动程序:在装了DDK后,可以自行编写驱动程序。在驱动程序中,不同
的部分、级别都是通过IRP来交换数据的。当一个例程处理完一个IRP后,它也设置好状态信息,然后将此IRP返回;
(4)硬件抽象层(HAL ): Windows管理,这样用户在写驱动程序的时候会灵活的多,而且HAL还提供了把同一个驱动程序解释到不同平台的功能; (5)硬件:完成某种功能的外围设备。
4.2.3 USB驱动程序体系结构
为了便于对驱动程序的开发、了解,Windows对USB驱动程序体系结构进行了
详细的说明,对不同软件部分进行了十分清楚的划分,如图14所示。其中USB总线客户软件仅仅包含了用来控制不同USB总线外设的设备驱动程序。USB总线客户软件会通过一个Windows所定义的软件接口与根集线器驱动程序进行通信,而USB总线根集线器驱动程序则要通过包含在USBD中的USBD1(通用串行总线驱动程序接口)实现与通用串行总线驱动程序((USBD)的通信。然后,USBD会选择三种主控制器驱动程序之一同其下方的主控制器进行通信。最后,主控制器驱动程序会直接实现对USB物理总线的访问。
像Windows NT环境下的设备驱动程序一样,USB总线驱动程序软件堆栈内的层间通信也使用了一个称为IRP(1/O请求包)的机制。一个设备驱动程序要与另一个设备驱动程序进行通信时,它会用IRP结构来组装一个请求,并把该请求传递到下一层。下一层接受了该请求之后,会向发送方发送一个应答(ACK)握手信号。重复该过程,就可以在不同分层结构之间实现通信了。
虽然不同的软件分层通信时要使用IRP,而实际的 USB总线请求却存放在一个被Microsoft称为通用串行总线请求URP结构内。在URP内包含了不同的域,在不同的软件分层结构中,每一个分层会使用不同的域进行处理操作。
客户软件
USB客户软件也是一种设备驱动程序,位于根集线器驱动程序之上,通过定义的USB总线接口访问其下方的USB总线软件,Windows USB接口提供了一系列供访问的USB总线接口函数。具体的使用情况可参考相应版本的Windows操作系统的设备驱动程序开发包(DDK)中的文档。
26
图14 USB驱动体系 (1)根集线器驱动程序
从图14可以看出,根集线器驱动程序位于USBD之上。在一个支持USB系统主机中,都会有一个根集线器,用来提供USB总线接口。所有的USB设备,包括USB功能设备和USB集线器都必须以一定方式接入一个USB根集线器。在Windows环境中,所有的客户驱动程序都可以通过指向这一根集线器驱动程序的接口来和所有接入的USB设备进行通信。另外,还有一种方法就是客户驱动程序通过USBDI而直接与USBD进行交互。
(2) USB驱动程序(USBD)
通用串行总线驱动程序(USBD)是USB总线系统中负责管理通用串行总线的工作且位于主机上的一个软件,提供了对USB设备的抽象和USBD上的客户同USB设备上的功能模块之间所存在的数据传输的抽象。USBD负责控制所有的USB协议操作和高层中断处理控制。
USBD为客户软件(设备驱动程序)提供了访问设备的一组接口,客户软件只能通过它来访问USB总线,并构建URB通过USBDI发送下去。对客户软件而言,它就是USB总线的底层。
(3)UHCD、OHCI、EHCI
Windows为不同的USB设备供应商提供了三种管理系统中的USB主控制器的软件接口,即通用主控制器(Universal Host Controller Driver, UHCD)和开放式主控制器接口(Open Host Controller
27
Interface, OHCI)和增强式主控制器接口EHCI(Enhanced Host Controller Interface)。其中EHCI是专为针对USB2.0提出的。
HCD(Host Controller Driver)通过主控制器来实现和物理总线的通信,负责所有USB物理层的总线操作。Windows在USB总线和主控制器之间又放置了一个PCI总线枚举器,在系统中,由PCI总线枚举负责在其检测到系统中存在一个通用串行总线时装载适当的USB总线驱动程序。
4.2.4 USB设备驱动程序设计
USB设备驱动程序是支持即插即用功能的标准WDM(Windows DriverModel)驱动程序,它与VXD和NT式的驱动程序不同,它是内核态程序,采用了分层处理的方式,不需要直接和硬件打交道。当USB设备插入USB集线器时,USB集线器驱动程序会检测到一个新设备的插入。PnP管理器使用厂商ID或设备类信息选择要运行的驱动程序。一般情况下,调用驱动程序的AddDevice例程,并发出其他的PnP IRP 。USB设备驱动程序决不会收到任何硬件资源(如端口或中断),因为USB类驱动程序处理所有的低层I/O。
在编写驱动程序时,需要包含以下几个头文件:
USBl00.h:包含有USB设备驱动程序中所用到的各种常量和结构; USBioctl.h: IOCTL的定义,包括各种驱动程序通用的数据结构; USBdlib.h: URB构造和各种例程,定义了USBD所输出的服务;
USBdi.h: USBDI例程,包括URB结构、各种驱动程序通用的数据结构。 在编译驱动程序时,build将会在欲编译的驱动程序所在的目录中寻找一个叫
sources的文件,这个文件将告诉编译程序,应该怎么做。在该文件中,以下五个内容是必须包含的: (1) TARGETNAME:表示编译出的结果名称;
(2) TARGETTYPE:表示编译出的结果类型(例如驱动程序);
(3) TARGETPATH:表示在当前目录(sources文件所在的目录)中建立一个什么名称的子目录来保存中间结果;
(4)TARGETLIBS:表示编译过程中需要那些库; (5) SOURCE:表示需要编译那些文件。 在本系统的驱动程序开发中,主要的分发例程有:
DriverEntry():是驱动程序的入口,主要完成各种初始化操作,同时把注册表复制到一个全局变量中,并告诉系统那些IRP由哪个例程处理,这部分被I/O系统直接调用。
28
USB_ D 12_Create():主要是用来在USB设备和驱动程序之间建立连接,当以打开文件的名义打开设备准备读写时,调用它。
USB_ D 12_pnp():处理即插即用的操作。 USB_ D 12_power():处理和电源相关的操作。
USB_ D 12_ Read()/USB_ D12_ Write():用来读写数据,把数据读到数据缓存区或把数据从缓存区写到端点专用寄存器,由此发往USB主机。
USB_ D 12_DeviceloControl():设备操作,一般是用来对硬件发出一些控制命令。 USB_ D 12_closeHandle():当用户关闭文件时,调用它清扫系统,卸载驱动程序。。 USB_ D 12_ AddDevice()第一次安装硬件(插上板子)时使用
USB_ D 12_ DriverUnload():卸载硬件时使用,当硬件完全卸载后,调用它清理此硬件在系统中留下的痕迹,释放全局变量中注册表路径字符串所占的内存。
以上是驱动程序中的几个重要的分发历程,只有上述这些例程正确执行,编译生成的*.SYS文件才是有效的,驱动程序才可以使用,设备才能和上位机通信。设备插上主机后,主机发现新硬件并提示安装驱动程序。
4.2.5 USB设备驱动程序的调用
USB设备通过客户驱动程序与设备打交道并响应内核或用户应用程序请求。在内核级,命令由客户驱动程序使用内部的IOCTL发送给USB系统,而不能用于用户态应用程序。最有用的IOCTL是IOCT_ INTERNAL USB_ SUBMIT_ URB,它发出USB请求块(URB)给系统USB驱动程序。URB允许发出多个功能调用给USB系统,通过URB进行与USB设备的大多数交互。用户只需在相应的分发例程中构造URB块(读取USB的描述表、选择配置和接口),并根据设备所支持的传输类型和设备自有的命令字将其通过USBDI发送下去,由USB类驱动程序处理所有的低层I/O,从而实现对USB设备的控制。
USB总线驱动程序由操作系统提供,它位于USB功能驱动程序的下面,负责与实际的硬件打交道,实现烦琐的低层通信。USB功能驱动程序由设备开发者编写,位于USB总线驱动程序的上面,不与实际的硬件打交道,而是通过向USB总线驱动程序发送包含URB (Request Block, USB请求块)的IRP (I/O Request Packet,IRP请求包),来实现对USB设备信息的发送或接收。采用这种分层驱动程序的方法有两个优点:
(1)多个USB设备可以通过USB总线驱动程序来协调它们的工作;
29
(2)编写分层驱动程序较之编写单一驱动程序相对简单,且可以节省内存和资源,不易出错。 整个驱动程序模型如图15所示。
图15 USB设备驱动程序的调用
USB设备驱动程序的工作原理可以通过图15单描述。若应用程序想对设备进行I/O操作,它便使用Windows API函数对WIN32子系统进行WIN32调用。此调用由I/O系统服务接收并通知I/O管理器,I/O管理器将此请求构造成一个合适的I/O请求包(I/O Request Packet IRP)并把它传送给USB功能驱动程序。USB功能驱动程序接收到这个IRP以后,根据IRP中包含的具体操作代码,构造相应的USB请求块 把该URP放到一个新的IRP中,并通过USBDI传送给USB驱动程序(USBD), USBD驱动程序根据IRP包含的不同传输类型将IRPs分解开来,并调用主控制器驱动程序来处理IRPs,同时将处理结果返还给I/O管理器,并最终返还给应用程序,从而实现了应用程序对设备的读写操作。
在此过程中,应用程序通过文件名(即设备名)和文件描述符找到设备驱动程序,驱动程序通过设备描述符和设备标识使用设备,三者为一链式调用方式。
功能驱动程序除负责处理应用程序的I/O请求外,还要处理PnP管理器发送给它的PnP请求(如设备启动请求IRP_ MN_ START_ DEVICE,设备删除请IRP MN REMOVE DEVICE等)。通过对这些请求的处理,USB功能驱动程序可支持设备的热插拔和即插即用功能。
30