1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/iic/iic_psl/iic_slaveclient.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1647 @@
1.4 +// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32test/iic/iic_slaveclient.cpp
1.18 +// Simulated client of IIC Platform Independent Layer (PIL) Slave functionality
1.19 +//
1.20 +
1.21 +#include <kernel/kern_priv.h> // for DThread, TDfc
1.22 +#ifdef STANDALONE_CHANNEL
1.23 +#include <drivers/iic_transaction.h>
1.24 +#else
1.25 +#include <drivers/iic.h>
1.26 +#endif
1.27 +#include "../t_iic.h"
1.28 +
1.29 +#ifdef STANDALONE_CHANNEL
1.30 +#include <drivers/iic_channel.h>
1.31 +#include "i2c.h"
1.32 +#endif
1.33 +#ifdef LOG_SLAVECLIENT
1.34 +#define CLIENT_PRINT(str) Kern::Printf str
1.35 +#else
1.36 +#define CLIENT_PRINT(str)
1.37 +#endif
1.38 +
1.39 +//For channel creation
1.40 +#ifdef STANDALONE_CHANNEL
1.41 +#define NUM_CHANNELS 3 // Arbitrary
1.42 +
1.43 +#if defined(MASTER_MODE) && !defined(SLAVE_MODE)
1.44 +const TInt KChannelTypeArray[NUM_CHANNELS] = {DIicBusChannel::EMaster, DIicBusChannel::EMaster, DIicBusChannel::EMaster};
1.45 +#elif defined(MASTER_MODE) && defined(SLAVE_MODE)
1.46 +const TInt KChannelTypeArray[NUM_CHANNELS] = {DIicBusChannel::EMaster, DIicBusChannel::ESlave, DIicBusChannel::EMasterSlave};
1.47 +#else
1.48 +const TInt KChannelTypeArray[NUM_CHANNELS] = {DIicBusChannel::ESlave, DIicBusChannel::ESlave, DIicBusChannel::ESlave};
1.49 +#endif
1.50 +#define CHANNEL_TYPE(n) (KChannelTypeArray[n])
1.51 +#define CHANNEL_DUPLEX(n) (DIicBusChannel::EHalfDuplex)
1.52 +#define BUS_TYPE (DIicBusChannel::EI2c)
1.53 +
1.54 +#if defined(MASTER_MODE)
1.55 +const TInt8 KI2cChannelNumBase = 10; // Arbitrary, real platform may consult the Configuration Repository
1.56 + // Note limit of 5 bit representation (0-31)
1.57 +
1.58 +#else
1.59 +const TInt8 KI2cChannelNumBase = 10 + NUM_CHANNELS; // For Slave mode, want to provide different response
1.60 + // If client assumes Master mode, should be informed not available
1.61 +#endif/*MASTER_MODE*/
1.62 +
1.63 +LOCAL_C TInt8 AssignChanNumI2c()
1.64 + {
1.65 + static TInt8 iBaseChanNumI2c = KI2cChannelNumBase;
1.66 + CLIENT_PRINT(("I2C AssignChanNum - on entry, iBaseChanNum = 0x%x\n",iBaseChanNumI2c));
1.67 + return iBaseChanNumI2c++; // Arbitrary, for illustration
1.68 + }
1.69 +
1.70 +class DIicSlaveClientChan : public DBase
1.71 + {
1.72 +public:
1.73 + DIicSlaveClientChan(DIicBusChannel* aChan, TInt8 aChanNum, TInt aChanType):iChan(aChan),iChanNumber(aChanNum),iChanType(aChanType){};
1.74 + ~DIicSlaveClientChan();
1.75 + TInt GetChanNum()const {return iChanNumber;};
1.76 + TInt GetChanType()const {return iChanType;};
1.77 + DIicBusChannel* GetChannelPtr(){return iChan;};
1.78 +private:
1.79 + TInt8 iChanNumber;
1.80 + TInt iChanType;
1.81 + DIicBusChannel* iChan;
1.82 + };
1.83 +
1.84 +DIicSlaveClientChan::~DIicSlaveClientChan()
1.85 + {
1.86 + if(iChan)
1.87 + delete iChan;
1.88 + }
1.89 +
1.90 +#endif/*STANDALONE_CHANNEL*/
1.91 +
1.92 +const TInt KIicSlaveClientThreadPriority = 24;
1.93 +
1.94 +const TInt KIicSlaveClientDfcPriority = 3; // 0 to 7, 7 is highest
1.95 +
1.96 +const TInt KMaxNumChannels = 2; // 1 "true" slave, one "dummy"
1.97 +
1.98 +#ifdef STANDALONE_CHANNEL
1.99 +_LIT(KLddRootName,"iic_slaveclient_ctrless");
1.100 +#else
1.101 +_LIT(KLddRootName,"iic_slaveclient");
1.102 +#endif
1.103 +_LIT(KIicSlaveClientThreadName,"IicSlaveClientLddThread");
1.104 +
1.105 +
1.106 +struct TCapsIicSlaveClient
1.107 + {
1.108 + TVersion version;
1.109 + };
1.110 +
1.111 +
1.112 +class DDeviceIicSlaveClient : public DLogicalDevice
1.113 + {
1.114 + public:
1.115 + /**
1.116 + * The constructor
1.117 + */
1.118 + DDeviceIicSlaveClient();
1.119 + /**
1.120 + * The destructor
1.121 + */
1.122 + ~DDeviceIicSlaveClient();
1.123 + /**
1.124 + * Second stage constructor - install the device
1.125 + */
1.126 + virtual TInt Install();
1.127 + /**
1.128 + * Get the Capabilites of the device
1.129 + * @param aDes descriptor that will contain the returned capibilites
1.130 + */
1.131 + virtual void GetCaps(TDes8 &aDes) const;
1.132 + /**
1.133 + * Create a logical channel to the device
1.134 + */
1.135 + virtual TInt Create(DLogicalChannelBase*& aChannel);
1.136 + };
1.137 +
1.138 +
1.139 +class DChannelIicSlaveClient : public DLogicalChannel
1.140 + {
1.141 + public:
1.142 + DChannelIicSlaveClient();
1.143 + ~DChannelIicSlaveClient();
1.144 +
1.145 + virtual TInt DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer);
1.146 +
1.147 + void RequestComplete(TInt r);
1.148 + TInt CheckDataWritten();
1.149 + TInt CheckDataRead();
1.150 +
1.151 + static void SlaveClientCallbackFunc(TInt aChannelId, TInt aReturn, TInt aTrigger, TInt16 aRxWords, TInt16 aTxWords, TAny* aParam);
1.152 +#ifdef STANDALONE_CHANNEL
1.153 + static TInt OrderEntries(const DIicSlaveClientChan& aMatch, const DIicSlaveClientChan& aEntry);
1.154 +#endif
1.155 + protected:
1.156 + virtual void HandleMsg(TMessageBase* aMsg); // Note: this is a pure virtual in DLogicalChannel
1.157 +
1.158 + TInt DoControl(TInt aId, TAny* a1, TAny* a2); // Name for convenience!
1.159 + TInt DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2); // Name for convenience!
1.160 +
1.161 + private:
1.162 + TInt InitSlaveClient();
1.163 + TInt CbProcessOverUnderRunRxTx();
1.164 + TInt RegisterRxBuffer(TInt aChannelId, TPtr8 aRxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset);
1.165 + TInt SetNotificationTrigger(TInt aChannelId, TInt aTrigger);
1.166 + TInt StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2);
1.167 + TInt RegisterTxBuffer(TInt aChannelId, TPtr8 aTxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset);
1.168 + TInt CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch=NULL);
1.169 + TInt ReleaseChannel(TInt aChannelId);
1.170 + private:
1.171 + TDynamicDfcQue* iDfcQue;
1.172 + TIicBusSlaveCallback* iNotif;
1.173 +
1.174 + HBuf8* iConfigHdr;
1.175 + TRequestStatus* iStatus;
1.176 +
1.177 + TUint8* iRxBuf;
1.178 + TUint8* iTxBuf;
1.179 +
1.180 + TUint8* iBusTxCheckBuf;
1.181 +
1.182 + TInt8 iNumRegRxWords;
1.183 + TInt8 iNumRegTxWords;
1.184 +
1.185 + TInt8 iTxRegGranularity;
1.186 + TInt8 iTxRegOffset;
1.187 + TInt8 iTxReqNumWords;
1.188 +
1.189 + TInt8 iRxRegGranularity;
1.190 + TInt8 iRxRegOffset;
1.191 + TInt8 iRxReqNumWords;
1.192 +
1.193 + TUint iBusId;
1.194 +#ifdef STANDALONE_CHANNEL
1.195 + // For some slave-channel-only functions,e.g. ReleaseChannel, RegisterRxBuffer, etc.
1.196 + // the client needs to remember the slave channel that has been captured
1.197 + struct TCapturedChannel
1.198 + {
1.199 + DIicSlaveClientChan* iChannel;
1.200 + TInt iChannelId;
1.201 + };
1.202 + TCapturedChannel iCapturedChan;
1.203 +#endif
1.204 + public:
1.205 + DThread* iClient;
1.206 + TInt iChannelId; // public to be accessible by callback
1.207 + TInt* iClientChanId;
1.208 +
1.209 + TInt iExpectedTrigger;
1.210 + TInt iFullDuplexReq;
1.211 + TInt iBlockedTrigger;
1.212 +
1.213 + typedef enum TTestOverUnderState
1.214 + {
1.215 + EStartState = 0x1,
1.216 + ERxOverrun_1,
1.217 + ERxOverrun_2,
1.218 + ETxUnderrun_1,
1.219 + ETxUnderrun_2
1.220 + };
1.221 + TTestOverUnderState iTestOverUnderState;
1.222 + };
1.223 +
1.224 +DDeviceIicSlaveClient::DDeviceIicSlaveClient()
1.225 +// Constructor
1.226 + {
1.227 + CLIENT_PRINT(("> DDeviceIicSlaveClient::DDeviceIicSlaveClient()"));
1.228 + iParseMask=0; // No info, no PDD, no Units
1.229 + iUnitsMask=0;
1.230 + iVersion=TVersion(KIicClientMajorVersionNumber,
1.231 + KIicClientMinorVersionNumber,
1.232 + KIicClientBuildVersionNumber);
1.233 + }
1.234 +
1.235 +#ifdef STANDALONE_CHANNEL
1.236 +//Store all the channels created by the client into an array
1.237 +RPointerArray<DIicSlaveClientChan> ChannelArray;
1.238 +#endif
1.239 +DDeviceIicSlaveClient::~DDeviceIicSlaveClient()
1.240 +// Destructor
1.241 + {
1.242 + CLIENT_PRINT(("> DDeviceIicSlaveClient::~DDeviceIicSlaveClient()"));
1.243 +#ifdef STANDALONE_CHANNEL
1.244 + //The client is reponsible for channel destroy in STANDALONE_CHANNEL mode
1.245 + ChannelArray.ResetAndDestroy();
1.246 +#endif
1.247 + }
1.248 +
1.249 +TInt DDeviceIicSlaveClient::Install()
1.250 +// Install the device driver.
1.251 + {
1.252 + CLIENT_PRINT(("> DDeviceIicSlaveClient::Install()"));
1.253 +
1.254 + return(SetName(&KLddRootName));
1.255 + }
1.256 +
1.257 +
1.258 +void DDeviceIicSlaveClient::GetCaps(TDes8& aDes) const
1.259 +// Return the IicClient capabilities.
1.260 + {
1.261 + CLIENT_PRINT(("> DDeviceIicSlaveClient::GetCaps(TDes8& aDes) const"));
1.262 + TPckgBuf<TCapsIicSlaveClient> b;
1.263 + b().version=TVersion(KIicClientMajorVersionNumber,
1.264 + KIicClientMinorVersionNumber,
1.265 + KIicClientBuildVersionNumber);
1.266 + Kern::InfoCopy(aDes,b);
1.267 + }
1.268 +
1.269 +
1.270 +TInt DDeviceIicSlaveClient::Create(DLogicalChannelBase*& aChannel)
1.271 +// Create a channel on the device.
1.272 + {
1.273 + CLIENT_PRINT(("> DDeviceIicSlaveClient::Create(DLogicalChannelBase*& aChannel)"));
1.274 + if(iOpenChannels>=KMaxNumChannels)
1.275 + return KErrOverflow;
1.276 + aChannel=new DChannelIicSlaveClient;
1.277 + return aChannel?KErrNone:KErrNoMemory;
1.278 + }
1.279 +
1.280 +#ifdef STANDALONE_CHANNEL
1.281 +// auxiliary function for ordering entries in the array of channels
1.282 +TInt DChannelIicSlaveClient::OrderEntries(const DIicSlaveClientChan& aMatch, const DIicSlaveClientChan& aEntry)
1.283 + {
1.284 + TUint8 l=(TUint8)aMatch.GetChanNum();
1.285 + TUint8 r=(TUint8)aEntry.GetChanNum();
1.286 + if(l>r)
1.287 + return -1;
1.288 + else if(l<r)
1.289 + return 1;
1.290 + else
1.291 + return 0;
1.292 + }
1.293 +
1.294 +// global ordering object to be passed to RPointerArray InsertInOrderXXX and FindInOrder
1.295 +TLinearOrder<DIicSlaveClientChan> EntryOrder(DChannelIicSlaveClient::OrderEntries);
1.296 +
1.297 +TInt GetChanPtr(const TInt aBusId, DIicSlaveClientChan*& aChan)
1.298 + {
1.299 + __KTRACE_OPT(KIIC, Kern::Printf("GetChanPtr, aBusId=0x%x\n",aBusId));
1.300 + TInt32 chanId;
1.301 + chanId = GET_CHAN_NUM(aBusId);
1.302 + __KTRACE_OPT(KIIC, Kern::Printf("GetChanPtr, chanId=0x%x\n",chanId));
1.303 + DIicSlaveClientChan chanEntry(NULL,(TInt8)chanId, DIicBusChannel::EMasterSlave);
1.304 +
1.305 + TInt r = KErrNotFound;
1.306 + TInt aIndex = ChannelArray.FindInOrder(&chanEntry, EntryOrder);
1.307 +
1.308 + if(aIndex >= 0)
1.309 + {
1.310 + aChan = ChannelArray[aIndex];
1.311 + r = KErrNone;
1.312 + }
1.313 +
1.314 + return r;
1.315 + }
1.316 +#endif/*STANDALONE_CHANNEL*/
1.317 +
1.318 +DECLARE_STANDARD_LDD()
1.319 + {
1.320 +#ifdef STANDALONE_CHANNEL
1.321 + TInt r = KErrNone;
1.322 + DIicBusChannel *chan = NULL, *chanM = NULL, *chanS = NULL;
1.323 + DIicSlaveClientChan* aSlaveClientChan;
1.324 + for(TInt i=0; i<NUM_CHANNELS; i++)
1.325 + {
1.326 + CLIENT_PRINT(("\n"));
1.327 + #if defined(MASTER_MODE)
1.328 + if(CHANNEL_TYPE(i) == (DIicBusChannel::EMaster))
1.329 + {
1.330 + chan=new DSimulatedIicBusChannelMasterI2c(BUS_TYPE,CHANNEL_DUPLEX(i));
1.331 + if(!chan)
1.332 + {
1.333 + CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE(i),i));
1.334 + return NULL;
1.335 + }
1.336 + CLIENT_PRINT(("I2C chan created at 0x%x\n",chan));
1.337 + if(((DSimulatedIicBusChannelMasterI2c*)chan)->Create()!=KErrNone)
1.338 + {
1.339 + delete chan;
1.340 + return NULL;
1.341 + }
1.342 + aSlaveClientChan = new DIicSlaveClientChan(chan,AssignChanNumI2c(),DIicBusChannel::EMaster);
1.343 + if(!aSlaveClientChan)
1.344 + {
1.345 + delete chan;
1.346 + return NULL;
1.347 + }
1.348 + r = ChannelArray.InsertInOrder(aSlaveClientChan,EntryOrder);
1.349 + if(r!=KErrNone)
1.350 + {
1.351 + delete chan;
1.352 + delete aSlaveClientChan;
1.353 + break;
1.354 + }
1.355 + }
1.356 + #endif
1.357 + #if defined(MASTER_MODE) && defined(SLAVE_MODE)
1.358 + if(CHANNEL_TYPE(i) == DIicBusChannel::EMasterSlave)
1.359 + {
1.360 + chanM=new DSimulatedIicBusChannelMasterI2c(BUS_TYPE,CHANNEL_DUPLEX(i));
1.361 + if(!chanM)
1.362 + return NULL;
1.363 + chanS=new DSimulatedIicBusChannelSlaveI2c(BUS_TYPE,CHANNEL_DUPLEX(i));
1.364 + if(!chanS)
1.365 + {
1.366 + delete chanM;
1.367 + return NULL;
1.368 + }
1.369 + chan=new DSimulatedIicBusChannelMasterSlaveI2c(BUS_TYPE,CHANNEL_DUPLEX(i),(DSimulatedIicBusChannelMasterI2c*)chanM,(DSimulatedIicBusChannelSlaveI2c*)chanS); // Generic implementation
1.370 + if(!chan)
1.371 + {
1.372 + CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE(i),i));
1.373 + delete chanM;
1.374 + delete chanS;
1.375 + return NULL;
1.376 + }
1.377 + CLIENT_PRINT(("I2C chan created at 0x%x\n",chan));
1.378 + if(((DIicBusChannelMasterSlave*)chan)->DoCreate()!=KErrNone)
1.379 + {
1.380 + delete chanM;
1.381 + delete chanS;
1.382 + delete chan;
1.383 + return NULL;
1.384 + }
1.385 + aSlaveClientChan = new DIicSlaveClientChan(chan,AssignChanNumI2c(),DIicBusChannel::EMasterSlave);
1.386 + if(!aSlaveClientChan)
1.387 + {
1.388 + delete chanM;
1.389 + delete chanS;
1.390 + delete chan;
1.391 + return NULL;
1.392 + }
1.393 + r = ChannelArray.InsertInOrder(aSlaveClientChan,EntryOrder);
1.394 + if(r!=KErrNone)
1.395 + {
1.396 + delete chanM;
1.397 + delete chanS;
1.398 + delete chan;
1.399 + delete aSlaveClientChan;
1.400 + break;
1.401 + }
1.402 + }
1.403 + #endif
1.404 + #if defined(SLAVE_MODE)
1.405 + if(CHANNEL_TYPE(i) == (DIicBusChannel::ESlave))
1.406 + {
1.407 + chan=new DSimulatedIicBusChannelSlaveI2c(BUS_TYPE,CHANNEL_DUPLEX(i));
1.408 + if(!chan)
1.409 + {
1.410 + CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE(i),i));
1.411 + return NULL;
1.412 + }
1.413 + CLIENT_PRINT(("I2C chan created at 0x%x\n",chan));
1.414 + if(((DSimulatedIicBusChannelSlaveI2c*)chan)->Create()!=KErrNone)
1.415 + return NULL;
1.416 + aSlaveClientChan = new DIicSlaveClientChan(chan,AssignChanNumI2c(),DIicBusChannel::ESlave);
1.417 + if(!aSlaveClientChan)
1.418 + {
1.419 + delete chan;
1.420 + return NULL;
1.421 + }
1.422 + r = ChannelArray.InsertInOrder(aSlaveClientChan,EntryOrder);
1.423 + if(r!=KErrNone)
1.424 + {
1.425 + delete chan;
1.426 + delete aSlaveClientChan;
1.427 + break;
1.428 + }
1.429 + }
1.430 + #endif
1.431 + #if !defined(MASTER_MODE) && !defined(SLAVE_MODE)
1.432 + #error I2C mode not defined as Master, Slave nor Master-Slave
1.433 + #endif
1.434 + }
1.435 +#endif
1.436 + return new DDeviceIicSlaveClient;
1.437 + }
1.438 +
1.439 +
1.440 +
1.441 +DChannelIicSlaveClient::DChannelIicSlaveClient()
1.442 +// Constructor
1.443 + {
1.444 + iFullDuplexReq=iBlockedTrigger=iExpectedTrigger=0;
1.445 + CLIENT_PRINT(("> DChannelIicSlaveClient::DChannelIicSlaveClient()"));
1.446 + iClient=&Kern::CurrentThread();
1.447 + // Increase the DThread's ref count so that it does not close without us
1.448 + iClient->Open();
1.449 + iTestOverUnderState = EStartState;
1.450 + }
1.451 +
1.452 +DChannelIicSlaveClient::~DChannelIicSlaveClient()
1.453 +// Destructor
1.454 + {
1.455 + CLIENT_PRINT(("> DChannelIicSlaveClient::~DChannelIicSlaveClient()"));
1.456 + iDfcQue->Destroy();
1.457 + delete iNotif;
1.458 + delete iRxBuf;
1.459 + delete iTxBuf;
1.460 + delete iBusTxCheckBuf;
1.461 + // decrement the DThread's reference count
1.462 + Kern::SafeClose((DObject*&)iClient, NULL);
1.463 + }
1.464 +
1.465 +void DChannelIicSlaveClient::RequestComplete(TInt r)
1.466 + {
1.467 + Kern::RequestComplete(iClient, iStatus, r);
1.468 + }
1.469 +
1.470 +TInt DChannelIicSlaveClient::RegisterRxBuffer(TInt aChannelId, TPtr8 aRxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
1.471 + {
1.472 + TInt r = KErrNone;
1.473 +#ifdef STANDALONE_CHANNEL
1.474 + DIicSlaveClientChan* aChanPtr = NULL;
1.475 + if(iCapturedChan.iChannelId == aChannelId)
1.476 + aChanPtr = iCapturedChan.iChannel;
1.477 + if(!aChanPtr)
1.478 + return KErrArgument;
1.479 + if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave)
1.480 + r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->RegisterRxBuffer(aRxBuffer, aBufGranularity, aNumWords, aOffset);
1.481 + else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave)
1.482 + r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->RegisterRxBuffer(aRxBuffer, aBufGranularity, aNumWords, aOffset);
1.483 +#else
1.484 + r = IicBus::RegisterRxBuffer(aChannelId, aRxBuffer, aBufGranularity, aNumWords, aOffset);
1.485 +#endif
1.486 + return r;
1.487 + }
1.488 +
1.489 +TInt DChannelIicSlaveClient::SetNotificationTrigger(TInt aChannelId, TInt aTrigger)
1.490 + {
1.491 + TInt r = KErrNone;
1.492 +#ifdef STANDALONE_CHANNEL
1.493 + DIicSlaveClientChan* aChanPtr = NULL;
1.494 + if(iCapturedChan.iChannelId == aChannelId)
1.495 + aChanPtr = iCapturedChan.iChannel;
1.496 + if(!aChanPtr)
1.497 + return KErrArgument;
1.498 + if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave)
1.499 + r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->SetNotificationTrigger(aTrigger);
1.500 + else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave)
1.501 + r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->SetNotificationTrigger(aTrigger);
1.502 +#else
1.503 + r = IicBus::SetNotificationTrigger(aChannelId, aTrigger);
1.504 +#endif
1.505 + return r;
1.506 + }
1.507 +
1.508 +TInt DChannelIicSlaveClient::StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2)
1.509 + {
1.510 + TInt r = KErrNone;
1.511 +#ifdef STANDALONE_CHANNEL
1.512 + DIicSlaveClientChan* aChanPtr;
1.513 + r = GetChanPtr(aId, aChanPtr);
1.514 + if(r != KErrNone)
1.515 + return r;
1.516 + if(!aChanPtr)
1.517 + return KErrArgument;
1.518 + if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave)
1.519 + r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->StaticExtension(aFunction, aParam1, aParam2);
1.520 + else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave)
1.521 + r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->StaticExtension(aFunction, aParam1, aParam2);
1.522 +#else
1.523 + r = IicBus::StaticExtension(aId, aFunction, aParam1, aParam2);
1.524 +#endif
1.525 + return r;
1.526 + }
1.527 +
1.528 +TInt DChannelIicSlaveClient::RegisterTxBuffer(TInt aChannelId, TPtr8 aTxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
1.529 + {
1.530 + TInt r = KErrNone;
1.531 +#ifdef STANDALONE_CHANNEL
1.532 + DIicSlaveClientChan* aChanPtr = NULL;
1.533 + if(iCapturedChan.iChannelId == aChannelId)
1.534 + aChanPtr = iCapturedChan.iChannel;
1.535 + if(!aChanPtr)
1.536 + return KErrArgument;
1.537 + if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave)
1.538 + r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->RegisterTxBuffer(aTxBuffer, aBufGranularity, aNumWords, aOffset);
1.539 + else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave)
1.540 + r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->RegisterTxBuffer(aTxBuffer, aBufGranularity, aNumWords, aOffset);
1.541 +#else
1.542 + r = IicBus::RegisterTxBuffer(aChannelId, aTxBuffer, aBufGranularity, aNumWords, aOffset);
1.543 +#endif
1.544 + return r;
1.545 + }
1.546 +
1.547 +TInt DChannelIicSlaveClient::CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch)
1.548 + {
1.549 + TInt r = KErrNone;
1.550 +#ifndef STANDALONE_CHANNEL
1.551 + r = IicBus::CaptureChannel(aBusId, aConfigHdr, aCallback, aChannelId, aAsynch);
1.552 +#else
1.553 + // Check that that aCallback!=NULL and aConfigHdr!=NULL - if not, return KErrArgument
1.554 + if(!aCallback || !aConfigHdr)
1.555 + {
1.556 + return KErrArgument;
1.557 + }
1.558 +
1.559 + // Get the channel
1.560 + DIicSlaveClientChan* chanPtr = NULL;
1.561 + if(r == KErrNone)
1.562 + {
1.563 + r = GetChanPtr(aBusId, chanPtr);
1.564 + if(r == KErrNone)
1.565 + {
1.566 + if(!chanPtr)
1.567 + {
1.568 + r = KErrArgument;
1.569 + }
1.570 + else
1.571 + {
1.572 + switch(chanPtr->GetChanType())
1.573 + {
1.574 + // CaptureChannel requests are only supported by channels in Slave mode.
1.575 + case DIicBusChannel::EMaster:
1.576 + {
1.577 + r = KErrNotSupported;
1.578 + break;
1.579 + }
1.580 + case DIicBusChannel::EMasterSlave:
1.581 + {
1.582 + r = ((DIicBusChannelMasterSlave*) (chanPtr->GetChannelPtr()))->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch);
1.583 + break;
1.584 + }
1.585 + case DIicBusChannel::ESlave:
1.586 + {
1.587 + r = ((DIicBusChannelSlave*) (chanPtr->GetChannelPtr()))->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch);
1.588 + break;
1.589 + }
1.590 + default:
1.591 + {
1.592 + r = KErrArgument;
1.593 + }
1.594 + }
1.595 + // For synchronous capture, if successful then install the channel
1.596 + if(r == KErrNone)
1.597 + {
1.598 + if(!aAsynch)
1.599 + {
1.600 + iCapturedChan.iChannel = chanPtr;
1.601 + iCapturedChan.iChannelId = aChannelId;
1.602 + }
1.603 + else
1.604 + //For asynchronous capture, record slaveChanPtr, if later failed capture,
1.605 + //clean iCapturedChannel in client's callback.
1.606 + iCapturedChan.iChannel = chanPtr;
1.607 + }
1.608 + }
1.609 + }
1.610 + }
1.611 +#endif
1.612 + return r;
1.613 + }
1.614 +
1.615 +TInt DChannelIicSlaveClient::ReleaseChannel(TInt aChannelId)
1.616 + {
1.617 + TInt r = KErrNone;
1.618 +#ifndef STANDALONE_CHANNEL
1.619 + r = IicBus::ReleaseChannel(aChannelId);
1.620 +#else
1.621 + __KTRACE_OPT(KIIC, Kern::Printf("DChannelIicSlaveClient::ReleaseChannel, channelID = 0x%x \n",aChannelId));
1.622 + // Acquire the pointer to the Slave Channel
1.623 + if(iCapturedChan.iChannelId != aChannelId)
1.624 + return KErrNotFound;
1.625 +
1.626 + if((iCapturedChan.iChannel)->GetChanType() == DIicBusChannel::EMasterSlave)
1.627 + r = ((DIicBusChannelMasterSlave*)((iCapturedChan.iChannel)->GetChannelPtr()))->ReleaseChannel();
1.628 + else if((iCapturedChan.iChannel)->GetChanType() == DIicBusChannel::ESlave)
1.629 + r = ((DIicBusChannelSlave*)((iCapturedChan.iChannel)->GetChannelPtr()))->ReleaseChannel();
1.630 + //After release channel, reset iCapturedChan
1.631 + iCapturedChan.iChannel = NULL;
1.632 + iCapturedChan.iChannelId = 0;
1.633 +#endif
1.634 + return r;
1.635 + }
1.636 +TInt DChannelIicSlaveClient::CbProcessOverUnderRunRxTx()
1.637 + {
1.638 + CLIENT_PRINT(("> DChannelIicSlaveClient::CbProcessOverUnderRunRxTx(), iTestOverUnderState=%d\n",iTestOverUnderState));
1.639 + TInt r = KErrNone;
1.640 + switch (iTestOverUnderState)
1.641 + {
1.642 + case(EStartState):
1.643 + {
1.644 + // In this state, no action is required
1.645 + break;
1.646 + };
1.647 + case(ERxOverrun_1):
1.648 + {
1.649 + CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ERxOverrun_1\n"));
1.650 + // At this point, the outstanding request trigger should be ETxAllBytes | ETxUnderrun
1.651 + // and the flag to indicate duplex transfers should be cleared
1.652 + if((iExpectedTrigger != (ETxAllBytes | ETxUnderrun)) || (iFullDuplexReq != ETxAllBytes))
1.653 + {
1.654 + CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq));
1.655 + r=KErrGeneral;
1.656 + }
1.657 + else
1.658 + {
1.659 + // Simulate providing a new buffer (actually, re-use existing buffer)
1.660 + CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterRxBuffer\n"));
1.661 + TPtr8 rxPtr(iRxBuf,KRxBufSizeInBytes);
1.662 + r = RegisterRxBuffer(iChannelId, rxPtr, iRxRegGranularity, iNumRegRxWords, iRxRegOffset);
1.663 +
1.664 + if(r != KErrNone)
1.665 + {
1.666 + CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterRxBuffer returned %d\n",r));
1.667 + }
1.668 + else
1.669 + {
1.670 + // For the next step, just specify the new Rx triggers (do not specify Tx triggers)
1.671 + r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun));
1.672 + if(r != KErrNone)
1.673 + {
1.674 + CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d\n",r));
1.675 + }
1.676 + else
1.677 + {
1.678 + iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun;
1.679 + iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
1.680 + iTestOverUnderState = ERxOverrun_2; // Prepare for callback
1.681 + // The requested number of words when the buffer was registered was 8, so simulate 10
1.682 + // to provoke an RxOverrun event.
1.683 + TInt numWords=10;
1.684 + // To support testing, any values of aId for StaticExtension must be shifted left one place
1.685 + // and for a Slave, the two msbs must be zero
1.686 + TInt ctrlIoVal = RBusDevIicClient::ECtrlIoRxWords;
1.687 + ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
1.688 + r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords);
1.689 + }
1.690 + }
1.691 + }
1.692 + break;
1.693 + };
1.694 + case(ERxOverrun_2):
1.695 + {
1.696 + CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ERxOverrun_2\n"));
1.697 + // At this point, the outstanding request trigger should be ETxAllBytes | ETxUnderrun
1.698 + // and the flag to indicate duplex transfers should be cleared
1.699 + if((iExpectedTrigger != (ETxAllBytes | ETxUnderrun)) || (iFullDuplexReq != ETxAllBytes))
1.700 + {
1.701 + CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq));
1.702 + r=KErrGeneral;
1.703 + }
1.704 + else
1.705 + {
1.706 + // Simulate providing a new buffer (actually, re-use existing buffer)
1.707 + CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterRxBuffer\n"));
1.708 + TPtr8 rxPtr(iRxBuf,KRxBufSizeInBytes);
1.709 + r = RegisterRxBuffer(iChannelId, rxPtr, iRxRegGranularity, iNumRegRxWords, iRxRegOffset);
1.710 + if(r != KErrNone)
1.711 + {
1.712 + CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterRxBuffer returned %d\n",r));
1.713 + }
1.714 + else
1.715 + {
1.716 + // Test that an attempt to modify existing Tx notification requests is rejected
1.717 + r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxOverrun));
1.718 + if(r != KErrInUse)
1.719 + {
1.720 + CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrInUse\n",r));
1.721 + }
1.722 + else
1.723 + {
1.724 + // For the next step, specify the new Rx triggers and the Tx triggers
1.725 + r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun));
1.726 + if(r != KErrNone)
1.727 + {
1.728 + CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrNone\n",r));
1.729 + }
1.730 + else
1.731 + {
1.732 + iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun;
1.733 + iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
1.734 + iTestOverUnderState = ETxUnderrun_1; // Prepare for callback
1.735 + // The requested number of words when the buffer was registered was 12, so simulate 14
1.736 + // to provoke an TxUnderrun event.
1.737 + TInt numWords=14;
1.738 + // To support testing, any values of aId for StaticExtension must be shifted left one place
1.739 + // and for a Slave, the two msbs must be zero
1.740 + TInt ctrlIoVal = RBusDevIicClient::ECtrlIoTxWords;
1.741 + ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
1.742 + r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords);
1.743 + }
1.744 + }
1.745 + }
1.746 + }
1.747 + break;
1.748 + };
1.749 + case(ETxUnderrun_1):
1.750 + {
1.751 + CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ETxOverrun_1\n"));
1.752 + // At this point, the outstanding request trigger should be ERxAllBytes | ERxOverrun
1.753 + // and the flag to indicate duplex transfers should be cleared
1.754 + if((iExpectedTrigger != (ERxAllBytes | ERxOverrun)) || (iFullDuplexReq != ERxAllBytes))
1.755 + {
1.756 + CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq));
1.757 + r=KErrGeneral;
1.758 + }
1.759 + else
1.760 + {
1.761 + // Simulate providing a new buffer (actually, re-use existing buffer)
1.762 + CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterTxBuffer\n"));
1.763 + TPtr8 rxPtr(iTxBuf,KTxBufSizeInBytes);
1.764 + r = RegisterTxBuffer(iChannelId, rxPtr, iTxRegGranularity, iNumRegTxWords, iTxRegOffset);
1.765 + if(r != KErrNone)
1.766 + {
1.767 + CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterTxBuffer returned %d\n",r));
1.768 + }
1.769 + else
1.770 + {
1.771 + // For the next step, just specify the new Tx triggers (do not specify Rx triggers)
1.772 + r = SetNotificationTrigger(iChannelId, (ETxAllBytes | ETxUnderrun));
1.773 + if(r != KErrNone)
1.774 + {
1.775 + CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d\n",r));
1.776 + }
1.777 + else
1.778 + {
1.779 + iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun;
1.780 + iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
1.781 + iTestOverUnderState = ETxUnderrun_2; // Prepare for callback
1.782 + // The requested number of words when the buffer was registered was 12, so simulate 14
1.783 + // to provoke an TxUnderrun event.
1.784 + TInt numWords=14;
1.785 + // To support testing, any values of aId for StaticExtension must be shifted left one place
1.786 + // and for a Slave, the two msbs must be zero
1.787 + TInt ctrlIoVal = RBusDevIicClient::ECtrlIoTxWords;
1.788 + ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
1.789 + r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords);
1.790 + }
1.791 + }
1.792 + }
1.793 + break;
1.794 + };
1.795 + case(ETxUnderrun_2):
1.796 + {
1.797 + CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ETxUnderrun_2\n"));
1.798 + // At this point, the outstanding request trigger should be ERxAllBytes | ERxOverrun
1.799 + // and the flag to indicate duplex transfers should be cleared
1.800 + if((iExpectedTrigger != (ERxAllBytes | ERxOverrun)) || (iFullDuplexReq != ERxAllBytes))
1.801 + {
1.802 + CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq));
1.803 + r=KErrGeneral;
1.804 + }
1.805 + else
1.806 + {
1.807 + // Simulate providing a new buffer (actually, re-use existing buffer)
1.808 + CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterRxBuffer\n"));
1.809 + TPtr8 rxPtr(iTxBuf,KTxBufSizeInBytes);
1.810 + r = RegisterTxBuffer(iChannelId, rxPtr, iTxRegGranularity, iNumRegTxWords, iTxRegOffset);
1.811 + if(r != KErrNone)
1.812 + {
1.813 + CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterTxBuffer returned %d\n",r));
1.814 + }
1.815 + else
1.816 + {
1.817 + // Test that an attempt to modify existing Rx notification requests is rejected
1.818 + r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxUnderrun | ETxAllBytes | ETxUnderrun));
1.819 + if(r != KErrInUse)
1.820 + {
1.821 + CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrInUse\n",r));
1.822 + }
1.823 + else
1.824 + {
1.825 + // For the next step, specify the new Rx triggers and the Tx triggers
1.826 + r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun));
1.827 +
1.828 + if(r != KErrNone)
1.829 + {
1.830 + CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrNone\n",r));
1.831 + }
1.832 + else
1.833 + {
1.834 + // Simulate a simultaneous ERxAllBytes and ETxAllBytes event.
1.835 + iExpectedTrigger = ERxAllBytes | ETxAllBytes;
1.836 + iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
1.837 + iTestOverUnderState = EStartState; // Prepare for callback - return to normal operation
1.838 + // Need to pass the number of words in an array, for use by StaticExtension
1.839 + TInt parms[2];
1.840 + parms[0]= 8; // Number of Rx Words
1.841 + parms[1]=12; // Number of Tx Words
1.842 + // To support testing, any values of aId for StaticExtension must be shifted left one place
1.843 + // and for a Slave, the two msbs must be zero
1.844 + TInt ctrlIoVal = RBusDevIicClient::ECtrlIoRxTxWords;
1.845 + ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
1.846 + r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)(&parms[0]));
1.847 + }
1.848 + }
1.849 + }
1.850 + }
1.851 + break;
1.852 + };
1.853 + default:
1.854 + {
1.855 + r = KErrGeneral;
1.856 + break;
1.857 + };
1.858 + }
1.859 + return r;
1.860 + }
1.861 +
1.862 +void DChannelIicSlaveClient::SlaveClientCallbackFunc(TInt aChannelId, TInt aReturn, TInt aTrigger, TInt16 aRxWords, TInt16 aTxWords, TAny* aParam)
1.863 + {
1.864 + 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));
1.865 + (void)aTxWords; // Unused if CLIENT_PRINT is undefined
1.866 + (void)aRxWords; // Unused if CLIENT_PRINT is undefined
1.867 + DChannelIicSlaveClient* channel = (DChannelIicSlaveClient*)aParam;
1.868 +
1.869 + // Ensure only the valid bits of aTrigger are processed
1.870 + aTrigger &= 0xff;
1.871 +
1.872 + CLIENT_PRINT(("SlaveClientCallbackFunc() - channel=0x%x\n",channel));
1.873 + if(aTrigger == EAsyncCaptChan)
1.874 + {
1.875 + CLIENT_PRINT(("SlaveClientCallbackFunc: capture channel completed\n"));
1.876 + // Set iChannelId, and write to user-side variable.
1.877 + channel->iChannelId=aChannelId;
1.878 + TInt r=Kern::ThreadRawWrite(channel->iClient,channel->iClientChanId,&aChannelId,sizeof(TInt));
1.879 + if(r == KErrNone)
1.880 + r=aReturn;
1.881 +#ifdef STANDALONE_CHANNEL
1.882 + // Set the captured channel's iChannelId if the capture succeeds.
1.883 + if(r != KErrCompletion)
1.884 + (channel->iCapturedChan).iChannel = NULL;
1.885 + else
1.886 + (channel->iCapturedChan).iChannelId = aChannelId;
1.887 +#endif/*STANDALONE_CHANNEL*/
1.888 + channel->RequestComplete(r); // Inform user of error
1.889 + return;
1.890 + }
1.891 + else
1.892 + {
1.893 + if(aTrigger&ERxAllBytes)
1.894 + {
1.895 + CLIENT_PRINT(("SlaveClientCallbackFunc() - ERxAllBytes\n"));
1.896 + aTrigger&= ~ERxAllBytes;
1.897 + channel->iExpectedTrigger&=~ERxAllBytes;
1.898 + channel->iFullDuplexReq&=~ERxAllBytes;
1.899 + aReturn=channel->CheckDataRead();
1.900 + // Check underrun
1.901 + if(aTrigger&ERxUnderrun)
1.902 + {
1.903 + if(channel->iExpectedTrigger&ERxUnderrun)
1.904 + {
1.905 + CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxUnderrun found OK\n\n"));
1.906 + channel->iExpectedTrigger&=~ERxUnderrun;
1.907 + }
1.908 + else
1.909 + {
1.910 + CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ERxUnderrun indicated\n\n"));
1.911 + aReturn = KErrGeneral;
1.912 + }
1.913 + }
1.914 + else
1.915 + {
1.916 + if(channel->iExpectedTrigger&ERxUnderrun)
1.917 + {
1.918 + CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxUnderrun not (yet) seen\n\n"));
1.919 + aReturn = KErrGeneral;
1.920 + }
1.921 + }
1.922 + // Check overrun
1.923 + if(aTrigger&ERxOverrun)
1.924 + {
1.925 + if(channel->iExpectedTrigger&ERxOverrun)
1.926 + {
1.927 + CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxOverrun found OK\n\n"));
1.928 + channel->iExpectedTrigger&=~ERxOverrun;
1.929 + }
1.930 + else
1.931 + {
1.932 + CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ERxOverrun indicated\n\n"));
1.933 + aReturn = KErrGeneral;
1.934 + }
1.935 + }
1.936 + else
1.937 + {
1.938 + if(channel->iExpectedTrigger&ERxOverrun)
1.939 + {
1.940 + CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxOverrun not (yet) seen\n\n"));
1.941 + aReturn = KErrGeneral;
1.942 + }
1.943 + }
1.944 + }
1.945 +
1.946 + if(aTrigger&ETxAllBytes)
1.947 + {
1.948 + CLIENT_PRINT(("SlaveClientCallbackFunc() - ETxAllBytes\n"));
1.949 + aTrigger&= ~ETxAllBytes;
1.950 + channel->iExpectedTrigger&=~ETxAllBytes;
1.951 + channel->iFullDuplexReq&=~ETxAllBytes;
1.952 + aReturn=channel->CheckDataWritten();
1.953 + // Check underrun
1.954 + if(aTrigger&ETxUnderrun)
1.955 + {
1.956 + if(channel->iExpectedTrigger&ETxUnderrun)
1.957 + {
1.958 + CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxUnderrun found OK\n\n"));
1.959 + channel->iExpectedTrigger&=~ETxUnderrun;
1.960 + }
1.961 + else
1.962 + {
1.963 + CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ETxUnderrun indicated\n\n"));
1.964 + aReturn = KErrGeneral;
1.965 + }
1.966 + }
1.967 + else
1.968 + {
1.969 + if(channel->iExpectedTrigger&ETxUnderrun)
1.970 + {
1.971 + CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxUnderrun not (yet) seen\n\n"));
1.972 + aReturn = KErrGeneral;
1.973 + }
1.974 + }
1.975 + // Check overrun
1.976 + if(aTrigger&ETxOverrun)
1.977 + {
1.978 + if(channel->iExpectedTrigger&ETxOverrun)
1.979 + {
1.980 + CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxOverrun found OK\n\n"));
1.981 + channel->iExpectedTrigger&=~ETxOverrun;
1.982 + }
1.983 + else
1.984 + {
1.985 + CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ETxOverrun indicated\n\n"));
1.986 + aReturn = KErrGeneral;
1.987 + }
1.988 + }
1.989 + else
1.990 + {
1.991 + if(channel->iExpectedTrigger&ETxOverrun)
1.992 + {
1.993 + CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxOverrun not (yet) seen\n\n"));
1.994 + aReturn = KErrGeneral;
1.995 + }
1.996 + }
1.997 + }
1.998 +
1.999 +
1.1000 + if(aTrigger&EGeneralBusError)
1.1001 + {
1.1002 + if(channel->iExpectedTrigger&EGeneralBusError)
1.1003 + {
1.1004 + CLIENT_PRINT(("\nSlaveClientCallbackFunc: EGeneralBusError - as expected\n\n"));
1.1005 + channel->iExpectedTrigger&=~EGeneralBusError;
1.1006 + if(aReturn == KErrGeneral)
1.1007 + {
1.1008 + aReturn=KErrNone; // If aReturn==KErrGeneral, set to KErrNone so t_iic knows test was successful
1.1009 + channel->iFullDuplexReq = 0; // The transaction is considered terminated, so don't wait for more triggers
1.1010 + }
1.1011 + else
1.1012 + {
1.1013 + CLIENT_PRINT(("\nSlaveClientCallbackFunc: aReturn not EGeneralBusError, =0x%x \n\n",aReturn));
1.1014 + aReturn=KErrGeneral;
1.1015 + }
1.1016 +
1.1017 + }
1.1018 + else
1.1019 + {
1.1020 + CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected EGeneralBusError indicated\n\n"));
1.1021 + aReturn = KErrGeneral;
1.1022 + }
1.1023 + }
1.1024 +
1.1025 + if((aTrigger < 0)||(aTrigger & (~0xFF)))
1.1026 + {
1.1027 + CLIENT_PRINT(("\nSlaveClientCallbackFunc: trigger condition 0x%x is not recognised \n\n",aTrigger));
1.1028 + }
1.1029 +
1.1030 + // For simulataneous Rx,Tx triggers with ERxOverrun or TxUnderrun testing, need to call the following
1.1031 + if(aReturn == KErrNone)
1.1032 + {
1.1033 + aReturn = channel->CbProcessOverUnderRunRxTx();
1.1034 + }
1.1035 +
1.1036 + if((channel->iExpectedTrigger == 0)&&(channel->iFullDuplexReq == 0))
1.1037 + channel->RequestComplete(aReturn); // Complete user-side request only if all the triggers have been satisfied
1.1038 +
1.1039 + } // if(aTrigger == EAsyncCaptChan)
1.1040 + }
1.1041 +
1.1042 +
1.1043 +TInt DChannelIicSlaveClient::CheckDataRead()
1.1044 + {
1.1045 + TInt r=KErrNone;
1.1046 + // This channel will have provided a buffer for writing to, with a specified offset and number of words
1.1047 + // Bytes in the buffer before the offset should be set to zero
1.1048 + // Bytes written at and beyond the offset should exhibit an incrementing count
1.1049 + // Bytes beyond the offset that were not written to should be set to zero
1.1050 + TInt8 numWords=(iRxReqNumWords>iNumRegRxWords)?iNumRegRxWords:iRxReqNumWords;
1.1051 + TInt8 currVal=0;
1.1052 + TInt8 index = 0;
1.1053 + while(index<iRxRegOffset)
1.1054 + {
1.1055 + currVal=*(iRxBuf+index);
1.1056 + if(currVal != 0)
1.1057 + {
1.1058 + CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataRead, index=%d, value =0x%x, expected 0",index,currVal));
1.1059 + r=KErrCorrupt;
1.1060 + }
1.1061 + ++index;
1.1062 + }
1.1063 +
1.1064 + TInt8 checkVal=0x10; // first value written by simulated bus channel
1.1065 + TInt8 endOfData= (TInt8)(iRxRegOffset+(numWords*iRxRegGranularity));
1.1066 + TInt8 wordCount=0;
1.1067 + while(index<endOfData)
1.1068 + {
1.1069 + currVal = *(iRxBuf+index);
1.1070 + if(checkVal != currVal)
1.1071 + {
1.1072 + CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataRead, index=%d, value =0x%x, expected 0x%x",index,currVal,checkVal));
1.1073 + r=KErrCorrupt;
1.1074 + }
1.1075 + if(++wordCount == iRxRegGranularity)
1.1076 + {
1.1077 + wordCount=0;
1.1078 + checkVal++;
1.1079 + }
1.1080 + ++index;
1.1081 + }
1.1082 +
1.1083 + while(index<KRxBufSizeInBytes)
1.1084 + {
1.1085 + currVal=*(iRxBuf+index);
1.1086 + if(currVal != 0)
1.1087 + {
1.1088 + CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataRead, index=%d, value =0x%x, expected 0",index,currVal);)
1.1089 + r=KErrCorrupt;
1.1090 + }
1.1091 + ++index;
1.1092 + }
1.1093 + return r;
1.1094 + }
1.1095 +
1.1096 +
1.1097 +TInt DChannelIicSlaveClient::CheckDataWritten()
1.1098 + {
1.1099 + TInt r=KErrNone;
1.1100 + // The pattern in the transmit buffer used by the simulated bus channel contains a incrementing count
1.1101 + // from 0 to (KTxBufSizeInBytes-1), therefore the first value to be present in the check buffer will be
1.1102 + // represented by the required offset.
1.1103 +
1.1104 + // The bytes "transmitted" are stored in the simulated bus' iTxCheckBuf
1.1105 + // Since the simulated bus channel is also in the kernel process it shares the same address space
1.1106 + // Get the address of the buffer
1.1107 + TUint testId = (((TUint)(RBusDevIicClient::ECtrlIoTxChkBuf))<<1)&0x3FFFFFFF;
1.1108 + CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataWritten invoking StaticExtension ECtrlIoTxChkBuf with iBusId=0x%x, testId=0x%x, iBusTxCheckBuf=0x%x\n",iBusId,testId,iBusTxCheckBuf));
1.1109 + r = StaticExtension(iBusId, testId, &iBusTxCheckBuf, NULL);
1.1110 + if(r!=KErrNone)
1.1111 + {
1.1112 + CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataWritten StaticExtension ECtrlIoTxChkBuf returned %d\n",r));
1.1113 + return r;
1.1114 + }
1.1115 +
1.1116 + // Check that the values in the check buffer increment for the
1.1117 + // required number of words, and that any remaining bytes in the check buffer are set to zero.
1.1118 + TInt8 firstValue = iTxRegOffset;
1.1119 + TInt8 currVal = 0;
1.1120 + TInt8 wordsWritten = 0;
1.1121 + wordsWritten=(iTxReqNumWords>iNumRegTxWords)?iNumRegTxWords:iTxReqNumWords;
1.1122 + TInt8 index=0;
1.1123 + while(index<(wordsWritten*iTxRegGranularity))
1.1124 + {
1.1125 + currVal=*(iBusTxCheckBuf+index);
1.1126 + if(currVal != (TInt8)(firstValue+index))
1.1127 + {
1.1128 + CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataWritten, index=%d, value =0x%x, expected 0x%x",index,currVal,(TInt8)(firstValue+index)));
1.1129 + r=KErrCorrupt;
1.1130 + }
1.1131 + ++index;
1.1132 + }
1.1133 + while(index<(iNumRegTxWords*iTxRegGranularity))
1.1134 + {
1.1135 + currVal=*(iBusTxCheckBuf+index);
1.1136 + if(currVal != 0)
1.1137 + {
1.1138 + CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataWritten, index=%d, value =0x%x, expected 0",index,currVal));
1.1139 + r=KErrCorrupt;
1.1140 + }
1.1141 + ++index;
1.1142 + }
1.1143 + return r;
1.1144 + }
1.1145 +
1.1146 +
1.1147 +TInt DChannelIicSlaveClient::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
1.1148 + {
1.1149 + CLIENT_PRINT(("> DChannelIicSlaveClient::DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion &aVer)"));
1.1150 +
1.1151 + TInt r = Kern::DynamicDfcQCreate(iDfcQue,KIicSlaveClientThreadPriority,KIicSlaveClientThreadName);
1.1152 + if(r!=KErrNone)
1.1153 + return r;
1.1154 + SetDfcQ(iDfcQue);
1.1155 +
1.1156 + // Allocate buffers for Rx, Tx operations
1.1157 + iRxBuf = new TUint8[KRxBufSizeInBytes];
1.1158 + iTxBuf = new TUint8[KTxBufSizeInBytes];
1.1159 + if((iRxBuf == NULL)||(iTxBuf == NULL))
1.1160 + return KErrNoMemory;
1.1161 + // Start receiving messages
1.1162 + iMsgQ.Receive();
1.1163 +
1.1164 + return r;
1.1165 + }
1.1166 +
1.1167 +TInt DChannelIicSlaveClient::InitSlaveClient()
1.1168 + {
1.1169 + iNotif = new TIicBusSlaveCallback(DChannelIicSlaveClient::SlaveClientCallbackFunc, (TAny*)this, iDfcQue, KIicSlaveClientDfcPriority);
1.1170 + if(iNotif == NULL)
1.1171 + {
1.1172 + CLIENT_PRINT(("> DChannelIicSlaveClient::InitSlaveClient ERROR unable to allocate space TIicBusSlaveCallback* iNotif \n"));
1.1173 + return KErrNoMemory;
1.1174 + }
1.1175 + return KErrNone;
1.1176 + }
1.1177 +
1.1178 +void DChannelIicSlaveClient::HandleMsg(TMessageBase* aMsg)
1.1179 + {
1.1180 + TThreadMessage& m=*(TThreadMessage*)aMsg;
1.1181 + TInt id=m.iValue;
1.1182 +
1.1183 + CLIENT_PRINT((" >ldd: DChannelIicSlaveClient::HandleMsg(TMessageBase* aMsg) id=%d\n", id));
1.1184 +
1.1185 + if (id == (TInt)ECloseMsg)
1.1186 + {
1.1187 + iMsgQ.iMessage->Complete(KErrNone,EFalse);
1.1188 + return;
1.1189 + }
1.1190 +
1.1191 + if (id<0)
1.1192 + {
1.1193 + TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
1.1194 + TInt r=DoRequest(~id, pS, m.Ptr1(), m.Ptr2());
1.1195 + if (r!=KErrNone)
1.1196 + {
1.1197 + Kern::RequestComplete(iClient, pS, r);
1.1198 + }
1.1199 + m.Complete(KErrNone,ETrue);
1.1200 + }
1.1201 + else
1.1202 + if((id>=0)&&(id!=KMaxTInt))
1.1203 + {
1.1204 + TInt r=DoControl(id,m.Ptr0(),m.Ptr1());
1.1205 + m.Complete(r,ETrue);
1.1206 + }
1.1207 + }
1.1208 +
1.1209 +
1.1210 +TInt DChannelIicSlaveClient::DoControl(TInt aId, TAny* a1, TAny* a2)
1.1211 + {
1.1212 + CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoked with aId=0x%x, a1=0x%x, a2=0x%x\n", aId,a1,a2));
1.1213 + TInt r=KErrNone;
1.1214 + // To support testing, any values of aId for StaticExtension must be shifted left one place
1.1215 + // and for a Slave, the two msbs must be zero
1.1216 + TInt ctrlIoVal = 0;
1.1217 + if((aId & KTestSlaveControlIo) == KTestSlaveControlIo)
1.1218 + ctrlIoVal = (aId << 1) & 0x3FFFFFFF;
1.1219 +
1.1220 + switch(aId)
1.1221 + {
1.1222 + case(RBusDevIicClient::EInitSlaveClient):
1.1223 + {
1.1224 + r=InitSlaveClient();
1.1225 + break;
1.1226 + }
1.1227 +
1.1228 + case(RBusDevIicClient::ECaptureChanSync):
1.1229 + {
1.1230 + // a1 is a pointer to the TDes8* aConfigHdr
1.1231 + // a2 is a pointer to TInt* parms[2], where:
1.1232 + // parms[0]=(TInt*)aBusId;
1.1233 + // parms[1]=&aChannelId;
1.1234 + //
1.1235 + TInt* parms[2];
1.1236 + r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt*));
1.1237 + if(r!=KErrNone)
1.1238 + break; // Can't proceed if can't access request parameters
1.1239 + //
1.1240 + TInt hdrSize = Kern::ThreadGetDesLength(iClient,a1);
1.1241 + CLIENT_PRINT(("DChannelIicSlaveClient::DoControl hdrSize = 0x%x\n",hdrSize));
1.1242 + if (hdrSize<=0)
1.1243 + {
1.1244 + CLIENT_PRINT(("DChannelIicSlaveClient::DoControl ERROR, hdrSize is invalid\n"));
1.1245 + r = KErrArgument;
1.1246 + break;
1.1247 + }
1.1248 + if((iConfigHdr = HBuf8::New(hdrSize)) == NULL)
1.1249 + return KErrNoMemory;
1.1250 + r = Kern::ThreadDesRead(iClient,a1,*iConfigHdr,0);
1.1251 + if(r!=KErrNone)
1.1252 + {
1.1253 + delete iConfigHdr;
1.1254 + break;
1.1255 + }
1.1256 + // Store the address of the user-side variable to update with the ChannelId
1.1257 + iClientChanId=parms[1];
1.1258 +
1.1259 + CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking (synchronous) CaptureChannel\n"));
1.1260 + r = CaptureChannel((TInt)(parms[0]), iConfigHdr, iNotif, iChannelId);
1.1261 + if(r != KErrNone)
1.1262 + {
1.1263 + delete iConfigHdr;
1.1264 + break;
1.1265 + }
1.1266 + CLIENT_PRINT(("DChannelIicSlaveClient::DoControl CaptureChannelgave iChannelId=0x%x\n",iChannelId));
1.1267 +
1.1268 + r = Kern::ThreadRawWrite(iClient,iClientChanId,&iChannelId,sizeof(TInt));
1.1269 + if(r != KErrNone)
1.1270 + delete iConfigHdr;
1.1271 + break;
1.1272 + }
1.1273 +
1.1274 + case(RBusDevIicClient::EReleaseChan):
1.1275 + {
1.1276 + // a1 represents TInt aChannelId
1.1277 + CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking ReleaseChannel\n"));
1.1278 + r = ReleaseChannel((TInt)a1);
1.1279 + delete iConfigHdr;
1.1280 + break;
1.1281 + }
1.1282 +
1.1283 + case(RBusDevIicClient::ERegisterRxBuffer):
1.1284 + {
1.1285 + // a1 represents TInt aChannelId
1.1286 + // a2 represents (TAny*) of TInt8 parms[3] where parms[0]=aBufGranularity; parms[1]=aNumWords; parms[2]=aOffset
1.1287 + TInt8 parms[3];
1.1288 + r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),3*sizeof(TInt8));
1.1289 + if(r!=KErrNone)
1.1290 + break; // Can't proceed if can't access request parameters
1.1291 + // Store parameters for checking in the callback
1.1292 + iRxRegGranularity = parms[0];
1.1293 + iRxRegOffset= parms[2];
1.1294 + iNumRegRxWords=parms[1];
1.1295 +
1.1296 + CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking RegisterRxBuffer\n"));
1.1297 + TPtr8 rxPtr(iRxBuf,KRxBufSizeInBytes);
1.1298 + r = RegisterRxBuffer((TInt)a1, rxPtr, parms[0], parms[1], parms[2]);
1.1299 + break;
1.1300 + }
1.1301 +
1.1302 + case(RBusDevIicClient::ERegisterTxBuffer):
1.1303 + {
1.1304 + // a1 represents TInt aChannelId
1.1305 + // a2 represents (TAny*) of TInt8 parms[3] where parms[0]=aBufGranularity; parms[1]=aNumWords; parms[2]=aOffset
1.1306 + TInt8 parms[3];
1.1307 + r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),3*sizeof(TInt8));
1.1308 + if(r!=KErrNone)
1.1309 + break; // Can't proceed if can't access request parameters
1.1310 + // Store parameters for checking in the callback
1.1311 + iTxRegGranularity = parms[0];
1.1312 + iTxRegOffset= parms[2];
1.1313 + iNumRegTxWords=parms[1];
1.1314 +
1.1315 + CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking RegisterTxBuffer\n"));
1.1316 + TPtr8 txPtr(iTxBuf,KTxBufSizeInBytes);
1.1317 + r = RegisterTxBuffer((TInt)a1, txPtr, parms[0], parms[1], parms[2]);
1.1318 + break;
1.1319 + }
1.1320 +
1.1321 + case(RBusDevIicClient::ESetNotifTrigger):
1.1322 + {
1.1323 + // a1 represents (TAny*) of TRequestStatus* aStatus
1.1324 + // a2 represents (TAny*) of TInt parms[2] where parms[0]=aChannelId; parms[1]=aTrigger
1.1325 + TInt parms[2];
1.1326 + r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt));
1.1327 + if(r!=KErrNone)
1.1328 + break; // Can't proceed if can't access request parameters
1.1329 + CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking SetNotificationTrigger with aStatus=0x%x, aChannelId=0x%x, aTrigger=0x%x\n",a1,parms[0],parms[1]));
1.1330 + if(a1 == NULL)
1.1331 + {
1.1332 + r = KErrArgument;
1.1333 + break;
1.1334 + }
1.1335 + iStatus=(TRequestStatus*)a1;
1.1336 + // Set the flags for duplex processing
1.1337 + if((parms[1]&ERxAllBytes)&&(parms[1]&ETxAllBytes))
1.1338 + iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
1.1339 + r = SetNotificationTrigger(parms[0],parms[1]);
1.1340 + if(r == KErrTimedOut)
1.1341 + r=KErrNone; // KErrTimedOut is returned if the Client has not interacted with IIC for a while
1.1342 + break;
1.1343 + }
1.1344 +
1.1345 + case(RBusDevIicClient::ECtrlIoNotifNoTrigger):
1.1346 + {
1.1347 + // a1 represents (TAny*) of aChannelId
1.1348 + // a2 represents (TAny*) of aTrigger
1.1349 + TInt chanId = (TInt)a1;
1.1350 + TInt trigger = (TInt)a2;
1.1351 + // No TRequestStatus is accessed because the call to SetNotificationTrigger
1.1352 + // is either with zero (when it is valid to do so), or it is being called with a
1.1353 + // trigger value that is expected to be rejected.
1.1354 + r = SetNotificationTrigger(chanId,trigger);
1.1355 +
1.1356 + if(r == KErrNone)
1.1357 + {
1.1358 + if((trigger&ERxAllBytes)&&(trigger&ETxAllBytes))
1.1359 + iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
1.1360 + }
1.1361 + if(r == KErrTimedOut)
1.1362 + r=KErrNone; // KErrTimedOut is returned if the Client has not interacted with IIC for a while
1.1363 + break;
1.1364 + }
1.1365 +
1.1366 + case(RBusDevIicClient::ECtrlIoRxWords):
1.1367 + {
1.1368 + // a1 represents TInt aBusId
1.1369 + // a2 represents (TAny*) of TInt parms[2] where parms[0]=aChannelId; parms[1]=aNumWords
1.1370 + TInt parms[2];
1.1371 + r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt));
1.1372 + if(r!=KErrNone)
1.1373 + break; // Can't proceed if can't access request parameters
1.1374 + // Prepare iRxBuf
1.1375 + memset(iRxBuf,0,KRxBufSizeInBytes);
1.1376 + // Store the number of words for checking in the callback
1.1377 + iRxReqNumWords=(TInt8)(parms[1]);
1.1378 +
1.1379 + TInt tempTrigger=0;
1.1380 + // Set the expected result
1.1381 + tempTrigger |= ERxAllBytes;
1.1382 + if(parms[1] < iNumRegRxWords)
1.1383 + tempTrigger |= ERxUnderrun;
1.1384 + if(parms[1] > iNumRegRxWords)
1.1385 + tempTrigger |= ERxOverrun;
1.1386 + if(iExpectedTrigger != EGeneralBusError)
1.1387 + iExpectedTrigger |= tempTrigger;
1.1388 + else
1.1389 + iBlockedTrigger |= tempTrigger;
1.1390 + CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoRxWords) with aBusId=0x%x, aChannelId=0x%x, aNumBytes=0x%x\n",(TInt)a1,parms[0],parms[1]));
1.1391 + r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)(parms[0]), (TAny*)(parms[1]));
1.1392 + if(r == KErrTimedOut)
1.1393 + r=KErrNone; // KErrTimedOut is returned if the Client has not interacted with IIC for a while
1.1394 + break;
1.1395 + }
1.1396 +
1.1397 + case(RBusDevIicClient::ECtrlIoTxWords):
1.1398 + {
1.1399 + // a1 represents TInt aBusId
1.1400 + // a2 represents (TAny*) of TInt parms[2] where parms[0]=aChannelId; parms[1]=aNumWords
1.1401 + TInt parms[2];
1.1402 + r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt));
1.1403 + if(r!=KErrNone)
1.1404 + break; // Can't proceed if can't access request parameters
1.1405 + // Prepare iTxBuf
1.1406 + TUint8* ptr=iTxBuf;
1.1407 + for(TInt offset=0; offset<KRxBufSizeInBytes; ++offset)
1.1408 + *ptr++=(TUint8)offset;
1.1409 + // Store the number of words for checking in the callback
1.1410 + iTxReqNumWords=(TInt8)(parms[1]);
1.1411 + TInt tempTrigger=0;
1.1412 + // Set the expected result
1.1413 + tempTrigger |= ETxAllBytes;
1.1414 + if(parms[1] < iNumRegTxWords)
1.1415 + tempTrigger |= ETxOverrun;
1.1416 + if(parms[1] > iNumRegTxWords)
1.1417 + tempTrigger |= ETxUnderrun;
1.1418 + if(iExpectedTrigger != EGeneralBusError)
1.1419 + iExpectedTrigger |= tempTrigger;
1.1420 + else
1.1421 + iBlockedTrigger |= tempTrigger;
1.1422 +
1.1423 + // The bytes "transmitted" are stored in the simulated bus' iTxCheckBuf
1.1424 + // Since the simulated bus channel is also in the kernel process it shares the same address space
1.1425 + // Get the address of the buffer
1.1426 + // As part of the callback invoked by IIC, this client will check the data stored by the simulated
1.1427 + // bus. Since the simulated bus channel is also in the kernel process it shares the same address space,
1.1428 + // so the buffer can be accessed directly - but the buffer is not created until it receives the following
1.1429 + // StaticExtension command, so the bus identifier represented by a1 is stored to allow accessing the buffer
1.1430 + // adddress from the callback.
1.1431 + iBusId=(TUint)a1;
1.1432 + CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoTxWords) with aBusId=0x%x, aChannelId=0x%x, aNumBytes=0x%x\n",(TInt)a1,parms[0],parms[1]));
1.1433 + aId<<=1;
1.1434 + r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)(parms[0]), (TAny*)(parms[1]));
1.1435 + break;
1.1436 + }
1.1437 +
1.1438 + case(RBusDevIicClient::ECtrlIoRxTxWords):
1.1439 + {
1.1440 + // a1 represents TInt aBusId
1.1441 + // a2 represents (TAny*) of TInt parms[3] where parms[0]=aChannelId; parms[1]=aNumRxWords; parms[2]=aNumTxWords
1.1442 + TInt parms[3];
1.1443 + r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),3*sizeof(TInt));
1.1444 + if(r!=KErrNone)
1.1445 + break; // Can't proceed if can't access request parameters
1.1446 + // Prepare iRxBuf, iTxBuf
1.1447 + memset(iRxBuf,0,KRxBufSizeInBytes);
1.1448 + TUint8* ptr=iTxBuf;
1.1449 + for(TInt offset=0; offset<KRxBufSizeInBytes; ++offset)
1.1450 + *ptr++=(TUint8)offset;
1.1451 +
1.1452 + // Store the number of words for checking in the callback
1.1453 + iRxReqNumWords=(TInt8)(parms[1]);
1.1454 + iTxReqNumWords=(TInt8)(parms[2]);
1.1455 +
1.1456 + TInt tempTrigger=0;
1.1457 + // Set the expected result
1.1458 + tempTrigger |= (ERxAllBytes|ETxAllBytes);
1.1459 +
1.1460 + if(parms[1] < iNumRegRxWords)
1.1461 + tempTrigger |= ERxUnderrun;
1.1462 + if(parms[1] > iNumRegRxWords)
1.1463 + tempTrigger |= ERxOverrun;
1.1464 +
1.1465 + if(parms[2] < iNumRegTxWords)
1.1466 + tempTrigger |= ETxOverrun;
1.1467 + if(parms[2] > iNumRegTxWords)
1.1468 + tempTrigger |= ETxUnderrun;
1.1469 +
1.1470 + if(iExpectedTrigger != EGeneralBusError)
1.1471 + iExpectedTrigger |= tempTrigger;
1.1472 + else
1.1473 + iBlockedTrigger |= tempTrigger;
1.1474 +
1.1475 + // The bytes "transmitted" are stored in the simulated bus' iTxCheckBuf
1.1476 + // Since the simulated bus channel is also in the kernel process it shares the same address space
1.1477 + // Get the address of the buffer
1.1478 + // As part of the callback invoked by IIC, this client will check the data stored by the simulated
1.1479 + // bus. Since the simulated bus channel is also in the kernel process it shares the same address space,
1.1480 + // so the buffer can be accessed directly - but the buffer is not created until it receives the following
1.1481 + // StaticExtension command, so the bus identifier represented by a1 is stored to allow accessing the buffer
1.1482 + // adddress from the callback.
1.1483 + iBusId=(TUint)a1;
1.1484 +
1.1485 + 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]));
1.1486 + r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)(parms[0]), (TAny*)(&(parms[1])));
1.1487 + if(r == KErrTimedOut)
1.1488 + r=KErrNone; // KErrTimedOut is returned if the Client has not interacted with IIC for a while
1.1489 + break;
1.1490 + }
1.1491 +
1.1492 + case(RBusDevIicClient::ECtlIoBusError):
1.1493 + {
1.1494 + // a1 represents TInt aBusId
1.1495 + // a2 represents TInt aChannelId
1.1496 + // Set the expected result
1.1497 + iExpectedTrigger |= EGeneralBusError;
1.1498 + CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtlIoBusError) \n"));
1.1499 + r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)a2, NULL);
1.1500 + break;
1.1501 + }
1.1502 +
1.1503 + case(RBusDevIicClient::ECtrlIoUnblockNotification):
1.1504 + {
1.1505 + // a1 represents TInt aBusId
1.1506 + // a2 represents TInt aChannelId
1.1507 + iExpectedTrigger = iBlockedTrigger;
1.1508 + iBlockedTrigger=0;
1.1509 + CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoUnblockNotification) \n"));
1.1510 + r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)a2, NULL);
1.1511 + break;
1.1512 + }
1.1513 +
1.1514 + case(RBusDevIicClient::ECtrlIoBlockNotification):
1.1515 + {
1.1516 + // a1 represents TInt aBusId
1.1517 + // a2 represents TInt aChannelId
1.1518 + iBlockedTrigger = iExpectedTrigger;
1.1519 + iExpectedTrigger = EGeneralBusError; // For this test, just interested in if the timeout is detected
1.1520 + // iExpectedTrigger will be reinstated prior to unblocking
1.1521 + CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoBlockNotification) \n"));
1.1522 + r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)a2, NULL);
1.1523 + break;
1.1524 + }
1.1525 +
1.1526 + case(RBusDevIicClient::ECtrlIoUpdTimeout):
1.1527 + {
1.1528 + // a1 represents TInt aBusId
1.1529 + // a2 represents TInt aChannelId
1.1530 +
1.1531 + // For this test, instruct the simulated bus to do the following for the Master and Client timeout values:
1.1532 + // (1) Read the current timeout value and check that it is set to the default
1.1533 + // (2) Set it to different value
1.1534 + // (3) Read it back to check success
1.1535 + // (4) Return to the original value, and readback to confirm
1.1536 + CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoBlockNotification) \n"));
1.1537 + r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, NULL, NULL);
1.1538 + break;
1.1539 + }
1.1540 +
1.1541 + default:
1.1542 + {
1.1543 + CLIENT_PRINT(("DChannelIicSlaveClient::DoControl - unrecognised value for aId=0x%x\n",aId));
1.1544 + r=KErrArgument;
1.1545 + break;
1.1546 + }
1.1547 +
1.1548 + }
1.1549 + return r;
1.1550 + }
1.1551 +
1.1552 +TInt DChannelIicSlaveClient::DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2)
1.1553 + {
1.1554 + CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest invoked with aId=0x%x, aStatus=0x%x, a1=0x%x, a2=0x%x\n", aId,aStatus,a1,a2));
1.1555 +
1.1556 + TInt r=KErrNone;
1.1557 + switch(aId)
1.1558 + {
1.1559 + case(RBusDevIicClient::ECaptureChanAsync):
1.1560 + {
1.1561 + // a1 is a pointer to the TDes8* aConfigHdr
1.1562 + // a2 is a pointer to TInt* parms[2], where:
1.1563 + // parms[0]=(TInt*)aBusId;
1.1564 + // parms[1]=&aChannelId;
1.1565 + //
1.1566 + TInt* parms[2];
1.1567 + r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt*));
1.1568 + if(r!=KErrNone)
1.1569 + break; // Can't proceed if can't access request parameters
1.1570 + //
1.1571 + TInt hdrSize = Kern::ThreadGetDesLength(iClient,a1);
1.1572 + CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest hdrSize = 0x%x\n",hdrSize));
1.1573 + if (hdrSize<=0)
1.1574 + {
1.1575 + CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest ERROR, hdrSize is invalid\n"));
1.1576 + return KErrArgument;
1.1577 + }
1.1578 + if((iConfigHdr = HBuf8::New(hdrSize)) == NULL)
1.1579 + return KErrNoMemory;
1.1580 + if((r = Kern::ThreadDesRead(iClient,a1,*iConfigHdr,0))!=KErrNone)
1.1581 + {
1.1582 + delete iConfigHdr;
1.1583 + return r;
1.1584 + }
1.1585 + iStatus=aStatus;
1.1586 + // Store the address of the user-side variable to update with the ChannelId
1.1587 + iClientChanId=parms[1];
1.1588 + // Invoke the IIC API
1.1589 + CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest invoking (asynchronous) CaptureChannel\n"));
1.1590 + r = CaptureChannel((TInt)(parms[0]), iConfigHdr, iNotif, iChannelId, ETrue);
1.1591 + if(r != KErrNone)
1.1592 + delete iConfigHdr;
1.1593 + CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest (asynchronous) CaptureChannel returned %d\n",r));
1.1594 + break;
1.1595 + }
1.1596 +
1.1597 + case(RBusDevIicClient::ECtrlIoOvUndRunRxTx):
1.1598 + {
1.1599 + iBusId = (TInt)a1;
1.1600 + iChannelId = (TInt)a2;
1.1601 + iStatus=aStatus;
1.1602 + CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest status = 0x%x, busId = 0x%x, chanId =0x%x\n",iStatus,iBusId,iChannelId));
1.1603 +
1.1604 + // This test is state-machine driven. It is instigated from this point, then subsequent steps
1.1605 + // are handled in the callback funciton SlaveClientCallbackFunc
1.1606 + //
1.1607 + // Check we in the appropriate state to start
1.1608 + if(iTestOverUnderState == EStartState)
1.1609 + {
1.1610 + // Re-use the previously-provided buffers. Just request the initial notification triggers,
1.1611 + // the simulate the first event (RxOverrun).
1.1612 + r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun));
1.1613 + if(r != KErrNone)
1.1614 + {
1.1615 + CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest SetNotificationTrigger returned %d\n",r));
1.1616 + }
1.1617 + else
1.1618 + {
1.1619 + // Trigger now set, so simulate the required event
1.1620 + iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun;
1.1621 + iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
1.1622 + iTestOverUnderState = ERxOverrun_1; // Prepare for callback
1.1623 + // The requested number of words when the buffer was registered was 8, so simulate 10
1.1624 + // to provoke an RxOverrun event.
1.1625 + TInt numWords=10;
1.1626 + // To support testing, any values of aId for StaticExtension must be shifted left one place
1.1627 + // and for a Slave, the two msbs must be zero
1.1628 + TInt ctrlIoVal = RBusDevIicClient::ECtrlIoRxWords;
1.1629 + ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
1.1630 + r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords);
1.1631 + }
1.1632 + }
1.1633 + else
1.1634 + {
1.1635 + CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest ECtrlIoOvUndRunRxTx, iTestOverUnderState = 0x%x\n",iTestOverUnderState));
1.1636 + r=KErrGeneral;
1.1637 + }
1.1638 + break;
1.1639 + }
1.1640 +
1.1641 + default:
1.1642 + {
1.1643 + CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest - unrecognised value for aId=0x%x\n",aId));
1.1644 + r=KErrArgument;
1.1645 + break;
1.1646 + }
1.1647 + }
1.1648 + return r;
1.1649 + }
1.1650 +