omap3530/omap3530_drivers/euart/euart.cpp
changeset 38 cdb163c0843f
child 108 181b2f6a9979
equal deleted inserted replaced
33:2905910218db 38:cdb163c0843f
       
     1 // This component and the accompanying materials are made available
       
     2 // under the terms of the License "Symbian Foundation License v1.0"
       
     3 // which accompanies this distribution, and is available
       
     4 // at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html".
       
     5 //
       
     6 // Initial Contributors:
       
     7 // Accenture
       
     8 //
       
     9 // Contributors:
       
    10 //
       
    11 // Description:
       
    12 // \sf\adaptation\beagleboard\omap3530\omap3530_drivers\euart\euart.cpp
       
    13 // pdd for serial ports
       
    14 // assume Modem Control Signals change cause an interrupt
       
    15 // 
       
    16 //
       
    17 
       
    18 #include <d32comm.h>
       
    19 #include <beagle\variant.h>
       
    20 #include "euart.h"
       
    21 
       
    22 #define TX_POLLING_HACK
       
    23 
       
    24 _LIT(KPddName,"Comm.Beagle");
       
    25 using namespace Omap3530Uart;
       
    26 
       
    27 DDriverComm::DDriverComm()
       
    28 //
       
    29 // Constructor
       
    30 //
       
    31 	{
       
    32 	iUnitsMask=0x7;
       
    33 	iVersion=TVersion(KCommsMajorVersionNumber,KCommsMinorVersionNumber,KCommsBuildVersionNumber);
       
    34 	}
       
    35 
       
    36 TInt DDriverComm::Install()
       
    37 //
       
    38 // Install the driver
       
    39 //
       
    40 	{
       
    41 	return SetName(&KPddName);
       
    42 	}
       
    43 
       
    44 void GetTemplateCommsCaps(TDes8 &aCaps, TInt aUnit)
       
    45 	{
       
    46 	TCommCaps2 capsBuf;
       
    47 
       
    48 	// Fill in the Caps structure with the relevant information for this Unit, e.g
       
    49 	TCommCapsV02 &c=capsBuf();
       
    50 	c.iRate=KCapsBps1200|KCapsBps2400|KCapsBps4800|KCapsBps9600|KCapsBps19200|KCapsBps38400|
       
    51 			KCapsBps57600|KCapsBps115200|KCapsBps230400|KCapsBps460800|KCapsBps4000000;
       
    52 			
       
    53 	c.iDataBits=KCapsData5|KCapsData6|KCapsData7|KCapsData8;
       
    54 	c.iStopBits=KCapsStop1|KCapsStop2;
       
    55 	c.iParity=KCapsParityNone|KCapsParityEven|KCapsParityOdd|KCapsParityMark|KCapsParitySpace;
       
    56 	c.iHandshake=0; //(OR in all KCapsObeyXXXSupported, KCapsSendXXXSupported, KCapsFailXXXSupported, KCapsFreeXXXSupported
       
    57 				    // as required for this Unit's configuration);.
       
    58 	c.iSignals=0;   //(OR in as many KCapsSignalXXXSupported as Modem control signals controllable by this Unit);
       
    59 	c.iSIR=0; 		//(0 or OR in as many KCapsSIRXXX as IR bit rates supported);
       
    60 	c.iNotificationCaps=0; //(OR in as many KNotifyXXXSupported as notifications supported by this Unit);
       
    61 	c.iFifo=0;				//(0 or KCapsHasFifo);
       
    62 	c.iRoleCaps=0;			//(0 or KCapsRoleSwitchSupported);
       
    63 	c.iFlowControlCaps=0;	//(0 or KCapsFlowControlStatusSupported);
       
    64 	/** @see TCommCapsV02 */
       
    65 
       
    66 	aCaps=capsBuf.Left(Min(capsBuf.Length(),aCaps.MaxLength()));
       
    67 	}
       
    68 
       
    69 void DDriverComm::GetCaps(TDes8 &aDes) const
       
    70 //
       
    71 // Return the drivers capabilities
       
    72 //
       
    73 	{
       
    74 	GetTemplateCommsCaps(aDes, 0);
       
    75 	}
       
    76 
       
    77 TInt DDriverComm::Create(DBase*& aChannel, TInt aUnit, const TDesC8* anInfo, const TVersion& aVer)
       
    78 //
       
    79 // Create a driver
       
    80 //
       
    81 	{
       
    82 	DCommBeagle* pD=new DCommBeagle;
       
    83 	aChannel=pD;
       
    84 	TInt r=KErrNoMemory;
       
    85 	if (pD)
       
    86 		r=pD->DoCreate(aUnit,anInfo);
       
    87 	return r;
       
    88 	}
       
    89 
       
    90 TInt DDriverComm::Validate(TInt aUnit, const TDesC8* /*anInfo*/, const TVersion& aVer)
       
    91 //
       
    92 //	Validate the requested configuration (Version and Unit)
       
    93 //
       
    94 	{
       
    95 	if ((!Kern::QueryVersionSupported(iVersion,aVer)) || (!Kern::QueryVersionSupported(aVer,TVersion(KMinimumLddMajorVersion,KMinimumLddMinorVersion,KMinimumLddBuild))))
       
    96 		return KErrNotSupported;
       
    97 		
       
    98 	if(aUnit<0 || aUnit >2)
       
    99 		return KErrNotSupported;
       
   100 		
       
   101 	return KErrNone;
       
   102 	}
       
   103 
       
   104 DCommBeagle::DCommBeagle()
       
   105 //
       
   106 // Constructor
       
   107 //
       
   108 	{
       
   109 	gData=0;
       
   110 	iInterruptId=-1;		// -1 means not bound
       
   111 	}
       
   112 
       
   113 DCommBeagle::~DCommBeagle()
       
   114 //
       
   115 // Destructor
       
   116 //
       
   117 	{
       
   118 	if (iInterruptId>=0)
       
   119 		Interrupt::Unbind(iInterruptId);
       
   120 	
       
   121 	if (iDfcQ)
       
   122 		{
       
   123 		iDfcQ->Destroy();
       
   124 		}
       
   125 	}
       
   126 
       
   127 const TInt KDCommBeagleDfcThreadPriority = 24;
       
   128 _LIT(KDCommBeagleDfcThread,"DCommBeagleDfcThread");
       
   129 
       
   130 TInt DCommBeagle::DoCreate(TInt aUnit, const TDesC8* /*anInfo*/)
       
   131 //
       
   132 // Sets up the PDD
       
   133 //
       
   134 	{
       
   135 	iUnit=aUnit;
       
   136 
       
   137 	//  Create own DFC queue
       
   138 	TInt r = Kern::DynamicDfcQCreate(iDfcQ, KDCommBeagleDfcThreadPriority, KDCommBeagleDfcThread);
       
   139 
       
   140 	if (r != KErrNone)
       
   141 		return r; 	
       
   142 
       
   143 	// Set iPortAddr and irq with the Linear Base address of the UART and the Interrupt ID coresponding to aUnit
       
   144 	iUart = new TUart((TUartNumber)aUnit);
       
   145 	Prcm::SetClockState(iUart->PrcmInterfaceClk(), Prcm::EClkOn);
       
   146 	Prcm::SetClockState(iUart->PrcmFunctionClk(), Prcm::EClkOn);
       
   147 	
       
   148 	// bind to UART interrupt
       
   149 	r=Interrupt::Bind(iUart->InterruptId(),Isr,this);
       
   150 	if (r==KErrNone)
       
   151 		iInterruptId=iUart->InterruptId();
       
   152 	return r;
       
   153 	}
       
   154 
       
   155 TDfcQue* DCommBeagle::DfcQ(TInt aUnit)
       
   156 //
       
   157 // Return the DFC queue to be used for this device
       
   158 // For UARTs just use the standard low priority DFC queue
       
   159 // For Serial PC cards, use the PC card controller thread for the socket in question.
       
   160 //
       
   161 	{
       
   162 	return aUnit==iUnit ? iDfcQ : NULL;
       
   163 	}
       
   164 
       
   165 TInt DCommBeagle::Start()
       
   166 //
       
   167 // Start receiving characters
       
   168 //
       
   169 	{
       
   170 	if(iUnit == Kern::SuperPage().iDebugPort)
       
   171 		Variant::MarkDebugPortOff();
       
   172 	
       
   173 	iTransmitting=EFalse;			// if EnableTransmit() called before Start()
       
   174 
       
   175 	if(iUart==NULL)
       
   176 		{
       
   177 		return KErrNotReady;
       
   178 		}
       
   179 	iSignals=Signals();
       
   180 	iLdd->UpdateSignals(iSignals);
       
   181 
       
   182 	Interrupt::Enable(iInterruptId);
       
   183 	iUart->EnableInterrupt(TUart::EIntRhr);
       
   184 	return KErrNone;
       
   185 	}
       
   186 
       
   187 TBool FinishedTransmitting(TAny* aPtr)
       
   188 	{
       
   189 	DCommBeagle* self = (DCommBeagle*)aPtr;
       
   190 	if(self->iUart==NULL)
       
   191 		{
       
   192 		return ETrue;
       
   193 		}
       
   194 		
       
   195 	if(!self->iUart->TxFifoEmpty())
       
   196 		{
       
   197 		return EFalse;
       
   198 		}
       
   199 	return ETrue;
       
   200 	}
       
   201 
       
   202 void DCommBeagle::Stop(TStopMode aMode)
       
   203 //
       
   204 // Stop receiving characters
       
   205 //
       
   206 	{
       
   207 	switch (aMode)
       
   208 		{
       
   209 		case EStopNormal:
       
   210 		case EStopPwrDown:
       
   211 			iUart->DisableInterrupt(TUart::EIntRhr);
       
   212 			iUart->DisableInterrupt(TUart::EIntThr);
       
   213 			Interrupt::Disable(iInterruptId);
       
   214 			
       
   215 			// wait for uart to stop tranmitting
       
   216 			Kern::PollingWait(FinishedTransmitting,this,3,100);
       
   217 			
       
   218 			iTransmitting=EFalse;
       
   219 			
       
   220 			iUart->Disable();			
       
   221 			Prcm::SetClockState(iUart->PrcmFunctionClk(), Prcm::EClkOff);
       
   222 			break;
       
   223 		case  EStopEmergency:
       
   224 			iUart->DisableInterrupt(TUart::EIntRhr);			
       
   225 			iUart->DisableInterrupt(TUart::EIntThr);
       
   226 			Interrupt::Disable(iInterruptId);
       
   227 			iTransmitting=EFalse;
       
   228 			break;
       
   229 		}
       
   230 	}
       
   231 
       
   232 void DCommBeagle::Break(TBool aState)
       
   233 //
       
   234 // Start or stop the uart breaking
       
   235 //
       
   236 	{
       
   237 	if (aState)
       
   238 		{
       
   239 		//
       
   240 		// TO DO: (mandatory)
       
   241 		//
       
   242 		// Enable sending a Break (space) condition
       
   243 		//
       
   244 		}
       
   245 	else
       
   246 		{
       
   247 		//
       
   248 		// TO DO: (mandatory)
       
   249 		//
       
   250 		// Stop sending a Break (space) condition
       
   251 		//
       
   252 		}
       
   253 	}
       
   254 
       
   255 void DCommBeagle::EnableTransmit()
       
   256 //
       
   257 // Start sending characters.
       
   258 //
       
   259 	{
       
   260 	TBool tx=(TBool)NKern::SafeSwap((TAny*)ETrue,(TAny*&)iTransmitting);
       
   261 	if (tx)
       
   262 		{
       
   263 		return;
       
   264 		}
       
   265 	TInt r = 0;
       
   266 	#ifdef TX_POLLING_HACK
       
   267 	while (Kern::PowerGood())
       
   268 	#else
       
   269 	while (Kern::PowerGood() && !iUart->TxFifoFull())
       
   270 	#endif
       
   271 		{	
       
   272 		r=TransmitIsr();
       
   273 		if(r<0)
       
   274 			{
       
   275 			//no more to send
       
   276 			iTransmitting=EFalse;
       
   277 			break;
       
   278 			}
       
   279 		#ifdef TX_POLLING_HACK
       
   280 		while(iUart->TxFifoFull());
       
   281 		#endif
       
   282 		iUart->Write(r);
       
   283 		}
       
   284 	TInt irq=0;
       
   285 	if (!iInInterrupt)					// CheckTxBuffer adds a Dfc: can only run from ISR or with NKernel locked
       
   286 		{
       
   287 		NKern::Lock();
       
   288 		irq=NKern::DisableAllInterrupts();
       
   289 		}
       
   290 	CheckTxBuffer();
       
   291 	if (!iInInterrupt)
       
   292 		{
       
   293 		NKern::RestoreInterrupts(irq);
       
   294 		NKern::Unlock();
       
   295 		}
       
   296 	if (r>=0)											// only enable interrupt if there's more data to send
       
   297 		{
       
   298 		iUart->EnableInterrupt(TUart::EIntThr);
       
   299 		}
       
   300 	}
       
   301 
       
   302 TUint DCommBeagle::Signals() const
       
   303 //
       
   304 // Read and translate the modem lines
       
   305 //
       
   306 	{
       
   307 	TUint signals=0;
       
   308 	//
       
   309 	// TO DO: (mandatory)
       
   310 	//
       
   311 	// If the UART corresponding to iUnit supports Modem Control Signals, read them and return a bitmask with one or 
       
   312 	// more of the following OR-ed in:
       
   313 	// - KSignalDTR,
       
   314 	// - KSignalRTS,
       
   315 	// - KSignalDSR,
       
   316 	// - KSignalCTS,
       
   317 	// - KSignalDCD.
       
   318 	// 
       
   319 	return signals;
       
   320 	}
       
   321 
       
   322 void DCommBeagle::SetSignals(TUint aSetMask, TUint aClearMask)
       
   323 //
       
   324 // Set signals.
       
   325 //
       
   326 	{
       
   327 	//
       
   328 	// TO DO: (mandatory)
       
   329 	//
       
   330 	// If the UART corresponding to iUnit supports Modem Control Signals, converts the flags in aSetMask and aClearMask 
       
   331 	// into hardware-specific bitmasks to write to the UART modem/handshake output register(s). 
       
   332 	// aSetMask, aClearMask will have one or more of the following OR-ed in:
       
   333 	// - KSignalDTR,
       
   334 	// - KSignalRTS,
       
   335 	//
       
   336 	}
       
   337 
       
   338 TInt DCommBeagle::ValidateConfig(const TCommConfigV01 &aConfig) const
       
   339 //
       
   340 // Check a config structure.
       
   341 //
       
   342 	{
       
   343 	//
       
   344 	// TO DO: (mandatory)
       
   345 	//
       
   346 	// Checks the the options in aConfig are supported by the UART corresponding to iUnit
       
   347 	// May need to check:
       
   348 	//  - aConfig.iParity (contains one of EParityXXX)
       
   349 	/** @see TParity */
       
   350 	//  - aConfig.iRate (contains one of EBpsXXX)
       
   351 	/** @see TBps */
       
   352 	//  - aConfig.iDataBits (contains one of EDataXXX)
       
   353 	/** @see TDataBits */
       
   354 	//  - aConfig.iStopBits (contains one of EStopXXX)
       
   355 	/** @see TDataBits */
       
   356 	//  - aConfig.iHandshake (contains one of KConfigObeyXXX or KConfigSendXXX or KConfigFailXXX or KConfigFreeXXX)
       
   357 	//  - aConfig.iParityError (contains KConfigParityErrorFail or KConfigParityErrorIgnore or KConfigParityErrorReplaceChar)
       
   358 	//  - aConfig.iFifo (contains ether EFifoEnable or EFifoDisable)
       
   359 	/** @see TFifo */
       
   360 	//  - aConfig.iSpecialRate (may contain a rate not listed under TBps)
       
   361 	//  - aConfig.iTerminatorCount (conatains number of special characters used as terminators)
       
   362 	//  - aConfig.iTerminator[] (contains a list of special characters which can be used as terminators)
       
   363 	//  - aConfig.iXonChar (contains the character used as XON - software flow control)
       
   364 	//  - aConfig.iXoffChar (contains the character used as XOFF - software flow control)
       
   365 	//  - aConfig.iParityErrorChar (contains the character used to replace bytes received with a parity error)
       
   366 	//  - aConfig.iSIREnable (contains either ESIREnable or ESIRDisable)
       
   367 	/** @see TSir */
       
   368 	//  - aConfig.iSIRSettings (contains one of KConfigSIRXXX)
       
   369 	// and returns KErrNotSupported if the UART corresponding to iUnit does not support this configuration
       
   370 	//
       
   371 	return KErrNone;
       
   372 	}
       
   373 
       
   374 void DCommBeagle::CheckConfig(TCommConfigV01& aConfig)
       
   375 	{
       
   376 	//
       
   377 	// TO DO: (optional)
       
   378 	//
       
   379 	// Validates the default configuration that is defined when a channel is first opened
       
   380 	//
       
   381 	}
       
   382 
       
   383 TInt DCommBeagle::DisableIrqs()
       
   384 //
       
   385 // Disable normal interrupts
       
   386 //
       
   387 	{
       
   388 	
       
   389 	return NKern::DisableInterrupts(1);
       
   390 	}
       
   391 
       
   392 void DCommBeagle::RestoreIrqs(TInt aLevel)
       
   393 //
       
   394 // Restore normal interrupts
       
   395 //
       
   396 	{
       
   397 	
       
   398 	NKern::RestoreInterrupts(aLevel);
       
   399 	}
       
   400 
       
   401 void DCommBeagle::Configure(TCommConfigV01 &aConfig)
       
   402 //
       
   403 // Configure the UART from aConfig
       
   404 //
       
   405 	{
       
   406 	Kern::PollingWait(FinishedTransmitting,this,3,100);	// wait for uart to stop tranmitting
       
   407 	iUart->Disable();
       
   408 	
       
   409 	iUart->Init();
       
   410 	iUart->DefineMode(TUart::EUart);
       
   411 
       
   412 	switch(aConfig.iRate)
       
   413 		{
       
   414 		case EBps1200:
       
   415 			iUart->SetBaud(TUart::E1200);
       
   416 			break;
       
   417 		case EBps2400:
       
   418 			iUart->SetBaud(TUart::E2400);
       
   419 			break;
       
   420 		case EBps4800:
       
   421 			iUart->SetBaud(TUart::E4800);
       
   422 			break;
       
   423 		case EBps9600:
       
   424 			iUart->SetBaud(TUart::E9600);
       
   425 			break;
       
   426 		case EBps19200:
       
   427 			iUart->SetBaud(TUart::E19200);
       
   428 			break;
       
   429 		case EBps38400:
       
   430 			iUart->SetBaud(TUart::E38400);
       
   431 			break;
       
   432 		case EBps57600:
       
   433 			iUart->SetBaud(TUart::E57600);
       
   434 			break;
       
   435 		case EBps460800:
       
   436 			iUart->SetBaud(TUart::E460800);
       
   437 			break;
       
   438 		case EBps115200:
       
   439 		default:
       
   440 			iUart->SetBaud(TUart::E115200);
       
   441 		}
       
   442 	
       
   443 	TUart::TDataBits databits = (TUart::TDataBits)aConfig.iDataBits;
       
   444 	TUart::TStopBits stopbits;
       
   445 	switch(aConfig.iStopBits)
       
   446 		{
       
   447 		case EStop2:
       
   448 			stopbits=TUart::E2Stop;
       
   449 			break;
       
   450 		case EStop1:
       
   451 		default:
       
   452 			stopbits=TUart::E1Stop;		
       
   453 		}
       
   454 
       
   455 	TUart::TParity parity;	
       
   456 	switch(aConfig.iParity)
       
   457 		{
       
   458 		case EParityEven:
       
   459 			parity=TUart::EEven;
       
   460 			break;
       
   461 		case EParityOdd:
       
   462 			parity=TUart::EOdd;
       
   463 			break;
       
   464 		case EParityMark:
       
   465 			parity=TUart::EMark;
       
   466 			break;
       
   467 		case EParitySpace:
       
   468 			parity=TUart::ESpace;
       
   469 			break;
       
   470 		case EParityNone:
       
   471 		default:
       
   472 			parity=TUart::ENone;
       
   473 		}
       
   474 
       
   475 	iUart->SetDataFormat(databits, stopbits, parity);
       
   476 	iUart->EnableFifo(TUart::EEnabled, TUart::ETrigger8, TUart::ETrigger8);
       
   477 
       
   478 	iUart->Enable();
       
   479 	}
       
   480 
       
   481 void DCommBeagle::Caps(TDes8 &aCaps) const
       
   482 //
       
   483 // return our caps
       
   484 //
       
   485 	{
       
   486 	GetTemplateCommsCaps(aCaps,iUnit);
       
   487 	}
       
   488 
       
   489 void DCommBeagle::Isr(TAny* aPtr)
       
   490 //
       
   491 // Service the UART interrupt
       
   492 //
       
   493 	{
       
   494 	DCommBeagle& d=*(DCommBeagle*)aPtr;
       
   495 	d.iInInterrupt=1;										// going in...
       
   496 	TUint xon=d.iLdd->iRxXonChar;
       
   497 	TUint xoff=d.iLdd->iRxXoffChar;
       
   498 
       
   499 	// Read the interrupt source register to determine if it is a Receive, Transmit or Modem Signals change interrupt.
       
   500 	// If required also, clear interrupts at the source.
       
   501 	// Then process the interrupt condition as in the following pseudo-code extract:
       
   502 	//
       
   503 	TUint interruptId = IIR::iMem.Read(*(d.iUart));
       
   504 	TUint interruptEn = IER::iMem.Read(*(d.iUart));	
       
   505 	
       
   506 	if((interruptId & IIR::IT_TYPE::ETHR) && (interruptEn & IER::THR_IT::KMask) )
       
   507 		{
       
   508 		while(Kern::PowerGood() && !d.iUart->TxFifoFull())	
       
   509 			{
       
   510 			TInt r=d.TransmitIsr();
       
   511 			if(r<0)
       
   512 				{
       
   513 				// Disable the Transmit Interrupt in Hardware
       
   514 				d.iUart->DisableInterrupt(TUart::EIntThr);
       
   515 				d.iTransmitting=EFalse;
       
   516 				break;
       
   517 				}
       
   518 			d.iUart->Write(r);
       
   519 			}
       
   520 		d.CheckTxBuffer();
       
   521 		}
       
   522 		
       
   523 	if((interruptId & IIR::IT_TYPE::ERHR) && (interruptEn & IER::RHR_IT::KMask) )
       
   524 		{
       
   525 		TUint rx[32];
       
   526 		TInt rxi=0;
       
   527 		TInt x=0;
       
   528 
       
   529 		while(!d.iUart->RxFifoEmpty() && rxi<32)
       
   530 			{
       
   531 			TUint ch = d.iUart->Read();
       
   532 			if (ch==xon)
       
   533 				x=1;
       
   534 			else if (ch==xoff)
       
   535 				x=-1;
       
   536 			else
       
   537 				rx[rxi++]=ch;
       
   538 			}
       
   539 		d.ReceiveIsr(rx,rxi,x);
       
   540 		}
       
   541 
       
   542 	if((interruptId & IIR::IT_TYPE::EModem) && (interruptEn & IER::MODEM_STS_IT::KMask) )
       
   543 		{
       
   544 		TUint signals=d.Signals()&KDTEInputSignals;
       
   545 		if (signals != d.iSignals)
       
   546 			{
       
   547 			d.iSignals=signals;
       
   548 			d.iLdd->StateIsr(signals);
       
   549 			}
       
   550 		}
       
   551 	d.iInInterrupt=0;										// going out...
       
   552 	}
       
   553 
       
   554 DECLARE_STANDARD_PDD()
       
   555 	{
       
   556 	return new DDriverComm;
       
   557 	}