3131import java .lang .invoke .MethodHandles ;
3232import java .lang .invoke .MethodType ;
3333import java .util .*;
34- import java .util .regex .Pattern ;
35- import java .util .stream .Collectors ;
3634
37- import static java .lang .System .Logger .Level .DEBUG ;
3835import static java .lang .System .Logger .Level .INFO ;
3936import static java .lang .foreign .MemorySegment .NULL ;
4037import static java .lang .foreign .ValueLayout .*;
@@ -177,61 +174,19 @@ private USBDevice createDeviceFromDeviceInfo(DeviceInfoSet deviceInfoSet, String
177174 hubHandles .put (hubPath , hubHandle );
178175 }
179176
180- // check for composite device
181- var children = getChildDevices (deviceInfoSet , devicePath );
182-
183- return createDevice (devicePath , children , hubHandle , usbPortNum );
184- }
185- }
186-
187- @ SuppressWarnings ({"java:S106" , "java:S1168" })
188- private Map <Integer , String > getChildDevices (DeviceInfoSet deviceInfoSet , String devicePath ) {
189- if (!deviceInfoSet .isCompositeDevice ())
190- return null ;
191-
192- // For certain devices, it seems to take some time until the "Device_Children"
193- // entry is present. So we retry a few times if needed and pause in between.
194- List <String > childrenInstanceIDs ;
195- var numTries = 5 ;
196- while (true ) {
197- numTries -= 1 ;
198- childrenInstanceIDs = deviceInfoSet .getStringListProperty (Children );
199- if (childrenInstanceIDs != null || numTries == 0 )
200- break ;
201-
202- // sleep and retry
203- try {
204- LOG .log (DEBUG , "Sleeping for 200ms (after unsuccessfully retrieving DEVPKEY_Device_Children)" );
205- //noinspection BusyWait
206- Thread .sleep (200 );
207- } catch (InterruptedException e ) {
208- Thread .currentThread ().interrupt ();
209- }
177+ return createDevice (devicePath , hubHandle , usbPortNum );
210178 }
211-
212- if (childrenInstanceIDs == null ) {
213- LOG .log (DEBUG , "unable to retrieve information about children of device {0} - ignoring" , devicePath );
214- return null ;
215- }
216-
217- // create children map (interface number -> device path)
218- return childrenInstanceIDs .stream ()
219- .map (WindowsUSBDeviceRegistry ::getNumberPathTuple )
220- .filter (Objects ::nonNull )
221- .collect (Collectors .toMap (Map .Entry ::getKey , Map .Entry ::getValue ));
222179 }
223180
224181 /**
225182 * Retrieve device descriptor and create {@code USBDevice} instance
226183 *
227184 * @param devicePath the device path
228- * @param children map of child device paths, indexed by the first interface number
229185 * @param hubHandle the hub handle (parent)
230186 * @param usbPortNum the USB port number
231187 * @return the {@code USBDevice} instance
232188 */
233- private USBDevice createDevice (String devicePath , Map <Integer , String > children , MemorySegment hubHandle ,
234- int usbPortNum ) {
189+ private USBDevice createDevice (String devicePath , MemorySegment hubHandle , int usbPortNum ) {
235190
236191 try (var arena = Arena .ofConfined ()) {
237192
@@ -253,7 +208,8 @@ private USBDevice createDevice(String devicePath, Map<Integer, String> children,
253208
254209 var configDesc = getDescriptor (hubHandle , usbPortNum , CONFIGURATION_DESCRIPTOR_TYPE , 0 , (short ) 0 , arena );
255210
256- var device = new WindowsUSBDevice (devicePath , children , vendorId , productId , configDesc );
211+ // create new device
212+ var device = new WindowsUSBDevice (devicePath , vendorId , productId , configDesc );
257213 device .setFromDeviceDescriptor (descriptorSegment );
258214 device .setProductString (descriptorSegment , index -> getStringDescriptor (hubHandle , usbPortNum , index ));
259215
@@ -397,54 +353,4 @@ protected int findDeviceIndex(List<USBDevice> deviceList, Object deviceId) {
397353 }
398354 return -1 ;
399355 }
400-
401- /**
402- * Looks up the interface number and device path for the child device with the given instance ID.
403- *
404- * @param instanceId child instance ID
405- * @return tuple consisting of interface number and device path, or {@code null} if unsuccessful
406- */
407- private static Map .Entry <Integer , String > getNumberPathTuple (String instanceId ) {
408- try (var deviceInfoSet = DeviceInfoSet .ofInstance (instanceId )) {
409-
410- // get hardware IDs (to extract interface number)
411- var hardwareIds = deviceInfoSet .getStringListProperty (HardwareIds );
412- if (hardwareIds == null )
413- throwException ("internal error (device property 'HardwareIds' is missing)" );
414- var interfaceNumber = extractInterfaceNumber (hardwareIds );
415- if (interfaceNumber == -1 ) {
416- LOG .log (DEBUG , "Child device {0} has no interface number" , instanceId );
417- return null ;
418- }
419-
420- var devicePath = deviceInfoSet .getDevicePathByGUID (instanceId );
421- if (devicePath == null ) {
422- LOG .log (DEBUG , "Child device {0} has no device path" , instanceId );
423- return null ;
424- }
425-
426- return new AbstractMap .SimpleImmutableEntry <>(interfaceNumber , devicePath );
427- }
428- }
429-
430- private static final Pattern MULTIPLE_INTERFACE_ID = Pattern .compile (
431- "USB\\ \\ VID_[0-9A-Fa-f]{4}&PID_[0-9A-Fa-f]{4}&MI_([0-9A-Fa-f]{2})" );
432-
433- private static int extractInterfaceNumber (List <String > hardwareIds ) {
434- // Also see https://docs.microsoft.com/en-us/windows-hardware/drivers/install/standard-usb-identifiers#multiple-interface-usb-devices
435-
436- for (var id : hardwareIds ) {
437- var matcher = MULTIPLE_INTERFACE_ID .matcher (id );
438- if (matcher .find ()) {
439- var intfHexNumber = matcher .group (1 );
440- try {
441- return Integer .parseInt (intfHexNumber , 16 );
442- } catch (NumberFormatException e ) {
443- // ignore and try next one
444- }
445- }
446- }
447-
448- return -1 ;
449- }
450356}
0 commit comments