@@ -412,17 +412,43 @@ static void hid_internal_get_ble_info(struct hid_device_info* dev, DEVINST dev_n
412412 }
413413}
414414
415+ /* USB Device Interface Number.
416+ It can be parsed out of the Hardware ID if a USB device is has multiple interfaces (composite device).
417+ See https://docs.microsoft.com/windows-hardware/drivers/hid/hidclass-hardware-ids-for-top-level-collections
418+ and https://docs.microsoft.com/windows-hardware/drivers/install/standard-usb-identifiers
419+
420+ hardware_id is always expected to be uppercase.
421+ */
422+ static int hid_internal_get_interface_number (const wchar_t * hardware_id )
423+ {
424+ int interface_number ;
425+ wchar_t * startptr , * endptr ;
426+ const wchar_t * interface_token = L"&MI_" ;
427+
428+ startptr = wcsstr (hardware_id , interface_token );
429+ if (!startptr )
430+ return -1 ;
431+
432+ startptr += wcslen (interface_token );
433+ interface_number = wcstol (startptr , & endptr , 16 );
434+ if (endptr == startptr )
435+ return -1 ;
436+
437+ return interface_number ;
438+ }
439+
415440static void hid_internal_get_info (struct hid_device_info * dev )
416441{
417442 const char * tmp = NULL ;
418- wchar_t * interface_path = NULL , * device_id = NULL , * compatible_ids = NULL ;
443+ wchar_t * interface_path = NULL , * device_id = NULL , * compatible_ids = NULL , * hardware_ids = NULL ;
419444 mbstate_t state ;
420445 ULONG len ;
421446 CONFIGRET cr ;
422447 DEVPROPTYPE property_type ;
423448 DEVINST dev_node ;
424449
425450 static DEVPROPKEY DEVPKEY_Device_InstanceId = { { 0x78c34fc8 , 0x104a , 0x4aca , 0x9e , 0xa4 , 0x52 , 0x4d , 0x52 , 0x99 , 0x6e , 0x57 }, 256 }; // DEVPROP_TYPE_STRING
451+ static DEVPROPKEY DEVPKEY_Device_HardwareIds = { { 0xa45c254e , 0xdf1c , 0x4efd , 0x80 , 0x20 , 0x67 , 0xd1 , 0x46 , 0xa8 , 0x50 , 0xe0 }, 3 }; // DEVPROP_TYPE_STRING_LIST
426452 static DEVPROPKEY DEVPKEY_Device_CompatibleIds = { { 0xa45c254e , 0xdf1c , 0x4efd , 0x80 , 0x20 , 0x67 , 0xd1 , 0x46 , 0xa8 , 0x50 , 0xe0 }, 4 }; // DEVPROP_TYPE_STRING_LIST
427453
428454 if (!CM_Get_Device_Interface_PropertyW ||
@@ -455,6 +481,27 @@ static void hid_internal_get_info(struct hid_device_info* dev)
455481 if (cr != CR_SUCCESS )
456482 goto end ;
457483
484+ /* Get the hardware ids from devnode */
485+ len = 0 ;
486+ cr = CM_Get_DevNode_PropertyW (dev_node , & DEVPKEY_Device_HardwareIds , & property_type , NULL , & len , 0 );
487+ if (cr == CR_BUFFER_SMALL && property_type == DEVPROP_TYPE_STRING_LIST ) {
488+ hardware_ids = (wchar_t * )calloc (len , sizeof (BYTE ));
489+ cr = CM_Get_DevNode_PropertyW (dev_node , & DEVPKEY_Device_HardwareIds , & property_type , (PBYTE )hardware_ids , & len , 0 );
490+ }
491+ if (cr != CR_SUCCESS )
492+ goto end ;
493+
494+ // Search for interface number in hardware ids
495+ for (wchar_t * hardware_id = hardware_ids ; * hardware_id ; hardware_id += wcslen (hardware_id ) + 1 ) {
496+ /* Normalize to upper case */
497+ for (wchar_t * p = hardware_id ; * p ; ++ p ) * p = towupper (* p );
498+
499+ dev -> interface_number = hid_internal_get_interface_number (hardware_id );
500+
501+ if (dev -> interface_number != -1 )
502+ break ;
503+ }
504+
458505 /* Get devnode parent */
459506 cr = CM_Get_Parent (& dev_node , dev_node , 0 );
460507 if (cr != CR_SUCCESS )
@@ -487,6 +534,7 @@ static void hid_internal_get_info(struct hid_device_info* dev)
487534end :
488535 free (interface_path );
489536 free (device_id );
537+ free (hardware_ids );
490538 free (compatible_ids );
491539}
492540
@@ -557,25 +605,6 @@ static struct hid_device_info *hid_get_device_info(const char *path, HANDLE hand
557605 wstr [WSTR_LEN - 1 ] = L'\0' ;
558606 dev -> product_string = _wcsdup (wstr );
559607
560- /* Interface Number. It can sometimes be parsed out of the path
561- on Windows if a device has multiple interfaces. See
562- https://docs.microsoft.com/windows-hardware/drivers/hid/hidclass-hardware-ids-for-top-level-collections
563- or search for "HIDClass Hardware IDs for Top-Level Collections" at Microsoft Docs. If it's not
564- in the path, it's set to -1. */
565- dev -> interface_number = -1 ;
566- if (dev -> path ) {
567- char * interface_component = strstr (dev -> path , "&mi_" );
568- if (interface_component ) {
569- char * hex_str = interface_component + 4 ;
570- char * endptr = NULL ;
571- dev -> interface_number = strtol (hex_str , & endptr , 16 );
572- if (endptr == hex_str ) {
573- /* The parsing failed. Set interface_number to -1. */
574- dev -> interface_number = -1 ;
575- }
576- }
577- }
578-
579608 hid_internal_get_info (dev );
580609
581610 return dev ;
0 commit comments