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_tto 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 toIOServiceAddMatchingNotificationwill 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, whenselfis 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
kUSBProductIDwith a singleNSNumber/CFNumber, provide akUSBProductIdsArrayName(akakUSBHostMatchingPropertyProductIDArray) and specify an array of numbers. (NSArray/CFArraycontaining aNSNumber/CFNumberfor every product ID.)
Alternatively, if your product IDs match some hex pattern, you can also usekUSBProductIDMaskin conjunction withkUSBProductID: in this case, candidate devices' product IDs will be bitwise masked (&) with the number provided forkUSBProductIDMaskbefore 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 thekUSBProductIdsArrayNamevalue 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);
}
