Update contrib.
1 // Copyright (c) 2002-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 "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 // wins/specific/serialldd.cpp
19 #include <kernel/kern_priv.h>
23 _LIT(KLddName,"Comm");
25 const TUint KBreaking=0x02;
26 const TUint KBreakPending=0x04;
31 ESetConfigWhileRequestPending,
32 ESetSignalsSetAndClear,
34 ESetReceiveBufferLength,
38 inline TUint32 SafeSwap(TUint32 aNewValue, TUint32& aWord)
39 { return __e32_atomic_swp_ord32(&aWord, aNewValue); }
41 DECLARE_STANDARD_LDD()
43 return new DDeviceComm;
47 DDeviceComm::DDeviceComm()
49 iParseMask = KDeviceAllowAll;
50 iUnitsMask = 0xffffffff; // Leave units decision to the PDD
51 iVersion = TVersion(KCommsMajorVersionNumber,KCommsMinorVersionNumber,KCommsBuildVersionNumber);
54 TInt DDeviceComm::Install()
56 return(SetName(&KLddName));
59 void DDeviceComm::GetCaps(TDes8& aDes) const
61 TPckgBuf<TCapsDevCommV01> b;
62 b().version = TVersion(KCommsMajorVersionNumber,KCommsMinorVersionNumber,KCommsBuildVersionNumber);
63 Kern::InfoCopy(aDes,b);
66 TInt DDeviceComm::Create(DLogicalChannelBase*& aChannel)
68 aChannel = new DChannelComm;
69 return aChannel?KErrNone:KErrNoMemory;
73 DChannelComm::DChannelComm()
75 iRxCompleteDfc(DChannelComm::CompleteRxDfc,this,2),
76 iTxCompleteDfc(DChannelComm::CompleteTxDfc,this,2),
77 iRxDataAvailableDfc(DChannelComm::RxDataAvailableDfc,this,2),
78 iSigNotifyDfc(DChannelComm::SignalNotifyDfc,this,2),
79 // iBreakMinMilliSeconds(0),
80 // iTurnaroundTimerRunning(EFalse),
81 // iTurnaroundTransmitDelayed(EFalse),
82 iTurnaroundTimer(DChannelComm::TurnaroundStartDfc, this),
83 iTurnaroundDfc(DChannelComm::TurnaroundTimeout, this, 2),
84 // iTurnaroundTxDesPtr(0),
85 // iTurnaroundTxDesLength(0)
86 iBreakDfc(DChannelComm::FinishBreakDfc, this, 2)
88 iConfig.iRate = EBps9600;
89 iConfig.iDataBits = EData8;
90 iConfig.iStopBits = EStop1;
91 iConfig.iParity = EParityNone;
92 iConfig.iHandshake = KConfigObeyCTS;
93 iConfig.iParityError = KConfigParityErrorFail;
94 iConfig.iFifo = EFifoEnable;
95 iConfig.iTerminatorCount = 0;
96 iConfig.iXonChar = 0x11;
97 iConfig.iXoffChar = 0x13;
98 iConfig.iSIREnable = ESIRDisable;
102 iRxDAError = KErrNone;
103 iSignalError = KErrNone;
105 iClientSignalResultPtr = 0;
106 iClient = &Kern::CurrentThread();
111 DChannelComm::~DChannelComm()
113 Kern::SafeClose((DObject*&)iClient, NULL);
116 void DChannelComm::Shutdown()
119 if (iStatus == EActive)
120 Stop(EStopPwrDown); // stop PDD
122 Complete(EAll, KErrAbort);
124 iRxCompleteDfc.Cancel();
125 iTxCompleteDfc.Cancel();
126 iTurnaroundTimer.Cancel();
127 iTurnaroundDfc.Cancel();
128 iSigNotifyDfc.Cancel();
129 iRxDataAvailableDfc.Cancel();
130 iBreakTimer.Cancel();
134 TInt DChannelComm::TurnaroundSet(TUint aNewTurnaroundMilliSeconds)
137 iTurnaroundMinMilliSeconds = aNewTurnaroundMilliSeconds;
141 TBool DChannelComm::TurnaroundStopTimer()
142 // Stop the timer and DFC
145 irq = NKern::DisableInterrupts(1);
146 TBool result = iTurnaroundTimerRunning;
149 iTurnaroundTimerRunning = EFalse;
150 iTurnaroundTimer.Cancel();
151 iTurnaroundDfc.Cancel();
153 NKern::RestoreInterrupts(irq);
157 TInt DChannelComm::TurnaroundClear()
158 // Clear any old timer and start timer based on new turnaround value.
159 // Called for any change: from T > 0 to T == 0 or (T = t1 > 0) to (T = t2 > 0)
160 // POLICY: If a write has already been delayed, it will be started immediately if the requested
161 // turnaround time is elapsed else will only start after it is elapsed.
166 if(iTurnaroundTimerStartTimeValid == 1)
168 //Calculate the turnaround time elapsed so far
169 delta = (NKern::TickCount() - iTurnaroundTimerStartTime) * NKern::TickPeriod();
171 if(delta < iTurnaroundMicroSeconds)
173 iTurnaroundMinMilliSeconds = (iTurnaroundMicroSeconds - delta) / 1000;
174 TInt irq = NKern::DisableInterrupts(1);
175 // POLICY: if timer is running from a previous read, stop it and re-start it
176 if(iTurnaroundTimerRunning)
178 iTurnaroundTimer.Cancel();
179 iTurnaroundDfc.Cancel();
181 iTurnaroundTimerRunning = ETrue;
182 TInt timeout = NKern::TimerTicks(iTurnaroundMinMilliSeconds);
183 iTurnaroundTimer.OneShot(timeout);
184 NKern::RestoreInterrupts(irq);
188 if(TurnaroundStopTimer())
190 // if a write is waiting, start a DFC to run it
191 TurnaroundStartDfcImplementation(EFalse);
194 iTurnaroundMinMilliSeconds = 0;
198 void DChannelComm::TurnaroundStartDfc(TAny* aSelf)
200 DChannelComm* self = (DChannelComm*)aSelf;
201 self->TurnaroundStartDfcImplementation(ETrue);
204 void DChannelComm::TurnaroundStartDfcImplementation(TBool inIsr)
209 irq = NKern::DisableInterrupts(1);
211 iTurnaroundTimerRunning = EFalse;
212 if(iTurnaroundTransmitDelayed || iTurnaroundBreakDelayed)
215 iTurnaroundDfc.Add();
218 NKern::RestoreInterrupts(irq);
219 iTurnaroundDfc.Enque();
225 NKern::RestoreInterrupts(irq);
229 void DChannelComm::TurnaroundTimeout(TAny* aSelf)
231 DChannelComm* self = (DChannelComm*)aSelf;
232 self->TurnaroundTimeoutImplementation();
235 void DChannelComm::TurnaroundTimeoutImplementation(void)
237 TInt irq = NKern::DisableInterrupts(1);
238 if (iTurnaroundBreakDelayed)
240 iTurnaroundBreakDelayed=EFalse;
241 if (iStatus==EClosed)
243 NKern::RestoreInterrupts(irq);
244 Complete(EBreak, KErrNotReady);
250 NKern::RestoreInterrupts(irq);
251 Complete(EBreak, KErrCommsLineFail);
255 if (iTurnaroundTransmitDelayed)
257 //delay write by break instead of turnaround
258 iBreakDelayedTx = ETrue;
259 iBreakDelayedTxDesPtr = iTurnaroundTxDesPtr;
260 iBreakDelayedTxDesLength = iTurnaroundTxDesLength;
261 iTurnaroundTxDesPtr=0;
262 iTurnaroundTxDesLength=0;
263 iTurnaroundTransmitDelayed=EFalse;
265 NKern::RestoreInterrupts(irq);
268 else if(iTurnaroundTransmitDelayed)
270 iTurnaroundTransmitDelayed = EFalse; // protected -> prevent reentrant ISR
271 NKern::RestoreInterrupts(irq);
272 if (iStatus==EClosed)
274 iTurnaroundTxDesPtr = 0;
275 iTurnaroundTxDesLength = 0;
276 Complete(ETx,KErrNotReady);
280 // fail signals checked in the PDD
281 InitiateWrite(iTurnaroundTxDesPtr, iTurnaroundTxDesLength);
282 iTurnaroundTimerStartTime = 0;
283 iTurnaroundTimerStartTimeValid = 2;
284 iTurnaroundTxDesPtr = 0;
285 iTurnaroundTxDesLength = 0;
288 NKern::RestoreInterrupts(irq);
291 TInt DChannelComm::DoCreate(TInt aUnit, const TDesC8* /*aInfo*/, const TVersion &aVer)
293 if(!Kern::CurrentThreadHasCapability(ECapabilityCommDD,__PLATSEC_DIAGNOSTIC_STRING("Checked by ECOMM.LDD (Comm Driver)")))
294 return KErrPermissionDenied;
295 if (!Kern::QueryVersionSupported(TVersion(KCommsMajorVersionNumber,KCommsMinorVersionNumber,KCommsBuildVersionNumber),aVer))
296 return KErrNotSupported;
298 // set up the correct DFC queue
299 SetDfcQ(((DComm*)iPdd)->DfcQ(aUnit));
300 iRxCompleteDfc.SetDfcQ(iDfcQ);
301 iTxCompleteDfc.SetDfcQ(iDfcQ);
302 iRxDataAvailableDfc.SetDfcQ(iDfcQ);
303 iSigNotifyDfc.SetDfcQ(iDfcQ);
304 iTurnaroundDfc.SetDfcQ(iDfcQ);
305 iBreakDfc.SetDfcQ(iDfcQ);
308 ((DComm *)iPdd)->iLdd = this;
310 //setup the initial port configuration
311 PddConfigure(iConfig);
319 void DChannelComm::Start()
321 if (iStatus != EClosed)
331 void DChannelComm::HandleMsg(TMessageBase* aMsg)
333 TThreadMessage& m = *(TThreadMessage*)aMsg;
335 if (id == (TInt)ECloseMsg)
339 m.Complete(KErrNone, EFalse);
342 else if (id == KMaxTInt)
346 m.Complete(KErrNone, ETrue);
353 TRequestStatus* pS = (TRequestStatus*)m.Ptr0();
354 TInt r = DoRequest(~id, pS, m.Ptr1(), m.Ptr2());
356 Kern::RequestComplete(iClient, pS, r);
357 m.Complete(KErrNone, ETrue);
362 TInt r = DoControl(id, m.Ptr0(), m.Ptr1());
363 m.Complete(r, ETrue);
368 TInt DChannelComm::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)
372 // First check if we have started
374 if (iStatus == EOpen)
379 // Now we can dispatch the request
384 case RBusDevComm::ERequestRead:
386 //get the size of the client data
387 r = Kern::ThreadRawRead(iClient, a2, &len, sizeof(len));
390 if (a1) //doing a read
394 InitiateRead(a1,len);
396 else //notify read data availiable
398 iRxDAStatus = aStatus;
399 NotifyReadDataAvailable();
404 case RBusDevComm::ERequestWrite:
406 if (iStatus == EClosed)
410 r = Kern::ThreadRawRead(iClient, a2, &len, sizeof(len)); //get the length of the data to write
414 TInt irq = NKern::DisableInterrupts(1);
415 if(iTurnaroundTimerRunning)
417 iTurnaroundTransmitDelayed = ETrue;
418 iTurnaroundTxDesPtr = a1;
419 iTurnaroundTxDesLength = len;
420 NKern::RestoreInterrupts(irq);
422 else if (iFlags & KBreaking)
424 // currently breaking, delay the write
425 iBreakDelayedTx = ETrue;
426 iBreakDelayedTxDesPtr = a1; // save these as client could could start trashing them before the
427 iBreakDelayedTxDesLength = len; // transmission effectively starts
428 NKern::RestoreInterrupts(irq);
432 NKern::RestoreInterrupts(irq);
433 InitiateWrite(a1, len); //a1 is ptr to data to write (on client side)
434 iTurnaroundTimerStartTime = 0;
435 iTurnaroundTimerStartTimeValid = 2;
441 case RBusDevComm::ERequestNotifySignalChange:
443 //a1 has place to put the result
444 //a2 has the signal mask
451 //start the signal request
453 r = Kern::ThreadRawRead(iClient, a2, &mask, sizeof(mask)); //get the signal mask
456 iSignalStatus = aStatus;
457 InitiateNotifySignals(a1, mask);
462 case RBusDevComm::ERequestBreak:
464 r = Kern::ThreadRawRead(iClient, a1, &iBreakTimeMicroSeconds, sizeof(TInt)); //get the time to break for
467 iBreakStatus=aStatus;
469 // check if turnaround timer running.
470 TInt irq = NKern::DisableInterrupts(1);
471 if(iTurnaroundTimerRunning)
473 iTurnaroundBreakDelayed = ETrue;
474 NKern::RestoreInterrupts(irq);
478 NKern::RestoreInterrupts(irq);
486 r = KErrNotSupported;
493 TInt DChannelComm::SetConfig(TCommConfigV01& c)
496 PddConfigure(iConfig);
500 TInt DChannelComm::DoControl(TInt aFunction, TAny* a1, TAny* a2)
508 case RBusDevComm::EControlConfig:
510 //get the current configuration
511 TPtrC8 cfg((const TUint8*)&iConfig, sizeof(iConfig));
512 r = Kern::ThreadDesWrite(iClient, a1, cfg, 0, KTruncateToMaxLength, iClient);
516 case RBusDevComm::EControlSetConfig:
519 Kern::PanicCurrentThread(_L("D32COMM"), ESetConfigWhileRequestPending);
522 memclr(&c, sizeof(c));
523 TPtr8 cfg((TUint8*)&c, 0, sizeof(c));
524 r = Kern::ThreadDesRead(iClient, a1, cfg, 0, 0);
526 r = SetConfig(c); //set the new configuration
531 case RBusDevComm::EControlCaps:
535 PddCaps(caps); //call ipdd->Caps
536 r = Kern::ThreadDesWrite(iClient, a1, caps, 0, KTruncateToMaxLength, iClient);
540 case RBusDevComm::EControlSignals:
546 case RBusDevComm::EControlSetSignals:
548 // if (((TUint)a1)&((TUint)a2)) //can't set and clear at same time
550 // Kern::PanicCurrentThread(_L("D32COMM"), ESetSignalsSetAndClear);
555 SetSignals((TUint)a1, (TUint)a2);
560 case RBusDevComm::EControlQueryReceiveBuffer:
564 case RBusDevComm::EControlResetBuffers:
566 Kern::PanicCurrentThread(_L("D32COMM"), EResetBuffers);
571 case RBusDevComm::EControlReceiveBufferLength:
575 case RBusDevComm::EControlSetReceiveBufferLength:
577 Kern::PanicCurrentThread(_L("D32COMM"), ESetReceiveBufferLength);
579 r = SetRxBufferSize((TInt)a1);
582 case RBusDevComm::EControlMinTurnaroundTime:
583 r = iTurnaroundMicroSeconds; // used saved value
586 case RBusDevComm::EControlSetMinTurnaroundTime:
590 iTurnaroundMicroSeconds = (TUint)a1; // save this
591 TUint newTurnaroundMilliSeconds = (TUint)a1/1000; // convert to ms
592 if(newTurnaroundMilliSeconds != iTurnaroundMinMilliSeconds)
594 // POLICY: if a new turnaround time is set before the previous running timer has expired
595 // then the timer is adjusted depending on the new value and if any
596 // write request has been queued, transmission will proceed after the timer has expired.
597 if(iTurnaroundTimerStartTimeValid == 0)
599 iTurnaroundTimerStartTime = NKern::TickCount();
600 iTurnaroundTimerStartTimeValid = 1;
602 if(iTurnaroundTimerStartTimeValid != 2)
604 if(newTurnaroundMilliSeconds > 0)
606 r = TurnaroundSet(newTurnaroundMilliSeconds);
613 r = KErrNotSupported;
619 void DChannelComm::SignalNotifyDfc(TAny* aPtr)
621 DChannelComm* pC = (DChannelComm*)aPtr;
622 pC->DoSignalNotify();
625 void DChannelComm::RxDataAvailableDfc(TAny* aPtr)
627 DChannelComm* pC = (DChannelComm*)aPtr;
628 pC->DoRxDataAvailable();
631 void DChannelComm::DoRxDataAvailable()
633 Complete(ERxDA, iRxDAError);
634 iRxDAError = KErrNone;
637 void DChannelComm::DoSignalNotify()
639 //copy the data back to the client
640 if (iSignalError == KErrNone)
641 iSignalError = Kern::ThreadRawWrite(iClient, iClientSignalResultPtr,&iSignalResult, sizeof(iSignalResult), iClient);
642 Complete(ESigChg, iSignalError);
643 iSignalError = KErrNone;
646 void DChannelComm::CompleteTxDfc(TAny* aPtr)
648 DChannelComm* pC = (DChannelComm*)aPtr;
652 void DChannelComm::DoCompleteTx()
654 Complete(ETx, iTxError);
658 void DChannelComm::CompleteRxDfc(TAny* aPtr)
660 DChannelComm* pC = (DChannelComm*)aPtr;
664 void DChannelComm::DoCompleteRx()
666 if (iRxError == KErrNone)
668 //copy the data back to the client
669 iRxError = Kern::ThreadDesWrite(iClient, (TDes8*)iClientDestPtr, *RxBuffer(), 0, KChunkShiftBy0, iClient);
671 Complete(ERx, iRxError);
673 TInt irq = NKern::DisableInterrupts(1);
674 if(iTurnaroundMinMilliSeconds > 0)
676 // POLICY: if timer is running from a previous read, stop it and re-start it
677 if(iTurnaroundTimerRunning)
679 iTurnaroundTimer.Cancel();
680 iTurnaroundDfc.Cancel();
682 iTurnaroundTimerRunning = ETrue;
683 TInt timeout = NKern::TimerTicks(iTurnaroundMinMilliSeconds);
684 iTurnaroundTimer.OneShot(timeout);
685 //Record the timestamp of turnaround timer start.
686 iTurnaroundTimerStartTimeValid = 1;
687 iTurnaroundTimerStartTime = NKern::TickCount();
689 NKern::RestoreInterrupts(irq);
692 void DChannelComm::DoCancel(TInt aMask)
694 if (aMask & RBusDevComm::ERequestReadCancel)
699 if (aMask & RBusDevComm::ERequestWriteCancel)
701 TInt irq = NKern::DisableInterrupts(1);
702 if(iTurnaroundTransmitDelayed)
704 iTurnaroundTxDesPtr = 0;
705 iTurnaroundTxDesLength = 0;
706 iTurnaroundTransmitDelayed = EFalse;
708 NKern::RestoreInterrupts(irq);
713 if (aMask & RBusDevComm::ERequestNotifySignalChangeCancel)
715 SignalChangeCancel();
716 Complete(ESigChg,KErrCancel);
719 if (aMask & RBusDevComm::ERequestBreakCancel)
721 TInt irq = NKern::DisableInterrupts(1);
722 if(iTurnaroundBreakDelayed)
723 iTurnaroundBreakDelayed = EFalse;
724 NKern::RestoreInterrupts(irq);
727 iBreakTimer.Cancel();
728 FinishBreakImplementation(KErrCancel);
733 void DChannelComm::InitiateWrite(TAny *aTxDes, TInt aLength)
735 //aTxDes has client side data
736 //aLength has the len
740 Complete(ETx, KErrArgument);
743 // call the pdd to fill its buffer and write the data
744 Write(iClient, aTxDes, aLength);
747 void DChannelComm::InitiateRead(TAny *aRxDes, TInt aLength)
750 // Complete zero-length read immediately. maybe not
754 // Complete(ERx, KErrNone);
757 TInt max=Kern::ThreadGetDesMaxLength(iClient,aRxDes);
759 if (max < Abs(aLength) || max < 0)
760 Complete(ERx, KErrGeneral);
761 // do not start the Turnaround timer (invalid Descriptor this read never starts)
764 iClientDestPtr = aRxDes;
765 Read(iClient, aRxDes, aLength);
769 void DChannelComm::InitiateNotifySignals(TAny *aSignalResultPtr, TInt aMask)
771 //aMask has the mask of signals we require
772 //aSignalResultPtr is a pointer to the clients area for the result
773 iClientSignalResultPtr = (TUint*)aSignalResultPtr;
774 NotifySignals(iClient, aMask);
777 void DChannelComm::NotifyReadDataAvailable()
779 NotifyDataAvailable();
783 void DChannelComm::Complete(TInt aMask, TInt aReason)
786 Kern::RequestComplete(iClient, iRxStatus, aReason);
788 Kern::RequestComplete(iClient, iTxStatus, aReason);
790 Kern::RequestComplete(iClient, iSignalStatus, aReason);
792 Kern::RequestComplete(iClient, iRxDAStatus, aReason);
794 Kern::RequestComplete(iClient, iBreakStatus, aReason);
797 void DChannelComm::BreakOn()
799 // Start the driver breaking.
802 iFlags&=(~KBreakPending);
805 iBreakTimer.OneShot(iBreakTimeMicroSeconds, DChannelComm::FinishBreak, this);
808 void DChannelComm::BreakOff()
810 // Stop the driver breaking.
817 void DChannelComm::FinishBreak(TAny* aSelf)
819 DChannelComm* self = (DChannelComm*)aSelf;
820 self->QueueFinishBreakDfc();
823 void DChannelComm::FinishBreakDfc(TAny* aSelf)
825 DChannelComm* self = (DChannelComm*)aSelf;
826 self->FinishBreakImplementation(KErrNone);
829 void DChannelComm::QueueFinishBreakDfc()
834 void DChannelComm::FinishBreakImplementation(TInt aBreakError)
836 if (iStatus==EClosed)
838 Complete(EBreak, KErrNotReady);
840 else if(LineFail()) // have signals changed in the meantime?
842 Complete(EBreak, KErrCommsLineFail);
847 Complete(EBreak, aBreakError);
849 TInt irq = NKern::DisableInterrupts(1);
852 iBreakDelayedTx = EFalse; // protected -> prevent reentrant ISR
853 NKern::RestoreInterrupts(irq);
854 if (iStatus==EClosed)
856 iBreakDelayedTxDesPtr = 0;
857 iBreakDelayedTxDesLength = 0;
858 Complete(ETx,KErrNotReady);
862 // fail signals checked in the PDD
863 InitiateWrite(iBreakDelayedTxDesPtr, iBreakDelayedTxDesLength);
864 iBreakDelayedTxDesPtr = 0;
865 iBreakDelayedTxDesLength = 0;
868 NKern::RestoreInterrupts(irq);