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