在函数驱动程序中启动设备

函数驱动程序设置 IoCompletion 例程,在设备堆栈中向下传递 IRP_MN_START_DEVICE 请求,并推迟其启动操作,直到所有较低的驱动程序都已完成 IRP。 有关使用内核事件和 IoCompletion 例程推迟 IRP 处理的详细信息,请参阅将 PnP IRP 处理推迟到较低的驱动程序完成

当其 DispatchPnP 例程在所有较低级驱动程序使用 IRP 完成后重新获得控制权时,函数驱动程序将执行其启动设备的任务。 函数驱动程序使用如下过程启动设备:

  1. 如果较低版本的驱动程序失败,IRP (IoCallDriver) 返回错误,请不要继续处理 IRP。 执行任何必要的清理并从 DispatchPnP 例程返回, (转到此列表中的最后一个步骤) 。

  2. 如果较低的驱动程序已成功处理 IRP,请启动设备。

    启动设备的确切步骤因设备而异。 此类步骤可能包括映射 I/O 空间、初始化硬件寄存器、将设备设置为 D0 电源状态,以及使用 IoConnectInterrupt 连接中断。 如果驱动程序在 IRP_MN_STOP_DEVICE 请求后重启设备,则驱动程序可能具有要还原的设备状态。

    必须先打开设备,然后任何驱动程序才能访问它。 有关详细信息 ,请参阅启动设备

    如果应为设备启用唤醒,其电源策略所有者 (通常函数驱动程序) 应在设备通电后和完成 IRP_MN_START_DEVICE 请求之前发送等待/唤醒 IRP。 有关详细信息,请参阅 发送等待/唤醒 IRP

  3. 启动 IRP 持有队列中的 IRP。

    清除驱动程序定义的HOLD_NEW_REQUESTS标志,并启动 IRP 持有队列中的 IRP。 驱动程序应在首次启动设备时以及查询停止或停止 IRP 后重启设备时执行此操作。 有关详细信息,请参阅在 设备暂停时保持传入 IRP

  4. [可选]通过调用 IoSetDeviceInterfaceState 为设备启用接口。

    启用驱动程序以前在其 AddDevice 例程 (、INF 或其他组件(如辅助安装程序) )中注册的接口(如果有)。

    在 Windows 2000 及更高版本的 Windows 上,在 IRP_MN_START_DEVICE IRP 完成之前,PnP 管理器不会发送设备接口到达通知,指示设备的所有驱动程序已完成其启动操作。 在设备的所有驱动程序完成启动 IRP 之前,PnP 管理器还会使到达的任何创建请求失败。

  5. 完成 IRP。

    函数驱动程序的 IoCompletion 例程STATUS_MORE_PROCESSING_REQUIRED返回,如 将 PnP IRP 处理推迟到较低驱动程序完成中所述,因此函数驱动程序的 DispatchPnP 例程必须调用 IoCompleteRequest 以恢复 I/O 完成处理。

    如果函数驱动程序的启动操作成功,驱动程序会将 Irp-IoStatus.Status> 设置为 STATUS_SUCCESS,调用 IoCompleteRequest,优先级提升为 IO_NO_INCREMENT,并从其 DispatchPnP 例程返回STATUS_SUCCESS。

    如果函数驱动程序在其启动操作期间遇到错误,驱动程序会在 IRP 中设置错误状态,使用 IO_NO_INCREMENT调用 IoCompleteRequest ,并从其 DispatchPnP 例程返回错误。

    如果较低级驱动程序失败,IRP (IoCallDriver 返回错误) ,函数驱动程序使用 IO_NO_INCREMENT 调用 IoCompleteRequest,并从其 DispatchPnP 例程返回 IoCallDriver 错误。 在这种情况下,函数驱动程序不会设置 Irp-IoStatus.Status>,因为状态已由 IRP 失败的较低驱动程序设置。

当函数驱动程序收到IRP_MN_START_DEVICE请求时,它应检查 IrpSp-Parameters.StartDevice.AllocatedResources>IrpSp-Parameters.StartDevice.AllocatedResourcesTranslated> 中的结构,它们分别描述了 PnP 管理器分配给设备的原始资源和已翻译的资源。 驱动程序应在设备扩展中保存每个资源列表的副本作为调试辅助。

资源列表 CM_RESOURCE_LIST 结构配对,其中原始列表的每个元素对应于已翻译列表的同一元素。 例如,如果 AllocatedResources.List[0] 描述原始 I/O 端口范围,则 AllocatedResourcesTranslated.List[0] 描述转换后的相同范围。 每个已翻译的资源都包含一个物理地址和资源类型。

如果为驱动程序分配了已转换的内存资源 (CmResourceTypeMemory) ,则必须调用 MmMapIoSpace 将物理地址映射到可访问设备寄存器的虚拟地址。 要使驱动程序以独立于平台的方式运行,它应检查每个返回的已翻译资源,并在必要时对其进行映射。

函数驱动程序应执行以下操作以响应 IRP_MN_START_DEVICE ,以确保访问所有设备资源:

  1. IrpSp-Parameters.StartDevice.AllocatedResources> 复制到设备扩展。

  2. IrpSp-Parameters.StartDevice.AllocatedResourcesTranslated> 复制到设备扩展。

  3. 在循环中,检查 AllocatedResourcesTranslated 中的每个描述符元素。 如果描述符资源类型为 CmResourceTypeMemory,请调用 MmMapIoSpace,传递已转换资源的物理地址和长度。

当驱动程序收到 IRP_MN_STOP_DEVICEIRP_MN_REMOVE_DEVICEIRP_MN_SURPRISE_REMOVAL 请求时,它必须通过在类似的循环中调用 MmUnmapIoSpace 来释放映射。 如果驱动程序必须使IRP_MN_START_DEVICE请求失败,则驱动程序还应调用 MmUnmapIoSpace

有关详细信息 ,请参阅将 Bus-Relative 地址映射到虚拟地址