libusb icon indicating copy to clipboard operation
libusb copied to clipboard

Windows device reset support via libusbK?

Open mxk opened this issue 3 years ago • 11 comments

I know that WinUSB is not capable of performing a full device reset, but I'm less clear about libusbK. As far as I can tell, it does support resetting a device that's using libusbK.sys driver, but the shared WinUSB API in libusb doesn't take advantage of this functionality:

https://github.com/libusb/libusb/blob/fcf0c710ef5911ae37fbbf1b39d48a89f6f14e8a/libusb/os/windows_winusb.c#L2526-L2527 https://github.com/libusb/libusb/blob/fcf0c710ef5911ae37fbbf1b39d48a89f6f14e8a/libusb/os/windows_winusb.c#L3413-L3418

Is that an accurate description of the current situation and is there a reason why this functionality is disabled?

I'm running into a problem where when I open a device (Bluetooth controller), I receive data that was sent previously, but never received (e.g. program crashed). I can't seem to find any way on Windows to flush all endpoints before re-initializing the device. A reset would be ideal for this purpose.

mxk avatar Mar 20 '23 14:03 mxk

@mxk

Have you tried it? The reset code is supposed to work for device with libusb0.sys or libsbK.sys driver.

mcuee avatar Mar 22 '23 10:03 mcuee

I have, and it doesn't seem to do anything. The only log output I get is:

[ 0.020002] [0000a430] libusb: debug [libusb_reset_device]  

Same output when I switch the device driver back to WinUSB.

mxk avatar Mar 22 '23 14:03 mxk

Ok, I figured it out. The reset wasn't working because this line was evaluating to false: https://github.com/libusb/libusb/blob/fcf0c710ef5911ae37fbbf1b39d48a89f6f14e8a/libusb/os/windows_winusb.c#L3416

I was trying to reset the device before claiming any interfaces. Once I added a call to claim interface 0 first, the reset worked.

Is this the expected behavior? I think it should at least be documented. I'm assuming that I don't need to re-claim interface 0 after the reset, is that correct?

mxk avatar Mar 22 '23 15:03 mxk

Yes this should be the expected bahavior.

After reset, the dveice handle is no longer valid. You have to wait a while (after Windows enumerates the device), re-open the device and then claim interface 0 again.

mcuee avatar Mar 23 '23 13:03 mcuee

Is that Windows-only behavior? The documentation says that the handle is invalidated only if libusb_reset_device return LIBUSB_ERROR_NOT_FOUND. In my testing, it's returning LIBUSB_SUCCESS and the handle appears to still be valid.

Just to double-check another assumption, I use libusb_get_port_numbers before the reset to get the full port path to the device. In the event that libusb_reset_device returns LIBUSB_ERROR_NOT_FOUND, I then re-scan all of the devices looking for the matching ports. I assume that this would be more reliable than using VID/PID (could have multiple devices) or bus number and address (could change). Is there a better way to do this?

mxk avatar Mar 23 '23 14:03 mxk

I tend to think libusb_reset behavior is platform specific and in general try to fix your device and only use this as the last resort. But I do not have deep understanding here.

Let's see if @tormodvolden or others can chime in here to help.

mcuee avatar Mar 23 '23 14:03 mcuee

Reference from historical discussion: behaviors are different across Linux, macOS, Windows and FreeBSD. https://marc.info/?t=135728164400001&r=1&w=2

mcuee avatar Mar 23 '23 14:03 mcuee

@mxk You may get better answers from libusb-devel mailing list for this issue. So you may want to try that as well. You need to subscribe to the mailing list in order to post to the mailing list. https://github.com/libusb/libusb/wiki#user-content-Support

mcuee avatar Mar 23 '23 14:03 mcuee

Ok, I figured it out. The reset wasn't working because this line was evaluating to false: libusb/os/windows_winusb.c#L3416 if (HANDLE_VALID(winusb_handle))

Just wondering if libusb should warn here if the handle is not valid.

The challenge here is that libusb doesn't really know what the correct "device handle" is unless it knows which interface is in play, since Windows may present interfaces as belonging to different logical devices for the same physical device. See for example PR #1181 which would make "open" a no-op and "claim_interface" the real device open.

tormodvolden avatar Mar 30 '23 16:03 tormodvolden

Ok, I figured it out. The reset wasn't working because this line was evaluating to false: libusb/os/windows_winusb.c#L3416 if (HANDLE_VALID(winusb_handle))

Just wondering if libusb should warn here if the handle is not valid.

I agree this is a good place to insert a warning.

The challenge here is that libusb doesn't really know what the correct "device handle" is unless it knows which interface is in play, since Windows may present interfaces as belonging to different logical devices for the same physical device. See for example PR #1181 which would make "open" a no-op and "claim_interface" the real device open.

It seems to me PR #1181 is a good one to be considered for Windows.

  • #1181

mcuee avatar Mar 31 '23 01:03 mcuee

Just to make clear, I am not suggesting that #1181 solves any issue in this case, but it demonstrates the challenge on Windows. libusb_open() gives you a libusb device handle, which at least references an open Windows handle to one of the [device paths associated with the] interfaces of the physical device. But with #1181, the libusb handle will have no Windows handle associated before a claim is performed.

tormodvolden avatar Mar 31 '23 11:03 tormodvolden