kerneltest/e32test/iic/iic_psl/iic_slaveclient.cpp
changeset 0 a41df078684a
child 90 947f0dc9f7a8
child 256 c1f20ce4abcf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/iic/iic_psl/iic_slaveclient.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,1647 @@
+// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// e32test/iic/iic_slaveclient.cpp
+// Simulated client of IIC Platform Independent Layer (PIL) Slave functionality
+//
+
+#include <kernel/kern_priv.h>		// for DThread, TDfc
+#ifdef STANDALONE_CHANNEL
+#include <drivers/iic_transaction.h>
+#else
+#include <drivers/iic.h>
+#endif
+#include "../t_iic.h"
+
+#ifdef STANDALONE_CHANNEL
+#include <drivers/iic_channel.h>
+#include "i2c.h"
+#endif
+#ifdef LOG_SLAVECLIENT
+#define CLIENT_PRINT(str) Kern::Printf str
+#else
+#define CLIENT_PRINT(str)
+#endif
+
+//For channel creation
+#ifdef STANDALONE_CHANNEL
+#define NUM_CHANNELS 3 // Arbitrary
+
+#if defined(MASTER_MODE) && !defined(SLAVE_MODE)
+const TInt KChannelTypeArray[NUM_CHANNELS] = {DIicBusChannel::EMaster, DIicBusChannel::EMaster, DIicBusChannel::EMaster};
+#elif defined(MASTER_MODE) && defined(SLAVE_MODE)
+const TInt KChannelTypeArray[NUM_CHANNELS] = {DIicBusChannel::EMaster, DIicBusChannel::ESlave, DIicBusChannel::EMasterSlave};
+#else
+const TInt KChannelTypeArray[NUM_CHANNELS] = {DIicBusChannel::ESlave, DIicBusChannel::ESlave, DIicBusChannel::ESlave};
+#endif
+#define CHANNEL_TYPE(n) (KChannelTypeArray[n])
+#define CHANNEL_DUPLEX(n) (DIicBusChannel::EHalfDuplex)
+#define BUS_TYPE (DIicBusChannel::EI2c)
+
+#if defined(MASTER_MODE)
+const TInt8 KI2cChannelNumBase = 10;	// Arbitrary, real platform may consult the Configuration Repository
+										// Note limit of 5 bit representation (0-31)
+
+#else
+const TInt8 KI2cChannelNumBase = 10 + NUM_CHANNELS;	// For Slave mode, want to provide different response
+													// If client assumes Master mode, should be informed not available
+#endif/*MASTER_MODE*/
+
+LOCAL_C TInt8 AssignChanNumI2c()
+	{
+	static TInt8 iBaseChanNumI2c = KI2cChannelNumBase;
+	CLIENT_PRINT(("I2C AssignChanNum - on entry, iBaseChanNum = 0x%x\n",iBaseChanNumI2c));
+	return iBaseChanNumI2c++; // Arbitrary, for illustration
+	}
+
+class DIicSlaveClientChan : public DBase
+	{
+public:
+	DIicSlaveClientChan(DIicBusChannel* aChan, TInt8 aChanNum, TInt aChanType):iChan(aChan),iChanNumber(aChanNum),iChanType(aChanType){};
+	~DIicSlaveClientChan();
+	TInt GetChanNum()const {return iChanNumber;};
+	TInt GetChanType()const {return iChanType;};
+	DIicBusChannel* GetChannelPtr(){return iChan;};
+private:
+	TInt8 iChanNumber;
+	TInt iChanType;
+	DIicBusChannel* iChan;
+	};
+
+DIicSlaveClientChan::~DIicSlaveClientChan()
+	{
+	if(iChan)
+		delete iChan;
+	}
+
+#endif/*STANDALONE_CHANNEL*/
+
+const TInt KIicSlaveClientThreadPriority = 24;
+
+const TInt KIicSlaveClientDfcPriority = 3; // 0 to 7, 7 is highest
+
+const TInt KMaxNumChannels = 2;	// 1 "true" slave, one "dummy"
+
+#ifdef STANDALONE_CHANNEL
+_LIT(KLddRootName,"iic_slaveclient_ctrless");
+#else
+_LIT(KLddRootName,"iic_slaveclient");
+#endif
+_LIT(KIicSlaveClientThreadName,"IicSlaveClientLddThread");
+
+
+struct TCapsIicSlaveClient
+    {
+    TVersion version;
+    };
+
+
+class DDeviceIicSlaveClient : public DLogicalDevice
+    {
+    public:
+    /**
+     * The constructor
+     */
+    DDeviceIicSlaveClient();
+    /**
+     * The destructor
+     */
+    ~DDeviceIicSlaveClient();
+    /**
+     * Second stage constructor - install the device
+     */
+    virtual TInt Install();
+    /**
+     * Get the Capabilites of the device
+     * @param aDes descriptor that will contain the returned capibilites
+     */
+    virtual void GetCaps(TDes8 &aDes) const;
+    /**
+     * Create a logical channel to the device
+     */
+    virtual TInt Create(DLogicalChannelBase*& aChannel);
+    };
+
+
+class DChannelIicSlaveClient : public DLogicalChannel
+    {
+    public:
+    DChannelIicSlaveClient();
+    ~DChannelIicSlaveClient();
+
+    virtual TInt DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer);
+
+	void RequestComplete(TInt r);
+	TInt CheckDataWritten();
+	TInt CheckDataRead();
+
+	static void SlaveClientCallbackFunc(TInt aChannelId, TInt aReturn, TInt aTrigger, TInt16 aRxWords, TInt16 aTxWords, TAny*	aParam);
+#ifdef STANDALONE_CHANNEL
+	static TInt OrderEntries(const DIicSlaveClientChan& aMatch, const DIicSlaveClientChan& aEntry);
+#endif
+    protected:
+    virtual void HandleMsg(TMessageBase* aMsg);	// Note: this is a pure virtual in DLogicalChannel
+
+	TInt DoControl(TInt aId, TAny* a1, TAny* a2); // Name for convenience!
+    TInt DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2); // Name for convenience!
+
+	private:
+	TInt InitSlaveClient();
+	TInt CbProcessOverUnderRunRxTx();
+	TInt RegisterRxBuffer(TInt aChannelId, TPtr8 aRxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset);
+	TInt SetNotificationTrigger(TInt aChannelId, TInt aTrigger);
+	TInt StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2);
+	TInt RegisterTxBuffer(TInt aChannelId, TPtr8 aTxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset);
+	TInt CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch=NULL);
+	TInt ReleaseChannel(TInt aChannelId);
+	private:
+	TDynamicDfcQue* iDfcQue;
+	TIicBusSlaveCallback* iNotif;
+
+	HBuf8* iConfigHdr;
+	TRequestStatus* iStatus;
+
+	TUint8* iRxBuf;
+	TUint8* iTxBuf;
+
+	TUint8* iBusTxCheckBuf;
+
+	TInt8 iNumRegRxWords;
+	TInt8 iNumRegTxWords;
+
+	TInt8 iTxRegGranularity;
+	TInt8 iTxRegOffset;
+	TInt8 iTxReqNumWords;
+
+	TInt8 iRxRegGranularity;
+	TInt8 iRxRegOffset;
+	TInt8 iRxReqNumWords;
+
+	TUint iBusId;
+#ifdef STANDALONE_CHANNEL
+	// For some slave-channel-only functions,e.g. ReleaseChannel, RegisterRxBuffer, etc.
+	// the client needs to remember the slave channel that has been captured
+	struct TCapturedChannel
+		{
+		DIicSlaveClientChan* iChannel;
+		TInt iChannelId;
+		};
+	TCapturedChannel iCapturedChan;
+#endif
+	public:
+	DThread* iClient;
+	TInt iChannelId;	// public to be accessible by callback
+	TInt* iClientChanId;
+
+	TInt iExpectedTrigger;
+	TInt iFullDuplexReq;
+	TInt iBlockedTrigger;
+
+	typedef enum TTestOverUnderState
+		{
+		EStartState  = 0x1,
+		ERxOverrun_1,
+		ERxOverrun_2,
+		ETxUnderrun_1,
+		ETxUnderrun_2
+		};
+	TTestOverUnderState iTestOverUnderState;
+	};
+
+DDeviceIicSlaveClient::DDeviceIicSlaveClient()
+// Constructor
+    {
+	CLIENT_PRINT(("> DDeviceIicSlaveClient::DDeviceIicSlaveClient()"));
+    iParseMask=0;		// No info, no PDD, no Units
+    iUnitsMask=0;
+    iVersion=TVersion(KIicClientMajorVersionNumber,
+		      KIicClientMinorVersionNumber,
+		      KIicClientBuildVersionNumber);
+    }
+
+#ifdef STANDALONE_CHANNEL
+//Store all the channels created by the client into an array
+RPointerArray<DIicSlaveClientChan> ChannelArray;
+#endif
+DDeviceIicSlaveClient::~DDeviceIicSlaveClient()
+// Destructor
+    {
+	CLIENT_PRINT(("> DDeviceIicSlaveClient::~DDeviceIicSlaveClient()"));
+#ifdef STANDALONE_CHANNEL
+	//The client is reponsible for channel destroy in STANDALONE_CHANNEL mode
+    ChannelArray.ResetAndDestroy();
+#endif
+	}
+
+TInt DDeviceIicSlaveClient::Install()
+// Install the device driver.
+    {
+	CLIENT_PRINT(("> DDeviceIicSlaveClient::Install()"));
+
+    return(SetName(&KLddRootName));
+    }
+
+
+void DDeviceIicSlaveClient::GetCaps(TDes8& aDes) const
+// Return the IicClient capabilities.
+    {
+	CLIENT_PRINT(("> DDeviceIicSlaveClient::GetCaps(TDes8& aDes) const"));
+    TPckgBuf<TCapsIicSlaveClient> b;
+    b().version=TVersion(KIicClientMajorVersionNumber,
+			 KIicClientMinorVersionNumber,
+			 KIicClientBuildVersionNumber);
+    Kern::InfoCopy(aDes,b);
+    }
+
+
+TInt DDeviceIicSlaveClient::Create(DLogicalChannelBase*& aChannel)
+// Create a channel on the device.
+    {
+	CLIENT_PRINT(("> DDeviceIicSlaveClient::Create(DLogicalChannelBase*& aChannel)"));
+	if(iOpenChannels>=KMaxNumChannels)
+		return KErrOverflow;
+    aChannel=new DChannelIicSlaveClient;
+    return aChannel?KErrNone:KErrNoMemory;
+    }
+
+#ifdef STANDALONE_CHANNEL
+//  auxiliary function for ordering entries in the array of channels
+TInt DChannelIicSlaveClient::OrderEntries(const DIicSlaveClientChan& aMatch, const DIicSlaveClientChan& aEntry)
+	{
+	TUint8 l=(TUint8)aMatch.GetChanNum();
+	TUint8 r=(TUint8)aEntry.GetChanNum();
+	if(l>r)
+		return -1;
+	else if(l<r)
+		return 1;
+	else
+		return 0;
+	}
+
+// global ordering object to be passed to RPointerArray InsertInOrderXXX and FindInOrder
+TLinearOrder<DIicSlaveClientChan> EntryOrder(DChannelIicSlaveClient::OrderEntries);
+
+TInt GetChanPtr(const TInt aBusId, DIicSlaveClientChan*& aChan)
+	{
+    __KTRACE_OPT(KIIC, 	Kern::Printf("GetChanPtr, aBusId=0x%x\n",aBusId));
+	TInt32 chanId;
+	chanId = GET_CHAN_NUM(aBusId);
+    __KTRACE_OPT(KIIC, 	Kern::Printf("GetChanPtr, chanId=0x%x\n",chanId));
+	DIicSlaveClientChan chanEntry(NULL,(TInt8)chanId, DIicBusChannel::EMasterSlave);
+
+	TInt r = KErrNotFound;
+	TInt aIndex = ChannelArray.FindInOrder(&chanEntry, EntryOrder);
+
+	if(aIndex >= 0)
+		{
+		aChan = ChannelArray[aIndex];
+		r = KErrNone;
+		}
+
+	return r;
+	}
+#endif/*STANDALONE_CHANNEL*/
+
+DECLARE_STANDARD_LDD()
+	{
+#ifdef STANDALONE_CHANNEL
+	TInt r = KErrNone;
+	DIicBusChannel *chan = NULL, *chanM = NULL, *chanS = NULL;
+	DIicSlaveClientChan* aSlaveClientChan;
+	for(TInt i=0; i<NUM_CHANNELS; i++)
+			{
+			CLIENT_PRINT(("\n"));
+	#if defined(MASTER_MODE)
+			if(CHANNEL_TYPE(i) == (DIicBusChannel::EMaster))
+				{
+				chan=new DSimulatedIicBusChannelMasterI2c(BUS_TYPE,CHANNEL_DUPLEX(i));
+				if(!chan)
+					{
+					CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE(i),i));
+					return NULL;
+					}
+				CLIENT_PRINT(("I2C chan created at 0x%x\n",chan));
+				if(((DSimulatedIicBusChannelMasterI2c*)chan)->Create()!=KErrNone)
+					{
+					delete chan;
+					return NULL;
+					}
+				aSlaveClientChan = new DIicSlaveClientChan(chan,AssignChanNumI2c(),DIicBusChannel::EMaster);
+				if(!aSlaveClientChan)
+					{
+					delete chan;
+					return NULL;
+					}
+				r = ChannelArray.InsertInOrder(aSlaveClientChan,EntryOrder);
+				if(r!=KErrNone)
+					{
+					delete chan;
+					delete aSlaveClientChan;
+					break;
+					}
+				}
+	#endif
+	#if defined(MASTER_MODE) && defined(SLAVE_MODE)
+			if(CHANNEL_TYPE(i) == DIicBusChannel::EMasterSlave)
+				{
+				chanM=new DSimulatedIicBusChannelMasterI2c(BUS_TYPE,CHANNEL_DUPLEX(i));
+				if(!chanM)
+					return NULL;
+				chanS=new DSimulatedIicBusChannelSlaveI2c(BUS_TYPE,CHANNEL_DUPLEX(i));
+				if(!chanS)
+					{
+					delete chanM;
+					return NULL;
+					}
+				chan=new DSimulatedIicBusChannelMasterSlaveI2c(BUS_TYPE,CHANNEL_DUPLEX(i),(DSimulatedIicBusChannelMasterI2c*)chanM,(DSimulatedIicBusChannelSlaveI2c*)chanS); // Generic implementation
+				if(!chan)
+					{
+					CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE(i),i));
+					delete chanM;
+					delete chanS;
+					return NULL;
+					}
+				CLIENT_PRINT(("I2C chan created at 0x%x\n",chan));
+				if(((DIicBusChannelMasterSlave*)chan)->DoCreate()!=KErrNone)
+					{
+					delete chanM;
+					delete chanS;
+					delete chan;
+					return NULL;
+					}
+				aSlaveClientChan = new DIicSlaveClientChan(chan,AssignChanNumI2c(),DIicBusChannel::EMasterSlave);
+				if(!aSlaveClientChan)
+					{
+					delete chanM;
+					delete chanS;
+					delete chan;
+					return NULL;
+					}
+				r = ChannelArray.InsertInOrder(aSlaveClientChan,EntryOrder);
+				if(r!=KErrNone)
+					{
+					delete chanM;
+					delete chanS;
+					delete chan;
+					delete aSlaveClientChan;
+					break;
+					}
+				}
+	#endif
+	#if defined(SLAVE_MODE)
+			if(CHANNEL_TYPE(i) == (DIicBusChannel::ESlave))
+				{
+				chan=new DSimulatedIicBusChannelSlaveI2c(BUS_TYPE,CHANNEL_DUPLEX(i));
+				if(!chan)
+					{
+					CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE(i),i));
+					return NULL;
+					}
+				CLIENT_PRINT(("I2C chan created at 0x%x\n",chan));
+				if(((DSimulatedIicBusChannelSlaveI2c*)chan)->Create()!=KErrNone)
+					return NULL;
+				aSlaveClientChan = new DIicSlaveClientChan(chan,AssignChanNumI2c(),DIicBusChannel::ESlave);
+				if(!aSlaveClientChan)
+					{
+					delete chan;
+					return NULL;
+					}
+				r = ChannelArray.InsertInOrder(aSlaveClientChan,EntryOrder);
+				if(r!=KErrNone)
+					{
+					delete chan;
+					delete aSlaveClientChan;
+					break;
+					}
+				}
+	#endif
+	#if !defined(MASTER_MODE) && !defined(SLAVE_MODE)
+	#error I2C mode not defined as Master, Slave nor Master-Slave
+	#endif
+			}
+#endif
+	return new DDeviceIicSlaveClient;
+	}
+
+
+
+DChannelIicSlaveClient::DChannelIicSlaveClient()
+// Constructor
+    {
+	iFullDuplexReq=iBlockedTrigger=iExpectedTrigger=0;
+	CLIENT_PRINT(("> DChannelIicSlaveClient::DChannelIicSlaveClient()"));
+    iClient=&Kern::CurrentThread();
+	// Increase the DThread's ref count so that it does not close without us
+	iClient->Open();
+	iTestOverUnderState = EStartState;
+    }
+
+DChannelIicSlaveClient::~DChannelIicSlaveClient()
+// Destructor
+    {
+	CLIENT_PRINT(("> DChannelIicSlaveClient::~DChannelIicSlaveClient()"));
+	iDfcQue->Destroy();
+	delete iNotif;
+	delete iRxBuf;
+	delete iTxBuf;
+	delete iBusTxCheckBuf;
+	// decrement the DThread's reference count
+	Kern::SafeClose((DObject*&)iClient, NULL);
+	}
+
+void DChannelIicSlaveClient::RequestComplete(TInt r)
+	{
+	Kern::RequestComplete(iClient, iStatus, r);
+	}
+
+TInt DChannelIicSlaveClient::RegisterRxBuffer(TInt aChannelId, TPtr8 aRxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
+	{
+	TInt r = KErrNone;
+#ifdef STANDALONE_CHANNEL
+	DIicSlaveClientChan* aChanPtr = NULL;
+	if(iCapturedChan.iChannelId == aChannelId)
+		aChanPtr = iCapturedChan.iChannel;
+	if(!aChanPtr)
+		return KErrArgument;
+	if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave)
+		r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->RegisterRxBuffer(aRxBuffer, aBufGranularity, aNumWords, aOffset);
+	else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave)
+		r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->RegisterRxBuffer(aRxBuffer, aBufGranularity, aNumWords, aOffset);
+#else
+	r = IicBus::RegisterRxBuffer(aChannelId, aRxBuffer, aBufGranularity, aNumWords, aOffset);
+#endif
+	return r;
+	}
+
+TInt DChannelIicSlaveClient::SetNotificationTrigger(TInt aChannelId, TInt aTrigger)
+	{
+	TInt r = KErrNone;
+#ifdef STANDALONE_CHANNEL
+	DIicSlaveClientChan* aChanPtr = NULL;
+	if(iCapturedChan.iChannelId == aChannelId)
+		aChanPtr = iCapturedChan.iChannel;
+	if(!aChanPtr)
+		return KErrArgument;
+	if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave)
+		r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->SetNotificationTrigger(aTrigger);
+	else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave)
+		r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->SetNotificationTrigger(aTrigger);
+#else
+	r = IicBus::SetNotificationTrigger(aChannelId, aTrigger);
+#endif
+	return r;
+	}
+
+TInt DChannelIicSlaveClient::StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2)
+	{
+	TInt r = KErrNone;
+#ifdef STANDALONE_CHANNEL
+	DIicSlaveClientChan* aChanPtr;
+	r = GetChanPtr(aId, aChanPtr);
+	if(r != KErrNone)
+		return r;
+	if(!aChanPtr)
+		return KErrArgument;
+	if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave)
+		r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->StaticExtension(aFunction, aParam1, aParam2);
+	else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave)
+	r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->StaticExtension(aFunction, aParam1, aParam2);
+#else
+	r = IicBus::StaticExtension(aId, aFunction, aParam1, aParam2);
+#endif
+	return r;
+	}
+
+TInt DChannelIicSlaveClient::RegisterTxBuffer(TInt aChannelId, TPtr8 aTxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
+	{
+	TInt r = KErrNone;
+#ifdef STANDALONE_CHANNEL
+	DIicSlaveClientChan* aChanPtr = NULL;
+	if(iCapturedChan.iChannelId == aChannelId)
+		aChanPtr = iCapturedChan.iChannel;
+	if(!aChanPtr)
+		return KErrArgument;
+	if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave)
+		r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->RegisterTxBuffer(aTxBuffer, aBufGranularity, aNumWords, aOffset);
+	else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave)
+		r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->RegisterTxBuffer(aTxBuffer, aBufGranularity, aNumWords, aOffset);
+#else
+	r = IicBus::RegisterTxBuffer(aChannelId, aTxBuffer, aBufGranularity, aNumWords, aOffset);
+#endif
+	return r;
+	}
+
+TInt DChannelIicSlaveClient::CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch)
+	{
+	TInt r = KErrNone;
+#ifndef STANDALONE_CHANNEL
+	r = IicBus::CaptureChannel(aBusId, aConfigHdr, aCallback, aChannelId, aAsynch);
+#else
+	// Check that that aCallback!=NULL and aConfigHdr!=NULL - if not, return KErrArgument
+	if(!aCallback || !aConfigHdr)
+		{
+		return KErrArgument;
+		}
+
+	// Get the channel
+	DIicSlaveClientChan* chanPtr = NULL;
+	if(r == KErrNone)
+		{
+		r = GetChanPtr(aBusId, chanPtr);
+		if(r == KErrNone)
+			{
+			if(!chanPtr)
+				{
+				r = KErrArgument;
+				}
+			else
+				{
+				switch(chanPtr->GetChanType())
+					{
+					// CaptureChannel requests are only supported by channels in Slave mode.
+					case DIicBusChannel::EMaster:
+						{
+						r = KErrNotSupported;
+						break;
+						}
+					case DIicBusChannel::EMasterSlave:
+						{
+						r = ((DIicBusChannelMasterSlave*) (chanPtr->GetChannelPtr()))->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch);
+						break;
+						}
+					case DIicBusChannel::ESlave:
+						{
+						r = ((DIicBusChannelSlave*) (chanPtr->GetChannelPtr()))->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch);
+						break;
+						}
+					default:
+						{
+						r = KErrArgument;
+						}
+					}
+				// For synchronous capture, if successful then install the channel
+				if(r == KErrNone)
+					{
+					if(!aAsynch)
+						{
+						 iCapturedChan.iChannel = chanPtr;
+						 iCapturedChan.iChannelId = aChannelId;
+						}
+					else
+						//For asynchronous capture, record slaveChanPtr, if later failed capture,
+						//clean iCapturedChannel in client's callback.
+						iCapturedChan.iChannel = chanPtr;
+					}
+				}
+			}
+		}
+#endif
+	return r;
+	}
+
+TInt DChannelIicSlaveClient::ReleaseChannel(TInt aChannelId)
+	{
+	TInt r = KErrNone;
+#ifndef STANDALONE_CHANNEL
+	r = IicBus::ReleaseChannel(aChannelId);
+#else
+    __KTRACE_OPT(KIIC, Kern::Printf("DChannelIicSlaveClient::ReleaseChannel, channelID = 0x%x \n",aChannelId));
+    // Acquire the pointer to the Slave Channel
+    if(iCapturedChan.iChannelId != aChannelId)
+		return KErrNotFound;
+
+	if((iCapturedChan.iChannel)->GetChanType() == DIicBusChannel::EMasterSlave)
+		r = ((DIicBusChannelMasterSlave*)((iCapturedChan.iChannel)->GetChannelPtr()))->ReleaseChannel();
+	else if((iCapturedChan.iChannel)->GetChanType() == DIicBusChannel::ESlave)
+		r = ((DIicBusChannelSlave*)((iCapturedChan.iChannel)->GetChannelPtr()))->ReleaseChannel();
+	//After release channel, reset iCapturedChan
+	iCapturedChan.iChannel = NULL;
+	iCapturedChan.iChannelId = 0;
+#endif
+	return r;
+	}
+TInt DChannelIicSlaveClient::CbProcessOverUnderRunRxTx()
+	{
+	CLIENT_PRINT(("> DChannelIicSlaveClient::CbProcessOverUnderRunRxTx(), iTestOverUnderState=%d\n",iTestOverUnderState));
+	TInt r = KErrNone;
+	switch (iTestOverUnderState)
+		{
+		case(EStartState):
+			{
+			// In this state, no action is required
+			break;
+			};
+		case(ERxOverrun_1):
+			{
+			CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ERxOverrun_1\n"));
+			// At this point, the outstanding request trigger should be ETxAllBytes | ETxUnderrun
+			// and the flag to indicate duplex transfers should be cleared
+			if((iExpectedTrigger != (ETxAllBytes | ETxUnderrun)) || (iFullDuplexReq != ETxAllBytes))
+				{
+				CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq));
+				r=KErrGeneral;
+				}
+			else
+				{
+				// Simulate providing a new buffer (actually, re-use existing buffer)
+				CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterRxBuffer\n"));
+				TPtr8 rxPtr(iRxBuf,KRxBufSizeInBytes);
+				r = RegisterRxBuffer(iChannelId, rxPtr, iRxRegGranularity, iNumRegRxWords, iRxRegOffset);
+
+				if(r != KErrNone)
+					{
+					CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterRxBuffer returned %d\n",r));
+					}
+				else
+					{
+					// For the next step, just specify the new Rx triggers (do not specify Tx triggers)
+					r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun));
+					if(r != KErrNone)
+						{
+						CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d\n",r));
+						}
+					else
+						{
+						iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun;
+						iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
+						iTestOverUnderState = ERxOverrun_2;	// Prepare for callback
+						// The requested number of words when the buffer was registered was 8, so simulate 10
+						// to provoke an RxOverrun event.
+						TInt numWords=10;
+						// To support testing, any values of aId for StaticExtension must be shifted left one place
+						// and for a Slave, the two msbs must be zero
+						TInt ctrlIoVal = RBusDevIicClient::ECtrlIoRxWords;
+						ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
+						r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords);
+						}
+					}
+				}
+			break;
+			};
+		case(ERxOverrun_2):
+			{
+			CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ERxOverrun_2\n"));
+			// At this point, the outstanding request trigger should be ETxAllBytes | ETxUnderrun
+			// and the flag to indicate duplex transfers should be cleared
+			if((iExpectedTrigger != (ETxAllBytes | ETxUnderrun)) || (iFullDuplexReq != ETxAllBytes))
+				{
+				CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq));
+				r=KErrGeneral;
+				}
+			else
+				{
+				// Simulate providing a new buffer (actually, re-use existing buffer)
+				CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterRxBuffer\n"));
+				TPtr8 rxPtr(iRxBuf,KRxBufSizeInBytes);
+				r = RegisterRxBuffer(iChannelId, rxPtr, iRxRegGranularity, iNumRegRxWords, iRxRegOffset);
+				if(r != KErrNone)
+					{
+					CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterRxBuffer returned %d\n",r));
+					}
+				else
+					{
+					// Test that an attempt to modify existing Tx notification requests is rejected
+					r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxOverrun));
+					if(r != KErrInUse)
+						{
+						CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrInUse\n",r));
+						}
+					else
+						{
+						// For the next step, specify the new Rx triggers and the Tx triggers
+						r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun));
+						if(r != KErrNone)
+							{
+							CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrNone\n",r));
+							}
+						else
+							{
+							iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun;
+							iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
+							iTestOverUnderState = ETxUnderrun_1;	// Prepare for callback
+							// The requested number of words when the buffer was registered was 12, so simulate 14
+							// to provoke an TxUnderrun event.
+							TInt numWords=14;
+							// To support testing, any values of aId for StaticExtension must be shifted left one place
+							// and for a Slave, the two msbs must be zero
+							TInt ctrlIoVal = RBusDevIicClient::ECtrlIoTxWords;
+							ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
+							r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords);
+							}
+						}
+					}
+				}
+			break;
+			};
+		case(ETxUnderrun_1):
+			{
+			CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ETxOverrun_1\n"));
+			// At this point, the outstanding request trigger should be ERxAllBytes | ERxOverrun
+			// and the flag to indicate duplex transfers should be cleared
+			if((iExpectedTrigger != (ERxAllBytes | ERxOverrun)) || (iFullDuplexReq != ERxAllBytes))
+				{
+				CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq));
+				r=KErrGeneral;
+				}
+			else
+				{
+				// Simulate providing a new buffer (actually, re-use existing buffer)
+				CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterTxBuffer\n"));
+				TPtr8 rxPtr(iTxBuf,KTxBufSizeInBytes);
+				r = RegisterTxBuffer(iChannelId, rxPtr, iTxRegGranularity, iNumRegTxWords, iTxRegOffset);
+				if(r != KErrNone)
+					{
+					CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterTxBuffer returned %d\n",r));
+					}
+				else
+					{
+					// For the next step, just specify the new Tx triggers (do not specify Rx triggers)
+					r = SetNotificationTrigger(iChannelId, (ETxAllBytes | ETxUnderrun));
+					if(r != KErrNone)
+						{
+						CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d\n",r));
+						}
+					else
+						{
+						iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun;
+						iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
+						iTestOverUnderState = ETxUnderrun_2;	// Prepare for callback
+						// The requested number of words when the buffer was registered was 12, so simulate 14
+						// to provoke an TxUnderrun event.
+						TInt numWords=14;
+						// To support testing, any values of aId for StaticExtension must be shifted left one place
+						// and for a Slave, the two msbs must be zero
+						TInt ctrlIoVal = RBusDevIicClient::ECtrlIoTxWords;
+						ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
+						r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords);
+						}
+					}
+				}
+			break;
+			};
+		case(ETxUnderrun_2):
+			{
+			CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ETxUnderrun_2\n"));
+			// At this point, the outstanding request trigger should be ERxAllBytes | ERxOverrun
+			// and the flag to indicate duplex transfers should be cleared
+			if((iExpectedTrigger != (ERxAllBytes | ERxOverrun)) || (iFullDuplexReq != ERxAllBytes))
+				{
+				CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq));
+				r=KErrGeneral;
+				}
+			else
+				{
+				// Simulate providing a new buffer (actually, re-use existing buffer)
+				CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterRxBuffer\n"));
+				TPtr8 rxPtr(iTxBuf,KTxBufSizeInBytes);
+				r = RegisterTxBuffer(iChannelId, rxPtr, iTxRegGranularity, iNumRegTxWords, iTxRegOffset);
+				if(r != KErrNone)
+					{
+					CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterTxBuffer returned %d\n",r));
+					}
+				else
+					{
+					// Test that an attempt to modify existing Rx notification requests is rejected
+					r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxUnderrun | ETxAllBytes | ETxUnderrun));
+					if(r != KErrInUse)
+						{
+						CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrInUse\n",r));
+						}
+					else
+						{
+						// For the next step, specify the new Rx triggers and the Tx triggers
+						r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun));
+
+						if(r != KErrNone)
+							{
+							CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrNone\n",r));
+							}
+						else
+							{
+							// Simulate a simultaneous ERxAllBytes and ETxAllBytes event.
+							iExpectedTrigger = ERxAllBytes | ETxAllBytes;
+							iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
+							iTestOverUnderState = EStartState;	// Prepare for callback - return to normal operation
+							// Need to pass the number of words in an array, for use by StaticExtension
+							TInt parms[2];
+							parms[0]= 8;	// Number of Rx Words
+							parms[1]=12;	// Number of Tx Words
+							// To support testing, any values of aId for StaticExtension must be shifted left one place
+							// and for a Slave, the two msbs must be zero
+							TInt ctrlIoVal = RBusDevIicClient::ECtrlIoRxTxWords;
+							ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
+							r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)(&parms[0]));
+							}
+						}
+					}
+				}
+			break;
+			};
+		default:
+			{
+			r = KErrGeneral;
+			break;
+			};
+		}
+	return r;
+	}
+
+void DChannelIicSlaveClient::SlaveClientCallbackFunc(TInt aChannelId, TInt aReturn, TInt aTrigger, TInt16 aRxWords, TInt16 aTxWords, TAny*	aParam)
+	{
+	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));
+	(void)aTxWords; // Unused if CLIENT_PRINT is undefined
+	(void)aRxWords; // Unused if CLIENT_PRINT is undefined
+	DChannelIicSlaveClient* channel = (DChannelIicSlaveClient*)aParam;
+
+	// Ensure only the valid bits of aTrigger are processed
+	aTrigger &= 0xff;
+
+	CLIENT_PRINT(("SlaveClientCallbackFunc() - channel=0x%x\n",channel));
+	if(aTrigger == EAsyncCaptChan)
+		{
+		CLIENT_PRINT(("SlaveClientCallbackFunc: capture channel completed\n"));
+		// Set iChannelId, and write to user-side variable.
+		channel->iChannelId=aChannelId;
+		TInt r=Kern::ThreadRawWrite(channel->iClient,channel->iClientChanId,&aChannelId,sizeof(TInt));
+		if(r == KErrNone)
+			r=aReturn;
+#ifdef STANDALONE_CHANNEL
+		// Set the captured channel's iChannelId if the capture succeeds.
+		if(r != KErrCompletion)
+			(channel->iCapturedChan).iChannel = NULL;
+		else
+			(channel->iCapturedChan).iChannelId = aChannelId;
+#endif/*STANDALONE_CHANNEL*/
+	    channel->RequestComplete(r);	// Inform user of error
+		return;
+		}
+	else
+		{
+		if(aTrigger&ERxAllBytes)
+			{
+			CLIENT_PRINT(("SlaveClientCallbackFunc() - ERxAllBytes\n"));
+			aTrigger&= ~ERxAllBytes;
+			channel->iExpectedTrigger&=~ERxAllBytes;
+			channel->iFullDuplexReq&=~ERxAllBytes;
+			aReturn=channel->CheckDataRead();
+			// Check underrun
+			if(aTrigger&ERxUnderrun)
+				{
+				if(channel->iExpectedTrigger&ERxUnderrun)
+					{
+					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxUnderrun found OK\n\n"));
+					channel->iExpectedTrigger&=~ERxUnderrun;
+					}
+				else
+					{
+					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ERxUnderrun indicated\n\n"));
+					aReturn = KErrGeneral;
+					}
+				}
+			else
+				{
+				if(channel->iExpectedTrigger&ERxUnderrun)
+					{
+					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxUnderrun not (yet) seen\n\n"));
+					aReturn = KErrGeneral;
+					}
+				}
+			// Check overrun
+			if(aTrigger&ERxOverrun)
+				{
+				if(channel->iExpectedTrigger&ERxOverrun)
+					{
+					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxOverrun found OK\n\n"));
+					channel->iExpectedTrigger&=~ERxOverrun;
+					}
+				else
+					{
+					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ERxOverrun indicated\n\n"));
+					aReturn = KErrGeneral;
+					}
+				}
+			else
+				{
+				if(channel->iExpectedTrigger&ERxOverrun)
+					{
+					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxOverrun not (yet) seen\n\n"));
+					aReturn = KErrGeneral;
+					}
+				}
+			}
+
+		if(aTrigger&ETxAllBytes)
+			{
+			CLIENT_PRINT(("SlaveClientCallbackFunc() - ETxAllBytes\n"));
+			aTrigger&= ~ETxAllBytes;
+			channel->iExpectedTrigger&=~ETxAllBytes;
+			channel->iFullDuplexReq&=~ETxAllBytes;
+			aReturn=channel->CheckDataWritten();
+			// Check underrun
+			if(aTrigger&ETxUnderrun)
+				{
+				if(channel->iExpectedTrigger&ETxUnderrun)
+					{
+					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxUnderrun found OK\n\n"));
+					channel->iExpectedTrigger&=~ETxUnderrun;
+					}
+				else
+					{
+					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ETxUnderrun indicated\n\n"));
+					aReturn = KErrGeneral;
+					}
+				}
+			else
+				{
+				if(channel->iExpectedTrigger&ETxUnderrun)
+					{
+					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxUnderrun not (yet) seen\n\n"));
+					aReturn = KErrGeneral;
+					}
+				}
+			// Check overrun
+			if(aTrigger&ETxOverrun)
+				{
+				if(channel->iExpectedTrigger&ETxOverrun)
+					{
+					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxOverrun found OK\n\n"));
+					channel->iExpectedTrigger&=~ETxOverrun;
+					}
+				else
+					{
+					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ETxOverrun indicated\n\n"));
+					aReturn = KErrGeneral;
+					}
+				}
+			else
+				{
+				if(channel->iExpectedTrigger&ETxOverrun)
+					{
+					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxOverrun not (yet) seen\n\n"));
+					aReturn = KErrGeneral;
+					}
+				}
+			}
+
+
+		if(aTrigger&EGeneralBusError)
+			{
+				if(channel->iExpectedTrigger&EGeneralBusError)
+					{
+					CLIENT_PRINT(("\nSlaveClientCallbackFunc: EGeneralBusError - as expected\n\n"));
+					channel->iExpectedTrigger&=~EGeneralBusError;
+					if(aReturn == KErrGeneral)
+						{
+						aReturn=KErrNone; // If aReturn==KErrGeneral, set to KErrNone so t_iic knows test was successful
+						channel->iFullDuplexReq = 0; // The transaction is considered terminated, so don't wait for more triggers
+						}
+					else
+						{
+						CLIENT_PRINT(("\nSlaveClientCallbackFunc: aReturn not EGeneralBusError, =0x%x \n\n",aReturn));
+						aReturn=KErrGeneral;
+						}
+
+					}
+				else
+					{
+					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected EGeneralBusError indicated\n\n"));
+					aReturn = KErrGeneral;
+					}
+			}
+
+		if((aTrigger < 0)||(aTrigger & (~0xFF)))
+			{
+			CLIENT_PRINT(("\nSlaveClientCallbackFunc: trigger condition 0x%x is not recognised \n\n",aTrigger));
+			}
+
+		// For simulataneous Rx,Tx triggers with ERxOverrun or TxUnderrun testing, need to call the following
+		if(aReturn == KErrNone)
+			{
+			aReturn = channel->CbProcessOverUnderRunRxTx();
+			}
+
+		if((channel->iExpectedTrigger == 0)&&(channel->iFullDuplexReq == 0))
+			channel->RequestComplete(aReturn);	// Complete user-side request only if all the triggers have been satisfied
+
+		} // if(aTrigger == EAsyncCaptChan)
+	}
+
+
+TInt DChannelIicSlaveClient::CheckDataRead()
+	{
+	TInt r=KErrNone;
+	// This channel will have provided a buffer for writing to, with a specified offset and number of words
+	// Bytes in the buffer before the offset should be set to zero
+	// Bytes written at and beyond the offset should exhibit an incrementing count
+	// Bytes beyond the offset that were not written to should be set to zero
+	TInt8 numWords=(iRxReqNumWords>iNumRegRxWords)?iNumRegRxWords:iRxReqNumWords;
+	TInt8 currVal=0;
+	TInt8 index = 0;
+	while(index<iRxRegOffset)
+		{
+		currVal=*(iRxBuf+index);
+		if(currVal != 0)
+			{
+			CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataRead, index=%d, value =0x%x, expected 0",index,currVal));
+			r=KErrCorrupt;
+			}
+		++index;
+		}
+
+	TInt8 checkVal=0x10; // first value written by simulated bus channel
+	TInt8 endOfData= (TInt8)(iRxRegOffset+(numWords*iRxRegGranularity));
+	TInt8 wordCount=0;
+	while(index<endOfData)
+		{
+		currVal = *(iRxBuf+index);
+		if(checkVal != currVal)
+			{
+			CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataRead, index=%d, value =0x%x, expected 0x%x",index,currVal,checkVal));
+			r=KErrCorrupt;
+			}
+		if(++wordCount == iRxRegGranularity)
+			{
+			wordCount=0;
+			checkVal++;
+			}
+		++index;
+		}
+
+	while(index<KRxBufSizeInBytes)
+		{
+		currVal=*(iRxBuf+index);
+		if(currVal != 0)
+			{
+			CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataRead, index=%d, value =0x%x, expected 0",index,currVal);)
+			r=KErrCorrupt;
+			}
+		++index;
+		}
+	return r;
+	}
+
+
+TInt DChannelIicSlaveClient::CheckDataWritten()
+	{
+	TInt r=KErrNone;
+	// The pattern in the transmit buffer used by the simulated bus channel contains a incrementing count
+	// from 0 to (KTxBufSizeInBytes-1), therefore the first value to be present in the check buffer will be
+	// represented by the required offset.
+
+	// The bytes "transmitted" are stored in the simulated bus' iTxCheckBuf
+	// Since the simulated bus channel is also in the kernel process it shares the same address space
+	// Get the address of the buffer
+	TUint testId = (((TUint)(RBusDevIicClient::ECtrlIoTxChkBuf))<<1)&0x3FFFFFFF;
+	CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataWritten invoking StaticExtension ECtrlIoTxChkBuf with iBusId=0x%x, testId=0x%x, iBusTxCheckBuf=0x%x\n",iBusId,testId,iBusTxCheckBuf));
+	r = StaticExtension(iBusId, testId, &iBusTxCheckBuf, NULL);
+	if(r!=KErrNone)
+		{
+		CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataWritten StaticExtension ECtrlIoTxChkBuf returned %d\n",r));
+		return r;
+		}
+
+	// Check that the values in the check buffer increment for the
+	// required number of words, and that any remaining bytes in the check buffer are set to zero.
+	TInt8 firstValue = iTxRegOffset;
+	TInt8 currVal = 0;
+	TInt8 wordsWritten = 0;
+	wordsWritten=(iTxReqNumWords>iNumRegTxWords)?iNumRegTxWords:iTxReqNumWords;
+	TInt8 index=0;
+	while(index<(wordsWritten*iTxRegGranularity))
+		{
+		currVal=*(iBusTxCheckBuf+index);
+		if(currVal != (TInt8)(firstValue+index))
+			{
+			CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataWritten, index=%d, value =0x%x, expected 0x%x",index,currVal,(TInt8)(firstValue+index)));
+			r=KErrCorrupt;
+			}
+		++index;
+		}
+	while(index<(iNumRegTxWords*iTxRegGranularity))
+		{
+		currVal=*(iBusTxCheckBuf+index);
+		if(currVal != 0)
+			{
+			CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataWritten, index=%d, value =0x%x, expected 0",index,currVal));
+			r=KErrCorrupt;
+			}
+		++index;
+		}
+	return r;
+	}
+
+
+TInt DChannelIicSlaveClient::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
+	{
+	CLIENT_PRINT(("> DChannelIicSlaveClient::DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion &aVer)"));
+
+	TInt r = Kern::DynamicDfcQCreate(iDfcQue,KIicSlaveClientThreadPriority,KIicSlaveClientThreadName);
+	if(r!=KErrNone)
+		return r;
+	SetDfcQ(iDfcQue);
+
+	// Allocate buffers for Rx, Tx operations
+	iRxBuf = new TUint8[KRxBufSizeInBytes];
+	iTxBuf = new TUint8[KTxBufSizeInBytes];
+	if((iRxBuf == NULL)||(iTxBuf == NULL))
+		return KErrNoMemory;
+	// Start receiving messages
+	iMsgQ.Receive();
+
+	return r;
+	}
+
+TInt DChannelIicSlaveClient::InitSlaveClient()
+	{
+	iNotif = new TIicBusSlaveCallback(DChannelIicSlaveClient::SlaveClientCallbackFunc, (TAny*)this, iDfcQue, KIicSlaveClientDfcPriority);
+	if(iNotif == NULL)
+		{
+		CLIENT_PRINT(("> DChannelIicSlaveClient::InitSlaveClient ERROR unable to allocate space TIicBusSlaveCallback* iNotif \n"));
+		return KErrNoMemory;
+		}
+	return KErrNone;
+	}
+
+void DChannelIicSlaveClient::HandleMsg(TMessageBase* aMsg)
+	{
+    TThreadMessage& m=*(TThreadMessage*)aMsg;
+    TInt id=m.iValue;
+
+	CLIENT_PRINT((" >ldd: DChannelIicSlaveClient::HandleMsg(TMessageBase* aMsg) id=%d\n", id));
+
+	if (id == (TInt)ECloseMsg)
+		{
+	    iMsgQ.iMessage->Complete(KErrNone,EFalse);
+		return;
+		}
+
+    if (id<0)
+		{
+		TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
+		TInt r=DoRequest(~id, pS, m.Ptr1(), m.Ptr2());
+		if (r!=KErrNone)
+			{
+	    	Kern::RequestComplete(iClient, pS, r);
+			}
+		m.Complete(KErrNone,ETrue);
+		}
+    else
+	if((id>=0)&&(id!=KMaxTInt))
+		{
+		TInt r=DoControl(id,m.Ptr0(),m.Ptr1());
+		m.Complete(r,ETrue);
+		}
+	}
+
+
+TInt DChannelIicSlaveClient::DoControl(TInt aId, TAny* a1, TAny* a2)
+	{
+	CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoked with aId=0x%x, a1=0x%x, a2=0x%x\n", aId,a1,a2));
+	TInt r=KErrNone;
+	// To support testing, any values of aId for StaticExtension must be shifted left one place
+	// and for a Slave, the two msbs must be zero
+	TInt ctrlIoVal = 0;
+	if((aId & KTestSlaveControlIo) == KTestSlaveControlIo)
+		ctrlIoVal = (aId << 1) & 0x3FFFFFFF;
+
+	switch(aId)
+		{
+		case(RBusDevIicClient::EInitSlaveClient):
+			{
+			r=InitSlaveClient();
+			break;
+			}
+
+		case(RBusDevIicClient::ECaptureChanSync):
+			{
+			// a1 is a pointer to the TDes8* aConfigHdr
+			// a2 is a pointer to TInt* parms[2], where:
+			// parms[0]=(TInt*)aBusId;
+			// parms[1]=&aChannelId;
+			//
+			TInt* parms[2];
+			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt*));
+			if(r!=KErrNone)
+				break;	// Can't proceed if can't access request parameters
+			//
+		  	TInt hdrSize = Kern::ThreadGetDesLength(iClient,a1);
+			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl hdrSize = 0x%x\n",hdrSize));
+  			if (hdrSize<=0)
+				{
+				CLIENT_PRINT(("DChannelIicSlaveClient::DoControl ERROR, hdrSize is invalid\n"));
+ 				r = KErrArgument;
+ 				break;
+				}
+			if((iConfigHdr = HBuf8::New(hdrSize)) == NULL)
+				return KErrNoMemory;
+			r = Kern::ThreadDesRead(iClient,a1,*iConfigHdr,0);
+			if(r!=KErrNone)
+				{
+				delete iConfigHdr;
+				break;
+				}
+			// Store the address of the user-side variable to update with the ChannelId
+			iClientChanId=parms[1];
+
+			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking (synchronous) CaptureChannel\n"));
+			r = CaptureChannel((TInt)(parms[0]), iConfigHdr, iNotif, iChannelId);
+			if(r != KErrNone)
+			    {
+			    delete iConfigHdr;
+			    break;
+			    }
+			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl CaptureChannelgave iChannelId=0x%x\n",iChannelId));
+
+			r = Kern::ThreadRawWrite(iClient,iClientChanId,&iChannelId,sizeof(TInt));
+			if(r != KErrNone)
+				delete iConfigHdr;
+			break;
+			}
+
+		case(RBusDevIicClient::EReleaseChan):
+			{
+			// a1 represents TInt aChannelId
+			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking ReleaseChannel\n"));
+			r = ReleaseChannel((TInt)a1);
+			delete iConfigHdr;
+			break;
+			}
+
+		case(RBusDevIicClient::ERegisterRxBuffer):
+			{
+			// a1 represents TInt aChannelId
+			// a2 represents (TAny*) of TInt8 parms[3] where parms[0]=aBufGranularity; parms[1]=aNumWords; parms[2]=aOffset
+			TInt8 parms[3];
+			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),3*sizeof(TInt8));
+			if(r!=KErrNone)
+				break;	// Can't proceed if can't access request parameters
+			// Store parameters for checking in the callback
+			iRxRegGranularity = parms[0];
+			iRxRegOffset= parms[2];
+			iNumRegRxWords=parms[1];
+
+			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking RegisterRxBuffer\n"));
+			TPtr8 rxPtr(iRxBuf,KRxBufSizeInBytes);
+			r = RegisterRxBuffer((TInt)a1, rxPtr, parms[0], parms[1], parms[2]);
+			break;
+			}
+
+		case(RBusDevIicClient::ERegisterTxBuffer):
+			{
+			// a1 represents TInt aChannelId
+			// a2 represents (TAny*) of TInt8 parms[3] where parms[0]=aBufGranularity; parms[1]=aNumWords; parms[2]=aOffset
+			TInt8 parms[3];
+			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),3*sizeof(TInt8));
+			if(r!=KErrNone)
+				break;	// Can't proceed if can't access request parameters
+			// Store parameters for checking in the callback
+			iTxRegGranularity = parms[0];
+			iTxRegOffset= parms[2];
+			iNumRegTxWords=parms[1];
+
+			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking RegisterTxBuffer\n"));
+			TPtr8 txPtr(iTxBuf,KTxBufSizeInBytes);
+			r = RegisterTxBuffer((TInt)a1, txPtr, parms[0], parms[1], parms[2]);
+			break;
+			}
+
+		case(RBusDevIicClient::ESetNotifTrigger):
+			{
+			// a1 represents (TAny*) of TRequestStatus* aStatus
+			// a2 represents (TAny*) of TInt parms[2] where parms[0]=aChannelId; parms[1]=aTrigger
+			TInt parms[2];
+			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt));
+			if(r!=KErrNone)
+				break;	// Can't proceed if can't access request parameters
+			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking SetNotificationTrigger with aStatus=0x%x, aChannelId=0x%x, aTrigger=0x%x\n",a1,parms[0],parms[1]));
+			if(a1 == NULL)
+				{
+				r = KErrArgument;
+				break;
+				}
+			iStatus=(TRequestStatus*)a1;
+			// Set the flags for duplex processing
+			if((parms[1]&ERxAllBytes)&&(parms[1]&ETxAllBytes))
+				iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
+			r = SetNotificationTrigger(parms[0],parms[1]);
+			if(r == KErrTimedOut)
+				r=KErrNone;	// KErrTimedOut is returned if the Client has not interacted with IIC for a while
+			break;
+			}
+
+		case(RBusDevIicClient::ECtrlIoNotifNoTrigger):
+			{
+			// a1 represents (TAny*) of aChannelId
+			// a2 represents (TAny*) of aTrigger
+			TInt chanId = (TInt)a1;
+			TInt trigger = (TInt)a2;
+			// No TRequestStatus is accessed because the call to SetNotificationTrigger
+			// is either with zero (when it is valid to do so), or it is being called with a
+			// trigger value that is expected to be rejected.
+			r = SetNotificationTrigger(chanId,trigger);
+
+			if(r == KErrNone)
+				{
+				if((trigger&ERxAllBytes)&&(trigger&ETxAllBytes))
+					iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
+				}
+			if(r == KErrTimedOut)
+				r=KErrNone;	// KErrTimedOut is returned if the Client has not interacted with IIC for a while
+			break;
+			}
+
+		case(RBusDevIicClient::ECtrlIoRxWords):
+			{
+			// a1 represents TInt aBusId
+			// a2 represents (TAny*) of TInt parms[2] where parms[0]=aChannelId; parms[1]=aNumWords
+			TInt parms[2];
+			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt));
+			if(r!=KErrNone)
+				break;	// Can't proceed if can't access request parameters
+			// Prepare iRxBuf
+			memset(iRxBuf,0,KRxBufSizeInBytes);
+			// Store the number of words for checking in the callback
+			iRxReqNumWords=(TInt8)(parms[1]);
+
+			TInt tempTrigger=0;
+			// Set the expected result
+			tempTrigger |= ERxAllBytes;
+			if(parms[1] < iNumRegRxWords)
+				tempTrigger |= ERxUnderrun;
+			if(parms[1] > iNumRegRxWords)
+				tempTrigger |= ERxOverrun;
+			if(iExpectedTrigger != EGeneralBusError)
+				iExpectedTrigger |= tempTrigger;
+			else
+				iBlockedTrigger |= tempTrigger;
+			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoRxWords) with aBusId=0x%x, aChannelId=0x%x, aNumBytes=0x%x\n",(TInt)a1,parms[0],parms[1]));
+			r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)(parms[0]), (TAny*)(parms[1]));
+			if(r == KErrTimedOut)
+				r=KErrNone;	// KErrTimedOut is returned if the Client has not interacted with IIC for a while
+			break;
+			}
+
+		case(RBusDevIicClient::ECtrlIoTxWords):
+			{
+			// a1 represents TInt aBusId
+			// a2 represents (TAny*) of TInt parms[2] where parms[0]=aChannelId; parms[1]=aNumWords
+			TInt parms[2];
+			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt));
+			if(r!=KErrNone)
+				break;	// Can't proceed if can't access request parameters
+			// Prepare iTxBuf
+			TUint8* ptr=iTxBuf;
+			for(TInt offset=0; offset<KRxBufSizeInBytes; ++offset)
+				*ptr++=(TUint8)offset;
+			// Store the number of words for checking in the callback
+			iTxReqNumWords=(TInt8)(parms[1]);
+			TInt tempTrigger=0;
+			// Set the expected result
+			tempTrigger |= ETxAllBytes;
+			if(parms[1] < iNumRegTxWords)
+				tempTrigger |= ETxOverrun;
+			if(parms[1] > iNumRegTxWords)
+				tempTrigger |= ETxUnderrun;
+			if(iExpectedTrigger != EGeneralBusError)
+				iExpectedTrigger |= tempTrigger;
+			else
+				iBlockedTrigger |= tempTrigger;
+
+			// The bytes "transmitted" are stored in the simulated bus' iTxCheckBuf
+			// Since the simulated bus channel is also in the kernel process it shares the same address space
+			// Get the address of the buffer
+			// As part of the callback invoked by IIC, this client will check the data stored by the simulated
+			// bus. Since the simulated bus channel is also in the kernel process it shares the same address space,
+			// so the buffer can be accessed directly - but the buffer is not created until it receives the following
+			// StaticExtension command, so the bus identifier represented by a1 is stored to allow accessing the buffer
+			// adddress from the callback.
+			iBusId=(TUint)a1;
+			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoTxWords) with aBusId=0x%x, aChannelId=0x%x, aNumBytes=0x%x\n",(TInt)a1,parms[0],parms[1]));
+			aId<<=1;
+			r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)(parms[0]), (TAny*)(parms[1]));
+			break;
+			}
+
+		case(RBusDevIicClient::ECtrlIoRxTxWords):
+			{
+			// a1 represents TInt aBusId
+			// a2 represents (TAny*) of TInt parms[3] where parms[0]=aChannelId; parms[1]=aNumRxWords; parms[2]=aNumTxWords
+			TInt parms[3];
+			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),3*sizeof(TInt));
+			if(r!=KErrNone)
+				break;	// Can't proceed if can't access request parameters
+			// Prepare iRxBuf, iTxBuf
+			memset(iRxBuf,0,KRxBufSizeInBytes);
+			TUint8* ptr=iTxBuf;
+			for(TInt offset=0; offset<KRxBufSizeInBytes; ++offset)
+				*ptr++=(TUint8)offset;
+
+			// Store the number of words for checking in the callback
+			iRxReqNumWords=(TInt8)(parms[1]);
+			iTxReqNumWords=(TInt8)(parms[2]);
+
+			TInt tempTrigger=0;
+			// Set the expected result
+			tempTrigger |= (ERxAllBytes|ETxAllBytes);
+
+			if(parms[1] < iNumRegRxWords)
+				tempTrigger |= ERxUnderrun;
+			if(parms[1] > iNumRegRxWords)
+				tempTrigger |= ERxOverrun;
+
+			if(parms[2] < iNumRegTxWords)
+				tempTrigger |= ETxOverrun;
+			if(parms[2] > iNumRegTxWords)
+				tempTrigger |= ETxUnderrun;
+
+			if(iExpectedTrigger != EGeneralBusError)
+				iExpectedTrigger |= tempTrigger;
+			else
+				iBlockedTrigger |= tempTrigger;
+
+			// The bytes "transmitted" are stored in the simulated bus' iTxCheckBuf
+			// Since the simulated bus channel is also in the kernel process it shares the same address space
+			// Get the address of the buffer
+			// As part of the callback invoked by IIC, this client will check the data stored by the simulated
+			// bus. Since the simulated bus channel is also in the kernel process it shares the same address space,
+			// so the buffer can be accessed directly - but the buffer is not created until it receives the following
+			// StaticExtension command, so the bus identifier represented by a1 is stored to allow accessing the buffer
+			// adddress from the callback.
+			iBusId=(TUint)a1;
+
+			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]));
+			r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)(parms[0]), (TAny*)(&(parms[1])));
+			if(r == KErrTimedOut)
+				r=KErrNone;	// KErrTimedOut is returned if the Client has not interacted with IIC for a while
+			break;
+			}
+
+		case(RBusDevIicClient::ECtlIoBusError):
+			{
+			// a1 represents TInt aBusId
+			// a2 represents TInt aChannelId
+			// Set the expected result
+			iExpectedTrigger |= EGeneralBusError;
+			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtlIoBusError) \n"));
+			r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)a2, NULL);
+			break;
+			}
+
+		case(RBusDevIicClient::ECtrlIoUnblockNotification):
+			{
+			// a1 represents TInt aBusId
+			// a2 represents TInt aChannelId
+			iExpectedTrigger = iBlockedTrigger;
+			iBlockedTrigger=0;
+			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoUnblockNotification) \n"));
+			r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)a2, NULL);
+			break;
+			}
+
+		case(RBusDevIicClient::ECtrlIoBlockNotification):
+			{
+			// a1 represents TInt aBusId
+			// a2 represents TInt aChannelId
+			iBlockedTrigger = iExpectedTrigger;
+			iExpectedTrigger = EGeneralBusError;	// For this test, just interested in if the timeout is detected
+													// iExpectedTrigger will be reinstated prior to unblocking
+			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoBlockNotification) \n"));
+			r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)a2, NULL);
+			break;
+			}
+
+		case(RBusDevIicClient::ECtrlIoUpdTimeout):
+			{
+			// a1 represents TInt aBusId
+			// a2 represents TInt aChannelId
+
+			// For this test, instruct the simulated bus to do the following for the Master and Client timeout values:
+			// (1) Read the current timeout value and check that it is set to the default
+			// (2) Set it to different value
+			// (3) Read it back to check success
+			// (4) Return to the original value, and readback to confirm
+			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoBlockNotification) \n"));
+			r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, NULL, NULL);
+			break;
+			}
+
+		default:
+			{
+			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl - unrecognised value for aId=0x%x\n",aId));
+			r=KErrArgument;
+			break;
+			}
+
+		}
+	return r;
+	}
+
+TInt DChannelIicSlaveClient::DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2)
+	{
+	CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest invoked with aId=0x%x, aStatus=0x%x, a1=0x%x, a2=0x%x\n", aId,aStatus,a1,a2));
+
+	TInt r=KErrNone;
+	switch(aId)
+		{
+		case(RBusDevIicClient::ECaptureChanAsync):
+			{
+			// a1 is a pointer to the TDes8* aConfigHdr
+			// a2 is a pointer to TInt* parms[2], where:
+			// parms[0]=(TInt*)aBusId;
+			// parms[1]=&aChannelId;
+			//
+			TInt* parms[2];
+			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt*));
+			if(r!=KErrNone)
+				break;	// Can't proceed if can't access request parameters
+			//
+		  	TInt hdrSize = Kern::ThreadGetDesLength(iClient,a1);
+			CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest hdrSize = 0x%x\n",hdrSize));
+  			if (hdrSize<=0)
+				{
+				CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest ERROR, hdrSize is invalid\n"));
+ 				return KErrArgument;
+				}
+			if((iConfigHdr = HBuf8::New(hdrSize)) == NULL)
+				return KErrNoMemory;
+			if((r = Kern::ThreadDesRead(iClient,a1,*iConfigHdr,0))!=KErrNone)
+				{
+				delete iConfigHdr;
+				return r;
+				}
+			iStatus=aStatus;
+			// Store the address of the user-side variable to update with the ChannelId
+			iClientChanId=parms[1];
+			// Invoke the IIC API
+			CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest invoking (asynchronous) CaptureChannel\n"));
+			r = CaptureChannel((TInt)(parms[0]), iConfigHdr, iNotif, iChannelId, ETrue);
+			if(r != KErrNone)
+			    delete iConfigHdr;
+			CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest (asynchronous) CaptureChannel returned %d\n",r));
+			break;
+			}
+
+		case(RBusDevIicClient::ECtrlIoOvUndRunRxTx):
+			{
+			iBusId = (TInt)a1;
+			iChannelId = (TInt)a2;
+			iStatus=aStatus;
+			CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest status = 0x%x, busId = 0x%x, chanId =0x%x\n",iStatus,iBusId,iChannelId));
+
+			// This test is state-machine driven. It is instigated from this point, then subsequent steps
+			// are handled in the callback funciton SlaveClientCallbackFunc
+			//
+			// Check we in the appropriate state to start
+			if(iTestOverUnderState == EStartState)
+				{
+				// Re-use the previously-provided buffers. Just request the initial notification triggers,
+				// the simulate the first event (RxOverrun).
+				r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun));
+				if(r != KErrNone)
+					{
+					CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest SetNotificationTrigger returned %d\n",r));
+					}
+				else
+					{
+					// Trigger now set, so simulate the required event
+					iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun;
+					iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
+					iTestOverUnderState = ERxOverrun_1;	// Prepare for callback
+					// The requested number of words when the buffer was registered was 8, so simulate 10
+					// to provoke an RxOverrun event.
+					TInt numWords=10;
+					// To support testing, any values of aId for StaticExtension must be shifted left one place
+					// and for a Slave, the two msbs must be zero
+					TInt ctrlIoVal = RBusDevIicClient::ECtrlIoRxWords;
+					ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
+					r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords);
+					}
+				}
+			else
+				{
+				CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest ECtrlIoOvUndRunRxTx, iTestOverUnderState = 0x%x\n",iTestOverUnderState));
+				r=KErrGeneral;
+				}
+			break;
+			}
+
+		default:
+			{
+			CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest - unrecognised value for aId=0x%x\n",aId));
+			r=KErrArgument;
+			break;
+			}
+		}
+	return r;
+	}
+