编写 DPC 例程
DpcForIsr 和 CustomDpc 例程的主要职责是确保迅速启动下一个设备 I/O 操作并完成当前 IRP。
任何 DpcForIsr 或 CustomDpc 例程完成的其他工作都取决于驱动程序的设计和设备的性质。 例如, DpcForIsr 或 CustomDpc 例程也可以执行以下任一操作:
重试已超时或失败的操作。
调用 IoAllocateErrorLogEntry,设置错误日志数据包以报告设备 I/O 错误,并调用 IoWriteErrorLogEntry。
有关处理 I/O 错误的详细信息,请参阅 记录错误。
如果驱动程序使用缓冲 I/O,或者如果 IRP 指定了设备控制操作,请在完成 IRP 之前,将读取的数据从设备传输到 Irp-AssociatedIrp.SystemBuffer> 的系统缓冲区。
如果驱动程序使用 直接 I/O ,并且必须将大型传输分解为较小的部分传输,请保存每个刚刚完成的部分传输操作的状态,计算下一个部分传输范围,并使用驱动程序提供的 SynchCritSection 例程对设备进行编程,以便执行下一个部分传输操作。
即使使用缓冲 I/O 的驱动程序也可能需要拆分传输请求(如果其设备具有有限的传输功能)。
如果驱动程序使用基于数据包的 DMA,请在每次设备传输操作后调用 FlushAdapterBuffers ,并在完成一系列部分传输并满足完整传输请求时调用 FreeAdapterChannel 或 FreeMapRegisters 。
如果单个 DMA 操作仅部分满足请求的传输, 则 DpcForIsr 或 CustomDpc 例程通常负责设置一个或多个 DMA 操作,直到 IRP 的指定字节数完全传输为止。
有关使用 DMA 的详细信息,请参阅 适配器对象和 DMA。
如果驱动程序使用编程的 I/O (PIO) ,则如果当前 IRP 请求读取,请在每次传输操作结束时调用 KeFlushIoBuffers 。
如果单个 PIO 操作仅部分满足请求的传输, 则 DpcForIsr 或 CustomDpc 例程通常负责设置一个或多个传输操作,直到 IRP 的指定字节数完全传输。
有关使用 PIO 的详细信息,请参阅 使用直接 I/O。
如果非 WDM 驱动程序具有 ControllerControl 例程,请在请求的操作完成时调用 IoFreeController 。
请注意, DpcForIsr 或 CustomDpc 例程通常执行驱动程序的大部分设备 I/O 处理以满足 IRP。 这些例程还与驱动程序的调度例程共同承担将 IRP 排队到设备的一些责任。
请考虑以下常规设计准则。
任何 DpcForIsr 或 CustomDpc 例程都应在能够安全地进行此调用后立即调用 IoStartNextPacket :也就是说,不会与驱动程序的 StartIo 例程或 StartIo 例程导致运行的任何其他例程发生资源冲突或争用情况。
如果驱动程序管理自己的 IRP 队列,则其 DpcForIsr 或 CustomDpc 例程应立即通知驱动程序,只要它安全地取消下一个 IRP 排队并为下一个请求设置设备。
DpcForIsr 或 CustomDpc 例程必须调用 IoStartNextPacket,或者在可以启动下一个请求的设备 I/O 处理时通知相应的驱动程序例程。 根据驱动程序及其设备,这种情况可能在 DpcForIsr 或 CustomDpc 例程使用 IoCompleteRequest 完成当前 IRP 之前发生,也可能在此例程完成当前 IRP 并返回控件之前立即发生。