Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@Novakov
Copy link

@Novakov Novakov commented Aug 27, 2022

This is work-in-progress, I'm opening PR to get initial feedback/review and possibly be tested by others.

Fixes #1177 and includes changes from #965.

Summary of changes:

  • Include Windows: Add ability to claim multiple associated interfaces for a WINUSBX composite function #965 to get IAD information
  • Make winusbx_open essentially no-op
  • When winusbx_claim_interface is called it ensures that device handle is valid, if not - CreateFile is called.
  • Ref-counting for claimed interfaces
    • For IAD, first interface is used to open WinUSB handle and must be closed after all associated interfaces are released
  • winusbx_release_interface uses refcounting to release WinUSB device and device handle.

I did not test how it behaves with libusb-filter (never used that, so some catching up to do first). With composite device containing several WinUSB devices (some of them grouped in IAD) libusb behaves correctly - CreateFile is delayed until claiming interfaces and handle is closed as soon as last associated interface is released.

Test report https://gist.github.com/Novakov/4b2d4094825b83ef58b23060224660f8

printfs are left on purpose and will be removed before finalizing - I'm dropping recompiled libusb.dll where I can (OpenOCD and Orbuculum mostly) to check if devices are opened/closed as supposed to, having debug printfs available makes it easier.

@mcuee mcuee added the windows label Aug 30, 2022
@Novakov Novakov force-pushed the winusb-lazy-create-file branch 3 times, most recently from 0872ad3 to 3b373df Compare September 7, 2022 18:47
@Novakov
Copy link
Author

Novakov commented Sep 7, 2022

I'm satisfied with current implemention. It's get a little tricky but reasonable. From my perspective it would be nice to get some feedback from someone with better understanding of libusb internals.

I've done some testing with composite and non-composite devices but my plan is to repeat them in more formalized manner before dropping WIP status. However I will be able to do that in ~2 weeks and I wanted to share current status.

There is dependency on PR #965 which waiting for some formatting fixes. If necessary I'm willing to apply them in this PR

@Novakov Novakov changed the title WIP: Lazy CreateFile with WinUSB backend Lazy CreateFile with WinUSB backend Oct 22, 2022
@Novakov
Copy link
Author

Novakov commented Oct 22, 2022

I finally managed to properly test these changes - things are working correctly, see test report linked in PR description.

@mcuee mcuee mentioned this pull request Oct 30, 2022
@tormodvolden
Copy link
Contributor

It is great that you have included a test report. I would be reassured if we had some more review comments and testing from others as well though. @RyanMetcalfeNovanta what do you think about this PR?

@Novakov Novakov force-pushed the winusb-lazy-create-file branch from 3b373df to ccac965 Compare January 22, 2023 11:08
@Novakov
Copy link
Author

Novakov commented Jan 22, 2023

@tormodvolden @mcuee I've rebased this branch on top of changes in #965 and performed testing again - works as expected, also in real use case where I found this issue in first place

@Novakov Novakov force-pushed the winusb-lazy-create-file branch from ccac965 to aa60876 Compare January 22, 2023 11:21
Copy link
Contributor

@tormodvolden tormodvolden left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did just a first quick look at the code. It is a significant behavior change so someone into Windows will need to check it.

@Novakov Novakov force-pushed the winusb-lazy-create-file branch 2 times, most recently from 177bebf to fe8cae8 Compare January 22, 2023 12:08
@mcuee
Copy link
Member

mcuee commented Jan 24, 2023

@Novakov

Is it possible for you to rebase to git master now that #965 has been merged? Thanks. I will see if I can test this PR.

@mcuee
Copy link
Member

mcuee commented Jan 24, 2023

This is not a test for the purpose of this PR (using two applications to access different interfaces of the same device), but rather to show some behavior differences of this PR with git master.

Test device: Raspberry Pi Pico W with CicrcuitPython FW. I have used WinUSB driver to replace the Mass Storage driver (Interface 2), the CDC-ACM driver (Interface 0/1, with IAD) and the USB Audion Driver (Interface 4/5, no IAD). Interface 3 is using USB HID driver (USB HID Keyboard).

Take note Claiming Interface 5 will fail as it is not using IAD -- therefore PR #965 will not help.

PS C:\work\libusb\libusb_pr1181> .\examples\xusb.exe 239a:8120
Using libusb v1.0.24.11644

Opening device 239A:8120...
libusb: warning [hid_open] could not open HID device in R/W mode (keyboard or mouse?) - trying without

Reading device descriptor:
            length: 18
      device class: 0
               S/N: 3
           VID:PID: 239A:8120
         bcdDevice: 0100
   iMan:iProd:iSer: 1:2:3
          nb confs: 1

Reading BOS descriptor: libusb: info [winusbx_ensure_dev_handle] Late opening device handle for interface 0, path: '\\?\USB#VID_239A&PID_8120&MI_00#7&1F881456&0&0000#{A9CBA50B-208C-BE9A-09AE-21D5FD6C571F}'

libusb: info [winusbx_release_interface] closing device handle '\\?\USB#VID_239A&PID_8120#E66141040387422B#{A5DCBF10-6530-11D2-901F-00C04FB951ED}'

no descriptor

Reading first configuration descriptor:
             nb interfaces: 6
              interface[0]: id = 0
interface[0].altsetting[0]: num endpoints = 1
   Class.SubClass.Protocol: 02.02.00
       endpoint[0].address: 81
           max packet size: 0040
          polling interval: 10
              interface[1]: id = 1
interface[1].altsetting[0]: num endpoints = 2
   Class.SubClass.Protocol: 0A.00.00
       endpoint[0].address: 02
           max packet size: 0040
          polling interval: 00
       endpoint[1].address: 82
           max packet size: 0040
          polling interval: 00
              interface[2]: id = 2
interface[2].altsetting[0]: num endpoints = 2
   Class.SubClass.Protocol: 08.06.50
       endpoint[0].address: 83
           max packet size: 0040
          polling interval: 00
       endpoint[1].address: 03
           max packet size: 0040
          polling interval: 00
              interface[3]: id = 3
interface[3].altsetting[0]: num endpoints = 2
   Class.SubClass.Protocol: 03.00.00
       endpoint[0].address: 84
           max packet size: 0040
          polling interval: 08
       endpoint[1].address: 04
           max packet size: 0040
          polling interval: 08
              interface[4]: id = 4
interface[4].altsetting[0]: num endpoints = 0
   Class.SubClass.Protocol: 01.01.00
              interface[5]: id = 5
interface[5].altsetting[0]: num endpoints = 2
   Class.SubClass.Protocol: 01.03.00
       endpoint[0].address: 05
           max packet size: 0040
          polling interval: 00
       endpoint[1].address: 85
           max packet size: 0040
          polling interval: 00

Kernel driver attached for interface 0: -12

Claiming interface 0...
libusb: info [winusbx_ensure_dev_handle] Late opening device handle for interface 0, path: '\\?\USB#VID_239A&PID_8120&MI_00#7&1F881456&0&0000#{A9CBA50B-208C-BE9A-09AE-21D5FD6C571F}'


Kernel driver attached for interface 1: -12

Claiming interface 1...

Kernel driver attached for interface 2: -12

Claiming interface 2...
libusb: info [winusbx_ensure_dev_handle] Late opening device handle for interface 2, path: '\\?\USB#VID_239A&PID_8120&MI_02#7&1F881456&0&0002#{7F0E090D-155E-CB25-0AA7-F8FAC1F4F499}'


Kernel driver attached for interface 3: -12

Claiming interface 3...

Kernel driver attached for interface 4: -12

Claiming interface 4...
libusb: info [winusbx_ensure_dev_handle] Late opening device handle for interface 4, path: '\\?\USB#VID_239A&PID_8120&MI_04#7&1F881456&0&0004#{FD46223B-D260-141A-A3B5-B1D9FCF25FDA}'


Kernel driver attached for interface 5: -12

Claiming interface 5...
   Failed.

Reading string descriptors:
   String (0x01): "Raspberry Pi"
   String (0x02): "Pico W"
   String (0x03): "E66141040387422B"

Reading interface association descriptors (IADs) for first configuration:
    nb IADs: 1
      IAD 0:
            bFirstInterface: 0
            bInterfaceCount: 2
             bFunctionClass: 02
          bFunctionSubClass: 02
          bFunctionProtocol: 00
                  iFunction: 0
Reading Max LUN:
   Failed: Pipe error   Max LUN = 154
Sending Inquiry:
   sent 6 CDB bytes
   Operation timed out
   Input/Output Error

PS C:\work\libusb\libusb> .\examples\xusb.exe 239a:8120
Using libusb v1.0.26.11778

Opening device 239A:8120...
libusb: warning [hid_open] could not open HID device in R/W mode (keyboard or mouse?) - trying without

Reading device descriptor:
            length: 18
      device class: 0
               S/N: 3
           VID:PID: 239A:8120
         bcdDevice: 0100
   iMan:iProd:iSer: 1:2:3
          nb confs: 1

Reading BOS descriptor: no descriptor

Reading first configuration descriptor:
              total length: 218
         descriptor length: 9
             nb interfaces: 6
              interface[0]: id = 0
interface[0].altsetting[0]: num endpoints = 1
   Class.SubClass.Protocol: 02.02.00
       endpoint[0].address: 81
           max packet size: 0040
          polling interval: 10
              interface[1]: id = 1
interface[1].altsetting[0]: num endpoints = 2
   Class.SubClass.Protocol: 0A.00.00
       endpoint[0].address: 02
           max packet size: 0040
          polling interval: 00
       endpoint[1].address: 82
           max packet size: 0040
          polling interval: 00
              interface[2]: id = 2
interface[2].altsetting[0]: num endpoints = 2
   Class.SubClass.Protocol: 08.06.50
       endpoint[0].address: 83
           max packet size: 0040
          polling interval: 00
       endpoint[1].address: 03
           max packet size: 0040
          polling interval: 00
              interface[3]: id = 3
interface[3].altsetting[0]: num endpoints = 2
   Class.SubClass.Protocol: 03.00.00
       endpoint[0].address: 84
           max packet size: 0040
          polling interval: 08
       endpoint[1].address: 04
           max packet size: 0040
          polling interval: 08
              interface[4]: id = 4
interface[4].altsetting[0]: num endpoints = 0
   Class.SubClass.Protocol: 01.01.00
              interface[5]: id = 5
interface[5].altsetting[0]: num endpoints = 2
   Class.SubClass.Protocol: 01.03.00
       endpoint[0].address: 05
           max packet size: 0040
          polling interval: 00
       endpoint[1].address: 85
           max packet size: 0040
          polling interval: 00

Kernel driver attached for interface 0: -12

Claiming interface 0...

Kernel driver attached for interface 1: -12

Claiming interface 1...

Kernel driver attached for interface 2: -12

Claiming interface 2...

Kernel driver attached for interface 3: -12

Claiming interface 3...

Kernel driver attached for interface 4: -12

Claiming interface 4...

Kernel driver attached for interface 5: -12

Claiming interface 5...
   Failed.

Reading string descriptors:
   String (0x01): "Raspberry Pi"
   String (0x02): "Pico W"
   String (0x03): "E66141040387422B"

Reading OS string descriptor: no descriptor

Reading interface association descriptors (IADs) for first configuration:
    nb IADs: 1
      IAD 0:
            bFirstInterface: 0
            bInterfaceCount: 2
             bFunctionClass: 02
          bFunctionSubClass: 02
          bFunctionProtocol: 00
                  iFunction: 0

Reading Max LUN:
   Failed: Pipe error   Max LUN = 10

Sending Inquiry:
   sent 6 CDB bytes
   Operation timed out
   Input/Output Error

@mcuee
Copy link
Member

mcuee commented Jan 24, 2023

@Novakov

Please take a look at my test result and see if the differences are expected. Thanks.

@Novakov Novakov force-pushed the winusb-lazy-create-file branch from fe8cae8 to 26b5740 Compare January 24, 2023 19:40
@Novakov
Copy link
Author

Novakov commented Jan 24, 2023

@mcuee Branch rebased with changes as requested by @tormodvolden applied. I still need to do some testing but I would like to at least let you proceed with code review.

I don't see any dangerous differences in outputs you provided. Probably verbosity of logs is a bit to high (will reduce them to debug). Could you re-run xusb with rebased branch? I assume that lack of "Reading OS string descriptor" is caused by not-including something that was added recently. I don't quite understand what Max LUN is and why it is different (it should be the same?)

@Novakov Novakov force-pushed the winusb-lazy-create-file branch from 26b5740 to d67cf68 Compare January 24, 2023 19:52
@mcuee
Copy link
Member

mcuee commented Jan 25, 2023

@Novakov

Great. Now I do not see differences between git master and this PR. Ignore the MAX LUN number as it seems to be random -- it seems to me the USB Mass Storage in this Circuit Python FW is not compliant and the number is random.

PS C:\work\libusb> .\libusb_pr1181\examples\xusb.exe 239a:8120
Using libusb v1.0.26.11778

Opening device 239A:8120...
libusb: warning [hid_open] could not open HID device in R/W mode (keyboard or mouse?) - trying without

Reading device descriptor:
            length: 18
      device class: 0
               S/N: 3
           VID:PID: 239A:8120
         bcdDevice: 0100
   iMan:iProd:iSer: 1:2:3
          nb confs: 1

Reading BOS descriptor: no descriptor

Reading first configuration descriptor:
              total length: 218
         descriptor length: 9
             nb interfaces: 6
              interface[0]: id = 0
interface[0].altsetting[0]: num endpoints = 1
   Class.SubClass.Protocol: 02.02.00
       endpoint[0].address: 81
           max packet size: 0040
          polling interval: 10
              interface[1]: id = 1
interface[1].altsetting[0]: num endpoints = 2
   Class.SubClass.Protocol: 0A.00.00
       endpoint[0].address: 02
           max packet size: 0040
          polling interval: 00
       endpoint[1].address: 82
           max packet size: 0040
          polling interval: 00
              interface[2]: id = 2
interface[2].altsetting[0]: num endpoints = 2
   Class.SubClass.Protocol: 08.06.50
       endpoint[0].address: 83
           max packet size: 0040
          polling interval: 00
       endpoint[1].address: 03
           max packet size: 0040
          polling interval: 00
              interface[3]: id = 3
interface[3].altsetting[0]: num endpoints = 2
   Class.SubClass.Protocol: 03.00.00
       endpoint[0].address: 84
           max packet size: 0040
          polling interval: 08
       endpoint[1].address: 04
           max packet size: 0040
          polling interval: 08
              interface[4]: id = 4
interface[4].altsetting[0]: num endpoints = 0
   Class.SubClass.Protocol: 01.01.00
              interface[5]: id = 5
interface[5].altsetting[0]: num endpoints = 2
   Class.SubClass.Protocol: 01.03.00
       endpoint[0].address: 05
           max packet size: 0040
          polling interval: 00
       endpoint[1].address: 85
           max packet size: 0040
          polling interval: 00

Kernel driver attached for interface 0: -12

Claiming interface 0...

Kernel driver attached for interface 1: -12

Claiming interface 1...

Kernel driver attached for interface 2: -12

Claiming interface 2...

Kernel driver attached for interface 3: -12

Claiming interface 3...

Kernel driver attached for interface 4: -12

Claiming interface 4...

Kernel driver attached for interface 5: -12

Claiming interface 5...
   Failed.

Reading string descriptors:
   String (0x01): "Raspberry Pi"
   String (0x02): "Pico W"
   String (0x03): "E661410403559F31"

Reading OS string descriptor: no descriptor

Reading interface association descriptors (IADs) for first configuration:
    nb IADs: 1
      IAD 0:
            bFirstInterface: 0
            bInterfaceCount: 2
             bFunctionClass: 02
          bFunctionSubClass: 02
          bFunctionProtocol: 00
                  iFunction: 0

Reading Max LUN:
   Failed: Pipe error   Max LUN = 23

Sending Inquiry:
   sent 6 CDB bytes
   Operation timed out
   Input/Output Error

@Novakov
Copy link
Author

Novakov commented Jan 30, 2023

I still need to do some testing

Still passes my tests :)

Could you share your test codes? Simplified yet complete test if possible. Thanks.

Here you go https://gist.github.com/Novakov/894862d4e9d8316ef5bd976cc85c2ea1 but I'm afraid that will be of little use to you without corresponding custom USB device.

@mcuee
Copy link
Member

mcuee commented Jan 31, 2023

Here you go https://gist.github.com/Novakov/894862d4e9d8316ef5bd976cc85c2ea1 but I'm afraid that will be of little use to you without corresponding custom USB device.

Thanks. It may still be useful if I take out the device specific codes.

I need to carry out minor changes in order to build under MSYS2 mingw64. The following zip file includes the modified code and binary.
libusb_tests.zip

libusb_pr1181_test.cpp: In function 'libusb::ContextHandle libusb::Init()':
libusb_pr1181_test.cpp:119:64: error: no matching function for call to 'std::exception::exception(const char [29])'
  119 |             throw std::exception("Failed to initialize context");
      |                                                                ^

@mcuee
Copy link
Member

mcuee commented Feb 28, 2023

@tormodvolden

Any other changes required from your side?

I understand that you want more reviewers who are familiar with Windows as well.

@tormodvolden
Copy link
Contributor

Yes, it is not in my capacity to approve this. At least not yet.

@mcuee
Copy link
Member

mcuee commented Mar 31, 2023

Hopefully more people can review this one.

@martinling and @sonatique
Just wondering if you can review this PR. Thanks.

@sonatique
Copy link
Member

@Novakov : Thank you for this PR. I read your proposed changes and I have a question:

As far as I understand, with current master code, it is possible to open a device and start doing control transfers before claiming any interface. I think that this is in line with how USB is designed: you only need to claim an interface for accessing "user" endpoint (endpoint number > 0).

This means that in practice, an application can do control transfers for as long as it want without claiming interface, and it is even possible for multiple application instances to do so concurrently (as long as the driver supports it, which is the case for libusbK): applications would open the same device and get an handle for issuing control transfers. It is only when one application wants to use another endpoint that it has to claim an interface. From now on, other application would not be able to claim the same interface, hence will be prevented from using the same non zero endpoints.

If I read you commit correctly, 'winusbx_open' doesn't really do anything any longer, i.e. there is no file open for dev_handle

My question is: wouldn't this prevent the behavior I described above? Would an application that use control_transfers before claim_interface still work as expected?

I would tend to answer "yes" given the file_handle in current master code are only used or interface_handle, but I wanted to make sure.

Thank you in advance.

@Novakov
Copy link
Author

Novakov commented Sep 19, 2023

@sonatique Application that issues control transfer before claiming interface will work as libusb will automatically claim interface (which will result in opening device file if necessary) and release it after control transfer is completed (and possible close device file). This behavior is already present in master branch under auto-claim name. This PR "only" delays opening device file handle until absolutely necessary.

@sonatique
Copy link
Member

sonatique commented Sep 19, 2023

@sonatique Application that issues control transfer before claiming interface will work as libusb will automatically claim interface

OK, yes, thank you, found the code.

So, the PR looks good to me, thank you.

@mcuee mcuee mentioned this pull request Sep 27, 2023
@mcuee
Copy link
Member

mcuee commented Sep 27, 2023

@tormodvolden

This PR seems to be good to go. Any changes needed from your side?

@tormodvolden
Copy link
Contributor

Github says I have one change requested, but I cannot find it...

So we have:

  • test report by OP Novakov
  • review by sonatique
  • tests by mcuee?

I think I must review it more in detail to give my own approval. But a multitude of documented tests would help also.

@mcuee
Copy link
Member

mcuee commented Dec 5, 2023

@Novakov

Looks like we have to postpone this after 1.0.27 release.

Still, please help to rebase your PR -- I'd like to test this PR again. Thanks.

Windows manages each sub-device of composite device as separate device -
each one requires separate call to CreateFile to obtain dev_handle.
Opening all sub-devices eagerly prevents other applications for
accessing any sub-device even if application that opened the device is
not using them.

This commit modifies WinUSB backend to call CreateFile lazily, so device
handle is opened when necessary (by claiming the interface) and release as
soon as possible (by releasing the interface).

Implementation details:
* winusbx_open becomes essentially no-operation
* winusbx_claim_interface ensures that device handle is opened
* interface used to initialize WinUSB handle has associated counter of
  claimed interfaces
* claiming and releasing interfaces modifies ref-counter accordingly
* when counter reaches zero on releasing interface, device handle is
  closed

Signed-off-by: Maciej Nowak <[email protected]>
@Novakov Novakov force-pushed the winusb-lazy-create-file branch from d67cf68 to 43d16cd Compare January 2, 2024 17:14
@Novakov
Copy link
Author

Novakov commented Jan 2, 2024

@mcuee Branch rebased on top of master, no conflicts reported.

I did not run my usual test suite after rebasing. It is ~day of work to go through all test cases, so I will run them once I get some confirmation that this PR will be merged soon(ish)

@mcuee
Copy link
Member

mcuee commented Jan 3, 2024

@mcuee Branch rebased on top of master, no conflicts reported.

Thanks a lot.

I did not run my usual test suite after rebasing. It is ~day of work to go through all test cases, so I will run them once I get some confirmation that this PR will be merged soon(ish)

That is okay. As of now, this PR will need to be postponed due to lack of resources. The idea is to fix Regression Issue #1386 and then release 1.0.27. Then this PR will hopefully get more reviews and be merged eventually.

@mcuee
Copy link
Member

mcuee commented Jan 3, 2024

First test shows that this PR is fine with an USB Composite Device (but git HEAD is also okay), one WinUSB interface and the other HID interface.

MINGW64 /c/work/libusb/libusb_pr1181
$ ./examples/xusb 16c0:05dc
Using libusb v1.0.27.11855

Opening device 16C0:05DC...

Reading device descriptor:
            length: 18
      device class: 0
               S/N: 3
           VID:PID: 16C0:05DC
         bcdDevice: 0110
   iMan:iProd:iSer: 1:2:3
          nb confs: 1

Reading BOS descriptor: 2 caps
    Container ID:
      {b9d357ad-6611-f843-8790-ebe14ddc7594}
    Platform descriptor:
      bLength                : 28
      PlatformCapabilityUUID : {df60ddd8-8945-c74c-9cd2-659d9e648a9f}

  00000000  00 00 03 06 36 01 5d 00                          ....6.].


Reading first configuration descriptor:
              total length: 50
         descriptor length: 9
             nb interfaces: 2
              interface[0]: id = 0
interface[0].altsetting[0]: num endpoints = 0
   Class.SubClass.Protocol: FF.00.00
              interface[1]: id = 1
interface[1].altsetting[0]: num endpoints = 2
   Class.SubClass.Protocol: 03.00.00
       endpoint[0].address: 81
           max packet size: 0008
          polling interval: 0A
       endpoint[1].address: 01
           max packet size: 0008
          polling interval: 0A

Kernel driver attached for interface 0: (not supported)

Claiming interface 0...

Kernel driver attached for interface 1: (not supported)

Claiming interface 1...

Reading string descriptors:
   String (0x01): "www.fischl.de"
   String (0x02): "USBasp"
   String (0x03): "0001"

Reading OS string descriptor: no descriptor

Reading interface association descriptors (IADs) for first configuration:
    nb IADs: 0

Releasing interface 0...
Releasing interface 1...
Closing device...

@Novakov
Copy link
Author

Novakov commented May 1, 2025

So, is there any chance for this PR to be merged someday?

@mcuee mcuee requested a review from tormodvolden May 1, 2025 11:40
@mcuee
Copy link
Member

mcuee commented May 1, 2025

So, is there any chance for this PR to be merged someday?

We hope to bring in reviewers who are more familiar with libusb project especially the Windows backend to help review and merge Windows related PRs.

@mcuee mcuee mentioned this pull request Jun 2, 2025
@mcuee
Copy link
Member

mcuee commented Aug 23, 2025

@tormodvolden and @sonatique

Please take a look at this PR when you got the time. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Multiple WinUSB devices in single composite device Windows: libusb Windows backend for some USB composite device with IAD

6 participants