USB 主控制器驱动程序的根集线器回调函数
UCX 执行根中心管理。 它模拟和管理虚拟控制与中断端点。 当主控制器驱动程序创建根中心对象时,UCX 会创建这些虚拟端点。
USB 集线器驱动程序与根集线器的交互方式与常规集线器设备交互的方式相同。 但是,主控制器驱动程序不必直接处理发送到根中心以控制端点和中断端点的请求。 UCX 处理这些请求。 UCX 调用由主机控制器驱动程序实现的回调函数,以便它可以返回有关主机控制器端口当前状态的相关信息。 完成这些回调函数后,基础 UCX 请求将完成并返回到中心驱动程序。
收到根中心的中断传输时,UCX 会将请求设置为挂起。 当在其中一个根中心端口上检测到更改时,主机控制器驱动程序将调用 UcxRootHubPortChanged。 然后,UCX 调用驱动程序的 EVT_UCX_ROOTHUB_INTERRUPT_TX 回调,驱动程序指示已更改的端口。 此时,UCX 将完成挂起的请求返回到中心驱动程序。 中心驱动程序将控制传输发送到根中心,以获取发出更改信号的端口的端口状态。 UCX 将该控制传输请求设置为挂起,并调用驱动程序的 EVT_UCX_ROOTHUB_CONTROL_URB 回调函数。 在实现中,返回根中心端口的当前状态,包括指示设备已连接。 UCX 完成对中心驱动程序的控制传输请求,设备枚举将继续。
处理 USB 主控制器驱动程序中的 I/O 请求
用于处理 UCX 发送的 I/O 请求的主控制器驱动程序的最佳做法。
UCX 跟踪由 USB 总线上的设备的主机控制器驱动程序创建的所有端点。 中心驱动程序或 USB 设备堆栈中较高位置的其他驱动程序发送的任何数据传输请求首先由 UCX 处理。 UCX 负责将框架请求对象转发到正确的端点队列。 请求中包含的 USB 请求块 (URB) 可以指定端点句柄。 如果指定了端点句柄,UCX 会在设备存在的端点中检查相应的端点。 如果存在指定的端点句柄,则请求将转发到端点的队列。 如果未找到指定的端点句柄,则请求失败。 如果未指定句柄,则请求针对默认端点,UCX 会将请求转发到该设备的主控制器驱动程序的默认端点队列。
为了确保与现有 USB 驱动程序兼容,主机控制器在完成 URB 请求时必须符合以下要求:
必须在DISPATCH_LEVEL调用 WdfRequestComplete。
如果 URB 已传递到其框架队列,并且驱动程序开始在调用驱动程序的线程或 DPC 上同步处理它,则不应同步完成请求。 必须在单独的 DPC 上完成请求,该 DPC 可以通过调用 WdfDpcEnqueue 进行计划。
与上述要求类似,在收到 EVT_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE 或 EVT_WDF_REQUEST_CANCEL时,主机控制器驱动程序必须在与调用线程或 DPC 不同的 DPC 上完成 URB 请求。 默认情况下,WDF 同步完成队列中已取消的请求。 该行为可能会导致 URB 请求出现问题。 因此,驱动程序必须为其 URB 队列提供 EvtIoCanceledOnQueue 回调。
IOCTL_INTERNAL_USB_SUBMIT_URB的框架请求对象包含位于请求的 Parameters.Others.Arg1 中的 URB。 请求完成后,URB 状态必须设置为USBD_STATUS_SUCCESS或指示失败性质的失败状态。 失败状态值在 usb.h 头文件中定义。
在 USB 主控制器驱动程序中配置 USB 端点
UCX 管理端点对象的创建,并通知主机控制器将端点编程或反编程到 USB 主控制器。
在对端点进行编程时,它也由 UCX 管理。 当设备连接到总线并断开连接时,端点的状态会更改,遇到电源事件(例如挂起和重置),并经历新的端点创建(例如备用设置更改)。
1. 端点配置:UCX 调用由主控制器驱动程序实现的回调函数,以在端点必须编程到 USB 主控制器或释放端点时通知驱动程序。 调用 EVT_UCX_USBDEVICE_ENABLE 时,驱动程序将准备控制器以执行到设备的默认端点的传输。 准备控制器包括对默认端点进行编程。 调用 EVT_UCX_USBDEVICE_DISABLE 时,驱动程序会取消对默认端点进行编程,并释放与设备关联的其他控制器资源。 调用 EVT_UCX_USBDEVICE_ENDPOINTS_CONFIGURE 时,会为驱动程序提供要编程到控制器中的非默认端点列表,并为其提供要从控制器中删除的另一个非默认端点列表。 然后,主控制器驱动程序将指定的非默认端点程序化到控制器中,并从控制器中删除其他列表中指定的非默认端点 。
2. 队列状态管理:UCX 调用由主机控制器驱动程序实现的回调函数,以执行对端点队列状态的更改。 然后,驱动程序对提供给 UCX 的端点队列以及驱动程序中维护的任何二级队列执行相应的操作。 在以下情况下,端点队列会中止或清除:
- USB 设备客户端驱动程序发送URB_FUNCTION_ABORT_PIPE请求;
- 暂停期间;
- 当设备连接到中心时,检测到设备断开连接;
- 在选择接口设置请求期间;
若要通知主机控制器驱动程序队列中止或清除,UCX 调用 EVT_UCX_ENDPOINT_ABORT 或 EVT_UCX_ENDPOINT_PURGE。 如果以后某个时候 UCX 需要端点队列,则 UCX 会调用 EVT_UCX_ENDPOINT_START 回调来通知驱动程序启动队列。
3. 转移取消:对于主机控制器驱动程序声明GUID_USB_CAPABILITY_CLEAR_TT_BUFFER_ON_ASYNC_TRANSFER_CANCEL的任何控制器,驱动程序必须调用 UcxEndpointNeedToCancelTransfers 并实现 EVT_UCX_ENDPOINT_OK_TO_CANCEL_TRANSFERS ,以取消异步 (批量或控制) USB 传输到位于事务转换器 (TT) 集线器后面的 USB 全速或低速设备。 在所有其他情况下,驱动程序可以选择调用 UcxEndpointNeedToCancelTransfers 以获取 EVT_UCX_ENDPOINT_OK_TO_CANCEL_TRANSFERS 通知,指示允许在此端点上取消传输,并且驱动程序可以继续取消传输。 或者,驱动程序可以直接取消传输,而无需调用 UcxEndpointNeedToCancelTransfers。
如果主控制器驱动程序始终对此 GUID 的请求失败,它可以完全忽略这两个函数调用。
如果驱动程序从未调用 UcxEndpointNeedToCancelTransfers,则不会调用驱动程序 的EVT_UCX_ENDPOINT_OK_TO_CANCEL_TRANSFERS 回调,并且可以在回调注册期间为 NULL。
如果驱动程序打算使用 UcxEndpointNeedToCancelTransfers,则在传输已编程到控制器中并取消时,驱动程序必须调用 方法,然后等待 EVT_UCX_ENDPOINT_OK_TO_CANCEL_TRANSFERS 才能完成。