Skip to content

Commit b516e97

Browse files
committed
macOS: fallback to parent entry kUSBInterfaceNumber prop
In macOS 13.3 the kUSBInterfaceNumber is no longer one of the properties of the IOHIDDevice (even if its transport is USB). In case if kUSBInterfaceNumber property (for USB Interface number) is not available as an IOHIDDevice property - find the value for that property in one of the Parent IORegistry Entries.
1 parent 80a206a commit b516e97

File tree

1 file changed

+70
-7
lines changed

1 file changed

+70
-7
lines changed

mac/hid.c

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,22 @@ static bool try_get_int_property(IOHIDDeviceRef device, CFStringRef key, int32_t
329329
return result;
330330
}
331331

332+
static bool try_get_ioregistry_int_property(io_service_t service, CFStringRef property, int32_t *out_val)
333+
{
334+
bool result = false;
335+
CFTypeRef ref = IORegistryEntryCreateCFProperty(service, property, kCFAllocatorDefault, 0);
336+
337+
if (ref) {
338+
if (CFGetTypeID(ref) == CFNumberGetTypeID()) {
339+
result = CFNumberGetValue(ref, kCFNumberSInt32Type, out_val);
340+
}
341+
342+
CFRelease(ref);
343+
}
344+
345+
return result;
346+
}
347+
332348
static CFArrayRef get_usage_pairs(IOHIDDeviceRef device)
333349
{
334350
return get_array_property(device, CFSTR(kIOHIDDeviceUsagePairsKey));
@@ -481,6 +497,46 @@ static void process_pending_events(void) {
481497
} while(res != kCFRunLoopRunFinished && res != kCFRunLoopRunTimedOut);
482498
}
483499

500+
static int read_usb_interface_from_hid_service_parent(io_service_t hid_service)
501+
{
502+
int32_t result = -1;
503+
bool success = false;
504+
io_registry_entry_t current = IO_OBJECT_NULL;
505+
kern_return_t res;
506+
int parent_number = 0;
507+
508+
res = IORegistryEntryGetParentEntry(hid_service, kIOServicePlane, &current);
509+
while (KERN_SUCCESS == res
510+
/* Only search up to 3 parent entries.
511+
* With the default driver - the parent-of-interest supposed to be the first one,
512+
* but lets assume some custom drivers or so, with deeper tree. */
513+
&& parent_number < 3) {
514+
io_registry_entry_t parent = IO_OBJECT_NULL;
515+
int32_t interface_number = -1;
516+
parent_number++;
517+
518+
success = try_get_ioregistry_int_property(current, CFSTR(kUSBInterfaceNumber), &interface_number);
519+
if (success) {
520+
result = interface_number;
521+
break;
522+
}
523+
524+
res = IORegistryEntryGetParentEntry(current, kIOServicePlane, &parent);
525+
if (parent) {
526+
IOObjectRelease(current);
527+
current = parent;
528+
}
529+
530+
}
531+
532+
if (current) {
533+
IOObjectRelease(current);
534+
current = IO_OBJECT_NULL;
535+
}
536+
537+
return result;
538+
}
539+
484540
static struct hid_device_info *create_device_info_with_usage(IOHIDDeviceRef dev, int32_t usage_page, int32_t usage)
485541
{
486542
unsigned short dev_vid;
@@ -490,7 +546,7 @@ static struct hid_device_info *create_device_info_with_usage(IOHIDDeviceRef dev,
490546
CFTypeRef transport_prop;
491547

492548
struct hid_device_info *cur_dev;
493-
io_object_t iokit_dev;
549+
io_service_t hid_service;
494550
kern_return_t res;
495551
uint64_t entry_id = 0;
496552

@@ -514,9 +570,9 @@ static struct hid_device_info *create_device_info_with_usage(IOHIDDeviceRef dev,
514570

515571
/* Fill in the path (as a unique ID of the service entry) */
516572
cur_dev->path = NULL;
517-
iokit_dev = IOHIDDeviceGetService(dev);
518-
if (iokit_dev != MACH_PORT_NULL) {
519-
res = IORegistryEntryGetRegistryEntryID(iokit_dev, &entry_id);
573+
hid_service = IOHIDDeviceGetService(dev);
574+
if (hid_service != MACH_PORT_NULL) {
575+
res = IORegistryEntryGetRegistryEntryID(hid_service, &entry_id);
520576
}
521577
else {
522578
res = KERN_INVALID_ARGUMENT;
@@ -567,11 +623,18 @@ static struct hid_device_info *create_device_info_with_usage(IOHIDDeviceRef dev,
567623
if (CFStringCompare((CFStringRef)transport_prop, CFSTR(kIOHIDTransportUSBValue), 0) == kCFCompareEqualTo) {
568624
int32_t interface_number = -1;
569625
cur_dev->bus_type = HID_API_BUS_USB;
626+
627+
/* A IOHIDDeviceRef used to have this simple property,
628+
* until macOS 13.3 - we will try to use it. */
570629
if (try_get_int_property(dev, CFSTR(kUSBInterfaceNumber), &interface_number)) {
571630
cur_dev->interface_number = interface_number;
572-
}
573-
else {
574-
// TODO: use a different approach - this is a USB device after all
631+
} else {
632+
/* Otherwise fallback to io_service_t property.
633+
* (of one of the parent services). */
634+
cur_dev->interface_number = read_usb_interface_from_hid_service_parent(hid_service);
635+
636+
/* If the above doesn't work -
637+
* no (known) fallback exists at this point. */
575638
}
576639

577640
/* Match "Bluetooth", "BluetoothLowEnergy" and "Bluetooth Low Energy" strings */

0 commit comments

Comments
 (0)