JackyWu
驱动小牛
驱动小牛
  • 注册日期2001-10-25
  • 最后登录2011-04-05
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度1点
  • 原创分0分
  • 专家分0分
阅读:1847回复:5

关于驱动程序的流程问题

楼主#
更多 发布于:2002-06-17 17:24
    我看了别人的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完成这个例程。

麻烦大家看看我的说法是否正确。谢谢!

最新喜欢:

luozhangyuluozha...
多年以后,我又回来了。
magicx
驱动老牛
驱动老牛
  • 注册日期2002-02-22
  • 最后登录2014-08-18
  • 粉丝1
  • 关注0
  • 积分-14分
  • 威望13点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2002-06-17 21:02
   我看了别人的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完成这个例程。

麻烦大家看看我的说法是否正确。谢谢!


长了点。。。。。。。。

头大。。。

 :(
[color=red]大头鬼! :P[/color]
JackyWu
驱动小牛
驱动小牛
  • 注册日期2001-10-25
  • 最后登录2011-04-05
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度1点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2002-06-17 21:21
是啊,我怕语句太短,不能表达我的意思。我的语文差,所以......
还是请您帮忙看看哦.
多年以后,我又回来了。
zydcat
驱动老牛
驱动老牛
  • 注册日期2001-12-06
  • 最后登录2006-04-12
  • 粉丝0
  • 关注0
  • 积分9分
  • 威望2点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地板#
发布于:2002-06-18 09:36
IoCompleteRequest
只会在最下层驱动中被调用
[color=red]肥虫虫[/color] [img]http://www.driverdevelop.com/forum/upload/bradley/2002-11-15_ig01.gif[/img]
JackyWu
驱动小牛
驱动小牛
  • 注册日期2001-10-25
  • 最后登录2011-04-05
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度1点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2002-06-18 10:08
是啊,我只考虑了两层驱动的情况。
您看看,还有没有其他原则性错误。
多年以后,我又回来了。
zydcat
驱动老牛
驱动老牛
  • 注册日期2001-12-06
  • 最后登录2006-04-12
  • 粉丝0
  • 关注0
  • 积分9分
  • 威望2点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
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。


[color=red]肥虫虫[/color] [img]http://www.driverdevelop.com/forum/upload/bradley/2002-11-15_ig01.gif[/img]
游客

返回顶部