os/kernelhwsrv/kernel/eka/drivers/iic/iic.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
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".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // e32\drivers\iic.cpp
    15 // IIC Controller and public API Implementation
    16 //
    17 
    18 #include <drivers/iic.h>
    19 #include <drivers/iic_channel.h>
    20 #include "iic_priv.h"
    21 
    22 #ifdef IIC_INSTRUMENTATION_MACRO
    23 #include <drivers/iic_trace.h>
    24 #endif
    25 
    26 // Global Controller pointer
    27 static DIicBusController* TheController = NULL;
    28 
    29 //
    30 //		Implementation of generic IicBus API for client interface
    31 //
    32 EXPORT_C TInt IicBus::QueueTransaction(TInt aBusId, TIicBusTransaction* aTransaction)
    33 	{
    34 #ifdef IIC_INSTRUMENTATION_MACRO
    35 	IIC_MQTRANSSYNC_START_PIL_TRACE;
    36 #endif
    37 	TInt r=TheController->QueueTransaction(aBusId, aTransaction);
    38 
    39 #ifdef IIC_INSTRUMENTATION_MACRO
    40 	IIC_MQTRANSSYNC_END_PIL_TRACE;
    41 #endif
    42 	return r;
    43 	}
    44 
    45 EXPORT_C TInt IicBus::QueueTransaction(TInt aBusId, TIicBusTransaction* aTransaction, TIicBusCallback* aCallback)
    46 	{
    47 #ifdef IIC_INSTRUMENTATION_MACRO
    48 	IIC_MQTRANSASYNC_START_PIL_TRACE;
    49 #endif
    50 	TInt r=TheController->QueueTransaction(aBusId, aTransaction, aCallback);
    51 
    52 #ifdef IIC_INSTRUMENTATION_MACRO
    53 	IIC_MQTRANSASYNC_END_PIL_TRACE;
    54 #endif
    55 	return r;
    56 	}
    57 
    58 EXPORT_C TInt IicBus::CancelTransaction(TInt aBusId, TIicBusTransaction* aTransaction)
    59 	{
    60 #ifdef IIC_INSTRUMENTATION_MACRO
    61 	IIC_MCANCELTRANS_START_PIL_TRACE;
    62 #endif
    63 	TInt r=TheController->CancelTransaction(aBusId, aTransaction);
    64 
    65 #ifdef IIC_INSTRUMENTATION_MACRO
    66 	IIC_MCANCELTRANS_END_PIL_TRACE;
    67 #endif
    68 	return r;
    69 	}
    70 
    71 EXPORT_C TInt IicBus::CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch)
    72 	{
    73 #ifdef IIC_INSTRUMENTATION_MACRO
    74 	if(!aAsynch)
    75 		{
    76 		IIC_SCAPTCHANSYNC_START_PIL_TRACE;
    77 		}
    78 	else
    79 		{
    80 		IIC_SCAPTCHANASYNC_START_PIL_TRACE;
    81 		}
    82 #endif
    83 	TInt r=TheController->CaptureChannel(aBusId, aConfigHdr, aCallback, aChannelId, aAsynch);
    84 
    85 #ifdef IIC_INSTRUMENTATION_MACRO
    86 	if(!aAsynch)
    87 		{
    88 		IIC_SCAPTCHANSYNC_END_PIL_TRACE;
    89 		}
    90 #endif
    91 	return r;
    92 	}
    93 
    94 EXPORT_C TInt IicBus::ReleaseChannel(TInt aChannelId)
    95 	{
    96 #ifdef IIC_INSTRUMENTATION_MACRO
    97 	IIC_SRELCHAN_START_PIL_TRACE;
    98 #endif
    99 	TInt r=TheController->ReleaseChannel(aChannelId);
   100 
   101 #ifdef IIC_INSTRUMENTATION_MACRO
   102 	IIC_SRELCHAN_END_PIL_TRACE;
   103 #endif
   104 	return r;
   105 	}
   106 
   107 EXPORT_C TInt IicBus::RegisterRxBuffer(TInt aChannelId, TPtr8 aRxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
   108 	{
   109 #ifdef IIC_INSTRUMENTATION_MACRO
   110 	IIC_SREGRXBUF_START_PIL_TRACE;
   111 #endif
   112 	TInt r=TheController->RegisterRxBuffer(aChannelId, aRxBuffer, aBufGranularity, aNumWords, aOffset);
   113 
   114 #ifdef IIC_INSTRUMENTATION_MACRO
   115 	IIC_SREGRXBUF_END_PIL_TRACE;
   116 #endif
   117 	return r;
   118 	}
   119 
   120 EXPORT_C TInt IicBus::RegisterTxBuffer(TInt aChannelId, TPtr8 aTxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
   121 	{
   122 #ifdef IIC_INSTRUMENTATION_MACRO
   123 	IIC_SREGTXBUF_START_PIL_TRACE;
   124 #endif
   125 	TInt r=TheController->RegisterTxBuffer(aChannelId, aTxBuffer, aBufGranularity, aNumWords, aOffset);
   126 
   127 #ifdef IIC_INSTRUMENTATION_MACRO
   128 	IIC_SREGTXBUF_END_PIL_TRACE;
   129 #endif
   130 	return r;
   131 	}
   132 
   133 EXPORT_C TInt IicBus::SetNotificationTrigger(TInt aChannelId, TInt aTrigger)
   134 	{
   135 #ifdef IIC_INSTRUMENTATION_MACRO
   136 	IIC_SNOTIFTRIG_START_PIL_TRACE;
   137 #endif
   138 	TInt r=TheController->SetNotificationTrigger(aChannelId, aTrigger);
   139 
   140 #ifdef IIC_INSTRUMENTATION_MACRO
   141 	IIC_SNOTIFTRIG_END_PIL_TRACE;
   142 #endif
   143 	return r;
   144 	}
   145 
   146 EXPORT_C TInt IicBus::StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2)
   147 	{
   148 	return(TheController->StaticExtension(aId, aFunction, aParam1, aParam2));
   149 	}
   150 
   151 
   152 //
   153 //		Bus Controller
   154 //
   155 
   156 //  auxiliary function for ordering entries in the array of channels
   157 TInt DIicBusController::OrderEntries(const DIicBusChannel& aMatch, const DIicBusChannel& aEntry)
   158 	{
   159 	TUint8 l=(TUint8)aMatch.ChannelNumber();
   160 	TUint8 r=(TUint8)aEntry.ChannelNumber();
   161 	if(l>r)
   162 		return -1;
   163 	else if(l<r)
   164 		return 1;
   165 	else
   166 		return 0;
   167 	}
   168 
   169 // global ordering object to be passed to RPointerArray InsertInOrderXXX and FindInOrder
   170 TLinearOrder<DIicBusChannel> EntryOrder(DIicBusController::OrderEntries);
   171 
   172 // Implementation for DIicBusController
   173 //
   174 
   175 TInt DIicBusController::Create()
   176 	{
   177 	TInt r=KErrNone;
   178 	iChanLock = new TSpinLock(TSpinLock::EOrderGenericIrqLow2);  // Semi-arbitrary, low priority value
   179 	iCaptLock = new TSpinLock(TSpinLock::EOrderGenericIrqLow2);  // Semi-arbitrary, low priority value
   180 	if((iChanLock == NULL)||(iCaptLock == NULL))
   181 		{
   182 		delete iChanLock;
   183 		delete iCaptLock;
   184 		r=KErrNoMemory;
   185 		}
   186 	return r;
   187 	}
   188 
   189 DIicBusController::~DIicBusController()
   190 	{
   191 #ifdef IIC_SIMULATED_PSL
   192 	for(TInt i=0; i<iChannelArray.Count(); i++)
   193 		{
   194 		DIicBusChannel* ptr=iChannelArray[i];
   195 		// Remove the channel from the array
   196 		iChannelArray.Remove(i);
   197 		// Delete the channel object
   198 		delete ptr;
   199 		};
   200 
   201 	iChannelArray.Reset();
   202 	delete iChanLock;
   203 	delete iCaptLock;
   204 #endif
   205 	}
   206 
   207 TInt DIicBusController::GetChanWriteAccess()
   208 	{
   209 	// Can only have one insertion or removal active at any one time
   210 	// Can not perform an insertion or removal while a read is in progress
   211 	// If either of the two above conditions exist, return KErrInUse
   212 	// Otherwise, set the flag to indicate that a write is in progress
   213 	// and return KErrNone.
   214 	TInt chanIntState=0;
   215 	chanIntState=__SPIN_LOCK_IRQSAVE(*iChanLock);
   216 	if(iChanRwFlags != 0)
   217 		{
   218 		__SPIN_UNLOCK_IRQRESTORE(*iChanLock,chanIntState);
   219 		return KErrInUse;
   220 		}
   221 	iChanRwFlags |= EWriteInProgress;
   222 	__SPIN_UNLOCK_IRQRESTORE(*iChanLock,chanIntState);
   223 	return KErrNone;
   224 	}
   225 
   226 void DIicBusController::FreeChanWriteAccess()
   227 	{
   228 	// If an insertion or removal is in progress, no other modifying operation
   229 	// can be active. Reads are also not permitted - so iChanRwFlags can only be
   230 	// EWriteInProgress.
   231 	__ASSERT_DEBUG(iChanRwFlags == EWriteInProgress, Kern::Fault(KIicPanic,__LINE__));
   232 	TInt chanIntState=0;
   233  	chanIntState=__SPIN_LOCK_IRQSAVE(*iChanLock);
   234  	iChanRwFlags &= ~EWriteInProgress;
   235  	__SPIN_UNLOCK_IRQRESTORE(*iChanLock,chanIntState);
   236 	}
   237 
   238 TInt DIicBusController::GetChanReadAccess()
   239 	{
   240 	// No reads are permitted while an insertion or removal is in progress
   241 	// If one of the above operations is in progress return KErrInUse
   242 	// Can have several concurrent reads at any one time - so increment
   243 	// the count of such operations as well as ensuring the flag is set to indicate
   244 	// a read is in progress
   245 	TInt chanIntState=0;
   246 	chanIntState=__SPIN_LOCK_IRQSAVE(*iChanLock);
   247 	if(iChanRwFlags == EWriteInProgress)
   248 		{
   249 		__SPIN_UNLOCK_IRQRESTORE(*iChanLock,chanIntState);
   250 		return KErrInUse;
   251 		}
   252 	__ASSERT_DEBUG(iChanRdCount!=0xFFFFFFFF, Kern::Fault(KIicPanic,__LINE__)); // Overflow
   253 	iChanRdCount++;
   254 	iChanRwFlags |= EReadInProgress;
   255 	__SPIN_UNLOCK_IRQRESTORE(*iChanLock,chanIntState);
   256 	return KErrNone;
   257 	}
   258 
   259 void DIicBusController::FreeChanReadAccess()
   260 	{
   261 	// No insertions or removals are permitted while a read is in progress
   262 	// so iChanRwFlags can only be EReadInProgress
   263 	// Multiple reads can be in progress concurrently, so the count must be decremented
   264 	TInt chanIntState=0;
   265 	chanIntState=__SPIN_LOCK_IRQSAVE(*iChanLock);
   266 	__ASSERT_DEBUG(iChanRwFlags == EReadInProgress, Kern::Fault(KIicPanic,__LINE__));
   267 	__ASSERT_DEBUG(iChanRdCount>0, Kern::Fault(KIicPanic,__LINE__));
   268 	iChanRdCount--;
   269 	if(iChanRdCount == 0)
   270 		iChanRwFlags &= ~EReadInProgress;
   271 	__SPIN_UNLOCK_IRQRESTORE(*iChanLock,chanIntState);
   272 	}
   273 
   274 TInt DIicBusController::RequestTypeSupported(const TInt aBusId, DIicBusChannelMaster* const aChannel)
   275 	{
   276 	TInt32 reqBusType;
   277 	reqBusType = GET_BUS_TYPE(aBusId);
   278 	__KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::RequestTypeSupported, BusType=0x%x\n", reqBusType));
   279 
   280 	if(reqBusType != aChannel->BusType())
   281 		{
   282 		return KErrNotSupported;
   283 		}
   284 
   285 	return KErrNone;
   286 	}
   287 
   288 
   289 EXPORT_C TInt DIicBusController::RegisterChannels(DIicBusChannel** aListChannels, TInt aNumberChannels)
   290 	{
   291 // To be used by Channel implementations to register a list of supported channels
   292     __KTRACE_OPT(KIIC, Kern::Printf("\nDIicBusController::RegisterChannels, aListChannels=0x%x, aNumberChannels=%d\n",aListChannels,aNumberChannels));
   293 	__ASSERT_DEBUG(aListChannels!=NULL, Kern::Fault(KIicPanic,__LINE__));
   294 
   295 	RPointerArray<DIicBusChannel>* chanArray = TheController->ChannelArray();
   296 
   297 #ifdef IIC_INSTRUMENTATION_MACRO
   298 	IIC_REGISTERCHANS_START_PIL_TRACE;
   299 #endif
   300 	// Get access to the channel pointer array - exit if it is currently being modfied
   301 	TInt r=KErrNone;
   302 	if((r=TheController->GetChanWriteAccess()) == KErrNone)
   303 		{
   304 #ifdef _DEBUG
   305 		__KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::RegisterChannels - On entry, iChannelArray ...\n"));
   306 		TheController->DumpChannelArray();
   307 #endif
   308 		// Loop for aNumberChannels	and write directly to the channel array
   309 		DIicBusChannel** chanIterator = aListChannels;
   310 		for(TInt iteration = 0; iteration < aNumberChannels; ++iteration, ++chanIterator)
   311 			{
   312 			DIicBusChannel* chanPtr = *chanIterator;
   313 			__KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::RegisterChannels - adding channel number %d\n",chanPtr->ChannelNumber()));
   314 			TInt r = chanArray->InsertInOrder(chanPtr,EntryOrder);
   315 			if(r!=KErrNone)
   316 				break;
   317 			}
   318 
   319 #ifdef _DEBUG
   320 		 __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::RegisterChannels - On exit, iChannelArray ...\n"));
   321 		TheController->DumpChannelArray();
   322 #endif
   323 		TheController->FreeChanWriteAccess();
   324 		}
   325 	else
   326 		{
   327 		__KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::GetChanWriteAccess returned %d\n",r));
   328 		}
   329 
   330 #ifdef IIC_INSTRUMENTATION_MACRO
   331 	IIC_REGISTERCHANS_END_PIL_TRACE;
   332 #endif
   333 	return r;
   334 	}
   335 
   336 
   337 EXPORT_C TInt DIicBusController::DeRegisterChannel(DIicBusChannel* aChannel)
   338 	{
   339 // To be used by Channel implementations to deregister a channel
   340     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::DeRegisterChannel, aChannel=0x%x\n",aChannel));
   341 	if(aChannel == NULL)
   342 		return KErrArgument;
   343 
   344 	RPointerArray<DIicBusChannel>* chanArray = TheController->ChannelArray();
   345 
   346 #ifdef IIC_INSTRUMENTATION_MACRO
   347 	IIC_DEREGISTERCHAN_START_PIL_TRACE;
   348 #endif
   349 	TInt r=KErrNone;
   350 	// Get access to the channel pointer array - exit if it is currently unavailable
   351 	// Gaining write access will prevent a client of a Master Channel from instigating a new QueueTransaction
   352 	// (or CancelTransaction), and it will obstruct a client of a Slave Channel in CaptureChannel.
   353 	if((r=TheController->GetChanWriteAccess())!=KErrNone)
   354 		return r;
   355 
   356 	// Check channel is registered
   357 	TInt chanIndex = chanArray->FindInOrder(aChannel,EntryOrder);
   358 	if(chanIndex<0)
   359 		{
   360 		TheController->FreeChanWriteAccess();
   361 		return KErrNotFound;
   362 		}
   363 
   364 #ifdef _DEBUG
   365     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::DeRegisterChannel - On entry, iChannelArray ...\n"));
   366 	TheController->DumpChannelArray();
   367 #endif
   368 
   369 	// Remove the channel from the array
   370 	// Note that this does not delete the channel object
   371 	chanArray->Remove(chanIndex);
   372 
   373 #ifdef _DEBUG
   374     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::DeRegisterChannel - On exit, iChannelArray ...\n"));
   375 	TheController->DumpChannelArray();
   376 #endif
   377 	TheController->FreeChanWriteAccess();
   378 
   379 #ifdef IIC_INSTRUMENTATION_MACRO
   380 	IIC_DEREGISTERCHAN_END_PIL_TRACE;
   381 #endif
   382 	return KErrNone;
   383 	}
   384 
   385 TInt DIicBusController::FindCapturedChanById(TCapturedChannel aCapturedChan, TInt& aIndex)
   386 	{
   387 	TInt index=0;
   388 	TInt r=KErrNotFound;
   389 	do
   390 		{
   391 		if(iCapturedChannels[index].iChannelId == aCapturedChan.iChannelId)
   392 			{
   393 			aIndex=index;
   394 			r=KErrNone;
   395 			}
   396 		index++;
   397 		} while ((index < KMaxNumCapturedChannels)&&(r == KErrNotFound));
   398 	return r;
   399 	}
   400 
   401 TInt DIicBusController::FindCapturedChan(TCapturedChannel aCapturedChan, TInt& aIndex)
   402 	{
   403 	TInt index=0;
   404 	TInt r=KErrNotFound;
   405 	do
   406 		{
   407 		if(iCapturedChannels[index] == aCapturedChan)
   408 			{
   409 			aIndex=index;
   410 			r=KErrNone;
   411 			}
   412 		index++;
   413 		} while ((index < KMaxNumCapturedChannels)&&(r == KErrNotFound));
   414 	return r;
   415 	}
   416 
   417 TInt DIicBusController::InsertCaptChanInArray(TCapturedChannel aCapturedChan)
   418 	{
   419 	__KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::InsertCaptChanInArray \n"));
   420 	// Ensure the channel hasn't already been inserted in the array
   421 	// If found, fault the Kernel
   422 	TInt dumInt = 0;
   423 	TInt r=FindCapturedChan(aCapturedChan,dumInt);
   424 	__ASSERT_DEBUG(r!=KErrNone, Kern::Fault(KIicPanic,__LINE__));
   425 
   426 	// Loop the array and insert in the first available slot
   427 	// If no slots are available return KErrNotReady
   428 	TInt index=0;
   429 	TCapturedChannel emptyChan;
   430 	for(;index<KMaxNumCapturedChannels;++index)
   431 		{
   432 		if(iCapturedChannels[index] == emptyChan)
   433 			{
   434 			// Found a space
   435 			iCapturedChannels[index]=aCapturedChan;
   436 			break;
   437 			}
   438 		}
   439 	if(index>=KMaxNumCapturedChannels)
   440 		r = KErrNotReady;
   441 	return r;
   442 	}
   443 
   444 TInt DIicBusController::RemoveCaptChanFromArray(TCapturedChannel aCapturedChan)
   445 	{
   446 	// Remove the entry from the array
   447 	// If the entry is not present return KErrArgument
   448 	TInt index=-1;
   449 	TInt r=FindCapturedChan(aCapturedChan,index);
   450 	if((r!=KErrNone)||(index>=KMaxNumCapturedChannels))
   451 		return KErrArgument;
   452 	iCapturedChannels[index].iChanPtr=NULL;
   453 	iCapturedChannels[index].iChannelId=0;
   454 	return KErrNone;
   455 	}
   456 
   457 
   458 TInt DIicBusController::InstallCapturedChannel(const TInt aChannelId, const DIicBusChannelSlave* aChanPtr)
   459 	{
   460 #ifdef _DEBUG
   461     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::InstallCapturedChannel - On entry, iCapturedChannels ...\n"));
   462 	DumpCapturedChannels();
   463 #endif
   464 	TInt r=KErrNone;
   465 	TCapturedChannel capturedChan((TInt)aChannelId,(DIicBusChannelSlave*)aChanPtr);
   466 	// Because insertions are bounded by the size of the array and do not involve allocating
   467 	// or freeing memory, simply take the spinlock at the start of the operation and release at the end
   468 	TInt captIntState=__SPIN_LOCK_IRQSAVE(*iCaptLock);
   469 	r=InsertCaptChanInArray(capturedChan);
   470 	__SPIN_UNLOCK_IRQRESTORE(*iCaptLock,captIntState);
   471 	if(r!=KErrNone)
   472 		return r;
   473 
   474 #ifdef _DEBUG
   475     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::InstallCapturedChannel - On exit, iCapturedChannels ...\n"));
   476 	DumpCapturedChannels();
   477 #endif
   478 	return KErrNone;
   479 	}
   480 
   481 TInt DIicBusController::DeInstallCapturedChannel(const TInt aChannelId, const DIicBusChannelSlave* aChanPtr)
   482 	{
   483 #ifdef _DEBUG
   484     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::DeInstallCapturedChannel - On entry, iCapturedChannels ...\n"));
   485 	DumpCapturedChannels();
   486 #endif
   487 	TInt r = KErrNone;
   488 	TCapturedChannel capturedChan((TInt) aChannelId, (DIicBusChannelSlave*) aChanPtr);
   489 	// Because removals are bounded by the size of the array and do not involve allocating
   490 	// or freeing memory, simply take the spinlock at the start of the operation and release at the end
   491 	TInt captIntState = __SPIN_LOCK_IRQSAVE(*iCaptLock);
   492 	r = RemoveCaptChanFromArray(capturedChan);
   493 	__SPIN_UNLOCK_IRQRESTORE(*iCaptLock, captIntState);
   494 	if(r != KErrNone)
   495 		return r;
   496 
   497 #ifdef _DEBUG
   498     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::DeInstallCapturedChannel - On exit, iCapturedChannels ...\n"));
   499 	DumpCapturedChannels();
   500 #endif
   501 	return KErrNone;
   502 	}
   503 
   504 	// Master-side API
   505 TInt DIicBusController::QueueTransaction(TInt aBusId, TIicBusTransaction* aTransaction)
   506 	{
   507 	__KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::QueueTransaction, aBusId=0x%x,aTransaction=0x%x\n", aBusId, aTransaction));
   508 	if(!aTransaction)
   509 		{
   510 		return KErrArgument;
   511 		}
   512 
   513 	// Get a pointer to the channel
   514 	TInt dumInt = 0;
   515 	DIicBusChannel* chanPtr = NULL;
   516 	// Can only read the channel array if it is not currently being modified
   517 	TInt r = GetChanReadAccess();
   518 	if(r != KErrNone)
   519 		{
   520 		return r;
   521 		}
   522 	r = GetChanPtr(aBusId, dumInt, chanPtr);
   523 	if(r == KErrNone)
   524 		{
   525 		if(!chanPtr)
   526 			{
   527 			r = KErrArgument;
   528 			}
   529 		else
   530 			{
   531 			switch(chanPtr->ChannelType())
   532 				{
   533 				// QueueTransaction requests are only supported by channels in Master mode.
   534 				case DIicBusChannel::ESlave:
   535 					{
   536 					r = KErrNotSupported;
   537 					break;
   538 					}
   539 				// If the request is supported by the Master channel, send it to the channel for processing in its thread
   540 				case DIicBusChannel::EMasterSlave:
   541 					{
   542 					r = RequestTypeSupported(aBusId, ((DIicBusChannelMasterSlave*)chanPtr)->iMasterChannel);
   543 					if(r == KErrNone)
   544 						{
   545 						aTransaction->iBusId = aBusId;
   546 						r = (((DIicBusChannelMasterSlave*) chanPtr)->QueueTransaction(aTransaction));
   547 						}
   548 					break;
   549 					}
   550 				case DIicBusChannel::EMaster:
   551 					{
   552 					r = RequestTypeSupported(aBusId, (DIicBusChannelMaster*)chanPtr);
   553 					if(r == KErrNone)
   554 						{
   555 						aTransaction->iBusId = aBusId;
   556 						r = (((DIicBusChannelMaster*) chanPtr)->QueueTransaction(aTransaction));
   557 						}
   558 					break;
   559 					}
   560 				default:
   561 					{
   562 					r = KErrGeneral;
   563 					}
   564 				}
   565 			}
   566 		}
   567 	FreeChanReadAccess();
   568 	return r;
   569 	}
   570 
   571 TInt DIicBusController::QueueTransaction(TInt aBusId, TIicBusTransaction* aTransaction, TIicBusCallback* aCallback)
   572 	{
   573     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::QueueTransaction, aBusId=0x%x,aTransaction=0x%x,aCallback=0x%x\n",aBusId,aTransaction,aCallback));
   574 	if(!aTransaction || !aCallback)
   575 		{
   576 		return KErrArgument;
   577 		}
   578 
   579 	// Get a pointer to the channel
   580 	TInt dumInt = 0;
   581 	DIicBusChannel* chanPtr = NULL;
   582 	// Can only read the channel array if it is not currently being modified
   583 	TInt r = GetChanReadAccess();
   584 	if(r == KErrNone)
   585 		{
   586 		r = GetChanPtr(aBusId, dumInt, chanPtr);
   587 		if(r == KErrNone)
   588 			{
   589 			if(!chanPtr)
   590 				{
   591 				r = KErrArgument;
   592 				}
   593 			else
   594 				{
   595 				switch(chanPtr->ChannelType())
   596 					{
   597 					// QueueTransaction requests are only supported by channels in Master mode.
   598 					case DIicBusChannel::ESlave:
   599 						{
   600 						r = KErrNotSupported;
   601 						break;
   602 						}
   603 					// If the request is supported by the Master channel, send it to the channel for processing in its thread
   604 					case DIicBusChannel::EMasterSlave:
   605 						{
   606 						r = RequestTypeSupported(aBusId, ((DIicBusChannelMasterSlave*)chanPtr)->iMasterChannel);
   607 						if(r == KErrNone)
   608 							{
   609 							aTransaction->iBusId = aBusId;
   610 							r = (((DIicBusChannelMasterSlave*) chanPtr)->QueueTransaction(aTransaction, aCallback));
   611 							}
   612 						break;
   613 						}
   614 					case DIicBusChannel::EMaster:
   615 						{
   616 						r = RequestTypeSupported(aBusId, (DIicBusChannelMaster*)chanPtr);
   617 						if(r == KErrNone)
   618 							{
   619 							aTransaction->iBusId = aBusId;
   620 							r = (((DIicBusChannelMaster*) chanPtr)->QueueTransaction(aTransaction, aCallback));
   621 							}
   622 						break;
   623 						}
   624 					default:
   625 						{
   626 						r = KErrGeneral;
   627 						}
   628 					}
   629 				}
   630 			}
   631 		}
   632 	FreeChanReadAccess();
   633 	return r;
   634 	}
   635 
   636 
   637 TInt DIicBusController::GetChanPtr(const TInt aBusId, TInt &aIndex, DIicBusChannel*& aChan)
   638 	{
   639     __KTRACE_OPT(KIIC, 	Kern::Printf("DIicBusController::GetChanPtr, aBusId=0x%x\n",aBusId));
   640 
   641 	TInt32 chanId;
   642 	chanId = GET_CHAN_NUM(aBusId);
   643 
   644 	__KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::GetChanPtr, chanId=0x%x\n", chanId));
   645 	DIicBusChannelSearcher searchChannel(DIicBusChannel::EMasterSlave, DIicBusChannel::ESccb, DIicBusChannel::EFullDuplex);
   646 	searchChannel.SetChannelNumber((TInt8)chanId);
   647 
   648 	TInt r = KErrNotFound;
   649 	aIndex = iChannelArray.FindInOrder(&searchChannel, EntryOrder);
   650 	if(aIndex >= 0)
   651 		{
   652 		aChan = iChannelArray[aIndex];
   653 		r = KErrNone;
   654 		}
   655 
   656 	__KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::GetChanPtr, chanPtr=0x%x, index=%d\n", aChan, aIndex));
   657 	return r;
   658 	}
   659 
   660 
   661 TInt DIicBusController::CancelTransaction(TInt aBusId, TIicBusTransaction* aTransaction)
   662 	{
   663     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::CancelTransaction, aBusId=0x%x,aTransaction=0x%x\n", aBusId, aTransaction));
   664 	if(!aTransaction)
   665 		{
   666 		return KErrArgument;
   667 		}
   668 
   669 	// Get the channel
   670 	TInt dumInt = 0;
   671 	DIicBusChannel* chanPtr = NULL;
   672 
   673 	// Can only read the channel array if it is not currently being modified
   674 	TInt r = GetChanReadAccess();
   675 	if(r == KErrNone)
   676 		{
   677 		r = GetChanPtr(aBusId, dumInt, chanPtr);
   678 		if(r == KErrNone)
   679 			{
   680 			if(!chanPtr)
   681 				{
   682 				r = KErrArgument;
   683 				}
   684 			else
   685 				{
   686 				// QueueTransaction requests are only supported by channels in Master mode.
   687 				switch(chanPtr->ChannelType())
   688 					{
   689 					case DIicBusChannel::ESlave:
   690 						{
   691 						r = KErrNotSupported;
   692 						break;
   693 						}
   694 					case DIicBusChannel::EMasterSlave:
   695 						{
   696 						r = RequestTypeSupported(aBusId, ((DIicBusChannelMasterSlave*)chanPtr)->iMasterChannel);
   697 						if(r == KErrNone)
   698 							{
   699 							r = (((DIicBusChannelMasterSlave*) chanPtr)->CancelTransaction(aTransaction));
   700 							}
   701 						break;
   702 						}
   703 					case DIicBusChannel::EMaster:
   704 						{
   705 						r = RequestTypeSupported(aBusId, (DIicBusChannelMaster*)chanPtr);
   706 						if(r == KErrNone)
   707 							{
   708 							r = (((DIicBusChannelMaster*) chanPtr)->CancelTransaction(aTransaction));
   709 							}
   710 						break;
   711 						}
   712 					default:
   713 						{
   714 						r = KErrGeneral;
   715 						}
   716 					}
   717 				}
   718 			}
   719 		}
   720 	FreeChanReadAccess();
   721 	return r;
   722 	}
   723 
   724 	// Slave-side API
   725 TInt DIicBusController::CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch)
   726 	{
   727 	// Check that that aCallback!=NULL and aConfigHdr!=NULL - if not, return KErrArgument
   728 	if(!aCallback || !aConfigHdr)
   729 		{
   730 		return KErrArgument;
   731 		}
   732 
   733 	// Get the channel
   734 	TInt chanIndex = 0;
   735 	DIicBusChannel* chanPtr = NULL;
   736 
   737 	// Can only read the channel array if it is not currently being modified
   738 	TInt r = GetChanReadAccess();
   739 	if(r == KErrNone)
   740 		{
   741 		r = GetChanPtr(aBusId, chanIndex, chanPtr);
   742 		if(r == KErrNone)
   743 			{
   744 			if(!chanPtr)
   745 				{
   746 				r = KErrArgument;
   747 				}
   748 			else
   749 				{
   750 				DIicBusChannelSlave* slaveChanPtr = NULL;
   751 				switch(chanPtr->ChannelType())
   752 					{
   753 					// CaptureChannel requests are only supported by channels in Slave mode.
   754 					case DIicBusChannel::EMaster:
   755 						{
   756 						r = KErrNotSupported;
   757 						break;
   758 						}
   759 					case DIicBusChannel::EMasterSlave:
   760 						{
   761 						slaveChanPtr = ((DIicBusChannelMasterSlave*) chanPtr)->iSlaveChannel;
   762 						__ASSERT_DEBUG(slaveChanPtr!=NULL, Kern::Fault(KIicPanic,__LINE__)); // MasterSlave channel should have a valid Slave channel
   763 						// Send the request to the channel
   764 						slaveChanPtr->iController = this;
   765 						r = ((DIicBusChannelMasterSlave*) chanPtr)->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch);
   766 						break;
   767 						}
   768 					case DIicBusChannel::ESlave:
   769 						{
   770 						slaveChanPtr = (DIicBusChannelSlave*) chanPtr; // chanPtr is non-NULL
   771 						// Send the request to the channel
   772 						slaveChanPtr->iController = this;
   773 						r = (slaveChanPtr->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch));
   774 						break;
   775 						}
   776 					default:
   777 						{
   778 						r = KErrArgument;
   779 						}
   780 					}
   781 				// For synchronous capture, if successful then install the channel
   782 				if(r == KErrNone && slaveChanPtr)
   783 					{
   784 					if(!aAsynch)
   785 						{
   786 						InstallCapturedChannel(aChannelId, slaveChanPtr);
   787 						}
   788 					}
   789 				}
   790 			}
   791 		}
   792 	FreeChanReadAccess();
   793 	return r;
   794 	}
   795 
   796 
   797 TInt DIicBusController::GetSlaveChanPtr(TInt aChannelId, DIicBusChannelSlave*& aSlaveChanPtr)
   798 	{
   799 	TInt r=KErrNone;
   800 	// Check that the channelID is recognised
   801 	TCapturedChannel capturedChan(aChannelId,NULL);
   802 	TInt chanIndex=-1;
   803 	// Ensure the array of captured channels will not be modified before it has been searched
   804 	// Because searches are bounded by the size of the array and do not involve allocating
   805 	// or freeing memory, simply take the spinlock at the start of the operation and release at the end
   806 	TInt captIntState=__SPIN_LOCK_IRQSAVE(*iCaptLock);
   807 	r=FindCapturedChanById(capturedChan, chanIndex);
   808 	if((chanIndex < 0)||(r == KErrNotFound))
   809 		r=KErrArgument;
   810 	else
   811 		aSlaveChanPtr = (DIicBusChannelSlave*)(iCapturedChannels[chanIndex].iChanPtr);
   812 	__SPIN_UNLOCK_IRQRESTORE(*iCaptLock,captIntState);
   813 
   814 	__ASSERT_DEBUG(aSlaveChanPtr!=NULL, Kern::Fault(KIicPanic,__LINE__));
   815 	return r;
   816 	}
   817 
   818 
   819 TInt DIicBusController::ReleaseChannel(TInt aChannelId)
   820 	{
   821     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::ReleaseChannel, channelID = 0x%x \n",aChannelId));
   822 	TInt r = KErrNone;
   823 	DIicBusChannel* chanPtr = NULL;
   824 	
   825 	// Get the pointer to the Slave Channel
   826 	DIicBusChannelSlave* slaveChanPtr = NULL;
   827 	if((r = GetSlaveChanPtr(aChannelId, slaveChanPtr)) != KErrNone)
   828 		return r;
   829 		
   830 	DIicBusChannelSearcher searchChannel(DIicBusChannel::EMasterSlave, DIicBusChannel::ESccb, DIicBusChannel::EFullDuplex);
   831 	searchChannel.SetChannelNumber(slaveChanPtr->ChannelNumber());
   832 
   833 	TInt dumIndex = iChannelArray.FindInOrder(&searchChannel, EntryOrder);
   834 	if(dumIndex < 0)
   835 		{
   836 		return KErrNotFound;
   837 		}
   838 	chanPtr = iChannelArray[dumIndex];
   839 
   840 	__ASSERT_DEBUG(chanPtr!=NULL, Kern::Fault(KIicPanic,__LINE__));
   841 
   842 	//if it is the masterslave channel, then call the masterslave's RelaseChannel
   843 	// which will call the slave channel's ReleaseChannel internally
   844 	if(chanPtr->ChannelType() == DIicBusChannel::EMasterSlave)
   845 		r = ((DIicBusChannelMasterSlave*)chanPtr)->ReleaseChannel();
   846 	else // Call the slave only ReleaseChannel
   847 		r = slaveChanPtr->ReleaseChannel();
   848 	
   849 	// In either case de-install the captured slave channel
   850 	if(r == KErrNone)
   851 		{
   852 		r = DeInstallCapturedChannel(aChannelId, slaveChanPtr);
   853 		}
   854 
   855 	// No need to unset iController - there is only one IIC Controller
   856 	return r;
   857 	}
   858 
   859 
   860 TInt DIicBusController::RegisterRxBuffer(TInt aChannelId, TPtr8 aRxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
   861 	{
   862     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::RegisterRxBuffer, channelID=0x%x,aRxBuffer=0x%x,aBufGranularity=0x%x,aNumWords=0x%x,aOffset=0x%x \n",aChannelId,(TInt)&aRxBuffer,aBufGranularity,aNumWords,aOffset));
   863 
   864     // Acquire the pointer to the Slave Channel
   865 	DIicBusChannelSlave* slaveChanPtr = NULL;
   866 	TInt r = GetSlaveChanPtr(aChannelId, slaveChanPtr);
   867 	if(r != KErrNone)
   868 		{
   869 		return r;
   870 		}
   871 
   872 	// Instigate the channel functionality
   873 	return(slaveChanPtr->RegisterRxBuffer(aRxBuffer,aBufGranularity,aNumWords,aOffset));
   874 	}
   875 
   876 TInt DIicBusController::RegisterTxBuffer(TInt aChannelId, TPtr8 aTxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
   877 	{
   878     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::RegisterTxBuffer, channelID=0x%x,aTxBuffer=0x%x,aBufGranularity=0x%x,aNumWords=0x%x,aOffset=0x%x \n",aChannelId,(TInt)&aTxBuffer,aBufGranularity,aNumWords,aOffset));
   879 
   880 	// Acquire the pointer to the Slave Channel
   881 	DIicBusChannelSlave* slaveChanPtr = NULL;
   882 	TInt r = GetSlaveChanPtr(aChannelId, slaveChanPtr);
   883 	if(r != KErrNone)
   884 		{
   885 		return r;
   886 		}
   887 
   888 	// Instigate the channel functionality
   889 	return (slaveChanPtr->RegisterTxBuffer(aTxBuffer, aBufGranularity, aNumWords, aOffset));
   890 	}
   891 
   892 
   893 TInt DIicBusController::SetNotificationTrigger(TInt aChannelId, TInt aTrigger)
   894 	{
   895     __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::SetNotificationTrigger - for aChannelId=0x%x, aTrigger=0x%x\n",aChannelId,aTrigger));
   896 	// Acquire the pointer to the Slave Channel
   897 	DIicBusChannelSlave* slaveChanPtr = NULL;
   898 	TInt r = GetSlaveChanPtr(aChannelId, slaveChanPtr);
   899 	if( r != KErrNone)
   900 		{
   901 		return r;
   902 		}
   903 
   904 	// Instigate the channel functionality
   905 	return(slaveChanPtr->SetNotificationTrigger(aTrigger));
   906 	}
   907 
   908 
   909 TInt DIicBusController::StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2)
   910 	{
   911 //		The IIC controller and channel classes are generic, and can serve many differing client and
   912 //		bus implementations. If a client and bus make use of specific functionality that is not
   913 //		common to other bus types, it makes sense to provide only the minimum-required support in the
   914 //		generic code. Here, the channel identifier is checked but all other parameters are passed
   915 //		directly to the bus implementation channel for processing; if the channel does not provide
   916 //		StaticExtension implementation, the generic DIicBusChannel::StaticExtension method is invoked.
   917 
   918 #ifdef IIC_INSTRUMENTATION_MACRO
   919 	if((aFunction & KControlIoMask) == KMasterSlaveControlIo)
   920 		{
   921 		IIC_MSSTATEXT_START_PIL_TRACE
   922 		}
   923 	else if((aFunction & KControlIoMask) == KMasterControlIo)
   924 		{
   925 		IIC_MSTATEXT_START_PIL_TRACE
   926 		}
   927 	else if((aFunction & KControlIoMask) == KSlaveControlIo)
   928 		{
   929 		IIC_SSTATEXT_START_PIL_TRACE
   930 		}
   931 //	else - Unexpected value - just pass silently to the PSL ...
   932 #endif
   933 
   934 	// Get the channel
   935 	TInt dumInt = 0;
   936 	DIicBusChannel* chanPtr = NULL;
   937 	// Can only read the channel array if it is not currently being modified
   938 	TInt r = GetChanReadAccess();
   939 	if(r == KErrNone)
   940 		{
   941 		r = GetChanPtr(aId, dumInt, chanPtr);
   942 		if(r == KErrNone)
   943 			{
   944 			if(!chanPtr)
   945 				{
   946 				r = KErrArgument;
   947 				}
   948 			else
   949 				{
   950 				r = chanPtr->StaticExtension(aFunction, aParam1, aParam2);
   951 				}
   952 			}
   953 		}
   954 
   955 #ifdef IIC_INSTRUMENTATION_MACRO
   956 	if((aFunction & KControlIoMask) == KMasterSlaveControlIo)
   957 		{
   958 		IIC_MSSTATEXT_START_PIL_TRACE
   959 		}
   960 	else if((aFunction & KControlIoMask) == KMasterControlIo)
   961 		{
   962 		IIC_MSTATEXT_START_PIL_TRACE
   963 		}
   964 	else if((aFunction & KControlIoMask) == KSlaveControlIo)
   965 		{
   966 		IIC_SSTATEXT_START_PIL_TRACE
   967 		}
   968 //	else	... do nothing
   969 #endif
   970 	FreeChanReadAccess();
   971 	return r;
   972 	}
   973 
   974 
   975 #ifdef _DEBUG
   976 
   977 void DIicBusController::DumpCapturedChannels()
   978 	{
   979 	// Print iCapturedChannels ...
   980 	TInt count=0;
   981 	TInt i=0;
   982 	TCapturedChannel emptyChan;
   983 	for(;i<KMaxNumCapturedChannels;++i)
   984 		{
   985 		if(iCapturedChannels[i] == emptyChan)
   986 			continue;
   987 		++count;
   988 		}
   989 
   990 	i = 0;
   991     __KTRACE_OPT(KIIC, Kern::Printf("	- Count gave %d\n",count));
   992 	for(;i<KMaxNumCapturedChannels;++i)
   993 		{
   994 		if(iCapturedChannels[i] == emptyChan)
   995 			continue;
   996 		DIicBusChannel* ptr=(DIicBusChannel*)(iCapturedChannels[i]).iChanPtr;
   997 	    __KTRACE_OPT(KIIC, Kern::Printf("	- ptr %d=0x%x\n",i,ptr));
   998 		ptr->StaticExtension(KCtrlIoDumpChan,0,0);
   999 		};
  1000 	}
  1001 
  1002 void DIicBusController::DumpChannelArray()
  1003 	{
  1004 	TInt i = 0;
  1005 	__KTRACE_OPT(KIIC, Kern::Printf("\nDIicBusController::DumpChannelArray\n"));
  1006     __KTRACE_OPT(KIIC, Kern::Printf("	- Count gave %d\n",iChannelArray.Count()));
  1007 	for(i=0; i<iChannelArray.Count(); i++)
  1008 		{
  1009 		DIicBusChannel* ptr=iChannelArray[i];
  1010 	    __KTRACE_OPT(KIIC, Kern::Printf("	- ptr %d=0x%x\n",i,ptr));
  1011 		ptr->StaticExtension(KCtrlIoDumpChan,0,0);
  1012 		};
  1013 	}
  1014 
  1015 #endif
  1016 
  1017 #ifdef IIC_SIMULATED_PSL
  1018 TVersion DIicPdd::VersionRequired()
  1019 	{
  1020 	const TInt KIicMajorVersionNumber=1;
  1021 	const TInt KIicMinorVersionNumber=0;
  1022 	const TInt KIicBuildVersionNumber=KE32BuildVersionNumber;
  1023 	return TVersion(KIicMajorVersionNumber,KIicMinorVersionNumber,KIicBuildVersionNumber);
  1024 	}
  1025 
  1026 /** Factory class constructor */
  1027 DIicPdd::DIicPdd()
  1028 	{
  1029     iVersion = DIicPdd::VersionRequired();
  1030 	}
  1031 
  1032 DIicPdd::~DIicPdd()
  1033 	{
  1034 	delete TheController;
  1035 	}
  1036 
  1037 TInt DIicPdd::Install()
  1038     {
  1039     return(SetName(&KPddName));
  1040     }
  1041 
  1042 /**  Called by the kernel's device driver framework to create a Physical Channel. */
  1043 TInt DIicPdd::Create(DBase*& /*aChannel*/, TInt /*aUint*/, const TDesC8* /*anInfo*/, const TVersion& /*aVer*/)
  1044     {
  1045     return KErrNone;
  1046     }
  1047 
  1048 /**  Called by the kernel's device driver framework to check if this PDD is suitable for use with a Logical Channel.*/
  1049 TInt DIicPdd::Validate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer)
  1050     {
  1051    	if (!Kern::QueryVersionSupported(DIicPdd::VersionRequired(),aVer))
  1052 		return(KErrNotSupported);
  1053     return KErrNone;
  1054     }
  1055 
  1056 /** Return the driver capabilities */
  1057 void DIicPdd::GetCaps(TDes8& aDes) const
  1058     {
  1059 	// Create a capabilities object
  1060 	TCaps caps;
  1061 	caps.iVersion = iVersion;
  1062 	// Zero the buffer
  1063 	TInt maxLen = aDes.MaxLength();
  1064 	aDes.FillZ(maxLen);
  1065 	// Copy cpabilities
  1066 	TInt size=sizeof(caps);
  1067 	if(size>maxLen)
  1068 	   size=maxLen;
  1069 	aDes.Copy((TUint8*)&caps,size);
  1070     }
  1071 #endif
  1072 
  1073 #ifndef IIC_SIMULATED_PSL
  1074 // Client interface entry point
  1075 DECLARE_EXTENSION_WITH_PRIORITY(KExtensionMaximumPriority-1)	// highest priority after Resource Manager
  1076 	{
  1077 	TheController = new DIicBusController;
  1078 	if(!TheController)
  1079 		return KErrNoMemory;
  1080 	TInt r=TheController->Create();
  1081 	return r;
  1082 	}
  1083 #else
  1084 static DIicPdd* TheIicPdd;
  1085 
  1086 DECLARE_STANDARD_PDD()
  1087 	{
  1088 	TheController = new DIicBusController;
  1089 	if(!TheController)
  1090 		return NULL;
  1091 	TInt r = TheController->Create();
  1092 	if(r == KErrNone)
  1093 		{
  1094 		TheIicPdd = new DIicPdd;
  1095 		if(TheIicPdd)
  1096 			return TheIicPdd;
  1097 		}
  1098 	
  1099 	delete TheController; 
  1100 	return NULL;
  1101 	}
  1102 #endif
  1103 
  1104 
  1105