#include "I2CUserClientPrivate.h"
#define super IOUserClient
OSDefineMetaClassAndStructors(I2CUserClient, IOUserClient)
IOExternalMethod *
I2CUserClient::getTargetAndMethodForIndex(IOService **target, UInt32 index)
{
DLOG("I2CUserClient::getTargetAndMethodForIndex (index=%lu)\n", index);
static const IOExternalMethod sMethods[kI2CUCNumMethods] =
{
{ NULL, (IOMethod) &I2CUserClient::userClientOpen,
kIOUCScalarIScalarO,
0, 0 },
{ NULL, (IOMethod) &I2CUserClient::userClientClose,
kIOUCScalarIScalarO,
0, 0 },
{ NULL, (IOMethod) &I2CUserClient::read,
kIOUCStructIStructO,
sizeof(I2CReadInput),
sizeof(I2CReadOutput)
},
{ NULL, (IOMethod) &I2CUserClient::write,
kIOUCStructIStructO,
sizeof(I2CWriteInput),
sizeof(I2CWriteOutput)
},
{ NULL, (IOMethod) &I2CUserClient::rmw,
kIOUCStructIStructO,
sizeof(I2CRMWInput),
0
}
};
if (index < (UInt32)kI2CUCNumMethods)
{
*target = this;
return((IOExternalMethod *) &sMethods[index]);
}
else
{
*target = NULL;
return(NULL);
}
}
bool I2CUserClient::start(IOService *provider)
{
DLOG("+I2CUserClient::start provider=%08lx\n", (UInt32)provider);
if (!super::start(provider)) return(false);
fProvider = OSDynamicCast(PPCI2CInterface, provider);
if (!fProvider)
{
DLOG("-I2CUserClient::start provider is not a PPCI2CInterface\n");
return(false);
}
fIsOpenLock = IOLockAlloc();
if (!fIsOpenLock)
{
DLOG("-I2CUserClient::start failed to allocate lock\n");
return(false);
}
return(true);
}
void I2CUserClient::stop(IOService *provider)
{
DLOG("+I2CUserClient::stop\n");
IOLockFree(fIsOpenLock);
super::stop(provider);
}
bool I2CUserClient::init(OSDictionary *dict)
{
DLOG("+I2CUserClient::init\n");
return(super::init(dict));
}
bool I2CUserClient::attach(IOService *provider)
{
DLOG("+I2CUserClient::attach\n");
return(super::attach(provider));
}
void I2CUserClient::detach(IOService *provider)
{
DLOG("+I2CUserClient::detach\n");
super::detach(provider);
}
bool I2CUserClient::initWithTask(task_t owningTask,
void *security_id, UInt32 type)
{
DLOG("+I2CUserClient::initWithTask\n");
if (clientHasPrivilege(security_id, kIOClientPrivilegeAdministrator)
!= kIOReturnSuccess)
{
DLOG("-I2CUserClient::initWithTask client is not root!\n");
return(false);
}
if ((!super::initWithTask(owningTask, security_id, type)) ||
(!owningTask))
{
DLOG("-I2CUserClient::initWithTask failed to init\n");
return(false);
}
fOwningTask = owningTask;
fIsOpen = false;
fIsOpenLock = NULL;
return(true);
}
IOReturn I2CUserClient::clientClose(void)
{
DLOG("+I2CUserClient::clientClose\n");
terminate();
return(kIOReturnSuccess);
}
IOReturn I2CUserClient::userClientOpen(void)
{
IOReturn ret = kIOReturnSuccess;
DLOG("+I2CUserClient::userClientOpen\n");
if (fIsOpen)
{
return(kIOReturnError);
}
IOLockLock(fIsOpenLock);
if (!fIsOpen)
{
fIsOpen = true;
ret = kIOReturnSuccess;
}
else
{
ret = kIOReturnError;
}
IOLockUnlock(fIsOpenLock);
return(ret);
}
IOReturn I2CUserClient::userClientClose(void)
{
IOReturn ret = kIOReturnSuccess;
DLOG("+I2CUserClient::userClientClose\n");
if (!fIsOpen)
{
return(kIOReturnError);
}
IOLockLock(fIsOpenLock);
if (fIsOpen)
{
fIsOpen = false;
ret = kIOReturnSuccess;
}
else
{
ret = kIOReturnError;
}
IOLockUnlock(fIsOpenLock);
return(ret);
}
IOReturn I2CUserClient::read( void *inStruct, void *outStruct,
void *inCount, void *outCount, void *p5, void *p6)
{
IOByteCount inputSize, *outputSizeP;
I2CReadInput *input;
I2CReadOutput *output;
UInt16 byteCount;
UInt8 sevenBitAddr;
int retries;
DLOG("+I2CUserClient::read\n");
if (!fIsOpen) return(kIOReturnNotReady);
input = (I2CReadInput *)inStruct;
inputSize = (IOByteCount)inCount;
output = (I2CReadOutput *)outStruct;
outputSizeP = (IOByteCount *)outCount;
if (!(fProvider && input && inputSize && output && outputSizeP) ||
(inputSize != sizeof(I2CReadInput)) ||
(*outputSizeP != sizeof(I2CReadOutput)) ||
(input->count > kI2CUCBufSize))
{
DLOG("-I2CUserClient::read got invalid arguments\n");
return(kIOReturnBadArgument);
}
if (!fProvider->openI2CBus(input->busNo))
{
DLOG("-I2CUserClient::read failed to open I2C bus\n");
return(kIOReturnError);
}
switch (input->mode)
{
case kI2CUCDumbMode:
fProvider->setDumbMode();
fProvider->setPollingMode(true);
break;
case kI2CUCStandardMode:
fProvider->setStandardMode();
fProvider->setPollingMode(true);
break;
case kI2CUCStandardSubMode:
fProvider->setStandardSubMode();
fProvider->setPollingMode(true);
break;
case kI2CUCCombinedMode:
fProvider->setCombinedMode();
fProvider->setPollingMode(true);
break;
case kI2CUCDumbIntMode:
fProvider->setDumbMode();
fProvider->setPollingMode(false); break;
case kI2CUCStandardIntMode:
fProvider->setStandardMode();
fProvider->setPollingMode(false); break;
case kI2CUCStandardSubIntMode:
fProvider->setStandardSubMode();
fProvider->setPollingMode(false); break;
case kI2CUCCombinedIntMode:
fProvider->setCombinedMode();
fProvider->setPollingMode(false); break;
default:
fProvider->closeI2CBus();
DLOG("-I2CUserClient::read got invalid transfer mode\n");
return(kIOReturnBadArgument);;;
}
byteCount = input->count; sevenBitAddr = input->addr >> 1;
retries = 1;
while (!fProvider->readI2CBus(sevenBitAddr, input->subAddr, output->buf, byteCount))
{
if (retries > 0)
{
IOLog("I2CUserClient::read read failed, retrying...\n");
retries--;
}
else
{
fProvider->closeI2CBus();
IOLog("I2CUserClient::read cannot read from I2C!!\n");
output->realCount = 0;
return(kIOReturnError);
}
}
fProvider->closeI2CBus();
output->realCount = input->count;
return(kIOReturnSuccess);
}
IOReturn I2CUserClient::write( void *inStruct, void *outStruct,
void *inCount, void *outCount, void *p5, void *p6)
{
IOByteCount inputSize, *outputSizeP;
I2CWriteInput *input;
I2CWriteOutput *output;
UInt16 byteCount;
UInt8 sevenBitAddr;
int retries;
DLOG("+I2CUserClient::write\n");
if (!fIsOpen) return(kIOReturnNotReady);
input = (I2CWriteInput *)inStruct;
inputSize = (IOByteCount)inCount;
output = (I2CWriteOutput *)outStruct;
outputSizeP = (IOByteCount *)outCount;
if (!(fProvider && input && inputSize && output && outputSizeP) ||
(inputSize != sizeof(I2CWriteInput)) ||
(*outputSizeP != sizeof(I2CWriteOutput)))
{
DLOG("-I2CUserClient::write got invalid arguments\n");
return(kIOReturnBadArgument);
}
if (!fProvider->openI2CBus(input->busNo))
{
DLOG("-I2CUserClient::write failed to open I2C bus\n");
return(kIOReturnError);
}
switch (input->mode)
{
case kI2CUCDumbMode:
fProvider->setDumbMode();
fProvider->setPollingMode(true);
break;
case kI2CUCStandardMode:
fProvider->setStandardMode();
fProvider->setPollingMode(true);
break;
case kI2CUCStandardSubMode:
fProvider->setStandardSubMode();
fProvider->setPollingMode(true);
break;
case kI2CUCCombinedMode:
fProvider->setCombinedMode();
fProvider->setPollingMode(true);
break;
case kI2CUCDumbIntMode:
fProvider->setDumbMode();
fProvider->setPollingMode(false); break;
case kI2CUCStandardIntMode:
fProvider->setStandardMode();
fProvider->setPollingMode(false); break;
case kI2CUCStandardSubIntMode:
fProvider->setStandardSubMode();
fProvider->setPollingMode(false); break;
case kI2CUCCombinedIntMode:
fProvider->setCombinedMode();
fProvider->setPollingMode(false); break;
default:
fProvider->closeI2CBus();
DLOG("-I2CUserClient::write got invalid transfer mode\n");
return(kIOReturnBadArgument);;;
}
byteCount = input->count; sevenBitAddr = input->addr >> 1;
retries = 1;
while (!fProvider->writeI2CBus(sevenBitAddr, input->subAddr, input->buf, byteCount))
{
if (retries > 0)
{
IOLog("I2CUserClient::write write failed, retrying...\n");
retries--;
}
else
{
fProvider->closeI2CBus();
IOLog("I2CUserClient::write cannot write to I2C!!\n");
output->realCount = 0;
return(kIOReturnError);
}
}
fProvider->closeI2CBus();
output->realCount = input->count;
return(kIOReturnSuccess);
}
IOReturn I2CUserClient::rmw( void *inStruct, void *inCount,
void *p3, void *p4, void *p5, void *p6)
{
IOByteCount inputSize;
I2CRMWInput *input;
UInt8 sevenBitAddr, newByte;
int retries;
DLOG("+I2CUserClient::rmw\n");
if (!fIsOpen) return(kIOReturnNotReady);
input = (I2CRMWInput *)inStruct;
inputSize = (IOByteCount)inCount;
if (!(fProvider && input && inputSize) ||
(inputSize != sizeof(I2CRMWInput)))
{
DLOG("-I2CUserClient::rmw got invalid arguments\n");
return(kIOReturnBadArgument);
}
if (!fProvider->openI2CBus(input->busNo))
{
DLOG("-I2CUserClient::rmw failed to open I2C bus\n");
return(kIOReturnError);
}
sevenBitAddr = input->addr >> 1;
switch (input->readMode)
{
case kI2CUCDumbMode:
fProvider->setDumbMode();
fProvider->setPollingMode(true);
break;
case kI2CUCStandardMode:
fProvider->setStandardMode();
fProvider->setPollingMode(true);
break;
case kI2CUCStandardSubMode:
fProvider->setStandardSubMode();
fProvider->setPollingMode(true);
break;
case kI2CUCCombinedMode:
fProvider->setCombinedMode();
fProvider->setPollingMode(true);
break;
case kI2CUCDumbIntMode:
fProvider->setDumbMode();
fProvider->setPollingMode(false); break;
case kI2CUCStandardIntMode:
fProvider->setStandardMode();
fProvider->setPollingMode(false); break;
case kI2CUCStandardSubIntMode:
fProvider->setStandardSubMode();
fProvider->setPollingMode(false); break;
case kI2CUCCombinedIntMode:
fProvider->setCombinedMode();
fProvider->setPollingMode(false); break;
default:
fProvider->closeI2CBus();
DLOG("-I2CUserClient::rmw got invalid read transfer mode\n");
return(kIOReturnBadArgument);
}
retries = 1;
while (!fProvider->readI2CBus(sevenBitAddr, input->subAddr, &newByte, 1))
{
if (retries > 0)
{
IOLog("I2CUserClient::rmw read failed, retrying...\n");
retries--;
}
else
{
fProvider->closeI2CBus();
IOLog("I2CUserClient::rmw cannot read from I2C!!\n");
return(kIOReturnError);
}
}
newByte = (newByte & ~input->mask) | (input->value & input->mask);
switch (input->writeMode)
{
case kI2CUCDumbMode:
fProvider->setDumbMode();
fProvider->setPollingMode(true);
break;
case kI2CUCStandardMode:
fProvider->setStandardMode();
fProvider->setPollingMode(true);
break;
case kI2CUCStandardSubMode:
fProvider->setStandardSubMode();
fProvider->setPollingMode(true);
break;
case kI2CUCCombinedMode:
fProvider->setCombinedMode();
fProvider->setPollingMode(true);
break;
case kI2CUCDumbIntMode:
fProvider->setDumbMode();
fProvider->setPollingMode(false); break;
case kI2CUCStandardIntMode:
fProvider->setStandardMode();
fProvider->setPollingMode(false); break;
case kI2CUCStandardSubIntMode:
fProvider->setStandardSubMode();
fProvider->setPollingMode(false); break;
case kI2CUCCombinedIntMode:
fProvider->setCombinedMode();
fProvider->setPollingMode(false); break;
default:
fProvider->closeI2CBus();
DLOG("-I2CUserClient::rmw got invalid write transfer mode\n");
return(kIOReturnBadArgument);;;
}
retries = 1;
while (!fProvider->writeI2CBus(sevenBitAddr, input->subAddr, &newByte, 1))
{
if (retries > 0)
{
IOLog("I2CUserClient::rmw write failed, retrying...\n");
retries--;
}
else
{
fProvider->closeI2CBus();
IOLog("I2CUserClient::rmw cannot write to I2C!!\n");
return(kIOReturnError);
}
}
fProvider->closeI2CBus();
return(kIOReturnSuccess);
}