|
1 // Copyright (c) 1995-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". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // e32\drivers\ecomm\d_comm.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 #include <drivers/comm.h> |
|
19 #include <kernel/kern_priv.h> |
|
20 #include <e32hal.h> |
|
21 #include <e32uid.h> |
|
22 |
|
23 // Logging |
|
24 #define LOG_ON(x) Kern::Printf##x |
|
25 #define LOG_OFF(x) |
|
26 #define LOG LOG_OFF |
|
27 |
|
28 |
|
29 //#define __UART_RX_ERROR(x) *(TUint*)0xfeedface=(x) |
|
30 //#define __OVERRUN() *(TUint*)0xfaece5=0 |
|
31 |
|
32 #define __UART_RX_ERROR(x) |
|
33 #define __OVERRUN() |
|
34 |
|
35 _LIT(KLddName,"Comm"); |
|
36 |
|
37 |
|
38 const TUint KXoffSignal=0x80; |
|
39 // |
|
40 const TUint KBreaking=0x02; |
|
41 const TUint KBreakPending=0x04; |
|
42 // |
|
43 enum TPanic |
|
44 { |
|
45 ESetConfigWhileRequestPending, |
|
46 ESetSignalsSetAndClear, |
|
47 EResetBuffers, |
|
48 ESetReceiveBufferLength, |
|
49 }; |
|
50 |
|
51 DECLARE_STANDARD_LDD() |
|
52 { |
|
53 return new DDeviceComm; |
|
54 } |
|
55 |
|
56 DDeviceComm::DDeviceComm() |
|
57 // |
|
58 // Constructor |
|
59 // |
|
60 { |
|
61 LOG(("DDeviceComm::DDeviceComm")); |
|
62 iParseMask=KDeviceAllowAll; |
|
63 iUnitsMask=0xffffffff; // Leave units decision to the PDD |
|
64 iVersion=TVersion(KCommsMajorVersionNumber,KCommsMinorVersionNumber,KCommsBuildVersionNumber); |
|
65 } |
|
66 |
|
67 TInt DDeviceComm::Install() |
|
68 // |
|
69 // Install the device driver. |
|
70 // |
|
71 { |
|
72 LOG(("DDeviceComm::Install")); |
|
73 return(SetName(&KLddName)); |
|
74 } |
|
75 |
|
76 void DDeviceComm::GetCaps(TDes8& aDes) const |
|
77 // |
|
78 // Return the Comm capabilities. |
|
79 // |
|
80 { |
|
81 LOG(("DDeviceComm::GetCaps")); |
|
82 TPckgBuf<TCapsDevCommV01> b; |
|
83 b().version=TVersion(KCommsMajorVersionNumber,KCommsMinorVersionNumber,KCommsBuildVersionNumber); |
|
84 Kern::InfoCopy(aDes,b); |
|
85 } |
|
86 |
|
87 TInt DDeviceComm::Create(DLogicalChannelBase*& aChannel) |
|
88 // |
|
89 // Create a channel on the device. |
|
90 // |
|
91 { |
|
92 LOG(("DDeviceComm::Create")); |
|
93 aChannel=new DChannelComm; |
|
94 return aChannel?KErrNone:KErrNoMemory; |
|
95 } |
|
96 |
|
97 DChannelComm::DChannelComm() |
|
98 // |
|
99 // Constructor |
|
100 // |
|
101 : iPowerUpDfc(DChannelComm::PowerUpDfc,this,3), |
|
102 iPowerDownDfc(DChannelComm::PowerDownDfc,this,3), |
|
103 iRxDrainDfc(DChannelComm::DrainRxDfc,this,2), |
|
104 iRxCompleteDfc(DChannelComm::CompleteRxDfc,this,2), |
|
105 iTxFillDfc(DChannelComm::FillTxDfc,this,2), |
|
106 iTxCompleteDfc(DChannelComm::CompleteTxDfc,this,2), |
|
107 iTimerDfc(DChannelComm::TimerDfcFn,this,3), |
|
108 iSigNotifyDfc(DChannelComm::SigNotifyDfc,this,2), |
|
109 // iTurnaroundMinMilliSeconds(0), |
|
110 // iTurnaroundTimerRunning(EFalse), |
|
111 // iTurnaroundTransmitDelayed(EFalse), |
|
112 iTurnaroundTimer(DChannelComm::TurnaroundStartDfc, this), |
|
113 iTurnaroundDfc(DChannelComm::TurnaroundTimeout, this, 2), |
|
114 iTimer(DChannelComm::MsCallBack,this), |
|
115 iBreakDfc(DChannelComm::FinishBreakDfc, this, 2), |
|
116 iLock(TSpinLock::EOrderGenericIrqLow3) |
|
117 { |
|
118 LOG(("DChannelComm")); |
|
119 // |
|
120 // Setup the default config |
|
121 // |
|
122 iConfig.iRate=EBps9600; |
|
123 iConfig.iDataBits=EData8; |
|
124 iConfig.iStopBits=EStop1; |
|
125 iConfig.iParity=EParityNone; |
|
126 iConfig.iFifo=EFifoEnable; |
|
127 iConfig.iHandshake=KConfigObeyCTS; |
|
128 iConfig.iParityError=KConfigParityErrorFail; |
|
129 iConfig.iSIREnable=ESIRDisable; |
|
130 // iConfig.iTerminatorCount=0; |
|
131 // iConfig.iTerminator[0]=0; |
|
132 // iConfig.iTerminator[1]=0; |
|
133 // iConfig.iTerminator[2]=0; |
|
134 // iConfig.iTerminator[3]=0; |
|
135 iConfig.iXonChar=0x11; // XON |
|
136 iConfig.iXoffChar=0x13; // XOFF |
|
137 // iConfig.iSpecialRate=0; |
|
138 // iConfig.iParityErrorChar=0; |
|
139 iRxXonChar=0xffffffff; |
|
140 iRxXoffChar=0xffffffff; |
|
141 iStatus=EOpen; |
|
142 // iFlags=0; |
|
143 // iSignals=0; |
|
144 // iFailSignals=0; |
|
145 // iHoldSignals=0; |
|
146 // iFlowControlSignals=0; |
|
147 // iAutoSignals=0; |
|
148 // iTerminatorMask[0...31]=0; |
|
149 // iShutdown=EFalse; |
|
150 // iRxCharBuf=NULL; |
|
151 // iRxErrorBuf=NULL; |
|
152 // iRxPutIndex=0; |
|
153 // iRxGetIndex=0; |
|
154 // iRxBufSize=0; |
|
155 // iFlowControlLowerThreshold=0; |
|
156 // iFlowControlUpperThreshold=0; |
|
157 // iRxDrainThreshold=0; |
|
158 // iRxBufCompleteIndex=0; |
|
159 // iInputHeld=EFalse; |
|
160 // iRxClientBufReq=NULL; |
|
161 // iRxDesPos=0; |
|
162 // iRxLength=0; |
|
163 // iRxOutstanding=EFalse; |
|
164 // iRxError=KErrNone; |
|
165 // iTxBuffer=NULL; |
|
166 // iTxPutIndex=0; |
|
167 // iTxGetIndex=0; |
|
168 // iTxBufSize=0; |
|
169 // iTxFillThreshold=0; |
|
170 iOutputHeld=0; |
|
171 iJamChar=KTxNoChar; |
|
172 // iTxDesPtr=NULL; |
|
173 // iTxDesPos=0; |
|
174 // iTxDesLength=0; |
|
175 // iTxOutstanding=EFalse; |
|
176 // iTxError=KErrNone; |
|
177 |
|
178 // iTimeout=10; |
|
179 iTimeout=NKern::TimerTicks(5); |
|
180 iClient=&Kern::CurrentThread(); |
|
181 iClient->Open(); |
|
182 // iSigNotifyMask=0; |
|
183 // iSignalsPtr=NULL; |
|
184 // iSigNotifyStatus=NULL; |
|
185 iBreakStatus=NULL; |
|
186 iNotifiedSignals=0xffffffff; |
|
187 iPinObjSetConfig=NULL; |
|
188 } |
|
189 |
|
190 DChannelComm::~DChannelComm() |
|
191 // |
|
192 // Destructor |
|
193 // |
|
194 { |
|
195 LOG(("~DChannelComm")); |
|
196 if (iPowerHandler) |
|
197 { |
|
198 iPowerHandler->Remove(); |
|
199 delete iPowerHandler; |
|
200 } |
|
201 if (iRxCharBuf) |
|
202 Kern::Free(iRxCharBuf); |
|
203 if (iTxBuffer) |
|
204 Kern::Free(iTxBuffer); |
|
205 if (iBreakStatus) |
|
206 Kern::DestroyClientRequest(iBreakStatus); |
|
207 if (iSignalsReq) |
|
208 Kern::DestroyClientRequest(iSignalsReq); |
|
209 if (iPinObjSetConfig) |
|
210 Kern::DestroyVirtualPinObject(iPinObjSetConfig); |
|
211 Kern::SafeClose((DObject*&)iClient, NULL); |
|
212 } |
|
213 |
|
214 |
|
215 void DChannelComm::Complete(TInt aMask, TInt aReason) |
|
216 { |
|
217 LOG(("Complete(aMask=%x aReason=%d)", aMask, aReason)); |
|
218 if (aMask & ERx) |
|
219 iRxBufReq.Complete(iClient, aReason); |
|
220 if (aMask & ETx) |
|
221 iTxBufReq.Complete(iClient, aReason); |
|
222 if (aMask & ESigChg) |
|
223 Kern::QueueRequestComplete(iClient, iSignalsReq, aReason); |
|
224 if ((aMask & EBreak) && iBreakStatus && iBreakStatus->IsReady()) |
|
225 Kern::QueueRequestComplete(iClient, iBreakStatus, aReason); |
|
226 } |
|
227 |
|
228 TInt DChannelComm::Shutdown() |
|
229 { |
|
230 __KTRACE_OPT(KPOWER,Kern::Printf("DChannelComm::Shutdown()")); |
|
231 LOG(("Shutdown()")); |
|
232 |
|
233 if (iStatus == EActive) |
|
234 Stop(EStopPwrDown); |
|
235 |
|
236 Complete(EAll, KErrAbort); |
|
237 |
|
238 // UART interrupts are disabled; must make sure DFCs are not queued. |
|
239 iRxDrainDfc.Cancel(); |
|
240 iRxCompleteDfc.Cancel(); |
|
241 iTxFillDfc.Cancel(); |
|
242 iTxCompleteDfc.Cancel(); |
|
243 iTimer.Cancel(); |
|
244 iTurnaroundTimer.Cancel(); |
|
245 iTurnaroundDfc.Cancel(); |
|
246 iTimerDfc.Cancel(); |
|
247 iSigNotifyDfc.Cancel(); |
|
248 iPowerUpDfc.Cancel(); |
|
249 iPowerDownDfc.Cancel(); |
|
250 iBreakTimer.Cancel(); |
|
251 iBreakDfc.Cancel(); |
|
252 |
|
253 if (iPdd) |
|
254 SetSignals(0,iFlowControlSignals|iAutoSignals); |
|
255 |
|
256 return KErrCompletion; |
|
257 } |
|
258 |
|
259 TInt DChannelComm::DoCreate(TInt aUnit, const TDesC8* /*anInfo*/, const TVersion &aVer) |
|
260 // |
|
261 // Create the channel from the passed info. |
|
262 // |
|
263 { |
|
264 LOG(("DoCreate(aUnit=%d,...)", aUnit)); |
|
265 if(!Kern::CurrentThreadHasCapability(ECapabilityCommDD,__PLATSEC_DIAGNOSTIC_STRING("Checked by ECOMM.LDD (Comm Driver)"))) |
|
266 return KErrPermissionDenied; |
|
267 if (!Kern::QueryVersionSupported(TVersion(KCommsMajorVersionNumber,KCommsMinorVersionNumber,KCommsBuildVersionNumber),aVer)) |
|
268 return KErrNotSupported; |
|
269 |
|
270 // set up the correct DFC queue |
|
271 SetDfcQ(((DComm*)iPdd)->DfcQ(aUnit)); |
|
272 iPowerUpDfc.SetDfcQ(iDfcQ); |
|
273 iPowerDownDfc.SetDfcQ(iDfcQ); |
|
274 iRxDrainDfc.SetDfcQ(iDfcQ); |
|
275 iRxCompleteDfc.SetDfcQ(iDfcQ); |
|
276 iTxFillDfc.SetDfcQ(iDfcQ); |
|
277 iTxCompleteDfc.SetDfcQ(iDfcQ); |
|
278 iTimerDfc.SetDfcQ(iDfcQ); |
|
279 iSigNotifyDfc.SetDfcQ(iDfcQ); |
|
280 iTurnaroundDfc.SetDfcQ(iDfcQ); |
|
281 iBreakDfc.SetDfcQ(iDfcQ); |
|
282 iMsgQ.Receive(); |
|
283 |
|
284 // initialise the TX buffer |
|
285 iTxBufSize=KTxBufferSize; |
|
286 iTxBuffer=(TUint8*)Kern::Alloc(iTxBufSize); |
|
287 if (!iTxBuffer) |
|
288 return KErrNoMemory; |
|
289 iTxFillThreshold=iTxBufSize>>1; |
|
290 |
|
291 // initialise the RX buffer |
|
292 iRxBufSize=KDefaultRxBufferSize; |
|
293 iRxCharBuf=(TUint8*)Kern::Alloc(iRxBufSize<<1); |
|
294 if (!iRxCharBuf) |
|
295 return KErrNoMemory; |
|
296 iRxErrorBuf=iRxCharBuf+iRxBufSize; |
|
297 iFlowControlLowerThreshold=iRxBufSize>>2; |
|
298 iFlowControlUpperThreshold=3*iRxBufSize>>2; |
|
299 iRxDrainThreshold=iRxBufSize>>1; |
|
300 |
|
301 // Create request objects |
|
302 TInt r = Kern::CreateClientDataRequest(iSignalsReq); |
|
303 if (r==KErrNone) |
|
304 r = Kern::CreateClientRequest(iBreakStatus); |
|
305 if (r==KErrNone) |
|
306 r = iRxBufReq.Create(); |
|
307 if (r==KErrNone) |
|
308 r = iTxBufReq.Create(); |
|
309 if (r==KErrNone) |
|
310 r = Kern::CreateVirtualPinObject(iPinObjSetConfig); |
|
311 if (r != KErrNone) |
|
312 return r; |
|
313 |
|
314 ((DComm *)iPdd)->iLdd=this; |
|
315 PddCheckConfig(iConfig); |
|
316 iFailSignals=FailSignals(iConfig.iHandshake); |
|
317 iHoldSignals=HoldSignals(iConfig.iHandshake); |
|
318 iFlowControlSignals=FlowControlSignals(iConfig.iHandshake); |
|
319 iAutoSignals=AutoSignals(iConfig.iHandshake); |
|
320 |
|
321 // create the power handler |
|
322 iPowerHandler=new DCommPowerHandler(this); |
|
323 if (!iPowerHandler) |
|
324 return KErrNoMemory; |
|
325 iPowerHandler->Add(); |
|
326 DoPowerUp(); |
|
327 |
|
328 return KErrNone; |
|
329 } |
|
330 |
|
331 TInt DChannelComm::RequestUserHandle(DThread* aThread, TOwnerType aType) |
|
332 { |
|
333 // Ensure that each channel can only be used by a single thread. |
|
334 return (aThread!=iClient) ? KErrAccessDenied : KErrNone; |
|
335 } |
|
336 |
|
337 void DChannelComm::MsCallBack(TAny* aPtr) |
|
338 { |
|
339 // called from ISR when timer completes |
|
340 DChannelComm *pC=(DChannelComm*)aPtr; |
|
341 pC->iTimerDfc.Add(); |
|
342 } |
|
343 |
|
344 void DChannelComm::TimerDfcFn(TAny* aPtr) |
|
345 { |
|
346 DChannelComm *pC=(DChannelComm*)aPtr; |
|
347 pC->TimerDfc(); |
|
348 } |
|
349 |
|
350 void DChannelComm::TimerDfc() |
|
351 { |
|
352 TInt irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
353 if (iRxOutstanding) |
|
354 { |
|
355 if (iRxGetIndex==iRxPutIndex) |
|
356 { |
|
357 // buffer empty after timeout period, so complete |
|
358 iRxBufCompleteIndex=iRxPutIndex; |
|
359 iRxOutstanding=EFalse; |
|
360 iRxOneOrMore=0; |
|
361 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
362 DoCompleteRx(); |
|
363 return; |
|
364 } |
|
365 // buffer not empty, so drain buffer and requeue timer |
|
366 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
367 DoDrainRxBuffer(iRxPutIndex); |
|
368 return; |
|
369 } |
|
370 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
371 } |
|
372 |
|
373 void DChannelComm::DrainRxDfc(TAny* aPtr) |
|
374 { |
|
375 DChannelComm *pC=(DChannelComm*)aPtr; |
|
376 pC->DoDrainRxBuffer(pC->iRxPutIndex); |
|
377 } |
|
378 |
|
379 // Drain RX buffer in a DFC |
|
380 void DChannelComm::DoDrainRxBuffer(TInt aEndIndex) |
|
381 { |
|
382 // if RX completion DFC is queued, leave buffer draining to it |
|
383 if (iRxCompleteDfc.Queued()) |
|
384 return; |
|
385 |
|
386 LOG(("DoDrainRxBuffer(aEndIndex=%d) iRxDesPos=%d iRxBufReq.iLen=%d", aEndIndex, iRxDesPos, iRxBufReq.iLen)); |
|
387 |
|
388 // If there's an Rx request with bytes outstanding... |
|
389 if (iRxBufReq.iBuf && iRxDesPos<iRxBufReq.iLen) |
|
390 { |
|
391 TInt space=iRxBufReq.iLen-iRxDesPos; // the amount of the client buffer left to fill |
|
392 TInt avail=aEndIndex-iRxGetIndex; // the amount of data in the Rx buffer to copy to the client buffer |
|
393 if (avail<0) // true if the data to drain wraps around the end of the buffer (i.e. the last byte to copy has a linear address less than that of the first byte) |
|
394 avail+=iRxBufSize; |
|
395 TInt len=Min(space,avail); // total number of bytes to drain |
|
396 |
|
397 // Drain up to (but not beyond) the end of the Rx buffer |
|
398 TInt len1=Min(len,iRxBufSize-iRxGetIndex); // number of bytes to the end of the buffer |
|
399 TPtrC8 des(iRxCharBuf+iRxGetIndex,len1); |
|
400 |
|
401 TInt r = Kern::ThreadBufWrite(iClient, iRxBufReq.iBuf, des, iRxDesPos, KChunkShiftBy0, iClient); |
|
402 if (r != KErrNone) |
|
403 { |
|
404 iRxError=r; |
|
405 DoCompleteRx(); |
|
406 return; |
|
407 } |
|
408 |
|
409 // Update the client buffer offset and the Rx buffer read pointer with what we've done so far |
|
410 TInt irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
411 iRxDesPos += len1; |
|
412 iRxGetIndex+=len1; |
|
413 if (iRxGetIndex>=iRxBufSize) |
|
414 iRxGetIndex-=iRxBufSize; |
|
415 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
416 |
|
417 // If the data wraps around the end of the Rx buffer, now write out the second part |
|
418 // which starts at the beginning of the Rx buffer. |
|
419 len-=len1; |
|
420 if (len) |
|
421 { |
|
422 des.Set(iRxCharBuf,len); |
|
423 r=Kern::ThreadBufWrite(iClient, iRxBufReq.iBuf, des, iRxDesPos, KChunkShiftBy0, iClient); |
|
424 if (r != KErrNone) |
|
425 { |
|
426 iRxError=r; |
|
427 DoCompleteRx(); |
|
428 return; |
|
429 } |
|
430 |
|
431 // Update client buffer offset and Rx buffer read offset |
|
432 irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
433 iRxDesPos += len; |
|
434 iRxGetIndex+=len; |
|
435 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
436 } |
|
437 |
|
438 // release flow control if necessary |
|
439 if (iInputHeld && RxCount()<=iFlowControlLowerThreshold) |
|
440 ReleaseFlowControl(); |
|
441 |
|
442 // if we are doing ReadOneOrMore, start the timer |
|
443 if (iRxOneOrMore>0) |
|
444 { |
|
445 iTimer.OneShot(iTimeout); |
|
446 } |
|
447 } |
|
448 } |
|
449 |
|
450 |
|
451 void DChannelComm::RxComplete() |
|
452 { |
|
453 if (NKern::CurrentContext()==NKern::EInterrupt) |
|
454 iRxCompleteDfc.Add(); |
|
455 else |
|
456 DoCompleteRx(); |
|
457 } |
|
458 |
|
459 |
|
460 void DChannelComm::CompleteRxDfc(TAny* aPtr) |
|
461 { |
|
462 DChannelComm *pC=(DChannelComm*)aPtr; |
|
463 pC->DoCompleteRx(); |
|
464 } |
|
465 |
|
466 void DChannelComm::DoCompleteRx() |
|
467 { |
|
468 LOG(("DoCompleteRx()")); |
|
469 if (iRxOneOrMore>0) |
|
470 iTimer.Cancel(); |
|
471 if (iRxBufReq.iLen) |
|
472 { |
|
473 iRxOneOrMore=0; |
|
474 DoDrainRxBuffer(iRxBufCompleteIndex); |
|
475 iRxBufReq.Complete(iClient, iRxError); |
|
476 iRxDesPos=0; |
|
477 |
|
478 iRxError=KErrNone; |
|
479 // start Turnaround timer (got here because it received all data, timed out on a ReadOneOrMore or was terminated |
|
480 // early by FailSignals) |
|
481 RestartTurnaroundTimer(); |
|
482 } |
|
483 else |
|
484 { |
|
485 Complete(ERx,KErrNone); |
|
486 // do not start Turnaround (got here on a request Data Available Notification) |
|
487 } |
|
488 } |
|
489 |
|
490 |
|
491 void DChannelComm::TxComplete() |
|
492 { |
|
493 if (NKern::CurrentContext()==NKern::EInterrupt) |
|
494 iTxCompleteDfc.Add(); |
|
495 else |
|
496 DoCompleteTx(); |
|
497 } |
|
498 |
|
499 |
|
500 void DChannelComm::FillTxDfc(TAny* aPtr) |
|
501 { |
|
502 DChannelComm *pC=(DChannelComm*)aPtr; |
|
503 pC->DoFillTxBuffer(); |
|
504 } |
|
505 |
|
506 // Fill TX buffer in a DFC |
|
507 void DChannelComm::DoFillTxBuffer() |
|
508 { |
|
509 LOG(("DFTB %d =%d",iTxDesPos,iTxBufReq.iLen)); |
|
510 if (iTxBufReq.iBuf && iTxDesPos<iTxBufReq.iLen) |
|
511 { |
|
512 TInt space=iTxBufSize-TxCount()-1; |
|
513 TInt remaining=iTxBufReq.iLen-iTxDesPos; |
|
514 TInt len=Min(space,remaining); // number of chars to transfer |
|
515 TInt len1=Min(len,iTxBufSize-iTxPutIndex); // number of chars to wrap point |
|
516 TPtr8 des(iTxBuffer+iTxPutIndex,len1,len1); |
|
517 LOG(("DFTxB sp = %d rem = %d iOPH = %d",space, remaining,iOutputHeld)); |
|
518 TInt r=Kern::ThreadBufRead(iClient, iTxBufReq.iBuf, des, iTxDesPos, KChunkShiftBy0); |
|
519 if (r != KErrNone) |
|
520 { |
|
521 iTxError=r; |
|
522 DoCompleteTx(); |
|
523 return; |
|
524 } |
|
525 |
|
526 TInt irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
527 iTxDesPos+=len1; |
|
528 iTxPutIndex+=len1; |
|
529 if (iTxPutIndex>=iTxBufSize) |
|
530 iTxPutIndex-=iTxBufSize; |
|
531 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
532 |
|
533 len-=len1; |
|
534 if (len) |
|
535 { |
|
536 des.Set(iTxBuffer,len,len); |
|
537 r=Kern::ThreadBufRead(iClient, iTxBufReq.iBuf, des, iTxDesPos, KChunkShiftBy0); |
|
538 if (r != KErrNone) |
|
539 { |
|
540 iTxError=r; |
|
541 DoCompleteTx(); |
|
542 return; |
|
543 } |
|
544 |
|
545 irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
546 iTxDesPos+=len; |
|
547 iTxPutIndex+=len; |
|
548 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
549 } |
|
550 if (iTxDesPos==iTxBufReq.iLen) |
|
551 { |
|
552 // we have used up the client descriptor |
|
553 if (iConfig.iHandshake & KConfigWriteBufferedComplete) |
|
554 { |
|
555 iTxOutstanding=EFalse; |
|
556 DoCompleteTx(); |
|
557 } |
|
558 } |
|
559 // if TX buffer not empty and not flow controlled, make sure TX is enabled |
|
560 if (iTxPutIndex!=iTxGetIndex && (!iOutputHeld)) |
|
561 { |
|
562 LOG(("Calling - DoTxBuff->ETx")); |
|
563 EnableTransmit(); |
|
564 } |
|
565 } |
|
566 } |
|
567 |
|
568 void DChannelComm::CompleteTxDfc(TAny* aPtr) |
|
569 { |
|
570 DChannelComm *pC=(DChannelComm*)aPtr; |
|
571 pC->DoCompleteTx(); |
|
572 } |
|
573 |
|
574 void DChannelComm::DoCompleteTx() |
|
575 { |
|
576 Complete(ETx,iTxError); |
|
577 iTxError=KErrNone; |
|
578 } |
|
579 |
|
580 void DChannelComm::Start() |
|
581 // |
|
582 // Start the driver receiving. |
|
583 // |
|
584 { |
|
585 LOG(("Start()")); |
|
586 if (iStatus!=EClosed) |
|
587 { |
|
588 PddConfigure(iConfig); |
|
589 PddStart(); |
|
590 iStatus=EActive; |
|
591 if ((iConfig.iHandshake & KConfigSendXoff) && iJamChar>=0) |
|
592 EnableTransmit(); // Send XOn if there is one |
|
593 } |
|
594 } |
|
595 |
|
596 void DChannelComm::BreakOn() |
|
597 // |
|
598 // Start the driver breaking. |
|
599 // |
|
600 { |
|
601 LOG(("BreakOn()")); |
|
602 iFlags&=(~KBreakPending); |
|
603 iFlags|=KBreaking; |
|
604 PddBreak(ETrue); |
|
605 iBreakTimer.OneShot(iBreakTimeMicroSeconds, DChannelComm::FinishBreak, this); |
|
606 } |
|
607 |
|
608 void DChannelComm::BreakOff() |
|
609 // |
|
610 // Stop the driver breaking. |
|
611 // |
|
612 { |
|
613 LOG(("BreakOff()")); |
|
614 PddBreak(EFalse); |
|
615 iFlags&=(~(KBreakPending|KBreaking)); |
|
616 } |
|
617 |
|
618 void DChannelComm::AssertFlowControl() |
|
619 { |
|
620 iInputHeld=ETrue; |
|
621 SetSignals(0,iFlowControlSignals); |
|
622 if (iConfig.iHandshake&KConfigSendXoff) // Doing input XON/XOFF |
|
623 { |
|
624 iJamChar=iConfig.iXoffChar; // set up to send Xoff |
|
625 EnableTransmit(); // Make sure we are transmitting |
|
626 } |
|
627 } |
|
628 |
|
629 void DChannelComm::ReleaseFlowControl() |
|
630 { |
|
631 iInputHeld=EFalse; |
|
632 SetSignals(iFlowControlSignals,0); |
|
633 if (iConfig.iHandshake&KConfigSendXoff) // Doing input XON/XOFF |
|
634 { |
|
635 iJamChar=iConfig.iXonChar; // set up to send Xon |
|
636 EnableTransmit(); // Make sure we are transmitting |
|
637 } |
|
638 } |
|
639 |
|
640 TInt DChannelComm::SetRxBufferSize(TInt aSize) |
|
641 // |
|
642 // Set the receive buffer size. |
|
643 // |
|
644 { |
|
645 LOG(("SetRxBufferSize(aSize=0x%X)", aSize)); |
|
646 aSize=(aSize+3)&~3; |
|
647 TUint8 *newBuf=(TUint8*)Kern::ReAlloc(iRxCharBuf,aSize<<1); |
|
648 if (!newBuf) |
|
649 return KErrNoMemory; |
|
650 TInt irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
651 iRxCharBuf=newBuf; |
|
652 iRxErrorBuf=newBuf+aSize; |
|
653 iRxBufSize=aSize; |
|
654 iFlowControlLowerThreshold=aSize>>2; |
|
655 iFlowControlUpperThreshold=3*aSize>>2; |
|
656 iRxDrainThreshold=aSize>>1; |
|
657 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
658 ResetBuffers(EFalse); |
|
659 return KErrNone; |
|
660 } |
|
661 |
|
662 TInt DChannelComm::TurnaroundSet(TUint aNewTurnaroundMilliSeconds) |
|
663 { |
|
664 LOG(("TurnaroundSet(val=0x%X)", aNewTurnaroundMilliSeconds)); |
|
665 TInt r = KErrNone; |
|
666 iTurnaroundMinMilliSeconds = aNewTurnaroundMilliSeconds; |
|
667 return r; |
|
668 } |
|
669 |
|
670 TBool DChannelComm::TurnaroundStopTimer() |
|
671 // Stop the timer and DFC |
|
672 { |
|
673 LOG(("TurnaroundStopTimer()")); |
|
674 |
|
675 TInt irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
676 TBool result = iTurnaroundTimerRunning; |
|
677 if(result) |
|
678 iTurnaroundTimerRunning = EFalse; |
|
679 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
680 |
|
681 if (result) |
|
682 { |
|
683 iTurnaroundTimer.Cancel(); |
|
684 iTurnaroundDfc.Cancel(); |
|
685 } |
|
686 return result; |
|
687 } |
|
688 |
|
689 TInt DChannelComm::TurnaroundClear() |
|
690 // Clear any old timer and start timer based on new turnaround timer |
|
691 // Called for any change: from T > 0 to T == 0 or (T = t1 > 0) to (T = t2 > 0) |
|
692 // POLICY: If a write has already been delayed, it will be started immediately if the requested |
|
693 // turnaround time is elapsed else will only start after it is elapsed. |
|
694 { |
|
695 LOG(("TurnaroundClear()")); |
|
696 TInt r = KErrNone; |
|
697 TUint delta = 0; |
|
698 |
|
699 if(iTurnaroundTimerStartTimeValid == 1) |
|
700 { |
|
701 //Calculate the turnaround time elapsed so far. |
|
702 delta = (NKern::TickCount() - iTurnaroundTimerStartTime) * NKern::TickPeriod(); |
|
703 } |
|
704 if(delta < iTurnaroundMicroSeconds) |
|
705 { |
|
706 iTurnaroundMinMilliSeconds = (iTurnaroundMicroSeconds - delta)/1000; |
|
707 iTurnaroundTimerStartTimeValid = 3; //Just to make sure that the turnaround timer start time is not captured. |
|
708 RestartTurnaroundTimer(); |
|
709 } |
|
710 else |
|
711 { |
|
712 if(TurnaroundStopTimer()) |
|
713 { |
|
714 // if a write is waiting, start a DFC to run it |
|
715 TurnaroundStartDfcImplementation(EFalse); |
|
716 } |
|
717 } |
|
718 iTurnaroundMinMilliSeconds = 0; |
|
719 return r; |
|
720 } |
|
721 |
|
722 TInt DChannelComm::RestartTurnaroundTimer() |
|
723 { |
|
724 LOG(("RestartTurnaroundTimer()")); |
|
725 TInt r=KErrNone; |
|
726 |
|
727 // POLICY: if timer is running from a previous read, stop it and re-start it |
|
728 TInt irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
729 TBool cancelDfcs = (iTurnaroundMinMilliSeconds > 0) && iTurnaroundTimerRunning; |
|
730 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
731 if (cancelDfcs) |
|
732 { |
|
733 iTurnaroundTimer.Cancel(); |
|
734 iTurnaroundDfc.Cancel(); |
|
735 } |
|
736 |
|
737 // Start the timer & update driver state to reflect that the timer is running |
|
738 TInt timeout = 0; |
|
739 irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
740 if(iTurnaroundMinMilliSeconds > 0) |
|
741 { |
|
742 iTurnaroundTimerRunning = ETrue; |
|
743 timeout = NKern::TimerTicks(iTurnaroundMinMilliSeconds); |
|
744 //Record the time stamp of turnaround timer start |
|
745 if(iTurnaroundTimerStartTimeValid != 3) |
|
746 iTurnaroundTimerStartTime = NKern::TickCount(); |
|
747 iTurnaroundTimerStartTimeValid = 1; |
|
748 } |
|
749 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
750 if (timeout) |
|
751 r=iTurnaroundTimer.OneShot(timeout); |
|
752 return r; |
|
753 } |
|
754 |
|
755 void DChannelComm::TurnaroundStartDfc(TAny* aSelf) |
|
756 { |
|
757 DChannelComm* self = (DChannelComm*)aSelf; |
|
758 self->TurnaroundStartDfcImplementation(ETrue); // in ISR so Irqs are already disabled |
|
759 } |
|
760 |
|
761 void DChannelComm::TurnaroundStartDfcImplementation(TBool aInIsr) |
|
762 { |
|
763 LOG(("TurnaroundStartDfcImplementation(inIsr=%d)", aInIsr)); |
|
764 TInt irq=0; |
|
765 if(!aInIsr) |
|
766 irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
767 else |
|
768 __SPIN_LOCK(iLock); |
|
769 |
|
770 iTurnaroundTimerRunning = EFalse; |
|
771 if(iTurnaroundTransmitDelayed || iTurnaroundBreakDelayed) |
|
772 { |
|
773 if(aInIsr) |
|
774 iTurnaroundDfc.Add(); |
|
775 else |
|
776 { |
|
777 if(!aInIsr) |
|
778 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
779 else |
|
780 __SPIN_UNLOCK(iLock); |
|
781 iTurnaroundDfc.Enque(); |
|
782 return; |
|
783 } |
|
784 } |
|
785 if(!aInIsr) |
|
786 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
787 else |
|
788 __SPIN_UNLOCK(iLock); |
|
789 } |
|
790 |
|
791 void DChannelComm::TurnaroundTimeout(TAny* aSelf) |
|
792 { |
|
793 DChannelComm* self = (DChannelComm*)aSelf; |
|
794 self->TurnaroundTimeoutImplementation(); |
|
795 } |
|
796 |
|
797 void DChannelComm::TurnaroundTimeoutImplementation() |
|
798 { |
|
799 LOG(("TurnaroundTimeoutImplementation()")); |
|
800 TInt irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
801 |
|
802 if(iTurnaroundBreakDelayed) |
|
803 { |
|
804 iTurnaroundBreakDelayed=EFalse; |
|
805 if (iStatus==EClosed) |
|
806 { |
|
807 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
808 Complete(EBreak, KErrNotReady); |
|
809 return; |
|
810 } |
|
811 else if(IsLineFail(iFailSignals)) // have signals changed in the meantime? |
|
812 { |
|
813 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
814 Complete(EBreak, KErrCommsLineFail); // protected -> changed in signals ISR |
|
815 return; |
|
816 } |
|
817 if (iTurnaroundTransmitDelayed) |
|
818 { |
|
819 //delay write by break instead of turnaround |
|
820 iBreakDelayedTx = ETrue; |
|
821 iTurnaroundTransmitDelayed=EFalse; |
|
822 } |
|
823 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
824 BreakOn(); |
|
825 } |
|
826 else if(iTurnaroundTransmitDelayed) |
|
827 { |
|
828 iTurnaroundTransmitDelayed = EFalse; // protected -> prevent reentrant ISR |
|
829 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
830 |
|
831 RestartDelayedTransmission(); |
|
832 } |
|
833 else |
|
834 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
835 } |
|
836 |
|
837 void DChannelComm::ResetBuffers(TBool aResetTx) |
|
838 // |
|
839 // Reset the receive and maybe the transmit buffer. |
|
840 // |
|
841 { |
|
842 LOG(("ResetBuffers(aResetTx=%d)", aResetTx)); |
|
843 TInt irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
844 iRxPutIndex=0; |
|
845 iRxGetIndex=0; |
|
846 iRxBufCompleteIndex=0; |
|
847 if (aResetTx) |
|
848 { |
|
849 iTxPutIndex=0; |
|
850 iTxGetIndex=0; |
|
851 } |
|
852 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
853 |
|
854 if (iStatus==EActive) |
|
855 ReleaseFlowControl(); |
|
856 iInputHeld=EFalse; |
|
857 } |
|
858 |
|
859 TInt DChannelComm::TransmitIsr() |
|
860 // |
|
861 // Return the next character to be transmitted to the ISR |
|
862 // |
|
863 { |
|
864 TInt tChar=iJamChar; // Look for control character to jam in |
|
865 if (tChar>=0) // Control character to send |
|
866 { |
|
867 iJamChar=KTxNoChar; |
|
868 } |
|
869 else if (!iOutputHeld && iTxGetIndex!=iTxPutIndex) |
|
870 { |
|
871 // Get spinlock, disable interrupts to ensure we can reach the unlock |
|
872 // statement. An FIQ before unlock that attempted to get lock would |
|
873 // lead to CPU deadlock |
|
874 TInt irqstate = __SPIN_LOCK_IRQSAVE(iLock); |
|
875 |
|
876 // output not held and buffer not empty, get next char |
|
877 tChar=iTxBuffer[iTxGetIndex++]; |
|
878 if (iTxGetIndex==iTxBufSize) |
|
879 iTxGetIndex=0; |
|
880 |
|
881 __SPIN_UNLOCK_IRQRESTORE(iLock, irqstate); |
|
882 } |
|
883 |
|
884 return tChar; |
|
885 } |
|
886 |
|
887 void DChannelComm::ReceiveIsr(TUint* aChar, TInt aCount, TInt aXonXoff) |
|
888 // |
|
889 // Handle received character block from the ISR. |
|
890 // aChar points to received characters, aCount=number received, |
|
891 // aXonXoff=1 if XON received, -1 if XOFF received, 0 if neither |
|
892 // |
|
893 { |
|
894 if (aXonXoff>0) |
|
895 { |
|
896 iOutputHeld &= ~KXoffSignal; // Mark output ok. for XON/XOFF |
|
897 if (iOutputHeld==0) |
|
898 EnableTransmit(); |
|
899 } |
|
900 else if (aXonXoff<0) |
|
901 { |
|
902 iOutputHeld |= KXoffSignal; // Mark output held for XON/XOFF |
|
903 } |
|
904 if (aCount==0) // if only XON or XOFF received |
|
905 return; |
|
906 |
|
907 // Get spinlock, disable interrupts to ensure we can reach the unlock |
|
908 // statement. An FIQ before unlock that attempted to get lock would |
|
909 // lead to CPU deadlock |
|
910 TInt irqstate = __SPIN_LOCK_IRQSAVE(iLock); |
|
911 |
|
912 TInt count = RxCount(); |
|
913 iReceived++; |
|
914 |
|
915 // At or above the high water mark send xoff every other character |
|
916 if (count>=iFlowControlUpperThreshold && ((count&1)!=0 || aCount>1)) |
|
917 AssertFlowControl(); |
|
918 |
|
919 TUint* pE=aChar+aCount; |
|
920 TInt e=KErrNone; |
|
921 TInt i=iRxPutIndex; |
|
922 TInt g=iRxGetIndex; |
|
923 TInt s=iRxBufSize; |
|
924 g=g?g-1:s-1; |
|
925 TInt p=iRxOutstanding?-1:0; |
|
926 TInt thresh=iRxBufReq.iLen-iRxDesPos; |
|
927 while(aChar<pE) |
|
928 { |
|
929 TUint c=*aChar++; |
|
930 |
|
931 // Check for parity errors and replace char if so configured. |
|
932 if (c & KReceiveIsrParityError) |
|
933 { |
|
934 // Replace bad character |
|
935 if (iConfig.iParityError==KConfigParityErrorReplaceChar) |
|
936 c = c & ~(0xff|KReceiveIsrParityError) | iConfig.iParityErrorChar; |
|
937 // Ignore parity error |
|
938 if (iConfig.iParityError==KConfigParityErrorIgnore) |
|
939 c = c & ~KReceiveIsrParityError; |
|
940 } |
|
941 |
|
942 if (i!=g) |
|
943 { |
|
944 iRxCharBuf[i]=(TUint8)c; |
|
945 iRxErrorBuf[i]=(TUint8)(c>>24); |
|
946 |
|
947 if (c & KReceiveIsrMaskError) |
|
948 { |
|
949 __UART_RX_ERROR(c); |
|
950 if (c & KReceiveIsrOverrunError) |
|
951 e = KErrCommsOverrun; |
|
952 else if (c & KReceiveIsrBreakError) |
|
953 e = KErrCommsBreak; |
|
954 else if (c & KReceiveIsrFrameError) |
|
955 e = KErrCommsFrame; |
|
956 else if (c & KReceiveIsrParityError) |
|
957 e = KErrCommsParity; |
|
958 } |
|
959 count++; |
|
960 if (++i==s) |
|
961 i=0; |
|
962 if (p<0) |
|
963 { |
|
964 if (e || IsTerminator(TUint8(c)) || count==thresh) |
|
965 { |
|
966 // need to complete client request |
|
967 iRxError = e; |
|
968 p=i; |
|
969 } |
|
970 } |
|
971 } |
|
972 else |
|
973 { |
|
974 __OVERRUN(); |
|
975 // buffer overrun, discard character |
|
976 e=KErrCommsOverrun; |
|
977 |
|
978 // make sure client is informed of overrun error |
|
979 iRxError=e; |
|
980 |
|
981 // discard remaining characters and complete |
|
982 p=i; |
|
983 break; |
|
984 } |
|
985 } |
|
986 iRxPutIndex=i; |
|
987 |
|
988 if (iRxOutstanding) |
|
989 { |
|
990 if (p>=0) |
|
991 { |
|
992 // need to complete client request |
|
993 iRxBufCompleteIndex=p; |
|
994 iRxOutstanding=EFalse; |
|
995 RxComplete(); |
|
996 } |
|
997 else if (count>=iRxDrainThreshold) |
|
998 { |
|
999 // drain buffer but don't complete |
|
1000 DrainRxBuffer(); |
|
1001 } |
|
1002 else if (iRxOneOrMore<0) |
|
1003 { |
|
1004 // doing read one or more - drain the buffer |
|
1005 // this will start the timer |
|
1006 iRxOneOrMore=1; |
|
1007 DrainRxBuffer(); |
|
1008 } |
|
1009 } |
|
1010 |
|
1011 __SPIN_UNLOCK_IRQRESTORE(iLock, irqstate); |
|
1012 |
|
1013 if (iNotifyData) |
|
1014 { |
|
1015 iNotifyData=EFalse; |
|
1016 RxComplete(); |
|
1017 } |
|
1018 } |
|
1019 |
|
1020 void DChannelComm::CheckTxBuffer() |
|
1021 { |
|
1022 // if buffer count < threshold, fill from client buffer |
|
1023 TInt count=TxCount(); |
|
1024 if (iTxOutstanding && iTxDesPos<iTxBufReq.iLen && count<iTxFillThreshold) |
|
1025 iTxFillDfc.Add(); |
|
1026 else if (count==0) |
|
1027 { |
|
1028 // TX buffer is now empty - see if we need to complete anything |
|
1029 if (iTxOutstanding) |
|
1030 { |
|
1031 if (iTxBufReq.iLen==0) |
|
1032 { |
|
1033 // request was a zero-length write - complete if hardware flow control |
|
1034 // is not asserted |
|
1035 if ((~iSignals & iHoldSignals)==0) |
|
1036 { |
|
1037 iTxOutstanding=EFalse; |
|
1038 TxComplete(); |
|
1039 } |
|
1040 } |
|
1041 else |
|
1042 { |
|
1043 // request was normal TX - complete now if not doing early completion |
|
1044 if (!(iConfig.iHandshake&KConfigWriteBufferedComplete)) |
|
1045 { |
|
1046 iTxOutstanding=EFalse; |
|
1047 TxComplete(); |
|
1048 } |
|
1049 } |
|
1050 } |
|
1051 } |
|
1052 } |
|
1053 |
|
1054 |
|
1055 // |
|
1056 // Pdd callback |
|
1057 // |
|
1058 void DChannelComm::UpdateSignals(TUint aSignals) |
|
1059 { |
|
1060 __KTRACE_OPT(KHARDWARE,Kern::Printf("CommSig: Upd %08x",aSignals)); |
|
1061 iSignals=(iSignals&~KDTEInputSignals)|(aSignals&KDTEInputSignals); |
|
1062 DoSigNotify(); |
|
1063 } |
|
1064 |
|
1065 |
|
1066 |
|
1067 /** |
|
1068 Handle a state change from the PDD. Called in ISR or DFC context. |
|
1069 */ |
|
1070 void DChannelComm::StateIsr(TUint aSignals) |
|
1071 { |
|
1072 iSignals=(iSignals&~KDTEInputSignals)|(aSignals&KDTEInputSignals); |
|
1073 if (iSignalsReq->IsReady() && ((iSignals^iNotifiedSignals)&iSigNotifyMask) ) |
|
1074 { |
|
1075 iSigNotifyDfc.Add(); |
|
1076 } |
|
1077 if (IsLineFail(iFailSignals)) |
|
1078 { |
|
1079 if (iRxOutstanding) |
|
1080 { |
|
1081 iRxError=KErrCommsLineFail; |
|
1082 iRxBufCompleteIndex=iRxPutIndex; |
|
1083 iRxOutstanding=EFalse; |
|
1084 RxComplete(); |
|
1085 } |
|
1086 if (iTxOutstanding) |
|
1087 { |
|
1088 iTxError = KErrCommsLineFail; |
|
1089 iTxOutstanding=EFalse; |
|
1090 TxComplete(); |
|
1091 } |
|
1092 } |
|
1093 |
|
1094 // |
|
1095 // Now we must determine if output is to be held |
|
1096 // |
|
1097 TUint status = ~iSignals & iHoldSignals; |
|
1098 if (iOutputHeld & KXoffSignal) |
|
1099 status |= KXoffSignal; // Leave the xon/xoff handshake bit |
|
1100 |
|
1101 LOG(("State - ISR - 0x%x",status)); |
|
1102 iOutputHeld=status; // record new flow control state |
|
1103 if (iTxGetIndex==iTxPutIndex) |
|
1104 { |
|
1105 // Tx buffer is empty |
|
1106 if (iTxOutstanding && iTxBufReq.iLen==0 && (status&~KXoffSignal)==0) |
|
1107 { |
|
1108 // if hardware flow control released, complete zero-length write |
|
1109 iTxOutstanding=EFalse; |
|
1110 TxComplete(); |
|
1111 } |
|
1112 } |
|
1113 else if (status==0) |
|
1114 { |
|
1115 // Tx buffer not empty and flow control released, so restart transmission |
|
1116 LOG(("Calling LDD:EnTx")); |
|
1117 EnableTransmit(); |
|
1118 } |
|
1119 } |
|
1120 |
|
1121 // check if transmitter is flow controlled |
|
1122 void DChannelComm::CheckOutputHeld() |
|
1123 { |
|
1124 iOutputHeld=(iOutputHeld & KXoffSignal) | (~iSignals & iHoldSignals); |
|
1125 LOG(("CheckOPH IOH = %d",iOutputHeld)); |
|
1126 } |
|
1127 |
|
1128 void DChannelComm::HandleMsg(TMessageBase* aMsg) |
|
1129 { |
|
1130 |
|
1131 if (iStandby) |
|
1132 { // postpone message handling to transition from standby |
|
1133 iMsgHeld=ETrue; |
|
1134 return; |
|
1135 } |
|
1136 |
|
1137 TThreadMessage& m=*(TThreadMessage*)aMsg; |
|
1138 LOG(("HandleMsg(%x a1=%x, a2=%x)", m.iValue, m.Int1(), m.Int2())); |
|
1139 TInt id=m.iValue; |
|
1140 if (id==(TInt)ECloseMsg) |
|
1141 { |
|
1142 Shutdown(); |
|
1143 iStatus = EClosed; |
|
1144 m.Complete(KErrNone, EFalse); |
|
1145 return; |
|
1146 } |
|
1147 else if (id==KMaxTInt) |
|
1148 { |
|
1149 // DoCancel |
|
1150 DoCancel(m.Int0()); |
|
1151 m.Complete(KErrNone,ETrue); |
|
1152 return; |
|
1153 } |
|
1154 |
|
1155 if (id<0) |
|
1156 { |
|
1157 // DoRequest |
|
1158 DoRequest(~id,m.Ptr1(),m.Ptr2()); |
|
1159 m.Complete(KErrNone,ETrue); |
|
1160 } |
|
1161 else |
|
1162 { |
|
1163 // DoControl |
|
1164 TInt r=DoControl(id,m.Ptr0(),m.Ptr1()); |
|
1165 m.Complete(r,ETrue); |
|
1166 } |
|
1167 } |
|
1168 |
|
1169 void DChannelComm::DoCancel(TInt aMask) |
|
1170 // |
|
1171 // Cancel an outstanding request. |
|
1172 // |
|
1173 { |
|
1174 LOG(("DoCancel(%d)", aMask)); |
|
1175 if (aMask & RBusDevComm::ERequestReadCancel) |
|
1176 { |
|
1177 TInt irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
1178 iRxOutstanding=EFalse; |
|
1179 iNotifyData=EFalse; |
|
1180 iRxDesPos=0; |
|
1181 iRxBufReq.iLen=0; |
|
1182 iRxError=KErrNone; |
|
1183 iRxOneOrMore=0; |
|
1184 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
1185 iRxCompleteDfc.Cancel(); |
|
1186 iRxDrainDfc.Cancel(); |
|
1187 iTimer.Cancel(); |
|
1188 iTimerDfc.Cancel(); |
|
1189 Complete(ERx,KErrCancel); |
|
1190 } |
|
1191 if (aMask & RBusDevComm::ERequestWriteCancel) |
|
1192 { |
|
1193 TInt irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
1194 iTurnaroundTransmitDelayed = EFalse; |
|
1195 iTxPutIndex=0; |
|
1196 iTxGetIndex=0; |
|
1197 iTxOutstanding=EFalse; |
|
1198 iTxDesPos=0; |
|
1199 iTxBufReq.iLen=0; |
|
1200 iTxError=KErrNone; |
|
1201 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
1202 iTxCompleteDfc.Cancel(); |
|
1203 iTxFillDfc.Cancel(); |
|
1204 Complete(ETx,KErrCancel); |
|
1205 } |
|
1206 if (aMask & RBusDevComm::ERequestNotifySignalChangeCancel) |
|
1207 { |
|
1208 iSigNotifyDfc.Cancel(); |
|
1209 Complete(ESigChg,KErrCancel); |
|
1210 } |
|
1211 if (aMask & RBusDevComm::ERequestBreakCancel) |
|
1212 { |
|
1213 TInt irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
1214 if (iTurnaroundBreakDelayed) |
|
1215 iTurnaroundBreakDelayed=EFalse; |
|
1216 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
1217 |
|
1218 iBreakDfc.Cancel(); |
|
1219 iBreakTimer.Cancel(); |
|
1220 FinishBreakImplementation(KErrCancel); |
|
1221 } |
|
1222 } |
|
1223 |
|
1224 /** |
|
1225 Intercept messages in client context before they are sent to the DFC queue |
|
1226 */ |
|
1227 TInt DChannelComm::SendMsg(TMessageBase* aMsg) |
|
1228 { |
|
1229 TInt r = KErrNone; |
|
1230 TInt max; |
|
1231 TInt len = 0; |
|
1232 TThreadMessage* m = (TThreadMessage*)aMsg; |
|
1233 |
|
1234 // Handle ECloseMsg & Cancel |
|
1235 TInt id=aMsg->iValue; |
|
1236 if (id==(TInt)ECloseMsg || id==KMaxTInt) |
|
1237 { |
|
1238 LOG(("SendMsg(%s)", (id==KMaxTInt)?"Cancel":"ECloseMsg")); |
|
1239 // do nothing cos these are handled on the DFC side |
|
1240 } |
|
1241 |
|
1242 // Handle control messages that access user memory here in client context |
|
1243 else if (id >= 0) |
|
1244 { |
|
1245 TAny* a1 = m->iArg[0]; |
|
1246 switch (aMsg->iValue) |
|
1247 { |
|
1248 case RBusDevComm::EControlConfig: |
|
1249 { |
|
1250 LOG(("SendMsg(EControlConfig, %x)", a1)); |
|
1251 TPtrC8 cfg((const TUint8*)&iConfig,sizeof(iConfig)); |
|
1252 return Kern::ThreadDesWrite(iClient,a1,cfg,0,KTruncateToMaxLength,iClient); |
|
1253 } |
|
1254 case RBusDevComm::EControlSetConfig: |
|
1255 { |
|
1256 LOG(("SendMsg(EControlSetConfig, %x)", a1)); |
|
1257 if (AreAnyPending()) |
|
1258 ; // r = ESetConfigWhileRequestPending; |
|
1259 else |
|
1260 r = Kern::PinVirtualMemory(iPinObjSetConfig, (TLinAddr)a1, sizeof(TCommConfigV01)); |
|
1261 } |
|
1262 break; |
|
1263 case RBusDevComm::EControlCaps: |
|
1264 { |
|
1265 LOG(("SendMsg(EControlCaps, %x)", a1)); |
|
1266 TCommCaps2 caps; |
|
1267 PddCaps(caps); |
|
1268 return Kern::ThreadDesWrite(iClient,a1,caps,0,KTruncateToMaxLength,iClient); |
|
1269 } |
|
1270 default: |
|
1271 // Allow other control messages to go to DFC thread |
|
1272 LOG(("SendMsg(Ctrl %d, %x)", aMsg->iValue, a1)); |
|
1273 break; |
|
1274 } |
|
1275 } |
|
1276 |
|
1277 |
|
1278 // Handle requests |
|
1279 else |
|
1280 { |
|
1281 TRequestStatus* status = (TRequestStatus*)m->iArg[0]; |
|
1282 TAny* a1 = m->iArg[1]; |
|
1283 TAny* a2 = m->iArg[2]; |
|
1284 TInt reqNo = ~aMsg->iValue; |
|
1285 TInt irq; |
|
1286 switch (reqNo) |
|
1287 { |
|
1288 case RBusDevComm::ERequestRead: |
|
1289 { |
|
1290 iNotifyData=EFalse; |
|
1291 // If client has *not* provided a buffer pointer, it means they only want |
|
1292 // to know when data becomes available. |
|
1293 if (!a1) |
|
1294 { |
|
1295 irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
1296 TBool isEmpty = (iRxPutIndex==iRxGetIndex); |
|
1297 iNotifyData = isEmpty; |
|
1298 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
1299 if (!isEmpty) // if Rx buffer has bytes in it we can complete the request immediately |
|
1300 { |
|
1301 Kern::RequestComplete(status, KErrNone); |
|
1302 return KErrNone; |
|
1303 } |
|
1304 // Do not start the Turnaround timer as this is not a Read request but a request for Data Available notification |
|
1305 LOG(("--Buf Empty--")); |
|
1306 } |
|
1307 |
|
1308 // Get buffer length if one has been given |
|
1309 if (a2) |
|
1310 r = Kern::ThreadRawRead(iClient,a2,&len,sizeof(len)); |
|
1311 |
|
1312 // Check the client descriptor is valid and large enough to hold the required amount of data. |
|
1313 if (a1 && r==KErrNone) |
|
1314 { |
|
1315 max = Kern::ThreadGetDesMaxLength(iClient, a1); |
|
1316 if (max<Abs(len) || max<0) |
|
1317 r = KErrGeneral; // do not start the Turnaround timer (invalid Descriptor this read never starts) |
|
1318 } |
|
1319 |
|
1320 LOG(("SendMsg(ERequestRead, %x, len=%d) max=%d r=%d", a1, len, max, r)); |
|
1321 |
|
1322 // Set client descriptor length to zero & set up client buffer object |
|
1323 if (a1 && r==KErrNone) |
|
1324 { |
|
1325 TPtrC8 p(NULL,0); |
|
1326 r = Kern::ThreadDesWrite(iClient,a1,p,0,0,iClient); |
|
1327 if (r == KErrNone) |
|
1328 r = iRxBufReq.Setup(status, a1, len); |
|
1329 } |
|
1330 } |
|
1331 break; |
|
1332 |
|
1333 |
|
1334 // |
|
1335 // ERequestWrite |
|
1336 // |
|
1337 case RBusDevComm::ERequestWrite: |
|
1338 if (iStatus==EClosed) |
|
1339 r = KErrNotReady; |
|
1340 else if (!a1) |
|
1341 r = KErrArgument; |
|
1342 else |
|
1343 r=Kern::ThreadRawRead(iClient, a2, &len, sizeof(len)); |
|
1344 LOG(("SendMsg(ERequestWrite, %x, len=%d) r=%d", a1, len, r)); |
|
1345 |
|
1346 // Setup pending client request for this write |
|
1347 if (r==KErrNone) |
|
1348 r = iTxBufReq.Setup(status, a1, len); |
|
1349 break; |
|
1350 |
|
1351 |
|
1352 // |
|
1353 // ERequestBreak: a1 points to the number of microseconds to break for |
|
1354 // |
|
1355 case RBusDevComm::ERequestBreak: |
|
1356 r = Kern::ThreadRawRead(iClient, a1, &iBreakTimeMicroSeconds, sizeof(TInt)); |
|
1357 if (r == KErrNone) |
|
1358 r = iBreakStatus->SetStatus(status); |
|
1359 LOG(("SendMsg(ERequestBreak, %x) bktime=%d r=%d", a1, iBreakTimeMicroSeconds, r)); |
|
1360 break; |
|
1361 |
|
1362 |
|
1363 // |
|
1364 // ERequestNotifySignalChange: a1 points to user-side int to receive the signals bitmask |
|
1365 // a2 points to the bitmask of signals the user is interested in |
|
1366 // |
|
1367 case RBusDevComm::ERequestNotifySignalChange: |
|
1368 LOG(("SendMsg(ERequestNotifySignalChange, %x, %x)", a1, a2)); |
|
1369 if (!a1 || !a2) |
|
1370 { |
|
1371 r = KErrArgument; |
|
1372 break; |
|
1373 } |
|
1374 // Setup word-sized client buffer |
|
1375 r = Kern::ThreadRawRead(iClient,a2,&iSigNotifyMask,sizeof(TUint)); |
|
1376 irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
1377 if (r==KErrNone) |
|
1378 { |
|
1379 r = iSignalsReq->SetStatus(status); |
|
1380 if (r==KErrNone) |
|
1381 iSignalsReq->SetDestPtr(a1); |
|
1382 } |
|
1383 LOG(("ERequestNotifySignalChange: mask is %x, r is %d", iSigNotifyMask, r)); |
|
1384 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
1385 break; |
|
1386 |
|
1387 |
|
1388 // Unknown request |
|
1389 default: |
|
1390 LOG(("SendMsg(req %d, %x, %x)", reqNo, a1, a2)); |
|
1391 r = KErrNotSupported; |
|
1392 break; |
|
1393 |
|
1394 } |
|
1395 |
|
1396 // If the request has an error, complete immediately |
|
1397 if (r!=KErrNone) |
|
1398 Kern::RequestComplete(status, r); |
|
1399 } |
|
1400 |
|
1401 // Send the client request to the DFC queue unless there's been an error |
|
1402 if (r==KErrNone) |
|
1403 r = DLogicalChannel::SendMsg(aMsg); |
|
1404 LOG(("<SendMsg ret %d", r)); |
|
1405 return r; |
|
1406 |
|
1407 } |
|
1408 |
|
1409 |
|
1410 /** |
|
1411 Handle asynchronous requests. Called in DFC context. |
|
1412 */ |
|
1413 void DChannelComm::DoRequest(TInt aReqNo, TAny* a1, TAny* a2) |
|
1414 { |
|
1415 LOG(("DoRequest(%d %x %x)", aReqNo, a1, a2)); |
|
1416 |
|
1417 // |
|
1418 // First check if we have started |
|
1419 // |
|
1420 if (iStatus==EOpen) |
|
1421 { |
|
1422 Start(); |
|
1423 CheckOutputHeld(); |
|
1424 SetSignals(iAutoSignals,0); |
|
1425 LOG(("DReq- RFC")); |
|
1426 ReleaseFlowControl(); |
|
1427 } |
|
1428 // |
|
1429 // Check for a line fail |
|
1430 // |
|
1431 if (IsLineFail(iFailSignals)) |
|
1432 { |
|
1433 Complete(EAll, KErrCommsLineFail); |
|
1434 return; |
|
1435 } |
|
1436 |
|
1437 // |
|
1438 // Now we can dispatch the async request |
|
1439 // |
|
1440 switch (aReqNo) |
|
1441 { |
|
1442 case RBusDevComm::ERequestRead: |
|
1443 InitiateRead(iRxBufReq.iLen); |
|
1444 break; |
|
1445 |
|
1446 case RBusDevComm::ERequestWrite: |
|
1447 { |
|
1448 |
|
1449 // See if we need to delay the write |
|
1450 TInt irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
1451 iTurnaroundTransmitDelayed = iTurnaroundTimerRunning!=0; |
|
1452 iBreakDelayedTx = (iFlags & KBreaking); |
|
1453 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
1454 |
|
1455 // If we do need to delay the write |
|
1456 if (iTurnaroundTransmitDelayed || iBreakDelayedTx) |
|
1457 break; |
|
1458 |
|
1459 // |
|
1460 InitiateWrite(); |
|
1461 break; |
|
1462 } |
|
1463 |
|
1464 case RBusDevComm::ERequestNotifySignalChange: |
|
1465 iNotifiedSignals = iSignals; |
|
1466 DoSigNotify(); |
|
1467 break; |
|
1468 |
|
1469 case RBusDevComm::ERequestBreak: |
|
1470 if(iTurnaroundTimerRunning) |
|
1471 iTurnaroundBreakDelayed = ETrue; |
|
1472 else |
|
1473 BreakOn(); |
|
1474 break; |
|
1475 |
|
1476 } |
|
1477 } |
|
1478 |
|
1479 /** |
|
1480 Called in DFC context upon receipt of ERequestRead |
|
1481 */ |
|
1482 void DChannelComm::InitiateRead(TInt aLength) |
|
1483 { |
|
1484 LOG(("InitiateRead(%d)", aLength)); |
|
1485 iRxOutstanding=EFalse; |
|
1486 iRxOneOrMore=0; |
|
1487 |
|
1488 // Complete zero-length read immediately |
|
1489 if (aLength==0) |
|
1490 { |
|
1491 iRxBufReq.Complete(iClient, KErrNone); |
|
1492 RestartTurnaroundTimer(); |
|
1493 return; |
|
1494 } |
|
1495 |
|
1496 TBool length_negative = (aLength<0); |
|
1497 if (length_negative) |
|
1498 aLength = -aLength; |
|
1499 iRxBufReq.iLen=aLength; |
|
1500 |
|
1501 // If the RX buffer is empty, we must wait for more data |
|
1502 TInt irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
1503 if (iRxPutIndex==iRxGetIndex) |
|
1504 { |
|
1505 if (length_negative) |
|
1506 iRxOneOrMore=-1; // -1 because timer not started |
|
1507 iRxOutstanding=ETrue; |
|
1508 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
1509 return; |
|
1510 } |
|
1511 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
1512 |
|
1513 // RX buffer contains characters, must scan buffer and then complete |
|
1514 if (length_negative) |
|
1515 { |
|
1516 // ReceiveOneOrMore, up to -aLength characters |
|
1517 iRxOneOrMore=1; |
|
1518 } |
|
1519 TInt getIndex=iRxGetIndex; |
|
1520 TInt count=0; |
|
1521 TUint stat=0; |
|
1522 TBool complete=EFalse; |
|
1523 while(!complete) |
|
1524 { |
|
1525 while(count<aLength && getIndex!=iRxPutIndex) |
|
1526 { |
|
1527 if ((stat=iRxErrorBuf[getIndex])!=0 || IsTerminator(iRxCharBuf[getIndex])) |
|
1528 { |
|
1529 // this character will complete the request |
|
1530 if (++getIndex==iRxBufSize) |
|
1531 getIndex=0; |
|
1532 count++; |
|
1533 complete=ETrue; |
|
1534 break; |
|
1535 } |
|
1536 if (++getIndex==iRxBufSize) |
|
1537 getIndex=0; |
|
1538 count++; |
|
1539 } |
|
1540 if (count==aLength) |
|
1541 complete=ETrue; |
|
1542 if (!complete) |
|
1543 { |
|
1544 TInt irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
1545 if (getIndex==iRxPutIndex) |
|
1546 { |
|
1547 // not enough chars to complete request, so set up to wait for more |
|
1548 iRxOutstanding=ETrue; |
|
1549 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
1550 if (count) |
|
1551 DoDrainRxBuffer(getIndex); |
|
1552 return; |
|
1553 } |
|
1554 // more characters have arrived, loop again |
|
1555 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
1556 } |
|
1557 } |
|
1558 |
|
1559 // can complete request right now |
|
1560 TInt e=KErrNone; |
|
1561 if (stat) |
|
1562 { |
|
1563 stat<<=24; |
|
1564 if (stat & KReceiveIsrOverrunError) |
|
1565 e = KErrCommsOverrun; |
|
1566 else if (stat & KReceiveIsrBreakError) |
|
1567 e = KErrCommsBreak; |
|
1568 else if (stat & KReceiveIsrFrameError) |
|
1569 e = KErrCommsFrame; |
|
1570 else if (stat & KReceiveIsrParityError) |
|
1571 e = KErrCommsParity; |
|
1572 } |
|
1573 if (iRxError==KErrNone) |
|
1574 iRxError=e; |
|
1575 iRxBufCompleteIndex=getIndex; |
|
1576 DoCompleteRx(); |
|
1577 } |
|
1578 |
|
1579 /** |
|
1580 Called in DFC context to start a write or a delayed write |
|
1581 */ |
|
1582 void DChannelComm::InitiateWrite() |
|
1583 { |
|
1584 LOG(("InitiateWrite() len=%d", iTxBufReq.iLen)); |
|
1585 |
|
1586 |
|
1587 TInt irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
1588 iTxDesPos=0; |
|
1589 iTurnaroundTimerStartTime = 0; |
|
1590 iTurnaroundTimerStartTimeValid = 2; |
|
1591 if (~iSignals & iFailSignals) |
|
1592 { |
|
1593 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
1594 iTxBufReq.Complete(iClient, KErrCommsLineFail); |
|
1595 return; |
|
1596 } |
|
1597 if (iTxBufReq.iLen==0) |
|
1598 { |
|
1599 if (iTxPutIndex==iTxGetIndex && (~iSignals & iHoldSignals)==0) |
|
1600 { |
|
1601 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
1602 iTxBufReq.Complete(iClient, KErrNone); |
|
1603 return; |
|
1604 } |
|
1605 } |
|
1606 |
|
1607 iTxOutstanding=ETrue; |
|
1608 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
1609 if (iTxBufReq.iLen!=0) |
|
1610 DoFillTxBuffer(); |
|
1611 } |
|
1612 |
|
1613 void DChannelComm::SigNotifyDfc(TAny* aPtr) |
|
1614 { |
|
1615 ((DChannelComm*)aPtr)->DoSigNotify(); |
|
1616 } |
|
1617 |
|
1618 void DChannelComm::DoSigNotify() |
|
1619 { |
|
1620 // Atomically update iNotifiedSignals and prepare to signal |
|
1621 TBool do_notify = EFalse; |
|
1622 TInt irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
1623 TUint orig_sig=iNotifiedSignals; |
|
1624 if (iSignalsReq->IsReady() && ( iNotifiedSignals==0xffffffff || ((iSignals^iNotifiedSignals)&iSigNotifyMask) ) ) |
|
1625 { |
|
1626 iNotifiedSignals=iSignals; |
|
1627 do_notify=ETrue; |
|
1628 } |
|
1629 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
1630 __KTRACE_OPT(KHARDWARE,Kern::Printf("CommSig: Orig=%08x New %08x Mask %08x",orig_sig,iNotifiedSignals,iSigNotifyMask)); |
|
1631 if (do_notify) |
|
1632 { |
|
1633 TUint changed=iSigNotifyMask; |
|
1634 if (orig_sig!=0xffffffff) |
|
1635 changed&=(orig_sig^iNotifiedSignals); |
|
1636 changed=(changed<<12)|(iNotifiedSignals&iSigNotifyMask); |
|
1637 |
|
1638 // Write the result back to client memory and complete the request |
|
1639 __KTRACE_OPT(KHARDWARE,Kern::Printf("CommSig: Notify %08x",changed)); |
|
1640 LOG(("DoSigNotify: %08x",changed)); |
|
1641 TUint& rr = iSignalsReq->Data(); |
|
1642 rr = changed; |
|
1643 Kern::QueueRequestComplete(iClient, iSignalsReq, KErrNone); |
|
1644 } |
|
1645 } |
|
1646 |
|
1647 |
|
1648 /** |
|
1649 Manually read and act on signals |
|
1650 */ |
|
1651 void DChannelComm::UpdateAndProcessSignals() |
|
1652 { |
|
1653 TUint signals=Signals(); |
|
1654 TBool notify=EFalse; |
|
1655 TBool complete_rx=EFalse; |
|
1656 TBool complete_tx=EFalse; |
|
1657 TInt irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
1658 iSignals=(iSignals&~KDTEInputSignals)|(signals&KDTEInputSignals); |
|
1659 if (iSignalsReq->IsReady() && ((iSignals^iNotifiedSignals)&iSigNotifyMask) ) |
|
1660 { |
|
1661 notify=ETrue; |
|
1662 } |
|
1663 if (IsLineFail(iFailSignals)) |
|
1664 { |
|
1665 if (iRxOutstanding) |
|
1666 { |
|
1667 iRxError=KErrCommsLineFail; |
|
1668 iRxBufCompleteIndex=iRxPutIndex; |
|
1669 iRxOutstanding=EFalse; |
|
1670 complete_rx=ETrue; |
|
1671 } |
|
1672 if (iTxOutstanding) |
|
1673 { |
|
1674 iTxError = KErrCommsLineFail; |
|
1675 iTxOutstanding=EFalse; |
|
1676 complete_tx=ETrue; |
|
1677 } |
|
1678 } |
|
1679 // |
|
1680 // Now we must determine if output is to be held |
|
1681 // |
|
1682 TUint status = ~iSignals & iHoldSignals; |
|
1683 if (iOutputHeld & KXoffSignal) |
|
1684 status |= KXoffSignal; // Leave the xon/xoff handshake bit |
|
1685 |
|
1686 iOutputHeld=status; // record new flow control state |
|
1687 if (iTxGetIndex==iTxPutIndex) |
|
1688 { |
|
1689 // Tx buffer is empty |
|
1690 if (iTxOutstanding && iTxBufReq.iLen==0 && (status&~KXoffSignal)==0) |
|
1691 { |
|
1692 // if hardware flow control released, complete zero-length write |
|
1693 iTxOutstanding=EFalse; |
|
1694 complete_tx=ETrue; |
|
1695 } |
|
1696 } |
|
1697 else if (status==0) |
|
1698 { |
|
1699 // Tx buffer not empty and flow control released, so restart transmission |
|
1700 EnableTransmit(); |
|
1701 } |
|
1702 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
1703 if (notify) |
|
1704 DoSigNotify(); |
|
1705 if (complete_rx) |
|
1706 DoCompleteRx(); |
|
1707 if (complete_tx) |
|
1708 DoCompleteTx(); |
|
1709 } |
|
1710 |
|
1711 |
|
1712 TUint DChannelComm::FailSignals(TUint aHandshake) |
|
1713 { |
|
1714 TUint r=0; |
|
1715 if ((aHandshake&(KConfigObeyCTS|KConfigFailCTS))==(KConfigObeyCTS|KConfigFailCTS)) |
|
1716 r|=KSignalCTS; |
|
1717 if ((aHandshake&(KConfigObeyDSR|KConfigFailDSR))==(KConfigObeyDSR|KConfigFailDSR)) |
|
1718 r|=KSignalDSR; |
|
1719 if ((aHandshake&(KConfigObeyDCD|KConfigFailDCD))==(KConfigObeyDCD|KConfigFailDCD)) |
|
1720 r|=KSignalDCD; |
|
1721 return r; |
|
1722 } |
|
1723 |
|
1724 TUint DChannelComm::HoldSignals(TUint aHandshake) |
|
1725 { |
|
1726 TUint r=0; |
|
1727 if (aHandshake & KConfigObeyCTS) |
|
1728 r|=KSignalCTS; |
|
1729 if (aHandshake & KConfigObeyDSR) |
|
1730 r|=KSignalDSR; |
|
1731 if (aHandshake & KConfigObeyDCD) |
|
1732 r|=KSignalDCD; |
|
1733 return r; |
|
1734 } |
|
1735 |
|
1736 TUint DChannelComm::FlowControlSignals(TUint aHandshake) |
|
1737 { |
|
1738 TUint r=0; |
|
1739 if (!(aHandshake & KConfigFreeRTS)) |
|
1740 r|=KSignalRTS; |
|
1741 else if (!(aHandshake & KConfigFreeDTR)) |
|
1742 r|=KSignalDTR; |
|
1743 return r; |
|
1744 } |
|
1745 |
|
1746 TUint DChannelComm::AutoSignals(TUint aHandshake) |
|
1747 { |
|
1748 TUint r=0; |
|
1749 if (!(aHandshake & KConfigFreeRTS) && !(aHandshake & KConfigFreeDTR)) |
|
1750 r|=KSignalDTR; |
|
1751 return r; |
|
1752 } |
|
1753 |
|
1754 TInt DChannelComm::SetConfig(TCommConfigV01& c) |
|
1755 { |
|
1756 LOG(("SetConfig(...)")); |
|
1757 TBool restart = EFalse; |
|
1758 TBool purge = EFalse; |
|
1759 TBool changeTerminators=EFalse; |
|
1760 TInt irq; |
|
1761 TInt r; |
|
1762 |
|
1763 if(c.iTerminatorCount>KConfigMaxTerminators) |
|
1764 return KErrNotSupported; |
|
1765 if ((r=ValidateConfig(c))!=KErrNone) |
|
1766 return r; |
|
1767 TUint failSignals=FailSignals(c.iHandshake); |
|
1768 if (IsLineFail(failSignals)) |
|
1769 return KErrCommsLineFail; |
|
1770 if (iConfig.iRate != c.iRate |
|
1771 || iConfig.iDataBits != c.iDataBits |
|
1772 || iConfig.iStopBits != c.iStopBits |
|
1773 || iConfig.iParity != c.iParity |
|
1774 || iConfig.iFifo != c.iFifo |
|
1775 || iConfig.iSpecialRate != c.iSpecialRate |
|
1776 || iConfig.iSIREnable != c.iSIREnable |
|
1777 || iConfig.iSIRSettings != c.iSIRSettings) |
|
1778 { |
|
1779 restart = ETrue; |
|
1780 } |
|
1781 else if (iConfig.iParityErrorChar != c.iParityErrorChar |
|
1782 || iConfig.iParityError != c.iParityError |
|
1783 || iConfig.iXonChar != c.iXonChar |
|
1784 || iConfig.iXoffChar != c.iXoffChar |
|
1785 || (iConfig.iHandshake&(KConfigObeyXoff|KConfigSendXoff)) |
|
1786 != (c.iHandshake&(KConfigObeyXoff|KConfigSendXoff))) |
|
1787 { |
|
1788 purge = ETrue; |
|
1789 } |
|
1790 else |
|
1791 { |
|
1792 if (iConfig.iTerminatorCount==c.iTerminatorCount) |
|
1793 { |
|
1794 for (TInt i=0; i<iConfig.iTerminatorCount; i++) |
|
1795 { |
|
1796 if (iConfig.iTerminator[i]!=c.iTerminator[i]) |
|
1797 { |
|
1798 changeTerminators=ETrue; |
|
1799 break; |
|
1800 } |
|
1801 } |
|
1802 } |
|
1803 else |
|
1804 changeTerminators=ETrue; |
|
1805 if (!changeTerminators && c.iHandshake == iConfig.iHandshake) |
|
1806 return r; // nothing to do. |
|
1807 } |
|
1808 if (iStatus==EActive && (restart || purge)) |
|
1809 { |
|
1810 SetSignals(0,iFlowControlSignals|iAutoSignals); // Drop RTS |
|
1811 Stop(EStopNormal); |
|
1812 iStatus=EOpen; |
|
1813 if(purge) |
|
1814 ResetBuffers(ETrue); |
|
1815 iConfig=c; |
|
1816 iFailSignals=failSignals; |
|
1817 iHoldSignals=HoldSignals(c.iHandshake); |
|
1818 iFlowControlSignals=FlowControlSignals(c.iHandshake); |
|
1819 iAutoSignals=AutoSignals(c.iHandshake); |
|
1820 Start(); |
|
1821 CheckOutputHeld(); |
|
1822 SetSignals(iFlowControlSignals|iAutoSignals,0); // Assert RTS |
|
1823 irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
1824 } |
|
1825 else |
|
1826 { |
|
1827 irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
1828 if(purge) |
|
1829 ResetBuffers(ETrue); |
|
1830 iConfig=c; |
|
1831 iFailSignals=failSignals; |
|
1832 iHoldSignals=HoldSignals(c.iHandshake); |
|
1833 iFlowControlSignals=FlowControlSignals(c.iHandshake); |
|
1834 iAutoSignals=AutoSignals(c.iHandshake); |
|
1835 } |
|
1836 if (iConfig.iHandshake&KConfigObeyXoff) |
|
1837 { |
|
1838 iRxXonChar=c.iXonChar; |
|
1839 iRxXoffChar=c.iXoffChar; |
|
1840 } |
|
1841 else |
|
1842 { |
|
1843 iRxXonChar=0xffffffff; |
|
1844 iRxXoffChar=0xffffffff; |
|
1845 iOutputHeld&=~KXoffSignal; |
|
1846 } |
|
1847 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
1848 if (iStatus==EActive) |
|
1849 ReleaseFlowControl(); |
|
1850 |
|
1851 // no request pending here, so no need to protect this against interrupts |
|
1852 if (restart || purge || changeTerminators) |
|
1853 { |
|
1854 memclr(iTerminatorMask, 32); |
|
1855 TInt i; |
|
1856 for (i=0; i<iConfig.iTerminatorCount; i++) |
|
1857 { |
|
1858 SetTerminator(iConfig.iTerminator[i]); |
|
1859 } |
|
1860 } |
|
1861 return r; |
|
1862 } |
|
1863 |
|
1864 TInt DChannelComm::DoControl(TInt aFunction, TAny* a1, TAny* a2) |
|
1865 // |
|
1866 // Sync requests. |
|
1867 // |
|
1868 { |
|
1869 LOG(("DoControl(aFunction=%d, a1=%x, a2=%x)", aFunction, a1, a2)); |
|
1870 |
|
1871 TInt r=KErrNone; |
|
1872 |
|
1873 switch (aFunction) |
|
1874 { |
|
1875 case RBusDevComm::EControlSetConfig: |
|
1876 { |
|
1877 TCommConfigV01 c; |
|
1878 memclr(&c, sizeof(c)); |
|
1879 TPtr8 cfg((TUint8*)&c,0,sizeof(c)); |
|
1880 r=Kern::ThreadDesRead(iClient,a1,cfg,0,0); |
|
1881 if (r==KErrNone) |
|
1882 r=SetConfig(c); |
|
1883 } |
|
1884 Kern::UnpinVirtualMemory(iPinObjSetConfig); |
|
1885 break; |
|
1886 |
|
1887 case RBusDevComm::EControlSignals: |
|
1888 { |
|
1889 UpdateAndProcessSignals(); |
|
1890 r=iSignals; |
|
1891 break; |
|
1892 } |
|
1893 case RBusDevComm::EControlSetSignals: |
|
1894 { |
|
1895 TUint set=(TUint)a1; |
|
1896 TUint clear=(TUint)a2; |
|
1897 if (set & clear) |
|
1898 ;// Kern::PanicCurrentThread(_L("D32COMM"), ESetSignalsSetAndClear); |
|
1899 else |
|
1900 { |
|
1901 if (iStatus==EOpen) |
|
1902 { |
|
1903 Start(); |
|
1904 if (!(iConfig.iHandshake & KConfigFreeDTR) && !(clear & KSignalDTR)) |
|
1905 set|=KSignalDTR; // Assert DTR |
|
1906 if (!(iConfig.iHandshake & KConfigFreeRTS) && !(clear & KSignalRTS)) |
|
1907 set|=KSignalRTS; // Assert RTS |
|
1908 if (iConfig.iHandshake & KConfigSendXoff) |
|
1909 iJamChar=iConfig.iXonChar; |
|
1910 iInputHeld = EFalse; |
|
1911 CheckOutputHeld(); |
|
1912 } |
|
1913 __e32_atomic_axo_ord32(&iSignals, ~(clear|set), set); |
|
1914 SetSignals(set,clear); |
|
1915 } |
|
1916 break; |
|
1917 } |
|
1918 case RBusDevComm::EControlQueryReceiveBuffer: |
|
1919 r=RxCount(); |
|
1920 break; |
|
1921 case RBusDevComm::EControlResetBuffers: |
|
1922 if (AreAnyPending()) |
|
1923 ;// Kern::PanicCurrentThread(_L("D32COMM"), EResetBuffers); |
|
1924 else |
|
1925 ResetBuffers(ETrue); |
|
1926 break; |
|
1927 case RBusDevComm::EControlReceiveBufferLength: |
|
1928 r=iRxBufSize; |
|
1929 break; |
|
1930 |
|
1931 case RBusDevComm::EControlSetReceiveBufferLength: |
|
1932 if (AreAnyPending()) |
|
1933 ;// iThread->Panic(_L("D32COMM"),ESetReceiveBufferLength); |
|
1934 else |
|
1935 r=SetRxBufferSize((TInt)a1); |
|
1936 break; |
|
1937 // *************************************** |
|
1938 |
|
1939 case RBusDevComm::EControlMinTurnaroundTime: |
|
1940 r = iTurnaroundMicroSeconds; // used saved value |
|
1941 break; |
|
1942 |
|
1943 case RBusDevComm::EControlSetMinTurnaroundTime: |
|
1944 { |
|
1945 if (a1<0) |
|
1946 a1=(TAny*)0; |
|
1947 iTurnaroundMicroSeconds = (TUint)a1; // save this |
|
1948 TUint newTurnaroundMilliSeconds = (TUint)a1/1000; // convert to ms |
|
1949 if(newTurnaroundMilliSeconds != iTurnaroundMinMilliSeconds) |
|
1950 { |
|
1951 // POLICY: if a new turnaround time is set before the previous running timer has expired |
|
1952 // then the timer is adjusted depending on the new value and if any |
|
1953 // write request has been queued, transmission will proceed after the timer has expired. |
|
1954 if(iTurnaroundTimerStartTimeValid == 0) |
|
1955 { |
|
1956 iTurnaroundTimerStartTimeValid = 1; |
|
1957 iTurnaroundTimerStartTime = NKern::TickCount(); |
|
1958 } |
|
1959 if(iTurnaroundTimerStartTimeValid != 2) |
|
1960 TurnaroundClear(); |
|
1961 if(newTurnaroundMilliSeconds > 0) |
|
1962 { |
|
1963 r = TurnaroundSet(newTurnaroundMilliSeconds); |
|
1964 } |
|
1965 } |
|
1966 } |
|
1967 break; |
|
1968 default: |
|
1969 r=KErrNotSupported; |
|
1970 } |
|
1971 return(r); |
|
1972 } |
|
1973 |
|
1974 void DChannelComm::DoPowerUp() |
|
1975 // |
|
1976 // Called at switch on and upon Opening. |
|
1977 // |
|
1978 { |
|
1979 LOG(("DoPowerUp()")); |
|
1980 __KTRACE_OPT(KPOWER,Kern::Printf("DChannelComm::DoPowerUp()")); |
|
1981 |
|
1982 ResetBuffers(ETrue); |
|
1983 iRxOutstanding=EFalse; |
|
1984 iNotifyData=EFalse; |
|
1985 iTxOutstanding=EFalse; |
|
1986 iTxDesPos=0; |
|
1987 iFlags=0; |
|
1988 |
|
1989 // Cancel turnaround |
|
1990 iTurnaroundMinMilliSeconds = 0; |
|
1991 iTurnaroundTimerRunning = EFalse; |
|
1992 iTurnaroundTransmitDelayed = EFalse; |
|
1993 |
|
1994 // cancel any DFCs/timers |
|
1995 iRxDrainDfc.Cancel(); |
|
1996 iRxCompleteDfc.Cancel(); |
|
1997 iTxFillDfc.Cancel(); |
|
1998 iTxCompleteDfc.Cancel(); |
|
1999 iTimer.Cancel(); |
|
2000 iTurnaroundTimer.Cancel(); |
|
2001 iTurnaroundDfc.Cancel(); |
|
2002 iTimerDfc.Cancel(); |
|
2003 iSigNotifyDfc.Cancel(); |
|
2004 |
|
2005 Complete(EAll, KErrAbort); |
|
2006 if (!Kern::PowerGood()) |
|
2007 return; |
|
2008 TUint hand=iConfig.iHandshake; |
|
2009 if (hand&(KConfigFreeRTS|KConfigFreeDTR)) |
|
2010 { |
|
2011 Start(); |
|
2012 if (!Kern::PowerGood()) |
|
2013 return; |
|
2014 if (hand&KConfigFreeRTS) |
|
2015 { |
|
2016 if (iSignals&KSignalRTS) |
|
2017 SetSignals(KSignalRTS,0); |
|
2018 else |
|
2019 SetSignals(0,KSignalRTS); |
|
2020 } |
|
2021 if (!Kern::PowerGood()) |
|
2022 return; |
|
2023 if (hand&KConfigFreeDTR) |
|
2024 { |
|
2025 if (iSignals&KSignalDTR) |
|
2026 SetSignals(KSignalDTR,0); |
|
2027 else |
|
2028 SetSignals(0,KSignalDTR); |
|
2029 } |
|
2030 CheckOutputHeld(); |
|
2031 } |
|
2032 else |
|
2033 { |
|
2034 if (iStatus==EActive) |
|
2035 iStatus=EOpen; |
|
2036 } |
|
2037 } |
|
2038 |
|
2039 void DChannelComm::PowerUpDfc(TAny* aPtr) |
|
2040 { |
|
2041 |
|
2042 DChannelComm* d = (DChannelComm*)aPtr; |
|
2043 __PM_ASSERT(d->iStandby); |
|
2044 if (d->iStatus != EClosed) |
|
2045 d->DoPowerUp(); |
|
2046 else |
|
2047 // There is racing Close(): driver was already closed (ECloseMsg) but the DPowerHandler was not destroyed yet. |
|
2048 {} |
|
2049 d->iStandby = EFalse; |
|
2050 d->iPowerHandler->PowerUpDone(); |
|
2051 if (d->iMsgHeld) |
|
2052 { |
|
2053 __PM_ASSERT(d->iStatus != EClosed); |
|
2054 d->iMsgHeld = EFalse; |
|
2055 d->HandleMsg(d->iMsgQ.iMessage); |
|
2056 } |
|
2057 } |
|
2058 |
|
2059 void DChannelComm::PowerDownDfc(TAny* aPtr) |
|
2060 { |
|
2061 DChannelComm* d = (DChannelComm*)aPtr; |
|
2062 __PM_ASSERT(!d->iStandby); |
|
2063 d->iStandby = ETrue; |
|
2064 if (d->iStatus != EClosed) |
|
2065 d->Shutdown(); |
|
2066 else |
|
2067 // There is racing Close(): driver was already closed (ECloseMsg) but the DPowerHandler was not destroyed yet. |
|
2068 {} |
|
2069 d->iPowerHandler->PowerDownDone(); |
|
2070 } |
|
2071 |
|
2072 DCommPowerHandler::DCommPowerHandler(DChannelComm* aChannel) |
|
2073 : DPowerHandler(KLddName), |
|
2074 iChannel(aChannel) |
|
2075 { |
|
2076 } |
|
2077 |
|
2078 void DCommPowerHandler::PowerUp() |
|
2079 { |
|
2080 iChannel->iPowerUpDfc.Enque(); |
|
2081 } |
|
2082 |
|
2083 void DCommPowerHandler::PowerDown(TPowerState) |
|
2084 { |
|
2085 iChannel->iPowerDownDfc.Enque(); |
|
2086 } |
|
2087 |
|
2088 void DChannelComm::FinishBreak(TAny* aSelf) |
|
2089 { |
|
2090 DChannelComm* self = (DChannelComm*)aSelf; |
|
2091 self->QueueFinishBreakDfc(); |
|
2092 } |
|
2093 |
|
2094 void DChannelComm::QueueFinishBreakDfc() |
|
2095 { |
|
2096 iBreakDfc.Enque(); |
|
2097 } |
|
2098 |
|
2099 |
|
2100 void DChannelComm::FinishBreakDfc(TAny* aSelf) |
|
2101 { |
|
2102 DChannelComm* self = (DChannelComm*)aSelf; |
|
2103 self->FinishBreakImplementation(KErrNone); |
|
2104 } |
|
2105 |
|
2106 void DChannelComm::FinishBreakImplementation(TInt aError) |
|
2107 { |
|
2108 if (iStatus==EClosed) |
|
2109 { |
|
2110 Complete(EBreak, KErrNotReady); |
|
2111 } |
|
2112 else |
|
2113 { |
|
2114 BreakOff(); |
|
2115 Complete(EBreak, aError); |
|
2116 } |
|
2117 |
|
2118 // re-setup transmission if needed, for writes after a break |
|
2119 TInt irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
2120 if (iBreakDelayedTx) |
|
2121 { |
|
2122 iBreakDelayedTx = EFalse; // protected -> prevent reentrant ISR |
|
2123 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
2124 |
|
2125 RestartDelayedTransmission(); |
|
2126 } |
|
2127 else |
|
2128 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
2129 } |
|
2130 void DChannelComm::RestartDelayedTransmission() |
|
2131 { |
|
2132 LOG(("RestartDelayedTransmission()")); |
|
2133 TInt irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
2134 TBool completeTx=EFalse; |
|
2135 |
|
2136 iBreakDelayedTx = EFalse; // protected -> prevent reentrant ISR |
|
2137 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
2138 |
|
2139 if (iStatus==EClosed) |
|
2140 { |
|
2141 irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
2142 iTxError = KErrNotReady; // protected -> changed in signals ISR |
|
2143 completeTx = ETrue; |
|
2144 } |
|
2145 |
|
2146 else if(IsLineFail(iFailSignals)) // have signals changed in the meantime? |
|
2147 { |
|
2148 irq = __SPIN_LOCK_IRQSAVE(iLock); |
|
2149 iTxError = KErrCommsLineFail; // protected -> changed in signals ISR |
|
2150 completeTx = ETrue; |
|
2151 } |
|
2152 |
|
2153 else |
|
2154 { |
|
2155 InitiateWrite(); |
|
2156 } |
|
2157 |
|
2158 |
|
2159 if(completeTx) |
|
2160 { |
|
2161 iTxError = KErrNone; |
|
2162 __SPIN_UNLOCK_IRQRESTORE(iLock, irq); |
|
2163 Complete(ETx, iTxError); |
|
2164 } |
|
2165 } |