Open Novakov opened 2 years ago
Naive thought: WinUSB_Initialize
call is delayed until winusbx_claim_interface
, so between calls to libusb_open
and libusb_claim_interface
child composite device is opened (so not accessible to other applications) but not usb-initialized (so no USB transfers yet). If it would be possible to delay CreateFile
until interface is claimed it would solve the issue. That would make libusb_open
call effectively no-op meaning that attempt to open non-existing or already opened device not fail.
@Novakov Just wondering if you can give Pull Request https://github.com/libusb/libusb/pull/965 a try. It is meant to sort out IAD device but it might help a bit as well.
I already tried, it does not help alone but I think it might be required to fix this issue.
In essence:
I'm planning to prototype solution as described by my previous comment (lazy CreateFile) and give it a try in daily work.
Thanks for the updates and I think your solution is worth a try.
I implemented something very quick and ridden with printf and TODO but I would like to share progress with you as I'm only scratching the surface of libusb source code: https://github.com/Novakov/libusb/commit/a339b426fd9078f70c8d73140c97f537be1290e8#diff-bd7e9ed3e7d8a4a69d0664da0f6b8dbbff0b2c608d8dd63de02c379c98cf88b4
Basically: I'm doing nothing in opening file and when claiming interface I'm opening dev_handle
if not already open.
Use case which previously failed: Orbtrace USB device and running orbuculum
concurrently with openocd
. Both applications can communicate with different interfaces of the same USB device which is great.
I'm planing to do much more testing with more sophisticated USB devices (MCU with different sets of descriptors) and see how it goes.
I woud very much appreciate any feedback and suggestions for edge cases, implementation itself or things to watch out for.
@Novakov I will suggest that you create a pull request and then mention it as WIP (Work in Progress) so that more people can review and test it. Thanks,
@mcuee submitted. Seems to be working fine and implementation is not hacky. Still some more testing to do but for now I'm optimistic about it
The use case is really valid (different applications can communicate with different interfaces of the same USB device) and hopefully more people can come and test it.
Just trying to summarize (probably helps me more writing this than it does anyone reading it!): PR 965 (merged) allows opening a non-first winusbx interface without wrongly trying to open the first (possibly non-winusbx) interface on the real device - when it should really only open the first associated interface (of the same child device). Prior to this, opening could be blocked unnecessarily if the first child device was taken by another driver (or context). It will still grab all the interfaces in the same group (child device). PR 1181 takes this further for the case of composite (child) devices, and will only open the interface needed, and not all interfaces of the same group, allowing the others to be opened by other drivers or libusb contexts.
That would make libusb_open call effectively no-op meaning that attempt to open non-existing or already opened device not fail.
This is possibly a significant change but one I think we should accept. Currently, opening the (child) device assures you have control of all its interfaces, and also that you have access. With 1181 you only know when claiming whether you have access. So access issues will pop up at a later point - maybe something to note in the release notes.
PR 1181 makes WinUSB look more like e.g. Linux where several processes can open the same device (unless exclusive locks are used), only claiming interfaces matters. So I think this is good for cross-platform applications. However on Linux you will pass the user permission test already at libusb_open.
To me #1181 is a good improvement. Unfortunately we need more reviews and tests so we can not get it inside 1.0.27 release.
Let's assume USB device reporting itself as composite device with two interfaces (0 and 1) of class vendor. Using Microsoft OS 1.0 descriptors they are assigned WinUSB driver (using WINUSB CompatibilityId descriptor with two sections) and unique
DeviceInterfaceGUID
(using two separate Extended Compatibilty descriptor, one for each interface)Some screenshots: Device manager:
Registry, interface 0 with GUID:
Registry, interface 1 with GUID:
Now, there is well known limitation of WinUSB: "WinUSB is not an option if: Your device is accessed by multiple applications". However in the context of composite device interface 0 and interface 1 are separate devices. Given that by using SetupAPI and WinUSB native API I'm able to lookup specific interface (single child device from composite device) that gives me paths:
\\?\usb#vid_4d4e&pid_4455&mi_00#7&57ec2a6&2&0000#{644991b2-1f10-45f7-a445-9a50ee4ce73d}
for interface 0\\?\usb#vid_4d4e&pid_4455&mi_01#7&57ec2a6&2&0001#{13b2b252-adbf-45f8-9512-07342e35f305}
for interface 1 As intended each path points to specific interface. Opening them (CreateFile
) and wraping it in WinUSB (WinUSB_Initialize
) in two different applications (one application for interface 0 and one for interface 1) gives me two separate handles for two separate devices. I can use these handles to issue control transfers and they are correctly interpreted by USB device as transfers to two different interfaces.Observation: From WinUSB point of view it is possible to access different child devices of composite device from multiple application. It is not possible to access the same child device of composite device from multiple application.
Sorry for long introduction and probably stating facts that might be obvious but I wanted to describe context and what is possible before going to libusb specifics.
Libusb allows to use WinUSB devices however it is not aware of
DeviceInterfaceGUID
and composite device is treated as a whole. In WinUSB backend implementation there is functionwinusbx_open
(https://github.com/libusb/libusb/blob/master/libusb/os/windows_winusb.c#L2428) which opens all child devices:As you can see
priv->usb_interface
array contains device paths for both child devices.As both child devices are opened (even if only single interface is required) no other application can open any child device of composite device.
Function
libusb_wrap_sys_device
that (in theory) could be used to mix SetupAPI (lookup and open device) with libusb (issue usb transfers) is not implemented on Windows.It would be great if libusb only opened child device required by specific application, as that would allow other applications to access remaining child devices. However, at this moment I have no idea how that can be implemented nicely in libusb. I'm reporting this issue to keep a record of my experiments and findings as it is not 100% clear from documentation how WinUSB and composite devices play together.