2012-06-01 94 views
7

我正在爲Mac編寫一個基礎工具,並嘗試檢測Apple設備何時通過USB連接和斷開連接。我在this post以及USBPrivateDataSample中找到了一些幫助 - 但是,如果我同時提供供應商ID和產品ID,它似乎才起作用。我想消除產品ID並查找Apple設備上的所有USB事件(供應商ID 1452)。這裏有幫助嗎?可可:通過供應商ID檢測USB設備

這裏是我的代碼,似乎並沒有檢測到任何設備:

#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。

+0

我不知道這樣做對USB設備的方式。對於PCI設備,IOKit允許您提供一個按位掩碼的供應商和產品ID,但這似乎不適用於USB。 – pmdj

回答

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("*")); 
+3

+1,我也想注意一下蘋果的[USB驅動匹配技巧](http://developer.apple.com/library/mac/#qa/qa1076/_index.html)頁面,其中包含匹配規則如何工作。這包括使用通配符和口罩的信息。 – Hasturkun

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