kerneltest/e32test/iic/iic_psl/iic_client.cpp
changeset 0 a41df078684a
child 43 c1f20ce4abcf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/iic/iic_psl/iic_client.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,2662 @@
+// 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_client.cpp
+// Simulated (kernel-side) client of IIC Platform Independent Layer (PIL)
+//
+#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"
+#include "spi.h"
+#endif
+
+#ifdef LOG_CLIENT
+#define CLIENT_PRINT(str) Kern::Printf str
+#else
+#define CLIENT_PRINT(str)
+#endif
+
+const TInt KIicClientThreadPriority = 24;
+const TInt KIicSlaveClientDfcPriority = 3; // 0 to 7, 7 is highest ... for MasterSlave functionality
+
+const TInt KMaxNumChannels = 3;	// 1 SPI and 2 I2C
+
+// Define an array of channel that the client is going to create.
+// For iic_client, it needs SPI channels for Master tests, and I2c channels for MasterSlave tests.
+#ifdef STANDALONE_CHANNEL
+
+const TUint NUM_CHANNELS_SPI = 4; // Arbitrary
+const TInt KChannelTypeArraySpi[NUM_CHANNELS_SPI] = {DIicBusChannel::EMaster, DIicBusChannel::EMaster, DIicBusChannel::ESlave, DIicBusChannel::EMaster};
+#define CHANNEL_TYPE_SPI(n) (KChannelTypeArraySpi[n])
+const DIicBusChannel::TChannelDuplex KChannelDuplexArraySpi[NUM_CHANNELS_SPI] = {DIicBusChannel::EHalfDuplex, DIicBusChannel::EHalfDuplex, DIicBusChannel::EHalfDuplex, DIicBusChannel::EFullDuplex};
+#define CHANNEL_DUPLEX_SPI(n) (KChannelDuplexArraySpi[n])
+#define BUS_TYPE_SPI (DIicBusChannel::ESpi)
+
+#define NUM_CHANNELS_I2C 3
+#if defined(MASTER_MODE) && !defined(SLAVE_MODE)
+const TInt KChannelTypeArrayI2c[NUM_CHANNELS_I2C] = {DIicBusChannel::EMaster, DIicBusChannel::EMaster, DIicBusChannel::EMaster};
+#elif defined(MASTER_MODE) && defined(SLAVE_MODE)
+const TInt KChannelTypeArrayI2c[NUM_CHANNELS_I2C] = {DIicBusChannel::EMaster, DIicBusChannel::ESlave, DIicBusChannel::EMasterSlave};
+#else
+const TInt KChannelTypeArrayI2c[NUM_CHANNELS_I2C] = {DIicBusChannel::ESlave, DIicBusChannel::ESlave, DIicBusChannel::ESlave};
+#endif
+#define CHANNEL_TYPE_I2C(n) (KChannelTypeArrayI2c[n])
+#define CHANNEL_DUPLEX_I2C(n) (DIicBusChannel::EHalfDuplex)
+#define BUS_TYPE_I2C (DIicBusChannel::EI2c)
+
+const TInt8 KSpiChannelNumBase = 1;	// Arbitrary, real platform may consult the Configuration Repository
+									// Note limit of 5 bit representation (0-31)
+
+LOCAL_C TInt8 AssignChanNumSpi()
+	{
+	static TInt8 iBaseChanNumSpi = KSpiChannelNumBase;
+	CLIENT_PRINT(("SPI AssignChanNum - on entry, iBaseCanNum = 0x%x\n",iBaseChanNumSpi));
+	return iBaseChanNumSpi++; // Arbitrary, for illustration
+	}
+
+#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
+
+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 DIicClientChan : public DBase
+	{
+public:
+	DIicClientChan(DIicBusChannel* aChan, TInt8 aChanNum, TUint8 aChanType):iChan(aChan),iChanNumber(aChanNum),iChanType(aChanType){};
+	~DIicClientChan();
+	TInt GetChanNum()const {return iChanNumber;};
+	TUint8 GetChanType()const {return iChanType;};
+	DIicBusChannel* GetChannelPtr(){return iChan;};
+	inline DIicClientChan& operator=(DIicClientChan& aChan) {iChanNumber=aChan.iChanNumber; iChanType=aChan.iChanType; iChan=aChan.iChan; return *this;};
+	inline TInt operator==(DIicClientChan& aChan) {if((iChanNumber == aChan.iChanNumber)&&(iChanType == aChan.iChanType)&&(iChan == aChan.iChan)) return 1;return 0;};
+private:
+	TInt iChanNumber;
+	TUint8 iChanType;
+	DIicBusChannel* iChan;
+	};
+
+DIicClientChan::~DIicClientChan()
+	{
+	delete iChan;
+	}
+
+#endif /*STANDALONE_CHANNEL*/
+
+
+#ifdef STANDALONE_CHANNEL
+_LIT(KLddRootName,"iic_client_ctrless");
+#else
+_LIT(KLddRootName,"iic_client");
+#endif
+_LIT(KIicClientThreadName,"IicClientLddThread");
+
+struct TCapsIicClient
+    {
+    TVersion version;
+    };
+
+struct TTransStatusPair
+	{
+	TRequestStatus* iReq;
+	TIicBusTransaction* iTrans;
+	};
+
+struct TTransCbPair
+	{
+	TIicBusTransaction* iTrans;
+	TIicBusCallback* iCb;
+	};
+
+struct TExtractInfo
+    {
+    TExtractInfo(){iBufPtr = NULL; iTfer = NULL;}
+    ~TExtractInfo(){delete iBufPtr; delete iTfer;}
+    TDes8* iBufPtr;
+    TIicBusTransfer* iTfer;
+    TIicBusTransaction* iTrans;
+    };
+
+struct TTransBufReuseData
+	{
+	// Convenience for testing, only - retain pointers to private data
+	// so that it can be re-used from a callback.
+	TIicBusTransaction* iTransaction;
+	TIicBusTransfer* iHdTfer;
+	TIicBusTransfer* iFdTfer;
+	TDes8* iHdr;
+	// Pointer to callback object (for cleanup)
+	TIicBusCallback* iCallback;
+	};
+
+class DDeviceIicClient : public DLogicalDevice
+    {
+    public:
+    /**
+     * The constructor
+     */
+    DDeviceIicClient();
+    /**
+     * The destructor
+     */
+    ~DDeviceIicClient();
+    /**
+     * 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);
+
+	public:
+    };
+
+#ifdef STANDALONE_CHANNEL
+/*This class is used to test the set and get inline functions
+ *  of DIicBusChannel Interface.
+ * */
+class TTestIicChannelInterface: public DIicBusChannel
+{
+public:
+    TTestIicChannelInterface(TChannelType aChannelType, TBusType aBusType, TChannelDuplex aChanDuplex);
+    ~TTestIicChannelInterface(){};
+    TInt DoCreate(){return 0;};
+    TInt CheckHdr(TDes8* /*aHdr*/){return 0;};
+    TInt TestInterface();
+private:
+    TBool TestChannelType(DIicBusChannel::TChannelType aType );
+    TBool TestBusType(DIicBusChannel::TBusType aType );
+    TBool TestDuplexType(DIicBusChannel::TChannelDuplex aType );
+};
+
+TTestIicChannelInterface::TTestIicChannelInterface(TChannelType aChannelType, TBusType aBusType, TChannelDuplex aChanDuplex)
+        : DIicBusChannel(aChannelType, aBusType, aChanDuplex)
+    {}
+
+TBool TTestIicChannelInterface::TestChannelType(DIicBusChannel::TChannelType aType)
+    {
+    CLIENT_PRINT(("Setting channel type 0x%x\n", aType));
+    SetChannelType(aType);
+    if(aType != ChannelType())
+        {
+        CLIENT_PRINT(("ERROR: Mismatch, looking for channel 0x%x but found 0x%x\n", aType, ChannelType()));
+        return EFalse;
+        }
+    else
+        {
+        CLIENT_PRINT(("Looking for channel 0x%x and found 0x%x\n", aType, ChannelType()));
+        }
+    return ETrue;
+    }
+
+TBool TTestIicChannelInterface::TestBusType(DIicBusChannel::TBusType aType)
+    {
+    CLIENT_PRINT(("Setting Bus type 0x%x\n", aType));
+    SetBusType(aType);
+    if(aType != BusType())
+        {
+        CLIENT_PRINT(("ERROR: Mismatch, looking for Bus 0x%x but found 0x%x\n", aType, BusType()));
+        return EFalse;
+        }
+    else
+        {
+        CLIENT_PRINT(("Looking for Bus 0x%x and found 0x%x\n", aType, BusType()));
+        }    
+    return ETrue;   
+    }
+
+TBool TTestIicChannelInterface::TestDuplexType(DIicBusChannel::TChannelDuplex aType)
+    {
+    CLIENT_PRINT(("Setting duplex channel type 0x%x\n", aType));
+    SetChannelType(aType);
+    if(aType != ChannelDuplex())
+        {
+        CLIENT_PRINT(("ERROR: Mismatch, looking for duplex channel 0x%x but found 0x%x\n", aType, ChannelDuplex()));
+        return EFalse;
+        }
+    else
+        {
+        CLIENT_PRINT(("Looking for Duplex Channel 0x%x and found 0x%x\n", aType, ChannelDuplex()));
+        }    
+    return ETrue;   
+    }
+
+TInt TTestIicChannelInterface::TestInterface()
+    {
+    
+    RArray <DIicBusChannel::TChannelType> chtype;
+    RArray <DIicBusChannel::TBusType> bustype;
+    RArray <DIicBusChannel::TChannelDuplex> dutype;
+
+    chtype.Append(DIicBusChannel::EMaster);
+    chtype.Append(DIicBusChannel::ESlave);
+    chtype.Append(DIicBusChannel::EMasterSlave);
+    
+    bustype.Append(DIicBusChannel::EI2c);
+    bustype.Append(DIicBusChannel::ESpi);
+    bustype.Append(DIicBusChannel::EMicrowire);
+    bustype.Append(DIicBusChannel::ECci);
+    bustype.Append(DIicBusChannel::ESccb);
+    
+    dutype.Append(DIicBusChannel::EHalfDuplex);
+    dutype.Append(DIicBusChannel::EFullDuplex);
+      
+    int result = KErrNone;
+    int count = chtype.Count();
+    int i=0;
+    
+    CLIENT_PRINT(("\nCheck Master/Slave channel setting\n"));
+    CLIENT_PRINT(("\nChannel MASK  = 0x%x\n", KChannelTypeMask));    
+    for(i=0; i< count; ++i)
+        {
+        if(!TestChannelType(chtype[i]))
+            {
+            result = KErrGeneral;
+            break;
+            }
+        }
+    CLIENT_PRINT(("\nCheck Master/Slave channel setting from higher bit number to lower, reverse enum.\n"));
+    for(i=count-1; i >= 0; --i)
+        {
+        if(!TestChannelType(chtype[i]))
+            {
+            result = KErrGeneral;
+            break;
+            }
+        }
+    
+    CLIENT_PRINT(("\nCheck Channel Bus type settings\n"));
+    CLIENT_PRINT(("\nBus MASK  = 0x%x\n", KBusTypeMask));     
+    count = bustype.Count();    
+    for(i=0; i< count; ++i)
+        {
+        if(!TestBusType(bustype[i]))
+            {
+            result = KErrGeneral;
+            break;
+            }
+        }
+    CLIENT_PRINT(("\nCheck Channel Bus type settings from higher bit number to lower, reverse enum.\n"));   
+    for(i = count-1; i >= 0; --i)
+        {
+        if(!TestBusType(bustype[i]))
+            {
+            result = KErrGeneral;
+            break;
+            }
+        }
+    CLIENT_PRINT(("\nCheck Channel Duplex settings\n"));
+    CLIENT_PRINT(("\nDuplex MASK  = 0x%x\n", KChannelDuplexMask));     
+    count = dutype.Count();
+    for(i=0; i < count; ++i)
+        {
+        if(!TestDuplexType(dutype[i]))
+            {
+            result = KErrGeneral;
+            break;
+            }
+        }
+    CLIENT_PRINT(("\nCheck Channel Duplex setting from higher bit number to lower, reverse enum.\n"));        
+    for(i = count-1; i >= 0; --i)
+        {
+        if(!TestDuplexType(dutype[i]))
+            {
+            result = KErrGeneral;
+            break;
+            }
+        }
+    chtype.Close();
+    dutype.Close();
+    bustype.Close();
+    return result;
+    }
+#endif //STANDALONE_CHANNEL
+
+class DChannelIicClient : public DLogicalChannel
+    {
+    public:
+    DChannelIicClient();
+    ~DChannelIicClient();
+
+	TInt CleanupExtractTrans(TIicBusTransaction *aTrans);
+
+	TInt InitIicClient();
+
+    virtual TInt DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer);
+
+    protected:
+    virtual void HandleMsg(TMessageBase* aMsg);	// Note: this is a pure virtual in DLogicalChannel
+
+    void DoCancel(TInt aMask);	// Name for convenience!
+	TInt DoControl(TInt aId, TAny* a1, TAny* a2); // Name for convenience!
+    TInt DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2); // Name for convenience!
+
+	void TestTransModification(TIicBusTransaction* aTransaction, // public to be accessed by callback
+							  TIicBusTransfer* aHdTfer,
+							  TIicBusTransfer* aFdTfer,
+							  TDes8* aHdr);
+#ifdef STANDALONE_CHANNEL
+    public:
+    static TInt OrderEntries(const DIicClientChan& aMatch, const DIicClientChan& aEntry);
+#endif
+	private:
+	TInt ExtractTransData(TUsideTracnDesc* aUsideTrancnDesc, TIicBusTransaction*& aTrans);
+	TInt CreateTransferListHalfDuplex(
+				TIicBusTransfer::TReqType aNodeDir1, TInt aNodeLength1,
+				TIicBusTransfer::TReqType aNodeDir2, TInt aNodeLength2,
+				TIicBusTransfer::TReqType aNodeDir3, TInt aNodeLength3);
+	TInt CreateTransferListFullDuplex(
+				TIicBusTransfer::TReqType aNodeDir1, TInt aNodeLength1,
+				TIicBusTransfer::TReqType aNodeDir2, TInt aNodeLength2,
+				TIicBusTransfer::TReqType aNodeDir3, TInt aNodeLength3);
+
+
+	TInt DeleteFullDuplexTest(TIicBusTransaction *aTrans);
+
+	TInt DoCreateFullDuplexTransTest(TInt aTestType);
+
+	TInt DoPriorityTest(TInt aBusId);
+	TInt ConstructTransactionOne(TIicBusTransaction*& aTrans);
+	void CleanupTransactionOne(TIicBusTransaction*& aTrans);
+
+
+	TInt InsertPairs(TTransStatusPair* aPair, TTransCbPair* aCbPair);
+
+	TInt CreateDefaultSpiBuf(TConfigSpiBufV01*& aBuf);
+
+	//Add new functions for controller-less mode
+	TInt QueueTransaction(TInt aBusId, TIicBusTransaction* aTransaction, TIicBusCallback *aCallback=NULL);
+	TInt CancelTransaction(TInt aBusId, TIicBusTransaction* aTransaction);
+	TInt StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2);
+	TInt CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch=NULL);
+	TInt ReleaseChannel(TInt aChannelId);
+	public:
+	inline void Lock() {Kern::MutexWait(*iArrayMutex);}
+	inline void Unlock() {Kern::MutexSignal(*iArrayMutex);}
+	inline void GetWriteAccess() {Kern::SemaphoreWait(*iChanArrWrtSem);}	// aNTicks not specified = wait forever
+	inline void FreeWriteAccess() {Kern::SemaphoreSignal(*iChanArrWrtSem);}
+
+	void CleanupTransaction(TIicBusTransaction*& aTrans); // public for access by callback
+
+	static TIicBusTransaction* MultiTranscCallbackFunc(TIicBusTransaction* aTrans, TAny* aParam);
+
+	static void TransModifCallback(TIicBusTransaction* aTrans, TInt aBusId, TInt aResult, TAny* aParam);
+
+	private:
+	TDynamicDfcQue* iDfcQue;
+
+	DMutex* iArrayMutex;		// used to protect array of channels
+	DSemaphore* iChanArrWrtSem;	// used to synchronise write access to iChannelArray
+
+	// Used for Transaction One
+	HBuf8* buf1;
+	HBuf8* buf2;
+	HBuf8* buf3;
+	HBuf8* buf4;
+	HBuf8* buf5;
+	HBuf8* buf6;
+	TIicBusTransfer* tfer1;
+	TIicBusTransfer* tfer2;
+	TIicBusTransfer* tfer3;
+	TIicBusTransfer* tfer4;
+	TIicBusTransfer* tfer5;
+	TIicBusTransfer* tfer6;
+	TIicBusTransfer* tfer7;
+	HBuf8* header;
+	HBuf8* header2;
+	HBuf8* header3;
+	HBuf8* header4;
+	HBuf8* header5;
+	HBuf8* headerBlock;
+	TConfigSpiBufV01* spiHeader;
+
+
+	static TIicBusTransaction* iMultiTransac;
+
+	// Used for simple transactions
+	TIicBusTransaction* iTrans;
+	TConfigSpiBufV01* iSpiBuf;
+	TConfigI2cBufV01* iI2cBuf;
+	TIicBusTransfer* iTfer;
+	TIicBusTransactionPreamble* iTransPreamble;
+	TIicBusTransfer* iFdTfer;
+
+	public:
+	DThread* iClient;
+	RPointerArray<TTransStatusPair> iTransStatArrayByTrans;
+	RPointerArray<TTransStatusPair> iTransStatArrayByStatus;
+	RPointerArray<TTransCbPair> iTransCbArrayByTrans;
+	RPointerArray<TExtractInfo> iExtractInfoArray;
+
+	// Support for Preamble testing
+	TRequestStatus* iPreambleStatus;
+	TRequestStatus* iMultiTranscStatus;
+
+	// Support for buffer re-use testing
+	TTransBufReuseData iTransBufReuseData;
+
+	// Support for MasterSlave processing
+	private:
+	TInt InitSlaveClient();
+
+	private:
+	HBuf8* iConfigHdr;
+	TRequestStatus* iStatus;
+
+	public:
+	void RequestComplete(TInt r);
+
+	public:
+	TIicBusSlaveCallback* iNotif;		// public to be accessible by callback
+	TInt iChannelId;				// public to be accessible by callback
+	TInt* iClientChanId;
+
+#ifdef STANDALONE_CHANNEL
+	//Used to store the captured channel
+	struct TCapturedChannel
+        {
+        DIicClientChan* iChanPtr;
+        TInt iChannelId;
+        };
+	TCapturedChannel iCapturedChannel;
+#endif
+	};
+
+DDeviceIicClient::DDeviceIicClient()
+// Constructor
+    {
+	CLIENT_PRINT(("> DDeviceIicClient::DDeviceIicClient()"));
+    __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DDeviceIicClient::DDeviceIicClient()"));
+    iParseMask=0;		// No info, no PDD, no Units
+    iUnitsMask=0;
+    iVersion=TVersion(KIicClientMajorVersionNumber,
+		      KIicClientMinorVersionNumber,
+		      KIicClientBuildVersionNumber);
+    }
+#ifdef STANDALONE_CHANNEL
+//  auxiliary function for ordering entries in the array of channels
+TInt DChannelIicClient::OrderEntries(const DIicClientChan& aMatch, const DIicClientChan& 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<DIicClientChan> EntryOrder(DChannelIicClient::OrderEntries);
+
+// Store all the channels created by the client
+RPointerArray<DIicClientChan> ChannelArray;
+#endif /*STANDALONE_CHANNEL*/
+
+DDeviceIicClient::~DDeviceIicClient()
+    {
+	CLIENT_PRINT(("> DDeviceIicClient::~DDeviceIicClient()"));
+    __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DDeviceIicClient::~DDeviceIicClient()"));
+#ifdef STANDALONE_CHANNEL
+    //For Standalone Channel, the client is responsible for channel destroy
+    ChannelArray.ResetAndDestroy();
+#endif
+	}
+
+TInt DDeviceIicClient::Install()
+// Install the device driver.
+    {
+	CLIENT_PRINT(("> DDeviceIicClient::Install()"));
+    __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DDeviceIicClient::Install()"));
+    return(SetName(&KLddRootName));
+    }
+
+// Auxiliary functions for ordering entries in the array of TTransStatusPair pointers
+// The first is to enable searching by Transaction (used by the callback)
+// The second is to enable searching by the TRequestStatus (used by cancel calls)
+TInt OrderEntriesByTrans(const TTransStatusPair& aMatch, const TTransStatusPair& aEntry)
+	{
+	TUint l=(TUint)(aMatch.iTrans);
+	TUint r=(TUint)(aEntry.iTrans);
+	if(l>r)
+		return -1;
+	else if(l<r)
+		return 1;
+	else
+		return 0;
+	}
+TLinearOrder<TTransStatusPair> TransStatusOrderByTrans(OrderEntriesByTrans);
+
+TInt OrderEntriesByStatus(const TTransStatusPair& aMatch, const TTransStatusPair& aEntry)
+	{
+	TUint l=(TUint)(aMatch.iReq);
+	TUint r=(TUint)(aEntry.iReq);
+	if(l>r)
+		return -1;
+	else if(l<r)
+		return 1;
+	else
+		return 0;
+	}
+TLinearOrder<TTransStatusPair> TransStatusOrderByStatus(OrderEntriesByStatus);
+
+// Auxilliary function to track callback objects assigned to asynchronous transactions
+TInt OrderCbEntriesByTrans(const TTransCbPair& aMatch, const TTransCbPair& aEntry)
+	{
+	TUint l=(TUint)(aMatch.iTrans);
+	TUint r=(TUint)(aEntry.iTrans);
+	if(l>r)
+		return -1;
+	else if(l<r)
+		return 1;
+	else
+		return 0;
+	}
+TLinearOrder<TTransCbPair> TransCbOrderByTrans(OrderCbEntriesByTrans);
+
+TInt OrderExtractInfoByTrans(const TExtractInfo& aMatch, const TExtractInfo& aEntry)
+    {
+    TUint l=(TUint)(aMatch.iTrans);
+    TUint r=(TUint)(aEntry.iTrans);
+    if(l>r)
+        return -1;
+    else if(l<r)
+        return 1;
+    else
+        return 0;
+    }
+TLinearOrder<TExtractInfo> ExtractInfoOrderByTrans(OrderExtractInfoByTrans);
+
+
+_LIT(KLitArrayMutexName,"IIC_CLIENT_ARRAY_MUTEX");
+_LIT(KLitArraySemName,"IIC_CLIENT_ARRAY_SEM");
+#define IIC_CLIENT_MUTEX_ORDER KMutexOrdGeneral4	// Semi-arbitrary - middle of general purpose range, allow higher and lower priorities
+
+TInt DChannelIicClient::InitIicClient()
+	{
+	TInt r = Kern::MutexCreate(iArrayMutex,KLitArrayMutexName,IIC_CLIENT_MUTEX_ORDER);
+	if(r!=KErrNone)
+		return r;
+	r = Kern::SemaphoreCreate(iChanArrWrtSem,KLitArraySemName,1); // Initial count of one allows first wait to be non-blocking
+	if(r!=KErrNone)
+		iArrayMutex->Close(NULL);
+
+	return r;
+	}
+
+TInt DChannelIicClient::InsertPairs(TTransStatusPair* aPair, TTransCbPair* aCbPair)
+	{
+	CLIENT_PRINT(("DChannelIicClient::InsertPairs invoked with aPair=0x%x, aPair->iReq=0x%x, aPair-iTrans=0x%x\n",aPair,aPair->iReq,aPair->iTrans ));
+	CLIENT_PRINT(("DChannelIicClient::InsertPairs ... and aCbPair=0x%x, aCbPair->iCb=0x%x, aCbPair-iTrans=0x%x\n",aCbPair,aCbPair->iCb,aCbPair->iTrans ));
+	TInt r = KErrNone;
+
+	GetWriteAccess();
+	Lock();
+
+	if((r = iTransStatArrayByTrans.InsertInOrder(aPair,TransStatusOrderByTrans)) == KErrNone)
+		{
+		if((r = iTransStatArrayByStatus.InsertInOrder(aPair,TransStatusOrderByStatus)) == KErrNone)
+			{
+			if((r = iTransCbArrayByTrans.InsertInOrder(aCbPair,TransCbOrderByTrans))!=KErrNone)
+				{
+				CLIENT_PRINT(("DChannelIicClient::InsertPairs, aCbPair=0x%x InsertInOrder(status) returned %d\n",aCbPair,r));
+				}
+			}
+		else
+			{
+			CLIENT_PRINT(("DChannelIicClient::InsertPairs, aPair=0x%x InsertInOrder(status) returned %d\n",aPair,r));
+			}
+		}
+	else
+		{
+		CLIENT_PRINT(("DChannelIicClient::InsertPairs, aPair=0x%x InsertInOrder(trans) returned %d\n",aPair,r));
+		}
+	FreeWriteAccess();
+	Unlock();
+	return r;
+	}
+
+//dummy call back func is provided for asyn call in priority test
+static void DummyCallbackFunc(TIicBusTransaction* /*aTrans*/, TInt /*aBusId*/, TInt /*aResult*/, TAny* /*aParam*/)
+	{
+	//do nothing
+	}
+
+static void AsyncCallbackFunc(TIicBusTransaction* aTrans, TInt aBusId, TInt aResult, TAny* aParam)
+	{
+	(void)aBusId; // aBusId is not used if CLIENT_PRINT is disabled
+	CLIENT_PRINT(("> AsyncCallbackFunc() - aTrans=0x%x, aBusId=0x%x, aResult=%d, aParam=0x%x\n",aTrans,aBusId,aResult,aParam));
+	DChannelIicClient* channel = (DChannelIicClient*)aParam;
+	CLIENT_PRINT(("AsyncCallbackFunc() - channel=0x%x\n",channel));
+
+	// Use the channel to get the user-side client's TRequestStatus and complete it with aResult
+	TTransStatusPair* searchPair = new TTransStatusPair();
+	searchPair->iTrans = aTrans;
+	channel->GetWriteAccess();
+	channel->Lock();
+	TInt pairIndex = (channel->iTransStatArrayByTrans).FindInOrder(searchPair,TransStatusOrderByTrans);
+	delete searchPair;
+	if(pairIndex<0)
+		{
+		CLIENT_PRINT(("AsyncCallbackFunc() - (trans) FindInOrder returned %d (aTrans=0x%x)\n",pairIndex,aTrans));
+		return;
+		}
+	TTransStatusPair* pairPtr = (channel->iTransStatArrayByTrans)[pairIndex];
+	TRequestStatus* status = pairPtr->iReq;
+
+	// Now remove the TTransStatusPair objects in iTransStatArrayByTrans, iTransStatArrayByStatus
+	(channel->iTransStatArrayByTrans).Remove(pairIndex);
+	pairIndex = (channel->iTransStatArrayByStatus).FindInOrder(pairPtr,TransStatusOrderByStatus);
+	if(pairIndex<0)
+		{
+		CLIENT_PRINT(("AsyncCallbackFunc() - (status) FindInOrder returned %d (status=0x%x)\n",pairIndex,status));
+		return;
+		}
+	(channel->iTransStatArrayByStatus).Remove(pairIndex);
+
+	// Now remove the TTransCbPair object in iTransCbArrayByTrans
+	TTransCbPair* SearchCbPair = new TTransCbPair();
+	SearchCbPair->iTrans = aTrans;
+	pairIndex = (channel->iTransCbArrayByTrans).FindInOrder(SearchCbPair,TransCbOrderByTrans);
+	delete SearchCbPair;
+	if(pairIndex<0)
+		{
+		CLIENT_PRINT(("AsyncCallbackFunc() - (cb) FindInOrder returned %d (aTrans=0x%x)\n",pairIndex,aTrans));
+		return;
+		}
+	TTransCbPair* cbPair = (channel->iTransCbArrayByTrans)[pairIndex];
+	(channel->iTransCbArrayByTrans).Remove(pairIndex);
+	delete cbPair->iCb;
+	delete cbPair;
+	channel->FreeWriteAccess();
+	channel->Unlock();
+	Kern::RequestComplete(channel->iClient, status, aResult);
+	// We should call CleanupExtractTrans() to delete all the objects created in ExtractTransData()
+	channel->CleanupExtractTrans(pairPtr->iTrans);
+	// The object referred to be pairPtr is finished with and can be deleted
+	channel->CleanupTransaction(pairPtr->iTrans);
+	delete pairPtr;
+	}
+
+
+void DDeviceIicClient::GetCaps(TDes8& aDes) const
+// Return the IicClient capabilities.
+    {
+	CLIENT_PRINT(("> DDeviceIicClient::GetCaps(TDes8& aDes) const"));
+    TPckgBuf<TCapsIicClient> b;
+    b().version=TVersion(KIicClientMajorVersionNumber,
+			 KIicClientMinorVersionNumber,
+			 KIicClientBuildVersionNumber);
+    Kern::InfoCopy(aDes,b);
+    }
+
+
+TInt DDeviceIicClient::Create(DLogicalChannelBase*& aChannel)
+// Create a channel on the device.
+    {
+	CLIENT_PRINT(("> DDeviceIicClient::Create(DLogicalChannelBase*& aChannel)"));
+	if(iOpenChannels>=KMaxNumChannels)
+		return KErrOverflow;
+    aChannel=new DChannelIicClient;
+    return aChannel?KErrNone:KErrNoMemory;
+    }
+
+#ifdef STANDALONE_CHANNEL
+
+TInt GetChanPtr(const TInt aBusId, TInt &aIndex, DIicClientChan*& 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));
+	DIicClientChan chanEntry(NULL,(TInt8)chanId, DIicBusChannel::EMasterSlave);
+	TInt r = KErrNotFound;
+	aIndex = ChannelArray.FindInOrder(&chanEntry, EntryOrder);
+	if(aIndex >= 0)
+		{
+		aChan = ChannelArray[aIndex];
+		r = KErrNone;
+		}
+
+	__KTRACE_OPT(KIIC, 	Kern::Printf("GetChanPtr, chanPtr=0x%x, index=%d\n",aChan,aIndex));
+	return r;
+	}
+#endif
+
+DECLARE_STANDARD_LDD()
+	{
+	//If in STANDALONE_CHANNEL mode, the client creates a list of channels
+#ifdef STANDALONE_CHANNEL
+	DIicClientChan* aClientChan;
+	TInt r = KErrNone;
+	DIicBusChannel *chan = NULL, *chanM = NULL, *chanS = NULL;
+	TInt i;
+	for(i=0; i<NUM_CHANNELS_SPI; i++)
+		{
+		CLIENT_PRINT(("\n"));
+#if defined(MASTER_MODE)
+		if(CHANNEL_TYPE_SPI(i) == (DIicBusChannel::EMaster))
+			{
+			chan=new DSimulatedIicBusChannelMasterSpi(BUS_TYPE_SPI,CHANNEL_DUPLEX_SPI(i));
+			if(!chan)
+			    {
+			    CLIENT_PRINT(("\n\nSpi: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE_SPI(i),i));
+				return NULL;
+			    }
+			CLIENT_PRINT(("SPI chan created at 0x%x\n",chan));
+			if(((DSimulatedIicBusChannelMasterSpi*)chan)->Create()!=KErrNone)
+			    {
+			    delete chan;
+				return NULL;
+			    }
+			aClientChan = new DIicClientChan(chan,AssignChanNumSpi(),DIicBusChannel::EMaster);
+            if(!aClientChan)
+                {
+                delete chan;
+                return NULL;
+                }
+            r = ChannelArray.InsertInOrder(aClientChan,EntryOrder);
+            if(r!=KErrNone)
+                {
+                delete chan;
+                delete aClientChan;
+                break;
+                }
+			}
+#endif
+#if defined(MASTER_MODE) && defined(SLAVE_MODE)
+		if(CHANNEL_TYPE_SPI(i) == DIicBusChannel::EMasterSlave)
+			{
+			//For MasterSlave channel, the client creates a Master channel, a Slave
+			//channel and a MasterSlave Channel, then store all of them in ChannelArray.
+			chanM=new DSimulatedIicBusChannelMasterSpi(BUS_TYPE_SPI,CHANNEL_DUPLEX_SPI(i));
+			if(!chanM)
+				return NULL;
+
+			chanS=new DSimulatedIicBusChannelSlaveSpi(BUS_TYPE_SPI,CHANNEL_DUPLEX_SPI(i));
+			if(!chanS)
+			    {
+			    delete chanM;
+				return NULL;
+			    }
+			chan=new DIicBusChannelMasterSlave(BUS_TYPE_SPI,CHANNEL_DUPLEX_SPI(i),(DSimulatedIicBusChannelMasterSpi*)chanM,(DSimulatedIicBusChannelSlaveSpi*)chanS); // Generic implementation
+			if(!chan)
+			    {
+			    CLIENT_PRINT(("\n\nSpi: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE_SPI(i),i));
+			    delete chanM;
+			    delete chanS;
+				return NULL;
+			    }
+			CLIENT_PRINT(("SPI chan created at 0x%x\n",chan));
+			if(((DIicBusChannelMasterSlave*)chan)->DoCreate()!=KErrNone)
+			    {
+			    delete chanM;
+			    delete chanS;
+			    delete chan;
+				return NULL;
+			    }
+			aClientChan = new DIicClientChan(chan,AssignChanNumSpi(),DIicBusChannel::EMasterSlave);
+			if(!aClientChan)
+			    {
+			    delete chanM;
+			    delete chanS;
+			    delete chan;
+			    return NULL;
+			    }
+            r = ChannelArray.InsertInOrder(aClientChan,EntryOrder);
+            if(r!=KErrNone)
+                {
+                delete chanM;
+                delete chanS;
+                delete chan;
+                delete aClientChan;
+                break;
+                }
+			}
+#endif
+#if defined(SLAVE_MODE)
+		if(CHANNEL_TYPE_SPI(i) == (DIicBusChannel::ESlave))
+			{
+			chan=new DSimulatedIicBusChannelSlaveSpi(BUS_TYPE_SPI,CHANNEL_DUPLEX_SPI(i));
+			if(!chan)
+			    {
+			    CLIENT_PRINT(("\n\nSpi: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE_SPI(i),i));
+				return NULL;
+			    }
+			CLIENT_PRINT(("SPI chan created at 0x%x\n",chan));
+			if(((DSimulatedIicBusChannelSlaveSpi*)chan)->Create()!=KErrNone)
+			    {
+			    delete chan;
+				return NULL;
+			    }
+			aClientChan = new DIicClientChan(chan,AssignChanNumSpi(),DIicBusChannel::ESlave);
+            if(!aClientChan)
+                {
+                delete chan;
+                return NULL;
+                }
+            r = ChannelArray.InsertInOrder(aClientChan,EntryOrder);
+            if(r!=KErrNone)
+                {
+                delete chan;
+                delete aClientChan;
+                break;
+                }
+			}
+#endif
+#if !defined(MASTER_MODE) && !defined(SLAVE_MODE)
+#error I2C mode not defined as Master, Slave nor Master-Slave
+#endif
+		}
+
+	for(i=0; i<NUM_CHANNELS_I2C; i++)
+			{
+			CLIENT_PRINT(("\n"));
+	#if defined(MASTER_MODE)
+			if(CHANNEL_TYPE_I2C(i) == (DIicBusChannel::EMaster))
+				{
+				chan=new DSimulatedIicBusChannelMasterI2c(BUS_TYPE_I2C,CHANNEL_DUPLEX_I2C(i));
+				if(!chan)
+				    {
+				    CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE_I2C(i),i));
+					return NULL;
+				    }
+				CLIENT_PRINT(("I2C chan created at 0x%x\n",chan));
+				if(((DSimulatedIicBusChannelMasterI2c*)chan)->Create()!=KErrNone)
+				    {
+				    delete chan;
+					return NULL;
+					}
+				aClientChan = new DIicClientChan(chan,AssignChanNumI2c(),DIicBusChannel::EMaster);
+				if(!aClientChan)
+				    {
+				    delete chan;
+				    return NULL;
+				    }
+                r = ChannelArray.InsertInOrder(aClientChan,EntryOrder);
+                if(r!=KErrNone)
+                    {
+                    delete chan;
+                    delete aClientChan;
+                    break;
+                    }
+				}
+	#endif
+	#if defined(MASTER_MODE) && defined(SLAVE_MODE)
+			if(CHANNEL_TYPE_I2C(i) == DIicBusChannel::EMasterSlave)
+				{
+				chanM=new DSimulatedIicBusChannelMasterI2c(BUS_TYPE_I2C,CHANNEL_DUPLEX_I2C(i));
+				if(!chanM)
+					return NULL;
+
+				chanS=new DSimulatedIicBusChannelSlaveI2c(BUS_TYPE_I2C,CHANNEL_DUPLEX_I2C(i));
+				if(!chanS)
+				    {
+				    delete chanM;
+					return NULL;
+				    }
+				//The client doesn't create the Master and Slave channels, as they should be created
+				//in MasterSlave channel's DoCreate().
+				chan=new DSimulatedIicBusChannelMasterSlaveI2c(BUS_TYPE_I2C,CHANNEL_DUPLEX_I2C(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_I2C(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;
+				    }
+			    aClientChan = new DIicClientChan(chan,AssignChanNumI2c(),DIicBusChannel::EMasterSlave);
+                if(!aClientChan)
+                    {
+                    delete chanM;
+                    delete chanS;
+                    delete chan;
+                    return NULL;
+                    }
+                r = ChannelArray.InsertInOrder(aClientChan,EntryOrder);
+                if(r!=KErrNone)
+                    {
+                    delete chanM;
+                    delete chanS;
+                    delete chan;
+                    delete aClientChan;
+                    break;
+                    }
+				}
+	#endif
+	#if defined(SLAVE_MODE)
+			if(CHANNEL_TYPE_I2C(i) == (DIicBusChannel::ESlave))
+				{
+				chan=new DSimulatedIicBusChannelSlaveI2c(BUS_TYPE_I2C,CHANNEL_DUPLEX_I2C(i));
+				if(!chan)
+				    {
+				    CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE_I2C(i),i));
+					return NULL;
+				    }
+				CLIENT_PRINT(("I2C chan created at 0x%x\n",chan));
+				if(((DSimulatedIicBusChannelSlaveI2c*)chan)->Create()!=KErrNone)
+				    {
+				    delete chan;
+					return NULL;
+				    }
+			    aClientChan = new DIicClientChan(chan,AssignChanNumI2c(),DIicBusChannel::ESlave);
+                if(!aClientChan)
+                    {
+                    delete chan;
+                    return NULL;
+                    }
+                r = ChannelArray.InsertInOrder(aClientChan,EntryOrder);
+                if(r!=KErrNone)
+                    {
+                    delete chan;
+                    delete aClientChan;
+                    break;
+                    }
+				}
+	#endif
+	#if !defined(MASTER_MODE) && !defined(SLAVE_MODE)
+	#error I2C mode not defined as Master, Slave nor Master-Slave
+	#endif
+			}
+
+#endif
+	return new DDeviceIicClient;
+	}
+
+
+
+DChannelIicClient::DChannelIicClient()
+// Constructor
+    {
+	CLIENT_PRINT(("> DChannelIicClient::DChannelIicClient()"));
+    iClient=&Kern::CurrentThread();
+	// Increase the DThread's ref count so that it does not close without us
+	iClient->Open();
+    }
+
+DChannelIicClient::~DChannelIicClient()
+// Destructor
+    {
+	CLIENT_PRINT(("> DChannelIicClient::~DChannelIicClient()"));
+    __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DChannelIicClient::~DChannelIicClient()"));
+    delete iNotif;
+    iArrayMutex->Close(NULL);
+    iChanArrWrtSem->Close(NULL);
+	iDfcQue->Destroy();
+	// decrement the DThread's reference count
+	Kern::SafeClose((DObject*&)iClient, NULL);
+
+    iTransStatArrayByTrans.Reset();
+    iTransStatArrayByStatus.Reset();
+    iTransCbArrayByTrans.Reset();
+	iExtractInfoArray.Reset();
+	}
+
+
+TInt DChannelIicClient::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
+	{
+	CLIENT_PRINT(("> DChannelIicClient::DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion &aVer)"));
+	TInt r = Kern::DynamicDfcQCreate(iDfcQue,KIicClientThreadPriority,KIicClientThreadName);
+	if(r!=KErrNone)
+		return r;
+	SetDfcQ(iDfcQue);
+	iMsgQ.Receive();
+
+	r = InitIicClient();
+	return r;
+	}
+
+void DChannelIicClient::HandleMsg(TMessageBase* aMsg)
+	{
+	TThreadMessage& m=*(TThreadMessage*)aMsg;
+    TInt id=m.iValue;
+
+	CLIENT_PRINT((" >ldd: DChannelIicClient::HandleMsg(TMessageBase* aMsg) id=%d\n", id));
+
+	if (id == (TInt)ECloseMsg)
+		{
+	    iMsgQ.iMessage->Complete(KErrNone,EFalse);
+		return;
+		}
+    else if (id == KMaxTInt)
+		{
+		DoCancel(m.Int0());
+		m.Complete(KErrNone,ETrue);
+		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
+		{
+		TInt r=DoControl(id,m.Ptr0(),m.Ptr1());
+		m.Complete(r,ETrue);
+		}
+	}
+
+TInt DChannelIicClient::QueueTransaction(TInt aBusId, TIicBusTransaction* aTransaction, TIicBusCallback *aCallback/*NULL*/)
+	{
+	TInt r = KErrNone;
+#ifndef STANDALONE_CHANNEL
+	if(!aCallback)
+		r = IicBus::QueueTransaction(aBusId, aTransaction);
+	else
+		r = IicBus::QueueTransaction(aBusId, aTransaction, aCallback);
+#else
+	__KTRACE_OPT(KIIC, Kern::Printf("DChannelIicClient::QueueTransaction, aBusId=0x%x,aTransaction=0x%x\n", aBusId, aTransaction));
+	if(!aTransaction)
+		{
+		return KErrArgument;
+		}
+
+	// Get a pointer to the channel
+	TInt dumInt = 0;
+	DIicClientChan* chanPtr = NULL;
+	r = GetChanPtr(aBusId, dumInt, chanPtr);
+	if(r == KErrNone)
+		{
+		if(!chanPtr)
+			{
+			r = KErrArgument;
+			}
+		else
+			{
+			switch(chanPtr->GetChanType())
+				{
+				// QueueTransaction requests are only supported by channels in Master mode.
+				case DIicBusChannel::ESlave:
+					{
+					r = KErrNotSupported;
+					break;
+					}
+				// If the request is supported by the Master channel, send it to the channel for processing in its thread
+				case DIicBusChannel::EMasterSlave:
+					{
+
+					aTransaction->iBusId = aBusId;
+					if(!aCallback)
+					    r = (((DIicBusChannelMasterSlave*) (chanPtr->GetChannelPtr()))->QueueTransaction(aTransaction));					    
+					else
+						r = (((DIicBusChannelMasterSlave*) (chanPtr->GetChannelPtr()))->QueueTransaction(aTransaction, aCallback));
+					break;
+					}
+				case DIicBusChannel::EMaster:
+					{
+					aTransaction->iBusId = aBusId;
+					if(!aCallback)
+						r = (((DIicBusChannelMaster*) (chanPtr->GetChannelPtr()))->QueueTransaction(aTransaction));
+					else
+						r = (((DIicBusChannelMaster*) (chanPtr->GetChannelPtr()))->QueueTransaction(aTransaction, aCallback));
+					break;
+					}
+				default:
+					{
+					r = KErrGeneral;
+					}
+				}
+			}
+		}
+#endif
+	return r;
+	}
+
+TInt DChannelIicClient::CancelTransaction(TInt aBusId, TIicBusTransaction* aTransaction)
+	{
+	TInt r = KErrNone;
+#ifndef STANDALONE_CHANNEL
+	r = IicBus::CancelTransaction(aBusId, aTransaction);
+#else
+    __KTRACE_OPT(KIIC, Kern::Printf("DChannelIicClient::CancelTransaction, aBusId=0x%x,aTransaction=0x%x\n", aBusId, aTransaction));
+	if(!aTransaction)
+		{
+		return KErrArgument;
+		}
+
+	// Get the channel
+	TInt dumInt = 0;
+	DIicClientChan* chanPtr = NULL;
+	if(r == KErrNone)
+		{
+		r = GetChanPtr(aBusId, dumInt, chanPtr);
+		if(r == KErrNone)
+			{
+			if(!chanPtr)
+				{
+				r = KErrArgument;
+				}
+			else
+				{
+				// QueueTransaction requests are only supported by channels in Master mode.
+				switch(chanPtr->GetChanType())
+					{
+					case DIicBusChannel::ESlave:
+						{
+						r = KErrNotSupported;
+						break;
+						}
+					case DIicBusChannel::EMasterSlave:
+						{
+						r = (((DIicBusChannelMasterSlave*) (chanPtr->GetChannelPtr()))->CancelTransaction(aTransaction));
+						break;
+						}
+					case DIicBusChannel::EMaster:
+						{
+						r = (((DIicBusChannelMaster*) (chanPtr->GetChannelPtr()))->CancelTransaction(aTransaction));
+						break;
+						}
+					default:
+						{
+						r = KErrGeneral;
+						}
+					}
+				}
+			}
+		}
+#endif
+	return r;
+	}
+
+
+TInt DChannelIicClient::StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2)
+	{
+	TInt r = KErrNone;
+#ifndef STANDALONE_CHANNEL
+	r = IicBus::StaticExtension(aId, aFunction, aParam1, aParam2);
+#else
+	// Get the channel
+	TInt dumInt = 0;
+	DIicClientChan* chanPtr = NULL;
+	if(r == KErrNone)
+		{
+		r = GetChanPtr(aId, dumInt, chanPtr);
+		if(r == KErrNone)
+			{
+			if(!chanPtr)
+				{
+				r = KErrArgument;
+				}
+			else
+				{
+				r = (chanPtr->GetChannelPtr())->StaticExtension(aFunction, aParam1, aParam2);
+				}
+			}
+		}
+#endif
+	return r;
+	}
+
+TInt DChannelIicClient::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
+	TInt chanIndex = 0;
+	DIicClientChan* chanPtr = NULL;
+	if(r == KErrNone)
+		{
+		r = GetChanPtr(aBusId, chanIndex, 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)
+						{
+						 iCapturedChannel.iChanPtr = chanPtr;
+						 iCapturedChannel.iChannelId = iChannelId;
+						}
+					else
+						//For asynchronous capture, record chanPtr, if later failed capture,
+						//clean iCapturedChannel in client's callback.
+						iCapturedChannel.iChanPtr = chanPtr;
+					}
+				}
+			}
+		}
+#endif
+	return r;
+	}
+
+TInt DChannelIicClient::ReleaseChannel(TInt aChannelId)
+	{
+	TInt r = KErrNone;
+#ifndef STANDALONE_CHANNEL
+	r = IicBus::ReleaseChannel(aChannelId);
+#else
+    __KTRACE_OPT(KIIC, Kern::Printf("DChannelIicClient::ReleaseChannel, channelID = 0x%x \n",aChannelId));
+    if(iCapturedChannel.iChannelId != aChannelId)
+            return KErrNotFound;
+
+    if((iCapturedChannel.iChanPtr)->GetChanType() == DIicBusChannel::EMasterSlave)
+        r = ((DIicBusChannelMasterSlave*)((iCapturedChannel.iChanPtr)->GetChannelPtr()))->ReleaseChannel();
+    else if((iCapturedChannel.iChanPtr)->GetChanType() == DIicBusChannel::ESlave)
+        r = ((DIicBusChannelSlave*)((iCapturedChannel.iChanPtr)->GetChannelPtr()))->ReleaseChannel();
+    //After release channel, reset iCapturedChan
+    iCapturedChannel.iChanPtr = NULL;
+    iCapturedChannel.iChannelId = 0;
+#endif
+    return r;
+	}
+
+void DChannelIicClient::DoCancel(TInt aMask)
+	{
+// Cancel an outstanding request.
+	CLIENT_PRINT(("DChannelIicClient::DoCancel invoked with aMask=0x%x\n", aMask));
+
+	// inline void CancelAsyncOperation(TRequestStatus* aStatus, TInt aBusId)	{TInt* parms[2]; parms[0]=(TInt*)aStatus; parms[1]=(TInt*)aBusId;DoCancel((TInt)&parms[0]);}
+	// aMask has the address on TInt* parms[2]
+	// parms[0] = TRequestStatus pointer
+	// parms[1] = Bus Identifier
+	TInt* parms[2];
+	TInt r=Kern::ThreadRawRead(iClient,(TAny*)aMask,&(parms[0]),2*sizeof(TInt*));
+	if(r!=KErrNone)
+		{
+		CLIENT_PRINT(("DChannelIicClient::DoCancel ERROR - Can't read parms[]\n"));
+		return;	// Can't proceed if can't access request parameters
+		}
+	CLIENT_PRINT(("DChannelIicClient::DoCancel - TRequestStatus 0x%x, BusID = 0x%x\n",parms[0],parms[1]));
+
+	TTransStatusPair* searchPair = new TTransStatusPair();
+	TTransCbPair* cbPair = new TTransCbPair();
+	searchPair->iReq = (TRequestStatus*)(parms[0]);
+
+	GetWriteAccess();
+	Lock();
+
+	TInt pairIndexByStatus = iTransStatArrayByStatus.FindInOrder(searchPair,TransStatusOrderByStatus);
+	CLIENT_PRINT(("DChannelIicClient::DoCancel - pairIndexByStatus=0x%x\n",pairIndexByStatus));
+	TInt pairIndexByTrans = KErrNotFound;
+
+	if(pairIndexByStatus<0)
+		{
+		// If the TRequestStatus object is not found then either the value was invalid or
+		// the object may already have been completed.
+		FreeWriteAccess();
+		Unlock();
+		CLIENT_PRINT(("DChannelIicClient::DoCancel() - (status) FindInOrder returned %d (status=0x%x)\n",pairIndexByStatus,parms[0]));
+		}
+	else
+		{
+		// The status-transaction pair exists in the status-index array - so remove it
+		TTransStatusPair* pairPtrStatus = iTransStatArrayByStatus[pairIndexByStatus];
+		iTransStatArrayByStatus.Remove(pairIndexByStatus);
+
+		pairIndexByTrans = iTransStatArrayByTrans.FindInOrder(pairPtrStatus,TransStatusOrderByTrans);
+		CLIENT_PRINT(("DChannelIicClient::DoCancel - pairIndexByTrans=0x%x\n",pairIndexByTrans));
+		if(pairIndexByTrans>=0)
+			{
+			iTransStatArrayByTrans.Remove(pairIndexByTrans);
+			}
+		FreeWriteAccess();
+		Unlock();
+
+		CLIENT_PRINT(("DChannelIicClient::DoCancel pairPtrStatus=0x%x\n", pairPtrStatus));
+
+		// Allow the bus to perform any required processing
+		TIicBusTransaction* trans = pairPtrStatus->iTrans;
+		CLIENT_PRINT(("DChannelIicClient::CancelTransaction - invoking with busId=0x%x, trans=0x%x\n",(TInt)(parms[1]),trans));
+		r = CancelTransaction((TInt)(parms[1]), trans);
+		cbPair->iTrans=trans;
+		TInt cbIndex = iTransCbArrayByTrans.FindInOrder(cbPair,TransCbOrderByTrans);
+		TTransCbPair* theCbPair = iTransCbArrayByTrans[cbIndex];
+		TIicBusCallback* cb= (iTransCbArrayByTrans[cbIndex])->iCb;
+		iTransCbArrayByTrans.Remove(cbIndex);
+		
+		// Complete the TRequestStatus object according to the returned value
+		TRequestStatus* status= (TRequestStatus*)(parms[0]);
+		Kern::RequestComplete(iClient, status, r);
+
+		// Clean up
+		delete cb;
+		delete theCbPair;
+		// We should call CleanupExtractTrans() to delete all the objects we created in ExtractTransData()
+		CleanupExtractTrans(trans);
+        CleanupTransaction(trans);  
+		delete pairPtrStatus;
+		}
+
+	delete cbPair;
+	delete searchPair;
+
+	return;
+	}
+
+
+// Function to support preamble testing
+void PreambleCallbackFunc(TIicBusTransaction* /*aTrans*/, TAny* aParam)
+	{
+	CLIENT_PRINT(("IIC Client: PreambleCallbackFunc invoked\n"));
+	// aParam is the address of the client that created the transaction object
+	__ASSERT_ALWAYS(aParam!=NULL,Kern::Fault("PreambleCallbackFunc, client address ==NULL",__LINE__));
+	DChannelIicClient *client = (DChannelIicClient*)aParam;
+	__ASSERT_ALWAYS(client->iClient!=NULL,Kern::Fault("PreambleCallbackFunc, iClient==NULL",__LINE__));
+	__ASSERT_ALWAYS(client->iPreambleStatus!=NULL,Kern::Fault("PreambleCallbackFunc, iPreambleStatus==NULL",__LINE__));
+	Kern::RequestComplete(client->iClient, client->iPreambleStatus, KErrNone);
+	}
+
+TIicBusTransaction* DChannelIicClient::iMultiTransac;
+
+// Function to support multi transc testing
+TIicBusTransaction* DChannelIicClient::MultiTranscCallbackFunc(TIicBusTransaction* /*aTrans*/, TAny* aParam)
+	{
+	CLIENT_PRINT(("IIC Client: MultiTranscCallbackFunc invoked\n"));
+	// aParam is the address of the client that created the transaction object
+	__ASSERT_ALWAYS(aParam!=NULL,Kern::Fault("MultiTranscCallbackFunc, client address ==NULL",__LINE__));
+	DChannelIicClient *client = (DChannelIicClient*)aParam;
+	__ASSERT_ALWAYS(client->iClient!=NULL,Kern::Fault("MultiTranscCallbackFunc, iClient==NULL",__LINE__));
+	__ASSERT_ALWAYS(client->iMultiTranscStatus!=NULL,Kern::Fault("MultiTranscCallbackFunc, iMultiTranscStatus==NULL",__LINE__));
+	Kern::RequestComplete(client->iClient, client->iMultiTranscStatus, KErrNone);
+	return iMultiTransac;
+	}
+
+TInt DChannelIicClient::CleanupExtractTrans(TIicBusTransaction* aTrans)
+	{
+	// Clean up the data created in ExtractTransData()
+	TExtractInfo *extractInfo = new TExtractInfo();
+	extractInfo->iTrans = aTrans;
+	TInt index = iExtractInfoArray.FindInOrder(extractInfo, ExtractInfoOrderByTrans);
+	if(index >= 0)
+	    {
+	    delete iExtractInfoArray[index];
+	    iExtractInfoArray.Remove(index);
+	    }
+	delete extractInfo;
+	return KErrNone;
+	}
+
+TInt DChannelIicClient::ExtractTransData(TUsideTracnDesc* aUsideTrancnDesc, TIicBusTransaction*& aTrans)
+	{
+// Utility function to create a TIicBusTransaction object from the parameters passed by the user-side TUsideTracnDesc object
+
+	TInt r = KErrNone;
+	TUsideTracnDesc usTrans;
+	r=Kern::ThreadRawRead(iClient,aUsideTrancnDesc,&usTrans,sizeof(TUsideTracnDesc));
+	if(r!=KErrNone)
+		{
+		CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't read usTrans\n"));
+		return KErrGeneral;	// Can't proceed if can't access request parameters
+		}
+	// Ensure pointers potentially used for allocation are NULL, to facilitate cleanup
+	iSpiBuf=NULL;
+	iI2cBuf=NULL;
+	iTfer=NULL;
+	iTransPreamble=NULL;
+	iFdTfer=NULL;
+
+	// Get the header (depends on the bus type)
+	TBusType busType = usTrans.iType;
+	TConfigSpiBufV01 *spiBuf = NULL;
+	TConfigI2cBufV01 *i2cBuf = NULL;
+	// extractInfo is used to keep the bufPtr and tfer of the transaction,
+	// and will later be stored in iExtractInfoArray, sorting by transaction.
+	// The extractInfo object will be freed in CleanupExtractTrans.
+	TExtractInfo *extractInfo = new TExtractInfo();
+	TDes8* bufPtr=NULL;
+	if(busType == ESpi)
+		{
+		if((spiBuf = new TConfigSpiBufV01()) == NULL)
+			{
+			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - unable to allocate spiBuf\n"));
+			return KErrNoMemory;
+			}
+		if((r=Kern::ThreadDesRead(iClient, usTrans.iHeader, *spiBuf, 0, KChunkShiftBy0 ))!=KErrNone)
+			{
+			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't read usTrans.iHeader to spiBuf\n"));
+			return KErrGeneral;
+			}
+		bufPtr=(TDes8*)spiBuf;
+		}
+	else if(busType == EI2c)
+		{
+		if((i2cBuf = new TConfigI2cBufV01()) == NULL)
+			{
+			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - unable to allocate i2cBuf\n"));
+			return KErrNoMemory;
+			}
+		if((r=Kern::ThreadDesRead(iClient, usTrans.iHeader, *i2cBuf, 0, KChunkShiftBy0 ))!=KErrNone)
+			{
+			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't read usTrans.iHeader to i2cBuf\n"));
+			return KErrGeneral;
+			}
+		bufPtr=(TDes8*)i2cBuf;
+		}
+	else
+		{
+		CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - unrecognised bus type\n"));
+		return KErrGeneral;
+		}
+	extractInfo->iBufPtr = bufPtr;
+	// Get the half-duplex transfer information
+	TUsideTferDesc* usTferPtr = usTrans.iHalfDuplexTrans;
+	TUsideTferDesc usTfer;
+	r=Kern::ThreadRawRead(iClient,usTferPtr,&usTfer,sizeof(TUsideTferDesc));
+	if(r!=KErrNone)
+		{
+		CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't read half-duplex usTfer\n"));
+		return KErrGeneral;	// Can't proceed if can't access request parameters
+		}
+	// Need to access the descriptor holding the information to be transferred
+	TBuf8 <MAX_TRANS_LENGTH> tferData;
+	r=Kern::ThreadDesRead(iClient,usTfer.iBuffer,tferData,0,KChunkShiftBy0);
+	if(r!=KErrNone)
+		{
+		CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't read half-duplex tferData\n"));
+		return KErrGeneral;	// Can't proceed if can't access request parameters
+		}
+
+	TIicBusTransfer::TReqType type=(usTfer.iType == EMasterWrite)?TIicBusTransfer::EMasterWrite:TIicBusTransfer::EMasterRead;
+	tfer7 = new TIicBusTransfer(type, usTfer.iBufGranularity, &tferData);
+	extractInfo->iTfer = tfer7;
+	// Construct the appropriate transaction object with the half-duplex information
+	TUint8 transFlags = usTrans.iFlags;
+
+	if((transFlags&KTransactionWithPreamble)&&(transFlags&KTransactionWithMultiTransc))
+		{
+		if(usTrans.iPreambleArg == NULL)
+			{
+			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - ExtTrans TRequestStatus==NULL\n"));
+			return KErrArgument;
+			}
+		if(usTrans.iMultiTranscArg == NULL)
+			{
+			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - ExtTrans TRequestStatus==NULL\n"));
+			return KErrArgument;
+			}
+		iPreambleStatus = (TRequestStatus*)(usTrans.iPreambleArg);
+		iMultiTranscStatus = (TRequestStatus*)(usTrans.iMultiTranscArg);
+		TIicBusTransactionPreambleExt* transExt;
+
+		transExt = new TIicBusTransactionPreambleExt(bufPtr, tfer7, (TIicBusPreamble)(&PreambleCallbackFunc), this,
+							(TIicBusMultiTranscCbFn)(&MultiTranscCallbackFunc), this);
+		if(transExt == NULL)
+			{
+			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't create trans\n"));
+			return KErrNoMemory;	// Can't proceed if can't access request parameters
+			}
+		aTrans = transExt;
+
+		}
+	else if(transFlags & KTransactionWithPreamble)
+		{
+		// Preamble required - construct the derived-class transaction object
+		if(usTrans.iPreambleArg == NULL)
+			{
+			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - preamble TRequestStatus==NULL\n"));
+			return KErrArgument;
+			}
+		iPreambleStatus = (TRequestStatus*)(usTrans.iPreambleArg);
+		TIicBusTransactionPreamble* TransPreamble;
+		TransPreamble = new TIicBusTransactionPreamble(bufPtr, tfer7, (TIicBusPreamble)(&PreambleCallbackFunc), this);
+		if(TransPreamble == NULL)
+			{
+			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't create trans\n"));
+			return KErrNoMemory;	// Can't proceed if can't access request parameters
+			}
+		aTrans = TransPreamble;
+		}
+	else if(transFlags & KTransactionWithMultiTransc)
+		{
+		// Preamble required - construct the derived-class transaction object
+		if(usTrans.iMultiTranscArg == NULL)
+			{
+			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Multi Transc TRequestStatus==NULL\n"));
+			return KErrArgument;
+			}
+		iMultiTranscStatus = (TRequestStatus*)(usTrans.iMultiTranscArg);
+		TIicBusTransactionMultiTransc* transMultiTransc;
+		transMultiTransc = new TIicBusTransactionMultiTransc(bufPtr, tfer7, (TIicBusMultiTranscCbFn)(&MultiTranscCallbackFunc), this);
+		if(transMultiTransc == NULL)
+			{
+			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't create trans\n"));
+			return KErrNoMemory;	// Can't proceed if can't access request parameters
+			}
+		aTrans = transMultiTransc;
+		}
+	else
+		{
+		// Preamble not required
+		aTrans = new TIicBusTransaction(bufPtr, tfer7);
+		if(aTrans == NULL)
+			{
+			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't create trans\n"));
+			return KErrNoMemory;	// Can't proceed if can't access request parameters
+			}
+		}
+
+	// If full duplex transaction is required get that information, too
+	usTferPtr = usTrans.iFullDuplexTrans;
+	if(usTferPtr!=NULL)
+		{
+		r=Kern::ThreadRawRead(iClient,usTferPtr,&usTfer,sizeof(TUsideTferDesc));
+		if(r!=KErrNone)
+			{
+			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't read full-duplex usTfer\n"));
+			return KErrGeneral;	// Can't proceed if can't access request parameters
+			}
+		// Need to access the descriptor holding the information to be transferred
+		TBuf8 <MAX_TRANS_LENGTH> fdTferData;
+		r=Kern::ThreadDesRead(iClient,usTfer.iBuffer,fdTferData,0,KChunkShiftBy0);
+		if(r!=KErrNone)
+			{
+			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't read full-duplex tferData\n"));
+			return KErrGeneral;	// Can't proceed if can't access request parameters
+			}
+
+		type=(usTfer.iType == EMasterWrite)?TIicBusTransfer::EMasterWrite:TIicBusTransfer::EMasterRead;
+		r=aTrans->SetFullDuplexTrans(iFdTfer);
+		if(r!=KErrNone)
+			{
+			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - SetFullDuplexTrans returned %d\n",r));
+			return r;
+			}
+		}
+	extractInfo->iTrans = aTrans;
+	iExtractInfoArray.InsertInOrder(extractInfo, ExtractInfoOrderByTrans);
+	return r;
+	}
+
+#define KMaxTferTextLength 20
+#define KLongNodeTestLength 15
+#define KShortNodeTestLength 5
+_LIT(KFullTracnHdrText,"Full duplex test");		// length = 22
+#define KFullTracnHdrTextLength 16
+
+
+// Create transfer list with three nodes
+// All memories are allocated from the kernel heap and referenced by class members
+// DeleteFullDuplexTest should be called to release memory after use.
+// List created here will be assigned to iHalfDuplexTrans in TIicBusTransaction
+// If aNodeLength3 = 0, only return a 2 nodes transfer
+TInt DChannelIicClient::CreateTransferListHalfDuplex(
+			TIicBusTransfer::TReqType aNodeDir1, TInt aNodeLength1,
+			TIicBusTransfer::TReqType aNodeDir2, TInt aNodeLength2,
+			TIicBusTransfer::TReqType aNodeDir3, TInt aNodeLength3)
+	{
+	buf1 = HBuf8::New(KMaxTferTextLength);
+	buf2 = HBuf8::New(KMaxTferTextLength);
+	buf3 = HBuf8::New(KMaxTferTextLength);
+	tfer1 = new TIicBusTransfer(aNodeDir1,8,buf1);
+	tfer2 = new TIicBusTransfer(aNodeDir2,8,buf2);
+	tfer3 = new TIicBusTransfer(aNodeDir3,8,buf3);
+
+	if(buf1 == NULL||buf2 == NULL||buf3 == NULL||
+		tfer1 == NULL||tfer2 == NULL||tfer3 == NULL)
+		{
+		delete buf1; delete buf2; delete buf3;
+		delete tfer1; delete tfer2;	delete tfer3;
+		return KErrNoMemory;
+		}
+
+	TInt i;
+	for(i=0; (i<KMaxTferTextLength)&&(i<aNodeLength1); i++) buf1->Append('*');
+	for(i=0; (i<KMaxTferTextLength)&&(i<aNodeLength2); i++) buf2->Append('*');
+	for(i=0; (i<KMaxTferTextLength)&&(i<aNodeLength3); i++) buf3->Append('*');
+
+	tfer1->LinkAfter(tfer2);
+
+	//allow two nodes
+	if(aNodeLength3>0)
+		{
+		tfer2->LinkAfter(tfer3);
+		}
+
+	return KErrNone;
+
+	}
+
+// Create transfer list with three nodes
+// All memories are allocated from the kernel heap and referenced by class members
+// DeleteFullDuplexTest should be called to release memory after use.
+// List created here will be assigned to iFullDuplexTrans in TIicBusTransaction
+// If aNodeLength3 = 0, only return a 2 nodes transfer
+TInt DChannelIicClient::CreateTransferListFullDuplex(
+			TIicBusTransfer::TReqType aNodeDir1, TInt aNodeLength1,
+			TIicBusTransfer::TReqType aNodeDir2, TInt aNodeLength2,
+			TIicBusTransfer::TReqType aNodeDir3, TInt aNodeLength3)
+	{
+	buf4 = HBuf8::New(KMaxTferTextLength);
+	buf5 = HBuf8::New(KMaxTferTextLength);
+	buf6 = HBuf8::New(KMaxTferTextLength);
+	tfer4 = new TIicBusTransfer(aNodeDir1,8,buf4);
+	tfer5 = new TIicBusTransfer(aNodeDir2,8,buf5);
+	tfer6 = new TIicBusTransfer(aNodeDir3,8,buf6);
+
+	if(buf4 == NULL||buf5 == NULL||buf6 == NULL||
+		tfer4 == NULL||tfer5 == NULL||tfer6 == NULL)
+		{
+		delete buf4; delete buf5; delete buf6;
+		delete tfer4; delete tfer5;	delete tfer6;
+		return KErrNoMemory;
+		}
+
+	TInt i;
+	for(i=0; (i<KMaxTferTextLength)&&(i<aNodeLength1); i++) buf4->Append('*');
+	for(i=0; (i<KMaxTferTextLength)&&(i<aNodeLength2); i++) buf5->Append('*');
+	for(i=0; (i<KMaxTferTextLength)&&(i<aNodeLength3); i++) buf6->Append('*');
+
+	tfer4->LinkAfter(tfer5);
+
+	//allow two nodes
+	if(aNodeLength3>0)
+		{
+		tfer5->LinkAfter(tfer6);
+		}
+
+	return KErrNone;
+
+	}
+
+// Delete transaction and all allocated transfers and buffers
+TInt DChannelIicClient::DeleteFullDuplexTest(TIicBusTransaction *aTrans)
+	{
+	delete buf1; delete buf2; delete buf3;
+	delete tfer1; delete tfer2; delete tfer3;
+
+	delete buf4; delete buf5; delete buf6;
+	delete tfer4; delete tfer5; delete tfer6;
+
+	delete header;
+	delete aTrans;
+
+	return KErrNone;
+	}
+
+// Do full duplex creation test
+TInt DChannelIicClient::DoCreateFullDuplexTransTest(TInt aTestType)
+	{
+	CLIENT_PRINT(("DChannelIicClient::DoCreateFullDuplexTransTest starts\n"));
+
+	TInt r=KErrNone;
+	switch(aTestType)
+		{
+		case RBusDevIicClient::ETestValidFullDuplexTrans:
+			{
+			// equal length, opposite transfer direction
+			r = CreateTransferListHalfDuplex(
+						TIicBusTransfer::EMasterWrite, KLongNodeTestLength,
+						TIicBusTransfer::EMasterRead, KLongNodeTestLength,
+						TIicBusTransfer::EMasterWrite, KLongNodeTestLength);
+			if(r!=KErrNone) break;
+			r = CreateTransferListFullDuplex(
+						TIicBusTransfer::EMasterRead, KLongNodeTestLength,
+						TIicBusTransfer::EMasterWrite, KLongNodeTestLength,
+						TIicBusTransfer::EMasterRead, KLongNodeTestLength);
+			if(r!=KErrNone) break;
+			break;
+			}
+		case RBusDevIicClient::ETestInvalidFullDuplexTrans1:
+			{
+			// equal length, same transfer direction
+			r = CreateTransferListHalfDuplex(
+						TIicBusTransfer::EMasterWrite, KLongNodeTestLength,
+						TIicBusTransfer::EMasterRead, KLongNodeTestLength,
+						TIicBusTransfer::EMasterWrite, KLongNodeTestLength);
+			if(r!=KErrNone) break;
+			r = CreateTransferListFullDuplex(
+						TIicBusTransfer::EMasterWrite, KLongNodeTestLength,
+						TIicBusTransfer::EMasterRead, KLongNodeTestLength,
+						TIicBusTransfer::EMasterWrite, KLongNodeTestLength);
+			if(r!=KErrNone) break;
+			break;
+			}
+		case RBusDevIicClient::ETestInvalidFullDuplexTrans2:
+			{
+			// different, opposite transfer direction
+			r = CreateTransferListHalfDuplex(
+						TIicBusTransfer::EMasterWrite, KShortNodeTestLength,
+						TIicBusTransfer::EMasterRead, KShortNodeTestLength,
+						TIicBusTransfer::EMasterWrite, KShortNodeTestLength);
+			if(r!=KErrNone) break;
+			r = CreateTransferListFullDuplex(
+						TIicBusTransfer::EMasterRead, KLongNodeTestLength,
+						TIicBusTransfer::EMasterWrite, KLongNodeTestLength,
+						TIicBusTransfer::EMasterRead, KLongNodeTestLength);
+			if(r!=KErrNone) break;
+			break;
+			}
+		case RBusDevIicClient::ETestLastNodeFullDuplexTrans:
+			{
+			// different length for the last node
+			r = CreateTransferListHalfDuplex(
+						TIicBusTransfer::EMasterWrite, KLongNodeTestLength,
+						TIicBusTransfer::EMasterRead, KLongNodeTestLength,
+						TIicBusTransfer::EMasterWrite, KShortNodeTestLength);
+			if(r!=KErrNone) break;
+			r = CreateTransferListFullDuplex(
+						TIicBusTransfer::EMasterRead, KLongNodeTestLength,
+						TIicBusTransfer::EMasterWrite, KLongNodeTestLength,
+						TIicBusTransfer::EMasterRead, KLongNodeTestLength);
+			if(r!=KErrNone) break;
+			break;
+			}
+		case RBusDevIicClient::ETestDiffNodeNoFullDuplexTrans:
+			{
+			// equal length, opposite transfer direction
+			r = CreateTransferListHalfDuplex(
+						TIicBusTransfer::EMasterWrite, KLongNodeTestLength,
+						TIicBusTransfer::EMasterRead, KLongNodeTestLength,
+						TIicBusTransfer::EMasterWrite, KShortNodeTestLength);
+			if(r!=KErrNone) break;
+			r = CreateTransferListFullDuplex(
+						TIicBusTransfer::EMasterRead, KLongNodeTestLength,
+						TIicBusTransfer::EMasterWrite, KShortNodeTestLength,
+						TIicBusTransfer::EMasterRead, 0);
+			if(r!=KErrNone) break;
+			break;
+			}
+
+
+		default:
+			break;
+		}
+
+	header = HBuf8::New(KFullTracnHdrTextLength);
+	TIicBusTransaction *Trans = new TIicBusTransaction(header,tfer1);
+
+	if((r!=KErrNone) || (header == NULL) || (Trans == NULL))
+		{
+		CLIENT_PRINT(("DChannelIicClient::DoCreateFullDuplexTransTest ERROR - failed to allocate the necessary memory\n"));
+		DeleteFullDuplexTest(Trans);
+		return KErrNoMemory;
+		}
+
+	header->Copy(KFullTracnHdrText);
+
+	TInt TestResult = Trans->SetFullDuplexTrans(tfer4);
+
+	CLIENT_PRINT(("DChannelIicClient::DoCreateFullDuplexTransTest IIC after SetFullDuplexTrans TestResult =%d\n", TestResult));
+
+	r = DeleteFullDuplexTest(Trans);
+
+	return TestResult;
+
+	}
+
+
+TInt DChannelIicClient::CreateDefaultSpiBuf(TConfigSpiBufV01*& aBuf)
+// Utility function to create a buffer for the SPI bus
+	{
+	TInt r=CreateSpiBuf(aBuf, ESpiWordWidth_8, 100000, ESpiPolarityLowRisingEdge, 100 ,ELittleEndian, EMsbFirst, 10, ESpiCSPinActiveLow);
+	return r;
+	}
+
+// DoPriorityTest does the following actions:
+// 1. switch the bus (only use SPI test PSL) to priority test mode
+// 2. create 5 test transactions with different priorities and 1 blocking transaction
+// 3. enable blocking in test channel
+//     we can only block the test channel, we cannot suspend the bus controller
+// 3. send blocking transaction to the test channel
+//     the blocking transaction is just normal transaction.
+//     the test channel will be blocked once the first transaction is arrived
+// 4. send test transactions in opposite order to their priority
+// 5. unblock test channel
+// 6. read test result from channel
+// 7. switch the bus to normal mode
+TInt DChannelIicClient::DoPriorityTest(TInt aBusId)
+	{
+	TInt TestResult=KErrNone;
+	// Use the IIC StaticExtension interface to pass the request to the bus implementation
+	// To support testing, any values of aId for StaticExtension must be shifted left one place
+	TUint testId = ((TUint)(RBusDevIicClient::ECtlIoPriorityTest))<<1;
+	TInt r = KErrNone;
+
+	r = StaticExtension(aBusId, testId, NULL, NULL);
+	__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__));
+	if(r == KErrNone)
+		{
+		buf1 = HBuf8::New(1);
+		buf2 = HBuf8::New(1);
+		buf3 = HBuf8::New(1);
+		buf4 = HBuf8::New(1);
+		buf5 = HBuf8::New(1);
+		//buffer for blocking transaction
+		buf6 = HBuf8::New(1);
+
+		if(buf1 == NULL||buf2 == NULL||buf3 == NULL||buf4 == NULL||buf5 == NULL||buf6 == NULL)
+			{
+			delete buf1; delete buf2; delete buf3; delete buf4; delete buf5; delete buf6;
+			r = StaticExtension(aBusId, (TUint)RBusDevIicClient::ECtlIoNone, NULL, NULL);
+			return KErrNoMemory;
+			}
+		tfer1 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf1);
+		tfer2 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf2);
+		tfer3 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf3);
+		tfer4 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf4);
+		tfer5 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf5);
+		//transfer for blocking transaction
+		tfer6 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf6);
+
+		if(tfer1 == NULL||tfer2 == NULL||tfer3 == NULL||tfer4 == NULL||tfer5 == NULL||tfer6 == NULL)
+			{
+			delete buf1; delete buf2; delete buf3; delete buf4; delete buf5; delete buf6;
+			delete tfer1; delete tfer2; delete tfer3; delete tfer4; delete tfer5; delete tfer6;
+			r = StaticExtension(aBusId, (TUint)RBusDevIicClient::ECtlIoNone, NULL, NULL);
+			return KErrNoMemory;
+			}
+
+		TConfigSpiBufV01* spiHeader1 = NULL;
+		TConfigSpiBufV01* spiHeader2 = NULL;
+		TConfigSpiBufV01* spiHeader3 = NULL;
+		TConfigSpiBufV01* spiHeader4 = NULL;
+		TConfigSpiBufV01* spiHeader5 = NULL;
+		TConfigSpiBufV01* spiHeaderBlock = NULL; 		//header for blocking transaction
+
+
+		TInt r = CreateDefaultSpiBuf(spiHeader1);
+		if(r == KErrNone)	r = CreateDefaultSpiBuf(spiHeader2);
+		if(r == KErrNone)	r = CreateDefaultSpiBuf(spiHeader3);
+		if(r == KErrNone)	r = CreateDefaultSpiBuf(spiHeader4);
+		if(r == KErrNone)	r = CreateDefaultSpiBuf(spiHeader5);
+		//header for blocking transaction
+		if(r == KErrNone)	r = CreateDefaultSpiBuf(spiHeaderBlock);
+
+		if(r != KErrNone||spiHeader1 == NULL||spiHeader2 == NULL||spiHeader3 == NULL||spiHeader4 == NULL||spiHeader5 == NULL||spiHeaderBlock == NULL)
+			{
+			delete buf1; delete buf2; delete buf3; delete buf4; delete buf5; delete buf6;
+			delete tfer1; delete tfer2; delete tfer3; delete tfer4; delete tfer5; delete tfer6;
+			delete spiHeader1; delete spiHeader2; delete spiHeader3; delete spiHeader4; delete spiHeader5; delete spiHeaderBlock;
+			r = StaticExtension(aBusId, (TUint)RBusDevIicClient::ECtlIoNone, NULL, NULL);
+			return KErrNoMemory;
+			}
+
+		TIicBusTransaction* Transc1; Transc1 = new TIicBusTransaction(spiHeader1,tfer1, KPriorityTestPrio[0]);
+		TIicBusTransaction* Transc2; Transc2 = new TIicBusTransaction(spiHeader2,tfer2, KPriorityTestPrio[1]);
+		TIicBusTransaction* Transc3; Transc3 = new TIicBusTransaction(spiHeader3,tfer3, KPriorityTestPrio[2]);
+		TIicBusTransaction* Transc4; Transc4 = new TIicBusTransaction(spiHeader4,tfer4, KPriorityTestPrio[3]);
+		TIicBusTransaction* Transc5; Transc5 = new TIicBusTransaction(spiHeader5,tfer5, KPriorityTestPrio[4]);
+		//blocking transaction
+		TIicBusTransaction* TranscBlock; TranscBlock = new TIicBusTransaction(spiHeaderBlock,tfer6, KPriorityTestPrio[5]);
+
+		if(Transc1 == NULL||Transc2 == NULL||Transc3 == NULL||Transc4 == NULL||Transc5 == NULL||TranscBlock == NULL)
+			{
+			delete buf1; delete buf2; delete buf3; delete buf4; delete buf5; delete buf6;
+			delete tfer1; delete tfer2; delete tfer3; delete tfer4; delete tfer5; delete tfer6;
+			delete spiHeader1; delete spiHeader2; delete spiHeader3; delete spiHeader4; delete spiHeader5; delete spiHeaderBlock;
+			delete Transc1; delete Transc2; delete Transc3; delete Transc4; delete Transc5; delete TranscBlock;
+			r = StaticExtension(aBusId, (TUint)RBusDevIicClient::ECtlIoNone, NULL, NULL);
+			return KErrNoMemory;
+			}
+
+		//dummy call back func is provided for asyn call
+		TIicBusCallback* cb = new TIicBusCallback(DummyCallbackFunc, this, iDfcQue, 5); // 5 arbitrary
+
+		// block the device channel. the channel will not be blocked until the first transaction arrive the channel
+		// To support testing, any values of aId for StaticExtension must be shifted left one place
+		TUint testId=((TUint)RBusDevIicClient::ECtlIoBlockReqCompletion)<<1;
+		r = StaticExtension(aBusId, testId, NULL, NULL);
+		__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__));
+
+		r = QueueTransaction(aBusId, TranscBlock, cb);  //send TranscBlock to block the channel
+		// send ordered transactions
+		__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__));
+
+		r = QueueTransaction(aBusId, Transc1, cb);
+		__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__));
+		r = QueueTransaction(aBusId, Transc2, cb);
+		__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__));
+		r = QueueTransaction(aBusId, Transc3, cb);
+		__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__));
+		r = QueueTransaction(aBusId, Transc4, cb);
+		__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__));
+		r = QueueTransaction(aBusId, Transc5, cb);
+		__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__));
+
+		// unblock device channel
+		testId=((TUint)RBusDevIicClient::ECtlIoUnblockReqCompletion)<<1;
+		r = StaticExtension(aBusId, testId, NULL, NULL);
+		__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__));
+
+		#define KPriorityTestGetResultRetry 3
+		for(TInt i=0; i<KPriorityTestGetResultRetry ; i++)
+			{
+			NKern::Sleep(500);
+			testId=((TUint)RBusDevIicClient::EGetTestResult)<<1;
+			TestResult = StaticExtension(aBusId, testId, NULL, NULL);
+			if(TestResult!=KErrNotReady) break;
+			}
+
+		cb->Cancel();
+		delete cb;
+		delete buf1; delete buf2; delete buf3; delete buf4; delete buf5; delete buf6;
+		delete tfer1; delete tfer2; delete tfer3; delete tfer4; delete tfer5; delete tfer6;
+		delete spiHeader1; delete spiHeader2; delete spiHeader3; delete spiHeader4; delete spiHeader5; delete spiHeaderBlock;
+		delete Transc1; delete Transc2; delete Transc3; delete Transc4; delete Transc5; delete TranscBlock;
+
+		}
+	r = StaticExtension(aBusId, (TUint)RBusDevIicClient::ECtlIoNone, NULL, NULL);
+	return TestResult;
+	}
+
+TInt DChannelIicClient::ConstructTransactionOne(TIicBusTransaction*& aTrans)
+	{
+	// Transaction is to contain three transfers, with data defined by
+	// KTransOneTferOne[], KTransOneTferTwo[], KTransOneTferThree[]
+	buf1 = HBuf8::New(21);
+	buf2 = HBuf8::New(8);
+	buf3 = HBuf8::New(6);
+	tfer1 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf1);
+	tfer2 = new TIicBusTransfer(TIicBusTransfer::EMasterRead,8,buf2);
+	tfer3 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf3);
+	TInt r = CreateDefaultSpiBuf(spiHeader);
+	if((r != KErrNone)||(spiHeader == NULL)||(buf1 == NULL)||(buf2 == NULL)||(buf3 == NULL)||(tfer1 == NULL)||(tfer2 == NULL)||(tfer3 == NULL))
+		{
+		CLIENT_PRINT(("DChannelIicClient::ConstructTransactionOne ERROR - failed to allocate the necessary memory\n"));
+		delete buf1;
+		delete buf2;
+		delete buf3;
+		delete tfer1;
+		delete tfer2;
+		delete tfer3;
+		delete spiHeader;
+		delete aTrans;
+		return KErrNoMemory;
+		}
+	aTrans = new TIicBusTransaction(spiHeader,tfer1);
+	buf1->Copy(&(KTransOneTferOne[0]),21);
+	buf2->Copy(&(KTransOneTferTwo[0]),8);
+	buf3->Copy(&(KTransOneTferThree[0]),6);
+	tfer1->LinkAfter(tfer2);
+	tfer2->LinkAfter(tfer3);
+	return KErrNone;
+	}
+
+void DChannelIicClient::CleanupTransactionOne(TIicBusTransaction*& aTrans)
+	{
+	// Release the allocated memory
+	delete buf1;
+	buf1=NULL;
+	delete buf2;
+	buf2=NULL;
+	delete buf3;
+	buf3=NULL;
+	delete tfer1;
+	tfer1=NULL;
+	delete tfer2;
+	tfer2=NULL;
+	delete tfer3;
+	tfer3=NULL;
+	delete spiHeader;
+	spiHeader=NULL;
+	delete aTrans;
+	aTrans=NULL;
+	}
+
+
+void DChannelIicClient::CleanupTransaction(TIicBusTransaction*& aTrans)
+	{
+	delete iSpiBuf;
+	iSpiBuf=NULL;
+	delete iI2cBuf;
+	iI2cBuf=NULL;
+	TIicBusTransfer* currTfer = iTfer;
+	TIicBusTransfer* nextTfer = NULL;
+	while(currTfer)
+		{
+		TIicBusTransfer* nextTfer = (TIicBusTransfer*)(currTfer->Next());
+		delete currTfer;
+		if(nextTfer)
+			currTfer = nextTfer;
+		else
+			currTfer = NULL;
+		};
+	iTfer=NULL;
+	currTfer = iFdTfer;
+	nextTfer = NULL;
+	while(currTfer)
+		{
+		TIicBusTransfer* nextTfer = (TIicBusTransfer*)(currTfer->Next());
+		delete currTfer;
+		if(nextTfer)
+			currTfer = nextTfer;
+		else
+			currTfer = NULL;
+		};
+	iFdTfer=NULL;
+	if(aTrans!=NULL)
+		{
+		delete aTrans;
+		aTrans=NULL;
+		}
+	if(iTransPreamble!=NULL)
+		{
+		delete iTransPreamble;
+		iTransPreamble=NULL;
+		}
+	}
+
+void DChannelIicClient::TransModifCallback(TIicBusTransaction* /*aTrans*/, TInt /*aBusId*/, TInt aResult, TAny* aParam)
+	{
+	// Callback function used to test re-use of transaction and transfer buffers
+	// aParam is the address of the simulated client driver
+	DChannelIicClient* channel = (DChannelIicClient*)aParam;
+	TTransBufReuseData* reuseData = &(channel->iTransBufReuseData);
+
+	// Since the transaction is no longer queued, should be able to modify the transfer and transaction content
+	channel->TestTransModification(reuseData->iTransaction, reuseData->iHdTfer, reuseData->iFdTfer, reuseData->iHdr);
+
+	// Complete the user's request, delete objects allocated for this test and return
+	Kern::RequestComplete(channel->iClient, channel->iStatus, aResult);
+	delete reuseData->iCallback;	// Must do this before deleting the Transaction, in CleanupTransaction
+	channel->CleanupTransaction(channel->iTrans);
+	return;
+	}
+
+
+void DChannelIicClient::TestTransModification(TIicBusTransaction* aTransaction,
+											  TIicBusTransfer* aHdTfer,
+											  TIicBusTransfer* aFdTfer,
+											  TDes8* aHdr)
+	{
+	// Function to test that the content of Transaction and Transfer objects can be modified
+	// This assumes that the Transaction is in the appropriate state (EFree) - otherwise, the code will assert
+	// This function also assumes that transaction has aleady added the half-duplex and full-duplex transfers
+	// that are passed in as arguments, and that the transfers lists are non-NULL
+	// The original type of the transfers (read, write) are ignored, since it is not of interest in this test -
+	// instead, what is important is to ensure that the half-duplex and full-duplex transfer types are in opposing
+	// directions - so the types are explicitly set in this test.
+	//
+	TDes8* origBuf = NULL;
+	TInt8 origGranularity = 0;
+
+	// Create a buffer for use in this function
+	_LIT(temporaryText,"Temporary Text");
+	TBuf8<15> tempBuf_8;
+	tempBuf_8.Copy(temporaryText);
+
+	// Test modification of the two transfer lists while still part of the transaction
+	origBuf = (TDes8*)(aHdTfer->GetBuffer());
+	origGranularity = aHdTfer->WordWidth();
+	aHdTfer->SetTransferData(TIicBusTransfer::EMasterRead, origGranularity, &tempBuf_8);
+	aHdTfer->SetTransferData(TIicBusTransfer::EMasterRead, origGranularity, origBuf);
+
+	origBuf = (TDes8*)(aFdTfer->GetBuffer());
+	origGranularity = aFdTfer->WordWidth();
+	aFdTfer->SetTransferData(TIicBusTransfer::EMasterWrite, origGranularity, &tempBuf_8);
+	aFdTfer->SetTransferData(TIicBusTransfer::EMasterWrite, origGranularity, origBuf);
+
+	// Test transfers can be removed from the transaction
+	aTransaction->RemoveHalfDuplexTrans();
+	aTransaction->RemoveFullDuplexTrans();
+
+	// Test modification of the two transfer lists while not part of a transaction
+	origBuf = (TDes8*)(aHdTfer->GetBuffer());
+	origGranularity = aHdTfer->WordWidth();
+	aHdTfer->SetTransferData(TIicBusTransfer::EMasterRead, origGranularity, &tempBuf_8);
+	aHdTfer->SetTransferData(TIicBusTransfer::EMasterRead, origGranularity, origBuf);
+
+	origBuf = (TDes8*)(aFdTfer->GetBuffer());
+	origGranularity = aFdTfer->WordWidth();
+	aFdTfer->SetTransferData(TIicBusTransfer::EMasterWrite, origGranularity, &tempBuf_8);
+	aFdTfer->SetTransferData(TIicBusTransfer::EMasterWrite, origGranularity, origBuf);
+
+	// Test transfers can be re-added to the transaction
+	aTransaction->SetHalfDuplexTrans(aHdr,aHdTfer);
+	aTransaction->SetFullDuplexTrans(aFdTfer);
+
+	// Test modification of the two transfer lists now re-added to the transaction
+	origBuf = (TDes8*)(aHdTfer->GetBuffer());
+	origGranularity = aHdTfer->WordWidth();
+	aHdTfer->SetTransferData(TIicBusTransfer::EMasterRead, origGranularity, &tempBuf_8);
+	aHdTfer->SetTransferData(TIicBusTransfer::EMasterRead, origGranularity, origBuf);
+
+	origBuf = (TDes8*)(aFdTfer->GetBuffer());
+	origGranularity = aFdTfer->WordWidth();
+	aFdTfer->SetTransferData(TIicBusTransfer::EMasterWrite, origGranularity, &tempBuf_8);
+	aFdTfer->SetTransferData(TIicBusTransfer::EMasterWrite, origGranularity, origBuf);
+
+	return;
+	}
+
+TInt DChannelIicClient::DoControl(TInt aId, TAny* a1, TAny* a2)
+	{
+	CLIENT_PRINT(("DChannelIicClient::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 tests, the two msbs must be zero
+	TInt ctrlIoVal = 0;
+	if((aId & KTestMasterControlIo) == KTestMasterControlIo)
+		ctrlIoVal = (aId << 1);
+	if((aId & KTestSlaveControlIo) == KTestSlaveControlIo)
+		ctrlIoVal = (aId << 1) & 0x3FFFFFFF;
+	switch(aId)
+		{
+		case(RBusDevIicClient::EQTransSync):
+			{
+			// a1 specifies Bus Realisation Config to use
+			// a2 is a pointer to TUsideTracnDesc
+			TIicBusTransaction* trans = NULL;
+			TIicBusTransfer* tfer = NULL;
+			TConfigSpiBufV01 *spiBuf = NULL;
+			
+			//Read the transaction header to determin if it is a multi-transaction type
+			TUsideTracnDesc usTrans;
+
+			if((Kern::ThreadRawRead(iClient,a2,&usTrans,sizeof(TUsideTracnDesc)))!=KErrNone)
+				{
+				CLIENT_PRINT(("DChannelIicClient::DoControl ERROR - Can't read iHeader to spiBuf\n"));
+				return KErrGeneral;
+				}
+
+			if((usTrans.iFlags)&KTransactionWithMultiTransc)
+				{
+				// Since we are testing a multi-transaction, create another transaction object iMultiTransac,
+				// to represent the delayed part of the multi-transaction. After the preliminary
+				// transaction(passed from t_iic, with one read transfer) has been performed, 
+				// the IIC code will find that it is part of a 
+				// multi-transaction; it will call the callback for the transaction(set as MultiTranscCallbackFunc,
+				// in ExtractTransData) and this will return a pointer to the next part of the multi-transaction
+				// to be performed(iMultiTransac). It will then immediately pass this transaction object
+				// to the PSL for processing - before considering any other transactions that have been 
+				// requested, and without completing the multi-transaction request(this is done once 
+				// iMultiTransac has been processed)
+				buf1 = HBuf8::New(1);
+				spiBuf = new TConfigSpiBufV01();
+				if(buf1 == NULL||spiBuf == NULL) {delete buf1;delete spiBuf; return KErrNoMemory;}
+
+
+				if((r=Kern::ThreadDesRead(iClient, usTrans.iHeader, *spiBuf, 0, KChunkShiftBy0 ))!=KErrNone)
+					{
+					CLIENT_PRINT(("DChannelIicClient::DoControl ERROR - Can't read iHeader to spiBuf\n"));
+					return KErrGeneral;
+					}
+
+				tfer = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf1);
+				if(tfer == NULL) {delete buf1; delete spiBuf; return KErrNoMemory;}
+
+				iMultiTransac = new TIicBusTransaction((TDes8*)spiBuf, tfer);
+				if(iMultiTransac == NULL) {delete buf1; delete spiBuf; delete tfer; return KErrNoMemory;}
+				}
+			r = ExtractTransData((TUsideTracnDesc*)a2, trans);
+			if(r!=KErrNone)
+				{
+				CLIENT_PRINT(("DChannelIicClient::DoControl ERROR - ExtractTransData returned %d\n",r));
+				return r;
+				}
+			CLIENT_PRINT(("DChannelIicClient::DoControl invoking (synchronous) QueueTransaction with busId=0x%x, trans=0x%x\n",(TUint32)a1,trans));
+
+			r = QueueTransaction((TUint32)a1, trans);
+			CleanupExtractTrans(trans);
+			CleanupTransaction(trans);
+			if((usTrans.iFlags)&KTransactionWithMultiTransc)
+				{
+				delete buf1;
+				delete spiBuf;
+				delete tfer;
+				delete iMultiTransac;
+				}
+			break;
+			}
+		case(RBusDevIicClient::ECtlIoBlockReqCompletion):
+		case(RBusDevIicClient::ECtlIoUnblockReqCompletion):
+		case(RBusDevIicClient::ECtlIoDeRegChan):
+			{
+			// a1 specifies Bus Realisation Config to use
+			CLIENT_PRINT(("DChannelIicClient::DoControl invoking StaticExtension with aId=%d, busId=0x%x\n",aId,(TUint32)a1));
+			// Use the IIC StaticExtension interface to pass the request to the bus implementation
+			r = StaticExtension((TUint32)a1, (TUint)ctrlIoVal, NULL, NULL);
+			break;
+			}
+		case(RBusDevIicClient::ECtlIoTestFullDuplexTrans):
+			{
+			// a1 specifies Bus Realisation Config to use
+			CLIENT_PRINT(("DChannelIicClient::DoControl invoking StaticExtension with aId=%d, busId=0x%x\n",aId,(TUint32)a1));
+			r = DoCreateFullDuplexTransTest((TInt)a2);
+			break;
+			}
+		case(RBusDevIicClient::ECtlIoPriorityTest):
+			{
+			// a1 specifies Bus Realisation Config to use
+			CLIENT_PRINT(("DChannelIicClient::DoControl invoking StaticExtension with aId=%d, busId=0x%x\n",aId,(TUint32)a1));
+			r = DoPriorityTest((TUint32)a1);
+			break;
+			}
+
+		case(RBusDevIicClient::ECtlIoTracnOne):
+			{
+			// a1 specifies Bus Realisation Config to use
+			CLIENT_PRINT(("DChannelIicClient::StaticExtension invoking StaticExtension with ctrlIoVal=%d, busId=0x%x\n",aId,(TUint32)a1));
+			// Use the IIC StaticExtension interface to pass the request to the bus implementation
+			r = StaticExtension((TUint32)a1, (TUint)ctrlIoVal, NULL, NULL);
+			__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("StaticExtension",__LINE__));
+			if(r == KErrNone)
+				{
+				// Create then send (synchronously) Transaction One
+				r = ConstructTransactionOne(iTrans);
+				__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__));
+				r = QueueTransaction((TUint32)a1, iTrans);
+				__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__));
+				CleanupTransactionOne(iTrans);
+				}
+			r = StaticExtension((TUint32)a1, (TUint)RBusDevIicClient::ECtlIoNone, NULL, NULL);
+			break;
+			}
+		case(RBusDevIicClient::ECtlIoSetTimeOutFlag):
+			{
+			CLIENT_PRINT(("DChannelIicClient::DoControl instruct the bus that it is to simulate a slave timeout"));
+			// To support testing, function index passed to StaticExtension must be shifted one place to the left
+			TUint testIndex = ((TUint)RBusDevIicClient::ECtlIoSetTimeOutFlag)<<1;;
+			r = StaticExtension((TUint32)a1, testIndex, NULL, NULL);
+			break;
+			}
+		case(RBusDevIicClient::ECtlIoNone):
+			{
+			CLIENT_PRINT(("DChannelIicClient::DoControl Return the bus to its default test state"));
+			r = StaticExtension((TUint32)a1, (TUint)RBusDevIicClient::ECtlIoNone, NULL, NULL);
+			break;
+			}
+
+// Support for MasterSlave processing
+
+		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"));
+ 				return KErrArgument;
+				}
+			if((iConfigHdr = HBuf8::New(hdrSize)) == NULL)
+				return KErrNoMemory;
+			r = Kern::ThreadDesRead(iClient,a1,*iConfigHdr,0);
+			if(r!=KErrNone)
+				{
+				delete iConfigHdr;
+				return r;
+				}
+			// 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;
+			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl CaptureChannelgave iChannelId=0x%x\n",iChannelId));
+
+			TInt r=Kern::ThreadRawWrite(iClient,iClientChanId,&iChannelId,sizeof(TInt));
+			(void)r;	// Silence the compiler
+
+			break;
+			}
+
+		case(RBusDevIicClient::EReleaseChan):
+			{
+			// a1 represents TInt aChannelId
+			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking ReleaseChannel\n"));
+			r = ReleaseChannel((TInt)a1);
+			delete iConfigHdr;
+			break;
+			}
+
+		case(RBusDevIicClient::EInitSlaveClient):
+			{
+			r=InitSlaveClient();
+			break;
+			}
+		
+#ifdef STANDALONE_CHANNEL		
+        case(RBusDevIicClient::ETestIicChannelInlineFunc):
+            {  
+            TTestIicChannelInterface channelInterface(DIicBusChannel::EMaster, DIicBusChannel::EI2c, DIicBusChannel::EHalfDuplex);
+            r = channelInterface.TestInterface();
+            break;         
+            }
+#endif
+        
+        default:
+			{
+			CLIENT_PRINT(("DChannelIicClient::DoControl - unrecognised value for aId=0x%x\n",aId));
+			r=KErrArgument;
+			break;
+			}
+		}
+	return r;
+	}
+
+TInt DChannelIicClient::DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2)
+	{
+	CLIENT_PRINT(("DChannelIicClient::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::EQTransAsync):
+			{
+			// a1 specifies Bus Realisation Config to use
+			// a2 is a pointer to TIicBusTransaction
+			TIicBusTransaction* trans = NULL;
+			r = ExtractTransData((TUsideTracnDesc*)a2, trans);
+			if(r!=KErrNone)
+				{
+				CLIENT_PRINT(("DChannelIicClient::DoRequest ERROR - ExtractTransData returned %d\n",r));
+				return r;
+				}
+			// Create TIicBusCallback object
+			TIicBusCallback* cb = new TIicBusCallback(AsyncCallbackFunc, this, iDfcQue, 5); // 5 arbitrary
+			TTransCbPair* cbPair = new TTransCbPair();
+			cbPair->iCb=cb;
+			cbPair->iTrans=trans;
+			// Create an entry in the RPointerArray for TRequestStatus - TIicBusTransaction pairs
+			TTransStatusPair* pair = new TTransStatusPair();
+			pair->iReq=aStatus;
+			pair->iTrans=trans;
+			r=InsertPairs(pair,cbPair);
+			if(r!=KErrNone)
+				{
+				CLIENT_PRINT(("DChannelIicClient::DoRequest ERROR - InsertInOrder returned %d\n",r));
+				return r;
+				}
+			CLIENT_PRINT(("DChannelIicClient::DoRequest invoking (asynchronous) QueueTransaction with busId=0x%x, trans=0x%x, cb=0x%x\n",(TUint32)a1,trans,cb));
+			r = QueueTransaction((TUint32)a1, trans, cb);
+			if(r!=KErrNone)
+				{
+				// The transaction was not queued - since it will not be completed asynchronously, need to remove it here
+				GetWriteAccess();
+				Lock();
+				TInt pairIndex=iTransStatArrayByTrans.FindInOrder(pair,TransStatusOrderByTrans);
+				__ASSERT_ALWAYS(pairIndex>=0,Kern::Fault("IIC Client, DoRequest, EQTransAsync ByTrans pairIndex<0",__LINE__));
+				iTransStatArrayByTrans.Remove(pairIndex);
+				pairIndex = iTransStatArrayByStatus.FindInOrder(pair,TransStatusOrderByStatus);
+				__ASSERT_ALWAYS(pairIndex>=0,Kern::Fault("IIC Client, DoRequest, EQTransAsync ByStatus pairIndex<0",__LINE__));
+				iTransStatArrayByStatus.Remove(pairIndex);
+				pairIndex = iTransCbArrayByTrans.FindInOrder(cbPair,TransCbOrderByTrans);
+				__ASSERT_ALWAYS(pairIndex>=0,Kern::Fault("IIC Client, DoRequest, EQTransAsync Cb by Trans pairIndex<0",__LINE__));
+				iTransCbArrayByTrans.Remove(pairIndex);
+				FreeWriteAccess();
+				Unlock();
+				Kern::RequestComplete(iClient, aStatus, r);
+				delete cb;
+				delete cbPair;
+				CleanupExtractTrans(pair->iTrans);
+				CleanupTransaction(pair->iTrans);			
+				delete pair;
+				}
+			break;
+			}
+
+		case(RBusDevIicClient::ECtrlIoTestBufReUse):
+			{
+			iStatus = aStatus;
+			// a1 specifies Bus Realisation Config to use
+
+			// Ensure object pointers are made available
+			CleanupTransaction(iTrans);
+
+			TInt r = KErrNone;
+			TIicBusCallback* cb = NULL;
+
+			// Use default constructor to create an empty transaction
+			iTrans = new TIicBusTransaction();
+			if(iTrans == NULL)
+				{
+				CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - iTrans=NULL\n"));
+				r = KErrNoMemory;
+				}
+
+			// Create a header for the transaction
+			if(r == KErrNone)
+				{
+				r = CreateDefaultSpiBuf(iSpiBuf);
+				if(r != KErrNone)
+					{
+					CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - CreateDefaultSpiBuf returned %d\n",r));
+					}
+				}
+
+			// Create and add transfer lists for half-duplex and full-duplex entries in the transaction
+			if(r == KErrNone)
+				{
+				// Use simple text as payload, 8bit granularity, half-duplex write, full-duplex read (ie payload ignored)
+				_LIT(halfDuplexText1,"Half Duplex Text 1");
+				TBuf8<19> halfDuplexBuf_8;
+				halfDuplexBuf_8.Copy(halfDuplexText1);
+				iTfer = new TIicBusTransfer(TIicBusTransfer::EMasterWrite, 8, &halfDuplexBuf_8);
+				if(iTfer == NULL)
+					{
+					CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - iTfer=NULL\n"));
+					r = KErrNoMemory;
+					}
+				else
+					{
+					_LIT(halfDuplexText2,"Half Duplex Text 2");
+					TBuf8<19> halfDuplexBuf2_8;
+					halfDuplexBuf2_8.Copy(halfDuplexText2);
+					TIicBusTransfer* tempHdTfer = new TIicBusTransfer(TIicBusTransfer::EMasterWrite, 8, &halfDuplexBuf2_8);
+					if(tempHdTfer == NULL)
+						{
+						CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - tempHdTfer=NULL\n"));
+						r = KErrNoMemory;
+						}
+					else
+						{
+						iTfer->LinkAfter(tempHdTfer);
+						}
+					}
+				if(r == KErrNone)
+					{
+					_LIT(fullDuplexText1,"Full Duplex Text 1");
+					TBuf8<19> fullDuplexBuf1_8;
+					fullDuplexBuf1_8.Copy(fullDuplexText1);
+					iFdTfer = new TIicBusTransfer(TIicBusTransfer::EMasterRead, 8, &fullDuplexBuf1_8);
+					if(iFdTfer == NULL)
+						{
+						CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - iFdTfer=NULL\n"));
+						r = KErrNoMemory;
+						}
+					else
+						{
+						_LIT(fullDuplexText2,"Full Duplex Text 2");
+						TBuf8<19> fullDuplexBuf2_8;
+						fullDuplexBuf2_8.Copy(fullDuplexText2);
+						TIicBusTransfer* tempFdTfer = new TIicBusTransfer(TIicBusTransfer::EMasterRead, 8, &fullDuplexBuf2_8);
+						if(tempFdTfer == NULL)
+							{
+							CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - tempFdTfer=NULL\n"));
+							r = KErrNoMemory;
+							}
+						else
+							{
+							iFdTfer->LinkAfter(tempFdTfer);
+							}
+						}
+					}
+				}
+
+			// Add the Header and Transfers to the Transaction
+			if(r == KErrNone)
+				r = iTrans->SetHalfDuplexTrans(iSpiBuf, iTfer);
+				if(r != KErrNone)
+					{
+					CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - SetHalfDuplexTrans returned %d\n",r));
+					}
+
+			if(r == KErrNone)
+				r = iTrans->SetFullDuplexTrans(iFdTfer);
+				if(r != KErrNone)
+					{
+					CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - SetFullDuplexTrans returned %d\n",r));
+					}
+
+			// Specify the callback object to use
+			if(r == KErrNone)
+				{
+				cb = new TIicBusCallback(TransModifCallback, this, iDfcQue, 5); // 5 arbitrary
+				if(cb == NULL)
+					{
+					CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - cb=NULL\n"));
+					r = KErrNoMemory;
+					}
+				}
+
+			// Since the transaction is not yet queued, should be able to modify the transfer and transaction content
+			TestTransModification(iTrans, iTfer, iFdTfer, iSpiBuf);
+
+			// Store the relevant data in this object's iTransBufReuseData member
+			iTransBufReuseData.iTransaction = iTrans;
+			iTransBufReuseData.iHdTfer = iTfer;
+			iTransBufReuseData.iFdTfer = iFdTfer;
+			iTransBufReuseData.iHdr = iSpiBuf;
+			iTransBufReuseData.iCallback = cb;
+
+			// Now queue the transaction. The callback function will re-apply the modification tests and delete the
+			// objects created here
+			// If the queueing fails, complete the test here and clean up
+			r = QueueTransaction((TInt)a1, iTrans, cb);
+			if(r != KErrNone)
+				{
+				Kern::RequestComplete(iClient, iStatus, r);
+				delete iTransBufReuseData.iCallback;	// Must do this before deleting the Transaction in CleanupTransaction
+				CleanupTransaction(iTrans);
+				}
+			break;
+			}
+		default:
+			{
+			CLIENT_PRINT(("DChannelIicClient::DoRequest - unrecognised value for aId=0x%x\n",aId));
+			r=KErrArgument;
+			break;
+			}
+		}
+	return r;
+	}
+
+
+// Support for MasterSlave processing
+static void MsSlaveClientCallbackFunc(TInt aChannelId, TInt aReturn, TInt aTrigger, TInt16 aRxWords, TInt16 aTxWords, TAny*	aParam)
+	{
+	CLIENT_PRINT(("> MsSlaveClientCallbackFunc() - 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 disabled
+	(void)aRxWords; // Unused if CLIENT_PRINT is disabled
+	DChannelIicClient* channel = (DChannelIicClient*)aParam;
+	CLIENT_PRINT(("MsSlaveClientCallbackFunc() - channel=0x%x\n",channel));
+	if(aTrigger == EAsyncCaptChan)
+		{
+		CLIENT_PRINT(("MsSlaveClientCallbackFunc: 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;
+	    channel->RequestComplete(r);	// Inform user of error
+		return;
+		}
+	else
+		{
+		CLIENT_PRINT(("\nMsSlaveClientCallbackFunc: trigger condition 0x%x is not recognised \n\n",aTrigger));
+		channel->RequestComplete(aReturn);	// Inform user of error
+		}
+	}
+
+void DChannelIicClient::RequestComplete(TInt r)
+	{
+	Kern::RequestComplete(iClient, iStatus, r);
+	}
+
+
+TInt DChannelIicClient::InitSlaveClient()
+	{
+	iNotif = new TIicBusSlaveCallback(MsSlaveClientCallbackFunc, (TAny*)this, iDfcQue, KIicSlaveClientDfcPriority);
+	if(iNotif == NULL)
+		{
+		CLIENT_PRINT(("> DChannelIicClient::InitSlaveClient ERROR unable to allocate space TIicBusSlaveCallback* iNotif \n"));
+		return KErrNoMemory;
+		}
+	return KErrNone;
+	}
+