diff -r 000000000000 -r bde4ae8d615e os/kernelhwsrv/kerneltest/e32test/iic/iic_psl/spi.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/kernelhwsrv/kerneltest/e32test/iic/iic_psl/spi.cpp Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,1000 @@ +// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32test/iic/iic_psl/spi.cpp +// +#include "spi.h" + +#ifdef IIC_INSTRUMENTATION_MACRO +#include +#endif + +#define NUM_CHANNELS 4 // Arbitrary + +// Macros to be updated(?) with interaction with Configuration Repository +const TInt KChannelTypeArray[NUM_CHANNELS] = {DIicBusChannel::EMaster, DIicBusChannel::EMaster, DIicBusChannel::ESlave, DIicBusChannel::EMaster}; +#define CHANNEL_TYPE(n) (KChannelTypeArray[n]) +const DIicBusChannel::TChannelDuplex KChannelDuplexArray[NUM_CHANNELS] = {DIicBusChannel::EHalfDuplex, DIicBusChannel::EHalfDuplex, DIicBusChannel::EHalfDuplex, DIicBusChannel::EFullDuplex}; +#define CHANNEL_DUPLEX(n) (KChannelDuplexArray[n]) + +#ifdef LOG_SPI +#define SPI_PRINT(str) Kern::Printf str +#else +#define SPI_PRINT(str) +#endif + +_LIT(KSpiThreadName,"SpiChannelThread"); + +const TInt KSpiThreadPriority = 5; // Arbitrary, can be 0-7, 7 highest + +#ifdef STANDALONE_CHANNEL +_LIT(KPddNameSpi,"spi_ctrless.pdd"); +#else +_LIT(KPddNameSpi,"spi.pdd"); +#endif + +#ifndef STANDALONE_CHANNEL +LOCAL_C TInt8 AssignChanNum() + { + static TInt8 iBaseChanNum = KSpiChannelNumBase; + SPI_PRINT(("SPI AssignChanNum - on entry, iBaseCanNum = 0x%x\n",iBaseChanNum)); + return iBaseChanNum++; // Arbitrary, for illustration + } +#endif + +NONSHARABLE_CLASS(DSimulatedSpiDevice) : public DPhysicalDevice + { +// Class to faciliate loading of the IIC classes +public: + class TCaps + { + public: + TVersion iVersion; + }; +public: + DSimulatedSpiDevice(); + virtual TInt Install(); + virtual TInt Create(DBase*& aChannel, TInt aUnit, const TDesC8* anInfo, const TVersion& aVer); + virtual TInt Validate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer); + virtual void GetCaps(TDes8& aDes) const; + inline static TVersion VersionRequired(); + }; + +TVersion DSimulatedSpiDevice::VersionRequired() + { + SPI_PRINT(("DSimulatedSpiDevice::VersionRequired\n")); + return TVersion(KIicClientMajorVersionNumber,KIicClientMinorVersionNumber,KIicClientBuildVersionNumber); + } + +/** Factory class constructor */ +DSimulatedSpiDevice::DSimulatedSpiDevice() + { + SPI_PRINT(("DSimulatedSpiDevice::DSimulatedSpiDevice\n")); + iVersion = DSimulatedSpiDevice::VersionRequired(); + } + +TInt DSimulatedSpiDevice::Install() + { + SPI_PRINT(("DSimulatedSpiDevice::Install\n")); + return(SetName(&KPddNameSpi)); + } + +/** Called by the kernel's device driver framework to create a Physical Channel. */ +TInt DSimulatedSpiDevice::Create(DBase*& /*aChannel*/, TInt /*aUint*/, const TDesC8* /*anInfo*/, const TVersion& /*aVer*/) + { + SPI_PRINT(("DSimulatedSpiDevice::Create\n")); + return KErrNone; + } + +/** Called by the kernel's device driver framework to check if this PDD is suitable for use with a Logical Channel.*/ +TInt DSimulatedSpiDevice::Validate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer) + { + SPI_PRINT(("DSimulatedSpiDevice::Validate\n")); + if (!Kern::QueryVersionSupported(DSimulatedSpiDevice::VersionRequired(),aVer)) + return(KErrNotSupported); + return KErrNone; + } + +/** Return the driver capabilities */ +void DSimulatedSpiDevice::GetCaps(TDes8& aDes) const + { + SPI_PRINT(("DSimulatedSpiDevice::GetCaps\n")); + // Create a capabilities object + TCaps caps; + caps.iVersion = iVersion; + // Zero the buffer + TInt maxLen = aDes.MaxLength(); + aDes.FillZ(maxLen); + // Copy capabilities + TInt size=sizeof(caps); + if(size>maxLen) + size=maxLen; + aDes.Copy((TUint8*)&caps,size); + } + +// supported channels for this implementation +static DIicBusChannel* ChannelPtrArray[NUM_CHANNELS]; + +//DECLARE_EXTENSION_WITH_PRIORITY(BUS_IMPLMENTATION_PRIORITY) +DECLARE_STANDARD_PDD() // SPI test driver to be explicitly loaded as an LDD, not kernel extension + { + SPI_PRINT(("\n\nSPI PDD, channel creation loop follows ...\n")); + +#ifndef STANDALONE_CHANNEL + DIicBusChannel* chan=NULL; + for(TInt i=0; iCreate()!=KErrNone) + return NULL; + } + else if(CHANNEL_TYPE(i) == DIicBusChannel::EMasterSlave) + { + DIicBusChannel* chanM=new DSimulatedIicBusChannelMasterSpi(BUS_TYPE,CHANNEL_DUPLEX(i)); + if(!chanM) + return NULL; + DIicBusChannel* chanS=new DSimulatedIicBusChannelSlaveSpi(BUS_TYPE,CHANNEL_DUPLEX(i)); + if(!chanS) + return NULL; + // For MasterSlave channel, the channel number for both the Master and Slave channels must be the same + TInt8 msChanNum = ((DSimulatedIicBusChannelMasterSpi*)chanM)->GetChanNum(); + ((DSimulatedIicBusChannelSlaveSpi*)chanS)->SetChanNum(msChanNum); + + chan=new DIicBusChannelMasterSlave(BUS_TYPE,CHANNEL_DUPLEX(i),(DIicBusChannelMaster*)chanM,(DIicBusChannelSlave*)chanS); // Generic implementation + if(!chan) + return NULL; + SPI_PRINT(("SPI chan created at 0x%x\n",chan)); + if(((DIicBusChannelMasterSlave*)chan)->DoCreate()!=KErrNone) + return NULL; + } + else + { + chan=new DSimulatedIicBusChannelSlaveSpi(BUS_TYPE,CHANNEL_DUPLEX(i)); + if(!chan) + return NULL; + SPI_PRINT(("SPI chan created at 0x%x\n",chan)); + if(((DSimulatedIicBusChannelSlaveSpi*)chan)->Create()!=KErrNone) + return NULL; + } + ChannelPtrArray[i]=chan; + } + SPI_PRINT(("\nSPI PDD, channel creation loop done- about to invoke RegisterChannels\n\n")); +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_REGISTERCHANS_START_PSL_TRACE; +#endif + + TInt r = KErrNone; + r=DIicBusController::RegisterChannels(ChannelPtrArray,NUM_CHANNELS); + +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_REGISTERCHANS_END_PSL_TRACE; +#endif + SPI_PRINT(("\nSPI - returned from RegisterChannels with r=%d\n",r)); + if(r!=KErrNone) + { + delete chan; + return NULL; + } +#endif + return new DSimulatedSpiDevice; + } + +#ifdef STANDALONE_CHANNEL +EXPORT_C +#endif + DSimulatedIicBusChannelMasterSpi::DSimulatedIicBusChannelMasterSpi(const TBusType aBusType, const TChannelDuplex aChanDuplex) + : DIicBusChannelMaster(aBusType,aChanDuplex) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::DSimulatedIicBusChannelMasterSpi, aBusType=%d,aChanDuplex=%d\n",aBusType,aChanDuplex)); +#ifndef STANDALONE_CHANNEL + iChannelNumber = AssignChanNum(); +#endif + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::DSimulatedIicBusChannelMasterSpi, iChannelNumber=%d\n",iChannelNumber)); + iTestState = ETestNone; + iChannelState = EIdle; + } + +// The time-out call back invoked when the Slave exeecds the allowed response time +TInt DSimulatedIicBusChannelMasterSpi::HandleSlaveTimeout() + { + SPI_PRINT(("HandleSlaveTimeout \n")); + return AsynchStateMachine(ETimeExpired); + } + +TInt DSimulatedIicBusChannelMasterSpi::DoCreate() + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::DoCreate\n")); + TInt r=Init(); // PIL Base class initialisation + r=Kern::DynamicDfcQCreate(iDynamicDfcQ,KSpiThreadPriority,KSpiThreadName); + if(r == KErrNone) + SetDfcQ((TDfcQue*)iDynamicDfcQ); + DSimulatedIicBusChannelMasterSpi::SetRequestDelayed(this,EFalse); + return r; + } + +TInt DSimulatedIicBusChannelMasterSpi::CheckHdr(TDes8* aHdr) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CheckHdr\n")); + + TConfigSpiBufV01* spiBuf = (TConfigSpiBufV01*)aHdr; + TConfigSpiV01* spiPtr = &((*spiBuf)()); + + // Valid values for the device ID will depend on the bus configuration + // + // Check that the values for word width, clock speed and clock mode are recognised + if((spiPtr->iWordWidth < 0) || (spiPtr->iWordWidth > ESpiWordWidth_16)) + { + SPI_PRINT(("ERROR: DSimulatedIicBusChannelMasterSpi::CheckHdr unrecognised word width identifier %d\n",spiPtr->iWordWidth)); + return KErrArgument; + } + if(spiPtr->iClkSpeedHz < 0) + { + SPI_PRINT(("ERROR: DSimulatedIicBusChannelMasterSpi::CheckHdr negative clock speed specified %d\n",spiPtr->iClkSpeedHz)); + return KErrArgument; + } + if((spiPtr->iClkMode < 0) || (spiPtr->iClkMode > ESpiPolarityHighRisingEdge)) + { + SPI_PRINT(("ERROR: DSimulatedIicBusChannelMasterSpi::CheckHdr unrecognised clock mode identifier %d\n",spiPtr->iClkMode)); + return KErrArgument; + } + // Values for the timeout period are arbitrary - can only check it is not a negative value + if(spiPtr->iTimeoutPeriod < 0) + { + SPI_PRINT(("ERROR: DSimulatedIicBusChannelMasterSpi::CheckHdr negative timeout period %d\n",spiPtr->iTimeoutPeriod)); + return KErrArgument; + } + if((spiPtr->iEndianness < 0) || (spiPtr->iEndianness > ELittleEndian)) + { + SPI_PRINT(("ERROR: DSimulatedIicBusChannelMasterSpi::CheckHdr unrecognised endianness identifier %d\n",spiPtr->iEndianness)); + return KErrArgument; + } + if((spiPtr->iBitOrder < 0) || (spiPtr->iBitOrder > EMsbFirst)) + { + SPI_PRINT(("ERROR: DSimulatedIicBusChannelMasterSpi::CheckHdr unrecognised bit order identifier %d\n",spiPtr->iBitOrder)); + return KErrArgument; + } + if((spiPtr->iSSPinActiveMode < 0) || (spiPtr->iSSPinActiveMode > ESpiCSPinActiveHigh)) + { + SPI_PRINT(("ERROR: DSimulatedIicBusChannelMasterSpi::CheckHdr unrecognised Slave select pin mode identifier %d\n",spiPtr->iSSPinActiveMode)); + return KErrArgument; + } + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CheckHdr word width = %d\n",spiPtr->iWordWidth)); + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CheckHdr clock speed = %d\n",spiPtr->iClkSpeedHz)); + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CheckHdr clock mode = %d\n",spiPtr->iClkMode)); + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CheckHdr timeout period = %d\n",spiPtr->iTimeoutPeriod)); + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CheckHdr endianness = %d\n",spiPtr->iEndianness)); + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CheckHdr bit order = %d\n",spiPtr->iBitOrder)); + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CheckHdr transaction wait cycles = %d\n",spiPtr->iTransactionWaitCycles)); + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CheckHdr slave select pin mode = %d\n",spiPtr->iSSPinActiveMode)); + + // For the set of tests expecft the following values + // ESpiWordWidth_8, 100kHz, ESpiPolarityLowRisingEdge,aTimeoutPeriod=100 + // EBigEndian, EMsbFirst, 10 wait cycles, Slave select active low + if( (spiPtr->iWordWidth != ESpiWordWidth_8) || + (spiPtr->iClkSpeedHz != 100000) || + (spiPtr->iClkMode != ESpiPolarityLowRisingEdge) || + (spiPtr->iTimeoutPeriod != 100) || + (spiPtr->iEndianness != ELittleEndian) || + (spiPtr->iBitOrder != EMsbFirst) || + (spiPtr->iTransactionWaitCycles != 10) || + (spiPtr->iSSPinActiveMode != ESpiCSPinActiveLow) ) + return KErrCorrupt; + return KErrNone; + } + +TInt DSimulatedIicBusChannelMasterSpi::CompareTransactionOne(TIicBusTransaction* aTransaction) +// Compares the indicated TIicBusTransaction with the expected content +// Returns KErrNone if there is a match, KErrCorrupt otherwise. + { + TInt i; + // Check the transaction header + // Should contain the default header for SPI + TDes8* bufPtr = GetTransactionHeader(aTransaction); + if(bufPtr == NULL) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - NULL header\n")); + return KErrCorrupt; + } + TConfigSpiV01 *buf = (TConfigSpiV01 *)(bufPtr->Ptr()); + if(buf->iWordWidth != ESpiWordWidth_8) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - Header wordwidth mis-match\n")); + return KErrCorrupt; + } + if(buf->iClkSpeedHz !=100000) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - Header clockspeed mis-match\n")); + return KErrCorrupt; + } + if(buf->iClkMode != ESpiPolarityLowRisingEdge) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - Header polarity mis-match\n")); + return KErrCorrupt; + } + if(buf->iTimeoutPeriod != 100) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - Header timeout mis-match\n")); + return KErrCorrupt; + } + + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne header OK\n")); + + // Check the half-duplex transfer list + TIicBusTransfer* tfer = GetTransHalfDuplexTferPtr(aTransaction); + if(tfer == NULL) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - NULL half-duplex transfer\n")); + return KErrCorrupt; + } + // Process each transfer in the list + TInt8 dummy; + + // tfer1 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf1); + // buf1 contains copy of TUint8 KTransOneTferOne[21] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; + dummy=GetTferType(tfer); + if(dummy!=TIicBusTransfer::EMasterWrite) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - tfer1 type=%d\n")); + return KErrCorrupt; + } + dummy=GetTferBufGranularity(tfer); + if(dummy!=8) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - tfer1 granularity=%d\n",dummy)); + return KErrCorrupt; + } + if((bufPtr = (TDes8*)GetTferBuffer(tfer)) == NULL) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - tfer1 buffer NULL\n")); + return KErrCorrupt; + } + for(i=0;i<21;++i) + { + if((*bufPtr)[i]!=i) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR tfer1 buffer element %d has 0x%x\n",i,(*bufPtr)[i])); + return KErrCorrupt; + } + } + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne tfer1 OK\n")); + + + tfer=GetTferNextTfer(tfer); + // tfer2 = new TIicBusTransfer(TIicBusTransfer::EMasterRead,8,buf2); + // buf2 contains copy of TUint8 KTransOneTferTwo[8] = {17,18,19,20,21,22,23,24}; + dummy=GetTferType(tfer); + if(dummy!=TIicBusTransfer::EMasterRead) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - tfer2 type=%d\n",dummy)); + return KErrCorrupt; + } + dummy=GetTferBufGranularity(tfer); + if(dummy!=8) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - tfer2 granularity=%d\n",dummy)); + return KErrCorrupt; + } + if((bufPtr = (TDes8*)GetTferBuffer(tfer)) == NULL) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - tfer2 buffer NULL\n")); + return KErrCorrupt; + } + for(i=0;i<8;++i) + { + if((*bufPtr)[i]!=(17+i)) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR tfer2 buffer element %d has 0x%x\n",i,(*bufPtr)[i])); + return KErrCorrupt; + } + } + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne tfer2 OK\n")); + + tfer=GetTferNextTfer(tfer); + // tfer3 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf3); + // buf2 contains copy of TUint8 KTransOneTferThree[6] = {87,85,83,81,79,77}; + dummy=GetTferType(tfer); + if(dummy!=TIicBusTransfer::EMasterWrite) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - tfer3 type=%d\n")); + return KErrCorrupt; + } + dummy=GetTferBufGranularity(tfer); + if(dummy!=8) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - tfer3 granularity=%d\n",dummy)); + return KErrCorrupt; + } + if((bufPtr = (TDes8*)GetTferBuffer(tfer)) == NULL) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - tfer3 buffer NULL\n")); + return KErrCorrupt; + } + for(i=0;i<6;++i) + { + if((*bufPtr)[i]!=(87-(2*i))) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR tfer3 buffer element %d has 0x%x\n",i,(*bufPtr)[i])); + return KErrCorrupt; + } + } + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne tfer3 OK\n")); + + // Shouldn't be any more transfers in the half duplex list + if((tfer=GetTferNextTfer(tfer))!=NULL) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - tfer3 iNext=0x%x\n",tfer)); + return KErrCorrupt; + } + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne half-duplex transfer OK\n")); + + // The full duplex transfer should be represented by a NULL pointer + if((tfer=GetTransFullDuplexTferPtr(aTransaction))!=NULL) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - full duplex pointer=0x%x\n",tfer)); + return KErrCorrupt; + } + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne full duplex pointer is NULL (OK)\n")); + + // Synchronous transaction, so check the callback pointer is NULL + TIicBusCallback* dumCb = NULL; + dumCb=GetTransCallback(aTransaction); + if(dumCb!=NULL) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - callback pointer=0x%x\n",dumCb)); + return KErrCorrupt; + } + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne callback pointer is NULL (OK)\n")); + + // Check the transaction flags are set to zero + TUint8 dumFlags; + dumFlags=GetTransFlags(aTransaction); + if(dumFlags!=0) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - flags=0x%x\n",dumFlags)); + return KErrCorrupt; + } + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne flags are zero (OK)\n")); + + return KErrNone; + } + + +// The THwCallbackFunc gets called if the hardware preparation completes successfully. +void THwCallbackFunc(TAny* aPtr) + { + SPI_PRINT(("Hardware preparation completed, calling the callback function")); + DSimulatedIicBusChannelMasterSpi* aChanMasterSpi=(DSimulatedIicBusChannelMasterSpi* )aPtr; + TInt r = aChanMasterSpi->DoSimulatedTransaction(); + ((DSimulatedIicBusChannelMasterSpi*)aChanMasterSpi)->CompleteReq(r); + } + +TInt DSimulatedIicBusChannelMasterSpi::DoSimulatedTransaction() + { + TInt r = AsynchStateMachine(EHwTransferDone); + if(iTimeoutTimer.Cancel() == FALSE) + { + SPI_PRINT(("timer is not cancelled")); + } + return r; + } + +TInt DSimulatedIicBusChannelMasterSpi::DoHwPreparation() + { + SPI_PRINT(("Preparing hardware for the transaction")); + + TInt r = KErrNone; + // The hardware preparation can either complete successfully or fail. + // If successful, invoke the callback function of THwDoneCallBack + // if not, execute the timeout machanism + // Currently DoHwPreparation is just a simple function. It should be more complicated + // for the real hardware. + switch(iTestState) + { + case (ETestSlaveTimeOut): + { + // In the timeout test, do nothing until the timeout callback function is invoked. + SPI_PRINT(("Simulating the timeout process.")); + break; + } + case (ETestNone): + { + // Pretend the hardware preparation's been done, and a callback function is invoked to call + // the Asynchronous State Machine + SPI_PRINT(("Hardware preparing work is executing normally.")); + iCb->Enque(); + break; + } + default: + { + SPI_PRINT(("Not a valid test.")); + r = KErrNotSupported; + break; + } + } + + return r; + } + +// Gateway function for PSL implementation, invoked for DFC processing +TInt DSimulatedIicBusChannelMasterSpi::DoRequest(TIicBusTransaction* aTransaction) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::DoRequest invoked with aTransaction=0x%x\n",aTransaction)); + + TInt r = KErrNone; + iCurrTrans=aTransaction; + + // Check if the Asynchronous State Machine is available. If not, then return KErrInUse. + // This is used to stop the second transaction executing if the machine has already been holding + // by a transaction. However, this situation cannot be tested because of the malfunction in PIL + if(iChannelState!= EIdle) + return KErrInUse; + + iChannelState = EBusy; +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_MPROCESSTRANS_START_PSL_TRACE; +#endif + r = ProcessTrans(aTransaction); + + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::DoRequest - exiting\n")); + return r; + } + +TInt DSimulatedIicBusChannelMasterSpi::ProcessTrans(TIicBusTransaction* aTransaction) + { + TInt r=KErrNone; + + switch(iTestState) + { + case(ETestWaitTransOne): + { + // The transaction received should exhibit the expected data + // Return KErrArgument if this is not the case + // The timer should be started at the beginning of every transaction + // For simplicity, we omit the timer here. + r=CompareTransactionOne(iCurrTrans); + iChannelState = EIdle; + CompleteRequest(KErrNone); + break; + } + case(ETestSlaveTimeOut): + { + // Test the timeout funciton + SPI_PRINT(("Test the slave timeout function\n")); + + // Simulate a timeout + // Start a timer and then wait for the Slave response to timeout + // A real bus would use its own means to identify a timeout + TInt aTime=1000000/NKern::TickPeriod(); + r = StartSlaveTimeOutTimer(aTime); + if(r != KErrNone) + return r; + r = DoHwPreparation(); + break; + } + case(ETestWaitPriorityTest): + { + static TInt TranCount = 0; + if(TranCount >= KPriorityTestNum) return KErrUnknown; + // block the channel + while(IsRequestDelayed(this)) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::DoRequest - starting Sleep...\n")); + NKern::Sleep(1000); // 1000 is arbitrary + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::DoRequest - completed Sleep, check if still delayed\n")); + }; + // get transaction header + TDes8* bufPtr = GetTransactionHeader(aTransaction); + if(bufPtr == NULL) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::DoRequest ERROR - NULL header\n")); + return KErrCorrupt; + } + + if(TranCount == 0) + { + // ignore the blocking transaction + TranCount++; + } + else + { + // store transaction header + iPriorityTestResult[TranCount++] = (*bufPtr)[0]; + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::DoRequest Priority test transaction no.:%d Priority:%d", + (*bufPtr)[0], aTransaction->iKey)); + } + iChannelState = EIdle; + CompleteRequest(KErrNone); + if(TranCount == KPriorityTestNum) iPriorityTestDone = ETrue; + break; + } + + + + case(ETestNone): + { + SPI_PRINT(("Nothing to be tested, just do the usual transaction")); + + // Start the timer on the Slave response. + // Since no timeout, this timer will be cancelled in the THwCallbackFunc + r = StartSlaveTimeOutTimer(100000); + if(r != KErrNone) + return r; + // Use a class THwDoneCallBack derived from TDfc to trigger the asynchronous state machine + // when the hardware preparation completes successfully. + // The priority is set with an arbitrary number 5 + iCb = new THwDoneCallBack(THwCallbackFunc, this, iDynamicDfcQ, 5); + r = DoHwPreparation(); + break; + } + default: + { + SPI_PRINT(("Test status not matched")); + return KErrNotSupported; + } + } + + return r; + } + + +TInt DSimulatedIicBusChannelMasterSpi::AsynchStateMachine(TInt aReason) + { + TInt r=KErrNone; + + // The asynchronous state machine has two states, it could either be idle or busy. + // Initially, it's in idle state. When a user queues a transaction, the hardware preparation starts + // and the state changes to busy. After the hardware preparation completes, either successfully or not, + // the state machine will do the corresponding work for the transaction and then goes back to the idle state. + switch(iChannelState) + { + case(EIdle): + { + return KErrGeneral; + } + case (EBusy): + { + switch(aReason) + { + case(EHwTransferDone): + { + + // Simulate processing - for now, do nothing! + // + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine aTransaction->iHeader=0x%x\n",GetTransactionHeader(iCurrTrans))); + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine aTransaction->iHalfDuplexTrans=0x%x\n",GetTransHalfDuplexTferPtr(iCurrTrans))); + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine aTransaction->iFullDuplexTrans=0x%x\n",GetTransFullDuplexTferPtr(iCurrTrans))); + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine aTransaction->iCallback=0x%x\n",GetTransCallback(iCurrTrans))); + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine aTransaction->iFlags=0x%x\n",GetTransFlags(iCurrTrans))); + + SPI_PRINT(("\nDSimulatedIicBusChannelMasterSpi::AsynchStateMachine, iHeader info \n")); + TDes8* bufPtr = GetTransactionHeader(iCurrTrans); + if(bufPtr == NULL) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine ERROR - NULL header\n")); + return KErrCorrupt; + } + TConfigSpiV01 *buf = (TConfigSpiV01 *)(bufPtr->Ptr()); + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine, header word width=0x%x\n",buf->iWordWidth)); + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine, header clock speed=0x%x\n",buf->iClkSpeedHz)); + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine, header clock mode=0x%x\n",buf->iClkMode)); + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine, header timeout period=0x%x\n",buf->iTimeoutPeriod)); + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine, header endianness=0x%x\n",buf->iEndianness)); + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine, header bit order=0x%x\n",buf->iBitOrder)); + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine, header wait cycles=0x%x\n",buf->iTransactionWaitCycles)); + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine, header Slave select pin mode=0x%x\n",buf->iSSPinActiveMode)); + (void)buf; // Silence compiler when SPI_PRINT not used + + SPI_PRINT(("\nDSimulatedIicBusChannelMasterSpi::AsynchStateMachine, iHalfDuplexTrans info \n")); + TIicBusTransfer* halfDuplexPtr=GetTransHalfDuplexTferPtr(iCurrTrans); + while(halfDuplexPtr != NULL) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine transfer type=0x%x\n",GetTferType(halfDuplexPtr))); + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine granularity=0x%x\n",GetTferBufGranularity(halfDuplexPtr))); + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine transfer buffer=0x%x\n",GetTferBuffer(halfDuplexPtr))); + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine next transfer =0x%x\n",GetTferNextTfer(halfDuplexPtr))); + halfDuplexPtr=GetTferNextTfer(halfDuplexPtr); + } + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine - End of iHalfDuplexTrans info")); + + while(IsRequestDelayed(this)) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine - starting Sleep...\n")); + NKern::Sleep(1000); // 1000 is arbitrary + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine - completed Sleep, check if still delayed\n")); + }; + + iChannelState=EIdle; + delete iCb; + break; + } + case(ETimeExpired): + { + SPI_PRINT(("Time expired, the Asynchrnous State Machine will be Idle again, and wait for the next request.")); + iChannelState=EIdle; + r = KErrTimedOut; + break; + } + default: + { + SPI_PRINT(("Request can not be handled, return error code.")); + return KErrNotSupported; + } + } + break; + } + default: + { + SPI_PRINT(("No matched state")); + return KErrGeneral; + } + } + return r; + } + + +TBool DSimulatedIicBusChannelMasterSpi::IsRequestDelayed(DSimulatedIicBusChannelMasterSpi* aChan) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::IsRequestDelayed invoked for aChan=0x%x\n",aChan)); + return aChan->iReqDelayed; + } + +void DSimulatedIicBusChannelMasterSpi::SetRequestDelayed(DSimulatedIicBusChannelMasterSpi* aChan,TBool aDelay) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::SetRequestDelayed invoked for aChan=0x%x, with aDelay=0x%d\n",aChan,aDelay)); + aChan->iReqDelayed=aDelay; + } + +TInt DSimulatedIicBusChannelMasterSpi::StaticExtension(TUint aFunction, TAny* aParam1, TAny* aParam2) + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::StaticExtension\n")); +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_MSTATEXT_START_PSL_TRACE; +#endif + (void)aParam1; + (void)aParam2; + TInt r = KErrNone; + // Test values of aFunction were shifted left one place by the (test) client driver + // and for Slave values the two msb were cleared + // Return to its original value. + if(aFunction>KTestControlIoPilOffset) + aFunction >>= 1; + switch(aFunction) + { + case(RBusDevIicClient::ECtlIoDumpChan): + { +#ifdef _DEBUG + DumpChannel(); +#endif + break; + } + case(RBusDevIicClient::ECtlIoBlockReqCompletion): + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::Blocking request completion\n")); + SetRequestDelayed(this, ETrue); + break; + } + case(RBusDevIicClient::ECtlIoUnblockReqCompletion): + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::Unlocking request completion\n")); + SetRequestDelayed(this, EFalse); + break; + } + case(RBusDevIicClient::ECtlIoDeRegChan): + { +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_DEREGISTERCHAN_START_PSL_TRACE; +#endif + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi: deregister channel\n")); +#ifndef STANDALONE_CHANNEL + r=DIicBusController::DeRegisterChannel(this); +#endif + +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_DEREGISTERCHAN_END_PSL_TRACE; +#endif + break; + } + + case(RBusDevIicClient::ECtlIoPriorityTest): + { + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi: warned to expect priority test\n")); + iPriorityTestDone = EFalse; + iTestState=ETestWaitPriorityTest; + break; + } + case(RBusDevIicClient::EGetTestResult): + { + if(!iPriorityTestDone) return KErrNotReady; + + SPI_PRINT(("DSimulatedIicBusChannelMasterSpi: get priority test order\n")); + + //iPriorityTestResult[0] is the blocking transaction, ignore it. start from entry 1. + for(TInt i=1; iChanCaptureCb(r); + } + +#ifdef STANDALONE_CHANNEL +EXPORT_C +#endif + DSimulatedIicBusChannelSlaveSpi::DSimulatedIicBusChannelSlaveSpi(const DIicBusChannel::TBusType aBusType, const DIicBusChannel::TChannelDuplex aChanDuplex) + : DIicBusChannelSlave(aBusType,aChanDuplex,0), // 0 to be ignored by base class + iSlaveTimer(SlaveAsyncSimCallback,this) + { + SPI_PRINT(("DSimulatedIicBusChannelSlaveSpi::DSimulatedIicBusChannelSlaveSpi, aBusType=%d,aChanDuplex=%d\n",aBusType,aChanDuplex)); +#ifndef STANDALONE_CHANNEL + iChannelNumber = AssignChanNum(); +#endif + SPI_PRINT(("DSimulatedIicBusChannelSlaveSpi::DSimulatedIicBusChannelSlaveSpi, iChannelNumber=%d\n",iChannelNumber)); + } + +TInt DSimulatedIicBusChannelSlaveSpi::CaptureChannelPsl(TDes8* /*aConfigHdr*/, TBool aAsynch) + { + SPI_PRINT(("DSimulatedIicBusChannelSlaveSpi::CaptureChannelPsl, aAsynch=%d\n",aAsynch)); + TInt r = KErrNone; + if(aAsynch) + { +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_SCAPTCHANASYNC_START_PSL_TRACE; +#endif + // To simulate an asynchronous operation, just set a timer to expire + iSlaveTimer.OneShot(1000, ETrue); // Arbitrary timeout - expiry executes callback in context of DfcThread1 + } + else + { +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_SCAPTCHANSYNC_START_PSL_TRACE; +#endif + // PSL processing would happen here ... + // Expected to include implementation of the header configuration information +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_SCAPTCHANSYNC_END_PSL_TRACE; +#endif + } + SPI_PRINT(("DSimulatedIicBusChannelSlaveI2c::CaptureChanSync ... no real processing to do \n")); + + return r; + } + +TInt DSimulatedIicBusChannelSlaveSpi::CheckHdr(TDes8* /*aHdr*/) + { + SPI_PRINT(("DSimulatedIicBusChannelSlaveSpi::CheckHdr\n")); + return KErrNone; + } + +TInt DSimulatedIicBusChannelSlaveSpi::DoCreate() + { + SPI_PRINT(("DSimulatedIicBusChannelSlaveSpi::DoCreate\n")); + TInt r=Init(); // PIL Base class initialisation + return r; + } + +TInt DSimulatedIicBusChannelSlaveSpi::DoRequest(TInt /*aTrigger*/) + { + SPI_PRINT(("DSimulatedIicBusChannelSlaveSpi::DoRequest\n")); + return KErrNotSupported; + } + +void DSimulatedIicBusChannelSlaveSpi::ProcessData(TInt /*aTrigger*/, TIicBusSlaveCallback* /*aCb*/) + { + SPI_PRINT(("DSimulatedIicBusChannelSlaveSpi::ProcessData\n")); + } + +TInt DSimulatedIicBusChannelSlaveSpi::StaticExtension(TUint aFunction, TAny* aParam1, TAny* aParam2) + { + SPI_PRINT(("DSimulatedIicBusChannelSlaveSpi::StaticExtension\n")); +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_SSTATEXT_START_PSL_TRACE; +#endif + (void)aParam1; + (void)aParam2; + // Test values of aFunction were shifted left one place by the (test) client driver + // and for Slave values the two msb were cleared + // Return to its original value. + if(aFunction>KTestControlIoPilOffset) + { + aFunction |= 0xC0000000; + aFunction >>= 1; + } + TInt r = KErrNone; + switch(aFunction) + { + case(RBusDevIicClient::ECtlIoDumpChan): + { +#ifdef _DEBUG + DumpChannel(); +#endif + break; + } + default: + { + Kern::Printf("aFunction %d is not recognised \n",aFunction); + r=KErrNotSupported; + } + } + +#ifdef IIC_INSTRUMENTATION_MACRO + IIC_SSTATEXT_START_PSL_TRACE; +#endif + (void)aFunction; + return r; + } + + + + + +