os/kernelhwsrv/kernel/eka/drivers/iic/iic_channel.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// e32\drivers\iic_channel.cpp
sl@0
    15
// IIC Channel Platform Independent Layer (PIL)
sl@0
    16
//
sl@0
    17
sl@0
    18
#include <drivers/iic_channel.h>
sl@0
    19
#ifdef IIC_INSTRUMENTATION_MACRO
sl@0
    20
#include <drivers/iic_trace.h>
sl@0
    21
#endif
sl@0
    22
sl@0
    23
// The timer call back function which calls the PSL's HandleSlaveTimeout()
sl@0
    24
// Note that this assumes that the channel thread has been unblocked - if this
sl@0
    25
// is not the case, the callback will never get to run
sl@0
    26
sl@0
    27
TInt DIicBusChannelMaster::DoCreate()
sl@0
    28
    {return KErrNone;}
sl@0
    29
sl@0
    30
void DIicBusChannelMaster::Lock()
sl@0
    31
    {NKern::FMWait(&iTransactionQLock);}
sl@0
    32
sl@0
    33
void DIicBusChannelMaster::Unlock()
sl@0
    34
    {NKern::FMSignal(&iTransactionQLock);}
sl@0
    35
sl@0
    36
TIicBusTransaction* DIicBusChannelMaster::NextTrans(TIicBusTransaction* aTrans)
sl@0
    37
    {
sl@0
    38
    // call multi-transaction call back function to get next transaction
sl@0
    39
    if((aTrans->iFlags&KTransactionWithPreamble)&&(aTrans->iFlags&KTransactionWithMultiTransc))
sl@0
    40
        return ((TIicBusTransactionPreambleExt*)aTrans)->iMultiTransc(aTrans, ((TIicBusTransactionPreambleExt*)aTrans)->iMultiTranscArg);
sl@0
    41
    else if(aTrans->iFlags&KTransactionWithMultiTransc)
sl@0
    42
        return ((TIicBusTransactionMultiTransc*)aTrans)->iMultiTransc(aTrans, ((TIicBusTransactionMultiTransc*)aTrans)->iMultiTranscArg);
sl@0
    43
    else
sl@0
    44
        return NULL;
sl@0
    45
    }
sl@0
    46
sl@0
    47
void DIicBusChannelMaster::UnlockAndKick()
sl@0
    48
    {iTransQDfc.Enque(&iTransactionQLock);}
sl@0
    49
sl@0
    50
void DIicBusChannelMaster::SlaveTimeoutCallback(TAny* aPtr)
sl@0
    51
	{
sl@0
    52
sl@0
    53
	DIicBusChannelMaster* aChanMaster=(DIicBusChannelMaster* )aPtr;
sl@0
    54
	TInt r = aChanMaster->HandleSlaveTimeout();
sl@0
    55
	aChanMaster->CompleteRequest(r);
sl@0
    56
	}
sl@0
    57
sl@0
    58
TInt DIicBusChannelMaster::TransFlow(TIicBusTransaction* aTransaction)
sl@0
    59
    {
sl@0
    60
    if(aTransaction->iHalfDuplexTrans == NULL)
sl@0
    61
        return KErrArgument;
sl@0
    62
    else if(aTransaction->iFullDuplexTrans == NULL)
sl@0
    63
        return DIicBusChannel::EHalfDuplex;
sl@0
    64
    else return DIicBusChannel::EFullDuplex;
sl@0
    65
    }
sl@0
    66
sl@0
    67
TInt8 DIicBusChannelMaster::IsMasterBusy()
sl@0
    68
    {
sl@0
    69
    if((iTransCount&~KTransCountMsBit) == 0)
sl@0
    70
        return 0;
sl@0
    71
    else return 1;
sl@0
    72
    }
sl@0
    73
sl@0
    74
DIicBusChannelMaster::DIicBusChannelMaster(TBusType aBusType, TChannelDuplex aChanDuplex)
sl@0
    75
		: DIicBusChannel(DIicBusChannel::EMaster, aBusType, aChanDuplex),
sl@0
    76
		iTransQDfc(DIicBusChannelMaster::MsgQFunc, this, NULL, 1), iChannelReady(EFalse)
sl@0
    77
	{
sl@0
    78
	new(&iTimeoutTimer) NTimer(SlaveTimeoutCallback,this);
sl@0
    79
	}
sl@0
    80
sl@0
    81
DIicBusChannelMaster::~DIicBusChannelMaster()
sl@0
    82
	{
sl@0
    83
	delete iSlaveTimeoutDfc;
sl@0
    84
	}
sl@0
    85
sl@0
    86
TInt DIicBusChannelMaster::Init()
sl@0
    87
	{
sl@0
    88
	iSlaveTimeoutDfc = new TDfc(SlaveTimeoutCallback,(TAny*)this, 7);	// Highest Dfc priority
sl@0
    89
	if(!iSlaveTimeoutDfc)
sl@0
    90
		return KErrNoMemory;
sl@0
    91
	else
sl@0
    92
		return KErrNone;
sl@0
    93
	}
sl@0
    94
sl@0
    95
// Function to used to indicate if the Slave response has exceeded
sl@0
    96
// an expected time
sl@0
    97
TInt DIicBusChannelMaster::StartSlaveTimeOutTimer(TInt aTime)
sl@0
    98
	{
sl@0
    99
	TInt r = iTimeoutTimer.OneShot(NKern::TimerTicks(aTime),(*iSlaveTimeoutDfc));
sl@0
   100
	return r;
sl@0
   101
	}
sl@0
   102
sl@0
   103
void DIicBusChannelMaster::SetDfcQ(TDfcQue* aDfcQue)
sl@0
   104
	{
sl@0
   105
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::SetDfcQ 0x%x\n",aDfcQue));
sl@0
   106
	__ASSERT_DEBUG(aDfcQue!=NULL, Kern::Fault(KIicChannelPanic,__LINE__));
sl@0
   107
	iDfcQ=aDfcQue;
sl@0
   108
	iTransQDfc.SetDfcQ(iDfcQ);
sl@0
   109
	iSlaveTimeoutDfc->SetDfcQ(iDfcQ);
sl@0
   110
	Lock();
sl@0
   111
	__ASSERT_DEBUG(!iChannelReady, Kern::Fault(KIicChannelPanic,__LINE__));
sl@0
   112
	if (!iTransactionQ.IsEmpty())
sl@0
   113
		{
sl@0
   114
		iTransaction=(TIicBusTransaction*)(iTransactionQ.First()->Deque());
sl@0
   115
		__KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::SetDfcQ got %08x",iTransaction));
sl@0
   116
		iTransaction->iState=TIicBusTransaction::EAccepted;
sl@0
   117
		iCurrentTransaction = iTransaction;
sl@0
   118
		UnlockAndKick();
sl@0
   119
		}
sl@0
   120
	else
sl@0
   121
		{
sl@0
   122
		__KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::SetDfcQ"));
sl@0
   123
		iChannelReady=ETrue;
sl@0
   124
		iTransaction=NULL;
sl@0
   125
		iCurrentTransaction = NULL;
sl@0
   126
		Unlock();
sl@0
   127
		}
sl@0
   128
	}
sl@0
   129
sl@0
   130
void DIicBusChannelMaster::CompleteRequest(TInt aResult)
sl@0
   131
	{
sl@0
   132
	TIicBusTransaction* nextTrans=NextTrans(iCurrentTransaction);
sl@0
   133
sl@0
   134
	if((aResult != KErrNone)||(nextTrans == NULL))
sl@0
   135
		EndTransaction(iTransaction,aResult,iTransaction->iCallback);
sl@0
   136
	else
sl@0
   137
		{
sl@0
   138
		nextTrans->iBusId = iCurrentTransaction->iBusId; // Pass the bus configuration info to the PSL
sl@0
   139
		iCurrentTransaction = nextTrans;
sl@0
   140
		DoRequest(nextTrans);
sl@0
   141
		}
sl@0
   142
	}
sl@0
   143
sl@0
   144
#ifdef MASTER_MODE
sl@0
   145
sl@0
   146
/*
sl@0
   147
For Master-side transaction queuing APIs
sl@0
   148
the Channel implementation sends the transaction as a message to the Channel's message queue,
sl@0
   149
optionally blocking the client thread on the message's semaphore (synchronous APIs).
sl@0
   150
*/
sl@0
   151
TInt DIicBusChannelMaster::QueueTransaction(TIicBusTransaction* aTransaction)
sl@0
   152
	{
sl@0
   153
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::QueueTransaction, aTransaction=0x%x\n",aTransaction));
sl@0
   154
	// Send the transaction as a message to the Channel's message queue
sl@0
   155
	// Synchronous API, so block the calling thread during the processing
sl@0
   156
	TInt r = QueueTransaction(aTransaction, NULL);
sl@0
   157
	if(r!=KErrNone)
sl@0
   158
		return r;	// Transaction was not queued - so don't wait for a notification that it completed.
sl@0
   159
sl@0
   160
	__KTRACE_OPT(KIIC, Kern::Printf("<DIicBusChannelMaster::QueueTransaction ret %d",aTransaction->iResult));
sl@0
   161
	return aTransaction->iResult;
sl@0
   162
	}
sl@0
   163
sl@0
   164
TInt DIicBusChannelMaster::QueueTransaction(TIicBusTransaction* aTransaction, TIicBusCallback* aCallback)
sl@0
   165
	{
sl@0
   166
	__KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::QueueTransaction, aTransaction=0x%x, aCallback=0x%x\n",aTransaction,aCallback));
sl@0
   167
sl@0
   168
	// Check aTransaction is non-NULL (aCallback may be NULL if the synchronous operation is required).
sl@0
   169
	if(aTransaction == NULL)
sl@0
   170
		{
sl@0
   171
		return KErrArgument;
sl@0
   172
		}
sl@0
   173
sl@0
   174
	// Send the transaction as a message to the Channel's message queue and return
sl@0
   175
	aTransaction->iCallback = aCallback;
sl@0
   176
	if(aCallback != NULL)
sl@0
   177
		{
sl@0
   178
		aCallback->iTransaction = aTransaction;
sl@0
   179
		}
sl@0
   180
sl@0
   181
	// Call the PSL implementation to check that the header is valid for this channel
sl@0
   182
	TInt r = CheckHdr(aTransaction->iHeader);
sl@0
   183
	if(r!=KErrNone)
sl@0
   184
		{
sl@0
   185
		return r;
sl@0
   186
		}
sl@0
   187
sl@0
   188
	// Duplex operation is indicated in the transaction object
sl@0
   189
	if((TransFlow((TIicBusTransaction*)aTransaction) == DIicBusChannel::EFullDuplex) &&
sl@0
   190
	   (ChannelDuplex()                              != DIicBusChannel::EFullDuplex))
sl@0
   191
		{
sl@0
   192
		return KErrNotSupported;
sl@0
   193
		}
sl@0
   194
sl@0
   195
	DThread* pC =& Kern::CurrentThread();
sl@0
   196
	Lock();
sl@0
   197
	__ASSERT_DEBUG(aTransaction->iState == TIicBusTransaction::EFree, Kern::Fault(KIicChannelPanic,__LINE__));
sl@0
   198
	if(!(iTransCount & KTransCountMsBit))
sl@0
   199
		{
sl@0
   200
		if(iTransCount < ~KTransCountMsBit)
sl@0
   201
			{
sl@0
   202
			++iTransCount;
sl@0
   203
			}
sl@0
   204
		else
sl@0
   205
			{
sl@0
   206
			Unlock();
sl@0
   207
			return KErrOverflow;
sl@0
   208
			}
sl@0
   209
		}
sl@0
   210
sl@0
   211
	aTransaction->iSyncNotification.iCount = 0;
sl@0
   212
	aTransaction->iSyncNotification.iOwningThread = &pC->iNThread;
sl@0
   213
	pC->Open();
sl@0
   214
	if (iChannelReady)
sl@0
   215
		{
sl@0
   216
		aTransaction->iState = TIicBusTransaction::EAccepted;
sl@0
   217
		iTransaction = aTransaction;
sl@0
   218
		iCurrentTransaction = aTransaction;
sl@0
   219
		iChannelReady = EFalse;
sl@0
   220
		UnlockAndKick();
sl@0
   221
		}
sl@0
   222
	else
sl@0
   223
		{
sl@0
   224
		iTransactionQ.Add(aTransaction);
sl@0
   225
		aTransaction->iState = TIicBusTransaction::EDelivered;
sl@0
   226
		Unlock();
sl@0
   227
		}
sl@0
   228
sl@0
   229
	// Wait on a semaphore if called from synchronous version
sl@0
   230
	if(aCallback == NULL)
sl@0
   231
		{
sl@0
   232
		NKern::FSWait(&aTransaction->iSyncNotification);
sl@0
   233
		}
sl@0
   234
sl@0
   235
	return KErrNone;
sl@0
   236
	}
sl@0
   237
sl@0
   238
TInt DIicBusChannelMaster::CancelTransaction(TIicBusTransaction* aTransaction)
sl@0
   239
	{
sl@0
   240
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::CancelTransaction, aTransaction=0x%x\n",aTransaction));
sl@0
   241
sl@0
   242
	// Check aTransaction is non-NULL
sl@0
   243
	if(aTransaction == NULL)
sl@0
   244
		{
sl@0
   245
		return KErrArgument;
sl@0
   246
		}
sl@0
   247
	// If the method is called on a synchronous transaction return KErrNotSupported
sl@0
   248
	if(aTransaction->iCallback == NULL)
sl@0
   249
		{
sl@0
   250
		return KErrNotSupported;
sl@0
   251
		}
sl@0
   252
	DThread* pT = NULL;
sl@0
   253
	Lock();
sl@0
   254
sl@0
   255
	TInt r = KErrNone;
sl@0
   256
	switch(aTransaction->iState)
sl@0
   257
		{
sl@0
   258
		case TIicBusTransaction::EDelivered:
sl@0
   259
			{
sl@0
   260
			aTransaction->Deque();
sl@0
   261
			pT=_LOFF(aTransaction->iSyncNotification.iOwningThread,DThread,iNThread);
sl@0
   262
			aTransaction->iState=TIicBusTransaction::EFree;
sl@0
   263
			--iTransCount; // Count must be greater than zero if the transaction is in this state
sl@0
   264
			r = KErrCancel;
sl@0
   265
			break;
sl@0
   266
			}
sl@0
   267
sl@0
   268
		case TIicBusTransaction::EAccepted:
sl@0
   269
			{
sl@0
   270
			r = KErrInUse;
sl@0
   271
			break;
sl@0
   272
			}
sl@0
   273
sl@0
   274
		case TIicBusTransaction::EFree:
sl@0
   275
			{
sl@0
   276
			r = KErrCancel;
sl@0
   277
			break;
sl@0
   278
			}
sl@0
   279
		}
sl@0
   280
	Unlock();
sl@0
   281
	if (pT)
sl@0
   282
		{
sl@0
   283
		pT->AsyncClose();
sl@0
   284
		}
sl@0
   285
sl@0
   286
	return r;
sl@0
   287
	}
sl@0
   288
sl@0
   289
#else /*MASTER_MODE*/
sl@0
   290
sl@0
   291
TInt DIicBusChannelMaster::QueueTransaction(TIicBusTransaction* /*aTransaction*/)
sl@0
   292
	{
sl@0
   293
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::QueueTransaction invoked when not in MASTER_MODE!\n"));
sl@0
   294
	return KErrNotSupported;
sl@0
   295
	}
sl@0
   296
sl@0
   297
TInt DIicBusChannelMaster::QueueTransaction(TIicBusTransaction* /*aTransaction*/, TIicBusCallback* /*aCallback*/)
sl@0
   298
	{
sl@0
   299
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::QueueTransaction invoked when not in MASTER_MODE!\n"));
sl@0
   300
	return KErrNotSupported;
sl@0
   301
	}
sl@0
   302
sl@0
   303
TInt DIicBusChannelMaster::CancelTransaction(TIicBusTransaction* /*aTransaction*/)
sl@0
   304
	{
sl@0
   305
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::CancelTransaction invoked when not in MASTER_MODE!\n"));
sl@0
   306
	return KErrNotSupported;
sl@0
   307
	}
sl@0
   308
#endif/*MASTER_MODE*/
sl@0
   309
sl@0
   310
// Invoked in response to receiving a message
sl@0
   311
// Function argument is a pointer to the required channel object
sl@0
   312
// Invoke the channel's PSL implementation of the DoRequest method with a pointer to the transaction object
sl@0
   313
//
sl@0
   314
void DIicBusChannelMaster::MsgQFunc(TAny* aPtr)
sl@0
   315
	{
sl@0
   316
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc, aPtr=0x%x\n",aPtr));
sl@0
   317
	DIicBusChannelMaster* channel=(DIicBusChannelMaster*)aPtr;
sl@0
   318
	TIicBusTransaction* trans = channel->iTransaction;
sl@0
   319
sl@0
   320
#ifdef IIC_INSTRUMENTATION_MACRO
sl@0
   321
	IIC_MPROCESSTRANS_START_PIL_TRACE;
sl@0
   322
#endif
sl@0
   323
sl@0
   324
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc trans->iHeader=0x%x\n",trans->iHeader));
sl@0
   325
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc trans->iHalfDuplexTrans=0x%x\n",trans->iHalfDuplexTrans));
sl@0
   326
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc trans->iFullDuplexTrans=0x%x\n",trans->iFullDuplexTrans));
sl@0
   327
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc trans->iCallback=0x%x\n",trans->iCallback));
sl@0
   328
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelMaster::MsgQFunc trans->iFlags=0x%x\n",trans->iFlags));
sl@0
   329
sl@0
   330
	TInt r = KErrNone;
sl@0
   331
	// invoke the preamble callback function supplied by the client of the IIC if there is any
sl@0
   332
	if(GetTransFlags(trans) & KTransactionWithPreamble)
sl@0
   333
		{
sl@0
   334
		TIicBusTransactionPreamble* transPreamble = (TIicBusTransactionPreamble*)trans;
sl@0
   335
		TIicBusPreamble funcPtr=NULL;
sl@0
   336
		funcPtr=(GetPreambleFuncPtr(transPreamble));
sl@0
   337
		funcPtr(transPreamble,GetPreambleFuncArg(transPreamble));
sl@0
   338
		}
sl@0
   339
	r = channel->DoRequest(trans);	// Instigate processing in the PSL
sl@0
   340
	if(r!=KErrNone)
sl@0
   341
		channel->EndTransaction(trans, r, trans->iCallback);
sl@0
   342
	}
sl@0
   343
sl@0
   344
void DIicBusChannelMaster::EndTransaction(TIicBusTransaction* aTrans, TInt aResult, TIicBusCallback* aCb)
sl@0
   345
	{
sl@0
   346
#ifdef IIC_INSTRUMENTATION_MACRO
sl@0
   347
	IIC_MPROCESSTRANS_END_PIL_TRACE;
sl@0
   348
#endif
sl@0
   349
	Complete(aResult,aTrans);
sl@0
   350
	if(aCb != NULL)
sl@0
   351
		{
sl@0
   352
		aCb->iResult = aResult;
sl@0
   353
		aCb->Enque();
sl@0
   354
		}
sl@0
   355
	}
sl@0
   356
sl@0
   357
void DIicBusChannelMaster::CancelTimeOut()
sl@0
   358
	{
sl@0
   359
	iTimeoutTimer.Cancel();
sl@0
   360
	}
sl@0
   361
sl@0
   362
void DIicBusChannelMaster::Complete(TInt aResult, TIicBusTransaction* aTransaction) //Completes a kernel message and receive the next one
sl@0
   363
	{
sl@0
   364
	__KTRACE_OPT(KIIC, Kern::Printf("MsgB::Complete %08x, %d",this,aResult));
sl@0
   365
	Lock();
sl@0
   366
	__ASSERT_DEBUG(aTransaction->iState == TIicBusTransaction::EAccepted, Kern::Fault(KIicChannelPanic,__LINE__));
sl@0
   367
	aTransaction->iResult=aResult;
sl@0
   368
	aTransaction->iState=TIicBusTransaction::EFree;
sl@0
   369
	--iTransCount;
sl@0
   370
	DThread* pT=_LOFF(aTransaction->iSyncNotification.iOwningThread,DThread,iNThread);
sl@0
   371
	__ASSERT_DEBUG(!iChannelReady, Kern::Fault(KIicChannelPanic,__LINE__));
sl@0
   372
	if (!iTransactionQ.IsEmpty())
sl@0
   373
		{
sl@0
   374
		TIicBusTransaction* pM=(TIicBusTransaction*)iTransactionQ.First()->Deque();
sl@0
   375
		__KTRACE_OPT(KIIC, Kern::Printf("rxnext: got %08x",pM));
sl@0
   376
		pM->iState=TIicBusTransaction::EAccepted;
sl@0
   377
		iTransaction = pM;
sl@0
   378
		iCurrentTransaction = pM;
sl@0
   379
		iTransQDfc.Enque();
sl@0
   380
		}
sl@0
   381
	else
sl@0
   382
		{
sl@0
   383
		__KTRACE_OPT(KIIC, Kern::Printf("rxnext"));
sl@0
   384
		iChannelReady=ETrue;
sl@0
   385
		iTransaction=NULL;
sl@0
   386
		iCurrentTransaction = NULL;
sl@0
   387
		}
sl@0
   388
	NKern::FSSignal(&aTransaction->iSyncNotification,&iTransactionQLock);
sl@0
   389
	pT->AsyncClose();
sl@0
   390
	}
sl@0
   391
sl@0
   392
TInt DIicBusChannelMaster::StaticExtension(TUint /*aFunction*/, TAny* /*aParam1*/, TAny* /*aParam*/)
sl@0
   393
 	{
sl@0
   394
 	return KErrNotSupported;
sl@0
   395
 	}
sl@0
   396
sl@0
   397
TInt DIicBusChannelMaster::Spare1(TInt /*aVal*/, TAny* /*aPtr1*/, TAny* /*aPtr2*/)
sl@0
   398
	{
sl@0
   399
	return KErrNotSupported;
sl@0
   400
	}
sl@0
   401
sl@0
   402
#ifdef SLAVE_MODE
sl@0
   403
sl@0
   404
TInt DIicBusChannelSlave::CaptureChannel(TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch)
sl@0
   405
	{
sl@0
   406
	// Only one client can have access to the Slave channel at any one time. Any subsequent attempts to capture the
sl@0
   407
	// same channel should return an error.
sl@0
   408
	//
sl@0
   409
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::CaptureChannel\n"));
sl@0
   410
	if((aConfigHdr == NULL) || (aCallback == NULL))
sl@0
   411
		{
sl@0
   412
	    __KTRACE_OPT(KIIC, Kern::Printf("ERROR: non-NULL argument aConfigHdr=0x%x, aCallback=0x%x\n",aConfigHdr,aCallback));
sl@0
   413
		return KErrArgument;
sl@0
   414
		}
sl@0
   415
	//
sl@0
   416
	// Check the header is valid for the channel
sl@0
   417
	TInt r = CheckHdr(aConfigHdr);
sl@0
   418
	if(r == KErrNone)
sl@0
   419
		{
sl@0
   420
		// Check Slave channel is available for capture
sl@0
   421
		// If iChannelInUse is not set, capture should succeed
sl@0
   422
		// If this Slave channel is part of a MasterSlave channel iChannelInUse will already be set
sl@0
   423
		// but iClient will still be NULL. In this case, the capture should succeed.
sl@0
   424
		TInt intState=__SPIN_LOCK_IRQSAVE(iSpinLock);
sl@0
   425
		DThread* pT=&(Kern::CurrentThread());
sl@0
   426
		if((iChannelInUse)&&(iClient!=NULL))
sl@0
   427
			r=KErrInUse;
sl@0
   428
		else
sl@0
   429
			{
sl@0
   430
			iChannelInUse=1;
sl@0
   431
			iClient=pT;
sl@0
   432
			}
sl@0
   433
		__SPIN_UNLOCK_IRQRESTORE(iSpinLock,intState);
sl@0
   434
sl@0
   435
		if(r == KErrNone)
sl@0
   436
			{
sl@0
   437
			iClient->Open();
sl@0
   438
			aCallback->iChannel=this;
sl@0
   439
			iNotif = aCallback;
sl@0
   440
			iConfigHeader=aConfigHdr;	// Header alread checked, so just assign it
sl@0
   441
sl@0
   442
			// Invoke the PSL processing
sl@0
   443
			if(aAsynch)
sl@0
   444
				{
sl@0
   445
				aChannelId = 0; // the client should read iChannelId from the callback object.
sl@0
   446
				r=DoRequest(EAsyncConfigPwrUp);
sl@0
   447
				}
sl@0
   448
			else
sl@0
   449
				r=DoRequest(ESyncConfigPwrUp);
sl@0
   450
sl@0
   451
			if(r == KErrNone)
sl@0
   452
				{
sl@0
   453
				if(!aAsynch)	// For asynchronous version there is nothing more to do until the callback is invoked
sl@0
   454
					{
sl@0
   455
					SetChannelId(aChannelId);
sl@0
   456
					iClientTimeoutDfc->SetDfcQ(iNotif->iDfcQ);
sl@0
   457
					}
sl@0
   458
				}
sl@0
   459
			else
sl@0
   460
				{
sl@0
   461
				// PSL encountered an error
sl@0
   462
				ReleaseChannel();
sl@0
   463
				if(aAsynch)
sl@0
   464
					CompleteAsynchCapture(r);	// Queue the client callback for execution
sl@0
   465
				}
sl@0
   466
			}
sl@0
   467
		}
sl@0
   468
	return r;
sl@0
   469
	}
sl@0
   470
sl@0
   471
TInt DIicBusChannelSlave::ReleaseChannel()
sl@0
   472
	{
sl@0
   473
	__KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::ReleaseChannel\n"));
sl@0
   474
	 // Release a previously-captured channel.
sl@0
   475
	TInt r=KErrNone;;
sl@0
   476
	// Ensure that only the channel's client may release the channel
sl@0
   477
	DThread* pT=&(Kern::CurrentThread());
sl@0
   478
	if(iClient!=pT)			// Direct access since iClient can't be modified while channel is still captured
sl@0
   479
		return KErrAccessDenied;
sl@0
   480
sl@0
   481
	r=SetNotificationTrigger(0);			// Attempt to clear notification requests
sl@0
   482
	if((r!=KErrNone)&&(r!=KErrTimedOut))	// KErrTimedOut refers to an earlier transaction, and is for information only
sl@0
   483
		return r;
sl@0
   484
	iTimeoutTimer.Cancel();
sl@0
   485
	r=DoRequest(EPowerDown);
sl@0
   486
	if(r == KErrNone)
sl@0
   487
		{
sl@0
   488
		TInt intState=__SPIN_LOCK_IRQSAVE(iSpinLock);
sl@0
   489
		iClient=NULL;
sl@0
   490
		iChannelInUse=0;	// Channel now available for capture by other clients
sl@0
   491
		__SPIN_UNLOCK_IRQRESTORE(iSpinLock,intState);
sl@0
   492
		pT->AsyncClose();	// Allow Client thread to close now channel has been released
sl@0
   493
		}
sl@0
   494
	else
sl@0
   495
		{
sl@0
   496
		// PSL error when releasing the channel - have to assume the hardware has a problem.
sl@0
   497
		// The channel is no longer considered "captured" by the controller, i.e. will not accept commands
sl@0
   498
		// But not having cleared the busy flag means that it can not be used for master channel
sl@0
   499
		// operations if it is part of a MasterSlave channel
sl@0
   500
		// Must Fault the Kernel.
sl@0
   501
		__KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::ReleaseChannel - PSL returned error code %d\n",r));
sl@0
   502
		__ASSERT_ALWAYS(EFalse, Kern::Fault(KIicChannelPanic,__LINE__));
sl@0
   503
		}
sl@0
   504
	return r;
sl@0
   505
	}
sl@0
   506
sl@0
   507
TInt DIicBusChannelSlave::RegisterRxBuffer(TPtr8 aRxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
sl@0
   508
	{
sl@0
   509
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::RegisterRxBuffer\n"));
sl@0
   510
#ifdef IIC_INSTRUMENTATION_MACRO
sl@0
   511
	IIC_SREGRXBUF_START_PIL_TRACE;
sl@0
   512
#endif
sl@0
   513
	TInt r=KErrNone;
sl@0
   514
	// Ensure that only the channel's client may perform this operation
sl@0
   515
	DThread* pT=&(Kern::CurrentThread());
sl@0
   516
	if(iClient!=pT)			// Direct access since iClient can't be modified while channel is still captured
sl@0
   517
		return KErrAccessDenied;
sl@0
   518
	//If the buffer pointer is NULL, return KErrArgument
sl@0
   519
	if(aRxBuffer.Ptr() == NULL)
sl@0
   520
		return KErrArgument;
sl@0
   521
	// If a buffer is already registered, a subsequent request to do the same should return KErrAlreadyExists
sl@0
   522
	// This will be the case if SetNotificationTrigger has been invoked with any of ERxAllBytes, ERxUnderrun or ERxOverrun
sl@0
   523
	if(iReqTrig&(ERxAllBytes|ERxUnderrun|ERxOverrun))
sl@0
   524
		r=KErrAlreadyExists;
sl@0
   525
	else
sl@0
   526
		{
sl@0
   527
		iRxBuf=(TInt8*)(aRxBuffer.Ptr());
sl@0
   528
		iRxGranularity=aBufGranularity;
sl@0
   529
		iNumRxWords=aNumWords;
sl@0
   530
		iRxOffset=aOffset;
sl@0
   531
		}
sl@0
   532
#ifdef IIC_INSTRUMENTATION_MACRO
sl@0
   533
	IIC_SREGRXBUF_END_PIL_TRACE;
sl@0
   534
#endif
sl@0
   535
	 return r;
sl@0
   536
	}
sl@0
   537
sl@0
   538
TInt DIicBusChannelSlave::RegisterTxBuffer(TPtr8 aTxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
sl@0
   539
	{
sl@0
   540
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::RegisterTxBuffer	- default implementation\n"));
sl@0
   541
#ifdef IIC_INSTRUMENTATION_MACRO
sl@0
   542
	IIC_SREGTXBUF_START_PIL_TRACE;
sl@0
   543
#endif
sl@0
   544
	TInt r=KErrNone;
sl@0
   545
	// Ensure that only the channel's client may perform this operation
sl@0
   546
	DThread* pT=&(Kern::CurrentThread());
sl@0
   547
	if(iClient!=pT)			// Direct access since iClient can't be modified while channel is still captured
sl@0
   548
		return KErrAccessDenied;
sl@0
   549
	//If the buffer pointer is NULL, return KErrArgument
sl@0
   550
	if(aTxBuffer.Ptr() == NULL)
sl@0
   551
		return KErrArgument;
sl@0
   552
	// If a buffer is already registered and a request is pending, a subsequent request to register a buffer should return
sl@0
   553
	// KErrAlreadyExists
sl@0
   554
	// This will be the case if SetNotificationTrigger has been invoked with any of ETxAllBytes, ETxUnderrun or ETxOverrun
sl@0
   555
	if(iReqTrig&(ETxAllBytes|ETxUnderrun|ETxOverrun))
sl@0
   556
		r=KErrAlreadyExists;
sl@0
   557
	else
sl@0
   558
		{
sl@0
   559
		iTxBuf=(TInt8*)(aTxBuffer.Ptr());
sl@0
   560
		iTxGranularity=aBufGranularity;
sl@0
   561
		iNumTxWords=aNumWords;
sl@0
   562
		iTxOffset=aOffset;
sl@0
   563
		}
sl@0
   564
#ifdef IIC_INSTRUMENTATION_MACRO
sl@0
   565
	IIC_SREGTXBUF_END_PIL_TRACE;
sl@0
   566
#endif
sl@0
   567
	return r;
sl@0
   568
	}
sl@0
   569
sl@0
   570
TInt DIicBusChannelSlave::SetNotificationTrigger(TInt aTrigger)
sl@0
   571
	{
sl@0
   572
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::SetNotificationTrigger invoked with aTrigger=0x%x\n",aTrigger));
sl@0
   573
	// Ensure that only the channel's client may perform this operation
sl@0
   574
	DThread* pT=&(Kern::CurrentThread());
sl@0
   575
	if(iClient!=pT)			// Direct access since iClient can't be modified while channel is still captured
sl@0
   576
		return KErrAccessDenied;
sl@0
   577
sl@0
   578
	TInt retVal = KErrNone;
sl@0
   579
	TInt trigger = aTrigger;
sl@0
   580
	switch (iTimerState)	// Handle existing timer conditions
sl@0
   581
		{
sl@0
   582
		case DIicBusChannelSlave::EInactive:
sl@0
   583
			{
sl@0
   584
			// In this state no timers have been started - so no action required
sl@0
   585
			break;
sl@0
   586
			}
sl@0
   587
		case DIicBusChannelSlave::EWaitForClient:
sl@0
   588
			{
sl@0
   589
			// Client has responded within the given time period, so stop the timer.
sl@0
   590
			StopTimer();
sl@0
   591
			break;
sl@0
   592
			}
sl@0
   593
		case DIicBusChannelSlave::EWaitForMaster:
sl@0
   594
			{
sl@0
   595
			// If both Rx and Tx events had been requested, and if ERxOverrun had occurred, the Client
sl@0
   596
			// may have called this function with new requests for Rx notifications, in order to
sl@0
   597
			// continue reading data sent by the Master. At this point, all Rx request flags in iReqTrig
sl@0
   598
			// will have been cleared.
sl@0
   599
			// If both Rx and Tx events had been requested, and if ETxUnderrun had occurred, the Client
sl@0
   600
			// may have called this function with new requests for Tx notifications, in order to
sl@0
   601
			// continue sending data to the Master. At this point, all Tx request flags in iReqTrig will
sl@0
   602
			// have been cleared.
sl@0
   603
			//
sl@0
   604
			// To handle the ERxOverrun situation, aTrigger may specify only the new Rx trigger settings,
sl@0
   605
			// or it may also re-specify the exisiting Tx settings. Similarly for the ETxUnderrun, aTrigger
sl@0
   606
			// may specify only the new Tx triggers, or both the new Tx triggers and the existing Rx triggers.
sl@0
   607
			//
sl@0
   608
			// However, if Rx flags are still set in iReqTrig, a request to change the Rx settings
sl@0
   609
			// will be rejected (similarly, for Tx).
sl@0
   610
			//
sl@0
   611
			// If the requested notification is zero, which would represent an attempt to clear all triggers
sl@0
   612
			// while the Master may have commenced a transfer, the request will be rejected.
sl@0
   613
			__ASSERT_DEBUG(iReqTrig != 0, Kern::Fault(KIicChannelPanic,__LINE__));
sl@0
   614
			if(trigger == 0)
sl@0
   615
				{
sl@0
   616
				return KErrInUse;
sl@0
   617
				}
sl@0
   618
			TInt allRxFlags = ERxAllBytes | ERxOverrun | ERxUnderrun;
sl@0
   619
			TInt allTxFlags = ETxAllBytes | ETxOverrun | ETxUnderrun;
sl@0
   620
			// Check the Rx flags
sl@0
   621
			TInt rxTrig = iReqTrig & allRxFlags;
sl@0
   622
			TInt reqRxTrig = trigger & allRxFlags;
sl@0
   623
			if(rxTrig == 0)
sl@0
   624
				{
sl@0
   625
				rxTrig = reqRxTrig;
sl@0
   626
				}
sl@0
   627
			else if(reqRxTrig != 0)
sl@0
   628
				{
sl@0
   629
				// New Rx triggers specified - check that Client is not attempting to modify the existing
sl@0
   630
				// settings
sl@0
   631
				if(rxTrig ^ reqRxTrig)
sl@0
   632
					{
sl@0
   633
					// Attempting to change the trigger settings - so reject the request
sl@0
   634
					return KErrInUse;
sl@0
   635
					}
sl@0
   636
				}
sl@0
   637
			// Check the Tx flags
sl@0
   638
			TInt txTrig = iReqTrig & allTxFlags;
sl@0
   639
			TInt reqTxTrig = trigger & allTxFlags;
sl@0
   640
			if(txTrig == 0)
sl@0
   641
				{
sl@0
   642
				txTrig = reqTxTrig;
sl@0
   643
				}
sl@0
   644
			else if(reqTxTrig != 0)
sl@0
   645
				{
sl@0
   646
				// New Tx triggers specified - check that Client is not attempting to modify the existing
sl@0
   647
				// settings
sl@0
   648
				if(txTrig ^ reqTxTrig)
sl@0
   649
					{
sl@0
   650
					// Attempting to change the trigger settings - so reject the request
sl@0
   651
					return KErrInUse;
sl@0
   652
					}
sl@0
   653
				}
sl@0
   654
			// Udate iReqTrig for the new requested trigger
sl@0
   655
			// and cancel the timer - since we are now starting a new transfer, we should
sl@0
   656
			// allow the Master the time to perform it
sl@0
   657
			trigger = rxTrig | txTrig;
sl@0
   658
			StopTimer();
sl@0
   659
			break;
sl@0
   660
			}
sl@0
   661
		case DIicBusChannelSlave::EClientTimeout:
sl@0
   662
			{
sl@0
   663
			// The Client did not respond within the expected time for the previous transfer. As a result,
sl@0
   664
			// the transaction will have been terminated for the Client.
sl@0
   665
			// Set the return value to inform the Client that it previously exceeded the expected response time
sl@0
   666
			retVal = KErrTimedOut;
sl@0
   667
			break;
sl@0
   668
			}
sl@0
   669
		default:
sl@0
   670
			{
sl@0
   671
			__ASSERT_DEBUG(0, Kern::Fault(KIicChannelPanic,__LINE__));
sl@0
   672
			break;
sl@0
   673
			}
sl@0
   674
		}
sl@0
   675
	// Ensure that requests for notification of asynchronous capture of channel is removed, since this
sl@0
   676
	// is not a valid event to request (the channel will already have been captured to get this far).
sl@0
   677
	// Also ensure that requests for EGeneralBusError are removed, since they are redundant (a notification
sl@0
   678
	// for a bus error is unconditional) and just represent overhead.
sl@0
   679
	trigger &= ~(EAsyncCaptChan | EGeneralBusError);
sl@0
   680
sl@0
   681
	iReqTrig = (TInt8)trigger; 				// Not atomic access since only client thread modifies iReqTrig
sl@0
   682
	iAccumTrig = 0;						// New transfer, so initialise accumulated event record
sl@0
   683
	TInt reqFlags=0;
sl@0
   684
	// Overrun and/or underrun may be requested if Client is unsure how much data is to follow,
sl@0
   685
	// so need to instigate Rx/Tx operation for any such request
sl@0
   686
	if(iReqTrig & (ERxOverrun|ERxUnderrun|ERxAllBytes))
sl@0
   687
		{
sl@0
   688
		reqFlags |= EReceive;
sl@0
   689
		}
sl@0
   690
	if(iReqTrig & (ETxOverrun|ETxUnderrun|ETxAllBytes))
sl@0
   691
		{
sl@0
   692
		reqFlags |= ETransmit;
sl@0
   693
		}
sl@0
   694
	TInt r = DoRequest(reqFlags);
sl@0
   695
	if(r != KErrNone)
sl@0
   696
		{
sl@0
   697
		// PSL encountered an error in intiating the requested trigger. Set the return value accordingly.
sl@0
   698
		// Assume triggers have been cancelled - if they have not, the client-provided callback will still
sl@0
   699
		// be invoked, but it will have been warned to expecte erroneous behaviour by the value assigned to retVal.
sl@0
   700
		iReqTrig = 0;
sl@0
   701
		retVal = KErrGeneral;
sl@0
   702
		}
sl@0
   703
	else	// PSL accepted the request, so update timer and state information
sl@0
   704
		{
sl@0
   705
		switch (iTimerState)
sl@0
   706
			{
sl@0
   707
			case DIicBusChannelSlave::EInactive:
sl@0
   708
				{
sl@0
   709
				// Do not start the timer. Must wait for the Master to access a Slave buffer before considering
sl@0
   710
				// a transaction as started.
sl@0
   711
				break;
sl@0
   712
				}
sl@0
   713
			case DIicBusChannelSlave::EWaitForClient:
sl@0
   714
				{
sl@0
   715
				// Client has responded within the given time period. The next state is
sl@0
   716
				// dependent on the requested trigger - if set to zero, the Client is explicitly
sl@0
   717
				// ending the transaction, so the next state is EInactive; otherwise, the
sl@0
   718
				// Client has indicated the next action expected from the Master and so the
sl@0
   719
				// timer is started and next state is EWaitForMaster
sl@0
   720
				if(iReqTrig == 0)
sl@0
   721
					{
sl@0
   722
					iTimerState = DIicBusChannelSlave::EInactive;
sl@0
   723
					}
sl@0
   724
				else
sl@0
   725
					{
sl@0
   726
					iTimerState = DIicBusChannelSlave::EWaitForMaster;
sl@0
   727
					StartTimerByState();
sl@0
   728
					}
sl@0
   729
				break;
sl@0
   730
				}
sl@0
   731
			case DIicBusChannelSlave::EClientTimeout:
sl@0
   732
				{
sl@0
   733
				// For the previous transfer, the Client failed to respond within the required time - and
sl@0
   734
				// the PSL will have been instructed to indicate a bus error (so the Master
sl@0
   735
				// will have been informed). The error code returned by this function will be KErrTimedOut
sl@0
   736
				// so the Client will be informed of what has happened.
sl@0
   737
				// A transaction is considered to start when the Slave is addressed by the Master
sl@0
   738
				// (as indicated by the PSL invoking NotifyClient) - which has not yet happened -
sl@0
   739
				// so the next state is EInactive.
sl@0
   740
				iTimerState=DIicBusChannelSlave::EInactive;
sl@0
   741
				break;
sl@0
   742
				}
sl@0
   743
			case DIicBusChannelSlave::EWaitForMaster:
sl@0
   744
				{
sl@0
   745
				// In this case we are handling a new requested trigger from the client to handle ERxOverrun or
sl@0
   746
				// ETxUnderrun. The PSL has accepted the new trigger, so must allow the Master sufficient time
sl@0
   747
				// to perform the newly-requested transfer; the timer has already been stopped, so just start it again..
sl@0
   748
				StartTimerByState();
sl@0
   749
				break;
sl@0
   750
				}
sl@0
   751
			default:
sl@0
   752
				{
sl@0
   753
				__ASSERT_DEBUG(0, Kern::Fault(KIicChannelPanic,__LINE__));
sl@0
   754
				break;
sl@0
   755
				}
sl@0
   756
			}
sl@0
   757
		}
sl@0
   758
sl@0
   759
	return retVal;
sl@0
   760
	}
sl@0
   761
#else /*SLAVE_MODE*/
sl@0
   762
sl@0
   763
TInt DIicBusChannelSlave::CaptureChannel(TDes8* /*aConfigHdr*/, TIicBusSlaveCallback* /*aCallback*/, TInt& /*aChannelId*/, TBool /*aAsynch*/)
sl@0
   764
	{
sl@0
   765
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::CaptureChannel invoked when not in SLAVE_MODE!\n"));
sl@0
   766
	 return KErrNotSupported;
sl@0
   767
	}
sl@0
   768
sl@0
   769
TInt DIicBusChannelSlave::ReleaseChannel()
sl@0
   770
	{
sl@0
   771
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::ReleaseChannel invoked when not in SLAVE_MODE!\n"));
sl@0
   772
	 return KErrNotSupported;
sl@0
   773
	}
sl@0
   774
sl@0
   775
TInt DIicBusChannelSlave::RegisterRxBuffer(TPtr8 /*aRxBuffer*/, TInt8 /*aBufGranularity*/, TInt8 /*aNumWords*/, TInt8 /*aOffset*/)
sl@0
   776
	{
sl@0
   777
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::RegisterRxBuffer invoked when not in SLAVE_MODE!\n"));
sl@0
   778
	 return KErrNotSupported;
sl@0
   779
	}
sl@0
   780
sl@0
   781
TInt DIicBusChannelSlave::RegisterTxBuffer(TPtr8 /*aTxBuffer*/, TInt8 /*aBufGranularity*/, TInt8 /*aNumWords*/, TInt8 /*aOffset*/)
sl@0
   782
	{
sl@0
   783
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::RegisterTxBuffer invoked when not in SLAVE_MODE!\n"));
sl@0
   784
	 return KErrNotSupported;
sl@0
   785
	}
sl@0
   786
sl@0
   787
TInt DIicBusChannelSlave::SetNotificationTrigger(TInt /*aTrigger*/)
sl@0
   788
	{
sl@0
   789
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::SetNotificationTrigger invoked when not in SLAVE_MODE!\n"));
sl@0
   790
	 return KErrNotSupported;
sl@0
   791
	}
sl@0
   792
#endif/*SLAVE_MODE*/
sl@0
   793
sl@0
   794
DIicBusChannelSlave::DIicBusChannelSlave(TBusType aBusType, TChannelDuplex aChanDuplex, TInt16 aChannelId)
sl@0
   795
	: DIicBusChannel(DIicBusChannel::ESlave, aBusType, aChanDuplex),
sl@0
   796
	iChannelId(aChannelId), iTimerState(EInactive),
sl@0
   797
	iMasterWaitTime(KSlaveDefMWaitTime), iClientWaitTime(KSlaveDefCWaitTime),
sl@0
   798
	iSpinLock(TSpinLock::EOrderGenericIrqLow2)  // Semi-arbitrary, low priority value
sl@0
   799
	{
sl@0
   800
#ifndef STANDALONE_CHANNEL
sl@0
   801
	iController = NULL;
sl@0
   802
#endif
sl@0
   803
	}
sl@0
   804
sl@0
   805
DIicBusChannelSlave::~DIicBusChannelSlave()
sl@0
   806
    {
sl@0
   807
    delete iClientTimeoutDfc;
sl@0
   808
    }
sl@0
   809
sl@0
   810
void DIicBusChannelSlave::SlaveStaticCB(TAny* aPtr)
sl@0
   811
	{
sl@0
   812
	DIicBusChannelSlave* chan = (DIicBusChannelSlave*)aPtr;
sl@0
   813
	chan->SlaveTimerCallBack();
sl@0
   814
	return;
sl@0
   815
	}
sl@0
   816
sl@0
   817
TInt DIicBusChannelSlave::Init()
sl@0
   818
	{
sl@0
   819
	iClientTimeoutDfc = new TDfc(SlaveStaticCB,(TAny*)this, 7);	// Highest Dfc priority
sl@0
   820
	if(!iClientTimeoutDfc)
sl@0
   821
		return KErrNoMemory;
sl@0
   822
	else
sl@0
   823
		return KErrNone;
sl@0
   824
	}
sl@0
   825
sl@0
   826
void DIicBusChannelSlave::ChanCaptureCallback(TInt aResult)
sl@0
   827
	{
sl@0
   828
    __KTRACE_OPT(KIIC, Kern::Printf("ChanCaptureCallback: aChannel=0x%x, aResult=%d\n",this,aResult));
sl@0
   829
sl@0
   830
	TInt r=aResult;
sl@0
   831
	TInt channelId = 0;
sl@0
   832
	if(aResult == KErrNone)
sl@0
   833
		{
sl@0
   834
		SetChannelId(channelId);
sl@0
   835
#ifndef STANDALONE_CHANNEL
sl@0
   836
		__ASSERT_DEBUG(iController, Kern::Fault(KIicChannelPanic,__LINE__));
sl@0
   837
		iController->InstallCapturedChannel(channelId, this);
sl@0
   838
#endif
sl@0
   839
		iClientTimeoutDfc->SetDfcQ(iNotif->iDfcQ);
sl@0
   840
		r=KErrCompletion;
sl@0
   841
		}
sl@0
   842
	else
sl@0
   843
		ReleaseChannel();
sl@0
   844
sl@0
   845
#ifdef IIC_INSTRUMENTATION_MACRO
sl@0
   846
	IIC_SCAPTCHANASYNC_END_PIL_TRACE;
sl@0
   847
#endif
sl@0
   848
	CompleteAsynchCapture(r);	// Queue the client callback for execution
sl@0
   849
	}
sl@0
   850
sl@0
   851
void DIicBusChannelSlave::SlaveTimerCallBack()
sl@0
   852
	{
sl@0
   853
    __KTRACE_OPT(KIIC, Kern::Printf("SlaveTimerCallBack"));
sl@0
   854
	if(iTimerState == DIicBusChannelSlave::EWaitForMaster)
sl@0
   855
		{
sl@0
   856
		// Master timeout. Consider the transaction terminated - call NotifyClient
sl@0
   857
		// to inform both the Client and the PSL, and update the state machine
sl@0
   858
		NotifyClient(EGeneralBusError);
sl@0
   859
		}
sl@0
   860
	else if(iTimerState == DIicBusChannelSlave::EWaitForClient)
sl@0
   861
		{
sl@0
   862
		// Client timeout. Instigate the PSL-specific bus error indication
sl@0
   863
		iTimerState=DIicBusChannelSlave::EClientTimeout;
sl@0
   864
		SendBusErrorAndReturn();
sl@0
   865
		}
sl@0
   866
	else
sl@0
   867
		{
sl@0
   868
		__ASSERT_DEBUG(0, Kern::Fault(KIicChannelPanic,__LINE__));
sl@0
   869
		}
sl@0
   870
	}
sl@0
   871
sl@0
   872
sl@0
   873
void DIicBusChannelSlave::StartTimerByState()
sl@0
   874
	{
sl@0
   875
	if(iTimerState == DIicBusChannelSlave::EWaitForMaster)
sl@0
   876
		{
sl@0
   877
		iTimeoutTimer.OneShot(NKern::TimerTicks(iMasterWaitTime),(*iClientTimeoutDfc));
sl@0
   878
		}
sl@0
   879
	else if(iTimerState == DIicBusChannelSlave::EWaitForClient)
sl@0
   880
		{
sl@0
   881
		iTimeoutTimer.OneShot(NKern::TimerTicks(iClientWaitTime),(*iClientTimeoutDfc));
sl@0
   882
		}
sl@0
   883
	else
sl@0
   884
		{
sl@0
   885
		__ASSERT_DEBUG(NULL, Kern::Fault(KIicChannelPanic,__LINE__));
sl@0
   886
		}
sl@0
   887
	}
sl@0
   888
sl@0
   889
void DIicBusChannelSlave::StopTimer()
sl@0
   890
	{
sl@0
   891
	iTimeoutTimer.Cancel();
sl@0
   892
	}
sl@0
   893
sl@0
   894
TInt DIicBusChannelSlave::UpdateReqTrig(TInt8& aCbTrigVal, TInt& aCallbackRet)
sl@0
   895
	{
sl@0
   896
    __KTRACE_OPT(KIIC, Kern::Printf("UpdateReqTrig"));
sl@0
   897
sl@0
   898
	TInt nextSteps = 0;
sl@0
   899
	iAccumTrig |= iNotif->iTrigger;	// Update the accumulated event history, regardless of if the trigger was requested
sl@0
   900
sl@0
   901
	if(iNotif->iTrigger & EGeneralBusError)
sl@0
   902
		{
sl@0
   903
		// In the event of a bus error, always cancel the timer and call the Client callback
sl@0
   904
		nextSteps |= (EStopTimer | EInvokeCb);
sl@0
   905
		iTimerState = EInactive;
sl@0
   906
		aCallbackRet = KErrGeneral;
sl@0
   907
		}
sl@0
   908
	else if(iNotif->iTrigger == EAsyncCaptChan)
sl@0
   909
		{
sl@0
   910
		// For asynchronous channel capture, no timers are involved - just call the Client callback
sl@0
   911
		nextSteps |= EInvokeCb;
sl@0
   912
		aCallbackRet = KErrCompletion;
sl@0
   913
		}
sl@0
   914
	else if((iNotif->iTrigger & iReqTrig) != 0)
sl@0
   915
		{
sl@0
   916
		// If a requested Rx event has occurred, clear all Rx flags from the requested triggers (similarly for Tx)
sl@0
   917
		if(iNotif->iTrigger & (ERxAllBytes | ERxUnderrun | ERxOverrun))
sl@0
   918
			{
sl@0
   919
			iReqTrig &= ~(ERxAllBytes | ERxUnderrun | ERxOverrun);
sl@0
   920
			}
sl@0
   921
		if(iNotif->iTrigger & (ETxAllBytes | ETxUnderrun | ETxOverrun))
sl@0
   922
			{
sl@0
   923
			iReqTrig &= ~(ETxAllBytes | ETxUnderrun | ETxOverrun);
sl@0
   924
			}
sl@0
   925
sl@0
   926
		if(iTimerState == EInactive)
sl@0
   927
			{
sl@0
   928
			nextSteps |= (EStartTimer | EInvokeCb);
sl@0
   929
			// The next state in the state machine depends on if all the requested events have occurred
sl@0
   930
			if(iReqTrig == 0)
sl@0
   931
				{
sl@0
   932
				// All triggers required have occurred, so transition to state EWaitForClient
sl@0
   933
				iTimerState = EWaitForClient;
sl@0
   934
				}
sl@0
   935
			else
sl@0
   936
				{
sl@0
   937
				// The Client can request both Rx an Tx triggers; if only one has occurred, must wait for
sl@0
   938
				// the Master to generate the other
sl@0
   939
				iTimerState = EWaitForMaster;
sl@0
   940
				}
sl@0
   941
			aCallbackRet = KErrNone;
sl@0
   942
			}
sl@0
   943
		else if(iTimerState == EWaitForMaster)
sl@0
   944
			{
sl@0
   945
			// The next state in the state machine depends on if all the requested events have occurred
sl@0
   946
			if(iReqTrig == 0)
sl@0
   947
				{
sl@0
   948
				// All triggers required have occurred, so transition to state EWaitForClient
sl@0
   949
				iTimerState = EWaitForClient;
sl@0
   950
				nextSteps |= (EStopTimer | EInvokeCb | EStartTimer);
sl@0
   951
				}
sl@0
   952
			else
sl@0
   953
				{
sl@0
   954
				// The Client can request both Rx an Tx triggers; if only one has occurred, must wait for
sl@0
   955
				// the Master to generate the other - so remain in this state, do not cancel the timer or
sl@0
   956
				// re-start it with a new timeout period. Still invoke the callback to notify the client
sl@0
   957
				// that at least one of the requested triggers has occurred.
sl@0
   958
				nextSteps |= EInvokeCb;
sl@0
   959
				}
sl@0
   960
			aCallbackRet = KErrNone;
sl@0
   961
			}
sl@0
   962
		else if((iTimerState == EWaitForClient) || (iTimerState == EClientTimeout))
sl@0
   963
			{
sl@0
   964
			// No triggers are expected in these states (iReqTrig==0).
sl@0
   965
			__ASSERT_DEBUG(NULL, Kern::Fault(KIicChannelPanic,__LINE__));
sl@0
   966
			}
sl@0
   967
		}
sl@0
   968
	aCbTrigVal = iAccumTrig;
sl@0
   969
	return nextSteps;
sl@0
   970
	}
sl@0
   971
sl@0
   972
sl@0
   973
void DIicBusChannelSlave::NotifyClient(TInt aTrigger)
sl@0
   974
	{
sl@0
   975
	TIicBusSlaveCallback* notif = iNotif;
sl@0
   976
	notif->iTrigger = aTrigger;	// Ensure ProcessData is provided with the trigger
sl@0
   977
sl@0
   978
	if(NKern::CurrentContext() == NKern::EThread && &(Kern::CurrentThread()) == iClient)
sl@0
   979
		{
sl@0
   980
		// PSL will update notif to represent the events that have occurred
sl@0
   981
		ProcessData(aTrigger, notif);
sl@0
   982
		// Only invoke the client's callback (and update the state machine) if one of the requested triggers has
sl@0
   983
		// occurred or if a bus error has been witnessed
sl@0
   984
		TInt8 callbackTrig=0;
sl@0
   985
		TInt callbackRet=0;
sl@0
   986
		TInt nextSteps = UpdateReqTrig(callbackTrig, callbackRet);
sl@0
   987
		if(nextSteps & EStopTimer)
sl@0
   988
			{
sl@0
   989
			iTimeoutTimer.Cancel();
sl@0
   990
			}
sl@0
   991
		if(nextSteps & EInvokeCb)
sl@0
   992
			{
sl@0
   993
			(notif->iCallback)(notif->iChannelId, (TInt)callbackRet, callbackTrig, notif->iRxWords, notif->iTxWords, notif->iParam);
sl@0
   994
			// Callback now processed, so re-initialise callback object members
sl@0
   995
			notif->iTrigger=0;
sl@0
   996
			notif->iReturn=KErrNone;
sl@0
   997
			notif->iRxWords=0;
sl@0
   998
			notif->iTxWords=0;
sl@0
   999
			iAccumTrig = 0;	// and re-initialise the accumulated history as the transaction is considered terminated
sl@0
  1000
			}
sl@0
  1001
		if(nextSteps & EStartTimer)
sl@0
  1002
			{
sl@0
  1003
			StartTimerByState();
sl@0
  1004
			}
sl@0
  1005
		}
sl@0
  1006
	else if(NKern::CurrentContext() == NKern::EInterrupt)
sl@0
  1007
			notif->Add();
sl@0
  1008
	else
sl@0
  1009
		notif->Enque();
sl@0
  1010
	}
sl@0
  1011
sl@0
  1012
TInt DIicBusChannelSlave::SetMasterWaitTime(TInt8 aWaitTime)
sl@0
  1013
	{
sl@0
  1014
	if((aWaitTime<0)||(aWaitTime>KMaxWaitTime))
sl@0
  1015
		return KErrArgument;
sl@0
  1016
	iMasterWaitTime=aWaitTime;
sl@0
  1017
	return KErrNone;
sl@0
  1018
	}
sl@0
  1019
sl@0
  1020
TInt DIicBusChannelSlave::SetClientWaitTime(TInt8 aWaitTime)
sl@0
  1021
	{
sl@0
  1022
	if((aWaitTime<0)||(aWaitTime>KMaxWaitTime))
sl@0
  1023
		return KErrArgument;
sl@0
  1024
	iClientWaitTime=aWaitTime;
sl@0
  1025
	return KErrNone;
sl@0
  1026
	}
sl@0
  1027
sl@0
  1028
void DIicBusChannelSlave::SendBusErrorAndReturn()
sl@0
  1029
	{
sl@0
  1030
	DoRequest(EAbort);
sl@0
  1031
	}
sl@0
  1032
sl@0
  1033
void DIicBusChannelSlave::SetChannelId(TInt& aChannelId)
sl@0
  1034
    {
sl@0
  1035
    ++iInstanceCount;
sl@0
  1036
    aChannelId = (iInstanceCount<<16);
sl@0
  1037
    //
sl@0
  1038
    // The PSL-specific channel identifier was stored in this generic class' member iChannelId at registration time
sl@0
  1039
    aChannelId |= iChannelId;
sl@0
  1040
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::SetChannelId: iInstanceCount=0x%x, iChannelId=0x%x returned aChannelId=0x%x\n",iInstanceCount,iChannelId,aChannelId));
sl@0
  1041
    iNotif->iChannelId=aChannelId;
sl@0
  1042
    }
sl@0
  1043
sl@0
  1044
void DIicBusChannelSlave::CompleteAsynchCapture(TInt aResult)
sl@0
  1045
    {
sl@0
  1046
    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusChannelSlave::CompleteAsynchCapture aResult = %d",aResult));
sl@0
  1047
    if(NKern::CurrentContext() == NKern::EThread && &Kern::CurrentThread() == iClient)
sl@0
  1048
        {
sl@0
  1049
        iNotif->iCallback(iNotif->iChannelId, aResult, EAsyncCaptChan, NULL, NULL, iNotif->iParam);
sl@0
  1050
        return;
sl@0
  1051
        }
sl@0
  1052
    else
sl@0
  1053
        {
sl@0
  1054
        iNotif->iReturn=aResult;
sl@0
  1055
        iNotif->iTrigger=EAsyncCaptChan;
sl@0
  1056
        iNotif->iTxWords=NULL;
sl@0
  1057
        iNotif->iRxWords=NULL;
sl@0
  1058
        }
sl@0
  1059
    if(NKern::CurrentContext() == NKern::EInterrupt)
sl@0
  1060
        iNotif->Add();
sl@0
  1061
    else
sl@0
  1062
        iNotif->Enque();
sl@0
  1063
    }
sl@0
  1064
sl@0
  1065
TInt DIicBusChannelSlave::StaticExtension(TUint /*aFunction*/, TAny* /*aParam1*/, TAny* /*aParam*/)
sl@0
  1066
 	{
sl@0
  1067
 	return KErrNotSupported;
sl@0
  1068
 	}
sl@0
  1069
sl@0
  1070
TInt DIicBusChannelSlave::Spare1(TInt /*aVal*/, TAny* /*aPtr1*/, TAny* /*aPtr2*/)
sl@0
  1071
	{
sl@0
  1072
	return KErrNotSupported;
sl@0
  1073
	}
sl@0
  1074
sl@0
  1075
TInt DIicBusChannelMasterSlave::QueueTransaction(TIicBusTransaction* aTransaction)
sl@0
  1076
	{
sl@0
  1077
	return QueueTransaction(aTransaction,NULL);
sl@0
  1078
	};
sl@0
  1079
sl@0
  1080
TInt DIicBusChannelMasterSlave::QueueTransaction(TIicBusTransaction* aTransaction, TIicBusCallback* aCallback)
sl@0
  1081
	{
sl@0
  1082
	TInt r=KErrNone;
sl@0
  1083
	iMasterChannel->Lock();
sl@0
  1084
	if(iSlaveChannel->iChannelInUse)
sl@0
  1085
		r=KErrInUse;
sl@0
  1086
	else
sl@0
  1087
		{
sl@0
  1088
		TInt16 count=(TInt16)((iMasterChannel->iTransCount)&~KTransCountMsBit);
sl@0
  1089
		if(count<~KTransCountMsBit)
sl@0
  1090
			{
sl@0
  1091
			++count;
sl@0
  1092
			count|=KTransCountMsBit;
sl@0
  1093
			}
sl@0
  1094
		else
sl@0
  1095
			r=KErrInUse;
sl@0
  1096
		}
sl@0
  1097
	iMasterChannel->Unlock();
sl@0
  1098
	if(r == KErrNone)
sl@0
  1099
		r=(iMasterChannel->QueueTransaction(aTransaction, aCallback));
sl@0
  1100
	return r;
sl@0
  1101
	};
sl@0
  1102
sl@0
  1103
TInt DIicBusChannelMasterSlave::CaptureChannel(TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch)
sl@0
  1104
	{
sl@0
  1105
	iMasterChannel->Lock();
sl@0
  1106
	TInt r=KErrNone;
sl@0
  1107
	if(iSlaveChannel->iChannelInUse)
sl@0
  1108
		r=KErrInUse;
sl@0
  1109
	else
sl@0
  1110
		{
sl@0
  1111
		if(iMasterChannel->IsMasterBusy())
sl@0
  1112
			r=KErrInUse;
sl@0
  1113
		else
sl@0
  1114
			iSlaveChannel->iChannelInUse = 1;
sl@0
  1115
		}
sl@0
  1116
	iMasterChannel->Unlock();
sl@0
  1117
	if(r == KErrNone)
sl@0
  1118
		r=iSlaveChannel->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch);
sl@0
  1119
	return r;
sl@0
  1120
	};
sl@0
  1121
sl@0
  1122
sl@0
  1123
TInt DIicBusChannelMasterSlave::ReleaseChannel()
sl@0
  1124
    {
sl@0
  1125
	iMasterChannel->Lock();
sl@0
  1126
	TInt r=iSlaveChannel->ReleaseChannel();
sl@0
  1127
	iMasterChannel->Unlock();
sl@0
  1128
	return r;
sl@0
  1129
	};
sl@0
  1130
sl@0
  1131
TInt DIicBusChannelMasterSlave::StaticExtension(TUint /*aFunction*/, TAny* /*aParam1*/, TAny* /*aParam*/)
sl@0
  1132
 	{
sl@0
  1133
 	return KErrNotSupported;
sl@0
  1134
 	}
sl@0
  1135
sl@0
  1136
#ifdef STANDALONE_CHANNEL
sl@0
  1137
EXPORT_C DIicBusChannelMasterSlave::DIicBusChannelMasterSlave(TBusType aBusType, TChannelDuplex aChanDuplex, DIicBusChannelMaster* aMasterChan, DIicBusChannelSlave* aSlaveChan)
sl@0
  1138
    : DIicBusChannel(DIicBusChannel::EMasterSlave, aBusType, aChanDuplex),
sl@0
  1139
    iMasterChannel(aMasterChan),
sl@0
  1140
    iSlaveChannel(aSlaveChan)
sl@0
  1141
    {
sl@0
  1142
    //If in stand-alone channel mode, the client assigns a channel number to the MasterSlave channel it creates.
sl@0
  1143
    }
sl@0
  1144
#endif
sl@0
  1145