--- /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;
+ }
+