Update contrib.
1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32\drivers\ecomm\uart16550.cpp
19 #include <drivers/comm.h>
22 #include <uart16550.h>
25 _LIT(KPddName,"Comm.16550");
27 #define __COMMS_MACHINE_CODED__
28 #ifdef __COMMS_MACHINE_CODED__
29 #define DBASE_VPTR_OFFSET 4
30 #define RX_ISR_VT_OFFSET 0x24
31 #define CHK_TXB_VT_OFFSET 0x28
32 #define STATE_ISR_VT_OFFSET 0x2C
35 // needs ldd version..
36 const TInt KMinimumLddMajorVersion=1;
37 const TInt KMinimumLddMinorVersion=1;
38 const TInt KMinimumLddBuild=122;
41 static const TUint16 BaudRateDivisor[19] =
43 2304, 1536, 1047, 860, 768, 384, 192, 96,
44 64, 58, 48, 32, 24, 16, 12, 6,
48 class DDriverComm : public DPhysicalDevice
52 virtual TInt Install();
53 virtual void GetCaps(TDes8 &aDes) const;
54 virtual TInt Create(DBase*& aChannel, TInt aUnit, const TDesC8* anInfo, const TVersion &aVer);
55 virtual TInt Validate(TInt aUnit, const TDesC8* anInfo, const TVersion &aVer);
57 TDynamicDfcQue* iDfcQ;
60 class DComm16550 : public DComm
65 TInt DoCreate(TInt aUnit, const TDesC8* anInfo);
68 virtual void Stop(TStopMode aMode);
69 virtual void Break(TBool aState);
70 virtual void EnableTransmit();
71 virtual TUint Signals() const;
72 virtual void SetSignals(TUint aSetMask,TUint aClearMask);
73 virtual TInt ValidateConfig(const TCommConfigV01 &aConfig) const;
74 virtual void Configure(TCommConfigV01 &aConfig);
75 virtual void Caps(TDes8 &aCaps) const;
76 virtual TInt DisableIrqs();
77 virtual void RestoreIrqs(TInt aIrq);
78 virtual TDfcQue* DfcQ(TInt aUnit);
79 virtual void CheckConfig(TCommConfigV01& aConfig);
81 static void Isr(TAny* aPtr);
89 DDriverComm::DDriverComm()
94 iUnitsMask=~(0xffffffffu<<KNum16550Uarts);
95 iVersion=TVersion(KCommsMajorVersionNumber,KCommsMinorVersionNumber,KCommsBuildVersionNumber);
99 TInt DDriverComm::Install()
101 // Install the driver
104 // Allocate a kernel thread to run the DFC
105 TInt r = Kern::DynamicDfcQCreate(iDfcQ, KUart16550ThreadPriority, KUar16550tDriverThread);
108 iDfcQ->SetRealtimeState(ERealtimeStateOff);
109 r = SetName(&KPddName);
117 DDriverComm::~DDriverComm()
123 void Get16550CommsCaps(TDes8& aCaps, TInt aUnit)
126 TCommCapsV03 &c=capsBuf();
127 c.iRate=KCapsBps110|KCapsBps150|KCapsBps300|KCapsBps600\
128 |KCapsBps1200|KCapsBps2400|KCapsBps4800|KCapsBps9600\
129 |KCapsBps19200|KCapsBps38400|KCapsBps57600|KCapsBps115200;
130 c.iDataBits=KCapsData5|KCapsData6|KCapsData7|KCapsData8;
131 c.iStopBits=KCapsStop1|KCapsStop2;
132 c.iParity=KCapsParityNone|KCapsParityEven|KCapsParityOdd|KCapsParityMark|KCapsParitySpace;
133 c.iHandshake=KCapsObeyXoffSupported|KCapsSendXoffSupported|
134 KCapsObeyCTSSupported|KCapsFailCTSSupported|
135 KCapsObeyDSRSupported|KCapsFailDSRSupported|
136 KCapsObeyDCDSupported|KCapsFailDCDSupported|
137 KCapsFreeRTSSupported|KCapsFreeDTRSupported;
139 c.iSignals=KCapsSignalCTSSupported|KCapsSignalRTSSupported|KCapsSignalDTRSupported|
140 KCapsSignalDSRSupported|KCapsSignalDCDSupported|KCapsSignalRNGSupported;
141 c.iFifo=KCapsHasFifo;
142 c.iNotificationCaps=KNotifyDataAvailableSupported|KNotifySignalsChangeSupported;
144 c.iFlowControlCaps=0;
145 c.iBreakSupported=ETrue;
146 aCaps.FillZ(aCaps.MaxLength());
147 aCaps=capsBuf.Left(Min(capsBuf.Length(),aCaps.MaxLength()));
150 void DDriverComm::GetCaps(TDes8 &aDes) const
152 // Return the drivers capabilities
155 Get16550CommsCaps(aDes, 0);
158 TInt DDriverComm::Create(DBase*& aChannel, TInt aUnit, const TDesC8* anInfo, const TVersion& aVer)
163 DComm16550* pD=new DComm16550;
167 r=pD->DoCreate(aUnit,anInfo);
171 TInt DDriverComm::Validate(TInt aUnit, const TDesC8* /*anInfo*/, const TVersion& aVer)
173 // Validate the requested configuration
176 if ((!Kern::QueryVersionSupported(iVersion,aVer)) || (!Kern::QueryVersionSupported(aVer,TVersion(KMinimumLddMajorVersion,KMinimumLddMinorVersion,KMinimumLddBuild))))
177 return KErrNotSupported;
178 if (aUnit<0 || aUnit>=KNum16550Uarts)
179 return KErrNotSupported;
183 DComm16550::DComm16550()
188 // iTransmitting=EFalse;
189 iInterruptId=-1; // -1 means not bound
192 DComm16550::~DComm16550()
198 Interrupt::Unbind(iInterruptId);
201 TInt DComm16550::DoCreate(TInt aUnit, const TDesC8* /*anInfo*/)
207 TInt irq=IrqFromUnit(aUnit);
209 // bind to UART interrupt
210 TInt r=Interrupt::Bind(irq,Isr,this);
214 iUart=UartFromUnit(aUnit);
223 TDfcQue* DComm16550::DfcQ(TInt /*aUnit*/)
225 // Return the DFC queue to be used for this device
226 // For PC cards, use the PC card controller thread for the socket in question.
233 TInt DComm16550::Start()
235 // Start receiving characters
238 // if EnableTransmit() called before Start()
239 iTransmitting=EFalse;
240 iUart->SetIER(K16550IER_RDAI|K16550IER_RLSI|K16550IER_MSI);
241 iLdd->UpdateSignals(Signals());
242 Interrupt::Enable(iInterruptId);
246 TBool FinishedTransmitting(TAny* aPtr)
248 DComm16550& d=*(DComm16550*)aPtr;
249 return d.iUart->TestLSR(K16550LSR_TxIdle);
252 void DComm16550::Stop(TStopMode aMode)
254 // Stop receiving characters
262 Interrupt::Disable(iInterruptId);
263 iTransmitting=EFalse;
265 // wait for uart to stop tranmitting
266 Kern::PollingWait(FinishedTransmitting,this,3,100);
270 Interrupt::Disable(iInterruptId);
271 iTransmitting=EFalse;
276 void DComm16550::Break(TBool aState)
278 // Start or stop the uart breaking
282 iUart->ModifyLCR(0,K16550LCR_TxBreak);
284 iUart->ModifyLCR(K16550LCR_TxBreak,0);
287 void DComm16550::EnableTransmit()
289 // Start sending characters.
292 TBool tx = (TBool)__e32_atomic_swp_ord32(&iTransmitting, 1);
295 iUart->ModifyIER(0,K16550IER_THREI);
298 TUint DComm16550::Signals() const
300 // Read and translate the modem lines
303 TUint msr=iUart->MSR();
304 msr=((msr>>4)&0x0f); // true input signals
305 TUint sig=msr & 3; // CTS,DSR OK
307 sig|=KSignalRNG; // swap DCD,RNG
313 void DComm16550::SetSignals(TUint aSetMask, TUint aClearMask)
320 if (aSetMask & KSignalRTS)
322 if (aSetMask & KSignalDTR)
324 if (aClearMask & KSignalRTS)
325 clear|=K16550MCR_RTS;
326 if (aClearMask & KSignalDTR)
327 clear|=K16550MCR_DTR;
328 iUart->ModifyMCR(clear,set);
331 TInt DComm16550::ValidateConfig(const TCommConfigV01 &aConfig) const
333 // Check a config structure.
336 if (aConfig.iSIREnable==ESIREnable)
337 return KErrNotSupported;
338 switch (aConfig.iParity)
347 return KErrNotSupported;
349 if (TUint(aConfig.iRate)>TUint(EBps115200))
350 return KErrNotSupported;
354 void DComm16550::CheckConfig(TCommConfigV01& aConfig)
359 TInt DComm16550::DisableIrqs()
361 // Disable normal interrupts
365 return NKern::DisableInterrupts(1);
368 void DComm16550::RestoreIrqs(TInt aLevel)
370 // Restore normal interrupts
374 NKern::RestoreInterrupts(aLevel);
377 void DComm16550::Configure(TCommConfigV01 &aConfig)
382 // wait for uart to stop tranmitting
383 Kern::PollingWait(FinishedTransmitting,this,3,100);
386 switch (aConfig.iDataBits)
388 case EData5: lcr=K16550LCR_Data5; break;
389 case EData6: lcr=K16550LCR_Data6; break;
390 case EData7: lcr=K16550LCR_Data7; break;
391 case EData8: lcr=K16550LCR_Data8; break;
393 switch (aConfig.iStopBits)
396 case EStop2: lcr|=K16550LCR_Stop2; break;
398 switch (aConfig.iParity)
400 case EParityNone: break;
401 case EParityEven: lcr|=K16550LCR_ParityEnable|K16550LCR_ParityEven; break;
402 case EParityOdd: lcr|=K16550LCR_ParityEnable; break;
403 case EParityMark: lcr|=K16550LCR_ParityEnable|K16550LCR_ParityMark; break;
404 case EParitySpace: lcr|=K16550LCR_ParityEnable|K16550LCR_ParitySpace; break;
406 iUart->SetLCR(lcr|K16550LCR_DLAB);
407 iUart->SetBaudRateDivisor(BaudRateDivisor[(TInt)aConfig.iRate]);
409 iUart->SetFCR(K16550FCR_Enable|K16550FCR_RxReset|K16550FCR_TxReset|K16550FCR_RxTrig8);
412 void DComm16550::Caps(TDes8 &aCaps) const
417 Get16550CommsCaps(aCaps,iUnit);
420 void DComm16550::Isr(TAny* aPtr)
422 // Service the UART interrupt
425 DComm16550& d=*(DComm16550*)aPtr;
426 T16550Uart& u=*d.iUart;
428 TUint xon=d.iLdd->iRxXonChar;
429 TUint xoff=d.iLdd->iRxXoffChar;
432 if (isr & K16550ISR_NotPending)
434 isr&=K16550ISR_IntIdMask;
436 // if receive data available or line status interrupt
437 if (isr==K16550ISR_RDAI || isr==K16550ISR_RLSI)
441 while(u.TestLSR(K16550LSR_RxReady|K16550LSR_RxParityErr|K16550LSR_RxOverrun|K16550LSR_RxFrameErr|K16550LSR_RxBreak) && Kern::PowerGood())
444 // checks for EIF flag
445 if (isr==K16550ISR_RLSI)
446 lsr=u.LSR()&(K16550LSR_RxParityErr|K16550LSR_RxOverrun|K16550LSR_RxFrameErr);
448 // if error in this character
451 if (lsr & K16550LSR_RxParityErr)
452 ch|=KReceiveIsrParityError;
453 if (lsr & K16550LSR_RxBreak)
454 ch|=KReceiveIsrBreakError;
455 if (lsr & K16550LSR_RxFrameErr)
456 ch|=KReceiveIsrFrameError;
457 if (lsr & K16550LSR_RxOverrun)
458 ch|=KReceiveIsrOverrunError;
467 d.ReceiveIsr(rx,rxi,x);
470 // if TFS flag and TIE
471 if (isr==K16550ISR_THREI)
476 TInt r=d.TransmitIsr();
480 // Disable the TX interrupt
481 u.ModifyIER(K16550IER_THREI,0);
482 d.iTransmitting=EFalse;
490 // must be signal change
491 d.StateIsr(d.Signals());
495 const TInt KUart16550ThreadPriority = 27;
496 _LIT(KUar16550tDriverThread,"UART16550_Thread");
498 DECLARE_STANDARD_PDD()
500 return new DDriverComm;