@@ -118,6 +118,26 @@ void usb_device::close() {
118118}
119119
120120void usb_device::claim_interface (int interface_number) {
121+ // When a device is plugged in, a notification is sent. For composite devices, it is a notification
122+ // that the composite device is ready. Each composite function will be registered separately and
123+ // the related information will be available with a delay. So for composite functions, several
124+ // retries might be needed until the device path is available.
125+ int num_retries = 30 ; // 30 x 100ms
126+ while (true ) {
127+ if (try_claim_interface (interface_number))
128+ return ; // success
129+
130+ num_retries -= 1 ;
131+ if (num_retries == 0 )
132+ throw usb_error (" claiming interface failed (function has no device interface GUID/path, might be missing WinUSB driver)" );
133+
134+ // sleep and retry
135+ std::cerr << " Sleeping for 100ms..." << std::endl;
136+ std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
137+ }
138+ }
139+
140+ bool usb_device::try_claim_interface (int interface_number) {
121141
122142 if (!is_open ())
123143 throw usb_error (" USB device is not open" );
@@ -135,7 +155,7 @@ void usb_device::claim_interface(int interface_number) {
135155 if (first_intf_handle->device_handle == nullptr ) {
136156 auto device_path = get_interface_device_path (first_intf_handle->interface_num );
137157 if (device_path.empty ())
138- throw usb_error ( " failed to claim interface (function has no device path, might be missing WinUSB driver) " ) ;
158+ return false ;
139159
140160 std::wcerr << " opening device " << device_path << std::endl;
141161
@@ -169,6 +189,7 @@ void usb_device::claim_interface(int interface_number) {
169189
170190 first_intf_handle->device_open_count += 1 ;
171191 intf->set_claimed (true );
192+ return true ;
172193}
173194
174195void usb_device::release_interface (int interface_number) {
@@ -465,72 +486,56 @@ std::wstring usb_device::get_interface_device_path(int interface_num) {
465486 if (it != interface_device_paths_.end ())
466487 return it->second ;
467488
468- int num_retries = 30 ; // 30 x 100ms
469-
470- while (num_retries > 0 ) {
471-
472- auto dev_info_set = device_info_set::of_path (device_path_);
473-
474- auto children_instance_ids = dev_info_set.get_device_property_string_list (DEVPKEY_Device_Children);
475- if (children_instance_ids.empty ()) {
476- std::wcerr << " missing children IDs for device " << device_path_ << std::endl;
489+ auto dev_info_set = device_info_set::of_path (device_path_);
477490
478- } else {
491+ auto children_instance_ids = dev_info_set. get_device_property_string_list (DEVPKEY_Device_Children);
479492
480- std::wcerr << " children IDs: " ;
481- for (auto it = children_instance_ids.begin (); it < children_instance_ids.end (); it++) {
482- if (it != children_instance_ids.begin ())
483- std::wcerr << " , " ;
484- std::wcerr << *it;
485- }
486- std::wcerr << std::endl;
487-
488- std::wstring child_path;
489- for (auto & child_id : children_instance_ids) {
490- auto res = get_child_device_path (child_id, interface_num, child_path);
491- if (res == 1 )
492- return child_path;
493- if (res == -1 )
494- break ;
495- }
496- }
493+ std::wcerr << " children IDs: " ;
494+ for (auto it = children_instance_ids.begin (); it < children_instance_ids.end (); it++) {
495+ if (it != children_instance_ids.begin ())
496+ std::wcerr << " , " ;
497+ std::wcerr << *it;
498+ }
499+ std::wcerr << std::endl;
497500
498- std::cerr << " Sleeping for 100ms..." << std::endl;
499- std::this_thread::sleep_for (std::chrono::milliseconds (100 ));
500- num_retries -= 1 ;
501+ std::wstring child_path;
502+ for (auto & child_id : children_instance_ids) {
503+ child_path = get_child_device_path (child_id, interface_num);
504+ if (!child_path.empty ())
505+ return child_path;
501506 }
502507
503- return {};
508+ return {}; // retry later
504509}
505510
506- int usb_device::get_child_device_path (const std::wstring& child_id, int interface_num, std::wstring& device_path ) {
511+ std::wstring usb_device::get_child_device_path (const std::wstring& child_id, int interface_num) {
507512
508513 auto dev_info_set = device_info_set::of_instance (child_id);
509514
510515 auto hardware_ids = dev_info_set.get_device_property_string_list (DEVPKEY_Device_HardwareIds);
511516 if (hardware_ids.empty ()) {
512517 std::wcerr << " child device " << child_id << " has no hardware IDs" << std::endl;
513- return 0 ; // continue with next child
518+ return {} ; // continue with next child
514519 }
515520
516521 auto intf_num = extract_interface_number (hardware_ids);
517522 if (intf_num == -1 ) {
518523 std::wcerr << " child device " << child_id << " has no interface number" << std::endl;
519- return 0 ; // continue with next child
524+ return {} ; // continue with next child
520525 }
521526
522527 if (intf_num != interface_num)
523- return 0 ; // continue with next child
528+ return {} ; // continue with next child
524529
525- device_path = dev_info_set.get_device_path_by_guid (child_id);
530+ auto device_path = dev_info_set.get_device_path_by_guid (child_id);
526531 if (device_path.empty ()) {
527532 std::wcerr << " child device " << child_id << " has no device path" << std::endl;
528- return - 1 ; // retry later
533+ throw usb_error ( " claiming interface failed (function has no device interface GUID/path, might be missing WinUSB driver) " );
529534 }
530535
531536 std::wcerr << " child device: interface=" << intf_num << " , device path=" << device_path << std::endl;
532537 interface_device_paths_[interface_num] = device_path;
533- return 1 ; // success
538+ return device_path ; // success
534539}
535540
536541static 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})" );
0 commit comments