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