SerCx2 Custom-Receive 事务

某些串行控制器硬件可能实现 PIO 或系统 DMA 以外的数据传输机制,以便从串行控制器读取数据。 串行控制器驱动程序可以支持自定义接收事务,使此数据传输机制可供 SerCx2 使用。

为了启动自定义接收事务,SerCx2 调用驱动程序的 EvtSerCx2CustomReceiveTransactionStart 事件回调函数,并作为参数提供读取 (IRP_MJ_READ) 请求和事务读取缓冲区的说明。 在此调用中,函数启动事务并返回 。 然后,驱动程序负责完成事务并完成读取请求。

创建自定义接收对象

在 SerCx2 可以调用任何串行控制器驱动程序的 EvtSerCx2CustomReceiveTransactionXxx** 函数之前,驱动程序必须调用 SerCx2CustomReceiveTransactionCreate 方法以将这些函数注册到 SerCx2。 此方法接受指向 SERCX2_CUSTOM_RECEIVE_TRANSACTION_CONFIG 结构的指针作为输入参数,该结构包含指向驱动程序的 EvtSerCx2CustomReceiveTransactionXxx** 函数的指针。

驱动程序必须实现以下两个函数:

作为选项,驱动程序可以实现以下三个函数中的任何或全部:

SerCx2CustomReceiveTransactionCreate 方法创建自定义接收对象,并为调用驱动程序提供此对象的 SERCX2CUSTOMRECEIVETRANSACTION 句柄。 驱动程序的 EvtSerCx2CustomReceiveTransactionXxx** 函数都将此句柄作为其第一个参数。 以下 SerCx2 方法将此句柄作为其第一个参数:

硬件初始化和清理

某些串行控制器驱动程序可能需要在自定义接收事务开始时初始化串行控制器硬件,或者在事务结束时清理串行控制器的硬件状态。

如果驱动程序实现 EvtSerCx2CustomReceiveTransactionInitialize 事件回调函数,SerCx2 将调用此函数以在启动事务之前初始化串行控制器。 如果实现, EvtSerCx2CustomReceiveTransactionInitialize 函数必须调用 SerCx2CustomReceiveTransactionInitializeComplete 方法,以在驱动程序完成串行控制器初始化时通知 SerCx2。

如果驱动程序实现 EvtSerCx2CustomReceiveTransactionCleanup 事件回调函数,则 SerCx2 调用此函数以在事务结束后清理硬件状态。 如果实现, EvtSerCx2CustomReceiveTransactionInitialize 函数必须调用 SerCx2CustomReceiveTransactionCleanupComplete 方法,以在驱动程序完成清理串行控制器时通知 SerCx2。

新数据通知

作为选项,串行控制器驱动程序可以实现 EvtSerCx2CustomReceiveTransactionEnableNewDataNotification 事件回调函数。 如果实现,SerCx2 使用此函数有效地管理在处理作为自定义接收事务处理的读取请求期间发生的间隔超时。

如果串行控制器接收的两个连续字节之间的间隔超过客户端指定的最长时间,则会发生间隔超时。 在外围驱动程序向 SerCx2 发送读取请求后,除非从串行连接的外围设备收到至少一个字节的数据,否则无法发生间隔超时。 读取请求的到达与从外围设备接收第一个字节数据之间的时间可能明显长于接收第一个字节后读取请求的其余数据所需的时间。 有关详细信息,请参阅 SERIAL_TIMEOUTS

SerCx2 调用 EvtSerCx2CustomReceiveTransactionEnableNewDataNotification 函数(如果已实现),以启用新数据通知。 如果启用此通知,并且串行控制器从外围设备接收一个或多个字节的新数据,或者其接收 FIFO 中已有数据,则串行控制器驱动程序必须调用 SerCx2CustomReceiveTransactionNewDataNotification 方法来通知 SerCx2。

为了检测可能的间隔超时,SerCx2 定期调用 EvtSerCx2CustomReceiveTransactionQueryProgress 事件回调函数,以检查在上述间隔期间是否收到任何数据。 SerCx2 如何检测接收第一个字节的数据取决于串行控制器驱动程序是否实现 EvtSerCx2CustomReceiveTransactionEnableNewDataNotification 函数。 如果实现此函数,SerCx2 将调用函数以启用新数据通知,并在收到数据的第一个字节时由驱动程序通知。 否则,SerCx2 会定期调用 EvtSerCx2CustomReceiveTransactionQueryProgress 函数来检测第一个字节的接收,并且可能需要定期唤醒处理器才能进行这些调用。 因此,实现 EvtSerCx2CustomReceiveTransactionEnableNewDataNotification 函数的驱动程序可以通过不要求处理器频繁唤醒来降低能耗。

SerCx2 不会显式取消自定义接收事务的挂起的新数据通知。 但是,如果启用了新数据通知,并且驱动程序出于以下原因之一必须完成关联的读取请求,则串行控制器驱动程序可能需要隐式取消新数据通知:

  • 读取请求超时或已取消。
  • 串行控制器即将退出 D0 设备电源状态,进入低功耗状态。

驱动程序通常调用 WdfRequestComplete 等方法来完成请求。 请求完成后,驱动程序不得调用 SerCx2CustomReceiveTransactionNewDataNotification

访问请求对象

为了启动自定义接收事务,SerCx2 调用驱动程序的 EvtSerCx2CustomReceiveTransactionStart 函数,并将封装在 WDFREQUEST 对象句柄中的关联读取请求 () 作为参数传递给此函数。 驱动程序负责调用 WdfRequestComplete 等方法,以便在事务完成时完成此请求。 除非请求可以立即完成,否则 在 EvtSerCx2CustomReceiveTransactionStart 函数返回之前,驱动程序必须调用 WdfRequestMarkCancelableEx 等方法,以将请求标记为可取消。

串行控制器驱动程序不得使用 WdfRequestRetrieveOutputBuffer 等方法来访问读取请求中的数据缓冲区。 相反,驱动程序应使用传递给 EvtSerCx2CustomReceiveTransactionStart 函数的 MdlOffsetLength 参数值来访问此缓冲区。

在自定义接收事务期间,驱动程序可能需要在附加到请求对象的上下文中存储有关事务的信息。 如果是这样,驱动程序的 EvtDriverDeviceAdd 事件回调函数可以调用 WdfDeviceInitSetRequestAttributes 方法,以设置要用于请求对象的属性。 这些属性包括用于请求上下文的名称和分配大小。 在此调用中指定的请求属性必须与驱动程序在对 SerCx2InitializeDevice 方法的调用中指定的请求属性匹配。 这些属性在驱动程序传递到 SerCx2InitializeDeviceSERCX2_CONFIG 结构的 RequestAttributes 成员中指定。 有关详细信息,请参阅 SERCX2_CONFIG

对于串行控制器驱动程序在自定义接收事务开始时收到的读取请求,驱动程序框架分配的请求上下文未初始化。 作为最佳做法,驱动程序应调用 RtlZeroMemory 例程,将此请求上下文初始化为所有零。