os/kernelhwsrv/kerneltest/e32test/iic/iic_psl/iic_client.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // e32test/iic/iic_client.cpp
    15 // Simulated (kernel-side) client of IIC Platform Independent Layer (PIL)
    16 //
    17 #include <kernel/kern_priv.h>		// for DThread, TDfc
    18 #ifdef STANDALONE_CHANNEL
    19 #include <drivers/iic_transaction.h>
    20 #else
    21 #include <drivers/iic.h>
    22 #endif
    23 #include "../t_iic.h"
    24 #ifdef STANDALONE_CHANNEL
    25 #include <drivers/iic_channel.h>
    26 #include "i2c.h"
    27 #include "spi.h"
    28 #endif
    29 
    30 #ifdef LOG_CLIENT
    31 #define CLIENT_PRINT(str) Kern::Printf str
    32 #else
    33 #define CLIENT_PRINT(str)
    34 #endif
    35 
    36 const TInt KIicClientThreadPriority = 24;
    37 const TInt KIicSlaveClientDfcPriority = 3; // 0 to 7, 7 is highest ... for MasterSlave functionality
    38 
    39 const TInt KMaxNumChannels = 3;	// 1 SPI and 2 I2C
    40 
    41 // Define an array of channel that the client is going to create.
    42 // For iic_client, it needs SPI channels for Master tests, and I2c channels for MasterSlave tests.
    43 #ifdef STANDALONE_CHANNEL
    44 
    45 const TUint NUM_CHANNELS_SPI = 4; // Arbitrary
    46 const TInt KChannelTypeArraySpi[NUM_CHANNELS_SPI] = {DIicBusChannel::EMaster, DIicBusChannel::EMaster, DIicBusChannel::ESlave, DIicBusChannel::EMaster};
    47 #define CHANNEL_TYPE_SPI(n) (KChannelTypeArraySpi[n])
    48 const DIicBusChannel::TChannelDuplex KChannelDuplexArraySpi[NUM_CHANNELS_SPI] = {DIicBusChannel::EHalfDuplex, DIicBusChannel::EHalfDuplex, DIicBusChannel::EHalfDuplex, DIicBusChannel::EFullDuplex};
    49 #define CHANNEL_DUPLEX_SPI(n) (KChannelDuplexArraySpi[n])
    50 #define BUS_TYPE_SPI (DIicBusChannel::ESpi)
    51 
    52 #define NUM_CHANNELS_I2C 3
    53 #if defined(MASTER_MODE) && !defined(SLAVE_MODE)
    54 const TInt KChannelTypeArrayI2c[NUM_CHANNELS_I2C] = {DIicBusChannel::EMaster, DIicBusChannel::EMaster, DIicBusChannel::EMaster};
    55 #elif defined(MASTER_MODE) && defined(SLAVE_MODE)
    56 const TInt KChannelTypeArrayI2c[NUM_CHANNELS_I2C] = {DIicBusChannel::EMaster, DIicBusChannel::ESlave, DIicBusChannel::EMasterSlave};
    57 #else
    58 const TInt KChannelTypeArrayI2c[NUM_CHANNELS_I2C] = {DIicBusChannel::ESlave, DIicBusChannel::ESlave, DIicBusChannel::ESlave};
    59 #endif
    60 #define CHANNEL_TYPE_I2C(n) (KChannelTypeArrayI2c[n])
    61 #define CHANNEL_DUPLEX_I2C(n) (DIicBusChannel::EHalfDuplex)
    62 #define BUS_TYPE_I2C (DIicBusChannel::EI2c)
    63 
    64 const TInt8 KSpiChannelNumBase = 1;	// Arbitrary, real platform may consult the Configuration Repository
    65 									// Note limit of 5 bit representation (0-31)
    66 
    67 LOCAL_C TInt8 AssignChanNumSpi()
    68 	{
    69 	static TInt8 iBaseChanNumSpi = KSpiChannelNumBase;
    70 	CLIENT_PRINT(("SPI AssignChanNum - on entry, iBaseCanNum = 0x%x\n",iBaseChanNumSpi));
    71 	return iBaseChanNumSpi++; // Arbitrary, for illustration
    72 	}
    73 
    74 #if defined(MASTER_MODE)
    75 const TInt8 KI2cChannelNumBase = 10;	// Arbitrary, real platform may consult the Configuration Repository
    76 										// Note limit of 5 bit representation (0-31)
    77 
    78 #else
    79 const TInt8 KI2cChannelNumBase = 10 + NUM_CHANNELS;	// For Slave mode, want to provide different response
    80 													// If client assumes Master mode, should be informed not available
    81 #endif
    82 
    83 LOCAL_C TInt8 AssignChanNumI2c()
    84 	{
    85 	static TInt8 iBaseChanNumI2c = KI2cChannelNumBase;
    86 	CLIENT_PRINT(("I2C AssignChanNum - on entry, iBaseChanNum = 0x%x\n",iBaseChanNumI2c));
    87 	return iBaseChanNumI2c++; // Arbitrary, for illustration
    88 	}
    89 
    90 class DIicClientChan : public DBase
    91 	{
    92 public:
    93 	DIicClientChan(DIicBusChannel* aChan, TInt8 aChanNum, TUint8 aChanType):iChan(aChan),iChanNumber(aChanNum),iChanType(aChanType){};
    94 	~DIicClientChan();
    95 	TInt GetChanNum()const {return iChanNumber;};
    96 	TUint8 GetChanType()const {return iChanType;};
    97 	DIicBusChannel* GetChannelPtr(){return iChan;};
    98 	inline DIicClientChan& operator=(DIicClientChan& aChan) {iChanNumber=aChan.iChanNumber; iChanType=aChan.iChanType; iChan=aChan.iChan; return *this;};
    99 	inline TInt operator==(DIicClientChan& aChan) {if((iChanNumber == aChan.iChanNumber)&&(iChanType == aChan.iChanType)&&(iChan == aChan.iChan)) return 1;return 0;};
   100 private:
   101 	TInt iChanNumber;
   102 	TUint8 iChanType;
   103 	DIicBusChannel* iChan;
   104 	};
   105 
   106 DIicClientChan::~DIicClientChan()
   107 	{
   108 	delete iChan;
   109 	}
   110 
   111 #endif /*STANDALONE_CHANNEL*/
   112 
   113 
   114 #ifdef STANDALONE_CHANNEL
   115 _LIT(KLddRootName,"iic_client_ctrless");
   116 #else
   117 _LIT(KLddRootName,"iic_client");
   118 #endif
   119 _LIT(KIicClientThreadName,"IicClientLddThread");
   120 
   121 struct TCapsIicClient
   122     {
   123     TVersion version;
   124     };
   125 
   126 struct TTransStatusPair
   127 	{
   128 	TRequestStatus* iReq;
   129 	TIicBusTransaction* iTrans;
   130 	};
   131 
   132 struct TTransCbPair
   133 	{
   134 	TIicBusTransaction* iTrans;
   135 	TIicBusCallback* iCb;
   136 	};
   137 
   138 struct TExtractInfo
   139     {
   140     TExtractInfo(){iBufPtr = NULL; iTfer = NULL;}
   141     ~TExtractInfo(){delete iBufPtr; delete iTfer;}
   142     TDes8* iBufPtr;
   143     TIicBusTransfer* iTfer;
   144     TIicBusTransaction* iTrans;
   145     };
   146 
   147 struct TTransBufReuseData
   148 	{
   149 	// Convenience for testing, only - retain pointers to private data
   150 	// so that it can be re-used from a callback.
   151 	TIicBusTransaction* iTransaction;
   152 	TIicBusTransfer* iHdTfer;
   153 	TIicBusTransfer* iFdTfer;
   154 	TDes8* iHdr;
   155 	// Pointer to callback object (for cleanup)
   156 	TIicBusCallback* iCallback;
   157 	};
   158 
   159 class DDeviceIicClient : public DLogicalDevice
   160     {
   161     public:
   162     /**
   163      * The constructor
   164      */
   165     DDeviceIicClient();
   166     /**
   167      * The destructor
   168      */
   169     ~DDeviceIicClient();
   170     /**
   171      * Second stage constructor - install the device
   172      */
   173     virtual TInt Install();
   174     /**
   175      * Get the Capabilites of the device
   176      * @param aDes descriptor that will contain the returned capibilites
   177      */
   178     virtual void GetCaps(TDes8 &aDes) const;
   179     /**
   180      * Create a logical channel to the device
   181      */
   182     virtual TInt Create(DLogicalChannelBase*& aChannel);
   183 
   184 	public:
   185     };
   186 
   187 #ifdef STANDALONE_CHANNEL
   188 /*This class is used to test the set and get inline functions
   189  *  of DIicBusChannel Interface.
   190  * */
   191 class TTestIicChannelInterface: public DIicBusChannel
   192 {
   193 public:
   194     TTestIicChannelInterface(TChannelType aChannelType, TBusType aBusType, TChannelDuplex aChanDuplex);
   195     ~TTestIicChannelInterface(){};
   196     TInt DoCreate(){return 0;};
   197     TInt CheckHdr(TDes8* /*aHdr*/){return 0;};
   198     TInt TestInterface();
   199 private:
   200     TBool TestChannelType(DIicBusChannel::TChannelType aType );
   201     TBool TestBusType(DIicBusChannel::TBusType aType );
   202     TBool TestDuplexType(DIicBusChannel::TChannelDuplex aType );
   203 };
   204 
   205 TTestIicChannelInterface::TTestIicChannelInterface(TChannelType aChannelType, TBusType aBusType, TChannelDuplex aChanDuplex)
   206         : DIicBusChannel(aChannelType, aBusType, aChanDuplex)
   207     {}
   208 
   209 TBool TTestIicChannelInterface::TestChannelType(DIicBusChannel::TChannelType aType)
   210     {
   211     CLIENT_PRINT(("Setting channel type 0x%x\n", aType));
   212     SetChannelType(aType);
   213     if(aType != ChannelType())
   214         {
   215         CLIENT_PRINT(("ERROR: Mismatch, looking for channel 0x%x but found 0x%x\n", aType, ChannelType()));
   216         return EFalse;
   217         }
   218     else
   219         {
   220         CLIENT_PRINT(("Looking for channel 0x%x and found 0x%x\n", aType, ChannelType()));
   221         }
   222     return ETrue;
   223     }
   224 
   225 TBool TTestIicChannelInterface::TestBusType(DIicBusChannel::TBusType aType)
   226     {
   227     CLIENT_PRINT(("Setting Bus type 0x%x\n", aType));
   228     SetBusType(aType);
   229     if(aType != BusType())
   230         {
   231         CLIENT_PRINT(("ERROR: Mismatch, looking for Bus 0x%x but found 0x%x\n", aType, BusType()));
   232         return EFalse;
   233         }
   234     else
   235         {
   236         CLIENT_PRINT(("Looking for Bus 0x%x and found 0x%x\n", aType, BusType()));
   237         }    
   238     return ETrue;   
   239     }
   240 
   241 TBool TTestIicChannelInterface::TestDuplexType(DIicBusChannel::TChannelDuplex aType)
   242     {
   243     CLIENT_PRINT(("Setting duplex channel type 0x%x\n", aType));
   244     SetChannelType(aType);
   245     if(aType != ChannelDuplex())
   246         {
   247         CLIENT_PRINT(("ERROR: Mismatch, looking for duplex channel 0x%x but found 0x%x\n", aType, ChannelDuplex()));
   248         return EFalse;
   249         }
   250     else
   251         {
   252         CLIENT_PRINT(("Looking for Duplex Channel 0x%x and found 0x%x\n", aType, ChannelDuplex()));
   253         }    
   254     return ETrue;   
   255     }
   256 
   257 TInt TTestIicChannelInterface::TestInterface()
   258     {
   259     
   260     RArray <DIicBusChannel::TChannelType> chtype;
   261     RArray <DIicBusChannel::TBusType> bustype;
   262     RArray <DIicBusChannel::TChannelDuplex> dutype;
   263 
   264     chtype.Append(DIicBusChannel::EMaster);
   265     chtype.Append(DIicBusChannel::ESlave);
   266     chtype.Append(DIicBusChannel::EMasterSlave);
   267     
   268     bustype.Append(DIicBusChannel::EI2c);
   269     bustype.Append(DIicBusChannel::ESpi);
   270     bustype.Append(DIicBusChannel::EMicrowire);
   271     bustype.Append(DIicBusChannel::ECci);
   272     bustype.Append(DIicBusChannel::ESccb);
   273     
   274     dutype.Append(DIicBusChannel::EHalfDuplex);
   275     dutype.Append(DIicBusChannel::EFullDuplex);
   276       
   277     int result = KErrNone;
   278     int count = chtype.Count();
   279     int i=0;
   280     
   281     CLIENT_PRINT(("\nCheck Master/Slave channel setting\n"));
   282     CLIENT_PRINT(("\nChannel MASK  = 0x%x\n", KChannelTypeMask));    
   283     for(i=0; i< count; ++i)
   284         {
   285         if(!TestChannelType(chtype[i]))
   286             {
   287             result = KErrGeneral;
   288             break;
   289             }
   290         }
   291     CLIENT_PRINT(("\nCheck Master/Slave channel setting from higher bit number to lower, reverse enum.\n"));
   292     for(i=count-1; i >= 0; --i)
   293         {
   294         if(!TestChannelType(chtype[i]))
   295             {
   296             result = KErrGeneral;
   297             break;
   298             }
   299         }
   300     
   301     CLIENT_PRINT(("\nCheck Channel Bus type settings\n"));
   302     CLIENT_PRINT(("\nBus MASK  = 0x%x\n", KBusTypeMask));     
   303     count = bustype.Count();    
   304     for(i=0; i< count; ++i)
   305         {
   306         if(!TestBusType(bustype[i]))
   307             {
   308             result = KErrGeneral;
   309             break;
   310             }
   311         }
   312     CLIENT_PRINT(("\nCheck Channel Bus type settings from higher bit number to lower, reverse enum.\n"));   
   313     for(i = count-1; i >= 0; --i)
   314         {
   315         if(!TestBusType(bustype[i]))
   316             {
   317             result = KErrGeneral;
   318             break;
   319             }
   320         }
   321     CLIENT_PRINT(("\nCheck Channel Duplex settings\n"));
   322     CLIENT_PRINT(("\nDuplex MASK  = 0x%x\n", KChannelDuplexMask));     
   323     count = dutype.Count();
   324     for(i=0; i < count; ++i)
   325         {
   326         if(!TestDuplexType(dutype[i]))
   327             {
   328             result = KErrGeneral;
   329             break;
   330             }
   331         }
   332     CLIENT_PRINT(("\nCheck Channel Duplex setting from higher bit number to lower, reverse enum.\n"));        
   333     for(i = count-1; i >= 0; --i)
   334         {
   335         if(!TestDuplexType(dutype[i]))
   336             {
   337             result = KErrGeneral;
   338             break;
   339             }
   340         }
   341     chtype.Close();
   342     dutype.Close();
   343     bustype.Close();
   344     return result;
   345     }
   346 #endif //STANDALONE_CHANNEL
   347 
   348 class DChannelIicClient : public DLogicalChannel
   349     {
   350     public:
   351     DChannelIicClient();
   352     ~DChannelIicClient();
   353 
   354 	TInt CleanupExtractTrans(TIicBusTransaction *aTrans);
   355 
   356 	TInt InitIicClient();
   357 
   358     virtual TInt DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer);
   359 
   360     protected:
   361     virtual void HandleMsg(TMessageBase* aMsg);	// Note: this is a pure virtual in DLogicalChannel
   362 
   363     void DoCancel(TInt aMask);	// Name for convenience!
   364 	TInt DoControl(TInt aId, TAny* a1, TAny* a2); // Name for convenience!
   365     TInt DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2); // Name for convenience!
   366 
   367 	void TestTransModification(TIicBusTransaction* aTransaction, // public to be accessed by callback
   368 							  TIicBusTransfer* aHdTfer,
   369 							  TIicBusTransfer* aFdTfer,
   370 							  TDes8* aHdr);
   371 #ifdef STANDALONE_CHANNEL
   372     public:
   373     static TInt OrderEntries(const DIicClientChan& aMatch, const DIicClientChan& aEntry);
   374 #endif
   375 	private:
   376 	TInt ExtractTransData(TUsideTracnDesc* aUsideTrancnDesc, TIicBusTransaction*& aTrans);
   377 	TInt CreateTransferListHalfDuplex(
   378 				TIicBusTransfer::TReqType aNodeDir1, TInt aNodeLength1,
   379 				TIicBusTransfer::TReqType aNodeDir2, TInt aNodeLength2,
   380 				TIicBusTransfer::TReqType aNodeDir3, TInt aNodeLength3);
   381 	TInt CreateTransferListFullDuplex(
   382 				TIicBusTransfer::TReqType aNodeDir1, TInt aNodeLength1,
   383 				TIicBusTransfer::TReqType aNodeDir2, TInt aNodeLength2,
   384 				TIicBusTransfer::TReqType aNodeDir3, TInt aNodeLength3);
   385 
   386 
   387 	TInt DeleteFullDuplexTest(TIicBusTransaction *aTrans);
   388 
   389 	TInt DoCreateFullDuplexTransTest(TInt aTestType);
   390 
   391 	TInt DoPriorityTest(TInt aBusId);
   392 	TInt ConstructTransactionOne(TIicBusTransaction*& aTrans);
   393 	void CleanupTransactionOne(TIicBusTransaction*& aTrans);
   394 
   395 
   396 	TInt InsertPairs(TTransStatusPair* aPair, TTransCbPair* aCbPair);
   397 
   398 	TInt CreateDefaultSpiBuf(TConfigSpiBufV01*& aBuf);
   399 
   400 	//Add new functions for controller-less mode
   401 	TInt QueueTransaction(TInt aBusId, TIicBusTransaction* aTransaction, TIicBusCallback *aCallback=NULL);
   402 	TInt CancelTransaction(TInt aBusId, TIicBusTransaction* aTransaction);
   403 	TInt StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2);
   404 	TInt CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch=NULL);
   405 	TInt ReleaseChannel(TInt aChannelId);
   406 	public:
   407 	inline void Lock() {Kern::MutexWait(*iArrayMutex);}
   408 	inline void Unlock() {Kern::MutexSignal(*iArrayMutex);}
   409 	inline void GetWriteAccess() {Kern::SemaphoreWait(*iChanArrWrtSem);}	// aNTicks not specified = wait forever
   410 	inline void FreeWriteAccess() {Kern::SemaphoreSignal(*iChanArrWrtSem);}
   411 
   412 	void CleanupTransaction(TIicBusTransaction*& aTrans); // public for access by callback
   413 
   414 	static TIicBusTransaction* MultiTranscCallbackFunc(TIicBusTransaction* aTrans, TAny* aParam);
   415 
   416 	static void TransModifCallback(TIicBusTransaction* aTrans, TInt aBusId, TInt aResult, TAny* aParam);
   417 
   418 	private:
   419 	TDynamicDfcQue* iDfcQue;
   420 
   421 	DMutex* iArrayMutex;		// used to protect array of channels
   422 	DSemaphore* iChanArrWrtSem;	// used to synchronise write access to iChannelArray
   423 
   424 	// Used for Transaction One
   425 	HBuf8* buf1;
   426 	HBuf8* buf2;
   427 	HBuf8* buf3;
   428 	HBuf8* buf4;
   429 	HBuf8* buf5;
   430 	HBuf8* buf6;
   431 	TIicBusTransfer* tfer1;
   432 	TIicBusTransfer* tfer2;
   433 	TIicBusTransfer* tfer3;
   434 	TIicBusTransfer* tfer4;
   435 	TIicBusTransfer* tfer5;
   436 	TIicBusTransfer* tfer6;
   437 	TIicBusTransfer* tfer7;
   438 	HBuf8* header;
   439 	HBuf8* header2;
   440 	HBuf8* header3;
   441 	HBuf8* header4;
   442 	HBuf8* header5;
   443 	HBuf8* headerBlock;
   444 	TConfigSpiBufV01* spiHeader;
   445 
   446 
   447 	static TIicBusTransaction* iMultiTransac;
   448 
   449 	// Used for simple transactions
   450 	TIicBusTransaction* iTrans;
   451 	TConfigSpiBufV01* iSpiBuf;
   452 	TConfigI2cBufV01* iI2cBuf;
   453 	TIicBusTransfer* iTfer;
   454 	TIicBusTransactionPreamble* iTransPreamble;
   455 	TIicBusTransfer* iFdTfer;
   456 
   457 	public:
   458 	DThread* iClient;
   459 	RPointerArray<TTransStatusPair> iTransStatArrayByTrans;
   460 	RPointerArray<TTransStatusPair> iTransStatArrayByStatus;
   461 	RPointerArray<TTransCbPair> iTransCbArrayByTrans;
   462 	RPointerArray<TExtractInfo> iExtractInfoArray;
   463 
   464 	// Support for Preamble testing
   465 	TRequestStatus* iPreambleStatus;
   466 	TRequestStatus* iMultiTranscStatus;
   467 
   468 	// Support for buffer re-use testing
   469 	TTransBufReuseData iTransBufReuseData;
   470 
   471 	// Support for MasterSlave processing
   472 	private:
   473 	TInt InitSlaveClient();
   474 
   475 	private:
   476 	HBuf8* iConfigHdr;
   477 	TRequestStatus* iStatus;
   478 
   479 	public:
   480 	void RequestComplete(TInt r);
   481 
   482 	public:
   483 	TIicBusSlaveCallback* iNotif;		// public to be accessible by callback
   484 	TInt iChannelId;				// public to be accessible by callback
   485 	TInt* iClientChanId;
   486 
   487 #ifdef STANDALONE_CHANNEL
   488 	//Used to store the captured channel
   489 	struct TCapturedChannel
   490         {
   491         DIicClientChan* iChanPtr;
   492         TInt iChannelId;
   493         };
   494 	TCapturedChannel iCapturedChannel;
   495 #endif
   496 	};
   497 
   498 DDeviceIicClient::DDeviceIicClient()
   499 // Constructor
   500     {
   501 	CLIENT_PRINT(("> DDeviceIicClient::DDeviceIicClient()"));
   502     __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DDeviceIicClient::DDeviceIicClient()"));
   503     iParseMask=0;		// No info, no PDD, no Units
   504     iUnitsMask=0;
   505     iVersion=TVersion(KIicClientMajorVersionNumber,
   506 		      KIicClientMinorVersionNumber,
   507 		      KIicClientBuildVersionNumber);
   508     }
   509 #ifdef STANDALONE_CHANNEL
   510 //  auxiliary function for ordering entries in the array of channels
   511 TInt DChannelIicClient::OrderEntries(const DIicClientChan& aMatch, const DIicClientChan& aEntry)
   512 	{
   513 	TUint8 l=(TUint8)aMatch.GetChanNum();
   514 	TUint8 r=(TUint8)aEntry.GetChanNum();
   515 	if(l<r)
   516 		return -1;
   517 	else if(l>r)
   518 		return 1;
   519 	else
   520 		return 0;
   521 	}
   522 // global ordering object to be passed to RPointerArray InsertInOrderXXX and FindInOrder
   523 TLinearOrder<DIicClientChan> EntryOrder(DChannelIicClient::OrderEntries);
   524 
   525 // Store all the channels created by the client
   526 RPointerArray<DIicClientChan> ChannelArray;
   527 #endif /*STANDALONE_CHANNEL*/
   528 
   529 DDeviceIicClient::~DDeviceIicClient()
   530     {
   531 	CLIENT_PRINT(("> DDeviceIicClient::~DDeviceIicClient()"));
   532     __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DDeviceIicClient::~DDeviceIicClient()"));
   533 #ifdef STANDALONE_CHANNEL
   534     //For Standalone Channel, the client is responsible for channel destroy
   535     ChannelArray.ResetAndDestroy();
   536 #endif
   537 	}
   538 
   539 TInt DDeviceIicClient::Install()
   540 // Install the device driver.
   541     {
   542 	CLIENT_PRINT(("> DDeviceIicClient::Install()"));
   543     __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DDeviceIicClient::Install()"));
   544     return(SetName(&KLddRootName));
   545     }
   546 
   547 // Auxiliary functions for ordering entries in the array of TTransStatusPair pointers
   548 // The first is to enable searching by Transaction (used by the callback)
   549 // The second is to enable searching by the TRequestStatus (used by cancel calls)
   550 TInt OrderEntriesByTrans(const TTransStatusPair& aMatch, const TTransStatusPair& aEntry)
   551 	{
   552 	TUint l=(TUint)(aMatch.iTrans);
   553 	TUint r=(TUint)(aEntry.iTrans);
   554 	if(l>r)
   555 		return -1;
   556 	else if(l<r)
   557 		return 1;
   558 	else
   559 		return 0;
   560 	}
   561 TLinearOrder<TTransStatusPair> TransStatusOrderByTrans(OrderEntriesByTrans);
   562 
   563 TInt OrderEntriesByStatus(const TTransStatusPair& aMatch, const TTransStatusPair& aEntry)
   564 	{
   565 	TUint l=(TUint)(aMatch.iReq);
   566 	TUint r=(TUint)(aEntry.iReq);
   567 	if(l>r)
   568 		return -1;
   569 	else if(l<r)
   570 		return 1;
   571 	else
   572 		return 0;
   573 	}
   574 TLinearOrder<TTransStatusPair> TransStatusOrderByStatus(OrderEntriesByStatus);
   575 
   576 // Auxilliary function to track callback objects assigned to asynchronous transactions
   577 TInt OrderCbEntriesByTrans(const TTransCbPair& aMatch, const TTransCbPair& aEntry)
   578 	{
   579 	TUint l=(TUint)(aMatch.iTrans);
   580 	TUint r=(TUint)(aEntry.iTrans);
   581 	if(l>r)
   582 		return -1;
   583 	else if(l<r)
   584 		return 1;
   585 	else
   586 		return 0;
   587 	}
   588 TLinearOrder<TTransCbPair> TransCbOrderByTrans(OrderCbEntriesByTrans);
   589 
   590 TInt OrderExtractInfoByTrans(const TExtractInfo& aMatch, const TExtractInfo& aEntry)
   591     {
   592     TUint l=(TUint)(aMatch.iTrans);
   593     TUint r=(TUint)(aEntry.iTrans);
   594     if(l>r)
   595         return -1;
   596     else if(l<r)
   597         return 1;
   598     else
   599         return 0;
   600     }
   601 TLinearOrder<TExtractInfo> ExtractInfoOrderByTrans(OrderExtractInfoByTrans);
   602 
   603 
   604 _LIT(KLitArrayMutexName,"IIC_CLIENT_ARRAY_MUTEX");
   605 _LIT(KLitArraySemName,"IIC_CLIENT_ARRAY_SEM");
   606 #define IIC_CLIENT_MUTEX_ORDER KMutexOrdGeneral4	// Semi-arbitrary - middle of general purpose range, allow higher and lower priorities
   607 
   608 TInt DChannelIicClient::InitIicClient()
   609 	{
   610 	TInt r = Kern::MutexCreate(iArrayMutex,KLitArrayMutexName,IIC_CLIENT_MUTEX_ORDER);
   611 	if(r!=KErrNone)
   612 		return r;
   613 	r = Kern::SemaphoreCreate(iChanArrWrtSem,KLitArraySemName,1); // Initial count of one allows first wait to be non-blocking
   614 	if(r!=KErrNone)
   615 		iArrayMutex->Close(NULL);
   616 
   617 	return r;
   618 	}
   619 
   620 TInt DChannelIicClient::InsertPairs(TTransStatusPair* aPair, TTransCbPair* aCbPair)
   621 	{
   622 	CLIENT_PRINT(("DChannelIicClient::InsertPairs invoked with aPair=0x%x, aPair->iReq=0x%x, aPair-iTrans=0x%x\n",aPair,aPair->iReq,aPair->iTrans ));
   623 	CLIENT_PRINT(("DChannelIicClient::InsertPairs ... and aCbPair=0x%x, aCbPair->iCb=0x%x, aCbPair-iTrans=0x%x\n",aCbPair,aCbPair->iCb,aCbPair->iTrans ));
   624 	TInt r = KErrNone;
   625 
   626 	GetWriteAccess();
   627 	Lock();
   628 
   629 	if((r = iTransStatArrayByTrans.InsertInOrder(aPair,TransStatusOrderByTrans)) == KErrNone)
   630 		{
   631 		if((r = iTransStatArrayByStatus.InsertInOrder(aPair,TransStatusOrderByStatus)) == KErrNone)
   632 			{
   633 			if((r = iTransCbArrayByTrans.InsertInOrder(aCbPair,TransCbOrderByTrans))!=KErrNone)
   634 				{
   635 				CLIENT_PRINT(("DChannelIicClient::InsertPairs, aCbPair=0x%x InsertInOrder(status) returned %d\n",aCbPair,r));
   636 				}
   637 			}
   638 		else
   639 			{
   640 			CLIENT_PRINT(("DChannelIicClient::InsertPairs, aPair=0x%x InsertInOrder(status) returned %d\n",aPair,r));
   641 			}
   642 		}
   643 	else
   644 		{
   645 		CLIENT_PRINT(("DChannelIicClient::InsertPairs, aPair=0x%x InsertInOrder(trans) returned %d\n",aPair,r));
   646 		}
   647 	FreeWriteAccess();
   648 	Unlock();
   649 	return r;
   650 	}
   651 
   652 //dummy call back func is provided for asyn call in priority test
   653 static void DummyCallbackFunc(TIicBusTransaction* /*aTrans*/, TInt /*aBusId*/, TInt /*aResult*/, TAny* /*aParam*/)
   654 	{
   655 	//do nothing
   656 	}
   657 
   658 static void AsyncCallbackFunc(TIicBusTransaction* aTrans, TInt aBusId, TInt aResult, TAny* aParam)
   659 	{
   660 	(void)aBusId; // aBusId is not used if CLIENT_PRINT is disabled
   661 	CLIENT_PRINT(("> AsyncCallbackFunc() - aTrans=0x%x, aBusId=0x%x, aResult=%d, aParam=0x%x\n",aTrans,aBusId,aResult,aParam));
   662 	DChannelIicClient* channel = (DChannelIicClient*)aParam;
   663 	CLIENT_PRINT(("AsyncCallbackFunc() - channel=0x%x\n",channel));
   664 
   665 	// Use the channel to get the user-side client's TRequestStatus and complete it with aResult
   666 	TTransStatusPair* searchPair = new TTransStatusPair();
   667 	searchPair->iTrans = aTrans;
   668 	channel->GetWriteAccess();
   669 	channel->Lock();
   670 	TInt pairIndex = (channel->iTransStatArrayByTrans).FindInOrder(searchPair,TransStatusOrderByTrans);
   671 	delete searchPair;
   672 	if(pairIndex<0)
   673 		{
   674 		CLIENT_PRINT(("AsyncCallbackFunc() - (trans) FindInOrder returned %d (aTrans=0x%x)\n",pairIndex,aTrans));
   675 		return;
   676 		}
   677 	TTransStatusPair* pairPtr = (channel->iTransStatArrayByTrans)[pairIndex];
   678 	TRequestStatus* status = pairPtr->iReq;
   679 
   680 	// Now remove the TTransStatusPair objects in iTransStatArrayByTrans, iTransStatArrayByStatus
   681 	(channel->iTransStatArrayByTrans).Remove(pairIndex);
   682 	pairIndex = (channel->iTransStatArrayByStatus).FindInOrder(pairPtr,TransStatusOrderByStatus);
   683 	if(pairIndex<0)
   684 		{
   685 		CLIENT_PRINT(("AsyncCallbackFunc() - (status) FindInOrder returned %d (status=0x%x)\n",pairIndex,status));
   686 		return;
   687 		}
   688 	(channel->iTransStatArrayByStatus).Remove(pairIndex);
   689 
   690 	// Now remove the TTransCbPair object in iTransCbArrayByTrans
   691 	TTransCbPair* SearchCbPair = new TTransCbPair();
   692 	SearchCbPair->iTrans = aTrans;
   693 	pairIndex = (channel->iTransCbArrayByTrans).FindInOrder(SearchCbPair,TransCbOrderByTrans);
   694 	delete SearchCbPair;
   695 	if(pairIndex<0)
   696 		{
   697 		CLIENT_PRINT(("AsyncCallbackFunc() - (cb) FindInOrder returned %d (aTrans=0x%x)\n",pairIndex,aTrans));
   698 		return;
   699 		}
   700 	TTransCbPair* cbPair = (channel->iTransCbArrayByTrans)[pairIndex];
   701 	(channel->iTransCbArrayByTrans).Remove(pairIndex);
   702 	delete cbPair->iCb;
   703 	delete cbPair;
   704 	channel->FreeWriteAccess();
   705 	channel->Unlock();
   706 	Kern::RequestComplete(channel->iClient, status, aResult);
   707 	// We should call CleanupExtractTrans() to delete all the objects created in ExtractTransData()
   708 	channel->CleanupExtractTrans(pairPtr->iTrans);
   709 	// The object referred to be pairPtr is finished with and can be deleted
   710 	channel->CleanupTransaction(pairPtr->iTrans);
   711 	delete pairPtr;
   712 	}
   713 
   714 
   715 void DDeviceIicClient::GetCaps(TDes8& aDes) const
   716 // Return the IicClient capabilities.
   717     {
   718 	CLIENT_PRINT(("> DDeviceIicClient::GetCaps(TDes8& aDes) const"));
   719     TPckgBuf<TCapsIicClient> b;
   720     b().version=TVersion(KIicClientMajorVersionNumber,
   721 			 KIicClientMinorVersionNumber,
   722 			 KIicClientBuildVersionNumber);
   723     Kern::InfoCopy(aDes,b);
   724     }
   725 
   726 
   727 TInt DDeviceIicClient::Create(DLogicalChannelBase*& aChannel)
   728 // Create a channel on the device.
   729     {
   730 	CLIENT_PRINT(("> DDeviceIicClient::Create(DLogicalChannelBase*& aChannel)"));
   731 	if(iOpenChannels>=KMaxNumChannels)
   732 		return KErrOverflow;
   733     aChannel=new DChannelIicClient;
   734     return aChannel?KErrNone:KErrNoMemory;
   735     }
   736 
   737 #ifdef STANDALONE_CHANNEL
   738 
   739 TInt GetChanPtr(const TInt aBusId, TInt &aIndex, DIicClientChan*& aChan)
   740 	{
   741     __KTRACE_OPT(KIIC, 	Kern::Printf("GetChanPtr, aBusId=0x%x\n",aBusId));
   742 	TInt32 chanId;
   743 	chanId = GET_CHAN_NUM(aBusId);
   744 	__KTRACE_OPT(KIIC, 	Kern::Printf("GetChanPtr, chanId=0x%x\n",chanId));
   745 	DIicClientChan chanEntry(NULL,(TInt8)chanId, DIicBusChannel::EMasterSlave);
   746 	TInt r = KErrNotFound;
   747 	aIndex = ChannelArray.FindInOrder(&chanEntry, EntryOrder);
   748 	if(aIndex >= 0)
   749 		{
   750 		aChan = ChannelArray[aIndex];
   751 		r = KErrNone;
   752 		}
   753 
   754 	__KTRACE_OPT(KIIC, 	Kern::Printf("GetChanPtr, chanPtr=0x%x, index=%d\n",aChan,aIndex));
   755 	return r;
   756 	}
   757 #endif
   758 
   759 DECLARE_STANDARD_LDD()
   760 	{
   761 	//If in STANDALONE_CHANNEL mode, the client creates a list of channels
   762 #ifdef STANDALONE_CHANNEL
   763 	DIicClientChan* aClientChan;
   764 	TInt r = KErrNone;
   765 	DIicBusChannel *chan = NULL, *chanM = NULL, *chanS = NULL;
   766 	TInt i;
   767 	for(i=0; i<NUM_CHANNELS_SPI; i++)
   768 		{
   769 		CLIENT_PRINT(("\n"));
   770 #if defined(MASTER_MODE)
   771 		if(CHANNEL_TYPE_SPI(i) == (DIicBusChannel::EMaster))
   772 			{
   773 			chan=new DSimulatedIicBusChannelMasterSpi(BUS_TYPE_SPI,CHANNEL_DUPLEX_SPI(i));
   774 			if(!chan)
   775 			    {
   776 			    CLIENT_PRINT(("\n\nSpi: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE_SPI(i),i));
   777 				return NULL;
   778 			    }
   779 			CLIENT_PRINT(("SPI chan created at 0x%x\n",chan));
   780 			if(((DSimulatedIicBusChannelMasterSpi*)chan)->Create()!=KErrNone)
   781 			    {
   782 			    delete chan;
   783 				return NULL;
   784 			    }
   785 			aClientChan = new DIicClientChan(chan,AssignChanNumSpi(),DIicBusChannel::EMaster);
   786             if(!aClientChan)
   787                 {
   788                 delete chan;
   789                 return NULL;
   790                 }
   791             r = ChannelArray.InsertInOrder(aClientChan,EntryOrder);
   792             if(r!=KErrNone)
   793                 {
   794                 delete chan;
   795                 delete aClientChan;
   796                 break;
   797                 }
   798 			}
   799 #endif
   800 #if defined(MASTER_MODE) && defined(SLAVE_MODE)
   801 		if(CHANNEL_TYPE_SPI(i) == DIicBusChannel::EMasterSlave)
   802 			{
   803 			//For MasterSlave channel, the client creates a Master channel, a Slave
   804 			//channel and a MasterSlave Channel, then store all of them in ChannelArray.
   805 			chanM=new DSimulatedIicBusChannelMasterSpi(BUS_TYPE_SPI,CHANNEL_DUPLEX_SPI(i));
   806 			if(!chanM)
   807 				return NULL;
   808 
   809 			chanS=new DSimulatedIicBusChannelSlaveSpi(BUS_TYPE_SPI,CHANNEL_DUPLEX_SPI(i));
   810 			if(!chanS)
   811 			    {
   812 			    delete chanM;
   813 				return NULL;
   814 			    }
   815 			chan=new DIicBusChannelMasterSlave(BUS_TYPE_SPI,CHANNEL_DUPLEX_SPI(i),(DSimulatedIicBusChannelMasterSpi*)chanM,(DSimulatedIicBusChannelSlaveSpi*)chanS); // Generic implementation
   816 			if(!chan)
   817 			    {
   818 			    CLIENT_PRINT(("\n\nSpi: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE_SPI(i),i));
   819 			    delete chanM;
   820 			    delete chanS;
   821 				return NULL;
   822 			    }
   823 			CLIENT_PRINT(("SPI chan created at 0x%x\n",chan));
   824 			if(((DIicBusChannelMasterSlave*)chan)->DoCreate()!=KErrNone)
   825 			    {
   826 			    delete chanM;
   827 			    delete chanS;
   828 			    delete chan;
   829 				return NULL;
   830 			    }
   831 			aClientChan = new DIicClientChan(chan,AssignChanNumSpi(),DIicBusChannel::EMasterSlave);
   832 			if(!aClientChan)
   833 			    {
   834 			    delete chanM;
   835 			    delete chanS;
   836 			    delete chan;
   837 			    return NULL;
   838 			    }
   839             r = ChannelArray.InsertInOrder(aClientChan,EntryOrder);
   840             if(r!=KErrNone)
   841                 {
   842                 delete chanM;
   843                 delete chanS;
   844                 delete chan;
   845                 delete aClientChan;
   846                 break;
   847                 }
   848 			}
   849 #endif
   850 #if defined(SLAVE_MODE)
   851 		if(CHANNEL_TYPE_SPI(i) == (DIicBusChannel::ESlave))
   852 			{
   853 			chan=new DSimulatedIicBusChannelSlaveSpi(BUS_TYPE_SPI,CHANNEL_DUPLEX_SPI(i));
   854 			if(!chan)
   855 			    {
   856 			    CLIENT_PRINT(("\n\nSpi: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE_SPI(i),i));
   857 				return NULL;
   858 			    }
   859 			CLIENT_PRINT(("SPI chan created at 0x%x\n",chan));
   860 			if(((DSimulatedIicBusChannelSlaveSpi*)chan)->Create()!=KErrNone)
   861 			    {
   862 			    delete chan;
   863 				return NULL;
   864 			    }
   865 			aClientChan = new DIicClientChan(chan,AssignChanNumSpi(),DIicBusChannel::ESlave);
   866             if(!aClientChan)
   867                 {
   868                 delete chan;
   869                 return NULL;
   870                 }
   871             r = ChannelArray.InsertInOrder(aClientChan,EntryOrder);
   872             if(r!=KErrNone)
   873                 {
   874                 delete chan;
   875                 delete aClientChan;
   876                 break;
   877                 }
   878 			}
   879 #endif
   880 #if !defined(MASTER_MODE) && !defined(SLAVE_MODE)
   881 #error I2C mode not defined as Master, Slave nor Master-Slave
   882 #endif
   883 		}
   884 
   885 	for(i=0; i<NUM_CHANNELS_I2C; i++)
   886 			{
   887 			CLIENT_PRINT(("\n"));
   888 	#if defined(MASTER_MODE)
   889 			if(CHANNEL_TYPE_I2C(i) == (DIicBusChannel::EMaster))
   890 				{
   891 				chan=new DSimulatedIicBusChannelMasterI2c(BUS_TYPE_I2C,CHANNEL_DUPLEX_I2C(i));
   892 				if(!chan)
   893 				    {
   894 				    CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE_I2C(i),i));
   895 					return NULL;
   896 				    }
   897 				CLIENT_PRINT(("I2C chan created at 0x%x\n",chan));
   898 				if(((DSimulatedIicBusChannelMasterI2c*)chan)->Create()!=KErrNone)
   899 				    {
   900 				    delete chan;
   901 					return NULL;
   902 					}
   903 				aClientChan = new DIicClientChan(chan,AssignChanNumI2c(),DIicBusChannel::EMaster);
   904 				if(!aClientChan)
   905 				    {
   906 				    delete chan;
   907 				    return NULL;
   908 				    }
   909                 r = ChannelArray.InsertInOrder(aClientChan,EntryOrder);
   910                 if(r!=KErrNone)
   911                     {
   912                     delete chan;
   913                     delete aClientChan;
   914                     break;
   915                     }
   916 				}
   917 	#endif
   918 	#if defined(MASTER_MODE) && defined(SLAVE_MODE)
   919 			if(CHANNEL_TYPE_I2C(i) == DIicBusChannel::EMasterSlave)
   920 				{
   921 				chanM=new DSimulatedIicBusChannelMasterI2c(BUS_TYPE_I2C,CHANNEL_DUPLEX_I2C(i));
   922 				if(!chanM)
   923 					return NULL;
   924 
   925 				chanS=new DSimulatedIicBusChannelSlaveI2c(BUS_TYPE_I2C,CHANNEL_DUPLEX_I2C(i));
   926 				if(!chanS)
   927 				    {
   928 				    delete chanM;
   929 					return NULL;
   930 				    }
   931 				//The client doesn't create the Master and Slave channels, as they should be created
   932 				//in MasterSlave channel's DoCreate().
   933 				chan=new DSimulatedIicBusChannelMasterSlaveI2c(BUS_TYPE_I2C,CHANNEL_DUPLEX_I2C(i),(DSimulatedIicBusChannelMasterI2c*)chanM,(DSimulatedIicBusChannelSlaveI2c*)chanS); // Generic implementation
   934 				if(!chan)
   935 				    {
   936 				    CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE_I2C(i),i));
   937 				    delete chanM;
   938 				    delete chanS;
   939 					return NULL;
   940 				    }
   941 				CLIENT_PRINT(("I2C chan created at 0x%x\n",chan));
   942 				if(((DIicBusChannelMasterSlave*)chan)->DoCreate()!=KErrNone)
   943 				    {
   944 				    delete chanM;
   945 				    delete chanS;
   946 				    delete chan;
   947 					return NULL;
   948 				    }
   949 			    aClientChan = new DIicClientChan(chan,AssignChanNumI2c(),DIicBusChannel::EMasterSlave);
   950                 if(!aClientChan)
   951                     {
   952                     delete chanM;
   953                     delete chanS;
   954                     delete chan;
   955                     return NULL;
   956                     }
   957                 r = ChannelArray.InsertInOrder(aClientChan,EntryOrder);
   958                 if(r!=KErrNone)
   959                     {
   960                     delete chanM;
   961                     delete chanS;
   962                     delete chan;
   963                     delete aClientChan;
   964                     break;
   965                     }
   966 				}
   967 	#endif
   968 	#if defined(SLAVE_MODE)
   969 			if(CHANNEL_TYPE_I2C(i) == (DIicBusChannel::ESlave))
   970 				{
   971 				chan=new DSimulatedIicBusChannelSlaveI2c(BUS_TYPE_I2C,CHANNEL_DUPLEX_I2C(i));
   972 				if(!chan)
   973 				    {
   974 				    CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE_I2C(i),i));
   975 					return NULL;
   976 				    }
   977 				CLIENT_PRINT(("I2C chan created at 0x%x\n",chan));
   978 				if(((DSimulatedIicBusChannelSlaveI2c*)chan)->Create()!=KErrNone)
   979 				    {
   980 				    delete chan;
   981 					return NULL;
   982 				    }
   983 			    aClientChan = new DIicClientChan(chan,AssignChanNumI2c(),DIicBusChannel::ESlave);
   984                 if(!aClientChan)
   985                     {
   986                     delete chan;
   987                     return NULL;
   988                     }
   989                 r = ChannelArray.InsertInOrder(aClientChan,EntryOrder);
   990                 if(r!=KErrNone)
   991                     {
   992                     delete chan;
   993                     delete aClientChan;
   994                     break;
   995                     }
   996 				}
   997 	#endif
   998 	#if !defined(MASTER_MODE) && !defined(SLAVE_MODE)
   999 	#error I2C mode not defined as Master, Slave nor Master-Slave
  1000 	#endif
  1001 			}
  1002 
  1003 #endif
  1004 	return new DDeviceIicClient;
  1005 	}
  1006 
  1007 
  1008 
  1009 DChannelIicClient::DChannelIicClient()
  1010 // Constructor
  1011     {
  1012 	CLIENT_PRINT(("> DChannelIicClient::DChannelIicClient()"));
  1013     iClient=&Kern::CurrentThread();
  1014 	// Increase the DThread's ref count so that it does not close without us
  1015 	iClient->Open();
  1016     }
  1017 
  1018 DChannelIicClient::~DChannelIicClient()
  1019 // Destructor
  1020     {
  1021 	CLIENT_PRINT(("> DChannelIicClient::~DChannelIicClient()"));
  1022     __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DChannelIicClient::~DChannelIicClient()"));
  1023     delete iNotif;
  1024     iArrayMutex->Close(NULL);
  1025     iChanArrWrtSem->Close(NULL);
  1026 	iDfcQue->Destroy();
  1027 	// decrement the DThread's reference count
  1028 	Kern::SafeClose((DObject*&)iClient, NULL);
  1029 
  1030     iTransStatArrayByTrans.Reset();
  1031     iTransStatArrayByStatus.Reset();
  1032     iTransCbArrayByTrans.Reset();
  1033 	iExtractInfoArray.Reset();
  1034 	}
  1035 
  1036 
  1037 TInt DChannelIicClient::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
  1038 	{
  1039 	CLIENT_PRINT(("> DChannelIicClient::DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion &aVer)"));
  1040 	TInt r = Kern::DynamicDfcQCreate(iDfcQue,KIicClientThreadPriority,KIicClientThreadName);
  1041 	if(r!=KErrNone)
  1042 		return r;
  1043 	SetDfcQ(iDfcQue);
  1044 	iMsgQ.Receive();
  1045 
  1046 	r = InitIicClient();
  1047 	return r;
  1048 	}
  1049 
  1050 void DChannelIicClient::HandleMsg(TMessageBase* aMsg)
  1051 	{
  1052 	TThreadMessage& m=*(TThreadMessage*)aMsg;
  1053     TInt id=m.iValue;
  1054 
  1055 	CLIENT_PRINT((" >ldd: DChannelIicClient::HandleMsg(TMessageBase* aMsg) id=%d\n", id));
  1056 
  1057 	if (id == (TInt)ECloseMsg)
  1058 		{
  1059 	    iMsgQ.iMessage->Complete(KErrNone,EFalse);
  1060 		return;
  1061 		}
  1062     else if (id == KMaxTInt)
  1063 		{
  1064 		DoCancel(m.Int0());
  1065 		m.Complete(KErrNone,ETrue);
  1066 		return;
  1067 		}
  1068 
  1069     if (id<0)
  1070 		{
  1071 		TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
  1072 		TInt r=DoRequest(~id, pS, m.Ptr1(), m.Ptr2());
  1073 		if (r!=KErrNone)
  1074 			{
  1075 	    	Kern::RequestComplete(iClient, pS, r);
  1076 			}
  1077 		m.Complete(KErrNone,ETrue);
  1078 		}
  1079     else
  1080 		{
  1081 		TInt r=DoControl(id,m.Ptr0(),m.Ptr1());
  1082 		m.Complete(r,ETrue);
  1083 		}
  1084 	}
  1085 
  1086 TInt DChannelIicClient::QueueTransaction(TInt aBusId, TIicBusTransaction* aTransaction, TIicBusCallback *aCallback/*NULL*/)
  1087 	{
  1088 	TInt r = KErrNone;
  1089 #ifndef STANDALONE_CHANNEL
  1090 	if(!aCallback)
  1091 		r = IicBus::QueueTransaction(aBusId, aTransaction);
  1092 	else
  1093 		r = IicBus::QueueTransaction(aBusId, aTransaction, aCallback);
  1094 #else
  1095 	__KTRACE_OPT(KIIC, Kern::Printf("DChannelIicClient::QueueTransaction, aBusId=0x%x,aTransaction=0x%x\n", aBusId, aTransaction));
  1096 	if(!aTransaction)
  1097 		{
  1098 		return KErrArgument;
  1099 		}
  1100 
  1101 	// Get a pointer to the channel
  1102 	TInt dumInt = 0;
  1103 	DIicClientChan* chanPtr = NULL;
  1104 	r = GetChanPtr(aBusId, dumInt, chanPtr);
  1105 	if(r == KErrNone)
  1106 		{
  1107 		if(!chanPtr)
  1108 			{
  1109 			r = KErrArgument;
  1110 			}
  1111 		else
  1112 			{
  1113 			switch(chanPtr->GetChanType())
  1114 				{
  1115 				// QueueTransaction requests are only supported by channels in Master mode.
  1116 				case DIicBusChannel::ESlave:
  1117 					{
  1118 					r = KErrNotSupported;
  1119 					break;
  1120 					}
  1121 				// If the request is supported by the Master channel, send it to the channel for processing in its thread
  1122 				case DIicBusChannel::EMasterSlave:
  1123 					{
  1124 
  1125 					aTransaction->iBusId = aBusId;
  1126 					if(!aCallback)
  1127 					    r = (((DIicBusChannelMasterSlave*) (chanPtr->GetChannelPtr()))->QueueTransaction(aTransaction));					    
  1128 					else
  1129 						r = (((DIicBusChannelMasterSlave*) (chanPtr->GetChannelPtr()))->QueueTransaction(aTransaction, aCallback));
  1130 					break;
  1131 					}
  1132 				case DIicBusChannel::EMaster:
  1133 					{
  1134 					aTransaction->iBusId = aBusId;
  1135 					if(!aCallback)
  1136 						r = (((DIicBusChannelMaster*) (chanPtr->GetChannelPtr()))->QueueTransaction(aTransaction));
  1137 					else
  1138 						r = (((DIicBusChannelMaster*) (chanPtr->GetChannelPtr()))->QueueTransaction(aTransaction, aCallback));
  1139 					break;
  1140 					}
  1141 				default:
  1142 					{
  1143 					r = KErrGeneral;
  1144 					}
  1145 				}
  1146 			}
  1147 		}
  1148 #endif
  1149 	return r;
  1150 	}
  1151 
  1152 TInt DChannelIicClient::CancelTransaction(TInt aBusId, TIicBusTransaction* aTransaction)
  1153 	{
  1154 	TInt r = KErrNone;
  1155 #ifndef STANDALONE_CHANNEL
  1156 	r = IicBus::CancelTransaction(aBusId, aTransaction);
  1157 #else
  1158     __KTRACE_OPT(KIIC, Kern::Printf("DChannelIicClient::CancelTransaction, aBusId=0x%x,aTransaction=0x%x\n", aBusId, aTransaction));
  1159 	if(!aTransaction)
  1160 		{
  1161 		return KErrArgument;
  1162 		}
  1163 
  1164 	// Get the channel
  1165 	TInt dumInt = 0;
  1166 	DIicClientChan* chanPtr = NULL;
  1167 	if(r == KErrNone)
  1168 		{
  1169 		r = GetChanPtr(aBusId, dumInt, chanPtr);
  1170 		if(r == KErrNone)
  1171 			{
  1172 			if(!chanPtr)
  1173 				{
  1174 				r = KErrArgument;
  1175 				}
  1176 			else
  1177 				{
  1178 				// QueueTransaction requests are only supported by channels in Master mode.
  1179 				switch(chanPtr->GetChanType())
  1180 					{
  1181 					case DIicBusChannel::ESlave:
  1182 						{
  1183 						r = KErrNotSupported;
  1184 						break;
  1185 						}
  1186 					case DIicBusChannel::EMasterSlave:
  1187 						{
  1188 						r = (((DIicBusChannelMasterSlave*) (chanPtr->GetChannelPtr()))->CancelTransaction(aTransaction));
  1189 						break;
  1190 						}
  1191 					case DIicBusChannel::EMaster:
  1192 						{
  1193 						r = (((DIicBusChannelMaster*) (chanPtr->GetChannelPtr()))->CancelTransaction(aTransaction));
  1194 						break;
  1195 						}
  1196 					default:
  1197 						{
  1198 						r = KErrGeneral;
  1199 						}
  1200 					}
  1201 				}
  1202 			}
  1203 		}
  1204 #endif
  1205 	return r;
  1206 	}
  1207 
  1208 
  1209 TInt DChannelIicClient::StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2)
  1210 	{
  1211 	TInt r = KErrNone;
  1212 #ifndef STANDALONE_CHANNEL
  1213 	r = IicBus::StaticExtension(aId, aFunction, aParam1, aParam2);
  1214 #else
  1215 	// Get the channel
  1216 	TInt dumInt = 0;
  1217 	DIicClientChan* chanPtr = NULL;
  1218 	if(r == KErrNone)
  1219 		{
  1220 		r = GetChanPtr(aId, dumInt, chanPtr);
  1221 		if(r == KErrNone)
  1222 			{
  1223 			if(!chanPtr)
  1224 				{
  1225 				r = KErrArgument;
  1226 				}
  1227 			else
  1228 				{
  1229 				r = (chanPtr->GetChannelPtr())->StaticExtension(aFunction, aParam1, aParam2);
  1230 				}
  1231 			}
  1232 		}
  1233 #endif
  1234 	return r;
  1235 	}
  1236 
  1237 TInt DChannelIicClient::CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch)
  1238 	{
  1239 	TInt r = KErrNone;
  1240 #ifndef STANDALONE_CHANNEL
  1241 	r = IicBus::CaptureChannel(aBusId, aConfigHdr, aCallback, aChannelId, aAsynch);
  1242 #else
  1243 	// Check that that aCallback!=NULL and aConfigHdr!=NULL - if not, return KErrArgument
  1244 	if(!aCallback || !aConfigHdr)
  1245 		{
  1246 		return KErrArgument;
  1247 		}
  1248 
  1249 	// Get the channel
  1250 	TInt chanIndex = 0;
  1251 	DIicClientChan* chanPtr = NULL;
  1252 	if(r == KErrNone)
  1253 		{
  1254 		r = GetChanPtr(aBusId, chanIndex, chanPtr);
  1255 		if(r == KErrNone)
  1256 			{
  1257 			if(!chanPtr)
  1258 				{
  1259 				r = KErrArgument;
  1260 				}
  1261 			else
  1262 				{
  1263 				switch(chanPtr->GetChanType())
  1264 					{
  1265 					// CaptureChannel requests are only supported by channels in Slave mode.
  1266 					case DIicBusChannel::EMaster:
  1267 						{
  1268 						r = KErrNotSupported;
  1269 						break;
  1270 						}
  1271 					case DIicBusChannel::EMasterSlave:
  1272 						{
  1273 						r = ((DIicBusChannelMasterSlave*) (chanPtr->GetChannelPtr()))->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch);
  1274 						break;
  1275 						}
  1276 					case DIicBusChannel::ESlave:
  1277 						{
  1278 						r = ((DIicBusChannelSlave*)(chanPtr->GetChannelPtr()))->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch);
  1279 						break;
  1280 						}
  1281 					default:
  1282 						{
  1283 						r = KErrArgument;
  1284 						}
  1285 					}
  1286 				// For synchronous capture, if successful then install the channel
  1287 				if(r == KErrNone)
  1288 					{
  1289 					if(!aAsynch)
  1290 						{
  1291 						 iCapturedChannel.iChanPtr = chanPtr;
  1292 						 iCapturedChannel.iChannelId = iChannelId;
  1293 						}
  1294 					else
  1295 						//For asynchronous capture, record chanPtr, if later failed capture,
  1296 						//clean iCapturedChannel in client's callback.
  1297 						iCapturedChannel.iChanPtr = chanPtr;
  1298 					}
  1299 				}
  1300 			}
  1301 		}
  1302 #endif
  1303 	return r;
  1304 	}
  1305 
  1306 TInt DChannelIicClient::ReleaseChannel(TInt aChannelId)
  1307 	{
  1308 	TInt r = KErrNone;
  1309 #ifndef STANDALONE_CHANNEL
  1310 	r = IicBus::ReleaseChannel(aChannelId);
  1311 #else
  1312     __KTRACE_OPT(KIIC, Kern::Printf("DChannelIicClient::ReleaseChannel, channelID = 0x%x \n",aChannelId));
  1313     if(iCapturedChannel.iChannelId != aChannelId)
  1314             return KErrNotFound;
  1315 
  1316     if((iCapturedChannel.iChanPtr)->GetChanType() == DIicBusChannel::EMasterSlave)
  1317         r = ((DIicBusChannelMasterSlave*)((iCapturedChannel.iChanPtr)->GetChannelPtr()))->ReleaseChannel();
  1318     else if((iCapturedChannel.iChanPtr)->GetChanType() == DIicBusChannel::ESlave)
  1319         r = ((DIicBusChannelSlave*)((iCapturedChannel.iChanPtr)->GetChannelPtr()))->ReleaseChannel();
  1320     //After release channel, reset iCapturedChan
  1321     iCapturedChannel.iChanPtr = NULL;
  1322     iCapturedChannel.iChannelId = 0;
  1323 #endif
  1324     return r;
  1325 	}
  1326 
  1327 void DChannelIicClient::DoCancel(TInt aMask)
  1328 	{
  1329 // Cancel an outstanding request.
  1330 	CLIENT_PRINT(("DChannelIicClient::DoCancel invoked with aMask=0x%x\n", aMask));
  1331 
  1332 	// inline void CancelAsyncOperation(TRequestStatus* aStatus, TInt aBusId)	{TInt* parms[2]; parms[0]=(TInt*)aStatus; parms[1]=(TInt*)aBusId;DoCancel((TInt)&parms[0]);}
  1333 	// aMask has the address on TInt* parms[2]
  1334 	// parms[0] = TRequestStatus pointer
  1335 	// parms[1] = Bus Identifier
  1336 	TInt* parms[2];
  1337 	TInt r=Kern::ThreadRawRead(iClient,(TAny*)aMask,&(parms[0]),2*sizeof(TInt*));
  1338 	if(r!=KErrNone)
  1339 		{
  1340 		CLIENT_PRINT(("DChannelIicClient::DoCancel ERROR - Can't read parms[]\n"));
  1341 		return;	// Can't proceed if can't access request parameters
  1342 		}
  1343 	CLIENT_PRINT(("DChannelIicClient::DoCancel - TRequestStatus 0x%x, BusID = 0x%x\n",parms[0],parms[1]));
  1344 
  1345 	TTransStatusPair* searchPair = new TTransStatusPair();
  1346 	TTransCbPair* cbPair = new TTransCbPair();
  1347 	searchPair->iReq = (TRequestStatus*)(parms[0]);
  1348 
  1349 	GetWriteAccess();
  1350 	Lock();
  1351 
  1352 	TInt pairIndexByStatus = iTransStatArrayByStatus.FindInOrder(searchPair,TransStatusOrderByStatus);
  1353 	CLIENT_PRINT(("DChannelIicClient::DoCancel - pairIndexByStatus=0x%x\n",pairIndexByStatus));
  1354 	TInt pairIndexByTrans = KErrNotFound;
  1355 
  1356 	if(pairIndexByStatus<0)
  1357 		{
  1358 		// If the TRequestStatus object is not found then either the value was invalid or
  1359 		// the object may already have been completed.
  1360 		FreeWriteAccess();
  1361 		Unlock();
  1362 		CLIENT_PRINT(("DChannelIicClient::DoCancel() - (status) FindInOrder returned %d (status=0x%x)\n",pairIndexByStatus,parms[0]));
  1363 		}
  1364 	else
  1365 		{
  1366 		// The status-transaction pair exists in the status-index array - so remove it
  1367 		TTransStatusPair* pairPtrStatus = iTransStatArrayByStatus[pairIndexByStatus];
  1368 		iTransStatArrayByStatus.Remove(pairIndexByStatus);
  1369 
  1370 		pairIndexByTrans = iTransStatArrayByTrans.FindInOrder(pairPtrStatus,TransStatusOrderByTrans);
  1371 		CLIENT_PRINT(("DChannelIicClient::DoCancel - pairIndexByTrans=0x%x\n",pairIndexByTrans));
  1372 		if(pairIndexByTrans>=0)
  1373 			{
  1374 			iTransStatArrayByTrans.Remove(pairIndexByTrans);
  1375 			}
  1376 		FreeWriteAccess();
  1377 		Unlock();
  1378 
  1379 		CLIENT_PRINT(("DChannelIicClient::DoCancel pairPtrStatus=0x%x\n", pairPtrStatus));
  1380 
  1381 		// Allow the bus to perform any required processing
  1382 		TIicBusTransaction* trans = pairPtrStatus->iTrans;
  1383 		CLIENT_PRINT(("DChannelIicClient::CancelTransaction - invoking with busId=0x%x, trans=0x%x\n",(TInt)(parms[1]),trans));
  1384 		r = CancelTransaction((TInt)(parms[1]), trans);
  1385 		cbPair->iTrans=trans;
  1386 		TInt cbIndex = iTransCbArrayByTrans.FindInOrder(cbPair,TransCbOrderByTrans);
  1387 		TTransCbPair* theCbPair = iTransCbArrayByTrans[cbIndex];
  1388 		TIicBusCallback* cb= (iTransCbArrayByTrans[cbIndex])->iCb;
  1389 		iTransCbArrayByTrans.Remove(cbIndex);
  1390 		
  1391 		// Complete the TRequestStatus object according to the returned value
  1392 		TRequestStatus* status= (TRequestStatus*)(parms[0]);
  1393 		Kern::RequestComplete(iClient, status, r);
  1394 
  1395 		// Clean up
  1396 		delete cb;
  1397 		delete theCbPair;
  1398 		// We should call CleanupExtractTrans() to delete all the objects we created in ExtractTransData()
  1399 		CleanupExtractTrans(trans);
  1400         CleanupTransaction(trans);  
  1401 		delete pairPtrStatus;
  1402 		}
  1403 
  1404 	delete cbPair;
  1405 	delete searchPair;
  1406 
  1407 	return;
  1408 	}
  1409 
  1410 
  1411 // Function to support preamble testing
  1412 void PreambleCallbackFunc(TIicBusTransaction* /*aTrans*/, TAny* aParam)
  1413 	{
  1414 	CLIENT_PRINT(("IIC Client: PreambleCallbackFunc invoked\n"));
  1415 	// aParam is the address of the client that created the transaction object
  1416 	__ASSERT_ALWAYS(aParam!=NULL,Kern::Fault("PreambleCallbackFunc, client address ==NULL",__LINE__));
  1417 	DChannelIicClient *client = (DChannelIicClient*)aParam;
  1418 	__ASSERT_ALWAYS(client->iClient!=NULL,Kern::Fault("PreambleCallbackFunc, iClient==NULL",__LINE__));
  1419 	__ASSERT_ALWAYS(client->iPreambleStatus!=NULL,Kern::Fault("PreambleCallbackFunc, iPreambleStatus==NULL",__LINE__));
  1420 	Kern::RequestComplete(client->iClient, client->iPreambleStatus, KErrNone);
  1421 	}
  1422 
  1423 TIicBusTransaction* DChannelIicClient::iMultiTransac;
  1424 
  1425 // Function to support multi transc testing
  1426 TIicBusTransaction* DChannelIicClient::MultiTranscCallbackFunc(TIicBusTransaction* /*aTrans*/, TAny* aParam)
  1427 	{
  1428 	CLIENT_PRINT(("IIC Client: MultiTranscCallbackFunc invoked\n"));
  1429 	// aParam is the address of the client that created the transaction object
  1430 	__ASSERT_ALWAYS(aParam!=NULL,Kern::Fault("MultiTranscCallbackFunc, client address ==NULL",__LINE__));
  1431 	DChannelIicClient *client = (DChannelIicClient*)aParam;
  1432 	__ASSERT_ALWAYS(client->iClient!=NULL,Kern::Fault("MultiTranscCallbackFunc, iClient==NULL",__LINE__));
  1433 	__ASSERT_ALWAYS(client->iMultiTranscStatus!=NULL,Kern::Fault("MultiTranscCallbackFunc, iMultiTranscStatus==NULL",__LINE__));
  1434 	Kern::RequestComplete(client->iClient, client->iMultiTranscStatus, KErrNone);
  1435 	return iMultiTransac;
  1436 	}
  1437 
  1438 TInt DChannelIicClient::CleanupExtractTrans(TIicBusTransaction* aTrans)
  1439 	{
  1440 	// Clean up the data created in ExtractTransData()
  1441 	TExtractInfo *extractInfo = new TExtractInfo();
  1442 	extractInfo->iTrans = aTrans;
  1443 	TInt index = iExtractInfoArray.FindInOrder(extractInfo, ExtractInfoOrderByTrans);
  1444 	if(index >= 0)
  1445 	    {
  1446 	    delete iExtractInfoArray[index];
  1447 	    iExtractInfoArray.Remove(index);
  1448 	    }
  1449 	delete extractInfo;
  1450 	return KErrNone;
  1451 	}
  1452 
  1453 TInt DChannelIicClient::ExtractTransData(TUsideTracnDesc* aUsideTrancnDesc, TIicBusTransaction*& aTrans)
  1454 	{
  1455 // Utility function to create a TIicBusTransaction object from the parameters passed by the user-side TUsideTracnDesc object
  1456 
  1457 	TInt r = KErrNone;
  1458 	TUsideTracnDesc usTrans;
  1459 	r=Kern::ThreadRawRead(iClient,aUsideTrancnDesc,&usTrans,sizeof(TUsideTracnDesc));
  1460 	if(r!=KErrNone)
  1461 		{
  1462 		CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't read usTrans\n"));
  1463 		return KErrGeneral;	// Can't proceed if can't access request parameters
  1464 		}
  1465 	// Ensure pointers potentially used for allocation are NULL, to facilitate cleanup
  1466 	iSpiBuf=NULL;
  1467 	iI2cBuf=NULL;
  1468 	iTfer=NULL;
  1469 	iTransPreamble=NULL;
  1470 	iFdTfer=NULL;
  1471 
  1472 	// Get the header (depends on the bus type)
  1473 	TBusType busType = usTrans.iType;
  1474 	TConfigSpiBufV01 *spiBuf = NULL;
  1475 	TConfigI2cBufV01 *i2cBuf = NULL;
  1476 	// extractInfo is used to keep the bufPtr and tfer of the transaction,
  1477 	// and will later be stored in iExtractInfoArray, sorting by transaction.
  1478 	// The extractInfo object will be freed in CleanupExtractTrans.
  1479 	TExtractInfo *extractInfo = new TExtractInfo();
  1480 	TDes8* bufPtr=NULL;
  1481 	if(busType == ESpi)
  1482 		{
  1483 		if((spiBuf = new TConfigSpiBufV01()) == NULL)
  1484 			{
  1485 			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - unable to allocate spiBuf\n"));
  1486 			return KErrNoMemory;
  1487 			}
  1488 		if((r=Kern::ThreadDesRead(iClient, usTrans.iHeader, *spiBuf, 0, KChunkShiftBy0 ))!=KErrNone)
  1489 			{
  1490 			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't read usTrans.iHeader to spiBuf\n"));
  1491 			return KErrGeneral;
  1492 			}
  1493 		bufPtr=(TDes8*)spiBuf;
  1494 		}
  1495 	else if(busType == EI2c)
  1496 		{
  1497 		if((i2cBuf = new TConfigI2cBufV01()) == NULL)
  1498 			{
  1499 			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - unable to allocate i2cBuf\n"));
  1500 			return KErrNoMemory;
  1501 			}
  1502 		if((r=Kern::ThreadDesRead(iClient, usTrans.iHeader, *i2cBuf, 0, KChunkShiftBy0 ))!=KErrNone)
  1503 			{
  1504 			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't read usTrans.iHeader to i2cBuf\n"));
  1505 			return KErrGeneral;
  1506 			}
  1507 		bufPtr=(TDes8*)i2cBuf;
  1508 		}
  1509 	else
  1510 		{
  1511 		CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - unrecognised bus type\n"));
  1512 		return KErrGeneral;
  1513 		}
  1514 	extractInfo->iBufPtr = bufPtr;
  1515 	// Get the half-duplex transfer information
  1516 	TUsideTferDesc* usTferPtr = usTrans.iHalfDuplexTrans;
  1517 	TUsideTferDesc usTfer;
  1518 	r=Kern::ThreadRawRead(iClient,usTferPtr,&usTfer,sizeof(TUsideTferDesc));
  1519 	if(r!=KErrNone)
  1520 		{
  1521 		CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't read half-duplex usTfer\n"));
  1522 		return KErrGeneral;	// Can't proceed if can't access request parameters
  1523 		}
  1524 	// Need to access the descriptor holding the information to be transferred
  1525 	TBuf8 <MAX_TRANS_LENGTH> tferData;
  1526 	r=Kern::ThreadDesRead(iClient,usTfer.iBuffer,tferData,0,KChunkShiftBy0);
  1527 	if(r!=KErrNone)
  1528 		{
  1529 		CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't read half-duplex tferData\n"));
  1530 		return KErrGeneral;	// Can't proceed if can't access request parameters
  1531 		}
  1532 
  1533 	TIicBusTransfer::TReqType type=(usTfer.iType == EMasterWrite)?TIicBusTransfer::EMasterWrite:TIicBusTransfer::EMasterRead;
  1534 	tfer7 = new TIicBusTransfer(type, usTfer.iBufGranularity, &tferData);
  1535 	extractInfo->iTfer = tfer7;
  1536 	// Construct the appropriate transaction object with the half-duplex information
  1537 	TUint8 transFlags = usTrans.iFlags;
  1538 
  1539 	if((transFlags&KTransactionWithPreamble)&&(transFlags&KTransactionWithMultiTransc))
  1540 		{
  1541 		if(usTrans.iPreambleArg == NULL)
  1542 			{
  1543 			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - ExtTrans TRequestStatus==NULL\n"));
  1544 			return KErrArgument;
  1545 			}
  1546 		if(usTrans.iMultiTranscArg == NULL)
  1547 			{
  1548 			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - ExtTrans TRequestStatus==NULL\n"));
  1549 			return KErrArgument;
  1550 			}
  1551 		iPreambleStatus = (TRequestStatus*)(usTrans.iPreambleArg);
  1552 		iMultiTranscStatus = (TRequestStatus*)(usTrans.iMultiTranscArg);
  1553 		TIicBusTransactionPreambleExt* transExt;
  1554 
  1555 		transExt = new TIicBusTransactionPreambleExt(bufPtr, tfer7, (TIicBusPreamble)(&PreambleCallbackFunc), this,
  1556 							(TIicBusMultiTranscCbFn)(&MultiTranscCallbackFunc), this);
  1557 		if(transExt == NULL)
  1558 			{
  1559 			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't create trans\n"));
  1560 			return KErrNoMemory;	// Can't proceed if can't access request parameters
  1561 			}
  1562 		aTrans = transExt;
  1563 
  1564 		}
  1565 	else if(transFlags & KTransactionWithPreamble)
  1566 		{
  1567 		// Preamble required - construct the derived-class transaction object
  1568 		if(usTrans.iPreambleArg == NULL)
  1569 			{
  1570 			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - preamble TRequestStatus==NULL\n"));
  1571 			return KErrArgument;
  1572 			}
  1573 		iPreambleStatus = (TRequestStatus*)(usTrans.iPreambleArg);
  1574 		TIicBusTransactionPreamble* TransPreamble;
  1575 		TransPreamble = new TIicBusTransactionPreamble(bufPtr, tfer7, (TIicBusPreamble)(&PreambleCallbackFunc), this);
  1576 		if(TransPreamble == NULL)
  1577 			{
  1578 			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't create trans\n"));
  1579 			return KErrNoMemory;	// Can't proceed if can't access request parameters
  1580 			}
  1581 		aTrans = TransPreamble;
  1582 		}
  1583 	else if(transFlags & KTransactionWithMultiTransc)
  1584 		{
  1585 		// Preamble required - construct the derived-class transaction object
  1586 		if(usTrans.iMultiTranscArg == NULL)
  1587 			{
  1588 			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Multi Transc TRequestStatus==NULL\n"));
  1589 			return KErrArgument;
  1590 			}
  1591 		iMultiTranscStatus = (TRequestStatus*)(usTrans.iMultiTranscArg);
  1592 		TIicBusTransactionMultiTransc* transMultiTransc;
  1593 		transMultiTransc = new TIicBusTransactionMultiTransc(bufPtr, tfer7, (TIicBusMultiTranscCbFn)(&MultiTranscCallbackFunc), this);
  1594 		if(transMultiTransc == NULL)
  1595 			{
  1596 			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't create trans\n"));
  1597 			return KErrNoMemory;	// Can't proceed if can't access request parameters
  1598 			}
  1599 		aTrans = transMultiTransc;
  1600 		}
  1601 	else
  1602 		{
  1603 		// Preamble not required
  1604 		aTrans = new TIicBusTransaction(bufPtr, tfer7);
  1605 		if(aTrans == NULL)
  1606 			{
  1607 			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't create trans\n"));
  1608 			return KErrNoMemory;	// Can't proceed if can't access request parameters
  1609 			}
  1610 		}
  1611 
  1612 	// If full duplex transaction is required get that information, too
  1613 	usTferPtr = usTrans.iFullDuplexTrans;
  1614 	if(usTferPtr!=NULL)
  1615 		{
  1616 		r=Kern::ThreadRawRead(iClient,usTferPtr,&usTfer,sizeof(TUsideTferDesc));
  1617 		if(r!=KErrNone)
  1618 			{
  1619 			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't read full-duplex usTfer\n"));
  1620 			return KErrGeneral;	// Can't proceed if can't access request parameters
  1621 			}
  1622 		// Need to access the descriptor holding the information to be transferred
  1623 		TBuf8 <MAX_TRANS_LENGTH> fdTferData;
  1624 		r=Kern::ThreadDesRead(iClient,usTfer.iBuffer,fdTferData,0,KChunkShiftBy0);
  1625 		if(r!=KErrNone)
  1626 			{
  1627 			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't read full-duplex tferData\n"));
  1628 			return KErrGeneral;	// Can't proceed if can't access request parameters
  1629 			}
  1630 
  1631 		type=(usTfer.iType == EMasterWrite)?TIicBusTransfer::EMasterWrite:TIicBusTransfer::EMasterRead;
  1632 		r=aTrans->SetFullDuplexTrans(iFdTfer);
  1633 		if(r!=KErrNone)
  1634 			{
  1635 			CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - SetFullDuplexTrans returned %d\n",r));
  1636 			return r;
  1637 			}
  1638 		}
  1639 	extractInfo->iTrans = aTrans;
  1640 	iExtractInfoArray.InsertInOrder(extractInfo, ExtractInfoOrderByTrans);
  1641 	return r;
  1642 	}
  1643 
  1644 #define KMaxTferTextLength 20
  1645 #define KLongNodeTestLength 15
  1646 #define KShortNodeTestLength 5
  1647 _LIT(KFullTracnHdrText,"Full duplex test");		// length = 22
  1648 #define KFullTracnHdrTextLength 16
  1649 
  1650 
  1651 // Create transfer list with three nodes
  1652 // All memories are allocated from the kernel heap and referenced by class members
  1653 // DeleteFullDuplexTest should be called to release memory after use.
  1654 // List created here will be assigned to iHalfDuplexTrans in TIicBusTransaction
  1655 // If aNodeLength3 = 0, only return a 2 nodes transfer
  1656 TInt DChannelIicClient::CreateTransferListHalfDuplex(
  1657 			TIicBusTransfer::TReqType aNodeDir1, TInt aNodeLength1,
  1658 			TIicBusTransfer::TReqType aNodeDir2, TInt aNodeLength2,
  1659 			TIicBusTransfer::TReqType aNodeDir3, TInt aNodeLength3)
  1660 	{
  1661 	buf1 = HBuf8::New(KMaxTferTextLength);
  1662 	buf2 = HBuf8::New(KMaxTferTextLength);
  1663 	buf3 = HBuf8::New(KMaxTferTextLength);
  1664 	tfer1 = new TIicBusTransfer(aNodeDir1,8,buf1);
  1665 	tfer2 = new TIicBusTransfer(aNodeDir2,8,buf2);
  1666 	tfer3 = new TIicBusTransfer(aNodeDir3,8,buf3);
  1667 
  1668 	if(buf1 == NULL||buf2 == NULL||buf3 == NULL||
  1669 		tfer1 == NULL||tfer2 == NULL||tfer3 == NULL)
  1670 		{
  1671 		delete buf1; delete buf2; delete buf3;
  1672 		delete tfer1; delete tfer2;	delete tfer3;
  1673 		return KErrNoMemory;
  1674 		}
  1675 
  1676 	TInt i;
  1677 	for(i=0; (i<KMaxTferTextLength)&&(i<aNodeLength1); i++) buf1->Append('*');
  1678 	for(i=0; (i<KMaxTferTextLength)&&(i<aNodeLength2); i++) buf2->Append('*');
  1679 	for(i=0; (i<KMaxTferTextLength)&&(i<aNodeLength3); i++) buf3->Append('*');
  1680 
  1681 	tfer1->LinkAfter(tfer2);
  1682 
  1683 	//allow two nodes
  1684 	if(aNodeLength3>0)
  1685 		{
  1686 		tfer2->LinkAfter(tfer3);
  1687 		}
  1688 
  1689 	return KErrNone;
  1690 
  1691 	}
  1692 
  1693 // Create transfer list with three nodes
  1694 // All memories are allocated from the kernel heap and referenced by class members
  1695 // DeleteFullDuplexTest should be called to release memory after use.
  1696 // List created here will be assigned to iFullDuplexTrans in TIicBusTransaction
  1697 // If aNodeLength3 = 0, only return a 2 nodes transfer
  1698 TInt DChannelIicClient::CreateTransferListFullDuplex(
  1699 			TIicBusTransfer::TReqType aNodeDir1, TInt aNodeLength1,
  1700 			TIicBusTransfer::TReqType aNodeDir2, TInt aNodeLength2,
  1701 			TIicBusTransfer::TReqType aNodeDir3, TInt aNodeLength3)
  1702 	{
  1703 	buf4 = HBuf8::New(KMaxTferTextLength);
  1704 	buf5 = HBuf8::New(KMaxTferTextLength);
  1705 	buf6 = HBuf8::New(KMaxTferTextLength);
  1706 	tfer4 = new TIicBusTransfer(aNodeDir1,8,buf4);
  1707 	tfer5 = new TIicBusTransfer(aNodeDir2,8,buf5);
  1708 	tfer6 = new TIicBusTransfer(aNodeDir3,8,buf6);
  1709 
  1710 	if(buf4 == NULL||buf5 == NULL||buf6 == NULL||
  1711 		tfer4 == NULL||tfer5 == NULL||tfer6 == NULL)
  1712 		{
  1713 		delete buf4; delete buf5; delete buf6;
  1714 		delete tfer4; delete tfer5;	delete tfer6;
  1715 		return KErrNoMemory;
  1716 		}
  1717 
  1718 	TInt i;
  1719 	for(i=0; (i<KMaxTferTextLength)&&(i<aNodeLength1); i++) buf4->Append('*');
  1720 	for(i=0; (i<KMaxTferTextLength)&&(i<aNodeLength2); i++) buf5->Append('*');
  1721 	for(i=0; (i<KMaxTferTextLength)&&(i<aNodeLength3); i++) buf6->Append('*');
  1722 
  1723 	tfer4->LinkAfter(tfer5);
  1724 
  1725 	//allow two nodes
  1726 	if(aNodeLength3>0)
  1727 		{
  1728 		tfer5->LinkAfter(tfer6);
  1729 		}
  1730 
  1731 	return KErrNone;
  1732 
  1733 	}
  1734 
  1735 // Delete transaction and all allocated transfers and buffers
  1736 TInt DChannelIicClient::DeleteFullDuplexTest(TIicBusTransaction *aTrans)
  1737 	{
  1738 	delete buf1; delete buf2; delete buf3;
  1739 	delete tfer1; delete tfer2; delete tfer3;
  1740 
  1741 	delete buf4; delete buf5; delete buf6;
  1742 	delete tfer4; delete tfer5; delete tfer6;
  1743 
  1744 	delete header;
  1745 	delete aTrans;
  1746 
  1747 	return KErrNone;
  1748 	}
  1749 
  1750 // Do full duplex creation test
  1751 TInt DChannelIicClient::DoCreateFullDuplexTransTest(TInt aTestType)
  1752 	{
  1753 	CLIENT_PRINT(("DChannelIicClient::DoCreateFullDuplexTransTest starts\n"));
  1754 
  1755 	TInt r=KErrNone;
  1756 	switch(aTestType)
  1757 		{
  1758 		case RBusDevIicClient::ETestValidFullDuplexTrans:
  1759 			{
  1760 			// equal length, opposite transfer direction
  1761 			r = CreateTransferListHalfDuplex(
  1762 						TIicBusTransfer::EMasterWrite, KLongNodeTestLength,
  1763 						TIicBusTransfer::EMasterRead, KLongNodeTestLength,
  1764 						TIicBusTransfer::EMasterWrite, KLongNodeTestLength);
  1765 			if(r!=KErrNone) break;
  1766 			r = CreateTransferListFullDuplex(
  1767 						TIicBusTransfer::EMasterRead, KLongNodeTestLength,
  1768 						TIicBusTransfer::EMasterWrite, KLongNodeTestLength,
  1769 						TIicBusTransfer::EMasterRead, KLongNodeTestLength);
  1770 			if(r!=KErrNone) break;
  1771 			break;
  1772 			}
  1773 		case RBusDevIicClient::ETestInvalidFullDuplexTrans1:
  1774 			{
  1775 			// equal length, same transfer direction
  1776 			r = CreateTransferListHalfDuplex(
  1777 						TIicBusTransfer::EMasterWrite, KLongNodeTestLength,
  1778 						TIicBusTransfer::EMasterRead, KLongNodeTestLength,
  1779 						TIicBusTransfer::EMasterWrite, KLongNodeTestLength);
  1780 			if(r!=KErrNone) break;
  1781 			r = CreateTransferListFullDuplex(
  1782 						TIicBusTransfer::EMasterWrite, KLongNodeTestLength,
  1783 						TIicBusTransfer::EMasterRead, KLongNodeTestLength,
  1784 						TIicBusTransfer::EMasterWrite, KLongNodeTestLength);
  1785 			if(r!=KErrNone) break;
  1786 			break;
  1787 			}
  1788 		case RBusDevIicClient::ETestInvalidFullDuplexTrans2:
  1789 			{
  1790 			// different, opposite transfer direction
  1791 			r = CreateTransferListHalfDuplex(
  1792 						TIicBusTransfer::EMasterWrite, KShortNodeTestLength,
  1793 						TIicBusTransfer::EMasterRead, KShortNodeTestLength,
  1794 						TIicBusTransfer::EMasterWrite, KShortNodeTestLength);
  1795 			if(r!=KErrNone) break;
  1796 			r = CreateTransferListFullDuplex(
  1797 						TIicBusTransfer::EMasterRead, KLongNodeTestLength,
  1798 						TIicBusTransfer::EMasterWrite, KLongNodeTestLength,
  1799 						TIicBusTransfer::EMasterRead, KLongNodeTestLength);
  1800 			if(r!=KErrNone) break;
  1801 			break;
  1802 			}
  1803 		case RBusDevIicClient::ETestLastNodeFullDuplexTrans:
  1804 			{
  1805 			// different length for the last node
  1806 			r = CreateTransferListHalfDuplex(
  1807 						TIicBusTransfer::EMasterWrite, KLongNodeTestLength,
  1808 						TIicBusTransfer::EMasterRead, KLongNodeTestLength,
  1809 						TIicBusTransfer::EMasterWrite, KShortNodeTestLength);
  1810 			if(r!=KErrNone) break;
  1811 			r = CreateTransferListFullDuplex(
  1812 						TIicBusTransfer::EMasterRead, KLongNodeTestLength,
  1813 						TIicBusTransfer::EMasterWrite, KLongNodeTestLength,
  1814 						TIicBusTransfer::EMasterRead, KLongNodeTestLength);
  1815 			if(r!=KErrNone) break;
  1816 			break;
  1817 			}
  1818 		case RBusDevIicClient::ETestDiffNodeNoFullDuplexTrans:
  1819 			{
  1820 			// equal length, opposite transfer direction
  1821 			r = CreateTransferListHalfDuplex(
  1822 						TIicBusTransfer::EMasterWrite, KLongNodeTestLength,
  1823 						TIicBusTransfer::EMasterRead, KLongNodeTestLength,
  1824 						TIicBusTransfer::EMasterWrite, KShortNodeTestLength);
  1825 			if(r!=KErrNone) break;
  1826 			r = CreateTransferListFullDuplex(
  1827 						TIicBusTransfer::EMasterRead, KLongNodeTestLength,
  1828 						TIicBusTransfer::EMasterWrite, KShortNodeTestLength,
  1829 						TIicBusTransfer::EMasterRead, 0);
  1830 			if(r!=KErrNone) break;
  1831 			break;
  1832 			}
  1833 
  1834 
  1835 		default:
  1836 			break;
  1837 		}
  1838 
  1839 	header = HBuf8::New(KFullTracnHdrTextLength);
  1840 	TIicBusTransaction *Trans = new TIicBusTransaction(header,tfer1);
  1841 
  1842 	if((r!=KErrNone) || (header == NULL) || (Trans == NULL))
  1843 		{
  1844 		CLIENT_PRINT(("DChannelIicClient::DoCreateFullDuplexTransTest ERROR - failed to allocate the necessary memory\n"));
  1845 		DeleteFullDuplexTest(Trans);
  1846 		return KErrNoMemory;
  1847 		}
  1848 
  1849 	header->Copy(KFullTracnHdrText);
  1850 
  1851 	TInt TestResult = Trans->SetFullDuplexTrans(tfer4);
  1852 
  1853 	CLIENT_PRINT(("DChannelIicClient::DoCreateFullDuplexTransTest IIC after SetFullDuplexTrans TestResult =%d\n", TestResult));
  1854 
  1855 	r = DeleteFullDuplexTest(Trans);
  1856 
  1857 	return TestResult;
  1858 
  1859 	}
  1860 
  1861 
  1862 TInt DChannelIicClient::CreateDefaultSpiBuf(TConfigSpiBufV01*& aBuf)
  1863 // Utility function to create a buffer for the SPI bus
  1864 	{
  1865 	TInt r=CreateSpiBuf(aBuf, ESpiWordWidth_8, 100000, ESpiPolarityLowRisingEdge, 100 ,ELittleEndian, EMsbFirst, 10, ESpiCSPinActiveLow);
  1866 	return r;
  1867 	}
  1868 
  1869 // DoPriorityTest does the following actions:
  1870 // 1. switch the bus (only use SPI test PSL) to priority test mode
  1871 // 2. create 5 test transactions with different priorities and 1 blocking transaction
  1872 // 3. enable blocking in test channel
  1873 //     we can only block the test channel, we cannot suspend the bus controller
  1874 // 3. send blocking transaction to the test channel
  1875 //     the blocking transaction is just normal transaction.
  1876 //     the test channel will be blocked once the first transaction is arrived
  1877 // 4. send test transactions in opposite order to their priority
  1878 // 5. unblock test channel
  1879 // 6. read test result from channel
  1880 // 7. switch the bus to normal mode
  1881 TInt DChannelIicClient::DoPriorityTest(TInt aBusId)
  1882 	{
  1883 	TInt TestResult=KErrNone;
  1884 	// Use the IIC StaticExtension interface to pass the request to the bus implementation
  1885 	// To support testing, any values of aId for StaticExtension must be shifted left one place
  1886 	TUint testId = ((TUint)(RBusDevIicClient::ECtlIoPriorityTest))<<1;
  1887 	TInt r = KErrNone;
  1888 
  1889 	r = StaticExtension(aBusId, testId, NULL, NULL);
  1890 	__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__));
  1891 	if(r == KErrNone)
  1892 		{
  1893 		buf1 = HBuf8::New(1);
  1894 		buf2 = HBuf8::New(1);
  1895 		buf3 = HBuf8::New(1);
  1896 		buf4 = HBuf8::New(1);
  1897 		buf5 = HBuf8::New(1);
  1898 		//buffer for blocking transaction
  1899 		buf6 = HBuf8::New(1);
  1900 
  1901 		if(buf1 == NULL||buf2 == NULL||buf3 == NULL||buf4 == NULL||buf5 == NULL||buf6 == NULL)
  1902 			{
  1903 			delete buf1; delete buf2; delete buf3; delete buf4; delete buf5; delete buf6;
  1904 			r = StaticExtension(aBusId, (TUint)RBusDevIicClient::ECtlIoNone, NULL, NULL);
  1905 			return KErrNoMemory;
  1906 			}
  1907 		tfer1 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf1);
  1908 		tfer2 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf2);
  1909 		tfer3 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf3);
  1910 		tfer4 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf4);
  1911 		tfer5 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf5);
  1912 		//transfer for blocking transaction
  1913 		tfer6 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf6);
  1914 
  1915 		if(tfer1 == NULL||tfer2 == NULL||tfer3 == NULL||tfer4 == NULL||tfer5 == NULL||tfer6 == NULL)
  1916 			{
  1917 			delete buf1; delete buf2; delete buf3; delete buf4; delete buf5; delete buf6;
  1918 			delete tfer1; delete tfer2; delete tfer3; delete tfer4; delete tfer5; delete tfer6;
  1919 			r = StaticExtension(aBusId, (TUint)RBusDevIicClient::ECtlIoNone, NULL, NULL);
  1920 			return KErrNoMemory;
  1921 			}
  1922 
  1923 		TConfigSpiBufV01* spiHeader1 = NULL;
  1924 		TConfigSpiBufV01* spiHeader2 = NULL;
  1925 		TConfigSpiBufV01* spiHeader3 = NULL;
  1926 		TConfigSpiBufV01* spiHeader4 = NULL;
  1927 		TConfigSpiBufV01* spiHeader5 = NULL;
  1928 		TConfigSpiBufV01* spiHeaderBlock = NULL; 		//header for blocking transaction
  1929 
  1930 
  1931 		TInt r = CreateDefaultSpiBuf(spiHeader1);
  1932 		if(r == KErrNone)	r = CreateDefaultSpiBuf(spiHeader2);
  1933 		if(r == KErrNone)	r = CreateDefaultSpiBuf(spiHeader3);
  1934 		if(r == KErrNone)	r = CreateDefaultSpiBuf(spiHeader4);
  1935 		if(r == KErrNone)	r = CreateDefaultSpiBuf(spiHeader5);
  1936 		//header for blocking transaction
  1937 		if(r == KErrNone)	r = CreateDefaultSpiBuf(spiHeaderBlock);
  1938 
  1939 		if(r != KErrNone||spiHeader1 == NULL||spiHeader2 == NULL||spiHeader3 == NULL||spiHeader4 == NULL||spiHeader5 == NULL||spiHeaderBlock == NULL)
  1940 			{
  1941 			delete buf1; delete buf2; delete buf3; delete buf4; delete buf5; delete buf6;
  1942 			delete tfer1; delete tfer2; delete tfer3; delete tfer4; delete tfer5; delete tfer6;
  1943 			delete spiHeader1; delete spiHeader2; delete spiHeader3; delete spiHeader4; delete spiHeader5; delete spiHeaderBlock;
  1944 			r = StaticExtension(aBusId, (TUint)RBusDevIicClient::ECtlIoNone, NULL, NULL);
  1945 			return KErrNoMemory;
  1946 			}
  1947 
  1948 		TIicBusTransaction* Transc1; Transc1 = new TIicBusTransaction(spiHeader1,tfer1, KPriorityTestPrio[0]);
  1949 		TIicBusTransaction* Transc2; Transc2 = new TIicBusTransaction(spiHeader2,tfer2, KPriorityTestPrio[1]);
  1950 		TIicBusTransaction* Transc3; Transc3 = new TIicBusTransaction(spiHeader3,tfer3, KPriorityTestPrio[2]);
  1951 		TIicBusTransaction* Transc4; Transc4 = new TIicBusTransaction(spiHeader4,tfer4, KPriorityTestPrio[3]);
  1952 		TIicBusTransaction* Transc5; Transc5 = new TIicBusTransaction(spiHeader5,tfer5, KPriorityTestPrio[4]);
  1953 		//blocking transaction
  1954 		TIicBusTransaction* TranscBlock; TranscBlock = new TIicBusTransaction(spiHeaderBlock,tfer6, KPriorityTestPrio[5]);
  1955 
  1956 		if(Transc1 == NULL||Transc2 == NULL||Transc3 == NULL||Transc4 == NULL||Transc5 == NULL||TranscBlock == NULL)
  1957 			{
  1958 			delete buf1; delete buf2; delete buf3; delete buf4; delete buf5; delete buf6;
  1959 			delete tfer1; delete tfer2; delete tfer3; delete tfer4; delete tfer5; delete tfer6;
  1960 			delete spiHeader1; delete spiHeader2; delete spiHeader3; delete spiHeader4; delete spiHeader5; delete spiHeaderBlock;
  1961 			delete Transc1; delete Transc2; delete Transc3; delete Transc4; delete Transc5; delete TranscBlock;
  1962 			r = StaticExtension(aBusId, (TUint)RBusDevIicClient::ECtlIoNone, NULL, NULL);
  1963 			return KErrNoMemory;
  1964 			}
  1965 
  1966 		//dummy call back func is provided for asyn call
  1967 		TIicBusCallback* cb = new TIicBusCallback(DummyCallbackFunc, this, iDfcQue, 5); // 5 arbitrary
  1968 
  1969 		// block the device channel. the channel will not be blocked until the first transaction arrive the channel
  1970 		// To support testing, any values of aId for StaticExtension must be shifted left one place
  1971 		TUint testId=((TUint)RBusDevIicClient::ECtlIoBlockReqCompletion)<<1;
  1972 		r = StaticExtension(aBusId, testId, NULL, NULL);
  1973 		__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__));
  1974 
  1975 		r = QueueTransaction(aBusId, TranscBlock, cb);  //send TranscBlock to block the channel
  1976 		// send ordered transactions
  1977 		__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__));
  1978 
  1979 		r = QueueTransaction(aBusId, Transc1, cb);
  1980 		__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__));
  1981 		r = QueueTransaction(aBusId, Transc2, cb);
  1982 		__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__));
  1983 		r = QueueTransaction(aBusId, Transc3, cb);
  1984 		__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__));
  1985 		r = QueueTransaction(aBusId, Transc4, cb);
  1986 		__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__));
  1987 		r = QueueTransaction(aBusId, Transc5, cb);
  1988 		__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__));
  1989 
  1990 		// unblock device channel
  1991 		testId=((TUint)RBusDevIicClient::ECtlIoUnblockReqCompletion)<<1;
  1992 		r = StaticExtension(aBusId, testId, NULL, NULL);
  1993 		__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__));
  1994 
  1995 		#define KPriorityTestGetResultRetry 3
  1996 		for(TInt i=0; i<KPriorityTestGetResultRetry ; i++)
  1997 			{
  1998 			NKern::Sleep(500);
  1999 			testId=((TUint)RBusDevIicClient::EGetTestResult)<<1;
  2000 			TestResult = StaticExtension(aBusId, testId, NULL, NULL);
  2001 			if(TestResult!=KErrNotReady) break;
  2002 			}
  2003 
  2004 		cb->Cancel();
  2005 		delete cb;
  2006 		delete buf1; delete buf2; delete buf3; delete buf4; delete buf5; delete buf6;
  2007 		delete tfer1; delete tfer2; delete tfer3; delete tfer4; delete tfer5; delete tfer6;
  2008 		delete spiHeader1; delete spiHeader2; delete spiHeader3; delete spiHeader4; delete spiHeader5; delete spiHeaderBlock;
  2009 		delete Transc1; delete Transc2; delete Transc3; delete Transc4; delete Transc5; delete TranscBlock;
  2010 
  2011 		}
  2012 	r = StaticExtension(aBusId, (TUint)RBusDevIicClient::ECtlIoNone, NULL, NULL);
  2013 	return TestResult;
  2014 	}
  2015 
  2016 TInt DChannelIicClient::ConstructTransactionOne(TIicBusTransaction*& aTrans)
  2017 	{
  2018 	// Transaction is to contain three transfers, with data defined by
  2019 	// KTransOneTferOne[], KTransOneTferTwo[], KTransOneTferThree[]
  2020 	buf1 = HBuf8::New(21);
  2021 	buf2 = HBuf8::New(8);
  2022 	buf3 = HBuf8::New(6);
  2023 	tfer1 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf1);
  2024 	tfer2 = new TIicBusTransfer(TIicBusTransfer::EMasterRead,8,buf2);
  2025 	tfer3 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf3);
  2026 	TInt r = CreateDefaultSpiBuf(spiHeader);
  2027 	if((r != KErrNone)||(spiHeader == NULL)||(buf1 == NULL)||(buf2 == NULL)||(buf3 == NULL)||(tfer1 == NULL)||(tfer2 == NULL)||(tfer3 == NULL))
  2028 		{
  2029 		CLIENT_PRINT(("DChannelIicClient::ConstructTransactionOne ERROR - failed to allocate the necessary memory\n"));
  2030 		delete buf1;
  2031 		delete buf2;
  2032 		delete buf3;
  2033 		delete tfer1;
  2034 		delete tfer2;
  2035 		delete tfer3;
  2036 		delete spiHeader;
  2037 		delete aTrans;
  2038 		return KErrNoMemory;
  2039 		}
  2040 	aTrans = new TIicBusTransaction(spiHeader,tfer1);
  2041 	buf1->Copy(&(KTransOneTferOne[0]),21);
  2042 	buf2->Copy(&(KTransOneTferTwo[0]),8);
  2043 	buf3->Copy(&(KTransOneTferThree[0]),6);
  2044 	tfer1->LinkAfter(tfer2);
  2045 	tfer2->LinkAfter(tfer3);
  2046 	return KErrNone;
  2047 	}
  2048 
  2049 void DChannelIicClient::CleanupTransactionOne(TIicBusTransaction*& aTrans)
  2050 	{
  2051 	// Release the allocated memory
  2052 	delete buf1;
  2053 	buf1=NULL;
  2054 	delete buf2;
  2055 	buf2=NULL;
  2056 	delete buf3;
  2057 	buf3=NULL;
  2058 	delete tfer1;
  2059 	tfer1=NULL;
  2060 	delete tfer2;
  2061 	tfer2=NULL;
  2062 	delete tfer3;
  2063 	tfer3=NULL;
  2064 	delete spiHeader;
  2065 	spiHeader=NULL;
  2066 	delete aTrans;
  2067 	aTrans=NULL;
  2068 	}
  2069 
  2070 
  2071 void DChannelIicClient::CleanupTransaction(TIicBusTransaction*& aTrans)
  2072 	{
  2073 	delete iSpiBuf;
  2074 	iSpiBuf=NULL;
  2075 	delete iI2cBuf;
  2076 	iI2cBuf=NULL;
  2077 	TIicBusTransfer* currTfer = iTfer;
  2078 	TIicBusTransfer* nextTfer = NULL;
  2079 	while(currTfer)
  2080 		{
  2081 		TIicBusTransfer* nextTfer = (TIicBusTransfer*)(currTfer->Next());
  2082 		delete currTfer;
  2083 		if(nextTfer)
  2084 			currTfer = nextTfer;
  2085 		else
  2086 			currTfer = NULL;
  2087 		};
  2088 	iTfer=NULL;
  2089 	currTfer = iFdTfer;
  2090 	nextTfer = NULL;
  2091 	while(currTfer)
  2092 		{
  2093 		TIicBusTransfer* nextTfer = (TIicBusTransfer*)(currTfer->Next());
  2094 		delete currTfer;
  2095 		if(nextTfer)
  2096 			currTfer = nextTfer;
  2097 		else
  2098 			currTfer = NULL;
  2099 		};
  2100 	iFdTfer=NULL;
  2101 	if(aTrans!=NULL)
  2102 		{
  2103 		delete aTrans;
  2104 		aTrans=NULL;
  2105 		}
  2106 	if(iTransPreamble!=NULL)
  2107 		{
  2108 		delete iTransPreamble;
  2109 		iTransPreamble=NULL;
  2110 		}
  2111 	}
  2112 
  2113 void DChannelIicClient::TransModifCallback(TIicBusTransaction* /*aTrans*/, TInt /*aBusId*/, TInt aResult, TAny* aParam)
  2114 	{
  2115 	// Callback function used to test re-use of transaction and transfer buffers
  2116 	// aParam is the address of the simulated client driver
  2117 	DChannelIicClient* channel = (DChannelIicClient*)aParam;
  2118 	TTransBufReuseData* reuseData = &(channel->iTransBufReuseData);
  2119 
  2120 	// Since the transaction is no longer queued, should be able to modify the transfer and transaction content
  2121 	channel->TestTransModification(reuseData->iTransaction, reuseData->iHdTfer, reuseData->iFdTfer, reuseData->iHdr);
  2122 
  2123 	// Complete the user's request, delete objects allocated for this test and return
  2124 	Kern::RequestComplete(channel->iClient, channel->iStatus, aResult);
  2125 	delete reuseData->iCallback;	// Must do this before deleting the Transaction, in CleanupTransaction
  2126 	channel->CleanupTransaction(channel->iTrans);
  2127 	return;
  2128 	}
  2129 
  2130 
  2131 void DChannelIicClient::TestTransModification(TIicBusTransaction* aTransaction,
  2132 											  TIicBusTransfer* aHdTfer,
  2133 											  TIicBusTransfer* aFdTfer,
  2134 											  TDes8* aHdr)
  2135 	{
  2136 	// Function to test that the content of Transaction and Transfer objects can be modified
  2137 	// This assumes that the Transaction is in the appropriate state (EFree) - otherwise, the code will assert
  2138 	// This function also assumes that transaction has aleady added the half-duplex and full-duplex transfers
  2139 	// that are passed in as arguments, and that the transfers lists are non-NULL
  2140 	// The original type of the transfers (read, write) are ignored, since it is not of interest in this test -
  2141 	// instead, what is important is to ensure that the half-duplex and full-duplex transfer types are in opposing
  2142 	// directions - so the types are explicitly set in this test.
  2143 	//
  2144 	TDes8* origBuf = NULL;
  2145 	TInt8 origGranularity = 0;
  2146 
  2147 	// Create a buffer for use in this function
  2148 	_LIT(temporaryText,"Temporary Text");
  2149 	TBuf8<15> tempBuf_8;
  2150 	tempBuf_8.Copy(temporaryText);
  2151 
  2152 	// Test modification of the two transfer lists while still part of the transaction
  2153 	origBuf = (TDes8*)(aHdTfer->GetBuffer());
  2154 	origGranularity = aHdTfer->WordWidth();
  2155 	aHdTfer->SetTransferData(TIicBusTransfer::EMasterRead, origGranularity, &tempBuf_8);
  2156 	aHdTfer->SetTransferData(TIicBusTransfer::EMasterRead, origGranularity, origBuf);
  2157 
  2158 	origBuf = (TDes8*)(aFdTfer->GetBuffer());
  2159 	origGranularity = aFdTfer->WordWidth();
  2160 	aFdTfer->SetTransferData(TIicBusTransfer::EMasterWrite, origGranularity, &tempBuf_8);
  2161 	aFdTfer->SetTransferData(TIicBusTransfer::EMasterWrite, origGranularity, origBuf);
  2162 
  2163 	// Test transfers can be removed from the transaction
  2164 	aTransaction->RemoveHalfDuplexTrans();
  2165 	aTransaction->RemoveFullDuplexTrans();
  2166 
  2167 	// Test modification of the two transfer lists while not part of a transaction
  2168 	origBuf = (TDes8*)(aHdTfer->GetBuffer());
  2169 	origGranularity = aHdTfer->WordWidth();
  2170 	aHdTfer->SetTransferData(TIicBusTransfer::EMasterRead, origGranularity, &tempBuf_8);
  2171 	aHdTfer->SetTransferData(TIicBusTransfer::EMasterRead, origGranularity, origBuf);
  2172 
  2173 	origBuf = (TDes8*)(aFdTfer->GetBuffer());
  2174 	origGranularity = aFdTfer->WordWidth();
  2175 	aFdTfer->SetTransferData(TIicBusTransfer::EMasterWrite, origGranularity, &tempBuf_8);
  2176 	aFdTfer->SetTransferData(TIicBusTransfer::EMasterWrite, origGranularity, origBuf);
  2177 
  2178 	// Test transfers can be re-added to the transaction
  2179 	aTransaction->SetHalfDuplexTrans(aHdr,aHdTfer);
  2180 	aTransaction->SetFullDuplexTrans(aFdTfer);
  2181 
  2182 	// Test modification of the two transfer lists now re-added to the transaction
  2183 	origBuf = (TDes8*)(aHdTfer->GetBuffer());
  2184 	origGranularity = aHdTfer->WordWidth();
  2185 	aHdTfer->SetTransferData(TIicBusTransfer::EMasterRead, origGranularity, &tempBuf_8);
  2186 	aHdTfer->SetTransferData(TIicBusTransfer::EMasterRead, origGranularity, origBuf);
  2187 
  2188 	origBuf = (TDes8*)(aFdTfer->GetBuffer());
  2189 	origGranularity = aFdTfer->WordWidth();
  2190 	aFdTfer->SetTransferData(TIicBusTransfer::EMasterWrite, origGranularity, &tempBuf_8);
  2191 	aFdTfer->SetTransferData(TIicBusTransfer::EMasterWrite, origGranularity, origBuf);
  2192 
  2193 	return;
  2194 	}
  2195 
  2196 TInt DChannelIicClient::DoControl(TInt aId, TAny* a1, TAny* a2)
  2197 	{
  2198 	CLIENT_PRINT(("DChannelIicClient::DoControl invoked with aId=0x%x, a1=0x%x, a2=0x%x\n", aId,a1,a2));
  2199 	TInt r=KErrNone;
  2200 	// To support testing, any values of aId for StaticExtension must be shifted left one place
  2201 	// and for a Slave tests, the two msbs must be zero
  2202 	TInt ctrlIoVal = 0;
  2203 	if((aId & KTestMasterControlIo) == KTestMasterControlIo)
  2204 		ctrlIoVal = (aId << 1);
  2205 	if((aId & KTestSlaveControlIo) == KTestSlaveControlIo)
  2206 		ctrlIoVal = (aId << 1) & 0x3FFFFFFF;
  2207 	switch(aId)
  2208 		{
  2209 		case(RBusDevIicClient::EQTransSync):
  2210 			{
  2211 			// a1 specifies Bus Realisation Config to use
  2212 			// a2 is a pointer to TUsideTracnDesc
  2213 			TIicBusTransaction* trans = NULL;
  2214 			TIicBusTransfer* tfer = NULL;
  2215 			TConfigSpiBufV01 *spiBuf = NULL;
  2216 			
  2217 			//Read the transaction header to determin if it is a multi-transaction type
  2218 			TUsideTracnDesc usTrans;
  2219 
  2220 			if((Kern::ThreadRawRead(iClient,a2,&usTrans,sizeof(TUsideTracnDesc)))!=KErrNone)
  2221 				{
  2222 				CLIENT_PRINT(("DChannelIicClient::DoControl ERROR - Can't read iHeader to spiBuf\n"));
  2223 				return KErrGeneral;
  2224 				}
  2225 
  2226 			if((usTrans.iFlags)&KTransactionWithMultiTransc)
  2227 				{
  2228 				// Since we are testing a multi-transaction, create another transaction object iMultiTransac,
  2229 				// to represent the delayed part of the multi-transaction. After the preliminary
  2230 				// transaction(passed from t_iic, with one read transfer) has been performed, 
  2231 				// the IIC code will find that it is part of a 
  2232 				// multi-transaction; it will call the callback for the transaction(set as MultiTranscCallbackFunc,
  2233 				// in ExtractTransData) and this will return a pointer to the next part of the multi-transaction
  2234 				// to be performed(iMultiTransac). It will then immediately pass this transaction object
  2235 				// to the PSL for processing - before considering any other transactions that have been 
  2236 				// requested, and without completing the multi-transaction request(this is done once 
  2237 				// iMultiTransac has been processed)
  2238 				buf1 = HBuf8::New(1);
  2239 				spiBuf = new TConfigSpiBufV01();
  2240 				if(buf1 == NULL||spiBuf == NULL) {delete buf1;delete spiBuf; return KErrNoMemory;}
  2241 
  2242 
  2243 				if((r=Kern::ThreadDesRead(iClient, usTrans.iHeader, *spiBuf, 0, KChunkShiftBy0 ))!=KErrNone)
  2244 					{
  2245 					CLIENT_PRINT(("DChannelIicClient::DoControl ERROR - Can't read iHeader to spiBuf\n"));
  2246 					return KErrGeneral;
  2247 					}
  2248 
  2249 				tfer = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf1);
  2250 				if(tfer == NULL) {delete buf1; delete spiBuf; return KErrNoMemory;}
  2251 
  2252 				iMultiTransac = new TIicBusTransaction((TDes8*)spiBuf, tfer);
  2253 				if(iMultiTransac == NULL) {delete buf1; delete spiBuf; delete tfer; return KErrNoMemory;}
  2254 				}
  2255 			r = ExtractTransData((TUsideTracnDesc*)a2, trans);
  2256 			if(r!=KErrNone)
  2257 				{
  2258 				CLIENT_PRINT(("DChannelIicClient::DoControl ERROR - ExtractTransData returned %d\n",r));
  2259 				return r;
  2260 				}
  2261 			CLIENT_PRINT(("DChannelIicClient::DoControl invoking (synchronous) QueueTransaction with busId=0x%x, trans=0x%x\n",(TUint32)a1,trans));
  2262 
  2263 			r = QueueTransaction((TUint32)a1, trans);
  2264 			CleanupExtractTrans(trans);
  2265 			CleanupTransaction(trans);
  2266 			if((usTrans.iFlags)&KTransactionWithMultiTransc)
  2267 				{
  2268 				delete buf1;
  2269 				delete spiBuf;
  2270 				delete tfer;
  2271 				delete iMultiTransac;
  2272 				}
  2273 			break;
  2274 			}
  2275 		case(RBusDevIicClient::ECtlIoBlockReqCompletion):
  2276 		case(RBusDevIicClient::ECtlIoUnblockReqCompletion):
  2277 		case(RBusDevIicClient::ECtlIoDeRegChan):
  2278 			{
  2279 			// a1 specifies Bus Realisation Config to use
  2280 			CLIENT_PRINT(("DChannelIicClient::DoControl invoking StaticExtension with aId=%d, busId=0x%x\n",aId,(TUint32)a1));
  2281 			// Use the IIC StaticExtension interface to pass the request to the bus implementation
  2282 			r = StaticExtension((TUint32)a1, (TUint)ctrlIoVal, NULL, NULL);
  2283 			break;
  2284 			}
  2285 		case(RBusDevIicClient::ECtlIoTestFullDuplexTrans):
  2286 			{
  2287 			// a1 specifies Bus Realisation Config to use
  2288 			CLIENT_PRINT(("DChannelIicClient::DoControl invoking StaticExtension with aId=%d, busId=0x%x\n",aId,(TUint32)a1));
  2289 			r = DoCreateFullDuplexTransTest((TInt)a2);
  2290 			break;
  2291 			}
  2292 		case(RBusDevIicClient::ECtlIoPriorityTest):
  2293 			{
  2294 			// a1 specifies Bus Realisation Config to use
  2295 			CLIENT_PRINT(("DChannelIicClient::DoControl invoking StaticExtension with aId=%d, busId=0x%x\n",aId,(TUint32)a1));
  2296 			r = DoPriorityTest((TUint32)a1);
  2297 			break;
  2298 			}
  2299 
  2300 		case(RBusDevIicClient::ECtlIoTracnOne):
  2301 			{
  2302 			// a1 specifies Bus Realisation Config to use
  2303 			CLIENT_PRINT(("DChannelIicClient::StaticExtension invoking StaticExtension with ctrlIoVal=%d, busId=0x%x\n",aId,(TUint32)a1));
  2304 			// Use the IIC StaticExtension interface to pass the request to the bus implementation
  2305 			r = StaticExtension((TUint32)a1, (TUint)ctrlIoVal, NULL, NULL);
  2306 			__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("StaticExtension",__LINE__));
  2307 			if(r == KErrNone)
  2308 				{
  2309 				// Create then send (synchronously) Transaction One
  2310 				r = ConstructTransactionOne(iTrans);
  2311 				__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__));
  2312 				r = QueueTransaction((TUint32)a1, iTrans);
  2313 				__ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__));
  2314 				CleanupTransactionOne(iTrans);
  2315 				}
  2316 			r = StaticExtension((TUint32)a1, (TUint)RBusDevIicClient::ECtlIoNone, NULL, NULL);
  2317 			break;
  2318 			}
  2319 		case(RBusDevIicClient::ECtlIoSetTimeOutFlag):
  2320 			{
  2321 			CLIENT_PRINT(("DChannelIicClient::DoControl instruct the bus that it is to simulate a slave timeout"));
  2322 			// To support testing, function index passed to StaticExtension must be shifted one place to the left
  2323 			TUint testIndex = ((TUint)RBusDevIicClient::ECtlIoSetTimeOutFlag)<<1;;
  2324 			r = StaticExtension((TUint32)a1, testIndex, NULL, NULL);
  2325 			break;
  2326 			}
  2327 		case(RBusDevIicClient::ECtlIoNone):
  2328 			{
  2329 			CLIENT_PRINT(("DChannelIicClient::DoControl Return the bus to its default test state"));
  2330 			r = StaticExtension((TUint32)a1, (TUint)RBusDevIicClient::ECtlIoNone, NULL, NULL);
  2331 			break;
  2332 			}
  2333 
  2334 // Support for MasterSlave processing
  2335 
  2336 		case(RBusDevIicClient::ECaptureChanSync):
  2337 			{
  2338 			// a1 is a pointer to the TDes8* aConfigHdr
  2339 			// a2 is a pointer to TInt* parms[2], where:
  2340 			// parms[0]=(TInt*)aBusId;
  2341 			// parms[1]=&aChannelId;
  2342 			//
  2343 			TInt* parms[2];
  2344 			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt*));
  2345 			if(r!=KErrNone)
  2346 				break;	// Can't proceed if can't access request parameters
  2347 			//
  2348 		  	TInt hdrSize = Kern::ThreadGetDesLength(iClient,a1);
  2349 			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl hdrSize = 0x%x\n",hdrSize));
  2350   			if (hdrSize<=0)
  2351 				{
  2352 				CLIENT_PRINT(("DChannelIicSlaveClient::DoControl ERROR, hdrSize is invalid\n"));
  2353  				return KErrArgument;
  2354 				}
  2355 			if((iConfigHdr = HBuf8::New(hdrSize)) == NULL)
  2356 				return KErrNoMemory;
  2357 			r = Kern::ThreadDesRead(iClient,a1,*iConfigHdr,0);
  2358 			if(r!=KErrNone)
  2359 				{
  2360 				delete iConfigHdr;
  2361 				return r;
  2362 				}
  2363 			// Store the address of the user-side variable to update with the ChannelId
  2364 			iClientChanId=parms[1];
  2365 
  2366 			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking (synchronous) CaptureChannel\n"));
  2367 			r = CaptureChannel((TInt)(parms[0]), iConfigHdr, iNotif, iChannelId);
  2368 			if(r != KErrNone)
  2369 			    delete iConfigHdr;
  2370 			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl CaptureChannelgave iChannelId=0x%x\n",iChannelId));
  2371 
  2372 			TInt r=Kern::ThreadRawWrite(iClient,iClientChanId,&iChannelId,sizeof(TInt));
  2373 			(void)r;	// Silence the compiler
  2374 
  2375 			break;
  2376 			}
  2377 
  2378 		case(RBusDevIicClient::EReleaseChan):
  2379 			{
  2380 			// a1 represents TInt aChannelId
  2381 			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking ReleaseChannel\n"));
  2382 			r = ReleaseChannel((TInt)a1);
  2383 			delete iConfigHdr;
  2384 			break;
  2385 			}
  2386 
  2387 		case(RBusDevIicClient::EInitSlaveClient):
  2388 			{
  2389 			r=InitSlaveClient();
  2390 			break;
  2391 			}
  2392 		
  2393 #ifdef STANDALONE_CHANNEL		
  2394         case(RBusDevIicClient::ETestIicChannelInlineFunc):
  2395             {  
  2396             TTestIicChannelInterface channelInterface(DIicBusChannel::EMaster, DIicBusChannel::EI2c, DIicBusChannel::EHalfDuplex);
  2397             r = channelInterface.TestInterface();
  2398             break;         
  2399             }
  2400 #endif
  2401         
  2402         default:
  2403 			{
  2404 			CLIENT_PRINT(("DChannelIicClient::DoControl - unrecognised value for aId=0x%x\n",aId));
  2405 			r=KErrArgument;
  2406 			break;
  2407 			}
  2408 		}
  2409 	return r;
  2410 	}
  2411 
  2412 TInt DChannelIicClient::DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2)
  2413 	{
  2414 	CLIENT_PRINT(("DChannelIicClient::DoRequest invoked with aId=0x%x, aStatus=0x%x, a1=0x%x, a2=0x%x\n", aId,aStatus,a1,a2));
  2415 
  2416 	TInt r=KErrNone;
  2417 	switch(aId)
  2418 		{
  2419 		case(RBusDevIicClient::EQTransAsync):
  2420 			{
  2421 			// a1 specifies Bus Realisation Config to use
  2422 			// a2 is a pointer to TIicBusTransaction
  2423 			TIicBusTransaction* trans = NULL;
  2424 			r = ExtractTransData((TUsideTracnDesc*)a2, trans);
  2425 			if(r!=KErrNone)
  2426 				{
  2427 				CLIENT_PRINT(("DChannelIicClient::DoRequest ERROR - ExtractTransData returned %d\n",r));
  2428 				return r;
  2429 				}
  2430 			// Create TIicBusCallback object
  2431 			TIicBusCallback* cb = new TIicBusCallback(AsyncCallbackFunc, this, iDfcQue, 5); // 5 arbitrary
  2432 			TTransCbPair* cbPair = new TTransCbPair();
  2433 			cbPair->iCb=cb;
  2434 			cbPair->iTrans=trans;
  2435 			// Create an entry in the RPointerArray for TRequestStatus - TIicBusTransaction pairs
  2436 			TTransStatusPair* pair = new TTransStatusPair();
  2437 			pair->iReq=aStatus;
  2438 			pair->iTrans=trans;
  2439 			r=InsertPairs(pair,cbPair);
  2440 			if(r!=KErrNone)
  2441 				{
  2442 				CLIENT_PRINT(("DChannelIicClient::DoRequest ERROR - InsertInOrder returned %d\n",r));
  2443 				return r;
  2444 				}
  2445 			CLIENT_PRINT(("DChannelIicClient::DoRequest invoking (asynchronous) QueueTransaction with busId=0x%x, trans=0x%x, cb=0x%x\n",(TUint32)a1,trans,cb));
  2446 			r = QueueTransaction((TUint32)a1, trans, cb);
  2447 			if(r!=KErrNone)
  2448 				{
  2449 				// The transaction was not queued - since it will not be completed asynchronously, need to remove it here
  2450 				GetWriteAccess();
  2451 				Lock();
  2452 				TInt pairIndex=iTransStatArrayByTrans.FindInOrder(pair,TransStatusOrderByTrans);
  2453 				__ASSERT_ALWAYS(pairIndex>=0,Kern::Fault("IIC Client, DoRequest, EQTransAsync ByTrans pairIndex<0",__LINE__));
  2454 				iTransStatArrayByTrans.Remove(pairIndex);
  2455 				pairIndex = iTransStatArrayByStatus.FindInOrder(pair,TransStatusOrderByStatus);
  2456 				__ASSERT_ALWAYS(pairIndex>=0,Kern::Fault("IIC Client, DoRequest, EQTransAsync ByStatus pairIndex<0",__LINE__));
  2457 				iTransStatArrayByStatus.Remove(pairIndex);
  2458 				pairIndex = iTransCbArrayByTrans.FindInOrder(cbPair,TransCbOrderByTrans);
  2459 				__ASSERT_ALWAYS(pairIndex>=0,Kern::Fault("IIC Client, DoRequest, EQTransAsync Cb by Trans pairIndex<0",__LINE__));
  2460 				iTransCbArrayByTrans.Remove(pairIndex);
  2461 				FreeWriteAccess();
  2462 				Unlock();
  2463 				Kern::RequestComplete(iClient, aStatus, r);
  2464 				delete cb;
  2465 				delete cbPair;
  2466 				CleanupExtractTrans(pair->iTrans);
  2467 				CleanupTransaction(pair->iTrans);			
  2468 				delete pair;
  2469 				}
  2470 			break;
  2471 			}
  2472 
  2473 		case(RBusDevIicClient::ECtrlIoTestBufReUse):
  2474 			{
  2475 			iStatus = aStatus;
  2476 			// a1 specifies Bus Realisation Config to use
  2477 
  2478 			// Ensure object pointers are made available
  2479 			CleanupTransaction(iTrans);
  2480 
  2481 			TInt r = KErrNone;
  2482 			TIicBusCallback* cb = NULL;
  2483 
  2484 			// Use default constructor to create an empty transaction
  2485 			iTrans = new TIicBusTransaction();
  2486 			if(iTrans == NULL)
  2487 				{
  2488 				CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - iTrans=NULL\n"));
  2489 				r = KErrNoMemory;
  2490 				}
  2491 
  2492 			// Create a header for the transaction
  2493 			if(r == KErrNone)
  2494 				{
  2495 				r = CreateDefaultSpiBuf(iSpiBuf);
  2496 				if(r != KErrNone)
  2497 					{
  2498 					CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - CreateDefaultSpiBuf returned %d\n",r));
  2499 					}
  2500 				}
  2501 
  2502 			// Create and add transfer lists for half-duplex and full-duplex entries in the transaction
  2503 			if(r == KErrNone)
  2504 				{
  2505 				// Use simple text as payload, 8bit granularity, half-duplex write, full-duplex read (ie payload ignored)
  2506 				_LIT(halfDuplexText1,"Half Duplex Text 1");
  2507 				TBuf8<19> halfDuplexBuf_8;
  2508 				halfDuplexBuf_8.Copy(halfDuplexText1);
  2509 				iTfer = new TIicBusTransfer(TIicBusTransfer::EMasterWrite, 8, &halfDuplexBuf_8);
  2510 				if(iTfer == NULL)
  2511 					{
  2512 					CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - iTfer=NULL\n"));
  2513 					r = KErrNoMemory;
  2514 					}
  2515 				else
  2516 					{
  2517 					_LIT(halfDuplexText2,"Half Duplex Text 2");
  2518 					TBuf8<19> halfDuplexBuf2_8;
  2519 					halfDuplexBuf2_8.Copy(halfDuplexText2);
  2520 					TIicBusTransfer* tempHdTfer = new TIicBusTransfer(TIicBusTransfer::EMasterWrite, 8, &halfDuplexBuf2_8);
  2521 					if(tempHdTfer == NULL)
  2522 						{
  2523 						CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - tempHdTfer=NULL\n"));
  2524 						r = KErrNoMemory;
  2525 						}
  2526 					else
  2527 						{
  2528 						iTfer->LinkAfter(tempHdTfer);
  2529 						}
  2530 					}
  2531 				if(r == KErrNone)
  2532 					{
  2533 					_LIT(fullDuplexText1,"Full Duplex Text 1");
  2534 					TBuf8<19> fullDuplexBuf1_8;
  2535 					fullDuplexBuf1_8.Copy(fullDuplexText1);
  2536 					iFdTfer = new TIicBusTransfer(TIicBusTransfer::EMasterRead, 8, &fullDuplexBuf1_8);
  2537 					if(iFdTfer == NULL)
  2538 						{
  2539 						CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - iFdTfer=NULL\n"));
  2540 						r = KErrNoMemory;
  2541 						}
  2542 					else
  2543 						{
  2544 						_LIT(fullDuplexText2,"Full Duplex Text 2");
  2545 						TBuf8<19> fullDuplexBuf2_8;
  2546 						fullDuplexBuf2_8.Copy(fullDuplexText2);
  2547 						TIicBusTransfer* tempFdTfer = new TIicBusTransfer(TIicBusTransfer::EMasterRead, 8, &fullDuplexBuf2_8);
  2548 						if(tempFdTfer == NULL)
  2549 							{
  2550 							CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - tempFdTfer=NULL\n"));
  2551 							r = KErrNoMemory;
  2552 							}
  2553 						else
  2554 							{
  2555 							iFdTfer->LinkAfter(tempFdTfer);
  2556 							}
  2557 						}
  2558 					}
  2559 				}
  2560 
  2561 			// Add the Header and Transfers to the Transaction
  2562 			if(r == KErrNone)
  2563 				r = iTrans->SetHalfDuplexTrans(iSpiBuf, iTfer);
  2564 				if(r != KErrNone)
  2565 					{
  2566 					CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - SetHalfDuplexTrans returned %d\n",r));
  2567 					}
  2568 
  2569 			if(r == KErrNone)
  2570 				r = iTrans->SetFullDuplexTrans(iFdTfer);
  2571 				if(r != KErrNone)
  2572 					{
  2573 					CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - SetFullDuplexTrans returned %d\n",r));
  2574 					}
  2575 
  2576 			// Specify the callback object to use
  2577 			if(r == KErrNone)
  2578 				{
  2579 				cb = new TIicBusCallback(TransModifCallback, this, iDfcQue, 5); // 5 arbitrary
  2580 				if(cb == NULL)
  2581 					{
  2582 					CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - cb=NULL\n"));
  2583 					r = KErrNoMemory;
  2584 					}
  2585 				}
  2586 
  2587 			// Since the transaction is not yet queued, should be able to modify the transfer and transaction content
  2588 			TestTransModification(iTrans, iTfer, iFdTfer, iSpiBuf);
  2589 
  2590 			// Store the relevant data in this object's iTransBufReuseData member
  2591 			iTransBufReuseData.iTransaction = iTrans;
  2592 			iTransBufReuseData.iHdTfer = iTfer;
  2593 			iTransBufReuseData.iFdTfer = iFdTfer;
  2594 			iTransBufReuseData.iHdr = iSpiBuf;
  2595 			iTransBufReuseData.iCallback = cb;
  2596 
  2597 			// Now queue the transaction. The callback function will re-apply the modification tests and delete the
  2598 			// objects created here
  2599 			// If the queueing fails, complete the test here and clean up
  2600 			r = QueueTransaction((TInt)a1, iTrans, cb);
  2601 			if(r != KErrNone)
  2602 				{
  2603 				Kern::RequestComplete(iClient, iStatus, r);
  2604 				delete iTransBufReuseData.iCallback;	// Must do this before deleting the Transaction in CleanupTransaction
  2605 				CleanupTransaction(iTrans);
  2606 				}
  2607 			break;
  2608 			}
  2609 		default:
  2610 			{
  2611 			CLIENT_PRINT(("DChannelIicClient::DoRequest - unrecognised value for aId=0x%x\n",aId));
  2612 			r=KErrArgument;
  2613 			break;
  2614 			}
  2615 		}
  2616 	return r;
  2617 	}
  2618 
  2619 
  2620 // Support for MasterSlave processing
  2621 static void MsSlaveClientCallbackFunc(TInt aChannelId, TInt aReturn, TInt aTrigger, TInt16 aRxWords, TInt16 aTxWords, TAny*	aParam)
  2622 	{
  2623 	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));
  2624 	(void)aTxWords; // Unused if CLIENT_PRINT is disabled
  2625 	(void)aRxWords; // Unused if CLIENT_PRINT is disabled
  2626 	DChannelIicClient* channel = (DChannelIicClient*)aParam;
  2627 	CLIENT_PRINT(("MsSlaveClientCallbackFunc() - channel=0x%x\n",channel));
  2628 	if(aTrigger == EAsyncCaptChan)
  2629 		{
  2630 		CLIENT_PRINT(("MsSlaveClientCallbackFunc: capture channel completed\n"));
  2631 		// Set iChannelId, and write to user-side variable.
  2632 		channel->iChannelId=aChannelId;
  2633 		TInt r=Kern::ThreadRawWrite(channel->iClient,channel->iClientChanId,&aChannelId,sizeof(TInt));
  2634 		if(r == KErrNone)
  2635 			r=aReturn;
  2636 	    channel->RequestComplete(r);	// Inform user of error
  2637 		return;
  2638 		}
  2639 	else
  2640 		{
  2641 		CLIENT_PRINT(("\nMsSlaveClientCallbackFunc: trigger condition 0x%x is not recognised \n\n",aTrigger));
  2642 		channel->RequestComplete(aReturn);	// Inform user of error
  2643 		}
  2644 	}
  2645 
  2646 void DChannelIicClient::RequestComplete(TInt r)
  2647 	{
  2648 	Kern::RequestComplete(iClient, iStatus, r);
  2649 	}
  2650 
  2651 
  2652 TInt DChannelIicClient::InitSlaveClient()
  2653 	{
  2654 	iNotif = new TIicBusSlaveCallback(MsSlaveClientCallbackFunc, (TAny*)this, iDfcQue, KIicSlaveClientDfcPriority);
  2655 	if(iNotif == NULL)
  2656 		{
  2657 		CLIENT_PRINT(("> DChannelIicClient::InitSlaveClient ERROR unable to allocate space TIicBusSlaveCallback* iNotif \n"));
  2658 		return KErrNoMemory;
  2659 		}
  2660 	return KErrNone;
  2661 	}
  2662