/* * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #include #include #include #include #include #include #include #include #include "IONDRVI2CInterface.h" #include #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 { // Open the interface and sets it in the wanted mode: fInterface->openI2CBus(fPort); // the i2c driver does not support well read in interrupt mode // so it is better to "go polling" (read does not timeout on errors // in interrupt mode). 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())) /*iMac*/) 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); }