Hi All,
I'm a newbie of the kernel driver on OS X although I'm an experienced driver developer on Windows.
Now I'm writing a very simple HID filter driver deriving from the IOHIDEventDriver for my game controller (UsagePage: 1, Usage: 4). So far, the driver doesn nothing but adding the matching criteria like product id and vendor id in the probe method. In the start method and handleStart method, I simply call the super::start and super::handleStart. However, when I use the command line sudo kextutil hidkext.kext (which is the target name of my driver), the result shows me that the driver gets loaded successfully. But the log in the Console.app shows me failure in the handleStart method.
0x1b6e kernel kernel 17:00:42.688418 +0800 LogiHidIoDriver::probe(IOHIDInterface)
0x1b6e hidkext kernel 17:00:42.688418 +0800 LogiHidIoDriver::probe
0x1b6e hidkext kernel 17:00:42.688420 +0800 vid: 0x6a3, pid: 0xc2d
0x1b6e hidkext kernel 17:00:42.688422 +0800 Saitek Pro Flight Quadrant
0x1b6e kernel kernel 17:00:42.688428 +0800 LogiHidIoDriver::start(IOHIDInterface) <1>
0x1b6e hidkext kernel 17:00:42.688668 +0800 LogiHidIoDriver::handleStart - 0
0x1b6e hidkext kernel 17:00:42.688670 +0800 LogiHidIoDriver::start - 0
0x1b6e kernel kernel 17:00:42.688673 +0800 LogiHidIoDriver::start(IOHIDInterface) <1> failed
0x1b6e hidkext kernel 17:00:42.688674 +0800 LogiHidIoDriver::free
The personalities of the driver is as below:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-/
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en_US</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>com.logi.gaming.hidkext</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Logitech HID I/O Driver</string>
<key>CFBundlePackageType</key>
<string>KEXT</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>IOKitPersonalities</key>
<dict>
<key>HID IO Driver</key>
<dict>
<key>CFBundleIdentifier</key>
<string>com.logi.gaming.hidkext</string>
<key>IOClass</key>
<string>LogiHidIoDriver</string>
<key>IOKitDebug</key>
<integer>65535</integer>
<key>IOProviderClass</key>
<string>IOHIDInterface</string>
<key>IOResourceMatch</key>
<string>IOKit</string>
<key>IOMatchCategory</key>
<string>LogiHidIoDriver</string>
</dict>
</dict>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2017 marcai. All rights reserved.</string>
<key>OSBundleLibraries</key>
<dict>
<key>com.apple.iokit.IOHIDFamily</key>
<string>2.0</string>
<key>com.apple.kpi.iokit</key>
<string>16.7</string>
<key>com.apple.kpi.libkern</key>
<string>16.7</string>
</dict>
<key>OSBundleRequired</key>
<string>Console</string>
</dict>
</plist>
My header file as below:
#ifndef _LOGIHIDIO_DRIVER_
#define _LOGIHIDIO_DRIVER_
#include <IOKit/hidevent/IOHIDEventDriver.h>
class LogiHidIoDriver : public IOHIDEventDriver
{
OSDeclareDefaultStructors(LogiHidIoDriver)
public:
virtual bool init(OSDictionary* dict) override;
virtual void free(void) override;
virtual IOService* probe(IOService* provider, SInt32* score) override;
virtual bool handleStart(IOService* provider) override;
virtual void handleStop(IOService * provider) override;
virtual bool start(IOService* provider) override;
virtual void stop(IOService* provider) override;
virtual bool willTerminate(IOService* provider, IOOptionBits options) override;
virtual bool didTerminate(IOService* provider, IOOptionBits options, bool* defer) override;
virtual bool terminate(IOOptionBits options) override;
virtual bool finalize(IOOptionBits options) override;
};
#endif
The implementation code is as below:
#include <IOKit/IOLib.h>
#include <IOKit/hid/IOHIDDevice.h>
#include "hidkext.h"
#define super IOHIDEventDriver
OSDefineMetaClassAndStructors(LogiHidIoDriver, IOHIDEventDriver)
bool LogiHidIoDriver::init(OSDictionary* dict)
{
IOLog("LogiHidIoDriver::%s\n", __FUNCTION__);
return super::init(dict);
}
void LogiHidIoDriver::free(void)
{
IOLog("LogiHidIoDriver::%s\n", __FUNCTION__);
super::free();
}
IOService* LogiHidIoDriver::probe(IOService* provider, SInt32* score)
{
IOLog("LogiHidIoDriver::%s\n", __FUNCTION__);
IOService* service = nullptr;
bool deviceFound = false;
IOHIDInterface* hidInterface = OSDynamicCast(IOHIDInterface, provider);
if (hidInterface != nullptr)
{
UInt32 vendorId = hidInterface->getVendorID();
UInt32 productId = hidInterface->getProductID();
IOLog("vid: 0x%x, pid: 0x%x\n", vendorId, productId);
if (vendorId == 0x6a3) /
{
switch (productId)
{
case 0xc2d: /
IOLog("Saitek Pro Flight Quadrant\n");
deviceFound = true;
break;
}
}
}
if (deviceFound)
{
service = super::probe(provider, score);
*score = 100000;
}
else
{
service = nullptr;
*score = 0;
}
return service;
}
bool LogiHidIoDriver::handleStart(IOService* provider)
{
bool retVal = super::handleStart(provider);
IOLog("LogiHidIoDriver::%s - %d\n", __FUNCTION__, retVal);
return retVal;
}
void LogiHidIoDriver::handleStop(IOService * provider)
{
IOLog("LogiHidIoDriver::%s\n", __FUNCTION__);
super::handleStop(provider);
}
bool LogiHidIoDriver::start(IOService* provider)
{
bool retVal = super::start(provider);
IOLog("LogiHidIoDriver::%s - %d\n", __FUNCTION__, retVal);
return retVal;
}
void LogiHidIoDriver::stop(IOService* provider)
{
IOLog("LogiHidIoDriver::%s\n", __FUNCTION__);
super::stop(provider);
}
bool LogiHidIoDriver::willTerminate(IOService* provider, IOOptionBits options)
{
IOLog("LogiHidIoDriver::%s - 0x%x\n", __FUNCTION__, options);
return super::willTerminate(provider, options);
}
bool LogiHidIoDriver::didTerminate(IOService* provider, IOOptionBits options, bool* defer)
{
IOLog("LogiHidIoDriver::%s - 0x%x\n", __FUNCTION__, options);
return super::didTerminate(provider, options, defer);
}
bool LogiHidIoDriver::terminate(IOOptionBits options)
{
IOLog("LogiHidIoDriver::%s - 0x%x\n", __FUNCTION__, options);
return super::terminate(options);
}
bool LogiHidIoDriver::finalize(IOOptionBits options)
{
IOLog("LogiHidIoDriver::%s - 0x%x\n", __FUNCTION__, options);
return super::finalize(options);
}
Thanks,
Marshall