0

我有一个发送报告描述符的全速 USB 设备,其相关端点描述符声明 abInterval为 8,即 8 毫秒。

当设备的驱动程序是 HidUsb 时,从 USB Descriptor Dumper 获取以下报告摘录:

Interface Descriptor: // +several attributes
------------------------------
0x04    bDescriptorType
0x03    bInterfaceClass      (Human Interface Device Class)
0x00    bInterfaceSubClass   
0x00    bInterfaceProtocol   
0x00    iInterface

HID Descriptor: // +bLength, bCountryCode
------------------------------
0x21    bDescriptorType
0x0110  bcdHID
0x01    bNumDescriptors
0x22    bDescriptorType   (Report descriptor)
0x00D6  bDescriptorLength

Endpoint Descriptor: // + bLength, bEndpointAddress, wMaxPacketSize
------------------------------
0x05    bDescriptorType
0x03    bmAttributes      (Transfer: Interrupt / Synch: None / Usage: Data)
0x08    bInterval         (8 frames)

在将驱动程序切换到 WinUSB 以便能够使用它之后,如果我使用 libusb 反复查询 IN 中断传输,并使用此脚本计算 2 个 libusb 调用之间和 libusb 调用期间花费的实际时间:

for (int i = 0; i < n; i++) {
    start = std::chrono::high_resolution_clock::now();
    forTime = (double)((start - end).count()) / 1000000;

    <libusb_interrupt_transfer on IN interrupt endpoint>

    end = std::chrono::high_resolution_clock::now();
    std::cout << "for " << forTime << std::endl;

    transferTime = (double)((end - start).count()) / 1000000;
    std::cout << "transfer " << transferTime << std::endl;

    std::cout << "sum " << transferTime + forTime << std::endl << std::endl;
}

这是获得值的示例:

for 2.60266
transfer 5.41087
sum 8.04307     //~8

for 3.04287
transfer 5.41087
sum 8.01353     //~8

for 6.42174
transfer 9.65907
sum 16.0808     //~16

for 2.27422
transfer 5.13271
sum 7.87691     //~8

for 3.29928
transfer 4.68676
sum 7.98604     //~8

总和值始终保持非常接近 8 毫秒,除非在启动新的中断传输调用之前经过的时间太长(对于我的特定情况,阈值似乎在 6 到 6.5 之间),在这种情况下它等于 16。我有曾经看到一个“for”度量等于 18 毫秒,而总和恰好等于 24 毫秒。使用 URB 跟踪器(在我的例子中是 Microsoft 消息分析器),Complete URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER消息之间的时间差也是 8 毫秒的倍数 - 通常是 8 毫秒。简而言之,它们与“总和”度量相匹配。

因此,很明显“libusb 中断传输调用”的两次返回之间经过的时间是 8ms 的倍数,我假设这与 bInterval 值 8(FullSpeed -> *1ms -> 8ms)有关。

但现在我已经,我希望,清楚地说明我在说什么——在哪里强制执行?尽管进行了研究,但我找不到关于 bInterval 值如何影响事物的明确解释。

显然,这是由驱动程序强制执行的。

因此,是不是:

  • 驱动程序禁止请求触发,直到 8 毫秒过去。听起来对我来说是最合理的选择,但从我的 URB Trace 来看,Dispatch message事件在请求返回前几毫秒就被引发了。这意味着离开主机的实时数据对我/消息分析器是隐藏的。

  • 驱动程序对我和分析器隐藏响应,直到自上次响应以来经过 8 毫秒。

如果它确实由驱动程序处理,那么在交换消息的日志中向我显示的内容有一个谎言。响应应该在请求之后立即出现,但事实并非如此。因此,请求在显示的时间之后发送,或者响应早于显示的时间。

尊重 bInterval 的执行如何工作?

我的最终目标是忽略 bInterval 值并以超过 8ms 的频率轮询设备(我有充分的理由相信它可以每 2ms 轮询一次,并且 8ms 的使用周期是不可接受的),但首先我想知道它当前的限制是如何工作的,如果我正在寻找的是可能的,所以我可以理解接下来要学习什么(例如编写自定义 WinUSB 驱动程序)

4

1 回答 1

2

我有一个全速 USB 设备

小心:你验证了吗?8ms 是低速 USB 设备的限制-许多常见的鼠标或键盘可能仍在使用。

8ms 调度在 USB 主机驱动程序 (ehci/xhci) AFAIK 内完成。您可以尝试通过释放和回收接口来赌博 - 但未经测试。(编辑:不起作用,请参阅评论)。

USB 设备不能自己说话,所以它必须是延迟的请求。请注意,当没有可用的新数据时,设备也可以拒绝任何中断 IN 请求。这只是bInterval在时间上增加了一个毫秒。

编写自定义 WinUSB 驱动程序

不推荐 - 更换 Windows 提供的驱动程序非常麻烦。我们用于 USB CDC 设备的 libusb-win32 替换器在所有大型 Windows 10 升级中都会中断 - 一旦升级完成,该设备将使用 COM 端口而不是 libusb。

于 2019-02-13T13:17:24.557 回答