--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bsptemplate/asspandvariant/template_variant/specific/uart.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,722 @@
+// 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;
+ }
+