I/O 传输序列

SPB 框架扩展 (SpbCx) 支持 I/O 传输序列。 I/O 传输序列是一组有序的总线传输, (读取和写入操作) 作为单个原子总线操作执行。 I/O 传输序列中的所有传输都访问总线上的同一目标设备。 在执行序列时,无法访问总线上的其他设备,即使 SPB 控制器驱动程序可能会在 I/O 传输序列完成之前收到其他设备的 I/O 请求。

I/O 传输序列的一个示例是写入-读取操作,该操作是一个总线写入操作,后跟一个总线读取操作。 客户端外围设备驱动程序可以使用这种类型的序列写入 SPB 连接的外围设备中的函数选择寄存器,然后读取所选设备函数的值。 这两个传输的长度可能不同。 例如,写入操作可能会传输一个字节的数据,读取操作可能会传输许多字节的数据。

I/O 传输序列的类型

客户端可以通过以下方式之一启动 I/O 传输序列:

  1. 客户端可以在 IOCTL_SPB_EXECUTE_SEQUENCE I/O 控制请求中指定整个序列。 此请求使 SPB 控制器驱动程序能够使用任何特定于硬件的性能优化来执行传输序列。 有关详细信息,请参阅 单请求序列

  2. 客户端可以发送 IOCTL_SPB_LOCK_CONTROLLER I/O 控制请求,以在序列开始时锁定控制器,并在序列完成时发送 IOCTL_SPB_UNLOCK_CONTROLLER 。 锁定控制器时,客户端 (IRP_MJ_READ或IRP_MJ_WRITE) 序列中的每个读取或写入操作发送单独的 I/O 请求。 有关详细信息,请参阅 客户端实现的序列

客户端应尽可能使用 IOCTL_SPB_EXECUTE_SEQUENCE 请求,该请求速度更快,不容易出错,并显著减少其他客户端被锁定在总线之外的时间。 但是,如果客户端必须查看在序列中的某个传输期间读取的值,则客户端可以使用 IOCTL_SPB_LOCK_CONTROLLERIOCTL_SPB_UNLOCK_CONTROLLER 请求,然后才能在序列中启动后续传输。 在这种情况下,需要仔细设计,以避免将其他客户端锁定在总线之外超过必要时间,并且设计不当的外围驱动程序可能会降低整体系统性能。

Single-Request序列

若要提高性能,SPB 控制器驱动程序应实现 EvtSpbControllerIoSequence 回调函数来处理 IOCTL_SPB_EXECUTE_SEQUENCE 请求。 此方法为 SPB 控制器驱动程序增加了一些复杂性,但避免了要求客户端执行 I/O 传输序列作为一系列单独的读取和写入操作,而其他客户端被锁定在总线之外。

注意

强烈建议实现 EvtSpbControllerIoSequence 函数,并可能成为Windows 8的要求。

传输序列的实现类似于简单的读取或写入操作,但还需要更新序列中各个传输之间的序列操作的存储状态。 第一次传输完成后,SPB 控制器驱动程序更新序列状态,以选择序列中的下一个传输。 序列状态存储在设备上下文中,包括传递给 EvtSpbControllerIoSequence 回调的 SPBREQUEST 句柄。 SPB 控制器驱动程序使用此句柄获取序列中各个传输的缓冲区、长度、方向和位置参数。 有关获取这些参数的详细信息,请参阅 SpbRequestGetTransferParameters

如果 SPB 控制器驱动程序无法执行请求 的IOCTL_SPB_EXECUTE_SEQUENCE 操作,它将以失败代码完成请求。 如果发生此类故障,客户端可以选择锁定总线,以一系列简单的 I/O 请求的形式显式执行 I/O 传输序列,然后解锁总线。 有关详细信息,请参阅 客户端实现的序列

SpbCx 对从外围设备驱动程序收到的 IOCTL_SPB_XXX 请求执行参数检查。 对于 IOCTL_SPB_EXECUTE_SEQUENCE 请求,SpbCx 会拒绝空序列和包含 NULL 缓冲区指针或零长度缓冲区的序列。

SPB 控制器驱动程序应验证序列中每个传输的长度是否不超过驱动程序指定的限制。 例如,Windows 驱动程序工具包中的 SkeletonI2C 示例驱动程序 (WDK) 失败了指定超过 4K 字节的传输的 IOCTL_SPB_EXECUTE_SEQUENCE 请求,并将此请求的状态代码设置为STATUS_INVALID_PARAMETER。 在为 IOCTL_SPB_EXECUTE_SEQUENCE 请求启动序列操作之前,驱动程序应验证序列中所有传输的参数,以验证操作是否可以成功完成。

SpbCx 永远不会在 EvtSpbControllerIoSequence 回调之前使用 EvtSpbControllerLock 回调,并且它永远不会在 EvtSpbControllerIoSequence 回调之后使用 EvtSpbControllerUnlock 回调。

Client-Implemented序列

SPB 控制器驱动程序的客户端可以显式执行 I/O 传输序列作为一系列简单的读取和写入操作。 客户端可以是内核模式驱动程序,也可以是控制连接到总线的外围设备的用户模式驱动程序。 在序列中的第一次传输之前,客户端会向目标设备发送 IOCTL_SPB_LOCK_CONTROLLER 请求,以防止在序列中的传输之间发生其他不相关的总线访问。 接下来,客户端发送 IRP_MJ_READIRP_MJ_WRITE 请求以按顺序执行传输。 最后,客户端发送 释放锁的IOCTL_SPB_UNLOCK_CONTROLLER 请求。

如果序列中的后续传输依赖于较早的传输,则客户端可能需要实现这种类型的 I/O 传输序列。 例如,第一次读取可能指示后续要读取或写入的字节数。 但是,如果不存在此类依赖项,客户端应向 SPB 控制器驱动程序发送 IOCTL_SPB_EXECUTE_SEQUENCE 请求,后者可以更有效地执行序列。

在启动客户端实现序列 的IOCTL_SPB_LOCK_CONTROLLER 请求和结束序列 的IOCTL_SPB_UNLOCK_CONTROLLER 请求之间,客户端可以发送到目标设备的唯一 I/O 请求是 IRP_MJ_READIRP_MJ_WRITE 请求。 任何违反此规则的行为都是错误。

SPB 锁仅用于保证读取和写入序列作为原子总线操作执行,并且应专用于此目的。

有关详细信息,请参阅 处理Client-Implemented序列