windows USB 设备驱动开发-USB 主控制器扩展 (UCX)

如果你正在编写与 Microsoft 提供的 USB 主机控制器扩展驱动程序 (Ucx01000.sys) 通信的新主机控制器驱动程序,则这部分内容适用于你。

下面是 Windows 中 USB 主机端驱动程序中显示的图表的修改版本。 此版本隐藏 USB 客户端驱动程序层的详细信息,这些详细信息与主控制器驱动程序开发无关。

在上图中,

  • USB 集线器驱动程序 (Usbhub3.sys) 是 KMDF 驱动程序。 集线器驱动程序负责管理 USB 集线器及其端口、枚举和创建物理设备对象, (PDO) USB 设备和可能连接到其下游端口的其他集线器;
  • USB 主机控制器扩展 (Ucx01000.sys) 是堆栈中上述集线器驱动程序的抽象层,提供一种通用机制,用于将请求排队到基础主机控制器驱动程序;
  • USB 主机控制器驱动程序 管理硬件。 Usbxhci.sys 是 Microsoft 提供的一个此类驱动程序,它尤其面向符合 xHCI 规范的 USB 控制器硬件。 独立硬件开发人员可能需要编写自己的主机控制器驱动程序,而不是使用收件箱 Usbxhci.sys。 例如,对于 XHCI 硬件,该硬件不完全符合规范,因此无法使用 Usbxhci.sys 或非 XHCI 硬件,例如 USB over TCP 连接;

UCX 和主机控制器驱动程序之间的双向通信通过使用 USB 主机控制器扩展 (UCX) 编程接口进行。 编译驱动程序时,每个驱动程序静态链接到 Microsoft 提供的存根库中的入口点 (Ucx01000.lib) 。

下面是为主机控制器驱动程序加载的设备堆栈:

主控制器驱动程序使用的 UCX 对象和句柄

UCX 扩展了 WDF 对象功能,以定义其自己的特定于 USB 的 UCX 对象。 UCX 使用这些对象将请求排队到任何基础主机控制器驱动程序。

总结

  • 主机控制器驱动程序使用 UCX 对象来处理与控制器、其根集线器和所有端点相关的操作。
  • UCX 对象由主机控制器驱动程序创建,每个对象的生存期由 UCX 管理。

重要的 API

  • UcxControllerCreate
  • UcxRootHubCreate
  • UcxUsbDeviceCreate

UCX 扩展了 WDF 对象功能,以定义其自己的特定于 USB 的 UCX 对象。 UCX 使用这些对象将请求排队到任何基础主机控制器驱动程序。

UCXCONTROLLER:主机控制器对象

表示由主机控制器驱动程序创建的主机控制器。 驱动程序必须为每个主机控制器实例仅创建一个主机控制器对象。 通常通过调用 UcxControllerCreate 方法在 EvtDriverDeviceAdd 回调中创建。

当主机控制器驱动程序创建对象时,驱动程序将注册由 UCX 调用的回调函数的实现。 驱动程序还应识别主机控制器连接的总线类型,例如 ACPI 或 PCI。 驱动程序还通过使用传递给 UcxControllerCreate 调用的 UCX_CONTROLLER_CONFIG 结构来提供主机控制器设备信息。

若要处理 I/O 请求,主机控制器驱动程序必须注册 GUID_DEVINTERFACE_USB_HOST_CONTROLLER 设备接口。 此驱动程序不需要实现此接口中定义的 IOCTL。 相反,UCX 客户端通过调用 UcxIoDeviceControl 将在此接口上收到的 IOCTL 请求传递给 UCX。

下面是与主机控制器对象关联的回调函数,这些函数由 UCX 调用。 这些函数必须由主机控制器驱动程序实现。

*EVT_UCX_CONTROLLER_USBDEVICE_ADD
当集线器驱动程序通过与根集线器和/或外部集线器的交互确定总线上有新设备时调用。

*EVT_UCX_CONTROLLER_QUERY_USB_CAPABILITY UCX
调用以收集有关 USB 主机控制器支持的各种功能的信息。

*EVT_UCX_CONTROLLER_RESET
由 UCX 调用以重置控制器硬件,以响应检测到的错误。

*EVT_UCX_CONTROLLER_GET_CURRENT_FRAMENUMBER
用于从主机控制器中检索当前帧编号,中心驱动程序使用它来计划时序传输。

UCXROOTHUB:根集线器对象

获取和控制主机控制器的根端口的状态。 主机控制器驱动程序通常在创建主机控制器对象后调用 UcxRootHubCreate 方法,在 EvtDriverDeviceAdd 回调中创建。 每个主机控制器实例只能有一个根集线器对象。 在 UcxRootHubCreate 调用中,驱动程序注册其回调实现。

EVT_UCX_ROOTHUB_GET_INFO
返回根集线器的 USB 2.0 和 USB 3.0 端口的数目。

EVT_UCX_ROOTHUB_GET_20PORT_INFO
返回有关根中心的 USB 2.0 或 USB 3.0 端口 (*EVT_UCX_ROOTHUB_GET_30PORT_INFO) 的信息。

创建并初始化根集线器对象后,集线器驱动程序通过发送中断和控制传输与根集线器端口交互。 UCX 通过调用主机控制器驱动程序实现的这些回调函数来帮助实现这些传输。

EVT_UCX_ROOTHUB_CONTROL_URB
处理 USB 集线器的功能控制请求。。

EVT_UCX_ROOTHUB_INTERRUPT_TX
处理有关已更改端口的信息的请求。

UCXUSBDEVICE:USB 设备对象

表示连接到总线的物理 USB 设备。 主机控制器驱动程序通常通过调用 UcxUsbDeviceCreate 方法在 EVT_UCX_CONTROLLER_USBDEVICE_ADD 回调中创建。

创建对象时,主机控制器驱动程序使用 UcxUsbDeviceCreate 调用注册其回调函数的实现。

这些回调函数旨在使控制器和驱动程序了解 USB 设备的当前状态。

EVT_UCX_USBDEVICE_ENABLE
准备控制器以执行到设备的默认端点的传输。

EVT_UCX_USBDEVICE_DISABLE
释放与设备及其默认端点关联的控制器资源。

EVT_UCX_USBDEVICE_ADDRESS
将地址编程到控制器中,并将 SET_ADDRESS 传输发送到设备,使其进入寻址状态。

EVT_UCX_USBDEVICE_ENDPOINTS_CONFIGURE
将非默认端点编程到控制器中,并/或释放其他非默认端点。

EVT_UCX_USBDEVICE_RESET
设备已重置的控制器通知,在这种情况下,驱动程序采取任何必要措施将控制器与 USB 设备同步。

EVT_UCX_USBDEVICE_UPDATE
通知控制器与设备相关的各种信息。

EVT_UCX_USBDEVICE_HUB_INFO
如果 UCXUSBDEVICE 句柄用于集线器设备,则通知集线器属性。

EVT_UCX_USBDEVICE_ENDPOINT_ADD
通知驱动程序为设备创建端点。 默认端点的 EVT_UCX_USBDEVICE_DEFAULT_ENDPOINT_ADD。

当挂起的 USB 3.0 设备上的接口发出唤醒信号时,驱动程序应调用 UcxUsbDeviceRemoteWakeNotification 来通知 UCX。

创建对象后,对象的生存期由 UCX 管理,驱动程序不得删除该对象。

UCXENDPOINT:端点对象

表示 USB 设备对象上的端点。 端点对象由主机控制器在 EVT_UCX_USBDEVICE_DEFAULT_ENDPOINT_ADD 或 EVT_UCX_USBDEVICE_ENDPOINT_ADD 回调期间创建。 创建端点对象时,驱动程序会注册其回调函数。

驱动程序还会为每个端点创建一个框架队列对象,并通过调用 UcxEndpointSetWdfIoQueue 将该队列的 WDFQUEUE 传递给 UCX。 创建端点后,对象及其关联的队列的生存期由 UCX 管理,驱动程序不得删除这些对象本身。

端点对象实现多个回调函数,使驱动程序能够协助 UCX 执行与端点相关的操作。

EVT_UCX_ENDPOINT_ABORT
中止与端点关联的队列。

EVT_UCX_ENDPOINT_OK_TO_CANCEL_TRANSFERS
通知控制器驱动程序,它可以在端点上完成取消的传输。

EVT_UCX_ENDPOINT_PURGE
完成端点上所有未完成的 I/O 请求。

EVT_UCX_ENDPOINT_START
开始与端点关联的队列。

EVT_UCX_ENDPOINT_STATIC_STREAMS_ADD
创建静态流。

EVT_UCX_ENDPOINT_RESET
通知驱动程序重置控制器的端点编程。

当主机控制器驱动程序在端点上收到 USB 3.0 无 Ping 响应错误时,驱动程序必须调用 UcxEndpointNoPingResponseError。 该调用会导致 USB 设备对象接收 EVT_UCX_USBDEVICE_UPDATE。

UCXSTREAMS:流对象

代表通过单个端点连接设备的管道数量。 主机控制器驱动程序通过调用 UcxStaticStreamsCreate 在 EVT_UCX_ENDPOINT_STATIC_STREAMS_ADD 回调中创建流对象。

在 UcxStaticStreamsCreate 调用期间,主机控制器驱动程序注册其回调函数。 对于特定的端点对象,驱动程序可以确定它是否已创建流对象,并通过调用 UcxEndpointGetStaticStreamsReferenced 返回 UCXSTREAMS 句柄。

创建对象后,驱动程序会为每个流创建一个框架队列对象,并通过调用 UcxStaticStreamsSetStreamInfo 将 WDFQUEUE 句柄发送到 UCX。

流对象为主机控制器提供了多个回调函数,以帮助 UCX 管理静态流。

EVT_UCX_ENDPOINT_STATIC_STREAMS_DISABLE
为端点的所有流发布控制器资源。

EVT_UCX_ENDPOINT_STATIC_STREAMS_ENABLE
为此端点启用所有流的控制器硬件。

对象的生存期和关联的队列由 UCX 管理,驱动程序不得删除这些对象。

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 管理。 当设备连接到总线并断开连接时,终结点的状态会更改,遇到电源事件(例如挂起和重置),并经历新的终结点创建(例如备用设置更改)。

终结点配置

UCX 调用由主控制器驱动程序实现的回调函数,以在终结点必须编程到 USB 主控制器或释放终结点时通知驱动程序。 调用 EVT_UCX_USBDEVICE_ENABLE 时,驱动程序将准备控制器以执行到设备的默认终结点的传输。 准备控制器包括对默认终结点进行编程。 调用 EVT_UCX_USBDEVICE_DISABLE 时,驱动程序会取消对默认终结点进行编程,并释放与设备关联的其他控制器资源。 调用 EVT_UCX_USBDEVICE_ENDPOINTS_CONFIGURE 时,会为驱动程序提供要编程到控制器中的非默认终结点列表,并为其提供要从控制器中删除的另一个非默认终结点列表。 然后,主控制器驱动程序将指定的非默认终结点程序化到控制器中,并从控制器中删除其他列表中) 指定的非默认终结点 (。

队列状态管理

UCX 调用由主机控制器驱动程序实现的回调函数,以执行对终结点队列状态的更改。 然后,驱动程序对提供给 UCX 的终结点队列以及驱动程序中维护的任何二级队列执行相应的操作。 在以下情况下,终结点队列会中止或清除:

  • USB 设备客户端驱动程序发送URB_FUNCTION_ABORT_PIPE请求。
  • 暂停期间。
  • 当设备连接到中心时,检测到设备断开连接。
  • 在选择接口设置请求期间。

若要通知主机控制器驱动程序队列中止或清除,UCX 调用 EVT_UCX_ENDPOINT_ABORT 或 EVT_UCX_ENDPOINT_PURGE。 如果以后某个时候 UCX 需要终结点队列,则 UCX 会调用 EVT_UCX_ENDPOINT_START 回调来通知驱动程序启动队列。

转移取消

对于主机控制器驱动程序声明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 才能完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值