From 43f4192fc668fd1476ae80c6284317402d933897 Mon Sep 17 00:00:00 2001 From: Manuel Bl Date: Fri, 29 Sep 2023 21:33:04 +0200 Subject: [PATCH] Windows: give up earlier on waiting for child device --- .../usb/windows/WindowsUSBDevice.java | 28 +++---- reference/windows/USB/usb_device.cpp | 83 ++++++++++--------- reference/windows/USB/usb_device.hpp | 3 +- 3 files changed, 57 insertions(+), 57 deletions(-) diff --git a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java index c7dc99e..f2d2d73 100644 --- a/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java +++ b/java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsUSBDevice.java @@ -44,10 +44,6 @@ public class WindowsUSBDevice extends USBDeviceImpl { private static final System.Logger LOG = System.getLogger(WindowsUSBDevice.class.getName()); - private static final int RETRY_LATER = 0; - private static final int TRY_NEXT_CHILD = 1; - private static final int SUCCESS = 2; - private final WindowsAsyncTask asyncTask; /** * Indicates if the device is a composite device @@ -125,7 +121,7 @@ public void claimInterface(int interfaceNumber) { numRetries -= 1; if (numRetries == 0) - throw new USBException("claiming interface failed (function has no device path, might be missing WinUSB driver)"); + throw new USBException("claiming interface failed (function has no device path / interface GUID, might be missing WinUSB driver)"); // sleep and retry try { @@ -534,11 +530,9 @@ private String getInterfaceDevicePath(int interfaceNumber) { LOG.log(DEBUG, "children instance IDs: {0}", childrenInstanceIDs); for (var instanceId : childrenInstanceIDs) { - var res = fetchChildDevicePath(instanceId, interfaceNumber); - if (res == SUCCESS) - return devicePaths.get(interfaceNumber); - if (res == RETRY_LATER) - return null; // retry later + devicePath = getChildDevicePath(instanceId, interfaceNumber); + if (devicePath != null) + return devicePath; } } } @@ -552,35 +546,35 @@ private String getCachedInterfaceDevicePath(int interfaceNumber) { return devicePaths.get(interfaceNumber); } - private int fetchChildDevicePath(String instanceId, int interfaceNumber) { + private String getChildDevicePath(String instanceId, int interfaceNumber) { try (var deviceInfoSet = DeviceInfoSet.ofInstance(instanceId)) { // get hardware IDs (to extract interface number) var hardwareIds = deviceInfoSet.getStringListProperty(HardwareIds); if (hardwareIds == null) { LOG.log(DEBUG, "child device {0} has no hardware IDs", instanceId); - return TRY_NEXT_CHILD; + return null; } var extractedNumber = extractInterfaceNumber(hardwareIds); if (extractedNumber == -1) { LOG.log(DEBUG, "child device {0} has no interface number", instanceId); - return TRY_NEXT_CHILD; + return null; } if (extractedNumber != interfaceNumber) - return TRY_NEXT_CHILD; + return null; var devicePath = deviceInfoSet.getDevicePathByGUID(instanceId); if (devicePath == null) { - LOG.log(INFO, "Child device {0} has no device path", instanceId); - return RETRY_LATER; + LOG.log(INFO, "Child device {0} has no device path / interface GUID", instanceId); + throw new USBException("claiming interface failed (function has no device path / interface GUID, might be missing WinUSB driver)"); } if (devicePaths == null) devicePaths = new HashMap<>(); devicePaths.put(interfaceNumber, devicePath); - return SUCCESS; + return devicePath; } } diff --git a/reference/windows/USB/usb_device.cpp b/reference/windows/USB/usb_device.cpp index e1d68a4..bcb8b72 100644 --- a/reference/windows/USB/usb_device.cpp +++ b/reference/windows/USB/usb_device.cpp @@ -118,6 +118,26 @@ void usb_device::close() { } void usb_device::claim_interface(int interface_number) { + // When a device is plugged in, a notification is sent. For composite devices, it is a notification + // that the composite device is ready. Each composite function will be registered separately and + // the related information will be available with a delay. So for composite functions, several + // retries might be needed until the device path is available. + int num_retries = 30; // 30 x 100ms + while (true) { + if (try_claim_interface(interface_number)) + return; // success + + num_retries -= 1; + if (num_retries == 0) + throw usb_error("claiming interface failed (function has no device interface GUID/path, might be missing WinUSB driver)"); + + // sleep and retry + std::cerr << "Sleeping for 100ms..." << std::endl; + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } +} + +bool usb_device::try_claim_interface(int interface_number) { if (!is_open()) throw usb_error("USB device is not open"); @@ -135,7 +155,7 @@ void usb_device::claim_interface(int interface_number) { if (first_intf_handle->device_handle == nullptr) { auto device_path = get_interface_device_path(first_intf_handle->interface_num); if (device_path.empty()) - throw usb_error("failed to claim interface (function has no device path, might be missing WinUSB driver)"); + return false; std::wcerr << "opening device " << device_path << std::endl; @@ -169,6 +189,7 @@ void usb_device::claim_interface(int interface_number) { first_intf_handle->device_open_count += 1; intf->set_claimed(true); + return true; } void usb_device::release_interface(int interface_number) { @@ -465,72 +486,56 @@ std::wstring usb_device::get_interface_device_path(int interface_num) { if (it != interface_device_paths_.end()) return it->second; - int num_retries = 30; // 30 x 100ms - - while (num_retries > 0) { - - auto dev_info_set = device_info_set::of_path(device_path_); - - auto children_instance_ids = dev_info_set.get_device_property_string_list(DEVPKEY_Device_Children); - if (children_instance_ids.empty()) { - std::wcerr << "missing children IDs for device " << device_path_ << std::endl; + auto dev_info_set = device_info_set::of_path(device_path_); - } else { + auto children_instance_ids = dev_info_set.get_device_property_string_list(DEVPKEY_Device_Children); - std::wcerr << "children IDs: "; - for (auto it = children_instance_ids.begin(); it < children_instance_ids.end(); it++) { - if (it != children_instance_ids.begin()) - std::wcerr << ", "; - std::wcerr << *it; - } - std::wcerr << std::endl; - - std::wstring child_path; - for (auto& child_id : children_instance_ids) { - auto res = get_child_device_path(child_id, interface_num, child_path); - if (res == 1) - return child_path; - if (res == -1) - break; - } - } + std::wcerr << "children IDs: "; + for (auto it = children_instance_ids.begin(); it < children_instance_ids.end(); it++) { + if (it != children_instance_ids.begin()) + std::wcerr << ", "; + std::wcerr << *it; + } + std::wcerr << std::endl; - std::cerr << "Sleeping for 100ms..." << std::endl; - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - num_retries -= 1; + std::wstring child_path; + for (auto& child_id : children_instance_ids) { + child_path = get_child_device_path(child_id, interface_num); + if (!child_path.empty()) + return child_path; } - return {}; + return {}; // retry later } -int usb_device::get_child_device_path(const std::wstring& child_id, int interface_num, std::wstring& device_path) { +std::wstring usb_device::get_child_device_path(const std::wstring& child_id, int interface_num) { auto dev_info_set = device_info_set::of_instance(child_id); auto hardware_ids = dev_info_set.get_device_property_string_list(DEVPKEY_Device_HardwareIds); if (hardware_ids.empty()) { std::wcerr << "child device " << child_id << " has no hardware IDs" << std::endl; - return 0; // continue with next child + return {}; // continue with next child } auto intf_num = extract_interface_number(hardware_ids); if (intf_num == -1) { std::wcerr << "child device " << child_id << " has no interface number" << std::endl; - return 0; // continue with next child + return {}; // continue with next child } if (intf_num != interface_num) - return 0; // continue with next child + return {}; // continue with next child - device_path = dev_info_set.get_device_path_by_guid(child_id); + auto device_path = dev_info_set.get_device_path_by_guid(child_id); if (device_path.empty()) { std::wcerr << "child device " << child_id << " has no device path" << std::endl; - return -1; // retry later + throw usb_error("claiming interface failed (function has no device interface GUID/path, might be missing WinUSB driver)"); } std::wcerr << "child device: interface=" << intf_num << ", device path=" << device_path << std::endl; interface_device_paths_[interface_num] = device_path; - return 1; // success + return device_path; // success } static const std::wregex multiple_interface_id_pattern(L"USB\\\\VID_[0-9A-Fa-f]{4}&PID_[0-9A-Fa-f]{4}&MI_([0-9A-Fa-f]{2})"); diff --git a/reference/windows/USB/usb_device.hpp b/reference/windows/USB/usb_device.hpp index 100a58f..6f5760c 100644 --- a/reference/windows/USB/usb_device.hpp +++ b/reference/windows/USB/usb_device.hpp @@ -251,8 +251,9 @@ class usb_device { usb_device(usb_registry* registry, std::wstring&& device_path, int vendor_id, int product_id, const std::vector& config_desc, bool is_composite); void set_product_names(const std::string& manufacturer, const std::string& product, const std::string& serial_number); void build_handles(const std::wstring& device_path); + bool try_claim_interface(int interface_number); std::wstring get_interface_device_path(int interface_num); - int get_child_device_path(const std::wstring& child_id, int interface_num, std::wstring& device_path); + std::wstring get_child_device_path(const std::wstring& child_id, int interface_num); static int extract_interface_number(const std::vector& hardware_ids); int control_transfer_core(const usb_control_request& request, uint8_t* data, int timeout);