处理客户端实现的序列

可选的 EvtSpbControllerLockEvtSpbControllerUnlock 事件回调函数执行补充操作。 EvtSpbControllerLock 函数是IOCTL_SPB_LOCK_CONTROLLER请求的处理程序。 EvtSpbControllerUnlock 函数是用于IOCTL_SPB_UNLOCK_CONTROLLER请求的处理程序。 客户端 (,即总线上外围设备的驱动程序) 发送这些请求以启动和结束 I/O 传输序列。 大多数 SPB 控制器驱动程序不支持 IOCTL_SPB_LOCK_CONTROLLERIOCTL_SPB_UNLOCK_CONTROLLER 请求,因此不实现 EvtSpbControllerLockEvtSpbControllerUnlock 函数。

客户端可以将 I/O 传输序列作为一系列简单的传输请求执行, () IRP_MJ_READIRP_MJ_WRITE 请求。 序列中的第一个传输前面必须是 IOCTL_SPB_LOCK_CONTROLLER 请求,此请求告知 SPB 控制器驱动程序在 I/O 传输序列期间锁定总线。 最后一次转移后必须有一个 IOCTL_SPB_UNLOCK_CONTROLLER 请求,告知司机解锁巴士。 这种类型的 I/O 传输序列称为 客户端实现的序列 ,以将其与 单请求序列区分开来,该序列使用 IOCTL_SPB_EXECUTE_SEQUENCE 请求而不是 IOCTL_SPB_LOCK_CONTROLLERIOCTL_SPB_UNLOCK_CONTROLLER 请求。

虽然外围设备的驱动程序在总线上持有锁,但总线控制器允许访问总线上的任何其他外围设备。 总线锁定操作的详细信息取决于总线类型。 对于 I2C 控制器,更改传输方向 (读取后再写入,反之亦然,) 需要 I2C 重启操作。 对于 SPI 控制器,当控制器锁保持有效时,目标设备的芯片选择必须保持断言状态。 有关详细信息,请参阅 原子总线操作

对客户端实现的传输序列的支持是可选的。 仅当控制器可以执行以下操作时,SPB 控制器驱动程序才应声明支持它们:

  • 在客户端实现的序列期间锁定总线。
  • 随时解锁总线。 例如,如果在字节传输之间发生解锁请求,则控制器应该能够解锁总线,而无需等待总线上的下一个字节传输。

当总线锁定时,客户端可以发送任意序列的简单传输请求。 也就是说,序列可以是任意长度,并且可以是读取和写入的任意组合。

为了指示对客户端实现的序列的支持,SPB 控制器驱动程序实现了 EvtSpbControllerUnlock 函数。 如果驱动程序实现此函数,SPB 框架扩展 (SpbCx) 接受 来自客户端的IOCTL_SPB_LOCK_CONTROLLERIOCTL_SPB_UNLOCK_CONTROLLER 请求。 否则,SpbCx 会通过STATUS_NOT_SUPPORTED状态代码完成这些请求,使这些请求失败。

实现 EvtSpbControllerUnlock 函数不需要实现 EvtSpbControllerUnlock 函数的 SPB 控制器驱动程序。 但是,实现 EvtSpbControllerLock 函数的 SPB 控制器驱动程序还必须实现 EvtSpbControllerUnlock 函数。

如果驱动程序实现 EvtSpbControllerUnlock 函数而不是 EvtSpbControllerLock 函数,则 SpbCx 调用 EvtSpbControllerUnlock 函数来处理 IOCTL_SPB_UNLOCK_CONTROLLER 请求,但只需使用 STATUS_SUCCESS 状态代码完成IOCTL_SPB_LOCK_CONTROLLER请求。

驱动程序有两种方法来检测客户端实现的序列的开始。 首先,如果驱动程序实现 EvtSpbControllerLock 函数,SpbCx 会调用此函数来处理来自客户端 的IOCTL_SPB_LOCK_CONTROLLER 请求。 驱动程序可以依赖于在序列中的第一个传输请求之前发生的此调用。 其次,如果驱动程序未实现 EvtSpbControllerLock 函数,则驱动程序可以在驱动程序处理来自客户端的简单传输请求时调用 SpbRequestGetParameters 方法。 为了指示请求的传输是序列中的第一个传输,此方法将方法的输出结构中的 Position 成员设置为 SpbRequestSequencePositionFirst

EvtSpbControllerUnlock 回调是驱动程序确定序列何时结束的唯一方法。 不实现 EvtSpbControllerUnlock 函数的驱动程序不能支持客户端实现的序列。