流Mini驱动开发指南(三)

类别:VC语言 点击:0 评论:0 推荐:

 

三、开始着手编写Stream Minidriver

设计Stream Class Driver的主要目标,就是处理两个工作,一是处理操作系统,操作系统包含了对复杂的对多处理器的支持,二就是对内核流进行支持。这样Minidriver只需要对它必须执行的,与设备相关的操作进行处理即可。Class Driver为Minidriver分配内存空间,对Minidriver可能用到的NT内核资源进行登记,并(随意地)处理同步问题。

Class Driver通过一系列由Minidriver提供的回调函数和Minidriver进行通讯。大部分对流式Minidriver写的动作都发生在写这些回调函数的时候。

在本文中,我们所提到的每种由Minidriver提供的例程都命名为StrMin×××。根据下层硬件可能执行的不同功能的数目,Minidriver也许要为每个例程提供一到更多的版本。

一个典型的流驱动都会支持数种不同的数据流。例如,DVD播放器会产生音频和视频流。在内核流环境中,每个流都用一个pin来描述。(参见KS Filters, Pins and Node Topology for a description of pins)。

流类驱动会跟踪Minidriver上的每个pin,在Class Driver看来, pin的每种类型都是一个流。流,就好比Pin的类型,有可能会有多个实例。因为流可以接收I/O请求,所以驱动程序必须为每个流提供相关的回调函数。

下面所列的例程,Minidriver一般都会提供。在参考大全中会更加详细记录这些函数的细节。

·每个Minidriver都必须提供的例程

StrMiniCancelPacket

StrMiniReceiveDevicePacket

StrMiniRequestTimeout

StrMiniEvent

StrMiniInterrupt

·Minidriver为每个单独的流提供的例程。

StrMiniReceiveStreamDataPacket

StrMiniReceiveStreamControlPacket

StrMiniEvent

StrMiniClock

对于Minidriver来说,对数个不同的流使用相同的回调例程是可以的。回调例程可以通过调用它的流的参数来确定执行何种动作。

同WDM驱动一样,Minidriver必须提供DriverEntry例程。Minidriver的DriverEntry例程的主要任务,就是向Class Driver注册Minidriver。

Class Driver代表Minidriver接收所有的I/O请求。为了获取完成此次请求所必须的信息,Class Driver创建一个流请求块(Stream Request Block,SRB)并把它传递给形如StrMin×××Packet的众多例程中的一个。总体的来说,Class Driver向某设备分派I/O请求就等同于向StrMiniReceiveDevicePacket例程传递流请求块SRB,它把请求发送到各个独立的流的StrMiniReceiveStreamDataPacket例程(适用于内核流的读写请求)或者StrMiniReceiveStreamControlPacket例程(适用于其他请求)。

通常说来,Class Driver会对所有的请求进行排队,然后每次发送一个请求给Minidriver。Minidriver可以随意地进行它自己的同步操作;Minidriver负责对它目前无法立即处理的请求进行排队。详见Minidriver Synchronization。

Minidriver必须提供两个额外的例程以对SRB进行操作。当Class Driver收到一个取消IRP包(Cancel IRP)时,就会去调用StrMiniCancelPacket,以此来通知Minidriver取消某个特定的包。Class Driver会跟踪Minidriver完成处理一个SRB所花费的时间。如果Minidriver花费了很长时间还没有处理完一个请求,Class Driver将会对该请求返回超时,同时调用StrMiniRequestTimeout例程。

当发生了一个硬件中断时,操作系统会照会Class Driver,然后Class Driver调用Minidriver的StrMiniInterrupt例程去处理该中断。

四、处理流请求块SRB

操作系统会把所有对设备的I/O请求分发到Class Driver。通过向Minidriver传递SRB,Class Driver轮流从Minidriver处获取硬件的相关信息,Class Driver通过设置SRB的命令成员来指定它要求完成的操作。

总体上看,整个Minidriver,和它包含的每个流,都可能会收到I/O请求。Minidriver必须提供StrMiniReceiveDevicePacket例程来处理整个设备范围内的请求(Device-wide requests)每个流必须支持两个用来处理I/O请求例程:一个用来处理数据请求的例程,还有一个例程用来处理控制请求。Class Driver会调用那个用来处理数据请求的回调例程:StrMiniReceiveStreamDataPacket,来处理所有对指定流的读写请求。所有其他对流的请求会传递给StrMiniReceiveStreamControlPacket例程进行处理。

如果Class Driver正在为Minidriver处理同步,那么它会把所有的流请求进行排队,然后依次把它们发送给Minidriver,每次只发送一个请求。Class Driver维护了三种相互独立的队列:一个设备请求队列,另外每个留都有一个数据请求队列和控制请求队列。Minidriver会通知说它已经准备好接收一个新的请求。每种请求队列所对应的、用来通知Class Driver的例程和参数如下表所示:

请求类型

例程

例程的通知类型参数

设备请求

StreamClassDeviceNotification

ReadyForNextDeviceRequest

流控制请求

StreamClassStreamNotification

ReadyForNextStreamControlRequest

流数据请求

StreamClassStreamNotification

ReadyForNextStreamDataRequest

当Class Driver调用StrMiniReceive×××Packet例程时,它会把SRB转交给Minidriver。在Minidriver通知Class Driver,它已经对完成处理该请求之前,Minidriver中负责进行处理的例程对SRB有独占存取权限。

当Minidriver完成对一个请求的处理后,它应当按如下方式通知Class Driver它已经完成对请求的处理:

1.设置SRB中表示当前请求状态的状态域;

2.调用例程StreamClassDeviceNotification或StreamClassStreamNotification,通知Class Driver说它已经完成对请求的处理。如果完成的是一个设备请求,Minidriver要使用DeviceRequestComplete作为通知类型参数来调用例程StreamClassDeviceNotification;如果完成的是一个流请求,Minidriver要用StreamRequestComplete作为通知类型参数调用例程StreamClassStreamNotification。

3. 如果Class Driver当前正在处理同步,并且如果与此同时Minidriver还没有通知Class Driver说它已经做好准备接收对当前类型队列(注意,前面说过有三种类型的请求队列)的下一个请求,那它现在应该立即这样做(通知Class Driver)。

Minidriver可以通过调用StreamClassCompleteRequestAndMarkQueueReady,把2、3两步合并一起做。

Minidriver是以异步的方式处理请求的。所以Class Driver也许会取消一个请求,或者让一个请求超时。为了达到这些目的,Minidriver必须分别提供一个StrMiniCancelPacket例程和一个StrMiniRequestTimeout例程。Class Driver会在他要取消,或者要超时一个请求的时候,调用这两个独立的例程。

当下层的I/O请求被操作系统取消,Class Driver就要取消请求。Class Driver会把那些处理时间过长的请求置为超时,那Class Driver又是如何知道一个请求有没有超时呢?原来,在SRB中有一个成员变量TimeoutCounter,它指定了此请求处理超过多少秒就算超时。Class Driver每秒将此变量减一,如果变量已经减为0,而Minidriver还没有完成该请求,Class Driver就会判定此请求超时,然后它会调用Minidriver的StrMiniRequestTimeout例程。如果Minidriver要推迟很长时间再去处理一个请求,那Minidriver就应该把TimeoutCounter设为0,这样Class Driver不会误判当前请求超时。一旦Minidriver重新开始处理该请求,它应该重置SRB中的TimeoutCounter变量和TimeoutOriginal的值相等,Minidriver可以在请求超时之前重设TimeoutOriginal变量来改变耗时长度。详细信息参见HW_STREAM_REQUEST_BLOCK结构体。

本文地址:http://com.8s8s.com/it/it816.htm