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