如果设备插入启动后,则IohidDevicereGisterInputValueCallback失败



我正在尝试使用iokit与游戏控制器进行通信,特别是我想通过IOHIDDeviceRegisterInputValueCallback通知价值更改。我的代码有效,除了自Mac被启动并且从未插入的情况下已插入设备。在这种情况下,IOHIDDeviceOpen仍然成功,但是价值回调从未被调用。而且,如果我尝试使用IOHIDDeviceGetValue获取值,它没有报告任何错误,但是我得到的整数值都是零,这是不正确的。

如果我拔下设备并将其插入,则程序开始获取值回调。

我可以做些什么来解决这个问题,还是应该责怪硬件?

也许有某种方法可以在软件上进行拔下插头。内核框架参考列出了听起来像这样做的函数 ReEnumerateDevice,但是如果从非内核代码可以使用,我将需要很多帮助。

static void ValueCallback(
    void *context, 
    IOReturn result, 
    void *sender, 
    IOHIDValueRef value )
{
    IOHIDElementRef theElement = IOHIDValueGetElement( value );
    uint32_t usagePage = IOHIDElementGetUsagePage( theElement );
    uint32_t usage = IOHIDElementGetUsage( theElement );
    IOHIDElementCookie cookie = IOHIDElementGetCookie( theElement );
    IOHIDElementType typeCode = IOHIDElementGetType( theElement );
    CFIndex intValue = IOHIDValueGetIntegerValue( value );
    double physValue = IOHIDValueGetScaledValue( value,
        kIOHIDValueScaleTypePhysical );
    double calibratedValue = IOHIDValueGetScaledValue( value,
        kIOHIDValueScaleTypeCalibrated );
    NSLog(@"Element %@ (0x%X, 0x%X, %p, type %d) changed to %d (%f, %f)",
        theElement, (int)usagePage, (int)usage, cookie, (int) typeCode,
        (int)intValue, physValue, calibratedValue );
}
static void DeviceMatchingCallback(
    void *context,
    IOReturn result, 
    void *sender, 
    IOHIDDeviceRef device )
{
    NSLog( @"Added device %@", device );
    IOHIDDeviceScheduleWithRunLoop( device, CFRunLoopGetMain(),
        kCFRunLoopDefaultMode );
    IOReturn err = IOHIDDeviceOpen( device, kIOHIDOptionsTypeNone );
    NSLog(@"IOHIDDeviceOpen result 0x%08X", err );
    IOHIDDeviceRegisterInputValueCallback( device, ValueCallback, context );
    // Let's see if I can get elements and values.
    CFArrayRef elementArray = IOHIDDeviceCopyMatchingElements( device,
        NULL, 0 );
    if ( elementArray != NULL )
    {
        NSArray* elArray = (NSArray*)elementArray;
        for (id oneEl in elArray)
        {
            IOHIDElementRef anElement = (IOHIDElementRef) oneEl;
            IOHIDElementType elType = IOHIDElementGetType( anElement );
            NSLog(@"Element type %d", (int)elType);
            if ( (elType == 1) || (elType == 2) || (elType == 3) )
            {
                IOHIDElementCookie theCookie =
                    IOHIDElementGetCookie( anElement );
                CFIndex val = -1;
                IOHIDValueRef valueRef = NULL;
                err = IOHIDDeviceGetValue( device, anElement, &valueRef );
                if (err == kIOReturnSuccess)
                {
                    val = IOHIDValueGetIntegerValue( valueRef );
                    NSLog(@"  cookie %p, value %ld", theCookie, val );
                }
                else
                {
                    NSLog(@"  cookie %p, error getting value 0x%08X",
                        theCookie, err );
                }
            }
        }
    }
}
static void DeviceRemovalCallback(
    void *context, 
    IOReturn result, 
    void *sender, 
    IOHIDDeviceRef device )
{
    NSLog( @"Removed device %@", device );
    IOHIDDeviceUnscheduleFromRunLoop( device, CFRunLoopGetMain(),
        kCFRunLoopDefaultMode );
}
@implementation AppDelegate
@synthesize window = _window;
- (void)dealloc
{
    if (_hidManager != NULL)
    {
        CFRelease( _hidManager );
    }
    [super dealloc];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    _hidManager = IOHIDManagerCreate( NULL, 0 );
    IOHIDManagerSetDeviceMatchingMultiple( _hidManager, (CFArrayRef) @[
        @{ @(kIOHIDDeviceUsagePageKey): @(kHIDPage_GenericDesktop),
            @(kIOHIDDeviceUsageKey): @(kHIDUsage_GD_Joystick)
        },
        @{ @(kIOHIDDeviceUsagePageKey): @(kHIDPage_GenericDesktop),
            @(kIOHIDDeviceUsageKey): @(kHIDUsage_GD_GamePad)
        }
        ] );
    IOHIDManagerRegisterDeviceMatchingCallback( _hidManager,
        DeviceMatchingCallback, self );
    IOHIDManagerRegisterDeviceRemovalCallback( _hidManager,
        DeviceRemovalCallback, self );
    IOHIDManagerScheduleWithRunLoop( _hidManager, CFRunLoopGetMain(),
        kCFRunLoopDefaultMode );
}
@end

启动过程中的操作系统看起来会自动卸载设备(因为未使用)


当您断开(并再次将其插入)设备时,操作系统将加载设备...


从文档中,根据驱动程序开发中使用的命令行工具,您可以使用:

kextload

加载内核扩展名(例如设备驱动程序)或生成一个 远程调试的静态链接符号文件。

kextunload

卸载内核扩展名(如果可能的话)。


可能对您有帮助的另一件事:

驱动程序加载

所有驱动程序都探测了该设备后,将附加了最高探头分数的设备,并且必须调用所有驱动程序的起始功能。启动功能将设备硬件初始化并为操作准备。如果驾驶员成功启动,它将返回真实;剩下的候选驾驶员实例被丢弃,开始成功运行的驾驶员。如果驱动程序无法初始化硬件,则必须将硬件留在启动时所在状态下并返回false。探测分数有机会开始。

发生在此之后的一段时间,当前未使用的所有加载驱动程序均已卸载。

结论一下此页面也可能对您有所帮助

相关内容

  • 没有找到相关文章

最新更新