bsptemplate/asspandvariant/template_variant/specific/uart.cpp
changeset 0 a41df078684a
child 109 b3a1d9898418
--- /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;
+	}
+