matching dictionary to find particular IOUSBInterface

Hello, I am trying to get value of InterfaceClass for particular USB Device. I modified matching dictionary and added the property locationID property.

    CFMutableDictionaryRef matchingDictionary = IOServiceMatching(kIOUSBInterfaceClassName);

    if (!matchingDictionary)
    {
        return -1;
    }


    int32_t locationID = 0xffff; 
    CFNumberRef cfLocationID = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &locationID);
    CFDictionaryAddValue(matchingDictionary, CFSTR(kUSBHostPropertyLocationID), cfLocationID);
    CFRelease(cfLocationID);

    io_service_t ioService = IOServiceGetMatchingService(kIOMasterPortDefault, matchingDictionary);

    if (!ioService)
    {
        return -1;
    }

    CFNumberRef cfInterfaceClass = (CFNumberRef)IORegistryEntrySearchCFProperty(ioService, kIOServicePlane, CFSTR(kUSBHostMatchingPropertyInterfaceClass), kCFAllocatorDefault, kNilOptions);
    ...

Unfortunately nothing is found and ioService is NULL. What can be wrong here?

Thank you in advance!

Answered by DTS Engineer in 801259022

Unfortunately nothing is found and ioService is NULL. What can be wrong here?

First, a few general things:

  • Several years ago we rewrote the entire USB stack, replacing the older "IOUSB*" classes with "IOUSBHost*" classes. So, the modern object would be "IOUSBHostInterface". The old classes are still present for compatibility reasons, but you should not be using them.

  • Related to that point, you'll want to use the IOUSBHost framework, not the older API. Note this this is a significant improvement, as the older API was not particularly fun to work with.

  • I've seen sandboxing issues with what exactly is accessible through IOKit, so I would disable sandboxing for the moment. You can reenable it and then resolve those issues once you've got something working, but the first step is to get matching working.

In any case, the specific issue here is that your match dictionary isn't set up correctly. Conceptually, the "top" level keys of the matching dictionary are always the "type" of match that particular key handles. You need an extra "level" of nesting for your property match dictionary. Here's what the correct dictionary would look like:

{
    IOPropertyMatch =     {
        locationID = 65535;
    };
    IOProviderClass = IOUSBHostInterface;
}

And here is the corresponding code for everything above:

void KE_PrintIOObject(io_service_t myObj)
{
    if(myObj != 0)
    {
        NSString* className = CFBridgingRelease(IOObjectCopyClass(myObj));
        NSLog(@"Class Name = %@", className);
        CFMutableDictionaryRef propDictionary = NULL;
        if(IORegistryEntryCreateCFProperties(myObj, &propDictionary, CFAllocatorGetDefault(), 0) == kIOReturnSuccess)
        {
            CFShow(propDictionary);
            CFRelease(propDictionary);
        }
        
    }
}

void KE_MatchUSBDevice(void)
{
    NSMutableDictionary* matchingDictionary = (__bridge NSMutableDictionary*) IOServiceMatching(kIOUSBHostInterfaceClassName);
#if 1
    NSNumber* locNum = [NSNumber numberWithInt: 0xffff];
    NSDictionary* matchProperty = @{ @kUSBHostPropertyLocationID: locNum};
    [matchingDictionary setObject:matchProperty forKey: @kIOPropertyMatchKey];
#endif
    if (matchingDictionary != NULL)
    {
        NSLog(@"matchDict: %@", matchingDictionary.debugDescription);
        io_iterator_t myIterator = 0;
        
        if(IOServiceGetMatchingServices(kIOMainPortDefault, (__bridge CFDictionaryRef)(matchingDictionary), &myIterator) == kIOReturnSuccess)
        {
            io_service_t myObj = 0;
            while((myObj = IOIteratorNext( myIterator)) != 0)
            {
                KV_PrintIOObject(myObj);
            }
            
        }
    }

}

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Accepted Answer

Unfortunately nothing is found and ioService is NULL. What can be wrong here?

First, a few general things:

  • Several years ago we rewrote the entire USB stack, replacing the older "IOUSB*" classes with "IOUSBHost*" classes. So, the modern object would be "IOUSBHostInterface". The old classes are still present for compatibility reasons, but you should not be using them.

  • Related to that point, you'll want to use the IOUSBHost framework, not the older API. Note this this is a significant improvement, as the older API was not particularly fun to work with.

  • I've seen sandboxing issues with what exactly is accessible through IOKit, so I would disable sandboxing for the moment. You can reenable it and then resolve those issues once you've got something working, but the first step is to get matching working.

In any case, the specific issue here is that your match dictionary isn't set up correctly. Conceptually, the "top" level keys of the matching dictionary are always the "type" of match that particular key handles. You need an extra "level" of nesting for your property match dictionary. Here's what the correct dictionary would look like:

{
    IOPropertyMatch =     {
        locationID = 65535;
    };
    IOProviderClass = IOUSBHostInterface;
}

And here is the corresponding code for everything above:

void KE_PrintIOObject(io_service_t myObj)
{
    if(myObj != 0)
    {
        NSString* className = CFBridgingRelease(IOObjectCopyClass(myObj));
        NSLog(@"Class Name = %@", className);
        CFMutableDictionaryRef propDictionary = NULL;
        if(IORegistryEntryCreateCFProperties(myObj, &propDictionary, CFAllocatorGetDefault(), 0) == kIOReturnSuccess)
        {
            CFShow(propDictionary);
            CFRelease(propDictionary);
        }
        
    }
}

void KE_MatchUSBDevice(void)
{
    NSMutableDictionary* matchingDictionary = (__bridge NSMutableDictionary*) IOServiceMatching(kIOUSBHostInterfaceClassName);
#if 1
    NSNumber* locNum = [NSNumber numberWithInt: 0xffff];
    NSDictionary* matchProperty = @{ @kUSBHostPropertyLocationID: locNum};
    [matchingDictionary setObject:matchProperty forKey: @kIOPropertyMatchKey];
#endif
    if (matchingDictionary != NULL)
    {
        NSLog(@"matchDict: %@", matchingDictionary.debugDescription);
        io_iterator_t myIterator = 0;
        
        if(IOServiceGetMatchingServices(kIOMainPortDefault, (__bridge CFDictionaryRef)(matchingDictionary), &myIterator) == kIOReturnSuccess)
        {
            io_service_t myObj = 0;
            while((myObj = IOIteratorNext( myIterator)) != 0)
            {
                KV_PrintIOObject(myObj);
            }
            
        }
    }

}

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Thank you a lot for your help, clear-cut explanation and example.

matching dictionary to find particular IOUSBInterface
 
 
Q