IOPlatformFunction.cpp [plain text]
#include "IOPlatformFunction.h"
#define super OSObject
OSDefineMetaClassAndStructors(IOPlatformFunction, OSObject);
bool IOPlatformFunction::initWithPlatformDoFunction(OSSymbol *functionName, OSData *functionData,
OSData **moreFunctionData)
{
char tmpFunctionName[128], *tmpNamePtr, *funcNamePtr;
UInt32 *moreData;
UInt32 totalLen, result;
if (!super::init() || !functionName || !functionData)
return false;
platformFunctionData = functionData;
platformFunctionPtr = (UInt32 *)functionData->getBytesNoCopy();
platformFunctionDataLen = functionData->getLength();
iterator = IOPlatformFunctionIterator::withIOPlatformFunction (this);
if (!iterator)
return false;
moreData = iterator->scanCommand (platformFunctionPtr, platformFunctionDataLen, &totalLen,
&flags, &pHandle, &result);
if (result != kIOPFNoError) {
iterator->release();
return false;
}
if (moreData) {
*moreFunctionData = OSData::withBytes (moreData, (platformFunctionDataLen - totalLen));
platformFunctionDataLen = totalLen; } else {
*moreFunctionData = NULL;
}
platformFunctionData->retain();
if (flags & (kIOPFFlagOnDemand | kIOPFFlagIntGen)) {
*tmpFunctionName = '\0';
tmpNamePtr = tmpFunctionName;
funcNamePtr = (char *)functionName->getCStringNoCopy();
while (*funcNamePtr != '-') *(tmpNamePtr++) = *(funcNamePtr++);
funcNamePtr += 3; while (*funcNamePtr) *(tmpNamePtr++) = *(funcNamePtr++);
sprintf (tmpNamePtr, "-%08lx", pHandle); platformFunctionSymbol = OSSymbol::withCString(tmpFunctionName);
DLOG ("IOPF::initWithPlatformDoFunction(%lx) - creating platformFunctionSymbol '%s'\n", this, tmpFunctionName);
} else
platformFunctionSymbol = NULL;
return true;
}
IOPlatformFunction *IOPlatformFunction::withPlatformDoFunction(OSSymbol *functionName, OSData *functionData,
OSData **moreFunctionData)
{
IOPlatformFunction *me = new IOPlatformFunction;
if (me && !me->initWithPlatformDoFunction(functionName, functionData, moreFunctionData)) {
me->free();
return NULL;
}
return me;
}
void IOPlatformFunction::free()
{
if (iterator) {
iterator->release();
iterator = NULL;
}
if (platformFunctionSymbol) {
platformFunctionSymbol->release();
platformFunctionSymbol = NULL;
}
if (platformFunctionData) {
platformFunctionData->release();
platformFunctionData = NULL;
}
super::free();
}
bool IOPlatformFunction::validatePlatformFunction(UInt32 flagsMask, UInt32 pHandleValue)
{
if (pHandleValue && (pHandle != pHandleValue))
return false;
return ((flags & flagsMask) != 0);
}
bool IOPlatformFunction::platformFunctionMatch(const OSSymbol *funcSym, UInt32 flagsMask, UInt32 pHandleValue)
{
return (platformFunctionSymbol->isEqualTo(funcSym) && validatePlatformFunction (flagsMask, pHandleValue));
}
const OSSymbol *IOPlatformFunction::getPlatformFunctionName() const
{
return platformFunctionSymbol;
}
UInt32 IOPlatformFunction::getCommandFlags() const
{
return flags;
}
UInt32 IOPlatformFunction::getCommandPHandle() const
{
return pHandle;
}
IOPlatformFunctionIterator *IOPlatformFunction::getCommandIterator()
{
if (iterator) {
iterator->retain();
iterator->reset();
}
return iterator;
}
void IOPlatformFunction::publishPlatformFunction(IOService *handler)
{
if (platformFunctionSymbol)
handler->publishResource(platformFunctionSymbol, handler);
return;
}
OSMetaClassDefineReservedUnused(IOPlatformFunction, 0);
OSMetaClassDefineReservedUnused(IOPlatformFunction, 1);
OSMetaClassDefineReservedUnused(IOPlatformFunction, 2);
OSMetaClassDefineReservedUnused(IOPlatformFunction, 3);
OSMetaClassDefineReservedUnused(IOPlatformFunction, 4);
OSMetaClassDefineReservedUnused(IOPlatformFunction, 5);
OSMetaClassDefineReservedUnused(IOPlatformFunction, 6);
OSMetaClassDefineReservedUnused(IOPlatformFunction, 7);
OSMetaClassDefineReservedUnused(IOPlatformFunction, 8);
OSMetaClassDefineReservedUnused(IOPlatformFunction, 9);
#undef super
#define super OSIterator
OSDefineMetaClassAndStructors(IOPlatformFunctionIterator, OSIterator);
IOPlatformFunctionIterator *IOPlatformFunctionIterator::withIOPlatformFunction(const IOPlatformFunction *inFunc)
{
IOPlatformFunctionIterator *me = new IOPlatformFunctionIterator;
if (me && !me->initWithIOPlatformFunction(inFunc)) {
me->free();
return 0;
}
return me;
}
bool IOPlatformFunctionIterator::initWithIOPlatformFunction(const IOPlatformFunction *inFunc)
{
if (!inFunc)
return false;
platformFunction = inFunc;
commandPtr = NULL;
totalCommandCount = 0;
currentCommandCount = 0;
isCommandList = false;
valid = true;
return true;
}
void IOPlatformFunctionIterator::free()
{
valid = false;
super::free();
return;
}
void IOPlatformFunctionIterator::reset()
{
commandPtr = platformFunction->platformFunctionPtr;
dataLengthRemaining = platformFunction->platformFunctionDataLen;
commandDone = false;
totalCommandCount = currentCommandCount = 0;
return;
}
bool IOPlatformFunctionIterator::isValid()
{
return valid;
}
OSObject *IOPlatformFunctionIterator::getNextObject()
{
return NULL;
}
bool IOPlatformFunctionIterator::getNextCommand(UInt32 *cmd, UInt32 *cmdLen,
UInt32 *param1, UInt32 *param2, UInt32 *param3, UInt32 *param4,
UInt32 *param5, UInt32 *param6, UInt32 *param7, UInt32 *param8,
UInt32 *param9, UInt32 *param10, UInt32 *result)
{
if (commandDone) {
*result = kIOPFNoError;
return false;
}
if (commandPtr == platformFunction->platformFunctionPtr) {
commandPtr += 2; dataLengthRemaining -= 2 * sizeof(UInt32);
if (isCommandList) {
commandPtr = scanSubCommand (commandPtr, dataLengthRemaining, true, cmd, cmdLen, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, result);
dataLengthRemaining -= *cmdLen;
}
}
commandPtr = scanSubCommand (commandPtr, dataLengthRemaining, false, cmd, cmdLen, param1, param2, param3, param4, param5,
param6, param7, param8, param9, param10, result);
if (*result != kIOPFNoError)
return false;
dataLengthRemaining -= *cmdLen;
commandDone = (commandPtr == NULL);
DLOG ("IOPFI::getNextCommand(%lx) - cmd %ld, dataLenRemaining %ld, cmdLen %ld, commandPtr 0x%lx\n",
this, *cmd, dataLengthRemaining, *cmdLen, commandPtr);
return true;
}
UInt32 *IOPlatformFunctionIterator::scanSubCommand (UInt32 *cmdPtr, UInt32 lenRemaining,
bool quickScan, UInt32 *cmd, UInt32 *cmdLen,
UInt32 *param1, UInt32 *param2, UInt32 *param3, UInt32 *param4,
UInt32 *param5, UInt32 *param6, UInt32 *param7, UInt32 *param8,
UInt32 *param9, UInt32 *param10, UInt32 *result)
{
UInt32 cmdLongLen, tmpLen, maskLen, arrayLen, offset, paramsUsed;
DLOG ("IOPFI::scanSubCommand(%lx) - entered\n", this);
*result = kIOPFNoError;
*cmd = *(cmdPtr++); cmdLongLen = 1;
if (*cmd == kCommandCommandList) {
isCommandList = true;
totalCommandCount = *(cmdPtr++);
DLOG ("IOPFI::scanSubCommand(%lx) - got commandList, totalCmdCount %ld\n", this, totalCommandCount);
cmdLongLen += kCommandCommandListLength;
*cmdLen = cmdLongLen * sizeof(UInt32);
if (*cmdLen > lenRemaining)
*result = kIOPFBadCmdLength; else
paramsUsed = 0;
} else {
DLOG ("IOPFI::scanSubCommand(%lx) - parsing command %ld\n", this, *cmd);
switch (*cmd) {
case kCommandWriteGPIO:
cmdLongLen += kCommandWriteGPIOLength;
break;
case kCommandReadGPIO:
cmdLongLen += kCommandReadGPIOLength;
break;
case kCommandWriteReg32:
cmdLongLen += kCommandWriteReg32Length;
break;
case kCommandReadReg32:
cmdLongLen += kCommandReadReg32Length;
break;
case kCommandWriteReg16:
cmdLongLen += kCommandWriteReg16Length;
break;
case kCommandReadReg16:
cmdLongLen += kCommandReadReg16Length;
break;
case kCommandWriteReg8:
cmdLongLen += kCommandWriteReg8Length;
break;
case kCommandReadReg8:
cmdLongLen += kCommandReadReg8Length;
break;
case kCommandDelay:
cmdLongLen += kCommandDelayLength;
break;
case kCommandWaitReg32:
cmdLongLen += kCommandWaitReg32Length;
break;
case kCommandWaitReg16:
cmdLongLen += kCommandWaitReg16Length;
break;
case kCommandWaitReg8:
cmdLongLen += kCommandWaitReg8Length;
break;
case kCommandReadI2C:
cmdLongLen += kCommandReadI2CLength;
break;
case kCommandGeneralI2C:
cmdLongLen += kCommandGeneralI2CLength;
break;
case kCommandShiftBytesRight:
cmdLongLen += kCommandShiftBytesRightLength;
break;
case kCommandShiftBytesLeft:
cmdLongLen += kCommandShiftBytesLeftLength;
break;
case kCommandReadConfig:
cmdLongLen += kCommandReadConfigLength;
break;
case kCommandWriteConfig:
cmdLongLen += kCommandWriteConfigLength;
break;
default:
*result = kIOPFUnknownCmd;
break;
}
if (*result != kIOPFUnknownCmd) {
tmpLen = cmdLongLen;
if (((tmpLen - 1) > kIOPFMaxParams) || ((tmpLen * sizeof(UInt32)) > lenRemaining))
*result = kIOPFBadCmdLength; else {
*cmdLen = cmdLongLen * sizeof(UInt32); tmpLen--;
if (quickScan) {
DLOG ("IOPFI::scanSubCommand(%lx) - quickScan skip %ld parameters\n", this, tmpLen);
cmdPtr += tmpLen;
} else {
DLOG ("IOPFI::scanSubCommand(%lx) - copying %ld parameters, 1st param 0x%lx\n", this, tmpLen, *cmdPtr);
paramsUsed = tmpLen;
while (1) {
*param1 = *(cmdPtr++);
if (!(--tmpLen)) break;
*param2 = *(cmdPtr++);
if (!(--tmpLen)) break;
*param3 = *(cmdPtr++);
if (!(--tmpLen)) break;
*param4 = *(cmdPtr++);
if (!(--tmpLen)) break;
*param5 = *(cmdPtr++);
if (!(--tmpLen)) break;
*param6 = *(cmdPtr++);
if (!(--tmpLen)) break;
*param7 = *(cmdPtr++);
if (!(--tmpLen)) break;
*param8 = *(cmdPtr++);
if (!(--tmpLen)) break;
*param9 = *(cmdPtr++);
if (!(--tmpLen)) break;
*param10 = *(cmdPtr++);
if (!(--tmpLen)) break;
DLOG ("IOPFI::scanSubCommand - passed param10, OOPS!\n");
break;
}
}
}
} else {
*result = kIOPFNoError;
DLOG ("IOPFI::scanSubCommand(%lx) - processing variable command %ld!\n", this, *cmd);
switch (*cmd) {
case kCommandWriteI2C:
*cmdLen = (cmdLongLen + kCommandWriteI2CLength) * sizeof (UInt32); arrayLen = *(cmdPtr++);
DLOG ("IOPFI::scanSubCommand(%lx) - arrayLen %ld\n", this, arrayLen);
*cmdLen += arrayLen;
if (*cmdLen > lenRemaining)
*result = kIOPFBadCmdLength; else {
if (!quickScan) {
*param1 = arrayLen; *param2 = (UInt32)cmdPtr; paramsUsed = 2;
}
cmdPtr = (UInt32 *)((UInt8 *)cmdPtr + arrayLen);
}
break;
case kCommandRMWI2C:
*cmdLen = (cmdLongLen + kCommandRMWI2CLength) * sizeof (UInt32); maskLen = *(cmdPtr++);
arrayLen = *(cmdPtr++);
*cmdLen += (arrayLen + maskLen);
if (*cmdLen > lenRemaining)
*result = kIOPFBadCmdLength; else {
if (!quickScan) {
*param1 = maskLen; *param2 = arrayLen; *param3 = *(cmdPtr++); *param4 = (UInt32)cmdPtr; cmdPtr = (UInt32 *)((UInt8 *)cmdPtr + maskLen);
*param5 = (UInt32)cmdPtr; cmdPtr = (UInt32 *)((UInt8 *)cmdPtr + arrayLen);
paramsUsed = 5;
} else
cmdPtr = (UInt32 *)((UInt8 *)cmdPtr + *cmdLen);
}
break;
case kCommandRMWConfig:
*cmdLen = (cmdLongLen + kCommandRMWConfigLength) * sizeof (UInt32); offset = *(cmdPtr++);
maskLen = *(cmdPtr++);
arrayLen = *(cmdPtr++);
*cmdLen += (arrayLen + maskLen);
if (*cmdLen > lenRemaining)
*result = kIOPFBadCmdLength; else {
if (!quickScan) {
*param1 = offset; *param2 = maskLen; *param3 = arrayLen; *param4 = *(cmdPtr++); *param5 = (UInt32)cmdPtr; cmdPtr = (UInt32 *)((UInt8 *)cmdPtr + maskLen);
*param6 = (UInt32)cmdPtr; cmdPtr = (UInt32 *)((UInt8 *)cmdPtr + arrayLen);
paramsUsed = 6;
} else
cmdPtr = (UInt32 *)((UInt8 *)cmdPtr + *cmdLen);
}
break;
default:
IOLog ("IOPFI::scanSubCommand - unknown command %ld\n", *cmd);
*result = kIOPFUnknownCmd;
break;
}
}
if (isCommandList)
currentCommandCount++;
if (!quickScan) {
switch (paramsUsed) {
case 0:
if (param1) *param1 = 0;
case 1:
if (param2) *param2 = 0;
case 2:
if (param3) *param3 = 0;
case 3:
if (param4) *param4 = 0;
case 4:
if (param5) *param5 = 0;
case 5:
if (param6) *param6 = 0;
case 6:
if (param7) *param7 = 0;
case 7:
if (param8) *param8 = 0;
case 8:
if (param9) *param9 = 0;
case 9:
if (param10) *param10 = 0;
default:
break;
}
}
}
if ((*result != kIOPFNoError) || (*cmdLen == lenRemaining))
cmdPtr = NULL;
DLOG ("IOPFI::scanSubCommand(%lx) - done, *result %ld, *cmdLen %ld, lenRemaining %ld, cmdPtr 0x%lx\n",
this, *result, *cmdLen, lenRemaining, cmdPtr);
return cmdPtr;
}
UInt32 *IOPlatformFunctionIterator::scanCommand (UInt32 *cmdPtr, UInt32 dataLen, UInt32 *cmdTotalLen,
UInt32 *flags, UInt32 *pHandle, UInt32 *result)
{
UInt32 cmdLen, cmd;
if (dataLen < 3) {
*result = kIOPFBadCmdLength;
return NULL;
}
*pHandle = *(cmdPtr++);
*flags = *(cmdPtr++);
dataLen -= 2 * sizeof(UInt32);
*cmdTotalLen = 0;
if ((*cmdPtr < 0) || (*cmdPtr > kCommandMaxCommand)) {
*result = kIOPFBadCmdLength;
return NULL;
}
do {
cmdPtr = scanSubCommand (cmdPtr, dataLen, true, &cmd, &cmdLen, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, result);
*cmdTotalLen += cmdLen;
if ((*result != kIOPFNoError) || !cmdPtr)
break;
dataLen -= cmdLen;
if (dataLen < 0) {
*result = kIOPFBadCmdLength;
return NULL;
}
if (isCommandList && (currentCommandCount == totalCommandCount))
break;
} while (dataLen);
return cmdPtr;
}
OSMetaClassDefineReservedUnused(IOPlatformFunctionIterator, 0);
OSMetaClassDefineReservedUnused(IOPlatformFunctionIterator, 1);
OSMetaClassDefineReservedUnused(IOPlatformFunctionIterator, 2);
OSMetaClassDefineReservedUnused(IOPlatformFunctionIterator, 3);
OSMetaClassDefineReservedUnused(IOPlatformFunctionIterator, 4);
OSMetaClassDefineReservedUnused(IOPlatformFunctionIterator, 5);
OSMetaClassDefineReservedUnused(IOPlatformFunctionIterator, 6);
OSMetaClassDefineReservedUnused(IOPlatformFunctionIterator, 7);
OSMetaClassDefineReservedUnused(IOPlatformFunctionIterator, 8);
OSMetaClassDefineReservedUnused(IOPlatformFunctionIterator, 9);