我们有一个基于 TI 的 CC2531 的嵌入式设备,它有一个(除了控制 EP0 和一些仅用于 IN 的端点)一个既是 IN 又是 OUT 的端点。我们注意到 Windows 发送 OUT 报告的方式与 Linux 发送报告的方式不同。这实际上困扰了我们很长一段时间,但我们一直无法找到解释。
在我看来,linux 以其应有的方式进行操作:OUT 报告通过与 HID 报告关联的端点传输,正如我们从 libusb 获取的那样:
Item | Dev | EP | Status | Speed |Payload
-----------------+-----+----+--------+-------+-------------------------------
OUT transaction | 13 | 4 | ACK | FS | 64 bytes (90 13 00 00 00 00 ..
另一方面,Windows 通过控制端点 (EP0) 发送它。我们使用setup API 来找到我们需要的usages 的设备,为IN 和OUT 打开它并使用相同的文件描述符进行读写。 EP4 IN 报告通过这个文件描述符很好地接收,但是通过相同的文件描述符写入报告,最终在 EP0 上:
Item | Dev | EP | Status | Speed |Payload
-------------------+-----+----+--------+-------+-------------------------------
Class request OUT | 25 | 0 | OK | FS | 64 bytes (90 13 00 00 00 00 ..
(抱歉,还不能发图片。我手抄了 Ellisys 报告)
嵌入式设备不检查接收到 OUT 报告的 EP(即 EP0 上的 SET 报告将汇集到与处理 HID 事件时在其他端点上发现的 OUT 报告相同的功能),因此它会以任何一种方式响应。
我的问题是:两种方式都正确吗?如果不正确,哪个正确,哪个不正确?会不会是我们的描述符中的错误在 Windows 上触发了这种行为?
为了完整起见:这是我们的描述符:http://tny.cz/ac745a8f (从供应商标识中删除以让我的老板高兴 :) )
在 Windows 上放大报告:(高兴!我现在可以拍照了 :) )
整个交易:
Windows 上使用的库:hid.lib、hidclass.lib 和 setupapi.lib。在编写报告时,我们使用函数 HidP_SetUsageValueArray 和 HidD_SetOutputReport。 PHIDP_PREPARSED_DATA 和 HIDP_CAPS 可通过函数 HidD_GetAttributes、HidD_GetPreparsedData 和 HidP_GetCaps 找到。使用 SetupDiEnumDeviceInterfaces 找到设备的文件路径。如果我们找到具有正确 VID、PID、caps.UsagePage 和 caps.Usage 的设备,那就是我们使用的设备。
在 Linux 上它有点棘手,因为我不是实现 Linux 代码的人。我可以说的是使用了 libusb-1.0.9,使用 libusb_open_device_with_vid_pid 打开设备,使用 libusb_fill_interrupt_transfer 和 libusb_submit_transfer 发送报告。我看到 libuwand_fill_interrupt_transfer 接受一个端点作为参数,所以我认为只要使用 libusb_open_device_with_vid_pid 的句柄并将正确的参数作为端点传递,libusb 就会确定将报告放在哪里。
最佳答案
我想我找到了答案。
纯属巧合,我偶然发现了 Keil 论坛,在那里我找到了这样的语句“HidD_SetOutputReport 将使用控制端点,如果您希望它通过另一个端点,请使用 WriteFile”。我知道 5 年多前我曾尝试过那条路,但我陷入了具有重叠结构的异步 IO 中。因为看起来我有出路(使用 HidD_SetOutputReport),所以我放弃了 WriteFile 路径。所以现在是时候再次寻求那条道路了,我做到了。代码:
res = HidD_SetOutputReport(m_DeviceControl[dev], report, m_CapsControl[dev].OutputReportByteLength);
已被替换为
DWORD bytesWritten;
OVERLAPPED eventWrite = {0};
eventWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
int rv3 = WriteFile(m_DeviceControl[dev], report, m_CapsControl[dev].OutputReportByteLength, &bytesWritten, &eventWrite);
if (rv3 == 0)
{
int err = GetLastError();
if (err == ERROR_IO_PENDING)
{
bool done = false;
do
{
// yes. Wait till pending state has gone
rv3 = WaitForSingleObject(eventWrite.hEvent, 25);
if (rv3 == WAIT_OBJECT_0)
{
GetOverlappedResult(m_DeviceControl[dev], &eventWrite, &bytesWritten, FALSE);
done = true;
res = TRUE;
}
else if (rv3 == WAIT_TIMEOUT)
{
// Need to try again.
}
else
{
m_StoppingControlOut = true;
done = true;
}
}
while (!done && !m_StoppingControlOut);
}
}
}
这使得请求通过正确的端点。
因此我得出以下结论:
- 我认为 HID 设备解释通过控制端点发送的 OUT 报告是错误的。
- 正确使用 WriteFile(使用重叠 IO)使 OUT 报告使用正确的端点。
关于linux - USB HID OUT 报告 - 哪个端点是正确的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28428776/