@@ -143,8 +143,26 @@ static struct hid_api_version api_version = {
143143
144144 typedef DWORD RETURN_TYPE ;
145145 typedef RETURN_TYPE CONFIGRET ;
146+ typedef DWORD DEVNODE , DEVINST ;
147+ typedef DEVNODE * PDEVNODE , * PDEVINST ;
148+ typedef WCHAR * DEVNODEID_W , * DEVINSTID_W ;
146149
147150#define CR_SUCCESS (0x00000000)
151+ #define CR_BUFFER_SMALL (0x0000001A)
152+
153+ #define CM_LOCATE_DEVNODE_NORMAL 0x00000000
154+
155+ #define DEVPROP_TYPE_STRING 0x00000012
156+
157+ typedef CONFIGRET (__stdcall* CM_Locate_DevNodeW_ )(PDEVINST pdnDevInst , DEVINSTID_W pDeviceID , ULONG ulFlags );
158+ typedef CONFIGRET (__stdcall* CM_Get_Parent_ )(PDEVINST pdnDevInst , DEVINST dnDevInst , ULONG ulFlags );
159+ typedef CONFIGRET (__stdcall* CM_Get_DevNode_PropertyW_ )(DEVINST dnDevInst , CONST DEVPROPKEY * PropertyKey , DEVPROPTYPE * PropertyType , PBYTE PropertyBuffer , PULONG PropertyBufferSize , ULONG ulFlags );
160+ typedef CONFIGRET (__stdcall* CM_Get_Device_Interface_PropertyW_ )(LPCWSTR pszDeviceInterface , CONST DEVPROPKEY * PropertyKey , DEVPROPTYPE * PropertyType , PBYTE PropertyBuffer , PULONG PropertyBufferSize , ULONG ulFlags );
161+
162+ static CM_Locate_DevNodeW_ CM_Locate_DevNodeW ;
163+ static CM_Get_Parent_ CM_Get_Parent ;
164+ static CM_Get_DevNode_PropertyW_ CM_Get_DevNode_PropertyW ;
165+ static CM_Get_Device_Interface_PropertyW_ CM_Get_Device_Interface_PropertyW ;
148166
149167 DECLARE_HANDLE (HCMNOTIFICATION );
150168 typedef HCMNOTIFICATION * PHCMNOTIFICATION ;
@@ -337,6 +355,10 @@ static int lookup_functions()
337355# pragma GCC diagnostic ignored "-Wcast-function-type"
338356#endif
339357#define RESOLVE (x ) x = (x##_)GetProcAddress(cfgmgr32_lib_handle, #x); if (!x) return -1;
358+ RESOLVE (CM_Locate_DevNodeW );
359+ RESOLVE (CM_Get_Parent );
360+ RESOLVE (CM_Get_DevNode_PropertyW );
361+ RESOLVE (CM_Get_Device_Interface_PropertyW );
340362 RESOLVE (CM_Register_Notification );
341363 RESOLVE (CM_Unregister_Notification );
342364#undef RESOLVE
@@ -404,6 +426,107 @@ int HID_API_EXPORT hid_exit(void)
404426 return 0 ;
405427}
406428
429+ static void hid_internal_get_info (struct hid_device_info * dev )
430+ {
431+ dev -> bus_type = HID_BUS_UNKNOWN ;
432+
433+ wchar_t * device_id , * interface_path ;
434+ ULONG len ;
435+ CONFIGRET cr ;
436+ DEVPROPTYPE property_type ;
437+ DEVINST dev_node ;
438+
439+ static DEVPROPKEY DEVPKEY_Device_InstanceId = { { 0x78c34fc8 , 0x104a , 0x4aca , 0x9e , 0xa4 , 0x52 , 0x4d , 0x52 , 0x99 , 0x6e , 0x57 }, 256 }; // DEVPROP_TYPE_STRING
440+
441+ if (!CM_Get_Device_Interface_PropertyW ||
442+ !CM_Locate_DevNodeW ||
443+ !CM_Get_Parent ||
444+ !CM_Get_DevNode_PropertyW )
445+ goto close ;
446+
447+ len = (ULONG )strlen (dev -> path );
448+ interface_path = (wchar_t * )calloc (len + 1 , sizeof (wchar_t ));
449+
450+ if (mbstowcs (interface_path , dev -> path , len ) == (size_t )-1 )
451+ goto close ;
452+
453+ /* Get the device id from interface path */
454+ len = 0 ;
455+ cr = CM_Get_Device_Interface_PropertyW (interface_path , & DEVPKEY_Device_InstanceId , & property_type , NULL , & len , 0 );
456+ if (cr == CR_BUFFER_SMALL || property_type == DEVPROP_TYPE_STRING ) {
457+ device_id = (wchar_t * )calloc (len , sizeof (BYTE ));
458+ cr = CM_Get_Device_Interface_PropertyW (interface_path , & DEVPKEY_Device_InstanceId , & property_type , (PBYTE )device_id , & len , 0 );
459+ }
460+
461+ if (cr != CR_SUCCESS )
462+ goto close ;
463+
464+ /* Open devnode from device id */
465+ cr = CM_Locate_DevNodeW (& dev_node , (DEVINSTID_W )device_id , CM_LOCATE_DEVNODE_NORMAL );
466+ if (cr != CR_SUCCESS )
467+ goto close ;
468+
469+ /* Get devnode parent */
470+ cr = CM_Get_Parent (& dev_node , dev_node , 0 );
471+ if (cr != CR_SUCCESS )
472+ goto close ;
473+
474+ /* Get the device id from parent devnode */
475+ len = 0 ;
476+ cr = CM_Get_DevNode_PropertyW (dev_node , & DEVPKEY_Device_InstanceId , & property_type , NULL , & len , 0 );
477+ if (cr == CR_BUFFER_SMALL || property_type == DEVPROP_TYPE_STRING ) {
478+ free (device_id );
479+ device_id = (wchar_t * )calloc (len , sizeof (BYTE ));
480+ cr = CM_Get_DevNode_PropertyW (dev_node , & DEVPKEY_Device_InstanceId , & property_type , (PBYTE )device_id , & len , 0 );
481+ }
482+ if (cr != CR_SUCCESS )
483+ goto close ;
484+
485+ /* Normalize the device id */
486+ for (wchar_t * p = device_id ; * p ; ++ p ) * p = towupper (* p );
487+
488+ /* Now we can parse parent's device ID to find out the device bus type */
489+
490+ /* USB device ids always have a special prefix
491+ https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-support
492+ https://docs.microsoft.com/windows-hardware/drivers/install/standard-usb-identifiers */
493+ if (wcsstr (device_id , L"USB\\" ) != 0 ) {
494+ dev -> bus_type = HID_BUS_USB ;
495+ goto close ;
496+ }
497+
498+ /* Bluetooth devices ids have a special prefix
499+ https://docs.microsoft.com/windows-hardware/drivers/bluetooth/installing-a-bluetooth-device */
500+ if (wcsstr (device_id , L"BTHENUM\\" ) != 0 ) {
501+ dev -> bus_type = HID_BUS_BLUETOOTH ;
502+ goto close ;
503+ }
504+
505+ /* Bluetooth LE HID device */
506+ if (wcsstr (device_id , L"BTHLEDEVICE\\" ) != 0 ) {
507+ dev -> bus_type = HID_BUS_BLUETOOTH ;
508+ goto close ;
509+ }
510+
511+ /* I2C HID devices have a special ACPI ID
512+ https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-support-and-power-management */
513+ if (wcsstr (device_id , L"ACPI\\PNP0C50" ) != 0 ) {
514+ dev -> bus_type = HID_BUS_I2C ;
515+ goto close ;
516+ }
517+
518+ /* SPI HID devices have a special ACPI ID
519+ https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-for-spi */
520+ if (wcsstr (device_id , L"ACPI\\PNP0C51" ) != 0 ) {
521+ dev -> bus_type = HID_BUS_SPI ;
522+ goto close ;
523+ }
524+
525+ close :
526+ free (device_id );
527+ free (interface_path );
528+ }
529+
407530static struct hid_device_info * hid_get_device_info (const char * path , HANDLE handle )
408531{
409532 struct hid_device_info * dev = NULL ; /* return object */
@@ -491,6 +614,8 @@ static struct hid_device_info *hid_get_device_info(const char *path, HANDLE hand
491614 }
492615 }
493616
617+ hid_internal_get_info (dev );
618+
494619 return dev ;
495620}
496621
0 commit comments