首页 文章

Cocoa:按供应商ID检测USB设备

提问于
浏览
7

我正在为Mac编写一个Foundation工具,并尝试检测Apple设备何时通过USB连接和断开连接 . 我在this post中找到了一些帮助以及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找到它 .

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("*"));
    
  • 1

    创建仅包含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
    

相关问题