功能驱动将构造请求包,就可以发送到底层总线驱动上。因此需要创建一个IRP,这就需要用IoBuildDeviceIoControlRequest创建一个IO控制码的IRP,用IoCallDriver将URB发送到底层总线驱动上。由于上层驱动无法知道底层驱动是同步还是异步完成的,因此需要做一个判断。if语句判断当异步完成IRP时,用事件等待总线驱动完成这个IRP。
#001 NTSTATUS
#002 VfatBlockDeviceIoControl (IN PDEVICE_OBJECT DeviceObject,
#003 IN ULONG CtlCode,
#004 IN PVOID InputBuffer OPTIONAL,
#005 IN ULONG InputBufferSize,
#006 IN OUT PVOID OutputBuffer OPTIONAL,
#007 IN OUT PULONG OutputBufferSize,
#008 IN BOOLEAN Override)
#009 {
#010 PIO_STACK_LOCATION Stack;
#011 KEVENT Event;
#012 PIRP Irp;
#013 IO_STATUS_BLOCK IoStatus;
#014 NTSTATUS Status;
#015
#016 DPRINT("VfatBlockDeviceIoControl(DeviceObject %p,CtlCode %x,"
#017 "InputBuffer %p,InputBufferSize %x,OutputBuffer %p,"
#018 "OutputBufferSize %p (%x)/n",DeviceObject,CtlCode,
#019 InputBuffer,InputBufferSize,OutputBuffer,OutputBufferSize,
#020 OutputBufferSize ? *OutputBufferSize : 0);
#021
初始化通知的事件。
#022 KeInitializeEvent (&Event,NotificationEvent,FALSE);
#023
#024 DPRINT("Building device I/O control request .../n");
创建控制码相关的IRP包。
#025 Irp = IoBuildDeviceIoControlRequest(CtlCode,
#026 DeviceObject,
#027 InputBuffer,
#028 InputBufferSize,
#029 OutputBuffer,
#030 (OutputBufferSize) ? *OutputBufferSize : 0,
#031 FALSE,
#032 &Event,
#033 &IoStatus);
如果创建IRP包不成功,就直接返回出错。
#034 if (Irp == NULL)
#035 {
#036 DPRINT("IoBuildDeviceIoControlRequest Failed/n");
#037 return STATUS_INSUFFICIENT_RESOURCES;
#038 }
#039
是否需要获取下一层的设备栈。
#040 if (Override)
#041 {
需要获取下一层次的设备栈。
#042 Stack = IoGetNextIrpStackLocation(Irp);
#043 Stack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
#044 }
#045
#046 DPRINT ("Calling IO Driver... with irp %p/n",Irp);
把IRP包发送到下一个设备驱动程序。
#047 Status = IoCallDriver(DeviceObject,Irp);
#048
#049 DPRINT ("Waiting for IO Operation for %p/n",Irp);
如果在阻塞状态,就等待下层驱动程序完成。
#050 if (Status == STATUS_PENDING)
#051 {
#052 DPRINT ("Operation pending/n");
这里就是等前面创建的事件。
#053 KeWaitForSingleObject (&Event,Suspended,KernelMode,FALSE,NULL);
#054 DPRINT ("Getting IO Status... for %p/n",Irp);
#055
#056 Status = IoStatus.Status;
#057 }
#058
返回输出缓冲区的大小。
#059 if (OutputBufferSize)
#060 {
#061 *OutputBufferSize = IoStatus.Information;
#062 }
#063
#064 DPRINT("Returning Status %x/n",Status);
#065
#066 return Status;
#067}