#include <pthread.h>
#include <CoreFoundation/CFRuntime.h>
#include <CoreFoundation/CFBase.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOCFSerialize.h>
#include <IOKit/hid/IOHIDKeys.h>
#include <IOKit/hid/IOHIDResourceUserClient.h>
#include "IOHIDUserDevice.h"
static IOHIDUserDeviceRef __IOHIDUserDeviceCreate(
CFAllocatorRef allocator,
CFAllocatorContext * context __unused);
static void __IOHIDUserDeviceRelease( CFTypeRef object );
static void __IOHIDUserDeviceRegister(void);
typedef struct __IOHIDUserDevice
{
CFRuntimeBase cfBase;
io_service_t service;
io_connect_t connect;
CFDictionaryRef properties;
} __IOHIDUserDevice, *__IOHIDUserDeviceRef;
static const CFRuntimeClass __IOHIDUserDeviceClass = {
0, "IOHIDUserDevice", NULL, NULL, __IOHIDUserDeviceRelease, NULL, NULL, NULL, NULL
};
static pthread_once_t __deviceTypeInit = PTHREAD_ONCE_INIT;
static CFTypeID __kIOHIDUserDeviceTypeID = _kCFRuntimeNotATypeID;
static mach_port_t __masterPort = MACH_PORT_NULL;
void __IOHIDUserDeviceRegister(void)
{
__kIOHIDUserDeviceTypeID = _CFRuntimeRegisterClass(&__IOHIDUserDeviceClass);
IOMasterPort(bootstrap_port, &__masterPort);
}
IOHIDUserDeviceRef __IOHIDUserDeviceCreate(
CFAllocatorRef allocator,
CFAllocatorContext * context __unused)
{
IOHIDUserDeviceRef device = NULL;
void * offset = NULL;
uint32_t size;
size = sizeof(__IOHIDUserDevice) - sizeof(CFRuntimeBase);
device = (IOHIDUserDeviceRef)_CFRuntimeCreateInstance(allocator, IOHIDUserDeviceGetTypeID(), size, NULL);
if (!device)
return NULL;
offset = device;
bzero(offset + sizeof(CFRuntimeBase), size);
return device;
}
void __IOHIDUserDeviceRelease( CFTypeRef object )
{
IOHIDUserDeviceRef device = (IOHIDUserDeviceRef)object;
if ( device->properties ) {
CFRelease(device->properties);
device->properties = NULL;
}
if ( device->connect ) {
IOObjectRelease(device->connect);
device->connect = 0;
}
if ( device->service ) {
IOObjectRelease(device->service);
device->service = 0;
}
}
CFTypeID IOHIDUserDeviceGetTypeID(void)
{
if ( _kCFRuntimeNotATypeID == __kIOHIDUserDeviceTypeID )
pthread_once(&__deviceTypeInit, __IOHIDUserDeviceRegister);
return __kIOHIDUserDeviceTypeID;
}
IOHIDUserDeviceRef IOHIDUserDeviceCreate(
CFAllocatorRef allocator,
CFDictionaryRef properties)
{
IOHIDUserDeviceRef device;
CFDataRef data;
kern_return_t kr;
do {
if ( !properties )
break;
device = __IOHIDUserDeviceCreate(allocator, NULL);
if ( !device )
break;
device->service = IOServiceGetMatchingService(__masterPort, IOServiceMatching( "IOHIDResource" ));
if ( device->service == MACH_PORT_NULL )
return NULL;
kr = IOServiceOpen(device->service, mach_task_self(), kIOHIDResourceUserClientTypeDevice, &device->connect);
if ( kr != KERN_SUCCESS )
break;
data = IOCFSerialize(properties, 0);
if ( !data )
break;
kr = IOConnectCallStructMethod(device->connect, kIOHIDResourceDeviceUserClientMethodCreate, CFDataGetBytePtr(data), CFDataGetLength(data), NULL, NULL);
CFRelease(data);
if ( kr != KERN_SUCCESS )
break;
return device;
} while ( FALSE );
if ( device )
CFRelease(device);
return device;
}
IOReturn IOHIDUserDeviceHandleReport(
IOHIDUserDeviceRef device,
uint8_t * report,
CFIndex reportLength)
{
return IOConnectCallStructMethod(device->connect, kIOHIDResourceDeviceUserClientMethodHandleReport, report, reportLength, NULL, NULL);
}