need to use IOServiceAddMatchingNotification routine for supporing multiple product identifications. To show the concept, I got part of this code from a site and revised it.Kept it short.
// Set up matching dictionary.
NSMutableDictionary* matchingDictionary;
for (int n = 0; n < numberOfDevices; n )
{
matchingDictionary = (NSMutableDictionary*)IOServiceMatching(kIOUSBDeviceClassName);
[matchingDictionary setObject:[NSNumber numberWithLong:myVid[n]] forKey:[NSString stringWithUTF8String:kUSBVendorID]];
[matchingDictionary setObject:[NSNumber numberWithLong:myPid[n]] forKey:[NSString stringWithUTF8String:kUSBProductID]];
// Set up a notification callback for device addition on first match.
IOServiceAddMatchingNotification(g_notificationPort, kIOFirstMatchNotification, (CFMutableDictionaryRef)matchingDictionary, deviceAddedCallback, (void*)self, &g_iteratorAdded);
}
I am not sure if it really is correct?. I did not see complains from the xcode and it works.
CodePudding user response:
This requires a nuanced answer - there are three things to note here:
- In principle, yes, you need to create distinct matching notifications for each independent match dictionary.
- However, it looks like you're expecting only one
io_iterator_t
to be created and updated with each matching dictionary, as you only have a single variable to store it,g_iteratorAdded
. This is not the case. The code shown suffers from a resource leak. Each successful call toIOServiceAddMatchingNotification
will create a new iterator, so you will need to retain all of them in an array or so. And then, when you no longer need the notifications (at the latest, whenself
is dealloc'd, or you'll get callbacks on a freed object!), you need to release all of the iterators. - For matching multiple different USB product IDs but identical vendor IDs, you actually don't need to create multiple match dictionaries and notifications. Instead of
kUSBProductID
with a singleNSNumber
/CFNumber
, provide akUSBProductIdsArrayName
(akakUSBHostMatchingPropertyProductIDArray
) and specify an array of numbers. (NSArray
/CFArray
containing aNSNumber
/CFNumber
for every product ID.)
Alternatively, if your product IDs match some hex pattern, you can also usekUSBProductIDMask
in conjunction withkUSBProductID
: in this case, candidate devices' product IDs will be bitwise masked (&
) with the number provided forkUSBProductIDMask
before comparing to thekUSBProductID
.
If you need to match multiple vendor IDs, you will still need to create a matching notification for each vendor ID, and provide the list of product IDs in thekUSBProductIdsArrayName
value for each.
Update: Sample code for array PID match dictionaries
Some rough untested code for dealing with kUSBProductIdsArrayName
, assuming your VIDs/PIDs are laid out like this:
static const uint16_t myVid[] = { 0x1234, 0x5555 };
static const size_t numberOfVids = sizeof(myVid) / sizeof(myVid[0]);
static const uint16_t myPid[] = {
// for VID 0x1234
0x1, 0x2, 0x3, 0x1001, 0x1002,
// for VID 0x555
0x100, 0x101,
};
static const unsigned pidsForVid[] = { 5, 2 };
Setting up the matching dictionaries would then look something like this:
unsigned next_pid_index = 0;
for (int n = 0; n < numberOfVids; n )
{
NSMutableDictionary* matchingDictionary =
(__bridge_transfer NSMutableDictionary*)IOServiceMatching(kIOUSBDeviceClassName);
[matchingDictionary setObject:@(myVid[n]) forKey:@kUSBVendorID];
NSMutableArray* pid_array = [NSMutableArray arrayWithCapacity:pidsForVid[n]];
for (unsigned i = 0; i < pidsForVid[n]; i)
{
[pid_array addObject:@(myPid[next_pid_index])];
next_pid_index;
}
[matchingDictionary setObject:pid_array forKey:@kUSBProductIdsArrayName];
// Set up a notification callback for device addition on first match.
IOReturn result = IOServiceAddMatchingNotification(
g_notificationPort,
kIOFirstMatchNotification,
(__bridge_retained CFMutableDictionaryRef)matchingDictionary,
deviceAddedCallback,
(__bridge void*)self,
&g_iteratorAdded[n]);
assert(result == kIOReturnSuccess);
}