Hello, I am very new to driver development - in fact, I have come to the conclusion that a project of mine involving a particular USB device could only be done by writing my own Windows driver, and upon realizing the complexity of driver development, I would like to have my conclusions checked by people knowledgeable on the subject. While I’ve interacted with USB devices in C++ and have read on driver writing, I have not written any custom driver code so far.
The problem is the following.
I have a vendor-provided USB device, whose only purpose is to poll another source of data, convert it to another format, and let the computer know.
This device is full-speed, USB 2, and its relevant endpoint for the problem is Interrupt OUT.
Its driver code specifies it uses a vendor driver, and it’s actually meant to be used with WinUSB. The data format is known.
The surprising bit is that it exposes a Interval of 8, which in the context of Full Speed devices, means it asks for an 8ms polling interval.
This is surprising because on the other end of this conversion device, the device polls periodically every ~1,4ms, and the data sent to the computer only provides the (post-conversion) data of the last of these ~1,4ms period polls. So I strongly suspect that new data is available in the device-side USB controller every ~1,4ms, and that the 8ms interval exposed in the descriptor is outright a mistake. While I am not certain of it, I would very much like to check and obtain all this data. If this is not possible, the next best thing I’m looking for is to be able to choose precisely the USB frame I poll that device at. So, an 8ms interval some times, a 10ms some other time…
Because this doesn’t appear to be possible with WinUSB. (From the perspective of the application, at least) WinUSB respects the polling interval requested by the device and will block calls and the emission of the request to at least 8ms after the previous request. And not only does it respect it, but it appears from my tests, both through libusb and directly using WinUSB functions, that WinUSB schedules an interval timer to check, every 8ms, if there’s a new request for data from this device, and proceeds to fire a request if there is. The consequence of this is that accurately timed WinUSB function calls will be postponed to the next “8ms-period poll”. As an example, if I attempt to read a pipe every 10ms very accurately, the time difference between two calls will be 75% of the time 8ms, and 25% of the time 16ms, in a cycle of [8ms - 8ms - 8ms - 16ms].
Applying a RAW_IO pipe policy does not change this behaviour.
My current beliefs are that this is due to WinUSB’s implementation and not the USB host scheduler, that only schedules transfers on the next frame, and that if I were to write my own driver, I would probably be able to control the polling rate regardless of the exposed interval, so, up to 1000Hz, and that if I can’t, I would at least be able to schedule transfers on the frames I want as long as they’re at least 8 frames apart. I haven’t found any simpler way to go about it so far, considering that the device isn’t HID. (so, no HIDUSBF stuff)
So my questions are the following:
- Is it possible ?
- Are my assumptions about the role of the driver in the transfer scheduling process correct ? If so, does it mean that writing my own driver will work ?
- Do simpler alternatives exist, meaning I’m attempting something way too complicated for this problem ? Is a higher-control WinUSB-like driver already written and available ?
And bonus questions:
- If this method looks good, is there any reason I should prefer KMDF instead of UMDF2 for this task ? I haven’t found any so far.
- Is there any kind of middle-man deception possible where I’d convince the OS that the exposed interval is not actually 8, but 1, without involving an external device ?
When @“Maxim_S._Shatskih” says in the first answer to https://community.osr.com/discussion/190849/usb-polling-rate that “For interrupt pipe, the polling rate it is hardcoded in the config descriptor to be BusPollingRate/( 1 << N ), where N is some small number (1 and up).” - does that mean it’s impossible ? This is the message that had me seek confirmation from experts before spending weeks or more attempting to do the impossible.
Thanks for reading !
Best regards