IOHIDEventService.cpp [plain text]
#include <TargetConditionals.h>
#include <IOKit/hid/IOHIDUsageTables.h>
#include <IOKit/IOLib.h>
#include <sys/kdebug.h>
#include <IOKit/usb/USB.h>
#include "IOHIDSystem.h"
#include "IOHIDEventService.h"
#include "IOHIDInterface.h"
#include "IOHIDKeys.h"
#include "IOHIDPrivateKeys.h"
#include "AppleHIDUsageTables.h"
#if !TARGET_OS_EMBEDDED
#include "IOHIDPointing.h"
#include "IOHIDKeyboard.h"
#include "IOHIDConsumer.h"
#endif
#include "IOHIDFamilyPrivate.h"
#include "IOHIDevicePrivateKeys.h"
#include "ev_private.h"
enum {
kBootProtocolNone = 0,
kBootProtocolKeyboard,
kBootProtocolMouse
};
enum {
kShimEventProcessor = 0x01
};
#define kDefaultFixedResolution (400 << 16)
#define kDefaultScrollFixedResolution (9 << 16)
#define kMaxSystemBarrelPressure 32767
#define kMaxSystemTipPressure 65535
#define kEjectDelayMS 250
#define kDelayedOption (1<<31)
#define NUB_LOCK if (_nubLock) IORecursiveLockLock(_nubLock)
#define NUB_UNLOCK if (_nubLock) IORecursiveLockUnlock(_nubLock)
#if TARGET_OS_EMBEDDED
#define SET_HID_PROPERTIES_EMBEDDED(service) \
service->setProperty(kIOHIDPrimaryUsagePageKey, getPrimaryUsagePage(), 32); \
service->setProperty(kIOHIDPrimaryUsageKey, getPrimaryUsage(), 32); \
service->setProperty(kIOHIDReportIntervalKey, getReportInterval(), 32);
#else
#define SET_HID_PROPERTIES_EMBEDDED(service) \
{};
#endif
#define SET_HID_PROPERTIES(service) \
service->setProperty(kIOHIDTransportKey, getTransport()); \
service->setProperty(kIOHIDLocationIDKey, getLocationID(), 32); \
service->setProperty(kIOHIDVendorIDKey, getVendorID(), 32); \
service->setProperty(kIOHIDVendorIDSourceKey, getVendorIDSource(), 32); \
service->setProperty(kIOHIDProductIDKey, getProductID(), 32); \
service->setProperty(kIOHIDVersionNumberKey, getVersion(), 32); \
service->setProperty(kIOHIDCountryCodeKey, getCountryCode(), 32); \
service->setProperty(kIOHIDManufacturerKey, getManufacturer()); \
service->setProperty(kIOHIDProductKey, getProduct()); \
service->setProperty(kIOHIDSerialNumberKey, getSerialNumber());
#define _provider _reserved->provider
#define _workLoop _reserved->workLoop
#define _ejectDelayMS _reserved->ejectDelayMS
#define _ejectTimerEventSource _reserved->ejectTimerEventSource
#define _ejectState _reserved->ejectState
#define _ejectOptions _reserved->ejectOptions
#define _capsDelayMS _reserved->capsDelayMS
#define _capsTimerEventSource _reserved->capsTimerEventSource
#define _capsState _reserved->capsState
#define _capsOptions _reserved->capsOptions
#if TARGET_OS_EMBEDDED
#define _clientDict _reserved->clientDict
#define _debuggerMask _reserved->debuggerMask
#define _startDebuggerMask _reserved->startDebuggerMask
#define _debuggerTimerEventSource _reserved->debuggerTimerEventSource
#define kDebuggerDelayMS 2500
#define kDebuggerDelayPwrOnlyMS 10000
class IOHIDClientData : public OSObject
{
OSDeclareDefaultStructors(IOHIDClientData)
IOService * client;
void * context;
void * action;
public:
static IOHIDClientData* withClientInfo(IOService *client, void* context, void * action);
inline IOService * getClient() { return client; }
inline void * getContext() { return context; }
inline void * getAction() { return action; }
};
#endif
struct TransducerData {
UInt32 reportID;
UInt32 deviceID;
UInt32 type;
UInt32 capabilities;
bool digitizerCollection;
bool supportsTransducerIndex;
};
#define super IOService
OSDefineMetaClassAndAbstractStructors( IOHIDEventService, super )
bool IOHIDEventService::init ( OSDictionary * properties )
{
if (!super::init(properties))
return false;
_reserved = IONew(ExpansionData, 1);
bzero(_reserved, sizeof(ExpansionData));
_nubLock = IORecursiveLockAlloc();
#if TARGET_OS_EMBEDDED
_clientDict = OSDictionary::withCapacity(2);
if ( _clientDict == 0 )
return false;
#endif
_ejectDelayMS = kEjectDelayMS;
return true;
}
bool IOHIDEventService::start ( IOService * provider )
{
UInt32 bootProtocol = 0;
OSNumber * number = NULL;
_provider = provider;
if ( !super::start(provider) )
return false;
if ( !handleStart(provider) )
return false;
_workLoop = provider->getWorkLoop();
if ( !_workLoop )
return false;
_workLoop->retain();
_ejectTimerEventSource = IOTimerEventSource::timerEventSource(this, OSMemberFunctionCast(IOTimerEventSource::Action, this, &IOHIDEventService::ejectTimerCallback));
if (!_ejectTimerEventSource || (_workLoop->addEventSource(_ejectTimerEventSource) != kIOReturnSuccess))
return false;
number = OSDynamicCast(OSNumber, getProperty(kIOHIDKeyboardEjectDelay));
if ( number )
_ejectDelayMS = number->unsigned32BitValue();
_capsTimerEventSource = IOTimerEventSource::timerEventSource(this, OSMemberFunctionCast(IOTimerEventSource::Action, this, &IOHIDEventService::capsTimerCallback));
if (!_capsTimerEventSource || (_workLoop->addEventSource(_capsTimerEventSource) != kIOReturnSuccess))
return false;
number = OSDynamicCast(OSNumber, getProperty(kIOHIDKeyboardCapsLockDelay));
if ( number )
_capsDelayMS = number->unsigned32BitValue();
SET_HID_PROPERTIES(this);
SET_HID_PROPERTIES_EMBEDDED(this);
OSObject * providerUsagePair = provider->getProperty(kIOHIDDeviceUsagePairsKey);
if ( providerUsagePair && (providerUsagePair != getProperty(kIOHIDDeviceUsagePairsKey)) ) {
setProperty(kIOHIDDeviceUsagePairsKey, providerUsagePair);
} else {
OSArray* array = OSArray::withCapacity(2);
#if TARGET_OS_EMBEDDED
OSDictionary * pair = OSDictionary::withCapacity(2);
number = OSNumber::withNumber(getPrimaryUsagePage(), 32);
pair->setObject(kIOHIDPrimaryUsagePageKey, number);
number->release();
number = OSNumber::withNumber(getPrimaryUsage(), 32);
pair->setObject(kIOHIDPrimaryUsageKey, number);
number->release();
array->setObject(pair);
pair->release();
#endif
setProperty(kIOHIDDeviceUsagePairsKey, array);
array->release();
}
number = OSDynamicCast(OSNumber, getProperty("BootProtocol"));
if (number)
bootProtocol = number->unsigned32BitValue();
parseSupportedElements (getReportElements(), bootProtocol);
#if !TARGET_OS_EMBEDDED
if ((!_consumerNub && _keyboardNub) || (!_keyboardNub && _consumerNub))
{
OSDictionary * matchingDictionary = IOService::serviceMatching( "IOHIDEventService" );
if( matchingDictionary )
{
OSDictionary * propertyMatch = OSDictionary::withCapacity(4);
OSObject * object;
if (propertyMatch)
{
object = getProperty(kIOHIDTransportKey);
if (object) propertyMatch->setObject(kIOHIDTransportKey, object);
object = getProperty(kIOHIDVendorIDKey);
if (object) propertyMatch->setObject(kIOHIDVendorIDKey, object);
object = getProperty(kIOHIDProductIDKey);
if (object) propertyMatch->setObject(kIOHIDProductIDKey, object);
object = getProperty(kIOHIDLocationIDKey);
if (object) propertyMatch->setObject(kIOHIDLocationIDKey, object);
matchingDictionary->setObject(gIOPropertyMatchKey, propertyMatch);
propertyMatch->release();
}
_publishNotify = addNotification( gIOPublishNotification,
matchingDictionary,
&IOHIDEventService::_publishNotificationHandler,
this, 0 );
}
}
#endif
_readyForInputReports = true;
registerService(kIOServiceSynchronous);
return true;
}
static void stopAndReleaseShim ( IOService * service, IOService * provider )
{
if ( !service )
return;
IOService * serviceProvider = service->getProvider();
if ( serviceProvider == provider )
{
service->stop(provider);
service->detach(provider);
}
service->release();
}
void IOHIDEventService::stop( IOService * provider )
{
handleStop ( provider );
#if !TARGET_OS_EMBEDDED
NUB_LOCK;
stopAndReleaseShim ( _keyboardNub, this );
_keyboardNub = 0;
stopAndReleaseShim ( _pointingNub, this );
_pointingNub = 0;
stopAndReleaseShim ( _consumerNub, this );
_consumerNub = 0;
if (_publishNotify) {
_publishNotify->remove();
_publishNotify = 0;
}
NUB_UNLOCK;
#endif
super::stop( provider );
}
bool IOHIDEventService::matchPropertyTable(OSDictionary * table, SInt32 * score)
{
if (super::matchPropertyTable(table, score) == false)
return false;
return MatchPropertyTable(this, table, score);
}
bool IOHIDEventService::_publishNotificationHandler(
void * target,
void * ,
IOService * newService )
{
#if !TARGET_OS_EMBEDDED
IOHIDEventService * self = (IOHIDEventService *) target;
IOHIDEventService * service = (IOHIDEventService *) newService;
IORecursiveLockLock(self->_nubLock);
if( service->_keyboardNub )
{
if ( self->_keyboardNub
&& self->_keyboardNub->isDispatcher()
&& !service->_keyboardNub->isDispatcher() )
{
stopAndReleaseShim ( self->_keyboardNub, self );
self->_keyboardNub = 0;
}
if ( !self->_keyboardNub )
{
self->_keyboardNub = service->_keyboardNub;
self->_keyboardNub->retain();
if (self->_publishNotify)
{
self->_publishNotify->remove();
self->_publishNotify = 0;
}
}
}
if( service->_consumerNub )
{
if ( self->_consumerNub
&& self->_consumerNub->isDispatcher()
&& !service->_consumerNub->isDispatcher() )
{
stopAndReleaseShim ( self->_consumerNub, self );
self->_consumerNub = 0;
}
if ( !self->_consumerNub )
{
self->_consumerNub = service->_consumerNub;
self->_consumerNub->retain();
if (self->_publishNotify)
{
self->_publishNotify->remove();
self->_publishNotify = 0;
}
}
}
IORecursiveLockUnlock(self->_nubLock);
#endif
return true;
}
IOReturn IOHIDEventService::setSystemProperties( OSDictionary * properties )
{
OSDictionary * dict = NULL;
OSArray * array = NULL;
OSNumber * number = NULL;
if ( !properties )
return kIOReturnBadArgument;
if ( properties->getObject(kIOHIDDeviceParametersKey) != kOSBooleanTrue )
{
OSDictionary * propsCopy = OSDictionary::withDictionary(properties);
if ( propsCopy ) {
propsCopy->setObject(kIOHIDEventServicePropertiesKey, kOSBooleanTrue);
#if !TARGET_OS_EMBEDDED
if ( _keyboardNub )
_keyboardNub->setParamProperties(properties);
if ( _pointingNub )
_pointingNub->setParamProperties(properties);
if ( _consumerNub )
_consumerNub->setParamProperties(properties);
#endif
propsCopy->release();
}
}
if ( ( array = OSDynamicCast(OSArray, properties->getObject(kIOHIDKeyboardModifierMappingPairsKey)) ) ) {
UInt32 srcVirtualCode, dstVirtualCode;
Boolean capsMap = FALSE;
for (UInt32 index=0; index<array->getCount(); index++) {
dict = OSDynamicCast(OSDictionary, array->getObject(index));
if ( !dict )
continue;
number = OSDynamicCast(OSNumber, dict->getObject(kIOHIDKeyboardModifierMappingSrcKey));
if ( !number )
continue;
srcVirtualCode = number->unsigned32BitValue();
if ( srcVirtualCode != NX_MODIFIERKEY_ALPHALOCK )
continue;
number = OSDynamicCast(OSNumber, dict->getObject(kIOHIDKeyboardModifierMappingDstKey));
if ( !number )
continue;
dstVirtualCode = number->unsigned32BitValue();
if ( dstVirtualCode == srcVirtualCode )
continue;
capsMap = TRUE;
break;
}
if ( capsMap ) {
_capsDelayMS = 0;
} else if ( !_capsDelayMS ) {
number = OSDynamicCast(OSNumber, getProperty(kIOHIDKeyboardCapsLockDelay));
if ( number )
_capsDelayMS = number->unsigned32BitValue();
}
}
if ( properties->getObject(kIOHIDDeviceParametersKey) == kOSBooleanTrue ) {
OSDictionary * eventServiceProperties = OSDynamicCast(OSDictionary, copyProperty(kIOHIDEventServicePropertiesKey));
if ( !eventServiceProperties )
eventServiceProperties = OSDictionary::withCapacity(4);
if ( eventServiceProperties ) {
eventServiceProperties->merge(properties);
eventServiceProperties->removeObject(kIOHIDResetKeyboardKey);
eventServiceProperties->removeObject(kIOHIDResetPointerKey);
eventServiceProperties->removeObject(kIOHIDDeviceParametersKey);
setProperty(kIOHIDEventServicePropertiesKey, eventServiceProperties);
eventServiceProperties->release();
}
}
return kIOReturnSuccess;
}
IOReturn IOHIDEventService::setProperties( OSObject * properties )
{
OSDictionary * propertyDict = OSDynamicCast(OSDictionary, properties);
IOReturn ret = kIOReturnBadArgument;
if ( propertyDict ) {
propertyDict->setObject(kIOHIDDeviceParametersKey, kOSBooleanTrue);
ret = setSystemProperties( propertyDict );
propertyDict->removeObject(kIOHIDDeviceParametersKey);
}
return ret;
}
void IOHIDEventService::parseSupportedElements ( OSArray * elementArray, UInt32 bootProtocol )
{
UInt32 count = 0;
UInt32 index = 0;
UInt32 usage = 0;
UInt32 usagePage = 0;
UInt32 supportedModifiers = 0;
UInt32 buttonCount = 0;
IOHIDElement * element = 0;
OSArray * functions = 0;
IOFixed pointingResolution = 0;
IOFixed scrollResolution = 0;
bool pointingDevice = false;
bool keyboardDevice = false;
bool consumerDevice = false;
switch ( bootProtocol )
{
case kBootProtocolMouse:
pointingDevice = true;
break;
case kBootProtocolKeyboard:
keyboardDevice = true;
break;
}
if ( elementArray )
{
count = elementArray->getCount();
for ( index = 0; index < count; index++ )
{
element = OSDynamicCast(IOHIDElement, elementArray->getObject(index));
if ( !element )
continue;
usagePage = element->getUsagePage();
usage = element->getUsage();
switch ( usagePage )
{
case kHIDPage_GenericDesktop:
switch ( usage )
{
case kHIDUsage_GD_Mouse:
pointingDevice = true;
break;
case kHIDUsage_GD_X:
if ( !(pointingResolution = determineResolution(element)) )
pointingResolution = kDefaultFixedResolution;
case kHIDUsage_GD_Y:
case kHIDUsage_GD_Z:
if ((element->getFlags() & kIOHIDElementFlagsRelativeMask) == 0)
{
processTabletElement ( element );
}
break;
case kHIDUsage_GD_Wheel:
if ( !(scrollResolution = determineResolution(element)) )
scrollResolution = kDefaultScrollFixedResolution;
break;
case kHIDUsage_GD_SystemPowerDown:
case kHIDUsage_GD_SystemSleep:
case kHIDUsage_GD_SystemWakeUp:
consumerDevice = true;
break;
}
break;
case kHIDPage_Button:
processTabletElement ( element );
buttonCount ++;
break;
case kHIDPage_KeyboardOrKeypad:
keyboardDevice = true;
switch ( usage )
{
case kHIDUsage_KeyboardLeftControl:
supportedModifiers |= NX_CONTROLMASK;
supportedModifiers |= NX_DEVICELCTLKEYMASK;
break;
case kHIDUsage_KeyboardLeftShift:
supportedModifiers |= NX_SHIFTMASK;
supportedModifiers |= NX_DEVICELSHIFTKEYMASK;
break;
case kHIDUsage_KeyboardLeftAlt:
supportedModifiers |= NX_ALTERNATEMASK;
supportedModifiers |= NX_DEVICELALTKEYMASK;
break;
case kHIDUsage_KeyboardLeftGUI:
supportedModifiers |= NX_COMMANDMASK;
supportedModifiers |= NX_DEVICELCMDKEYMASK;
break;
case kHIDUsage_KeyboardRightControl:
supportedModifiers |= NX_CONTROLMASK;
supportedModifiers |= NX_DEVICERCTLKEYMASK;
break;
case kHIDUsage_KeyboardRightShift:
supportedModifiers |= NX_SHIFTMASK;
supportedModifiers |= NX_DEVICERSHIFTKEYMASK;
break;
case kHIDUsage_KeyboardRightAlt:
supportedModifiers |= NX_ALTERNATEMASK;
supportedModifiers |= NX_DEVICERALTKEYMASK;
break;
case kHIDUsage_KeyboardRightGUI:
supportedModifiers |= NX_COMMANDMASK;
supportedModifiers |= NX_DEVICERCMDKEYMASK;
break;
}
break;
case kHIDPage_Consumer:
consumerDevice = true;
break;
case kHIDPage_Digitizer:
pointingDevice = true;
switch ( usage )
{
case kHIDUsage_Dig_TipSwitch:
case kHIDUsage_Dig_BarrelSwitch:
case kHIDUsage_Dig_Eraser:
buttonCount ++;
default:
processTabletElement ( element );
break;
}
break;
case kHIDPage_AppleVendorTopCase:
if ((getVendorID() == kIOUSBVendorIDAppleComputer) &&
(usage == kHIDUsage_AV_TopCase_KeyboardFn))
{
supportedModifiers |= NX_SECONDARYFNMASK;
}
break;
}
if ((element->getType() == kIOHIDElementTypeCollection) &&
((element->getCollectionType() == kIOHIDElementCollectionTypeApplication) ||
(element->getCollectionType() == kIOHIDElementCollectionTypePhysical)))
{
OSNumber * usagePageRef, * usageRef;
OSDictionary * pairRef;
if(!functions) functions = OSArray::withCapacity(2);
pairRef = OSDictionary::withCapacity(2);
usageRef = OSNumber::withNumber(usage, 32);
usagePageRef= OSNumber::withNumber(usagePage, 32);
pairRef->setObject(kIOHIDDeviceUsageKey, usageRef);
pairRef->setObject(kIOHIDDeviceUsagePageKey, usagePageRef);
UInt32 pairCount = functions->getCount();
bool found = false;
for(unsigned i=0; i<pairCount; i++)
{
OSDictionary *tempPair = (OSDictionary *)functions->getObject(i);
if (found = tempPair->isEqualTo(pairRef))
break;
}
if (!found)
{
functions->setObject(functions->getCount(), pairRef);
}
pairRef->release();
usageRef->release();
usagePageRef->release();
}
}
setProperty(kIOHIDDeviceUsagePairsKey, functions);
if (functions) functions->release();
}
processTransducerData();
if ( pointingDevice )
{
_pointingNub = newPointingShim(buttonCount, pointingResolution, scrollResolution, kShimEventProcessor);
}
if ( keyboardDevice )
{
_keyboardNub = newKeyboardShim(supportedModifiers, kShimEventProcessor);
}
if ( consumerDevice )
{
_consumerNub = newConsumerShim(kShimEventProcessor);
}
}
void IOHIDEventService::processTabletElement ( IOHIDElement * element )
{
TransducerData * transducerRef;
IOHIDElement * parent;
transducerRef = getTransducerData(element->getReportID());
if ( !transducerRef )
{
transducerRef = createTransducerData ( element->getReportID() );
}
if ( element->getUsagePage() == kHIDPage_Digitizer )
{
switch (element->getUsage())
{
case kHIDUsage_Dig_Stylus:
transducerRef->type = NX_TABLET_POINTER_PEN;
break;
case kHIDUsage_Dig_Puck:
transducerRef->type = NX_TABLET_POINTER_CURSOR;
break;
case kHIDUsage_Dig_XTilt:
transducerRef->capabilities |= NX_TABLET_CAPABILITY_TILTXMASK;
break;
case kHIDUsage_Dig_YTilt:
transducerRef->capabilities |= NX_TABLET_CAPABILITY_TILTYMASK;
break;
case kHIDUsage_Dig_TipPressure:
if ( transducerRef->type == NX_TABLET_POINTER_UNKNOWN )
transducerRef->type = NX_TABLET_POINTER_PEN;
transducerRef->capabilities |= NX_TABLET_CAPABILITY_PRESSUREMASK;
break;
case kHIDUsage_Dig_BarrelPressure:
if ( transducerRef->type == NX_TABLET_POINTER_UNKNOWN )
transducerRef->type = NX_TABLET_POINTER_PEN;
transducerRef->capabilities |= NX_TABLET_CAPABILITY_TANGENTIALPRESSUREMASK;
break;
case kHIDUsage_Dig_Twist:
transducerRef->capabilities |= NX_TABLET_CAPABILITY_ROTATIONMASK;
break;
case kHIDUsage_Dig_TransducerIndex:
transducerRef->supportsTransducerIndex = true;
break;
case kHIDUsage_Dig_Eraser:
if ( transducerRef->type == NX_TABLET_POINTER_UNKNOWN )
transducerRef->type = NX_TABLET_POINTER_ERASER;
case kHIDUsage_Dig_TipSwitch:
case kHIDUsage_Dig_BarrelSwitch:
if ( transducerRef->type == NX_TABLET_POINTER_UNKNOWN )
transducerRef->type = NX_TABLET_POINTER_PEN;
transducerRef->capabilities |= NX_TABLET_CAPABILITY_BUTTONSMASK;
break;
}
}
else if ( element->getUsagePage() == kHIDPage_GenericDesktop )
{
switch (element->getUsage())
{
case kHIDUsage_GD_X:
transducerRef->capabilities |= NX_TABLET_CAPABILITY_ABSXMASK;
break;
case kHIDUsage_GD_Y:
transducerRef->capabilities |= NX_TABLET_CAPABILITY_ABSYMASK;
break;
case kHIDUsage_GD_Z:
transducerRef->capabilities |= NX_TABLET_CAPABILITY_ABSZMASK;
break;
}
}
else if ( element->getUsagePage() == kHIDPage_Button )
{
transducerRef->capabilities |= NX_TABLET_CAPABILITY_BUTTONSMASK;
}
if ( element->getType() != kIOHIDElementTypeCollection )
{
parent = element->getParentElement();
if ( parent && ( parent->getUsagePage() == kHIDPage_Digitizer ))
{
transducerRef->digitizerCollection = true;
}
}
}
TransducerData * IOHIDEventService::createTransducerData ( UInt32 tranducerID )
{
TransducerData temp;
OSData * data;
if ( ! _transducerDataArray )
_transducerDataArray = OSArray::withCapacity(4);
bzero(&temp, sizeof(TransducerData));
temp.reportID = tranducerID;
temp.type = NX_TABLET_POINTER_UNKNOWN;
data = OSData::withBytes(&temp, sizeof(TransducerData));
_transducerDataArray->setObject(data);
data->release();
return (data) ? (TransducerData *)data->getBytesNoCopy() : 0;
}
TransducerData * IOHIDEventService::getTransducerData ( UInt32 tranducerID )
{
TransducerData * transducerRef = 0;
TransducerData * transducerIndexRef = 0;
OSData * data = 0;
bool found = 0;
if ( !_transducerDataArray )
return NULL;
UInt32 count = _transducerDataArray->getCount();
for (unsigned i=0; i<count; i++)
{
data = (OSData *)_transducerDataArray->getObject(i);
if (!data) continue;
transducerRef = (TransducerData *)data->getBytesNoCopy();
if (!transducerRef) continue;
if (transducerRef->supportsTransducerIndex)
transducerIndexRef = transducerRef;
if (transducerRef->reportID != tranducerID) continue;
found = true;
break;
}
return ( found ) ? transducerRef : transducerIndexRef;
}
void IOHIDEventService::processTransducerData ()
{
#if !TARGET_OS_EMBEDDED
TransducerData * transducerRef;
OSData * data;
if ( ! _transducerDataArray )
return;
for (unsigned i=0; i<_transducerDataArray->getCount(); i++)
{
data = (OSData *)_transducerDataArray->getObject(i);
if (!data) continue;
transducerRef = (TransducerData *)data->getBytesNoCopy();
if ( (transducerRef->capabilities & ~NX_TABLET_CAPABILITY_BUTTONSMASK) ||
(transducerRef->digitizerCollection))
{
transducerRef->deviceID = IOHIDPointing::generateDeviceID();
transducerRef->capabilities |= NX_TABLET_CAPABILITY_DEVICEIDMASK;
}
else
{
_transducerDataArray->removeObject(i--);
}
}
if ( _transducerDataArray->getCount() == 0 )
{
_transducerDataArray->release();
_transducerDataArray = 0;
}
#endif
}
IOHIDPointing * IOHIDEventService::newPointingShim (
UInt32 buttonCount,
IOFixed pointerResolution,
IOFixed scrollResolution,
IOOptionBits options)
{
IOHIDPointing * pointingNub = NULL;
#if !TARGET_OS_EMBEDDED
bool isDispatcher = ((options & kShimEventProcessor) == 0);
pointingNub = IOHIDPointing::Pointing(buttonCount, pointerResolution, scrollResolution, isDispatcher);
if (pointingNub) {
SET_HID_PROPERTIES(pointingNub);
if (!pointingNub->attach(this) || !pointingNub->start(this))
{
pointingNub->release();
pointingNub = 0;
}
}
#endif
return pointingNub;
}
IOHIDKeyboard * IOHIDEventService::newKeyboardShim (
UInt32 supportedModifiers,
IOOptionBits options)
{
IOHIDKeyboard * keyboardNub = NULL;
#if !TARGET_OS_EMBEDDED
bool isDispatcher = ((options & kShimEventProcessor) == 0);
keyboardNub = IOHIDKeyboard::Keyboard(supportedModifiers, isDispatcher);
if (keyboardNub) {
SET_HID_PROPERTIES(keyboardNub);
if (!keyboardNub->attach(this) || !keyboardNub->start(this))
{
keyboardNub->release();
keyboardNub = 0;
}
}
#endif
return keyboardNub;
}
IOHIDConsumer * IOHIDEventService::newConsumerShim ( IOOptionBits options )
{
IOHIDConsumer * consumerNub = NULL;
#if !TARGET_OS_EMBEDDED
bool isDispatcher = ((options & kShimEventProcessor) == 0);
consumerNub = IOHIDConsumer::Consumer(isDispatcher);
if (consumerNub) {
SET_HID_PROPERTIES(consumerNub);
if (!consumerNub->attach(this) || !consumerNub->start(this))
{
consumerNub->release();
consumerNub = 0;
}
}
#endif
return consumerNub;
}
IOFixed IOHIDEventService::determineResolution ( IOHIDElement * element )
{
IOFixed resolution = 0;
if ((element->getPhysicalMin() != element->getLogicalMin()) &&
(element->getPhysicalMax() != element->getLogicalMax()))
{
SInt32 logicalDiff = (element->getLogicalMax() - element->getLogicalMin());
SInt32 physicalDiff = (element->getPhysicalMax() - element->getPhysicalMin());
SInt32 resExponent = element->getUnitExponent() & 0x0F;
if (resExponent < 8)
{
for (int i = resExponent; i > 0; i--)
{
physicalDiff *= 10;
}
}
else
{
for (int i = 0x10 - resExponent; i > 0; i--)
{
logicalDiff *= 10;
}
}
resolution = (logicalDiff / physicalDiff) << 16;
}
return resolution;
}
void IOHIDEventService::free()
{
IORecursiveLock* tempLock = NULL;
if ( _nubLock )
{
IORecursiveLockLock(_nubLock);
tempLock = _nubLock;
_nubLock = NULL;
}
if ( _transducerDataArray )
{
_transducerDataArray->release();
_transducerDataArray = 0;
}
if ( _transducerDataArray )
{
_transducerDataArray->release();
_transducerDataArray = 0;
}
if (_ejectTimerEventSource) {
if ( _workLoop )
_workLoop->removeEventSource(_ejectTimerEventSource);
_ejectTimerEventSource->release();
_ejectTimerEventSource = 0;
}
if (_capsTimerEventSource) {
if ( _workLoop )
_workLoop->removeEventSource(_capsTimerEventSource);
_capsTimerEventSource->release();
_capsTimerEventSource = 0;
}
if ( _workLoop ) {
_workLoop->release();
_workLoop = NULL;
}
#if TARGET_OS_EMBEDDED
if ( _clientDict )
{
assert(_clientDict->getCount() == 0);
_clientDict->release();
_clientDict = NULL;
}
#endif
if (_reserved) {
IODelete(_reserved, ExpansionData, 1);
_reserved = NULL;
}
if ( tempLock )
{
IORecursiveLockUnlock(tempLock);
IORecursiveLockFree(tempLock);
}
super::free();
}
bool IOHIDEventService::handleOpen(IOService * client,
IOOptionBits options,
void * argument)
{
#if TARGET_OS_EMBEDDED
bool accept = false;
do {
if ( _clientDict->getObject((const OSSymbol *)client) ) {
accept = true;
break;
}
if ( !OSDynamicCast(IOHIDClientData, (OSObject *)argument) ||
!_clientDict->setObject((const OSSymbol *)client, (IOHIDClientData *)argument))
break;
accept = true;
} while (false);
return accept;
#else
return super::handleOpen(client, options, argument);
#endif
}
void IOHIDEventService::handleClose(IOService * client, IOOptionBits options)
{
#if TARGET_OS_EMBEDDED
if ( _clientDict->getObject((const OSSymbol *)client) )
_clientDict->removeObject((const OSSymbol *)client);
#else
super::handleClose(client, options);
#endif
}
bool IOHIDEventService::handleIsOpen(const IOService * client) const
{
#if TARGET_OS_EMBEDDED
if (client)
return _clientDict->getObject((const OSSymbol *)client) != NULL;
else
return (_clientDict->getCount() > 0);
#else
return super::handleIsOpen(client);
#endif
}
bool IOHIDEventService::handleStart( IOService * provider )
{
return true;
}
void IOHIDEventService::handleStop( IOService * provider )
{}
OSString * IOHIDEventService::getTransport ()
{
return _provider ? OSDynamicCast(OSString, _provider->getProperty(kIOHIDTransportKey)) : 0;
}
OSString * IOHIDEventService::getManufacturer ()
{
return _provider ? OSDynamicCast(OSString, _provider->getProperty(kIOHIDManufacturerKey)) : 0;
}
OSString * IOHIDEventService::getProduct ()
{
return _provider ? OSDynamicCast(OSString, _provider->getProperty(kIOHIDProductKey)) : 0;
}
OSString * IOHIDEventService::getSerialNumber ()
{
return _provider ? OSDynamicCast(OSString, _provider->getProperty(kIOHIDSerialNumberKey)) : 0;
}
UInt32 IOHIDEventService::getLocationID ()
{
UInt32 value = 0;
if ( _provider ) {
OSNumber * number = OSDynamicCast(OSNumber, _provider->getProperty(kIOHIDSerialNumberKey));
if ( number )
value = number->unsigned32BitValue();
}
return value;
}
UInt32 IOHIDEventService::getVendorID ()
{
UInt32 value = 0;
if ( _provider ) {
OSNumber * number = OSDynamicCast(OSNumber, _provider->getProperty(kIOHIDVendorIDKey));
if ( number )
value = number->unsigned32BitValue();
}
return value;
}
UInt32 IOHIDEventService::getVendorIDSource ()
{
UInt32 value = 0;
if ( _provider ) {
OSNumber * number = OSDynamicCast(OSNumber, _provider->getProperty(kIOHIDVendorIDSourceKey));
if ( number )
value = number->unsigned32BitValue();
}
return value;
}
UInt32 IOHIDEventService::getProductID ()
{
UInt32 value = 0;
if ( _provider ) {
OSNumber * number = OSDynamicCast(OSNumber, _provider->getProperty(kIOHIDProductIDKey));
if ( number )
value = number->unsigned32BitValue();
}
return value;
}
UInt32 IOHIDEventService::getVersion ()
{
UInt32 value = 0;
if ( _provider ) {
OSNumber * number = OSDynamicCast(OSNumber, _provider->getProperty(kIOHIDVersionNumberKey));
if ( number )
value = number->unsigned32BitValue();
}
return value;
}
UInt32 IOHIDEventService::getCountryCode ()
{
UInt32 value = 0;
if ( _provider ) {
OSNumber * number = OSDynamicCast(OSNumber, _provider->getProperty(kIOHIDCountryCodeKey));
if ( number )
value = number->unsigned32BitValue();
}
return value;
}
OSArray * IOHIDEventService::getReportElements()
{
return 0;
}
void IOHIDEventService::setElementValue (
UInt32 usagePage,
UInt32 usage,
UInt32 value )
{
}
UInt32 IOHIDEventService::getElementValue (
UInt32 usagePage,
UInt32 usage )
{
return 0;
}
void IOHIDEventService::ejectTimerCallback(IOTimerEventSource *sender)
{
NUB_LOCK;
if ( _ejectState ) {
AbsoluteTime timeStamp;
clock_get_uptime(&timeStamp);
dispatchKeyboardEvent(timeStamp, kHIDPage_Consumer, kHIDUsage_Csmr_Eject, 1, _ejectOptions | kDelayedOption);
dispatchKeyboardEvent(timeStamp, kHIDPage_Consumer, kHIDUsage_Csmr_Eject, 0, _ejectOptions | kDelayedOption);
_ejectState = 0;
}
NUB_UNLOCK;
}
void IOHIDEventService::capsTimerCallback(IOTimerEventSource *sender)
{
NUB_LOCK;
if ( _capsState ) {
AbsoluteTime timeStamp;
clock_get_uptime(&timeStamp);
dispatchKeyboardEvent(timeStamp, kHIDPage_KeyboardOrKeypad, kHIDUsage_KeyboardCapsLock, 1, _capsOptions | kDelayedOption);
dispatchKeyboardEvent(timeStamp, kHIDPage_KeyboardOrKeypad, kHIDUsage_KeyboardCapsLock, 0, _capsOptions | kDelayedOption);
_capsState = 0;
}
NUB_UNLOCK;
}
#if TARGET_OS_EMBEDDED
void IOHIDEventService::debuggerTimerCallback(IOTimerEventSource *sender)
{
NUB_LOCK;
if ( _debuggerMask && _debuggerMask == _startDebuggerMask )
PE_enter_debugger("NMI");
NUB_UNLOCK;
}
#endif
void IOHIDEventService::dispatchKeyboardEvent(
AbsoluteTime timeStamp,
UInt32 usagePage,
UInt32 usage,
UInt32 value,
IOOptionBits options)
{
if ( ! _readyForInputReports )
return;
NUB_LOCK;
#if TARGET_OS_EMBEDDED
IOHIDEvent * event = NULL;
UInt32 debugMask = 0;
switch (usagePage) {
case kHIDPage_Consumer:
switch (usage) {
case kHIDUsage_Csmr_Power:
debugMask = 0x1;
break;
case kHIDUsage_Csmr_VolumeIncrement:
case kHIDUsage_Csmr_VolumeDecrement:
debugMask = 0x2;
break;
};
break;
case kHIDPage_Telephony:
switch (usage) {
case kHIDUsage_Tfon_Hold:
debugMask = 0x1;
break;
};
break;
};
if ( value )
_debuggerMask |= debugMask;
else
_debuggerMask &= ~debugMask;
if ( _debuggerMask == 0x3 || _debuggerMask == 0x1 ) {
if ( !_debuggerTimerEventSource ) {
_debuggerTimerEventSource = IOTimerEventSource::timerEventSource(this, OSMemberFunctionCast(IOTimerEventSource::Action, this, &IOHIDEventService::debuggerTimerCallback));
if (_debuggerTimerEventSource) {
IOWorkLoop * wl = getWorkLoop();
if (!wl || (wl->addEventSource(_debuggerTimerEventSource) != kIOReturnSuccess)) {
_debuggerTimerEventSource->release();
_debuggerTimerEventSource = NULL;
}
}
}
if ( _debuggerTimerEventSource ) {
if ( _debuggerMask == 0x3 ) {
_debuggerTimerEventSource->setTimeoutMS( kDebuggerDelayMS );
} else {
_debuggerTimerEventSource->setTimeoutMS( kDebuggerDelayPwrOnlyMS );
}
_startDebuggerMask = _debuggerMask;
}
}
event = IOHIDEvent::keyboardEvent(timeStamp, usagePage, usage, value, options);
if ( !event )
return;
dispatchEvent(event);
event->release();
#else
if ((( usagePage == kHIDPage_KeyboardOrKeypad ) &&
(usage != kHIDUsage_KeyboardLockingNumLock) &&
!(_capsDelayMS && (usage == kHIDUsage_KeyboardCapsLock))) ||
((getVendorID() == kIOUSBVendorIDAppleComputer) &&
((usagePage == kHIDPage_AppleVendorKeyboard) ||
((usagePage == kHIDPage_AppleVendorTopCase) &&
(usage == kHIDUsage_AV_TopCase_KeyboardFn)))))
{
if ( !_keyboardNub )
_keyboardNub = newKeyboardShim();
if ( _keyboardNub )
_keyboardNub->dispatchKeyboardEvent(timeStamp, usagePage, usage, (value != 0), options);
}
else
{
if ( !_consumerNub )
_consumerNub = newConsumerShim();
if ( _consumerNub ) {
if ( (usagePage == kHIDPage_Consumer) && (usage == kHIDUsage_Csmr_Eject) && ((options & kDelayedOption) == 0) && _keyboardNub && ((_keyboardNub->eventFlags() & SPECIALKEYS_MODIFIER_MASK) == 0))
{
if ( _ejectState != value ) {
if ( value ) {
_ejectOptions = options;
_ejectTimerEventSource->setTimeoutMS( _ejectDelayMS );
} else
_ejectTimerEventSource->cancelTimeout();
_ejectState = value;
}
}
else if (!(((options & kDelayedOption) == 0) && _ejectState && (usagePage == kHIDPage_Consumer) && (usage == kHIDUsage_Csmr_Eject)))
{
_consumerNub->dispatchConsumerEvent(_keyboardNub, timeStamp, usagePage, usage, value, options);
}
}
if ( _capsDelayMS && (usagePage == kHIDPage_KeyboardOrKeypad) && (usage == kHIDUsage_KeyboardCapsLock))
{
if ( (options & kDelayedOption) == 0)
{
if ( getElementValue(kHIDPage_LEDs, kHIDUsage_LED_CapsLock) == 0 ) {
if ( _capsState != value ) {
if ( value ) {
_capsOptions = options;
_capsTimerEventSource->setTimeoutMS( _capsDelayMS );
} else
_capsTimerEventSource->cancelTimeout();
_capsState = value;
}
} else {
_keyboardNub->dispatchKeyboardEvent(timeStamp, usagePage, usage, value, options);
}
}
else if (!( ((options & kDelayedOption) == 0) && _capsState ) )
{
_keyboardNub->dispatchKeyboardEvent(timeStamp, usagePage, usage, value, options);
}
}
}
#endif
NUB_UNLOCK;
}
void IOHIDEventService::dispatchRelativePointerEvent(
AbsoluteTime timeStamp,
SInt32 dx,
SInt32 dy,
UInt32 buttonState,
IOOptionBits options)
{
#if !TARGET_OS_EMBEDDED
if ( ! _readyForInputReports )
return;
NUB_LOCK;
if ( !_pointingNub )
_pointingNub = newPointingShim();
if ( _pointingNub )
_pointingNub->dispatchRelativePointerEvent(timeStamp, dx, dy, buttonState, options);
NUB_UNLOCK;
#endif
}
void IOHIDEventService::dispatchAbsolutePointerEvent(
AbsoluteTime timeStamp,
SInt32 x,
SInt32 y,
IOGBounds * bounds,
UInt32 buttonState,
bool inRange,
SInt32 tipPressure,
SInt32 tipPressureMin,
SInt32 tipPressureMax,
IOOptionBits options)
{
#if !TARGET_OS_EMBEDDED
if ( ! _readyForInputReports )
return;
NUB_LOCK;
if ( !_pointingNub )
_pointingNub = newPointingShim();
IOGPoint newLoc;
newLoc.x = x;
newLoc.y = y;
_pointingNub->dispatchAbsolutePointerEvent(timeStamp, &newLoc, bounds, buttonState, inRange, tipPressure, tipPressureMin, tipPressureMax, options);
NUB_UNLOCK;
#endif
}
void IOHIDEventService::dispatchScrollWheelEvent(
AbsoluteTime timeStamp,
SInt32 deltaAxis1,
SInt32 deltaAxis2,
SInt32 deltaAxis3,
IOOptionBits options)
{
#if !TARGET_OS_EMBEDDED
if ( ! _readyForInputReports )
return;
NUB_LOCK;
if ( !_pointingNub )
_pointingNub = newPointingShim();
if ( !_pointingNub )
return;
_pointingNub->dispatchScrollWheelEvent(timeStamp, deltaAxis1, deltaAxis2, deltaAxis3, options);
NUB_UNLOCK;
#endif
}
#if !TARGET_OS_EMBEDDED
static void ScalePressure(SInt32 *pressure, SInt32 pressureMin, SInt32 pressureMax, SInt32 systemPressureMin, SInt32 systemPressureMax)
{
SInt64 systemScale = systemPressureMax - systemPressureMin;
*pressure = ((pressureMin != pressureMax)) ?
(((unsigned)(*pressure - pressureMin) * systemScale) /
(unsigned)( pressureMax - pressureMin)) + systemPressureMin: 0;
}
#endif
void IOHIDEventService::dispatchTabletPointerEvent(
AbsoluteTime timeStamp,
UInt32 tranducerID,
SInt32 x,
SInt32 y,
SInt32 z,
IOGBounds * bounds,
UInt32 buttonState,
SInt32 tipPressure,
SInt32 tipPressureMin,
SInt32 tipPressureMax,
SInt32 barrelPressure,
SInt32 barrelPressureMin,
SInt32 barrelPressureMax,
SInt32 tiltX,
SInt32 tiltY,
UInt32 twist,
IOOptionBits options)
{
#if !TARGET_OS_EMBEDDED
if ( ! _readyForInputReports )
return;
NUB_LOCK;
if ( !_pointingNub )
_pointingNub = newPointingShim();
TransducerData * transducerRef = getTransducerData(tranducerID);
NXEventData tabletData;
if (!transducerRef) return;
bzero(&tabletData, sizeof(NXEventData));
ScalePressure(&tipPressure, tipPressureMin, tipPressureMax, 0, kMaxSystemTipPressure);
ScalePressure(&barrelPressure, barrelPressureMin, barrelPressureMax, -kMaxSystemBarrelPressure, kMaxSystemBarrelPressure);
IOGPoint newLoc;
newLoc.x = x;
newLoc.y = y;
tabletData.tablet.x = newLoc.x;
tabletData.tablet.y = newLoc.y;
tabletData.tablet.z = z;
tabletData.tablet.buttons = buttonState;
tabletData.tablet.pressure = tipPressure;
tabletData.tablet.tilt.x = tiltX;
tabletData.tablet.tilt.y = tiltY;
tabletData.tablet.rotation = twist;
tabletData.tablet.tangentialPressure = barrelPressure;
tabletData.tablet.deviceID = transducerRef->deviceID;
_pointingNub->dispatchTabletEvent(&tabletData, timeStamp);
NUB_UNLOCK;
#endif
}
void IOHIDEventService::dispatchTabletProximityEvent(
AbsoluteTime timeStamp,
UInt32 tranducerID,
bool inRange,
bool invert,
UInt32 vendorTransducerUniqueID,
UInt32 vendorTransducerSerialNumber,
IOOptionBits options)
{
#if !TARGET_OS_EMBEDDED
if ( ! _readyForInputReports )
return;
NUB_LOCK;
if ( !_pointingNub )
_pointingNub = newPointingShim();
TransducerData * transducerRef = getTransducerData(tranducerID);
NXEventData tabletData;
if (!transducerRef) return;
bzero(&tabletData, sizeof(NXEventData));
tabletData.proximity.vendorID = getVendorID();
tabletData.proximity.tabletID = getProductID();
tabletData.proximity.pointerID = tranducerID;
tabletData.proximity.deviceID = transducerRef->deviceID;
tabletData.proximity.vendorPointerType = transducerRef->type;
tabletData.proximity.pointerSerialNumber = vendorTransducerSerialNumber;
tabletData.proximity.uniqueID = vendorTransducerUniqueID;
tabletData.proximity.capabilityMask = transducerRef->capabilities;
tabletData.proximity.enterProximity = inRange;
tabletData.proximity.pointerType =
(invert && (transducerRef->type == NX_TABLET_POINTER_PEN)) ?
NX_TABLET_POINTER_ERASER : NX_TABLET_POINTER_PEN;
_pointingNub->dispatchProximityEvent(&tabletData, timeStamp);
NUB_UNLOCK;
#endif
}
#if TARGET_OS_EMBEDDED
OSDefineMetaClassAndStructors(IOHIDClientData, OSObject)
IOHIDClientData * IOHIDClientData::withClientInfo(IOService *client, void* context, void * action)
{
IOHIDClientData * data = new IOHIDClientData;
if (!data) { }
else if (data->init()) {
data->client = client;
data->context = context;
data->action = action;
} else {
data->release();
data = NULL;
}
return data;
}
OSMetaClassDefineReservedUsed(IOHIDEventService, 0);
bool IOHIDEventService::open( IOService * client,
IOOptionBits options,
void * context,
Action action)
{
IOHIDClientData * clientData =
IOHIDClientData::withClientInfo(client, context, (void*)action);
bool ret = false;
if ( clientData ) {
if ( super::open(client, options, clientData) )
ret = true;
clientData->release();
}
return ret;
}
OSMetaClassDefineReservedUsed(IOHIDEventService, 1);
void IOHIDEventService::dispatchEvent(IOHIDEvent * event, IOOptionBits options)
{
OSCollectionIterator * iterator = OSCollectionIterator::withCollection(_clientDict);
IOHIDClientData * clientData;
OSObject * clientKey;
IOService * client;
void * context;
Action action;
if ( !iterator )
return;
while ((clientKey = iterator->getNextObject())) {
clientData = OSDynamicCast(IOHIDClientData, _clientDict->getObject((const OSSymbol *)clientKey));
if ( !clientData )
continue;
client = clientData->getClient();
context = clientData->getContext();
action = (Action)clientData->getAction();
if ( action )
(*action)(client, this, context, event, options);
}
iterator->release();
}
OSMetaClassDefineReservedUsed(IOHIDEventService, 2);
UInt32 IOHIDEventService::getPrimaryUsagePage ()
{
return 0;
}
OSMetaClassDefineReservedUsed(IOHIDEventService, 3);
UInt32 IOHIDEventService::getPrimaryUsage ()
{
return 0;
}
OSMetaClassDefineReservedUsed(IOHIDEventService, 4);
UInt32 IOHIDEventService::getReportInterval()
{
return 8000;
}
OSMetaClassDefineReservedUsed(IOHIDEventService, 5);
IOHIDEvent * IOHIDEventService::copyEvent(
IOHIDEventType type,
IOHIDEvent * matching,
IOOptionBits options)
{
return NULL;
}
#else
OSMetaClassDefineReservedUnused(IOHIDEventService, 0);
OSMetaClassDefineReservedUnused(IOHIDEventService, 1);
OSMetaClassDefineReservedUnused(IOHIDEventService, 2);
OSMetaClassDefineReservedUnused(IOHIDEventService, 3);
OSMetaClassDefineReservedUnused(IOHIDEventService, 4);
OSMetaClassDefineReservedUnused(IOHIDEventService, 5);
#endif
OSMetaClassDefineReservedUnused(IOHIDEventService, 6);
OSMetaClassDefineReservedUnused(IOHIDEventService, 7);
OSMetaClassDefineReservedUnused(IOHIDEventService, 8);
OSMetaClassDefineReservedUnused(IOHIDEventService, 9);
OSMetaClassDefineReservedUnused(IOHIDEventService, 10);
OSMetaClassDefineReservedUnused(IOHIDEventService, 11);
OSMetaClassDefineReservedUnused(IOHIDEventService, 12);
OSMetaClassDefineReservedUnused(IOHIDEventService, 13);
OSMetaClassDefineReservedUnused(IOHIDEventService, 14);
OSMetaClassDefineReservedUnused(IOHIDEventService, 15);
OSMetaClassDefineReservedUnused(IOHIDEventService, 16);
OSMetaClassDefineReservedUnused(IOHIDEventService, 17);
OSMetaClassDefineReservedUnused(IOHIDEventService, 18);
OSMetaClassDefineReservedUnused(IOHIDEventService, 19);
OSMetaClassDefineReservedUnused(IOHIDEventService, 20);
OSMetaClassDefineReservedUnused(IOHIDEventService, 21);
OSMetaClassDefineReservedUnused(IOHIDEventService, 22);
OSMetaClassDefineReservedUnused(IOHIDEventService, 23);
OSMetaClassDefineReservedUnused(IOHIDEventService, 24);
OSMetaClassDefineReservedUnused(IOHIDEventService, 25);
OSMetaClassDefineReservedUnused(IOHIDEventService, 26);
OSMetaClassDefineReservedUnused(IOHIDEventService, 27);
OSMetaClassDefineReservedUnused(IOHIDEventService, 28);
OSMetaClassDefineReservedUnused(IOHIDEventService, 29);
OSMetaClassDefineReservedUnused(IOHIDEventService, 30);
OSMetaClassDefineReservedUnused(IOHIDEventService, 31);