问题描述
我正在一个使用 UEFI 启动的小型业余操作系统中为 Intel xHC 编写一个小型驱动程序。
在我重置所有 Root Hub 端口后,我收到 2 个端口状态更改事件,这是因为我要求 QEMU 在命令行中模拟 USB 键盘和 USB 鼠标。每个设备的一个端口状态更改事件似乎是公平的。在此之后,我按照 USB 设备的初始化步骤进行操作。如 xHCI 规范所述:
在端口成功达到启用状态后,系统软件应使用启用插槽命令为新连接的设备获取设备插槽,如第 4.3.2 节所述。
因此,我向每个存在端口状态更改事件的根集线器端口发送启用插槽命令。这似乎有效,因为我在事件环上收到 2 个命令完成事件,它们都触发了中断。这两个事件都标有表示成功的完成代码 1。
我的问题从这里开始。在端口状态更改事件中是一个端口 ID 字段,它允许确定哪个端口触发了事件。在命令完成事件中,没有这些。我可以链接到触发事件的命令 TRB,但命令 TRB 不包含端口 ID。我的问题是,在启用插槽命令之后,我需要创建一个输入上下文,包括一个应包含根集线器端口号的插槽上下文。
我可以保留我向其发送启用插槽命令的端口列表,但这会导致竞争条件,尤其是在启用多处理后。
如何正确获取触发命令完成事件的 Root Hub 端口?
解决方法
在 linux-usb 邮件列表上也有人问过类似的问题。
There,Mathias Nyman,points out that the Enable Slot is misleading 因为它不启用特定端口的插槽,而是该命令仅返回设备上下文基地址数组中的空闲索引。
该索引是Slot ID 值。
程序员必须用一个指向设备上下文结构的指针设置相应的条目(即dev_ctx_base_addr[slot_id]
),并用填充它的槽上下文任何端口号和路由字符串他们认为合适的。
需要强调的是,Slot ID 和端口号/路由字符串之间没有先验关系。
因此,当命令完成事件到达时,您可以拥有一个插槽队列来初始化和出列它们。