os/kernelhwsrv/kernel/eka/drivers/iic/iic_channel.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // e32\drivers\iic_channel.cpp
    15 // IIC Channel Platform Independent Layer (PIL)
    16 //
    17 
    18 #include <drivers/iic_channel.h>
    19 #ifdef IIC_INSTRUMENTATION_MACRO
    20 #include <drivers/iic_trace.h>
    21 #endif
    22 
    23 // The timer call back function which calls the PSL's HandleSlaveTimeout()
    24 // Note that this assumes that the channel thread has been unblocked - if this
    25 // is not the case, the callback will never get to run
    26 
    27 TInt DIicBusChannelMaster::DoCreate()
    28     {return KErrNone;}
    29 
    30 void DIicBusChannelMaster::Lock()
    31     {NKern::FMWait(&iTransactionQLock);}
    32 
    33 void DIicBusChannelMaster::Unlock()
    34     {NKern::FMSignal(&iTransactionQLock);}
    35 
    36 TIicBusTransaction* DIicBusChannelMaster::NextTrans(TIicBusTransaction* aTrans)
    37     {
    38     // call multi-transaction call back function to get next transaction
    39     if((aTrans->iFlags&KTransactionWithPreamble)&&(aTrans->iFlags&KTransactionWithMultiTransc))
    40         return ((TIicBusTransactionPreambleExt*)aTrans)->iMultiTransc(aTrans, ((TIicBusTransactionPreambleExt*)aTrans)->iMultiTranscArg);
    41     else if(aTrans->iFlags&KTransactionWithMultiTransc)
    42         return ((TIicBusTransactionMultiTransc*)aTrans)->iMultiTransc(aTrans, ((TIicBusTransactionMultiTransc*)aTrans)->iMultiTranscArg);
    43     else
    44         return NULL;
    45     }
    46 
    47 void DIicBusChannelMaster::UnlockAndKick()
    48     {iTransQDfc.Enque(&iTransactionQLock);}
    49 
    50 void DIicBusChannelMaster::SlaveTimeoutCallback(TAny* aPtr)
    51 	{
    52 
    53 	DIicBusChannelMaster* aChanMaster=(DIicBusChannelMaster* )aPtr;
    54 	TInt r = aChanMaster->HandleSlaveTimeout();
    55 	aChanMaster->CompleteRequest(r);
    56 	}
    57 
    58 TInt DIicBusChannelMaster::TransFlow(TIicBusTransaction* aTransaction)
    59     {
    60     if(aTransaction->iHalfDuplexTrans == NULL)
    61         return KErrArgument;
    62     else if(aTransaction->iFullDuplexTrans == NULL)
    63         return DIicBusChannel::EHalfDuplex;
    64     else return DIicBusChannel::EFullDuplex;
    65     }
    66 
    67 TInt8 DIicBusChannelMaster::IsMasterBusy()
    68     {
    69     if((iTransCount&~KTransCountMsBit) == 0)
    70         return 0;
    71     else return 1;
    72     }
    73 
    74 DIicBusChannelMaster::DIicBusChannelMaster(TBusType aBusType, TChannelDuplex aChanDuplex)
    75 		: DIicBusChannel(DIicBusChannel::EMaster, aBusType, aChanDuplex),
    76 		iTransQDfc(DIicBusChannelMaster::MsgQFunc, this, NULL, 1), iChannelReady(EFalse)
    77 	{
    78 	new(&iTimeoutTimer) NTimer(SlaveTimeoutCallback,this);
    79 	}
    80 
    81 DIicBusChannelMaster::~DIicBusChannelMaster()
    82 	{
    83 	delete iSlaveTimeoutDfc;
    84 	}
    85 
    86 TInt DIicBusChannelMaster::Init()
    87 	{
    88 	iSlaveTimeoutDfc = new TDfc(SlaveTimeoutCallback,(TAny*)this, 7);	// Highest Dfc priority
    89 	if(!iSlaveTimeoutDfc)
    90 		return KErrNoMemory;
    91 	else
    92 		return KErrNone;
    93 	}
    94 
    95 // Function to used to indicate if the Slave response has exceeded
    96 // an expected time
    97 TInt DIicBusChannelMaster::StartSlaveTimeOutTimer(TInt aTime)
    98 	{
    99 	TInt r = iTimeoutTimer.OneShot(NKern::TimerTicks(aTime),(*iSlaveTimeoutDfc));
   100 	return r;
   101 	}
   102 
   103 void DIicBusChannelMaster::SetDfcQ(TDfcQue* aDfcQue)
   104 	{
   105     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::SetDfcQ 0x%x\n",aDfcQue));
   106 	__ASSERT_DEBUG(aDfcQue!=NULL, Kern::Fault(KIicChannelPanic,__LINE__));
   107 	iDfcQ=aDfcQue;
   108 	iTransQDfc.SetDfcQ(iDfcQ);
   109 	iSlaveTimeoutDfc->SetDfcQ(iDfcQ);
   110 	Lock();
   111 	__ASSERT_DEBUG(!iChannelReady, Kern::Fault(KIicChannelPanic,__LINE__));
   112 	if (!iTransactionQ.IsEmpty())
   113 		{
   114 		iTransaction=(TIicBusTransaction*)(iTransactionQ.First()->Deque());
   115 		__KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::SetDfcQ got %08x",iTransaction));
   116 		iTransaction->iState=TIicBusTransaction::EAccepted;
   117 		iCurrentTransaction = iTransaction;
   118 		UnlockAndKick();
   119 		}
   120 	else
   121 		{
   122 		__KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::SetDfcQ"));
   123 		iChannelReady=ETrue;
   124 		iTransaction=NULL;
   125 		iCurrentTransaction = NULL;
   126 		Unlock();
   127 		}
   128 	}
   129 
   130 void DIicBusChannelMaster::CompleteRequest(TInt aResult)
   131 	{
   132 	TIicBusTransaction* nextTrans=NextTrans(iCurrentTransaction);
   133 
   134 	if((aResult != KErrNone)||(nextTrans == NULL))
   135 		EndTransaction(iTransaction,aResult,iTransaction->iCallback);
   136 	else
   137 		{
   138 		nextTrans->iBusId = iCurrentTransaction->iBusId; // Pass the bus configuration info to the PSL
   139 		iCurrentTransaction = nextTrans;
   140 		DoRequest(nextTrans);
   141 		}
   142 	}
   143 
   144 #ifdef MASTER_MODE
   145 
   146 /*
   147 For Master-side transaction queuing APIs
   148 the Channel implementation sends the transaction as a message to the Channel's message queue,
   149 optionally blocking the client thread on the message's semaphore (synchronous APIs).
   150 */
   151 TInt DIicBusChannelMaster::QueueTransaction(TIicBusTransaction* aTransaction)
   152 	{
   153     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::QueueTransaction, aTransaction=0x%x\n",aTransaction));
   154 	// Send the transaction as a message to the Channel's message queue
   155 	// Synchronous API, so block the calling thread during the processing
   156 	TInt r = QueueTransaction(aTransaction, NULL);
   157 	if(r!=KErrNone)
   158 		return r;	// Transaction was not queued - so don't wait for a notification that it completed.
   159 
   160 	__KTRACE_OPT(KIIC, Kern::Printf("<DIicBusChannelMaster::QueueTransaction ret %d",aTransaction->iResult));
   161 	return aTransaction->iResult;
   162 	}
   163 
   164 TInt DIicBusChannelMaster::QueueTransaction(TIicBusTransaction* aTransaction, TIicBusCallback* aCallback)
   165 	{
   166 	__KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::QueueTransaction, aTransaction=0x%x, aCallback=0x%x\n",aTransaction,aCallback));
   167 
   168 	// Check aTransaction is non-NULL (aCallback may be NULL if the synchronous operation is required).
   169 	if(aTransaction == NULL)
   170 		{
   171 		return KErrArgument;
   172 		}
   173 
   174 	// Send the transaction as a message to the Channel's message queue and return
   175 	aTransaction->iCallback = aCallback;
   176 	if(aCallback != NULL)
   177 		{
   178 		aCallback->iTransaction = aTransaction;
   179 		}
   180 
   181 	// Call the PSL implementation to check that the header is valid for this channel
   182 	TInt r = CheckHdr(aTransaction->iHeader);
   183 	if(r!=KErrNone)
   184 		{
   185 		return r;
   186 		}
   187 
   188 	// Duplex operation is indicated in the transaction object
   189 	if((TransFlow((TIicBusTransaction*)aTransaction) == DIicBusChannel::EFullDuplex) &&
   190 	   (ChannelDuplex()                              != DIicBusChannel::EFullDuplex))
   191 		{
   192 		return KErrNotSupported;
   193 		}
   194 
   195 	DThread* pC =& Kern::CurrentThread();
   196 	Lock();
   197 	__ASSERT_DEBUG(aTransaction->iState == TIicBusTransaction::EFree, Kern::Fault(KIicChannelPanic,__LINE__));
   198 	if(!(iTransCount & KTransCountMsBit))
   199 		{
   200 		if(iTransCount < ~KTransCountMsBit)
   201 			{
   202 			++iTransCount;
   203 			}
   204 		else
   205 			{
   206 			Unlock();
   207 			return KErrOverflow;
   208 			}
   209 		}
   210 
   211 	aTransaction->iSyncNotification.iCount = 0;
   212 	aTransaction->iSyncNotification.iOwningThread = &pC->iNThread;
   213 	pC->Open();
   214 	if (iChannelReady)
   215 		{
   216 		aTransaction->iState = TIicBusTransaction::EAccepted;
   217 		iTransaction = aTransaction;
   218 		iCurrentTransaction = aTransaction;
   219 		iChannelReady = EFalse;
   220 		UnlockAndKick();
   221 		}
   222 	else
   223 		{
   224 		iTransactionQ.Add(aTransaction);
   225 		aTransaction->iState = TIicBusTransaction::EDelivered;
   226 		Unlock();
   227 		}
   228 
   229 	// Wait on a semaphore if called from synchronous version
   230 	if(aCallback == NULL)
   231 		{
   232 		NKern::FSWait(&aTransaction->iSyncNotification);
   233 		}
   234 
   235 	return KErrNone;
   236 	}
   237 
   238 TInt DIicBusChannelMaster::CancelTransaction(TIicBusTransaction* aTransaction)
   239 	{
   240     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::CancelTransaction, aTransaction=0x%x\n",aTransaction));
   241 
   242 	// Check aTransaction is non-NULL
   243 	if(aTransaction == NULL)
   244 		{
   245 		return KErrArgument;
   246 		}
   247 	// If the method is called on a synchronous transaction return KErrNotSupported
   248 	if(aTransaction->iCallback == NULL)
   249 		{
   250 		return KErrNotSupported;
   251 		}
   252 	DThread* pT = NULL;
   253 	Lock();
   254 
   255 	TInt r = KErrNone;
   256 	switch(aTransaction->iState)
   257 		{
   258 		case TIicBusTransaction::EDelivered:
   259 			{
   260 			aTransaction->Deque();
   261 			pT=_LOFF(aTransaction->iSyncNotification.iOwningThread,DThread,iNThread);
   262 			aTransaction->iState=TIicBusTransaction::EFree;
   263 			--iTransCount; // Count must be greater than zero if the transaction is in this state
   264 			r = KErrCancel;
   265 			break;
   266 			}
   267 
   268 		case TIicBusTransaction::EAccepted:
   269 			{
   270 			r = KErrInUse;
   271 			break;
   272 			}
   273 
   274 		case TIicBusTransaction::EFree:
   275 			{
   276 			r = KErrCancel;
   277 			break;
   278 			}
   279 		}
   280 	Unlock();
   281 	if (pT)
   282 		{
   283 		pT->AsyncClose();
   284 		}
   285 
   286 	return r;
   287 	}
   288 
   289 #else /*MASTER_MODE*/
   290 
   291 TInt DIicBusChannelMaster::QueueTransaction(TIicBusTransaction* /*aTransaction*/)
   292 	{
   293     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::QueueTransaction invoked when not in MASTER_MODE!\n"));
   294 	return KErrNotSupported;
   295 	}
   296 
   297 TInt DIicBusChannelMaster::QueueTransaction(TIicBusTransaction* /*aTransaction*/, TIicBusCallback* /*aCallback*/)
   298 	{
   299     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::QueueTransaction invoked when not in MASTER_MODE!\n"));
   300 	return KErrNotSupported;
   301 	}
   302 
   303 TInt DIicBusChannelMaster::CancelTransaction(TIicBusTransaction* /*aTransaction*/)
   304 	{
   305     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::CancelTransaction invoked when not in MASTER_MODE!\n"));
   306 	return KErrNotSupported;
   307 	}
   308 #endif/*MASTER_MODE*/
   309 
   310 // Invoked in response to receiving a message
   311 // Function argument is a pointer to the required channel object
   312 // Invoke the channel's PSL implementation of the DoRequest method with a pointer to the transaction object
   313 //
   314 void DIicBusChannelMaster::MsgQFunc(TAny* aPtr)
   315 	{
   316     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc, aPtr=0x%x\n",aPtr));
   317 	DIicBusChannelMaster* channel=(DIicBusChannelMaster*)aPtr;
   318 	TIicBusTransaction* trans = channel->iTransaction;
   319 
   320 #ifdef IIC_INSTRUMENTATION_MACRO
   321 	IIC_MPROCESSTRANS_START_PIL_TRACE;
   322 #endif
   323 
   324     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc trans->iHeader=0x%x\n",trans->iHeader));
   325     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc trans->iHalfDuplexTrans=0x%x\n",trans->iHalfDuplexTrans));
   326     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc trans->iFullDuplexTrans=0x%x\n",trans->iFullDuplexTrans));
   327     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc trans->iCallback=0x%x\n",trans->iCallback));
   328     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc trans->iFlags=0x%x\n",trans->iFlags));
   329 
   330 	TInt r = KErrNone;
   331 	// invoke the preamble callback function supplied by the client of the IIC if there is any
   332 	if(GetTransFlags(trans) & KTransactionWithPreamble)
   333 		{
   334 		TIicBusTransactionPreamble* transPreamble = (TIicBusTransactionPreamble*)trans;
   335 		TIicBusPreamble funcPtr=NULL;
   336 		funcPtr=(GetPreambleFuncPtr(transPreamble));
   337 		funcPtr(transPreamble,GetPreambleFuncArg(transPreamble));
   338 		}
   339 	r = channel->DoRequest(trans);	// Instigate processing in the PSL
   340 	if(r!=KErrNone)
   341 		channel->EndTransaction(trans, r, trans->iCallback);
   342 	}
   343 
   344 void DIicBusChannelMaster::EndTransaction(TIicBusTransaction* aTrans, TInt aResult, TIicBusCallback* aCb)
   345 	{
   346 #ifdef IIC_INSTRUMENTATION_MACRO
   347 	IIC_MPROCESSTRANS_END_PIL_TRACE;
   348 #endif
   349 	Complete(aResult,aTrans);
   350 	if(aCb != NULL)
   351 		{
   352 		aCb->iResult = aResult;
   353 		aCb->Enque();
   354 		}
   355 	}
   356 
   357 void DIicBusChannelMaster::CancelTimeOut()
   358 	{
   359 	iTimeoutTimer.Cancel();
   360 	}
   361 
   362 void DIicBusChannelMaster::Complete(TInt aResult, TIicBusTransaction* aTransaction) //Completes a kernel message and receive the next one
   363 	{
   364 	__KTRACE_OPT(KIIC, Kern::Printf("MsgB::Complete %08x, %d",this,aResult));
   365 	Lock();
   366 	__ASSERT_DEBUG(aTransaction->iState == TIicBusTransaction::EAccepted, Kern::Fault(KIicChannelPanic,__LINE__));
   367 	aTransaction->iResult=aResult;
   368 	aTransaction->iState=TIicBusTransaction::EFree;
   369 	--iTransCount;
   370 	DThread* pT=_LOFF(aTransaction->iSyncNotification.iOwningThread,DThread,iNThread);
   371 	__ASSERT_DEBUG(!iChannelReady, Kern::Fault(KIicChannelPanic,__LINE__));
   372 	if (!iTransactionQ.IsEmpty())
   373 		{
   374 		TIicBusTransaction* pM=(TIicBusTransaction*)iTransactionQ.First()->Deque();
   375 		__KTRACE_OPT(KIIC, Kern::Printf("rxnext: got %08x",pM));
   376 		pM->iState=TIicBusTransaction::EAccepted;
   377 		iTransaction = pM;
   378 		iCurrentTransaction = pM;
   379 		iTransQDfc.Enque();
   380 		}
   381 	else
   382 		{
   383 		__KTRACE_OPT(KIIC, Kern::Printf("rxnext"));
   384 		iChannelReady=ETrue;
   385 		iTransaction=NULL;
   386 		iCurrentTransaction = NULL;
   387 		}
   388 	NKern::FSSignal(&aTransaction->iSyncNotification,&iTransactionQLock);
   389 	pT->AsyncClose();
   390 	}
   391 
   392 TInt DIicBusChannelMaster::StaticExtension(TUint /*aFunction*/, TAny* /*aParam1*/, TAny* /*aParam*/)
   393  	{
   394  	return KErrNotSupported;
   395  	}
   396 
   397 TInt DIicBusChannelMaster::Spare1(TInt /*aVal*/, TAny* /*aPtr1*/, TAny* /*aPtr2*/)
   398 	{
   399 	return KErrNotSupported;
   400 	}
   401 
   402 #ifdef SLAVE_MODE
   403 
   404 TInt DIicBusChannelSlave::CaptureChannel(TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch)
   405 	{
   406 	// Only one client can have access to the Slave channel at any one time. Any subsequent attempts to capture the
   407 	// same channel should return an error.
   408 	//
   409     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::CaptureChannel\n"));
   410 	if((aConfigHdr == NULL) || (aCallback == NULL))
   411 		{
   412 	    __KTRACE_OPT(KIIC, Kern::Printf("ERROR: non-NULL argument aConfigHdr=0x%x, aCallback=0x%x\n",aConfigHdr,aCallback));
   413 		return KErrArgument;
   414 		}
   415 	//
   416 	// Check the header is valid for the channel
   417 	TInt r = CheckHdr(aConfigHdr);
   418 	if(r == KErrNone)
   419 		{
   420 		// Check Slave channel is available for capture
   421 		// If iChannelInUse is not set, capture should succeed
   422 		// If this Slave channel is part of a MasterSlave channel iChannelInUse will already be set
   423 		// but iClient will still be NULL. In this case, the capture should succeed.
   424 		TInt intState=__SPIN_LOCK_IRQSAVE(iSpinLock);
   425 		DThread* pT=&(Kern::CurrentThread());
   426 		if((iChannelInUse)&&(iClient!=NULL))
   427 			r=KErrInUse;
   428 		else
   429 			{
   430 			iChannelInUse=1;
   431 			iClient=pT;
   432 			}
   433 		__SPIN_UNLOCK_IRQRESTORE(iSpinLock,intState);
   434 
   435 		if(r == KErrNone)
   436 			{
   437 			iClient->Open();
   438 			aCallback->iChannel=this;
   439 			iNotif = aCallback;
   440 			iConfigHeader=aConfigHdr;	// Header alread checked, so just assign it
   441 
   442 			// Invoke the PSL processing
   443 			if(aAsynch)
   444 				{
   445 				aChannelId = 0; // the client should read iChannelId from the callback object.
   446 				r=DoRequest(EAsyncConfigPwrUp);
   447 				}
   448 			else
   449 				r=DoRequest(ESyncConfigPwrUp);
   450 
   451 			if(r == KErrNone)
   452 				{
   453 				if(!aAsynch)	// For asynchronous version there is nothing more to do until the callback is invoked
   454 					{
   455 					SetChannelId(aChannelId);
   456 					iClientTimeoutDfc->SetDfcQ(iNotif->iDfcQ);
   457 					}
   458 				}
   459 			else
   460 				{
   461 				// PSL encountered an error
   462 				ReleaseChannel();
   463 				if(aAsynch)
   464 					CompleteAsynchCapture(r);	// Queue the client callback for execution
   465 				}
   466 			}
   467 		}
   468 	return r;
   469 	}
   470 
   471 TInt DIicBusChannelSlave::ReleaseChannel()
   472 	{
   473 	__KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::ReleaseChannel\n"));
   474 	 // Release a previously-captured channel.
   475 	TInt r=KErrNone;;
   476 	// Ensure that only the channel's client may release the channel
   477 	DThread* pT=&(Kern::CurrentThread());
   478 	if(iClient!=pT)			// Direct access since iClient can't be modified while channel is still captured
   479 		return KErrAccessDenied;
   480 
   481 	r=SetNotificationTrigger(0);			// Attempt to clear notification requests
   482 	if((r!=KErrNone)&&(r!=KErrTimedOut))	// KErrTimedOut refers to an earlier transaction, and is for information only
   483 		return r;
   484 	iTimeoutTimer.Cancel();
   485 	r=DoRequest(EPowerDown);
   486 	if(r == KErrNone)
   487 		{
   488 		TInt intState=__SPIN_LOCK_IRQSAVE(iSpinLock);
   489 		iClient=NULL;
   490 		iChannelInUse=0;	// Channel now available for capture by other clients
   491 		__SPIN_UNLOCK_IRQRESTORE(iSpinLock,intState);
   492 		pT->AsyncClose();	// Allow Client thread to close now channel has been released
   493 		}
   494 	else
   495 		{
   496 		// PSL error when releasing the channel - have to assume the hardware has a problem.
   497 		// The channel is no longer considered "captured" by the controller, i.e. will not accept commands
   498 		// But not having cleared the busy flag means that it can not be used for master channel
   499 		// operations if it is part of a MasterSlave channel
   500 		// Must Fault the Kernel.
   501 		__KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::ReleaseChannel - PSL returned error code %d\n",r));
   502 		__ASSERT_ALWAYS(EFalse, Kern::Fault(KIicChannelPanic,__LINE__));
   503 		}
   504 	return r;
   505 	}
   506 
   507 TInt DIicBusChannelSlave::RegisterRxBuffer(TPtr8 aRxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
   508 	{
   509     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::RegisterRxBuffer\n"));
   510 #ifdef IIC_INSTRUMENTATION_MACRO
   511 	IIC_SREGRXBUF_START_PIL_TRACE;
   512 #endif
   513 	TInt r=KErrNone;
   514 	// Ensure that only the channel's client may perform this operation
   515 	DThread* pT=&(Kern::CurrentThread());
   516 	if(iClient!=pT)			// Direct access since iClient can't be modified while channel is still captured
   517 		return KErrAccessDenied;
   518 	//If the buffer pointer is NULL, return KErrArgument
   519 	if(aRxBuffer.Ptr() == NULL)
   520 		return KErrArgument;
   521 	// If a buffer is already registered, a subsequent request to do the same should return KErrAlreadyExists
   522 	// This will be the case if SetNotificationTrigger has been invoked with any of ERxAllBytes, ERxUnderrun or ERxOverrun
   523 	if(iReqTrig&(ERxAllBytes|ERxUnderrun|ERxOverrun))
   524 		r=KErrAlreadyExists;
   525 	else
   526 		{
   527 		iRxBuf=(TInt8*)(aRxBuffer.Ptr());
   528 		iRxGranularity=aBufGranularity;
   529 		iNumRxWords=aNumWords;
   530 		iRxOffset=aOffset;
   531 		}
   532 #ifdef IIC_INSTRUMENTATION_MACRO
   533 	IIC_SREGRXBUF_END_PIL_TRACE;
   534 #endif
   535 	 return r;
   536 	}
   537 
   538 TInt DIicBusChannelSlave::RegisterTxBuffer(TPtr8 aTxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
   539 	{
   540     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::RegisterTxBuffer	- default implementation\n"));
   541 #ifdef IIC_INSTRUMENTATION_MACRO
   542 	IIC_SREGTXBUF_START_PIL_TRACE;
   543 #endif
   544 	TInt r=KErrNone;
   545 	// Ensure that only the channel's client may perform this operation
   546 	DThread* pT=&(Kern::CurrentThread());
   547 	if(iClient!=pT)			// Direct access since iClient can't be modified while channel is still captured
   548 		return KErrAccessDenied;
   549 	//If the buffer pointer is NULL, return KErrArgument
   550 	if(aTxBuffer.Ptr() == NULL)
   551 		return KErrArgument;
   552 	// If a buffer is already registered and a request is pending, a subsequent request to register a buffer should return
   553 	// KErrAlreadyExists
   554 	// This will be the case if SetNotificationTrigger has been invoked with any of ETxAllBytes, ETxUnderrun or ETxOverrun
   555 	if(iReqTrig&(ETxAllBytes|ETxUnderrun|ETxOverrun))
   556 		r=KErrAlreadyExists;
   557 	else
   558 		{
   559 		iTxBuf=(TInt8*)(aTxBuffer.Ptr());
   560 		iTxGranularity=aBufGranularity;
   561 		iNumTxWords=aNumWords;
   562 		iTxOffset=aOffset;
   563 		}
   564 #ifdef IIC_INSTRUMENTATION_MACRO
   565 	IIC_SREGTXBUF_END_PIL_TRACE;
   566 #endif
   567 	return r;
   568 	}
   569 
   570 TInt DIicBusChannelSlave::SetNotificationTrigger(TInt aTrigger)
   571 	{
   572     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::SetNotificationTrigger invoked with aTrigger=0x%x\n",aTrigger));
   573 	// Ensure that only the channel's client may perform this operation
   574 	DThread* pT=&(Kern::CurrentThread());
   575 	if(iClient!=pT)			// Direct access since iClient can't be modified while channel is still captured
   576 		return KErrAccessDenied;
   577 
   578 	TInt retVal = KErrNone;
   579 	TInt trigger = aTrigger;
   580 	switch (iTimerState)	// Handle existing timer conditions
   581 		{
   582 		case DIicBusChannelSlave::EInactive:
   583 			{
   584 			// In this state no timers have been started - so no action required
   585 			break;
   586 			}
   587 		case DIicBusChannelSlave::EWaitForClient:
   588 			{
   589 			// Client has responded within the given time period, so stop the timer.
   590 			StopTimer();
   591 			break;
   592 			}
   593 		case DIicBusChannelSlave::EWaitForMaster:
   594 			{
   595 			// If both Rx and Tx events had been requested, and if ERxOverrun had occurred, the Client
   596 			// may have called this function with new requests for Rx notifications, in order to
   597 			// continue reading data sent by the Master. At this point, all Rx request flags in iReqTrig
   598 			// will have been cleared.
   599 			// If both Rx and Tx events had been requested, and if ETxUnderrun had occurred, the Client
   600 			// may have called this function with new requests for Tx notifications, in order to
   601 			// continue sending data to the Master. At this point, all Tx request flags in iReqTrig will
   602 			// have been cleared.
   603 			//
   604 			// To handle the ERxOverrun situation, aTrigger may specify only the new Rx trigger settings,
   605 			// or it may also re-specify the exisiting Tx settings. Similarly for the ETxUnderrun, aTrigger
   606 			// may specify only the new Tx triggers, or both the new Tx triggers and the existing Rx triggers.
   607 			//
   608 			// However, if Rx flags are still set in iReqTrig, a request to change the Rx settings
   609 			// will be rejected (similarly, for Tx).
   610 			//
   611 			// If the requested notification is zero, which would represent an attempt to clear all triggers
   612 			// while the Master may have commenced a transfer, the request will be rejected.
   613 			__ASSERT_DEBUG(iReqTrig != 0, Kern::Fault(KIicChannelPanic,__LINE__));
   614 			if(trigger == 0)
   615 				{
   616 				return KErrInUse;
   617 				}
   618 			TInt allRxFlags = ERxAllBytes | ERxOverrun | ERxUnderrun;
   619 			TInt allTxFlags = ETxAllBytes | ETxOverrun | ETxUnderrun;
   620 			// Check the Rx flags
   621 			TInt rxTrig = iReqTrig & allRxFlags;
   622 			TInt reqRxTrig = trigger & allRxFlags;
   623 			if(rxTrig == 0)
   624 				{
   625 				rxTrig = reqRxTrig;
   626 				}
   627 			else if(reqRxTrig != 0)
   628 				{
   629 				// New Rx triggers specified - check that Client is not attempting to modify the existing
   630 				// settings
   631 				if(rxTrig ^ reqRxTrig)
   632 					{
   633 					// Attempting to change the trigger settings - so reject the request
   634 					return KErrInUse;
   635 					}
   636 				}
   637 			// Check the Tx flags
   638 			TInt txTrig = iReqTrig & allTxFlags;
   639 			TInt reqTxTrig = trigger & allTxFlags;
   640 			if(txTrig == 0)
   641 				{
   642 				txTrig = reqTxTrig;
   643 				}
   644 			else if(reqTxTrig != 0)
   645 				{
   646 				// New Tx triggers specified - check that Client is not attempting to modify the existing
   647 				// settings
   648 				if(txTrig ^ reqTxTrig)
   649 					{
   650 					// Attempting to change the trigger settings - so reject the request
   651 					return KErrInUse;
   652 					}
   653 				}
   654 			// Udate iReqTrig for the new requested trigger
   655 			// and cancel the timer - since we are now starting a new transfer, we should
   656 			// allow the Master the time to perform it
   657 			trigger = rxTrig | txTrig;
   658 			StopTimer();
   659 			break;
   660 			}
   661 		case DIicBusChannelSlave::EClientTimeout:
   662 			{
   663 			// The Client did not respond within the expected time for the previous transfer. As a result,
   664 			// the transaction will have been terminated for the Client.
   665 			// Set the return value to inform the Client that it previously exceeded the expected response time
   666 			retVal = KErrTimedOut;
   667 			break;
   668 			}
   669 		default:
   670 			{
   671 			__ASSERT_DEBUG(0, Kern::Fault(KIicChannelPanic,__LINE__));
   672 			break;
   673 			}
   674 		}
   675 	// Ensure that requests for notification of asynchronous capture of channel is removed, since this
   676 	// is not a valid event to request (the channel will already have been captured to get this far).
   677 	// Also ensure that requests for EGeneralBusError are removed, since they are redundant (a notification
   678 	// for a bus error is unconditional) and just represent overhead.
   679 	trigger &= ~(EAsyncCaptChan | EGeneralBusError);
   680 
   681 	iReqTrig = (TInt8)trigger; 				// Not atomic access since only client thread modifies iReqTrig
   682 	iAccumTrig = 0;						// New transfer, so initialise accumulated event record
   683 	TInt reqFlags=0;
   684 	// Overrun and/or underrun may be requested if Client is unsure how much data is to follow,
   685 	// so need to instigate Rx/Tx operation for any such request
   686 	if(iReqTrig & (ERxOverrun|ERxUnderrun|ERxAllBytes))
   687 		{
   688 		reqFlags |= EReceive;
   689 		}
   690 	if(iReqTrig & (ETxOverrun|ETxUnderrun|ETxAllBytes))
   691 		{
   692 		reqFlags |= ETransmit;
   693 		}
   694 	TInt r = DoRequest(reqFlags);
   695 	if(r != KErrNone)
   696 		{
   697 		// PSL encountered an error in intiating the requested trigger. Set the return value accordingly.
   698 		// Assume triggers have been cancelled - if they have not, the client-provided callback will still
   699 		// be invoked, but it will have been warned to expecte erroneous behaviour by the value assigned to retVal.
   700 		iReqTrig = 0;
   701 		retVal = KErrGeneral;
   702 		}
   703 	else	// PSL accepted the request, so update timer and state information
   704 		{
   705 		switch (iTimerState)
   706 			{
   707 			case DIicBusChannelSlave::EInactive:
   708 				{
   709 				// Do not start the timer. Must wait for the Master to access a Slave buffer before considering
   710 				// a transaction as started.
   711 				break;
   712 				}
   713 			case DIicBusChannelSlave::EWaitForClient:
   714 				{
   715 				// Client has responded within the given time period. The next state is
   716 				// dependent on the requested trigger - if set to zero, the Client is explicitly
   717 				// ending the transaction, so the next state is EInactive; otherwise, the
   718 				// Client has indicated the next action expected from the Master and so the
   719 				// timer is started and next state is EWaitForMaster
   720 				if(iReqTrig == 0)
   721 					{
   722 					iTimerState = DIicBusChannelSlave::EInactive;
   723 					}
   724 				else
   725 					{
   726 					iTimerState = DIicBusChannelSlave::EWaitForMaster;
   727 					StartTimerByState();
   728 					}
   729 				break;
   730 				}
   731 			case DIicBusChannelSlave::EClientTimeout:
   732 				{
   733 				// For the previous transfer, the Client failed to respond within the required time - and
   734 				// the PSL will have been instructed to indicate a bus error (so the Master
   735 				// will have been informed). The error code returned by this function will be KErrTimedOut
   736 				// so the Client will be informed of what has happened.
   737 				// A transaction is considered to start when the Slave is addressed by the Master
   738 				// (as indicated by the PSL invoking NotifyClient) - which has not yet happened -
   739 				// so the next state is EInactive.
   740 				iTimerState=DIicBusChannelSlave::EInactive;
   741 				break;
   742 				}
   743 			case DIicBusChannelSlave::EWaitForMaster:
   744 				{
   745 				// In this case we are handling a new requested trigger from the client to handle ERxOverrun or
   746 				// ETxUnderrun. The PSL has accepted the new trigger, so must allow the Master sufficient time
   747 				// to perform the newly-requested transfer; the timer has already been stopped, so just start it again..
   748 				StartTimerByState();
   749 				break;
   750 				}
   751 			default:
   752 				{
   753 				__ASSERT_DEBUG(0, Kern::Fault(KIicChannelPanic,__LINE__));
   754 				break;
   755 				}
   756 			}
   757 		}
   758 
   759 	return retVal;
   760 	}
   761 #else /*SLAVE_MODE*/
   762 
   763 TInt DIicBusChannelSlave::CaptureChannel(TDes8* /*aConfigHdr*/, TIicBusSlaveCallback* /*aCallback*/, TInt& /*aChannelId*/, TBool /*aAsynch*/)
   764 	{
   765     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::CaptureChannel invoked when not in SLAVE_MODE!\n"));
   766 	 return KErrNotSupported;
   767 	}
   768 
   769 TInt DIicBusChannelSlave::ReleaseChannel()
   770 	{
   771     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::ReleaseChannel invoked when not in SLAVE_MODE!\n"));
   772 	 return KErrNotSupported;
   773 	}
   774 
   775 TInt DIicBusChannelSlave::RegisterRxBuffer(TPtr8 /*aRxBuffer*/, TInt8 /*aBufGranularity*/, TInt8 /*aNumWords*/, TInt8 /*aOffset*/)
   776 	{
   777     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::RegisterRxBuffer invoked when not in SLAVE_MODE!\n"));
   778 	 return KErrNotSupported;
   779 	}
   780 
   781 TInt DIicBusChannelSlave::RegisterTxBuffer(TPtr8 /*aTxBuffer*/, TInt8 /*aBufGranularity*/, TInt8 /*aNumWords*/, TInt8 /*aOffset*/)
   782 	{
   783     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::RegisterTxBuffer invoked when not in SLAVE_MODE!\n"));
   784 	 return KErrNotSupported;
   785 	}
   786 
   787 TInt DIicBusChannelSlave::SetNotificationTrigger(TInt /*aTrigger*/)
   788 	{
   789     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::SetNotificationTrigger invoked when not in SLAVE_MODE!\n"));
   790 	 return KErrNotSupported;
   791 	}
   792 #endif/*SLAVE_MODE*/
   793 
   794 DIicBusChannelSlave::DIicBusChannelSlave(TBusType aBusType, TChannelDuplex aChanDuplex, TInt16 aChannelId)
   795 	: DIicBusChannel(DIicBusChannel::ESlave, aBusType, aChanDuplex),
   796 	iChannelId(aChannelId), iTimerState(EInactive),
   797 	iMasterWaitTime(KSlaveDefMWaitTime), iClientWaitTime(KSlaveDefCWaitTime),
   798 	iSpinLock(TSpinLock::EOrderGenericIrqLow2)  // Semi-arbitrary, low priority value
   799 	{
   800 #ifndef STANDALONE_CHANNEL
   801 	iController = NULL;
   802 #endif
   803 	}
   804 
   805 DIicBusChannelSlave::~DIicBusChannelSlave()
   806     {
   807     delete iClientTimeoutDfc;
   808     }
   809 
   810 void DIicBusChannelSlave::SlaveStaticCB(TAny* aPtr)
   811 	{
   812 	DIicBusChannelSlave* chan = (DIicBusChannelSlave*)aPtr;
   813 	chan->SlaveTimerCallBack();
   814 	return;
   815 	}
   816 
   817 TInt DIicBusChannelSlave::Init()
   818 	{
   819 	iClientTimeoutDfc = new TDfc(SlaveStaticCB,(TAny*)this, 7);	// Highest Dfc priority
   820 	if(!iClientTimeoutDfc)
   821 		return KErrNoMemory;
   822 	else
   823 		return KErrNone;
   824 	}
   825 
   826 void DIicBusChannelSlave::ChanCaptureCallback(TInt aResult)
   827 	{
   828     __KTRACE_OPT(KIIC, Kern::Printf("ChanCaptureCallback: aChannel=0x%x, aResult=%d\n",this,aResult));
   829 
   830 	TInt r=aResult;
   831 	TInt channelId = 0;
   832 	if(aResult == KErrNone)
   833 		{
   834 		SetChannelId(channelId);
   835 #ifndef STANDALONE_CHANNEL
   836 		__ASSERT_DEBUG(iController, Kern::Fault(KIicChannelPanic,__LINE__));
   837 		iController->InstallCapturedChannel(channelId, this);
   838 #endif
   839 		iClientTimeoutDfc->SetDfcQ(iNotif->iDfcQ);
   840 		r=KErrCompletion;
   841 		}
   842 	else
   843 		ReleaseChannel();
   844 
   845 #ifdef IIC_INSTRUMENTATION_MACRO
   846 	IIC_SCAPTCHANASYNC_END_PIL_TRACE;
   847 #endif
   848 	CompleteAsynchCapture(r);	// Queue the client callback for execution
   849 	}
   850 
   851 void DIicBusChannelSlave::SlaveTimerCallBack()
   852 	{
   853     __KTRACE_OPT(KIIC, Kern::Printf("SlaveTimerCallBack"));
   854 	if(iTimerState == DIicBusChannelSlave::EWaitForMaster)
   855 		{
   856 		// Master timeout. Consider the transaction terminated - call NotifyClient
   857 		// to inform both the Client and the PSL, and update the state machine
   858 		NotifyClient(EGeneralBusError);
   859 		}
   860 	else if(iTimerState == DIicBusChannelSlave::EWaitForClient)
   861 		{
   862 		// Client timeout. Instigate the PSL-specific bus error indication
   863 		iTimerState=DIicBusChannelSlave::EClientTimeout;
   864 		SendBusErrorAndReturn();
   865 		}
   866 	else
   867 		{
   868 		__ASSERT_DEBUG(0, Kern::Fault(KIicChannelPanic,__LINE__));
   869 		}
   870 	}
   871 
   872 
   873 void DIicBusChannelSlave::StartTimerByState()
   874 	{
   875 	if(iTimerState == DIicBusChannelSlave::EWaitForMaster)
   876 		{
   877 		iTimeoutTimer.OneShot(NKern::TimerTicks(iMasterWaitTime),(*iClientTimeoutDfc));
   878 		}
   879 	else if(iTimerState == DIicBusChannelSlave::EWaitForClient)
   880 		{
   881 		iTimeoutTimer.OneShot(NKern::TimerTicks(iClientWaitTime),(*iClientTimeoutDfc));
   882 		}
   883 	else
   884 		{
   885 		__ASSERT_DEBUG(NULL, Kern::Fault(KIicChannelPanic,__LINE__));
   886 		}
   887 	}
   888 
   889 void DIicBusChannelSlave::StopTimer()
   890 	{
   891 	iTimeoutTimer.Cancel();
   892 	}
   893 
   894 TInt DIicBusChannelSlave::UpdateReqTrig(TInt8& aCbTrigVal, TInt& aCallbackRet)
   895 	{
   896     __KTRACE_OPT(KIIC, Kern::Printf("UpdateReqTrig"));
   897 
   898 	TInt nextSteps = 0;
   899 	iAccumTrig |= iNotif->iTrigger;	// Update the accumulated event history, regardless of if the trigger was requested
   900 
   901 	if(iNotif->iTrigger & EGeneralBusError)
   902 		{
   903 		// In the event of a bus error, always cancel the timer and call the Client callback
   904 		nextSteps |= (EStopTimer | EInvokeCb);
   905 		iTimerState = EInactive;
   906 		aCallbackRet = KErrGeneral;
   907 		}
   908 	else if(iNotif->iTrigger == EAsyncCaptChan)
   909 		{
   910 		// For asynchronous channel capture, no timers are involved - just call the Client callback
   911 		nextSteps |= EInvokeCb;
   912 		aCallbackRet = KErrCompletion;
   913 		}
   914 	else if((iNotif->iTrigger & iReqTrig) != 0)
   915 		{
   916 		// If a requested Rx event has occurred, clear all Rx flags from the requested triggers (similarly for Tx)
   917 		if(iNotif->iTrigger & (ERxAllBytes | ERxUnderrun | ERxOverrun))
   918 			{
   919 			iReqTrig &= ~(ERxAllBytes | ERxUnderrun | ERxOverrun);
   920 			}
   921 		if(iNotif->iTrigger & (ETxAllBytes | ETxUnderrun | ETxOverrun))
   922 			{
   923 			iReqTrig &= ~(ETxAllBytes | ETxUnderrun | ETxOverrun);
   924 			}
   925 
   926 		if(iTimerState == EInactive)
   927 			{
   928 			nextSteps |= (EStartTimer | EInvokeCb);
   929 			// The next state in the state machine depends on if all the requested events have occurred
   930 			if(iReqTrig == 0)
   931 				{
   932 				// All triggers required have occurred, so transition to state EWaitForClient
   933 				iTimerState = EWaitForClient;
   934 				}
   935 			else
   936 				{
   937 				// The Client can request both Rx an Tx triggers; if only one has occurred, must wait for
   938 				// the Master to generate the other
   939 				iTimerState = EWaitForMaster;
   940 				}
   941 			aCallbackRet = KErrNone;
   942 			}
   943 		else if(iTimerState == EWaitForMaster)
   944 			{
   945 			// The next state in the state machine depends on if all the requested events have occurred
   946 			if(iReqTrig == 0)
   947 				{
   948 				// All triggers required have occurred, so transition to state EWaitForClient
   949 				iTimerState = EWaitForClient;
   950 				nextSteps |= (EStopTimer | EInvokeCb | EStartTimer);
   951 				}
   952 			else
   953 				{
   954 				// The Client can request both Rx an Tx triggers; if only one has occurred, must wait for
   955 				// the Master to generate the other - so remain in this state, do not cancel the timer or
   956 				// re-start it with a new timeout period. Still invoke the callback to notify the client
   957 				// that at least one of the requested triggers has occurred.
   958 				nextSteps |= EInvokeCb;
   959 				}
   960 			aCallbackRet = KErrNone;
   961 			}
   962 		else if((iTimerState == EWaitForClient) || (iTimerState == EClientTimeout))
   963 			{
   964 			// No triggers are expected in these states (iReqTrig==0).
   965 			__ASSERT_DEBUG(NULL, Kern::Fault(KIicChannelPanic,__LINE__));
   966 			}
   967 		}
   968 	aCbTrigVal = iAccumTrig;
   969 	return nextSteps;
   970 	}
   971 
   972 
   973 void DIicBusChannelSlave::NotifyClient(TInt aTrigger)
   974 	{
   975 	TIicBusSlaveCallback* notif = iNotif;
   976 	notif->iTrigger = aTrigger;	// Ensure ProcessData is provided with the trigger
   977 
   978 	if(NKern::CurrentContext() == NKern::EThread && &(Kern::CurrentThread()) == iClient)
   979 		{
   980 		// PSL will update notif to represent the events that have occurred
   981 		ProcessData(aTrigger, notif);
   982 		// Only invoke the client's callback (and update the state machine) if one of the requested triggers has
   983 		// occurred or if a bus error has been witnessed
   984 		TInt8 callbackTrig=0;
   985 		TInt callbackRet=0;
   986 		TInt nextSteps = UpdateReqTrig(callbackTrig, callbackRet);
   987 		if(nextSteps & EStopTimer)
   988 			{
   989 			iTimeoutTimer.Cancel();
   990 			}
   991 		if(nextSteps & EInvokeCb)
   992 			{
   993 			(notif->iCallback)(notif->iChannelId, (TInt)callbackRet, callbackTrig, notif->iRxWords, notif->iTxWords, notif->iParam);
   994 			// Callback now processed, so re-initialise callback object members
   995 			notif->iTrigger=0;
   996 			notif->iReturn=KErrNone;
   997 			notif->iRxWords=0;
   998 			notif->iTxWords=0;
   999 			iAccumTrig = 0;	// and re-initialise the accumulated history as the transaction is considered terminated
  1000 			}
  1001 		if(nextSteps & EStartTimer)
  1002 			{
  1003 			StartTimerByState();
  1004 			}
  1005 		}
  1006 	else if(NKern::CurrentContext() == NKern::EInterrupt)
  1007 			notif->Add();
  1008 	else
  1009 		notif->Enque();
  1010 	}
  1011 
  1012 TInt DIicBusChannelSlave::SetMasterWaitTime(TInt8 aWaitTime)
  1013 	{
  1014 	if((aWaitTime<0)||(aWaitTime>KMaxWaitTime))
  1015 		return KErrArgument;
  1016 	iMasterWaitTime=aWaitTime;
  1017 	return KErrNone;
  1018 	}
  1019 
  1020 TInt DIicBusChannelSlave::SetClientWaitTime(TInt8 aWaitTime)
  1021 	{
  1022 	if((aWaitTime<0)||(aWaitTime>KMaxWaitTime))
  1023 		return KErrArgument;
  1024 	iClientWaitTime=aWaitTime;
  1025 	return KErrNone;
  1026 	}
  1027 
  1028 void DIicBusChannelSlave::SendBusErrorAndReturn()
  1029 	{
  1030 	DoRequest(EAbort);
  1031 	}
  1032 
  1033 void DIicBusChannelSlave::SetChannelId(TInt& aChannelId)
  1034     {
  1035     ++iInstanceCount;
  1036     aChannelId = (iInstanceCount<<16);
  1037     //
  1038     // The PSL-specific channel identifier was stored in this generic class' member iChannelId at registration time
  1039     aChannelId |= iChannelId;
  1040     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::SetChannelId: iInstanceCount=0x%x, iChannelId=0x%x returned aChannelId=0x%x\n",iInstanceCount,iChannelId,aChannelId));
  1041     iNotif->iChannelId=aChannelId;
  1042     }
  1043 
  1044 void DIicBusChannelSlave::CompleteAsynchCapture(TInt aResult)
  1045     {
  1046     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::CompleteAsynchCapture aResult = %d",aResult));
  1047     if(NKern::CurrentContext() == NKern::EThread && &Kern::CurrentThread() == iClient)
  1048         {
  1049         iNotif->iCallback(iNotif->iChannelId, aResult, EAsyncCaptChan, NULL, NULL, iNotif->iParam);
  1050         return;
  1051         }
  1052     else
  1053         {
  1054         iNotif->iReturn=aResult;
  1055         iNotif->iTrigger=EAsyncCaptChan;
  1056         iNotif->iTxWords=NULL;
  1057         iNotif->iRxWords=NULL;
  1058         }
  1059     if(NKern::CurrentContext() == NKern::EInterrupt)
  1060         iNotif->Add();
  1061     else
  1062         iNotif->Enque();
  1063     }
  1064 
  1065 TInt DIicBusChannelSlave::StaticExtension(TUint /*aFunction*/, TAny* /*aParam1*/, TAny* /*aParam*/)
  1066  	{
  1067  	return KErrNotSupported;
  1068  	}
  1069 
  1070 TInt DIicBusChannelSlave::Spare1(TInt /*aVal*/, TAny* /*aPtr1*/, TAny* /*aPtr2*/)
  1071 	{
  1072 	return KErrNotSupported;
  1073 	}
  1074 
  1075 TInt DIicBusChannelMasterSlave::QueueTransaction(TIicBusTransaction* aTransaction)
  1076 	{
  1077 	return QueueTransaction(aTransaction,NULL);
  1078 	};
  1079 
  1080 TInt DIicBusChannelMasterSlave::QueueTransaction(TIicBusTransaction* aTransaction, TIicBusCallback* aCallback)
  1081 	{
  1082 	TInt r=KErrNone;
  1083 	iMasterChannel->Lock();
  1084 	if(iSlaveChannel->iChannelInUse)
  1085 		r=KErrInUse;
  1086 	else
  1087 		{
  1088 		TInt16 count=(TInt16)((iMasterChannel->iTransCount)&~KTransCountMsBit);
  1089 		if(count<~KTransCountMsBit)
  1090 			{
  1091 			++count;
  1092 			count|=KTransCountMsBit;
  1093 			}
  1094 		else
  1095 			r=KErrInUse;
  1096 		}
  1097 	iMasterChannel->Unlock();
  1098 	if(r == KErrNone)
  1099 		r=(iMasterChannel->QueueTransaction(aTransaction, aCallback));
  1100 	return r;
  1101 	};
  1102 
  1103 TInt DIicBusChannelMasterSlave::CaptureChannel(TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch)
  1104 	{
  1105 	iMasterChannel->Lock();
  1106 	TInt r=KErrNone;
  1107 	if(iSlaveChannel->iChannelInUse)
  1108 		r=KErrInUse;
  1109 	else
  1110 		{
  1111 		if(iMasterChannel->IsMasterBusy())
  1112 			r=KErrInUse;
  1113 		else
  1114 			iSlaveChannel->iChannelInUse = 1;
  1115 		}
  1116 	iMasterChannel->Unlock();
  1117 	if(r == KErrNone)
  1118 		r=iSlaveChannel->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch);
  1119 	return r;
  1120 	};
  1121 
  1122 
  1123 TInt DIicBusChannelMasterSlave::ReleaseChannel()
  1124     {
  1125 	iMasterChannel->Lock();
  1126 	TInt r=iSlaveChannel->ReleaseChannel();
  1127 	iMasterChannel->Unlock();
  1128 	return r;
  1129 	};
  1130 
  1131 TInt DIicBusChannelMasterSlave::StaticExtension(TUint /*aFunction*/, TAny* /*aParam1*/, TAny* /*aParam*/)
  1132  	{
  1133  	return KErrNotSupported;
  1134  	}
  1135 
  1136 #ifdef STANDALONE_CHANNEL
  1137 EXPORT_C DIicBusChannelMasterSlave::DIicBusChannelMasterSlave(TBusType aBusType, TChannelDuplex aChanDuplex, DIicBusChannelMaster* aMasterChan, DIicBusChannelSlave* aSlaveChan)
  1138     : DIicBusChannel(DIicBusChannel::EMasterSlave, aBusType, aChanDuplex),
  1139     iMasterChannel(aMasterChan),
  1140     iSlaveChannel(aSlaveChan)
  1141     {
  1142     //If in stand-alone channel mode, the client assigns a channel number to the MasterSlave channel it creates.
  1143     }
  1144 #endif
  1145