kernel/eka/drivers/iic/iic.cpp
changeset 0 a41df078684a
child 199 189ece41fa29
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/iic/iic.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,1105 @@
+// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// e32\drivers\iic.cpp
+// IIC Controller and public API Implementation
+//
+
+#include <drivers/iic.h>
+#include <drivers/iic_channel.h>
+#include "iic_priv.h"
+
+#ifdef IIC_INSTRUMENTATION_MACRO
+#include <drivers/iic_trace.h>
+#endif
+
+// Global Controller pointer
+static DIicBusController* TheController = NULL;
+
+//
+//		Implementation of generic IicBus API for client interface
+//
+EXPORT_C TInt IicBus::QueueTransaction(TInt aBusId, TIicBusTransaction* aTransaction)
+	{
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_MQTRANSSYNC_START_PIL_TRACE;
+#endif
+	TInt r=TheController->QueueTransaction(aBusId, aTransaction);
+
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_MQTRANSSYNC_END_PIL_TRACE;
+#endif
+	return r;
+	}
+
+EXPORT_C TInt IicBus::QueueTransaction(TInt aBusId, TIicBusTransaction* aTransaction, TIicBusCallback* aCallback)
+	{
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_MQTRANSASYNC_START_PIL_TRACE;
+#endif
+	TInt r=TheController->QueueTransaction(aBusId, aTransaction, aCallback);
+
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_MQTRANSASYNC_END_PIL_TRACE;
+#endif
+	return r;
+	}
+
+EXPORT_C TInt IicBus::CancelTransaction(TInt aBusId, TIicBusTransaction* aTransaction)
+	{
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_MCANCELTRANS_START_PIL_TRACE;
+#endif
+	TInt r=TheController->CancelTransaction(aBusId, aTransaction);
+
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_MCANCELTRANS_END_PIL_TRACE;
+#endif
+	return r;
+	}
+
+EXPORT_C TInt IicBus::CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch)
+	{
+#ifdef IIC_INSTRUMENTATION_MACRO
+	if(!aAsynch)
+		{
+		IIC_SCAPTCHANSYNC_START_PIL_TRACE;
+		}
+	else
+		{
+		IIC_SCAPTCHANASYNC_START_PIL_TRACE;
+		}
+#endif
+	TInt r=TheController->CaptureChannel(aBusId, aConfigHdr, aCallback, aChannelId, aAsynch);
+
+#ifdef IIC_INSTRUMENTATION_MACRO
+	if(!aAsynch)
+		{
+		IIC_SCAPTCHANSYNC_END_PIL_TRACE;
+		}
+#endif
+	return r;
+	}
+
+EXPORT_C TInt IicBus::ReleaseChannel(TInt aChannelId)
+	{
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_SRELCHAN_START_PIL_TRACE;
+#endif
+	TInt r=TheController->ReleaseChannel(aChannelId);
+
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_SRELCHAN_END_PIL_TRACE;
+#endif
+	return r;
+	}
+
+EXPORT_C TInt IicBus::RegisterRxBuffer(TInt aChannelId, TPtr8 aRxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
+	{
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_SREGRXBUF_START_PIL_TRACE;
+#endif
+	TInt r=TheController->RegisterRxBuffer(aChannelId, aRxBuffer, aBufGranularity, aNumWords, aOffset);
+
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_SREGRXBUF_END_PIL_TRACE;
+#endif
+	return r;
+	}
+
+EXPORT_C TInt IicBus::RegisterTxBuffer(TInt aChannelId, TPtr8 aTxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
+	{
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_SREGTXBUF_START_PIL_TRACE;
+#endif
+	TInt r=TheController->RegisterTxBuffer(aChannelId, aTxBuffer, aBufGranularity, aNumWords, aOffset);
+
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_SREGTXBUF_END_PIL_TRACE;
+#endif
+	return r;
+	}
+
+EXPORT_C TInt IicBus::SetNotificationTrigger(TInt aChannelId, TInt aTrigger)
+	{
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_SNOTIFTRIG_START_PIL_TRACE;
+#endif
+	TInt r=TheController->SetNotificationTrigger(aChannelId, aTrigger);
+
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_SNOTIFTRIG_END_PIL_TRACE;
+#endif
+	return r;
+	}
+
+EXPORT_C TInt IicBus::StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2)
+	{
+	return(TheController->StaticExtension(aId, aFunction, aParam1, aParam2));
+	}
+
+
+//
+//		Bus Controller
+//
+
+//  auxiliary function for ordering entries in the array of channels
+TInt DIicBusController::OrderEntries(const DIicBusChannel& aMatch, const DIicBusChannel& aEntry)
+	{
+	TUint8 l=(TUint8)aMatch.ChannelNumber();
+	TUint8 r=(TUint8)aEntry.ChannelNumber();
+	if(l>r)
+		return -1;
+	else if(l<r)
+		return 1;
+	else
+		return 0;
+	}
+
+// global ordering object to be passed to RPointerArray InsertInOrderXXX and FindInOrder
+TLinearOrder<DIicBusChannel> EntryOrder(DIicBusController::OrderEntries);
+
+// Implementation for DIicBusController
+//
+
+TInt DIicBusController::Create()
+	{
+	TInt r=KErrNone;
+	iChanLock = new TSpinLock(TSpinLock::EOrderGenericIrqLow2);  // Semi-arbitrary, low priority value
+	iCaptLock = new TSpinLock(TSpinLock::EOrderGenericIrqLow2);  // Semi-arbitrary, low priority value
+	if((iChanLock == NULL)||(iCaptLock == NULL))
+		{
+		delete iChanLock;
+		delete iCaptLock;
+		r=KErrNoMemory;
+		}
+	return r;
+	}
+
+DIicBusController::~DIicBusController()
+	{
+#ifdef IIC_SIMULATED_PSL
+	for(TInt i=0; i<iChannelArray.Count(); i++)
+		{
+		DIicBusChannel* ptr=iChannelArray[i];
+		// Remove the channel from the array
+		iChannelArray.Remove(i);
+		// Delete the channel object
+		delete ptr;
+		};
+
+	iChannelArray.Reset();
+	delete iChanLock;
+	delete iCaptLock;
+#endif
+	}
+
+TInt DIicBusController::GetChanWriteAccess()
+	{
+	// Can only have one insertion or removal active at any one time
+	// Can not perform an insertion or removal while a read is in progress
+	// If either of the two above conditions exist, return KErrInUse
+	// Otherwise, set the flag to indicate that a write is in progress
+	// and return KErrNone.
+	TInt chanIntState=0;
+	chanIntState=__SPIN_LOCK_IRQSAVE(*iChanLock);
+	if(iChanRwFlags != 0)
+		{
+		__SPIN_UNLOCK_IRQRESTORE(*iChanLock,chanIntState);
+		return KErrInUse;
+		}
+	iChanRwFlags |= EWriteInProgress;
+	__SPIN_UNLOCK_IRQRESTORE(*iChanLock,chanIntState);
+	return KErrNone;
+	}
+
+void DIicBusController::FreeChanWriteAccess()
+	{
+	// If an insertion or removal is in progress, no other modifying operation
+	// can be active. Reads are also not permitted - so iChanRwFlags can only be
+	// EWriteInProgress.
+	__ASSERT_DEBUG(iChanRwFlags == EWriteInProgress, Kern::Fault(KIicPanic,__LINE__));
+	TInt chanIntState=0;
+ 	chanIntState=__SPIN_LOCK_IRQSAVE(*iChanLock);
+ 	iChanRwFlags &= ~EWriteInProgress;
+ 	__SPIN_UNLOCK_IRQRESTORE(*iChanLock,chanIntState);
+	}
+
+TInt DIicBusController::GetChanReadAccess()
+	{
+	// No reads are permitted while an insertion or removal is in progress
+	// If one of the above operations is in progress return KErrInUse
+	// Can have several concurrent reads at any one time - so increment
+	// the count of such operations as well as ensuring the flag is set to indicate
+	// a read is in progress
+	TInt chanIntState=0;
+	chanIntState=__SPIN_LOCK_IRQSAVE(*iChanLock);
+	if(iChanRwFlags == EWriteInProgress)
+		{
+		__SPIN_UNLOCK_IRQRESTORE(*iChanLock,chanIntState);
+		return KErrInUse;
+		}
+	__ASSERT_DEBUG(iChanRdCount!=0xFFFFFFFF, Kern::Fault(KIicPanic,__LINE__)); // Overflow
+	iChanRdCount++;
+	iChanRwFlags |= EReadInProgress;
+	__SPIN_UNLOCK_IRQRESTORE(*iChanLock,chanIntState);
+	return KErrNone;
+	}
+
+void DIicBusController::FreeChanReadAccess()
+	{
+	// No insertions or removals are permitted while a read is in progress
+	// so iChanRwFlags can only be EReadInProgress
+	// Multiple reads can be in progress concurrently, so the count must be decremented
+	TInt chanIntState=0;
+	chanIntState=__SPIN_LOCK_IRQSAVE(*iChanLock);
+	__ASSERT_DEBUG(iChanRwFlags == EReadInProgress, Kern::Fault(KIicPanic,__LINE__));
+	__ASSERT_DEBUG(iChanRdCount>0, Kern::Fault(KIicPanic,__LINE__));
+	iChanRdCount--;
+	if(iChanRdCount == 0)
+		iChanRwFlags &= ~EReadInProgress;
+	__SPIN_UNLOCK_IRQRESTORE(*iChanLock,chanIntState);
+	}
+
+TInt DIicBusController::RequestTypeSupported(const TInt aBusId, DIicBusChannelMaster* const aChannel)
+	{
+	TInt32 reqBusType;
+	reqBusType = GET_BUS_TYPE(aBusId);
+	__KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::RequestTypeSupported, BusType=0x%x\n", reqBusType));
+
+	if(reqBusType != aChannel->BusType())
+		{
+		return KErrNotSupported;
+		}
+
+	return KErrNone;
+	}
+
+
+EXPORT_C TInt DIicBusController::RegisterChannels(DIicBusChannel** aListChannels, TInt aNumberChannels)
+	{
+// To be used by Channel implementations to register a list of supported channels
+    __KTRACE_OPT(KIIC, Kern::Printf("\nDIicBusController::RegisterChannels, aListChannels=0x%x, aNumberChannels=%d\n",aListChannels,aNumberChannels));
+	__ASSERT_DEBUG(aListChannels!=NULL, Kern::Fault(KIicPanic,__LINE__));
+
+	RPointerArray<DIicBusChannel>* chanArray = TheController->ChannelArray();
+
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_REGISTERCHANS_START_PIL_TRACE;
+#endif
+	// Get access to the channel pointer array - exit if it is currently being modfied
+	TInt r=KErrNone;
+	if((r=TheController->GetChanWriteAccess()) == KErrNone)
+		{
+#ifdef _DEBUG
+		__KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::RegisterChannels - On entry, iChannelArray ...\n"));
+		TheController->DumpChannelArray();
+#endif
+		// Loop for aNumberChannels	and write directly to the channel array
+		DIicBusChannel** chanIterator = aListChannels;
+		for(TInt iteration = 0; iteration < aNumberChannels; ++iteration, ++chanIterator)
+			{
+			DIicBusChannel* chanPtr = *chanIterator;
+			__KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::RegisterChannels - adding channel number %d\n",chanPtr->ChannelNumber()));
+			TInt r = chanArray->InsertInOrder(chanPtr,EntryOrder);
+			if(r!=KErrNone)
+				break;
+			}
+
+#ifdef _DEBUG
+		 __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::RegisterChannels - On exit, iChannelArray ...\n"));
+		TheController->DumpChannelArray();
+#endif
+		TheController->FreeChanWriteAccess();
+		}
+	else
+		{
+		__KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::GetChanWriteAccess returned %d\n",r));
+		}
+
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_REGISTERCHANS_END_PIL_TRACE;
+#endif
+	return r;
+	}
+
+
+EXPORT_C TInt DIicBusController::DeRegisterChannel(DIicBusChannel* aChannel)
+	{
+// To be used by Channel implementations to deregister a channel
+    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::DeRegisterChannel, aChannel=0x%x\n",aChannel));
+	if(aChannel == NULL)
+		return KErrArgument;
+
+	RPointerArray<DIicBusChannel>* chanArray = TheController->ChannelArray();
+
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_DEREGISTERCHAN_START_PIL_TRACE;
+#endif
+	TInt r=KErrNone;
+	// Get access to the channel pointer array - exit if it is currently unavailable
+	// Gaining write access will prevent a client of a Master Channel from instigating a new QueueTransaction
+	// (or CancelTransaction), and it will obstruct a client of a Slave Channel in CaptureChannel.
+	if((r=TheController->GetChanWriteAccess())!=KErrNone)
+		return r;
+
+	// Check channel is registered
+	TInt chanIndex = chanArray->FindInOrder(aChannel,EntryOrder);
+	if(chanIndex<0)
+		{
+		TheController->FreeChanWriteAccess();
+		return KErrNotFound;
+		}
+
+#ifdef _DEBUG
+    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::DeRegisterChannel - On entry, iChannelArray ...\n"));
+	TheController->DumpChannelArray();
+#endif
+
+	// Remove the channel from the array
+	// Note that this does not delete the channel object
+	chanArray->Remove(chanIndex);
+
+#ifdef _DEBUG
+    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::DeRegisterChannel - On exit, iChannelArray ...\n"));
+	TheController->DumpChannelArray();
+#endif
+	TheController->FreeChanWriteAccess();
+
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_DEREGISTERCHAN_END_PIL_TRACE;
+#endif
+	return KErrNone;
+	}
+
+TInt DIicBusController::FindCapturedChanById(TCapturedChannel aCapturedChan, TInt& aIndex)
+	{
+	TInt index=0;
+	TInt r=KErrNotFound;
+	do
+		{
+		if(iCapturedChannels[index].iChannelId == aCapturedChan.iChannelId)
+			{
+			aIndex=index;
+			r=KErrNone;
+			}
+		index++;
+		} while ((index < KMaxNumCapturedChannels)&&(r == KErrNotFound));
+	return r;
+	}
+
+TInt DIicBusController::FindCapturedChan(TCapturedChannel aCapturedChan, TInt& aIndex)
+	{
+	TInt index=0;
+	TInt r=KErrNotFound;
+	do
+		{
+		if(iCapturedChannels[index] == aCapturedChan)
+			{
+			aIndex=index;
+			r=KErrNone;
+			}
+		index++;
+		} while ((index < KMaxNumCapturedChannels)&&(r == KErrNotFound));
+	return r;
+	}
+
+TInt DIicBusController::InsertCaptChanInArray(TCapturedChannel aCapturedChan)
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::InsertCaptChanInArray \n"));
+	// Ensure the channel hasn't already been inserted in the array
+	// If found, fault the Kernel
+	TInt dumInt = 0;
+	TInt r=FindCapturedChan(aCapturedChan,dumInt);
+	__ASSERT_DEBUG(r!=KErrNone, Kern::Fault(KIicPanic,__LINE__));
+
+	// Loop the array and insert in the first available slot
+	// If no slots are available return KErrNotReady
+	TInt index=0;
+	TCapturedChannel emptyChan;
+	for(;index<KMaxNumCapturedChannels;++index)
+		{
+		if(iCapturedChannels[index] == emptyChan)
+			{
+			// Found a space
+			iCapturedChannels[index]=aCapturedChan;
+			break;
+			}
+		}
+	if(index>=KMaxNumCapturedChannels)
+		r = KErrNotReady;
+	return r;
+	}
+
+TInt DIicBusController::RemoveCaptChanFromArray(TCapturedChannel aCapturedChan)
+	{
+	// Remove the entry from the array
+	// If the entry is not present return KErrArgument
+	TInt index=-1;
+	TInt r=FindCapturedChan(aCapturedChan,index);
+	if((r!=KErrNone)||(index>=KMaxNumCapturedChannels))
+		return KErrArgument;
+	iCapturedChannels[index].iChanPtr=NULL;
+	iCapturedChannels[index].iChannelId=0;
+	return KErrNone;
+	}
+
+
+TInt DIicBusController::InstallCapturedChannel(const TInt aChannelId, const DIicBusChannelSlave* aChanPtr)
+	{
+#ifdef _DEBUG
+    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::InstallCapturedChannel - On entry, iCapturedChannels ...\n"));
+	DumpCapturedChannels();
+#endif
+	TInt r=KErrNone;
+	TCapturedChannel capturedChan((TInt)aChannelId,(DIicBusChannelSlave*)aChanPtr);
+	// Because insertions are bounded by the size of the array and do not involve allocating
+	// or freeing memory, simply take the spinlock at the start of the operation and release at the end
+	TInt captIntState=__SPIN_LOCK_IRQSAVE(*iCaptLock);
+	r=InsertCaptChanInArray(capturedChan);
+	__SPIN_UNLOCK_IRQRESTORE(*iCaptLock,captIntState);
+	if(r!=KErrNone)
+		return r;
+
+#ifdef _DEBUG
+    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::InstallCapturedChannel - On exit, iCapturedChannels ...\n"));
+	DumpCapturedChannels();
+#endif
+	return KErrNone;
+	}
+
+TInt DIicBusController::DeInstallCapturedChannel(const TInt aChannelId, const DIicBusChannelSlave* aChanPtr)
+	{
+#ifdef _DEBUG
+    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::DeInstallCapturedChannel - On entry, iCapturedChannels ...\n"));
+	DumpCapturedChannels();
+#endif
+	TInt r = KErrNone;
+	TCapturedChannel capturedChan((TInt) aChannelId, (DIicBusChannelSlave*) aChanPtr);
+	// Because removals are bounded by the size of the array and do not involve allocating
+	// or freeing memory, simply take the spinlock at the start of the operation and release at the end
+	TInt captIntState = __SPIN_LOCK_IRQSAVE(*iCaptLock);
+	r = RemoveCaptChanFromArray(capturedChan);
+	__SPIN_UNLOCK_IRQRESTORE(*iCaptLock, captIntState);
+	if(r != KErrNone)
+		return r;
+
+#ifdef _DEBUG
+    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::DeInstallCapturedChannel - On exit, iCapturedChannels ...\n"));
+	DumpCapturedChannels();
+#endif
+	return KErrNone;
+	}
+
+	// Master-side API
+TInt DIicBusController::QueueTransaction(TInt aBusId, TIicBusTransaction* aTransaction)
+	{
+	__KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::QueueTransaction, aBusId=0x%x,aTransaction=0x%x\n", aBusId, aTransaction));
+	if(!aTransaction)
+		{
+		return KErrArgument;
+		}
+
+	// Get a pointer to the channel
+	TInt dumInt = 0;
+	DIicBusChannel* chanPtr = NULL;
+	// Can only read the channel array if it is not currently being modified
+	TInt r = GetChanReadAccess();
+	if(r != KErrNone)
+		{
+		return r;
+		}
+	r = GetChanPtr(aBusId, dumInt, chanPtr);
+	if(r == KErrNone)
+		{
+		if(!chanPtr)
+			{
+			r = KErrArgument;
+			}
+		else
+			{
+			switch(chanPtr->ChannelType())
+				{
+				// QueueTransaction requests are only supported by channels in Master mode.
+				case DIicBusChannel::ESlave:
+					{
+					r = KErrNotSupported;
+					break;
+					}
+				// If the request is supported by the Master channel, send it to the channel for processing in its thread
+				case DIicBusChannel::EMasterSlave:
+					{
+					r = RequestTypeSupported(aBusId, ((DIicBusChannelMasterSlave*)chanPtr)->iMasterChannel);
+					if(r == KErrNone)
+						{
+						aTransaction->iBusId = aBusId;
+						r = (((DIicBusChannelMasterSlave*) chanPtr)->QueueTransaction(aTransaction));
+						}
+					break;
+					}
+				case DIicBusChannel::EMaster:
+					{
+					r = RequestTypeSupported(aBusId, (DIicBusChannelMaster*)chanPtr);
+					if(r == KErrNone)
+						{
+						aTransaction->iBusId = aBusId;
+						r = (((DIicBusChannelMaster*) chanPtr)->QueueTransaction(aTransaction));
+						}
+					break;
+					}
+				default:
+					{
+					r = KErrGeneral;
+					}
+				}
+			}
+		}
+	FreeChanReadAccess();
+	return r;
+	}
+
+TInt DIicBusController::QueueTransaction(TInt aBusId, TIicBusTransaction* aTransaction, TIicBusCallback* aCallback)
+	{
+    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::QueueTransaction, aBusId=0x%x,aTransaction=0x%x,aCallback=0x%x\n",aBusId,aTransaction,aCallback));
+	if(!aTransaction || !aCallback)
+		{
+		return KErrArgument;
+		}
+
+	// Get a pointer to the channel
+	TInt dumInt = 0;
+	DIicBusChannel* chanPtr = NULL;
+	// Can only read the channel array if it is not currently being modified
+	TInt r = GetChanReadAccess();
+	if(r == KErrNone)
+		{
+		r = GetChanPtr(aBusId, dumInt, chanPtr);
+		if(r == KErrNone)
+			{
+			if(!chanPtr)
+				{
+				r = KErrArgument;
+				}
+			else
+				{
+				switch(chanPtr->ChannelType())
+					{
+					// QueueTransaction requests are only supported by channels in Master mode.
+					case DIicBusChannel::ESlave:
+						{
+						r = KErrNotSupported;
+						break;
+						}
+					// If the request is supported by the Master channel, send it to the channel for processing in its thread
+					case DIicBusChannel::EMasterSlave:
+						{
+						r = RequestTypeSupported(aBusId, ((DIicBusChannelMasterSlave*)chanPtr)->iMasterChannel);
+						if(r == KErrNone)
+							{
+							aTransaction->iBusId = aBusId;
+							r = (((DIicBusChannelMasterSlave*) chanPtr)->QueueTransaction(aTransaction, aCallback));
+							}
+						break;
+						}
+					case DIicBusChannel::EMaster:
+						{
+						r = RequestTypeSupported(aBusId, (DIicBusChannelMaster*)chanPtr);
+						if(r == KErrNone)
+							{
+							aTransaction->iBusId = aBusId;
+							r = (((DIicBusChannelMaster*) chanPtr)->QueueTransaction(aTransaction, aCallback));
+							}
+						break;
+						}
+					default:
+						{
+						r = KErrGeneral;
+						}
+					}
+				}
+			}
+		}
+	FreeChanReadAccess();
+	return r;
+	}
+
+
+TInt DIicBusController::GetChanPtr(const TInt aBusId, TInt &aIndex, DIicBusChannel*& aChan)
+	{
+    __KTRACE_OPT(KIIC, 	Kern::Printf("DIicBusController::GetChanPtr, aBusId=0x%x\n",aBusId));
+
+	TInt32 chanId;
+	chanId = GET_CHAN_NUM(aBusId);
+
+	__KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::GetChanPtr, chanId=0x%x\n", chanId));
+	DIicBusChannelSearcher searchChannel(DIicBusChannel::EMasterSlave, DIicBusChannel::ESccb, DIicBusChannel::EFullDuplex);
+	searchChannel.SetChannelNumber((TInt8)chanId);
+
+	TInt r = KErrNotFound;
+	aIndex = iChannelArray.FindInOrder(&searchChannel, EntryOrder);
+	if(aIndex >= 0)
+		{
+		aChan = iChannelArray[aIndex];
+		r = KErrNone;
+		}
+
+	__KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::GetChanPtr, chanPtr=0x%x, index=%d\n", aChan, aIndex));
+	return r;
+	}
+
+
+TInt DIicBusController::CancelTransaction(TInt aBusId, TIicBusTransaction* aTransaction)
+	{
+    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::CancelTransaction, aBusId=0x%x,aTransaction=0x%x\n", aBusId, aTransaction));
+	if(!aTransaction)
+		{
+		return KErrArgument;
+		}
+
+	// Get the channel
+	TInt dumInt = 0;
+	DIicBusChannel* chanPtr = NULL;
+
+	// Can only read the channel array if it is not currently being modified
+	TInt r = GetChanReadAccess();
+	if(r == KErrNone)
+		{
+		r = GetChanPtr(aBusId, dumInt, chanPtr);
+		if(r == KErrNone)
+			{
+			if(!chanPtr)
+				{
+				r = KErrArgument;
+				}
+			else
+				{
+				// QueueTransaction requests are only supported by channels in Master mode.
+				switch(chanPtr->ChannelType())
+					{
+					case DIicBusChannel::ESlave:
+						{
+						r = KErrNotSupported;
+						break;
+						}
+					case DIicBusChannel::EMasterSlave:
+						{
+						r = RequestTypeSupported(aBusId, ((DIicBusChannelMasterSlave*)chanPtr)->iMasterChannel);
+						if(r == KErrNone)
+							{
+							r = (((DIicBusChannelMasterSlave*) chanPtr)->CancelTransaction(aTransaction));
+							}
+						break;
+						}
+					case DIicBusChannel::EMaster:
+						{
+						r = RequestTypeSupported(aBusId, (DIicBusChannelMaster*)chanPtr);
+						if(r == KErrNone)
+							{
+							r = (((DIicBusChannelMaster*) chanPtr)->CancelTransaction(aTransaction));
+							}
+						break;
+						}
+					default:
+						{
+						r = KErrGeneral;
+						}
+					}
+				}
+			}
+		}
+	FreeChanReadAccess();
+	return r;
+	}
+
+	// Slave-side API
+TInt DIicBusController::CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch)
+	{
+	// Check that that aCallback!=NULL and aConfigHdr!=NULL - if not, return KErrArgument
+	if(!aCallback || !aConfigHdr)
+		{
+		return KErrArgument;
+		}
+
+	// Get the channel
+	TInt chanIndex = 0;
+	DIicBusChannel* chanPtr = NULL;
+
+	// Can only read the channel array if it is not currently being modified
+	TInt r = GetChanReadAccess();
+	if(r == KErrNone)
+		{
+		r = GetChanPtr(aBusId, chanIndex, chanPtr);
+		if(r == KErrNone)
+			{
+			if(!chanPtr)
+				{
+				r = KErrArgument;
+				}
+			else
+				{
+				DIicBusChannelSlave* slaveChanPtr = NULL;
+				switch(chanPtr->ChannelType())
+					{
+					// CaptureChannel requests are only supported by channels in Slave mode.
+					case DIicBusChannel::EMaster:
+						{
+						r = KErrNotSupported;
+						break;
+						}
+					case DIicBusChannel::EMasterSlave:
+						{
+						slaveChanPtr = ((DIicBusChannelMasterSlave*) chanPtr)->iSlaveChannel;
+						__ASSERT_DEBUG(slaveChanPtr!=NULL, Kern::Fault(KIicPanic,__LINE__)); // MasterSlave channel should have a valid Slave channel
+						// Send the request to the channel
+						slaveChanPtr->iController = this;
+						r = ((DIicBusChannelMasterSlave*) chanPtr)->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch);
+						break;
+						}
+					case DIicBusChannel::ESlave:
+						{
+						slaveChanPtr = (DIicBusChannelSlave*) chanPtr; // chanPtr is non-NULL
+						// Send the request to the channel
+						slaveChanPtr->iController = this;
+						r = (slaveChanPtr->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch));
+						break;
+						}
+					default:
+						{
+						r = KErrArgument;
+						}
+					}
+				// For synchronous capture, if successful then install the channel
+				if(r == KErrNone && slaveChanPtr)
+					{
+					if(!aAsynch)
+						{
+						InstallCapturedChannel(aChannelId, slaveChanPtr);
+						}
+					}
+				}
+			}
+		}
+	FreeChanReadAccess();
+	return r;
+	}
+
+
+TInt DIicBusController::GetSlaveChanPtr(TInt aChannelId, DIicBusChannelSlave*& aSlaveChanPtr)
+	{
+	TInt r=KErrNone;
+	// Check that the channelID is recognised
+	TCapturedChannel capturedChan(aChannelId,NULL);
+	TInt chanIndex=-1;
+	// Ensure the array of captured channels will not be modified before it has been searched
+	// Because searches are bounded by the size of the array and do not involve allocating
+	// or freeing memory, simply take the spinlock at the start of the operation and release at the end
+	TInt captIntState=__SPIN_LOCK_IRQSAVE(*iCaptLock);
+	r=FindCapturedChanById(capturedChan, chanIndex);
+	if((chanIndex < 0)||(r == KErrNotFound))
+		r=KErrArgument;
+	else
+		aSlaveChanPtr = (DIicBusChannelSlave*)(iCapturedChannels[chanIndex].iChanPtr);
+	__SPIN_UNLOCK_IRQRESTORE(*iCaptLock,captIntState);
+
+	__ASSERT_DEBUG(aSlaveChanPtr!=NULL, Kern::Fault(KIicPanic,__LINE__));
+	return r;
+	}
+
+
+TInt DIicBusController::ReleaseChannel(TInt aChannelId)
+	{
+    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::ReleaseChannel, channelID = 0x%x \n",aChannelId));
+	TInt r = KErrNone;
+	DIicBusChannel* chanPtr = NULL;
+	
+	// Get the pointer to the Slave Channel
+	DIicBusChannelSlave* slaveChanPtr = NULL;
+	if((r = GetSlaveChanPtr(aChannelId, slaveChanPtr)) != KErrNone)
+		return r;
+		
+	DIicBusChannelSearcher searchChannel(DIicBusChannel::EMasterSlave, DIicBusChannel::ESccb, DIicBusChannel::EFullDuplex);
+	searchChannel.SetChannelNumber(slaveChanPtr->ChannelNumber());
+
+	TInt dumIndex = iChannelArray.FindInOrder(&searchChannel, EntryOrder);
+	if(dumIndex < 0)
+		{
+		return KErrNotFound;
+		}
+	chanPtr = iChannelArray[dumIndex];
+
+	__ASSERT_DEBUG(chanPtr!=NULL, Kern::Fault(KIicPanic,__LINE__));
+
+	//if it is the masterslave channel, then call the masterslave's RelaseChannel
+	// which will call the slave channel's ReleaseChannel internally
+	if(chanPtr->ChannelType() == DIicBusChannel::EMasterSlave)
+		r = ((DIicBusChannelMasterSlave*)chanPtr)->ReleaseChannel();
+	else // Call the slave only ReleaseChannel
+		r = slaveChanPtr->ReleaseChannel();
+	
+	// In either case de-install the captured slave channel
+	if(r == KErrNone)
+		{
+		r = DeInstallCapturedChannel(aChannelId, slaveChanPtr);
+		}
+
+	// No need to unset iController - there is only one IIC Controller
+	return r;
+	}
+
+
+TInt DIicBusController::RegisterRxBuffer(TInt aChannelId, TPtr8 aRxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
+	{
+    __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));
+
+    // Acquire the pointer to the Slave Channel
+	DIicBusChannelSlave* slaveChanPtr = NULL;
+	TInt r = GetSlaveChanPtr(aChannelId, slaveChanPtr);
+	if(r != KErrNone)
+		{
+		return r;
+		}
+
+	// Instigate the channel functionality
+	return(slaveChanPtr->RegisterRxBuffer(aRxBuffer,aBufGranularity,aNumWords,aOffset));
+	}
+
+TInt DIicBusController::RegisterTxBuffer(TInt aChannelId, TPtr8 aTxBuffer, TInt8 aBufGranularity, TInt8 aNumWords, TInt8 aOffset)
+	{
+    __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));
+
+	// Acquire the pointer to the Slave Channel
+	DIicBusChannelSlave* slaveChanPtr = NULL;
+	TInt r = GetSlaveChanPtr(aChannelId, slaveChanPtr);
+	if(r != KErrNone)
+		{
+		return r;
+		}
+
+	// Instigate the channel functionality
+	return (slaveChanPtr->RegisterTxBuffer(aTxBuffer, aBufGranularity, aNumWords, aOffset));
+	}
+
+
+TInt DIicBusController::SetNotificationTrigger(TInt aChannelId, TInt aTrigger)
+	{
+    __KTRACE_OPT(KIIC, Kern::Printf("DIicBusController::SetNotificationTrigger - for aChannelId=0x%x, aTrigger=0x%x\n",aChannelId,aTrigger));
+	// Acquire the pointer to the Slave Channel
+	DIicBusChannelSlave* slaveChanPtr = NULL;
+	TInt r = GetSlaveChanPtr(aChannelId, slaveChanPtr);
+	if( r != KErrNone)
+		{
+		return r;
+		}
+
+	// Instigate the channel functionality
+	return(slaveChanPtr->SetNotificationTrigger(aTrigger));
+	}
+
+
+TInt DIicBusController::StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2)
+	{
+//		The IIC controller and channel classes are generic, and can serve many differing client and
+//		bus implementations. If a client and bus make use of specific functionality that is not
+//		common to other bus types, it makes sense to provide only the minimum-required support in the
+//		generic code. Here, the channel identifier is checked but all other parameters are passed
+//		directly to the bus implementation channel for processing; if the channel does not provide
+//		StaticExtension implementation, the generic DIicBusChannel::StaticExtension method is invoked.
+
+#ifdef IIC_INSTRUMENTATION_MACRO
+	if((aFunction & KControlIoMask) == KMasterSlaveControlIo)
+		{
+		IIC_MSSTATEXT_START_PIL_TRACE
+		}
+	else if((aFunction & KControlIoMask) == KMasterControlIo)
+		{
+		IIC_MSTATEXT_START_PIL_TRACE
+		}
+	else if((aFunction & KControlIoMask) == KSlaveControlIo)
+		{
+		IIC_SSTATEXT_START_PIL_TRACE
+		}
+//	else - Unexpected value - just pass silently to the PSL ...
+#endif
+
+	// Get the channel
+	TInt dumInt = 0;
+	DIicBusChannel* chanPtr = NULL;
+	// Can only read the channel array if it is not currently being modified
+	TInt r = GetChanReadAccess();
+	if(r == KErrNone)
+		{
+		r = GetChanPtr(aId, dumInt, chanPtr);
+		if(r == KErrNone)
+			{
+			if(!chanPtr)
+				{
+				r = KErrArgument;
+				}
+			else
+				{
+				r = chanPtr->StaticExtension(aFunction, aParam1, aParam2);
+				}
+			}
+		}
+
+#ifdef IIC_INSTRUMENTATION_MACRO
+	if((aFunction & KControlIoMask) == KMasterSlaveControlIo)
+		{
+		IIC_MSSTATEXT_START_PIL_TRACE
+		}
+	else if((aFunction & KControlIoMask) == KMasterControlIo)
+		{
+		IIC_MSTATEXT_START_PIL_TRACE
+		}
+	else if((aFunction & KControlIoMask) == KSlaveControlIo)
+		{
+		IIC_SSTATEXT_START_PIL_TRACE
+		}
+//	else	... do nothing
+#endif
+	FreeChanReadAccess();
+	return r;
+	}
+
+
+#ifdef _DEBUG
+
+void DIicBusController::DumpCapturedChannels()
+	{
+	// Print iCapturedChannels ...
+	TInt count=0;
+	TInt i=0;
+	TCapturedChannel emptyChan;
+	for(;i<KMaxNumCapturedChannels;++i)
+		{
+		if(iCapturedChannels[i] == emptyChan)
+			continue;
+		++count;
+		}
+
+	i = 0;
+    __KTRACE_OPT(KIIC, Kern::Printf("	- Count gave %d\n",count));
+	for(;i<KMaxNumCapturedChannels;++i)
+		{
+		if(iCapturedChannels[i] == emptyChan)
+			continue;
+		DIicBusChannel* ptr=(DIicBusChannel*)(iCapturedChannels[i]).iChanPtr;
+	    __KTRACE_OPT(KIIC, Kern::Printf("	- ptr %d=0x%x\n",i,ptr));
+		ptr->StaticExtension(KCtrlIoDumpChan,0,0);
+		};
+	}
+
+void DIicBusController::DumpChannelArray()
+	{
+	TInt i = 0;
+	__KTRACE_OPT(KIIC, Kern::Printf("\nDIicBusController::DumpChannelArray\n"));
+    __KTRACE_OPT(KIIC, Kern::Printf("	- Count gave %d\n",iChannelArray.Count()));
+	for(i=0; i<iChannelArray.Count(); i++)
+		{
+		DIicBusChannel* ptr=iChannelArray[i];
+	    __KTRACE_OPT(KIIC, Kern::Printf("	- ptr %d=0x%x\n",i,ptr));
+		ptr->StaticExtension(KCtrlIoDumpChan,0,0);
+		};
+	}
+
+#endif
+
+#ifdef IIC_SIMULATED_PSL
+TVersion DIicPdd::VersionRequired()
+	{
+	const TInt KIicMajorVersionNumber=1;
+	const TInt KIicMinorVersionNumber=0;
+	const TInt KIicBuildVersionNumber=KE32BuildVersionNumber;
+	return TVersion(KIicMajorVersionNumber,KIicMinorVersionNumber,KIicBuildVersionNumber);
+	}
+
+/** Factory class constructor */
+DIicPdd::DIicPdd()
+	{
+    iVersion = DIicPdd::VersionRequired();
+	}
+
+DIicPdd::~DIicPdd()
+	{
+	delete TheController;
+	}
+
+TInt DIicPdd::Install()
+    {
+    return(SetName(&KPddName));
+    }
+
+/**  Called by the kernel's device driver framework to create a Physical Channel. */
+TInt DIicPdd::Create(DBase*& /*aChannel*/, TInt /*aUint*/, const TDesC8* /*anInfo*/, const TVersion& /*aVer*/)
+    {
+    return KErrNone;
+    }
+
+/**  Called by the kernel's device driver framework to check if this PDD is suitable for use with a Logical Channel.*/
+TInt DIicPdd::Validate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer)
+    {
+   	if (!Kern::QueryVersionSupported(DIicPdd::VersionRequired(),aVer))
+		return(KErrNotSupported);
+    return KErrNone;
+    }
+
+/** Return the driver capabilities */
+void DIicPdd::GetCaps(TDes8& aDes) const
+    {
+	// Create a capabilities object
+	TCaps caps;
+	caps.iVersion = iVersion;
+	// Zero the buffer
+	TInt maxLen = aDes.MaxLength();
+	aDes.FillZ(maxLen);
+	// Copy cpabilities
+	TInt size=sizeof(caps);
+	if(size>maxLen)
+	   size=maxLen;
+	aDes.Copy((TUint8*)&caps,size);
+    }
+#endif
+
+#ifndef IIC_SIMULATED_PSL
+// Client interface entry point
+DECLARE_EXTENSION_WITH_PRIORITY(KExtensionMaximumPriority-1)	// highest priority after Resource Manager
+	{
+	TheController = new DIicBusController;
+	if(!TheController)
+		return KErrNoMemory;
+	TInt r=TheController->Create();
+	return r;
+	}
+#else
+static DIicPdd* TheIicPdd;
+
+DECLARE_STANDARD_PDD()
+	{
+	TheController = new DIicBusController;
+	if(!TheController)
+		return NULL;
+	TInt r = TheController->Create();
+	if(r == KErrNone)
+		{
+		TheIicPdd = new DIicPdd;
+		if(TheIicPdd)
+			return TheIicPdd;
+		}
+	
+	delete TheController; 
+	return NULL;
+	}
+#endif
+
+
+