diff -r 000000000000 -r a41df078684a kernel/eka/drivers/iic/iic.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/iic/iic.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,1105 @@ +// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32\drivers\iic.cpp +// IIC Controller and public API Implementation +// + +#include +#include +#include "iic_priv.h" + +#ifdef IIC_INSTRUMENTATION_MACRO +#include +#endif + +// Global Controller pointer +static DIicBusController* TheController = NULL; + +// +// Implementation of generic IicBus API for client interface +// +EXPORT_C TInt IicBus::QueueTransaction(TInt aBusId, TIicBusTransaction* aTransaction) + { +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_MQTRANSSYNC_START_PIL_TRACE; +#endif + TInt r=TheController->QueueTransaction(aBusId, aTransaction); + +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_MQTRANSSYNC_END_PIL_TRACE; +#endif + return r; + } + +EXPORT_C TInt IicBus::QueueTransaction(TInt aBusId, TIicBusTransaction* aTransaction, TIicBusCallback* aCallback) + { +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_MQTRANSASYNC_START_PIL_TRACE; +#endif + TInt r=TheController->QueueTransaction(aBusId, aTransaction, aCallback); + +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_MQTRANSASYNC_END_PIL_TRACE; +#endif + return r; + } + +EXPORT_C TInt IicBus::CancelTransaction(TInt aBusId, TIicBusTransaction* aTransaction) + { +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_MCANCELTRANS_START_PIL_TRACE; +#endif + TInt r=TheController->CancelTransaction(aBusId, aTransaction); + +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_MCANCELTRANS_END_PIL_TRACE; +#endif + return r; + } + +EXPORT_C TInt IicBus::CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch) + { +#ifdef IIC_INSTRUMENTATION_MACRO + if(!aAsynch) + { + IIC_SCAPTCHANSYNC_START_PIL_TRACE; + } + else + { + IIC_SCAPTCHANASYNC_START_PIL_TRACE; + } +#endif + TInt r=TheController->CaptureChannel(aBusId, aConfigHdr, aCallback, aChannelId, aAsynch); + +#ifdef IIC_INSTRUMENTATION_MACRO + if(!aAsynch) + { + IIC_SCAPTCHANSYNC_END_PIL_TRACE; + } +#endif + return r; + } + +EXPORT_C TInt IicBus::ReleaseChannel(TInt aChannelId) + { +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_SRELCHAN_START_PIL_TRACE; +#endif + TInt r=TheController->ReleaseChannel(aChannelId); + +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_SRELCHAN_END_PIL_TRACE; +#endif + return r; + } + +EXPORT_C TInt IicBus::RegisterRxBuffer(TInt aChannelId, TPtr8 aRxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset) + { +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_SREGRXBUF_START_PIL_TRACE; +#endif + TInt r=TheController->RegisterRxBuffer(aChannelId, aRxBuffer, aBufGranularity, aNumWords, aOffset); + +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_SREGRXBUF_END_PIL_TRACE; +#endif + return r; + } + +EXPORT_C TInt IicBus::RegisterTxBuffer(TInt aChannelId, TPtr8 aTxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset) + { +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_SREGTXBUF_START_PIL_TRACE; +#endif + TInt r=TheController->RegisterTxBuffer(aChannelId, aTxBuffer, aBufGranularity, aNumWords, aOffset); + +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_SREGTXBUF_END_PIL_TRACE; +#endif + return r; + } + +EXPORT_C TInt IicBus::SetNotificationTrigger(TInt aChannelId, TInt aTrigger) + { +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_SNOTIFTRIG_START_PIL_TRACE; +#endif + TInt r=TheController->SetNotificationTrigger(aChannelId, aTrigger); + +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_SNOTIFTRIG_END_PIL_TRACE; +#endif + return r; + } + +EXPORT_C TInt IicBus::StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2) + { + return(TheController->StaticExtension(aId, aFunction, aParam1, aParam2)); + } + + +// +// Bus Controller +// + +// auxiliary function for ordering entries in the array of channels +TInt DIicBusController::OrderEntries(const DIicBusChannel& aMatch, const DIicBusChannel& aEntry) + { + TUint8 l=(TUint8)aMatch.ChannelNumber(); + TUint8 r=(TUint8)aEntry.ChannelNumber(); + if(l>r) + return -1; + else if(l EntryOrder(DIicBusController::OrderEntries); + +// Implementation for DIicBusController +// + +TInt DIicBusController::Create() + { + TInt r=KErrNone; + iChanLock = new TSpinLock(TSpinLock::EOrderGenericIrqLow2); // Semi-arbitrary, low priority value + iCaptLock = new TSpinLock(TSpinLock::EOrderGenericIrqLow2); // Semi-arbitrary, low priority value + if((iChanLock == NULL)||(iCaptLock == NULL)) + { + delete iChanLock; + delete iCaptLock; + r=KErrNoMemory; + } + return r; + } + +DIicBusController::~DIicBusController() + { +#ifdef IIC_SIMULATED_PSL + for(TInt i=0; i0, Kern::Fault(KIicPanic,__LINE__)); + iChanRdCount--; + if(iChanRdCount == 0) + iChanRwFlags &= ~EReadInProgress; + __SPIN_UNLOCK_IRQRESTORE(*iChanLock,chanIntState); + } + +TInt DIicBusController::RequestTypeSupported(const TInt aBusId, DIicBusChannelMaster* const aChannel) + { + TInt32 reqBusType; + reqBusType = GET_BUS_TYPE(aBusId); + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::RequestTypeSupported, BusType=0x%x\n", reqBusType)); + + if(reqBusType != aChannel->BusType()) + { + return KErrNotSupported; + } + + return KErrNone; + } + + +EXPORT_C TInt DIicBusController::RegisterChannels(DIicBusChannel** aListChannels, TInt aNumberChannels) + { +// To be used by Channel implementations to register a list of supported channels + __KTRACE_OPT(KIIC, Kern::Printf("\nDIicBusController::RegisterChannels, aListChannels=0x%x, aNumberChannels=%d\n",aListChannels,aNumberChannels)); + __ASSERT_DEBUG(aListChannels!=NULL, Kern::Fault(KIicPanic,__LINE__)); + + RPointerArray* chanArray = TheController->ChannelArray(); + +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_REGISTERCHANS_START_PIL_TRACE; +#endif + // Get access to the channel pointer array - exit if it is currently being modfied + TInt r=KErrNone; + if((r=TheController->GetChanWriteAccess()) == KErrNone) + { +#ifdef _DEBUG + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::RegisterChannels - On entry, iChannelArray ...\n")); + TheController->DumpChannelArray(); +#endif + // Loop for aNumberChannels and write directly to the channel array + DIicBusChannel** chanIterator = aListChannels; + for(TInt iteration = 0; iteration < aNumberChannels; ++iteration, ++chanIterator) + { + DIicBusChannel* chanPtr = *chanIterator; + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::RegisterChannels - adding channel number %d\n",chanPtr->ChannelNumber())); + TInt r = chanArray->InsertInOrder(chanPtr,EntryOrder); + if(r!=KErrNone) + break; + } + +#ifdef _DEBUG + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::RegisterChannels - On exit, iChannelArray ...\n")); + TheController->DumpChannelArray(); +#endif + TheController->FreeChanWriteAccess(); + } + else + { + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::GetChanWriteAccess returned %d\n",r)); + } + +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_REGISTERCHANS_END_PIL_TRACE; +#endif + return r; + } + + +EXPORT_C TInt DIicBusController::DeRegisterChannel(DIicBusChannel* aChannel) + { +// To be used by Channel implementations to deregister a channel + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::DeRegisterChannel, aChannel=0x%x\n",aChannel)); + if(aChannel == NULL) + return KErrArgument; + + RPointerArray* chanArray = TheController->ChannelArray(); + +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_DEREGISTERCHAN_START_PIL_TRACE; +#endif + TInt r=KErrNone; + // Get access to the channel pointer array - exit if it is currently unavailable + // Gaining write access will prevent a client of a Master Channel from instigating a new QueueTransaction + // (or CancelTransaction), and it will obstruct a client of a Slave Channel in CaptureChannel. + if((r=TheController->GetChanWriteAccess())!=KErrNone) + return r; + + // Check channel is registered + TInt chanIndex = chanArray->FindInOrder(aChannel,EntryOrder); + if(chanIndex<0) + { + TheController->FreeChanWriteAccess(); + return KErrNotFound; + } + +#ifdef _DEBUG + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::DeRegisterChannel - On entry, iChannelArray ...\n")); + TheController->DumpChannelArray(); +#endif + + // Remove the channel from the array + // Note that this does not delete the channel object + chanArray->Remove(chanIndex); + +#ifdef _DEBUG + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::DeRegisterChannel - On exit, iChannelArray ...\n")); + TheController->DumpChannelArray(); +#endif + TheController->FreeChanWriteAccess(); + +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_DEREGISTERCHAN_END_PIL_TRACE; +#endif + return KErrNone; + } + +TInt DIicBusController::FindCapturedChanById(TCapturedChannel aCapturedChan, TInt& aIndex) + { + TInt index=0; + TInt r=KErrNotFound; + do + { + if(iCapturedChannels[index].iChannelId == aCapturedChan.iChannelId) + { + aIndex=index; + r=KErrNone; + } + index++; + } while ((index < KMaxNumCapturedChannels)&&(r == KErrNotFound)); + return r; + } + +TInt DIicBusController::FindCapturedChan(TCapturedChannel aCapturedChan, TInt& aIndex) + { + TInt index=0; + TInt r=KErrNotFound; + do + { + if(iCapturedChannels[index] == aCapturedChan) + { + aIndex=index; + r=KErrNone; + } + index++; + } while ((index < KMaxNumCapturedChannels)&&(r == KErrNotFound)); + return r; + } + +TInt DIicBusController::InsertCaptChanInArray(TCapturedChannel aCapturedChan) + { + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::InsertCaptChanInArray \n")); + // Ensure the channel hasn't already been inserted in the array + // If found, fault the Kernel + TInt dumInt = 0; + TInt r=FindCapturedChan(aCapturedChan,dumInt); + __ASSERT_DEBUG(r!=KErrNone, Kern::Fault(KIicPanic,__LINE__)); + + // Loop the array and insert in the first available slot + // If no slots are available return KErrNotReady + TInt index=0; + TCapturedChannel emptyChan; + for(;index=KMaxNumCapturedChannels) + r = KErrNotReady; + return r; + } + +TInt DIicBusController::RemoveCaptChanFromArray(TCapturedChannel aCapturedChan) + { + // Remove the entry from the array + // If the entry is not present return KErrArgument + TInt index=-1; + TInt r=FindCapturedChan(aCapturedChan,index); + if((r!=KErrNone)||(index>=KMaxNumCapturedChannels)) + return KErrArgument; + iCapturedChannels[index].iChanPtr=NULL; + iCapturedChannels[index].iChannelId=0; + return KErrNone; + } + + +TInt DIicBusController::InstallCapturedChannel(const TInt aChannelId, const DIicBusChannelSlave* aChanPtr) + { +#ifdef _DEBUG + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::InstallCapturedChannel - On entry, iCapturedChannels ...\n")); + DumpCapturedChannels(); +#endif + TInt r=KErrNone; + TCapturedChannel capturedChan((TInt)aChannelId,(DIicBusChannelSlave*)aChanPtr); + // Because insertions are bounded by the size of the array and do not involve allocating + // or freeing memory, simply take the spinlock at the start of the operation and release at the end + TInt captIntState=__SPIN_LOCK_IRQSAVE(*iCaptLock); + r=InsertCaptChanInArray(capturedChan); + __SPIN_UNLOCK_IRQRESTORE(*iCaptLock,captIntState); + if(r!=KErrNone) + return r; + +#ifdef _DEBUG + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::InstallCapturedChannel - On exit, iCapturedChannels ...\n")); + DumpCapturedChannels(); +#endif + return KErrNone; + } + +TInt DIicBusController::DeInstallCapturedChannel(const TInt aChannelId, const DIicBusChannelSlave* aChanPtr) + { +#ifdef _DEBUG + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::DeInstallCapturedChannel - On entry, iCapturedChannels ...\n")); + DumpCapturedChannels(); +#endif + TInt r = KErrNone; + TCapturedChannel capturedChan((TInt) aChannelId, (DIicBusChannelSlave*) aChanPtr); + // Because removals are bounded by the size of the array and do not involve allocating + // or freeing memory, simply take the spinlock at the start of the operation and release at the end + TInt captIntState = __SPIN_LOCK_IRQSAVE(*iCaptLock); + r = RemoveCaptChanFromArray(capturedChan); + __SPIN_UNLOCK_IRQRESTORE(*iCaptLock, captIntState); + if(r != KErrNone) + return r; + +#ifdef _DEBUG + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::DeInstallCapturedChannel - On exit, iCapturedChannels ...\n")); + DumpCapturedChannels(); +#endif + return KErrNone; + } + + // Master-side API +TInt DIicBusController::QueueTransaction(TInt aBusId, TIicBusTransaction* aTransaction) + { + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::QueueTransaction, aBusId=0x%x,aTransaction=0x%x\n", aBusId, aTransaction)); + if(!aTransaction) + { + return KErrArgument; + } + + // Get a pointer to the channel + TInt dumInt = 0; + DIicBusChannel* chanPtr = NULL; + // Can only read the channel array if it is not currently being modified + TInt r = GetChanReadAccess(); + if(r != KErrNone) + { + return r; + } + r = GetChanPtr(aBusId, dumInt, chanPtr); + if(r == KErrNone) + { + if(!chanPtr) + { + r = KErrArgument; + } + else + { + switch(chanPtr->ChannelType()) + { + // QueueTransaction requests are only supported by channels in Master mode. + case DIicBusChannel::ESlave: + { + r = KErrNotSupported; + break; + } + // If the request is supported by the Master channel, send it to the channel for processing in its thread + case DIicBusChannel::EMasterSlave: + { + r = RequestTypeSupported(aBusId, ((DIicBusChannelMasterSlave*)chanPtr)->iMasterChannel); + if(r == KErrNone) + { + aTransaction->iBusId = aBusId; + r = (((DIicBusChannelMasterSlave*) chanPtr)->QueueTransaction(aTransaction)); + } + break; + } + case DIicBusChannel::EMaster: + { + r = RequestTypeSupported(aBusId, (DIicBusChannelMaster*)chanPtr); + if(r == KErrNone) + { + aTransaction->iBusId = aBusId; + r = (((DIicBusChannelMaster*) chanPtr)->QueueTransaction(aTransaction)); + } + break; + } + default: + { + r = KErrGeneral; + } + } + } + } + FreeChanReadAccess(); + return r; + } + +TInt DIicBusController::QueueTransaction(TInt aBusId, TIicBusTransaction* aTransaction, TIicBusCallback* aCallback) + { + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::QueueTransaction, aBusId=0x%x,aTransaction=0x%x,aCallback=0x%x\n",aBusId,aTransaction,aCallback)); + if(!aTransaction || !aCallback) + { + return KErrArgument; + } + + // Get a pointer to the channel + TInt dumInt = 0; + DIicBusChannel* chanPtr = NULL; + // Can only read the channel array if it is not currently being modified + TInt r = GetChanReadAccess(); + if(r == KErrNone) + { + r = GetChanPtr(aBusId, dumInt, chanPtr); + if(r == KErrNone) + { + if(!chanPtr) + { + r = KErrArgument; + } + else + { + switch(chanPtr->ChannelType()) + { + // QueueTransaction requests are only supported by channels in Master mode. + case DIicBusChannel::ESlave: + { + r = KErrNotSupported; + break; + } + // If the request is supported by the Master channel, send it to the channel for processing in its thread + case DIicBusChannel::EMasterSlave: + { + r = RequestTypeSupported(aBusId, ((DIicBusChannelMasterSlave*)chanPtr)->iMasterChannel); + if(r == KErrNone) + { + aTransaction->iBusId = aBusId; + r = (((DIicBusChannelMasterSlave*) chanPtr)->QueueTransaction(aTransaction, aCallback)); + } + break; + } + case DIicBusChannel::EMaster: + { + r = RequestTypeSupported(aBusId, (DIicBusChannelMaster*)chanPtr); + if(r == KErrNone) + { + aTransaction->iBusId = aBusId; + r = (((DIicBusChannelMaster*) chanPtr)->QueueTransaction(aTransaction, aCallback)); + } + break; + } + default: + { + r = KErrGeneral; + } + } + } + } + } + FreeChanReadAccess(); + return r; + } + + +TInt DIicBusController::GetChanPtr(const TInt aBusId, TInt &aIndex, DIicBusChannel*& aChan) + { + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::GetChanPtr, aBusId=0x%x\n",aBusId)); + + TInt32 chanId; + chanId = GET_CHAN_NUM(aBusId); + + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::GetChanPtr, chanId=0x%x\n", chanId)); + DIicBusChannelSearcher searchChannel(DIicBusChannel::EMasterSlave, DIicBusChannel::ESccb, DIicBusChannel::EFullDuplex); + searchChannel.SetChannelNumber((TInt8)chanId); + + TInt r = KErrNotFound; + aIndex = iChannelArray.FindInOrder(&searchChannel, EntryOrder); + if(aIndex >= 0) + { + aChan = iChannelArray[aIndex]; + r = KErrNone; + } + + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::GetChanPtr, chanPtr=0x%x, index=%d\n", aChan, aIndex)); + return r; + } + + +TInt DIicBusController::CancelTransaction(TInt aBusId, TIicBusTransaction* aTransaction) + { + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::CancelTransaction, aBusId=0x%x,aTransaction=0x%x\n", aBusId, aTransaction)); + if(!aTransaction) + { + return KErrArgument; + } + + // Get the channel + TInt dumInt = 0; + DIicBusChannel* chanPtr = NULL; + + // Can only read the channel array if it is not currently being modified + TInt r = GetChanReadAccess(); + if(r == KErrNone) + { + r = GetChanPtr(aBusId, dumInt, chanPtr); + if(r == KErrNone) + { + if(!chanPtr) + { + r = KErrArgument; + } + else + { + // QueueTransaction requests are only supported by channels in Master mode. + switch(chanPtr->ChannelType()) + { + case DIicBusChannel::ESlave: + { + r = KErrNotSupported; + break; + } + case DIicBusChannel::EMasterSlave: + { + r = RequestTypeSupported(aBusId, ((DIicBusChannelMasterSlave*)chanPtr)->iMasterChannel); + if(r == KErrNone) + { + r = (((DIicBusChannelMasterSlave*) chanPtr)->CancelTransaction(aTransaction)); + } + break; + } + case DIicBusChannel::EMaster: + { + r = RequestTypeSupported(aBusId, (DIicBusChannelMaster*)chanPtr); + if(r == KErrNone) + { + r = (((DIicBusChannelMaster*) chanPtr)->CancelTransaction(aTransaction)); + } + break; + } + default: + { + r = KErrGeneral; + } + } + } + } + } + FreeChanReadAccess(); + return r; + } + + // Slave-side API +TInt DIicBusController::CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch) + { + // Check that that aCallback!=NULL and aConfigHdr!=NULL - if not, return KErrArgument + if(!aCallback || !aConfigHdr) + { + return KErrArgument; + } + + // Get the channel + TInt chanIndex = 0; + DIicBusChannel* chanPtr = NULL; + + // Can only read the channel array if it is not currently being modified + TInt r = GetChanReadAccess(); + if(r == KErrNone) + { + r = GetChanPtr(aBusId, chanIndex, chanPtr); + if(r == KErrNone) + { + if(!chanPtr) + { + r = KErrArgument; + } + else + { + DIicBusChannelSlave* slaveChanPtr = NULL; + switch(chanPtr->ChannelType()) + { + // CaptureChannel requests are only supported by channels in Slave mode. + case DIicBusChannel::EMaster: + { + r = KErrNotSupported; + break; + } + case DIicBusChannel::EMasterSlave: + { + slaveChanPtr = ((DIicBusChannelMasterSlave*) chanPtr)->iSlaveChannel; + __ASSERT_DEBUG(slaveChanPtr!=NULL, Kern::Fault(KIicPanic,__LINE__)); // MasterSlave channel should have a valid Slave channel + // Send the request to the channel + slaveChanPtr->iController = this; + r = ((DIicBusChannelMasterSlave*) chanPtr)->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch); + break; + } + case DIicBusChannel::ESlave: + { + slaveChanPtr = (DIicBusChannelSlave*) chanPtr; // chanPtr is non-NULL + // Send the request to the channel + slaveChanPtr->iController = this; + r = (slaveChanPtr->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch)); + break; + } + default: + { + r = KErrArgument; + } + } + // For synchronous capture, if successful then install the channel + if(r == KErrNone && slaveChanPtr) + { + if(!aAsynch) + { + InstallCapturedChannel(aChannelId, slaveChanPtr); + } + } + } + } + } + FreeChanReadAccess(); + return r; + } + + +TInt DIicBusController::GetSlaveChanPtr(TInt aChannelId, DIicBusChannelSlave*& aSlaveChanPtr) + { + TInt r=KErrNone; + // Check that the channelID is recognised + TCapturedChannel capturedChan(aChannelId,NULL); + TInt chanIndex=-1; + // Ensure the array of captured channels will not be modified before it has been searched + // Because searches are bounded by the size of the array and do not involve allocating + // or freeing memory, simply take the spinlock at the start of the operation and release at the end + TInt captIntState=__SPIN_LOCK_IRQSAVE(*iCaptLock); + r=FindCapturedChanById(capturedChan, chanIndex); + if((chanIndex < 0)||(r == KErrNotFound)) + r=KErrArgument; + else + aSlaveChanPtr = (DIicBusChannelSlave*)(iCapturedChannels[chanIndex].iChanPtr); + __SPIN_UNLOCK_IRQRESTORE(*iCaptLock,captIntState); + + __ASSERT_DEBUG(aSlaveChanPtr!=NULL, Kern::Fault(KIicPanic,__LINE__)); + return r; + } + + +TInt DIicBusController::ReleaseChannel(TInt aChannelId) + { + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::ReleaseChannel, channelID = 0x%x \n",aChannelId)); + TInt r = KErrNone; + DIicBusChannel* chanPtr = NULL; + + // Get the pointer to the Slave Channel + DIicBusChannelSlave* slaveChanPtr = NULL; + if((r = GetSlaveChanPtr(aChannelId, slaveChanPtr)) != KErrNone) + return r; + + DIicBusChannelSearcher searchChannel(DIicBusChannel::EMasterSlave, DIicBusChannel::ESccb, DIicBusChannel::EFullDuplex); + searchChannel.SetChannelNumber(slaveChanPtr->ChannelNumber()); + + TInt dumIndex = iChannelArray.FindInOrder(&searchChannel, EntryOrder); + if(dumIndex < 0) + { + return KErrNotFound; + } + chanPtr = iChannelArray[dumIndex]; + + __ASSERT_DEBUG(chanPtr!=NULL, Kern::Fault(KIicPanic,__LINE__)); + + //if it is the masterslave channel, then call the masterslave's RelaseChannel + // which will call the slave channel's ReleaseChannel internally + if(chanPtr->ChannelType() == DIicBusChannel::EMasterSlave) + r = ((DIicBusChannelMasterSlave*)chanPtr)->ReleaseChannel(); + else // Call the slave only ReleaseChannel + r = slaveChanPtr->ReleaseChannel(); + + // In either case de-install the captured slave channel + if(r == KErrNone) + { + r = DeInstallCapturedChannel(aChannelId, slaveChanPtr); + } + + // No need to unset iController - there is only one IIC Controller + return r; + } + + +TInt DIicBusController::RegisterRxBuffer(TInt aChannelId, TPtr8 aRxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset) + { + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::RegisterRxBuffer, channelID=0x%x,aRxBuffer=0x%x,aBufGranularity=0x%x,aNumWords=0x%x,aOffset=0x%x \n",aChannelId,(TInt)&aRxBuffer,aBufGranularity,aNumWords,aOffset)); + + // Acquire the pointer to the Slave Channel + DIicBusChannelSlave* slaveChanPtr = NULL; + TInt r = GetSlaveChanPtr(aChannelId, slaveChanPtr); + if(r != KErrNone) + { + return r; + } + + // Instigate the channel functionality + return(slaveChanPtr->RegisterRxBuffer(aRxBuffer,aBufGranularity,aNumWords,aOffset)); + } + +TInt DIicBusController::RegisterTxBuffer(TInt aChannelId, TPtr8 aTxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset) + { + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::RegisterTxBuffer, channelID=0x%x,aTxBuffer=0x%x,aBufGranularity=0x%x,aNumWords=0x%x,aOffset=0x%x \n",aChannelId,(TInt)&aTxBuffer,aBufGranularity,aNumWords,aOffset)); + + // Acquire the pointer to the Slave Channel + DIicBusChannelSlave* slaveChanPtr = NULL; + TInt r = GetSlaveChanPtr(aChannelId, slaveChanPtr); + if(r != KErrNone) + { + return r; + } + + // Instigate the channel functionality + return (slaveChanPtr->RegisterTxBuffer(aTxBuffer, aBufGranularity, aNumWords, aOffset)); + } + + +TInt DIicBusController::SetNotificationTrigger(TInt aChannelId, TInt aTrigger) + { + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::SetNotificationTrigger - for aChannelId=0x%x, aTrigger=0x%x\n",aChannelId,aTrigger)); + // Acquire the pointer to the Slave Channel + DIicBusChannelSlave* slaveChanPtr = NULL; + TInt r = GetSlaveChanPtr(aChannelId, slaveChanPtr); + if( r != KErrNone) + { + return r; + } + + // Instigate the channel functionality + return(slaveChanPtr->SetNotificationTrigger(aTrigger)); + } + + +TInt DIicBusController::StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2) + { +// The IIC controller and channel classes are generic, and can serve many differing client and +// bus implementations. If a client and bus make use of specific functionality that is not +// common to other bus types, it makes sense to provide only the minimum-required support in the +// generic code. Here, the channel identifier is checked but all other parameters are passed +// directly to the bus implementation channel for processing; if the channel does not provide +// StaticExtension implementation, the generic DIicBusChannel::StaticExtension method is invoked. + +#ifdef IIC_INSTRUMENTATION_MACRO + if((aFunction & KControlIoMask) == KMasterSlaveControlIo) + { + IIC_MSSTATEXT_START_PIL_TRACE + } + else if((aFunction & KControlIoMask) == KMasterControlIo) + { + IIC_MSTATEXT_START_PIL_TRACE + } + else if((aFunction & KControlIoMask) == KSlaveControlIo) + { + IIC_SSTATEXT_START_PIL_TRACE + } +// else - Unexpected value - just pass silently to the PSL ... +#endif + + // Get the channel + TInt dumInt = 0; + DIicBusChannel* chanPtr = NULL; + // Can only read the channel array if it is not currently being modified + TInt r = GetChanReadAccess(); + if(r == KErrNone) + { + r = GetChanPtr(aId, dumInt, chanPtr); + if(r == KErrNone) + { + if(!chanPtr) + { + r = KErrArgument; + } + else + { + r = chanPtr->StaticExtension(aFunction, aParam1, aParam2); + } + } + } + +#ifdef IIC_INSTRUMENTATION_MACRO + if((aFunction & KControlIoMask) == KMasterSlaveControlIo) + { + IIC_MSSTATEXT_START_PIL_TRACE + } + else if((aFunction & KControlIoMask) == KMasterControlIo) + { + IIC_MSTATEXT_START_PIL_TRACE + } + else if((aFunction & KControlIoMask) == KSlaveControlIo) + { + IIC_SSTATEXT_START_PIL_TRACE + } +// else ... do nothing +#endif + FreeChanReadAccess(); + return r; + } + + +#ifdef _DEBUG + +void DIicBusController::DumpCapturedChannels() + { + // Print iCapturedChannels ... + TInt count=0; + TInt i=0; + TCapturedChannel emptyChan; + for(;iStaticExtension(KCtrlIoDumpChan,0,0); + }; + } + +void DIicBusController::DumpChannelArray() + { + TInt i = 0; + __KTRACE_OPT(KIIC, Kern::Printf("\nDIicBusController::DumpChannelArray\n")); + __KTRACE_OPT(KIIC, Kern::Printf(" - Count gave %d\n",iChannelArray.Count())); + for(i=0; iStaticExtension(KCtrlIoDumpChan,0,0); + }; + } + +#endif + +#ifdef IIC_SIMULATED_PSL +TVersion DIicPdd::VersionRequired() + { + const TInt KIicMajorVersionNumber=1; + const TInt KIicMinorVersionNumber=0; + const TInt KIicBuildVersionNumber=KE32BuildVersionNumber; + return TVersion(KIicMajorVersionNumber,KIicMinorVersionNumber,KIicBuildVersionNumber); + } + +/** Factory class constructor */ +DIicPdd::DIicPdd() + { + iVersion = DIicPdd::VersionRequired(); + } + +DIicPdd::~DIicPdd() + { + delete TheController; + } + +TInt DIicPdd::Install() + { + return(SetName(&KPddName)); + } + +/** Called by the kernel's device driver framework to create a Physical Channel. */ +TInt DIicPdd::Create(DBase*& /*aChannel*/, TInt /*aUint*/, const TDesC8* /*anInfo*/, const TVersion& /*aVer*/) + { + return KErrNone; + } + +/** Called by the kernel's device driver framework to check if this PDD is suitable for use with a Logical Channel.*/ +TInt DIicPdd::Validate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer) + { + if (!Kern::QueryVersionSupported(DIicPdd::VersionRequired(),aVer)) + return(KErrNotSupported); + return KErrNone; + } + +/** Return the driver capabilities */ +void DIicPdd::GetCaps(TDes8& aDes) const + { + // Create a capabilities object + TCaps caps; + caps.iVersion = iVersion; + // Zero the buffer + TInt maxLen = aDes.MaxLength(); + aDes.FillZ(maxLen); + // Copy cpabilities + TInt size=sizeof(caps); + if(size>maxLen) + size=maxLen; + aDes.Copy((TUint8*)&caps,size); + } +#endif + +#ifndef IIC_SIMULATED_PSL +// Client interface entry point +DECLARE_EXTENSION_WITH_PRIORITY(KExtensionMaximumPriority-1) // highest priority after Resource Manager + { + TheController = new DIicBusController; + if(!TheController) + return KErrNoMemory; + TInt r=TheController->Create(); + return r; + } +#else +static DIicPdd* TheIicPdd; + +DECLARE_STANDARD_PDD() + { + TheController = new DIicBusController; + if(!TheController) + return NULL; + TInt r = TheController->Create(); + if(r == KErrNone) + { + TheIicPdd = new DIicPdd; + if(TheIicPdd) + return TheIicPdd; + } + + delete TheController; + return NULL; + } +#endif + + +