Hen*_*Kok 5 linux windows usb hid endpoint
我们有一个基于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 ..
Run Code Online (Sandbox Code Playgroud)
另一方面,Windows通过控制端点(EP0)发送它.我们使用安装API来查找具有我们需要的用法的设备,为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 ..
Run Code Online (Sandbox Code Playgroud)
(抱歉,无法发布图片(还).我手动复制了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);
Run Code Online (Sandbox Code Playgroud)
已被替换为
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
这使得请求通过正确的端点。
因此我得出以下结论: