os/kernelhwsrv/kernel/eka/drivers/iic/iic_channel.cpp
changeset 0 bde4ae8d615e
     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 +