驱动的请求处理
2021-07-01
122
0
开发一个驱动要有可能要处理各种IRP。但是本书范围内,只处理为了应用程序和驱动交互而产生的IRP。IRP的结构非常复杂,但是目前的需求下没有必要去深究它。应用程序为了和驱动通信,首先必须打开设备。然后发送或者接收信息。最后关闭它。这至少需要三个IRP:第一个是打开请求。第二个发送或者接收信息。第三个是关闭请求。
IRP的种类取决于主功能号。主功能号就是前面的说的DRIVER_OBJECT中的分发函数指针数组中的索引。打开请求的主功能号是IRP_MJ_CREATE,而关闭请求的主功能号是IRP_MJ_CLOSE。
如果写有独立的处理IRP_MJ_CREATE和IRP_MJ_CLOSE的分发函数,就没有必要自然判断IRP的主功能号。如果像前面的例子一样,使用一个函数处理所有的IRP,那么首先就要得到IRP的主功能号。IRP的主功能号在IRP的当前栈空间中。
IRP总是发送给一个设备栈。到每个设备上的时候拥有一个“当前栈空间”来保存在这个设备上的请求信息。读者请暂时忽略这些细节。下面的代码在MyDispatch中获得主功能号,同时展示了几个常见的主功能号:
NTSTATUS MyDispatchFunction(PDEVICE_OBJECT device,PIRP irp)
{
// 获得当前irp调用栈空间
PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(irp);
NTSTATUS status = STATUS_UNSUCCESSFUL;
swtich(irpsp->MajorFunction)
{
// 处理打开请求
case IRP_MJ_CREATE:
……
break;
// 处理关闭请求
case IRP_MJ_CLOSE:
……
break;
// 处理设备控制信息
case IRP_MJ_DEVICE_CONTROL:
……
break;
// 处理读请求
case IRP_MJ_READ:
……
break;
// 处理写请求
case IRP_MJ_WRITE:
……
break;
default:
…
break;
}
return status;
}
用于与应用程序通信时,上面这些请求都由应用层API引发。对应的关系大致如下:
应用层调用的API | 驱动层收到的IRP主功能号 |
---|---|
CreateFile | IRP_MJ_CREATE |
CloseHandle | IRP_MJ_CLOSE |
DeviceIoControl | IRP_MJ_DEVICE_CONTROL |
ReadFile | IRP_MJ_READ |
WriteFile | IRP_MJ_WRITE |
了解以上信息的情况下,完成相关IRP的处理,就可以实现应用层和驱动层的通信了。具体的编程在紧接后面的两小节里完成。