【问题标题】:Get callback using IOKit using an Interrupt Input Endpoint使用 IOKit 使用中断输入端点获取回调
【发布时间】:2014-01-03 05:16:28
【问题描述】:

我正在尝试掌握 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

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);

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

IOHIDDeviceRegisterInputValueCallback(inIOHIDDeviceRef, Handle_IOHIDDeviceInputValueCallback, NULL);

//这里还必须再次注册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

我什至不确定设备是否正在发送任何内容...我尝试在第 7 级使用 USB 记录器进行记录,但仅按下按钮似乎没有显示任何内容...我如何确保它是实际工作?

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

更新 2:让它工作!两个问题...我没有打开设备进行阅读,也没有在 Current RunLoop 上注册设备本身,这也是必需的。来自 WWDC 2011 的有关 Userland 设备访问的精彩 WWDC 视频提供了很大帮助。我还不得不说,我使用的 BigRedBUtton 可能不是一个标准设备,并且从未按计划工作,但我想使用的实际设备就像一个魅力,并且正在给我输入!所以现在一切都很好,感谢 WWDC 视频!

【问题讨论】:

  • 我实际上使用的代码块与 Michael Dolinars 教程中的代码块相同。您能否发布或发送您打开设备(不仅仅是 HID 管理器)然后将其添加到运行循环中的代码块?这就是我自己目前陷入的困境。
  • 实际上,我看到发生了什么,你的代码块被分解了,它的某些部分看起来像文本。

标签: cocoa usb driver iokit


【解决方案1】:

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

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

在 OS X 上,New HID Manager APIs for Mac OS X version 10.5 TechNote 是一个很好的阅读材料。虽然它可以追溯到 10.5,但它是最新版本,包含所有适当的调用,并且可以更好地理解这一切是如何工作的。

另外,要了解描述符,this tutorial 也很有帮助。

【讨论】:

    猜你喜欢
    • 2020-10-10
    • 1970-01-01
    • 2010-10-11
    • 1970-01-01
    • 2015-06-12
    • 1970-01-01
    • 2023-03-15
    • 2014-10-08
    相关资源
    最近更新 更多