os/kernelhwsrv/kerneltest/e32test/iic/iic_psl/iic_slaveclient.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// e32test/iic/iic_slaveclient.cpp
sl@0
    15
// Simulated client of IIC Platform Independent Layer (PIL) Slave functionality
sl@0
    16
//
sl@0
    17
sl@0
    18
#include <kernel/kern_priv.h>		// for DThread, TDfc
sl@0
    19
#ifdef STANDALONE_CHANNEL
sl@0
    20
#include <drivers/iic_transaction.h>
sl@0
    21
#else
sl@0
    22
#include <drivers/iic.h>
sl@0
    23
#endif
sl@0
    24
#include "../t_iic.h"
sl@0
    25
sl@0
    26
#ifdef STANDALONE_CHANNEL
sl@0
    27
#include <drivers/iic_channel.h>
sl@0
    28
#include "i2c.h"
sl@0
    29
#endif
sl@0
    30
#ifdef LOG_SLAVECLIENT
sl@0
    31
#define CLIENT_PRINT(str) Kern::Printf str
sl@0
    32
#else
sl@0
    33
#define CLIENT_PRINT(str)
sl@0
    34
#endif
sl@0
    35
sl@0
    36
//For channel creation
sl@0
    37
#ifdef STANDALONE_CHANNEL
sl@0
    38
#define NUM_CHANNELS 3 // Arbitrary
sl@0
    39
sl@0
    40
#if defined(MASTER_MODE) && !defined(SLAVE_MODE)
sl@0
    41
const TInt KChannelTypeArray[NUM_CHANNELS] = {DIicBusChannel::EMaster, DIicBusChannel::EMaster, DIicBusChannel::EMaster};
sl@0
    42
#elif defined(MASTER_MODE) && defined(SLAVE_MODE)
sl@0
    43
const TInt KChannelTypeArray[NUM_CHANNELS] = {DIicBusChannel::EMaster, DIicBusChannel::ESlave, DIicBusChannel::EMasterSlave};
sl@0
    44
#else
sl@0
    45
const TInt KChannelTypeArray[NUM_CHANNELS] = {DIicBusChannel::ESlave, DIicBusChannel::ESlave, DIicBusChannel::ESlave};
sl@0
    46
#endif
sl@0
    47
#define CHANNEL_TYPE(n) (KChannelTypeArray[n])
sl@0
    48
#define CHANNEL_DUPLEX(n) (DIicBusChannel::EHalfDuplex)
sl@0
    49
#define BUS_TYPE (DIicBusChannel::EI2c)
sl@0
    50
sl@0
    51
#if defined(MASTER_MODE)
sl@0
    52
const TInt8 KI2cChannelNumBase = 10;	// Arbitrary, real platform may consult the Configuration Repository
sl@0
    53
										// Note limit of 5 bit representation (0-31)
sl@0
    54
sl@0
    55
#else
sl@0
    56
const TInt8 KI2cChannelNumBase = 10 + NUM_CHANNELS;	// For Slave mode, want to provide different response
sl@0
    57
													// If client assumes Master mode, should be informed not available
sl@0
    58
#endif/*MASTER_MODE*/
sl@0
    59
sl@0
    60
LOCAL_C TInt8 AssignChanNumI2c()
sl@0
    61
	{
sl@0
    62
	static TInt8 iBaseChanNumI2c = KI2cChannelNumBase;
sl@0
    63
	CLIENT_PRINT(("I2C AssignChanNum - on entry, iBaseChanNum = 0x%x\n",iBaseChanNumI2c));
sl@0
    64
	return iBaseChanNumI2c++; // Arbitrary, for illustration
sl@0
    65
	}
sl@0
    66
sl@0
    67
class DIicSlaveClientChan : public DBase
sl@0
    68
	{
sl@0
    69
public:
sl@0
    70
	DIicSlaveClientChan(DIicBusChannel* aChan, TInt8 aChanNum, TInt aChanType):iChan(aChan),iChanNumber(aChanNum),iChanType(aChanType){};
sl@0
    71
	~DIicSlaveClientChan();
sl@0
    72
	TInt GetChanNum()const {return iChanNumber;};
sl@0
    73
	TInt GetChanType()const {return iChanType;};
sl@0
    74
	DIicBusChannel* GetChannelPtr(){return iChan;};
sl@0
    75
private:
sl@0
    76
	TInt8 iChanNumber;
sl@0
    77
	TInt iChanType;
sl@0
    78
	DIicBusChannel* iChan;
sl@0
    79
	};
sl@0
    80
sl@0
    81
DIicSlaveClientChan::~DIicSlaveClientChan()
sl@0
    82
	{
sl@0
    83
	if(iChan)
sl@0
    84
		delete iChan;
sl@0
    85
	}
sl@0
    86
sl@0
    87
#endif/*STANDALONE_CHANNEL*/
sl@0
    88
sl@0
    89
const TInt KIicSlaveClientThreadPriority = 24;
sl@0
    90
sl@0
    91
const TInt KIicSlaveClientDfcPriority = 3; // 0 to 7, 7 is highest
sl@0
    92
sl@0
    93
const TInt KMaxNumChannels = 2;	// 1 "true" slave, one "dummy"
sl@0
    94
sl@0
    95
#ifdef STANDALONE_CHANNEL
sl@0
    96
_LIT(KLddRootName,"iic_slaveclient_ctrless");
sl@0
    97
#else
sl@0
    98
_LIT(KLddRootName,"iic_slaveclient");
sl@0
    99
#endif
sl@0
   100
_LIT(KIicSlaveClientThreadName,"IicSlaveClientLddThread");
sl@0
   101
sl@0
   102
sl@0
   103
struct TCapsIicSlaveClient
sl@0
   104
    {
sl@0
   105
    TVersion version;
sl@0
   106
    };
sl@0
   107
sl@0
   108
sl@0
   109
class DDeviceIicSlaveClient : public DLogicalDevice
sl@0
   110
    {
sl@0
   111
    public:
sl@0
   112
    /**
sl@0
   113
     * The constructor
sl@0
   114
     */
sl@0
   115
    DDeviceIicSlaveClient();
sl@0
   116
    /**
sl@0
   117
     * The destructor
sl@0
   118
     */
sl@0
   119
    ~DDeviceIicSlaveClient();
sl@0
   120
    /**
sl@0
   121
     * Second stage constructor - install the device
sl@0
   122
     */
sl@0
   123
    virtual TInt Install();
sl@0
   124
    /**
sl@0
   125
     * Get the Capabilites of the device
sl@0
   126
     * @param aDes descriptor that will contain the returned capibilites
sl@0
   127
     */
sl@0
   128
    virtual void GetCaps(TDes8 &aDes) const;
sl@0
   129
    /**
sl@0
   130
     * Create a logical channel to the device
sl@0
   131
     */
sl@0
   132
    virtual TInt Create(DLogicalChannelBase*& aChannel);
sl@0
   133
    };
sl@0
   134
sl@0
   135
sl@0
   136
class DChannelIicSlaveClient : public DLogicalChannel
sl@0
   137
    {
sl@0
   138
    public:
sl@0
   139
    DChannelIicSlaveClient();
sl@0
   140
    ~DChannelIicSlaveClient();
sl@0
   141
sl@0
   142
    virtual TInt DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer);
sl@0
   143
sl@0
   144
	void RequestComplete(TInt r);
sl@0
   145
	TInt CheckDataWritten();
sl@0
   146
	TInt CheckDataRead();
sl@0
   147
sl@0
   148
	static void SlaveClientCallbackFunc(TInt aChannelId, TInt aReturn, TInt aTrigger, TInt16 aRxWords, TInt16 aTxWords, TAny*	aParam);
sl@0
   149
#ifdef STANDALONE_CHANNEL
sl@0
   150
	static TInt OrderEntries(const DIicSlaveClientChan& aMatch, const DIicSlaveClientChan& aEntry);
sl@0
   151
#endif
sl@0
   152
    protected:
sl@0
   153
    virtual void HandleMsg(TMessageBase* aMsg);	// Note: this is a pure virtual in DLogicalChannel
sl@0
   154
sl@0
   155
	TInt DoControl(TInt aId, TAny* a1, TAny* a2); // Name for convenience!
sl@0
   156
    TInt DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2); // Name for convenience!
sl@0
   157
sl@0
   158
	private:
sl@0
   159
	TInt InitSlaveClient();
sl@0
   160
	TInt CbProcessOverUnderRunRxTx();
sl@0
   161
	TInt RegisterRxBuffer(TInt aChannelId, TPtr8 aRxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset);
sl@0
   162
	TInt SetNotificationTrigger(TInt aChannelId, TInt aTrigger);
sl@0
   163
	TInt StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2);
sl@0
   164
	TInt RegisterTxBuffer(TInt aChannelId, TPtr8 aTxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset);
sl@0
   165
	TInt CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch=NULL);
sl@0
   166
	TInt ReleaseChannel(TInt aChannelId);
sl@0
   167
	private:
sl@0
   168
	TDynamicDfcQue* iDfcQue;
sl@0
   169
	TIicBusSlaveCallback* iNotif;
sl@0
   170
sl@0
   171
	HBuf8* iConfigHdr;
sl@0
   172
	TRequestStatus* iStatus;
sl@0
   173
sl@0
   174
	TUint8* iRxBuf;
sl@0
   175
	TUint8* iTxBuf;
sl@0
   176
sl@0
   177
	TUint8* iBusTxCheckBuf;
sl@0
   178
sl@0
   179
	TInt8 iNumRegRxWords;
sl@0
   180
	TInt8 iNumRegTxWords;
sl@0
   181
sl@0
   182
	TInt8 iTxRegGranularity;
sl@0
   183
	TInt8 iTxRegOffset;
sl@0
   184
	TInt8 iTxReqNumWords;
sl@0
   185
sl@0
   186
	TInt8 iRxRegGranularity;
sl@0
   187
	TInt8 iRxRegOffset;
sl@0
   188
	TInt8 iRxReqNumWords;
sl@0
   189
sl@0
   190
	TUint iBusId;
sl@0
   191
#ifdef STANDALONE_CHANNEL
sl@0
   192
	// For some slave-channel-only functions,e.g. ReleaseChannel, RegisterRxBuffer, etc.
sl@0
   193
	// the client needs to remember the slave channel that has been captured
sl@0
   194
	struct TCapturedChannel
sl@0
   195
		{
sl@0
   196
		DIicSlaveClientChan* iChannel;
sl@0
   197
		TInt iChannelId;
sl@0
   198
		};
sl@0
   199
	TCapturedChannel iCapturedChan;
sl@0
   200
#endif
sl@0
   201
	public:
sl@0
   202
	DThread* iClient;
sl@0
   203
	TInt iChannelId;	// public to be accessible by callback
sl@0
   204
	TInt* iClientChanId;
sl@0
   205
sl@0
   206
	TInt iExpectedTrigger;
sl@0
   207
	TInt iFullDuplexReq;
sl@0
   208
	TInt iBlockedTrigger;
sl@0
   209
sl@0
   210
	typedef enum TTestOverUnderState
sl@0
   211
		{
sl@0
   212
		EStartState  = 0x1,
sl@0
   213
		ERxOverrun_1,
sl@0
   214
		ERxOverrun_2,
sl@0
   215
		ETxUnderrun_1,
sl@0
   216
		ETxUnderrun_2
sl@0
   217
		};
sl@0
   218
	TTestOverUnderState iTestOverUnderState;
sl@0
   219
	};
sl@0
   220
sl@0
   221
DDeviceIicSlaveClient::DDeviceIicSlaveClient()
sl@0
   222
// Constructor
sl@0
   223
    {
sl@0
   224
	CLIENT_PRINT(("> DDeviceIicSlaveClient::DDeviceIicSlaveClient()"));
sl@0
   225
    iParseMask=0;		// No info, no PDD, no Units
sl@0
   226
    iUnitsMask=0;
sl@0
   227
    iVersion=TVersion(KIicClientMajorVersionNumber,
sl@0
   228
		      KIicClientMinorVersionNumber,
sl@0
   229
		      KIicClientBuildVersionNumber);
sl@0
   230
    }
sl@0
   231
sl@0
   232
#ifdef STANDALONE_CHANNEL
sl@0
   233
//Store all the channels created by the client into an array
sl@0
   234
RPointerArray<DIicSlaveClientChan> ChannelArray;
sl@0
   235
#endif
sl@0
   236
DDeviceIicSlaveClient::~DDeviceIicSlaveClient()
sl@0
   237
// Destructor
sl@0
   238
    {
sl@0
   239
	CLIENT_PRINT(("> DDeviceIicSlaveClient::~DDeviceIicSlaveClient()"));
sl@0
   240
#ifdef STANDALONE_CHANNEL
sl@0
   241
	//The client is reponsible for channel destroy in STANDALONE_CHANNEL mode
sl@0
   242
    ChannelArray.ResetAndDestroy();
sl@0
   243
#endif
sl@0
   244
	}
sl@0
   245
sl@0
   246
TInt DDeviceIicSlaveClient::Install()
sl@0
   247
// Install the device driver.
sl@0
   248
    {
sl@0
   249
	CLIENT_PRINT(("> DDeviceIicSlaveClient::Install()"));
sl@0
   250
sl@0
   251
    return(SetName(&KLddRootName));
sl@0
   252
    }
sl@0
   253
sl@0
   254
sl@0
   255
void DDeviceIicSlaveClient::GetCaps(TDes8& aDes) const
sl@0
   256
// Return the IicClient capabilities.
sl@0
   257
    {
sl@0
   258
	CLIENT_PRINT(("> DDeviceIicSlaveClient::GetCaps(TDes8& aDes) const"));
sl@0
   259
    TPckgBuf<TCapsIicSlaveClient> b;
sl@0
   260
    b().version=TVersion(KIicClientMajorVersionNumber,
sl@0
   261
			 KIicClientMinorVersionNumber,
sl@0
   262
			 KIicClientBuildVersionNumber);
sl@0
   263
    Kern::InfoCopy(aDes,b);
sl@0
   264
    }
sl@0
   265
sl@0
   266
sl@0
   267
TInt DDeviceIicSlaveClient::Create(DLogicalChannelBase*& aChannel)
sl@0
   268
// Create a channel on the device.
sl@0
   269
    {
sl@0
   270
	CLIENT_PRINT(("> DDeviceIicSlaveClient::Create(DLogicalChannelBase*& aChannel)"));
sl@0
   271
	if(iOpenChannels>=KMaxNumChannels)
sl@0
   272
		return KErrOverflow;
sl@0
   273
    aChannel=new DChannelIicSlaveClient;
sl@0
   274
    return aChannel?KErrNone:KErrNoMemory;
sl@0
   275
    }
sl@0
   276
sl@0
   277
#ifdef STANDALONE_CHANNEL
sl@0
   278
//  auxiliary function for ordering entries in the array of channels
sl@0
   279
TInt DChannelIicSlaveClient::OrderEntries(const DIicSlaveClientChan& aMatch, const DIicSlaveClientChan& aEntry)
sl@0
   280
	{
sl@0
   281
	TUint8 l=(TUint8)aMatch.GetChanNum();
sl@0
   282
	TUint8 r=(TUint8)aEntry.GetChanNum();
sl@0
   283
	if(l>r)
sl@0
   284
		return -1;
sl@0
   285
	else if(l<r)
sl@0
   286
		return 1;
sl@0
   287
	else
sl@0
   288
		return 0;
sl@0
   289
	}
sl@0
   290
sl@0
   291
// global ordering object to be passed to RPointerArray InsertInOrderXXX and FindInOrder
sl@0
   292
TLinearOrder<DIicSlaveClientChan> EntryOrder(DChannelIicSlaveClient::OrderEntries);
sl@0
   293
sl@0
   294
TInt GetChanPtr(const TInt aBusId, DIicSlaveClientChan*& aChan)
sl@0
   295
	{
sl@0
   296
    __KTRACE_OPT(KIIC, 	Kern::Printf("GetChanPtr, aBusId=0x%x\n",aBusId));
sl@0
   297
	TInt32 chanId;
sl@0
   298
	chanId = GET_CHAN_NUM(aBusId);
sl@0
   299
    __KTRACE_OPT(KIIC, 	Kern::Printf("GetChanPtr, chanId=0x%x\n",chanId));
sl@0
   300
	DIicSlaveClientChan chanEntry(NULL,(TInt8)chanId, DIicBusChannel::EMasterSlave);
sl@0
   301
sl@0
   302
	TInt r = KErrNotFound;
sl@0
   303
	TInt aIndex = ChannelArray.FindInOrder(&chanEntry, EntryOrder);
sl@0
   304
sl@0
   305
	if(aIndex >= 0)
sl@0
   306
		{
sl@0
   307
		aChan = ChannelArray[aIndex];
sl@0
   308
		r = KErrNone;
sl@0
   309
		}
sl@0
   310
sl@0
   311
	return r;
sl@0
   312
	}
sl@0
   313
#endif/*STANDALONE_CHANNEL*/
sl@0
   314
sl@0
   315
DECLARE_STANDARD_LDD()
sl@0
   316
	{
sl@0
   317
#ifdef STANDALONE_CHANNEL
sl@0
   318
	TInt r = KErrNone;
sl@0
   319
	DIicBusChannel *chan = NULL, *chanM = NULL, *chanS = NULL;
sl@0
   320
	DIicSlaveClientChan* aSlaveClientChan;
sl@0
   321
	for(TInt i=0; i<NUM_CHANNELS; i++)
sl@0
   322
			{
sl@0
   323
			CLIENT_PRINT(("\n"));
sl@0
   324
	#if defined(MASTER_MODE)
sl@0
   325
			if(CHANNEL_TYPE(i) == (DIicBusChannel::EMaster))
sl@0
   326
				{
sl@0
   327
				chan=new DSimulatedIicBusChannelMasterI2c(BUS_TYPE,CHANNEL_DUPLEX(i));
sl@0
   328
				if(!chan)
sl@0
   329
					{
sl@0
   330
					CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE(i),i));
sl@0
   331
					return NULL;
sl@0
   332
					}
sl@0
   333
				CLIENT_PRINT(("I2C chan created at 0x%x\n",chan));
sl@0
   334
				if(((DSimulatedIicBusChannelMasterI2c*)chan)->Create()!=KErrNone)
sl@0
   335
					{
sl@0
   336
					delete chan;
sl@0
   337
					return NULL;
sl@0
   338
					}
sl@0
   339
				aSlaveClientChan = new DIicSlaveClientChan(chan,AssignChanNumI2c(),DIicBusChannel::EMaster);
sl@0
   340
				if(!aSlaveClientChan)
sl@0
   341
					{
sl@0
   342
					delete chan;
sl@0
   343
					return NULL;
sl@0
   344
					}
sl@0
   345
				r = ChannelArray.InsertInOrder(aSlaveClientChan,EntryOrder);
sl@0
   346
				if(r!=KErrNone)
sl@0
   347
					{
sl@0
   348
					delete chan;
sl@0
   349
					delete aSlaveClientChan;
sl@0
   350
					break;
sl@0
   351
					}
sl@0
   352
				}
sl@0
   353
	#endif
sl@0
   354
	#if defined(MASTER_MODE) && defined(SLAVE_MODE)
sl@0
   355
			if(CHANNEL_TYPE(i) == DIicBusChannel::EMasterSlave)
sl@0
   356
				{
sl@0
   357
				chanM=new DSimulatedIicBusChannelMasterI2c(BUS_TYPE,CHANNEL_DUPLEX(i));
sl@0
   358
				if(!chanM)
sl@0
   359
					return NULL;
sl@0
   360
				chanS=new DSimulatedIicBusChannelSlaveI2c(BUS_TYPE,CHANNEL_DUPLEX(i));
sl@0
   361
				if(!chanS)
sl@0
   362
					{
sl@0
   363
					delete chanM;
sl@0
   364
					return NULL;
sl@0
   365
					}
sl@0
   366
				chan=new DSimulatedIicBusChannelMasterSlaveI2c(BUS_TYPE,CHANNEL_DUPLEX(i),(DSimulatedIicBusChannelMasterI2c*)chanM,(DSimulatedIicBusChannelSlaveI2c*)chanS); // Generic implementation
sl@0
   367
				if(!chan)
sl@0
   368
					{
sl@0
   369
					CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE(i),i));
sl@0
   370
					delete chanM;
sl@0
   371
					delete chanS;
sl@0
   372
					return NULL;
sl@0
   373
					}
sl@0
   374
				CLIENT_PRINT(("I2C chan created at 0x%x\n",chan));
sl@0
   375
				if(((DIicBusChannelMasterSlave*)chan)->DoCreate()!=KErrNone)
sl@0
   376
					{
sl@0
   377
					delete chanM;
sl@0
   378
					delete chanS;
sl@0
   379
					delete chan;
sl@0
   380
					return NULL;
sl@0
   381
					}
sl@0
   382
				aSlaveClientChan = new DIicSlaveClientChan(chan,AssignChanNumI2c(),DIicBusChannel::EMasterSlave);
sl@0
   383
				if(!aSlaveClientChan)
sl@0
   384
					{
sl@0
   385
					delete chanM;
sl@0
   386
					delete chanS;
sl@0
   387
					delete chan;
sl@0
   388
					return NULL;
sl@0
   389
					}
sl@0
   390
				r = ChannelArray.InsertInOrder(aSlaveClientChan,EntryOrder);
sl@0
   391
				if(r!=KErrNone)
sl@0
   392
					{
sl@0
   393
					delete chanM;
sl@0
   394
					delete chanS;
sl@0
   395
					delete chan;
sl@0
   396
					delete aSlaveClientChan;
sl@0
   397
					break;
sl@0
   398
					}
sl@0
   399
				}
sl@0
   400
	#endif
sl@0
   401
	#if defined(SLAVE_MODE)
sl@0
   402
			if(CHANNEL_TYPE(i) == (DIicBusChannel::ESlave))
sl@0
   403
				{
sl@0
   404
				chan=new DSimulatedIicBusChannelSlaveI2c(BUS_TYPE,CHANNEL_DUPLEX(i));
sl@0
   405
				if(!chan)
sl@0
   406
					{
sl@0
   407
					CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE(i),i));
sl@0
   408
					return NULL;
sl@0
   409
					}
sl@0
   410
				CLIENT_PRINT(("I2C chan created at 0x%x\n",chan));
sl@0
   411
				if(((DSimulatedIicBusChannelSlaveI2c*)chan)->Create()!=KErrNone)
sl@0
   412
					return NULL;
sl@0
   413
				aSlaveClientChan = new DIicSlaveClientChan(chan,AssignChanNumI2c(),DIicBusChannel::ESlave);
sl@0
   414
				if(!aSlaveClientChan)
sl@0
   415
					{
sl@0
   416
					delete chan;
sl@0
   417
					return NULL;
sl@0
   418
					}
sl@0
   419
				r = ChannelArray.InsertInOrder(aSlaveClientChan,EntryOrder);
sl@0
   420
				if(r!=KErrNone)
sl@0
   421
					{
sl@0
   422
					delete chan;
sl@0
   423
					delete aSlaveClientChan;
sl@0
   424
					break;
sl@0
   425
					}
sl@0
   426
				}
sl@0
   427
	#endif
sl@0
   428
	#if !defined(MASTER_MODE) && !defined(SLAVE_MODE)
sl@0
   429
	#error I2C mode not defined as Master, Slave nor Master-Slave
sl@0
   430
	#endif
sl@0
   431
			}
sl@0
   432
#endif
sl@0
   433
	return new DDeviceIicSlaveClient;
sl@0
   434
	}
sl@0
   435
sl@0
   436
sl@0
   437
sl@0
   438
DChannelIicSlaveClient::DChannelIicSlaveClient()
sl@0
   439
// Constructor
sl@0
   440
    {
sl@0
   441
	iFullDuplexReq=iBlockedTrigger=iExpectedTrigger=0;
sl@0
   442
	CLIENT_PRINT(("> DChannelIicSlaveClient::DChannelIicSlaveClient()"));
sl@0
   443
    iClient=&Kern::CurrentThread();
sl@0
   444
	// Increase the DThread's ref count so that it does not close without us
sl@0
   445
	iClient->Open();
sl@0
   446
	iTestOverUnderState = EStartState;
sl@0
   447
    }
sl@0
   448
sl@0
   449
DChannelIicSlaveClient::~DChannelIicSlaveClient()
sl@0
   450
// Destructor
sl@0
   451
    {
sl@0
   452
	CLIENT_PRINT(("> DChannelIicSlaveClient::~DChannelIicSlaveClient()"));
sl@0
   453
	iDfcQue->Destroy();
sl@0
   454
	delete iNotif;
sl@0
   455
	delete iRxBuf;
sl@0
   456
	delete iTxBuf;
sl@0
   457
	delete iBusTxCheckBuf;
sl@0
   458
	// decrement the DThread's reference count
sl@0
   459
	Kern::SafeClose((DObject*&)iClient, NULL);
sl@0
   460
	}
sl@0
   461
sl@0
   462
void DChannelIicSlaveClient::RequestComplete(TInt r)
sl@0
   463
	{
sl@0
   464
	Kern::RequestComplete(iClient, iStatus, r);
sl@0
   465
	}
sl@0
   466
sl@0
   467
TInt DChannelIicSlaveClient::RegisterRxBuffer(TInt aChannelId, TPtr8 aRxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
sl@0
   468
	{
sl@0
   469
	TInt r = KErrNone;
sl@0
   470
#ifdef STANDALONE_CHANNEL
sl@0
   471
	DIicSlaveClientChan* aChanPtr = NULL;
sl@0
   472
	if(iCapturedChan.iChannelId == aChannelId)
sl@0
   473
		aChanPtr = iCapturedChan.iChannel;
sl@0
   474
	if(!aChanPtr)
sl@0
   475
		return KErrArgument;
sl@0
   476
	if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave)
sl@0
   477
		r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->RegisterRxBuffer(aRxBuffer, aBufGranularity, aNumWords, aOffset);
sl@0
   478
	else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave)
sl@0
   479
		r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->RegisterRxBuffer(aRxBuffer, aBufGranularity, aNumWords, aOffset);
sl@0
   480
#else
sl@0
   481
	r = IicBus::RegisterRxBuffer(aChannelId, aRxBuffer, aBufGranularity, aNumWords, aOffset);
sl@0
   482
#endif
sl@0
   483
	return r;
sl@0
   484
	}
sl@0
   485
sl@0
   486
TInt DChannelIicSlaveClient::SetNotificationTrigger(TInt aChannelId, TInt aTrigger)
sl@0
   487
	{
sl@0
   488
	TInt r = KErrNone;
sl@0
   489
#ifdef STANDALONE_CHANNEL
sl@0
   490
	DIicSlaveClientChan* aChanPtr = NULL;
sl@0
   491
	if(iCapturedChan.iChannelId == aChannelId)
sl@0
   492
		aChanPtr = iCapturedChan.iChannel;
sl@0
   493
	if(!aChanPtr)
sl@0
   494
		return KErrArgument;
sl@0
   495
	if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave)
sl@0
   496
		r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->SetNotificationTrigger(aTrigger);
sl@0
   497
	else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave)
sl@0
   498
		r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->SetNotificationTrigger(aTrigger);
sl@0
   499
#else
sl@0
   500
	r = IicBus::SetNotificationTrigger(aChannelId, aTrigger);
sl@0
   501
#endif
sl@0
   502
	return r;
sl@0
   503
	}
sl@0
   504
sl@0
   505
TInt DChannelIicSlaveClient::StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2)
sl@0
   506
	{
sl@0
   507
	TInt r = KErrNone;
sl@0
   508
#ifdef STANDALONE_CHANNEL
sl@0
   509
	DIicSlaveClientChan* aChanPtr;
sl@0
   510
	r = GetChanPtr(aId, aChanPtr);
sl@0
   511
	if(r != KErrNone)
sl@0
   512
		return r;
sl@0
   513
	if(!aChanPtr)
sl@0
   514
		return KErrArgument;
sl@0
   515
	if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave)
sl@0
   516
		r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->StaticExtension(aFunction, aParam1, aParam2);
sl@0
   517
	else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave)
sl@0
   518
	r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->StaticExtension(aFunction, aParam1, aParam2);
sl@0
   519
#else
sl@0
   520
	r = IicBus::StaticExtension(aId, aFunction, aParam1, aParam2);
sl@0
   521
#endif
sl@0
   522
	return r;
sl@0
   523
	}
sl@0
   524
sl@0
   525
TInt DChannelIicSlaveClient::RegisterTxBuffer(TInt aChannelId, TPtr8 aTxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
sl@0
   526
	{
sl@0
   527
	TInt r = KErrNone;
sl@0
   528
#ifdef STANDALONE_CHANNEL
sl@0
   529
	DIicSlaveClientChan* aChanPtr = NULL;
sl@0
   530
	if(iCapturedChan.iChannelId == aChannelId)
sl@0
   531
		aChanPtr = iCapturedChan.iChannel;
sl@0
   532
	if(!aChanPtr)
sl@0
   533
		return KErrArgument;
sl@0
   534
	if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave)
sl@0
   535
		r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->RegisterTxBuffer(aTxBuffer, aBufGranularity, aNumWords, aOffset);
sl@0
   536
	else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave)
sl@0
   537
		r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->RegisterTxBuffer(aTxBuffer, aBufGranularity, aNumWords, aOffset);
sl@0
   538
#else
sl@0
   539
	r = IicBus::RegisterTxBuffer(aChannelId, aTxBuffer, aBufGranularity, aNumWords, aOffset);
sl@0
   540
#endif
sl@0
   541
	return r;
sl@0
   542
	}
sl@0
   543
sl@0
   544
TInt DChannelIicSlaveClient::CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch)
sl@0
   545
	{
sl@0
   546
	TInt r = KErrNone;
sl@0
   547
#ifndef STANDALONE_CHANNEL
sl@0
   548
	r = IicBus::CaptureChannel(aBusId, aConfigHdr, aCallback, aChannelId, aAsynch);
sl@0
   549
#else
sl@0
   550
	// Check that that aCallback!=NULL and aConfigHdr!=NULL - if not, return KErrArgument
sl@0
   551
	if(!aCallback || !aConfigHdr)
sl@0
   552
		{
sl@0
   553
		return KErrArgument;
sl@0
   554
		}
sl@0
   555
sl@0
   556
	// Get the channel
sl@0
   557
	DIicSlaveClientChan* chanPtr = NULL;
sl@0
   558
	if(r == KErrNone)
sl@0
   559
		{
sl@0
   560
		r = GetChanPtr(aBusId, chanPtr);
sl@0
   561
		if(r == KErrNone)
sl@0
   562
			{
sl@0
   563
			if(!chanPtr)
sl@0
   564
				{
sl@0
   565
				r = KErrArgument;
sl@0
   566
				}
sl@0
   567
			else
sl@0
   568
				{
sl@0
   569
				switch(chanPtr->GetChanType())
sl@0
   570
					{
sl@0
   571
					// CaptureChannel requests are only supported by channels in Slave mode.
sl@0
   572
					case DIicBusChannel::EMaster:
sl@0
   573
						{
sl@0
   574
						r = KErrNotSupported;
sl@0
   575
						break;
sl@0
   576
						}
sl@0
   577
					case DIicBusChannel::EMasterSlave:
sl@0
   578
						{
sl@0
   579
						r = ((DIicBusChannelMasterSlave*) (chanPtr->GetChannelPtr()))->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch);
sl@0
   580
						break;
sl@0
   581
						}
sl@0
   582
					case DIicBusChannel::ESlave:
sl@0
   583
						{
sl@0
   584
						r = ((DIicBusChannelSlave*) (chanPtr->GetChannelPtr()))->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch);
sl@0
   585
						break;
sl@0
   586
						}
sl@0
   587
					default:
sl@0
   588
						{
sl@0
   589
						r = KErrArgument;
sl@0
   590
						}
sl@0
   591
					}
sl@0
   592
				// For synchronous capture, if successful then install the channel
sl@0
   593
				if(r == KErrNone)
sl@0
   594
					{
sl@0
   595
					if(!aAsynch)
sl@0
   596
						{
sl@0
   597
						 iCapturedChan.iChannel = chanPtr;
sl@0
   598
						 iCapturedChan.iChannelId = aChannelId;
sl@0
   599
						}
sl@0
   600
					else
sl@0
   601
						//For asynchronous capture, record slaveChanPtr, if later failed capture,
sl@0
   602
						//clean iCapturedChannel in client's callback.
sl@0
   603
						iCapturedChan.iChannel = chanPtr;
sl@0
   604
					}
sl@0
   605
				}
sl@0
   606
			}
sl@0
   607
		}
sl@0
   608
#endif
sl@0
   609
	return r;
sl@0
   610
	}
sl@0
   611
sl@0
   612
TInt DChannelIicSlaveClient::ReleaseChannel(TInt aChannelId)
sl@0
   613
	{
sl@0
   614
	TInt r = KErrNone;
sl@0
   615
#ifndef STANDALONE_CHANNEL
sl@0
   616
	r = IicBus::ReleaseChannel(aChannelId);
sl@0
   617
#else
sl@0
   618
    __KTRACE_OPT(KIIC, Kern::Printf("DChannelIicSlaveClient::ReleaseChannel, channelID = 0x%x \n",aChannelId));
sl@0
   619
    // Acquire the pointer to the Slave Channel
sl@0
   620
    if(iCapturedChan.iChannelId != aChannelId)
sl@0
   621
		return KErrNotFound;
sl@0
   622
sl@0
   623
	if((iCapturedChan.iChannel)->GetChanType() == DIicBusChannel::EMasterSlave)
sl@0
   624
		r = ((DIicBusChannelMasterSlave*)((iCapturedChan.iChannel)->GetChannelPtr()))->ReleaseChannel();
sl@0
   625
	else if((iCapturedChan.iChannel)->GetChanType() == DIicBusChannel::ESlave)
sl@0
   626
		r = ((DIicBusChannelSlave*)((iCapturedChan.iChannel)->GetChannelPtr()))->ReleaseChannel();
sl@0
   627
	//After release channel, reset iCapturedChan
sl@0
   628
	iCapturedChan.iChannel = NULL;
sl@0
   629
	iCapturedChan.iChannelId = 0;
sl@0
   630
#endif
sl@0
   631
	return r;
sl@0
   632
	}
sl@0
   633
TInt DChannelIicSlaveClient::CbProcessOverUnderRunRxTx()
sl@0
   634
	{
sl@0
   635
	CLIENT_PRINT(("> DChannelIicSlaveClient::CbProcessOverUnderRunRxTx(), iTestOverUnderState=%d\n",iTestOverUnderState));
sl@0
   636
	TInt r = KErrNone;
sl@0
   637
	switch (iTestOverUnderState)
sl@0
   638
		{
sl@0
   639
		case(EStartState):
sl@0
   640
			{
sl@0
   641
			// In this state, no action is required
sl@0
   642
			break;
sl@0
   643
			};
sl@0
   644
		case(ERxOverrun_1):
sl@0
   645
			{
sl@0
   646
			CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ERxOverrun_1\n"));
sl@0
   647
			// At this point, the outstanding request trigger should be ETxAllBytes | ETxUnderrun
sl@0
   648
			// and the flag to indicate duplex transfers should be cleared
sl@0
   649
			if((iExpectedTrigger != (ETxAllBytes | ETxUnderrun)) || (iFullDuplexReq != ETxAllBytes))
sl@0
   650
				{
sl@0
   651
				CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq));
sl@0
   652
				r=KErrGeneral;
sl@0
   653
				}
sl@0
   654
			else
sl@0
   655
				{
sl@0
   656
				// Simulate providing a new buffer (actually, re-use existing buffer)
sl@0
   657
				CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterRxBuffer\n"));
sl@0
   658
				TPtr8 rxPtr(iRxBuf,KRxBufSizeInBytes);
sl@0
   659
				r = RegisterRxBuffer(iChannelId, rxPtr, iRxRegGranularity, iNumRegRxWords, iRxRegOffset);
sl@0
   660
sl@0
   661
				if(r != KErrNone)
sl@0
   662
					{
sl@0
   663
					CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterRxBuffer returned %d\n",r));
sl@0
   664
					}
sl@0
   665
				else
sl@0
   666
					{
sl@0
   667
					// For the next step, just specify the new Rx triggers (do not specify Tx triggers)
sl@0
   668
					r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun));
sl@0
   669
					if(r != KErrNone)
sl@0
   670
						{
sl@0
   671
						CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d\n",r));
sl@0
   672
						}
sl@0
   673
					else
sl@0
   674
						{
sl@0
   675
						iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun;
sl@0
   676
						iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
sl@0
   677
						iTestOverUnderState = ERxOverrun_2;	// Prepare for callback
sl@0
   678
						// The requested number of words when the buffer was registered was 8, so simulate 10
sl@0
   679
						// to provoke an RxOverrun event.
sl@0
   680
						TInt numWords=10;
sl@0
   681
						// To support testing, any values of aId for StaticExtension must be shifted left one place
sl@0
   682
						// and for a Slave, the two msbs must be zero
sl@0
   683
						TInt ctrlIoVal = RBusDevIicClient::ECtrlIoRxWords;
sl@0
   684
						ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
sl@0
   685
						r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords);
sl@0
   686
						}
sl@0
   687
					}
sl@0
   688
				}
sl@0
   689
			break;
sl@0
   690
			};
sl@0
   691
		case(ERxOverrun_2):
sl@0
   692
			{
sl@0
   693
			CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ERxOverrun_2\n"));
sl@0
   694
			// At this point, the outstanding request trigger should be ETxAllBytes | ETxUnderrun
sl@0
   695
			// and the flag to indicate duplex transfers should be cleared
sl@0
   696
			if((iExpectedTrigger != (ETxAllBytes | ETxUnderrun)) || (iFullDuplexReq != ETxAllBytes))
sl@0
   697
				{
sl@0
   698
				CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq));
sl@0
   699
				r=KErrGeneral;
sl@0
   700
				}
sl@0
   701
			else
sl@0
   702
				{
sl@0
   703
				// Simulate providing a new buffer (actually, re-use existing buffer)
sl@0
   704
				CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterRxBuffer\n"));
sl@0
   705
				TPtr8 rxPtr(iRxBuf,KRxBufSizeInBytes);
sl@0
   706
				r = RegisterRxBuffer(iChannelId, rxPtr, iRxRegGranularity, iNumRegRxWords, iRxRegOffset);
sl@0
   707
				if(r != KErrNone)
sl@0
   708
					{
sl@0
   709
					CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterRxBuffer returned %d\n",r));
sl@0
   710
					}
sl@0
   711
				else
sl@0
   712
					{
sl@0
   713
					// Test that an attempt to modify existing Tx notification requests is rejected
sl@0
   714
					r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxOverrun));
sl@0
   715
					if(r != KErrInUse)
sl@0
   716
						{
sl@0
   717
						CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrInUse\n",r));
sl@0
   718
						}
sl@0
   719
					else
sl@0
   720
						{
sl@0
   721
						// For the next step, specify the new Rx triggers and the Tx triggers
sl@0
   722
						r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun));
sl@0
   723
						if(r != KErrNone)
sl@0
   724
							{
sl@0
   725
							CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrNone\n",r));
sl@0
   726
							}
sl@0
   727
						else
sl@0
   728
							{
sl@0
   729
							iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun;
sl@0
   730
							iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
sl@0
   731
							iTestOverUnderState = ETxUnderrun_1;	// Prepare for callback
sl@0
   732
							// The requested number of words when the buffer was registered was 12, so simulate 14
sl@0
   733
							// to provoke an TxUnderrun event.
sl@0
   734
							TInt numWords=14;
sl@0
   735
							// To support testing, any values of aId for StaticExtension must be shifted left one place
sl@0
   736
							// and for a Slave, the two msbs must be zero
sl@0
   737
							TInt ctrlIoVal = RBusDevIicClient::ECtrlIoTxWords;
sl@0
   738
							ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
sl@0
   739
							r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords);
sl@0
   740
							}
sl@0
   741
						}
sl@0
   742
					}
sl@0
   743
				}
sl@0
   744
			break;
sl@0
   745
			};
sl@0
   746
		case(ETxUnderrun_1):
sl@0
   747
			{
sl@0
   748
			CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ETxOverrun_1\n"));
sl@0
   749
			// At this point, the outstanding request trigger should be ERxAllBytes | ERxOverrun
sl@0
   750
			// and the flag to indicate duplex transfers should be cleared
sl@0
   751
			if((iExpectedTrigger != (ERxAllBytes | ERxOverrun)) || (iFullDuplexReq != ERxAllBytes))
sl@0
   752
				{
sl@0
   753
				CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq));
sl@0
   754
				r=KErrGeneral;
sl@0
   755
				}
sl@0
   756
			else
sl@0
   757
				{
sl@0
   758
				// Simulate providing a new buffer (actually, re-use existing buffer)
sl@0
   759
				CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterTxBuffer\n"));
sl@0
   760
				TPtr8 rxPtr(iTxBuf,KTxBufSizeInBytes);
sl@0
   761
				r = RegisterTxBuffer(iChannelId, rxPtr, iTxRegGranularity, iNumRegTxWords, iTxRegOffset);
sl@0
   762
				if(r != KErrNone)
sl@0
   763
					{
sl@0
   764
					CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterTxBuffer returned %d\n",r));
sl@0
   765
					}
sl@0
   766
				else
sl@0
   767
					{
sl@0
   768
					// For the next step, just specify the new Tx triggers (do not specify Rx triggers)
sl@0
   769
					r = SetNotificationTrigger(iChannelId, (ETxAllBytes | ETxUnderrun));
sl@0
   770
					if(r != KErrNone)
sl@0
   771
						{
sl@0
   772
						CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d\n",r));
sl@0
   773
						}
sl@0
   774
					else
sl@0
   775
						{
sl@0
   776
						iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun;
sl@0
   777
						iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
sl@0
   778
						iTestOverUnderState = ETxUnderrun_2;	// Prepare for callback
sl@0
   779
						// The requested number of words when the buffer was registered was 12, so simulate 14
sl@0
   780
						// to provoke an TxUnderrun event.
sl@0
   781
						TInt numWords=14;
sl@0
   782
						// To support testing, any values of aId for StaticExtension must be shifted left one place
sl@0
   783
						// and for a Slave, the two msbs must be zero
sl@0
   784
						TInt ctrlIoVal = RBusDevIicClient::ECtrlIoTxWords;
sl@0
   785
						ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
sl@0
   786
						r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords);
sl@0
   787
						}
sl@0
   788
					}
sl@0
   789
				}
sl@0
   790
			break;
sl@0
   791
			};
sl@0
   792
		case(ETxUnderrun_2):
sl@0
   793
			{
sl@0
   794
			CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ETxUnderrun_2\n"));
sl@0
   795
			// At this point, the outstanding request trigger should be ERxAllBytes | ERxOverrun
sl@0
   796
			// and the flag to indicate duplex transfers should be cleared
sl@0
   797
			if((iExpectedTrigger != (ERxAllBytes | ERxOverrun)) || (iFullDuplexReq != ERxAllBytes))
sl@0
   798
				{
sl@0
   799
				CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq));
sl@0
   800
				r=KErrGeneral;
sl@0
   801
				}
sl@0
   802
			else
sl@0
   803
				{
sl@0
   804
				// Simulate providing a new buffer (actually, re-use existing buffer)
sl@0
   805
				CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterRxBuffer\n"));
sl@0
   806
				TPtr8 rxPtr(iTxBuf,KTxBufSizeInBytes);
sl@0
   807
				r = RegisterTxBuffer(iChannelId, rxPtr, iTxRegGranularity, iNumRegTxWords, iTxRegOffset);
sl@0
   808
				if(r != KErrNone)
sl@0
   809
					{
sl@0
   810
					CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterTxBuffer returned %d\n",r));
sl@0
   811
					}
sl@0
   812
				else
sl@0
   813
					{
sl@0
   814
					// Test that an attempt to modify existing Rx notification requests is rejected
sl@0
   815
					r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxUnderrun | ETxAllBytes | ETxUnderrun));
sl@0
   816
					if(r != KErrInUse)
sl@0
   817
						{
sl@0
   818
						CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrInUse\n",r));
sl@0
   819
						}
sl@0
   820
					else
sl@0
   821
						{
sl@0
   822
						// For the next step, specify the new Rx triggers and the Tx triggers
sl@0
   823
						r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun));
sl@0
   824
sl@0
   825
						if(r != KErrNone)
sl@0
   826
							{
sl@0
   827
							CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrNone\n",r));
sl@0
   828
							}
sl@0
   829
						else
sl@0
   830
							{
sl@0
   831
							// Simulate a simultaneous ERxAllBytes and ETxAllBytes event.
sl@0
   832
							iExpectedTrigger = ERxAllBytes | ETxAllBytes;
sl@0
   833
							iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
sl@0
   834
							iTestOverUnderState = EStartState;	// Prepare for callback - return to normal operation
sl@0
   835
							// Need to pass the number of words in an array, for use by StaticExtension
sl@0
   836
							TInt parms[2];
sl@0
   837
							parms[0]= 8;	// Number of Rx Words
sl@0
   838
							parms[1]=12;	// Number of Tx Words
sl@0
   839
							// To support testing, any values of aId for StaticExtension must be shifted left one place
sl@0
   840
							// and for a Slave, the two msbs must be zero
sl@0
   841
							TInt ctrlIoVal = RBusDevIicClient::ECtrlIoRxTxWords;
sl@0
   842
							ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
sl@0
   843
							r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)(&parms[0]));
sl@0
   844
							}
sl@0
   845
						}
sl@0
   846
					}
sl@0
   847
				}
sl@0
   848
			break;
sl@0
   849
			};
sl@0
   850
		default:
sl@0
   851
			{
sl@0
   852
			r = KErrGeneral;
sl@0
   853
			break;
sl@0
   854
			};
sl@0
   855
		}
sl@0
   856
	return r;
sl@0
   857
	}
sl@0
   858
sl@0
   859
void DChannelIicSlaveClient::SlaveClientCallbackFunc(TInt aChannelId, TInt aReturn, TInt aTrigger, TInt16 aRxWords, TInt16 aTxWords, TAny*	aParam)
sl@0
   860
	{
sl@0
   861
	CLIENT_PRINT(("> SlaveClientCallbackFunc() - aChannelId=0x%x,aReturn=%d,aTrigger=0x%x,aRxWords=0x%x,aTxWords=0x%x,aParam=0x%x\n",aChannelId,aReturn,aTrigger,aRxWords,aTxWords,aParam));
sl@0
   862
	(void)aTxWords; // Unused if CLIENT_PRINT is undefined
sl@0
   863
	(void)aRxWords; // Unused if CLIENT_PRINT is undefined
sl@0
   864
	DChannelIicSlaveClient* channel = (DChannelIicSlaveClient*)aParam;
sl@0
   865
sl@0
   866
	// Ensure only the valid bits of aTrigger are processed
sl@0
   867
	aTrigger &= 0xff;
sl@0
   868
sl@0
   869
	CLIENT_PRINT(("SlaveClientCallbackFunc() - channel=0x%x\n",channel));
sl@0
   870
	if(aTrigger == EAsyncCaptChan)
sl@0
   871
		{
sl@0
   872
		CLIENT_PRINT(("SlaveClientCallbackFunc: capture channel completed\n"));
sl@0
   873
		// Set iChannelId, and write to user-side variable.
sl@0
   874
		channel->iChannelId=aChannelId;
sl@0
   875
		TInt r=Kern::ThreadRawWrite(channel->iClient,channel->iClientChanId,&aChannelId,sizeof(TInt));
sl@0
   876
		if(r == KErrNone)
sl@0
   877
			r=aReturn;
sl@0
   878
#ifdef STANDALONE_CHANNEL
sl@0
   879
		// Set the captured channel's iChannelId if the capture succeeds.
sl@0
   880
		if(r != KErrCompletion)
sl@0
   881
			(channel->iCapturedChan).iChannel = NULL;
sl@0
   882
		else
sl@0
   883
			(channel->iCapturedChan).iChannelId = aChannelId;
sl@0
   884
#endif/*STANDALONE_CHANNEL*/
sl@0
   885
	    channel->RequestComplete(r);	// Inform user of error
sl@0
   886
		return;
sl@0
   887
		}
sl@0
   888
	else
sl@0
   889
		{
sl@0
   890
		if(aTrigger&ERxAllBytes)
sl@0
   891
			{
sl@0
   892
			CLIENT_PRINT(("SlaveClientCallbackFunc() - ERxAllBytes\n"));
sl@0
   893
			aTrigger&= ~ERxAllBytes;
sl@0
   894
			channel->iExpectedTrigger&=~ERxAllBytes;
sl@0
   895
			channel->iFullDuplexReq&=~ERxAllBytes;
sl@0
   896
			aReturn=channel->CheckDataRead();
sl@0
   897
			// Check underrun
sl@0
   898
			if(aTrigger&ERxUnderrun)
sl@0
   899
				{
sl@0
   900
				if(channel->iExpectedTrigger&ERxUnderrun)
sl@0
   901
					{
sl@0
   902
					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxUnderrun found OK\n\n"));
sl@0
   903
					channel->iExpectedTrigger&=~ERxUnderrun;
sl@0
   904
					}
sl@0
   905
				else
sl@0
   906
					{
sl@0
   907
					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ERxUnderrun indicated\n\n"));
sl@0
   908
					aReturn = KErrGeneral;
sl@0
   909
					}
sl@0
   910
				}
sl@0
   911
			else
sl@0
   912
				{
sl@0
   913
				if(channel->iExpectedTrigger&ERxUnderrun)
sl@0
   914
					{
sl@0
   915
					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxUnderrun not (yet) seen\n\n"));
sl@0
   916
					aReturn = KErrGeneral;
sl@0
   917
					}
sl@0
   918
				}
sl@0
   919
			// Check overrun
sl@0
   920
			if(aTrigger&ERxOverrun)
sl@0
   921
				{
sl@0
   922
				if(channel->iExpectedTrigger&ERxOverrun)
sl@0
   923
					{
sl@0
   924
					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxOverrun found OK\n\n"));
sl@0
   925
					channel->iExpectedTrigger&=~ERxOverrun;
sl@0
   926
					}
sl@0
   927
				else
sl@0
   928
					{
sl@0
   929
					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ERxOverrun indicated\n\n"));
sl@0
   930
					aReturn = KErrGeneral;
sl@0
   931
					}
sl@0
   932
				}
sl@0
   933
			else
sl@0
   934
				{
sl@0
   935
				if(channel->iExpectedTrigger&ERxOverrun)
sl@0
   936
					{
sl@0
   937
					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxOverrun not (yet) seen\n\n"));
sl@0
   938
					aReturn = KErrGeneral;
sl@0
   939
					}
sl@0
   940
				}
sl@0
   941
			}
sl@0
   942
sl@0
   943
		if(aTrigger&ETxAllBytes)
sl@0
   944
			{
sl@0
   945
			CLIENT_PRINT(("SlaveClientCallbackFunc() - ETxAllBytes\n"));
sl@0
   946
			aTrigger&= ~ETxAllBytes;
sl@0
   947
			channel->iExpectedTrigger&=~ETxAllBytes;
sl@0
   948
			channel->iFullDuplexReq&=~ETxAllBytes;
sl@0
   949
			aReturn=channel->CheckDataWritten();
sl@0
   950
			// Check underrun
sl@0
   951
			if(aTrigger&ETxUnderrun)
sl@0
   952
				{
sl@0
   953
				if(channel->iExpectedTrigger&ETxUnderrun)
sl@0
   954
					{
sl@0
   955
					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxUnderrun found OK\n\n"));
sl@0
   956
					channel->iExpectedTrigger&=~ETxUnderrun;
sl@0
   957
					}
sl@0
   958
				else
sl@0
   959
					{
sl@0
   960
					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ETxUnderrun indicated\n\n"));
sl@0
   961
					aReturn = KErrGeneral;
sl@0
   962
					}
sl@0
   963
				}
sl@0
   964
			else
sl@0
   965
				{
sl@0
   966
				if(channel->iExpectedTrigger&ETxUnderrun)
sl@0
   967
					{
sl@0
   968
					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxUnderrun not (yet) seen\n\n"));
sl@0
   969
					aReturn = KErrGeneral;
sl@0
   970
					}
sl@0
   971
				}
sl@0
   972
			// Check overrun
sl@0
   973
			if(aTrigger&ETxOverrun)
sl@0
   974
				{
sl@0
   975
				if(channel->iExpectedTrigger&ETxOverrun)
sl@0
   976
					{
sl@0
   977
					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxOverrun found OK\n\n"));
sl@0
   978
					channel->iExpectedTrigger&=~ETxOverrun;
sl@0
   979
					}
sl@0
   980
				else
sl@0
   981
					{
sl@0
   982
					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ETxOverrun indicated\n\n"));
sl@0
   983
					aReturn = KErrGeneral;
sl@0
   984
					}
sl@0
   985
				}
sl@0
   986
			else
sl@0
   987
				{
sl@0
   988
				if(channel->iExpectedTrigger&ETxOverrun)
sl@0
   989
					{
sl@0
   990
					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxOverrun not (yet) seen\n\n"));
sl@0
   991
					aReturn = KErrGeneral;
sl@0
   992
					}
sl@0
   993
				}
sl@0
   994
			}
sl@0
   995
sl@0
   996
sl@0
   997
		if(aTrigger&EGeneralBusError)
sl@0
   998
			{
sl@0
   999
				if(channel->iExpectedTrigger&EGeneralBusError)
sl@0
  1000
					{
sl@0
  1001
					CLIENT_PRINT(("\nSlaveClientCallbackFunc: EGeneralBusError - as expected\n\n"));
sl@0
  1002
					channel->iExpectedTrigger&=~EGeneralBusError;
sl@0
  1003
					if(aReturn == KErrGeneral)
sl@0
  1004
						{
sl@0
  1005
						aReturn=KErrNone; // If aReturn==KErrGeneral, set to KErrNone so t_iic knows test was successful
sl@0
  1006
						channel->iFullDuplexReq = 0; // The transaction is considered terminated, so don't wait for more triggers
sl@0
  1007
						}
sl@0
  1008
					else
sl@0
  1009
						{
sl@0
  1010
						CLIENT_PRINT(("\nSlaveClientCallbackFunc: aReturn not EGeneralBusError, =0x%x \n\n",aReturn));
sl@0
  1011
						aReturn=KErrGeneral;
sl@0
  1012
						}
sl@0
  1013
sl@0
  1014
					}
sl@0
  1015
				else
sl@0
  1016
					{
sl@0
  1017
					CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected EGeneralBusError indicated\n\n"));
sl@0
  1018
					aReturn = KErrGeneral;
sl@0
  1019
					}
sl@0
  1020
			}
sl@0
  1021
sl@0
  1022
		if((aTrigger < 0)||(aTrigger & (~0xFF)))
sl@0
  1023
			{
sl@0
  1024
			CLIENT_PRINT(("\nSlaveClientCallbackFunc: trigger condition 0x%x is not recognised \n\n",aTrigger));
sl@0
  1025
			}
sl@0
  1026
sl@0
  1027
		// For simulataneous Rx,Tx triggers with ERxOverrun or TxUnderrun testing, need to call the following
sl@0
  1028
		if(aReturn == KErrNone)
sl@0
  1029
			{
sl@0
  1030
			aReturn = channel->CbProcessOverUnderRunRxTx();
sl@0
  1031
			}
sl@0
  1032
sl@0
  1033
		if((channel->iExpectedTrigger == 0)&&(channel->iFullDuplexReq == 0))
sl@0
  1034
			channel->RequestComplete(aReturn);	// Complete user-side request only if all the triggers have been satisfied
sl@0
  1035
sl@0
  1036
		} // if(aTrigger == EAsyncCaptChan)
sl@0
  1037
	}
sl@0
  1038
sl@0
  1039
sl@0
  1040
TInt DChannelIicSlaveClient::CheckDataRead()
sl@0
  1041
	{
sl@0
  1042
	TInt r=KErrNone;
sl@0
  1043
	// This channel will have provided a buffer for writing to, with a specified offset and number of words
sl@0
  1044
	// Bytes in the buffer before the offset should be set to zero
sl@0
  1045
	// Bytes written at and beyond the offset should exhibit an incrementing count
sl@0
  1046
	// Bytes beyond the offset that were not written to should be set to zero
sl@0
  1047
	TInt8 numWords=(iRxReqNumWords>iNumRegRxWords)?iNumRegRxWords:iRxReqNumWords;
sl@0
  1048
	TInt8 currVal=0;
sl@0
  1049
	TInt8 index = 0;
sl@0
  1050
	while(index<iRxRegOffset)
sl@0
  1051
		{
sl@0
  1052
		currVal=*(iRxBuf+index);
sl@0
  1053
		if(currVal != 0)
sl@0
  1054
			{
sl@0
  1055
			CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataRead, index=%d, value =0x%x, expected 0",index,currVal));
sl@0
  1056
			r=KErrCorrupt;
sl@0
  1057
			}
sl@0
  1058
		++index;
sl@0
  1059
		}
sl@0
  1060
sl@0
  1061
	TInt8 checkVal=0x10; // first value written by simulated bus channel
sl@0
  1062
	TInt8 endOfData= (TInt8)(iRxRegOffset+(numWords*iRxRegGranularity));
sl@0
  1063
	TInt8 wordCount=0;
sl@0
  1064
	while(index<endOfData)
sl@0
  1065
		{
sl@0
  1066
		currVal = *(iRxBuf+index);
sl@0
  1067
		if(checkVal != currVal)
sl@0
  1068
			{
sl@0
  1069
			CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataRead, index=%d, value =0x%x, expected 0x%x",index,currVal,checkVal));
sl@0
  1070
			r=KErrCorrupt;
sl@0
  1071
			}
sl@0
  1072
		if(++wordCount == iRxRegGranularity)
sl@0
  1073
			{
sl@0
  1074
			wordCount=0;
sl@0
  1075
			checkVal++;
sl@0
  1076
			}
sl@0
  1077
		++index;
sl@0
  1078
		}
sl@0
  1079
sl@0
  1080
	while(index<KRxBufSizeInBytes)
sl@0
  1081
		{
sl@0
  1082
		currVal=*(iRxBuf+index);
sl@0
  1083
		if(currVal != 0)
sl@0
  1084
			{
sl@0
  1085
			CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataRead, index=%d, value =0x%x, expected 0",index,currVal);)
sl@0
  1086
			r=KErrCorrupt;
sl@0
  1087
			}
sl@0
  1088
		++index;
sl@0
  1089
		}
sl@0
  1090
	return r;
sl@0
  1091
	}
sl@0
  1092
sl@0
  1093
sl@0
  1094
TInt DChannelIicSlaveClient::CheckDataWritten()
sl@0
  1095
	{
sl@0
  1096
	TInt r=KErrNone;
sl@0
  1097
	// The pattern in the transmit buffer used by the simulated bus channel contains a incrementing count
sl@0
  1098
	// from 0 to (KTxBufSizeInBytes-1), therefore the first value to be present in the check buffer will be
sl@0
  1099
	// represented by the required offset.
sl@0
  1100
sl@0
  1101
	// The bytes "transmitted" are stored in the simulated bus' iTxCheckBuf
sl@0
  1102
	// Since the simulated bus channel is also in the kernel process it shares the same address space
sl@0
  1103
	// Get the address of the buffer
sl@0
  1104
	TUint testId = (((TUint)(RBusDevIicClient::ECtrlIoTxChkBuf))<<1)&0x3FFFFFFF;
sl@0
  1105
	CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataWritten invoking StaticExtension ECtrlIoTxChkBuf with iBusId=0x%x, testId=0x%x, iBusTxCheckBuf=0x%x\n",iBusId,testId,iBusTxCheckBuf));
sl@0
  1106
	r = StaticExtension(iBusId, testId, &iBusTxCheckBuf, NULL);
sl@0
  1107
	if(r!=KErrNone)
sl@0
  1108
		{
sl@0
  1109
		CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataWritten StaticExtension ECtrlIoTxChkBuf returned %d\n",r));
sl@0
  1110
		return r;
sl@0
  1111
		}
sl@0
  1112
sl@0
  1113
	// Check that the values in the check buffer increment for the
sl@0
  1114
	// required number of words, and that any remaining bytes in the check buffer are set to zero.
sl@0
  1115
	TInt8 firstValue = iTxRegOffset;
sl@0
  1116
	TInt8 currVal = 0;
sl@0
  1117
	TInt8 wordsWritten = 0;
sl@0
  1118
	wordsWritten=(iTxReqNumWords>iNumRegTxWords)?iNumRegTxWords:iTxReqNumWords;
sl@0
  1119
	TInt8 index=0;
sl@0
  1120
	while(index<(wordsWritten*iTxRegGranularity))
sl@0
  1121
		{
sl@0
  1122
		currVal=*(iBusTxCheckBuf+index);
sl@0
  1123
		if(currVal != (TInt8)(firstValue+index))
sl@0
  1124
			{
sl@0
  1125
			CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataWritten, index=%d, value =0x%x, expected 0x%x",index,currVal,(TInt8)(firstValue+index)));
sl@0
  1126
			r=KErrCorrupt;
sl@0
  1127
			}
sl@0
  1128
		++index;
sl@0
  1129
		}
sl@0
  1130
	while(index<(iNumRegTxWords*iTxRegGranularity))
sl@0
  1131
		{
sl@0
  1132
		currVal=*(iBusTxCheckBuf+index);
sl@0
  1133
		if(currVal != 0)
sl@0
  1134
			{
sl@0
  1135
			CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataWritten, index=%d, value =0x%x, expected 0",index,currVal));
sl@0
  1136
			r=KErrCorrupt;
sl@0
  1137
			}
sl@0
  1138
		++index;
sl@0
  1139
		}
sl@0
  1140
	return r;
sl@0
  1141
	}
sl@0
  1142
sl@0
  1143
sl@0
  1144
TInt DChannelIicSlaveClient::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
sl@0
  1145
	{
sl@0
  1146
	CLIENT_PRINT(("> DChannelIicSlaveClient::DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion &aVer)"));
sl@0
  1147
sl@0
  1148
	TInt r = Kern::DynamicDfcQCreate(iDfcQue,KIicSlaveClientThreadPriority,KIicSlaveClientThreadName);
sl@0
  1149
	if(r!=KErrNone)
sl@0
  1150
		return r;
sl@0
  1151
	SetDfcQ(iDfcQue);
sl@0
  1152
sl@0
  1153
	// Allocate buffers for Rx, Tx operations
sl@0
  1154
	iRxBuf = new TUint8[KRxBufSizeInBytes];
sl@0
  1155
	iTxBuf = new TUint8[KTxBufSizeInBytes];
sl@0
  1156
	if((iRxBuf == NULL)||(iTxBuf == NULL))
sl@0
  1157
		return KErrNoMemory;
sl@0
  1158
	// Start receiving messages
sl@0
  1159
	iMsgQ.Receive();
sl@0
  1160
sl@0
  1161
	return r;
sl@0
  1162
	}
sl@0
  1163
sl@0
  1164
TInt DChannelIicSlaveClient::InitSlaveClient()
sl@0
  1165
	{
sl@0
  1166
	iNotif = new TIicBusSlaveCallback(DChannelIicSlaveClient::SlaveClientCallbackFunc, (TAny*)this, iDfcQue, KIicSlaveClientDfcPriority);
sl@0
  1167
	if(iNotif == NULL)
sl@0
  1168
		{
sl@0
  1169
		CLIENT_PRINT(("> DChannelIicSlaveClient::InitSlaveClient ERROR unable to allocate space TIicBusSlaveCallback* iNotif \n"));
sl@0
  1170
		return KErrNoMemory;
sl@0
  1171
		}
sl@0
  1172
	return KErrNone;
sl@0
  1173
	}
sl@0
  1174
sl@0
  1175
void DChannelIicSlaveClient::HandleMsg(TMessageBase* aMsg)
sl@0
  1176
	{
sl@0
  1177
    TThreadMessage& m=*(TThreadMessage*)aMsg;
sl@0
  1178
    TInt id=m.iValue;
sl@0
  1179
sl@0
  1180
	CLIENT_PRINT((" >ldd: DChannelIicSlaveClient::HandleMsg(TMessageBase* aMsg) id=%d\n", id));
sl@0
  1181
sl@0
  1182
	if (id == (TInt)ECloseMsg)
sl@0
  1183
		{
sl@0
  1184
	    iMsgQ.iMessage->Complete(KErrNone,EFalse);
sl@0
  1185
		return;
sl@0
  1186
		}
sl@0
  1187
sl@0
  1188
    if (id<0)
sl@0
  1189
		{
sl@0
  1190
		TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
sl@0
  1191
		TInt r=DoRequest(~id, pS, m.Ptr1(), m.Ptr2());
sl@0
  1192
		if (r!=KErrNone)
sl@0
  1193
			{
sl@0
  1194
	    	Kern::RequestComplete(iClient, pS, r);
sl@0
  1195
			}
sl@0
  1196
		m.Complete(KErrNone,ETrue);
sl@0
  1197
		}
sl@0
  1198
    else
sl@0
  1199
	if((id>=0)&&(id!=KMaxTInt))
sl@0
  1200
		{
sl@0
  1201
		TInt r=DoControl(id,m.Ptr0(),m.Ptr1());
sl@0
  1202
		m.Complete(r,ETrue);
sl@0
  1203
		}
sl@0
  1204
	}
sl@0
  1205
sl@0
  1206
sl@0
  1207
TInt DChannelIicSlaveClient::DoControl(TInt aId, TAny* a1, TAny* a2)
sl@0
  1208
	{
sl@0
  1209
	CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoked with aId=0x%x, a1=0x%x, a2=0x%x\n", aId,a1,a2));
sl@0
  1210
	TInt r=KErrNone;
sl@0
  1211
	// To support testing, any values of aId for StaticExtension must be shifted left one place
sl@0
  1212
	// and for a Slave, the two msbs must be zero
sl@0
  1213
	TInt ctrlIoVal = 0;
sl@0
  1214
	if((aId & KTestSlaveControlIo) == KTestSlaveControlIo)
sl@0
  1215
		ctrlIoVal = (aId << 1) & 0x3FFFFFFF;
sl@0
  1216
sl@0
  1217
	switch(aId)
sl@0
  1218
		{
sl@0
  1219
		case(RBusDevIicClient::EInitSlaveClient):
sl@0
  1220
			{
sl@0
  1221
			r=InitSlaveClient();
sl@0
  1222
			break;
sl@0
  1223
			}
sl@0
  1224
sl@0
  1225
		case(RBusDevIicClient::ECaptureChanSync):
sl@0
  1226
			{
sl@0
  1227
			// a1 is a pointer to the TDes8* aConfigHdr
sl@0
  1228
			// a2 is a pointer to TInt* parms[2], where:
sl@0
  1229
			// parms[0]=(TInt*)aBusId;
sl@0
  1230
			// parms[1]=&aChannelId;
sl@0
  1231
			//
sl@0
  1232
			TInt* parms[2];
sl@0
  1233
			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt*));
sl@0
  1234
			if(r!=KErrNone)
sl@0
  1235
				break;	// Can't proceed if can't access request parameters
sl@0
  1236
			//
sl@0
  1237
		  	TInt hdrSize = Kern::ThreadGetDesLength(iClient,a1);
sl@0
  1238
			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl hdrSize = 0x%x\n",hdrSize));
sl@0
  1239
  			if (hdrSize<=0)
sl@0
  1240
				{
sl@0
  1241
				CLIENT_PRINT(("DChannelIicSlaveClient::DoControl ERROR, hdrSize is invalid\n"));
sl@0
  1242
 				r = KErrArgument;
sl@0
  1243
 				break;
sl@0
  1244
				}
sl@0
  1245
			if((iConfigHdr = HBuf8::New(hdrSize)) == NULL)
sl@0
  1246
				return KErrNoMemory;
sl@0
  1247
			r = Kern::ThreadDesRead(iClient,a1,*iConfigHdr,0);
sl@0
  1248
			if(r!=KErrNone)
sl@0
  1249
				{
sl@0
  1250
				delete iConfigHdr;
sl@0
  1251
				break;
sl@0
  1252
				}
sl@0
  1253
			// Store the address of the user-side variable to update with the ChannelId
sl@0
  1254
			iClientChanId=parms[1];
sl@0
  1255
sl@0
  1256
			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking (synchronous) CaptureChannel\n"));
sl@0
  1257
			r = CaptureChannel((TInt)(parms[0]), iConfigHdr, iNotif, iChannelId);
sl@0
  1258
			if(r != KErrNone)
sl@0
  1259
			    {
sl@0
  1260
			    delete iConfigHdr;
sl@0
  1261
			    break;
sl@0
  1262
			    }
sl@0
  1263
			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl CaptureChannelgave iChannelId=0x%x\n",iChannelId));
sl@0
  1264
sl@0
  1265
			r = Kern::ThreadRawWrite(iClient,iClientChanId,&iChannelId,sizeof(TInt));
sl@0
  1266
			if(r != KErrNone)
sl@0
  1267
				delete iConfigHdr;
sl@0
  1268
			break;
sl@0
  1269
			}
sl@0
  1270
sl@0
  1271
		case(RBusDevIicClient::EReleaseChan):
sl@0
  1272
			{
sl@0
  1273
			// a1 represents TInt aChannelId
sl@0
  1274
			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking ReleaseChannel\n"));
sl@0
  1275
			r = ReleaseChannel((TInt)a1);
sl@0
  1276
			delete iConfigHdr;
sl@0
  1277
			break;
sl@0
  1278
			}
sl@0
  1279
sl@0
  1280
		case(RBusDevIicClient::ERegisterRxBuffer):
sl@0
  1281
			{
sl@0
  1282
			// a1 represents TInt aChannelId
sl@0
  1283
			// a2 represents (TAny*) of TInt8 parms[3] where parms[0]=aBufGranularity; parms[1]=aNumWords; parms[2]=aOffset
sl@0
  1284
			TInt8 parms[3];
sl@0
  1285
			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),3*sizeof(TInt8));
sl@0
  1286
			if(r!=KErrNone)
sl@0
  1287
				break;	// Can't proceed if can't access request parameters
sl@0
  1288
			// Store parameters for checking in the callback
sl@0
  1289
			iRxRegGranularity = parms[0];
sl@0
  1290
			iRxRegOffset= parms[2];
sl@0
  1291
			iNumRegRxWords=parms[1];
sl@0
  1292
sl@0
  1293
			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking RegisterRxBuffer\n"));
sl@0
  1294
			TPtr8 rxPtr(iRxBuf,KRxBufSizeInBytes);
sl@0
  1295
			r = RegisterRxBuffer((TInt)a1, rxPtr, parms[0], parms[1], parms[2]);
sl@0
  1296
			break;
sl@0
  1297
			}
sl@0
  1298
sl@0
  1299
		case(RBusDevIicClient::ERegisterTxBuffer):
sl@0
  1300
			{
sl@0
  1301
			// a1 represents TInt aChannelId
sl@0
  1302
			// a2 represents (TAny*) of TInt8 parms[3] where parms[0]=aBufGranularity; parms[1]=aNumWords; parms[2]=aOffset
sl@0
  1303
			TInt8 parms[3];
sl@0
  1304
			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),3*sizeof(TInt8));
sl@0
  1305
			if(r!=KErrNone)
sl@0
  1306
				break;	// Can't proceed if can't access request parameters
sl@0
  1307
			// Store parameters for checking in the callback
sl@0
  1308
			iTxRegGranularity = parms[0];
sl@0
  1309
			iTxRegOffset= parms[2];
sl@0
  1310
			iNumRegTxWords=parms[1];
sl@0
  1311
sl@0
  1312
			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking RegisterTxBuffer\n"));
sl@0
  1313
			TPtr8 txPtr(iTxBuf,KTxBufSizeInBytes);
sl@0
  1314
			r = RegisterTxBuffer((TInt)a1, txPtr, parms[0], parms[1], parms[2]);
sl@0
  1315
			break;
sl@0
  1316
			}
sl@0
  1317
sl@0
  1318
		case(RBusDevIicClient::ESetNotifTrigger):
sl@0
  1319
			{
sl@0
  1320
			// a1 represents (TAny*) of TRequestStatus* aStatus
sl@0
  1321
			// a2 represents (TAny*) of TInt parms[2] where parms[0]=aChannelId; parms[1]=aTrigger
sl@0
  1322
			TInt parms[2];
sl@0
  1323
			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt));
sl@0
  1324
			if(r!=KErrNone)
sl@0
  1325
				break;	// Can't proceed if can't access request parameters
sl@0
  1326
			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking SetNotificationTrigger with aStatus=0x%x, aChannelId=0x%x, aTrigger=0x%x\n",a1,parms[0],parms[1]));
sl@0
  1327
			if(a1 == NULL)
sl@0
  1328
				{
sl@0
  1329
				r = KErrArgument;
sl@0
  1330
				break;
sl@0
  1331
				}
sl@0
  1332
			iStatus=(TRequestStatus*)a1;
sl@0
  1333
			// Set the flags for duplex processing
sl@0
  1334
			if((parms[1]&ERxAllBytes)&&(parms[1]&ETxAllBytes))
sl@0
  1335
				iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
sl@0
  1336
			r = SetNotificationTrigger(parms[0],parms[1]);
sl@0
  1337
			if(r == KErrTimedOut)
sl@0
  1338
				r=KErrNone;	// KErrTimedOut is returned if the Client has not interacted with IIC for a while
sl@0
  1339
			break;
sl@0
  1340
			}
sl@0
  1341
sl@0
  1342
		case(RBusDevIicClient::ECtrlIoNotifNoTrigger):
sl@0
  1343
			{
sl@0
  1344
			// a1 represents (TAny*) of aChannelId
sl@0
  1345
			// a2 represents (TAny*) of aTrigger
sl@0
  1346
			TInt chanId = (TInt)a1;
sl@0
  1347
			TInt trigger = (TInt)a2;
sl@0
  1348
			// No TRequestStatus is accessed because the call to SetNotificationTrigger
sl@0
  1349
			// is either with zero (when it is valid to do so), or it is being called with a
sl@0
  1350
			// trigger value that is expected to be rejected.
sl@0
  1351
			r = SetNotificationTrigger(chanId,trigger);
sl@0
  1352
sl@0
  1353
			if(r == KErrNone)
sl@0
  1354
				{
sl@0
  1355
				if((trigger&ERxAllBytes)&&(trigger&ETxAllBytes))
sl@0
  1356
					iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
sl@0
  1357
				}
sl@0
  1358
			if(r == KErrTimedOut)
sl@0
  1359
				r=KErrNone;	// KErrTimedOut is returned if the Client has not interacted with IIC for a while
sl@0
  1360
			break;
sl@0
  1361
			}
sl@0
  1362
sl@0
  1363
		case(RBusDevIicClient::ECtrlIoRxWords):
sl@0
  1364
			{
sl@0
  1365
			// a1 represents TInt aBusId
sl@0
  1366
			// a2 represents (TAny*) of TInt parms[2] where parms[0]=aChannelId; parms[1]=aNumWords
sl@0
  1367
			TInt parms[2];
sl@0
  1368
			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt));
sl@0
  1369
			if(r!=KErrNone)
sl@0
  1370
				break;	// Can't proceed if can't access request parameters
sl@0
  1371
			// Prepare iRxBuf
sl@0
  1372
			memset(iRxBuf,0,KRxBufSizeInBytes);
sl@0
  1373
			// Store the number of words for checking in the callback
sl@0
  1374
			iRxReqNumWords=(TInt8)(parms[1]);
sl@0
  1375
sl@0
  1376
			TInt tempTrigger=0;
sl@0
  1377
			// Set the expected result
sl@0
  1378
			tempTrigger |= ERxAllBytes;
sl@0
  1379
			if(parms[1] < iNumRegRxWords)
sl@0
  1380
				tempTrigger |= ERxUnderrun;
sl@0
  1381
			if(parms[1] > iNumRegRxWords)
sl@0
  1382
				tempTrigger |= ERxOverrun;
sl@0
  1383
			if(iExpectedTrigger != EGeneralBusError)
sl@0
  1384
				iExpectedTrigger |= tempTrigger;
sl@0
  1385
			else
sl@0
  1386
				iBlockedTrigger |= tempTrigger;
sl@0
  1387
			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoRxWords) with aBusId=0x%x, aChannelId=0x%x, aNumBytes=0x%x\n",(TInt)a1,parms[0],parms[1]));
sl@0
  1388
			r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)(parms[0]), (TAny*)(parms[1]));
sl@0
  1389
			if(r == KErrTimedOut)
sl@0
  1390
				r=KErrNone;	// KErrTimedOut is returned if the Client has not interacted with IIC for a while
sl@0
  1391
			break;
sl@0
  1392
			}
sl@0
  1393
sl@0
  1394
		case(RBusDevIicClient::ECtrlIoTxWords):
sl@0
  1395
			{
sl@0
  1396
			// a1 represents TInt aBusId
sl@0
  1397
			// a2 represents (TAny*) of TInt parms[2] where parms[0]=aChannelId; parms[1]=aNumWords
sl@0
  1398
			TInt parms[2];
sl@0
  1399
			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt));
sl@0
  1400
			if(r!=KErrNone)
sl@0
  1401
				break;	// Can't proceed if can't access request parameters
sl@0
  1402
			// Prepare iTxBuf
sl@0
  1403
			TUint8* ptr=iTxBuf;
sl@0
  1404
			for(TInt offset=0; offset<KRxBufSizeInBytes; ++offset)
sl@0
  1405
				*ptr++=(TUint8)offset;
sl@0
  1406
			// Store the number of words for checking in the callback
sl@0
  1407
			iTxReqNumWords=(TInt8)(parms[1]);
sl@0
  1408
			TInt tempTrigger=0;
sl@0
  1409
			// Set the expected result
sl@0
  1410
			tempTrigger |= ETxAllBytes;
sl@0
  1411
			if(parms[1] < iNumRegTxWords)
sl@0
  1412
				tempTrigger |= ETxOverrun;
sl@0
  1413
			if(parms[1] > iNumRegTxWords)
sl@0
  1414
				tempTrigger |= ETxUnderrun;
sl@0
  1415
			if(iExpectedTrigger != EGeneralBusError)
sl@0
  1416
				iExpectedTrigger |= tempTrigger;
sl@0
  1417
			else
sl@0
  1418
				iBlockedTrigger |= tempTrigger;
sl@0
  1419
sl@0
  1420
			// The bytes "transmitted" are stored in the simulated bus' iTxCheckBuf
sl@0
  1421
			// Since the simulated bus channel is also in the kernel process it shares the same address space
sl@0
  1422
			// Get the address of the buffer
sl@0
  1423
			// As part of the callback invoked by IIC, this client will check the data stored by the simulated
sl@0
  1424
			// bus. Since the simulated bus channel is also in the kernel process it shares the same address space,
sl@0
  1425
			// so the buffer can be accessed directly - but the buffer is not created until it receives the following
sl@0
  1426
			// StaticExtension command, so the bus identifier represented by a1 is stored to allow accessing the buffer
sl@0
  1427
			// adddress from the callback.
sl@0
  1428
			iBusId=(TUint)a1;
sl@0
  1429
			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoTxWords) with aBusId=0x%x, aChannelId=0x%x, aNumBytes=0x%x\n",(TInt)a1,parms[0],parms[1]));
sl@0
  1430
			aId<<=1;
sl@0
  1431
			r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)(parms[0]), (TAny*)(parms[1]));
sl@0
  1432
			break;
sl@0
  1433
			}
sl@0
  1434
sl@0
  1435
		case(RBusDevIicClient::ECtrlIoRxTxWords):
sl@0
  1436
			{
sl@0
  1437
			// a1 represents TInt aBusId
sl@0
  1438
			// a2 represents (TAny*) of TInt parms[3] where parms[0]=aChannelId; parms[1]=aNumRxWords; parms[2]=aNumTxWords
sl@0
  1439
			TInt parms[3];
sl@0
  1440
			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),3*sizeof(TInt));
sl@0
  1441
			if(r!=KErrNone)
sl@0
  1442
				break;	// Can't proceed if can't access request parameters
sl@0
  1443
			// Prepare iRxBuf, iTxBuf
sl@0
  1444
			memset(iRxBuf,0,KRxBufSizeInBytes);
sl@0
  1445
			TUint8* ptr=iTxBuf;
sl@0
  1446
			for(TInt offset=0; offset<KRxBufSizeInBytes; ++offset)
sl@0
  1447
				*ptr++=(TUint8)offset;
sl@0
  1448
sl@0
  1449
			// Store the number of words for checking in the callback
sl@0
  1450
			iRxReqNumWords=(TInt8)(parms[1]);
sl@0
  1451
			iTxReqNumWords=(TInt8)(parms[2]);
sl@0
  1452
sl@0
  1453
			TInt tempTrigger=0;
sl@0
  1454
			// Set the expected result
sl@0
  1455
			tempTrigger |= (ERxAllBytes|ETxAllBytes);
sl@0
  1456
sl@0
  1457
			if(parms[1] < iNumRegRxWords)
sl@0
  1458
				tempTrigger |= ERxUnderrun;
sl@0
  1459
			if(parms[1] > iNumRegRxWords)
sl@0
  1460
				tempTrigger |= ERxOverrun;
sl@0
  1461
sl@0
  1462
			if(parms[2] < iNumRegTxWords)
sl@0
  1463
				tempTrigger |= ETxOverrun;
sl@0
  1464
			if(parms[2] > iNumRegTxWords)
sl@0
  1465
				tempTrigger |= ETxUnderrun;
sl@0
  1466
sl@0
  1467
			if(iExpectedTrigger != EGeneralBusError)
sl@0
  1468
				iExpectedTrigger |= tempTrigger;
sl@0
  1469
			else
sl@0
  1470
				iBlockedTrigger |= tempTrigger;
sl@0
  1471
sl@0
  1472
			// The bytes "transmitted" are stored in the simulated bus' iTxCheckBuf
sl@0
  1473
			// Since the simulated bus channel is also in the kernel process it shares the same address space
sl@0
  1474
			// Get the address of the buffer
sl@0
  1475
			// As part of the callback invoked by IIC, this client will check the data stored by the simulated
sl@0
  1476
			// bus. Since the simulated bus channel is also in the kernel process it shares the same address space,
sl@0
  1477
			// so the buffer can be accessed directly - but the buffer is not created until it receives the following
sl@0
  1478
			// StaticExtension command, so the bus identifier represented by a1 is stored to allow accessing the buffer
sl@0
  1479
			// adddress from the callback.
sl@0
  1480
			iBusId=(TUint)a1;
sl@0
  1481
sl@0
  1482
			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoRxTxWords) with aBusId=0x%x, aChannelId=0x%x, aNumRxBytes=0x%x, aNumTxBytes=0x%x\n",(TInt)a1,parms[0],parms[1],parms[2]));
sl@0
  1483
			r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)(parms[0]), (TAny*)(&(parms[1])));
sl@0
  1484
			if(r == KErrTimedOut)
sl@0
  1485
				r=KErrNone;	// KErrTimedOut is returned if the Client has not interacted with IIC for a while
sl@0
  1486
			break;
sl@0
  1487
			}
sl@0
  1488
sl@0
  1489
		case(RBusDevIicClient::ECtlIoBusError):
sl@0
  1490
			{
sl@0
  1491
			// a1 represents TInt aBusId
sl@0
  1492
			// a2 represents TInt aChannelId
sl@0
  1493
			// Set the expected result
sl@0
  1494
			iExpectedTrigger |= EGeneralBusError;
sl@0
  1495
			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtlIoBusError) \n"));
sl@0
  1496
			r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)a2, NULL);
sl@0
  1497
			break;
sl@0
  1498
			}
sl@0
  1499
sl@0
  1500
		case(RBusDevIicClient::ECtrlIoUnblockNotification):
sl@0
  1501
			{
sl@0
  1502
			// a1 represents TInt aBusId
sl@0
  1503
			// a2 represents TInt aChannelId
sl@0
  1504
			iExpectedTrigger = iBlockedTrigger;
sl@0
  1505
			iBlockedTrigger=0;
sl@0
  1506
			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoUnblockNotification) \n"));
sl@0
  1507
			r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)a2, NULL);
sl@0
  1508
			break;
sl@0
  1509
			}
sl@0
  1510
sl@0
  1511
		case(RBusDevIicClient::ECtrlIoBlockNotification):
sl@0
  1512
			{
sl@0
  1513
			// a1 represents TInt aBusId
sl@0
  1514
			// a2 represents TInt aChannelId
sl@0
  1515
			iBlockedTrigger = iExpectedTrigger;
sl@0
  1516
			iExpectedTrigger = EGeneralBusError;	// For this test, just interested in if the timeout is detected
sl@0
  1517
													// iExpectedTrigger will be reinstated prior to unblocking
sl@0
  1518
			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoBlockNotification) \n"));
sl@0
  1519
			r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)a2, NULL);
sl@0
  1520
			break;
sl@0
  1521
			}
sl@0
  1522
sl@0
  1523
		case(RBusDevIicClient::ECtrlIoUpdTimeout):
sl@0
  1524
			{
sl@0
  1525
			// a1 represents TInt aBusId
sl@0
  1526
			// a2 represents TInt aChannelId
sl@0
  1527
sl@0
  1528
			// For this test, instruct the simulated bus to do the following for the Master and Client timeout values:
sl@0
  1529
			// (1) Read the current timeout value and check that it is set to the default
sl@0
  1530
			// (2) Set it to different value
sl@0
  1531
			// (3) Read it back to check success
sl@0
  1532
			// (4) Return to the original value, and readback to confirm
sl@0
  1533
			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoBlockNotification) \n"));
sl@0
  1534
			r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, NULL, NULL);
sl@0
  1535
			break;
sl@0
  1536
			}
sl@0
  1537
sl@0
  1538
		default:
sl@0
  1539
			{
sl@0
  1540
			CLIENT_PRINT(("DChannelIicSlaveClient::DoControl - unrecognised value for aId=0x%x\n",aId));
sl@0
  1541
			r=KErrArgument;
sl@0
  1542
			break;
sl@0
  1543
			}
sl@0
  1544
sl@0
  1545
		}
sl@0
  1546
	return r;
sl@0
  1547
	}
sl@0
  1548
sl@0
  1549
TInt DChannelIicSlaveClient::DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2)
sl@0
  1550
	{
sl@0
  1551
	CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest invoked with aId=0x%x, aStatus=0x%x, a1=0x%x, a2=0x%x\n", aId,aStatus,a1,a2));
sl@0
  1552
sl@0
  1553
	TInt r=KErrNone;
sl@0
  1554
	switch(aId)
sl@0
  1555
		{
sl@0
  1556
		case(RBusDevIicClient::ECaptureChanAsync):
sl@0
  1557
			{
sl@0
  1558
			// a1 is a pointer to the TDes8* aConfigHdr
sl@0
  1559
			// a2 is a pointer to TInt* parms[2], where:
sl@0
  1560
			// parms[0]=(TInt*)aBusId;
sl@0
  1561
			// parms[1]=&aChannelId;
sl@0
  1562
			//
sl@0
  1563
			TInt* parms[2];
sl@0
  1564
			r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt*));
sl@0
  1565
			if(r!=KErrNone)
sl@0
  1566
				break;	// Can't proceed if can't access request parameters
sl@0
  1567
			//
sl@0
  1568
		  	TInt hdrSize = Kern::ThreadGetDesLength(iClient,a1);
sl@0
  1569
			CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest hdrSize = 0x%x\n",hdrSize));
sl@0
  1570
  			if (hdrSize<=0)
sl@0
  1571
				{
sl@0
  1572
				CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest ERROR, hdrSize is invalid\n"));
sl@0
  1573
 				return KErrArgument;
sl@0
  1574
				}
sl@0
  1575
			if((iConfigHdr = HBuf8::New(hdrSize)) == NULL)
sl@0
  1576
				return KErrNoMemory;
sl@0
  1577
			if((r = Kern::ThreadDesRead(iClient,a1,*iConfigHdr,0))!=KErrNone)
sl@0
  1578
				{
sl@0
  1579
				delete iConfigHdr;
sl@0
  1580
				return r;
sl@0
  1581
				}
sl@0
  1582
			iStatus=aStatus;
sl@0
  1583
			// Store the address of the user-side variable to update with the ChannelId
sl@0
  1584
			iClientChanId=parms[1];
sl@0
  1585
			// Invoke the IIC API
sl@0
  1586
			CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest invoking (asynchronous) CaptureChannel\n"));
sl@0
  1587
			r = CaptureChannel((TInt)(parms[0]), iConfigHdr, iNotif, iChannelId, ETrue);
sl@0
  1588
			if(r != KErrNone)
sl@0
  1589
			    delete iConfigHdr;
sl@0
  1590
			CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest (asynchronous) CaptureChannel returned %d\n",r));
sl@0
  1591
			break;
sl@0
  1592
			}
sl@0
  1593
sl@0
  1594
		case(RBusDevIicClient::ECtrlIoOvUndRunRxTx):
sl@0
  1595
			{
sl@0
  1596
			iBusId = (TInt)a1;
sl@0
  1597
			iChannelId = (TInt)a2;
sl@0
  1598
			iStatus=aStatus;
sl@0
  1599
			CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest status = 0x%x, busId = 0x%x, chanId =0x%x\n",iStatus,iBusId,iChannelId));
sl@0
  1600
sl@0
  1601
			// This test is state-machine driven. It is instigated from this point, then subsequent steps
sl@0
  1602
			// are handled in the callback funciton SlaveClientCallbackFunc
sl@0
  1603
			//
sl@0
  1604
			// Check we in the appropriate state to start
sl@0
  1605
			if(iTestOverUnderState == EStartState)
sl@0
  1606
				{
sl@0
  1607
				// Re-use the previously-provided buffers. Just request the initial notification triggers,
sl@0
  1608
				// the simulate the first event (RxOverrun).
sl@0
  1609
				r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun));
sl@0
  1610
				if(r != KErrNone)
sl@0
  1611
					{
sl@0
  1612
					CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest SetNotificationTrigger returned %d\n",r));
sl@0
  1613
					}
sl@0
  1614
				else
sl@0
  1615
					{
sl@0
  1616
					// Trigger now set, so simulate the required event
sl@0
  1617
					iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun;
sl@0
  1618
					iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
sl@0
  1619
					iTestOverUnderState = ERxOverrun_1;	// Prepare for callback
sl@0
  1620
					// The requested number of words when the buffer was registered was 8, so simulate 10
sl@0
  1621
					// to provoke an RxOverrun event.
sl@0
  1622
					TInt numWords=10;
sl@0
  1623
					// To support testing, any values of aId for StaticExtension must be shifted left one place
sl@0
  1624
					// and for a Slave, the two msbs must be zero
sl@0
  1625
					TInt ctrlIoVal = RBusDevIicClient::ECtrlIoRxWords;
sl@0
  1626
					ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
sl@0
  1627
					r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords);
sl@0
  1628
					}
sl@0
  1629
				}
sl@0
  1630
			else
sl@0
  1631
				{
sl@0
  1632
				CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest ECtrlIoOvUndRunRxTx, iTestOverUnderState = 0x%x\n",iTestOverUnderState));
sl@0
  1633
				r=KErrGeneral;
sl@0
  1634
				}
sl@0
  1635
			break;
sl@0
  1636
			}
sl@0
  1637
sl@0
  1638
		default:
sl@0
  1639
			{
sl@0
  1640
			CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest - unrecognised value for aId=0x%x\n",aId));
sl@0
  1641
			r=KErrArgument;
sl@0
  1642
			break;
sl@0
  1643
			}
sl@0
  1644
		}
sl@0
  1645
	return r;
sl@0
  1646
	}
sl@0
  1647