os/kernelhwsrv/kerneltest/e32test/iic/iic_psl/iic_slaveclient.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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 // e32test/iic/iic_slaveclient.cpp
    15 // Simulated client of IIC Platform Independent Layer (PIL) Slave functionality
    16 //
    17 
    18 #include <kernel/kern_priv.h>		// for DThread, TDfc
    19 #ifdef STANDALONE_CHANNEL
    20 #include <drivers/iic_transaction.h>
    21 #else
    22 #include <drivers/iic.h>
    23 #endif
    24 #include "../t_iic.h"
    25 
    26 #ifdef STANDALONE_CHANNEL
    27 #include <drivers/iic_channel.h>
    28 #include "i2c.h"
    29 #endif
    30 #ifdef LOG_SLAVECLIENT
    31 #define CLIENT_PRINT(str) Kern::Printf str
    32 #else
    33 #define CLIENT_PRINT(str)
    34 #endif
    35 
    36 //For channel creation
    37 #ifdef STANDALONE_CHANNEL
    38 #define NUM_CHANNELS 3 // Arbitrary
    39 
    40 #if defined(MASTER_MODE) && !defined(SLAVE_MODE)
    41 const TInt KChannelTypeArray[NUM_CHANNELS] = {DIicBusChannel::EMaster, DIicBusChannel::EMaster, DIicBusChannel::EMaster};
    42 #elif defined(MASTER_MODE) && defined(SLAVE_MODE)
    43 const TInt KChannelTypeArray[NUM_CHANNELS] = {DIicBusChannel::EMaster, DIicBusChannel::ESlave, DIicBusChannel::EMasterSlave};
    44 #else
    45 const TInt KChannelTypeArray[NUM_CHANNELS] = {DIicBusChannel::ESlave, DIicBusChannel::ESlave, DIicBusChannel::ESlave};
    46 #endif
    47 #define CHANNEL_TYPE(n) (KChannelTypeArray[n])
    48 #define CHANNEL_DUPLEX(n) (DIicBusChannel::EHalfDuplex)
    49 #define BUS_TYPE (DIicBusChannel::EI2c)
    50 
    51 #if defined(MASTER_MODE)
    52 const TInt8 KI2cChannelNumBase = 10;	// Arbitrary, real platform may consult the Configuration Repository
    53 										// Note limit of 5 bit representation (0-31)
    54 
    55 #else
    56 const TInt8 KI2cChannelNumBase = 10 + NUM_CHANNELS;	// For Slave mode, want to provide different response
    57 													// If client assumes Master mode, should be informed not available
    58 #endif/*MASTER_MODE*/
    59 
    60 LOCAL_C TInt8 AssignChanNumI2c()
    61 	{
    62 	static TInt8 iBaseChanNumI2c = KI2cChannelNumBase;
    63 	CLIENT_PRINT(("I2C AssignChanNum - on entry, iBaseChanNum = 0x%x\n",iBaseChanNumI2c));
    64 	return iBaseChanNumI2c++; // Arbitrary, for illustration
    65 	}
    66 
    67 class DIicSlaveClientChan : public DBase
    68 	{
    69 public:
    70 	DIicSlaveClientChan(DIicBusChannel* aChan, TInt8 aChanNum, TInt aChanType):iChan(aChan),iChanNumber(aChanNum),iChanType(aChanType){};
    71 	~DIicSlaveClientChan();
    72 	TInt GetChanNum()const {return iChanNumber;};
    73 	TInt GetChanType()const {return iChanType;};
    74 	DIicBusChannel* GetChannelPtr(){return iChan;};
    75 private:
    76 	TInt8 iChanNumber;
    77 	TInt iChanType;
    78 	DIicBusChannel* iChan;
    79 	};
    80 
    81 DIicSlaveClientChan::~DIicSlaveClientChan()
    82 	{
    83 	if(iChan)
    84 		delete iChan;
    85 	}
    86 
    87 #endif/*STANDALONE_CHANNEL*/
    88 
    89 const TInt KIicSlaveClientThreadPriority = 24;
    90 
    91 const TInt KIicSlaveClientDfcPriority = 3; // 0 to 7, 7 is highest
    92 
    93 const TInt KMaxNumChannels = 2;	// 1 "true" slave, one "dummy"
    94 
    95 #ifdef STANDALONE_CHANNEL
    96 _LIT(KLddRootName,"iic_slaveclient_ctrless");
    97 #else
    98 _LIT(KLddRootName,"iic_slaveclient");
    99 #endif
   100 _LIT(KIicSlaveClientThreadName,"IicSlaveClientLddThread");
   101 
   102 
   103 struct TCapsIicSlaveClient
   104     {
   105     TVersion version;
   106     };
   107 
   108 
   109 class DDeviceIicSlaveClient : public DLogicalDevice
   110     {
   111     public:
   112     /**
   113      * The constructor
   114      */
   115     DDeviceIicSlaveClient();
   116     /**
   117      * The destructor
   118      */
   119     ~DDeviceIicSlaveClient();
   120     /**
   121      * Second stage constructor - install the device
   122      */
   123     virtual TInt Install();
   124     /**
   125      * Get the Capabilites of the device
   126      * @param aDes descriptor that will contain the returned capibilites
   127      */
   128     virtual void GetCaps(TDes8 &aDes) const;
   129     /**
   130      * Create a logical channel to the device
   131      */
   132     virtual TInt Create(DLogicalChannelBase*& aChannel);
   133     };
   134 
   135 
   136 class DChannelIicSlaveClient : public DLogicalChannel
   137     {
   138     public:
   139     DChannelIicSlaveClient();
   140     ~DChannelIicSlaveClient();
   141 
   142     virtual TInt DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer);
   143 
   144 	void RequestComplete(TInt r);
   145 	TInt CheckDataWritten();
   146 	TInt CheckDataRead();
   147 
   148 	static void SlaveClientCallbackFunc(TInt aChannelId, TInt aReturn, TInt aTrigger, TInt16 aRxWords, TInt16 aTxWords, TAny*	aParam);
   149 #ifdef STANDALONE_CHANNEL
   150 	static TInt OrderEntries(const DIicSlaveClientChan& aMatch, const DIicSlaveClientChan& aEntry);
   151 #endif
   152     protected:
   153     virtual void HandleMsg(TMessageBase* aMsg);	// Note: this is a pure virtual in DLogicalChannel
   154 
   155 	TInt DoControl(TInt aId, TAny* a1, TAny* a2); // Name for convenience!
   156     TInt DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2); // Name for convenience!
   157 
   158 	private:
   159 	TInt InitSlaveClient();
   160 	TInt CbProcessOverUnderRunRxTx();
   161 	TInt RegisterRxBuffer(TInt aChannelId, TPtr8 aRxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset);
   162 	TInt SetNotificationTrigger(TInt aChannelId, TInt aTrigger);
   163 	TInt StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2);
   164 	TInt RegisterTxBuffer(TInt aChannelId, TPtr8 aTxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset);
   165 	TInt CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch=NULL);
   166 	TInt ReleaseChannel(TInt aChannelId);
   167 	private:
   168 	TDynamicDfcQue* iDfcQue;
   169 	TIicBusSlaveCallback* iNotif;
   170 
   171 	HBuf8* iConfigHdr;
   172 	TRequestStatus* iStatus;
   173 
   174 	TUint8* iRxBuf;
   175 	TUint8* iTxBuf;
   176 
   177 	TUint8* iBusTxCheckBuf;
   178 
   179 	TInt8 iNumRegRxWords;
   180 	TInt8 iNumRegTxWords;
   181 
   182 	TInt8 iTxRegGranularity;
   183 	TInt8 iTxRegOffset;
   184 	TInt8 iTxReqNumWords;
   185 
   186 	TInt8 iRxRegGranularity;
   187 	TInt8 iRxRegOffset;
   188 	TInt8 iRxReqNumWords;
   189 
   190 	TUint iBusId;
   191 #ifdef STANDALONE_CHANNEL
   192 	// For some slave-channel-only functions,e.g. ReleaseChannel, RegisterRxBuffer, etc.
   193 	// the client needs to remember the slave channel that has been captured
   194 	struct TCapturedChannel
   195 		{
   196 		DIicSlaveClientChan* iChannel;
   197 		TInt iChannelId;
   198 		};
   199 	TCapturedChannel iCapturedChan;
   200 #endif
   201 	public:
   202 	DThread* iClient;
   203 	TInt iChannelId;	// public to be accessible by callback
   204 	TInt* iClientChanId;
   205 
   206 	TInt iExpectedTrigger;
   207 	TInt iFullDuplexReq;
   208 	TInt iBlockedTrigger;
   209 
   210 	typedef enum TTestOverUnderState
   211 		{
   212 		EStartState  = 0x1,
   213 		ERxOverrun_1,
   214 		ERxOverrun_2,
   215 		ETxUnderrun_1,
   216 		ETxUnderrun_2
   217 		};
   218 	TTestOverUnderState iTestOverUnderState;
   219 	};
   220 
   221 DDeviceIicSlaveClient::DDeviceIicSlaveClient()
   222 // Constructor
   223     {
   224 	CLIENT_PRINT(("> DDeviceIicSlaveClient::DDeviceIicSlaveClient()"));
   225     iParseMask=0;		// No info, no PDD, no Units
   226     iUnitsMask=0;
   227     iVersion=TVersion(KIicClientMajorVersionNumber,
   228 		      KIicClientMinorVersionNumber,
   229 		      KIicClientBuildVersionNumber);
   230     }
   231 
   232 #ifdef STANDALONE_CHANNEL
   233 //Store all the channels created by the client into an array
   234 RPointerArray<DIicSlaveClientChan> ChannelArray;
   235 #endif
   236 DDeviceIicSlaveClient::~DDeviceIicSlaveClient()
   237 // Destructor
   238     {
   239 	CLIENT_PRINT(("> DDeviceIicSlaveClient::~DDeviceIicSlaveClient()"));
   240 #ifdef STANDALONE_CHANNEL
   241 	//The client is reponsible for channel destroy in STANDALONE_CHANNEL mode
   242     ChannelArray.ResetAndDestroy();
   243 #endif
   244 	}
   245 
   246 TInt DDeviceIicSlaveClient::Install()
   247 // Install the device driver.
   248     {
   249 	CLIENT_PRINT(("> DDeviceIicSlaveClient::Install()"));
   250 
   251     return(SetName(&KLddRootName));
   252     }
   253 
   254 
   255 void DDeviceIicSlaveClient::GetCaps(TDes8& aDes) const
   256 // Return the IicClient capabilities.
   257     {
   258 	CLIENT_PRINT(("> DDeviceIicSlaveClient::GetCaps(TDes8& aDes) const"));
   259     TPckgBuf<TCapsIicSlaveClient> b;
   260     b().version=TVersion(KIicClientMajorVersionNumber,
   261 			 KIicClientMinorVersionNumber,
   262 			 KIicClientBuildVersionNumber);
   263     Kern::InfoCopy(aDes,b);
   264     }
   265 
   266 
   267 TInt DDeviceIicSlaveClient::Create(DLogicalChannelBase*& aChannel)
   268 // Create a channel on the device.
   269     {
   270 	CLIENT_PRINT(("> DDeviceIicSlaveClient::Create(DLogicalChannelBase*& aChannel)"));
   271 	if(iOpenChannels>=KMaxNumChannels)
   272 		return KErrOverflow;
   273     aChannel=new DChannelIicSlaveClient;
   274     return aChannel?KErrNone:KErrNoMemory;
   275     }
   276 
   277 #ifdef STANDALONE_CHANNEL
   278 //  auxiliary function for ordering entries in the array of channels
   279 TInt DChannelIicSlaveClient::OrderEntries(const DIicSlaveClientChan& aMatch, const DIicSlaveClientChan& aEntry)
   280 	{
   281 	TUint8 l=(TUint8)aMatch.GetChanNum();
   282 	TUint8 r=(TUint8)aEntry.GetChanNum();
   283 	if(l>r)
   284 		return -1;
   285 	else if(l<r)
   286 		return 1;
   287 	else
   288 		return 0;
   289 	}
   290 
   291 // global ordering object to be passed to RPointerArray InsertInOrderXXX and FindInOrder
   292 TLinearOrder<DIicSlaveClientChan> EntryOrder(DChannelIicSlaveClient::OrderEntries);
   293 
   294 TInt GetChanPtr(const TInt aBusId, DIicSlaveClientChan*& aChan)
   295 	{
   296     __KTRACE_OPT(KIIC, 	Kern::Printf("GetChanPtr, aBusId=0x%x\n",aBusId));
   297 	TInt32 chanId;
   298 	chanId = GET_CHAN_NUM(aBusId);
   299     __KTRACE_OPT(KIIC, 	Kern::Printf("GetChanPtr, chanId=0x%x\n",chanId));
   300 	DIicSlaveClientChan chanEntry(NULL,(TInt8)chanId, DIicBusChannel::EMasterSlave);
   301 
   302 	TInt r = KErrNotFound;
   303 	TInt aIndex = ChannelArray.FindInOrder(&chanEntry, EntryOrder);
   304 
   305 	if(aIndex >= 0)
   306 		{
   307 		aChan = ChannelArray[aIndex];
   308 		r = KErrNone;
   309 		}
   310 
   311 	return r;
   312 	}
   313 #endif/*STANDALONE_CHANNEL*/
   314 
   315 DECLARE_STANDARD_LDD()
   316 	{
   317 #ifdef STANDALONE_CHANNEL
   318 	TInt r = KErrNone;
   319 	DIicBusChannel *chan = NULL, *chanM = NULL, *chanS = NULL;
   320 	DIicSlaveClientChan* aSlaveClientChan;
   321 	for(TInt i=0; i<NUM_CHANNELS; i++)
   322 			{
   323 			CLIENT_PRINT(("\n"));
   324 	#if defined(MASTER_MODE)
   325 			if(CHANNEL_TYPE(i) == (DIicBusChannel::EMaster))
   326 				{
   327 				chan=new DSimulatedIicBusChannelMasterI2c(BUS_TYPE,CHANNEL_DUPLEX(i));
   328 				if(!chan)
   329 					{
   330 					CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE(i),i));
   331 					return NULL;
   332 					}
   333 				CLIENT_PRINT(("I2C chan created at 0x%x\n",chan));
   334 				if(((DSimulatedIicBusChannelMasterI2c*)chan)->Create()!=KErrNone)
   335 					{
   336 					delete chan;
   337 					return NULL;
   338 					}
   339 				aSlaveClientChan = new DIicSlaveClientChan(chan,AssignChanNumI2c(),DIicBusChannel::EMaster);
   340 				if(!aSlaveClientChan)
   341 					{
   342 					delete chan;
   343 					return NULL;
   344 					}
   345 				r = ChannelArray.InsertInOrder(aSlaveClientChan,EntryOrder);
   346 				if(r!=KErrNone)
   347 					{
   348 					delete chan;
   349 					delete aSlaveClientChan;
   350 					break;
   351 					}
   352 				}
   353 	#endif
   354 	#if defined(MASTER_MODE) && defined(SLAVE_MODE)
   355 			if(CHANNEL_TYPE(i) == DIicBusChannel::EMasterSlave)
   356 				{
   357 				chanM=new DSimulatedIicBusChannelMasterI2c(BUS_TYPE,CHANNEL_DUPLEX(i));
   358 				if(!chanM)
   359 					return NULL;
   360 				chanS=new DSimulatedIicBusChannelSlaveI2c(BUS_TYPE,CHANNEL_DUPLEX(i));
   361 				if(!chanS)
   362 					{
   363 					delete chanM;
   364 					return NULL;
   365 					}
   366 				chan=new DSimulatedIicBusChannelMasterSlaveI2c(BUS_TYPE,CHANNEL_DUPLEX(i),(DSimulatedIicBusChannelMasterI2c*)chanM,(DSimulatedIicBusChannelSlaveI2c*)chanS); // Generic implementation
   367 				if(!chan)
   368 					{
   369 					CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE(i),i));
   370 					delete chanM;
   371 					delete chanS;
   372 					return NULL;
   373 					}
   374 				CLIENT_PRINT(("I2C chan created at 0x%x\n",chan));
   375 				if(((DIicBusChannelMasterSlave*)chan)->DoCreate()!=KErrNone)
   376 					{
   377 					delete chanM;
   378 					delete chanS;
   379 					delete chan;
   380 					return NULL;
   381 					}
   382 				aSlaveClientChan = new DIicSlaveClientChan(chan,AssignChanNumI2c(),DIicBusChannel::EMasterSlave);
   383 				if(!aSlaveClientChan)
   384 					{
   385 					delete chanM;
   386 					delete chanS;
   387 					delete chan;
   388 					return NULL;
   389 					}
   390 				r = ChannelArray.InsertInOrder(aSlaveClientChan,EntryOrder);
   391 				if(r!=KErrNone)
   392 					{
   393 					delete chanM;
   394 					delete chanS;
   395 					delete chan;
   396 					delete aSlaveClientChan;
   397 					break;
   398 					}
   399 				}
   400 	#endif
   401 	#if defined(SLAVE_MODE)
   402 			if(CHANNEL_TYPE(i) == (DIicBusChannel::ESlave))
   403 				{
   404 				chan=new DSimulatedIicBusChannelSlaveI2c(BUS_TYPE,CHANNEL_DUPLEX(i));
   405 				if(!chan)
   406 					{
   407 					CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE(i),i));
   408 					return NULL;
   409 					}
   410 				CLIENT_PRINT(("I2C chan created at 0x%x\n",chan));
   411 				if(((DSimulatedIicBusChannelSlaveI2c*)chan)->Create()!=KErrNone)
   412 					return NULL;
   413 				aSlaveClientChan = new DIicSlaveClientChan(chan,AssignChanNumI2c(),DIicBusChannel::ESlave);
   414 				if(!aSlaveClientChan)
   415 					{
   416 					delete chan;
   417 					return NULL;
   418 					}
   419 				r = ChannelArray.InsertInOrder(aSlaveClientChan,EntryOrder);
   420 				if(r!=KErrNone)
   421 					{
   422 					delete chan;
   423 					delete aSlaveClientChan;
   424 					break;
   425 					}
   426 				}
   427 	#endif
   428 	#if !defined(MASTER_MODE) && !defined(SLAVE_MODE)
   429 	#error I2C mode not defined as Master, Slave nor Master-Slave
   430 	#endif
   431 			}
   432 #endif
   433 	return new DDeviceIicSlaveClient;
   434 	}
   435 
   436 
   437 
   438 DChannelIicSlaveClient::DChannelIicSlaveClient()
   439 // Constructor
   440     {
   441 	iFullDuplexReq=iBlockedTrigger=iExpectedTrigger=0;
   442 	CLIENT_PRINT(("> DChannelIicSlaveClient::DChannelIicSlaveClient()"));
   443     iClient=&Kern::CurrentThread();
   444 	// Increase the DThread's ref count so that it does not close without us
   445 	iClient->Open();
   446 	iTestOverUnderState = EStartState;
   447     }
   448 
   449 DChannelIicSlaveClient::~DChannelIicSlaveClient()
   450 // Destructor
   451     {
   452 	CLIENT_PRINT(("> DChannelIicSlaveClient::~DChannelIicSlaveClient()"));
   453 	iDfcQue->Destroy();
   454 	delete iNotif;
   455 	delete iRxBuf;
   456 	delete iTxBuf;
   457 	delete iBusTxCheckBuf;
   458 	// decrement the DThread's reference count
   459 	Kern::SafeClose((DObject*&)iClient, NULL);
   460 	}
   461 
   462 void DChannelIicSlaveClient::RequestComplete(TInt r)
   463 	{
   464 	Kern::RequestComplete(iClient, iStatus, r);
   465 	}
   466 
   467 TInt DChannelIicSlaveClient::RegisterRxBuffer(TInt aChannelId, TPtr8 aRxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
   468 	{
   469 	TInt r = KErrNone;
   470 #ifdef STANDALONE_CHANNEL
   471 	DIicSlaveClientChan* aChanPtr = NULL;
   472 	if(iCapturedChan.iChannelId == aChannelId)
   473 		aChanPtr = iCapturedChan.iChannel;
   474 	if(!aChanPtr)
   475 		return KErrArgument;
   476 	if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave)
   477 		r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->RegisterRxBuffer(aRxBuffer, aBufGranularity, aNumWords, aOffset);
   478 	else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave)
   479 		r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->RegisterRxBuffer(aRxBuffer, aBufGranularity, aNumWords, aOffset);
   480 #else
   481 	r = IicBus::RegisterRxBuffer(aChannelId, aRxBuffer, aBufGranularity, aNumWords, aOffset);
   482 #endif
   483 	return r;
   484 	}
   485 
   486 TInt DChannelIicSlaveClient::SetNotificationTrigger(TInt aChannelId, TInt aTrigger)
   487 	{
   488 	TInt r = KErrNone;
   489 #ifdef STANDALONE_CHANNEL
   490 	DIicSlaveClientChan* aChanPtr = NULL;
   491 	if(iCapturedChan.iChannelId == aChannelId)
   492 		aChanPtr = iCapturedChan.iChannel;
   493 	if(!aChanPtr)
   494 		return KErrArgument;
   495 	if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave)
   496 		r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->SetNotificationTrigger(aTrigger);
   497 	else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave)
   498 		r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->SetNotificationTrigger(aTrigger);
   499 #else
   500 	r = IicBus::SetNotificationTrigger(aChannelId, aTrigger);
   501 #endif
   502 	return r;
   503 	}
   504 
   505 TInt DChannelIicSlaveClient::StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2)
   506 	{
   507 	TInt r = KErrNone;
   508 #ifdef STANDALONE_CHANNEL
   509 	DIicSlaveClientChan* aChanPtr;
   510 	r = GetChanPtr(aId, aChanPtr);
   511 	if(r != KErrNone)
   512 		return r;
   513 	if(!aChanPtr)
   514 		return KErrArgument;
   515 	if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave)
   516 		r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->StaticExtension(aFunction, aParam1, aParam2);
   517 	else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave)
   518 	r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->StaticExtension(aFunction, aParam1, aParam2);
   519 #else
   520 	r = IicBus::StaticExtension(aId, aFunction, aParam1, aParam2);
   521 #endif
   522 	return r;
   523 	}
   524 
   525 TInt DChannelIicSlaveClient::RegisterTxBuffer(TInt aChannelId, TPtr8 aTxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
   526 	{
   527 	TInt r = KErrNone;
   528 #ifdef STANDALONE_CHANNEL
   529 	DIicSlaveClientChan* aChanPtr = NULL;
   530 	if(iCapturedChan.iChannelId == aChannelId)
   531 		aChanPtr = iCapturedChan.iChannel;
   532 	if(!aChanPtr)
   533 		return KErrArgument;
   534 	if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave)
   535 		r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->RegisterTxBuffer(aTxBuffer, aBufGranularity, aNumWords, aOffset);
   536 	else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave)
   537 		r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->RegisterTxBuffer(aTxBuffer, aBufGranularity, aNumWords, aOffset);
   538 #else
   539 	r = IicBus::RegisterTxBuffer(aChannelId, aTxBuffer, aBufGranularity, aNumWords, aOffset);
   540 #endif
   541 	return r;
   542 	}
   543 
   544 TInt DChannelIicSlaveClient::CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch)
   545 	{
   546 	TInt r = KErrNone;
   547 #ifndef STANDALONE_CHANNEL
   548 	r = IicBus::CaptureChannel(aBusId, aConfigHdr, aCallback, aChannelId, aAsynch);
   549 #else
   550 	// Check that that aCallback!=NULL and aConfigHdr!=NULL - if not, return KErrArgument
   551 	if(!aCallback || !aConfigHdr)
   552 		{
   553 		return KErrArgument;
   554 		}
   555 
   556 	// Get the channel
   557 	DIicSlaveClientChan* chanPtr = NULL;
   558 	if(r == KErrNone)
   559 		{
   560 		r = GetChanPtr(aBusId, chanPtr);
   561 		if(r == KErrNone)
   562 			{
   563 			if(!chanPtr)
   564 				{
   565 				r = KErrArgument;
   566 				}
   567 			else
   568 				{
   569 				switch(chanPtr->GetChanType())
   570 					{
   571 					// CaptureChannel requests are only supported by channels in Slave mode.
   572 					case DIicBusChannel::EMaster:
   573 						{
   574 						r = KErrNotSupported;
   575 						break;
   576 						}
   577 					case DIicBusChannel::EMasterSlave:
   578 						{
   579 						r = ((DIicBusChannelMasterSlave*) (chanPtr->GetChannelPtr()))->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch);
   580 						break;
   581 						}
   582 					case DIicBusChannel::ESlave:
   583 						{
   584 						r = ((DIicBusChannelSlave*) (chanPtr->GetChannelPtr()))->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch);
   585 						break;
   586 						}
   587 					default:
   588 						{
   589 						r = KErrArgument;
   590 						}
   591 					}
   592 				// For synchronous capture, if successful then install the channel
   593 				if(r == KErrNone)
   594 					{
   595 					if(!aAsynch)
   596 						{
   597 						 iCapturedChan.iChannel = chanPtr;
   598 						 iCapturedChan.iChannelId = aChannelId;
   599 						}
   600 					else
   601 						//For asynchronous capture, record slaveChanPtr, if later failed capture,
   602 						//clean iCapturedChannel in client's callback.
   603 						iCapturedChan.iChannel = chanPtr;
   604 					}
   605 				}
   606 			}
   607 		}
   608 #endif
   609 	return r;
   610 	}
   611 
   612 TInt DChannelIicSlaveClient::ReleaseChannel(TInt aChannelId)
   613 	{
   614 	TInt r = KErrNone;
   615 #ifndef STANDALONE_CHANNEL
   616 	r = IicBus::ReleaseChannel(aChannelId);
   617 #else
   618     __KTRACE_OPT(KIIC, Kern::Printf("DChannelIicSlaveClient::ReleaseChannel, channelID = 0x%x \n",aChannelId));
   619     // Acquire the pointer to the Slave Channel
   620     if(iCapturedChan.iChannelId != aChannelId)
   621 		return KErrNotFound;
   622 
   623 	if((iCapturedChan.iChannel)->GetChanType() == DIicBusChannel::EMasterSlave)
   624 		r = ((DIicBusChannelMasterSlave*)((iCapturedChan.iChannel)->GetChannelPtr()))->ReleaseChannel();
   625 	else if((iCapturedChan.iChannel)->GetChanType() == DIicBusChannel::ESlave)
   626 		r = ((DIicBusChannelSlave*)((iCapturedChan.iChannel)->GetChannelPtr()))->ReleaseChannel();
   627 	//After release channel, reset iCapturedChan
   628 	iCapturedChan.iChannel = NULL;
   629 	iCapturedChan.iChannelId = 0;
   630 #endif
   631 	return r;
   632 	}
   633 TInt DChannelIicSlaveClient::CbProcessOverUnderRunRxTx()
   634 	{
   635 	CLIENT_PRINT(("> DChannelIicSlaveClient::CbProcessOverUnderRunRxTx(), iTestOverUnderState=%d\n",iTestOverUnderState));
   636 	TInt r = KErrNone;
   637 	switch (iTestOverUnderState)
   638 		{
   639 		case(EStartState):
   640 			{
   641 			// In this state, no action is required
   642 			break;
   643 			};
   644 		case(ERxOverrun_1):
   645 			{
   646 			CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ERxOverrun_1\n"));
   647 			// At this point, the outstanding request trigger should be ETxAllBytes | ETxUnderrun
   648 			// and the flag to indicate duplex transfers should be cleared
   649 			if((iExpectedTrigger != (ETxAllBytes | ETxUnderrun)) || (iFullDuplexReq != ETxAllBytes))
   650 				{
   651 				CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq));
   652 				r=KErrGeneral;
   653 				}
   654 			else
   655 				{
   656 				// Simulate providing a new buffer (actually, re-use existing buffer)
   657 				CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterRxBuffer\n"));
   658 				TPtr8 rxPtr(iRxBuf,KRxBufSizeInBytes);
   659 				r = RegisterRxBuffer(iChannelId, rxPtr, iRxRegGranularity, iNumRegRxWords, iRxRegOffset);
   660 
   661 				if(r != KErrNone)
   662 					{
   663 					CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterRxBuffer returned %d\n",r));
   664 					}
   665 				else
   666 					{
   667 					// For the next step, just specify the new Rx triggers (do not specify Tx triggers)
   668 					r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun));
   669 					if(r != KErrNone)
   670 						{
   671 						CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d\n",r));
   672 						}
   673 					else
   674 						{
   675 						iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun;
   676 						iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
   677 						iTestOverUnderState = ERxOverrun_2;	// Prepare for callback
   678 						// The requested number of words when the buffer was registered was 8, so simulate 10
   679 						// to provoke an RxOverrun event.
   680 						TInt numWords=10;
   681 						// To support testing, any values of aId for StaticExtension must be shifted left one place
   682 						// and for a Slave, the two msbs must be zero
   683 						TInt ctrlIoVal = RBusDevIicClient::ECtrlIoRxWords;
   684 						ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
   685 						r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords);
   686 						}
   687 					}
   688 				}
   689 			break;
   690 			};
   691 		case(ERxOverrun_2):
   692 			{
   693 			CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ERxOverrun_2\n"));
   694 			// At this point, the outstanding request trigger should be ETxAllBytes | ETxUnderrun
   695 			// and the flag to indicate duplex transfers should be cleared
   696 			if((iExpectedTrigger != (ETxAllBytes | ETxUnderrun)) || (iFullDuplexReq != ETxAllBytes))
   697 				{
   698 				CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq));
   699 				r=KErrGeneral;
   700 				}
   701 			else
   702 				{
   703 				// Simulate providing a new buffer (actually, re-use existing buffer)
   704 				CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterRxBuffer\n"));
   705 				TPtr8 rxPtr(iRxBuf,KRxBufSizeInBytes);
   706 				r = RegisterRxBuffer(iChannelId, rxPtr, iRxRegGranularity, iNumRegRxWords, iRxRegOffset);
   707 				if(r != KErrNone)
   708 					{
   709 					CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterRxBuffer returned %d\n",r));
   710 					}
   711 				else
   712 					{
   713 					// Test that an attempt to modify existing Tx notification requests is rejected
   714 					r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxOverrun));
   715 					if(r != KErrInUse)
   716 						{
   717 						CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrInUse\n",r));
   718 						}
   719 					else
   720 						{
   721 						// For the next step, specify the new Rx triggers and the Tx triggers
   722 						r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun));
   723 						if(r != KErrNone)
   724 							{
   725 							CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrNone\n",r));
   726 							}
   727 						else
   728 							{
   729 							iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun;
   730 							iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
   731 							iTestOverUnderState = ETxUnderrun_1;	// Prepare for callback
   732 							// The requested number of words when the buffer was registered was 12, so simulate 14
   733 							// to provoke an TxUnderrun event.
   734 							TInt numWords=14;
   735 							// To support testing, any values of aId for StaticExtension must be shifted left one place
   736 							// and for a Slave, the two msbs must be zero
   737 							TInt ctrlIoVal = RBusDevIicClient::ECtrlIoTxWords;
   738 							ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
   739 							r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords);
   740 							}
   741 						}
   742 					}
   743 				}
   744 			break;
   745 			};
   746 		case(ETxUnderrun_1):
   747 			{
   748 			CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ETxOverrun_1\n"));
   749 			// At this point, the outstanding request trigger should be ERxAllBytes | ERxOverrun
   750 			// and the flag to indicate duplex transfers should be cleared
   751 			if((iExpectedTrigger != (ERxAllBytes | ERxOverrun)) || (iFullDuplexReq != ERxAllBytes))
   752 				{
   753 				CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq));
   754 				r=KErrGeneral;
   755 				}
   756 			else
   757 				{
   758 				// Simulate providing a new buffer (actually, re-use existing buffer)
   759 				CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterTxBuffer\n"));
   760 				TPtr8 rxPtr(iTxBuf,KTxBufSizeInBytes);
   761 				r = RegisterTxBuffer(iChannelId, rxPtr, iTxRegGranularity, iNumRegTxWords, iTxRegOffset);
   762 				if(r != KErrNone)
   763 					{
   764 					CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterTxBuffer returned %d\n",r));
   765 					}
   766 				else
   767 					{
   768 					// For the next step, just specify the new Tx triggers (do not specify Rx triggers)
   769 					r = SetNotificationTrigger(iChannelId, (ETxAllBytes | ETxUnderrun));
   770 					if(r != KErrNone)
   771 						{
   772 						CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d\n",r));
   773 						}
   774 					else
   775 						{
   776 						iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun;
   777 						iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
   778 						iTestOverUnderState = ETxUnderrun_2;	// Prepare for callback
   779 						// The requested number of words when the buffer was registered was 12, so simulate 14
   780 						// to provoke an TxUnderrun event.
   781 						TInt numWords=14;
   782 						// To support testing, any values of aId for StaticExtension must be shifted left one place
   783 						// and for a Slave, the two msbs must be zero
   784 						TInt ctrlIoVal = RBusDevIicClient::ECtrlIoTxWords;
   785 						ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
   786 						r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords);
   787 						}
   788 					}
   789 				}
   790 			break;
   791 			};
   792 		case(ETxUnderrun_2):
   793 			{
   794 			CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ETxUnderrun_2\n"));
   795 			// At this point, the outstanding request trigger should be ERxAllBytes | ERxOverrun
   796 			// and the flag to indicate duplex transfers should be cleared
   797 			if((iExpectedTrigger != (ERxAllBytes | ERxOverrun)) || (iFullDuplexReq != ERxAllBytes))
   798 				{
   799 				CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq));
   800 				r=KErrGeneral;
   801 				}
   802 			else
   803 				{
   804 				// Simulate providing a new buffer (actually, re-use existing buffer)
   805 				CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterRxBuffer\n"));
   806 				TPtr8 rxPtr(iTxBuf,KTxBufSizeInBytes);
   807 				r = RegisterTxBuffer(iChannelId, rxPtr, iTxRegGranularity, iNumRegTxWords, iTxRegOffset);
   808 				if(r != KErrNone)
   809 					{
   810 					CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterTxBuffer returned %d\n",r));
   811 					}
   812 				else
   813 					{
   814 					// Test that an attempt to modify existing Rx notification requests is rejected
   815 					r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxUnderrun | ETxAllBytes | ETxUnderrun));
   816 					if(r != KErrInUse)
   817 						{
   818 						CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrInUse\n",r));
   819 						}
   820 					else
   821 						{
   822 						// For the next step, specify the new Rx triggers and the Tx triggers
   823 						r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun));
   824 
   825 						if(r != KErrNone)
   826 							{
   827 							CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrNone\n",r));
   828 							}
   829 						else
   830 							{
   831 							// Simulate a simultaneous ERxAllBytes and ETxAllBytes event.
   832 							iExpectedTrigger = ERxAllBytes | ETxAllBytes;
   833 							iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
   834 							iTestOverUnderState = EStartState;	// Prepare for callback - return to normal operation
   835 							// Need to pass the number of words in an array, for use by StaticExtension
   836 							TInt parms[2];
   837 							parms[0]= 8;	// Number of Rx Words
   838 							parms[1]=12;	// Number of Tx Words
   839 							// To support testing, any values of aId for StaticExtension must be shifted left one place
   840 							// and for a Slave, the two msbs must be zero
   841 							TInt ctrlIoVal = RBusDevIicClient::ECtrlIoRxTxWords;
   842 							ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
   843 							r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)(&parms[0]));
   844 							}
   845 						}
   846 					}
   847 				}
   848 			break;
   849 			};
   850 		default:
   851 			{
   852 			r = KErrGeneral;
   853 			break;
   854 			};
   855 		}
   856 	return r;
   857 	}
   858 
   859 void DChannelIicSlaveClient::SlaveClientCallbackFunc(TInt aChannelId, TInt aReturn, TInt aTrigger, TInt16 aRxWords, TInt16 aTxWords, TAny*	aParam)
   860 	{
   861 	CLIENT_PRINT(("> SlaveClientCallbackFunc() - aChannelId=0x%x,aReturn=%d,aTrigger=0x%x,aRxWords=0x%x,aTxWords=0x%x,aParam=0x%x\n",aChannelId,aReturn,aTrigger,aRxWords,aTxWords,aParam));
   862 	(void)aTxWords; // Unused if CLIENT_PRINT is undefined
   863 	(void)aRxWords; // Unused if CLIENT_PRINT is undefined
   864 	DChannelIicSlaveClient* channel = (DChannelIicSlaveClient*)aParam;
   865 
   866 	// Ensure only the valid bits of aTrigger are processed
   867 	aTrigger &= 0xff;
   868 
   869 	CLIENT_PRINT(("SlaveClientCallbackFunc() - channel=0x%x\n",channel));
   870 	if(aTrigger == EAsyncCaptChan)
   871 		{
   872 		CLIENT_PRINT(("SlaveClientCallbackFunc: capture channel completed\n"));
   873 		// Set iChannelId, and write to user-side variable.
   874 		channel->iChannelId=aChannelId;
   875 		TInt r=Kern::ThreadRawWrite(channel->iClient,channel->iClientChanId,&aChannelId,sizeof(TInt));
   876 		if(r == KErrNone)
   877 			r=aReturn;
   878 #ifdef STANDALONE_CHANNEL
   879 		// Set the captured channel's iChannelId if the capture succeeds.
   880 		if(r != KErrCompletion)
   881 			(channel->iCapturedChan).iChannel = NULL;
   882 		else
   883 			(channel->iCapturedChan).iChannelId = aChannelId;
   884 #endif/*STANDALONE_CHANNEL*/
   885 	    channel->RequestComplete(r);	// Inform user of error
   886 		return;
   887 		}
   888 	else
   889 		{
   890 		if(aTrigger&ERxAllBytes)
   891 			{
   892 			CLIENT_PRINT(("SlaveClientCallbackFunc() - ERxAllBytes\n"));
   893 			aTrigger&= ~ERxAllBytes;
   894 			channel->iExpectedTrigger&=~ERxAllBytes;
   895 			channel->iFullDuplexReq&=~ERxAllBytes;
   896 			aReturn=channel->CheckDataRead();
   897 			// Check underrun
   898 			if(aTrigger&ERxUnderrun)
   899 				{
   900 				if(channel->iExpectedTrigger&ERxUnderrun)
   901 					{
   902 					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxUnderrun found OK\n\n"));
   903 					channel->iExpectedTrigger&=~ERxUnderrun;
   904 					}
   905 				else
   906 					{
   907 					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ERxUnderrun indicated\n\n"));
   908 					aReturn = KErrGeneral;
   909 					}
   910 				}
   911 			else
   912 				{
   913 				if(channel->iExpectedTrigger&ERxUnderrun)
   914 					{
   915 					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxUnderrun not (yet) seen\n\n"));
   916 					aReturn = KErrGeneral;
   917 					}
   918 				}
   919 			// Check overrun
   920 			if(aTrigger&ERxOverrun)
   921 				{
   922 				if(channel->iExpectedTrigger&ERxOverrun)
   923 					{
   924 					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxOverrun found OK\n\n"));
   925 					channel->iExpectedTrigger&=~ERxOverrun;
   926 					}
   927 				else
   928 					{
   929 					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ERxOverrun indicated\n\n"));
   930 					aReturn = KErrGeneral;
   931 					}
   932 				}
   933 			else
   934 				{
   935 				if(channel->iExpectedTrigger&ERxOverrun)
   936 					{
   937 					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxOverrun not (yet) seen\n\n"));
   938 					aReturn = KErrGeneral;
   939 					}
   940 				}
   941 			}
   942 
   943 		if(aTrigger&ETxAllBytes)
   944 			{
   945 			CLIENT_PRINT(("SlaveClientCallbackFunc() - ETxAllBytes\n"));
   946 			aTrigger&= ~ETxAllBytes;
   947 			channel->iExpectedTrigger&=~ETxAllBytes;
   948 			channel->iFullDuplexReq&=~ETxAllBytes;
   949 			aReturn=channel->CheckDataWritten();
   950 			// Check underrun
   951 			if(aTrigger&ETxUnderrun)
   952 				{
   953 				if(channel->iExpectedTrigger&ETxUnderrun)
   954 					{
   955 					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxUnderrun found OK\n\n"));
   956 					channel->iExpectedTrigger&=~ETxUnderrun;
   957 					}
   958 				else
   959 					{
   960 					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ETxUnderrun indicated\n\n"));
   961 					aReturn = KErrGeneral;
   962 					}
   963 				}
   964 			else
   965 				{
   966 				if(channel->iExpectedTrigger&ETxUnderrun)
   967 					{
   968 					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxUnderrun not (yet) seen\n\n"));
   969 					aReturn = KErrGeneral;
   970 					}
   971 				}
   972 			// Check overrun
   973 			if(aTrigger&ETxOverrun)
   974 				{
   975 				if(channel->iExpectedTrigger&ETxOverrun)
   976 					{
   977 					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxOverrun found OK\n\n"));
   978 					channel->iExpectedTrigger&=~ETxOverrun;
   979 					}
   980 				else
   981 					{
   982 					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ETxOverrun indicated\n\n"));
   983 					aReturn = KErrGeneral;
   984 					}
   985 				}
   986 			else
   987 				{
   988 				if(channel->iExpectedTrigger&ETxOverrun)
   989 					{
   990 					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxOverrun not (yet) seen\n\n"));
   991 					aReturn = KErrGeneral;
   992 					}
   993 				}
   994 			}
   995 
   996 
   997 		if(aTrigger&EGeneralBusError)
   998 			{
   999 				if(channel->iExpectedTrigger&EGeneralBusError)
  1000 					{
  1001 					CLIENT_PRINT(("\nSlaveClientCallbackFunc: EGeneralBusError - as expected\n\n"));
  1002 					channel->iExpectedTrigger&=~EGeneralBusError;
  1003 					if(aReturn == KErrGeneral)
  1004 						{
  1005 						aReturn=KErrNone; // If aReturn==KErrGeneral, set to KErrNone so t_iic knows test was successful
  1006 						channel->iFullDuplexReq = 0; // The transaction is considered terminated, so don't wait for more triggers
  1007 						}
  1008 					else
  1009 						{
  1010 						CLIENT_PRINT(("\nSlaveClientCallbackFunc: aReturn not EGeneralBusError, =0x%x \n\n",aReturn));
  1011 						aReturn=KErrGeneral;
  1012 						}
  1013 
  1014 					}
  1015 				else
  1016 					{
  1017 					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected EGeneralBusError indicated\n\n"));
  1018 					aReturn = KErrGeneral;
  1019 					}
  1020 			}
  1021 
  1022 		if((aTrigger < 0)||(aTrigger & (~0xFF)))
  1023 			{
  1024 			CLIENT_PRINT(("\nSlaveClientCallbackFunc: trigger condition 0x%x is not recognised \n\n",aTrigger));
  1025 			}
  1026 
  1027 		// For simulataneous Rx,Tx triggers with ERxOverrun or TxUnderrun testing, need to call the following
  1028 		if(aReturn == KErrNone)
  1029 			{
  1030 			aReturn = channel->CbProcessOverUnderRunRxTx();
  1031 			}
  1032 
  1033 		if((channel->iExpectedTrigger == 0)&&(channel->iFullDuplexReq == 0))
  1034 			channel->RequestComplete(aReturn);	// Complete user-side request only if all the triggers have been satisfied
  1035 
  1036 		} // if(aTrigger == EAsyncCaptChan)
  1037 	}
  1038 
  1039 
  1040 TInt DChannelIicSlaveClient::CheckDataRead()
  1041 	{
  1042 	TInt r=KErrNone;
  1043 	// This channel will have provided a buffer for writing to, with a specified offset and number of words
  1044 	// Bytes in the buffer before the offset should be set to zero
  1045 	// Bytes written at and beyond the offset should exhibit an incrementing count
  1046 	// Bytes beyond the offset that were not written to should be set to zero
  1047 	TInt8 numWords=(iRxReqNumWords>iNumRegRxWords)?iNumRegRxWords:iRxReqNumWords;
  1048 	TInt8 currVal=0;
  1049 	TInt8 index = 0;
  1050 	while(index<iRxRegOffset)
  1051 		{
  1052 		currVal=*(iRxBuf+index);
  1053 		if(currVal != 0)
  1054 			{
  1055 			CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataRead, index=%d, value =0x%x, expected 0",index,currVal));
  1056 			r=KErrCorrupt;
  1057 			}
  1058 		++index;
  1059 		}
  1060 
  1061 	TInt8 checkVal=0x10; // first value written by simulated bus channel
  1062 	TInt8 endOfData= (TInt8)(iRxRegOffset+(numWords*iRxRegGranularity));
  1063 	TInt8 wordCount=0;
  1064 	while(index<endOfData)
  1065 		{
  1066 		currVal = *(iRxBuf+index);
  1067 		if(checkVal != currVal)
  1068 			{
  1069 			CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataRead, index=%d, value =0x%x, expected 0x%x",index,currVal,checkVal));
  1070 			r=KErrCorrupt;
  1071 			}
  1072 		if(++wordCount == iRxRegGranularity)
  1073 			{
  1074 			wordCount=0;
  1075 			checkVal++;
  1076 			}
  1077 		++index;
  1078 		}
  1079 
  1080 	while(index<KRxBufSizeInBytes)
  1081 		{
  1082 		currVal=*(iRxBuf+index);
  1083 		if(currVal != 0)
  1084 			{
  1085 			CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataRead, index=%d, value =0x%x, expected 0",index,currVal);)
  1086 			r=KErrCorrupt;
  1087 			}
  1088 		++index;
  1089 		}
  1090 	return r;
  1091 	}
  1092 
  1093 
  1094 TInt DChannelIicSlaveClient::CheckDataWritten()
  1095 	{
  1096 	TInt r=KErrNone;
  1097 	// The pattern in the transmit buffer used by the simulated bus channel contains a incrementing count
  1098 	// from 0 to (KTxBufSizeInBytes-1), therefore the first value to be present in the check buffer will be
  1099 	// represented by the required offset.
  1100 
  1101 	// The bytes "transmitted" are stored in the simulated bus' iTxCheckBuf
  1102 	// Since the simulated bus channel is also in the kernel process it shares the same address space
  1103 	// Get the address of the buffer
  1104 	TUint testId = (((TUint)(RBusDevIicClient::ECtrlIoTxChkBuf))<<1)&0x3FFFFFFF;
  1105 	CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataWritten invoking StaticExtension ECtrlIoTxChkBuf with iBusId=0x%x, testId=0x%x, iBusTxCheckBuf=0x%x\n",iBusId,testId,iBusTxCheckBuf));
  1106 	r = StaticExtension(iBusId, testId, &iBusTxCheckBuf, NULL);
  1107 	if(r!=KErrNone)
  1108 		{
  1109 		CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataWritten StaticExtension ECtrlIoTxChkBuf returned %d\n",r));
  1110 		return r;
  1111 		}
  1112 
  1113 	// Check that the values in the check buffer increment for the
  1114 	// required number of words, and that any remaining bytes in the check buffer are set to zero.
  1115 	TInt8 firstValue = iTxRegOffset;
  1116 	TInt8 currVal = 0;
  1117 	TInt8 wordsWritten = 0;
  1118 	wordsWritten=(iTxReqNumWords>iNumRegTxWords)?iNumRegTxWords:iTxReqNumWords;
  1119 	TInt8 index=0;
  1120 	while(index<(wordsWritten*iTxRegGranularity))
  1121 		{
  1122 		currVal=*(iBusTxCheckBuf+index);
  1123 		if(currVal != (TInt8)(firstValue+index))
  1124 			{
  1125 			CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataWritten, index=%d, value =0x%x, expected 0x%x",index,currVal,(TInt8)(firstValue+index)));
  1126 			r=KErrCorrupt;
  1127 			}
  1128 		++index;
  1129 		}
  1130 	while(index<(iNumRegTxWords*iTxRegGranularity))
  1131 		{
  1132 		currVal=*(iBusTxCheckBuf+index);
  1133 		if(currVal != 0)
  1134 			{
  1135 			CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataWritten, index=%d, value =0x%x, expected 0",index,currVal));
  1136 			r=KErrCorrupt;
  1137 			}
  1138 		++index;
  1139 		}
  1140 	return r;
  1141 	}
  1142 
  1143 
  1144 TInt DChannelIicSlaveClient::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
  1145 	{
  1146 	CLIENT_PRINT(("> DChannelIicSlaveClient::DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion &aVer)"));
  1147 
  1148 	TInt r = Kern::DynamicDfcQCreate(iDfcQue,KIicSlaveClientThreadPriority,KIicSlaveClientThreadName);
  1149 	if(r!=KErrNone)
  1150 		return r;
  1151 	SetDfcQ(iDfcQue);
  1152 
  1153 	// Allocate buffers for Rx, Tx operations
  1154 	iRxBuf = new TUint8[KRxBufSizeInBytes];
  1155 	iTxBuf = new TUint8[KTxBufSizeInBytes];
  1156 	if((iRxBuf == NULL)||(iTxBuf == NULL))
  1157 		return KErrNoMemory;
  1158 	// Start receiving messages
  1159 	iMsgQ.Receive();
  1160 
  1161 	return r;
  1162 	}
  1163 
  1164 TInt DChannelIicSlaveClient::InitSlaveClient()
  1165 	{
  1166 	iNotif = new TIicBusSlaveCallback(DChannelIicSlaveClient::SlaveClientCallbackFunc, (TAny*)this, iDfcQue, KIicSlaveClientDfcPriority);
  1167 	if(iNotif == NULL)
  1168 		{
  1169 		CLIENT_PRINT(("> DChannelIicSlaveClient::InitSlaveClient ERROR unable to allocate space TIicBusSlaveCallback* iNotif \n"));
  1170 		return KErrNoMemory;
  1171 		}
  1172 	return KErrNone;
  1173 	}
  1174 
  1175 void DChannelIicSlaveClient::HandleMsg(TMessageBase* aMsg)
  1176 	{
  1177     TThreadMessage& m=*(TThreadMessage*)aMsg;
  1178     TInt id=m.iValue;
  1179 
  1180 	CLIENT_PRINT((" >ldd: DChannelIicSlaveClient::HandleMsg(TMessageBase* aMsg) id=%d\n", id));
  1181 
  1182 	if (id == (TInt)ECloseMsg)
  1183 		{
  1184 	    iMsgQ.iMessage->Complete(KErrNone,EFalse);
  1185 		return;
  1186 		}
  1187 
  1188     if (id<0)
  1189 		{
  1190 		TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
  1191 		TInt r=DoRequest(~id, pS, m.Ptr1(), m.Ptr2());
  1192 		if (r!=KErrNone)
  1193 			{
  1194 	    	Kern::RequestComplete(iClient, pS, r);
  1195 			}
  1196 		m.Complete(KErrNone,ETrue);
  1197 		}
  1198     else
  1199 	if((id>=0)&&(id!=KMaxTInt))
  1200 		{
  1201 		TInt r=DoControl(id,m.Ptr0(),m.Ptr1());
  1202 		m.Complete(r,ETrue);
  1203 		}
  1204 	}
  1205 
  1206 
  1207 TInt DChannelIicSlaveClient::DoControl(TInt aId, TAny* a1, TAny* a2)
  1208 	{
  1209 	CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoked with aId=0x%x, a1=0x%x, a2=0x%x\n", aId,a1,a2));
  1210 	TInt r=KErrNone;
  1211 	// To support testing, any values of aId for StaticExtension must be shifted left one place
  1212 	// and for a Slave, the two msbs must be zero
  1213 	TInt ctrlIoVal = 0;
  1214 	if((aId & KTestSlaveControlIo) == KTestSlaveControlIo)
  1215 		ctrlIoVal = (aId << 1) & 0x3FFFFFFF;
  1216 
  1217 	switch(aId)
  1218 		{
  1219 		case(RBusDevIicClient::EInitSlaveClient):
  1220 			{
  1221 			r=InitSlaveClient();
  1222 			break;
  1223 			}
  1224 
  1225 		case(RBusDevIicClient::ECaptureChanSync):
  1226 			{
  1227 			// a1 is a pointer to the TDes8* aConfigHdr
  1228 			// a2 is a pointer to TInt* parms[2], where:
  1229 			// parms[0]=(TInt*)aBusId;
  1230 			// parms[1]=&aChannelId;
  1231 			//
  1232 			TInt* parms[2];
  1233 			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt*));
  1234 			if(r!=KErrNone)
  1235 				break;	// Can't proceed if can't access request parameters
  1236 			//
  1237 		  	TInt hdrSize = Kern::ThreadGetDesLength(iClient,a1);
  1238 			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl hdrSize = 0x%x\n",hdrSize));
  1239   			if (hdrSize<=0)
  1240 				{
  1241 				CLIENT_PRINT(("DChannelIicSlaveClient::DoControl ERROR, hdrSize is invalid\n"));
  1242  				r = KErrArgument;
  1243  				break;
  1244 				}
  1245 			if((iConfigHdr = HBuf8::New(hdrSize)) == NULL)
  1246 				return KErrNoMemory;
  1247 			r = Kern::ThreadDesRead(iClient,a1,*iConfigHdr,0);
  1248 			if(r!=KErrNone)
  1249 				{
  1250 				delete iConfigHdr;
  1251 				break;
  1252 				}
  1253 			// Store the address of the user-side variable to update with the ChannelId
  1254 			iClientChanId=parms[1];
  1255 
  1256 			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking (synchronous) CaptureChannel\n"));
  1257 			r = CaptureChannel((TInt)(parms[0]), iConfigHdr, iNotif, iChannelId);
  1258 			if(r != KErrNone)
  1259 			    {
  1260 			    delete iConfigHdr;
  1261 			    break;
  1262 			    }
  1263 			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl CaptureChannelgave iChannelId=0x%x\n",iChannelId));
  1264 
  1265 			r = Kern::ThreadRawWrite(iClient,iClientChanId,&iChannelId,sizeof(TInt));
  1266 			if(r != KErrNone)
  1267 				delete iConfigHdr;
  1268 			break;
  1269 			}
  1270 
  1271 		case(RBusDevIicClient::EReleaseChan):
  1272 			{
  1273 			// a1 represents TInt aChannelId
  1274 			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking ReleaseChannel\n"));
  1275 			r = ReleaseChannel((TInt)a1);
  1276 			delete iConfigHdr;
  1277 			break;
  1278 			}
  1279 
  1280 		case(RBusDevIicClient::ERegisterRxBuffer):
  1281 			{
  1282 			// a1 represents TInt aChannelId
  1283 			// a2 represents (TAny*) of TInt8 parms[3] where parms[0]=aBufGranularity; parms[1]=aNumWords; parms[2]=aOffset
  1284 			TInt8 parms[3];
  1285 			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),3*sizeof(TInt8));
  1286 			if(r!=KErrNone)
  1287 				break;	// Can't proceed if can't access request parameters
  1288 			// Store parameters for checking in the callback
  1289 			iRxRegGranularity = parms[0];
  1290 			iRxRegOffset= parms[2];
  1291 			iNumRegRxWords=parms[1];
  1292 
  1293 			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking RegisterRxBuffer\n"));
  1294 			TPtr8 rxPtr(iRxBuf,KRxBufSizeInBytes);
  1295 			r = RegisterRxBuffer((TInt)a1, rxPtr, parms[0], parms[1], parms[2]);
  1296 			break;
  1297 			}
  1298 
  1299 		case(RBusDevIicClient::ERegisterTxBuffer):
  1300 			{
  1301 			// a1 represents TInt aChannelId
  1302 			// a2 represents (TAny*) of TInt8 parms[3] where parms[0]=aBufGranularity; parms[1]=aNumWords; parms[2]=aOffset
  1303 			TInt8 parms[3];
  1304 			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),3*sizeof(TInt8));
  1305 			if(r!=KErrNone)
  1306 				break;	// Can't proceed if can't access request parameters
  1307 			// Store parameters for checking in the callback
  1308 			iTxRegGranularity = parms[0];
  1309 			iTxRegOffset= parms[2];
  1310 			iNumRegTxWords=parms[1];
  1311 
  1312 			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking RegisterTxBuffer\n"));
  1313 			TPtr8 txPtr(iTxBuf,KTxBufSizeInBytes);
  1314 			r = RegisterTxBuffer((TInt)a1, txPtr, parms[0], parms[1], parms[2]);
  1315 			break;
  1316 			}
  1317 
  1318 		case(RBusDevIicClient::ESetNotifTrigger):
  1319 			{
  1320 			// a1 represents (TAny*) of TRequestStatus* aStatus
  1321 			// a2 represents (TAny*) of TInt parms[2] where parms[0]=aChannelId; parms[1]=aTrigger
  1322 			TInt parms[2];
  1323 			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt));
  1324 			if(r!=KErrNone)
  1325 				break;	// Can't proceed if can't access request parameters
  1326 			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking SetNotificationTrigger with aStatus=0x%x, aChannelId=0x%x, aTrigger=0x%x\n",a1,parms[0],parms[1]));
  1327 			if(a1 == NULL)
  1328 				{
  1329 				r = KErrArgument;
  1330 				break;
  1331 				}
  1332 			iStatus=(TRequestStatus*)a1;
  1333 			// Set the flags for duplex processing
  1334 			if((parms[1]&ERxAllBytes)&&(parms[1]&ETxAllBytes))
  1335 				iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
  1336 			r = SetNotificationTrigger(parms[0],parms[1]);
  1337 			if(r == KErrTimedOut)
  1338 				r=KErrNone;	// KErrTimedOut is returned if the Client has not interacted with IIC for a while
  1339 			break;
  1340 			}
  1341 
  1342 		case(RBusDevIicClient::ECtrlIoNotifNoTrigger):
  1343 			{
  1344 			// a1 represents (TAny*) of aChannelId
  1345 			// a2 represents (TAny*) of aTrigger
  1346 			TInt chanId = (TInt)a1;
  1347 			TInt trigger = (TInt)a2;
  1348 			// No TRequestStatus is accessed because the call to SetNotificationTrigger
  1349 			// is either with zero (when it is valid to do so), or it is being called with a
  1350 			// trigger value that is expected to be rejected.
  1351 			r = SetNotificationTrigger(chanId,trigger);
  1352 
  1353 			if(r == KErrNone)
  1354 				{
  1355 				if((trigger&ERxAllBytes)&&(trigger&ETxAllBytes))
  1356 					iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
  1357 				}
  1358 			if(r == KErrTimedOut)
  1359 				r=KErrNone;	// KErrTimedOut is returned if the Client has not interacted with IIC for a while
  1360 			break;
  1361 			}
  1362 
  1363 		case(RBusDevIicClient::ECtrlIoRxWords):
  1364 			{
  1365 			// a1 represents TInt aBusId
  1366 			// a2 represents (TAny*) of TInt parms[2] where parms[0]=aChannelId; parms[1]=aNumWords
  1367 			TInt parms[2];
  1368 			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt));
  1369 			if(r!=KErrNone)
  1370 				break;	// Can't proceed if can't access request parameters
  1371 			// Prepare iRxBuf
  1372 			memset(iRxBuf,0,KRxBufSizeInBytes);
  1373 			// Store the number of words for checking in the callback
  1374 			iRxReqNumWords=(TInt8)(parms[1]);
  1375 
  1376 			TInt tempTrigger=0;
  1377 			// Set the expected result
  1378 			tempTrigger |= ERxAllBytes;
  1379 			if(parms[1] < iNumRegRxWords)
  1380 				tempTrigger |= ERxUnderrun;
  1381 			if(parms[1] > iNumRegRxWords)
  1382 				tempTrigger |= ERxOverrun;
  1383 			if(iExpectedTrigger != EGeneralBusError)
  1384 				iExpectedTrigger |= tempTrigger;
  1385 			else
  1386 				iBlockedTrigger |= tempTrigger;
  1387 			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoRxWords) with aBusId=0x%x, aChannelId=0x%x, aNumBytes=0x%x\n",(TInt)a1,parms[0],parms[1]));
  1388 			r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)(parms[0]), (TAny*)(parms[1]));
  1389 			if(r == KErrTimedOut)
  1390 				r=KErrNone;	// KErrTimedOut is returned if the Client has not interacted with IIC for a while
  1391 			break;
  1392 			}
  1393 
  1394 		case(RBusDevIicClient::ECtrlIoTxWords):
  1395 			{
  1396 			// a1 represents TInt aBusId
  1397 			// a2 represents (TAny*) of TInt parms[2] where parms[0]=aChannelId; parms[1]=aNumWords
  1398 			TInt parms[2];
  1399 			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt));
  1400 			if(r!=KErrNone)
  1401 				break;	// Can't proceed if can't access request parameters
  1402 			// Prepare iTxBuf
  1403 			TUint8* ptr=iTxBuf;
  1404 			for(TInt offset=0; offset<KRxBufSizeInBytes; ++offset)
  1405 				*ptr++=(TUint8)offset;
  1406 			// Store the number of words for checking in the callback
  1407 			iTxReqNumWords=(TInt8)(parms[1]);
  1408 			TInt tempTrigger=0;
  1409 			// Set the expected result
  1410 			tempTrigger |= ETxAllBytes;
  1411 			if(parms[1] < iNumRegTxWords)
  1412 				tempTrigger |= ETxOverrun;
  1413 			if(parms[1] > iNumRegTxWords)
  1414 				tempTrigger |= ETxUnderrun;
  1415 			if(iExpectedTrigger != EGeneralBusError)
  1416 				iExpectedTrigger |= tempTrigger;
  1417 			else
  1418 				iBlockedTrigger |= tempTrigger;
  1419 
  1420 			// The bytes "transmitted" are stored in the simulated bus' iTxCheckBuf
  1421 			// Since the simulated bus channel is also in the kernel process it shares the same address space
  1422 			// Get the address of the buffer
  1423 			// As part of the callback invoked by IIC, this client will check the data stored by the simulated
  1424 			// bus. Since the simulated bus channel is also in the kernel process it shares the same address space,
  1425 			// so the buffer can be accessed directly - but the buffer is not created until it receives the following
  1426 			// StaticExtension command, so the bus identifier represented by a1 is stored to allow accessing the buffer
  1427 			// adddress from the callback.
  1428 			iBusId=(TUint)a1;
  1429 			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoTxWords) with aBusId=0x%x, aChannelId=0x%x, aNumBytes=0x%x\n",(TInt)a1,parms[0],parms[1]));
  1430 			aId<<=1;
  1431 			r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)(parms[0]), (TAny*)(parms[1]));
  1432 			break;
  1433 			}
  1434 
  1435 		case(RBusDevIicClient::ECtrlIoRxTxWords):
  1436 			{
  1437 			// a1 represents TInt aBusId
  1438 			// a2 represents (TAny*) of TInt parms[3] where parms[0]=aChannelId; parms[1]=aNumRxWords; parms[2]=aNumTxWords
  1439 			TInt parms[3];
  1440 			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),3*sizeof(TInt));
  1441 			if(r!=KErrNone)
  1442 				break;	// Can't proceed if can't access request parameters
  1443 			// Prepare iRxBuf, iTxBuf
  1444 			memset(iRxBuf,0,KRxBufSizeInBytes);
  1445 			TUint8* ptr=iTxBuf;
  1446 			for(TInt offset=0; offset<KRxBufSizeInBytes; ++offset)
  1447 				*ptr++=(TUint8)offset;
  1448 
  1449 			// Store the number of words for checking in the callback
  1450 			iRxReqNumWords=(TInt8)(parms[1]);
  1451 			iTxReqNumWords=(TInt8)(parms[2]);
  1452 
  1453 			TInt tempTrigger=0;
  1454 			// Set the expected result
  1455 			tempTrigger |= (ERxAllBytes|ETxAllBytes);
  1456 
  1457 			if(parms[1] < iNumRegRxWords)
  1458 				tempTrigger |= ERxUnderrun;
  1459 			if(parms[1] > iNumRegRxWords)
  1460 				tempTrigger |= ERxOverrun;
  1461 
  1462 			if(parms[2] < iNumRegTxWords)
  1463 				tempTrigger |= ETxOverrun;
  1464 			if(parms[2] > iNumRegTxWords)
  1465 				tempTrigger |= ETxUnderrun;
  1466 
  1467 			if(iExpectedTrigger != EGeneralBusError)
  1468 				iExpectedTrigger |= tempTrigger;
  1469 			else
  1470 				iBlockedTrigger |= tempTrigger;
  1471 
  1472 			// The bytes "transmitted" are stored in the simulated bus' iTxCheckBuf
  1473 			// Since the simulated bus channel is also in the kernel process it shares the same address space
  1474 			// Get the address of the buffer
  1475 			// As part of the callback invoked by IIC, this client will check the data stored by the simulated
  1476 			// bus. Since the simulated bus channel is also in the kernel process it shares the same address space,
  1477 			// so the buffer can be accessed directly - but the buffer is not created until it receives the following
  1478 			// StaticExtension command, so the bus identifier represented by a1 is stored to allow accessing the buffer
  1479 			// adddress from the callback.
  1480 			iBusId=(TUint)a1;
  1481 
  1482 			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoRxTxWords) with aBusId=0x%x, aChannelId=0x%x, aNumRxBytes=0x%x, aNumTxBytes=0x%x\n",(TInt)a1,parms[0],parms[1],parms[2]));
  1483 			r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)(parms[0]), (TAny*)(&(parms[1])));
  1484 			if(r == KErrTimedOut)
  1485 				r=KErrNone;	// KErrTimedOut is returned if the Client has not interacted with IIC for a while
  1486 			break;
  1487 			}
  1488 
  1489 		case(RBusDevIicClient::ECtlIoBusError):
  1490 			{
  1491 			// a1 represents TInt aBusId
  1492 			// a2 represents TInt aChannelId
  1493 			// Set the expected result
  1494 			iExpectedTrigger |= EGeneralBusError;
  1495 			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtlIoBusError) \n"));
  1496 			r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)a2, NULL);
  1497 			break;
  1498 			}
  1499 
  1500 		case(RBusDevIicClient::ECtrlIoUnblockNotification):
  1501 			{
  1502 			// a1 represents TInt aBusId
  1503 			// a2 represents TInt aChannelId
  1504 			iExpectedTrigger = iBlockedTrigger;
  1505 			iBlockedTrigger=0;
  1506 			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoUnblockNotification) \n"));
  1507 			r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)a2, NULL);
  1508 			break;
  1509 			}
  1510 
  1511 		case(RBusDevIicClient::ECtrlIoBlockNotification):
  1512 			{
  1513 			// a1 represents TInt aBusId
  1514 			// a2 represents TInt aChannelId
  1515 			iBlockedTrigger = iExpectedTrigger;
  1516 			iExpectedTrigger = EGeneralBusError;	// For this test, just interested in if the timeout is detected
  1517 													// iExpectedTrigger will be reinstated prior to unblocking
  1518 			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoBlockNotification) \n"));
  1519 			r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)a2, NULL);
  1520 			break;
  1521 			}
  1522 
  1523 		case(RBusDevIicClient::ECtrlIoUpdTimeout):
  1524 			{
  1525 			// a1 represents TInt aBusId
  1526 			// a2 represents TInt aChannelId
  1527 
  1528 			// For this test, instruct the simulated bus to do the following for the Master and Client timeout values:
  1529 			// (1) Read the current timeout value and check that it is set to the default
  1530 			// (2) Set it to different value
  1531 			// (3) Read it back to check success
  1532 			// (4) Return to the original value, and readback to confirm
  1533 			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoBlockNotification) \n"));
  1534 			r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, NULL, NULL);
  1535 			break;
  1536 			}
  1537 
  1538 		default:
  1539 			{
  1540 			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl - unrecognised value for aId=0x%x\n",aId));
  1541 			r=KErrArgument;
  1542 			break;
  1543 			}
  1544 
  1545 		}
  1546 	return r;
  1547 	}
  1548 
  1549 TInt DChannelIicSlaveClient::DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2)
  1550 	{
  1551 	CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest invoked with aId=0x%x, aStatus=0x%x, a1=0x%x, a2=0x%x\n", aId,aStatus,a1,a2));
  1552 
  1553 	TInt r=KErrNone;
  1554 	switch(aId)
  1555 		{
  1556 		case(RBusDevIicClient::ECaptureChanAsync):
  1557 			{
  1558 			// a1 is a pointer to the TDes8* aConfigHdr
  1559 			// a2 is a pointer to TInt* parms[2], where:
  1560 			// parms[0]=(TInt*)aBusId;
  1561 			// parms[1]=&aChannelId;
  1562 			//
  1563 			TInt* parms[2];
  1564 			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt*));
  1565 			if(r!=KErrNone)
  1566 				break;	// Can't proceed if can't access request parameters
  1567 			//
  1568 		  	TInt hdrSize = Kern::ThreadGetDesLength(iClient,a1);
  1569 			CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest hdrSize = 0x%x\n",hdrSize));
  1570   			if (hdrSize<=0)
  1571 				{
  1572 				CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest ERROR, hdrSize is invalid\n"));
  1573  				return KErrArgument;
  1574 				}
  1575 			if((iConfigHdr = HBuf8::New(hdrSize)) == NULL)
  1576 				return KErrNoMemory;
  1577 			if((r = Kern::ThreadDesRead(iClient,a1,*iConfigHdr,0))!=KErrNone)
  1578 				{
  1579 				delete iConfigHdr;
  1580 				return r;
  1581 				}
  1582 			iStatus=aStatus;
  1583 			// Store the address of the user-side variable to update with the ChannelId
  1584 			iClientChanId=parms[1];
  1585 			// Invoke the IIC API
  1586 			CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest invoking (asynchronous) CaptureChannel\n"));
  1587 			r = CaptureChannel((TInt)(parms[0]), iConfigHdr, iNotif, iChannelId, ETrue);
  1588 			if(r != KErrNone)
  1589 			    delete iConfigHdr;
  1590 			CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest (asynchronous) CaptureChannel returned %d\n",r));
  1591 			break;
  1592 			}
  1593 
  1594 		case(RBusDevIicClient::ECtrlIoOvUndRunRxTx):
  1595 			{
  1596 			iBusId = (TInt)a1;
  1597 			iChannelId = (TInt)a2;
  1598 			iStatus=aStatus;
  1599 			CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest status = 0x%x, busId = 0x%x, chanId =0x%x\n",iStatus,iBusId,iChannelId));
  1600 
  1601 			// This test is state-machine driven. It is instigated from this point, then subsequent steps
  1602 			// are handled in the callback funciton SlaveClientCallbackFunc
  1603 			//
  1604 			// Check we in the appropriate state to start
  1605 			if(iTestOverUnderState == EStartState)
  1606 				{
  1607 				// Re-use the previously-provided buffers. Just request the initial notification triggers,
  1608 				// the simulate the first event (RxOverrun).
  1609 				r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun));
  1610 				if(r != KErrNone)
  1611 					{
  1612 					CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest SetNotificationTrigger returned %d\n",r));
  1613 					}
  1614 				else
  1615 					{
  1616 					// Trigger now set, so simulate the required event
  1617 					iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun;
  1618 					iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
  1619 					iTestOverUnderState = ERxOverrun_1;	// Prepare for callback
  1620 					// The requested number of words when the buffer was registered was 8, so simulate 10
  1621 					// to provoke an RxOverrun event.
  1622 					TInt numWords=10;
  1623 					// To support testing, any values of aId for StaticExtension must be shifted left one place
  1624 					// and for a Slave, the two msbs must be zero
  1625 					TInt ctrlIoVal = RBusDevIicClient::ECtrlIoRxWords;
  1626 					ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
  1627 					r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords);
  1628 					}
  1629 				}
  1630 			else
  1631 				{
  1632 				CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest ECtrlIoOvUndRunRxTx, iTestOverUnderState = 0x%x\n",iTestOverUnderState));
  1633 				r=KErrGeneral;
  1634 				}
  1635 			break;
  1636 			}
  1637 
  1638 		default:
  1639 			{
  1640 			CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest - unrecognised value for aId=0x%x\n",aId));
  1641 			r=KErrArgument;
  1642 			break;
  1643 			}
  1644 		}
  1645 	return r;
  1646 	}
  1647