编写 DPC 例程

DpcForIsrCustomDpc 例程的主要职责是确保迅速启动下一个设备 I/O 操作并完成当前 IRP。

任何 DpcForIsrCustomDpc 例程完成的其他工作都取决于驱动程序的设计和设备的性质。 例如, DpcForIsrCustomDpc 例程也可以执行以下任一操作:

  • 重试已超时或失败的操作。

  • 调用 IoAllocateErrorLogEntry,设置错误日志数据包以报告设备 I/O 错误,并调用 IoWriteErrorLogEntry

    有关处理 I/O 错误的详细信息,请参阅 记录错误

  • 如果驱动程序使用缓冲 I/O,或者如果 IRP 指定了设备控制操作,请在完成 IRP 之前,将读取的数据从设备传输到 Irp-AssociatedIrp.SystemBuffer> 的系统缓冲区。

  • 如果驱动程序使用 直接 I/O ,并且必须将大型传输分解为较小的部分传输,请保存每个刚刚完成的部分传输操作的状态,计算下一个部分传输范围,并使用驱动程序提供的 SynchCritSection 例程对设备进行编程,以便执行下一个部分传输操作。

    即使使用缓冲 I/O 的驱动程序也可能需要拆分传输请求(如果其设备具有有限的传输功能)。

  • 如果驱动程序使用基于数据包的 DMA,请在每次设备传输操作后调用 FlushAdapterBuffers ,并在完成一系列部分传输并满足完整传输请求时调用 FreeAdapterChannelFreeMapRegisters

    如果单个 DMA 操作仅部分满足请求的传输, 则 DpcForIsrCustomDpc 例程通常负责设置一个或多个 DMA 操作,直到 IRP 的指定字节数完全传输为止。

    有关使用 DMA 的详细信息,请参阅 适配器对象和 DMA

  • 如果驱动程序使用编程的 I/O (PIO) ,则如果当前 IRP 请求读取,请在每次传输操作结束时调用 KeFlushIoBuffers

    如果单个 PIO 操作仅部分满足请求的传输, 则 DpcForIsrCustomDpc 例程通常负责设置一个或多个传输操作,直到 IRP 的指定字节数完全传输。

    有关使用 PIO 的详细信息,请参阅 使用直接 I/O

  • 如果非 WDM 驱动程序具有 ControllerControl 例程,请在请求的操作完成时调用 IoFreeController

请注意, DpcForIsrCustomDpc 例程通常执行驱动程序的大部分设备 I/O 处理以满足 IRP。 这些例程还与驱动程序的调度例程共同承担将 IRP 排队到设备的一些责任。

请考虑以下常规设计准则。

  • 任何 DpcForIsrCustomDpc 例程都应在能够安全地进行此调用后立即调用 IoStartNextPacket :也就是说,不会与驱动程序的 StartIo 例程或 StartIo 例程导致运行的任何其他例程发生资源冲突或争用情况。

  • 如果驱动程序管理自己的 IRP 队列,则其 DpcForIsrCustomDpc 例程应立即通知驱动程序,只要它安全地取消下一个 IRP 排队并为下一个请求设置设备。

DpcForIsrCustomDpc 例程必须调用 IoStartNextPacket,或者在可以启动下一个请求的设备 I/O 处理时通知相应的驱动程序例程。 根据驱动程序及其设备,这种情况可能在 DpcForIsrCustomDpc 例程使用 IoCompleteRequest 完成当前 IRP 之前发生,也可能在此例程完成当前 IRP 并返回控件之前立即发生。