IONDRVI2CInterface.cpp [plain text]
#include <IOKit/IOLib.h>
#include <IOKit/IODeviceTreeSupport.h>
#include <IOKit/ndrvsupport/IONDRVFramebuffer.h>
#include <IOKit/graphics/IOGraphicsInterfaceTypes.h>
#include <IOKit/assert.h>
#include <IOKit/i2c/IOI2CInterface.h>
#include <IOKit/i2c/PPCI2CInterface.h>
#include <libkern/c++/OSContainers.h>
#include "IONDRVI2CInterface.h"
#include <string.h>
#define IONDRVI2CLOG 0
class AppleOnboardI2CInterface : public IOI2CInterface
{
OSDeclareDefaultStructors(AppleOnboardI2CInterface)
class PPCI2CInterface * fInterface;
SInt32 fPort;
public:
virtual bool start( IOService * provider );
virtual IOReturn startIO( IOI2CRequest * request );
static AppleOnboardI2CInterface * withInterface( PPCI2CInterface * interface, SInt32 port );
};
#undef super
#define super IOI2CInterface
OSDefineMetaClassAndStructors(IONDRVI2CInterface, IOI2CInterface)
IONDRVI2CInterface * IONDRVI2CInterface::withNDRV(
IONDRVFramebuffer * ndrv, SInt32 busID )
{
IONDRVI2CInterface * interface;
UInt64 id = (((UInt64) (UInt32) ndrv) << 32) | busID;
interface = new IONDRVI2CInterface;
if (interface)
{
interface->fNdrv = ndrv;
interface->fBusID = busID;
if (!interface->init()
|| !interface->attach(ndrv)
|| !interface->start(ndrv)
)
{
interface->detach( ndrv );
interface->release();
interface = 0;
}
else
interface->registerI2C(id);
}
return (interface);
}
bool IONDRVI2CInterface::start( IOService * provider )
{
IOReturn err;
VDCommunicationInfoRec commInfo;
if (!super::start(provider))
return (false);
bzero( &commInfo, sizeof( commInfo));
commInfo.csBusID = fBusID;
err = fNdrv->doStatus( cscGetCommunicationInfo, &commInfo );
if (kIOReturnSuccess != err)
return (false);
supportedTypes = commInfo.csSupportedTypes;
supportedCommFlags = commInfo.csSupportedCommFlags;
setProperty(kIOI2CBusTypeKey, commInfo.csBusType, 32);
setProperty(kIOI2CTransactionTypesKey, commInfo.csSupportedTypes, 32);
setProperty(kIOI2CSupportedCommFlagsKey, commInfo.csSupportedCommFlags, 32);
return (true);
}
IOReturn IONDRVFramebuffer::_iicAction( IONDRVFramebuffer * self, VDCommunicationRec * comm )
{
return (self->doControl(cscDoCommunication, comm));
}
IOReturn IONDRVI2CInterface::startIO( IOI2CRequest * request )
{
IOReturn err;
IOWorkLoop * wl;
VDCommunicationRec comm;
bzero( &comm, sizeof( comm));
do
{
if (0 == ((1 << request->sendTransactionType) & supportedTypes))
{
err = kIOReturnUnsupportedMode;
continue;
}
if (0 == ((1 << request->replyTransactionType) & supportedTypes))
{
err = kIOReturnUnsupportedMode;
continue;
}
if (request->commFlags != (request->commFlags & supportedCommFlags))
{
err = kIOReturnUnsupportedMode;
continue;
}
comm.csBusID = fBusID;
comm.csCommFlags = request->commFlags;
comm.csMinReplyDelay = 0;
if (kIOI2CUseSubAddressCommFlag & request->commFlags)
comm.csSendAddress = (request->sendAddress << 8) | request->sendSubAddress;
else
comm.csSendAddress = request->sendAddress;
comm.csSendType = request->sendTransactionType;
comm.csSendBuffer = (LogicalAddress) request->sendBuffer;
comm.csSendSize = request->sendBytes;
if (kIOI2CUseSubAddressCommFlag & request->commFlags)
comm.csReplyAddress = (request->replyAddress << 8) | request->replySubAddress;
else
comm.csReplyAddress = request->replyAddress;
comm.csReplyType = request->replyTransactionType;
comm.csReplyBuffer = (LogicalAddress) request->replyBuffer;
comm.csReplySize = request->replyBytes;
if ((wl = getWorkLoop()))
err = wl->runAction( (IOWorkLoop::Action) &fNdrv->_iicAction,
fNdrv, (void *) &comm );
else
err = kIOReturnNotReady;
}
while (false);
switch (err)
{
case kVideoI2CReplyPendingErr:
err = kIOReturnNoCompletion;
break;
case kVideoI2CTransactionErr:
err = kIOReturnNoDevice;
break;
case kVideoI2CBusyErr:
err = kIOReturnBusy;
break;
case kVideoI2CTransactionTypeErr:
err = kIOReturnUnsupportedMode;
break;
case kVideoBufferSizeErr:
err = kIOReturnOverrun;
break;
}
request->result = err;
if (request->completion)
(*request->completion)(request);
err = kIOReturnSuccess;
return (err);
}
#undef super
#define super IOI2CInterface
OSDefineMetaClassAndStructors(AppleOnboardI2CInterface, IOI2CInterface)
AppleOnboardI2CInterface * AppleOnboardI2CInterface::withInterface(
PPCI2CInterface * onboardInterface, SInt32 port )
{
AppleOnboardI2CInterface * interface;
UInt64 id = (((UInt64) (UInt32) onboardInterface) << 32) | port;
interface = new AppleOnboardI2CInterface;
if (interface)
{
interface->fInterface = onboardInterface;
interface->fPort = port;
if (!interface->init()
|| !interface->attach(onboardInterface)
|| !interface->start(onboardInterface)
)
{
interface->detach( onboardInterface );
interface->release();
interface = 0;
}
else
interface->registerI2C(id);
}
return (interface);
}
bool AppleOnboardI2CInterface::start( IOService * provider )
{
if (!super::start(provider))
return (false);
setProperty(kIOI2CBusTypeKey,
(UInt64) kIOI2CBusTypeI2C, 32);
setProperty(kIOI2CTransactionTypesKey,
(UInt64) ((1 << kIOI2CNoTransactionType)
| (1 << kIOI2CSimpleTransactionType)
| (1 << kIOI2CDDCciReplyTransactionType)
| (1 << kIOI2CCombinedTransactionType)), 32);
setProperty(kIOI2CSupportedCommFlagsKey,
(UInt64) kIOI2CUseSubAddressCommFlag, 32);
return (true);
}
IOReturn AppleOnboardI2CInterface::startIO( IOI2CRequest * request )
{
IOReturn err = kIOReturnSuccess;
do
{
fInterface->openI2CBus(fPort);
fInterface->setPollingMode(true);
if (request->sendBytes && (kIOI2CNoTransactionType != request->sendTransactionType))
{
if (kIOI2CCombinedTransactionType == request->sendTransactionType)
fInterface->setCombinedMode();
else if (kIOI2CUseSubAddressCommFlag & request->commFlags)
fInterface->setStandardSubMode();
else
fInterface->setStandardMode();
if (!fInterface->writeI2CBus(request->sendAddress >> 1, request->sendSubAddress,
(UInt8 *) request->sendBuffer, request->sendBytes))
err = kIOReturnNotWritable;
}
if (request->replyBytes && (kIOI2CNoTransactionType != request->replyTransactionType))
{
if (kIOI2CCombinedTransactionType == request->replyTransactionType)
fInterface->setCombinedMode();
else if (kIOI2CUseSubAddressCommFlag & request->commFlags)
fInterface->setStandardSubMode();
else
fInterface->setStandardMode();
if (!fInterface->readI2CBus(request->replyAddress >> 1, request->replySubAddress,
(UInt8 *) request->replyBuffer, request->replyBytes))
err = kIOReturnNotReadable;
}
fInterface->closeI2CBus();
}
while (false);
request->result = err;
err = kIOReturnSuccess;
return (err);
}
IOReturn IONDRVI2CInterface::create( IONDRVFramebuffer * ndrv )
{
IOReturn err;
VDCommunicationInfoRec commInfo;
IOI2CInterface * interface;
SInt32 busID;
OSObject * num;
bool ok = true;
OSArray * array = OSArray::withCapacity(1);
if (!array)
return (kIOReturnNoMemory);
do
{
bzero( &commInfo, sizeof( commInfo));
commInfo.csBusID = kVideoDefaultBus;
err = ndrv->doStatus( cscGetCommunicationInfo, &commInfo );
#if IONDRVI2CLOG
IOLog("%s: cscGetCommunicationInfo: ", ndrv->getName());
#endif
if (kIOReturnSuccess != err)
{
#if IONDRVI2CLOG
IOLog("fails with %d\n", err);
#endif
continue;
}
#if IONDRVI2CLOG
IOLog("csBusType %lx, csMinBus %lx, csMaxBus %lx\n"
"csSupportedTypes %lx, csSupportedCommFlags %lx\n",
commInfo.csBusType,
commInfo.csMinBus, commInfo.csMaxBus,
commInfo.csSupportedTypes, commInfo.csSupportedCommFlags);
#endif
if (commInfo.csMaxBus < commInfo.csMinBus)
continue;
for (busID = commInfo.csMinBus;
busID <= commInfo.csMaxBus;
busID++)
{
interface = IONDRVI2CInterface::withNDRV( ndrv, busID );
if (!interface)
break;
num = interface->getProperty(kIOI2CInterfaceIDKey);
if (num)
array->setObject( num );
else
break;
}
ok = (busID > commInfo.csMaxBus);
}
while (false);
OSData * data = OSDynamicCast( OSData, ndrv->getProvider()->getProperty("iic-address"));
if (data && (!ndrv->getProperty(kIOFBDependentIDKey))
&& (0x8c == *((UInt32 *) data->getBytesNoCopy())) )
do
{
PPCI2CInterface * onboardInterface =
(PPCI2CInterface*) getResourceService()->getProperty("PPCI2CInterface.i2c-uni-n");
if (!onboardInterface)
continue;
interface = AppleOnboardI2CInterface::withInterface( onboardInterface, 1 );
if (!interface)
break;
num = interface->getProperty(kIOI2CInterfaceIDKey);
if (num)
array->setObject( num );
else
break;
}
while (false);
if (ok)
ndrv->setProperty(kIOFBI2CInterfaceIDsKey, array);
array->release();
return (kIOReturnSuccess);
}