@@ -381,7 +381,7 @@ static struct hid_device_info *create_device_info_with_usage(IOHIDDeviceRef dev,
381381 struct hid_device_info * cur_dev ;
382382 io_object_t iokit_dev ;
383383 kern_return_t res ;
384- io_string_t path ;
384+ uint64_t entry_id ;
385385
386386 if (dev == NULL ) {
387387 return NULL ;
@@ -401,13 +401,30 @@ static struct hid_device_info *create_device_info_with_usage(IOHIDDeviceRef dev,
401401 /* Fill out the record */
402402 cur_dev -> next = NULL ;
403403
404- /* Fill in the path (IOService plane) */
404+ /* Fill in the path (as a unique ID of the service entry) */
405+ cur_dev -> path = NULL ;
405406 iokit_dev = IOHIDDeviceGetService (dev );
406- res = IORegistryEntryGetPath (iokit_dev , kIOServicePlane , path );
407- if (res == KERN_SUCCESS )
408- cur_dev -> path = strdup (path );
409- else
407+ if (iokit_dev != MACH_PORT_NULL ) {
408+ res = IORegistryEntryGetRegistryEntryID (iokit_dev , & entry_id );
409+ }
410+ else {
411+ res = KERN_INVALID_ARGUMENT ;
412+ }
413+
414+ if (res == KERN_SUCCESS ) {
415+ /* max value of entry_id(uint64_t) is 18446744073709551615 which is 20 characters long,
416+ so for (max) "path" string 'DevSrvsID:18446744073709551615' we would need
417+ 9+1+20+1=31 bytes byffer, but allocate 32 for simple alignment */
418+ cur_dev -> path = calloc (1 , 32 );
419+ if (cur_dev -> path != NULL ) {
420+ sprintf (cur_dev -> path , "DevSrvsID:%llu" , entry_id );
421+ }
422+ }
423+
424+ if (cur_dev -> path == NULL ) {
425+ /* for whatever reason, trying to keep it a non-NULL string */
410426 cur_dev -> path = strdup ("" );
427+ }
411428
412429 /* Serial Number */
413430 get_serial_number (dev , buf , BUF_LEN );
@@ -759,11 +776,33 @@ static void *read_thread(void *param)
759776 return NULL ;
760777}
761778
762- /* hid_open_path()
763- *
764- * path must be a valid path to an IOHIDDevice in the IOService plane
765- * Example: "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/EHC1@1D,7/AppleUSBEHCI/PLAYSTATION(R)3 Controller@fd120000/IOUSBInterface@0/IOUSBHIDDriver"
766- */
779+ /* \p path must be one of:
780+ - in format 'DevSrvsID:<RegistryEntryID>' (as returned by hid_enumerate);
781+ - a valid path to an IOHIDDevice in the IOService plane (as returned by IORegistryEntryGetPath,
782+ e.g.: "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/EHC1@1D,7/AppleUSBEHCI/PLAYSTATION(R)3 Controller@fd120000/IOUSBInterface@0/IOUSBHIDDriver");
783+ Second format is for compatibility with paths accepted by older versions of HIDAPI.
784+ */
785+ static io_registry_entry_t hid_open_service_registry_from_path (const char * path )
786+ {
787+ if (path == NULL )
788+ return MACH_PORT_NULL ;
789+
790+ /* Get the IORegistry entry for the given path */
791+ if (strncmp ("DevSrvsID:" , path , 10 ) == 0 ) {
792+ char * endptr ;
793+ uint64_t entry_id = strtoull (path + 10 , & endptr , 10 );
794+ if (* endptr == '\0' ) {
795+ return IOServiceGetMatchingService (kIOMasterPortDefault , IORegistryEntryIDMatching (entry_id ));
796+ }
797+ }
798+ else {
799+ /* Fallback to older format of the path */
800+ return IORegistryEntryFromPath (kIOMasterPortDefault , path );
801+ }
802+
803+ return MACH_PORT_NULL ;
804+ }
805+
767806hid_device * HID_API_EXPORT hid_open_path (const char * path )
768807{
769808 hid_device * dev = NULL ;
@@ -777,7 +816,7 @@ hid_device * HID_API_EXPORT hid_open_path(const char *path)
777816 dev = new_hid_device ();
778817
779818 /* Get the IORegistry entry for the given path */
780- entry = IORegistryEntryFromPath ( kIOMasterPortDefault , path );
819+ entry = hid_open_service_registry_from_path ( path );
781820 if (entry == MACH_PORT_NULL ) {
782821 /* Path wasn't valid (maybe device was removed?) */
783822 goto return_error ;
0 commit comments