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_channel.cpp sl@0: // IIC Channel Platform Independent Layer (PIL) sl@0: // sl@0: sl@0: #include sl@0: #ifdef IIC_INSTRUMENTATION_MACRO sl@0: #include sl@0: #endif sl@0: sl@0: // The timer call back function which calls the PSL's HandleSlaveTimeout() sl@0: // Note that this assumes that the channel thread has been unblocked - if this sl@0: // is not the case, the callback will never get to run sl@0: sl@0: TInt DIicBusChannelMaster::DoCreate() sl@0: {return KErrNone;} sl@0: sl@0: void DIicBusChannelMaster::Lock() sl@0: {NKern::FMWait(&iTransactionQLock);} sl@0: sl@0: void DIicBusChannelMaster::Unlock() sl@0: {NKern::FMSignal(&iTransactionQLock);} sl@0: sl@0: TIicBusTransaction* DIicBusChannelMaster::NextTrans(TIicBusTransaction* aTrans) sl@0: { sl@0: // call multi-transaction call back function to get next transaction sl@0: if((aTrans->iFlags&KTransactionWithPreamble)&&(aTrans->iFlags&KTransactionWithMultiTransc)) sl@0: return ((TIicBusTransactionPreambleExt*)aTrans)->iMultiTransc(aTrans, ((TIicBusTransactionPreambleExt*)aTrans)->iMultiTranscArg); sl@0: else if(aTrans->iFlags&KTransactionWithMultiTransc) sl@0: return ((TIicBusTransactionMultiTransc*)aTrans)->iMultiTransc(aTrans, ((TIicBusTransactionMultiTransc*)aTrans)->iMultiTranscArg); sl@0: else sl@0: return NULL; sl@0: } sl@0: sl@0: void DIicBusChannelMaster::UnlockAndKick() sl@0: {iTransQDfc.Enque(&iTransactionQLock);} sl@0: sl@0: void DIicBusChannelMaster::SlaveTimeoutCallback(TAny* aPtr) sl@0: { sl@0: sl@0: DIicBusChannelMaster* aChanMaster=(DIicBusChannelMaster* )aPtr; sl@0: TInt r = aChanMaster->HandleSlaveTimeout(); sl@0: aChanMaster->CompleteRequest(r); sl@0: } sl@0: sl@0: TInt DIicBusChannelMaster::TransFlow(TIicBusTransaction* aTransaction) sl@0: { sl@0: if(aTransaction->iHalfDuplexTrans == NULL) sl@0: return KErrArgument; sl@0: else if(aTransaction->iFullDuplexTrans == NULL) sl@0: return DIicBusChannel::EHalfDuplex; sl@0: else return DIicBusChannel::EFullDuplex; sl@0: } sl@0: sl@0: TInt8 DIicBusChannelMaster::IsMasterBusy() sl@0: { sl@0: if((iTransCount&~KTransCountMsBit) == 0) sl@0: return 0; sl@0: else return 1; sl@0: } sl@0: sl@0: DIicBusChannelMaster::DIicBusChannelMaster(TBusType aBusType, TChannelDuplex aChanDuplex) sl@0: : DIicBusChannel(DIicBusChannel::EMaster, aBusType, aChanDuplex), sl@0: iTransQDfc(DIicBusChannelMaster::MsgQFunc, this, NULL, 1), iChannelReady(EFalse) sl@0: { sl@0: new(&iTimeoutTimer) NTimer(SlaveTimeoutCallback,this); sl@0: } sl@0: sl@0: DIicBusChannelMaster::~DIicBusChannelMaster() sl@0: { sl@0: delete iSlaveTimeoutDfc; sl@0: } sl@0: sl@0: TInt DIicBusChannelMaster::Init() sl@0: { sl@0: iSlaveTimeoutDfc = new TDfc(SlaveTimeoutCallback,(TAny*)this, 7); // Highest Dfc priority sl@0: if(!iSlaveTimeoutDfc) sl@0: return KErrNoMemory; sl@0: else sl@0: return KErrNone; sl@0: } sl@0: sl@0: // Function to used to indicate if the Slave response has exceeded sl@0: // an expected time sl@0: TInt DIicBusChannelMaster::StartSlaveTimeOutTimer(TInt aTime) sl@0: { sl@0: TInt r = iTimeoutTimer.OneShot(NKern::TimerTicks(aTime),(*iSlaveTimeoutDfc)); sl@0: return r; sl@0: } sl@0: sl@0: void DIicBusChannelMaster::SetDfcQ(TDfcQue* aDfcQue) sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::SetDfcQ 0x%x\n",aDfcQue)); sl@0: __ASSERT_DEBUG(aDfcQue!=NULL, Kern::Fault(KIicChannelPanic,__LINE__)); sl@0: iDfcQ=aDfcQue; sl@0: iTransQDfc.SetDfcQ(iDfcQ); sl@0: iSlaveTimeoutDfc->SetDfcQ(iDfcQ); sl@0: Lock(); sl@0: __ASSERT_DEBUG(!iChannelReady, Kern::Fault(KIicChannelPanic,__LINE__)); sl@0: if (!iTransactionQ.IsEmpty()) sl@0: { sl@0: iTransaction=(TIicBusTransaction*)(iTransactionQ.First()->Deque()); sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::SetDfcQ got %08x",iTransaction)); sl@0: iTransaction->iState=TIicBusTransaction::EAccepted; sl@0: iCurrentTransaction = iTransaction; sl@0: UnlockAndKick(); sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::SetDfcQ")); sl@0: iChannelReady=ETrue; sl@0: iTransaction=NULL; sl@0: iCurrentTransaction = NULL; sl@0: Unlock(); sl@0: } sl@0: } sl@0: sl@0: void DIicBusChannelMaster::CompleteRequest(TInt aResult) sl@0: { sl@0: TIicBusTransaction* nextTrans=NextTrans(iCurrentTransaction); sl@0: sl@0: if((aResult != KErrNone)||(nextTrans == NULL)) sl@0: EndTransaction(iTransaction,aResult,iTransaction->iCallback); sl@0: else sl@0: { sl@0: nextTrans->iBusId = iCurrentTransaction->iBusId; // Pass the bus configuration info to the PSL sl@0: iCurrentTransaction = nextTrans; sl@0: DoRequest(nextTrans); sl@0: } sl@0: } sl@0: sl@0: #ifdef MASTER_MODE sl@0: sl@0: /* sl@0: For Master-side transaction queuing APIs sl@0: the Channel implementation sends the transaction as a message to the Channel's message queue, sl@0: optionally blocking the client thread on the message's semaphore (synchronous APIs). sl@0: */ sl@0: TInt DIicBusChannelMaster::QueueTransaction(TIicBusTransaction* aTransaction) sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::QueueTransaction, aTransaction=0x%x\n",aTransaction)); sl@0: // Send the transaction as a message to the Channel's message queue sl@0: // Synchronous API, so block the calling thread during the processing sl@0: TInt r = QueueTransaction(aTransaction, NULL); sl@0: if(r!=KErrNone) sl@0: return r; // Transaction was not queued - so don't wait for a notification that it completed. sl@0: sl@0: __KTRACE_OPT(KIIC, Kern::Printf("iResult)); sl@0: return aTransaction->iResult; sl@0: } sl@0: sl@0: TInt DIicBusChannelMaster::QueueTransaction(TIicBusTransaction* aTransaction, TIicBusCallback* aCallback) sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::QueueTransaction, aTransaction=0x%x, aCallback=0x%x\n",aTransaction,aCallback)); sl@0: sl@0: // Check aTransaction is non-NULL (aCallback may be NULL if the synchronous operation is required). sl@0: if(aTransaction == NULL) sl@0: { sl@0: return KErrArgument; sl@0: } sl@0: sl@0: // Send the transaction as a message to the Channel's message queue and return sl@0: aTransaction->iCallback = aCallback; sl@0: if(aCallback != NULL) sl@0: { sl@0: aCallback->iTransaction = aTransaction; sl@0: } sl@0: sl@0: // Call the PSL implementation to check that the header is valid for this channel sl@0: TInt r = CheckHdr(aTransaction->iHeader); sl@0: if(r!=KErrNone) sl@0: { sl@0: return r; sl@0: } sl@0: sl@0: // Duplex operation is indicated in the transaction object sl@0: if((TransFlow((TIicBusTransaction*)aTransaction) == DIicBusChannel::EFullDuplex) && sl@0: (ChannelDuplex() != DIicBusChannel::EFullDuplex)) sl@0: { sl@0: return KErrNotSupported; sl@0: } sl@0: sl@0: DThread* pC =& Kern::CurrentThread(); sl@0: Lock(); sl@0: __ASSERT_DEBUG(aTransaction->iState == TIicBusTransaction::EFree, Kern::Fault(KIicChannelPanic,__LINE__)); sl@0: if(!(iTransCount & KTransCountMsBit)) sl@0: { sl@0: if(iTransCount < ~KTransCountMsBit) sl@0: { sl@0: ++iTransCount; sl@0: } sl@0: else sl@0: { sl@0: Unlock(); sl@0: return KErrOverflow; sl@0: } sl@0: } sl@0: sl@0: aTransaction->iSyncNotification.iCount = 0; sl@0: aTransaction->iSyncNotification.iOwningThread = &pC->iNThread; sl@0: pC->Open(); sl@0: if (iChannelReady) sl@0: { sl@0: aTransaction->iState = TIicBusTransaction::EAccepted; sl@0: iTransaction = aTransaction; sl@0: iCurrentTransaction = aTransaction; sl@0: iChannelReady = EFalse; sl@0: UnlockAndKick(); sl@0: } sl@0: else sl@0: { sl@0: iTransactionQ.Add(aTransaction); sl@0: aTransaction->iState = TIicBusTransaction::EDelivered; sl@0: Unlock(); sl@0: } sl@0: sl@0: // Wait on a semaphore if called from synchronous version sl@0: if(aCallback == NULL) sl@0: { sl@0: NKern::FSWait(&aTransaction->iSyncNotification); sl@0: } sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt DIicBusChannelMaster::CancelTransaction(TIicBusTransaction* aTransaction) sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::CancelTransaction, aTransaction=0x%x\n",aTransaction)); sl@0: sl@0: // Check aTransaction is non-NULL sl@0: if(aTransaction == NULL) sl@0: { sl@0: return KErrArgument; sl@0: } sl@0: // If the method is called on a synchronous transaction return KErrNotSupported sl@0: if(aTransaction->iCallback == NULL) sl@0: { sl@0: return KErrNotSupported; sl@0: } sl@0: DThread* pT = NULL; sl@0: Lock(); sl@0: sl@0: TInt r = KErrNone; sl@0: switch(aTransaction->iState) sl@0: { sl@0: case TIicBusTransaction::EDelivered: sl@0: { sl@0: aTransaction->Deque(); sl@0: pT=_LOFF(aTransaction->iSyncNotification.iOwningThread,DThread,iNThread); sl@0: aTransaction->iState=TIicBusTransaction::EFree; sl@0: --iTransCount; // Count must be greater than zero if the transaction is in this state sl@0: r = KErrCancel; sl@0: break; sl@0: } sl@0: sl@0: case TIicBusTransaction::EAccepted: sl@0: { sl@0: r = KErrInUse; sl@0: break; sl@0: } sl@0: sl@0: case TIicBusTransaction::EFree: sl@0: { sl@0: r = KErrCancel; sl@0: break; sl@0: } sl@0: } sl@0: Unlock(); sl@0: if (pT) sl@0: { sl@0: pT->AsyncClose(); sl@0: } sl@0: sl@0: return r; sl@0: } sl@0: sl@0: #else /*MASTER_MODE*/ sl@0: sl@0: TInt DIicBusChannelMaster::QueueTransaction(TIicBusTransaction* /*aTransaction*/) sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::QueueTransaction invoked when not in MASTER_MODE!\n")); sl@0: return KErrNotSupported; sl@0: } sl@0: sl@0: TInt DIicBusChannelMaster::QueueTransaction(TIicBusTransaction* /*aTransaction*/, TIicBusCallback* /*aCallback*/) sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::QueueTransaction invoked when not in MASTER_MODE!\n")); sl@0: return KErrNotSupported; sl@0: } sl@0: sl@0: TInt DIicBusChannelMaster::CancelTransaction(TIicBusTransaction* /*aTransaction*/) sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::CancelTransaction invoked when not in MASTER_MODE!\n")); sl@0: return KErrNotSupported; sl@0: } sl@0: #endif/*MASTER_MODE*/ sl@0: sl@0: // Invoked in response to receiving a message sl@0: // Function argument is a pointer to the required channel object sl@0: // Invoke the channel's PSL implementation of the DoRequest method with a pointer to the transaction object sl@0: // sl@0: void DIicBusChannelMaster::MsgQFunc(TAny* aPtr) sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc, aPtr=0x%x\n",aPtr)); sl@0: DIicBusChannelMaster* channel=(DIicBusChannelMaster*)aPtr; sl@0: TIicBusTransaction* trans = channel->iTransaction; sl@0: sl@0: #ifdef IIC_INSTRUMENTATION_MACRO sl@0: IIC_MPROCESSTRANS_START_PIL_TRACE; sl@0: #endif sl@0: sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc trans->iHeader=0x%x\n",trans->iHeader)); sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc trans->iHalfDuplexTrans=0x%x\n",trans->iHalfDuplexTrans)); sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc trans->iFullDuplexTrans=0x%x\n",trans->iFullDuplexTrans)); sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc trans->iCallback=0x%x\n",trans->iCallback)); sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc trans->iFlags=0x%x\n",trans->iFlags)); sl@0: sl@0: TInt r = KErrNone; sl@0: // invoke the preamble callback function supplied by the client of the IIC if there is any sl@0: if(GetTransFlags(trans) & KTransactionWithPreamble) sl@0: { sl@0: TIicBusTransactionPreamble* transPreamble = (TIicBusTransactionPreamble*)trans; sl@0: TIicBusPreamble funcPtr=NULL; sl@0: funcPtr=(GetPreambleFuncPtr(transPreamble)); sl@0: funcPtr(transPreamble,GetPreambleFuncArg(transPreamble)); sl@0: } sl@0: r = channel->DoRequest(trans); // Instigate processing in the PSL sl@0: if(r!=KErrNone) sl@0: channel->EndTransaction(trans, r, trans->iCallback); sl@0: } sl@0: sl@0: void DIicBusChannelMaster::EndTransaction(TIicBusTransaction* aTrans, TInt aResult, TIicBusCallback* aCb) sl@0: { sl@0: #ifdef IIC_INSTRUMENTATION_MACRO sl@0: IIC_MPROCESSTRANS_END_PIL_TRACE; sl@0: #endif sl@0: Complete(aResult,aTrans); sl@0: if(aCb != NULL) sl@0: { sl@0: aCb->iResult = aResult; sl@0: aCb->Enque(); sl@0: } sl@0: } sl@0: sl@0: void DIicBusChannelMaster::CancelTimeOut() sl@0: { sl@0: iTimeoutTimer.Cancel(); sl@0: } sl@0: sl@0: void DIicBusChannelMaster::Complete(TInt aResult, TIicBusTransaction* aTransaction) //Completes a kernel message and receive the next one sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("MsgB::Complete %08x, %d",this,aResult)); sl@0: Lock(); sl@0: __ASSERT_DEBUG(aTransaction->iState == TIicBusTransaction::EAccepted, Kern::Fault(KIicChannelPanic,__LINE__)); sl@0: aTransaction->iResult=aResult; sl@0: aTransaction->iState=TIicBusTransaction::EFree; sl@0: --iTransCount; sl@0: DThread* pT=_LOFF(aTransaction->iSyncNotification.iOwningThread,DThread,iNThread); sl@0: __ASSERT_DEBUG(!iChannelReady, Kern::Fault(KIicChannelPanic,__LINE__)); sl@0: if (!iTransactionQ.IsEmpty()) sl@0: { sl@0: TIicBusTransaction* pM=(TIicBusTransaction*)iTransactionQ.First()->Deque(); sl@0: __KTRACE_OPT(KIIC, Kern::Printf("rxnext: got %08x",pM)); sl@0: pM->iState=TIicBusTransaction::EAccepted; sl@0: iTransaction = pM; sl@0: iCurrentTransaction = pM; sl@0: iTransQDfc.Enque(); sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("rxnext")); sl@0: iChannelReady=ETrue; sl@0: iTransaction=NULL; sl@0: iCurrentTransaction = NULL; sl@0: } sl@0: NKern::FSSignal(&aTransaction->iSyncNotification,&iTransactionQLock); sl@0: pT->AsyncClose(); sl@0: } sl@0: sl@0: TInt DIicBusChannelMaster::StaticExtension(TUint /*aFunction*/, TAny* /*aParam1*/, TAny* /*aParam*/) sl@0: { sl@0: return KErrNotSupported; sl@0: } sl@0: sl@0: TInt DIicBusChannelMaster::Spare1(TInt /*aVal*/, TAny* /*aPtr1*/, TAny* /*aPtr2*/) sl@0: { sl@0: return KErrNotSupported; sl@0: } sl@0: sl@0: #ifdef SLAVE_MODE sl@0: sl@0: TInt DIicBusChannelSlave::CaptureChannel(TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch) sl@0: { sl@0: // Only one client can have access to the Slave channel at any one time. Any subsequent attempts to capture the sl@0: // same channel should return an error. sl@0: // sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::CaptureChannel\n")); sl@0: if((aConfigHdr == NULL) || (aCallback == NULL)) sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("ERROR: non-NULL argument aConfigHdr=0x%x, aCallback=0x%x\n",aConfigHdr,aCallback)); sl@0: return KErrArgument; sl@0: } sl@0: // sl@0: // Check the header is valid for the channel sl@0: TInt r = CheckHdr(aConfigHdr); sl@0: if(r == KErrNone) sl@0: { sl@0: // Check Slave channel is available for capture sl@0: // If iChannelInUse is not set, capture should succeed sl@0: // If this Slave channel is part of a MasterSlave channel iChannelInUse will already be set sl@0: // but iClient will still be NULL. In this case, the capture should succeed. sl@0: TInt intState=__SPIN_LOCK_IRQSAVE(iSpinLock); sl@0: DThread* pT=&(Kern::CurrentThread()); sl@0: if((iChannelInUse)&&(iClient!=NULL)) sl@0: r=KErrInUse; sl@0: else sl@0: { sl@0: iChannelInUse=1; sl@0: iClient=pT; sl@0: } sl@0: __SPIN_UNLOCK_IRQRESTORE(iSpinLock,intState); sl@0: sl@0: if(r == KErrNone) sl@0: { sl@0: iClient->Open(); sl@0: aCallback->iChannel=this; sl@0: iNotif = aCallback; sl@0: iConfigHeader=aConfigHdr; // Header alread checked, so just assign it sl@0: sl@0: // Invoke the PSL processing sl@0: if(aAsynch) sl@0: { sl@0: aChannelId = 0; // the client should read iChannelId from the callback object. sl@0: r=DoRequest(EAsyncConfigPwrUp); sl@0: } sl@0: else sl@0: r=DoRequest(ESyncConfigPwrUp); sl@0: sl@0: if(r == KErrNone) sl@0: { sl@0: if(!aAsynch) // For asynchronous version there is nothing more to do until the callback is invoked sl@0: { sl@0: SetChannelId(aChannelId); sl@0: iClientTimeoutDfc->SetDfcQ(iNotif->iDfcQ); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: // PSL encountered an error sl@0: ReleaseChannel(); sl@0: if(aAsynch) sl@0: CompleteAsynchCapture(r); // Queue the client callback for execution sl@0: } sl@0: } sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: TInt DIicBusChannelSlave::ReleaseChannel() sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::ReleaseChannel\n")); sl@0: // Release a previously-captured channel. sl@0: TInt r=KErrNone;; sl@0: // Ensure that only the channel's client may release the channel sl@0: DThread* pT=&(Kern::CurrentThread()); sl@0: if(iClient!=pT) // Direct access since iClient can't be modified while channel is still captured sl@0: return KErrAccessDenied; sl@0: sl@0: r=SetNotificationTrigger(0); // Attempt to clear notification requests sl@0: if((r!=KErrNone)&&(r!=KErrTimedOut)) // KErrTimedOut refers to an earlier transaction, and is for information only sl@0: return r; sl@0: iTimeoutTimer.Cancel(); sl@0: r=DoRequest(EPowerDown); sl@0: if(r == KErrNone) sl@0: { sl@0: TInt intState=__SPIN_LOCK_IRQSAVE(iSpinLock); sl@0: iClient=NULL; sl@0: iChannelInUse=0; // Channel now available for capture by other clients sl@0: __SPIN_UNLOCK_IRQRESTORE(iSpinLock,intState); sl@0: pT->AsyncClose(); // Allow Client thread to close now channel has been released sl@0: } sl@0: else sl@0: { sl@0: // PSL error when releasing the channel - have to assume the hardware has a problem. sl@0: // The channel is no longer considered "captured" by the controller, i.e. will not accept commands sl@0: // But not having cleared the busy flag means that it can not be used for master channel sl@0: // operations if it is part of a MasterSlave channel sl@0: // Must Fault the Kernel. sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::ReleaseChannel - PSL returned error code %d\n",r)); sl@0: __ASSERT_ALWAYS(EFalse, Kern::Fault(KIicChannelPanic,__LINE__)); sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: TInt DIicBusChannelSlave::RegisterRxBuffer(TPtr8 aRxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset) sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::RegisterRxBuffer\n")); sl@0: #ifdef IIC_INSTRUMENTATION_MACRO sl@0: IIC_SREGRXBUF_START_PIL_TRACE; sl@0: #endif sl@0: TInt r=KErrNone; sl@0: // Ensure that only the channel's client may perform this operation sl@0: DThread* pT=&(Kern::CurrentThread()); sl@0: if(iClient!=pT) // Direct access since iClient can't be modified while channel is still captured sl@0: return KErrAccessDenied; sl@0: //If the buffer pointer is NULL, return KErrArgument sl@0: if(aRxBuffer.Ptr() == NULL) sl@0: return KErrArgument; sl@0: // If a buffer is already registered, a subsequent request to do the same should return KErrAlreadyExists sl@0: // This will be the case if SetNotificationTrigger has been invoked with any of ERxAllBytes, ERxUnderrun or ERxOverrun sl@0: if(iReqTrig&(ERxAllBytes|ERxUnderrun|ERxOverrun)) sl@0: r=KErrAlreadyExists; sl@0: else sl@0: { sl@0: iRxBuf=(TInt8*)(aRxBuffer.Ptr()); sl@0: iRxGranularity=aBufGranularity; sl@0: iNumRxWords=aNumWords; sl@0: iRxOffset=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: TInt DIicBusChannelSlave::RegisterTxBuffer(TPtr8 aTxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset) sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::RegisterTxBuffer - default implementation\n")); sl@0: #ifdef IIC_INSTRUMENTATION_MACRO sl@0: IIC_SREGTXBUF_START_PIL_TRACE; sl@0: #endif sl@0: TInt r=KErrNone; sl@0: // Ensure that only the channel's client may perform this operation sl@0: DThread* pT=&(Kern::CurrentThread()); sl@0: if(iClient!=pT) // Direct access since iClient can't be modified while channel is still captured sl@0: return KErrAccessDenied; sl@0: //If the buffer pointer is NULL, return KErrArgument sl@0: if(aTxBuffer.Ptr() == NULL) sl@0: return KErrArgument; sl@0: // If a buffer is already registered and a request is pending, a subsequent request to register a buffer should return sl@0: // KErrAlreadyExists sl@0: // This will be the case if SetNotificationTrigger has been invoked with any of ETxAllBytes, ETxUnderrun or ETxOverrun sl@0: if(iReqTrig&(ETxAllBytes|ETxUnderrun|ETxOverrun)) sl@0: r=KErrAlreadyExists; sl@0: else sl@0: { sl@0: iTxBuf=(TInt8*)(aTxBuffer.Ptr()); sl@0: iTxGranularity=aBufGranularity; sl@0: iNumTxWords=aNumWords; sl@0: iTxOffset=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: TInt DIicBusChannelSlave::SetNotificationTrigger(TInt aTrigger) sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::SetNotificationTrigger invoked with aTrigger=0x%x\n",aTrigger)); sl@0: // Ensure that only the channel's client may perform this operation sl@0: DThread* pT=&(Kern::CurrentThread()); sl@0: if(iClient!=pT) // Direct access since iClient can't be modified while channel is still captured sl@0: return KErrAccessDenied; sl@0: sl@0: TInt retVal = KErrNone; sl@0: TInt trigger = aTrigger; sl@0: switch (iTimerState) // Handle existing timer conditions sl@0: { sl@0: case DIicBusChannelSlave::EInactive: sl@0: { sl@0: // In this state no timers have been started - so no action required sl@0: break; sl@0: } sl@0: case DIicBusChannelSlave::EWaitForClient: sl@0: { sl@0: // Client has responded within the given time period, so stop the timer. sl@0: StopTimer(); sl@0: break; sl@0: } sl@0: case DIicBusChannelSlave::EWaitForMaster: sl@0: { sl@0: // If both Rx and Tx events had been requested, and if ERxOverrun had occurred, the Client sl@0: // may have called this function with new requests for Rx notifications, in order to sl@0: // continue reading data sent by the Master. At this point, all Rx request flags in iReqTrig sl@0: // will have been cleared. sl@0: // If both Rx and Tx events had been requested, and if ETxUnderrun had occurred, the Client sl@0: // may have called this function with new requests for Tx notifications, in order to sl@0: // continue sending data to the Master. At this point, all Tx request flags in iReqTrig will sl@0: // have been cleared. sl@0: // sl@0: // To handle the ERxOverrun situation, aTrigger may specify only the new Rx trigger settings, sl@0: // or it may also re-specify the exisiting Tx settings. Similarly for the ETxUnderrun, aTrigger sl@0: // may specify only the new Tx triggers, or both the new Tx triggers and the existing Rx triggers. sl@0: // sl@0: // However, if Rx flags are still set in iReqTrig, a request to change the Rx settings sl@0: // will be rejected (similarly, for Tx). sl@0: // sl@0: // If the requested notification is zero, which would represent an attempt to clear all triggers sl@0: // while the Master may have commenced a transfer, the request will be rejected. sl@0: __ASSERT_DEBUG(iReqTrig != 0, Kern::Fault(KIicChannelPanic,__LINE__)); sl@0: if(trigger == 0) sl@0: { sl@0: return KErrInUse; sl@0: } sl@0: TInt allRxFlags = ERxAllBytes | ERxOverrun | ERxUnderrun; sl@0: TInt allTxFlags = ETxAllBytes | ETxOverrun | ETxUnderrun; sl@0: // Check the Rx flags sl@0: TInt rxTrig = iReqTrig & allRxFlags; sl@0: TInt reqRxTrig = trigger & allRxFlags; sl@0: if(rxTrig == 0) sl@0: { sl@0: rxTrig = reqRxTrig; sl@0: } sl@0: else if(reqRxTrig != 0) sl@0: { sl@0: // New Rx triggers specified - check that Client is not attempting to modify the existing sl@0: // settings sl@0: if(rxTrig ^ reqRxTrig) sl@0: { sl@0: // Attempting to change the trigger settings - so reject the request sl@0: return KErrInUse; sl@0: } sl@0: } sl@0: // Check the Tx flags sl@0: TInt txTrig = iReqTrig & allTxFlags; sl@0: TInt reqTxTrig = trigger & allTxFlags; sl@0: if(txTrig == 0) sl@0: { sl@0: txTrig = reqTxTrig; sl@0: } sl@0: else if(reqTxTrig != 0) sl@0: { sl@0: // New Tx triggers specified - check that Client is not attempting to modify the existing sl@0: // settings sl@0: if(txTrig ^ reqTxTrig) sl@0: { sl@0: // Attempting to change the trigger settings - so reject the request sl@0: return KErrInUse; sl@0: } sl@0: } sl@0: // Udate iReqTrig for the new requested trigger sl@0: // and cancel the timer - since we are now starting a new transfer, we should sl@0: // allow the Master the time to perform it sl@0: trigger = rxTrig | txTrig; sl@0: StopTimer(); sl@0: break; sl@0: } sl@0: case DIicBusChannelSlave::EClientTimeout: sl@0: { sl@0: // The Client did not respond within the expected time for the previous transfer. As a result, sl@0: // the transaction will have been terminated for the Client. sl@0: // Set the return value to inform the Client that it previously exceeded the expected response time sl@0: retVal = KErrTimedOut; sl@0: break; sl@0: } sl@0: default: sl@0: { sl@0: __ASSERT_DEBUG(0, Kern::Fault(KIicChannelPanic,__LINE__)); sl@0: break; sl@0: } sl@0: } sl@0: // Ensure that requests for notification of asynchronous capture of channel is removed, since this sl@0: // is not a valid event to request (the channel will already have been captured to get this far). sl@0: // Also ensure that requests for EGeneralBusError are removed, since they are redundant (a notification sl@0: // for a bus error is unconditional) and just represent overhead. sl@0: trigger &= ~(EAsyncCaptChan | EGeneralBusError); sl@0: sl@0: iReqTrig = (TInt8)trigger; // Not atomic access since only client thread modifies iReqTrig sl@0: iAccumTrig = 0; // New transfer, so initialise accumulated event record sl@0: TInt reqFlags=0; sl@0: // Overrun and/or underrun may be requested if Client is unsure how much data is to follow, sl@0: // so need to instigate Rx/Tx operation for any such request sl@0: if(iReqTrig & (ERxOverrun|ERxUnderrun|ERxAllBytes)) sl@0: { sl@0: reqFlags |= EReceive; sl@0: } sl@0: if(iReqTrig & (ETxOverrun|ETxUnderrun|ETxAllBytes)) sl@0: { sl@0: reqFlags |= ETransmit; sl@0: } sl@0: TInt r = DoRequest(reqFlags); sl@0: if(r != KErrNone) sl@0: { sl@0: // PSL encountered an error in intiating the requested trigger. Set the return value accordingly. sl@0: // Assume triggers have been cancelled - if they have not, the client-provided callback will still sl@0: // be invoked, but it will have been warned to expecte erroneous behaviour by the value assigned to retVal. sl@0: iReqTrig = 0; sl@0: retVal = KErrGeneral; sl@0: } sl@0: else // PSL accepted the request, so update timer and state information sl@0: { sl@0: switch (iTimerState) sl@0: { sl@0: case DIicBusChannelSlave::EInactive: sl@0: { sl@0: // Do not start the timer. Must wait for the Master to access a Slave buffer before considering sl@0: // a transaction as started. sl@0: break; sl@0: } sl@0: case DIicBusChannelSlave::EWaitForClient: sl@0: { sl@0: // Client has responded within the given time period. The next state is sl@0: // dependent on the requested trigger - if set to zero, the Client is explicitly sl@0: // ending the transaction, so the next state is EInactive; otherwise, the sl@0: // Client has indicated the next action expected from the Master and so the sl@0: // timer is started and next state is EWaitForMaster sl@0: if(iReqTrig == 0) sl@0: { sl@0: iTimerState = DIicBusChannelSlave::EInactive; sl@0: } sl@0: else sl@0: { sl@0: iTimerState = DIicBusChannelSlave::EWaitForMaster; sl@0: StartTimerByState(); sl@0: } sl@0: break; sl@0: } sl@0: case DIicBusChannelSlave::EClientTimeout: sl@0: { sl@0: // For the previous transfer, the Client failed to respond within the required time - and sl@0: // the PSL will have been instructed to indicate a bus error (so the Master sl@0: // will have been informed). The error code returned by this function will be KErrTimedOut sl@0: // so the Client will be informed of what has happened. sl@0: // A transaction is considered to start when the Slave is addressed by the Master sl@0: // (as indicated by the PSL invoking NotifyClient) - which has not yet happened - sl@0: // so the next state is EInactive. sl@0: iTimerState=DIicBusChannelSlave::EInactive; sl@0: break; sl@0: } sl@0: case DIicBusChannelSlave::EWaitForMaster: sl@0: { sl@0: // In this case we are handling a new requested trigger from the client to handle ERxOverrun or sl@0: // ETxUnderrun. The PSL has accepted the new trigger, so must allow the Master sufficient time sl@0: // to perform the newly-requested transfer; the timer has already been stopped, so just start it again.. sl@0: StartTimerByState(); sl@0: break; sl@0: } sl@0: default: sl@0: { sl@0: __ASSERT_DEBUG(0, Kern::Fault(KIicChannelPanic,__LINE__)); sl@0: break; sl@0: } sl@0: } sl@0: } sl@0: sl@0: return retVal; sl@0: } sl@0: #else /*SLAVE_MODE*/ sl@0: sl@0: TInt DIicBusChannelSlave::CaptureChannel(TDes8* /*aConfigHdr*/, TIicBusSlaveCallback* /*aCallback*/, TInt& /*aChannelId*/, TBool /*aAsynch*/) sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::CaptureChannel invoked when not in SLAVE_MODE!\n")); sl@0: return KErrNotSupported; sl@0: } sl@0: sl@0: TInt DIicBusChannelSlave::ReleaseChannel() sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::ReleaseChannel invoked when not in SLAVE_MODE!\n")); sl@0: return KErrNotSupported; sl@0: } sl@0: sl@0: TInt DIicBusChannelSlave::RegisterRxBuffer(TPtr8 /*aRxBuffer*/, TInt8 /*aBufGranularity*/, TInt8 /*aNumWords*/, TInt8 /*aOffset*/) sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::RegisterRxBuffer invoked when not in SLAVE_MODE!\n")); sl@0: return KErrNotSupported; sl@0: } sl@0: sl@0: TInt DIicBusChannelSlave::RegisterTxBuffer(TPtr8 /*aTxBuffer*/, TInt8 /*aBufGranularity*/, TInt8 /*aNumWords*/, TInt8 /*aOffset*/) sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::RegisterTxBuffer invoked when not in SLAVE_MODE!\n")); sl@0: return KErrNotSupported; sl@0: } sl@0: sl@0: TInt DIicBusChannelSlave::SetNotificationTrigger(TInt /*aTrigger*/) sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::SetNotificationTrigger invoked when not in SLAVE_MODE!\n")); sl@0: return KErrNotSupported; sl@0: } sl@0: #endif/*SLAVE_MODE*/ sl@0: sl@0: DIicBusChannelSlave::DIicBusChannelSlave(TBusType aBusType, TChannelDuplex aChanDuplex, TInt16 aChannelId) sl@0: : DIicBusChannel(DIicBusChannel::ESlave, aBusType, aChanDuplex), sl@0: iChannelId(aChannelId), iTimerState(EInactive), sl@0: iMasterWaitTime(KSlaveDefMWaitTime), iClientWaitTime(KSlaveDefCWaitTime), sl@0: iSpinLock(TSpinLock::EOrderGenericIrqLow2) // Semi-arbitrary, low priority value sl@0: { sl@0: #ifndef STANDALONE_CHANNEL sl@0: iController = NULL; sl@0: #endif sl@0: } sl@0: sl@0: DIicBusChannelSlave::~DIicBusChannelSlave() sl@0: { sl@0: delete iClientTimeoutDfc; sl@0: } sl@0: sl@0: void DIicBusChannelSlave::SlaveStaticCB(TAny* aPtr) sl@0: { sl@0: DIicBusChannelSlave* chan = (DIicBusChannelSlave*)aPtr; sl@0: chan->SlaveTimerCallBack(); sl@0: return; sl@0: } sl@0: sl@0: TInt DIicBusChannelSlave::Init() sl@0: { sl@0: iClientTimeoutDfc = new TDfc(SlaveStaticCB,(TAny*)this, 7); // Highest Dfc priority sl@0: if(!iClientTimeoutDfc) sl@0: return KErrNoMemory; sl@0: else sl@0: return KErrNone; sl@0: } sl@0: sl@0: void DIicBusChannelSlave::ChanCaptureCallback(TInt aResult) sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("ChanCaptureCallback: aChannel=0x%x, aResult=%d\n",this,aResult)); sl@0: sl@0: TInt r=aResult; sl@0: TInt channelId = 0; sl@0: if(aResult == KErrNone) sl@0: { sl@0: SetChannelId(channelId); sl@0: #ifndef STANDALONE_CHANNEL sl@0: __ASSERT_DEBUG(iController, Kern::Fault(KIicChannelPanic,__LINE__)); sl@0: iController->InstallCapturedChannel(channelId, this); sl@0: #endif sl@0: iClientTimeoutDfc->SetDfcQ(iNotif->iDfcQ); sl@0: r=KErrCompletion; sl@0: } sl@0: else sl@0: ReleaseChannel(); sl@0: sl@0: #ifdef IIC_INSTRUMENTATION_MACRO sl@0: IIC_SCAPTCHANASYNC_END_PIL_TRACE; sl@0: #endif sl@0: CompleteAsynchCapture(r); // Queue the client callback for execution sl@0: } sl@0: sl@0: void DIicBusChannelSlave::SlaveTimerCallBack() sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("SlaveTimerCallBack")); sl@0: if(iTimerState == DIicBusChannelSlave::EWaitForMaster) sl@0: { sl@0: // Master timeout. Consider the transaction terminated - call NotifyClient sl@0: // to inform both the Client and the PSL, and update the state machine sl@0: NotifyClient(EGeneralBusError); sl@0: } sl@0: else if(iTimerState == DIicBusChannelSlave::EWaitForClient) sl@0: { sl@0: // Client timeout. Instigate the PSL-specific bus error indication sl@0: iTimerState=DIicBusChannelSlave::EClientTimeout; sl@0: SendBusErrorAndReturn(); sl@0: } sl@0: else sl@0: { sl@0: __ASSERT_DEBUG(0, Kern::Fault(KIicChannelPanic,__LINE__)); sl@0: } sl@0: } sl@0: sl@0: sl@0: void DIicBusChannelSlave::StartTimerByState() sl@0: { sl@0: if(iTimerState == DIicBusChannelSlave::EWaitForMaster) sl@0: { sl@0: iTimeoutTimer.OneShot(NKern::TimerTicks(iMasterWaitTime),(*iClientTimeoutDfc)); sl@0: } sl@0: else if(iTimerState == DIicBusChannelSlave::EWaitForClient) sl@0: { sl@0: iTimeoutTimer.OneShot(NKern::TimerTicks(iClientWaitTime),(*iClientTimeoutDfc)); sl@0: } sl@0: else sl@0: { sl@0: __ASSERT_DEBUG(NULL, Kern::Fault(KIicChannelPanic,__LINE__)); sl@0: } sl@0: } sl@0: sl@0: void DIicBusChannelSlave::StopTimer() sl@0: { sl@0: iTimeoutTimer.Cancel(); sl@0: } sl@0: sl@0: TInt DIicBusChannelSlave::UpdateReqTrig(TInt8& aCbTrigVal, TInt& aCallbackRet) sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("UpdateReqTrig")); sl@0: sl@0: TInt nextSteps = 0; sl@0: iAccumTrig |= iNotif->iTrigger; // Update the accumulated event history, regardless of if the trigger was requested sl@0: sl@0: if(iNotif->iTrigger & EGeneralBusError) sl@0: { sl@0: // In the event of a bus error, always cancel the timer and call the Client callback sl@0: nextSteps |= (EStopTimer | EInvokeCb); sl@0: iTimerState = EInactive; sl@0: aCallbackRet = KErrGeneral; sl@0: } sl@0: else if(iNotif->iTrigger == EAsyncCaptChan) sl@0: { sl@0: // For asynchronous channel capture, no timers are involved - just call the Client callback sl@0: nextSteps |= EInvokeCb; sl@0: aCallbackRet = KErrCompletion; sl@0: } sl@0: else if((iNotif->iTrigger & iReqTrig) != 0) sl@0: { sl@0: // If a requested Rx event has occurred, clear all Rx flags from the requested triggers (similarly for Tx) sl@0: if(iNotif->iTrigger & (ERxAllBytes | ERxUnderrun | ERxOverrun)) sl@0: { sl@0: iReqTrig &= ~(ERxAllBytes | ERxUnderrun | ERxOverrun); sl@0: } sl@0: if(iNotif->iTrigger & (ETxAllBytes | ETxUnderrun | ETxOverrun)) sl@0: { sl@0: iReqTrig &= ~(ETxAllBytes | ETxUnderrun | ETxOverrun); sl@0: } sl@0: sl@0: if(iTimerState == EInactive) sl@0: { sl@0: nextSteps |= (EStartTimer | EInvokeCb); sl@0: // The next state in the state machine depends on if all the requested events have occurred sl@0: if(iReqTrig == 0) sl@0: { sl@0: // All triggers required have occurred, so transition to state EWaitForClient sl@0: iTimerState = EWaitForClient; sl@0: } sl@0: else sl@0: { sl@0: // The Client can request both Rx an Tx triggers; if only one has occurred, must wait for sl@0: // the Master to generate the other sl@0: iTimerState = EWaitForMaster; sl@0: } sl@0: aCallbackRet = KErrNone; sl@0: } sl@0: else if(iTimerState == EWaitForMaster) sl@0: { sl@0: // The next state in the state machine depends on if all the requested events have occurred sl@0: if(iReqTrig == 0) sl@0: { sl@0: // All triggers required have occurred, so transition to state EWaitForClient sl@0: iTimerState = EWaitForClient; sl@0: nextSteps |= (EStopTimer | EInvokeCb | EStartTimer); sl@0: } sl@0: else sl@0: { sl@0: // The Client can request both Rx an Tx triggers; if only one has occurred, must wait for sl@0: // the Master to generate the other - so remain in this state, do not cancel the timer or sl@0: // re-start it with a new timeout period. Still invoke the callback to notify the client sl@0: // that at least one of the requested triggers has occurred. sl@0: nextSteps |= EInvokeCb; sl@0: } sl@0: aCallbackRet = KErrNone; sl@0: } sl@0: else if((iTimerState == EWaitForClient) || (iTimerState == EClientTimeout)) sl@0: { sl@0: // No triggers are expected in these states (iReqTrig==0). sl@0: __ASSERT_DEBUG(NULL, Kern::Fault(KIicChannelPanic,__LINE__)); sl@0: } sl@0: } sl@0: aCbTrigVal = iAccumTrig; sl@0: return nextSteps; sl@0: } sl@0: sl@0: sl@0: void DIicBusChannelSlave::NotifyClient(TInt aTrigger) sl@0: { sl@0: TIicBusSlaveCallback* notif = iNotif; sl@0: notif->iTrigger = aTrigger; // Ensure ProcessData is provided with the trigger sl@0: sl@0: if(NKern::CurrentContext() == NKern::EThread && &(Kern::CurrentThread()) == iClient) sl@0: { sl@0: // PSL will update notif to represent the events that have occurred sl@0: ProcessData(aTrigger, notif); sl@0: // Only invoke the client's callback (and update the state machine) if one of the requested triggers has sl@0: // occurred or if a bus error has been witnessed sl@0: TInt8 callbackTrig=0; sl@0: TInt callbackRet=0; sl@0: TInt nextSteps = UpdateReqTrig(callbackTrig, callbackRet); sl@0: if(nextSteps & EStopTimer) sl@0: { sl@0: iTimeoutTimer.Cancel(); sl@0: } sl@0: if(nextSteps & EInvokeCb) sl@0: { sl@0: (notif->iCallback)(notif->iChannelId, (TInt)callbackRet, callbackTrig, notif->iRxWords, notif->iTxWords, notif->iParam); sl@0: // Callback now processed, so re-initialise callback object members sl@0: notif->iTrigger=0; sl@0: notif->iReturn=KErrNone; sl@0: notif->iRxWords=0; sl@0: notif->iTxWords=0; sl@0: iAccumTrig = 0; // and re-initialise the accumulated history as the transaction is considered terminated sl@0: } sl@0: if(nextSteps & EStartTimer) sl@0: { sl@0: StartTimerByState(); sl@0: } sl@0: } sl@0: else if(NKern::CurrentContext() == NKern::EInterrupt) sl@0: notif->Add(); sl@0: else sl@0: notif->Enque(); sl@0: } sl@0: sl@0: TInt DIicBusChannelSlave::SetMasterWaitTime(TInt8 aWaitTime) sl@0: { sl@0: if((aWaitTime<0)||(aWaitTime>KMaxWaitTime)) sl@0: return KErrArgument; sl@0: iMasterWaitTime=aWaitTime; sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt DIicBusChannelSlave::SetClientWaitTime(TInt8 aWaitTime) sl@0: { sl@0: if((aWaitTime<0)||(aWaitTime>KMaxWaitTime)) sl@0: return KErrArgument; sl@0: iClientWaitTime=aWaitTime; sl@0: return KErrNone; sl@0: } sl@0: sl@0: void DIicBusChannelSlave::SendBusErrorAndReturn() sl@0: { sl@0: DoRequest(EAbort); sl@0: } sl@0: sl@0: void DIicBusChannelSlave::SetChannelId(TInt& aChannelId) sl@0: { sl@0: ++iInstanceCount; sl@0: aChannelId = (iInstanceCount<<16); sl@0: // sl@0: // The PSL-specific channel identifier was stored in this generic class' member iChannelId at registration time sl@0: aChannelId |= iChannelId; sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::SetChannelId: iInstanceCount=0x%x, iChannelId=0x%x returned aChannelId=0x%x\n",iInstanceCount,iChannelId,aChannelId)); sl@0: iNotif->iChannelId=aChannelId; sl@0: } sl@0: sl@0: void DIicBusChannelSlave::CompleteAsynchCapture(TInt aResult) sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::CompleteAsynchCapture aResult = %d",aResult)); sl@0: if(NKern::CurrentContext() == NKern::EThread && &Kern::CurrentThread() == iClient) sl@0: { sl@0: iNotif->iCallback(iNotif->iChannelId, aResult, EAsyncCaptChan, NULL, NULL, iNotif->iParam); sl@0: return; sl@0: } sl@0: else sl@0: { sl@0: iNotif->iReturn=aResult; sl@0: iNotif->iTrigger=EAsyncCaptChan; sl@0: iNotif->iTxWords=NULL; sl@0: iNotif->iRxWords=NULL; sl@0: } sl@0: if(NKern::CurrentContext() == NKern::EInterrupt) sl@0: iNotif->Add(); sl@0: else sl@0: iNotif->Enque(); sl@0: } sl@0: sl@0: TInt DIicBusChannelSlave::StaticExtension(TUint /*aFunction*/, TAny* /*aParam1*/, TAny* /*aParam*/) sl@0: { sl@0: return KErrNotSupported; sl@0: } sl@0: sl@0: TInt DIicBusChannelSlave::Spare1(TInt /*aVal*/, TAny* /*aPtr1*/, TAny* /*aPtr2*/) sl@0: { sl@0: return KErrNotSupported; sl@0: } sl@0: sl@0: TInt DIicBusChannelMasterSlave::QueueTransaction(TIicBusTransaction* aTransaction) sl@0: { sl@0: return QueueTransaction(aTransaction,NULL); sl@0: }; sl@0: sl@0: TInt DIicBusChannelMasterSlave::QueueTransaction(TIicBusTransaction* aTransaction, TIicBusCallback* aCallback) sl@0: { sl@0: TInt r=KErrNone; sl@0: iMasterChannel->Lock(); sl@0: if(iSlaveChannel->iChannelInUse) sl@0: r=KErrInUse; sl@0: else sl@0: { sl@0: TInt16 count=(TInt16)((iMasterChannel->iTransCount)&~KTransCountMsBit); sl@0: if(count<~KTransCountMsBit) sl@0: { sl@0: ++count; sl@0: count|=KTransCountMsBit; sl@0: } sl@0: else sl@0: r=KErrInUse; sl@0: } sl@0: iMasterChannel->Unlock(); sl@0: if(r == KErrNone) sl@0: r=(iMasterChannel->QueueTransaction(aTransaction, aCallback)); sl@0: return r; sl@0: }; sl@0: sl@0: TInt DIicBusChannelMasterSlave::CaptureChannel(TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch) sl@0: { sl@0: iMasterChannel->Lock(); sl@0: TInt r=KErrNone; sl@0: if(iSlaveChannel->iChannelInUse) sl@0: r=KErrInUse; sl@0: else sl@0: { sl@0: if(iMasterChannel->IsMasterBusy()) sl@0: r=KErrInUse; sl@0: else sl@0: iSlaveChannel->iChannelInUse = 1; sl@0: } sl@0: iMasterChannel->Unlock(); sl@0: if(r == KErrNone) sl@0: r=iSlaveChannel->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch); sl@0: return r; sl@0: }; sl@0: sl@0: sl@0: TInt DIicBusChannelMasterSlave::ReleaseChannel() sl@0: { sl@0: iMasterChannel->Lock(); sl@0: TInt r=iSlaveChannel->ReleaseChannel(); sl@0: iMasterChannel->Unlock(); sl@0: return r; sl@0: }; sl@0: sl@0: TInt DIicBusChannelMasterSlave::StaticExtension(TUint /*aFunction*/, TAny* /*aParam1*/, TAny* /*aParam*/) sl@0: { sl@0: return KErrNotSupported; sl@0: } sl@0: sl@0: #ifdef STANDALONE_CHANNEL sl@0: EXPORT_C DIicBusChannelMasterSlave::DIicBusChannelMasterSlave(TBusType aBusType, TChannelDuplex aChanDuplex, DIicBusChannelMaster* aMasterChan, DIicBusChannelSlave* aSlaveChan) sl@0: : DIicBusChannel(DIicBusChannel::EMasterSlave, aBusType, aChanDuplex), sl@0: iMasterChannel(aMasterChan), sl@0: iSlaveChannel(aSlaveChan) sl@0: { sl@0: //If in stand-alone channel mode, the client assigns a channel number to the MasterSlave channel it creates. sl@0: } sl@0: #endif sl@0: