|
1 // Copyright (c) 1997-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". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // This file implements a loopback driver for use with the ETel Regression test harness. This |
|
15 // driver supports two ports with signalling capabilities for DCD, DSR, DTR, RTS, RI, and CTS. |
|
16 // In order for the signalling to function properly, one port should be opened as a DCE, though |
|
17 // the driver will allow both ports to operate as DTE's. |
|
18 // By default, the driver marks or asserts (sets to 1) the following signals when the method |
|
19 // SetRole is called. |
|
20 // For the DTE: |
|
21 // KSignalRTS KSignalDTR |
|
22 // For the DCE: |
|
23 // KSignalCTS KSignalDSR |
|
24 // Note that the DCE does NOT set DCD, thus it's initial state is space or de-asserted |
|
25 // (set to zero). This was chosen because of the desire of test script authors to fully |
|
26 // control DCD. |
|
27 // The driver supports the following signalling configuration handshake capabilities: |
|
28 // For the DTE: |
|
29 // KCapsObeyCTSSupported KCapsFailCTSSupported |
|
30 // KCapsObeyDSRSupported KCapsFailDSRSupported |
|
31 // KCapsObeyDCDSupported KCapsFailDCDSupported |
|
32 // For the DCE: |
|
33 // KCapsObeyRTSSupported KCapsObeyDTRSupported |
|
34 // Break, Configuration Change Notification, Flow Control Notification, and Data Available |
|
35 // Notifications are not supported. |
|
36 // directory exists. The log file is named loopback. |
|
37 // |
|
38 // |
|
39 |
|
40 /** |
|
41 @file |
|
42 @note This driver will create a log file in the Logs\ETel directory if the Logs\ETel |
|
43 */ |
|
44 #include <cs_port.h> |
|
45 #include "LOGGER.H" |
|
46 #include <d32comm.h> |
|
47 #include <c32comm.h> |
|
48 #include <e32hal.h> |
|
49 #include <c32comm_internal.h> |
|
50 |
|
51 #ifdef __LOGGER__XTRA |
|
52 #define LOGI(AAA) CETelLogger::WriteFormat(TRefByValue<const TDesC8>(AAA),iPortName,iSignals,&iPtr); |
|
53 #else |
|
54 #define LOGI(AAA) |
|
55 #endif |
|
56 |
|
57 #if defined(__VC32__) && _MSC_VER==1100 |
|
58 // Disable MSVC++ 5.0 aggressive warnings about non-expansion of inline functions. |
|
59 #pragma warning(disable : 4710) // function '...' not expanded |
|
60 #endif |
|
61 |
|
62 const TUint KCommLowUnit=0; |
|
63 const TUint KBufferGrowthIncrement=0x1000; |
|
64 const TUint KMaxBufferSize = 0x8000; |
|
65 |
|
66 // This should be even |
|
67 const TUint KLoopbackCount=8; |
|
68 |
|
69 |
|
70 #define SERIAL_DESCRIPTION _L("Loopback CSY") |
|
71 #define SERIAL_NAME _S("Loopback") |
|
72 |
|
73 // #define _DEBUG_CONSOLE_ |
|
74 |
|
75 #if defined(_DEBUG_CONSOLE_) |
|
76 // This class is not used in the loopback csy. It is left here for future reference. |
|
77 #include <e32twin.h> |
|
78 class RDebugConsole : public RConsole |
|
79 { |
|
80 public: |
|
81 RDebugConsole(); |
|
82 public: |
|
83 void Printf(TRefByValue<const TDesC> aFmt,...); |
|
84 }; |
|
85 |
|
86 #define DEBUG_TRACE(m) m |
|
87 |
|
88 #else // (_DEBUG) |
|
89 |
|
90 #define DEBUG_TRACE(m) |
|
91 // |
|
92 #endif |
|
93 |
|
94 // |
|
95 // "Entry point object" makes the objects which do the work |
|
96 class CHWPort; |
|
97 |
|
98 |
|
99 /** |
|
100 * This class is the factory port object. It drives the "entry point object" which |
|
101 * makes the reset of the objects do their work. It is based on the basic serial port |
|
102 * class CSerial. |
|
103 */ |
|
104 class CHWPortFactory : public CSerial |
|
105 { |
|
106 public: |
|
107 CHWPortFactory(); |
|
108 ~CHWPortFactory(); |
|
109 virtual CPort * NewPortL(const TUint aUnit); |
|
110 virtual void Info(TSerialInfo &aSerialInfo); |
|
111 void Remove(CHWPort* aPort); |
|
112 public: //CSerial |
|
113 TSecurityPolicy PortPlatSecCapability(TUint aPort) const; |
|
114 private: |
|
115 |
|
116 CHWPort* iPort[KLoopbackCount]; // pairs of ports |
|
117 CHWPort* PairedPort(TUint aPort) { return iPort[aPort^1]; } // returns the other half |
|
118 |
|
119 }; |
|
120 |
|
121 |
|
122 /** |
|
123 * This class is the object that interfaces with the commserver. An instance of this class |
|
124 * represents one port in the loopback driver. |
|
125 */ |
|
126 class CHWPort : public CPort |
|
127 { |
|
128 public: |
|
129 static CHWPort * NewL(TUint aUnit); |
|
130 private: |
|
131 CHWPort(); |
|
132 |
|
133 public: |
|
134 virtual void StartRead(const TAny* aClientBuffer,TInt aLength); |
|
135 virtual void ReadCancel(); |
|
136 virtual TInt QueryReceiveBuffer(TInt& aLength) const; |
|
137 virtual void ResetBuffers(TUint aFlags); |
|
138 virtual void StartWrite(const TAny* aClientBuffer,TInt aLength); |
|
139 virtual void WriteCancel(); |
|
140 virtual void Break(TInt aTime); |
|
141 virtual void BreakCancel(); |
|
142 virtual TInt GetConfig(TDes8& aDes) const; |
|
143 virtual TInt SetConfig(const TDesC8& aDes); |
|
144 virtual TInt SetServerConfig(const TDesC8& aDes); |
|
145 virtual TInt GetServerConfig(TDes8& aDes); |
|
146 virtual TInt GetCaps(TDes8& aDes); |
|
147 virtual TInt GetSignals(TUint& aSignals); |
|
148 virtual TInt SetSignalsToMark(TUint aSignals); |
|
149 virtual TInt SetSignalsToSpace(TUint aSignals); |
|
150 virtual TInt GetReceiveBufferLength(TInt& aLength) const; |
|
151 virtual TInt SetReceiveBufferLength(TInt aSignals); |
|
152 virtual void Destruct(); |
|
153 virtual void FreeMemory(); |
|
154 virtual void NotifySignalChange(TUint aSignalMask); |
|
155 virtual void NotifySignalChangeCancel(); |
|
156 virtual void NotifyConfigChange(); |
|
157 virtual void NotifyConfigChangeCancel(); |
|
158 virtual void NotifyFlowControlChange(); |
|
159 virtual void NotifyFlowControlChangeCancel(); |
|
160 virtual void NotifyBreak(); |
|
161 virtual void NotifyBreakCancel(); |
|
162 virtual void NotifyDataAvailable(); |
|
163 virtual void NotifyDataAvailableCancel(); |
|
164 virtual void NotifyOutputEmpty(); |
|
165 virtual void NotifyOutputEmptyCancel(); |
|
166 virtual TInt GetFlowControlStatus(TFlowControl& aFlowControl); |
|
167 virtual TInt GetRole(TCommRole& aRole); |
|
168 virtual TInt SetRole(TCommRole aRole); |
|
169 |
|
170 virtual ~CHWPort(); |
|
171 #if defined (_DEBUG_DEVCOMM) |
|
172 virtual void DoDumpDebugInfo(const RMessage2 &aMessage); |
|
173 #endif |
|
174 public: |
|
175 void SetLoopbackPort(CHWPort* aHWPort); |
|
176 TInt WriteBuf(const TAny* aClientBuffer,TInt aLength, TBool& aIssueComplete); |
|
177 void TryToCompleteRead(); |
|
178 void UpdatePortResources(); |
|
179 |
|
180 private: |
|
181 void CheckSigsAndCompleteRead(); |
|
182 public: |
|
183 TPtr8 iPtr; //< A pointer to the buffer created during class creation. |
|
184 |
|
185 private: |
|
186 TCommRole iRole; //< The role of this port (ECommRoleDTE or ECommRoleDCE) |
|
187 TUint iSignals; //< The current signals for this port |
|
188 TUint iSignalMask; //< The mask used when a NotifySignalChange request is posted. |
|
189 //< If it is clear, no request is outstanding. It is cleared when |
|
190 //< a request is either cancelled or completed. |
|
191 |
|
192 TBool iWritePending; //< True if a write is left pending |
|
193 TInt iWritePendingLength; //< The length of the buffer that was left pending. |
|
194 const TAny* iClientWriteBuffer; //< The buffer pointer that was pended. A pended write |
|
195 //< implies that the WriteCompleted was NOT called when |
|
196 //< the write was posted. |
|
197 |
|
198 TPckgBuf<TCommServerConfigV01> iServerConfig; //< A placeholder; no real function in loopback. |
|
199 TPckgBuf<TCommConfigV01> iConfig; //< The configuration of this port. Important fields for |
|
200 //< the loopback driver are: iHandShake |
|
201 |
|
202 CHWPort* iLoopbackPort; //< The pointer to the loopback port to which this port is connected. |
|
203 |
|
204 /** |
|
205 An HBufC created during port creation, pointed to by iPtr. |
|
206 This buffer is only appended to by this object on a write request; |
|
207 this object never reads from the buffer. iLoopbackPort is the |
|
208 object responsible for reading from this iBuf (via iPtr), and send |
|
209 the data it reads to iLoopbackPort's client (as a completion of a |
|
210 read request). |
|
211 */ |
|
212 HBufC8* iBuf; //< An HBuf created during port creation, pointed to by iPtr. |
|
213 //< Note that this buffer can grow during operation, but it will |
|
214 //< not shrink. |
|
215 TInt iBufSize; //< The initial size of the buffer and it's growth increment. |
|
216 TBool iReadPending; //< Boolean indicating that a read has been left pending for later |
|
217 //< completion. |
|
218 |
|
219 TBool iReadOneOrMore; //< Should the current read (even if it is pending) complete before |
|
220 //< the buffer is full? |
|
221 |
|
222 TBool iDataNotify; //< Set when a data notify event is pending |
|
223 |
|
224 TInt iBytesWritten; //< The number of bytes written to the current read buffer. |
|
225 TInt iPendingLength; //< Count of how many more bytes can be written to the read buffer |
|
226 /** |
|
227 Pointer to the client buffer to be filled by a read. The read |
|
228 actually takes the data from iLoopbackPort->iPtr to send to the |
|
229 client. |
|
230 */ |
|
231 const TAny* iClientReadBuffer; //< Pointer to the client buffer to be filled by a read. |
|
232 |
|
233 TUint iPortName; //< Unit number of this port |
|
234 |
|
235 #if defined (_DEBUG_CONSOLE_) |
|
236 // Not used in the current loopback driver. |
|
237 #if defined (_DEBUG_DEVCOMM) |
|
238 CCommDebugDumper *iDumper; //< Pointer to debug class. |
|
239 #endif |
|
240 public: |
|
241 RDebugConsole iConsole; //< Console for debugging. |
|
242 #endif |
|
243 }; |
|
244 |
|
245 // |
|
246 // CHWPort definitions |
|
247 // |
|
248 CHWPort::CHWPort() : iPtr(NULL,0,0) |
|
249 /** |
|
250 * This method is the basic constructor for the CHWPort class. In initializes |
|
251 * the iPtr member specifically to NULL. |
|
252 * |
|
253 * @param None |
|
254 * |
|
255 * @return None |
|
256 */ |
|
257 { |
|
258 __DECLARE_NAME(_S("CHWPort")); |
|
259 } |
|
260 |
|
261 void CloseObject(TAny* anObject) |
|
262 /** |
|
263 * This method simply closes an object from the cleanup stack. The object must contain |
|
264 * a Close method. |
|
265 * |
|
266 * @param anObject - a TAny pointer to the object to close. |
|
267 * @return None |
|
268 */ |
|
269 { |
|
270 ((CObject*)anObject)->Close(); |
|
271 } |
|
272 |
|
273 CHWPort* CHWPort::NewL(TUint aUnit) |
|
274 /** |
|
275 * This method is used by the factory object to create the new CHWPort instances. |
|
276 * After newing the CHWPort object, the buffer is created, roles and signals are defaulted, |
|
277 * and names are initialized. |
|
278 * |
|
279 * @param aUnit - the unit to create. |
|
280 * |
|
281 * @return A pointer to the created object |
|
282 */ |
|
283 { |
|
284 |
|
285 LOGTEXTREL(_S8("Loopback:NewL: Called")); |
|
286 LOGTEXTREL2(_L8("Loopback:NewL: Unit %d..."), aUnit); |
|
287 |
|
288 CHWPort *p=new(ELeave) CHWPort; |
|
289 TCleanupItem closePort(CloseObject,p); |
|
290 |
|
291 CleanupStack::PushL(closePort); |
|
292 |
|
293 |
|
294 p->iBuf=HBufC8::NewL(KBufferGrowthIncrement); |
|
295 p->iBufSize=KBufferGrowthIncrement; |
|
296 p->iPtr.Set((TUint8*)p->iBuf->Ptr(),0,KBufferGrowthIncrement); |
|
297 |
|
298 p->iRole = ECommRoleDTE; |
|
299 p->iSignals = 0; // start with no signals asserted. |
|
300 p->iSignalMask = 0; // Prevents any spurrious notifications, etc. |
|
301 |
|
302 TName name; |
|
303 name.Format(_L("%d"),aUnit); |
|
304 p->SetName(&name); |
|
305 p->iPortName = aUnit; |
|
306 #if defined (_DEBUG_CONSOLE_) |
|
307 name.Format(_L("Comm::%d"),aUnit); |
|
308 p->iConsole.SetTitle(name); |
|
309 #if defined (_DEBUG_DEVCOMM) |
|
310 p->iDumper=CCommDebugDumper::NewL(p->iConsole); |
|
311 #endif |
|
312 #endif |
|
313 CleanupStack::Pop(); |
|
314 |
|
315 return p; |
|
316 } |
|
317 |
|
318 void CHWPort::SetLoopbackPort(CHWPort* aHWPort) |
|
319 /** |
|
320 * This method sets up the loopback port member of the CHWPort. It is used after |
|
321 * both ports have been created (NewL). This allows each port to "know" to whom he is |
|
322 * connected. |
|
323 * |
|
324 * @param aHWPort - the port which THIS port should be connected to. |
|
325 * |
|
326 * @return None |
|
327 */ |
|
328 { |
|
329 if (aHWPort != NULL) |
|
330 { |
|
331 LOGTEXT3(_L8("SetLoopbackPort: Unit %d-%d"), iPortName, aHWPort->iPortName); |
|
332 } |
|
333 else |
|
334 { |
|
335 LOGTEXT2(_L8("Loopback:SetLoopbackPort: Unit %d..."), iPortName); |
|
336 } |
|
337 |
|
338 // Now set up the loopback |
|
339 iLoopbackPort=aHWPort; |
|
340 |
|
341 } |
|
342 |
|
343 |
|
344 void CHWPort::CheckSigsAndCompleteRead() |
|
345 /** |
|
346 * This method checks the configuration of the port and the current state of the signals |
|
347 * and determines if the read should even attempt to be completed. Based on configurations, |
|
348 * reads can fail or be left pending (KConfigObeyXXX). This method calls TryToCompleteRead |
|
349 * if all configuration and signal state allows the read to continue. |
|
350 * |
|
351 * Note that this method is called to either complete a pended read (from WriteBuf) or |
|
352 * to complete an incoming read request (from StartRead). Also note that this routine does |
|
353 * not check the fail flags. These flags are checked when the read is first posted and |
|
354 * when the signals are first asserted/deasserted. It is unnecessary (and maybe even undesirable) |
|
355 * to check the fail flags here. |
|
356 * |
|
357 * @param None |
|
358 * |
|
359 * @return None |
|
360 */ |
|
361 { |
|
362 LOGI(_L8("CheckSigsAndCompleteRead:%04d %x \"%S\"")); |
|
363 |
|
364 LOGTEXT2(_L8("Loopback:CheckSigsAndCompleteRead: Unit %d..."), iPortName); |
|
365 |
|
366 |
|
367 // At this point, we must check the config flags and signals. If we have been |
|
368 // configured to obey signals, then we must pend the read and not complete it. |
|
369 // Note that the iReadPending flag was set in StartRead(). |
|
370 if (ECommRoleDTE == iRole) |
|
371 { |
|
372 if (((iConfig().iHandshake & KConfigObeyDCD) && (!(iSignals & KSignalDCD))) || |
|
373 ((iConfig().iHandshake & KConfigObeyDSR) && (!(iSignals & KSignalDSR)))) |
|
374 { |
|
375 LOGI(_L8("CheckSigsAndCompleteRead DTE:%04d %x \"%S\"")); |
|
376 return; |
|
377 } |
|
378 } |
|
379 else if (ECommRoleDCE == iRole) |
|
380 { |
|
381 if ((iConfig().iHandshake & (KConfigObeyDTR)) && (!(iSignals & (KSignalDTR)))) |
|
382 { |
|
383 LOGI(_L8("CheckSigsAndCompleteRead DCE:%04d %x \"%S\"")); |
|
384 return; |
|
385 } |
|
386 } |
|
387 |
|
388 |
|
389 // Can the request be satisfied now? Note that we call TryToCompleteRead on THIS instance. |
|
390 // This means that CheckSigsAndCompleteRead must be called on the desired instance. |
|
391 TryToCompleteRead(); |
|
392 LOGI(_L8("CheckSigsAndCompleteRead:%04d %x \"%S\"")); |
|
393 } |
|
394 |
|
395 |
|
396 void CHWPort::StartRead(const TAny* aClientBuffer,TInt aLength) |
|
397 /** |
|
398 * This method queues a read operation to the driver. If the read length is zero (which is a |
|
399 * special case used during initialization) the read completes immediately without being |
|
400 * concerned about any of the configuration flags. Failure flags are checked in this routine. |
|
401 * If the port has been configured to fail (KConfigFailXXX) and the signals are NOT asserted, |
|
402 * then the read will fail immediately with KErrCommsLineFail. Obey flags are not handled here, |
|
403 * but are handled in a different method. The code was structured in this manner so that the |
|
404 * Obey flags are checked any time a read is attempted to be completed, not just when the read |
|
405 * is initially sent to the driver. This is needed because reads can pend and before the reads |
|
406 * are completed the signal state could change. |
|
407 * |
|
408 * @param aClientBuffer - a TAny * to the buffer into which data is placed. |
|
409 * @param aLength - the length of the buffer. If the length is less than zero the |
|
410 * read can be completed with less than length bytes available. If |
|
411 * a positive length value is specified, the read will not complete |
|
412 * until length bytes have been read. |
|
413 * |
|
414 * @return None |
|
415 */ |
|
416 { |
|
417 |
|
418 // DEBUG_TRACE((iConsole.Write(_L("DoRead \n\r")))); |
|
419 LOGI(_L8("LOGIStartRead:%04d %x \"%S\"")); |
|
420 |
|
421 LOGTEXT2(_L8("Loopback:StartRead: Unit %d..."), iPortName); |
|
422 |
|
423 // Because a length of zero is a special case, we will complete this without |
|
424 // worries about the config/fail flags. |
|
425 if(aLength==0) |
|
426 { |
|
427 ReadCompleted(KErrNone); |
|
428 |
|
429 LOGI(_L8("StartRead 0:%04d %x \"%S\"")); |
|
430 |
|
431 return; |
|
432 } |
|
433 |
|
434 |
|
435 // At this point, we must check the config flags and signals. If we have been |
|
436 // configured to fail operations if certain signals are not set, then we must |
|
437 // fail the read. |
|
438 if (ECommRoleDTE == iRole) |
|
439 { |
|
440 if (((iConfig().iHandshake & KConfigFailDCD) && (!(iSignals & KSignalDCD))) || |
|
441 ((iConfig().iHandshake & KConfigFailDSR) && (!(iSignals & KSignalDSR)))) |
|
442 { |
|
443 ReadCompleted(KErrCommsLineFail); |
|
444 LOGI(_L8("XtartRead DTE:%04d %x \"%S\"")); |
|
445 return; |
|
446 } |
|
447 } |
|
448 else if (ECommRoleDCE == iRole) |
|
449 { |
|
450 if ((iConfig().iHandshake & (KConfigFailDTR)) && (!(iSignals & (KSignalDTR)))) |
|
451 { |
|
452 ReadCompleted(KErrCommsLineFail); |
|
453 LOGI(_L8("StartRead DCE:%04d %x \"%S\"")); |
|
454 return; |
|
455 } |
|
456 } |
|
457 |
|
458 |
|
459 // At this point, we set up for the read. If the obey flags later don't let us |
|
460 // complete the read, having this work done is vital. |
|
461 iReadOneOrMore=EFalse; |
|
462 if(aLength<0) |
|
463 { |
|
464 aLength=-aLength; |
|
465 iReadOneOrMore=ETrue; |
|
466 } |
|
467 |
|
468 iBytesWritten=0; |
|
469 iPendingLength=aLength; |
|
470 iClientReadBuffer=aClientBuffer; |
|
471 iReadPending=ETrue; |
|
472 |
|
473 // Later code will assert iLoopback, so check it now to avoid crashes during startup. |
|
474 // The CheckSigsAndCompeteRead method will actually process the Obey flags. |
|
475 if (iLoopbackPort != NULL) |
|
476 { |
|
477 CheckSigsAndCompleteRead(); |
|
478 } |
|
479 |
|
480 LOGI(_L8("StartRead:%04d %x \"%S\"")); |
|
481 } |
|
482 |
|
483 void CHWPort::ReadCancel() |
|
484 /** |
|
485 * Cancel a pending read and complete it with KErrCancel. The handling of the CActive class |
|
486 * will by default complete any outstanding read with KErrCancel, but it is cleaner to handle |
|
487 * that processing here. |
|
488 * |
|
489 * @param None |
|
490 * |
|
491 * @return None |
|
492 */ |
|
493 { |
|
494 LOGI(_L8("ReadCancel:%04d %x \"%S\"")); |
|
495 |
|
496 LOGTEXT2(_L8("Loopback:ReadCancel: Unit %d..."), iPortName); |
|
497 |
|
498 iReadPending=EFalse; |
|
499 |
|
500 ReadCompleted(KErrCancel); |
|
501 |
|
502 } |
|
503 |
|
504 |
|
505 TInt CHWPort::WriteBuf(const TAny* aClientBuffer,TInt aLength, TBool& aIssueComplete) |
|
506 /** |
|
507 * This method writes the client buffer to the loopback port. It must take into consideration |
|
508 * all of the KConfigFailXXX and KConfigObeyXXX flags that might have been specified in the |
|
509 * configuration of the port. Any fail configuration results with writes failing with the |
|
510 * KErrCommsLineFail error. This method is used both when the write is originally posted to |
|
511 * the driver and when trying to finish any write that was pended by the driver based on the |
|
512 * Obey flags. This routine does not actually complete the read, but returns a value with |
|
513 * which the caller should complete the read. Because this routine can also leave the operation |
|
514 * pended, it uses the aIssueComplete boolean to tell the caller whether or not to complete the |
|
515 * read. |
|
516 * |
|
517 * @param aClientBuffer - a TAny * to the buffer which contains the data to write |
|
518 * @param aLength - the length of the buffer. |
|
519 * @param aIssueComplete - a reference to a boolean used to indicate to the caller if the |
|
520 * write operation should be completed. |
|
521 * - ETrue - Caller should issue the WriteCompleted with returned |
|
522 * result code. |
|
523 * - EFalse - Caller shoud not issue the WriteCompleted. |
|
524 * |
|
525 * @return KErrNone - Everything is okay |
|
526 * @return KErrCommsLineFail - Write failed based on signal state and configuration. |
|
527 * @return Varies - Non-Zero return from Kernel calls |
|
528 */ |
|
529 |
|
530 { |
|
531 TInt res=KErrNone; |
|
532 |
|
533 LOGI(_L8("WriteBuf:%04d %x \"%S\"")); |
|
534 |
|
535 // Plan on completeing, so set aIssueComplete to TRUE. |
|
536 aIssueComplete = ETrue; |
|
537 |
|
538 |
|
539 LOGTEXT3(_L8("Config 0x%x Sigs 0x%x"), iConfig().iHandshake, iSignals); |
|
540 |
|
541 // At this point, we must check the config flags and signals. Note that Fail |
|
542 // flags always take precedence over Obey flags. |
|
543 if (ECommRoleDTE == iRole) |
|
544 { |
|
545 // if we are configured to fail if CD, DSR, or CTS are not present, then we |
|
546 // must fail the write here. |
|
547 if (((iConfig().iHandshake & KConfigFailDCD) && (!(iSignals & KSignalDCD))) || |
|
548 ((iConfig().iHandshake & KConfigFailDSR) && (!(iSignals & KSignalDSR))) || |
|
549 ((iConfig().iHandshake & KConfigFailCTS) && (!(iSignals & KSignalCTS)))) |
|
550 { |
|
551 LOGTEXT2(_L8("WriteBuf: DTE Failure Unit %d..."), iPortName); |
|
552 LOGTEXT3(_L8("...Config 0x%x Sigs 0x%x..."), (iConfig().iHandshake), iSignals); |
|
553 res=KErrCommsLineFail; |
|
554 LOGI(_L8("WriteBuf:%04d %x \"%S\"")); |
|
555 return res; |
|
556 } |
|
557 |
|
558 // At this point, we must check the config flags and signals. If we have been |
|
559 // configured to obey signals, then we must pend the write and not complete the |
|
560 // write. |
|
561 if (((iConfig().iHandshake & KConfigObeyDCD) && (!(iSignals & KSignalDCD))) || |
|
562 ((iConfig().iHandshake & KConfigObeyDSR) && (!(iSignals & KSignalDSR))) || |
|
563 ((iConfig().iHandshake & KConfigObeyCTS) && (!(iSignals & KSignalCTS)))) |
|
564 { |
|
565 LOGTEXT2(_L8("WriteBuf: DTE Pended: Unit %d..."), iPortName); |
|
566 iWritePending = ETrue; |
|
567 iClientWriteBuffer = aClientBuffer; |
|
568 iWritePendingLength = aLength; |
|
569 aIssueComplete = EFalse; |
|
570 res=KErrNone; |
|
571 LOGI(_L8("WriteBuf:%04d %x \"%S\"")); |
|
572 return res; |
|
573 } |
|
574 } |
|
575 else if (ECommRoleDCE == iRole) |
|
576 { |
|
577 // if we are configured to fail when DTR or RTS are not present, then |
|
578 // fail the write here. |
|
579 if (((iConfig().iHandshake & KConfigFailRTS) && (!(iSignals & KSignalRTS))) || |
|
580 ((iConfig().iHandshake & KConfigFailDTR) && (!(iSignals & KSignalDTR)))) |
|
581 { |
|
582 LOGTEXT2(_L8("WriteBuf: DCE Failure... Unit %d..."), iPortName); |
|
583 LOGTEXT3(_L8("...Config 0x%x Sigs 0x%x..."), (iConfig().iHandshake), iSignals); |
|
584 res=KErrCommsLineFail; |
|
585 LOGI(_L8("WriteBuf:%04d %x \"%S\"")); |
|
586 return res; |
|
587 } |
|
588 |
|
589 // At this point, we must check the config flags and signals. If we have been |
|
590 // configured to obey signals, then we must pend the write and not complete the |
|
591 // write. |
|
592 if (((iConfig().iHandshake & KConfigObeyRTS) && (!(iSignals & KSignalRTS))) || |
|
593 ((iConfig().iHandshake & KConfigObeyDTR) && (!(iSignals & KSignalDTR)))) |
|
594 { |
|
595 LOGTEXT2(_L8("WriteBuf: DCE Pended: Unit %d..."), iPortName); |
|
596 LOGTEXT3(_L8("...Config 0x%x Sigs 0x%x..."), (iConfig().iHandshake), iSignals); |
|
597 iWritePending = ETrue; |
|
598 iClientWriteBuffer = aClientBuffer; |
|
599 iWritePendingLength = aLength; |
|
600 aIssueComplete = EFalse; |
|
601 res=KErrNone; |
|
602 LOGI(_L8("WriteBuf:%04d %x \"%S\"")); |
|
603 return res; |
|
604 } |
|
605 } |
|
606 |
|
607 // Resize the receiving buffer if it is not big enough or it is |
|
608 // more than twice as big as it needs to be for this write. |
|
609 if ((iPtr.Length() + aLength) > iBufSize) |
|
610 { |
|
611 // New buffer size will be just big enough to fit the existing |
|
612 // data + new data, rounded up to nearest multiple of |
|
613 // KBufferGrowthIncrement. |
|
614 TInt newBufSize; |
|
615 |
|
616 if (((iPtr.Length() + aLength) % KBufferGrowthIncrement) == 0) |
|
617 { |
|
618 newBufSize = iPtr.Length() + aLength; |
|
619 |
|
620 } |
|
621 else |
|
622 { |
|
623 // New buffer size = length of data already in the buffer |
|
624 // + length of data to be added to the buffer |
|
625 // + round up to next KBufferGrowthIncrement |
|
626 newBufSize = iPtr.Length() + aLength |
|
627 + KBufferGrowthIncrement - ((iPtr.Length() + aLength)%KBufferGrowthIncrement); |
|
628 } |
|
629 |
|
630 |
|
631 // Need to resize the buffer |
|
632 // Note: iBuf should not be deleted, buffer may be emptied |
|
633 // later if this ReAllocL fails and tmpBuffer remains NULL. |
|
634 HBufC8* tmpBuffer = NULL; |
|
635 TRAP(res, tmpBuffer = iBuf->ReAllocL(newBufSize)); |
|
636 |
|
637 if (tmpBuffer == NULL || res != KErrNone) |
|
638 { |
|
639 // Could not reallocate the buffer (maybe not enough |
|
640 // memory) so write request fails. |
|
641 iWritePending = EFalse; |
|
642 |
|
643 // return with an Issue complete and an error message |
|
644 aIssueComplete = ETrue; |
|
645 LOGI(_L8("WriteBuf:%04d %x \"%S\"")); |
|
646 return KErrNoMemory; |
|
647 } |
|
648 |
|
649 iBufSize = newBufSize; |
|
650 iBuf = tmpBuffer; |
|
651 |
|
652 |
|
653 // Note: the aIssueComplete flag has already been set to ETrue |
|
654 // so, don't need to set it again here. |
|
655 iWritePending = EFalse; |
|
656 } |
|
657 |
|
658 // Fill the receiving buffer |
|
659 if (aLength!=0) |
|
660 { |
|
661 // point to where the new data will be located in our buffer |
|
662 TPtr8 ptrWriteLocation((TUint8*)(iBuf->Ptr() + iPtr.Length()), aLength); |
|
663 |
|
664 res = IPCRead(aClientBuffer,ptrWriteLocation); // Must go through correct port |
|
665 |
|
666 LOGTEXT2(_L8("Read \"%S\""), &ptrWriteLocation); |
|
667 if(res!=KErrNone) |
|
668 { |
|
669 LOGI(_L8("WriteBuf:%04d %x \"%S\"")); |
|
670 return res; |
|
671 } |
|
672 |
|
673 // memory leak detection : we create a single memory leak, if our input buffer contains |
|
674 // special token string: |
|
675 _LIT8(KMemLeakToken, "--MemoryLeakToken--"); |
|
676 TInt nRetVal = ptrWriteLocation.Compare(KMemLeakToken); |
|
677 if (nRetVal == 0) |
|
678 { |
|
679 // coverity [returned_pointer] |
|
680 // coverity [memory_leak] - create a memory leak intentionally, look at the comments above |
|
681 TInt* pArr = new TInt[1024]; // deliberatly causing a memory leak here... |
|
682 } |
|
683 |
|
684 // set the iPtr to point to the new iBuffer and keep a record of data length |
|
685 iPtr.Set((TUint8*)iBuf->Ptr(), iPtr.Length() + aLength, iBufSize); |
|
686 } |
|
687 // Since we are completing a write on THIS instance, see if we can complete a read on |
|
688 // the loopback port. A read could have been left pending. |
|
689 if (iLoopbackPort != NULL) |
|
690 { |
|
691 iLoopbackPort->CheckSigsAndCompleteRead(); |
|
692 } |
|
693 |
|
694 return res; |
|
695 } |
|
696 |
|
697 void CHWPort::TryToCompleteRead() |
|
698 /** |
|
699 * This method attempts to complete reads, either as they are initially issued or at a later |
|
700 * time because they were pended when initially issued. Data is moved from the buffer associated |
|
701 * with this port to a buffer that was supplied by the client when the read is issued. The |
|
702 * read is completed when either the client buffer is full or when some data has been written |
|
703 * to the client buffer and the iReadOneOrMore member set. This member data is set when then |
|
704 * initial read was passed a negative length value. Using this method allows a read to complete |
|
705 * without filling the entire buffer. |
|
706 * |
|
707 * @param None |
|
708 * |
|
709 * @return None |
|
710 */ |
|
711 |
|
712 { |
|
713 LOGI(_L8("TryToCompleteRead:%04d %x \"%S\"")); |
|
714 |
|
715 LOGTEXT2(_L8("Loopback:TryToCompleteRead: Unit %d ..."), iPortName); |
|
716 |
|
717 ASSERT(iLoopbackPort); |
|
718 TPtr8& refLoopBackiPtr = iLoopbackPort->iPtr; // Loopback listening port's buffer |
|
719 |
|
720 // Is there a Data Available notification pending? |
|
721 TInt s = refLoopBackiPtr.Length(); |
|
722 if(iDataNotify) |
|
723 { |
|
724 NotifyDataAvailableCompleted(KErrNone); |
|
725 iDataNotify=EFalse; |
|
726 } |
|
727 |
|
728 // Is there a Read Pending? |
|
729 if(!iReadPending) |
|
730 return; |
|
731 |
|
732 // If there's somthing in the buffer then try to copy that... |
|
733 TInt stillToBeWritten=iPendingLength-iBytesWritten; |
|
734 TInt len=Min(s, stillToBeWritten); |
|
735 |
|
736 // only point to the data we are going to read |
|
737 TPtrC8 ptr(refLoopBackiPtr.Ptr(), len); |
|
738 |
|
739 LOGTEXT2(_L8("Write \"%S\""), &ptr); |
|
740 |
|
741 // Search for terminator characters |
|
742 TBool terminatorFound = EFalse; |
|
743 const TText8* terminators = iConfig().iTerminator; |
|
744 TInt termNum; |
|
745 for (termNum=0; termNum < iConfig().iTerminatorCount; ++termNum) |
|
746 { |
|
747 TInt termIndex = ptr.Locate(terminators[termNum]); |
|
748 if (termIndex >= 0) |
|
749 { |
|
750 // Found the terminator; reduce the length of ptr and search for the next one |
|
751 len = termIndex + 1; |
|
752 ptr.Set(refLoopBackiPtr.Ptr(), len); |
|
753 terminatorFound = ETrue; |
|
754 } |
|
755 } |
|
756 |
|
757 TInt res=IPCWrite(iClientReadBuffer,ptr,iBytesWritten); |
|
758 if(res == KErrNone) |
|
759 { |
|
760 // Delete the read data from the buffer |
|
761 ASSERT(refLoopBackiPtr.Length() >= len); |
|
762 TPtrC8 source = refLoopBackiPtr.Right(refLoopBackiPtr.Length() - len); |
|
763 // a memory move occurs on each read. This must be inefficient |
|
764 refLoopBackiPtr.Copy(source); |
|
765 iBytesWritten+=len; |
|
766 } |
|
767 |
|
768 if((iBytesWritten==iPendingLength)||(iReadOneOrMore&&(s>=1))||terminatorFound) |
|
769 { |
|
770 LOGTEXT2(_L8("Loopback:TryToCompleteRead: Completing Read Unit %d ..."), iPortName); |
|
771 iReadPending=EFalse; |
|
772 // a complete read has succeeded, now update the Ports memory usage |
|
773 iLoopbackPort->UpdatePortResources(); |
|
774 ReadCompleted(res); |
|
775 } |
|
776 } |
|
777 |
|
778 void CHWPort::UpdatePortResources() |
|
779 /** |
|
780 * This method recalculate how much memory is actually required by a ports write buffer |
|
781 * |
|
782 * @param Not used |
|
783 * |
|
784 * @return None |
|
785 */ |
|
786 { |
|
787 LOGTEXT2(_L8("Loopback:UpdatePortResources: Unit %d ..."), iPortName); |
|
788 |
|
789 |
|
790 TInt newBufSize = 0; |
|
791 |
|
792 // it is possible to have a length of 0 therefore we leave the buffer size |
|
793 // to KBufferGrowthIncrement |
|
794 if(iPtr.Length() > 0) |
|
795 { |
|
796 newBufSize = iPtr.Length() + KBufferGrowthIncrement - ((iPtr.Length()) % KBufferGrowthIncrement); |
|
797 } |
|
798 else |
|
799 { |
|
800 // the minimum buffer size is KBufferGrowthIncrement |
|
801 newBufSize = KBufferGrowthIncrement; |
|
802 } |
|
803 |
|
804 // if the buffer needs changing then resize it otherwise leave as is |
|
805 if(newBufSize != iBufSize) |
|
806 { |
|
807 TInt res = KErrNone; |
|
808 // Shrink the buffer to the new size calculated above. If this fails we return leaving memory as it was |
|
809 HBufC8* tmpBuffer = NULL; |
|
810 TRAP(res, tmpBuffer = iBuf->ReAllocL(newBufSize)); |
|
811 |
|
812 if (tmpBuffer == NULL || res != KErrNone) |
|
813 { |
|
814 // could not resize the buffer - return without modifying anything |
|
815 return; |
|
816 } |
|
817 |
|
818 iBuf = tmpBuffer; |
|
819 iBufSize = newBufSize; |
|
820 |
|
821 // update the public interface to our buffer. |
|
822 iPtr.Set((TUint8*)iBuf->Ptr(), iPtr.Length(), iBufSize); |
|
823 } |
|
824 } |
|
825 |
|
826 TInt CHWPort::QueryReceiveBuffer(TInt& aLength) const |
|
827 /** |
|
828 * This method returns the length of the buffer associated with this instance of the |
|
829 * port. |
|
830 * |
|
831 * @param aLength - a reference to return the length of the buffer. |
|
832 * |
|
833 * @return KErrNone |
|
834 */ |
|
835 { |
|
836 LOGTEXT2(_L8("Loopback:QueryReceiveBuffer: Unit %d..."), iPortName); |
|
837 |
|
838 aLength=iPtr.Length(); |
|
839 return KErrNone; |
|
840 } |
|
841 |
|
842 void CHWPort::ResetBuffers(TUint) |
|
843 /** |
|
844 * This method resets the buffer used by this loopback port |
|
845 * |
|
846 * @note Note that most ResetBuffers methods derived from CPort allow a parameter for flags. |
|
847 * This ResetBuffers method does not. |
|
848 * |
|
849 * @param Not Used |
|
850 * |
|
851 * @return None |
|
852 */ |
|
853 { |
|
854 |
|
855 LOGI(_L8("ResetBuffers:%04d %x \"%S\"")); |
|
856 |
|
857 LOGTEXT2(_L8("Loopback:ResetBuffers: Unit %d..."), iPortName); |
|
858 |
|
859 // reset the length of data to zero and update port resources |
|
860 iPtr.Set((TUint8*)iBuf->Ptr(), 0, iBufSize); |
|
861 |
|
862 // this method will perform any memory re-sizing required on the port |
|
863 UpdatePortResources(); |
|
864 } |
|
865 |
|
866 void CHWPort::StartWrite(const TAny* aClientBuffer,TInt aLength) |
|
867 /** |
|
868 * This method queues a write operation to the driver. This method is simply the outside |
|
869 * interface to the class for writing data. It calls a private method to actually process |
|
870 * the write. StartWrite passes a reference to a boolean value to the private routine that |
|
871 * indicates whether or not StartWrite should issue a WriteCompleted response. This is necessary |
|
872 * because some combinations of signals and configuration can cause writes to be pended and |
|
873 * thus NOT completed. |
|
874 * |
|
875 * @param aClientBuffer - a TAny * to the buffer into which data should be read. |
|
876 * @param aLength - the length of the data to be written. |
|
877 * |
|
878 * @return None |
|
879 */ |
|
880 { |
|
881 |
|
882 LOGI(_L8("StartWrite:%04d %x \"%S\"")); |
|
883 |
|
884 LOGTEXT2(_L8("Loopback:StartWrite: Unit %d..."), iPortName); |
|
885 |
|
886 // memory leak detection mechanism: |
|
887 // if special write buffer token is received is received, we create memory leak |
|
888 // this condition is triggered, when working with "te_C32_leakdetection.script" |
|
889 |
|
890 DEBUG_TRACE((iConsole.Write(_L("DoWrite \n\r")))); |
|
891 TBool issueComplete = ETrue; |
|
892 |
|
893 TInt res = KErrNone; |
|
894 |
|
895 if((iPtr.Length() + aLength) > KMaxBufferSize) |
|
896 { |
|
897 // we are exceeding our buffer growth size. Do not process the |
|
898 // write message |
|
899 iWritePending = EFalse; |
|
900 res = KErrNoMemory; |
|
901 } |
|
902 else |
|
903 { |
|
904 res = WriteBuf(aClientBuffer,aLength, issueComplete); |
|
905 } |
|
906 |
|
907 // Only complete the write if allowed to by WriteBuf. |
|
908 if (issueComplete) |
|
909 { |
|
910 LOGTEXT2(_L8("Loopback:StartWrite: Completing Write Unit %d..."), iPortName); |
|
911 LOGTEXT2(_L8("Loopback:StartWrite: Completing Write Unit %d..."), res); |
|
912 WriteCompleted(res); |
|
913 } |
|
914 |
|
915 LOGI(_L8("StartWrite:%04d %x \"%S\"")); |
|
916 |
|
917 } |
|
918 |
|
919 void CHWPort::WriteCancel() |
|
920 /** |
|
921 * This method cancels a pending write and issues a WriteCompleted with the result |
|
922 * KErrCancel. If no writes are pending, then this method simply returns. |
|
923 * |
|
924 * @param None |
|
925 * |
|
926 * @return None |
|
927 */ |
|
928 |
|
929 { |
|
930 |
|
931 LOGI(_L8("WriteCancel:%04d %x \"%S\"")); |
|
932 |
|
933 LOGTEXT2(_L8("Loopback:WriteCancel: Unit %d..."), iPortName); |
|
934 |
|
935 |
|
936 // if there is a pending write (which could happen with the obey |
|
937 // flags), then we have to cancel the write. |
|
938 if (iWritePending) |
|
939 { |
|
940 iWritePending = EFalse; |
|
941 WriteCompleted(KErrCancel); |
|
942 } |
|
943 } |
|
944 |
|
945 void CHWPort::Break(TInt /* aTime */) |
|
946 /** |
|
947 * This method is currently not implemented in the loopback driver as breaks are |
|
948 * not supported. |
|
949 * |
|
950 * @param Not Used |
|
951 * |
|
952 * @return None |
|
953 */ |
|
954 |
|
955 // |
|
956 // Queue a Break |
|
957 // |
|
958 {} |
|
959 |
|
960 void CHWPort::BreakCancel() |
|
961 /** |
|
962 * This method is currently not implemented in the loopback driver as breaks are |
|
963 * not supported. |
|
964 * |
|
965 * @param None |
|
966 * |
|
967 * @return None |
|
968 */ |
|
969 // |
|
970 // Cancel a pending break |
|
971 // |
|
972 {} |
|
973 |
|
974 TInt CHWPort::GetConfig(TDes8& aDes) const |
|
975 /** |
|
976 * This gets the current configuration from the loopback driver. |
|
977 * |
|
978 * @param aDes - a TDes8 reference to copy the configuration into. |
|
979 * |
|
980 * @return KErrNone |
|
981 */ |
|
982 { |
|
983 |
|
984 LOGI(_L8("GetConfig:%04d %x \"%S\"")); |
|
985 |
|
986 LOGTEXT2(_L8("Loopback:GetConfig: Unit %d..."), iPortName); |
|
987 |
|
988 aDes.Copy(iConfig); |
|
989 return KErrNone; |
|
990 } |
|
991 |
|
992 TInt CHWPort::SetConfig(const TDesC8& aDes) |
|
993 /** |
|
994 * This sets the current configuration for the loopback driver. Note that |
|
995 * no error checking is done when setting the configuration. |
|
996 * |
|
997 * @param aDes - a TDes8 reference to copy the configuration from. |
|
998 * |
|
999 * @return KErrNone |
|
1000 */ |
|
1001 { |
|
1002 |
|
1003 LOGI(_L8("SetConfig:%04d %x \"%S\"")); |
|
1004 |
|
1005 LOGTEXT2(_L8("Loopback:SetConfig: Unit %d..."), iPortName); |
|
1006 |
|
1007 iConfig.Copy(aDes); |
|
1008 return KErrNone; |
|
1009 } |
|
1010 |
|
1011 TInt CHWPort::GetCaps(TDes8& aDes) |
|
1012 /** |
|
1013 * This gets the supported capabilities from the loopback driver. The actual capabilities of |
|
1014 * the driver will vary based on the role the port is playing (DCE or DTE). The loopback driver |
|
1015 * supports capabilities via TCommCapsV01 and TCommCapsV02. |
|
1016 * |
|
1017 * @param aDes - a TDes8 reference to copy the capabilities into. |
|
1018 * |
|
1019 * @return KErrNone - Everything is okay. |
|
1020 * @return KErrNotSupported - The length of the descriptor passed to this method indicates a |
|
1021 * capabilities structure which we don't support. |
|
1022 */ |
|
1023 { |
|
1024 |
|
1025 LOGI(_L8("GetCaps:%04d %x \"%S\"")); |
|
1026 |
|
1027 LOGTEXT2(_L8("Loopback:GetCaps: Unit %d..."), iPortName); |
|
1028 |
|
1029 if(aDes.Length()==sizeof(TCommCapsV01)) |
|
1030 { |
|
1031 TCommCapsV01* commcaps=(TCommCapsV01*)(aDes.Ptr()); |
|
1032 |
|
1033 // We've got all of these |
|
1034 commcaps->iRate=0x3fffff; |
|
1035 commcaps->iDataBits=0xf; |
|
1036 commcaps->iStopBits=0x3; |
|
1037 commcaps->iParity=0x1f; |
|
1038 commcaps->iFifo=0x1; |
|
1039 |
|
1040 if (ECommRoleDTE == iRole) |
|
1041 { |
|
1042 commcaps->iHandshake= KCapsObeyCTSSupported | KCapsFailCTSSupported | |
|
1043 KCapsObeyDSRSupported | KCapsFailDSRSupported | |
|
1044 KCapsObeyDCDSupported | KCapsFailDCDSupported; |
|
1045 } |
|
1046 else |
|
1047 { |
|
1048 commcaps->iHandshake= KCapsObeyRTSSupported | KCapsObeyDTRSupported; |
|
1049 } |
|
1050 |
|
1051 commcaps->iSignals=0x3f; |
|
1052 commcaps->iSIR=0x0; |
|
1053 return KErrNone; |
|
1054 } |
|
1055 else if(aDes.Length()==sizeof(TCommCapsV02)) |
|
1056 { |
|
1057 TCommCapsV02* commcaps=(TCommCapsV02*)(aDes.Ptr()); |
|
1058 // We've got all of these |
|
1059 commcaps->iRate=0x3fffff; |
|
1060 commcaps->iDataBits=0xf; |
|
1061 commcaps->iStopBits=0x3; |
|
1062 commcaps->iParity=0x1f; |
|
1063 commcaps->iFifo=0x1; |
|
1064 |
|
1065 if (ECommRoleDTE == iRole) |
|
1066 { |
|
1067 commcaps->iHandshake= KCapsObeyCTSSupported | KCapsFailCTSSupported | |
|
1068 KCapsObeyDSRSupported | KCapsFailDSRSupported | |
|
1069 KCapsObeyDCDSupported | KCapsFailDCDSupported | |
|
1070 KCapsFreeRTSSupported | KCapsFreeDTRSupported; |
|
1071 } |
|
1072 else |
|
1073 { |
|
1074 commcaps->iHandshake= KCapsObeyRTSSupported | KCapsObeyDTRSupported; |
|
1075 } |
|
1076 |
|
1077 commcaps->iSignals=0x3f; |
|
1078 commcaps->iSIR=0x0; |
|
1079 commcaps->iNotificationCaps=KNotifySignalsChangeSupported; |
|
1080 commcaps->iRoleCaps=0x0; |
|
1081 return KErrNone; |
|
1082 } |
|
1083 else |
|
1084 return KErrNotSupported; |
|
1085 } |
|
1086 |
|
1087 TInt CHWPort::SetServerConfig(const TDesC8& aDes) |
|
1088 /** |
|
1089 * This sets the current server configuration for the loopback driver. The loopback driver |
|
1090 * stores this information but does nothing with it. |
|
1091 * |
|
1092 * @param aDes - a TDes8 reference to copy the configuration from. |
|
1093 * |
|
1094 * @return KErrNone |
|
1095 */ |
|
1096 { |
|
1097 |
|
1098 LOGI(_L8("SetServerConfig:%04d %x \"%S\"")); |
|
1099 |
|
1100 LOGTEXT2(_L8("Loopback:SetServerConfig: Unit %d..."), iPortName); |
|
1101 |
|
1102 iServerConfig.Copy(aDes); |
|
1103 return KErrNone; |
|
1104 } |
|
1105 |
|
1106 TInt CHWPort::GetServerConfig(TDes8& aDes) |
|
1107 /** |
|
1108 * This gets the current server configuration for the loopback driver. The loopback driver |
|
1109 * stores this information but does nothing with it other than return it here. |
|
1110 * |
|
1111 * @param aDes - a TDes8 reference to copy the configuration to. |
|
1112 * |
|
1113 * @return KErrNone |
|
1114 */ |
|
1115 { |
|
1116 |
|
1117 LOGI(_L8("GetServerConfig:%04d %x \"%S\"")); |
|
1118 |
|
1119 LOGTEXT2(_L8("Loopback:GetServerConfig: Unit %d..."), iPortName); |
|
1120 |
|
1121 aDes.Copy(iServerConfig); |
|
1122 return KErrNone; |
|
1123 } |
|
1124 |
|
1125 TInt CHWPort::GetSignals(TUint& aSignals) |
|
1126 /** |
|
1127 * This method retrieves the current setting of the signals for THIS port. |
|
1128 * |
|
1129 * @param aSignals - A reference to a TUint to return the signal settings. |
|
1130 * |
|
1131 * @return KErrNone |
|
1132 */ |
|
1133 { |
|
1134 |
|
1135 LOGI(_L8("GetSignals:%04d %x \"%S\"")); |
|
1136 |
|
1137 LOGTEXT3(_L8("Loopback:GetSignals: Unit %d... Sigs 0x%x"), iPortName, iSignals); |
|
1138 |
|
1139 aSignals=iSignals; |
|
1140 return KErrNone; |
|
1141 } |
|
1142 |
|
1143 TInt CHWPort::SetSignalsToMark(TUint aSignals) |
|
1144 /** |
|
1145 * This method asserts the signals specified by the parameter aSignals. In addition to |
|
1146 * simply asserting the signals, this routine will complete any signal notification requests |
|
1147 * that are outstanding. After handling any signal notification requests, this routine will |
|
1148 * also update the signal state of it's partner loopback port. The other port's signals are |
|
1149 * updated only if they are considered output signals for the role that this port is playing. |
|
1150 * For example, assume that a DTE port is setting the RTS signal. It determines that RTS is |
|
1151 * an output signal for a DTE port, so it must propagate the signal to the DCE by calling |
|
1152 * this routine on the DCE instance of the port. When the DCE instance runs, it sets RTS, then |
|
1153 * determines that RTS is NOT a DCE output signal, so it does NOT attempt to propagate the signal. |
|
1154 * It is NOT an error for a DCE port to call this routine with DTE output signals. In fact, |
|
1155 * this behaviour is required in order to propagate signal settings from one port to the other. |
|
1156 * |
|
1157 * After propagating the signal settings, this method will attempt to complete reads and writes |
|
1158 * that have been outstanding, based on the changed signals and the configuration of the |
|
1159 * port. For example, say that the DTE port had been configured to Obey CTS (i.e., to flow control |
|
1160 * when CTS is not asserted). When the DCE asserts CTS, this signal would be propagated to the |
|
1161 * DTE port. Then the DTE port would check the current configuration and note that CTS has |
|
1162 * been asserted. At this point, there could be operations which were pended (because of the |
|
1163 * lack of CTS) that should be attempted. This method will attempt these operations. |
|
1164 * |
|
1165 * |
|
1166 * @param aSignals - a bitmask specifying which signals to assert (See definition |
|
1167 * of KSignalDCD, KSignalCTS, etc. for bit values). |
|
1168 * |
|
1169 * @return KErrNone |
|
1170 */ |
|
1171 { |
|
1172 |
|
1173 TBool attemptRead = EFalse; |
|
1174 TBool attemptWrite = EFalse; |
|
1175 TUint sigsChanged; |
|
1176 TUint tmpSigs; |
|
1177 |
|
1178 |
|
1179 |
|
1180 LOGI(_L8("SetSignalsToMark:%04d %x \"%S\"")); |
|
1181 |
|
1182 |
|
1183 LOGTEXT3(_L8("Loopback:SetSignalsToMark: Unit %d...Sigs 0x%x"), iPortName, aSignals); |
|
1184 |
|
1185 // If no signals are passed in to set, then get out of here. This is possible when |
|
1186 // the upper layers have used the RComm::SetSignals interface. This interface is used |
|
1187 // to both space and mark signals with a single call. Frequently, this interface is used |
|
1188 // with one of the two masks set to zero. |
|
1189 if (!aSignals) |
|
1190 return KErrNone; |
|
1191 |
|
1192 tmpSigs = iSignals; |
|
1193 iSignals |= aSignals; |
|
1194 |
|
1195 // sigsChanged contains only the signals changed by this operation, no history is contained. |
|
1196 sigsChanged = (iSignals ^ tmpSigs); |
|
1197 |
|
1198 // Only complete notifications if the changed sigs were specified in the mask. |
|
1199 if (sigsChanged & iSignalMask) |
|
1200 { |
|
1201 // Notify people that the signals have changed. |
|
1202 // Note that the KSignalChanged bits are stored in sigsChanged, but passed. |
|
1203 // The tmpSigs value has the state of all the signals that they were interested in |
|
1204 // as specified by the iSignalMask and the Changed flags. |
|
1205 tmpSigs = (((sigsChanged & iSignalMask) * KSignalChanged) | (iSignals & iSignalMask)); |
|
1206 SignalChangeCompleted(tmpSigs, KErrNone); |
|
1207 // Reset signal mask, another NotifiySignalChange is necessary to get any |
|
1208 // more signal information out of the driver. |
|
1209 iSignalMask = 0; |
|
1210 } |
|
1211 |
|
1212 // if I'm a DTE port and the signals changed are DTE outputs, then |
|
1213 // I've got to figure out what signals to change on the DCE side (as inputs). |
|
1214 // else if I'm a DCE port and the signals changed are DCE outputs, then |
|
1215 // I've got to figure out what DTE signals I've got to change. |
|
1216 if ((ECommRoleDTE == iRole) && (sigsChanged & KSignalDTEOutputs)) |
|
1217 { |
|
1218 if (iLoopbackPort) |
|
1219 iLoopbackPort->SetSignalsToMark(aSignals); |
|
1220 } |
|
1221 else if ((ECommRoleDCE == iRole) && (sigsChanged & KSignalDCEOutputs)) |
|
1222 { |
|
1223 if (iLoopbackPort) |
|
1224 iLoopbackPort->SetSignalsToMark(aSignals); |
|
1225 } |
|
1226 |
|
1227 |
|
1228 // if we dropped DCD, CTS, or DSR, then we need to complete any outstanding writes and |
|
1229 // reads on the DTE port if they have been configured to fail. |
|
1230 // We only look at the DTE input signals to see if the roles, etc. change. |
|
1231 if (ECommRoleDTE == iRole) |
|
1232 { |
|
1233 |
|
1234 // DCD and DSR affect both Reads and Writes, so we'll want to attempt both |
|
1235 // reads and writes later. |
|
1236 if (((iConfig().iHandshake & KConfigObeyDCD) && (sigsChanged & KSignalDCD)) || |
|
1237 ((iConfig().iHandshake & KConfigObeyDSR) && (sigsChanged & KSignalDSR))) |
|
1238 { |
|
1239 attemptRead = attemptWrite = ETrue; |
|
1240 } |
|
1241 |
|
1242 // CTS has NO effect on the Reads, so don't attempt to complete any reads here. |
|
1243 // No need to do this if we executed the above if ... |
|
1244 else if (((iConfig().iHandshake & KConfigObeyCTS) && (sigsChanged & KSignalCTS))) |
|
1245 { |
|
1246 attemptWrite = ETrue; |
|
1247 } |
|
1248 } |
|
1249 // if the DTE dropped the signals (RTS and DTR) the complete actions for the DCE |
|
1250 // only look at the DCE input signals. |
|
1251 else if (ECommRoleDCE == iRole) |
|
1252 { |
|
1253 // if DTR has changed, then we need to try to complete both reads and writes. |
|
1254 if (((iConfig().iHandshake & KConfigObeyDTR) && (sigsChanged & KSignalDTR))) |
|
1255 { |
|
1256 attemptRead = attemptWrite = ETrue; |
|
1257 } |
|
1258 // if RTS has changed, only attempt the Writes, RTS does not effect Reads. |
|
1259 // No need to do this if we executed the above if ... |
|
1260 else if (((iConfig().iHandshake & KConfigObeyRTS) && (sigsChanged & KSignalRTS))) |
|
1261 { |
|
1262 attemptWrite = ETrue; |
|
1263 } |
|
1264 |
|
1265 } |
|
1266 |
|
1267 // Attempt to complete any writes if necessary. Note that if we do a write for THIS |
|
1268 // port, it will attempt to complete a read for the Loopback port. Because this method |
|
1269 // calls itself (on the other port), we can end up trying to complete reads and writes |
|
1270 // a couple of times. By checking the pending flags for writes and reads, we should |
|
1271 // avoid this extra work (even though it probably would not hurt anything). |
|
1272 if ((attemptWrite) && (iWritePending)) |
|
1273 { |
|
1274 TBool issueComplete = EFalse; |
|
1275 TInt res=WriteBuf(iClientWriteBuffer,iWritePendingLength, issueComplete); |
|
1276 |
|
1277 if (issueComplete) |
|
1278 { |
|
1279 WriteCompleted(res); |
|
1280 } |
|
1281 } |
|
1282 |
|
1283 // Attempt to complete any reads if necessary. See comment above writes for information |
|
1284 // regarding the use of the pending flags. Note that we call this on our own port. This |
|
1285 // is by design. If a write was attempted, then it called the the read completion on the |
|
1286 // other port. |
|
1287 if ((attemptRead) && (iReadPending)) |
|
1288 { |
|
1289 CheckSigsAndCompleteRead(); |
|
1290 } |
|
1291 |
|
1292 |
|
1293 return KErrNone; |
|
1294 } |
|
1295 |
|
1296 |
|
1297 |
|
1298 TInt CHWPort::SetSignalsToSpace(TUint aSignals) |
|
1299 /** |
|
1300 * This method de-asserts the signals specified by the parameter aSignals. In addition to |
|
1301 * simply de-asserting the signals, this routine will complete any signal notification requests |
|
1302 * that are outstanding. After handling any signal notification requests, this routine will |
|
1303 * also update the signal state of it's partner loopback port. The other ports signals are |
|
1304 * updated only if they are considered output signals for the role that this port is playing. |
|
1305 * For example, assume that a DTE port is deasserting the RTS signal. It determines that RTS is |
|
1306 * an output signal for a DTE port, so it must propagate the signal to the DCE by calling |
|
1307 * this routine on the DCE instance of the port. When the DCE instance runs, it clears RTS, then |
|
1308 * determines that RTS is NOT a DCE output signal, so it does NOT attempt to propagate the signal. |
|
1309 * It is NOT an error for a DCE port to call this routine with DTE output signals. |
|
1310 * In fact, this behaviour is required in order to * propagate signal settings from one port |
|
1311 * to the other. |
|
1312 * |
|
1313 * If signals are de-asserted, then it may be necessary to FAIL pending operations. For example, |
|
1314 * if the port is configured to Fail if DCD is de-asserted and there is a read pending, this |
|
1315 * routine will complete the outstanding read with KErrCommsLineFail. |
|
1316 * |
|
1317 * |
|
1318 * @param aSignals - a bitmask specifying which signals to assert (See definition |
|
1319 * of KSignalDCD, KSignalCTS, etc. for bit values). |
|
1320 * |
|
1321 * @return KErrNone |
|
1322 */ |
|
1323 { |
|
1324 TBool completeRead = EFalse; |
|
1325 TBool completeWrite = EFalse; |
|
1326 TUint sigsChanged; |
|
1327 TUint tmpSigs; |
|
1328 |
|
1329 LOGI(_L8("SetSignalsToSpace:%04d %x \"%S\"")); |
|
1330 |
|
1331 LOGTEXT3(_L8("Loopback:SetSignalsToSpace: Unit %d...Sigs 0x%x"), iPortName, aSignals); |
|
1332 |
|
1333 |
|
1334 // If no signals are passed in to set, then get out of here. This is possible when |
|
1335 // the upper layers have used the RComm::SetSignals interface. This interface is used |
|
1336 // to both space and mark signals with a single call. Frequently, this interface is used |
|
1337 // with one of the two masks set to zero. |
|
1338 if (!aSignals) |
|
1339 return KErrNone; |
|
1340 |
|
1341 |
|
1342 // iSignals is used to store the current state of the signals only, it does not |
|
1343 // include the changed masks. This is so that history will not be reflected. |
|
1344 tmpSigs = iSignals; |
|
1345 iSignals &= ~aSignals; |
|
1346 |
|
1347 // sigsChanged contains only the signals changed by this operation, no history is contained. |
|
1348 sigsChanged = (iSignals ^ tmpSigs); |
|
1349 |
|
1350 // Only complete notifications if the changed sigs were specified in the mask. |
|
1351 if (sigsChanged & iSignalMask) |
|
1352 { |
|
1353 // Notify people that the signals have changed. |
|
1354 // Note that the KSignalChanged bits are stored in sigsChanged, but passed. |
|
1355 // The tmpSigs value has the state of all the signals that they were interested in |
|
1356 // as specified by the iSignalMask and the Changed flags. |
|
1357 tmpSigs = (((sigsChanged & iSignalMask) * KSignalChanged) | (iSignals & iSignalMask)); |
|
1358 SignalChangeCompleted(tmpSigs, KErrNone); |
|
1359 // Reset signal mask, another NotifiySignalChange is necessary to get any |
|
1360 // more signal information out of the driver. |
|
1361 iSignalMask = 0; |
|
1362 } |
|
1363 |
|
1364 // if I'm a DTE port and the signals changed are DTE outputs, then |
|
1365 // I've got to figure out what signals to change on the DCE side (as inputs). |
|
1366 // else if I'm a DCE port and the signals changed are DCE outputs, then |
|
1367 // I've got to figure out what DTE signals I've got to change. |
|
1368 |
|
1369 // The DTE Role could be ignored safely (Req7) but as long as the test |
|
1370 // harness does not ever request notification, it won't matter. This is |
|
1371 // for potential future use. |
|
1372 if ((ECommRoleDTE == iRole) && (sigsChanged & KSignalDTEOutputs)) |
|
1373 { |
|
1374 if (iLoopbackPort) |
|
1375 iLoopbackPort->SetSignalsToSpace(aSignals); |
|
1376 } |
|
1377 else if ((ECommRoleDCE == iRole) && (sigsChanged & KSignalDCEOutputs)) |
|
1378 { |
|
1379 if (iLoopbackPort) |
|
1380 iLoopbackPort->SetSignalsToSpace(aSignals); |
|
1381 } |
|
1382 |
|
1383 // if we dropped DCD, CTS, or DSR, then we need to complete any outstanding writes and |
|
1384 // reads on the DTE port if they have been configured to fail. |
|
1385 // We only look at the DTE input signals to see if the roles, etc. change. |
|
1386 if (ECommRoleDTE == iRole) |
|
1387 { |
|
1388 // DCD and DSR affect both Reads and Writes, so we'll want to complete both |
|
1389 // reads and writes later. |
|
1390 if (((iConfig().iHandshake & KConfigFailDCD) && (sigsChanged & KSignalDCD)) || |
|
1391 ((iConfig().iHandshake & KConfigFailDSR) && (sigsChanged & KSignalDSR))) |
|
1392 { |
|
1393 completeRead = completeWrite = ETrue; |
|
1394 } |
|
1395 |
|
1396 // CTS has NO effect on the Reads, so don't attempt to complete any reads here. |
|
1397 // No need to do this if we executed the above if ... |
|
1398 else if (((iConfig().iHandshake & KConfigFailCTS) && (sigsChanged & KSignalCTS))) |
|
1399 { |
|
1400 completeWrite = ETrue; |
|
1401 } |
|
1402 } |
|
1403 // if the DTE dropped the signals (RTS and DTR) the complete actions for the DCE |
|
1404 // only look at the DCE input signals. |
|
1405 else if (ECommRoleDCE == iRole) |
|
1406 { |
|
1407 // if DTR has changed, then we need to try to complete both reads and writes. |
|
1408 if (((iConfig().iHandshake & KConfigFailDTR) && (sigsChanged & KSignalDTR))) |
|
1409 { |
|
1410 completeRead = completeWrite = ETrue; |
|
1411 } |
|
1412 // if RTS has changed, only attempt the Writes, RTS does not effect Reads. |
|
1413 // No need to do this if we executed the above if ... |
|
1414 else if (((iConfig().iHandshake & KConfigFailRTS) && (sigsChanged & KSignalRTS))) |
|
1415 { |
|
1416 completeWrite = ETrue; |
|
1417 } |
|
1418 } |
|
1419 |
|
1420 // Note: We don't have to work with the Obey flags when we set signals. The obey flags |
|
1421 // when something is set force future operations to be pended. Operations currently pended |
|
1422 // or already completed don't have any effect. If any of the signals were treated as Active |
|
1423 // Low (or Asserted means error condition) then we would have to attempt to complete |
|
1424 // reads or writes. |
|
1425 // |
|
1426 |
|
1427 // if we need to complete the read and there is one pending, fail it. |
|
1428 if ((completeRead) && (iReadPending)) |
|
1429 { |
|
1430 ReadCompleted(KErrCommsLineFail); |
|
1431 iReadPending = EFalse; |
|
1432 } |
|
1433 |
|
1434 // if we need to complete writes, do it here. |
|
1435 if ((completeWrite) && (iWritePending)) |
|
1436 { |
|
1437 WriteCompleted(KErrCommsLineFail); |
|
1438 iWritePending = EFalse; |
|
1439 } |
|
1440 |
|
1441 return KErrNone; |
|
1442 } |
|
1443 |
|
1444 TInt CHWPort::GetReceiveBufferLength(TInt& /* aLength */) const |
|
1445 /** |
|
1446 * This method is currently not implemented in the loopback driver. Calling this |
|
1447 * method will return an error |
|
1448 * |
|
1449 * @param Not Used |
|
1450 * |
|
1451 * @return KErrNotSupported |
|
1452 */ |
|
1453 { |
|
1454 |
|
1455 LOGI(_L8("GetReceiveBufferLength:%04d %x \"%S\"")); |
|
1456 return KErrNotSupported; |
|
1457 } |
|
1458 |
|
1459 TInt CHWPort::SetReceiveBufferLength(TInt /* aLength */) |
|
1460 /** |
|
1461 * This method is currently not implemented in the loopback driver. Calling this |
|
1462 * method will return an error |
|
1463 * |
|
1464 * @param Not Used |
|
1465 * |
|
1466 * @return KErrNotSupported |
|
1467 */ |
|
1468 { |
|
1469 LOGI(_L8("SetReceiveBufferLength:%04d %x \"%S\"")); |
|
1470 return KErrNotSupported; |
|
1471 } |
|
1472 |
|
1473 #ifdef _DEBUG_DEVCOMM |
|
1474 // This code will not compile given current class structure, etc. It is left here for |
|
1475 // future reference. |
|
1476 void CHWPort::DoDumpDebugInfo(const RMessage2 &aMessage) |
|
1477 { |
|
1478 TCommDebugInfoPckg d; |
|
1479 if (iRole==ECommRoleDTE) |
|
1480 iPort.DebugInfo(d); |
|
1481 else |
|
1482 iPortDCE.DebugInfo(d); |
|
1483 TRAPD(leave,aMessage.WriteL(0,d)); // trap but ignore leaves |
|
1484 aMessage.Complete(KErrNone); |
|
1485 } |
|
1486 #endif |
|
1487 |
|
1488 void CHWPort::Destruct() |
|
1489 /** |
|
1490 * This method is simply deletes this instance of the port, comitting sucide. |
|
1491 * |
|
1492 * @param None |
|
1493 * |
|
1494 * @return None |
|
1495 */ |
|
1496 { |
|
1497 delete this; |
|
1498 } |
|
1499 |
|
1500 |
|
1501 |
|
1502 void CHWPort::NotifySignalChange(TUint aSignalMask) |
|
1503 /** |
|
1504 * This method sets up a request to be notified when a signal change occurs on the specified |
|
1505 * signals. Later operations will send a message to the requestor indicating the signal |
|
1506 * change. |
|
1507 * |
|
1508 * @param aSignalMask - the signals that the caller is interested in monitoring. |
|
1509 * |
|
1510 * @return None |
|
1511 */ |
|
1512 { |
|
1513 |
|
1514 LOGTEXT3(_L8("Loopback:NotifySignalChange: Unit %d...Mask 0x%x"), iPortName, aSignalMask); |
|
1515 |
|
1516 iSignalMask|=aSignalMask; |
|
1517 |
|
1518 } |
|
1519 |
|
1520 |
|
1521 void CHWPort::NotifySignalChangeCancel() |
|
1522 /** |
|
1523 * This method cancels an outstanding request to be notified when a signal change occurs. Any |
|
1524 * outstanding signal change request will be completed with KErrCancel. |
|
1525 * |
|
1526 * @param None |
|
1527 * |
|
1528 * @return None |
|
1529 */ |
|
1530 { |
|
1531 |
|
1532 LOGTEXT2(_L8("Loopback:NotifySignalChangeCancel: Unit %d..."), iPortName); |
|
1533 |
|
1534 if (iSignalMask != 0) |
|
1535 { |
|
1536 // Complete any outstanding notifications with KErrCancel |
|
1537 SignalChangeCompleted(0, KErrCancel); |
|
1538 iSignalMask = 0; // set mask to zero |
|
1539 } |
|
1540 } |
|
1541 |
|
1542 |
|
1543 void CHWPort::NotifyConfigChange() |
|
1544 /** |
|
1545 * This method is currently not implemented in the loopback driver. |
|
1546 * |
|
1547 * @param None |
|
1548 * |
|
1549 * @return None |
|
1550 */ |
|
1551 {} |
|
1552 |
|
1553 void CHWPort::NotifyConfigChangeCancel() |
|
1554 /** |
|
1555 * This method is currently not implemented in the loopback driver. |
|
1556 * |
|
1557 * @param None |
|
1558 * |
|
1559 * @return None |
|
1560 */ |
|
1561 {} |
|
1562 |
|
1563 void CHWPort::NotifyFlowControlChange() |
|
1564 /** |
|
1565 * This method is currently not implemented in the loopback driver. |
|
1566 * |
|
1567 * @param None |
|
1568 * |
|
1569 * @return None |
|
1570 */ |
|
1571 {} |
|
1572 |
|
1573 void CHWPort::NotifyFlowControlChangeCancel() |
|
1574 /** |
|
1575 * This method is currently not implemented in the loopback driver. |
|
1576 * |
|
1577 * @param None |
|
1578 * |
|
1579 * @return None |
|
1580 */ |
|
1581 {} |
|
1582 |
|
1583 |
|
1584 void CHWPort::NotifyBreak() |
|
1585 /** |
|
1586 * This method is currently not implemented in the loopback driver. |
|
1587 * |
|
1588 * @param None |
|
1589 * |
|
1590 * @return None |
|
1591 */ |
|
1592 {} |
|
1593 |
|
1594 void CHWPort::NotifyBreakCancel() |
|
1595 /** |
|
1596 * This method is currently not implemented in the loopback driver. |
|
1597 * |
|
1598 * @param None |
|
1599 * |
|
1600 * @return None |
|
1601 */ |
|
1602 {} |
|
1603 |
|
1604 void CHWPort::NotifyDataAvailable() |
|
1605 /** |
|
1606 * Wake up when data is sent by the other side |
|
1607 * |
|
1608 * @param None |
|
1609 * |
|
1610 * @return None |
|
1611 */ |
|
1612 { |
|
1613 iDataNotify=ETrue; |
|
1614 CheckSigsAndCompleteRead(); |
|
1615 } |
|
1616 |
|
1617 void CHWPort::NotifyDataAvailableCancel() |
|
1618 /** |
|
1619 * Cancel data available notification |
|
1620 * |
|
1621 * @param None |
|
1622 * |
|
1623 * @return None |
|
1624 */ |
|
1625 { |
|
1626 iDataNotify=EFalse; |
|
1627 NotifyDataAvailableCompleted(KErrCancel); |
|
1628 } |
|
1629 |
|
1630 void CHWPort::NotifyOutputEmpty() |
|
1631 /** |
|
1632 * This method is currently not implemented in the loopback driver. |
|
1633 * |
|
1634 * @param None |
|
1635 * |
|
1636 * @return None |
|
1637 */ |
|
1638 {} |
|
1639 |
|
1640 void CHWPort::NotifyOutputEmptyCancel() |
|
1641 /** |
|
1642 * This method is currently not implemented in the loopback driver. |
|
1643 * |
|
1644 * @param None |
|
1645 * |
|
1646 * @return None |
|
1647 */ |
|
1648 { |
|
1649 } |
|
1650 |
|
1651 TInt CHWPort::GetFlowControlStatus(TFlowControl& /* aFlowControl */) |
|
1652 /** |
|
1653 * This method is currently not implemented in the loopback driver. |
|
1654 * |
|
1655 * @param Not Used |
|
1656 * |
|
1657 * @return KErrNotSupported |
|
1658 */ |
|
1659 { |
|
1660 return KErrNotSupported; |
|
1661 } |
|
1662 |
|
1663 TInt CHWPort::GetRole(TCommRole& aRole) |
|
1664 /** |
|
1665 * This method returns the current Role that this port is playing (ECommRoleDCE or ECommRoleDTE) |
|
1666 * |
|
1667 * @param aRole - a reference to a TCommRole to return the role value in. |
|
1668 * |
|
1669 * @return KErrNone |
|
1670 */ |
|
1671 { |
|
1672 LOGTEXT2(_L8("Loopback:GetRole: Unit %d..."), iPortName); |
|
1673 |
|
1674 aRole=iRole; |
|
1675 return KErrNone; |
|
1676 } |
|
1677 |
|
1678 TInt CHWPort::SetRole(TCommRole aRole) |
|
1679 /** |
|
1680 * This method sets the role of the port. Additionally, it sets the default state of the |
|
1681 * signals for this type of port. This is the first place where signals are set as a port |
|
1682 * is opening. The ports will assert their output signals with the exception of DCD (which |
|
1683 * is an output signal from the DCE). DCD is left to be driven by the test harness. |
|
1684 * |
|
1685 * A test could be put into place to insure that each port is in a different role. This was |
|
1686 * not done at this time for backwards compatibility reasons. |
|
1687 * |
|
1688 * @param aRole - the TCommRole value that this port should be set to. |
|
1689 * |
|
1690 * @return None |
|
1691 */ |
|
1692 { |
|
1693 LOGTEXT2(_L8("Loopback:SetRole: Unit %d..."), iPortName); |
|
1694 |
|
1695 if (ECommRoleDTE == aRole) |
|
1696 { |
|
1697 SetSignalsToMark(KSignalDTR|KSignalRTS); |
|
1698 } |
|
1699 else // DCE |
|
1700 { |
|
1701 SetSignalsToMark(KSignalDSR|KSignalCTS); |
|
1702 } |
|
1703 |
|
1704 |
|
1705 // Informational test only. This will produce output to the log file if both sides have the |
|
1706 // same role set. With both sides having the same role, none of the signal handling will |
|
1707 // function properly. |
|
1708 #if defined (_DEBUG) |
|
1709 if (iLoopbackPort) |
|
1710 { |
|
1711 TCommRole otherSide; |
|
1712 iLoopbackPort->GetRole(otherSide); |
|
1713 if (otherSide == aRole) |
|
1714 LOGTEXT3(_L8("Loopback:SetRole: Unit %d...Both sides same role %d"), iPortName, aRole); |
|
1715 } |
|
1716 #endif |
|
1717 |
|
1718 iRole = aRole; |
|
1719 return KErrNone; |
|
1720 } |
|
1721 |
|
1722 CHWPort::~CHWPort() |
|
1723 /** |
|
1724 * This method is the standard destructor for the port. It deletes the buffer |
|
1725 * which was allocated to the port and resets the loopback port pointer to NULL. |
|
1726 * |
|
1727 * @param None |
|
1728 * |
|
1729 * @return None |
|
1730 */ |
|
1731 { |
|
1732 |
|
1733 |
|
1734 delete iBuf; |
|
1735 iBuf=NULL; |
|
1736 iPtr.Set(NULL,0,0); |
|
1737 if(iLoopbackPort) |
|
1738 iLoopbackPort->SetLoopbackPort(NULL); |
|
1739 ((CHWPortFactory*)Owner())->Remove(this); |
|
1740 |
|
1741 #if defined (_DEBUG_CONSOLE_) |
|
1742 #if defined (_DEBUG_DEVCOMM) |
|
1743 delete iDumper; |
|
1744 #endif |
|
1745 iConsole.Close(); |
|
1746 #endif |
|
1747 } |
|
1748 |
|
1749 void CHWPort::FreeMemory() |
|
1750 /** |
|
1751 * This method is currently not implemented in the loopback driver. |
|
1752 * |
|
1753 * @param None |
|
1754 * |
|
1755 * @return None |
|
1756 */ |
|
1757 {} |
|
1758 |
|
1759 CPort* CHWPortFactory::NewPortL(const TUint aUnit) |
|
1760 /** |
|
1761 * This method creates a new port object. It identifies the new object with the unit number that |
|
1762 * is supplied. If both ports that are supported by the CHWPortFactory object have been created, |
|
1763 * then the loopback ports are initialized. |
|
1764 * |
|
1765 * @param aUnit - The unit number to create. |
|
1766 * |
|
1767 * @return CPort * - A pointer to the newly created object. |
|
1768 */ |
|
1769 { |
|
1770 LOGTEXT2(_L8("Loopback:NewPortL: Unit %d"), aUnit); |
|
1771 if(aUnit >= (KLoopbackCount&~1)) |
|
1772 User::Leave(KErrNotSupported); |
|
1773 |
|
1774 CPort* newPort; |
|
1775 if (iPort[aUnit]) |
|
1776 { |
|
1777 LOGTEXT3(_L8("Loopback:NewPortL: Unit %d already exists! @%x"), aUnit, iPort[aUnit]); |
|
1778 } |
|
1779 newPort=iPort[aUnit]=CHWPort::NewL(aUnit); |
|
1780 |
|
1781 if((iPort[aUnit])&&(PairedPort(aUnit))) |
|
1782 { |
|
1783 iPort[aUnit]->SetLoopbackPort(PairedPort(aUnit)); |
|
1784 PairedPort(aUnit)->SetLoopbackPort(iPort[aUnit]); |
|
1785 } |
|
1786 return newPort; |
|
1787 } |
|
1788 |
|
1789 void CHWPortFactory::Info(TSerialInfo &aSerialInfo) |
|
1790 /** |
|
1791 * This method fills information into the passed structure. It is required for factory objects. |
|
1792 * |
|
1793 * @param aSerialInfo - a reference to the structure to fill in. |
|
1794 * |
|
1795 * @return None |
|
1796 */ |
|
1797 { |
|
1798 aSerialInfo.iDescription=SERIAL_DESCRIPTION; |
|
1799 aSerialInfo.iName=SERIAL_NAME; |
|
1800 aSerialInfo.iLowUnit=KCommLowUnit; |
|
1801 aSerialInfo.iHighUnit=KLoopbackCount - 1; |
|
1802 } |
|
1803 |
|
1804 CHWPortFactory::CHWPortFactory() |
|
1805 /** |
|
1806 * This method is the constructor for the factory object. |
|
1807 * |
|
1808 * @param None |
|
1809 * |
|
1810 * @return None |
|
1811 */ |
|
1812 { |
|
1813 __DECLARE_NAME(_S("CHWPortFactory")); |
|
1814 TName name(SERIAL_NAME); |
|
1815 SetName(&name); |
|
1816 iVersion=TVersion(KEC32MajorVersionNumber,KEC32MinorVersionNumber,KEC32BuildVersionNumber); |
|
1817 } |
|
1818 |
|
1819 void CHWPortFactory::Remove(CHWPort* aPort) |
|
1820 /** |
|
1821 * This method removes an instance of the CHWPort from the factory package CHWPortFactory. |
|
1822 * |
|
1823 * @param aPort - The pointer to the CHWPort pointer to be removed from the factory object. |
|
1824 * |
|
1825 * @return None |
|
1826 * |
|
1827 * @note If the passed in value does not match a current port, this method will panic. |
|
1828 */ |
|
1829 { |
|
1830 LOGTEXT2(_L8("Loopback:Remove: Port %x"), aPort); |
|
1831 for(TUint i=0; i<KLoopbackCount; i++) |
|
1832 { |
|
1833 if(iPort[i]==aPort) |
|
1834 { |
|
1835 iPort[i]=NULL; |
|
1836 return; |
|
1837 } |
|
1838 } |
|
1839 User::Panic(_L("CHWPortFactory Panic"),0); |
|
1840 } |
|
1841 |
|
1842 CHWPortFactory::~CHWPortFactory() |
|
1843 /** |
|
1844 * This method is the destructor for the factory object. |
|
1845 * |
|
1846 * @param None |
|
1847 * |
|
1848 * @return None |
|
1849 * |
|
1850 */ |
|
1851 { |
|
1852 |
|
1853 LOGDESTROY(); |
|
1854 |
|
1855 } |
|
1856 |
|
1857 /** |
|
1858 Returns capabilities for requested port |
|
1859 */ |
|
1860 TSecurityPolicy CHWPortFactory::PortPlatSecCapability(TUint /*aPort*/) const |
|
1861 { |
|
1862 return TSecurityPolicy(TSecurityPolicy::EAlwaysPass); |
|
1863 } |
|
1864 |
|
1865 extern "C" |
|
1866 { |
|
1867 IMPORT_C CSerial * LibEntry(void); // Force export |
|
1868 } |
|
1869 |
|
1870 EXPORT_C CSerial * LibEntry(void) |
|
1871 /** |
|
1872 * This method is the library's main entry point. It simply new's the factory object. |
|
1873 * |
|
1874 * @param None |
|
1875 * |
|
1876 * @return None |
|
1877 * |
|
1878 */ |
|
1879 { |
|
1880 |
|
1881 return new CHWPortFactory; |
|
1882 } |
|
1883 |
|
1884 |
|
1885 #if defined(_DEBUG_CONSOLE_) |
|
1886 // This code will not compile given current class structure, etc. It is left here for |
|
1887 // future reference. |
|
1888 RDebugConsole::RDebugConsole() |
|
1889 { |
|
1890 Create(); |
|
1891 Set(_L(""),TSize(64,15)); |
|
1892 |
|
1893 } |
|
1894 |
|
1895 void RDebugConsole::Printf(TRefByValue<const TDesC> aFmt,...) |
|
1896 // |
|
1897 // Print to a console screen. |
|
1898 // |
|
1899 { |
|
1900 |
|
1901 VA_LIST list; |
|
1902 VA_START(list,aFmt); |
|
1903 TBuf<0x100> aBuf; |
|
1904 aBuf.AppendFormatList(aFmt,list); |
|
1905 Write(aBuf); |
|
1906 } |
|
1907 #endif |
|
1908 |
|
1909 #if defined (_DEBUG_DEVCOMM) && defined (_DEBUG_CONSOLE_) |
|
1910 CCommDebugDumper* CCommDebugDumper::NewL(RDebugConsole &aConsole) |
|
1911 { |
|
1912 CCommDebugDumper* p=new CCommDebugDumper(aConsole); |
|
1913 return p; |
|
1914 } |
|
1915 |
|
1916 CCommDebugDumper::CCommDebugDumper(RDebugConsole &aConsole) |
|
1917 :CActive(EPriorityStandard) |
|
1918 { |
|
1919 iRole=ECommRoleDTE; |
|
1920 iConsole=&aConsole; |
|
1921 CActiveScheduler::Add(this); |
|
1922 SetActive(); |
|
1923 iConsole->Read(iKeystroke,iStatus); |
|
1924 }; |
|
1925 |
|
1926 CCommDebugDumper::~CCommDebugDumper() |
|
1927 { |
|
1928 Cancel(); |
|
1929 } |
|
1930 |
|
1931 void CCommDebugDumper::RunL() |
|
1932 { |
|
1933 TInt key=iKeystroke.Code(); |
|
1934 switch(key) |
|
1935 { |
|
1936 case 'd': |
|
1937 case 'D': |
|
1938 { |
|
1939 TCommDebugInfoPckg d; |
|
1940 if (iRole==ECommRoleDTE) |
|
1941 iParent->DTEPort().DebugInfo(d); |
|
1942 else |
|
1943 iParent->DCEPort().DebugInfo(d); |
|
1944 TCommDebugInfo& debug=d(); |
|
1945 iConsole->Printf(_L("rxbusy : 0x%04x, rxHeld : 0x%04x, \n\r"),debug.iRxBusy,debug.iRxHeld); |
|
1946 iConsole->Printf(_L("txbusy : 0x%04x, txHeld : 0x%04x, \n\r"),debug.iTxBusy,debug.iTxHeld); |
|
1947 iConsole->Printf(_L("drainRx : 0x%04x, fillTx : 0x%04x\n\r"),debug.iDrainingRxBuf,debug.iFillingTxBuf); |
|
1948 iConsole->Printf(_L("Txonchar: 0x%04x, TxOffchar: 0x%04x\n\r"),debug.iTxXon,debug.iTxXoff); |
|
1949 iConsole->Printf(_L("RxonChar: 0x%04x, RxOffchar: 0x%04x\n\r"),debug.iRxXon,debug.iRxXoff); |
|
1950 iConsole->Printf(_L("NumTX : 0x%04x, NumRx : 0x%04x\n\r"),debug.iTxChars,debug.iRxChars); |
|
1951 iConsole->Printf(_L("TxLen : 0x%04x, RxLen : 0x%04x\n\r"),debug.iTxLength,debug.iRxLength); |
|
1952 iConsole->Printf(_L("TxOffset: 0x%04x, RxOffset : 0x%04x\n\r"),debug.iTxOffset,debug.iRxOffset); |
|
1953 iConsole->Printf(_L("TxInts : 0x%04x, RxInts : 0x%04x\n\r"),debug.iTxIntCount,debug.iRxIntCount); |
|
1954 } |
|
1955 break; |
|
1956 case 's': |
|
1957 case 'S': |
|
1958 { |
|
1959 TUint signals=0; |
|
1960 if (iRole==ECommRoleDTE) |
|
1961 signals=iParent->DTEPort().Signals(); |
|
1962 else |
|
1963 signals=iParent->DCEPort().Signals(); |
|
1964 iConsole->Printf(_L("Signals: ")); |
|
1965 if (signals&KSignalCTS) |
|
1966 iConsole->Printf(_L("CTS ")); |
|
1967 if (signals&KSignalDSR) |
|
1968 iConsole->Printf(_L("DSR ")); |
|
1969 if (signals&KSignalDCD) |
|
1970 iConsole->Printf(_L("DCD ")); |
|
1971 if (signals&KSignalRTS) |
|
1972 iConsole->Printf(_L("RTS ")); |
|
1973 if (signals&KSignalDTR) |
|
1974 iConsole->Printf(_L("DTR ")); |
|
1975 iConsole->Printf(_L("\n\r")); |
|
1976 } |
|
1977 break; |
|
1978 default: |
|
1979 break; |
|
1980 } |
|
1981 |
|
1982 SetActive(); |
|
1983 iConsole->Read(iKeystroke,iStatus); |
|
1984 }; |
|
1985 |
|
1986 void CCommDebugDumper::DoCancel() |
|
1987 { |
|
1988 iConsole->ReadCancel(); |
|
1989 } |
|
1990 |
|
1991 #endif |