Trying to figure out how to implement my WINC like compatibility layer. Going the emulation way is probably not so smart. We should not use the kernel but rather hook native functions in the Exec calls.
// 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