sl@0: // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32test/iic/iic_slaveclient.cpp sl@0: // Simulated client of IIC Platform Independent Layer (PIL) Slave functionality sl@0: // sl@0: sl@0: #include // for DThread, TDfc sl@0: #ifdef STANDALONE_CHANNEL sl@0: #include sl@0: #else sl@0: #include sl@0: #endif sl@0: #include "../t_iic.h" sl@0: sl@0: #ifdef STANDALONE_CHANNEL sl@0: #include sl@0: #include "i2c.h" sl@0: #endif sl@0: #ifdef LOG_SLAVECLIENT sl@0: #define CLIENT_PRINT(str) Kern::Printf str sl@0: #else sl@0: #define CLIENT_PRINT(str) sl@0: #endif sl@0: sl@0: //For channel creation sl@0: #ifdef STANDALONE_CHANNEL sl@0: #define NUM_CHANNELS 3 // Arbitrary sl@0: sl@0: #if defined(MASTER_MODE) && !defined(SLAVE_MODE) sl@0: const TInt KChannelTypeArray[NUM_CHANNELS] = {DIicBusChannel::EMaster, DIicBusChannel::EMaster, DIicBusChannel::EMaster}; sl@0: #elif defined(MASTER_MODE) && defined(SLAVE_MODE) sl@0: const TInt KChannelTypeArray[NUM_CHANNELS] = {DIicBusChannel::EMaster, DIicBusChannel::ESlave, DIicBusChannel::EMasterSlave}; sl@0: #else sl@0: const TInt KChannelTypeArray[NUM_CHANNELS] = {DIicBusChannel::ESlave, DIicBusChannel::ESlave, DIicBusChannel::ESlave}; sl@0: #endif sl@0: #define CHANNEL_TYPE(n) (KChannelTypeArray[n]) sl@0: #define CHANNEL_DUPLEX(n) (DIicBusChannel::EHalfDuplex) sl@0: #define BUS_TYPE (DIicBusChannel::EI2c) sl@0: sl@0: #if defined(MASTER_MODE) sl@0: const TInt8 KI2cChannelNumBase = 10; // Arbitrary, real platform may consult the Configuration Repository sl@0: // Note limit of 5 bit representation (0-31) sl@0: sl@0: #else sl@0: const TInt8 KI2cChannelNumBase = 10 + NUM_CHANNELS; // For Slave mode, want to provide different response sl@0: // If client assumes Master mode, should be informed not available sl@0: #endif/*MASTER_MODE*/ sl@0: sl@0: LOCAL_C TInt8 AssignChanNumI2c() sl@0: { sl@0: static TInt8 iBaseChanNumI2c = KI2cChannelNumBase; sl@0: CLIENT_PRINT(("I2C AssignChanNum - on entry, iBaseChanNum = 0x%x\n",iBaseChanNumI2c)); sl@0: return iBaseChanNumI2c++; // Arbitrary, for illustration sl@0: } sl@0: sl@0: class DIicSlaveClientChan : public DBase sl@0: { sl@0: public: sl@0: DIicSlaveClientChan(DIicBusChannel* aChan, TInt8 aChanNum, TInt aChanType):iChan(aChan),iChanNumber(aChanNum),iChanType(aChanType){}; sl@0: ~DIicSlaveClientChan(); sl@0: TInt GetChanNum()const {return iChanNumber;}; sl@0: TInt GetChanType()const {return iChanType;}; sl@0: DIicBusChannel* GetChannelPtr(){return iChan;}; sl@0: private: sl@0: TInt8 iChanNumber; sl@0: TInt iChanType; sl@0: DIicBusChannel* iChan; sl@0: }; sl@0: sl@0: DIicSlaveClientChan::~DIicSlaveClientChan() sl@0: { sl@0: if(iChan) sl@0: delete iChan; sl@0: } sl@0: sl@0: #endif/*STANDALONE_CHANNEL*/ sl@0: sl@0: const TInt KIicSlaveClientThreadPriority = 24; sl@0: sl@0: const TInt KIicSlaveClientDfcPriority = 3; // 0 to 7, 7 is highest sl@0: sl@0: const TInt KMaxNumChannels = 2; // 1 "true" slave, one "dummy" sl@0: sl@0: #ifdef STANDALONE_CHANNEL sl@0: _LIT(KLddRootName,"iic_slaveclient_ctrless"); sl@0: #else sl@0: _LIT(KLddRootName,"iic_slaveclient"); sl@0: #endif sl@0: _LIT(KIicSlaveClientThreadName,"IicSlaveClientLddThread"); sl@0: sl@0: sl@0: struct TCapsIicSlaveClient sl@0: { sl@0: TVersion version; sl@0: }; sl@0: sl@0: sl@0: class DDeviceIicSlaveClient : public DLogicalDevice sl@0: { sl@0: public: sl@0: /** sl@0: * The constructor sl@0: */ sl@0: DDeviceIicSlaveClient(); sl@0: /** sl@0: * The destructor sl@0: */ sl@0: ~DDeviceIicSlaveClient(); sl@0: /** sl@0: * Second stage constructor - install the device sl@0: */ sl@0: virtual TInt Install(); sl@0: /** sl@0: * Get the Capabilites of the device sl@0: * @param aDes descriptor that will contain the returned capibilites sl@0: */ sl@0: virtual void GetCaps(TDes8 &aDes) const; sl@0: /** sl@0: * Create a logical channel to the device sl@0: */ sl@0: virtual TInt Create(DLogicalChannelBase*& aChannel); sl@0: }; sl@0: sl@0: sl@0: class DChannelIicSlaveClient : public DLogicalChannel sl@0: { sl@0: public: sl@0: DChannelIicSlaveClient(); sl@0: ~DChannelIicSlaveClient(); sl@0: sl@0: virtual TInt DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer); sl@0: sl@0: void RequestComplete(TInt r); sl@0: TInt CheckDataWritten(); sl@0: TInt CheckDataRead(); sl@0: sl@0: static void SlaveClientCallbackFunc(TInt aChannelId, TInt aReturn, TInt aTrigger, TInt16 aRxWords, TInt16 aTxWords, TAny* aParam); sl@0: #ifdef STANDALONE_CHANNEL sl@0: static TInt OrderEntries(const DIicSlaveClientChan& aMatch, const DIicSlaveClientChan& aEntry); sl@0: #endif sl@0: protected: sl@0: virtual void HandleMsg(TMessageBase* aMsg); // Note: this is a pure virtual in DLogicalChannel sl@0: sl@0: TInt DoControl(TInt aId, TAny* a1, TAny* a2); // Name for convenience! sl@0: TInt DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2); // Name for convenience! sl@0: sl@0: private: sl@0: TInt InitSlaveClient(); sl@0: TInt CbProcessOverUnderRunRxTx(); sl@0: TInt RegisterRxBuffer(TInt aChannelId, TPtr8 aRxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset); sl@0: TInt SetNotificationTrigger(TInt aChannelId, TInt aTrigger); sl@0: TInt StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2); sl@0: TInt RegisterTxBuffer(TInt aChannelId, TPtr8 aTxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset); sl@0: TInt CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch=NULL); sl@0: TInt ReleaseChannel(TInt aChannelId); sl@0: private: sl@0: TDynamicDfcQue* iDfcQue; sl@0: TIicBusSlaveCallback* iNotif; sl@0: sl@0: HBuf8* iConfigHdr; sl@0: TRequestStatus* iStatus; sl@0: sl@0: TUint8* iRxBuf; sl@0: TUint8* iTxBuf; sl@0: sl@0: TUint8* iBusTxCheckBuf; sl@0: sl@0: TInt8 iNumRegRxWords; sl@0: TInt8 iNumRegTxWords; sl@0: sl@0: TInt8 iTxRegGranularity; sl@0: TInt8 iTxRegOffset; sl@0: TInt8 iTxReqNumWords; sl@0: sl@0: TInt8 iRxRegGranularity; sl@0: TInt8 iRxRegOffset; sl@0: TInt8 iRxReqNumWords; sl@0: sl@0: TUint iBusId; sl@0: #ifdef STANDALONE_CHANNEL sl@0: // For some slave-channel-only functions,e.g. ReleaseChannel, RegisterRxBuffer, etc. sl@0: // the client needs to remember the slave channel that has been captured sl@0: struct TCapturedChannel sl@0: { sl@0: DIicSlaveClientChan* iChannel; sl@0: TInt iChannelId; sl@0: }; sl@0: TCapturedChannel iCapturedChan; sl@0: #endif sl@0: public: sl@0: DThread* iClient; sl@0: TInt iChannelId; // public to be accessible by callback sl@0: TInt* iClientChanId; sl@0: sl@0: TInt iExpectedTrigger; sl@0: TInt iFullDuplexReq; sl@0: TInt iBlockedTrigger; sl@0: sl@0: typedef enum TTestOverUnderState sl@0: { sl@0: EStartState = 0x1, sl@0: ERxOverrun_1, sl@0: ERxOverrun_2, sl@0: ETxUnderrun_1, sl@0: ETxUnderrun_2 sl@0: }; sl@0: TTestOverUnderState iTestOverUnderState; sl@0: }; sl@0: sl@0: DDeviceIicSlaveClient::DDeviceIicSlaveClient() sl@0: // Constructor sl@0: { sl@0: CLIENT_PRINT(("> DDeviceIicSlaveClient::DDeviceIicSlaveClient()")); sl@0: iParseMask=0; // No info, no PDD, no Units sl@0: iUnitsMask=0; sl@0: iVersion=TVersion(KIicClientMajorVersionNumber, sl@0: KIicClientMinorVersionNumber, sl@0: KIicClientBuildVersionNumber); sl@0: } sl@0: sl@0: #ifdef STANDALONE_CHANNEL sl@0: //Store all the channels created by the client into an array sl@0: RPointerArray ChannelArray; sl@0: #endif sl@0: DDeviceIicSlaveClient::~DDeviceIicSlaveClient() sl@0: // Destructor sl@0: { sl@0: CLIENT_PRINT(("> DDeviceIicSlaveClient::~DDeviceIicSlaveClient()")); sl@0: #ifdef STANDALONE_CHANNEL sl@0: //The client is reponsible for channel destroy in STANDALONE_CHANNEL mode sl@0: ChannelArray.ResetAndDestroy(); sl@0: #endif sl@0: } sl@0: sl@0: TInt DDeviceIicSlaveClient::Install() sl@0: // Install the device driver. sl@0: { sl@0: CLIENT_PRINT(("> DDeviceIicSlaveClient::Install()")); sl@0: sl@0: return(SetName(&KLddRootName)); sl@0: } sl@0: sl@0: sl@0: void DDeviceIicSlaveClient::GetCaps(TDes8& aDes) const sl@0: // Return the IicClient capabilities. sl@0: { sl@0: CLIENT_PRINT(("> DDeviceIicSlaveClient::GetCaps(TDes8& aDes) const")); sl@0: TPckgBuf b; sl@0: b().version=TVersion(KIicClientMajorVersionNumber, sl@0: KIicClientMinorVersionNumber, sl@0: KIicClientBuildVersionNumber); sl@0: Kern::InfoCopy(aDes,b); sl@0: } sl@0: sl@0: sl@0: TInt DDeviceIicSlaveClient::Create(DLogicalChannelBase*& aChannel) sl@0: // Create a channel on the device. sl@0: { sl@0: CLIENT_PRINT(("> DDeviceIicSlaveClient::Create(DLogicalChannelBase*& aChannel)")); sl@0: if(iOpenChannels>=KMaxNumChannels) sl@0: return KErrOverflow; sl@0: aChannel=new DChannelIicSlaveClient; sl@0: return aChannel?KErrNone:KErrNoMemory; sl@0: } sl@0: sl@0: #ifdef STANDALONE_CHANNEL sl@0: // auxiliary function for ordering entries in the array of channels sl@0: TInt DChannelIicSlaveClient::OrderEntries(const DIicSlaveClientChan& aMatch, const DIicSlaveClientChan& aEntry) sl@0: { sl@0: TUint8 l=(TUint8)aMatch.GetChanNum(); sl@0: TUint8 r=(TUint8)aEntry.GetChanNum(); sl@0: if(l>r) sl@0: return -1; sl@0: else if(l EntryOrder(DChannelIicSlaveClient::OrderEntries); sl@0: sl@0: TInt GetChanPtr(const TInt aBusId, DIicSlaveClientChan*& aChan) sl@0: { sl@0: __KTRACE_OPT(KIIC, Kern::Printf("GetChanPtr, aBusId=0x%x\n",aBusId)); sl@0: TInt32 chanId; sl@0: chanId = GET_CHAN_NUM(aBusId); sl@0: __KTRACE_OPT(KIIC, Kern::Printf("GetChanPtr, chanId=0x%x\n",chanId)); sl@0: DIicSlaveClientChan chanEntry(NULL,(TInt8)chanId, DIicBusChannel::EMasterSlave); sl@0: sl@0: TInt r = KErrNotFound; sl@0: TInt aIndex = ChannelArray.FindInOrder(&chanEntry, EntryOrder); sl@0: sl@0: if(aIndex >= 0) sl@0: { sl@0: aChan = ChannelArray[aIndex]; sl@0: r = KErrNone; sl@0: } sl@0: sl@0: return r; sl@0: } sl@0: #endif/*STANDALONE_CHANNEL*/ sl@0: sl@0: DECLARE_STANDARD_LDD() sl@0: { sl@0: #ifdef STANDALONE_CHANNEL sl@0: TInt r = KErrNone; sl@0: DIicBusChannel *chan = NULL, *chanM = NULL, *chanS = NULL; sl@0: DIicSlaveClientChan* aSlaveClientChan; sl@0: for(TInt i=0; iCreate()!=KErrNone) sl@0: { sl@0: delete chan; sl@0: return NULL; sl@0: } sl@0: aSlaveClientChan = new DIicSlaveClientChan(chan,AssignChanNumI2c(),DIicBusChannel::EMaster); sl@0: if(!aSlaveClientChan) sl@0: { sl@0: delete chan; sl@0: return NULL; sl@0: } sl@0: r = ChannelArray.InsertInOrder(aSlaveClientChan,EntryOrder); sl@0: if(r!=KErrNone) sl@0: { sl@0: delete chan; sl@0: delete aSlaveClientChan; sl@0: break; sl@0: } sl@0: } sl@0: #endif sl@0: #if defined(MASTER_MODE) && defined(SLAVE_MODE) sl@0: if(CHANNEL_TYPE(i) == DIicBusChannel::EMasterSlave) sl@0: { sl@0: chanM=new DSimulatedIicBusChannelMasterI2c(BUS_TYPE,CHANNEL_DUPLEX(i)); sl@0: if(!chanM) sl@0: return NULL; sl@0: chanS=new DSimulatedIicBusChannelSlaveI2c(BUS_TYPE,CHANNEL_DUPLEX(i)); sl@0: if(!chanS) sl@0: { sl@0: delete chanM; sl@0: return NULL; sl@0: } sl@0: chan=new DSimulatedIicBusChannelMasterSlaveI2c(BUS_TYPE,CHANNEL_DUPLEX(i),(DSimulatedIicBusChannelMasterI2c*)chanM,(DSimulatedIicBusChannelSlaveI2c*)chanS); // Generic implementation sl@0: if(!chan) sl@0: { sl@0: CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE(i),i)); sl@0: delete chanM; sl@0: delete chanS; sl@0: return NULL; sl@0: } sl@0: CLIENT_PRINT(("I2C chan created at 0x%x\n",chan)); sl@0: if(((DIicBusChannelMasterSlave*)chan)->DoCreate()!=KErrNone) sl@0: { sl@0: delete chanM; sl@0: delete chanS; sl@0: delete chan; sl@0: return NULL; sl@0: } sl@0: aSlaveClientChan = new DIicSlaveClientChan(chan,AssignChanNumI2c(),DIicBusChannel::EMasterSlave); sl@0: if(!aSlaveClientChan) sl@0: { sl@0: delete chanM; sl@0: delete chanS; sl@0: delete chan; sl@0: return NULL; sl@0: } sl@0: r = ChannelArray.InsertInOrder(aSlaveClientChan,EntryOrder); sl@0: if(r!=KErrNone) sl@0: { sl@0: delete chanM; sl@0: delete chanS; sl@0: delete chan; sl@0: delete aSlaveClientChan; sl@0: break; sl@0: } sl@0: } sl@0: #endif sl@0: #if defined(SLAVE_MODE) sl@0: if(CHANNEL_TYPE(i) == (DIicBusChannel::ESlave)) sl@0: { sl@0: chan=new DSimulatedIicBusChannelSlaveI2c(BUS_TYPE,CHANNEL_DUPLEX(i)); sl@0: if(!chan) sl@0: { sl@0: CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE(i),i)); sl@0: return NULL; sl@0: } sl@0: CLIENT_PRINT(("I2C chan created at 0x%x\n",chan)); sl@0: if(((DSimulatedIicBusChannelSlaveI2c*)chan)->Create()!=KErrNone) sl@0: return NULL; sl@0: aSlaveClientChan = new DIicSlaveClientChan(chan,AssignChanNumI2c(),DIicBusChannel::ESlave); sl@0: if(!aSlaveClientChan) sl@0: { sl@0: delete chan; sl@0: return NULL; sl@0: } sl@0: r = ChannelArray.InsertInOrder(aSlaveClientChan,EntryOrder); sl@0: if(r!=KErrNone) sl@0: { sl@0: delete chan; sl@0: delete aSlaveClientChan; sl@0: break; sl@0: } sl@0: } sl@0: #endif sl@0: #if !defined(MASTER_MODE) && !defined(SLAVE_MODE) sl@0: #error I2C mode not defined as Master, Slave nor Master-Slave sl@0: #endif sl@0: } sl@0: #endif sl@0: return new DDeviceIicSlaveClient; sl@0: } sl@0: sl@0: sl@0: sl@0: DChannelIicSlaveClient::DChannelIicSlaveClient() sl@0: // Constructor sl@0: { sl@0: iFullDuplexReq=iBlockedTrigger=iExpectedTrigger=0; sl@0: CLIENT_PRINT(("> DChannelIicSlaveClient::DChannelIicSlaveClient()")); sl@0: iClient=&Kern::CurrentThread(); sl@0: // Increase the DThread's ref count so that it does not close without us sl@0: iClient->Open(); sl@0: iTestOverUnderState = EStartState; sl@0: } sl@0: sl@0: DChannelIicSlaveClient::~DChannelIicSlaveClient() sl@0: // Destructor sl@0: { sl@0: CLIENT_PRINT(("> DChannelIicSlaveClient::~DChannelIicSlaveClient()")); sl@0: iDfcQue->Destroy(); sl@0: delete iNotif; sl@0: delete iRxBuf; sl@0: delete iTxBuf; sl@0: delete iBusTxCheckBuf; sl@0: // decrement the DThread's reference count sl@0: Kern::SafeClose((DObject*&)iClient, NULL); sl@0: } sl@0: sl@0: void DChannelIicSlaveClient::RequestComplete(TInt r) sl@0: { sl@0: Kern::RequestComplete(iClient, iStatus, r); sl@0: } sl@0: sl@0: TInt DChannelIicSlaveClient::RegisterRxBuffer(TInt aChannelId, TPtr8 aRxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset) sl@0: { sl@0: TInt r = KErrNone; sl@0: #ifdef STANDALONE_CHANNEL sl@0: DIicSlaveClientChan* aChanPtr = NULL; sl@0: if(iCapturedChan.iChannelId == aChannelId) sl@0: aChanPtr = iCapturedChan.iChannel; sl@0: if(!aChanPtr) sl@0: return KErrArgument; sl@0: if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave) sl@0: r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->RegisterRxBuffer(aRxBuffer, aBufGranularity, aNumWords, aOffset); sl@0: else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave) sl@0: r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->RegisterRxBuffer(aRxBuffer, aBufGranularity, aNumWords, aOffset); sl@0: #else sl@0: r = IicBus::RegisterRxBuffer(aChannelId, aRxBuffer, aBufGranularity, aNumWords, aOffset); sl@0: #endif sl@0: return r; sl@0: } sl@0: sl@0: TInt DChannelIicSlaveClient::SetNotificationTrigger(TInt aChannelId, TInt aTrigger) sl@0: { sl@0: TInt r = KErrNone; sl@0: #ifdef STANDALONE_CHANNEL sl@0: DIicSlaveClientChan* aChanPtr = NULL; sl@0: if(iCapturedChan.iChannelId == aChannelId) sl@0: aChanPtr = iCapturedChan.iChannel; sl@0: if(!aChanPtr) sl@0: return KErrArgument; sl@0: if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave) sl@0: r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->SetNotificationTrigger(aTrigger); sl@0: else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave) sl@0: r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->SetNotificationTrigger(aTrigger); sl@0: #else sl@0: r = IicBus::SetNotificationTrigger(aChannelId, aTrigger); sl@0: #endif sl@0: return r; sl@0: } sl@0: sl@0: TInt DChannelIicSlaveClient::StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2) sl@0: { sl@0: TInt r = KErrNone; sl@0: #ifdef STANDALONE_CHANNEL sl@0: DIicSlaveClientChan* aChanPtr; sl@0: r = GetChanPtr(aId, aChanPtr); sl@0: if(r != KErrNone) sl@0: return r; sl@0: if(!aChanPtr) sl@0: return KErrArgument; sl@0: if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave) sl@0: r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->StaticExtension(aFunction, aParam1, aParam2); sl@0: else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave) sl@0: r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->StaticExtension(aFunction, aParam1, aParam2); sl@0: #else sl@0: r = IicBus::StaticExtension(aId, aFunction, aParam1, aParam2); sl@0: #endif sl@0: return r; sl@0: } sl@0: sl@0: TInt DChannelIicSlaveClient::RegisterTxBuffer(TInt aChannelId, TPtr8 aTxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset) sl@0: { sl@0: TInt r = KErrNone; sl@0: #ifdef STANDALONE_CHANNEL sl@0: DIicSlaveClientChan* aChanPtr = NULL; sl@0: if(iCapturedChan.iChannelId == aChannelId) sl@0: aChanPtr = iCapturedChan.iChannel; sl@0: if(!aChanPtr) sl@0: return KErrArgument; sl@0: if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave) sl@0: r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->RegisterTxBuffer(aTxBuffer, aBufGranularity, aNumWords, aOffset); sl@0: else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave) sl@0: r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->RegisterTxBuffer(aTxBuffer, aBufGranularity, aNumWords, aOffset); sl@0: #else sl@0: r = IicBus::RegisterTxBuffer(aChannelId, aTxBuffer, aBufGranularity, aNumWords, aOffset); sl@0: #endif sl@0: return r; sl@0: } sl@0: sl@0: TInt DChannelIicSlaveClient::CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch) sl@0: { sl@0: TInt r = KErrNone; sl@0: #ifndef STANDALONE_CHANNEL sl@0: r = IicBus::CaptureChannel(aBusId, aConfigHdr, aCallback, aChannelId, aAsynch); sl@0: #else sl@0: // Check that that aCallback!=NULL and aConfigHdr!=NULL - if not, return KErrArgument sl@0: if(!aCallback || !aConfigHdr) sl@0: { sl@0: return KErrArgument; sl@0: } sl@0: sl@0: // Get the channel sl@0: DIicSlaveClientChan* chanPtr = NULL; sl@0: if(r == KErrNone) sl@0: { sl@0: r = GetChanPtr(aBusId, chanPtr); sl@0: if(r == KErrNone) sl@0: { sl@0: if(!chanPtr) sl@0: { sl@0: r = KErrArgument; sl@0: } sl@0: else sl@0: { sl@0: switch(chanPtr->GetChanType()) sl@0: { sl@0: // CaptureChannel requests are only supported by channels in Slave mode. sl@0: case DIicBusChannel::EMaster: sl@0: { sl@0: r = KErrNotSupported; sl@0: break; sl@0: } sl@0: case DIicBusChannel::EMasterSlave: sl@0: { sl@0: r = ((DIicBusChannelMasterSlave*) (chanPtr->GetChannelPtr()))->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch); sl@0: break; sl@0: } sl@0: case DIicBusChannel::ESlave: sl@0: { sl@0: r = ((DIicBusChannelSlave*) (chanPtr->GetChannelPtr()))->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch); sl@0: break; sl@0: } sl@0: default: sl@0: { sl@0: r = KErrArgument; sl@0: } sl@0: } sl@0: // For synchronous capture, if successful then install the channel sl@0: if(r == KErrNone) sl@0: { sl@0: if(!aAsynch) sl@0: { sl@0: iCapturedChan.iChannel = chanPtr; sl@0: iCapturedChan.iChannelId = aChannelId; sl@0: } sl@0: else sl@0: //For asynchronous capture, record slaveChanPtr, if later failed capture, sl@0: //clean iCapturedChannel in client's callback. sl@0: iCapturedChan.iChannel = chanPtr; sl@0: } sl@0: } sl@0: } sl@0: } sl@0: #endif sl@0: return r; sl@0: } sl@0: sl@0: TInt DChannelIicSlaveClient::ReleaseChannel(TInt aChannelId) sl@0: { sl@0: TInt r = KErrNone; sl@0: #ifndef STANDALONE_CHANNEL sl@0: r = IicBus::ReleaseChannel(aChannelId); sl@0: #else sl@0: __KTRACE_OPT(KIIC, Kern::Printf("DChannelIicSlaveClient::ReleaseChannel, channelID = 0x%x \n",aChannelId)); sl@0: // Acquire the pointer to the Slave Channel sl@0: if(iCapturedChan.iChannelId != aChannelId) sl@0: return KErrNotFound; sl@0: sl@0: if((iCapturedChan.iChannel)->GetChanType() == DIicBusChannel::EMasterSlave) sl@0: r = ((DIicBusChannelMasterSlave*)((iCapturedChan.iChannel)->GetChannelPtr()))->ReleaseChannel(); sl@0: else if((iCapturedChan.iChannel)->GetChanType() == DIicBusChannel::ESlave) sl@0: r = ((DIicBusChannelSlave*)((iCapturedChan.iChannel)->GetChannelPtr()))->ReleaseChannel(); sl@0: //After release channel, reset iCapturedChan sl@0: iCapturedChan.iChannel = NULL; sl@0: iCapturedChan.iChannelId = 0; sl@0: #endif sl@0: return r; sl@0: } sl@0: TInt DChannelIicSlaveClient::CbProcessOverUnderRunRxTx() sl@0: { sl@0: CLIENT_PRINT(("> DChannelIicSlaveClient::CbProcessOverUnderRunRxTx(), iTestOverUnderState=%d\n",iTestOverUnderState)); sl@0: TInt r = KErrNone; sl@0: switch (iTestOverUnderState) sl@0: { sl@0: case(EStartState): sl@0: { sl@0: // In this state, no action is required sl@0: break; sl@0: }; sl@0: case(ERxOverrun_1): sl@0: { sl@0: CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ERxOverrun_1\n")); sl@0: // At this point, the outstanding request trigger should be ETxAllBytes | ETxUnderrun sl@0: // and the flag to indicate duplex transfers should be cleared sl@0: if((iExpectedTrigger != (ETxAllBytes | ETxUnderrun)) || (iFullDuplexReq != ETxAllBytes)) sl@0: { sl@0: CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq)); sl@0: r=KErrGeneral; sl@0: } sl@0: else sl@0: { sl@0: // Simulate providing a new buffer (actually, re-use existing buffer) sl@0: CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterRxBuffer\n")); sl@0: TPtr8 rxPtr(iRxBuf,KRxBufSizeInBytes); sl@0: r = RegisterRxBuffer(iChannelId, rxPtr, iRxRegGranularity, iNumRegRxWords, iRxRegOffset); sl@0: sl@0: if(r != KErrNone) sl@0: { sl@0: CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterRxBuffer returned %d\n",r)); sl@0: } sl@0: else sl@0: { sl@0: // For the next step, just specify the new Rx triggers (do not specify Tx triggers) sl@0: r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun)); sl@0: if(r != KErrNone) sl@0: { sl@0: CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d\n",r)); sl@0: } sl@0: else sl@0: { sl@0: iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun; sl@0: iFullDuplexReq |= (ERxAllBytes|ETxAllBytes); sl@0: iTestOverUnderState = ERxOverrun_2; // Prepare for callback sl@0: // The requested number of words when the buffer was registered was 8, so simulate 10 sl@0: // to provoke an RxOverrun event. sl@0: TInt numWords=10; sl@0: // To support testing, any values of aId for StaticExtension must be shifted left one place sl@0: // and for a Slave, the two msbs must be zero sl@0: TInt ctrlIoVal = RBusDevIicClient::ECtrlIoRxWords; sl@0: ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF; sl@0: r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords); sl@0: } sl@0: } sl@0: } sl@0: break; sl@0: }; sl@0: case(ERxOverrun_2): sl@0: { sl@0: CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ERxOverrun_2\n")); sl@0: // At this point, the outstanding request trigger should be ETxAllBytes | ETxUnderrun sl@0: // and the flag to indicate duplex transfers should be cleared sl@0: if((iExpectedTrigger != (ETxAllBytes | ETxUnderrun)) || (iFullDuplexReq != ETxAllBytes)) sl@0: { sl@0: CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq)); sl@0: r=KErrGeneral; sl@0: } sl@0: else sl@0: { sl@0: // Simulate providing a new buffer (actually, re-use existing buffer) sl@0: CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterRxBuffer\n")); sl@0: TPtr8 rxPtr(iRxBuf,KRxBufSizeInBytes); sl@0: r = RegisterRxBuffer(iChannelId, rxPtr, iRxRegGranularity, iNumRegRxWords, iRxRegOffset); sl@0: if(r != KErrNone) sl@0: { sl@0: CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterRxBuffer returned %d\n",r)); sl@0: } sl@0: else sl@0: { sl@0: // Test that an attempt to modify existing Tx notification requests is rejected sl@0: r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxOverrun)); sl@0: if(r != KErrInUse) sl@0: { sl@0: CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrInUse\n",r)); sl@0: } sl@0: else sl@0: { sl@0: // For the next step, specify the new Rx triggers and the Tx triggers sl@0: r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun)); sl@0: if(r != KErrNone) sl@0: { sl@0: CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrNone\n",r)); sl@0: } sl@0: else sl@0: { sl@0: iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun; sl@0: iFullDuplexReq |= (ERxAllBytes|ETxAllBytes); sl@0: iTestOverUnderState = ETxUnderrun_1; // Prepare for callback sl@0: // The requested number of words when the buffer was registered was 12, so simulate 14 sl@0: // to provoke an TxUnderrun event. sl@0: TInt numWords=14; sl@0: // To support testing, any values of aId for StaticExtension must be shifted left one place sl@0: // and for a Slave, the two msbs must be zero sl@0: TInt ctrlIoVal = RBusDevIicClient::ECtrlIoTxWords; sl@0: ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF; sl@0: r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords); sl@0: } sl@0: } sl@0: } sl@0: } sl@0: break; sl@0: }; sl@0: case(ETxUnderrun_1): sl@0: { sl@0: CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ETxOverrun_1\n")); sl@0: // At this point, the outstanding request trigger should be ERxAllBytes | ERxOverrun sl@0: // and the flag to indicate duplex transfers should be cleared sl@0: if((iExpectedTrigger != (ERxAllBytes | ERxOverrun)) || (iFullDuplexReq != ERxAllBytes)) sl@0: { sl@0: CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq)); sl@0: r=KErrGeneral; sl@0: } sl@0: else sl@0: { sl@0: // Simulate providing a new buffer (actually, re-use existing buffer) sl@0: CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterTxBuffer\n")); sl@0: TPtr8 rxPtr(iTxBuf,KTxBufSizeInBytes); sl@0: r = RegisterTxBuffer(iChannelId, rxPtr, iTxRegGranularity, iNumRegTxWords, iTxRegOffset); sl@0: if(r != KErrNone) sl@0: { sl@0: CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterTxBuffer returned %d\n",r)); sl@0: } sl@0: else sl@0: { sl@0: // For the next step, just specify the new Tx triggers (do not specify Rx triggers) sl@0: r = SetNotificationTrigger(iChannelId, (ETxAllBytes | ETxUnderrun)); sl@0: if(r != KErrNone) sl@0: { sl@0: CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d\n",r)); sl@0: } sl@0: else sl@0: { sl@0: iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun; sl@0: iFullDuplexReq |= (ERxAllBytes|ETxAllBytes); sl@0: iTestOverUnderState = ETxUnderrun_2; // Prepare for callback sl@0: // The requested number of words when the buffer was registered was 12, so simulate 14 sl@0: // to provoke an TxUnderrun event. sl@0: TInt numWords=14; sl@0: // To support testing, any values of aId for StaticExtension must be shifted left one place sl@0: // and for a Slave, the two msbs must be zero sl@0: TInt ctrlIoVal = RBusDevIicClient::ECtrlIoTxWords; sl@0: ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF; sl@0: r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords); sl@0: } sl@0: } sl@0: } sl@0: break; sl@0: }; sl@0: case(ETxUnderrun_2): sl@0: { sl@0: CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ETxUnderrun_2\n")); sl@0: // At this point, the outstanding request trigger should be ERxAllBytes | ERxOverrun sl@0: // and the flag to indicate duplex transfers should be cleared sl@0: if((iExpectedTrigger != (ERxAllBytes | ERxOverrun)) || (iFullDuplexReq != ERxAllBytes)) sl@0: { sl@0: CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq)); sl@0: r=KErrGeneral; sl@0: } sl@0: else sl@0: { sl@0: // Simulate providing a new buffer (actually, re-use existing buffer) sl@0: CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterRxBuffer\n")); sl@0: TPtr8 rxPtr(iTxBuf,KTxBufSizeInBytes); sl@0: r = RegisterTxBuffer(iChannelId, rxPtr, iTxRegGranularity, iNumRegTxWords, iTxRegOffset); sl@0: if(r != KErrNone) sl@0: { sl@0: CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterTxBuffer returned %d\n",r)); sl@0: } sl@0: else sl@0: { sl@0: // Test that an attempt to modify existing Rx notification requests is rejected sl@0: r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxUnderrun | ETxAllBytes | ETxUnderrun)); sl@0: if(r != KErrInUse) sl@0: { sl@0: CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrInUse\n",r)); sl@0: } sl@0: else sl@0: { sl@0: // For the next step, specify the new Rx triggers and the Tx triggers sl@0: r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun)); sl@0: sl@0: if(r != KErrNone) sl@0: { sl@0: CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrNone\n",r)); sl@0: } sl@0: else sl@0: { sl@0: // Simulate a simultaneous ERxAllBytes and ETxAllBytes event. sl@0: iExpectedTrigger = ERxAllBytes | ETxAllBytes; sl@0: iFullDuplexReq |= (ERxAllBytes|ETxAllBytes); sl@0: iTestOverUnderState = EStartState; // Prepare for callback - return to normal operation sl@0: // Need to pass the number of words in an array, for use by StaticExtension sl@0: TInt parms[2]; sl@0: parms[0]= 8; // Number of Rx Words sl@0: parms[1]=12; // Number of Tx Words sl@0: // To support testing, any values of aId for StaticExtension must be shifted left one place sl@0: // and for a Slave, the two msbs must be zero sl@0: TInt ctrlIoVal = RBusDevIicClient::ECtrlIoRxTxWords; sl@0: ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF; sl@0: r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)(&parms[0])); sl@0: } sl@0: } sl@0: } sl@0: } sl@0: break; sl@0: }; sl@0: default: sl@0: { sl@0: r = KErrGeneral; sl@0: break; sl@0: }; sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: void DChannelIicSlaveClient::SlaveClientCallbackFunc(TInt aChannelId, TInt aReturn, TInt aTrigger, TInt16 aRxWords, TInt16 aTxWords, TAny* aParam) sl@0: { sl@0: 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: (void)aTxWords; // Unused if CLIENT_PRINT is undefined sl@0: (void)aRxWords; // Unused if CLIENT_PRINT is undefined sl@0: DChannelIicSlaveClient* channel = (DChannelIicSlaveClient*)aParam; sl@0: sl@0: // Ensure only the valid bits of aTrigger are processed sl@0: aTrigger &= 0xff; sl@0: sl@0: CLIENT_PRINT(("SlaveClientCallbackFunc() - channel=0x%x\n",channel)); sl@0: if(aTrigger == EAsyncCaptChan) sl@0: { sl@0: CLIENT_PRINT(("SlaveClientCallbackFunc: capture channel completed\n")); sl@0: // Set iChannelId, and write to user-side variable. sl@0: channel->iChannelId=aChannelId; sl@0: TInt r=Kern::ThreadRawWrite(channel->iClient,channel->iClientChanId,&aChannelId,sizeof(TInt)); sl@0: if(r == KErrNone) sl@0: r=aReturn; sl@0: #ifdef STANDALONE_CHANNEL sl@0: // Set the captured channel's iChannelId if the capture succeeds. sl@0: if(r != KErrCompletion) sl@0: (channel->iCapturedChan).iChannel = NULL; sl@0: else sl@0: (channel->iCapturedChan).iChannelId = aChannelId; sl@0: #endif/*STANDALONE_CHANNEL*/ sl@0: channel->RequestComplete(r); // Inform user of error sl@0: return; sl@0: } sl@0: else sl@0: { sl@0: if(aTrigger&ERxAllBytes) sl@0: { sl@0: CLIENT_PRINT(("SlaveClientCallbackFunc() - ERxAllBytes\n")); sl@0: aTrigger&= ~ERxAllBytes; sl@0: channel->iExpectedTrigger&=~ERxAllBytes; sl@0: channel->iFullDuplexReq&=~ERxAllBytes; sl@0: aReturn=channel->CheckDataRead(); sl@0: // Check underrun sl@0: if(aTrigger&ERxUnderrun) sl@0: { sl@0: if(channel->iExpectedTrigger&ERxUnderrun) sl@0: { sl@0: CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxUnderrun found OK\n\n")); sl@0: channel->iExpectedTrigger&=~ERxUnderrun; sl@0: } sl@0: else sl@0: { sl@0: CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ERxUnderrun indicated\n\n")); sl@0: aReturn = KErrGeneral; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: if(channel->iExpectedTrigger&ERxUnderrun) sl@0: { sl@0: CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxUnderrun not (yet) seen\n\n")); sl@0: aReturn = KErrGeneral; sl@0: } sl@0: } sl@0: // Check overrun sl@0: if(aTrigger&ERxOverrun) sl@0: { sl@0: if(channel->iExpectedTrigger&ERxOverrun) sl@0: { sl@0: CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxOverrun found OK\n\n")); sl@0: channel->iExpectedTrigger&=~ERxOverrun; sl@0: } sl@0: else sl@0: { sl@0: CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ERxOverrun indicated\n\n")); sl@0: aReturn = KErrGeneral; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: if(channel->iExpectedTrigger&ERxOverrun) sl@0: { sl@0: CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxOverrun not (yet) seen\n\n")); sl@0: aReturn = KErrGeneral; sl@0: } sl@0: } sl@0: } sl@0: sl@0: if(aTrigger&ETxAllBytes) sl@0: { sl@0: CLIENT_PRINT(("SlaveClientCallbackFunc() - ETxAllBytes\n")); sl@0: aTrigger&= ~ETxAllBytes; sl@0: channel->iExpectedTrigger&=~ETxAllBytes; sl@0: channel->iFullDuplexReq&=~ETxAllBytes; sl@0: aReturn=channel->CheckDataWritten(); sl@0: // Check underrun sl@0: if(aTrigger&ETxUnderrun) sl@0: { sl@0: if(channel->iExpectedTrigger&ETxUnderrun) sl@0: { sl@0: CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxUnderrun found OK\n\n")); sl@0: channel->iExpectedTrigger&=~ETxUnderrun; sl@0: } sl@0: else sl@0: { sl@0: CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ETxUnderrun indicated\n\n")); sl@0: aReturn = KErrGeneral; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: if(channel->iExpectedTrigger&ETxUnderrun) sl@0: { sl@0: CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxUnderrun not (yet) seen\n\n")); sl@0: aReturn = KErrGeneral; sl@0: } sl@0: } sl@0: // Check overrun sl@0: if(aTrigger&ETxOverrun) sl@0: { sl@0: if(channel->iExpectedTrigger&ETxOverrun) sl@0: { sl@0: CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxOverrun found OK\n\n")); sl@0: channel->iExpectedTrigger&=~ETxOverrun; sl@0: } sl@0: else sl@0: { sl@0: CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ETxOverrun indicated\n\n")); sl@0: aReturn = KErrGeneral; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: if(channel->iExpectedTrigger&ETxOverrun) sl@0: { sl@0: CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxOverrun not (yet) seen\n\n")); sl@0: aReturn = KErrGeneral; sl@0: } sl@0: } sl@0: } sl@0: sl@0: sl@0: if(aTrigger&EGeneralBusError) sl@0: { sl@0: if(channel->iExpectedTrigger&EGeneralBusError) sl@0: { sl@0: CLIENT_PRINT(("\nSlaveClientCallbackFunc: EGeneralBusError - as expected\n\n")); sl@0: channel->iExpectedTrigger&=~EGeneralBusError; sl@0: if(aReturn == KErrGeneral) sl@0: { sl@0: aReturn=KErrNone; // If aReturn==KErrGeneral, set to KErrNone so t_iic knows test was successful sl@0: channel->iFullDuplexReq = 0; // The transaction is considered terminated, so don't wait for more triggers sl@0: } sl@0: else sl@0: { sl@0: CLIENT_PRINT(("\nSlaveClientCallbackFunc: aReturn not EGeneralBusError, =0x%x \n\n",aReturn)); sl@0: aReturn=KErrGeneral; sl@0: } sl@0: sl@0: } sl@0: else sl@0: { sl@0: CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected EGeneralBusError indicated\n\n")); sl@0: aReturn = KErrGeneral; sl@0: } sl@0: } sl@0: sl@0: if((aTrigger < 0)||(aTrigger & (~0xFF))) sl@0: { sl@0: CLIENT_PRINT(("\nSlaveClientCallbackFunc: trigger condition 0x%x is not recognised \n\n",aTrigger)); sl@0: } sl@0: sl@0: // For simulataneous Rx,Tx triggers with ERxOverrun or TxUnderrun testing, need to call the following sl@0: if(aReturn == KErrNone) sl@0: { sl@0: aReturn = channel->CbProcessOverUnderRunRxTx(); sl@0: } sl@0: sl@0: if((channel->iExpectedTrigger == 0)&&(channel->iFullDuplexReq == 0)) sl@0: channel->RequestComplete(aReturn); // Complete user-side request only if all the triggers have been satisfied sl@0: sl@0: } // if(aTrigger == EAsyncCaptChan) sl@0: } sl@0: sl@0: sl@0: TInt DChannelIicSlaveClient::CheckDataRead() sl@0: { sl@0: TInt r=KErrNone; sl@0: // This channel will have provided a buffer for writing to, with a specified offset and number of words sl@0: // Bytes in the buffer before the offset should be set to zero sl@0: // Bytes written at and beyond the offset should exhibit an incrementing count sl@0: // Bytes beyond the offset that were not written to should be set to zero sl@0: TInt8 numWords=(iRxReqNumWords>iNumRegRxWords)?iNumRegRxWords:iRxReqNumWords; sl@0: TInt8 currVal=0; sl@0: TInt8 index = 0; sl@0: while(indexiNumRegTxWords)?iNumRegTxWords:iTxReqNumWords; sl@0: TInt8 index=0; sl@0: while(index<(wordsWritten*iTxRegGranularity)) sl@0: { sl@0: currVal=*(iBusTxCheckBuf+index); sl@0: if(currVal != (TInt8)(firstValue+index)) sl@0: { sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataWritten, index=%d, value =0x%x, expected 0x%x",index,currVal,(TInt8)(firstValue+index))); sl@0: r=KErrCorrupt; sl@0: } sl@0: ++index; sl@0: } sl@0: while(index<(iNumRegTxWords*iTxRegGranularity)) sl@0: { sl@0: currVal=*(iBusTxCheckBuf+index); sl@0: if(currVal != 0) sl@0: { sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataWritten, index=%d, value =0x%x, expected 0",index,currVal)); sl@0: r=KErrCorrupt; sl@0: } sl@0: ++index; sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: sl@0: TInt DChannelIicSlaveClient::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/) sl@0: { sl@0: CLIENT_PRINT(("> DChannelIicSlaveClient::DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion &aVer)")); sl@0: sl@0: TInt r = Kern::DynamicDfcQCreate(iDfcQue,KIicSlaveClientThreadPriority,KIicSlaveClientThreadName); sl@0: if(r!=KErrNone) sl@0: return r; sl@0: SetDfcQ(iDfcQue); sl@0: sl@0: // Allocate buffers for Rx, Tx operations sl@0: iRxBuf = new TUint8[KRxBufSizeInBytes]; sl@0: iTxBuf = new TUint8[KTxBufSizeInBytes]; sl@0: if((iRxBuf == NULL)||(iTxBuf == NULL)) sl@0: return KErrNoMemory; sl@0: // Start receiving messages sl@0: iMsgQ.Receive(); sl@0: sl@0: return r; sl@0: } sl@0: sl@0: TInt DChannelIicSlaveClient::InitSlaveClient() sl@0: { sl@0: iNotif = new TIicBusSlaveCallback(DChannelIicSlaveClient::SlaveClientCallbackFunc, (TAny*)this, iDfcQue, KIicSlaveClientDfcPriority); sl@0: if(iNotif == NULL) sl@0: { sl@0: CLIENT_PRINT(("> DChannelIicSlaveClient::InitSlaveClient ERROR unable to allocate space TIicBusSlaveCallback* iNotif \n")); sl@0: return KErrNoMemory; sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: void DChannelIicSlaveClient::HandleMsg(TMessageBase* aMsg) sl@0: { sl@0: TThreadMessage& m=*(TThreadMessage*)aMsg; sl@0: TInt id=m.iValue; sl@0: sl@0: CLIENT_PRINT((" >ldd: DChannelIicSlaveClient::HandleMsg(TMessageBase* aMsg) id=%d\n", id)); sl@0: sl@0: if (id == (TInt)ECloseMsg) sl@0: { sl@0: iMsgQ.iMessage->Complete(KErrNone,EFalse); sl@0: return; sl@0: } sl@0: sl@0: if (id<0) sl@0: { sl@0: TRequestStatus* pS=(TRequestStatus*)m.Ptr0(); sl@0: TInt r=DoRequest(~id, pS, m.Ptr1(), m.Ptr2()); sl@0: if (r!=KErrNone) sl@0: { sl@0: Kern::RequestComplete(iClient, pS, r); sl@0: } sl@0: m.Complete(KErrNone,ETrue); sl@0: } sl@0: else sl@0: if((id>=0)&&(id!=KMaxTInt)) sl@0: { sl@0: TInt r=DoControl(id,m.Ptr0(),m.Ptr1()); sl@0: m.Complete(r,ETrue); sl@0: } sl@0: } sl@0: sl@0: sl@0: TInt DChannelIicSlaveClient::DoControl(TInt aId, TAny* a1, TAny* a2) sl@0: { sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoked with aId=0x%x, a1=0x%x, a2=0x%x\n", aId,a1,a2)); sl@0: TInt r=KErrNone; sl@0: // To support testing, any values of aId for StaticExtension must be shifted left one place sl@0: // and for a Slave, the two msbs must be zero sl@0: TInt ctrlIoVal = 0; sl@0: if((aId & KTestSlaveControlIo) == KTestSlaveControlIo) sl@0: ctrlIoVal = (aId << 1) & 0x3FFFFFFF; sl@0: sl@0: switch(aId) sl@0: { sl@0: case(RBusDevIicClient::EInitSlaveClient): sl@0: { sl@0: r=InitSlaveClient(); sl@0: break; sl@0: } sl@0: sl@0: case(RBusDevIicClient::ECaptureChanSync): sl@0: { sl@0: // a1 is a pointer to the TDes8* aConfigHdr sl@0: // a2 is a pointer to TInt* parms[2], where: sl@0: // parms[0]=(TInt*)aBusId; sl@0: // parms[1]=&aChannelId; sl@0: // sl@0: TInt* parms[2]; sl@0: r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt*)); sl@0: if(r!=KErrNone) sl@0: break; // Can't proceed if can't access request parameters sl@0: // sl@0: TInt hdrSize = Kern::ThreadGetDesLength(iClient,a1); sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::DoControl hdrSize = 0x%x\n",hdrSize)); sl@0: if (hdrSize<=0) sl@0: { sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::DoControl ERROR, hdrSize is invalid\n")); sl@0: r = KErrArgument; sl@0: break; sl@0: } sl@0: if((iConfigHdr = HBuf8::New(hdrSize)) == NULL) sl@0: return KErrNoMemory; sl@0: r = Kern::ThreadDesRead(iClient,a1,*iConfigHdr,0); sl@0: if(r!=KErrNone) sl@0: { sl@0: delete iConfigHdr; sl@0: break; sl@0: } sl@0: // Store the address of the user-side variable to update with the ChannelId sl@0: iClientChanId=parms[1]; sl@0: sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking (synchronous) CaptureChannel\n")); sl@0: r = CaptureChannel((TInt)(parms[0]), iConfigHdr, iNotif, iChannelId); sl@0: if(r != KErrNone) sl@0: { sl@0: delete iConfigHdr; sl@0: break; sl@0: } sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::DoControl CaptureChannelgave iChannelId=0x%x\n",iChannelId)); sl@0: sl@0: r = Kern::ThreadRawWrite(iClient,iClientChanId,&iChannelId,sizeof(TInt)); sl@0: if(r != KErrNone) sl@0: delete iConfigHdr; sl@0: break; sl@0: } sl@0: sl@0: case(RBusDevIicClient::EReleaseChan): sl@0: { sl@0: // a1 represents TInt aChannelId sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking ReleaseChannel\n")); sl@0: r = ReleaseChannel((TInt)a1); sl@0: delete iConfigHdr; sl@0: break; sl@0: } sl@0: sl@0: case(RBusDevIicClient::ERegisterRxBuffer): sl@0: { sl@0: // a1 represents TInt aChannelId sl@0: // a2 represents (TAny*) of TInt8 parms[3] where parms[0]=aBufGranularity; parms[1]=aNumWords; parms[2]=aOffset sl@0: TInt8 parms[3]; sl@0: r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),3*sizeof(TInt8)); sl@0: if(r!=KErrNone) sl@0: break; // Can't proceed if can't access request parameters sl@0: // Store parameters for checking in the callback sl@0: iRxRegGranularity = parms[0]; sl@0: iRxRegOffset= parms[2]; sl@0: iNumRegRxWords=parms[1]; sl@0: sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking RegisterRxBuffer\n")); sl@0: TPtr8 rxPtr(iRxBuf,KRxBufSizeInBytes); sl@0: r = RegisterRxBuffer((TInt)a1, rxPtr, parms[0], parms[1], parms[2]); sl@0: break; sl@0: } sl@0: sl@0: case(RBusDevIicClient::ERegisterTxBuffer): sl@0: { sl@0: // a1 represents TInt aChannelId sl@0: // a2 represents (TAny*) of TInt8 parms[3] where parms[0]=aBufGranularity; parms[1]=aNumWords; parms[2]=aOffset sl@0: TInt8 parms[3]; sl@0: r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),3*sizeof(TInt8)); sl@0: if(r!=KErrNone) sl@0: break; // Can't proceed if can't access request parameters sl@0: // Store parameters for checking in the callback sl@0: iTxRegGranularity = parms[0]; sl@0: iTxRegOffset= parms[2]; sl@0: iNumRegTxWords=parms[1]; sl@0: sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking RegisterTxBuffer\n")); sl@0: TPtr8 txPtr(iTxBuf,KTxBufSizeInBytes); sl@0: r = RegisterTxBuffer((TInt)a1, txPtr, parms[0], parms[1], parms[2]); sl@0: break; sl@0: } sl@0: sl@0: case(RBusDevIicClient::ESetNotifTrigger): sl@0: { sl@0: // a1 represents (TAny*) of TRequestStatus* aStatus sl@0: // a2 represents (TAny*) of TInt parms[2] where parms[0]=aChannelId; parms[1]=aTrigger sl@0: TInt parms[2]; sl@0: r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt)); sl@0: if(r!=KErrNone) sl@0: break; // Can't proceed if can't access request parameters sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking SetNotificationTrigger with aStatus=0x%x, aChannelId=0x%x, aTrigger=0x%x\n",a1,parms[0],parms[1])); sl@0: if(a1 == NULL) sl@0: { sl@0: r = KErrArgument; sl@0: break; sl@0: } sl@0: iStatus=(TRequestStatus*)a1; sl@0: // Set the flags for duplex processing sl@0: if((parms[1]&ERxAllBytes)&&(parms[1]&ETxAllBytes)) sl@0: iFullDuplexReq |= (ERxAllBytes|ETxAllBytes); sl@0: r = SetNotificationTrigger(parms[0],parms[1]); sl@0: if(r == KErrTimedOut) sl@0: r=KErrNone; // KErrTimedOut is returned if the Client has not interacted with IIC for a while sl@0: break; sl@0: } sl@0: sl@0: case(RBusDevIicClient::ECtrlIoNotifNoTrigger): sl@0: { sl@0: // a1 represents (TAny*) of aChannelId sl@0: // a2 represents (TAny*) of aTrigger sl@0: TInt chanId = (TInt)a1; sl@0: TInt trigger = (TInt)a2; sl@0: // No TRequestStatus is accessed because the call to SetNotificationTrigger sl@0: // is either with zero (when it is valid to do so), or it is being called with a sl@0: // trigger value that is expected to be rejected. sl@0: r = SetNotificationTrigger(chanId,trigger); sl@0: sl@0: if(r == KErrNone) sl@0: { sl@0: if((trigger&ERxAllBytes)&&(trigger&ETxAllBytes)) sl@0: iFullDuplexReq |= (ERxAllBytes|ETxAllBytes); sl@0: } sl@0: if(r == KErrTimedOut) sl@0: r=KErrNone; // KErrTimedOut is returned if the Client has not interacted with IIC for a while sl@0: break; sl@0: } sl@0: sl@0: case(RBusDevIicClient::ECtrlIoRxWords): sl@0: { sl@0: // a1 represents TInt aBusId sl@0: // a2 represents (TAny*) of TInt parms[2] where parms[0]=aChannelId; parms[1]=aNumWords sl@0: TInt parms[2]; sl@0: r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt)); sl@0: if(r!=KErrNone) sl@0: break; // Can't proceed if can't access request parameters sl@0: // Prepare iRxBuf sl@0: memset(iRxBuf,0,KRxBufSizeInBytes); sl@0: // Store the number of words for checking in the callback sl@0: iRxReqNumWords=(TInt8)(parms[1]); sl@0: sl@0: TInt tempTrigger=0; sl@0: // Set the expected result sl@0: tempTrigger |= ERxAllBytes; sl@0: if(parms[1] < iNumRegRxWords) sl@0: tempTrigger |= ERxUnderrun; sl@0: if(parms[1] > iNumRegRxWords) sl@0: tempTrigger |= ERxOverrun; sl@0: if(iExpectedTrigger != EGeneralBusError) sl@0: iExpectedTrigger |= tempTrigger; sl@0: else sl@0: iBlockedTrigger |= tempTrigger; sl@0: 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: r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)(parms[0]), (TAny*)(parms[1])); sl@0: if(r == KErrTimedOut) sl@0: r=KErrNone; // KErrTimedOut is returned if the Client has not interacted with IIC for a while sl@0: break; sl@0: } sl@0: sl@0: case(RBusDevIicClient::ECtrlIoTxWords): sl@0: { sl@0: // a1 represents TInt aBusId sl@0: // a2 represents (TAny*) of TInt parms[2] where parms[0]=aChannelId; parms[1]=aNumWords sl@0: TInt parms[2]; sl@0: r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt)); sl@0: if(r!=KErrNone) sl@0: break; // Can't proceed if can't access request parameters sl@0: // Prepare iTxBuf sl@0: TUint8* ptr=iTxBuf; sl@0: for(TInt offset=0; offset iNumRegTxWords) sl@0: tempTrigger |= ETxUnderrun; sl@0: if(iExpectedTrigger != EGeneralBusError) sl@0: iExpectedTrigger |= tempTrigger; sl@0: else sl@0: iBlockedTrigger |= tempTrigger; sl@0: sl@0: // The bytes "transmitted" are stored in the simulated bus' iTxCheckBuf sl@0: // Since the simulated bus channel is also in the kernel process it shares the same address space sl@0: // Get the address of the buffer sl@0: // As part of the callback invoked by IIC, this client will check the data stored by the simulated sl@0: // bus. Since the simulated bus channel is also in the kernel process it shares the same address space, sl@0: // so the buffer can be accessed directly - but the buffer is not created until it receives the following sl@0: // StaticExtension command, so the bus identifier represented by a1 is stored to allow accessing the buffer sl@0: // adddress from the callback. sl@0: iBusId=(TUint)a1; sl@0: 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: aId<<=1; sl@0: r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)(parms[0]), (TAny*)(parms[1])); sl@0: break; sl@0: } sl@0: sl@0: case(RBusDevIicClient::ECtrlIoRxTxWords): sl@0: { sl@0: // a1 represents TInt aBusId sl@0: // a2 represents (TAny*) of TInt parms[3] where parms[0]=aChannelId; parms[1]=aNumRxWords; parms[2]=aNumTxWords sl@0: TInt parms[3]; sl@0: r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),3*sizeof(TInt)); sl@0: if(r!=KErrNone) sl@0: break; // Can't proceed if can't access request parameters sl@0: // Prepare iRxBuf, iTxBuf sl@0: memset(iRxBuf,0,KRxBufSizeInBytes); sl@0: TUint8* ptr=iTxBuf; sl@0: for(TInt offset=0; offset iNumRegRxWords) sl@0: tempTrigger |= ERxOverrun; sl@0: sl@0: if(parms[2] < iNumRegTxWords) sl@0: tempTrigger |= ETxOverrun; sl@0: if(parms[2] > iNumRegTxWords) sl@0: tempTrigger |= ETxUnderrun; sl@0: sl@0: if(iExpectedTrigger != EGeneralBusError) sl@0: iExpectedTrigger |= tempTrigger; sl@0: else sl@0: iBlockedTrigger |= tempTrigger; sl@0: sl@0: // The bytes "transmitted" are stored in the simulated bus' iTxCheckBuf sl@0: // Since the simulated bus channel is also in the kernel process it shares the same address space sl@0: // Get the address of the buffer sl@0: // As part of the callback invoked by IIC, this client will check the data stored by the simulated sl@0: // bus. Since the simulated bus channel is also in the kernel process it shares the same address space, sl@0: // so the buffer can be accessed directly - but the buffer is not created until it receives the following sl@0: // StaticExtension command, so the bus identifier represented by a1 is stored to allow accessing the buffer sl@0: // adddress from the callback. sl@0: iBusId=(TUint)a1; sl@0: sl@0: 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: r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)(parms[0]), (TAny*)(&(parms[1]))); sl@0: if(r == KErrTimedOut) sl@0: r=KErrNone; // KErrTimedOut is returned if the Client has not interacted with IIC for a while sl@0: break; sl@0: } sl@0: sl@0: case(RBusDevIicClient::ECtlIoBusError): sl@0: { sl@0: // a1 represents TInt aBusId sl@0: // a2 represents TInt aChannelId sl@0: // Set the expected result sl@0: iExpectedTrigger |= EGeneralBusError; sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtlIoBusError) \n")); sl@0: r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)a2, NULL); sl@0: break; sl@0: } sl@0: sl@0: case(RBusDevIicClient::ECtrlIoUnblockNotification): sl@0: { sl@0: // a1 represents TInt aBusId sl@0: // a2 represents TInt aChannelId sl@0: iExpectedTrigger = iBlockedTrigger; sl@0: iBlockedTrigger=0; sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoUnblockNotification) \n")); sl@0: r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)a2, NULL); sl@0: break; sl@0: } sl@0: sl@0: case(RBusDevIicClient::ECtrlIoBlockNotification): sl@0: { sl@0: // a1 represents TInt aBusId sl@0: // a2 represents TInt aChannelId sl@0: iBlockedTrigger = iExpectedTrigger; sl@0: iExpectedTrigger = EGeneralBusError; // For this test, just interested in if the timeout is detected sl@0: // iExpectedTrigger will be reinstated prior to unblocking sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoBlockNotification) \n")); sl@0: r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)a2, NULL); sl@0: break; sl@0: } sl@0: sl@0: case(RBusDevIicClient::ECtrlIoUpdTimeout): sl@0: { sl@0: // a1 represents TInt aBusId sl@0: // a2 represents TInt aChannelId sl@0: sl@0: // For this test, instruct the simulated bus to do the following for the Master and Client timeout values: sl@0: // (1) Read the current timeout value and check that it is set to the default sl@0: // (2) Set it to different value sl@0: // (3) Read it back to check success sl@0: // (4) Return to the original value, and readback to confirm sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoBlockNotification) \n")); sl@0: r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, NULL, NULL); sl@0: break; sl@0: } sl@0: sl@0: default: sl@0: { sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::DoControl - unrecognised value for aId=0x%x\n",aId)); sl@0: r=KErrArgument; sl@0: break; sl@0: } sl@0: sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: TInt DChannelIicSlaveClient::DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2) sl@0: { sl@0: 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: sl@0: TInt r=KErrNone; sl@0: switch(aId) sl@0: { sl@0: case(RBusDevIicClient::ECaptureChanAsync): sl@0: { sl@0: // a1 is a pointer to the TDes8* aConfigHdr sl@0: // a2 is a pointer to TInt* parms[2], where: sl@0: // parms[0]=(TInt*)aBusId; sl@0: // parms[1]=&aChannelId; sl@0: // sl@0: TInt* parms[2]; sl@0: r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt*)); sl@0: if(r!=KErrNone) sl@0: break; // Can't proceed if can't access request parameters sl@0: // sl@0: TInt hdrSize = Kern::ThreadGetDesLength(iClient,a1); sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest hdrSize = 0x%x\n",hdrSize)); sl@0: if (hdrSize<=0) sl@0: { sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest ERROR, hdrSize is invalid\n")); sl@0: return KErrArgument; sl@0: } sl@0: if((iConfigHdr = HBuf8::New(hdrSize)) == NULL) sl@0: return KErrNoMemory; sl@0: if((r = Kern::ThreadDesRead(iClient,a1,*iConfigHdr,0))!=KErrNone) sl@0: { sl@0: delete iConfigHdr; sl@0: return r; sl@0: } sl@0: iStatus=aStatus; sl@0: // Store the address of the user-side variable to update with the ChannelId sl@0: iClientChanId=parms[1]; sl@0: // Invoke the IIC API sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest invoking (asynchronous) CaptureChannel\n")); sl@0: r = CaptureChannel((TInt)(parms[0]), iConfigHdr, iNotif, iChannelId, ETrue); sl@0: if(r != KErrNone) sl@0: delete iConfigHdr; sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest (asynchronous) CaptureChannel returned %d\n",r)); sl@0: break; sl@0: } sl@0: sl@0: case(RBusDevIicClient::ECtrlIoOvUndRunRxTx): sl@0: { sl@0: iBusId = (TInt)a1; sl@0: iChannelId = (TInt)a2; sl@0: iStatus=aStatus; sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest status = 0x%x, busId = 0x%x, chanId =0x%x\n",iStatus,iBusId,iChannelId)); sl@0: sl@0: // This test is state-machine driven. It is instigated from this point, then subsequent steps sl@0: // are handled in the callback funciton SlaveClientCallbackFunc sl@0: // sl@0: // Check we in the appropriate state to start sl@0: if(iTestOverUnderState == EStartState) sl@0: { sl@0: // Re-use the previously-provided buffers. Just request the initial notification triggers, sl@0: // the simulate the first event (RxOverrun). sl@0: r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun)); sl@0: if(r != KErrNone) sl@0: { sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest SetNotificationTrigger returned %d\n",r)); sl@0: } sl@0: else sl@0: { sl@0: // Trigger now set, so simulate the required event sl@0: iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun; sl@0: iFullDuplexReq |= (ERxAllBytes|ETxAllBytes); sl@0: iTestOverUnderState = ERxOverrun_1; // Prepare for callback sl@0: // The requested number of words when the buffer was registered was 8, so simulate 10 sl@0: // to provoke an RxOverrun event. sl@0: TInt numWords=10; sl@0: // To support testing, any values of aId for StaticExtension must be shifted left one place sl@0: // and for a Slave, the two msbs must be zero sl@0: TInt ctrlIoVal = RBusDevIicClient::ECtrlIoRxWords; sl@0: ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF; sl@0: r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest ECtrlIoOvUndRunRxTx, iTestOverUnderState = 0x%x\n",iTestOverUnderState)); sl@0: r=KErrGeneral; sl@0: } sl@0: break; sl@0: } sl@0: sl@0: default: sl@0: { sl@0: CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest - unrecognised value for aId=0x%x\n",aId)); sl@0: r=KErrArgument; sl@0: break; sl@0: } sl@0: } sl@0: return r; sl@0: } sl@0: