使用中断输入端点使用IOKit获取回调

Ren*_*oly 5 usb cocoa driver iokit

我正在努力掌握IOKit,我觉得我很接近,但还没有.请原谅我的困惑.

我设法编写了检测我的USB设备的代码(USB电缆末端的一个简单按钮,它有一个Windows驱动程序,但没有Mac驱动程序).

我按下按钮时试图获得某种回调.

当设备连接到USB或移除时,我设法收到回叫.现在,我试图找出按下按钮时如何获得通知,但我无法弄明白.文档对我来说非常混乱,因为IOKit似乎可以同时使用c ++和c,具体取决于你如何访问它(内核扩展或用户空间驱动程序,或类似的东西.不确定我有正确的术语.

我已经尝试添加一些方法来获取回调,当任何中断值发生变化时,您将在代码中看到.但没有任何反应.

这是我当前的AppDelegate.m文件以及设备上的USB Probe信息.

Low Speed device @ 5 (0x14100000): .............................................   Composite device: "DL100B Dream Cheeky Generic Controller"
Port Information:   0x101a
Number Of Endpoints (includes EP0):   
Device Descriptor   
Configuration Descriptor (current config)   
    Length (and contents):   34
    Number of Interfaces:   1
    Configuration Value:   1
    Attributes:   0x80 (bus-powered)
    MaxPower:   500 mA
    Interface #0 - HID   
        Alternate Setting   0
        Number of Endpoints   1
        Interface Class:   3   (HID)
        Interface Subclass;   0
        Interface Protocol:   0
        HID Descriptor   
        Endpoint 0x81 - Interrupt Input   
            Address:   0x81  (IN)
            Attributes:   0x03  (Interrupt)
            Max Packet Size:   8
            Polling Interval:   10 ms
Run Code Online (Sandbox Code Playgroud)

App Delegate.m文件:

    //
//  USBHIDAppDelegate.m
//  USBHID
//
//  Created by Michael Dolinar on 12-05-02.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#import "USBHIDAppDelegate.h"      
#import "IOKit/hid/IOHIDManager.h" 
#include <IOKit/IOKitLib.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/usb/IOUSBLib.h>
#include <IOKit/usb/USBSpec.h>

@implementation USBHIDAppDelegate

@synthesize window = _window;

// New USB device specified in the matching dictionary has been added (callback function)
static void Handle_DeviceMatchingCallback(void *inContext,
                                          IOReturn inResult,
                                          void *inSender,
                                          IOHIDDeviceRef inIOHIDDeviceRef){

    // Retrieve the device name & serial number
    NSString *devName = [NSString stringWithUTF8String:
                         CFStringGetCStringPtr(
                                               IOHIDDeviceGetProperty(inIOHIDDeviceRef,
                                                                      CFSTR("Product")),
                                               kCFStringEncodingMacRoman)];

   UInt32 serialString = CFStringGetCStringPtr(
                          IOHIDDeviceGetProperty(inIOHIDDeviceRef,
                                                 CFSTR("SerialNumber")),
                          kCFStringEncodingMacRoman);
    NSString *devSerialNumber;
    if (serialString == 0) {
        devSerialNumber = @"No Serial Number";

    } else {
        devSerialNumber = [NSString stringWithUTF8String:serialString];

    }
    // Log the device reference, Name, Serial Number & device count
    NSLog(@"\nDevice added: %p\nModel: %@\nSerial Number:%@\nDevice count: %ld",
          inIOHIDDeviceRef,
          devName,
          devSerialNumber,
          USBDeviceCount(inSender));

//Open the device (Was missing)
IOReturn err = IOHIDDeviceOpen(inIOHIDDeviceRef, 0);
Run Code Online (Sandbox Code Playgroud)

//应该在这里检查错误......

IOHIDDeviceRegisterInputValueCallback(inIOHIDDeviceRef, Handle_IOHIDDeviceInputValueCallback, NULL);
Run Code Online (Sandbox Code Playgroud)

//还必须在这里再次注册RunLoop ...还缺少IOHIDDeviceScheduleWithRunLoop(inIOHIDDeviceRef,CFRunLoopGetCurrent(),kCFRunLoopCommonModes);

}

static void Handle_IOHIDDeviceInputValueCallback(void *inContext,
                                                 IOReturn inResult,
                                                  void *inSender,
                                                 IOHIDValueRef inIOHIDValueRef
                                                 )
{
    NSLog(@"Value changed");
}


// USB device specified in the matching dictionary has been removed (callback function)
static void Handle_DeviceRemovalCallback(void *inContext,
                                         IOReturn inResult,
                                         void *inSender,
                                         IOHIDDeviceRef inIOHIDDeviceRef){

    // Log the device ID & device count
    NSLog(@"\nDevice removed: %p\nDevice count: %ld",
          (void *)inIOHIDDeviceRef,
          USBDeviceCount(inSender));
     IOHIDDeviceRegisterInputValueCallback(inIOHIDDeviceRef, NULL, NULL); //Remove callback

}





// Counts the number of devices in the device set (incudes all USB devices that match our dictionary)
static long USBDeviceCount(IOHIDManagerRef HIDManager){

    // The device set includes all USB devices that match our matching dictionary. Fetch it.
    CFSetRef devSet = IOHIDManagerCopyDevices(HIDManager);

    // The devSet will be NULL if there are 0 devices, so only try to count the devices if devSet exists
    if(devSet) return CFSetGetCount(devSet);

    // There were no matching devices (devSet was NULL), so return a count of 0
    return 0;
}


- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // Insert code here to initialize your application
    SInt32 idVendor = 0x1D34;//0x062A;//0x1d34; //0x1AAD; //// set vendor id
    SInt32 idProduct = 0x000D;//0x0000;//0x000d; //0x000F; //// set product id

    // Create an HID Manager
    IOHIDManagerRef HIDManager = IOHIDManagerCreate(kCFAllocatorDefault, 
                                                    kIOHIDOptionsTypeNone);

    // Create a Matching Dictionary
    CFMutableDictionaryRef matchDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 
                                                                 2, 
                                                                 &kCFTypeDictionaryKeyCallBacks, 
                                                                 &kCFTypeDictionaryValueCallBacks); 

    // Specify a device manufacturer in the Matching Dictionary

    CFDictionarySetValue(matchDict,
                         CFSTR(kIOHIDVendorIDKey),
                         CFNumberCreate(kCFAllocatorDefault,
                                        kCFNumberSInt32Type, &idVendor));
    CFDictionarySetValue(matchDict,
                         CFSTR(kIOHIDProductKey),
                         CFNumberCreate(kCFAllocatorDefault,
                                        kCFNumberSInt32Type, &idProduct));


    // Register the Matching Dictionary to the HID Manager
    IOHIDManagerSetDeviceMatching(HIDManager, matchDict); 

    // Register a callback for USB device detection with the HID Manager
    IOHIDManagerRegisterDeviceMatchingCallback(HIDManager, &Handle_DeviceMatchingCallback, NULL);
    // Register a callback fro USB device removal with the HID Manager
    IOHIDManagerRegisterDeviceRemovalCallback(HIDManager, &Handle_DeviceRemovalCallback, NULL);

    // Register the HID Manager on our app’s run loop
    IOHIDManagerScheduleWithRunLoop(HIDManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode);

    // Open the HID Manager
    IOReturn IOReturn = IOHIDManagerOpen(HIDManager, kIOHIDOptionsTypeNone);
    if(IOReturn) NSLog(@"IOHIDManagerOpen failed.");  //  Couldn't open the HID manager! TODO: proper error handling
}
@end
Run Code Online (Sandbox Code Playgroud)

我甚至不确定设备是否正在发送任何东西......我尝试在7级中使用USB记录器进行记录,但只按下按钮似乎没有显示任何内容......我怎样才能确保它实际上正在工作?

更新:能够使用这个用于了解BigRedButton的Ruby Open Source项目来检测按钮按下.所以我知道它确实有效.我还重新编写了代码,仅在实际检测到设备时注册值更改,并在删除设备时将其删除.此时仍然没有.

更新2:让这个工作!两个问题......我没有打开设备进行读取,也没有在Current RunLoop上注册设备本身,这也是必需的.来自WWDC 2011的Userland设备访问的WWDC视频非常有用.我还必须说,我使用的BigRedBUtton可能不是一个标准设备,并且从未像计划那样工作,但我想要使用的实际设备就像一个魅力并且给我输入!因为WWDC视频,现在一切都很好!

Ren*_*oly 5

最后,上面的代码现在可以工作了,因为我已经打开了设备并在当前运行循环上安排了设备。此外,更改设备使我可以使用其他设备,这似乎提供了更可预测的更改其值的体验。我建议任何对此进行研究的人观看 WWDC 2011 的 Userland Device Access 视频,以深入了解其工作原理(视频播放约 30 分钟)

更新:设备反应不同的原因有点复杂。首先,每个 USB HID 设备都可以有多个“配置”,并且可能不会启用默认配置。你必须明确地这样做。然后,第二部分是关于理解从设备发送的值。这是通过理解“HID 设备报告描述符”来完成的,它详细描述了返回的每种值(称为报告)及其位和字节的排列方式。

在 OS X 上,一个很好的读物是适用于 Mac OS X 版本 10.5技术说明的新 HID 管理器 API。虽然它是 10.5 的最新版本,但它是最新版本,包含所有适当的调用,并且可以更好地理解这一切是如何工作的。

此外,要了解描述符,本教程很有帮助。