We have an embedded device based on TI's CC2531 which has (apart from the control EP0 and a number of IN-only endpoints) an endpoint that is both IN and OUT. We have noticed a difference in how windows sends OUT reports and how linux does this. This has actually boggled us quite some time, but we have never been able to find an explanation.
It seems to me that linux does it the way it is supposed to be: the OUT report is transmitted through the endpoint that is associated with the HID report, as we get it from libusb:
Item | Dev | EP | Status | Speed |Payload
-----------------+-----+----+--------+-------+-------------------------------
OUT transaction | 13 | 4 | ACK | FS | 64 bytes (90 13 00 00 00 00 ..
Windows on the other hand, sends it through the control endpoint (EP0). We use the setup API to find the device with the usages we need, open it for IN and OUT and use the same file descriptor for reading and writing. The EP4 IN reports are nicely received through this file descriptor, but writing a report through the same file descriptor, ends up on EP0:
Item | Dev | EP | Status | Speed |Payload
-------------------+-----+----+--------+-------+-------------------------------
Class request OUT | 25 | 0 | OK | FS | 64 bytes (90 13 00 00 00 00 ..
(sorry, can't post pictures (yet). I copied the Ellisys reports by hand)
The embedded device does not check on which EP the OUT report is received (i.e. SET reports on EP0 will funnel into the same function as OUT reports found on the other endpoints when processing HID events), so it will respond either way.
My question is: are both ways correct, and if not, which is correct and which is not? Could it be that an error in our descriptors triggers this behaviour on windows?
To be complete: here is our descriptor: http://tny.cz/ac745a8f (stripped from vendor identification to keep my boss happy :) )
Zooming into the report when on windows: (Joy! I am allowed to do pictures now :) )
The whole transaction:
Used libraries on Windows: hid.lib, hidclass.lib and setupapi.lib. When writing a report we use the functions HidP_SetUsageValueArray and HidD_SetOutputReport. PHIDP_PREPARSED_DATA and HIDP_CAPS are found with the functions HidD_GetAttributes, HidD_GetPreparsedData and HidP_GetCaps. The file path for the device is found using SetupDiEnumDeviceInterfaces. If we find a device with correct VID, PID, caps.UsagePage and caps.Usage, that is the device we use.
On linux it is a bit trickier, as I am not the one who implemented the linux code. What I can tell is libusb-1.0.9 is used, the device is opened using libusb_open_device_with_vid_pid, reports are sent with libusb_fill_interrupt_transfer and libusb_submit_transfer. I see that libuwand_fill_interrupt_transfer accepts an endpoint as parameter, so I think with just the handle from libusb_open_device_with_vid_pid and passing the right parameter as endpoint, libusb will figure out where to put the report.