@@ -140,6 +140,31 @@ static struct hid_api_version api_version = {
140140
141141 static HMODULE lib_handle = NULL ;
142142 static BOOLEAN initialized = FALSE;
143+
144+ typedef DWORD RETURN_TYPE ;
145+ typedef RETURN_TYPE CONFIGRET ;
146+ typedef DWORD DEVNODE , DEVINST ;
147+ typedef DEVNODE * PDEVNODE , * PDEVINST ;
148+ typedef WCHAR * DEVNODEID_W , * DEVINSTID_W ;
149+
150+ #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 ;
166+
167+ static HMODULE cfgmgr32_lib_handle = NULL ;
143168#endif /* HIDAPI_USE_DDK */
144169
145170struct hid_device_ {
@@ -253,6 +278,23 @@ static int lookup_functions()
253278 else
254279 return -1 ;
255280
281+ cfgmgr32_lib_handle = LoadLibraryA ("cfgmgr32.dll" );
282+ if (cfgmgr32_lib_handle ) {
283+ #if defined(__GNUC__ )
284+ # pragma GCC diagnostic push
285+ # pragma GCC diagnostic ignored "-Wcast-function-type"
286+ #endif
287+ #define RESOLVE (x ) x = (x##_)GetProcAddress(cfgmgr32_lib_handle, #x); if (!x) return -1;
288+ RESOLVE (CM_Locate_DevNodeW );
289+ RESOLVE (CM_Get_Parent );
290+ RESOLVE (CM_Get_DevNode_PropertyW );
291+ RESOLVE (CM_Get_Device_Interface_PropertyW );
292+ #undef RESOLVE
293+ #if defined(__GNUC__ )
294+ # pragma GCC diagnostic pop
295+ #endif
296+ }
297+
256298 return 0 ;
257299}
258300#endif
@@ -304,11 +346,114 @@ int HID_API_EXPORT hid_exit(void)
304346 if (lib_handle )
305347 FreeLibrary (lib_handle );
306348 lib_handle = NULL ;
349+ if (cfgmgr32_lib_handle )
350+ FreeLibrary (cfgmgr32_lib_handle );
351+ cfgmgr32_lib_handle = NULL ;
307352 initialized = FALSE;
308353#endif
309354 return 0 ;
310355}
311356
357+ static void hid_internal_get_info (struct hid_device_info * dev )
358+ {
359+ dev -> bus_type = HID_BUS_UNKNOWN ;
360+
361+ wchar_t * device_id , * interface_path ;
362+ ULONG len ;
363+ CONFIGRET cr ;
364+ DEVPROPTYPE property_type ;
365+ DEVINST dev_node ;
366+
367+ static DEVPROPKEY DEVPKEY_Device_InstanceId = { { 0x78c34fc8 , 0x104a , 0x4aca , 0x9e , 0xa4 , 0x52 , 0x4d , 0x52 , 0x99 , 0x6e , 0x57 }, 256 }; // DEVPROP_TYPE_STRING
368+
369+ if (!CM_Get_Device_Interface_PropertyW ||
370+ !CM_Locate_DevNodeW ||
371+ !CM_Get_Parent ||
372+ !CM_Get_DevNode_PropertyW )
373+ goto close ;
374+
375+ len = (ULONG )strlen (dev -> path );
376+ interface_path = (wchar_t * )calloc (len + 1 , sizeof (wchar_t ));
377+
378+ if (mbstowcs (interface_path , dev -> path , len ) == (size_t )-1 )
379+ goto close ;
380+
381+ /* Get the device id from interface path */
382+ len = 0 ;
383+ cr = CM_Get_Device_Interface_PropertyW (interface_path , & DEVPKEY_Device_InstanceId , & property_type , NULL , & len , 0 );
384+ if (cr == CR_BUFFER_SMALL && property_type == DEVPROP_TYPE_STRING ) {
385+ device_id = (wchar_t * )calloc (len , sizeof (BYTE ));
386+ cr = CM_Get_Device_Interface_PropertyW (interface_path , & DEVPKEY_Device_InstanceId , & property_type , (PBYTE )device_id , & len , 0 );
387+ }
388+ if (cr != CR_SUCCESS )
389+ goto close ;
390+
391+ /* Open devnode from device id */
392+ cr = CM_Locate_DevNodeW (& dev_node , (DEVINSTID_W )device_id , CM_LOCATE_DEVNODE_NORMAL );
393+ if (cr != CR_SUCCESS )
394+ goto close ;
395+
396+ /* Get devnode parent */
397+ cr = CM_Get_Parent (& dev_node , dev_node , 0 );
398+ if (cr != CR_SUCCESS )
399+ goto close ;
400+
401+ /* Get the device id from parent devnode */
402+ len = 0 ;
403+ cr = CM_Get_DevNode_PropertyW (dev_node , & DEVPKEY_Device_InstanceId , & property_type , NULL , & len , 0 );
404+ if (cr == CR_BUFFER_SMALL && property_type == DEVPROP_TYPE_STRING ) {
405+ free (device_id );
406+ device_id = (wchar_t * )calloc (len , sizeof (BYTE ));
407+ cr = CM_Get_DevNode_PropertyW (dev_node , & DEVPKEY_Device_InstanceId , & property_type , (PBYTE )device_id , & len , 0 );
408+ }
409+ if (cr != CR_SUCCESS )
410+ goto close ;
411+
412+ /* Normalize the device id */
413+ for (wchar_t * p = device_id ; * p ; ++ p ) * p = towupper (* p );
414+
415+ /* Now we can parse parent's device ID to find out the device bus type */
416+
417+ /* USB device ids always have a special prefix
418+ https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-support
419+ https://docs.microsoft.com/windows-hardware/drivers/install/standard-usb-identifiers */
420+ if (wcsstr (device_id , L"USB\\" ) != 0 ) {
421+ dev -> bus_type = HID_BUS_USB ;
422+ goto close ;
423+ }
424+
425+ /* Bluetooth devices ids have a special prefix
426+ https://docs.microsoft.com/windows-hardware/drivers/bluetooth/installing-a-bluetooth-device */
427+ if (wcsstr (device_id , L"BTHENUM\\" ) != 0 ) {
428+ dev -> bus_type = HID_BUS_BLUETOOTH ;
429+ goto close ;
430+ }
431+
432+ /* Bluetooth LE device */
433+ if (wcsstr (device_id , L"BTHLEDEVICE\\" ) != 0 ) {
434+ dev -> bus_type = HID_BUS_BLUETOOTH ;
435+ goto close ;
436+ }
437+
438+ /* I2C HID devices have a special ACPI ID
439+ https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-support-and-power-management */
440+ if (wcsstr (device_id , L"ACPI\\PNP0C50" ) != 0 ) {
441+ dev -> bus_type = HID_BUS_I2C ;
442+ goto close ;
443+ }
444+
445+ /* SPI HID devices have a special ACPI ID
446+ https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-for-spi */
447+ if (wcsstr (device_id , L"ACPI\\PNP0C51" ) != 0 ) {
448+ dev -> bus_type = HID_BUS_SPI ;
449+ goto close ;
450+ }
451+
452+ close :
453+ free (device_id );
454+ free (interface_path );
455+ }
456+
312457static struct hid_device_info * hid_get_device_info (const char * path , HANDLE handle )
313458{
314459 struct hid_device_info * dev = NULL ; /* return object */
@@ -396,6 +541,8 @@ static struct hid_device_info *hid_get_device_info(const char *path, HANDLE hand
396541 }
397542 }
398543
544+ hid_internal_get_info (dev );
545+
399546 return dev ;
400547}
401548
0 commit comments