阅读:1847回复:5
关于驱动程序的流程问题
我看了别人的WDM驱动程序。看到向下传递IRP大概有两种情况。
1,在不挂接完成例程的情况下调用IoCallDriver。最典型的例子就是我们经常用的: NTSTATUS PnpDefaultHandler(IN PDEVICE_OBJECT fdo,IN PIRP Irp) { P_DEVICE_EXTENSION dx=(P_DEVICE_EXTENSION)fdo->DeviceExtension; IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(dx->NextStackDevice,Irp); } 2,在挂接一个完成例程的情况下调用IoCallDriver。而且完成例程返回STATUS_MORE_PROCESSING_REQUIRED。这样就可以让自己的驱动程序去调用IoCompleteRequest。最典型的例子就是以下代码: NTSTATUS ForwardAndWait(PDEVICE_OBJECT fdo, PIRP Irp) { KEVENT event; KeInitializeEvent(&event,NotificationEvent,FALSE); IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp,(PIO_COMPLETION_ROUTINE)OnRequestComplete, (PVOID)&event, TRUE, TRUE, TRUE); PPCI9054_DEVICE_EXTENSION pdx=(PPCI9054_DEVICE_EXTENSION)fdo->DeviceExtension; IoCallDriver(pdx->NextStackDevice,Irp); KeWaitForSingleObject(&event,Executive,KernelMode,false,NULL); return Irp->IoStatus.Status; } NTSTATUS OnRequestComplete(PDEVICE_OBJECT fdo,PIRP Irp,PKEVENT pev) { KeSetEvent(pev,0,FALSE); return STATUS_MORE_PROCESSING_REQUIRED; } ////////////////////////////////////////////////////// 我下面将提出我对程序流程的理解,希望大家看看,我的理解是否正确,给我批评和指正。 1,对于第一种向下传递IRP的方法。当我在自己的驱动程序里的某个函数“A”中调用PnpDefaultHandler后,程序的控制权就给了下层的驱动例程“B”了。当下层的驱动程序做完相应的工作后,“B”应该调用了IoCompleteRequest来完成“A”给它的IRP。在IoCompleteRequest里面它自动去查看是否挂接了完成例程,如果有就一层一层往上调用,直到调用到最上层驱动,或者有某一层完成例程返回了STATUS_MORE_PROCESSING_REQUIRED,它就停止回卷。然后IoCompleteRequest函数就返回,在它返回的一瞬间,控制权又交回给了下层驱动程序中调用IoCompleteRequest的例程“B”。一般情况下“B”就会函数返回了。在“B”返回后,“A”中PnpDefaultHandler后面如果有其他的语句的话,这些语句将在这个时候得到执行。 我想说明的是:“A”中PnpDefaultHandler的执行是阻塞的,即在“B”中相应的函数没有返回之前PnpDefaultHandler中的IoCallDriver是不会返回的。 2,如果对于第二中向下传递IRP的方法。则如上面所说,“A”中挂接了完成例程,并且此例程返回STATUS_MORE_PROCESSING_REQUIRED。则“B”中的IoCompleteRequest就会停止回卷了,并且“B”函数返回,让“A”从新得到控制权。“A”在得到控制权以后执行了某些操作,最后还是会调用IoCompleteRequest来完成这个例程。 我的想法是: 这两种方法的实施过程中,其实“A”里面处于PnpDefaultHandler或ForwardAndWait后面的语句都会得到调用的,并不存在PnpDefaultHandler后面的语句得不到控制权,而ForwardAndWait后面的语句能够得到控制权的情况。 所不通的是PnpDefaultHandler后面的语句不需要再IoCompleteRequest了。而ForwardAndWait后面的语句是需要IoCompleteRequest的。 我不知道我上面的一大堆理解是否正确,如果您看了觉得我理解错了,请您一定要回这个帖子,让我改正错误。 我对以上两个方法所适用的场合有以下理解: 其实两个方法对于一般的调用差不多。只有当“A”得到一个IRP,而且发现对于“B”来说,一次调用并不能完成这个IRP的情况下,我们必须ForwardAndWait。 具体例子是:如果上层驱动要求我Read一个10K的数据,我发现“B”里面一次Read只能读1K,那么我显然要对“B”调用10次IoCallDriver,等到所有数据到齐,再在“A”里面调用IoCompleteRequest完成这个例程。 麻烦大家看看我的说法是否正确。谢谢! |
|
最新喜欢:luozha...
|
沙发#
发布于:2002-06-17 21:02
我看了别人的WDM驱动程序。看到向下传递IRP大概有两种情况。 长了点。。。。。。。。 头大。。。 :( |
|
|
板凳#
发布于:2002-06-17 21:21
是啊,我怕语句太短,不能表达我的意思。我的语文差,所以......
还是请您帮忙看看哦. |
|
|
地板#
发布于:2002-06-18 09:36
IoCompleteRequest
只会在最下层驱动中被调用 |
|
|
地下室#
发布于:2002-06-18 10:08
是啊,我只考虑了两层驱动的情况。
您看看,还有没有其他原则性错误。 |
|
|
5楼#
发布于:2002-06-18 10:19
别的没有了,至少我没有看出来
其实关于完成irp我以前也不太明白,直到上次在论坛上和一个网友争论,后来仔细看书后才明白是我以前得理解错了。 看看这段话: 完成例程如何获得调用 IoCompleteRequest函数负责调用每个驱动程序安装在各自堆栈单元中的完成例程。这个调用过程见流程图5-7,开始,底层驱动程序的某段代码调用IoCompleteRequest例程以通知IRP处理结束。然后,IoCompleteRequest参考当前的堆栈单元以查明其上层驱动程序是否安装了完成例程。如果没有,它就把堆栈指针前进到上一层堆栈单元并重复测试,直到找到某个完成例程或者到达堆栈顶部。最后IoCompleteRequest函数执行其它操作(如释放IRP占用的内存)。 当IoCompleteRequest函数发现含有完成例程指针的堆栈单元时,它就调用这个完成例程并检查其返回代码。如果返回代码是除了STATUS_MORE_PROCESSING_REQUIRED以外的其它值,它就把堆栈指针移动到上一层并重复前面的工作。如果返回代码是STATUS_MORE_PROCESSING_REQUIRED,IoCompleteRequest将停止前进并返回到调用者,而此时的IRP将处于一个中间状态。因此,如果完成例程在堆栈单元回卷过程中停止,那么其驱动程序有责任处理这个处于中间状态的IRP。 |
|
|