Update contrib.
1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32test/iic/iic_slaveclient.cpp
15 // Simulated client of IIC Platform Independent Layer (PIL) Slave functionality
18 #include <kernel/kern_priv.h> // for DThread, TDfc
19 #ifdef STANDALONE_CHANNEL
20 #include <drivers/iic_transaction.h>
22 #include <drivers/iic.h>
26 #ifdef STANDALONE_CHANNEL
27 #include <drivers/iic_channel.h>
30 #ifdef LOG_SLAVECLIENT
31 #define CLIENT_PRINT(str) Kern::Printf str
33 #define CLIENT_PRINT(str)
36 //For channel creation
37 #ifdef STANDALONE_CHANNEL
38 #define NUM_CHANNELS 3 // Arbitrary
40 #if defined(MASTER_MODE) && !defined(SLAVE_MODE)
41 const TInt KChannelTypeArray[NUM_CHANNELS] = {DIicBusChannel::EMaster, DIicBusChannel::EMaster, DIicBusChannel::EMaster};
42 #elif defined(MASTER_MODE) && defined(SLAVE_MODE)
43 const TInt KChannelTypeArray[NUM_CHANNELS] = {DIicBusChannel::EMaster, DIicBusChannel::ESlave, DIicBusChannel::EMasterSlave};
45 const TInt KChannelTypeArray[NUM_CHANNELS] = {DIicBusChannel::ESlave, DIicBusChannel::ESlave, DIicBusChannel::ESlave};
47 #define CHANNEL_TYPE(n) (KChannelTypeArray[n])
48 #define CHANNEL_DUPLEX(n) (DIicBusChannel::EHalfDuplex)
49 #define BUS_TYPE (DIicBusChannel::EI2c)
51 #if defined(MASTER_MODE)
52 const TInt8 KI2cChannelNumBase = 10; // Arbitrary, real platform may consult the Configuration Repository
53 // Note limit of 5 bit representation (0-31)
56 const TInt8 KI2cChannelNumBase = 10 + NUM_CHANNELS; // For Slave mode, want to provide different response
57 // If client assumes Master mode, should be informed not available
60 LOCAL_C TInt8 AssignChanNumI2c()
62 static TInt8 iBaseChanNumI2c = KI2cChannelNumBase;
63 CLIENT_PRINT(("I2C AssignChanNum - on entry, iBaseChanNum = 0x%x\n",iBaseChanNumI2c));
64 return iBaseChanNumI2c++; // Arbitrary, for illustration
67 class DIicSlaveClientChan : public DBase
70 DIicSlaveClientChan(DIicBusChannel* aChan, TInt8 aChanNum, TInt aChanType):iChan(aChan),iChanNumber(aChanNum),iChanType(aChanType){};
71 ~DIicSlaveClientChan();
72 TInt GetChanNum()const {return iChanNumber;};
73 TInt GetChanType()const {return iChanType;};
74 DIicBusChannel* GetChannelPtr(){return iChan;};
78 DIicBusChannel* iChan;
81 DIicSlaveClientChan::~DIicSlaveClientChan()
87 #endif/*STANDALONE_CHANNEL*/
89 const TInt KIicSlaveClientThreadPriority = 24;
91 const TInt KIicSlaveClientDfcPriority = 3; // 0 to 7, 7 is highest
93 const TInt KMaxNumChannels = 2; // 1 "true" slave, one "dummy"
95 #ifdef STANDALONE_CHANNEL
96 _LIT(KLddRootName,"iic_slaveclient_ctrless");
98 _LIT(KLddRootName,"iic_slaveclient");
100 _LIT(KIicSlaveClientThreadName,"IicSlaveClientLddThread");
103 struct TCapsIicSlaveClient
109 class DDeviceIicSlaveClient : public DLogicalDevice
115 DDeviceIicSlaveClient();
119 ~DDeviceIicSlaveClient();
121 * Second stage constructor - install the device
123 virtual TInt Install();
125 * Get the Capabilites of the device
126 * @param aDes descriptor that will contain the returned capibilites
128 virtual void GetCaps(TDes8 &aDes) const;
130 * Create a logical channel to the device
132 virtual TInt Create(DLogicalChannelBase*& aChannel);
136 class DChannelIicSlaveClient : public DLogicalChannel
139 DChannelIicSlaveClient();
140 ~DChannelIicSlaveClient();
142 virtual TInt DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer);
144 void RequestComplete(TInt r);
145 TInt CheckDataWritten();
146 TInt CheckDataRead();
148 static void SlaveClientCallbackFunc(TInt aChannelId, TInt aReturn, TInt aTrigger, TInt16 aRxWords, TInt16 aTxWords, TAny* aParam);
149 #ifdef STANDALONE_CHANNEL
150 static TInt OrderEntries(const DIicSlaveClientChan& aMatch, const DIicSlaveClientChan& aEntry);
153 virtual void HandleMsg(TMessageBase* aMsg); // Note: this is a pure virtual in DLogicalChannel
155 TInt DoControl(TInt aId, TAny* a1, TAny* a2); // Name for convenience!
156 TInt DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2); // Name for convenience!
159 TInt InitSlaveClient();
160 TInt CbProcessOverUnderRunRxTx();
161 TInt RegisterRxBuffer(TInt aChannelId, TPtr8 aRxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset);
162 TInt SetNotificationTrigger(TInt aChannelId, TInt aTrigger);
163 TInt StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2);
164 TInt RegisterTxBuffer(TInt aChannelId, TPtr8 aTxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset);
165 TInt CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch=NULL);
166 TInt ReleaseChannel(TInt aChannelId);
168 TDynamicDfcQue* iDfcQue;
169 TIicBusSlaveCallback* iNotif;
172 TRequestStatus* iStatus;
177 TUint8* iBusTxCheckBuf;
179 TInt8 iNumRegRxWords;
180 TInt8 iNumRegTxWords;
182 TInt8 iTxRegGranularity;
184 TInt8 iTxReqNumWords;
186 TInt8 iRxRegGranularity;
188 TInt8 iRxReqNumWords;
191 #ifdef STANDALONE_CHANNEL
192 // For some slave-channel-only functions,e.g. ReleaseChannel, RegisterRxBuffer, etc.
193 // the client needs to remember the slave channel that has been captured
194 struct TCapturedChannel
196 DIicSlaveClientChan* iChannel;
199 TCapturedChannel iCapturedChan;
203 TInt iChannelId; // public to be accessible by callback
206 TInt iExpectedTrigger;
208 TInt iBlockedTrigger;
210 typedef enum TTestOverUnderState
218 TTestOverUnderState iTestOverUnderState;
221 DDeviceIicSlaveClient::DDeviceIicSlaveClient()
224 CLIENT_PRINT(("> DDeviceIicSlaveClient::DDeviceIicSlaveClient()"));
225 iParseMask=0; // No info, no PDD, no Units
227 iVersion=TVersion(KIicClientMajorVersionNumber,
228 KIicClientMinorVersionNumber,
229 KIicClientBuildVersionNumber);
232 #ifdef STANDALONE_CHANNEL
233 //Store all the channels created by the client into an array
234 RPointerArray<DIicSlaveClientChan> ChannelArray;
236 DDeviceIicSlaveClient::~DDeviceIicSlaveClient()
239 CLIENT_PRINT(("> DDeviceIicSlaveClient::~DDeviceIicSlaveClient()"));
240 #ifdef STANDALONE_CHANNEL
241 //The client is reponsible for channel destroy in STANDALONE_CHANNEL mode
242 ChannelArray.ResetAndDestroy();
246 TInt DDeviceIicSlaveClient::Install()
247 // Install the device driver.
249 CLIENT_PRINT(("> DDeviceIicSlaveClient::Install()"));
251 return(SetName(&KLddRootName));
255 void DDeviceIicSlaveClient::GetCaps(TDes8& aDes) const
256 // Return the IicClient capabilities.
258 CLIENT_PRINT(("> DDeviceIicSlaveClient::GetCaps(TDes8& aDes) const"));
259 TPckgBuf<TCapsIicSlaveClient> b;
260 b().version=TVersion(KIicClientMajorVersionNumber,
261 KIicClientMinorVersionNumber,
262 KIicClientBuildVersionNumber);
263 Kern::InfoCopy(aDes,b);
267 TInt DDeviceIicSlaveClient::Create(DLogicalChannelBase*& aChannel)
268 // Create a channel on the device.
270 CLIENT_PRINT(("> DDeviceIicSlaveClient::Create(DLogicalChannelBase*& aChannel)"));
271 if(iOpenChannels>=KMaxNumChannels)
273 aChannel=new DChannelIicSlaveClient;
274 return aChannel?KErrNone:KErrNoMemory;
277 #ifdef STANDALONE_CHANNEL
278 // auxiliary function for ordering entries in the array of channels
279 TInt DChannelIicSlaveClient::OrderEntries(const DIicSlaveClientChan& aMatch, const DIicSlaveClientChan& aEntry)
281 TUint8 l=(TUint8)aMatch.GetChanNum();
282 TUint8 r=(TUint8)aEntry.GetChanNum();
291 // global ordering object to be passed to RPointerArray InsertInOrderXXX and FindInOrder
292 TLinearOrder<DIicSlaveClientChan> EntryOrder(DChannelIicSlaveClient::OrderEntries);
294 TInt GetChanPtr(const TInt aBusId, DIicSlaveClientChan*& aChan)
296 __KTRACE_OPT(KIIC, Kern::Printf("GetChanPtr, aBusId=0x%x\n",aBusId));
298 chanId = GET_CHAN_NUM(aBusId);
299 __KTRACE_OPT(KIIC, Kern::Printf("GetChanPtr, chanId=0x%x\n",chanId));
300 DIicSlaveClientChan chanEntry(NULL,(TInt8)chanId, DIicBusChannel::EMasterSlave);
302 TInt r = KErrNotFound;
303 TInt aIndex = ChannelArray.FindInOrder(&chanEntry, EntryOrder);
307 aChan = ChannelArray[aIndex];
313 #endif/*STANDALONE_CHANNEL*/
315 DECLARE_STANDARD_LDD()
317 #ifdef STANDALONE_CHANNEL
319 DIicBusChannel *chan = NULL, *chanM = NULL, *chanS = NULL;
320 DIicSlaveClientChan* aSlaveClientChan;
321 for(TInt i=0; i<NUM_CHANNELS; i++)
323 CLIENT_PRINT(("\n"));
324 #if defined(MASTER_MODE)
325 if(CHANNEL_TYPE(i) == (DIicBusChannel::EMaster))
327 chan=new DSimulatedIicBusChannelMasterI2c(BUS_TYPE,CHANNEL_DUPLEX(i));
330 CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE(i),i));
333 CLIENT_PRINT(("I2C chan created at 0x%x\n",chan));
334 if(((DSimulatedIicBusChannelMasterI2c*)chan)->Create()!=KErrNone)
339 aSlaveClientChan = new DIicSlaveClientChan(chan,AssignChanNumI2c(),DIicBusChannel::EMaster);
340 if(!aSlaveClientChan)
345 r = ChannelArray.InsertInOrder(aSlaveClientChan,EntryOrder);
349 delete aSlaveClientChan;
354 #if defined(MASTER_MODE) && defined(SLAVE_MODE)
355 if(CHANNEL_TYPE(i) == DIicBusChannel::EMasterSlave)
357 chanM=new DSimulatedIicBusChannelMasterI2c(BUS_TYPE,CHANNEL_DUPLEX(i));
360 chanS=new DSimulatedIicBusChannelSlaveI2c(BUS_TYPE,CHANNEL_DUPLEX(i));
366 chan=new DSimulatedIicBusChannelMasterSlaveI2c(BUS_TYPE,CHANNEL_DUPLEX(i),(DSimulatedIicBusChannelMasterI2c*)chanM,(DSimulatedIicBusChannelSlaveI2c*)chanS); // Generic implementation
369 CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE(i),i));
374 CLIENT_PRINT(("I2C chan created at 0x%x\n",chan));
375 if(((DIicBusChannelMasterSlave*)chan)->DoCreate()!=KErrNone)
382 aSlaveClientChan = new DIicSlaveClientChan(chan,AssignChanNumI2c(),DIicBusChannel::EMasterSlave);
383 if(!aSlaveClientChan)
390 r = ChannelArray.InsertInOrder(aSlaveClientChan,EntryOrder);
396 delete aSlaveClientChan;
401 #if defined(SLAVE_MODE)
402 if(CHANNEL_TYPE(i) == (DIicBusChannel::ESlave))
404 chan=new DSimulatedIicBusChannelSlaveI2c(BUS_TYPE,CHANNEL_DUPLEX(i));
407 CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE(i),i));
410 CLIENT_PRINT(("I2C chan created at 0x%x\n",chan));
411 if(((DSimulatedIicBusChannelSlaveI2c*)chan)->Create()!=KErrNone)
413 aSlaveClientChan = new DIicSlaveClientChan(chan,AssignChanNumI2c(),DIicBusChannel::ESlave);
414 if(!aSlaveClientChan)
419 r = ChannelArray.InsertInOrder(aSlaveClientChan,EntryOrder);
423 delete aSlaveClientChan;
428 #if !defined(MASTER_MODE) && !defined(SLAVE_MODE)
429 #error I2C mode not defined as Master, Slave nor Master-Slave
433 return new DDeviceIicSlaveClient;
438 DChannelIicSlaveClient::DChannelIicSlaveClient()
441 iFullDuplexReq=iBlockedTrigger=iExpectedTrigger=0;
442 CLIENT_PRINT(("> DChannelIicSlaveClient::DChannelIicSlaveClient()"));
443 iClient=&Kern::CurrentThread();
444 // Increase the DThread's ref count so that it does not close without us
446 iTestOverUnderState = EStartState;
449 DChannelIicSlaveClient::~DChannelIicSlaveClient()
452 CLIENT_PRINT(("> DChannelIicSlaveClient::~DChannelIicSlaveClient()"));
457 delete iBusTxCheckBuf;
458 // decrement the DThread's reference count
459 Kern::SafeClose((DObject*&)iClient, NULL);
462 void DChannelIicSlaveClient::RequestComplete(TInt r)
464 Kern::RequestComplete(iClient, iStatus, r);
467 TInt DChannelIicSlaveClient::RegisterRxBuffer(TInt aChannelId, TPtr8 aRxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
470 #ifdef STANDALONE_CHANNEL
471 DIicSlaveClientChan* aChanPtr = NULL;
472 if(iCapturedChan.iChannelId == aChannelId)
473 aChanPtr = iCapturedChan.iChannel;
476 if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave)
477 r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->RegisterRxBuffer(aRxBuffer, aBufGranularity, aNumWords, aOffset);
478 else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave)
479 r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->RegisterRxBuffer(aRxBuffer, aBufGranularity, aNumWords, aOffset);
481 r = IicBus::RegisterRxBuffer(aChannelId, aRxBuffer, aBufGranularity, aNumWords, aOffset);
486 TInt DChannelIicSlaveClient::SetNotificationTrigger(TInt aChannelId, TInt aTrigger)
489 #ifdef STANDALONE_CHANNEL
490 DIicSlaveClientChan* aChanPtr = NULL;
491 if(iCapturedChan.iChannelId == aChannelId)
492 aChanPtr = iCapturedChan.iChannel;
495 if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave)
496 r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->SetNotificationTrigger(aTrigger);
497 else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave)
498 r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->SetNotificationTrigger(aTrigger);
500 r = IicBus::SetNotificationTrigger(aChannelId, aTrigger);
505 TInt DChannelIicSlaveClient::StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2)
508 #ifdef STANDALONE_CHANNEL
509 DIicSlaveClientChan* aChanPtr;
510 r = GetChanPtr(aId, aChanPtr);
515 if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave)
516 r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->StaticExtension(aFunction, aParam1, aParam2);
517 else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave)
518 r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->StaticExtension(aFunction, aParam1, aParam2);
520 r = IicBus::StaticExtension(aId, aFunction, aParam1, aParam2);
525 TInt DChannelIicSlaveClient::RegisterTxBuffer(TInt aChannelId, TPtr8 aTxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
528 #ifdef STANDALONE_CHANNEL
529 DIicSlaveClientChan* aChanPtr = NULL;
530 if(iCapturedChan.iChannelId == aChannelId)
531 aChanPtr = iCapturedChan.iChannel;
534 if(aChanPtr->GetChanType() == DIicBusChannel::EMasterSlave)
535 r = ((DIicBusChannelMasterSlave*)(aChanPtr->GetChannelPtr()))->RegisterTxBuffer(aTxBuffer, aBufGranularity, aNumWords, aOffset);
536 else if(aChanPtr->GetChanType() == DIicBusChannel::ESlave)
537 r = ((DIicBusChannelSlave*)(aChanPtr->GetChannelPtr()))->RegisterTxBuffer(aTxBuffer, aBufGranularity, aNumWords, aOffset);
539 r = IicBus::RegisterTxBuffer(aChannelId, aTxBuffer, aBufGranularity, aNumWords, aOffset);
544 TInt DChannelIicSlaveClient::CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch)
547 #ifndef STANDALONE_CHANNEL
548 r = IicBus::CaptureChannel(aBusId, aConfigHdr, aCallback, aChannelId, aAsynch);
550 // Check that that aCallback!=NULL and aConfigHdr!=NULL - if not, return KErrArgument
551 if(!aCallback || !aConfigHdr)
557 DIicSlaveClientChan* chanPtr = NULL;
560 r = GetChanPtr(aBusId, chanPtr);
569 switch(chanPtr->GetChanType())
571 // CaptureChannel requests are only supported by channels in Slave mode.
572 case DIicBusChannel::EMaster:
574 r = KErrNotSupported;
577 case DIicBusChannel::EMasterSlave:
579 r = ((DIicBusChannelMasterSlave*) (chanPtr->GetChannelPtr()))->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch);
582 case DIicBusChannel::ESlave:
584 r = ((DIicBusChannelSlave*) (chanPtr->GetChannelPtr()))->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch);
592 // For synchronous capture, if successful then install the channel
597 iCapturedChan.iChannel = chanPtr;
598 iCapturedChan.iChannelId = aChannelId;
601 //For asynchronous capture, record slaveChanPtr, if later failed capture,
602 //clean iCapturedChannel in client's callback.
603 iCapturedChan.iChannel = chanPtr;
612 TInt DChannelIicSlaveClient::ReleaseChannel(TInt aChannelId)
615 #ifndef STANDALONE_CHANNEL
616 r = IicBus::ReleaseChannel(aChannelId);
618 __KTRACE_OPT(KIIC, Kern::Printf("DChannelIicSlaveClient::ReleaseChannel, channelID = 0x%x \n",aChannelId));
619 // Acquire the pointer to the Slave Channel
620 if(iCapturedChan.iChannelId != aChannelId)
623 if((iCapturedChan.iChannel)->GetChanType() == DIicBusChannel::EMasterSlave)
624 r = ((DIicBusChannelMasterSlave*)((iCapturedChan.iChannel)->GetChannelPtr()))->ReleaseChannel();
625 else if((iCapturedChan.iChannel)->GetChanType() == DIicBusChannel::ESlave)
626 r = ((DIicBusChannelSlave*)((iCapturedChan.iChannel)->GetChannelPtr()))->ReleaseChannel();
627 //After release channel, reset iCapturedChan
628 iCapturedChan.iChannel = NULL;
629 iCapturedChan.iChannelId = 0;
633 TInt DChannelIicSlaveClient::CbProcessOverUnderRunRxTx()
635 CLIENT_PRINT(("> DChannelIicSlaveClient::CbProcessOverUnderRunRxTx(), iTestOverUnderState=%d\n",iTestOverUnderState));
637 switch (iTestOverUnderState)
641 // In this state, no action is required
646 CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ERxOverrun_1\n"));
647 // At this point, the outstanding request trigger should be ETxAllBytes | ETxUnderrun
648 // and the flag to indicate duplex transfers should be cleared
649 if((iExpectedTrigger != (ETxAllBytes | ETxUnderrun)) || (iFullDuplexReq != ETxAllBytes))
651 CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq));
656 // Simulate providing a new buffer (actually, re-use existing buffer)
657 CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterRxBuffer\n"));
658 TPtr8 rxPtr(iRxBuf,KRxBufSizeInBytes);
659 r = RegisterRxBuffer(iChannelId, rxPtr, iRxRegGranularity, iNumRegRxWords, iRxRegOffset);
663 CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterRxBuffer returned %d\n",r));
667 // For the next step, just specify the new Rx triggers (do not specify Tx triggers)
668 r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun));
671 CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d\n",r));
675 iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun;
676 iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
677 iTestOverUnderState = ERxOverrun_2; // Prepare for callback
678 // The requested number of words when the buffer was registered was 8, so simulate 10
679 // to provoke an RxOverrun event.
681 // To support testing, any values of aId for StaticExtension must be shifted left one place
682 // and for a Slave, the two msbs must be zero
683 TInt ctrlIoVal = RBusDevIicClient::ECtrlIoRxWords;
684 ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
685 r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords);
693 CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ERxOverrun_2\n"));
694 // At this point, the outstanding request trigger should be ETxAllBytes | ETxUnderrun
695 // and the flag to indicate duplex transfers should be cleared
696 if((iExpectedTrigger != (ETxAllBytes | ETxUnderrun)) || (iFullDuplexReq != ETxAllBytes))
698 CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq));
703 // Simulate providing a new buffer (actually, re-use existing buffer)
704 CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterRxBuffer\n"));
705 TPtr8 rxPtr(iRxBuf,KRxBufSizeInBytes);
706 r = RegisterRxBuffer(iChannelId, rxPtr, iRxRegGranularity, iNumRegRxWords, iRxRegOffset);
709 CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterRxBuffer returned %d\n",r));
713 // Test that an attempt to modify existing Tx notification requests is rejected
714 r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxOverrun));
717 CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrInUse\n",r));
721 // For the next step, specify the new Rx triggers and the Tx triggers
722 r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun));
725 CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrNone\n",r));
729 iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun;
730 iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
731 iTestOverUnderState = ETxUnderrun_1; // Prepare for callback
732 // The requested number of words when the buffer was registered was 12, so simulate 14
733 // to provoke an TxUnderrun event.
735 // To support testing, any values of aId for StaticExtension must be shifted left one place
736 // and for a Slave, the two msbs must be zero
737 TInt ctrlIoVal = RBusDevIicClient::ECtrlIoTxWords;
738 ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
739 r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords);
748 CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ETxOverrun_1\n"));
749 // At this point, the outstanding request trigger should be ERxAllBytes | ERxOverrun
750 // and the flag to indicate duplex transfers should be cleared
751 if((iExpectedTrigger != (ERxAllBytes | ERxOverrun)) || (iFullDuplexReq != ERxAllBytes))
753 CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq));
758 // Simulate providing a new buffer (actually, re-use existing buffer)
759 CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterTxBuffer\n"));
760 TPtr8 rxPtr(iTxBuf,KTxBufSizeInBytes);
761 r = RegisterTxBuffer(iChannelId, rxPtr, iTxRegGranularity, iNumRegTxWords, iTxRegOffset);
764 CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterTxBuffer returned %d\n",r));
768 // For the next step, just specify the new Tx triggers (do not specify Rx triggers)
769 r = SetNotificationTrigger(iChannelId, (ETxAllBytes | ETxUnderrun));
772 CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d\n",r));
776 iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun;
777 iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
778 iTestOverUnderState = ETxUnderrun_2; // Prepare for callback
779 // The requested number of words when the buffer was registered was 12, so simulate 14
780 // to provoke an TxUnderrun event.
782 // To support testing, any values of aId for StaticExtension must be shifted left one place
783 // and for a Slave, the two msbs must be zero
784 TInt ctrlIoVal = RBusDevIicClient::ECtrlIoTxWords;
785 ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
786 r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords);
794 CLIENT_PRINT(("CbProcessOverUnderRunRxTx: entry state = ETxUnderrun_2\n"));
795 // At this point, the outstanding request trigger should be ERxAllBytes | ERxOverrun
796 // and the flag to indicate duplex transfers should be cleared
797 if((iExpectedTrigger != (ERxAllBytes | ERxOverrun)) || (iFullDuplexReq != ERxAllBytes))
799 CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx, iExpectedTrigger=0x%x, iFullDuplexReq=%d\n",iExpectedTrigger,iFullDuplexReq));
804 // Simulate providing a new buffer (actually, re-use existing buffer)
805 CLIENT_PRINT(("CbProcessOverUnderRunRxTx: invoking RegisterRxBuffer\n"));
806 TPtr8 rxPtr(iTxBuf,KTxBufSizeInBytes);
807 r = RegisterTxBuffer(iChannelId, rxPtr, iTxRegGranularity, iNumRegTxWords, iTxRegOffset);
810 CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - RegisterTxBuffer returned %d\n",r));
814 // Test that an attempt to modify existing Rx notification requests is rejected
815 r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxUnderrun | ETxAllBytes | ETxUnderrun));
818 CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrInUse\n",r));
822 // For the next step, specify the new Rx triggers and the Tx triggers
823 r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun));
827 CLIENT_PRINT(("Error: CbProcessOverUnderRunRxTx - SetNotificationTrigger returned %d, expected KErrNone\n",r));
831 // Simulate a simultaneous ERxAllBytes and ETxAllBytes event.
832 iExpectedTrigger = ERxAllBytes | ETxAllBytes;
833 iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
834 iTestOverUnderState = EStartState; // Prepare for callback - return to normal operation
835 // Need to pass the number of words in an array, for use by StaticExtension
837 parms[0]= 8; // Number of Rx Words
838 parms[1]=12; // Number of Tx Words
839 // To support testing, any values of aId for StaticExtension must be shifted left one place
840 // and for a Slave, the two msbs must be zero
841 TInt ctrlIoVal = RBusDevIicClient::ECtrlIoRxTxWords;
842 ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
843 r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)(&parms[0]));
859 void DChannelIicSlaveClient::SlaveClientCallbackFunc(TInt aChannelId, TInt aReturn, TInt aTrigger, TInt16 aRxWords, TInt16 aTxWords, TAny* aParam)
861 CLIENT_PRINT(("> SlaveClientCallbackFunc() - aChannelId=0x%x,aReturn=%d,aTrigger=0x%x,aRxWords=0x%x,aTxWords=0x%x,aParam=0x%x\n",aChannelId,aReturn,aTrigger,aRxWords,aTxWords,aParam));
862 (void)aTxWords; // Unused if CLIENT_PRINT is undefined
863 (void)aRxWords; // Unused if CLIENT_PRINT is undefined
864 DChannelIicSlaveClient* channel = (DChannelIicSlaveClient*)aParam;
866 // Ensure only the valid bits of aTrigger are processed
869 CLIENT_PRINT(("SlaveClientCallbackFunc() - channel=0x%x\n",channel));
870 if(aTrigger == EAsyncCaptChan)
872 CLIENT_PRINT(("SlaveClientCallbackFunc: capture channel completed\n"));
873 // Set iChannelId, and write to user-side variable.
874 channel->iChannelId=aChannelId;
875 TInt r=Kern::ThreadRawWrite(channel->iClient,channel->iClientChanId,&aChannelId,sizeof(TInt));
878 #ifdef STANDALONE_CHANNEL
879 // Set the captured channel's iChannelId if the capture succeeds.
880 if(r != KErrCompletion)
881 (channel->iCapturedChan).iChannel = NULL;
883 (channel->iCapturedChan).iChannelId = aChannelId;
884 #endif/*STANDALONE_CHANNEL*/
885 channel->RequestComplete(r); // Inform user of error
890 if(aTrigger&ERxAllBytes)
892 CLIENT_PRINT(("SlaveClientCallbackFunc() - ERxAllBytes\n"));
893 aTrigger&= ~ERxAllBytes;
894 channel->iExpectedTrigger&=~ERxAllBytes;
895 channel->iFullDuplexReq&=~ERxAllBytes;
896 aReturn=channel->CheckDataRead();
898 if(aTrigger&ERxUnderrun)
900 if(channel->iExpectedTrigger&ERxUnderrun)
902 CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxUnderrun found OK\n\n"));
903 channel->iExpectedTrigger&=~ERxUnderrun;
907 CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ERxUnderrun indicated\n\n"));
908 aReturn = KErrGeneral;
913 if(channel->iExpectedTrigger&ERxUnderrun)
915 CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxUnderrun not (yet) seen\n\n"));
916 aReturn = KErrGeneral;
920 if(aTrigger&ERxOverrun)
922 if(channel->iExpectedTrigger&ERxOverrun)
924 CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxOverrun found OK\n\n"));
925 channel->iExpectedTrigger&=~ERxOverrun;
929 CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ERxOverrun indicated\n\n"));
930 aReturn = KErrGeneral;
935 if(channel->iExpectedTrigger&ERxOverrun)
937 CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ERxOverrun not (yet) seen\n\n"));
938 aReturn = KErrGeneral;
943 if(aTrigger&ETxAllBytes)
945 CLIENT_PRINT(("SlaveClientCallbackFunc() - ETxAllBytes\n"));
946 aTrigger&= ~ETxAllBytes;
947 channel->iExpectedTrigger&=~ETxAllBytes;
948 channel->iFullDuplexReq&=~ETxAllBytes;
949 aReturn=channel->CheckDataWritten();
951 if(aTrigger&ETxUnderrun)
953 if(channel->iExpectedTrigger&ETxUnderrun)
955 CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxUnderrun found OK\n\n"));
956 channel->iExpectedTrigger&=~ETxUnderrun;
960 CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ETxUnderrun indicated\n\n"));
961 aReturn = KErrGeneral;
966 if(channel->iExpectedTrigger&ETxUnderrun)
968 CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxUnderrun not (yet) seen\n\n"));
969 aReturn = KErrGeneral;
973 if(aTrigger&ETxOverrun)
975 if(channel->iExpectedTrigger&ETxOverrun)
977 CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxOverrun found OK\n\n"));
978 channel->iExpectedTrigger&=~ETxOverrun;
982 CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected ETxOverrun indicated\n\n"));
983 aReturn = KErrGeneral;
988 if(channel->iExpectedTrigger&ETxOverrun)
990 CLIENT_PRINT(("\nSlaveClientCallbackFunc() - expected ETxOverrun not (yet) seen\n\n"));
991 aReturn = KErrGeneral;
997 if(aTrigger&EGeneralBusError)
999 if(channel->iExpectedTrigger&EGeneralBusError)
1001 CLIENT_PRINT(("\nSlaveClientCallbackFunc: EGeneralBusError - as expected\n\n"));
1002 channel->iExpectedTrigger&=~EGeneralBusError;
1003 if(aReturn == KErrGeneral)
1005 aReturn=KErrNone; // If aReturn==KErrGeneral, set to KErrNone so t_iic knows test was successful
1006 channel->iFullDuplexReq = 0; // The transaction is considered terminated, so don't wait for more triggers
1010 CLIENT_PRINT(("\nSlaveClientCallbackFunc: aReturn not EGeneralBusError, =0x%x \n\n",aReturn));
1011 aReturn=KErrGeneral;
1017 CLIENT_PRINT(("\nSlaveClientCallbackFunc() - unexpected EGeneralBusError indicated\n\n"));
1018 aReturn = KErrGeneral;
1022 if((aTrigger < 0)||(aTrigger & (~0xFF)))
1024 CLIENT_PRINT(("\nSlaveClientCallbackFunc: trigger condition 0x%x is not recognised \n\n",aTrigger));
1027 // For simulataneous Rx,Tx triggers with ERxOverrun or TxUnderrun testing, need to call the following
1028 if(aReturn == KErrNone)
1030 aReturn = channel->CbProcessOverUnderRunRxTx();
1033 if((channel->iExpectedTrigger == 0)&&(channel->iFullDuplexReq == 0))
1034 channel->RequestComplete(aReturn); // Complete user-side request only if all the triggers have been satisfied
1036 } // if(aTrigger == EAsyncCaptChan)
1040 TInt DChannelIicSlaveClient::CheckDataRead()
1043 // This channel will have provided a buffer for writing to, with a specified offset and number of words
1044 // Bytes in the buffer before the offset should be set to zero
1045 // Bytes written at and beyond the offset should exhibit an incrementing count
1046 // Bytes beyond the offset that were not written to should be set to zero
1047 TInt8 numWords=(iRxReqNumWords>iNumRegRxWords)?iNumRegRxWords:iRxReqNumWords;
1050 while(index<iRxRegOffset)
1052 currVal=*(iRxBuf+index);
1055 CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataRead, index=%d, value =0x%x, expected 0",index,currVal));
1061 TInt8 checkVal=0x10; // first value written by simulated bus channel
1062 TInt8 endOfData= (TInt8)(iRxRegOffset+(numWords*iRxRegGranularity));
1064 while(index<endOfData)
1066 currVal = *(iRxBuf+index);
1067 if(checkVal != currVal)
1069 CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataRead, index=%d, value =0x%x, expected 0x%x",index,currVal,checkVal));
1072 if(++wordCount == iRxRegGranularity)
1080 while(index<KRxBufSizeInBytes)
1082 currVal=*(iRxBuf+index);
1085 CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataRead, index=%d, value =0x%x, expected 0",index,currVal);)
1094 TInt DChannelIicSlaveClient::CheckDataWritten()
1097 // The pattern in the transmit buffer used by the simulated bus channel contains a incrementing count
1098 // from 0 to (KTxBufSizeInBytes-1), therefore the first value to be present in the check buffer will be
1099 // represented by the required offset.
1101 // The bytes "transmitted" are stored in the simulated bus' iTxCheckBuf
1102 // Since the simulated bus channel is also in the kernel process it shares the same address space
1103 // Get the address of the buffer
1104 TUint testId = (((TUint)(RBusDevIicClient::ECtrlIoTxChkBuf))<<1)&0x3FFFFFFF;
1105 CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataWritten invoking StaticExtension ECtrlIoTxChkBuf with iBusId=0x%x, testId=0x%x, iBusTxCheckBuf=0x%x\n",iBusId,testId,iBusTxCheckBuf));
1106 r = StaticExtension(iBusId, testId, &iBusTxCheckBuf, NULL);
1109 CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataWritten StaticExtension ECtrlIoTxChkBuf returned %d\n",r));
1113 // Check that the values in the check buffer increment for the
1114 // required number of words, and that any remaining bytes in the check buffer are set to zero.
1115 TInt8 firstValue = iTxRegOffset;
1117 TInt8 wordsWritten = 0;
1118 wordsWritten=(iTxReqNumWords>iNumRegTxWords)?iNumRegTxWords:iTxReqNumWords;
1120 while(index<(wordsWritten*iTxRegGranularity))
1122 currVal=*(iBusTxCheckBuf+index);
1123 if(currVal != (TInt8)(firstValue+index))
1125 CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataWritten, index=%d, value =0x%x, expected 0x%x",index,currVal,(TInt8)(firstValue+index)));
1130 while(index<(iNumRegTxWords*iTxRegGranularity))
1132 currVal=*(iBusTxCheckBuf+index);
1135 CLIENT_PRINT(("DChannelIicSlaveClient::CheckDataWritten, index=%d, value =0x%x, expected 0",index,currVal));
1144 TInt DChannelIicSlaveClient::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
1146 CLIENT_PRINT(("> DChannelIicSlaveClient::DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion &aVer)"));
1148 TInt r = Kern::DynamicDfcQCreate(iDfcQue,KIicSlaveClientThreadPriority,KIicSlaveClientThreadName);
1153 // Allocate buffers for Rx, Tx operations
1154 iRxBuf = new TUint8[KRxBufSizeInBytes];
1155 iTxBuf = new TUint8[KTxBufSizeInBytes];
1156 if((iRxBuf == NULL)||(iTxBuf == NULL))
1157 return KErrNoMemory;
1158 // Start receiving messages
1164 TInt DChannelIicSlaveClient::InitSlaveClient()
1166 iNotif = new TIicBusSlaveCallback(DChannelIicSlaveClient::SlaveClientCallbackFunc, (TAny*)this, iDfcQue, KIicSlaveClientDfcPriority);
1169 CLIENT_PRINT(("> DChannelIicSlaveClient::InitSlaveClient ERROR unable to allocate space TIicBusSlaveCallback* iNotif \n"));
1170 return KErrNoMemory;
1175 void DChannelIicSlaveClient::HandleMsg(TMessageBase* aMsg)
1177 TThreadMessage& m=*(TThreadMessage*)aMsg;
1180 CLIENT_PRINT((" >ldd: DChannelIicSlaveClient::HandleMsg(TMessageBase* aMsg) id=%d\n", id));
1182 if (id == (TInt)ECloseMsg)
1184 iMsgQ.iMessage->Complete(KErrNone,EFalse);
1190 TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
1191 TInt r=DoRequest(~id, pS, m.Ptr1(), m.Ptr2());
1194 Kern::RequestComplete(iClient, pS, r);
1196 m.Complete(KErrNone,ETrue);
1199 if((id>=0)&&(id!=KMaxTInt))
1201 TInt r=DoControl(id,m.Ptr0(),m.Ptr1());
1202 m.Complete(r,ETrue);
1207 TInt DChannelIicSlaveClient::DoControl(TInt aId, TAny* a1, TAny* a2)
1209 CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoked with aId=0x%x, a1=0x%x, a2=0x%x\n", aId,a1,a2));
1211 // To support testing, any values of aId for StaticExtension must be shifted left one place
1212 // and for a Slave, the two msbs must be zero
1214 if((aId & KTestSlaveControlIo) == KTestSlaveControlIo)
1215 ctrlIoVal = (aId << 1) & 0x3FFFFFFF;
1219 case(RBusDevIicClient::EInitSlaveClient):
1221 r=InitSlaveClient();
1225 case(RBusDevIicClient::ECaptureChanSync):
1227 // a1 is a pointer to the TDes8* aConfigHdr
1228 // a2 is a pointer to TInt* parms[2], where:
1229 // parms[0]=(TInt*)aBusId;
1230 // parms[1]=&aChannelId;
1233 r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt*));
1235 break; // Can't proceed if can't access request parameters
1237 TInt hdrSize = Kern::ThreadGetDesLength(iClient,a1);
1238 CLIENT_PRINT(("DChannelIicSlaveClient::DoControl hdrSize = 0x%x\n",hdrSize));
1241 CLIENT_PRINT(("DChannelIicSlaveClient::DoControl ERROR, hdrSize is invalid\n"));
1245 if((iConfigHdr = HBuf8::New(hdrSize)) == NULL)
1246 return KErrNoMemory;
1247 r = Kern::ThreadDesRead(iClient,a1,*iConfigHdr,0);
1253 // Store the address of the user-side variable to update with the ChannelId
1254 iClientChanId=parms[1];
1256 CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking (synchronous) CaptureChannel\n"));
1257 r = CaptureChannel((TInt)(parms[0]), iConfigHdr, iNotif, iChannelId);
1263 CLIENT_PRINT(("DChannelIicSlaveClient::DoControl CaptureChannelgave iChannelId=0x%x\n",iChannelId));
1265 r = Kern::ThreadRawWrite(iClient,iClientChanId,&iChannelId,sizeof(TInt));
1271 case(RBusDevIicClient::EReleaseChan):
1273 // a1 represents TInt aChannelId
1274 CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking ReleaseChannel\n"));
1275 r = ReleaseChannel((TInt)a1);
1280 case(RBusDevIicClient::ERegisterRxBuffer):
1282 // a1 represents TInt aChannelId
1283 // a2 represents (TAny*) of TInt8 parms[3] where parms[0]=aBufGranularity; parms[1]=aNumWords; parms[2]=aOffset
1285 r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),3*sizeof(TInt8));
1287 break; // Can't proceed if can't access request parameters
1288 // Store parameters for checking in the callback
1289 iRxRegGranularity = parms[0];
1290 iRxRegOffset= parms[2];
1291 iNumRegRxWords=parms[1];
1293 CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking RegisterRxBuffer\n"));
1294 TPtr8 rxPtr(iRxBuf,KRxBufSizeInBytes);
1295 r = RegisterRxBuffer((TInt)a1, rxPtr, parms[0], parms[1], parms[2]);
1299 case(RBusDevIicClient::ERegisterTxBuffer):
1301 // a1 represents TInt aChannelId
1302 // a2 represents (TAny*) of TInt8 parms[3] where parms[0]=aBufGranularity; parms[1]=aNumWords; parms[2]=aOffset
1304 r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),3*sizeof(TInt8));
1306 break; // Can't proceed if can't access request parameters
1307 // Store parameters for checking in the callback
1308 iTxRegGranularity = parms[0];
1309 iTxRegOffset= parms[2];
1310 iNumRegTxWords=parms[1];
1312 CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking RegisterTxBuffer\n"));
1313 TPtr8 txPtr(iTxBuf,KTxBufSizeInBytes);
1314 r = RegisterTxBuffer((TInt)a1, txPtr, parms[0], parms[1], parms[2]);
1318 case(RBusDevIicClient::ESetNotifTrigger):
1320 // a1 represents (TAny*) of TRequestStatus* aStatus
1321 // a2 represents (TAny*) of TInt parms[2] where parms[0]=aChannelId; parms[1]=aTrigger
1323 r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt));
1325 break; // Can't proceed if can't access request parameters
1326 CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking SetNotificationTrigger with aStatus=0x%x, aChannelId=0x%x, aTrigger=0x%x\n",a1,parms[0],parms[1]));
1332 iStatus=(TRequestStatus*)a1;
1333 // Set the flags for duplex processing
1334 if((parms[1]&ERxAllBytes)&&(parms[1]&ETxAllBytes))
1335 iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
1336 r = SetNotificationTrigger(parms[0],parms[1]);
1337 if(r == KErrTimedOut)
1338 r=KErrNone; // KErrTimedOut is returned if the Client has not interacted with IIC for a while
1342 case(RBusDevIicClient::ECtrlIoNotifNoTrigger):
1344 // a1 represents (TAny*) of aChannelId
1345 // a2 represents (TAny*) of aTrigger
1346 TInt chanId = (TInt)a1;
1347 TInt trigger = (TInt)a2;
1348 // No TRequestStatus is accessed because the call to SetNotificationTrigger
1349 // is either with zero (when it is valid to do so), or it is being called with a
1350 // trigger value that is expected to be rejected.
1351 r = SetNotificationTrigger(chanId,trigger);
1355 if((trigger&ERxAllBytes)&&(trigger&ETxAllBytes))
1356 iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
1358 if(r == KErrTimedOut)
1359 r=KErrNone; // KErrTimedOut is returned if the Client has not interacted with IIC for a while
1363 case(RBusDevIicClient::ECtrlIoRxWords):
1365 // a1 represents TInt aBusId
1366 // a2 represents (TAny*) of TInt parms[2] where parms[0]=aChannelId; parms[1]=aNumWords
1368 r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt));
1370 break; // Can't proceed if can't access request parameters
1372 memset(iRxBuf,0,KRxBufSizeInBytes);
1373 // Store the number of words for checking in the callback
1374 iRxReqNumWords=(TInt8)(parms[1]);
1377 // Set the expected result
1378 tempTrigger |= ERxAllBytes;
1379 if(parms[1] < iNumRegRxWords)
1380 tempTrigger |= ERxUnderrun;
1381 if(parms[1] > iNumRegRxWords)
1382 tempTrigger |= ERxOverrun;
1383 if(iExpectedTrigger != EGeneralBusError)
1384 iExpectedTrigger |= tempTrigger;
1386 iBlockedTrigger |= tempTrigger;
1387 CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoRxWords) with aBusId=0x%x, aChannelId=0x%x, aNumBytes=0x%x\n",(TInt)a1,parms[0],parms[1]));
1388 r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)(parms[0]), (TAny*)(parms[1]));
1389 if(r == KErrTimedOut)
1390 r=KErrNone; // KErrTimedOut is returned if the Client has not interacted with IIC for a while
1394 case(RBusDevIicClient::ECtrlIoTxWords):
1396 // a1 represents TInt aBusId
1397 // a2 represents (TAny*) of TInt parms[2] where parms[0]=aChannelId; parms[1]=aNumWords
1399 r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt));
1401 break; // Can't proceed if can't access request parameters
1404 for(TInt offset=0; offset<KRxBufSizeInBytes; ++offset)
1405 *ptr++=(TUint8)offset;
1406 // Store the number of words for checking in the callback
1407 iTxReqNumWords=(TInt8)(parms[1]);
1409 // Set the expected result
1410 tempTrigger |= ETxAllBytes;
1411 if(parms[1] < iNumRegTxWords)
1412 tempTrigger |= ETxOverrun;
1413 if(parms[1] > iNumRegTxWords)
1414 tempTrigger |= ETxUnderrun;
1415 if(iExpectedTrigger != EGeneralBusError)
1416 iExpectedTrigger |= tempTrigger;
1418 iBlockedTrigger |= tempTrigger;
1420 // The bytes "transmitted" are stored in the simulated bus' iTxCheckBuf
1421 // Since the simulated bus channel is also in the kernel process it shares the same address space
1422 // Get the address of the buffer
1423 // As part of the callback invoked by IIC, this client will check the data stored by the simulated
1424 // bus. Since the simulated bus channel is also in the kernel process it shares the same address space,
1425 // so the buffer can be accessed directly - but the buffer is not created until it receives the following
1426 // StaticExtension command, so the bus identifier represented by a1 is stored to allow accessing the buffer
1427 // adddress from the callback.
1429 CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoTxWords) with aBusId=0x%x, aChannelId=0x%x, aNumBytes=0x%x\n",(TInt)a1,parms[0],parms[1]));
1431 r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)(parms[0]), (TAny*)(parms[1]));
1435 case(RBusDevIicClient::ECtrlIoRxTxWords):
1437 // a1 represents TInt aBusId
1438 // a2 represents (TAny*) of TInt parms[3] where parms[0]=aChannelId; parms[1]=aNumRxWords; parms[2]=aNumTxWords
1440 r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),3*sizeof(TInt));
1442 break; // Can't proceed if can't access request parameters
1443 // Prepare iRxBuf, iTxBuf
1444 memset(iRxBuf,0,KRxBufSizeInBytes);
1446 for(TInt offset=0; offset<KRxBufSizeInBytes; ++offset)
1447 *ptr++=(TUint8)offset;
1449 // Store the number of words for checking in the callback
1450 iRxReqNumWords=(TInt8)(parms[1]);
1451 iTxReqNumWords=(TInt8)(parms[2]);
1454 // Set the expected result
1455 tempTrigger |= (ERxAllBytes|ETxAllBytes);
1457 if(parms[1] < iNumRegRxWords)
1458 tempTrigger |= ERxUnderrun;
1459 if(parms[1] > iNumRegRxWords)
1460 tempTrigger |= ERxOverrun;
1462 if(parms[2] < iNumRegTxWords)
1463 tempTrigger |= ETxOverrun;
1464 if(parms[2] > iNumRegTxWords)
1465 tempTrigger |= ETxUnderrun;
1467 if(iExpectedTrigger != EGeneralBusError)
1468 iExpectedTrigger |= tempTrigger;
1470 iBlockedTrigger |= tempTrigger;
1472 // The bytes "transmitted" are stored in the simulated bus' iTxCheckBuf
1473 // Since the simulated bus channel is also in the kernel process it shares the same address space
1474 // Get the address of the buffer
1475 // As part of the callback invoked by IIC, this client will check the data stored by the simulated
1476 // bus. Since the simulated bus channel is also in the kernel process it shares the same address space,
1477 // so the buffer can be accessed directly - but the buffer is not created until it receives the following
1478 // StaticExtension command, so the bus identifier represented by a1 is stored to allow accessing the buffer
1479 // adddress from the callback.
1482 CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoRxTxWords) with aBusId=0x%x, aChannelId=0x%x, aNumRxBytes=0x%x, aNumTxBytes=0x%x\n",(TInt)a1,parms[0],parms[1],parms[2]));
1483 r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)(parms[0]), (TAny*)(&(parms[1])));
1484 if(r == KErrTimedOut)
1485 r=KErrNone; // KErrTimedOut is returned if the Client has not interacted with IIC for a while
1489 case(RBusDevIicClient::ECtlIoBusError):
1491 // a1 represents TInt aBusId
1492 // a2 represents TInt aChannelId
1493 // Set the expected result
1494 iExpectedTrigger |= EGeneralBusError;
1495 CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtlIoBusError) \n"));
1496 r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)a2, NULL);
1500 case(RBusDevIicClient::ECtrlIoUnblockNotification):
1502 // a1 represents TInt aBusId
1503 // a2 represents TInt aChannelId
1504 iExpectedTrigger = iBlockedTrigger;
1506 CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoUnblockNotification) \n"));
1507 r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)a2, NULL);
1511 case(RBusDevIicClient::ECtrlIoBlockNotification):
1513 // a1 represents TInt aBusId
1514 // a2 represents TInt aChannelId
1515 iBlockedTrigger = iExpectedTrigger;
1516 iExpectedTrigger = EGeneralBusError; // For this test, just interested in if the timeout is detected
1517 // iExpectedTrigger will be reinstated prior to unblocking
1518 CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoBlockNotification) \n"));
1519 r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, (TAny*)a2, NULL);
1523 case(RBusDevIicClient::ECtrlIoUpdTimeout):
1525 // a1 represents TInt aBusId
1526 // a2 represents TInt aChannelId
1528 // For this test, instruct the simulated bus to do the following for the Master and Client timeout values:
1529 // (1) Read the current timeout value and check that it is set to the default
1530 // (2) Set it to different value
1531 // (3) Read it back to check success
1532 // (4) Return to the original value, and readback to confirm
1533 CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking StaticExtension (ECtrlIoBlockNotification) \n"));
1534 r = StaticExtension((TUint)a1, (TUint)ctrlIoVal, NULL, NULL);
1540 CLIENT_PRINT(("DChannelIicSlaveClient::DoControl - unrecognised value for aId=0x%x\n",aId));
1549 TInt DChannelIicSlaveClient::DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2)
1551 CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest invoked with aId=0x%x, aStatus=0x%x, a1=0x%x, a2=0x%x\n", aId,aStatus,a1,a2));
1556 case(RBusDevIicClient::ECaptureChanAsync):
1558 // a1 is a pointer to the TDes8* aConfigHdr
1559 // a2 is a pointer to TInt* parms[2], where:
1560 // parms[0]=(TInt*)aBusId;
1561 // parms[1]=&aChannelId;
1564 r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt*));
1566 break; // Can't proceed if can't access request parameters
1568 TInt hdrSize = Kern::ThreadGetDesLength(iClient,a1);
1569 CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest hdrSize = 0x%x\n",hdrSize));
1572 CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest ERROR, hdrSize is invalid\n"));
1573 return KErrArgument;
1575 if((iConfigHdr = HBuf8::New(hdrSize)) == NULL)
1576 return KErrNoMemory;
1577 if((r = Kern::ThreadDesRead(iClient,a1,*iConfigHdr,0))!=KErrNone)
1583 // Store the address of the user-side variable to update with the ChannelId
1584 iClientChanId=parms[1];
1585 // Invoke the IIC API
1586 CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest invoking (asynchronous) CaptureChannel\n"));
1587 r = CaptureChannel((TInt)(parms[0]), iConfigHdr, iNotif, iChannelId, ETrue);
1590 CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest (asynchronous) CaptureChannel returned %d\n",r));
1594 case(RBusDevIicClient::ECtrlIoOvUndRunRxTx):
1597 iChannelId = (TInt)a2;
1599 CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest status = 0x%x, busId = 0x%x, chanId =0x%x\n",iStatus,iBusId,iChannelId));
1601 // This test is state-machine driven. It is instigated from this point, then subsequent steps
1602 // are handled in the callback funciton SlaveClientCallbackFunc
1604 // Check we in the appropriate state to start
1605 if(iTestOverUnderState == EStartState)
1607 // Re-use the previously-provided buffers. Just request the initial notification triggers,
1608 // the simulate the first event (RxOverrun).
1609 r = SetNotificationTrigger(iChannelId, (ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun));
1612 CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest SetNotificationTrigger returned %d\n",r));
1616 // Trigger now set, so simulate the required event
1617 iExpectedTrigger = ERxAllBytes | ERxOverrun | ETxAllBytes | ETxUnderrun;
1618 iFullDuplexReq |= (ERxAllBytes|ETxAllBytes);
1619 iTestOverUnderState = ERxOverrun_1; // Prepare for callback
1620 // The requested number of words when the buffer was registered was 8, so simulate 10
1621 // to provoke an RxOverrun event.
1623 // To support testing, any values of aId for StaticExtension must be shifted left one place
1624 // and for a Slave, the two msbs must be zero
1625 TInt ctrlIoVal = RBusDevIicClient::ECtrlIoRxWords;
1626 ctrlIoVal = (ctrlIoVal << 1) & 0x3FFFFFFF;
1627 r = StaticExtension(iBusId, ctrlIoVal, (TAny*)iChannelId, (TAny*)numWords);
1632 CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest ECtrlIoOvUndRunRxTx, iTestOverUnderState = 0x%x\n",iTestOverUnderState));
1640 CLIENT_PRINT(("DChannelIicSlaveClient::DoRequest - unrecognised value for aId=0x%x\n",aId));