WinUsb_ControlTransfer() sets wIndex to zero
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 35/100
- Issue type
- Documentation
- Clarity
- Clearly specified
- Activity status
- Stale
- Domain
- documentation
Research direction
Start with the Windows Known Restrictions section of the libusb wiki, linked in the issue, and compare its wording with the reported behavior for separate WinUSB device paths. Clarify the documented conditions under which wIndex is changed and how to access the other interface; done means the wiki no longer implies that sending the request is impossible.
Written by the indexing model from the issue text.
Description
This page:
https://github.com/libusb/libusb/wiki/Windows#Known_Restrictions
says under "Knows Issues":
With WinUSB, when LIBUSB_RECIPIENT_INTERFACE is used for the transfer,
the WinUSB DLL forces the low byte of wIndex to the interface number, regardless of what you set it to.
This sounds like if this was a bug in WinUSB.dll.
I saw in internet that many people misunderstood that, even saying that it is impossible that you send an interface request with wIndex = 1.
But I can send a SETUP request to the second interface setting wIndex = 1 and this will be transferred correctly over the USB cable which I prove with my hardware USB Spy Beagle and I also see it in my USB sniff software USBlyzer:
I use the CANable Candlelight.
I'am currently implementing a firmware uploader into my software HUD ECU Hacker
I have to send this specific SETUP request to the second interface which will switch the processor from ST Microelectronics into DFU mode (Device Firmware Update mode).
The Candlelight has 2 interfaces:
Interface 0 has two endpoints (pipes) and is used to send data to and receive data from the CAN bus:
On the other hand interface 1 has no endpoint.
It receives only SETUP requests and does nothing else than to switch the processor into bootloader mode:
To upload a new firmware I have to send a SETUP packet with command DFU_DETACH (see first screenshot) to the second interface.
Now comes the important point:
If I send this SETUP command to the same WinUSB instance that I use to transfer the CAN bus data I will see that Windows resets wIndex to zero which I send with value 1. So Windows manipulates my SETUP packet and I see on the USB cable a corrupt packet that has no effect. It will NOT switch the device into bootloader mode.
But the conclusion is wrong, that sending such a packet with WinUSB is impossible or that this is a bug.
I have read this in other places linking to this wiki and people saying that WinUSB cannot do this.
People are even saying that this is a limitation of the WinUSB driver.
I have seen other websites where this wrong information is spread citing this Wiki .
I have also seen people saying that Microsoft is giving us a limited WinUSB library and that Linux is supposedly much better.
All this is WRONG.
And these misunderstanding could be avoided by making this much clearer by using the following information.
The main problem is the lack of details in the MSDN explaining how to handle multi-interface devices correctly.
The point is that WinUSB sees a USB device with 2 interface as if they were TWO DIFFERENT devices.
When you call WinUsb_Initialize() you get only ONE of the interfaces.
And calling WinUsb_GetAssociatedInterface() does not give you the second interface!
The second interface is not an "associated" nor an "alternate" interface.
The second interface is handled by WinUSB as if it was a completely separate USB device.
So to send a SETUP packet to the second interface we have to OPEN ANOTHER device.
To communicate with both interfaces we have to call CreateFile() and WinUsb_Initialize() twice with a different device path.
A look into the registry of the CANable device:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\VID_1D50&PID_606F
The Device Parameters of Interface 0 (Multi Interface 0 = "MI_00") are in:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\VID_1D50&PID_606F&MI_00\7&380dcbb4&0&0000\Device Parameters
The resulting Device ID is easy to build by appending this GUID:
"\?\USB#VID_1D50&PID_606F&MI_00#7&380dcbb4&0&0000#{c15b4308-04d3-11e6-b3ea-6057189e6443}"
Passing this to CreateFile() and the file handle to WinUsb_Initialize() gives full access to interface 0.
But with this device path Microsoft does not allow to access interface 1.
If you send anything to interface 1 with this handle of interface 0 Microsoft will reset wIndex from 1 to 0.
To access the second interface we have again a look into the registry:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\VID_1D50&PID_606F&MI_01\7&380dcbb4&0&0001\Device Parameters
This GUID is a random number that was created by Zadig.
This allows us to build the device path for interface 1:
"\?\USB#VID_1D50&PID_606F&MI_01#7&380dcbb4&0&0001#{43BFF950-A1BD-4BBD-9629-082ADFB0B8EC}"
Passing this to CreateFile() allows us to communicate with the second interface.
Why did Microsoft implement it like this?
The obvious reason is that a Multi-Interface USB device may have the driver installed for one interface, but the driver for the other interface is not installed. That means that one interface is operational and the other one is not.
This design allows to use the operational interface while ignoring the other one.
A CANable can send data to a CAN bus while the driver for the firmware update interface is missing.
It is even possible that one application uses one interface while a completely different process uses the other interface at the same time. For example with a USB headset one application may send sound to the speakers while another application listens to the microphone.
Microsoft did even go one step further:
I found that Microsoft did a lot of work to make working with different interfaces easy for the developer.
When I request the configuration descriptor I get different results depending on the interface for which I open WinUSB.
When I use the DeviceID for interface 0 Microsoft removes the descriptor for the interface 1 and the DFU descriptor from the returned data.
When I use the DeviceID for interface 1 Microsoft removes the descriptor for the interface 0 and the 2 endpoint descriptos from the returned data.
So WinUSB behaves really as if I was working with 2 completely independent devices.
Summary:
There is no bug in WinUSB.
You have only to use it correctly.
Microsoft should have documented this.
And your Wiki should explain how to avoid that the SETUP packet is manipulated to avoid all the misunderstandings.!
I have to admit that in internet there is very few detailed information about USB.
Therefore I compiled and uploaded a very useful USB tutorial that I recommend to everybody.
It is part of my project Oszi Waveform Analyzer which transfers an oscilloscope capture over USB:
https://github.com/Elmue/Oszi-Waveform-Analyzer/blob/main/Documentation/USB%20Tutorial.chm
Elmü
- Dominant language
- C
- Stars
- 6.2k
- Forks
- 2.1k
- PR merge metrics
- No merged PRs in 30d
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from libusb/libusb
-
Difficulty 2/5 1-3 hours Newbie friendliness 67/100
-
android core
Difficulty 5/5 Over a week Newbie friendliness 35/100
-
Windows version of libusb-master (MSVC build) can't be built when git installed w/o bashPossibly taken @Youw claimed this 20 days ago. Openwindows
-
windows
Difficulty 4/5 3-5 days Newbie friendliness 48/100
-
core enhancement
Difficulty 5/5 Over a week Newbie friendliness 30/100
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
semantic-reasoning/wirelog#2163 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
Maintainers usually reply within 3 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 63/100
Xinyuan-LilyGO/T-Display-S3#352 · 3 comments ·
-
documentation severity/minor
Difficulty 1/5 1-3 hours Newbie friendliness 88/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
shenmintao/aic8800d80#107 · 1 comment ·