IOHIDEventServiceUserClient.cpp [plain text]
#include "IOHIDEventServiceUserClient.h"
#include "IOHIDEventServiceQueue.h"
#include "IOHIDEventData.h"
#include "IOHIDEvent.h"
#define super IOUserClient
OSDefineMetaClassAndStructors( IOHIDEventServiceUserClient, super )
const IOExternalMethodDispatch IOHIDEventServiceUserClient::sMethods[kIOHIDEventServiceUserClientNumCommands] = {
{ (IOExternalMethodAction) &IOHIDEventServiceUserClient::_open,
1, 0,
0, 0
},
{ (IOExternalMethodAction) &IOHIDEventServiceUserClient::_close,
1, 0,
0, 0
},
{ (IOExternalMethodAction) &IOHIDEventServiceUserClient::_copyEvent,
2, -1,
0, -1
}
};
IOService * IOHIDEventServiceUserClient::getService( void )
{
return _owner;
}
IOReturn IOHIDEventServiceUserClient::clientClose( void )
{
if (_client) {
task_deallocate(_client);
_client = 0;
}
if (_owner) {
_owner->close(this, _options);
detach(_owner);
}
return kIOReturnSuccess;
}
IOReturn IOHIDEventServiceUserClient::registerNotificationPort(
mach_port_t port,
UInt32 type,
UInt32 refCon )
{
_queue->setNotificationPort(port);
return kIOReturnSuccess;
}
IOReturn IOHIDEventServiceUserClient::clientMemoryForType(
UInt32 type,
IOOptionBits * options,
IOMemoryDescriptor ** memory )
{
IOReturn ret = kIOReturnNoMemory;
if ( _queue ) {
IOMemoryDescriptor * memoryToShare = _queue->getMemoryDescriptor();
if (memoryToShare)
{
memoryToShare->retain();
ret = kIOReturnSuccess;
}
*options = 0;
*memory = memoryToShare;
}
return ret;
}
typedef struct HIDCommandGateArgs {
uint32_t selector;
IOExternalMethodArguments * arguments;
IOExternalMethodDispatch * dispatch;
OSObject * target;
void * reference;
}HIDCommandGateArgs;
IOReturn IOHIDEventServiceUserClient::externalMethod(
uint32_t selector,
IOExternalMethodArguments * arguments,
IOExternalMethodDispatch * dispatch,
OSObject * target,
void * reference)
{
if (selector < (uint32_t) kIOHIDEventServiceUserClientNumCommands)
{
dispatch = (IOExternalMethodDispatch *) &sMethods[selector];
if (!target)
target = this;
}
return super::externalMethod(selector, arguments, dispatch, target, reference);
}
bool IOHIDEventServiceUserClient::initWithTask(task_t owningTask, void * security_id, UInt32 type)
{
if (!super::init())
return false;
_client = owningTask;
task_reference (_client);
_queue = IOHIDEventServiceQueue::withCapacity(1024);
if ( !_queue )
return false;
return true;
}
bool IOHIDEventServiceUserClient::start( IOService * provider )
{
if ( !super::start(provider) )
return false;
_owner = OSDynamicCast(IOHIDEventService, provider);
if ( !_owner )
return false;
return true;
}
IOReturn IOHIDEventServiceUserClient::_open(
IOHIDEventServiceUserClient * target,
void * reference,
IOExternalMethodArguments * arguments)
{
return target->open((IOOptionBits)arguments->scalarInput[0]);
}
IOReturn IOHIDEventServiceUserClient::open(IOOptionBits options)
{
_queue->setState(true);
_options = options;
if (!_owner->open( this,
options,
NULL,
OSMemberFunctionCast(IOHIDEventService::Action,
this, &IOHIDEventServiceUserClient::eventServiceCallback)) ) {
_queue->setState(false);
return kIOReturnExclusiveAccess;
}
return kIOReturnSuccess;
}
IOReturn IOHIDEventServiceUserClient::_close(
IOHIDEventServiceUserClient * target,
void * reference,
IOExternalMethodArguments * arguments)
{
return target->close();
}
IOReturn IOHIDEventServiceUserClient::close()
{
_queue->setState(false);
_owner->close(this, _options);
return kIOReturnSuccess;
}
IOReturn IOHIDEventServiceUserClient::_copyEvent(
IOHIDEventServiceUserClient * target,
void * reference,
IOExternalMethodArguments * arguments)
{
IOHIDEvent * inEvent = NULL;
IOHIDEvent * outEvent = NULL;
IOReturn ret = kIOReturnError;
IOByteCount length = 0;
if ( arguments->structureInput && arguments->structureInputSize)
inEvent = IOHIDEvent::withBytes(arguments->structureInput, arguments->structureInputSize);
do {
outEvent = target->copyEvent(arguments->scalarInput[0], inEvent, arguments->scalarInput[1]);
if ( !outEvent )
break;
length = outEvent->getLength();
if ( length > arguments->structureOutputSize ) {
ret = kIOReturnBadArgument;
break;
}
outEvent->readBytes(arguments->structureOutput, length);
arguments->structureOutputSize = length;
ret = kIOReturnSuccess;
} while ( 0 );
if ( inEvent )
inEvent->release();
if ( outEvent )
outEvent->release();
return ret;
}
IOHIDEvent * IOHIDEventServiceUserClient::copyEvent(IOHIDEventType type, IOHIDEvent * matching, IOOptionBits options)
{
return _owner->copyEvent(type, matching, options);
}
bool IOHIDEventServiceUserClient::didTerminate(IOService *provider, IOOptionBits options, bool *defer)
{
_owner->close(this, _options);
return super::didTerminate(provider, options, defer);
}
void IOHIDEventServiceUserClient::free()
{
if (_queue) {
_queue->release();
_queue = 0;
}
if (_owner) {
_owner = 0;
}
super::free();
}
IOReturn IOHIDEventServiceUserClient::setProperties( OSObject * properties )
{
return _owner->setProperties(properties);
}
void IOHIDEventServiceUserClient::eventServiceCallback(
IOHIDEventService * sender,
void * context,
IOHIDEvent * event,
IOOptionBits options)
{
if (!_queue || !_queue->getState())
return;
_queue->enqueueEvent(event);
}