1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kernel/eka/drivers/iic/iic_channel.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1145 @@
1.4 +// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32\drivers\iic_channel.cpp
1.18 +// IIC Channel Platform Independent Layer (PIL)
1.19 +//
1.20 +
1.21 +#include <drivers/iic_channel.h>
1.22 +#ifdef IIC_INSTRUMENTATION_MACRO
1.23 +#include <drivers/iic_trace.h>
1.24 +#endif
1.25 +
1.26 +// The timer call back function which calls the PSL's HandleSlaveTimeout()
1.27 +// Note that this assumes that the channel thread has been unblocked - if this
1.28 +// is not the case, the callback will never get to run
1.29 +
1.30 +TInt DIicBusChannelMaster::DoCreate()
1.31 + {return KErrNone;}
1.32 +
1.33 +void DIicBusChannelMaster::Lock()
1.34 + {NKern::FMWait(&iTransactionQLock);}
1.35 +
1.36 +void DIicBusChannelMaster::Unlock()
1.37 + {NKern::FMSignal(&iTransactionQLock);}
1.38 +
1.39 +TIicBusTransaction* DIicBusChannelMaster::NextTrans(TIicBusTransaction* aTrans)
1.40 + {
1.41 + // call multi-transaction call back function to get next transaction
1.42 + if((aTrans->iFlags&KTransactionWithPreamble)&&(aTrans->iFlags&KTransactionWithMultiTransc))
1.43 + return ((TIicBusTransactionPreambleExt*)aTrans)->iMultiTransc(aTrans, ((TIicBusTransactionPreambleExt*)aTrans)->iMultiTranscArg);
1.44 + else if(aTrans->iFlags&KTransactionWithMultiTransc)
1.45 + return ((TIicBusTransactionMultiTransc*)aTrans)->iMultiTransc(aTrans, ((TIicBusTransactionMultiTransc*)aTrans)->iMultiTranscArg);
1.46 + else
1.47 + return NULL;
1.48 + }
1.49 +
1.50 +void DIicBusChannelMaster::UnlockAndKick()
1.51 + {iTransQDfc.Enque(&iTransactionQLock);}
1.52 +
1.53 +void DIicBusChannelMaster::SlaveTimeoutCallback(TAny* aPtr)
1.54 + {
1.55 +
1.56 + DIicBusChannelMaster* aChanMaster=(DIicBusChannelMaster* )aPtr;
1.57 + TInt r = aChanMaster->HandleSlaveTimeout();
1.58 + aChanMaster->CompleteRequest(r);
1.59 + }
1.60 +
1.61 +TInt DIicBusChannelMaster::TransFlow(TIicBusTransaction* aTransaction)
1.62 + {
1.63 + if(aTransaction->iHalfDuplexTrans == NULL)
1.64 + return KErrArgument;
1.65 + else if(aTransaction->iFullDuplexTrans == NULL)
1.66 + return DIicBusChannel::EHalfDuplex;
1.67 + else return DIicBusChannel::EFullDuplex;
1.68 + }
1.69 +
1.70 +TInt8 DIicBusChannelMaster::IsMasterBusy()
1.71 + {
1.72 + if((iTransCount&~KTransCountMsBit) == 0)
1.73 + return 0;
1.74 + else return 1;
1.75 + }
1.76 +
1.77 +DIicBusChannelMaster::DIicBusChannelMaster(TBusType aBusType, TChannelDuplex aChanDuplex)
1.78 + : DIicBusChannel(DIicBusChannel::EMaster, aBusType, aChanDuplex),
1.79 + iTransQDfc(DIicBusChannelMaster::MsgQFunc, this, NULL, 1), iChannelReady(EFalse)
1.80 + {
1.81 + new(&iTimeoutTimer) NTimer(SlaveTimeoutCallback,this);
1.82 + }
1.83 +
1.84 +DIicBusChannelMaster::~DIicBusChannelMaster()
1.85 + {
1.86 + delete iSlaveTimeoutDfc;
1.87 + }
1.88 +
1.89 +TInt DIicBusChannelMaster::Init()
1.90 + {
1.91 + iSlaveTimeoutDfc = new TDfc(SlaveTimeoutCallback,(TAny*)this, 7); // Highest Dfc priority
1.92 + if(!iSlaveTimeoutDfc)
1.93 + return KErrNoMemory;
1.94 + else
1.95 + return KErrNone;
1.96 + }
1.97 +
1.98 +// Function to used to indicate if the Slave response has exceeded
1.99 +// an expected time
1.100 +TInt DIicBusChannelMaster::StartSlaveTimeOutTimer(TInt aTime)
1.101 + {
1.102 + TInt r = iTimeoutTimer.OneShot(NKern::TimerTicks(aTime),(*iSlaveTimeoutDfc));
1.103 + return r;
1.104 + }
1.105 +
1.106 +void DIicBusChannelMaster::SetDfcQ(TDfcQue* aDfcQue)
1.107 + {
1.108 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::SetDfcQ 0x%x\n",aDfcQue));
1.109 + __ASSERT_DEBUG(aDfcQue!=NULL, Kern::Fault(KIicChannelPanic,__LINE__));
1.110 + iDfcQ=aDfcQue;
1.111 + iTransQDfc.SetDfcQ(iDfcQ);
1.112 + iSlaveTimeoutDfc->SetDfcQ(iDfcQ);
1.113 + Lock();
1.114 + __ASSERT_DEBUG(!iChannelReady, Kern::Fault(KIicChannelPanic,__LINE__));
1.115 + if (!iTransactionQ.IsEmpty())
1.116 + {
1.117 + iTransaction=(TIicBusTransaction*)(iTransactionQ.First()->Deque());
1.118 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::SetDfcQ got %08x",iTransaction));
1.119 + iTransaction->iState=TIicBusTransaction::EAccepted;
1.120 + iCurrentTransaction = iTransaction;
1.121 + UnlockAndKick();
1.122 + }
1.123 + else
1.124 + {
1.125 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::SetDfcQ"));
1.126 + iChannelReady=ETrue;
1.127 + iTransaction=NULL;
1.128 + iCurrentTransaction = NULL;
1.129 + Unlock();
1.130 + }
1.131 + }
1.132 +
1.133 +void DIicBusChannelMaster::CompleteRequest(TInt aResult)
1.134 + {
1.135 + TIicBusTransaction* nextTrans=NextTrans(iCurrentTransaction);
1.136 +
1.137 + if((aResult != KErrNone)||(nextTrans == NULL))
1.138 + EndTransaction(iTransaction,aResult,iTransaction->iCallback);
1.139 + else
1.140 + {
1.141 + nextTrans->iBusId = iCurrentTransaction->iBusId; // Pass the bus configuration info to the PSL
1.142 + iCurrentTransaction = nextTrans;
1.143 + DoRequest(nextTrans);
1.144 + }
1.145 + }
1.146 +
1.147 +#ifdef MASTER_MODE
1.148 +
1.149 +/*
1.150 +For Master-side transaction queuing APIs
1.151 +the Channel implementation sends the transaction as a message to the Channel's message queue,
1.152 +optionally blocking the client thread on the message's semaphore (synchronous APIs).
1.153 +*/
1.154 +TInt DIicBusChannelMaster::QueueTransaction(TIicBusTransaction* aTransaction)
1.155 + {
1.156 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::QueueTransaction, aTransaction=0x%x\n",aTransaction));
1.157 + // Send the transaction as a message to the Channel's message queue
1.158 + // Synchronous API, so block the calling thread during the processing
1.159 + TInt r = QueueTransaction(aTransaction, NULL);
1.160 + if(r!=KErrNone)
1.161 + return r; // Transaction was not queued - so don't wait for a notification that it completed.
1.162 +
1.163 + __KTRACE_OPT(KIIC, Kern::Printf("<DIicBusChannelMaster::QueueTransaction ret %d",aTransaction->iResult));
1.164 + return aTransaction->iResult;
1.165 + }
1.166 +
1.167 +TInt DIicBusChannelMaster::QueueTransaction(TIicBusTransaction* aTransaction, TIicBusCallback* aCallback)
1.168 + {
1.169 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::QueueTransaction, aTransaction=0x%x, aCallback=0x%x\n",aTransaction,aCallback));
1.170 +
1.171 + // Check aTransaction is non-NULL (aCallback may be NULL if the synchronous operation is required).
1.172 + if(aTransaction == NULL)
1.173 + {
1.174 + return KErrArgument;
1.175 + }
1.176 +
1.177 + // Send the transaction as a message to the Channel's message queue and return
1.178 + aTransaction->iCallback = aCallback;
1.179 + if(aCallback != NULL)
1.180 + {
1.181 + aCallback->iTransaction = aTransaction;
1.182 + }
1.183 +
1.184 + // Call the PSL implementation to check that the header is valid for this channel
1.185 + TInt r = CheckHdr(aTransaction->iHeader);
1.186 + if(r!=KErrNone)
1.187 + {
1.188 + return r;
1.189 + }
1.190 +
1.191 + // Duplex operation is indicated in the transaction object
1.192 + if((TransFlow((TIicBusTransaction*)aTransaction) == DIicBusChannel::EFullDuplex) &&
1.193 + (ChannelDuplex() != DIicBusChannel::EFullDuplex))
1.194 + {
1.195 + return KErrNotSupported;
1.196 + }
1.197 +
1.198 + DThread* pC =& Kern::CurrentThread();
1.199 + Lock();
1.200 + __ASSERT_DEBUG(aTransaction->iState == TIicBusTransaction::EFree, Kern::Fault(KIicChannelPanic,__LINE__));
1.201 + if(!(iTransCount & KTransCountMsBit))
1.202 + {
1.203 + if(iTransCount < ~KTransCountMsBit)
1.204 + {
1.205 + ++iTransCount;
1.206 + }
1.207 + else
1.208 + {
1.209 + Unlock();
1.210 + return KErrOverflow;
1.211 + }
1.212 + }
1.213 +
1.214 + aTransaction->iSyncNotification.iCount = 0;
1.215 + aTransaction->iSyncNotification.iOwningThread = &pC->iNThread;
1.216 + pC->Open();
1.217 + if (iChannelReady)
1.218 + {
1.219 + aTransaction->iState = TIicBusTransaction::EAccepted;
1.220 + iTransaction = aTransaction;
1.221 + iCurrentTransaction = aTransaction;
1.222 + iChannelReady = EFalse;
1.223 + UnlockAndKick();
1.224 + }
1.225 + else
1.226 + {
1.227 + iTransactionQ.Add(aTransaction);
1.228 + aTransaction->iState = TIicBusTransaction::EDelivered;
1.229 + Unlock();
1.230 + }
1.231 +
1.232 + // Wait on a semaphore if called from synchronous version
1.233 + if(aCallback == NULL)
1.234 + {
1.235 + NKern::FSWait(&aTransaction->iSyncNotification);
1.236 + }
1.237 +
1.238 + return KErrNone;
1.239 + }
1.240 +
1.241 +TInt DIicBusChannelMaster::CancelTransaction(TIicBusTransaction* aTransaction)
1.242 + {
1.243 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::CancelTransaction, aTransaction=0x%x\n",aTransaction));
1.244 +
1.245 + // Check aTransaction is non-NULL
1.246 + if(aTransaction == NULL)
1.247 + {
1.248 + return KErrArgument;
1.249 + }
1.250 + // If the method is called on a synchronous transaction return KErrNotSupported
1.251 + if(aTransaction->iCallback == NULL)
1.252 + {
1.253 + return KErrNotSupported;
1.254 + }
1.255 + DThread* pT = NULL;
1.256 + Lock();
1.257 +
1.258 + TInt r = KErrNone;
1.259 + switch(aTransaction->iState)
1.260 + {
1.261 + case TIicBusTransaction::EDelivered:
1.262 + {
1.263 + aTransaction->Deque();
1.264 + pT=_LOFF(aTransaction->iSyncNotification.iOwningThread,DThread,iNThread);
1.265 + aTransaction->iState=TIicBusTransaction::EFree;
1.266 + --iTransCount; // Count must be greater than zero if the transaction is in this state
1.267 + r = KErrCancel;
1.268 + break;
1.269 + }
1.270 +
1.271 + case TIicBusTransaction::EAccepted:
1.272 + {
1.273 + r = KErrInUse;
1.274 + break;
1.275 + }
1.276 +
1.277 + case TIicBusTransaction::EFree:
1.278 + {
1.279 + r = KErrCancel;
1.280 + break;
1.281 + }
1.282 + }
1.283 + Unlock();
1.284 + if (pT)
1.285 + {
1.286 + pT->AsyncClose();
1.287 + }
1.288 +
1.289 + return r;
1.290 + }
1.291 +
1.292 +#else /*MASTER_MODE*/
1.293 +
1.294 +TInt DIicBusChannelMaster::QueueTransaction(TIicBusTransaction* /*aTransaction*/)
1.295 + {
1.296 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::QueueTransaction invoked when not in MASTER_MODE!\n"));
1.297 + return KErrNotSupported;
1.298 + }
1.299 +
1.300 +TInt DIicBusChannelMaster::QueueTransaction(TIicBusTransaction* /*aTransaction*/, TIicBusCallback* /*aCallback*/)
1.301 + {
1.302 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::QueueTransaction invoked when not in MASTER_MODE!\n"));
1.303 + return KErrNotSupported;
1.304 + }
1.305 +
1.306 +TInt DIicBusChannelMaster::CancelTransaction(TIicBusTransaction* /*aTransaction*/)
1.307 + {
1.308 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::CancelTransaction invoked when not in MASTER_MODE!\n"));
1.309 + return KErrNotSupported;
1.310 + }
1.311 +#endif/*MASTER_MODE*/
1.312 +
1.313 +// Invoked in response to receiving a message
1.314 +// Function argument is a pointer to the required channel object
1.315 +// Invoke the channel's PSL implementation of the DoRequest method with a pointer to the transaction object
1.316 +//
1.317 +void DIicBusChannelMaster::MsgQFunc(TAny* aPtr)
1.318 + {
1.319 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc, aPtr=0x%x\n",aPtr));
1.320 + DIicBusChannelMaster* channel=(DIicBusChannelMaster*)aPtr;
1.321 + TIicBusTransaction* trans = channel->iTransaction;
1.322 +
1.323 +#ifdef IIC_INSTRUMENTATION_MACRO
1.324 + IIC_MPROCESSTRANS_START_PIL_TRACE;
1.325 +#endif
1.326 +
1.327 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc trans->iHeader=0x%x\n",trans->iHeader));
1.328 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc trans->iHalfDuplexTrans=0x%x\n",trans->iHalfDuplexTrans));
1.329 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc trans->iFullDuplexTrans=0x%x\n",trans->iFullDuplexTrans));
1.330 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc trans->iCallback=0x%x\n",trans->iCallback));
1.331 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc trans->iFlags=0x%x\n",trans->iFlags));
1.332 +
1.333 + TInt r = KErrNone;
1.334 + // invoke the preamble callback function supplied by the client of the IIC if there is any
1.335 + if(GetTransFlags(trans) & KTransactionWithPreamble)
1.336 + {
1.337 + TIicBusTransactionPreamble* transPreamble = (TIicBusTransactionPreamble*)trans;
1.338 + TIicBusPreamble funcPtr=NULL;
1.339 + funcPtr=(GetPreambleFuncPtr(transPreamble));
1.340 + funcPtr(transPreamble,GetPreambleFuncArg(transPreamble));
1.341 + }
1.342 + r = channel->DoRequest(trans); // Instigate processing in the PSL
1.343 + if(r!=KErrNone)
1.344 + channel->EndTransaction(trans, r, trans->iCallback);
1.345 + }
1.346 +
1.347 +void DIicBusChannelMaster::EndTransaction(TIicBusTransaction* aTrans, TInt aResult, TIicBusCallback* aCb)
1.348 + {
1.349 +#ifdef IIC_INSTRUMENTATION_MACRO
1.350 + IIC_MPROCESSTRANS_END_PIL_TRACE;
1.351 +#endif
1.352 + Complete(aResult,aTrans);
1.353 + if(aCb != NULL)
1.354 + {
1.355 + aCb->iResult = aResult;
1.356 + aCb->Enque();
1.357 + }
1.358 + }
1.359 +
1.360 +void DIicBusChannelMaster::CancelTimeOut()
1.361 + {
1.362 + iTimeoutTimer.Cancel();
1.363 + }
1.364 +
1.365 +void DIicBusChannelMaster::Complete(TInt aResult, TIicBusTransaction* aTransaction) //Completes a kernel message and receive the next one
1.366 + {
1.367 + __KTRACE_OPT(KIIC, Kern::Printf("MsgB::Complete %08x, %d",this,aResult));
1.368 + Lock();
1.369 + __ASSERT_DEBUG(aTransaction->iState == TIicBusTransaction::EAccepted, Kern::Fault(KIicChannelPanic,__LINE__));
1.370 + aTransaction->iResult=aResult;
1.371 + aTransaction->iState=TIicBusTransaction::EFree;
1.372 + --iTransCount;
1.373 + DThread* pT=_LOFF(aTransaction->iSyncNotification.iOwningThread,DThread,iNThread);
1.374 + __ASSERT_DEBUG(!iChannelReady, Kern::Fault(KIicChannelPanic,__LINE__));
1.375 + if (!iTransactionQ.IsEmpty())
1.376 + {
1.377 + TIicBusTransaction* pM=(TIicBusTransaction*)iTransactionQ.First()->Deque();
1.378 + __KTRACE_OPT(KIIC, Kern::Printf("rxnext: got %08x",pM));
1.379 + pM->iState=TIicBusTransaction::EAccepted;
1.380 + iTransaction = pM;
1.381 + iCurrentTransaction = pM;
1.382 + iTransQDfc.Enque();
1.383 + }
1.384 + else
1.385 + {
1.386 + __KTRACE_OPT(KIIC, Kern::Printf("rxnext"));
1.387 + iChannelReady=ETrue;
1.388 + iTransaction=NULL;
1.389 + iCurrentTransaction = NULL;
1.390 + }
1.391 + NKern::FSSignal(&aTransaction->iSyncNotification,&iTransactionQLock);
1.392 + pT->AsyncClose();
1.393 + }
1.394 +
1.395 +TInt DIicBusChannelMaster::StaticExtension(TUint /*aFunction*/, TAny* /*aParam1*/, TAny* /*aParam*/)
1.396 + {
1.397 + return KErrNotSupported;
1.398 + }
1.399 +
1.400 +TInt DIicBusChannelMaster::Spare1(TInt /*aVal*/, TAny* /*aPtr1*/, TAny* /*aPtr2*/)
1.401 + {
1.402 + return KErrNotSupported;
1.403 + }
1.404 +
1.405 +#ifdef SLAVE_MODE
1.406 +
1.407 +TInt DIicBusChannelSlave::CaptureChannel(TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch)
1.408 + {
1.409 + // Only one client can have access to the Slave channel at any one time. Any subsequent attempts to capture the
1.410 + // same channel should return an error.
1.411 + //
1.412 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::CaptureChannel\n"));
1.413 + if((aConfigHdr == NULL) || (aCallback == NULL))
1.414 + {
1.415 + __KTRACE_OPT(KIIC, Kern::Printf("ERROR: non-NULL argument aConfigHdr=0x%x, aCallback=0x%x\n",aConfigHdr,aCallback));
1.416 + return KErrArgument;
1.417 + }
1.418 + //
1.419 + // Check the header is valid for the channel
1.420 + TInt r = CheckHdr(aConfigHdr);
1.421 + if(r == KErrNone)
1.422 + {
1.423 + // Check Slave channel is available for capture
1.424 + // If iChannelInUse is not set, capture should succeed
1.425 + // If this Slave channel is part of a MasterSlave channel iChannelInUse will already be set
1.426 + // but iClient will still be NULL. In this case, the capture should succeed.
1.427 + TInt intState=__SPIN_LOCK_IRQSAVE(iSpinLock);
1.428 + DThread* pT=&(Kern::CurrentThread());
1.429 + if((iChannelInUse)&&(iClient!=NULL))
1.430 + r=KErrInUse;
1.431 + else
1.432 + {
1.433 + iChannelInUse=1;
1.434 + iClient=pT;
1.435 + }
1.436 + __SPIN_UNLOCK_IRQRESTORE(iSpinLock,intState);
1.437 +
1.438 + if(r == KErrNone)
1.439 + {
1.440 + iClient->Open();
1.441 + aCallback->iChannel=this;
1.442 + iNotif = aCallback;
1.443 + iConfigHeader=aConfigHdr; // Header alread checked, so just assign it
1.444 +
1.445 + // Invoke the PSL processing
1.446 + if(aAsynch)
1.447 + {
1.448 + aChannelId = 0; // the client should read iChannelId from the callback object.
1.449 + r=DoRequest(EAsyncConfigPwrUp);
1.450 + }
1.451 + else
1.452 + r=DoRequest(ESyncConfigPwrUp);
1.453 +
1.454 + if(r == KErrNone)
1.455 + {
1.456 + if(!aAsynch) // For asynchronous version there is nothing more to do until the callback is invoked
1.457 + {
1.458 + SetChannelId(aChannelId);
1.459 + iClientTimeoutDfc->SetDfcQ(iNotif->iDfcQ);
1.460 + }
1.461 + }
1.462 + else
1.463 + {
1.464 + // PSL encountered an error
1.465 + ReleaseChannel();
1.466 + if(aAsynch)
1.467 + CompleteAsynchCapture(r); // Queue the client callback for execution
1.468 + }
1.469 + }
1.470 + }
1.471 + return r;
1.472 + }
1.473 +
1.474 +TInt DIicBusChannelSlave::ReleaseChannel()
1.475 + {
1.476 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::ReleaseChannel\n"));
1.477 + // Release a previously-captured channel.
1.478 + TInt r=KErrNone;;
1.479 + // Ensure that only the channel's client may release the channel
1.480 + DThread* pT=&(Kern::CurrentThread());
1.481 + if(iClient!=pT) // Direct access since iClient can't be modified while channel is still captured
1.482 + return KErrAccessDenied;
1.483 +
1.484 + r=SetNotificationTrigger(0); // Attempt to clear notification requests
1.485 + if((r!=KErrNone)&&(r!=KErrTimedOut)) // KErrTimedOut refers to an earlier transaction, and is for information only
1.486 + return r;
1.487 + iTimeoutTimer.Cancel();
1.488 + r=DoRequest(EPowerDown);
1.489 + if(r == KErrNone)
1.490 + {
1.491 + TInt intState=__SPIN_LOCK_IRQSAVE(iSpinLock);
1.492 + iClient=NULL;
1.493 + iChannelInUse=0; // Channel now available for capture by other clients
1.494 + __SPIN_UNLOCK_IRQRESTORE(iSpinLock,intState);
1.495 + pT->AsyncClose(); // Allow Client thread to close now channel has been released
1.496 + }
1.497 + else
1.498 + {
1.499 + // PSL error when releasing the channel - have to assume the hardware has a problem.
1.500 + // The channel is no longer considered "captured" by the controller, i.e. will not accept commands
1.501 + // But not having cleared the busy flag means that it can not be used for master channel
1.502 + // operations if it is part of a MasterSlave channel
1.503 + // Must Fault the Kernel.
1.504 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::ReleaseChannel - PSL returned error code %d\n",r));
1.505 + __ASSERT_ALWAYS(EFalse, Kern::Fault(KIicChannelPanic,__LINE__));
1.506 + }
1.507 + return r;
1.508 + }
1.509 +
1.510 +TInt DIicBusChannelSlave::RegisterRxBuffer(TPtr8 aRxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
1.511 + {
1.512 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::RegisterRxBuffer\n"));
1.513 +#ifdef IIC_INSTRUMENTATION_MACRO
1.514 + IIC_SREGRXBUF_START_PIL_TRACE;
1.515 +#endif
1.516 + TInt r=KErrNone;
1.517 + // Ensure that only the channel's client may perform this operation
1.518 + DThread* pT=&(Kern::CurrentThread());
1.519 + if(iClient!=pT) // Direct access since iClient can't be modified while channel is still captured
1.520 + return KErrAccessDenied;
1.521 + //If the buffer pointer is NULL, return KErrArgument
1.522 + if(aRxBuffer.Ptr() == NULL)
1.523 + return KErrArgument;
1.524 + // If a buffer is already registered, a subsequent request to do the same should return KErrAlreadyExists
1.525 + // This will be the case if SetNotificationTrigger has been invoked with any of ERxAllBytes, ERxUnderrun or ERxOverrun
1.526 + if(iReqTrig&(ERxAllBytes|ERxUnderrun|ERxOverrun))
1.527 + r=KErrAlreadyExists;
1.528 + else
1.529 + {
1.530 + iRxBuf=(TInt8*)(aRxBuffer.Ptr());
1.531 + iRxGranularity=aBufGranularity;
1.532 + iNumRxWords=aNumWords;
1.533 + iRxOffset=aOffset;
1.534 + }
1.535 +#ifdef IIC_INSTRUMENTATION_MACRO
1.536 + IIC_SREGRXBUF_END_PIL_TRACE;
1.537 +#endif
1.538 + return r;
1.539 + }
1.540 +
1.541 +TInt DIicBusChannelSlave::RegisterTxBuffer(TPtr8 aTxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
1.542 + {
1.543 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::RegisterTxBuffer - default implementation\n"));
1.544 +#ifdef IIC_INSTRUMENTATION_MACRO
1.545 + IIC_SREGTXBUF_START_PIL_TRACE;
1.546 +#endif
1.547 + TInt r=KErrNone;
1.548 + // Ensure that only the channel's client may perform this operation
1.549 + DThread* pT=&(Kern::CurrentThread());
1.550 + if(iClient!=pT) // Direct access since iClient can't be modified while channel is still captured
1.551 + return KErrAccessDenied;
1.552 + //If the buffer pointer is NULL, return KErrArgument
1.553 + if(aTxBuffer.Ptr() == NULL)
1.554 + return KErrArgument;
1.555 + // If a buffer is already registered and a request is pending, a subsequent request to register a buffer should return
1.556 + // KErrAlreadyExists
1.557 + // This will be the case if SetNotificationTrigger has been invoked with any of ETxAllBytes, ETxUnderrun or ETxOverrun
1.558 + if(iReqTrig&(ETxAllBytes|ETxUnderrun|ETxOverrun))
1.559 + r=KErrAlreadyExists;
1.560 + else
1.561 + {
1.562 + iTxBuf=(TInt8*)(aTxBuffer.Ptr());
1.563 + iTxGranularity=aBufGranularity;
1.564 + iNumTxWords=aNumWords;
1.565 + iTxOffset=aOffset;
1.566 + }
1.567 +#ifdef IIC_INSTRUMENTATION_MACRO
1.568 + IIC_SREGTXBUF_END_PIL_TRACE;
1.569 +#endif
1.570 + return r;
1.571 + }
1.572 +
1.573 +TInt DIicBusChannelSlave::SetNotificationTrigger(TInt aTrigger)
1.574 + {
1.575 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::SetNotificationTrigger invoked with aTrigger=0x%x\n",aTrigger));
1.576 + // Ensure that only the channel's client may perform this operation
1.577 + DThread* pT=&(Kern::CurrentThread());
1.578 + if(iClient!=pT) // Direct access since iClient can't be modified while channel is still captured
1.579 + return KErrAccessDenied;
1.580 +
1.581 + TInt retVal = KErrNone;
1.582 + TInt trigger = aTrigger;
1.583 + switch (iTimerState) // Handle existing timer conditions
1.584 + {
1.585 + case DIicBusChannelSlave::EInactive:
1.586 + {
1.587 + // In this state no timers have been started - so no action required
1.588 + break;
1.589 + }
1.590 + case DIicBusChannelSlave::EWaitForClient:
1.591 + {
1.592 + // Client has responded within the given time period, so stop the timer.
1.593 + StopTimer();
1.594 + break;
1.595 + }
1.596 + case DIicBusChannelSlave::EWaitForMaster:
1.597 + {
1.598 + // If both Rx and Tx events had been requested, and if ERxOverrun had occurred, the Client
1.599 + // may have called this function with new requests for Rx notifications, in order to
1.600 + // continue reading data sent by the Master. At this point, all Rx request flags in iReqTrig
1.601 + // will have been cleared.
1.602 + // If both Rx and Tx events had been requested, and if ETxUnderrun had occurred, the Client
1.603 + // may have called this function with new requests for Tx notifications, in order to
1.604 + // continue sending data to the Master. At this point, all Tx request flags in iReqTrig will
1.605 + // have been cleared.
1.606 + //
1.607 + // To handle the ERxOverrun situation, aTrigger may specify only the new Rx trigger settings,
1.608 + // or it may also re-specify the exisiting Tx settings. Similarly for the ETxUnderrun, aTrigger
1.609 + // may specify only the new Tx triggers, or both the new Tx triggers and the existing Rx triggers.
1.610 + //
1.611 + // However, if Rx flags are still set in iReqTrig, a request to change the Rx settings
1.612 + // will be rejected (similarly, for Tx).
1.613 + //
1.614 + // If the requested notification is zero, which would represent an attempt to clear all triggers
1.615 + // while the Master may have commenced a transfer, the request will be rejected.
1.616 + __ASSERT_DEBUG(iReqTrig != 0, Kern::Fault(KIicChannelPanic,__LINE__));
1.617 + if(trigger == 0)
1.618 + {
1.619 + return KErrInUse;
1.620 + }
1.621 + TInt allRxFlags = ERxAllBytes | ERxOverrun | ERxUnderrun;
1.622 + TInt allTxFlags = ETxAllBytes | ETxOverrun | ETxUnderrun;
1.623 + // Check the Rx flags
1.624 + TInt rxTrig = iReqTrig & allRxFlags;
1.625 + TInt reqRxTrig = trigger & allRxFlags;
1.626 + if(rxTrig == 0)
1.627 + {
1.628 + rxTrig = reqRxTrig;
1.629 + }
1.630 + else if(reqRxTrig != 0)
1.631 + {
1.632 + // New Rx triggers specified - check that Client is not attempting to modify the existing
1.633 + // settings
1.634 + if(rxTrig ^ reqRxTrig)
1.635 + {
1.636 + // Attempting to change the trigger settings - so reject the request
1.637 + return KErrInUse;
1.638 + }
1.639 + }
1.640 + // Check the Tx flags
1.641 + TInt txTrig = iReqTrig & allTxFlags;
1.642 + TInt reqTxTrig = trigger & allTxFlags;
1.643 + if(txTrig == 0)
1.644 + {
1.645 + txTrig = reqTxTrig;
1.646 + }
1.647 + else if(reqTxTrig != 0)
1.648 + {
1.649 + // New Tx triggers specified - check that Client is not attempting to modify the existing
1.650 + // settings
1.651 + if(txTrig ^ reqTxTrig)
1.652 + {
1.653 + // Attempting to change the trigger settings - so reject the request
1.654 + return KErrInUse;
1.655 + }
1.656 + }
1.657 + // Udate iReqTrig for the new requested trigger
1.658 + // and cancel the timer - since we are now starting a new transfer, we should
1.659 + // allow the Master the time to perform it
1.660 + trigger = rxTrig | txTrig;
1.661 + StopTimer();
1.662 + break;
1.663 + }
1.664 + case DIicBusChannelSlave::EClientTimeout:
1.665 + {
1.666 + // The Client did not respond within the expected time for the previous transfer. As a result,
1.667 + // the transaction will have been terminated for the Client.
1.668 + // Set the return value to inform the Client that it previously exceeded the expected response time
1.669 + retVal = KErrTimedOut;
1.670 + break;
1.671 + }
1.672 + default:
1.673 + {
1.674 + __ASSERT_DEBUG(0, Kern::Fault(KIicChannelPanic,__LINE__));
1.675 + break;
1.676 + }
1.677 + }
1.678 + // Ensure that requests for notification of asynchronous capture of channel is removed, since this
1.679 + // is not a valid event to request (the channel will already have been captured to get this far).
1.680 + // Also ensure that requests for EGeneralBusError are removed, since they are redundant (a notification
1.681 + // for a bus error is unconditional) and just represent overhead.
1.682 + trigger &= ~(EAsyncCaptChan | EGeneralBusError);
1.683 +
1.684 + iReqTrig = (TInt8)trigger; // Not atomic access since only client thread modifies iReqTrig
1.685 + iAccumTrig = 0; // New transfer, so initialise accumulated event record
1.686 + TInt reqFlags=0;
1.687 + // Overrun and/or underrun may be requested if Client is unsure how much data is to follow,
1.688 + // so need to instigate Rx/Tx operation for any such request
1.689 + if(iReqTrig & (ERxOverrun|ERxUnderrun|ERxAllBytes))
1.690 + {
1.691 + reqFlags |= EReceive;
1.692 + }
1.693 + if(iReqTrig & (ETxOverrun|ETxUnderrun|ETxAllBytes))
1.694 + {
1.695 + reqFlags |= ETransmit;
1.696 + }
1.697 + TInt r = DoRequest(reqFlags);
1.698 + if(r != KErrNone)
1.699 + {
1.700 + // PSL encountered an error in intiating the requested trigger. Set the return value accordingly.
1.701 + // Assume triggers have been cancelled - if they have not, the client-provided callback will still
1.702 + // be invoked, but it will have been warned to expecte erroneous behaviour by the value assigned to retVal.
1.703 + iReqTrig = 0;
1.704 + retVal = KErrGeneral;
1.705 + }
1.706 + else // PSL accepted the request, so update timer and state information
1.707 + {
1.708 + switch (iTimerState)
1.709 + {
1.710 + case DIicBusChannelSlave::EInactive:
1.711 + {
1.712 + // Do not start the timer. Must wait for the Master to access a Slave buffer before considering
1.713 + // a transaction as started.
1.714 + break;
1.715 + }
1.716 + case DIicBusChannelSlave::EWaitForClient:
1.717 + {
1.718 + // Client has responded within the given time period. The next state is
1.719 + // dependent on the requested trigger - if set to zero, the Client is explicitly
1.720 + // ending the transaction, so the next state is EInactive; otherwise, the
1.721 + // Client has indicated the next action expected from the Master and so the
1.722 + // timer is started and next state is EWaitForMaster
1.723 + if(iReqTrig == 0)
1.724 + {
1.725 + iTimerState = DIicBusChannelSlave::EInactive;
1.726 + }
1.727 + else
1.728 + {
1.729 + iTimerState = DIicBusChannelSlave::EWaitForMaster;
1.730 + StartTimerByState();
1.731 + }
1.732 + break;
1.733 + }
1.734 + case DIicBusChannelSlave::EClientTimeout:
1.735 + {
1.736 + // For the previous transfer, the Client failed to respond within the required time - and
1.737 + // the PSL will have been instructed to indicate a bus error (so the Master
1.738 + // will have been informed). The error code returned by this function will be KErrTimedOut
1.739 + // so the Client will be informed of what has happened.
1.740 + // A transaction is considered to start when the Slave is addressed by the Master
1.741 + // (as indicated by the PSL invoking NotifyClient) - which has not yet happened -
1.742 + // so the next state is EInactive.
1.743 + iTimerState=DIicBusChannelSlave::EInactive;
1.744 + break;
1.745 + }
1.746 + case DIicBusChannelSlave::EWaitForMaster:
1.747 + {
1.748 + // In this case we are handling a new requested trigger from the client to handle ERxOverrun or
1.749 + // ETxUnderrun. The PSL has accepted the new trigger, so must allow the Master sufficient time
1.750 + // to perform the newly-requested transfer; the timer has already been stopped, so just start it again..
1.751 + StartTimerByState();
1.752 + break;
1.753 + }
1.754 + default:
1.755 + {
1.756 + __ASSERT_DEBUG(0, Kern::Fault(KIicChannelPanic,__LINE__));
1.757 + break;
1.758 + }
1.759 + }
1.760 + }
1.761 +
1.762 + return retVal;
1.763 + }
1.764 +#else /*SLAVE_MODE*/
1.765 +
1.766 +TInt DIicBusChannelSlave::CaptureChannel(TDes8* /*aConfigHdr*/, TIicBusSlaveCallback* /*aCallback*/, TInt& /*aChannelId*/, TBool /*aAsynch*/)
1.767 + {
1.768 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::CaptureChannel invoked when not in SLAVE_MODE!\n"));
1.769 + return KErrNotSupported;
1.770 + }
1.771 +
1.772 +TInt DIicBusChannelSlave::ReleaseChannel()
1.773 + {
1.774 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::ReleaseChannel invoked when not in SLAVE_MODE!\n"));
1.775 + return KErrNotSupported;
1.776 + }
1.777 +
1.778 +TInt DIicBusChannelSlave::RegisterRxBuffer(TPtr8 /*aRxBuffer*/, TInt8 /*aBufGranularity*/, TInt8 /*aNumWords*/, TInt8 /*aOffset*/)
1.779 + {
1.780 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::RegisterRxBuffer invoked when not in SLAVE_MODE!\n"));
1.781 + return KErrNotSupported;
1.782 + }
1.783 +
1.784 +TInt DIicBusChannelSlave::RegisterTxBuffer(TPtr8 /*aTxBuffer*/, TInt8 /*aBufGranularity*/, TInt8 /*aNumWords*/, TInt8 /*aOffset*/)
1.785 + {
1.786 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::RegisterTxBuffer invoked when not in SLAVE_MODE!\n"));
1.787 + return KErrNotSupported;
1.788 + }
1.789 +
1.790 +TInt DIicBusChannelSlave::SetNotificationTrigger(TInt /*aTrigger*/)
1.791 + {
1.792 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::SetNotificationTrigger invoked when not in SLAVE_MODE!\n"));
1.793 + return KErrNotSupported;
1.794 + }
1.795 +#endif/*SLAVE_MODE*/
1.796 +
1.797 +DIicBusChannelSlave::DIicBusChannelSlave(TBusType aBusType, TChannelDuplex aChanDuplex, TInt16 aChannelId)
1.798 + : DIicBusChannel(DIicBusChannel::ESlave, aBusType, aChanDuplex),
1.799 + iChannelId(aChannelId), iTimerState(EInactive),
1.800 + iMasterWaitTime(KSlaveDefMWaitTime), iClientWaitTime(KSlaveDefCWaitTime),
1.801 + iSpinLock(TSpinLock::EOrderGenericIrqLow2) // Semi-arbitrary, low priority value
1.802 + {
1.803 +#ifndef STANDALONE_CHANNEL
1.804 + iController = NULL;
1.805 +#endif
1.806 + }
1.807 +
1.808 +DIicBusChannelSlave::~DIicBusChannelSlave()
1.809 + {
1.810 + delete iClientTimeoutDfc;
1.811 + }
1.812 +
1.813 +void DIicBusChannelSlave::SlaveStaticCB(TAny* aPtr)
1.814 + {
1.815 + DIicBusChannelSlave* chan = (DIicBusChannelSlave*)aPtr;
1.816 + chan->SlaveTimerCallBack();
1.817 + return;
1.818 + }
1.819 +
1.820 +TInt DIicBusChannelSlave::Init()
1.821 + {
1.822 + iClientTimeoutDfc = new TDfc(SlaveStaticCB,(TAny*)this, 7); // Highest Dfc priority
1.823 + if(!iClientTimeoutDfc)
1.824 + return KErrNoMemory;
1.825 + else
1.826 + return KErrNone;
1.827 + }
1.828 +
1.829 +void DIicBusChannelSlave::ChanCaptureCallback(TInt aResult)
1.830 + {
1.831 + __KTRACE_OPT(KIIC, Kern::Printf("ChanCaptureCallback: aChannel=0x%x, aResult=%d\n",this,aResult));
1.832 +
1.833 + TInt r=aResult;
1.834 + TInt channelId = 0;
1.835 + if(aResult == KErrNone)
1.836 + {
1.837 + SetChannelId(channelId);
1.838 +#ifndef STANDALONE_CHANNEL
1.839 + __ASSERT_DEBUG(iController, Kern::Fault(KIicChannelPanic,__LINE__));
1.840 + iController->InstallCapturedChannel(channelId, this);
1.841 +#endif
1.842 + iClientTimeoutDfc->SetDfcQ(iNotif->iDfcQ);
1.843 + r=KErrCompletion;
1.844 + }
1.845 + else
1.846 + ReleaseChannel();
1.847 +
1.848 +#ifdef IIC_INSTRUMENTATION_MACRO
1.849 + IIC_SCAPTCHANASYNC_END_PIL_TRACE;
1.850 +#endif
1.851 + CompleteAsynchCapture(r); // Queue the client callback for execution
1.852 + }
1.853 +
1.854 +void DIicBusChannelSlave::SlaveTimerCallBack()
1.855 + {
1.856 + __KTRACE_OPT(KIIC, Kern::Printf("SlaveTimerCallBack"));
1.857 + if(iTimerState == DIicBusChannelSlave::EWaitForMaster)
1.858 + {
1.859 + // Master timeout. Consider the transaction terminated - call NotifyClient
1.860 + // to inform both the Client and the PSL, and update the state machine
1.861 + NotifyClient(EGeneralBusError);
1.862 + }
1.863 + else if(iTimerState == DIicBusChannelSlave::EWaitForClient)
1.864 + {
1.865 + // Client timeout. Instigate the PSL-specific bus error indication
1.866 + iTimerState=DIicBusChannelSlave::EClientTimeout;
1.867 + SendBusErrorAndReturn();
1.868 + }
1.869 + else
1.870 + {
1.871 + __ASSERT_DEBUG(0, Kern::Fault(KIicChannelPanic,__LINE__));
1.872 + }
1.873 + }
1.874 +
1.875 +
1.876 +void DIicBusChannelSlave::StartTimerByState()
1.877 + {
1.878 + if(iTimerState == DIicBusChannelSlave::EWaitForMaster)
1.879 + {
1.880 + iTimeoutTimer.OneShot(NKern::TimerTicks(iMasterWaitTime),(*iClientTimeoutDfc));
1.881 + }
1.882 + else if(iTimerState == DIicBusChannelSlave::EWaitForClient)
1.883 + {
1.884 + iTimeoutTimer.OneShot(NKern::TimerTicks(iClientWaitTime),(*iClientTimeoutDfc));
1.885 + }
1.886 + else
1.887 + {
1.888 + __ASSERT_DEBUG(NULL, Kern::Fault(KIicChannelPanic,__LINE__));
1.889 + }
1.890 + }
1.891 +
1.892 +void DIicBusChannelSlave::StopTimer()
1.893 + {
1.894 + iTimeoutTimer.Cancel();
1.895 + }
1.896 +
1.897 +TInt DIicBusChannelSlave::UpdateReqTrig(TInt8& aCbTrigVal, TInt& aCallbackRet)
1.898 + {
1.899 + __KTRACE_OPT(KIIC, Kern::Printf("UpdateReqTrig"));
1.900 +
1.901 + TInt nextSteps = 0;
1.902 + iAccumTrig |= iNotif->iTrigger; // Update the accumulated event history, regardless of if the trigger was requested
1.903 +
1.904 + if(iNotif->iTrigger & EGeneralBusError)
1.905 + {
1.906 + // In the event of a bus error, always cancel the timer and call the Client callback
1.907 + nextSteps |= (EStopTimer | EInvokeCb);
1.908 + iTimerState = EInactive;
1.909 + aCallbackRet = KErrGeneral;
1.910 + }
1.911 + else if(iNotif->iTrigger == EAsyncCaptChan)
1.912 + {
1.913 + // For asynchronous channel capture, no timers are involved - just call the Client callback
1.914 + nextSteps |= EInvokeCb;
1.915 + aCallbackRet = KErrCompletion;
1.916 + }
1.917 + else if((iNotif->iTrigger & iReqTrig) != 0)
1.918 + {
1.919 + // If a requested Rx event has occurred, clear all Rx flags from the requested triggers (similarly for Tx)
1.920 + if(iNotif->iTrigger & (ERxAllBytes | ERxUnderrun | ERxOverrun))
1.921 + {
1.922 + iReqTrig &= ~(ERxAllBytes | ERxUnderrun | ERxOverrun);
1.923 + }
1.924 + if(iNotif->iTrigger & (ETxAllBytes | ETxUnderrun | ETxOverrun))
1.925 + {
1.926 + iReqTrig &= ~(ETxAllBytes | ETxUnderrun | ETxOverrun);
1.927 + }
1.928 +
1.929 + if(iTimerState == EInactive)
1.930 + {
1.931 + nextSteps |= (EStartTimer | EInvokeCb);
1.932 + // The next state in the state machine depends on if all the requested events have occurred
1.933 + if(iReqTrig == 0)
1.934 + {
1.935 + // All triggers required have occurred, so transition to state EWaitForClient
1.936 + iTimerState = EWaitForClient;
1.937 + }
1.938 + else
1.939 + {
1.940 + // The Client can request both Rx an Tx triggers; if only one has occurred, must wait for
1.941 + // the Master to generate the other
1.942 + iTimerState = EWaitForMaster;
1.943 + }
1.944 + aCallbackRet = KErrNone;
1.945 + }
1.946 + else if(iTimerState == EWaitForMaster)
1.947 + {
1.948 + // The next state in the state machine depends on if all the requested events have occurred
1.949 + if(iReqTrig == 0)
1.950 + {
1.951 + // All triggers required have occurred, so transition to state EWaitForClient
1.952 + iTimerState = EWaitForClient;
1.953 + nextSteps |= (EStopTimer | EInvokeCb | EStartTimer);
1.954 + }
1.955 + else
1.956 + {
1.957 + // The Client can request both Rx an Tx triggers; if only one has occurred, must wait for
1.958 + // the Master to generate the other - so remain in this state, do not cancel the timer or
1.959 + // re-start it with a new timeout period. Still invoke the callback to notify the client
1.960 + // that at least one of the requested triggers has occurred.
1.961 + nextSteps |= EInvokeCb;
1.962 + }
1.963 + aCallbackRet = KErrNone;
1.964 + }
1.965 + else if((iTimerState == EWaitForClient) || (iTimerState == EClientTimeout))
1.966 + {
1.967 + // No triggers are expected in these states (iReqTrig==0).
1.968 + __ASSERT_DEBUG(NULL, Kern::Fault(KIicChannelPanic,__LINE__));
1.969 + }
1.970 + }
1.971 + aCbTrigVal = iAccumTrig;
1.972 + return nextSteps;
1.973 + }
1.974 +
1.975 +
1.976 +void DIicBusChannelSlave::NotifyClient(TInt aTrigger)
1.977 + {
1.978 + TIicBusSlaveCallback* notif = iNotif;
1.979 + notif->iTrigger = aTrigger; // Ensure ProcessData is provided with the trigger
1.980 +
1.981 + if(NKern::CurrentContext() == NKern::EThread && &(Kern::CurrentThread()) == iClient)
1.982 + {
1.983 + // PSL will update notif to represent the events that have occurred
1.984 + ProcessData(aTrigger, notif);
1.985 + // Only invoke the client's callback (and update the state machine) if one of the requested triggers has
1.986 + // occurred or if a bus error has been witnessed
1.987 + TInt8 callbackTrig=0;
1.988 + TInt callbackRet=0;
1.989 + TInt nextSteps = UpdateReqTrig(callbackTrig, callbackRet);
1.990 + if(nextSteps & EStopTimer)
1.991 + {
1.992 + iTimeoutTimer.Cancel();
1.993 + }
1.994 + if(nextSteps & EInvokeCb)
1.995 + {
1.996 + (notif->iCallback)(notif->iChannelId, (TInt)callbackRet, callbackTrig, notif->iRxWords, notif->iTxWords, notif->iParam);
1.997 + // Callback now processed, so re-initialise callback object members
1.998 + notif->iTrigger=0;
1.999 + notif->iReturn=KErrNone;
1.1000 + notif->iRxWords=0;
1.1001 + notif->iTxWords=0;
1.1002 + iAccumTrig = 0; // and re-initialise the accumulated history as the transaction is considered terminated
1.1003 + }
1.1004 + if(nextSteps & EStartTimer)
1.1005 + {
1.1006 + StartTimerByState();
1.1007 + }
1.1008 + }
1.1009 + else if(NKern::CurrentContext() == NKern::EInterrupt)
1.1010 + notif->Add();
1.1011 + else
1.1012 + notif->Enque();
1.1013 + }
1.1014 +
1.1015 +TInt DIicBusChannelSlave::SetMasterWaitTime(TInt8 aWaitTime)
1.1016 + {
1.1017 + if((aWaitTime<0)||(aWaitTime>KMaxWaitTime))
1.1018 + return KErrArgument;
1.1019 + iMasterWaitTime=aWaitTime;
1.1020 + return KErrNone;
1.1021 + }
1.1022 +
1.1023 +TInt DIicBusChannelSlave::SetClientWaitTime(TInt8 aWaitTime)
1.1024 + {
1.1025 + if((aWaitTime<0)||(aWaitTime>KMaxWaitTime))
1.1026 + return KErrArgument;
1.1027 + iClientWaitTime=aWaitTime;
1.1028 + return KErrNone;
1.1029 + }
1.1030 +
1.1031 +void DIicBusChannelSlave::SendBusErrorAndReturn()
1.1032 + {
1.1033 + DoRequest(EAbort);
1.1034 + }
1.1035 +
1.1036 +void DIicBusChannelSlave::SetChannelId(TInt& aChannelId)
1.1037 + {
1.1038 + ++iInstanceCount;
1.1039 + aChannelId = (iInstanceCount<<16);
1.1040 + //
1.1041 + // The PSL-specific channel identifier was stored in this generic class' member iChannelId at registration time
1.1042 + aChannelId |= iChannelId;
1.1043 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::SetChannelId: iInstanceCount=0x%x, iChannelId=0x%x returned aChannelId=0x%x\n",iInstanceCount,iChannelId,aChannelId));
1.1044 + iNotif->iChannelId=aChannelId;
1.1045 + }
1.1046 +
1.1047 +void DIicBusChannelSlave::CompleteAsynchCapture(TInt aResult)
1.1048 + {
1.1049 + __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::CompleteAsynchCapture aResult = %d",aResult));
1.1050 + if(NKern::CurrentContext() == NKern::EThread && &Kern::CurrentThread() == iClient)
1.1051 + {
1.1052 + iNotif->iCallback(iNotif->iChannelId, aResult, EAsyncCaptChan, NULL, NULL, iNotif->iParam);
1.1053 + return;
1.1054 + }
1.1055 + else
1.1056 + {
1.1057 + iNotif->iReturn=aResult;
1.1058 + iNotif->iTrigger=EAsyncCaptChan;
1.1059 + iNotif->iTxWords=NULL;
1.1060 + iNotif->iRxWords=NULL;
1.1061 + }
1.1062 + if(NKern::CurrentContext() == NKern::EInterrupt)
1.1063 + iNotif->Add();
1.1064 + else
1.1065 + iNotif->Enque();
1.1066 + }
1.1067 +
1.1068 +TInt DIicBusChannelSlave::StaticExtension(TUint /*aFunction*/, TAny* /*aParam1*/, TAny* /*aParam*/)
1.1069 + {
1.1070 + return KErrNotSupported;
1.1071 + }
1.1072 +
1.1073 +TInt DIicBusChannelSlave::Spare1(TInt /*aVal*/, TAny* /*aPtr1*/, TAny* /*aPtr2*/)
1.1074 + {
1.1075 + return KErrNotSupported;
1.1076 + }
1.1077 +
1.1078 +TInt DIicBusChannelMasterSlave::QueueTransaction(TIicBusTransaction* aTransaction)
1.1079 + {
1.1080 + return QueueTransaction(aTransaction,NULL);
1.1081 + };
1.1082 +
1.1083 +TInt DIicBusChannelMasterSlave::QueueTransaction(TIicBusTransaction* aTransaction, TIicBusCallback* aCallback)
1.1084 + {
1.1085 + TInt r=KErrNone;
1.1086 + iMasterChannel->Lock();
1.1087 + if(iSlaveChannel->iChannelInUse)
1.1088 + r=KErrInUse;
1.1089 + else
1.1090 + {
1.1091 + TInt16 count=(TInt16)((iMasterChannel->iTransCount)&~KTransCountMsBit);
1.1092 + if(count<~KTransCountMsBit)
1.1093 + {
1.1094 + ++count;
1.1095 + count|=KTransCountMsBit;
1.1096 + }
1.1097 + else
1.1098 + r=KErrInUse;
1.1099 + }
1.1100 + iMasterChannel->Unlock();
1.1101 + if(r == KErrNone)
1.1102 + r=(iMasterChannel->QueueTransaction(aTransaction, aCallback));
1.1103 + return r;
1.1104 + };
1.1105 +
1.1106 +TInt DIicBusChannelMasterSlave::CaptureChannel(TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch)
1.1107 + {
1.1108 + iMasterChannel->Lock();
1.1109 + TInt r=KErrNone;
1.1110 + if(iSlaveChannel->iChannelInUse)
1.1111 + r=KErrInUse;
1.1112 + else
1.1113 + {
1.1114 + if(iMasterChannel->IsMasterBusy())
1.1115 + r=KErrInUse;
1.1116 + else
1.1117 + iSlaveChannel->iChannelInUse = 1;
1.1118 + }
1.1119 + iMasterChannel->Unlock();
1.1120 + if(r == KErrNone)
1.1121 + r=iSlaveChannel->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch);
1.1122 + return r;
1.1123 + };
1.1124 +
1.1125 +
1.1126 +TInt DIicBusChannelMasterSlave::ReleaseChannel()
1.1127 + {
1.1128 + iMasterChannel->Lock();
1.1129 + TInt r=iSlaveChannel->ReleaseChannel();
1.1130 + iMasterChannel->Unlock();
1.1131 + return r;
1.1132 + };
1.1133 +
1.1134 +TInt DIicBusChannelMasterSlave::StaticExtension(TUint /*aFunction*/, TAny* /*aParam1*/, TAny* /*aParam*/)
1.1135 + {
1.1136 + return KErrNotSupported;
1.1137 + }
1.1138 +
1.1139 +#ifdef STANDALONE_CHANNEL
1.1140 +EXPORT_C DIicBusChannelMasterSlave::DIicBusChannelMasterSlave(TBusType aBusType, TChannelDuplex aChanDuplex, DIicBusChannelMaster* aMasterChan, DIicBusChannelSlave* aSlaveChan)
1.1141 + : DIicBusChannel(DIicBusChannel::EMasterSlave, aBusType, aChanDuplex),
1.1142 + iMasterChannel(aMasterChan),
1.1143 + iSlaveChannel(aSlaveChan)
1.1144 + {
1.1145 + //If in stand-alone channel mode, the client assigns a channel number to the MasterSlave channel it creates.
1.1146 + }
1.1147 +#endif
1.1148 +