8

我正在为 Mac 编写一个 Foundation 工具,并尝试检测 Apple 设备何时通过 USB 连接和断开连接。我在这篇文章USBPrivateDataSample中找到了一些帮助——但它似乎只有在我同时提供供应商 ID 和产品 ID 时才有效。我想消除产品 ID 并找到检测 Apple 设备上的所有 USB 事件(供应商 ID 1452)。这里有什么帮助吗?

这是我的代码,似乎没有检测到任何设备:

#include <CoreFoundation/CoreFoundation.h>

#include <IOKit/IOKitLib.h>
#include <IOKit/IOMessage.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/usb/IOUSBLib.h>

#define kMyVendorID 1452

int list_devices(void);

int list_devices(void){
    CFMutableDictionaryRef matchingDict;
    io_iterator_t iter;
    kern_return_t kr;
    io_service_t device;
    CFNumberRef numberRef;
    long usbVendor = kMyVendorID;

    /* set up a matching dictionary for the class */
    matchingDict = IOServiceMatching(kIOUSBDeviceClassName);    // Interested in instances of class
    // IOUSBDevice and its subclasses
    if (matchingDict == NULL) {
        fprintf(stderr, "IOServiceMatching returned NULL.\n");
        return -1;
    }

    // We are interested in all USB devices (as opposed to USB interfaces).  The Common Class Specification
    // tells us that we need to specify the idVendor, idProduct, and bcdDevice fields, or, if we're not interested
    // in particular bcdDevices, just the idVendor and idProduct.  Note that if we were trying to match an 
    // IOUSBInterface, we would need to set more values in the matching dictionary (e.g. idVendor, idProduct, 
    // bInterfaceNumber and bConfigurationValue.

    // Create a CFNumber for the idVendor and set the value in the dictionary
    numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &usbVendor);
    CFDictionarySetValue(matchingDict, 
                         CFSTR(kUSBVendorID), 
                         numberRef);
    CFRelease(numberRef);
    numberRef = NULL;    


    /* Now we have a dictionary, get an iterator.*/
    kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter);
    if (kr != KERN_SUCCESS)
        return -1;

    /* iterate */
    while ((device = IOIteratorNext(iter)))
    {
        io_name_t       deviceName;
        CFStringRef     deviceNameAsCFString;   

        /* do something with device, eg. check properties */
        /* ... */
        /* And free the reference taken before continuing to the next item */

        // Get the USB device's name.
        kr = IORegistryEntryGetName(device, deviceName);
        if (KERN_SUCCESS != kr) {
            deviceName[0] = '\0';
        }

        deviceNameAsCFString = CFStringCreateWithCString(kCFAllocatorDefault, deviceName, 
                                                         kCFStringEncodingASCII);

        // Dump our data to stderr just to see what it looks like.
        fprintf(stderr, "deviceName: ");
        CFShow(deviceNameAsCFString);

        IOObjectRelease(device);
    }

    /* Done, release the iterator */
    IOObjectRelease(iter);

    return 1;
}

int main(int argc, char* argv[])
{
    while(1){
        list_devices();
        sleep(1);
    }
    return 0;
}

注意:如果我将产品 ID 添加到 matchingDict 并插入这样的设备,它会发现设备没有问题(不更改供应商 ID)。但我无法单独使用供应商 ID 找到它。

4

2 回答 2

4

要获取属于特定供应商的所有产品列表,您可以在产品 ID 字段中使用通配符。示例匹配条件如下:

            long vid = 1452; //Apple vendor ID
        CFNumberRef refVendorId = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &vid);
        CFDictionarySetValue (matchingDict, CFSTR ("idVendor"), refVendorId);
        CFRelease(refVendorId);
        //all product by same vendor
        CFDictionarySetValue (matchingDict, CFSTR ("idProduct"), CFSTR("*"));
于 2013-05-09T06:42:46.577 回答
3

创建仅包含 VID 条目的字典过滤器应匹配该供应商的所有 PID。我建议注册设备插入回调,而不是在您自己的代码中轮询。让操作系统处理检测并异步通知您的应用程序。

这段代码对我有用:

#import "IOKit/hid/IOHIDManager.h"
#include <IOKit/usb/IOUSBLib.h>

@implementation MyApp

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {

    IOHIDManagerRef HIDManager = IOHIDManagerCreate(kCFAllocatorDefault,
                                                    kIOHIDOptionsTypeNone);
    CFMutableDictionaryRef matchDict = CFDictionaryCreateMutable(
                                                    kCFAllocatorDefault,
                                                    2,
                                                    &kCFTypeDictionaryKeyCallBacks,
                                                    &kCFTypeDictionaryValueCallBacks);
    int vid = 0x1234; // ToDo: Place your VID here
    CFNumberRef vid_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &vid);
    CFDictionarySetValue(matchDict, CFSTR(kUSBVendorID), vid_num);
    CFRelease(vid_num);

    IOHIDManagerSetDeviceMatching(HIDManager, matchDict);
    // Here we use the same callback for insertion & removal.
    // Use separate handlers if desired.
    IOHIDManagerRegisterDeviceMatchingCallback(HIDManager, Handle_UsbDetectionCallback, (__bridge void*)self);
    IOHIDManagerRegisterDeviceRemovalCallback(HIDManager, Handle_UsbDetectionCallback, (__bridge void*)self);
    IOHIDManagerScheduleWithRunLoop(HIDManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
    IOHIDManagerOpen(HIDManager, kIOHIDOptionsTypeNone);
}

// New USB device specified in the matching dictionary has been added (callback function)
static void Handle_UsbDetectionCallback(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef) {
    //ToDo: Code for dealing with the USB device
}

@end
于 2014-07-18T19:46:02.867 回答