diff -r 2d65c2f76d7b -r 947f0dc9f7a8 kerneltest/e32test/iic/iic_psl/i2c.cpp --- a/kerneltest/e32test/iic/iic_psl/i2c.cpp Tue Feb 02 01:24:03 2010 +0200 +++ b/kerneltest/e32test/iic/iic_psl/i2c.cpp Fri Apr 16 16:24:37 2010 +0300 @@ -20,7 +20,7 @@ #include #endif - +#ifndef STANDALONE_CHANNEL #if defined(MASTER_MODE) && !defined(SLAVE_MODE) const TInt KChannelTypeArray[NUM_CHANNELS] = {DIicBusChannel::EMaster, DIicBusChannel::EMaster, DIicBusChannel::EMaster}; #elif defined(MASTER_MODE) && defined(SLAVE_MODE) @@ -30,6 +30,7 @@ #endif #define CHANNEL_TYPE(n) (KChannelTypeArray[n]) #define CHANNEL_DUPLEX(n) (DIicBusChannel::EHalfDuplex) +#endif/*STANDALONE_CHANNEL*/ #ifdef STANDALONE_CHANNEL _LIT(KPddNameI2c,"i2c_ctrless.pdd"); @@ -125,9 +126,10 @@ aDes.Copy((TUint8*)&caps,size); } +#ifndef STANDALONE_CHANNEL // supported channels for this implementation static DIicBusChannel* ChannelPtrArray[NUM_CHANNELS]; - +#endif //DECLARE_EXTENSION_WITH_PRIORITY(BUS_IMPLMENTATION_PRIORITY) DECLARE_STANDARD_PDD() // I2c test driver to be explicitly loaded as an LDD, not kernel extension @@ -439,14 +441,46 @@ void DSimulatedIicBusChannelSlaveI2c::SlaveAsyncSimCallback(TAny* aPtr) { // To support simulating an asynchronous capture operation - // NOTE: this will be invoked in the context of DfcThread1 I2C_PRINT(("SlaveAsyncSimCallback\n")); DSimulatedIicBusChannelSlaveI2c* channel = (DSimulatedIicBusChannelSlaveI2c*)aPtr; - TInt r=KErrNone;// Just simulate successful capture + + // This will be invoked in the context of DfcThread1, so require + // synchronised access to iAsyncEvent and iRxTxTrigger + // Use local variables to enable early release of the spin lock + // + // If DfcThread1 runs on a separate core to the simulated I2C bus, the other core + // will have updated values, and since this core may cached copies, memory access + // should be observed. The spin lock mechanism is expected to incorpoate this. + TInt intState=__SPIN_LOCK_IRQSAVE(channel->iEventSpinLock); + + TAsyncEvent asyncEvent = channel->iAsyncEvent; + TInt rxTxTrigger = channel->iRxTxTrigger; + channel->iAsyncEvent = ENoEvent; + channel->iRxTxTrigger = 0; + __SPIN_UNLOCK_IRQRESTORE(channel->iEventSpinLock,intState); + + switch(asyncEvent) + { + case (EAsyncChanCapture): + { + TInt r=KErrNone;// Just simulate successful capture #ifdef IIC_INSTRUMENTATION_MACRO - IIC_SCAPTCHANASYNC_END_PSL_TRACE; + IIC_SCAPTCHANASYNC_END_PSL_TRACE; #endif - channel->ChanCaptureCb(r); + channel->ChanCaptureCb(r); + break; + } + case (ERxWords): + case (ETxWords): + case (ERxTxWords): + { + channel->ChanNotifyClient(rxTxTrigger); + break; + } + default: + { + } + } } #ifdef STANDALONE_CHANNEL @@ -454,8 +488,9 @@ #endif DSimulatedIicBusChannelSlaveI2c::DSimulatedIicBusChannelSlaveI2c(const DIicBusChannel::TBusType aBusType, const DIicBusChannel::TChannelDuplex aChanDuplex) : DIicBusChannelSlave(aBusType,aChanDuplex,0), // 0 to be ignored by base class - iBlockedTrigger(0),iBlockNotification(EFalse), - iSlaveTimer(DSimulatedIicBusChannelSlaveI2c::SlaveAsyncSimCallback,this) + iBlockedTrigger(0),iBlockNotification(EFalse),iAsyncEvent(ENoEvent),iRxTxTrigger(0), + iSlaveTimer(DSimulatedIicBusChannelSlaveI2c::SlaveAsyncSimCallback,this), + iEventSpinLock(TSpinLock::EOrderGenericIrqHigh2) // Semi-arbitrary, high priority value (NTimer used) { I2C_PRINT(("DSimulatedIicBusChannelSlaveI2c::DSimulatedIicBusChannelSlaveI2c, aBusType=%d,aChanDuplex=%d\n",aBusType,aChanDuplex)); #ifndef STANDALONE_CHANNEL @@ -488,7 +523,10 @@ IIC_SCAPTCHANASYNC_START_PSL_TRACE; #endif // To simulate an asynchronous capture operation, just set a timer to expire - iSlaveTimer.OneShot(1000, ETrue); // Arbitrary timeout - expiry executes callback in context of DfcThread1 + TInt intState=__SPIN_LOCK_IRQSAVE(iEventSpinLock); + iAsyncEvent = EAsyncChanCapture; + __SPIN_UNLOCK_IRQRESTORE(iEventSpinLock,intState); + iSlaveTimer.OneShot(KI2cSlaveAsyncDelaySim, ETrue); // Arbitrary timeout - expiry executes callback in context of DfcThread1 } else { @@ -600,7 +638,7 @@ void DSimulatedIicBusChannelSlaveI2c::ProcessData(TInt aTrigger, TIicBusSlaveCallback* aCb) { - I2C_PRINT(("DSimulatedIicBusChannelSlaveI2c::ProcessData\n")); + I2C_PRINT(("DSimulatedIicBusChannelSlaveI2c::ProcessData trigger=0x%x\n",aTrigger)); // fills in iReturn, iRxWords and/or iTxWords // if(aTrigger & ERxAllBytes) @@ -631,7 +669,6 @@ iRxTxUnderOverRun&= ~ETxOverrun; } } - aCb->SetTrigger(aTrigger); } @@ -709,8 +746,13 @@ if(iBlockNotification == EFalse) { // - // Invoke DIicBusChannelSlave::NotifyClient - this will invoke ProcessData and invoke the client callback - NotifyClient(trigger); + // Use a timer for asynchronous call to NotifyClient - this will invoke ProcessData and invoke the client callback + TInt intState=__SPIN_LOCK_IRQSAVE(iEventSpinLock); + // Tx may already have been requested, to add to the existing flags set in iRxTxTrigger + iRxTxTrigger |= trigger; + iAsyncEvent = ERxWords; + __SPIN_UNLOCK_IRQRESTORE(iEventSpinLock,intState); + iSlaveTimer.OneShot(KI2cSlaveAsyncDelaySim, ETrue); // Arbitrary timeout - expiry executes callback in context of DfcThread1 } else { @@ -784,8 +826,14 @@ if(iBlockNotification == EFalse) { // - // Invoke DIicBusChannelSlave::NotifyClient - this will invoke ProcessData and invoke the client callback - NotifyClient(trigger); + // Use a timer for asynchronous call to NotifyClient - this will invoke ProcessData and invoke the client callback + TInt intState=__SPIN_LOCK_IRQSAVE(iEventSpinLock); + // Rx may already have been requested, to add to the existing flags set in iRxTxTrigger + iRxTxTrigger |= trigger; + iAsyncEvent = ETxWords; + __SPIN_UNLOCK_IRQRESTORE(iEventSpinLock,intState); + iSlaveTimer.OneShot(KI2cSlaveAsyncDelaySim, ETrue); // Arbitrary timeout - expiry executes callback in context of DfcThread1 + // No effect if OneShot already invoked } else { @@ -868,8 +916,13 @@ if(iBlockNotification == EFalse) { // - // Invoke DIicBusChannelSlave::NotifyClient - this will invoke ProcessData and invoke the client callback - NotifyClient(trigger); + // Use a timer for asynchronous call to NotifyClient - this will invoke ProcessData and invoke the client callback + TInt intState=__SPIN_LOCK_IRQSAVE(iEventSpinLock); + // Rx or Tx may already have been requested, to add to the existing flags set in iRxTxTrigger + iRxTxTrigger |= trigger; + iAsyncEvent = ERxTxWords; + __SPIN_UNLOCK_IRQRESTORE(iEventSpinLock,intState); + iSlaveTimer.OneShot(KI2cSlaveAsyncDelaySim, ETrue); // Arbitrary timeout - expiry executes callback in context of DfcThread1 } else { @@ -1035,7 +1088,7 @@ #ifndef STANDALONE_CHANNEL r=DIicBusController::DeRegisterChannel(this); #else - return KErrNotSupported; + r = KErrNotSupported; #endif break; }