Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h)
Have multiple extension sections in the bld.inf, one for each version
of the compiler. The RVCT version building the tools will build the
runtime libraries for its version, but make sure we extract all the other
versions from zip archives. Also add the archive for RVCT4.
// Copyright (c) 1998-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:
// template\template_variant\specific\uart.cpp
// pdd for serial ports
// assume Modem Control Signals change cause an interrupt
//
//
#include <drivers/comm.h>
#include <template_assp.h>
#include "iolines.h"
#include <e32hal.h>
_LIT(KPddName,"Comm.Template");
// needs ldd version..
const TInt KMinimumLddMajorVersion=1;
const TInt KMinimumLddMinorVersion=1;
const TInt KMinimumLddBuild=122;
//
// TO DO: (mandatory)
//
// Define here the UART enumeration data for the serial ports.
// It is a good idea to define each enumerated value as a bit mask that can be written to (or OR-ed or AND-ed to)
// a hardware register to provide the configuration option desired (the following are EXAMPLES ONLY):
//
// EXAMPLE ONLY
enum TUartBaudRate
{
EUartBaudRate115200/* =bitmask for 115200 Baud */,
EUartBaudRate76800/* =bitmask for 76800 Baud */,
EUartBaudRate57600/* =bitmask for 57600 Baud */,
EUartBaudRate38400/* =bitmask for 38400 Baud */,
EUartBaudRate19200/* =bitmask for 19200 Baud */,
EUartBaudRate14400/* =bitmask for 14400 Baud */,
EUartBaudRate9600/* =bitmask for 9600 Baud */,
EUartBaudRate4800/* =bitmask for 4800 Baud */,
EUartBaudRate2400/* =bitmask for 2400 Baud */,
EUartBaudRate1200/* =bitmask for 1200 Baud */,
EUartBaudRate600/* =bitmask for 600 Baud */,
EUartBaudRate300/* =bitmask for 300 Baud */,
EUartBaudRate150/* =bitmask for 150 Baud */,
EUartBaudRate110/* =bitmask for 110 Baud */
};
// EXAMPLE ONLY
enum TUartBreak
{
EUartBreakOff/* =bitmask for turning Break Off */,
EUartBreakOn/* =bitmask for turning Break On */
};
// EXAMPLE ONLY
enum TUartParity
{
EUartParityNone/* =bitmask for no Parity */,
EUartParityOdd/* =bitmask for odd Parity */,
EUartParityEven/* =bitmask for even Parity */
};
// EXAMPLE ONLY
enum TUartStopBit
{
EUartStopBitOne/* =bitmask for one stop bit */,
EUartStopBitTwo/* =bitmask for two stop bits */
};
enum TUartDataLength
{
EUartDataLength5/* =bitmask for five data bits */,
EUartDataLength6/* =bitmask for six data bits */,
EUartDataLength7/* =bitmask for seven data bits */,
EUartDataLength8/* =bitmask for eight data bits */
};
//
// TO DO: (mandatory)
//
// Lookup table to convert EPOC baud rates into hardware-specific baud rate values
// Unsupported baud rates select the nearest lower rate.
//
// EXAMPLE ONLY
static const TUartBaudRate BaudRate[19] =
{
EUartBaudRate110,EUartBaudRate110,EUartBaudRate110,
EUartBaudRate110,EUartBaudRate150,EUartBaudRate300,
EUartBaudRate600,EUartBaudRate1200,EUartBaudRate110,
EUartBaudRate110,EUartBaudRate2400,EUartBaudRate110,
EUartBaudRate4800,EUartBaudRate110,EUartBaudRate9600,
EUartBaudRate19200,EUartBaudRate38400,EUartBaudRate57600,
EUartBaudRate115200
};
//
// TO DO: (mandatory)
//
// Lookup table to convert EPOC parity settings into hardware-specific values
//
// EXAMPLE ONLY
static const TUartParity Parity[3] =
{
EUartParityNone,EUartParityEven,EUartParityOdd
};
//
// TO DO: (mandatory)
//
// Lookup table to convert EPOC stop bit values into hardware-specific values
//
// EXAMPLE ONLY
static const TUartStopBit StopBit[2] =
{
EUartStopBitOne,EUartStopBitTwo
};
//
// TO DO: (mandatory)
//
// Lookup table to convert EPOC data bit settings into hardware-specific values
//
// EXAMPLE ONLY
static const TUartDataLength DataLength[4] =
{
EUartDataLength5,EUartDataLength6,
EUartDataLength7,EUartDataLength8
};
class DDriverComm : public DPhysicalDevice
{
public:
DDriverComm();
virtual TInt Install();
virtual void GetCaps(TDes8 &aDes) const;
virtual TInt Create(DBase*& aChannel, TInt aUnit, const TDesC8* anInfo, const TVersion &aVer);
virtual TInt Validate(TInt aUnit, const TDesC8* anInfo, const TVersion &aVer);
};
class DCommTemplate : public DComm
{
public:
DCommTemplate();
~DCommTemplate();
TInt DoCreate(TInt aUnit, const TDesC8* anInfo);
public:
virtual TInt Start();
virtual void Stop(TStopMode aMode);
virtual void Break(TBool aState);
virtual void EnableTransmit();
virtual TUint Signals() const;
virtual void SetSignals(TUint aSetMask,TUint aClearMask);
virtual TInt ValidateConfig(const TCommConfigV01 &aConfig) const;
virtual void Configure(TCommConfigV01 &aConfig);
virtual void Caps(TDes8 &aCaps) const;
virtual TInt DisableIrqs();
virtual void RestoreIrqs(TInt aIrq);
virtual TDfcQue* DfcQ(TInt aUnit);
virtual void CheckConfig(TCommConfigV01& aConfig);
public:
static void Isr(TAny* aPtr);
public:
TInt iInterruptId;
TInt iUnit;
TLinAddr iPortAddr;
TInt iInInterrupt;
TUint iSignals;
TDynamicDfcQue* iDfcQ;
};
DDriverComm::DDriverComm()
//
// Constructor
//
{
//
// TO DO: (mandatory)
//
// Set up iUnitMask with the number of Units (Serial Ports) supported by this PDD,
// 1 bit set per Unit supported e.g.:
// iUnitsMask=0x7; -> supports units 0, 1, 2
//
iVersion=TVersion(KCommsMajorVersionNumber,KCommsMinorVersionNumber,KCommsBuildVersionNumber);
}
TInt DDriverComm::Install()
//
// Install the driver
//
{
return SetName(&KPddName);
}
void GetTemplateCommsCaps(TDes8 &aCaps, TInt aUnit)
{
TCommCaps2 capsBuf;
//
// TO DO: (mandatory)
//
// Fill in the Caps structure with the relevant information for this Unit, e.g
// TCommCapsV02 &c=capsBuf();
// c.iRate=(OR in as many KCapsBpsXXX as bit rates supported);
// c.iDataBits=(OR in as many KCapsDataXXX as data length configuration supported);
// c.iStopBits=(OR in as many KCapsStopXXX as the number of stop bits configurations supported);
// c.iParity=(OR in as many KCapsParityXXX as parity configuration supported);
// c.iHandshake=(OR in all KCapsObeyXXXSupported, KCapsSendXXXSupported, KCapsFailXXXSupported, KCapsFreeXXXSupported
// as required for this Unit's configuration);.
// c.iSignals=(OR in as many KCapsSignalXXXSupported as Modem control signals controllable by this Unit);
// c.iSIR=(0 or OR in as many KCapsSIRXXX as IR bit rates supported);
// c.iNotificationCaps=(OR in as many KNotifyXXXSupported as notifications supported by this Unit);
// c.iFifo=(0 or KCapsHasFifo);
// c.iRoleCaps=(0 or KCapsRoleSwitchSupported);
// c.iFlowControlCaps=(0 or KCapsFlowControlStatusSupported);
/** @see TCommCapsV02 */
//
aCaps.FillZ(aCaps.MaxLength());
aCaps=capsBuf.Left(Min(capsBuf.Length(),aCaps.MaxLength()));
}
void DDriverComm::GetCaps(TDes8 &aDes) const
//
// Return the drivers capabilities
//
{
GetTemplateCommsCaps(aDes, 0);
}
TInt DDriverComm::Create(DBase*& aChannel, TInt aUnit, const TDesC8* anInfo, const TVersion& aVer)
//
// Create a driver
//
{
DCommTemplate* pD=new DCommTemplate;
aChannel=pD;
TInt r=KErrNoMemory;
if (pD)
r=pD->DoCreate(aUnit,anInfo);
return r;
}
TInt DDriverComm::Validate(TInt aUnit, const TDesC8* /*anInfo*/, const TVersion& aVer)
//
// Validate the requested configuration (Version and Unit)
//
{
if ((!Kern::QueryVersionSupported(iVersion,aVer)) || (!Kern::QueryVersionSupported(aVer,TVersion(KMinimumLddMajorVersion,KMinimumLddMinorVersion,KMinimumLddBuild))))
return KErrNotSupported;
//
// TO DO: (mandatory)
//
// Return KErrNotSupported if aUnit is not in the supported range for this driver, KErrNone if it is
//
return KErrNone;
}
DCommTemplate::DCommTemplate()
//
// Constructor
//
{
iInterruptId=-1; // -1 means not bound
}
DCommTemplate::~DCommTemplate()
//
// Destructor
//
{
if (iInterruptId>=0)
Interrupt::Unbind(iInterruptId);
if (iDfcQ)
{
iDfcQ->Destroy();
}
}
const TInt KDCommTemplDfcThreadPriority = 24;
_LIT(KDCommTemplDfcThread,"DCommTemplDfcThread");
TInt DCommTemplate::DoCreate(TInt aUnit, const TDesC8* /*anInfo*/)
//
// Sets up the PDD
//
{
iUnit=aUnit;
TInt irq=-1;
//
// TO DO: (mandatory)
//
// Create own DFC queue
TInt r = Kern::DynamicDfcQCreate(iDfcQ, KDCommTemplDfcThreadPriority, KDCommTemplDfcThread);
if (r != KErrNone)
return r;
// Set iPortAddr and irq with the Linear Base address of the UART and the Interrupt ID coresponding to aUnit
//
// bind to UART interrupt
r=Interrupt::Bind(irq,Isr,this);
if (r==KErrNone)
iInterruptId=irq;
//
// TO DO: (optional)
//
// Any other setting up of UART hardware registers, required for:
// - Disabling the UART operation
// - disabling all UART Interrupts
// - clearing all Rx errors
// - clearing all UART interrupts
// - de-activating output Modem Control signals
//
Variant::MarkDebugPortOff();
return r;
}
TDfcQue* DCommTemplate::DfcQ(TInt aUnit)
//
// Return the DFC queue to be used for this device
// For UARTs just use the standard low priority DFC queue
// For Serial PC cards, use the PC card controller thread for the socket in question.
//
{
return aUnit==iUnit ? iDfcQ : NULL;
}
TInt DCommTemplate::Start()
//
// Start receiving characters
//
{
iTransmitting=EFalse; // if EnableTransmit() called before Start()
//
// TO DO: (mandatory)
//
// Set up hardware registers to enable the UART and switch receive mode on
//
// if (iUnit!=IR Port) TO DO: (mandatory): Implement
{
iSignals=Signals();
iLdd->UpdateSignals(iSignals);
}
//
// TO DO: (optional)
//
// If Unit is IR Port may need to start the IR port
//
Interrupt::Enable(iInterruptId);
return KErrNone;
}
TBool FinishedTransmitting(TAny* aPtr)
{
//
// TO DO: (mandatory)
//
// Return ETrue if UART is still transmitting, EFalse Otherwise
//
return EFalse; // EXAMPLE ONLY
}
void DCommTemplate::Stop(TStopMode aMode)
//
// Stop receiving characters
//
{
switch (aMode)
{
case EStopNormal:
case EStopPwrDown:
Interrupt::Disable(iInterruptId);
iTransmitting=EFalse;
// wait for uart to stop tranmitting
Kern::PollingWait(FinishedTransmitting,this,3,100);
//
// TO DO: (optional)
//
// Any other setting up of UART hardware registers, required for:
// - Disabling the UART operation
// - disabling all UART Interrupts
// - disabling Transmit and Receive pathes
// - clearing all UART interrupts
//
break;
case EStopEmergency:
Interrupt::Disable(iInterruptId);
iTransmitting=EFalse;
break;
}
//
// TO DO: (optional)
//
// If Unit is IR Port may need to stop the IR port
//
Variant::MarkDebugPortOff();
}
void DCommTemplate::Break(TBool aState)
//
// Start or stop the uart breaking
//
{
if (aState)
{
//
// TO DO: (mandatory)
//
// Enable sending a Break (space) condition
//
}
else
{
//
// TO DO: (mandatory)
//
// Stop sending a Break (space) condition
//
}
}
void DCommTemplate::EnableTransmit()
//
// Start sending characters.
//
{
TBool tx = (TBool)__e32_atomic_swp_ord32(&iTransmitting, 1);
if (tx)
return;
TInt r = 0;
while (/* (Transmit FIFO Not full) && */ Kern::PowerGood()) // TO DO: (mandatory): Implement
{
TInt r=TransmitIsr();
if(r<0)
{
//no more to send
iTransmitting=EFalse;
break;
}
//
// TO DO: (mandatory)
//
// Write transmit character into transmit FIFO or output register
//
}
TInt irq=0;
if (!iInInterrupt) // CheckTxBuffer adds a Dfc: can only run from ISR or with NKernel locked
{
NKern::Lock();
irq=NKern::DisableAllInterrupts();
}
CheckTxBuffer();
if (!iInInterrupt)
{
NKern::RestoreInterrupts(irq);
NKern::Unlock();
}
//
// TO DO: (mandatory)
//
// Enable transmission of data
//
if (r>=0) // only enable interrupt if there's more data to send
{
//
// TO DO: (mandatory)
//
// Enable transmit interrupt in the Hardware (Interrupt::Enable() has already been called in Start())
//
}
}
TUint DCommTemplate::Signals() const
//
// Read and translate the modem lines
//
{
TUint signals=0;
//
// TO DO: (mandatory)
//
// If the UART corresponding to iUnit supports Modem Control Signals, read them and return a bitmask with one or
// more of the following OR-ed in:
// - KSignalDTR,
// - KSignalRTS,
// - KSignalDSR,
// - KSignalCTS,
// - KSignalDCD.
//
return signals;
}
void DCommTemplate::SetSignals(TUint aSetMask, TUint aClearMask)
//
// Set signals.
//
{
//
// TO DO: (mandatory)
//
// If the UART corresponding to iUnit supports Modem Control Signals, converts the flags in aSetMask and aClearMask
// into hardware-specific bitmasks to write to the UART modem/handshake output register(s).
// aSetMask, aClearMask will have one or more of the following OR-ed in:
// - KSignalDTR,
// - KSignalRTS,
//
}
TInt DCommTemplate::ValidateConfig(const TCommConfigV01 &aConfig) const
//
// Check a config structure.
//
{
//
// TO DO: (mandatory)
//
// Checks the the options in aConfig are supported by the UART corresponding to iUnit
// May need to check:
// - aConfig.iParity (contains one of EParityXXX)
/** @see TParity */
// - aConfig.iRate (contains one of EBpsXXX)
/** @see TBps */
// - aConfig.iDataBits (contains one of EDataXXX)
/** @see TDataBits */
// - aConfig.iStopBits (contains one of EStopXXX)
/** @see TDataBits */
// - aConfig.iHandshake (contains one of KConfigObeyXXX or KConfigSendXXX or KConfigFailXXX or KConfigFreeXXX)
// - aConfig.iParityError (contains KConfigParityErrorFail or KConfigParityErrorIgnore or KConfigParityErrorReplaceChar)
// - aConfig.iFifo (contains ether EFifoEnable or EFifoDisable)
/** @see TFifo */
// - aConfig.iSpecialRate (may contain a rate not listed under TBps)
// - aConfig.iTerminatorCount (conatains number of special characters used as terminators)
// - aConfig.iTerminator[] (contains a list of special characters which can be used as terminators)
// - aConfig.iXonChar (contains the character used as XON - software flow control)
// - aConfig.iXoffChar (contains the character used as XOFF - software flow control)
// - aConfig.iParityErrorChar (contains the character used to replace bytes received with a parity error)
// - aConfig.iSIREnable (contains either ESIREnable or ESIRDisable)
/** @see TSir */
// - aConfig.iSIRSettings (contains one of KConfigSIRXXX)
// and returns KErrNotSupported if the UART corresponding to iUnit does not support this configuration
//
return KErrNone;
}
void DCommTemplate::CheckConfig(TCommConfigV01& aConfig)
{
//
// TO DO: (optional)
//
// Validates the default configuration that is defined when a channel is first opened
//
}
TInt DCommTemplate::DisableIrqs()
//
// Disable normal interrupts
//
{
return NKern::DisableInterrupts(1);
}
void DCommTemplate::RestoreIrqs(TInt aLevel)
//
// Restore normal interrupts
//
{
NKern::RestoreInterrupts(aLevel);
}
void DCommTemplate::Configure(TCommConfigV01 &aConfig)
//
// Configure the UART from aConfig
//
{
Kern::PollingWait(FinishedTransmitting,this,3,100); // wait for uart to stop tranmitting
//
// TO DO: (optional)
//
// Ensure Tx, Rx and the UART are disabled and disable sending Break (space) condition.
// May need to modify clocks settings, pin functions etc.
//
//
// TO DO: (mandatory)
//
// Set communications parameters such as:
// - Baud rate
// - Parity
// - Stop bits
// - Data bits
// These can be obtained from aConfig using the look-up tables above, e.g.
// TUint baudRate=BaudRate[aConfig.iRate];
// TUint parity=Parity[aConfig.iParity];
// TUint stopBits=StopBit[aConfig.iStopBits];
// TUint dataBits=DataLength[aConfig.iDataBits];
// Write these to the appropriate hardware registers using iPortAddr to identify which ste of register to modify
//
//
// TO DO: (optional)
//
// If the UART corresponding to iUnit supports IR may need to set up IR transceiver
//
}
void DCommTemplate::Caps(TDes8 &aCaps) const
//
// return our caps
//
{
GetTemplateCommsCaps(aCaps,iUnit);
}
void DCommTemplate::Isr(TAny* aPtr)
//
// Service the UART interrupt
//
{
DCommTemplate& d=*(DCommTemplate*)aPtr;
d.iInInterrupt=1; // going in...
// TUint portAddr=d.iPortAddr; TO DO: (mandatory): Uncomment this
//
// TO DO: (mandatory)
//
// Read the interrupt source register to determine if it is a Receive, Transmit or Modem Signals change interrupt.
// If required also, clear interrupts at the source.
// Then process the interrupt condition as in the following pseudo-code extract:
//
// if((Received character Interrupts) || (Error in received character Interupt)) TO DO: (mandatory): Implement
{
TUint rx[32];
TUint xon=d.iLdd->iRxXonChar;
TUint xoff=d.iLdd->iRxXoffChar;
TInt rxi=0;
TInt x=0;
TUint ch=0;
// while((Receive FIFO not empty) && Kern::PowerGood()) TO DO: (mandatory): Implement
{
TUint regStatus1=0;
// NOTE: for some hardware the order the following 2 operations is performed may have to be reversed
// if(Error in received character interrupt) TO DO: (mandatory): Implement
// regStatus1=(Read receive error bitmask off appropriate register);
// ch=(Read received character);
// coverity[dead_error_condition]
// The next line should be reachable when this template file is edited for use
if(regStatus1!=0) // if error in this character
{
// if (ch & (Parity Error)) TO DO: (mandatory): Implement
ch|=KReceiveIsrParityError;
// if (ch & (Framing Error)) TO DO: (mandatory): Implement
ch|=KReceiveIsrFrameError;
// if (ch & (Overrun)) TO DO: (mandatory): Implement
ch|=KReceiveIsrOverrunError;
}
if (ch==xon)
x=1;
else if (ch==xoff)
x=-1;
else
rx[rxi++]=ch;
}
d.ReceiveIsr(rx,rxi,x);
}
// if((Transmitted character Interrupt)) TO DO: (mandatory): Implement
{
while(/* (Transmit FIFO Not full) && */ Kern::PowerGood()) // TO DO: (mandatory): Implement
{
TInt r=d.TransmitIsr();
if(r<0)
{
//no more to send
//
// TO DO: (mandatory)
//
// Disable the Transmit Interrupt in Hardware
d.iTransmitting=EFalse;
break;
}
// (write transmit character to output FIFO or Data register) TO DO: (mandatory): Implement
}
d.CheckTxBuffer();
}
// if((Modem Signals changed Interrupt)) TO DO: (mandatory): Implement
{
TUint signals=d.Signals()&KDTEInputSignals;
if (signals != d.iSignals)
{
d.iSignals=signals;
d.iLdd->StateIsr(signals);
}
}
d.iInInterrupt=0; // going out...
}
DECLARE_STANDARD_PDD()
{
return new DDriverComm;
}