IOHIDResourceUserClient.cpp [plain text]
#include "IOHIDResourceUserClient.h"
#include <IOKit/IOLib.h>
#define super IOUserClient
OSDefineMetaClassAndStructors( IOHIDResourceDeviceUserClient, super )
const IOExternalMethodDispatch IOHIDResourceDeviceUserClient::_methods[kIOHIDResourceDeviceUserClientMethodCount] = {
{ (IOExternalMethodAction) &IOHIDResourceDeviceUserClient::_createDevice,
0, -1,
0, 0
},
{ (IOExternalMethodAction) &IOHIDResourceDeviceUserClient::_terminateDevice,
0, 0,
0, 0
},
{ (IOExternalMethodAction) &IOHIDResourceDeviceUserClient::_handleReport,
0, -1,
0, 0
}
};
#pragma mark -
#pragma mark Methods
bool IOHIDResourceDeviceUserClient::initWithTask(task_t owningTask, void * security_id, UInt32 type)
{
if (!super::initWithTask(owningTask, security_id, type)) {
IOLog("%s failed\n", __FUNCTION__);
return false;
}
_device = NULL;
return true;
}
bool IOHIDResourceDeviceUserClient::start(IOService * provider)
{
if (!super::start(provider)) {
IOLog("%s failed\n", __FUNCTION__);
return false;
}
_owner = (IOHIDResource *) provider;
_device = NULL;
return true;
}
IOReturn IOHIDResourceDeviceUserClient::externalMethod(
uint32_t selector,
IOExternalMethodArguments * arguments,
IOExternalMethodDispatch * dispatch,
OSObject * target,
void * reference)
{
if (selector < (uint32_t) kIOHIDResourceDeviceUserClientMethodCount)
{
dispatch = (IOExternalMethodDispatch *) &_methods[selector];
if (!target)
target = this;
}
return super::externalMethod(selector, arguments, dispatch, target, reference);
}
IOMemoryDescriptor * IOHIDResourceDeviceUserClient::createMemoryDescriptorFromInputArguments(
IOExternalMethodArguments * arguments)
{
IOMemoryDescriptor * report = NULL;
if ( arguments->structureInputDescriptor ) {
report = arguments->structureInputDescriptor;
report->retain();
} else {
report = IOMemoryDescriptor::withAddress((void *)arguments->structureInput, arguments->structureInputSize, kIODirectionOut);
}
return report;
}
IOService *IOHIDResourceDeviceUserClient::getService(void)
{
return _owner;
}
IOReturn IOHIDResourceDeviceUserClient::clientClose(void)
{
terminateDevice();
terminate();
return kIOReturnSuccess;
}
#pragma mark -
#pragma mark Private functions (Driver communication)
IOReturn IOHIDResourceDeviceUserClient::createDevice(
IOHIDResourceDeviceUserClient * target,
void * reference,
IOExternalMethodArguments * arguments)
{
if (_device == NULL) {
IOReturn ret;
IOMemoryDescriptor * propertiesDesc = NULL;
OSDictionary * properties = NULL;
propertiesDesc = createMemoryDescriptorFromInputArguments(arguments);
if ( !propertiesDesc ) {
IOLog("%s failed : could not create descriptor\n", __FUNCTION__);
return kIOReturnNoMemory;
}
ret = propertiesDesc->prepare();
if ( ret == kIOReturnSuccess ) {
void * propertiesData;
IOByteCount propertiesLength;
propertiesLength = propertiesDesc->getLength();
if ( propertiesLength ) {
propertiesData = IOMalloc(propertiesLength);
if ( propertiesData ) {
OSObject * object;
propertiesDesc->readBytes(0, propertiesData, propertiesLength);
object = OSUnserializeXML((const char *)propertiesData);
properties = OSDynamicCast(OSDictionary, object);
if( !properties )
object->release();
IOFree(propertiesData, propertiesLength);
}
}
propertiesDesc->complete();
}
propertiesDesc->release();
if ( properties ) {
_device = IOHIDUserDevice::withProperties(properties);
properties->release();
}
} else {
IOLog("%s failed : _device already exists\n", __FUNCTION__);
return kIOReturnInternalError;
}
if (_device == NULL) {
IOLog("%s failed : _device is NULL\n", __FUNCTION__);
return kIOReturnNoResources;
}
if (!_device->attach(this) || !_device->start(this)) {
IOLog("%s attach or start failed\n", __FUNCTION__);
_device->release();
_device = NULL;
return kIOReturnInternalError;
}
return kIOReturnSuccess;
}
IOReturn IOHIDResourceDeviceUserClient::_createDevice(
IOHIDResourceDeviceUserClient * target,
void * reference,
IOExternalMethodArguments * arguments)
{
return target->createDevice(target, reference, arguments);
}
IOReturn IOHIDResourceDeviceUserClient::handleReport(
IOHIDResourceDeviceUserClient * target,
void * reference,
IOExternalMethodArguments * arguments)
{
if (_device == NULL) {
IOLog("%s failed : device is NULL\n", __FUNCTION__);
return kIOReturnNotOpen;
}
if (target != this) {
IOLog("%s failed : this is not target\n", __FUNCTION__);
return kIOReturnInternalError;
}
IOReturn ret;
IOMemoryDescriptor * report;
report = createMemoryDescriptorFromInputArguments(arguments);
if ( !report ) {
IOLog("%s failed : could not create descriptor\n", __FUNCTION__);
return kIOReturnNoMemory;
}
ret = report->prepare();
if ( ret == kIOReturnSuccess ) {
ret = _device->handleReport(report);
report->complete();
}
report->release();
return ret;
}
IOReturn IOHIDResourceDeviceUserClient::_handleReport(IOHIDResourceDeviceUserClient *target,
void *reference,
IOExternalMethodArguments *arguments)
{
return target->handleReport(target, reference, arguments);
}
IOReturn IOHIDResourceDeviceUserClient::terminateDevice()
{
if (_device) {
_device->stop(this);
_device->release();
}
_device = NULL;
return kIOReturnSuccess;
}
IOReturn IOHIDResourceDeviceUserClient::_terminateDevice(
IOHIDResourceDeviceUserClient *target,
void *reference,
IOExternalMethodArguments *arguments)
{
return target->terminateDevice();
}