Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2408 lines
79 KiB

  1. /***************************************************************************
  2. Name : FCOM.C
  3. Comment : Functions for dealing with Windows Comm driver
  4. Revision Log
  5. Num Date Name Description
  6. --- -------- ---------- -----------------------------------------------
  7. ***************************************************************************/
  8. #define USE_DEBUG_CONTEXT DEBUG_CONTEXT_T30_COMM
  9. #include "prep.h"
  10. #include <comdevi.h>
  11. #include "fcomapi.h"
  12. #include "fcomint.h"
  13. #include "fdebug.h"
  14. ///RSL
  15. #include "t30gl.h"
  16. #include "glbproto.h"
  17. #include "psslog.h"
  18. #define FILE_ID FILE_ID_FCOM
  19. /***------------- Local Vars and defines ------------------***/
  20. #define AT "AT"
  21. #define cr "\r"
  22. #define iSyncModemDialog2(pTG, s, l, w1, w2)\
  23. iiModemDialog(pTG, s, l, 990, TRUE, 2, TRUE, (CBPSTR)w1, (CBPSTR)w2, (CBPSTR)(NULL))
  24. #define LONG_DEADCOMMTIMEOUT 60000L
  25. #define SHORT_DEADCOMMTIMEOUT 10000L
  26. #define WAIT_FCOM_FILTER_FILLCACHE_TIMEOUT 120000
  27. #define WAIT_FCOM_FILTER_READBUF_TIMEOUT 120000
  28. // don't want DEADCOMMTIMEOUT to be greater than 32767, so make sure
  29. // buf sizes are always 9000 or less. maybe OK.
  30. // Our COMM timeout settings, used in call to SetCommTimeouts. These
  31. // values (expect read_interval_timeout) are the default values for
  32. // Daytona NT Beta 2, and seem to work fine..
  33. #define READ_INTERVAL_TIMEOUT 100
  34. #define READ_TOTAL_TIMEOUT_MULTIPLIER 0
  35. #define READ_TOTAL_TIMEOUT_CONSTANT 0
  36. #define WRITE_TOTAL_TIMEOUT_MULTIPLIER 0
  37. #define WRITE_TOTAL_TIMEOUT_CONSTANT LONG_DEADCOMMTIMEOUT
  38. #define CTRL_P 0x10
  39. #define CTRL_Q 0x11
  40. #define CTRL_S 0x13
  41. #define MYGETCOMMERROR_FAILED 117437834L
  42. // Forward declarations
  43. static BOOL FComFilterFillCache(PThrdGlbl pTG, UWORD cbSize, LPTO lptoRead);
  44. static BOOL CancellPendingIO(PThrdGlbl pTG, HANDLE hComm, LPOVERLAPPED lpOverlapped, LPDWORD lpCounter);
  45. BOOL FComDTR(PThrdGlbl pTG, BOOL fEnable)
  46. {
  47. DEBUG_FUNCTION_NAME(_T("FComDTR"));
  48. DebugPrintEx(DEBUG_MSG,"FComDTR = %d", fEnable);
  49. if(!GetCommState(pTG->hComm, &(pTG->Comm.dcb)))
  50. goto error;
  51. DebugPrintEx(DEBUG_MSG, "Before: %02x", pTG->Comm.dcb.fDtrControl);
  52. pTG->Comm.dcb.fDtrControl = (fEnable ? DTR_CONTROL_ENABLE : DTR_CONTROL_DISABLE);
  53. if(!SetCommState(pTG->hComm, &(pTG->Comm.dcb)))
  54. goto error;
  55. DebugPrintEx(DEBUG_MSG,"After: %02x", pTG->Comm.dcb.fDtrControl);
  56. return TRUE;
  57. error:
  58. DebugPrintEx(DEBUG_ERR, "Can't Set/Get DCB");
  59. GetCommErrorNT(pTG);
  60. return FALSE;
  61. }
  62. BOOL FComClose(PThrdGlbl pTG)
  63. {
  64. BOOL fRet = TRUE;
  65. DEBUG_FUNCTION_NAME(_T("FComClose"));
  66. DebugPrintEx( DEBUG_MSG, "Closing Comm pTG->hComm=%d", pTG->hComm);
  67. //
  68. // handoff
  69. //
  70. if (pTG->Comm.fEnableHandoff && pTG->Comm.fDataCall)
  71. {
  72. if (pTG->hComm)
  73. {
  74. if (!CloseHandle(pTG->hComm))
  75. {
  76. DebugPrintEx( DEBUG_ERR,
  77. "Close Handle pTG->hComm failed (ec=%d)",
  78. GetLastError());
  79. }
  80. else
  81. {
  82. pTG->hComm = NULL;
  83. }
  84. }
  85. goto lEnd;
  86. }
  87. // We flush our internal buffer here...
  88. if (pTG->Comm.lpovrCur)
  89. {
  90. int nNumWrote; // Must be 32bits in WIN32
  91. if (!ov_write(pTG, pTG->Comm.lpovrCur, &nNumWrote))
  92. {
  93. // error...
  94. DebugPrintEx(DEBUG_ERR, "1st ov_write failed");
  95. }
  96. pTG->Comm.lpovrCur=NULL;
  97. DebugPrintEx(DEBUG_MSG,"done writing mybuf.");
  98. }
  99. ov_drain(pTG, FALSE);
  100. {
  101. // Here we will restore settings to what it was when we
  102. // took over the port. Currently (9/23/94) we (a) restore the
  103. // DCB to pTG->Comm.dcbOrig and (b) If DTR was originally ON,
  104. // try to sync the modem to
  105. // the original speed by issueing "AT" -- because unimodem does
  106. // only a half-hearted attempt at synching before giving up.
  107. if(pTG->Comm.fStateChanged && (!pTG->Comm.fEnableHandoff || !pTG->Comm.fDataCall))
  108. {
  109. if (!SetCommState(pTG->hComm, &(pTG->Comm.dcbOrig)))
  110. {
  111. DebugPrintEx( DEBUG_WRN,
  112. "Couldn't restore state. Err=0x%lx",
  113. (unsigned long) GetLastError());
  114. }
  115. DebugPrintEx( DEBUG_MSG,
  116. "restored DCB to Baud=%d, fOutxCtsFlow=%d, "
  117. " fDtrControl=%d, fOutX=%d",
  118. pTG->Comm.dcbOrig.BaudRate,
  119. pTG->Comm.dcbOrig.fOutxCtsFlow,
  120. pTG->Comm.dcbOrig.fDtrControl,
  121. pTG->Comm.dcbOrig.fOutX);
  122. pTG->CurrentSerialSpeed = (UWORD) pTG->Comm.dcbOrig.BaudRate;
  123. if (pTG->Comm.dcbOrig.fDtrControl==DTR_CONTROL_ENABLE)
  124. {
  125. // Try to pre-sync modem at new speed before we hand
  126. // it back to TAPI. Can't call iiSyncModemDialog here because
  127. // it's defined at a higher level. We don't really care
  128. // to determine if we get an OK response anyway...
  129. if (!iSyncModemDialog2(pTG, AT cr,sizeof(AT cr)-1,"OK", "0"))
  130. {
  131. DebugPrintEx(DEBUG_ERR,"couldn't sync AT command");
  132. }
  133. else
  134. {
  135. DebugPrintEx(DEBUG_MSG,"Sync AT command OK");
  136. // We flush our internal buffer here...
  137. if (pTG->Comm.lpovrCur)
  138. {
  139. int nNumWrote; // Must be 32bits in WIN32
  140. if (!ov_write(pTG, pTG->Comm.lpovrCur, &nNumWrote))
  141. {
  142. // error...
  143. DebugPrintEx(DEBUG_ERR, "2nd ov_write failed");
  144. }
  145. pTG->Comm.lpovrCur=NULL;
  146. DebugPrintEx(DEBUG_MSG,"done writing mybuf.");
  147. }
  148. ov_drain(pTG, FALSE);
  149. }
  150. }
  151. }
  152. pTG->Comm.fStateChanged=FALSE;
  153. pTG->Comm.fDataCall=FALSE;
  154. }
  155. if (pTG->hComm)
  156. {
  157. DebugPrintEx(DEBUG_MSG,"Closing Comm pTG->hComm=%d.", pTG->hComm);
  158. if (!CloseHandle(pTG->hComm))
  159. {
  160. DebugPrintEx( DEBUG_ERR,
  161. "Close Handle pTG->hComm failed (ec=%d)",
  162. GetLastError());
  163. GetCommErrorNT(pTG);
  164. fRet=FALSE;
  165. }
  166. else
  167. {
  168. pTG->hComm = NULL;
  169. }
  170. }
  171. lEnd:
  172. if (pTG->Comm.ovAux.hEvent) CloseHandle(pTG->Comm.ovAux.hEvent);
  173. _fmemset(&pTG->Comm.ovAux, 0, sizeof(pTG->Comm.ovAux));
  174. ov_deinit(pTG);
  175. pTG->Comm.fCommOpen = FALSE;
  176. pTG->Comm.fDoOverlapped=FALSE;
  177. return fRet;
  178. }
  179. /////////////////////////////////////////////////////////////////////////////////////////////
  180. BOOL
  181. T30ComInit
  182. (
  183. PThrdGlbl pTG
  184. )
  185. {
  186. DEBUG_FUNCTION_NAME(("T30ComInit"));
  187. if (pTG->fCommInitialized)
  188. {
  189. goto lSecondInit;
  190. }
  191. pTG->Comm.fDataCall=FALSE;
  192. DebugPrintEx(DEBUG_MSG,"Opening Comm Port=%x", pTG->hComm);
  193. pTG->CommCache.dwMaxSize = 4096;
  194. ClearCommCache(pTG);
  195. pTG->CommCache.fReuse = 0;
  196. DebugPrintEx( DEBUG_MSG,
  197. "OPENCOMM: bufs in=%d out=%d",
  198. COM_INBUFSIZE,
  199. COM_OUTBUFSIZE);
  200. if (BAD_HANDLE(pTG->hComm))
  201. {
  202. DebugPrintEx(DEBUG_ERR,"OPENCOMM failed. nRet=%d", pTG->hComm);
  203. goto error2;
  204. }
  205. DebugPrintEx(DEBUG_MSG,"OPENCOMM succeeded hComm=%d", pTG->hComm);
  206. pTG->Comm.fCommOpen = TRUE;
  207. pTG->Comm.cbInSize = COM_INBUFSIZE;
  208. pTG->Comm.cbOutSize = COM_OUTBUFSIZE;
  209. // Reset Comm timeouts...
  210. {
  211. COMMTIMEOUTS cto;
  212. _fmemset(&cto, 0, sizeof(cto));
  213. // Out of curiosity, see what they are set at currently...
  214. if (!GetCommTimeouts(pTG->hComm, &cto))
  215. {
  216. DebugPrintEx( DEBUG_WRN,
  217. "GetCommTimeouts fails for handle=0x%lx",
  218. pTG->hComm);
  219. }
  220. else
  221. {
  222. DebugPrintEx( DEBUG_MSG,
  223. "GetCommTimeouts: cto={%lu, %lu, %lu, %lu, %lu}",
  224. (unsigned long) cto.ReadIntervalTimeout,
  225. (unsigned long) cto.ReadTotalTimeoutMultiplier,
  226. (unsigned long) cto.ReadTotalTimeoutConstant,
  227. (unsigned long) cto.WriteTotalTimeoutMultiplier,
  228. (unsigned long) cto.WriteTotalTimeoutConstant);
  229. }
  230. cto.ReadIntervalTimeout = READ_INTERVAL_TIMEOUT;
  231. cto.ReadTotalTimeoutMultiplier = READ_TOTAL_TIMEOUT_MULTIPLIER;
  232. cto.ReadTotalTimeoutConstant = READ_TOTAL_TIMEOUT_CONSTANT;
  233. cto.WriteTotalTimeoutMultiplier = WRITE_TOTAL_TIMEOUT_MULTIPLIER;
  234. cto.WriteTotalTimeoutConstant = WRITE_TOTAL_TIMEOUT_CONSTANT;
  235. if (!SetCommTimeouts(pTG->hComm, &cto))
  236. {
  237. DebugPrintEx( DEBUG_WRN,
  238. "SetCommTimeouts fails for handle=0x%lx",
  239. pTG->hComm);
  240. }
  241. }
  242. pTG->Comm.fCommOpen = TRUE;
  243. pTG->Comm.cbInSize = COM_INBUFSIZE;
  244. pTG->Comm.cbOutSize = COM_OUTBUFSIZE;
  245. _fmemset(&(pTG->Comm.comstat), 0, sizeof(COMSTAT));
  246. if(!GetCommState(pTG->hComm, &(pTG->Comm.dcb)))
  247. goto error2;
  248. pTG->Comm.dcbOrig = pTG->Comm.dcb; // structure copy.
  249. pTG->Comm.fStateChanged=TRUE;
  250. lSecondInit:
  251. // Use of 2400/ 8N1 and 19200 8N1 is not actually specified
  252. // in Class1, but seems to be adhered to be universal convention
  253. // watch out for modems that break this!
  254. if (pTG->SerialSpeedInit)
  255. {
  256. pTG->Comm.dcb.BaudRate = pTG->SerialSpeedInit;
  257. }
  258. else
  259. {
  260. pTG->Comm.dcb.BaudRate = 57600; // default
  261. }
  262. pTG->CurrentSerialSpeed = (UWORD) pTG->Comm.dcb.BaudRate;
  263. pTG->Comm.dcb.ByteSize = 8;
  264. pTG->Comm.dcb.Parity = NOPARITY;
  265. pTG->Comm.dcb.StopBits = ONESTOPBIT;
  266. pTG->Comm.dcb.fBinary = 1;
  267. pTG->Comm.dcb.fParity = 0;
  268. /************************************
  269. Pins assignments, & Usage
  270. Protective Gnd -- 1
  271. Transmit TxD (DTE to DCE) 3 2
  272. Recv RxD (DCE to DTE) 2 3
  273. RTS (Recv Ready--DTE to DCE) 7 4
  274. CTS (TransReady--DCE to DTE) 8 5
  275. DSR (DCE to DTE) 6 6
  276. signal ground 5 7
  277. CD (DCE to DTR) 1 8
  278. DTR (DTE to DCE) 4 20
  279. RI (DCE to DTE) 9 22
  280. Many 9-pin adaptors & cables use only 6 pins, 2,3,4,5, and 7.
  281. We need to worry about this because some modems actively
  282. use CTS, ie. pin 8.
  283. We don't care about RI and CD (Unless a really weird modem
  284. uses CD for flow control). We ignore DSR, but some (not so
  285. weird, but not so common either) modems use DSR for flow
  286. control.
  287. Thought :: Doesn't generate DSR. Seems to tie CD and CTS together
  288. DOVE :: Generates only CTS. But the Appletalk-9pin cable
  289. only passes 1-5 and pin 8.
  290. GVC :: CTS, DSR and CD
  291. ************************************/
  292. // CTS -- dunno. There is some evidence that the
  293. // modem actually uses it for flow control
  294. if (pTG->fEnableHardwareFlowControl)
  295. {
  296. pTG->Comm.dcb.fOutxCtsFlow = 1; // Using it hangs the output sometimes...
  297. }
  298. else
  299. {
  300. pTG->Comm.dcb.fOutxCtsFlow = 0;
  301. }
  302. // Try ignoring it and see if it works?
  303. pTG->Comm.dcb.fOutxDsrFlow = 0; // Never use this??
  304. pTG->Comm.dcb.fRtsControl = RTS_CONTROL_ENABLE; // Current code seems to leave this ON
  305. pTG->Comm.dcb.fDtrControl = DTR_CONTROL_DISABLE;
  306. pTG->Comm.dcb.fErrorChar = 0;
  307. pTG->Comm.dcb.ErrorChar = 0;
  308. // Can't change this cause SetCommState() resets hardware.
  309. pTG->Comm.dcb.EvtChar = ETX; // set this when we set an EventWait
  310. pTG->Comm.dcb.fOutX = 0; // Has to be OFF during HDLC recv phase
  311. pTG->Comm.dcb.fInX = 0; // Will this do any good??
  312. // Using flow-control on input is only a good
  313. // idea if the modem has a largish buffer
  314. pTG->Comm.dcb.fNull = 0;
  315. pTG->Comm.dcb.XonChar = CTRL_Q;
  316. pTG->Comm.dcb.XoffChar = CTRL_S;
  317. pTG->Comm.dcb.XonLim = 100; // Need to set this when BufSize is set
  318. pTG->Comm.dcb.XoffLim = 50; // Set this when BufSize is set
  319. // actually we *never* use XON/XOFF in recv, so don't worry about this
  320. // right now. (Later, when we have smart modems with large buffers, &
  321. // we are worried about our ISR buffer filling up before our windows
  322. // process gets run, we can use this). Some tuning will be reqd.
  323. pTG->Comm.dcb.EofChar = 0;
  324. pTG->Comm.dcb.fAbortOnError = 0; // RSL don't fail if minor problems
  325. if(!SetCommState(pTG->hComm, &(pTG->Comm.dcb)))
  326. goto error2;
  327. if (pTG->fCommInitialized)
  328. {
  329. return TRUE;
  330. }
  331. pTG->Comm.fStateChanged=TRUE;
  332. if (!SetCommMask(pTG->hComm, 0)) // all events off
  333. {
  334. DebugPrintEx(DEBUG_ERR, "SetCommMask failed (ec=%d)",GetLastError());
  335. }
  336. pTG->Comm.lpovrCur=NULL;
  337. _fmemset(&pTG->Comm.ovAux,0, sizeof(pTG->Comm.ovAux));
  338. pTG->Comm.ovAux.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  339. if (pTG->Comm.ovAux.hEvent==NULL)
  340. {
  341. DebugPrintEx(DEBUG_ERR, "FComOpen: couldn't create event");
  342. goto error2;
  343. }
  344. if (!ov_init(pTG))
  345. {
  346. CloseHandle(pTG->Comm.ovAux.hEvent);
  347. pTG->Comm.ovAux.hEvent=0;
  348. goto error2;
  349. }
  350. return TRUE;
  351. error2:
  352. DebugPrintEx(DEBUG_ERR, "FComOpen failed");
  353. GetCommErrorNT(pTG);
  354. if (pTG->Comm.fCommOpen)
  355. {
  356. FComClose(pTG);
  357. }
  358. return FALSE;
  359. }
  360. BOOL FComSetBaudRate(PThrdGlbl pTG, UWORD uwBaudRate)
  361. {
  362. DEBUG_FUNCTION_NAME(("FComSetBaudRate"));
  363. DebugPrintEx(DEBUG_MSG,"Setting BAUDRATE=%d",uwBaudRate);
  364. if(!GetCommState( pTG->hComm, &(pTG->Comm.dcb)))
  365. goto error;
  366. pTG->Comm.dcb.BaudRate = uwBaudRate;
  367. pTG->CurrentSerialSpeed = uwBaudRate;
  368. if(!SetCommState( pTG->hComm, &(pTG->Comm.dcb)))
  369. goto error;
  370. return TRUE;
  371. error:
  372. DebugPrintEx(DEBUG_ERR, "Set Baud Rate --- Can't Get/Set DCB");
  373. GetCommErrorNT(pTG);
  374. return FALSE;
  375. }
  376. BOOL FComInXOFFHold(PThrdGlbl pTG)
  377. {
  378. DEBUG_FUNCTION_NAME(_T("FComInXOFFHold"));
  379. GetCommErrorNT(pTG);
  380. if(pTG->Comm.comstat.fXoffHold)
  381. {
  382. DebugPrintEx(DEBUG_MSG,"In XOFF hold");
  383. return TRUE;
  384. }
  385. else
  386. {
  387. return FALSE;
  388. }
  389. }
  390. BOOL FComXon(PThrdGlbl pTG, BOOL fEnable)
  391. {
  392. DEBUG_FUNCTION_NAME(_T("FComXon"));
  393. if (pTG->fEnableHardwareFlowControl)
  394. {
  395. DebugPrintEx( DEBUG_MSG,
  396. "FComXon = %d IGNORED : h/w flow control",
  397. fEnable);
  398. return TRUE;
  399. }
  400. DebugPrintEx(DEBUG_MSG,"FComXon = %d",fEnable);
  401. // enables/disables flow control
  402. // returns TRUE on success, false on failure
  403. if(!GetCommState( pTG->hComm, &(pTG->Comm.dcb)))
  404. goto error;
  405. DebugPrintEx(DEBUG_MSG,"FaxXon Before: %02x", pTG->Comm.dcb.fOutX);
  406. pTG->Comm.dcb.fOutX = fEnable;
  407. if(!SetCommState(pTG->hComm, &(pTG->Comm.dcb)))
  408. goto error;
  409. DebugPrintEx(DEBUG_MSG,"After: %02x",pTG->Comm.dcb.fOutX);
  410. return TRUE;
  411. error:
  412. DebugPrintEx(DEBUG_ERR,"Can't Set/Get DCB");
  413. GetCommErrorNT(pTG);
  414. return FALSE;
  415. }
  416. // queue=0 --> receiving queue
  417. // queue=1 --> transmitting queue
  418. void FComFlushQueue(PThrdGlbl pTG, int queue)
  419. {
  420. int nRet;
  421. DWORD lRet;
  422. DEBUG_FUNCTION_NAME(_T("FComFlushQueue"));
  423. DebugPrintEx(DEBUG_MSG, "FlushQueue = %d", queue);
  424. if (queue == 1)
  425. {
  426. DebugPrintEx(DEBUG_MSG,"ClearCommCache");
  427. ClearCommCache(pTG);
  428. }
  429. nRet = PurgeComm(pTG->hComm, (queue ? PURGE_RXCLEAR : PURGE_TXCLEAR));
  430. if(!nRet)
  431. {
  432. DebugPrintEx(DEBUG_ERR,"FlushComm failed (ec=%d)", GetLastError());
  433. GetCommErrorNT(pTG);
  434. // Throwing away errors that happen here.
  435. // No good reason for it!
  436. }
  437. if(queue == 1)
  438. {
  439. FComInFilterInit(pTG);
  440. }
  441. else // (queue == 0)
  442. {
  443. // Let's dump any stuff we may have in *our* buffer.
  444. if (pTG->Comm.lpovrCur && pTG->Comm.lpovrCur->dwcb)
  445. {
  446. DebugPrintEx( DEBUG_WRN,
  447. "Clearing NonNULL pTG->Comm.lpovrCur->dwcb=%lx",
  448. (unsigned long) pTG->Comm.lpovrCur->dwcb);
  449. pTG->Comm.lpovrCur->dwcb=0;
  450. ov_unget(pTG, pTG->Comm.lpovrCur);
  451. pTG->Comm.lpovrCur=NULL;
  452. }
  453. // Lets "drain" -- should always return immediately, because
  454. // we have just purged the output comm buffers.
  455. if (pTG->Comm.fovInited)
  456. {
  457. DebugPrintEx(DEBUG_MSG," before ov_drain");
  458. ov_drain(pTG, FALSE);
  459. DebugPrintEx(DEBUG_MSG," after ov_drain");
  460. }
  461. // just incase it got stuck due to a mistaken XOFF
  462. lRet = EscapeCommFunction(pTG->hComm, SETXON);
  463. if(!lRet)
  464. {
  465. // Returns the comm error value CE!!
  466. DebugPrintEx(DEBUG_MSG,"EscapeCommFunc(SETXON) returned %d", lRet);
  467. GetCommErrorNT(pTG);
  468. }
  469. }
  470. }
  471. /***************************************************************************
  472. Name : FComDrain(BOOL fLongTO, BOOL fDrainComm)
  473. Purpose : Drain internal buffers. If fDrainComm, wait for Comm
  474. ISR Output buffer to drain.
  475. Returns when buffer is drained or if no progress is made
  476. for DRAINTIMEOUT millisecs. (What about XOFFed sections?
  477. Need to set Drain timeout high enough)
  478. Parameters:
  479. Returns : TRUE on success (buffer drained)
  480. FALSE on failure (error or timeout)
  481. Revision Log
  482. Num Date Name Description
  483. --- -------- ---------- -----------------------------------------------
  484. 101 06/03/92 arulm Created it in a new incarnation
  485. ***************************************************************************/
  486. // This timeout has to be low at time and high at others. We want it low
  487. // so we don't spend too much time trying to talk to a non-existent modem
  488. // during Init/Setup. However in PhaseC, when the timer expires all we
  489. // do is abort and kill everything. So it serves no purpose to make it
  490. // too low. With the Hayes ESP FIFO card long stretches can elapse without
  491. // any visible "progress", so we fail with that card because we think
  492. // "no progress" is being made
  493. // So....make it short for init/install
  494. // but not too short. Some cmds (e.g. AT&F take a long time)
  495. // Used to be 800ms & seemed to work then, so leave it at that
  496. #define SHORT_DRAINTIMEOUT 800
  497. // So....make it long for PhaseC
  498. // 4secs should be about long enough
  499. #define LONG_DRAINTIMEOUT 4000
  500. BOOL FComDrain(PThrdGlbl pTG, BOOL fLongTO, BOOL fDrainComm)
  501. {
  502. WORD wTimer = 0;
  503. UWORD cbPrevOut = 0xFFFF;
  504. BOOL fStuckOnce=FALSE;
  505. BOOL fRet=FALSE;
  506. DEBUG_FUNCTION_NAME(_T("FComDrain"));
  507. // We flush our internal buffer here...
  508. if (pTG->Comm.lpovrCur)
  509. {
  510. int nNumWrote; // Must be 32bits in WIN32
  511. if (!ov_write(pTG, pTG->Comm.lpovrCur, &nNumWrote))
  512. goto done;
  513. pTG->Comm.lpovrCur=NULL;
  514. DebugPrintEx(DEBUG_MSG,"done writing mybuf.");
  515. }
  516. if (!fDrainComm)
  517. {
  518. fRet=TRUE;
  519. goto done;
  520. }
  521. // +++ Here we drain all our overlapped events..
  522. // If we setup the system comm timeouts properly, we
  523. // don't need to do anything else, except for the XOFF/XON
  524. // stuff...
  525. fRet = ov_drain(pTG, fLongTO);
  526. goto done;
  527. done:
  528. return fRet; //+++ was (cbOut == 0);
  529. }
  530. /***************************************************************************
  531. Name : FComDirectWrite(, lpb, cb)
  532. Purpose : Write cb bytes starting from lpb to pTG->Comm. If Comm buffer
  533. is full, set up notifications and timers and wait until space
  534. is available. Returns when all bytes have been written to
  535. the Comm buffer or if no progress is made
  536. for WRITETIMEOUT millisecs. (What about XOFFed sections?
  537. Need to set timeout high enough)
  538. Parameters: , lpb, cb
  539. Returns : Number of bytes written, i.e. cb on success and <cb on timeout,
  540. or error.
  541. Revision Log
  542. Num Date Name Description
  543. --- -------- ---------- -----------------------------------------------
  544. 101 06/03/92 arulm Created it
  545. ***************************************************************************/
  546. // This is WRONG -- see below!!
  547. // totally arbitrary should be no more than the time as it would
  548. // take to write WRITEQUANTUM out at the fastest speed
  549. // (say 14400 approx 2 bytes/ms)
  550. // #define WRITETIMEOUT min((WRITEQUANTUM / 2), 200)
  551. // This timeout was too low. We wanted it low so we don't spend too much
  552. // time trying to talk to a non-existent modem during Init/Setup. But in
  553. // those cases we _never_ reach full buffer, so we don't wait here
  554. // we wait in FComDrain(). Here we wait _only_ in PhaseC, so when the
  555. // timer expires all we do is abort and kill everything. So it serves
  556. // no purpose to make it too low. With the Hayes ESP FIFO card long
  557. // stretches can elapse without any visible "progress", so we fail with
  558. // that card because we think "no progress" is being made
  559. // So....make it long
  560. // 2secs should be about long enough
  561. #define WRITETIMEOUT 2000
  562. UWORD FComDirectWrite(PThrdGlbl pTG, LPB lpb, UWORD cb)
  563. {
  564. DWORD cbLeft = cb;
  565. DEBUG_FUNCTION_NAME(_T("FComDirectWrite"));
  566. while(cbLeft)
  567. {
  568. DWORD dwcbCopy;
  569. DWORD dwcbWrote;
  570. if (!pTG->Comm.lpovrCur)
  571. {
  572. pTG->Comm.lpovrCur = ov_get(pTG);
  573. if (!pTG->Comm.lpovrCur) goto error;
  574. }
  575. dwcbCopy = OVBUFSIZE-pTG->Comm.lpovrCur->dwcb;
  576. if (dwcbCopy>cbLeft)
  577. {
  578. dwcbCopy = cbLeft;
  579. }
  580. // Copy as much as we can to the overlapped buffer...
  581. _fmemcpy(pTG->Comm.lpovrCur->rgby+pTG->Comm.lpovrCur->dwcb, lpb, dwcbCopy);
  582. cbLeft -= dwcbCopy;
  583. pTG->Comm.lpovrCur->dwcb += dwcbCopy;
  584. lpb += dwcbCopy;
  585. // Let's always update comstat here...
  586. GetCommErrorNT(pTG);
  587. DebugPrintEx( DEBUG_MSG,
  588. "OutQ has %d fDoOverlapped=%d",
  589. pTG->Comm.comstat.cbOutQue,
  590. pTG->Comm.fDoOverlapped);
  591. // We write to comm if our buffer is full or the comm buffer is
  592. // empty or if we're not in overlapped mode...
  593. if ( !pTG->Comm.fDoOverlapped ||
  594. pTG->Comm.lpovrCur->dwcb>=OVBUFSIZE ||
  595. !pTG->Comm.comstat.cbOutQue)
  596. {
  597. BOOL fRet = ov_write(pTG, pTG->Comm.lpovrCur, &dwcbWrote);
  598. pTG->Comm.lpovrCur=NULL;
  599. if (!fRet)
  600. {
  601. goto error;
  602. }
  603. }
  604. } // while (cbLeft)
  605. return cb;
  606. error:
  607. return 0;
  608. }
  609. /***************************************************************************
  610. Name : FComFilterReadLine(, lpb, cbSize, pto)
  611. Purpose : Reads upto cbSize bytes from Comm into memory starting from
  612. lpb. If Comm buffer is empty, set up notifications and timers
  613. and wait until characters are available.
  614. Filters out DLE characters. i.e DLE-DLE is reduced to
  615. a single DLE, DLE ETX is left intact and DLE-X is deleted.
  616. Returns success (+ve bytes count) when CR-LF has been
  617. encountered, and returns failure (-ve bytes count).
  618. when either (a) cbSize bytes have been read (i.e. buffer is
  619. full) or (b) PTO times out or an error is encountered.
  620. It is critical that this function never returns a
  621. timeout, as long as data
  622. is still pouring/trickling in. This implies two things
  623. (a) FIRST get all that is in the InQue (not more than a
  624. line, though), THEN check the timeout.
  625. (b) Ensure that at least 1 char-arrival-time at the
  626. slowest Comm speed passes between the function entry
  627. point and the last time we check for a byte, or between
  628. two consecutive checks for a byte, before we return a timeout.
  629. Therefor conditions to return a timeout are Macro timeout
  630. over and inter-char timeout over.
  631. In theory the slowest speed we need to worry about is 2400,
  632. because that's the slowest we run the Comm at, but be paranoid
  633. and assume the modem sends the chars at the same speed that
  634. they come in the wire, so slowest is now 300. 1 char-arrival-time
  635. is now 1000 / (300/8) == 26.67ms.
  636. If pto expires, returns error, i.e. -ve of the number of
  637. bytes read.
  638. Returns : Number of bytes read, i.e. cb on success and -ve of number
  639. of bytes read on timeout. 0 is a timeout error with no bytes
  640. read.
  641. Revision Log
  642. Num Date Name Description
  643. --- -------- ---------- -----------------------------------------------
  644. 101 06/03/92 arulm Created it
  645. ***************************************************************************/
  646. // totally arbitrary
  647. #define READLINETIMEOUT 50
  648. #define ONECHARTIME (30 * 2) // see above *2 to be safe
  649. // void WINAPI OutputDebugStr(LPSTR);
  650. // char szJunk[200];
  651. // Read a line of size no more than cbSize to lpb
  652. //
  653. #undef USE_DEBUG_CONTEXT
  654. #define USE_DEBUG_CONTEXT DEBUG_CONTEXT_T30_CLASS1
  655. SWORD FComFilterReadLine(PThrdGlbl pTG, LPB lpb, UWORD cbSize, LPTO lptoRead)
  656. {
  657. WORD wTimer = 0;
  658. UWORD cbIn = 0, cbGot = 0;
  659. LPB lpbNext;
  660. BOOL fPrevDLE = 0;
  661. SWORD i, beg;
  662. TO to;
  663. DWORD dwLoopCount = 0;
  664. DEBUG_FUNCTION_NAME(_T("FComFilterReadLine"));
  665. DebugPrintEx( DEBUG_MSG,
  666. "lpb=0x%08lx cb=%d timeout=%lu",
  667. lpb,
  668. cbSize,
  669. lptoRead->ulTimeout);
  670. cbSize--; // make room for terminal NULL
  671. lpbNext = lpb; // we write the NULL to *lpbNext, so init this NOW!
  672. cbGot = 0; // return value (even err return) is cbGot. Init NOW!!
  673. fPrevDLE=0;
  674. pTG->fLineTooLongWasIgnored = FALSE;
  675. //
  676. // check the cache first.
  677. // Maybe the cache contains data
  678. if ( ! pTG->CommCache.dwCurrentSize)
  679. {
  680. DebugPrintEx(DEBUG_MSG,"Cache is empty. Resetting comm cache.");
  681. ClearCommCache(pTG);
  682. // Try to fill the cache
  683. if (!FComFilterFillCache(pTG, cbSize, lptoRead))
  684. {
  685. DebugPrintEx(DEBUG_ERR,"FillCache failed");
  686. goto error;
  687. }
  688. }
  689. while (1)
  690. {
  691. if ( ! pTG->CommCache.dwCurrentSize)
  692. {
  693. DebugPrintEx(DEBUG_ERR, "Cache is empty after FillCache");
  694. goto error;
  695. }
  696. DebugPrintEx( DEBUG_MSG,
  697. "Cache: size=%d, offset=%d",
  698. pTG->CommCache.dwCurrentSize,
  699. pTG->CommCache.dwOffset);
  700. lpbNext = pTG->CommCache.lpBuffer + pTG->CommCache.dwOffset;
  701. if (pTG->CommCache.dwCurrentSize >= 3)
  702. {
  703. DebugPrintEx( DEBUG_MSG,
  704. "0=%x 1=%x 2=%x 3=%x 4=%x 5=%x 6=%x 7=%x 8=%x /"
  705. " %d=%x, %d=%x, %d=%x",
  706. *lpbNext,
  707. *(lpbNext+1),
  708. *(lpbNext+2),
  709. *(lpbNext+3),
  710. *(lpbNext+4),
  711. *(lpbNext+5),
  712. *(lpbNext+6),
  713. *(lpbNext+7),
  714. *(lpbNext+8),
  715. pTG->CommCache.dwCurrentSize-3,
  716. *(lpbNext+ pTG->CommCache.dwCurrentSize-3),
  717. pTG->CommCache.dwCurrentSize-2,
  718. *(lpbNext+ pTG->CommCache.dwCurrentSize-2),
  719. pTG->CommCache.dwCurrentSize-1,
  720. *(lpbNext+ pTG->CommCache.dwCurrentSize-1) );
  721. }
  722. else
  723. {
  724. DebugPrintEx(DEBUG_MSG,"1=%x 2=%x", *lpbNext, *(lpbNext+1) );
  725. }
  726. for (i=0, beg=0; i< (SWORD) pTG->CommCache.dwCurrentSize; i++)
  727. {
  728. if (i > 0 )
  729. { // check from the second char in the buffer for CR + LF.
  730. if ( ( *(pTG->CommCache.lpBuffer + pTG->CommCache.dwOffset + i - 1) == CR ) &&
  731. ( *(pTG->CommCache.lpBuffer + pTG->CommCache.dwOffset + i) == LF ) )
  732. {
  733. if ( i - beg >= cbSize)
  734. {
  735. // line too long. try next one.
  736. DebugPrintEx( DEBUG_ERR,
  737. "Line len=%d is longer than bufsize=%d "
  738. " Found in cache pos=%d, CacheSize=%d, Offset=%d",
  739. i-beg,
  740. cbSize,
  741. i+1,
  742. pTG->CommCache.dwCurrentSize,
  743. pTG->CommCache.dwOffset);
  744. beg = i + 1;
  745. pTG->fLineTooLongWasIgnored = TRUE;
  746. continue;
  747. }
  748. // found the line.
  749. CopyMemory (lpb, (pTG->CommCache.lpBuffer + pTG->CommCache.dwOffset + beg), (i - beg + 1) );
  750. pTG->CommCache.dwOffset += (i+1);
  751. pTG->CommCache.dwCurrentSize -= (i+1);
  752. *(lpb+i-beg+1) = '\0'; // Make sure that the line is null terminated
  753. DebugPrintEx( DEBUG_MSG,
  754. "Found in cache pos=%d, CacheSize=%d, Offset=%d",
  755. i+1,
  756. pTG->CommCache.dwCurrentSize,
  757. pTG->CommCache.dwOffset);
  758. // return how much bytes in the line
  759. return ( i-beg+1 );
  760. }
  761. }
  762. }
  763. // we get here if we didn't find CrLf in Cache
  764. DebugPrintEx(DEBUG_MSG,"Cache wasn't empty but we didn't find CrLf");
  765. // if cache too big (and we have not found anything anyway) --> clean it
  766. if (pTG->CommCache.dwCurrentSize >= cbSize)
  767. {
  768. DebugPrintEx(DEBUG_MSG, "ClearCommCache");
  769. ClearCommCache(pTG);
  770. }
  771. else if ( ! pTG->CommCache.dwCurrentSize)
  772. {
  773. DebugPrintEx(DEBUG_MSG,"Cache is empty. Resetting comm cache.");
  774. ClearCommCache(pTG);
  775. }
  776. // If the modem returned part of a line, the rest of the line should already be
  777. // in the serial buffer. In this case, read again with a short timeout (500ms).
  778. // However, some modems can get into a state where they give random data forever.
  779. // So... give the modem only one "second chance".
  780. if (dwLoopCount && (!checkTimeOut(pTG, lptoRead)))
  781. {
  782. DebugPrintEx(DEBUG_ERR,"Total Timeout passed");
  783. goto error;
  784. }
  785. dwLoopCount++;
  786. to.ulStart = 0;
  787. to.ulTimeout = 0;
  788. to.ulEnd = 500;
  789. if ( ! FComFilterFillCache(pTG, cbSize, &to/*lptoRead*/) )
  790. {
  791. DebugPrintEx(DEBUG_ERR, "FillCache failed");
  792. goto error;
  793. }
  794. }
  795. error:
  796. ClearCommCache(pTG);
  797. return (0);
  798. }
  799. // Read from the comm port.
  800. // The input is written to 'the end' of pTG->CommCache.lpBuffer buffer.
  801. // returns TRUE on success, FALSE - otherwise.
  802. BOOL FComFilterFillCache(PThrdGlbl pTG, UWORD cbSize, LPTO lptoRead)
  803. {
  804. WORD wTimer = 0;
  805. UWORD cbGot = 0, cbAvail = 0;
  806. DWORD cbRequested = 0;
  807. char lpBuffer[4096]; // ATTENTION: We do overlapped read into the stack!!
  808. LPB lpbNext;
  809. int nNumRead; // _must_ be 32 bits in Win32!!
  810. LPOVERLAPPED lpOverlapped;
  811. COMMTIMEOUTS cto;
  812. DWORD dwLastErr;
  813. DWORD dwTimeoutRead;
  814. DWORD dwTimeoutOrig;
  815. DWORD dwTickCountOrig;
  816. char *pSrc;
  817. char *pDest;
  818. DWORD i, j;
  819. DWORD dwErr;
  820. COMSTAT ErrStat;
  821. DWORD NumHandles=2;
  822. HANDLE HandlesArray[2];
  823. DWORD WaitResult;
  824. DEBUG_FUNCTION_NAME(_T("FComFilterFillCache"));
  825. HandlesArray[1] = pTG->AbortReqEvent;
  826. dwTickCountOrig = GetTickCount();
  827. dwTimeoutOrig = (DWORD) (lptoRead->ulEnd - lptoRead->ulStart);
  828. dwTimeoutRead = dwTimeoutOrig;
  829. lpbNext = lpBuffer;
  830. DebugPrintEx( DEBUG_MSG,
  831. "cb=%d to=%d",
  832. cbSize,
  833. dwTimeoutRead);
  834. // we want to request the read such that we will be back
  835. // no much later than dwTimeOut either with the requested
  836. // amount of data or without it.
  837. cbRequested = cbSize;
  838. do
  839. {
  840. // use COMMTIMEOUTS to detect there are no more data
  841. cto.ReadIntervalTimeout = 50; // 30 ms is during negotiation frames; del(ff, 2ndchar> = 54 ms with USR 28.8
  842. cto.ReadTotalTimeoutMultiplier = 0;
  843. cto.ReadTotalTimeoutConstant = dwTimeoutRead; // RSL may want to set first time ONLY*/
  844. cto.WriteTotalTimeoutMultiplier = WRITE_TOTAL_TIMEOUT_MULTIPLIER;
  845. cto.WriteTotalTimeoutConstant = WRITE_TOTAL_TIMEOUT_CONSTANT;
  846. if (!SetCommTimeouts(pTG->hComm, &cto))
  847. {
  848. DebugPrintEx( DEBUG_ERR,
  849. "SetCommTimeouts fails for handle %lx , le=%x",
  850. pTG->hComm,
  851. GetLastError());
  852. }
  853. lpOverlapped = &pTG->Comm.ovAux;
  854. (lpOverlapped)->Internal = 0;
  855. (lpOverlapped)->InternalHigh = 0;
  856. (lpOverlapped)->Offset = 0;
  857. (lpOverlapped)->OffsetHigh = 0;
  858. if ((lpOverlapped)->hEvent)
  859. {
  860. if (!ResetEvent((lpOverlapped)->hEvent))
  861. {
  862. DebugPrintEx( DEBUG_ERR,
  863. "ResetEvent failed (ec=%d)",
  864. GetLastError());
  865. }
  866. }
  867. nNumRead = 0;
  868. DebugPrintEx( DEBUG_MSG,
  869. "Before ReadFile Req=%d",
  870. cbRequested);
  871. if (! ReadFile( pTG->hComm, lpbNext, cbRequested, &nNumRead, lpOverlapped) )
  872. {
  873. if ( (dwLastErr = GetLastError() ) == ERROR_IO_PENDING)
  874. {
  875. //
  876. // We want to be able to un-block ONCE only from waiting on I/O when the AbortReqEvent is signaled.
  877. //
  878. if (pTG->fAbortRequested)
  879. {
  880. if (pTG->fOkToResetAbortReqEvent && (!pTG->fAbortReqEventWasReset))
  881. {
  882. DebugPrintEx(DEBUG_MSG,"RESETTING AbortReqEvent");
  883. pTG->fAbortReqEventWasReset = TRUE;
  884. if (!ResetEvent(pTG->AbortReqEvent))
  885. {
  886. DebugPrintEx( DEBUG_ERR,
  887. "ResetEvent failed (ec=%d)",
  888. GetLastError());
  889. }
  890. }
  891. pTG->fUnblockIO = TRUE;
  892. }
  893. HandlesArray[0] = pTG->Comm.ovAux.hEvent;
  894. // Remeber that: HandlesArray[1] = pTG->AbortReqEvent;
  895. if (pTG->fUnblockIO)
  896. {
  897. NumHandles = 1; // We don't want to be disturb by an abort
  898. }
  899. else
  900. {
  901. NumHandles = 2;
  902. }
  903. if (pTG->fStallAbortRequest)
  904. {
  905. // this is used to complete a whole IO operation (presumably a short one)
  906. // when this flag is set, the IO won't be disturbed by the abort event
  907. // this flag should NOT be set for long periods of time since abort
  908. // is disabled while it is set.
  909. DebugPrintEx(DEBUG_MSG,"StallAbortRequest, do not abort here...");
  910. NumHandles = 1; // We don't want to be disturb by an abort
  911. pTG->fStallAbortRequest = FALSE;
  912. }
  913. DebugPrintEx(DEBUG_MSG,"Waiting for %d Event(s)",NumHandles);
  914. WaitResult = WaitForMultipleObjects(NumHandles, HandlesArray, FALSE, WAIT_FCOM_FILTER_FILLCACHE_TIMEOUT);
  915. DebugPrintEx(DEBUG_MSG,"WaitForMultipleObjects returned %d",WaitResult);
  916. if (WaitResult == WAIT_TIMEOUT)
  917. {
  918. DebugPrintEx(DEBUG_ERR, "WaitForMultipleObjects TIMEOUT");
  919. goto error;
  920. }
  921. if (WaitResult == WAIT_FAILED)
  922. {
  923. DebugPrintEx( DEBUG_ERR,
  924. "WaitForMultipleObjects FAILED le=%lx NumHandles=%d",
  925. GetLastError(),
  926. NumHandles);
  927. goto error;
  928. }
  929. if ( (NumHandles == 2) && (WaitResult == WAIT_OBJECT_0 + 1) )
  930. {
  931. // There was an abort by the user and that there are still pending reads
  932. // Lets cancell the pending I/O operations, and then wait for the overlapped results
  933. pTG->fUnblockIO = TRUE;
  934. DebugPrintEx(DEBUG_MSG,"ABORTed");
  935. goto error;
  936. }
  937. // The IO operation was complete. Lets try to get the overlapped result.
  938. if ( ! GetOverlappedResult ( pTG->hComm, lpOverlapped, &nNumRead, TRUE) )
  939. {
  940. DebugPrintEx(DEBUG_ERR, "GetOverlappedResult le=%x", GetLastError());
  941. if (! ClearCommError( pTG->hComm, &dwErr, &ErrStat) )
  942. {
  943. DebugPrintEx(DEBUG_ERR, "ClearCommError le=%x", GetLastError());
  944. }
  945. else
  946. {
  947. DebugPrintEx( DEBUG_ERR,
  948. "ClearCommError dwErr=%x ErrSTAT: Cts=%d Dsr=%d "
  949. " Rls=%d XoffHold=%d XoffSent=%d fEof=%d Txim=%d "
  950. " In=%d Out=%d",
  951. dwErr,
  952. ErrStat.fCtsHold,
  953. ErrStat.fDsrHold,
  954. ErrStat.fRlsdHold,
  955. ErrStat.fXoffHold,
  956. ErrStat.fXoffSent,
  957. ErrStat.fEof,
  958. ErrStat.fTxim,
  959. ErrStat.cbInQue,
  960. ErrStat.cbOutQue);
  961. }
  962. goto errorWithoutCancel;
  963. }
  964. }
  965. else
  966. {
  967. DebugPrintEx(DEBUG_ERR, "ReadFile");
  968. // We will do cancell pending IO, should we?
  969. goto errorWithoutCancel;
  970. }
  971. }
  972. else
  973. {
  974. DebugPrintEx(DEBUG_WRN,"ReadFile returned w/o WAIT");
  975. }
  976. DebugPrintEx( DEBUG_MSG,
  977. "After ReadFile Req=%d Ret=%d",
  978. cbRequested,
  979. nNumRead);
  980. // How much bytes we actually have read
  981. cbAvail = (UWORD)nNumRead;
  982. if (!cbAvail)
  983. {
  984. // With USB modems, ReadFile sometimes returns after 60ms with 0 bytes
  985. // read regardless of supplied timeout. So, if we got 0 bytes, check
  986. // whether timeout has passed, and if not - issue another ReadFile.
  987. DWORD dwTimePassed = GetTickCount() - dwTickCountOrig;
  988. // Allow for 20ms inaccuracy in TickCount
  989. if (dwTimePassed+20 >= dwTimeoutOrig)
  990. {
  991. DebugPrintEx(DEBUG_ERR, "0 read, to=%d, passed=%d", dwTimeoutOrig, dwTimePassed);
  992. goto errorWithoutCancel;
  993. }
  994. dwTimeoutRead = dwTimeoutOrig - dwTimePassed;
  995. DebugPrintEx( DEBUG_WRN,
  996. "0 read, to=%d, passed=%d, re-reading with to=%d",
  997. dwTimeoutOrig,
  998. dwTimePassed,
  999. dwTimeoutRead);
  1000. }
  1001. } while (cbAvail==0);
  1002. // filter DLE stuff
  1003. pSrc = lpbNext;
  1004. pDest = pTG->CommCache.lpBuffer + pTG->CommCache.dwOffset+ pTG->CommCache.dwCurrentSize;
  1005. for (i=0, j=0; i<cbAvail; )
  1006. {
  1007. if ( *(pSrc+i) == DLE)
  1008. {
  1009. if ( *(pSrc+i+1) == DLE )
  1010. {
  1011. *(pDest+j) = DLE;
  1012. j += 1;
  1013. i += 2;
  1014. }
  1015. else if ( *(pSrc+i+1) == ETX )
  1016. {
  1017. *(pDest+j) = DLE;
  1018. *(pDest+j+1) = ETX;
  1019. j += 2;
  1020. i += 2;
  1021. }
  1022. else
  1023. {
  1024. i += 2;
  1025. }
  1026. }
  1027. else
  1028. {
  1029. *(pDest+j) = *(pSrc+i);
  1030. i++;
  1031. j++;
  1032. }
  1033. }
  1034. pTG->CommCache.dwCurrentSize += j;
  1035. return TRUE;
  1036. error:
  1037. if (!CancellPendingIO(pTG , pTG->hComm , lpOverlapped , (LPDWORD) &nNumRead))
  1038. {
  1039. DebugPrintEx(DEBUG_ERR, "failed when call to CancellPendingIO");
  1040. }
  1041. errorWithoutCancel:
  1042. return FALSE;
  1043. }
  1044. /***************************************************************************
  1045. Name : FComDirectReadBuf(, lpb, cbSize, lpto, pfEOF)
  1046. Purpose : Reads upto cbSize bytes from Comm into memory starting from
  1047. lpb. If Comm buffer is empty, set up notifications and timers
  1048. and wait until characters are available.
  1049. Returns when success (+ve byte count) either (a) cbSize
  1050. bytes have been read or (b) DLE-ETX has been encountered
  1051. (in which case *pfEOF is set to TRUE).
  1052. Does no filtering. Reads the Comm buffer in large quanta.
  1053. If lpto expires, returns error, i.e. -ve of the number of
  1054. bytes read.
  1055. Returns : Number of bytes read, i.e. cb on success and -ve of number
  1056. of bytes read on timeout. 0 is a timeout error with no bytes
  1057. read.
  1058. Revision Log
  1059. Num Date Name Description
  1060. --- -------- ---------- -----------------------------------------------
  1061. 101 06/03/92 arulm Created it
  1062. ***************************************************************************/
  1063. // +++ #define READBUFQUANTUM (pTG->Comm.cbInSize / 8)
  1064. // totally arbitrary
  1065. // +++ #define READBUFTIMEOUT 200
  1066. // *lpswEOF is 1 on Class1 EOF, 0 on non-EOF, -1 on Class2 EOF, -2 on error -3 on timeout
  1067. UWORD FComFilterReadBuf
  1068. (
  1069. PThrdGlbl pTG,
  1070. LPB lpb,
  1071. UWORD cbSize,
  1072. LPTO lptoRead,
  1073. BOOL fClass2,
  1074. LPSWORD lpswEOF
  1075. )
  1076. {
  1077. WORD wTimer = 0;
  1078. UWORD cbGot = 0, cbAvail = 0;
  1079. UWORD cbUsed = 0;
  1080. DWORD cbRequested = 0;
  1081. LPB lpbNext;
  1082. int nNumRead = 0; // _must_ be 32 bits in Win32!!
  1083. LPOVERLAPPED lpOverlapped;
  1084. COMMTIMEOUTS cto;
  1085. DWORD dwLastErr;
  1086. DWORD dwTimeoutRead;
  1087. DWORD cbFromCache = 0;
  1088. DWORD dwErr;
  1089. COMSTAT ErrStat;
  1090. DWORD NumHandles=2;
  1091. HANDLE HandlesArray[2];
  1092. DWORD WaitResult;
  1093. DEBUG_FUNCTION_NAME(_T("FComFilterReadBuf"));
  1094. HandlesArray[1] = pTG->AbortReqEvent;
  1095. dwTimeoutRead = (DWORD) (lptoRead->ulEnd - lptoRead->ulStart);
  1096. DebugPrintEx( DEBUG_MSG,
  1097. "lpb=0x%08lx cbSize=%d to=%d",
  1098. lpb,
  1099. cbSize,
  1100. dwTimeoutRead);
  1101. // Dont want to take ^Q/^S from modem to
  1102. // be XON/XOFF in the receive data phase!!
  1103. *lpswEOF=0;
  1104. // Leave TWO spaces at start to make sure Out pointer will
  1105. // never get ahead of the In pointer in StripBuf, even
  1106. // if the last byte of prev block was DLE & first byte
  1107. // of this one is SUB (i.e need to insert two DLEs in
  1108. // output).
  1109. // Save a byte at end for the NULL terminator (Why? Dunno...)
  1110. lpb += 2;
  1111. cbSize -= 3;
  1112. cbRequested = cbSize;
  1113. for(lpbNext=lpb;;)
  1114. {
  1115. DebugPrintEx( DEBUG_MSG,
  1116. "cbSize=%d cbGot=%d cbAvail=%d",
  1117. cbSize,
  1118. cbGot,
  1119. cbAvail);
  1120. if((cbSize - cbGot) < cbAvail)
  1121. {
  1122. cbAvail = cbSize - cbGot;
  1123. }
  1124. if( (!cbGot) && !checkTimeOut(pTG, lptoRead) )
  1125. {
  1126. // No chars available *and* lptoRead expired
  1127. DebugPrintEx( DEBUG_ERR,
  1128. "ReadLn:Timeout %ld-toRd=%ld start=%ld",
  1129. GetTickCount(),
  1130. lptoRead->ulTimeout,
  1131. lptoRead->ulStart);
  1132. *lpswEOF = -3;
  1133. goto done;
  1134. }
  1135. // check Comm cache first (AT+FRH leftovers)
  1136. if ( pTG->CommCache.fReuse && pTG->CommCache.dwCurrentSize )
  1137. {
  1138. DebugPrintEx( DEBUG_MSG,
  1139. "CommCache will REUSE %d offset=%d 0=%x 1=%x",
  1140. pTG->CommCache.dwCurrentSize,
  1141. pTG->CommCache.dwOffset,
  1142. *(pTG->CommCache.lpBuffer + pTG->CommCache.dwOffset),
  1143. *(pTG->CommCache.lpBuffer + pTG->CommCache.dwOffset+1) );
  1144. if ( pTG->CommCache.dwCurrentSize >= cbRequested)
  1145. {
  1146. CopyMemory (lpbNext, pTG->CommCache.lpBuffer + pTG->CommCache.dwOffset, cbRequested);
  1147. pTG->CommCache.dwOffset += cbRequested;
  1148. pTG->CommCache.dwCurrentSize -= cbRequested;
  1149. cbAvail = (UWORD) cbRequested;
  1150. cbRequested = 0;
  1151. DebugPrintEx(DEBUG_MSG,"CommCache still left; no need to read");
  1152. goto l_merge;
  1153. }
  1154. else
  1155. {
  1156. cbFromCache = pTG->CommCache.dwCurrentSize;
  1157. CopyMemory (lpbNext, pTG->CommCache.lpBuffer + pTG->CommCache.dwOffset, cbFromCache);
  1158. ClearCommCache(pTG);
  1159. cbRequested -= cbFromCache;
  1160. DebugPrintEx(DEBUG_MSG,"CommCache used all %d",cbFromCache);
  1161. }
  1162. }
  1163. // use COMMTIMEOUTS to detect there are no more data
  1164. cto.ReadIntervalTimeout = 20; // 0 RSL make 15 later
  1165. cto.ReadTotalTimeoutMultiplier = 0;
  1166. cto.ReadTotalTimeoutConstant = dwTimeoutRead; // RSL may want to set first time ONLY
  1167. cto.WriteTotalTimeoutMultiplier = WRITE_TOTAL_TIMEOUT_MULTIPLIER;
  1168. cto.WriteTotalTimeoutConstant = WRITE_TOTAL_TIMEOUT_CONSTANT;
  1169. if (!SetCommTimeouts(pTG->hComm, &cto))
  1170. {
  1171. DebugPrintEx( DEBUG_ERR,
  1172. "SetCommTimeouts fails for handle %lx , le=%x",
  1173. pTG->hComm,
  1174. GetLastError());
  1175. }
  1176. lpOverlapped = &pTG->Comm.ovAux;
  1177. (lpOverlapped)->Internal = (lpOverlapped)->InternalHigh = (lpOverlapped)->Offset = \
  1178. (lpOverlapped)->OffsetHigh = 0;
  1179. if ((lpOverlapped)->hEvent)
  1180. {
  1181. if(!ResetEvent((lpOverlapped)->hEvent))
  1182. {
  1183. DebugPrintEx( DEBUG_ERR,
  1184. "ResetEvent failed (ec=%d)",
  1185. GetLastError());
  1186. }
  1187. }
  1188. nNumRead = 0;
  1189. DebugPrintEx(DEBUG_MSG,"Before ReadFile Req=%d",cbRequested);
  1190. if (! ReadFile( pTG->hComm, lpbNext+cbFromCache, cbRequested, &nNumRead, &pTG->Comm.ovAux) )
  1191. {
  1192. if ( (dwLastErr = GetLastError() ) == ERROR_IO_PENDING)
  1193. {
  1194. // We want to be able to un-block ONCE only from waiting on I/O when the AbortReqEvent is signaled.
  1195. //
  1196. if (pTG->fAbortRequested)
  1197. {
  1198. if (pTG->fOkToResetAbortReqEvent && (!pTG->fAbortReqEventWasReset))
  1199. {
  1200. DebugPrintEx(DEBUG_MSG,"RESETTING AbortReqEvent");
  1201. pTG->fAbortReqEventWasReset = TRUE;
  1202. if (!ResetEvent(pTG->AbortReqEvent))
  1203. {
  1204. DebugPrintEx( DEBUG_ERR,
  1205. "ResetEvent failed (ec=%d)",
  1206. GetLastError());
  1207. }
  1208. }
  1209. pTG->fUnblockIO = TRUE;
  1210. *lpswEOF = -2;
  1211. goto error;
  1212. }
  1213. HandlesArray[0] = pTG->Comm.ovAux.hEvent;
  1214. HandlesArray[1] = pTG->AbortReqEvent;
  1215. if (pTG->fUnblockIO)
  1216. {
  1217. NumHandles = 1;
  1218. }
  1219. else
  1220. {
  1221. NumHandles = 2;
  1222. }
  1223. WaitResult = WaitForMultipleObjects(NumHandles, HandlesArray, FALSE, WAIT_FCOM_FILTER_READBUF_TIMEOUT);
  1224. if (WaitResult == WAIT_TIMEOUT)
  1225. {
  1226. DebugPrintEx(DEBUG_ERR, "WaitForMultipleObjects TIMEOUT");
  1227. *lpswEOF = -3;
  1228. goto error;
  1229. }
  1230. if (WaitResult == WAIT_FAILED)
  1231. {
  1232. DebugPrintEx( DEBUG_ERR,
  1233. "WaitForMultipleObjects FAILED le=%lx",
  1234. GetLastError());
  1235. *lpswEOF = -3;
  1236. goto error;
  1237. }
  1238. if ( (NumHandles == 2) && (WaitResult == WAIT_OBJECT_0 + 1) )
  1239. {
  1240. // We have an abort and also there is pending IO ReadFile.
  1241. pTG->fUnblockIO = TRUE;
  1242. DebugPrintEx(DEBUG_MSG,"ABORTed");
  1243. *lpswEOF = -2;
  1244. goto error;
  1245. }
  1246. if ( ! GetOverlappedResult ( pTG->hComm, &pTG->Comm.ovAux, &nNumRead, TRUE) )
  1247. {
  1248. DebugPrintEx(DEBUG_ERR, "GetOverlappedResult le=%x", GetLastError());
  1249. if (! ClearCommError( pTG->hComm, &dwErr, &ErrStat) )
  1250. {
  1251. DebugPrintEx(DEBUG_ERR, "ClearCommError le=%x", GetLastError());
  1252. }
  1253. else
  1254. {
  1255. DebugPrintEx( DEBUG_WRN,
  1256. "ClearCommError dwErr=%x ErrSTAT: Cts=%d "
  1257. "Dsr=%d Rls=%d XoffHold=%d XoffSent=%d "
  1258. "fEof=%d Txim=%d In=%d Out=%d",
  1259. dwErr,
  1260. ErrStat.fCtsHold,
  1261. ErrStat.fDsrHold,
  1262. ErrStat.fRlsdHold,
  1263. ErrStat.fXoffHold,
  1264. ErrStat.fXoffSent,
  1265. ErrStat.fEof,
  1266. ErrStat.fTxim,
  1267. ErrStat.cbInQue,
  1268. ErrStat.cbOutQue);
  1269. }
  1270. *lpswEOF = -3;
  1271. goto done;
  1272. }
  1273. }
  1274. else
  1275. {
  1276. DebugPrintEx(DEBUG_ERR, "ReadFile le=%x", dwLastErr);
  1277. *lpswEOF = -3;
  1278. goto done;
  1279. }
  1280. }
  1281. else
  1282. {
  1283. DebugPrintEx(DEBUG_WRN,"ReadFile returned w/o WAIT");
  1284. }
  1285. DebugPrintEx( DEBUG_MSG,
  1286. "After ReadFile Req=%d Ret=%d",
  1287. cbRequested,
  1288. nNumRead);
  1289. cbAvail = (UWORD) (nNumRead + cbFromCache);
  1290. l_merge:
  1291. if (!cbAvail)
  1292. {
  1293. DebugPrintEx(DEBUG_MSG,"cbAvail = %d --> continue", cbAvail);
  1294. continue;
  1295. }
  1296. // else we just drop through
  1297. // try to catch COMM read problems
  1298. DebugPrintEx( DEBUG_MSG,
  1299. "Just read %d bytes, from cache =%d, "
  1300. "log [%x .. %x], 1st=%x last=%x",
  1301. nNumRead,
  1302. cbFromCache,
  1303. pTG->CommLogOffset,
  1304. (pTG->CommLogOffset+cbAvail),
  1305. *lpbNext,
  1306. *(lpbNext+cbAvail-1) );
  1307. pTG->CommLogOffset += cbAvail;
  1308. // Strip the redunant chars. The return value is the number of chars we got.
  1309. cbAvail = FComStripBuf(pTG, lpbNext-2, lpbNext, cbAvail, fClass2, lpswEOF, &cbUsed);
  1310. // If the requested buffer size is small, and the buffer includes some <dle>
  1311. // chars, FComStripBuf could return 0. In this case, reset cbRequested, so
  1312. // that we read the next characters correctly.
  1313. if (cbAvail==0)
  1314. {
  1315. cbRequested = cbSize - cbGot;
  1316. }
  1317. if (fClass2)
  1318. {
  1319. // for class 2 FComFilterReadBuf should keep cache for FComFilterReadLine
  1320. if ((*lpswEOF)==-1)
  1321. {
  1322. // We got EOF, we should keep the extra data we got for FComFilterReadLine
  1323. // cbUsed is the number of input bytes consumed by FComStripBuf, including dle-etx
  1324. // any data after cbUsed bytes should go to ComCache
  1325. INT iExtraChars = nNumRead - cbUsed;
  1326. if (iExtraChars>0)
  1327. {
  1328. DebugPrintEx(DEBUG_MSG,"There are %ld chars after EOF",iExtraChars);
  1329. CopyMemory (pTG->CommCache.lpBuffer,lpbNext+cbUsed, iExtraChars);
  1330. pTG->CommCache.dwOffset = 0;
  1331. pTG->CommCache.dwCurrentSize = iExtraChars;
  1332. }
  1333. else
  1334. {
  1335. DebugPrintEx(DEBUG_MSG,"No extra data after EOF");
  1336. }
  1337. }
  1338. }
  1339. DebugPrintEx(DEBUG_MSG,"After FComStripBuf cbAvail=%ld",cbAvail);
  1340. cbGot += cbAvail;
  1341. lpbNext += cbAvail;
  1342. // RSL 970123. Dont wanna loop if got anything.
  1343. if ( (*lpswEOF != 0) || (cbGot > 0) )
  1344. { // some eof or full buf
  1345. goto done;
  1346. }
  1347. }
  1348. *lpswEOF = -2;
  1349. goto done;
  1350. error:
  1351. if (!CancellPendingIO(pTG , pTG->hComm , lpOverlapped , (LPDWORD) &nNumRead))
  1352. {
  1353. DebugPrintEx(DEBUG_ERR, "failed when call to CancellPendingIO");
  1354. }
  1355. // fall through to done
  1356. done:
  1357. // DebugPrintEx(DEBUG_MSG,"exit: cbGot=%d swEOF=%d", cbGot, *lpswEOF);
  1358. return cbGot;
  1359. }
  1360. #undef USE_DEBUG_CONTEXT
  1361. #define USE_DEBUG_CONTEXT DEBUG_CONTEXT_T30_COMM
  1362. BOOL
  1363. FComGetOneChar
  1364. (
  1365. PThrdGlbl pTG,
  1366. UWORD ch
  1367. )
  1368. {
  1369. BYTE rgbRead[10]; // must be 3 or more. 10 for safety
  1370. // ATTENTION: We do overlapped read into the stack!!
  1371. TO toCtrlQ;
  1372. int nNumRead; // _must_ be 32 bits in WIN32
  1373. LPOVERLAPPED lpOverlapped;
  1374. DWORD dwErr;
  1375. COMSTAT ErrStat;
  1376. DWORD NumHandles=2;
  1377. HANDLE HandlesArray[2];
  1378. DWORD WaitResult;
  1379. DWORD dwLastErr;
  1380. SWORD i;
  1381. DEBUG_FUNCTION_NAME(("FComGetOneChar"));
  1382. HandlesArray[1] = pTG->AbortReqEvent;
  1383. //
  1384. // check the cache first.
  1385. //
  1386. if ( ! pTG->CommCache.dwCurrentSize)
  1387. {
  1388. DebugPrintEx(DEBUG_MSG, "Cache is empty. Resetting comm cache.");
  1389. ClearCommCache(pTG);
  1390. }
  1391. else
  1392. {
  1393. // The cache is not empty, lets look for ch in the cache
  1394. for (i=0; i< (SWORD) pTG->CommCache.dwCurrentSize; i++)
  1395. {
  1396. if ( *(pTG->CommCache.lpBuffer + pTG->CommCache.dwOffset + i) == ch)
  1397. {
  1398. // found in cache
  1399. DebugPrintEx( DEBUG_MSG,
  1400. "Found XON in cache pos=%d total=%d",
  1401. i,
  1402. pTG->CommCache.dwCurrentSize);
  1403. pTG->CommCache.dwOffset += (i+1);
  1404. pTG->CommCache.dwCurrentSize -= (i+1);
  1405. goto GotCtrlQ;
  1406. }
  1407. }
  1408. DebugPrintEx( DEBUG_MSG,
  1409. "Cache wasn't empty. Didn't find XON. Resetting comm cache.");
  1410. ClearCommCache(pTG);
  1411. }
  1412. // Send nothing - look for cntl-Q (XON) after connect
  1413. startTimeOut(pTG, &toCtrlQ, 1000);
  1414. do
  1415. {
  1416. lpOverlapped = &pTG->Comm.ovAux;
  1417. (lpOverlapped)->Internal = 0;
  1418. (lpOverlapped)->InternalHigh = 0;
  1419. (lpOverlapped)->Offset = 0;
  1420. (lpOverlapped)->OffsetHigh = 0;
  1421. if ((lpOverlapped)->hEvent)
  1422. {
  1423. if (!ResetEvent((lpOverlapped)->hEvent))
  1424. {
  1425. DebugPrintEx( DEBUG_ERR,
  1426. "ResetEvent failed (ec=%d)",
  1427. GetLastError());
  1428. }
  1429. }
  1430. nNumRead = 0;
  1431. DebugPrintEx(DEBUG_MSG, "Before ReadFile Req=1");
  1432. if (! ReadFile( pTG->hComm, rgbRead, 1, &nNumRead, lpOverlapped) )
  1433. {
  1434. if ( (dwLastErr = GetLastError() ) == ERROR_IO_PENDING)
  1435. {
  1436. // We want to be able to un-block ONCE only from waiting on I/O when the AbortReqEvent is signaled.
  1437. //
  1438. if (pTG->fAbortRequested)
  1439. {
  1440. if (pTG->fOkToResetAbortReqEvent && (!pTG->fAbortReqEventWasReset))
  1441. {
  1442. DebugPrintEx(DEBUG_MSG,"RESETTING AbortReqEvent");
  1443. pTG->fAbortReqEventWasReset = TRUE;
  1444. if (!ResetEvent(pTG->AbortReqEvent))
  1445. {
  1446. DebugPrintEx( DEBUG_ERR,
  1447. "ResetEvent failed (ec=%d)",
  1448. GetLastError());
  1449. }
  1450. }
  1451. pTG->fUnblockIO = TRUE;
  1452. goto error;
  1453. }
  1454. HandlesArray[0] = pTG->Comm.ovAux.hEvent;
  1455. HandlesArray[1] = pTG->AbortReqEvent;
  1456. if (pTG->fUnblockIO)
  1457. {
  1458. NumHandles = 1;
  1459. }
  1460. else
  1461. {
  1462. NumHandles = 2;
  1463. }
  1464. WaitResult = WaitForMultipleObjects(NumHandles, HandlesArray, FALSE, WAIT_FCOM_FILTER_READBUF_TIMEOUT);
  1465. if (WaitResult == WAIT_TIMEOUT)
  1466. {
  1467. DebugPrintEx(DEBUG_ERR, "WaitForMultipleObjects TIMEOUT");
  1468. goto error;
  1469. }
  1470. if (WaitResult == WAIT_FAILED)
  1471. {
  1472. DebugPrintEx( DEBUG_ERR,
  1473. "WaitForMultipleObjects FAILED le=%lx",
  1474. GetLastError());
  1475. goto error;
  1476. }
  1477. if ( (NumHandles == 2) && (WaitResult == WAIT_OBJECT_0 + 1) )
  1478. {
  1479. pTG->fUnblockIO = TRUE;
  1480. DebugPrintEx(DEBUG_MSG,"ABORTed");
  1481. goto error;
  1482. }
  1483. // The IO operation was complete. Lets try to get the overlapped result.
  1484. if ( ! GetOverlappedResult ( pTG->hComm, lpOverlapped, &nNumRead, TRUE) )
  1485. {
  1486. DebugPrintEx(DEBUG_ERR,"GetOverlappedResult le=%x",GetLastError());
  1487. if (! ClearCommError( pTG->hComm, &dwErr, &ErrStat) )
  1488. {
  1489. DebugPrintEx(DEBUG_ERR, "ClearCommError le=%x",GetLastError());
  1490. }
  1491. else
  1492. {
  1493. DebugPrintEx( DEBUG_ERR,
  1494. "ClearCommError dwErr=%x ErrSTAT: Cts=%d "
  1495. "Dsr=%d Rls=%d XoffHold=%d XoffSent=%d "
  1496. "fEof=%d Txim=%d In=%d Out=%d",
  1497. dwErr,
  1498. ErrStat.fCtsHold,
  1499. ErrStat.fDsrHold,
  1500. ErrStat.fRlsdHold,
  1501. ErrStat.fXoffHold,
  1502. ErrStat.fXoffSent,
  1503. ErrStat.fEof,
  1504. ErrStat.fTxim,
  1505. ErrStat.cbInQue,
  1506. ErrStat.cbOutQue);
  1507. }
  1508. goto errorWithoutCancel;
  1509. }
  1510. }
  1511. else
  1512. { // error in ReadFile (not ERROR_IO_PENDING), so there is no Pending IO operations
  1513. DebugPrintEx(DEBUG_ERR, "ReadFile le=%x at",dwLastErr);
  1514. goto errorWithoutCancel;
  1515. }
  1516. }
  1517. else
  1518. {
  1519. DebugPrintEx(DEBUG_WRN,"ReadFile returned w/o WAIT");
  1520. }
  1521. DebugPrintEx(DEBUG_MSG,"After ReadFile Req=1 Ret=%d",nNumRead);
  1522. switch(nNumRead)
  1523. {
  1524. case 0: break; // loop until we get something
  1525. case 1:
  1526. if(rgbRead[0] == ch)
  1527. {
  1528. goto GotCtrlQ;
  1529. }
  1530. else
  1531. {
  1532. DebugPrintEx(DEBUG_ERR,"GetCntlQ: Found non ^Q char");
  1533. goto errorWithoutCancel;
  1534. }
  1535. default: goto errorWithoutCancel;
  1536. }
  1537. }
  1538. while(checkTimeOut(pTG, &toCtrlQ));
  1539. goto errorWithoutCancel;
  1540. GotCtrlQ:
  1541. return TRUE;
  1542. error:
  1543. if (!CancellPendingIO(pTG , pTG->hComm , lpOverlapped , (LPDWORD) &nNumRead))
  1544. {
  1545. DebugPrintEx(DEBUG_ERR, "failed when call to CancellPendingIO");
  1546. }
  1547. errorWithoutCancel:
  1548. return FALSE;
  1549. }
  1550. OVREC *ov_get(PThrdGlbl pTG)
  1551. {
  1552. OVREC *lpovr=NULL;
  1553. DEBUG_FUNCTION_NAME(_T("ov_get"));
  1554. if (!pTG->Comm.covAlloced)
  1555. {
  1556. // There are no OVREC in use now.
  1557. lpovr = &(pTG->Comm.rgovr[0]);
  1558. }
  1559. else
  1560. {
  1561. UINT uNewLast = (pTG->Comm.uovLast+1) % NUM_OVS;
  1562. DebugPrintEx( DEBUG_MSG,
  1563. "iov_flush: 1st=%d, last=%d",
  1564. pTG->Comm.uovFirst,
  1565. pTG->Comm.uovLast);
  1566. lpovr = pTG->Comm.rgovr+uNewLast;
  1567. if (uNewLast == pTG->Comm.uovFirst)
  1568. {
  1569. if (!iov_flush(pTG, lpovr, TRUE))
  1570. {
  1571. ov_unget(pTG, lpovr);
  1572. lpovr=NULL; // We fail if a flush operation failed...
  1573. }
  1574. else
  1575. {
  1576. pTG->Comm.uovFirst = (pTG->Comm.uovFirst+1) % NUM_OVS;
  1577. }
  1578. }
  1579. if (lpovr)
  1580. pTG->Comm.uovLast = uNewLast;
  1581. }
  1582. if (lpovr && lpovr->eState!=eALLOC)
  1583. {
  1584. pTG->Comm.covAlloced++;
  1585. lpovr->eState=eALLOC;
  1586. }
  1587. return lpovr;
  1588. }
  1589. // We have array of overllaped structures (size: NUM_OVS)
  1590. // This function release given OVREC
  1591. BOOL ov_unget(PThrdGlbl pTG, OVREC *lpovr)
  1592. {
  1593. BOOL fRet = FALSE;
  1594. DEBUG_FUNCTION_NAME(("ov_unget"));
  1595. DebugPrintEx(DEBUG_MSG,"lpovr=%lx",lpovr);
  1596. if ( lpovr->eState!=eALLOC ||
  1597. !pTG->Comm.covAlloced ||
  1598. lpovr!=(pTG->Comm.rgovr+pTG->Comm.uovLast))
  1599. {
  1600. DebugPrintEx(DEBUG_ERR, "invalid lpovr.");
  1601. goto end;
  1602. }
  1603. if (pTG->Comm.covAlloced==1)
  1604. {
  1605. pTG->Comm.uovLast = pTG->Comm.uovFirst = 0;
  1606. }
  1607. else
  1608. {
  1609. pTG->Comm.uovLast = (pTG->Comm.uovLast)? (pTG->Comm.uovLast-1) : (NUM_OVS-1);
  1610. }
  1611. pTG->Comm.covAlloced--;
  1612. lpovr->eState=eFREE;
  1613. fRet = TRUE;
  1614. end:
  1615. return fRet;
  1616. }
  1617. // function: ov_write
  1618. // This function writes the buffer from lpovr to the comm. In case of error or return w/o waiting, the function free
  1619. // the ovrec. In case of IO_PENDING we write to *lpdwcbWrote the size of the buffer to write and return without waiting
  1620. // for operation to complete
  1621. //
  1622. BOOL ov_write(PThrdGlbl pTG, OVREC *lpovr, LPDWORD lpdwcbWrote)
  1623. {
  1624. DEBUG_FUNCTION_NAME(_T("ov_write"));
  1625. // Write out the buffer associated with lpovr.
  1626. if (!lpovr->dwcb) // Nothing in the buffer
  1627. {
  1628. // Just free the overlapped structure
  1629. ov_unget(pTG, lpovr);
  1630. lpovr=NULL;
  1631. }
  1632. else
  1633. {
  1634. BOOL fRet;
  1635. DWORD dw;
  1636. OVERLAPPED *lpov = &(lpovr->ov);
  1637. DWORD cbQueue;
  1638. pTG->Comm.comstat.cbOutQue += lpovr->dwcb;
  1639. GetCommErrorNT(pTG);
  1640. cbQueue = pTG->Comm.comstat.cbOutQue;
  1641. {
  1642. DebugPrintEx( DEBUG_MSG,
  1643. "Before WriteFile lpb=%x, cb=%d lpovr=%lx",
  1644. lpovr->rgby,
  1645. lpovr->dwcb,
  1646. lpovr);
  1647. if (!(fRet = WriteFile( pTG->hComm,
  1648. lpovr->rgby,
  1649. lpovr->dwcb,
  1650. lpdwcbWrote,
  1651. lpov)))
  1652. {
  1653. dw=GetLastError();
  1654. }
  1655. DebugPrintEx(DEBUG_MSG,"After, wrote %ld",*lpdwcbWrote);
  1656. GetCommErrorNT(pTG);
  1657. DebugPrintEx( DEBUG_MSG,
  1658. "Queue before=%lu; after = %lu. n= %lu, *pn=%lu",
  1659. (unsigned long) cbQueue,
  1660. (unsigned long) (pTG->Comm.comstat.cbOutQue),
  1661. (unsigned long) lpovr->dwcb,
  1662. (unsigned long) *lpdwcbWrote);
  1663. }
  1664. if (fRet)
  1665. {
  1666. // Write operation completed
  1667. DebugPrintEx(DEBUG_WRN, "WriteFile returned w/o wait");
  1668. OVL_CLEAR( lpov);
  1669. lpovr->dwcb=0;
  1670. ov_unget(pTG, lpovr);
  1671. lpovr=NULL;
  1672. }
  1673. else
  1674. {
  1675. if (dw==ERROR_IO_PENDING)
  1676. {
  1677. DebugPrintEx(DEBUG_MSG,"WriteFile returned PENDING");
  1678. *lpdwcbWrote = lpovr->dwcb; // We set *pn to n on success else 0.
  1679. lpovr->eState=eIO_PENDING;
  1680. }
  1681. else
  1682. {
  1683. DebugPrintEx( DEBUG_ERR,
  1684. "WriteFile returns error 0x%lx",
  1685. (unsigned long)dw);
  1686. OVL_CLEAR(lpov);
  1687. lpovr->dwcb=0;
  1688. ov_unget(pTG, lpovr);
  1689. lpovr=NULL;
  1690. goto error;
  1691. }
  1692. }
  1693. }
  1694. return TRUE;
  1695. error:
  1696. return FALSE;
  1697. }
  1698. // This function do "iov_flush" on all the allocated OVREC, and free the OVREC for future use.
  1699. BOOL ov_drain(PThrdGlbl pTG, BOOL fLongTO)
  1700. {
  1701. BOOL fRet = TRUE;
  1702. // We want to iterate on all the OVREC that are in use.
  1703. UINT u = pTG->Comm.covAlloced;
  1704. DEBUG_FUNCTION_NAME(_T("ov_drain"));
  1705. while(u--)
  1706. {
  1707. OVREC *lpovr = pTG->Comm.rgovr+pTG->Comm.uovFirst;
  1708. OVERLAPPED *lpov = &(lpovr->ov);
  1709. if (lpovr->eState==eIO_PENDING)
  1710. {
  1711. if (!iov_flush(pTG, lpovr, fLongTO))
  1712. fRet=FALSE;
  1713. lpovr->eState=eFREE;
  1714. pTG->Comm.covAlloced--;
  1715. pTG->Comm.uovFirst = (pTG->Comm.uovFirst+1) % NUM_OVS;
  1716. }
  1717. else
  1718. {
  1719. // Only the newest (last) structure can be still in the
  1720. // allocated state.
  1721. DebugPrintEx(DEBUG_WRN,"called when alloc'd structure pending");
  1722. }
  1723. }
  1724. if (!pTG->Comm.covAlloced)
  1725. {
  1726. pTG->Comm.uovFirst=pTG->Comm.uovLast=0;
  1727. }
  1728. return fRet;
  1729. }
  1730. BOOL ov_init(PThrdGlbl pTG)
  1731. {
  1732. UINT u;
  1733. OVREC *lpovr = pTG->Comm.rgovr;
  1734. DEBUG_FUNCTION_NAME(_T("ov_init"));
  1735. // init overlapped structures, including creating events...
  1736. if (pTG->Comm.fovInited)
  1737. {
  1738. DebugPrintEx(DEBUG_ERR, "we're *already* inited.");
  1739. ov_deinit(pTG);
  1740. }
  1741. for (u=0;u<NUM_OVS;u++,lpovr++)
  1742. {
  1743. OVERLAPPED *lpov = &(lpovr->ov);
  1744. _fmemset(lpov, 0, sizeof(OVERLAPPED));
  1745. lpov->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  1746. if (lpov->hEvent==NULL)
  1747. {
  1748. DebugPrintEx( DEBUG_ERR,
  1749. "couldn't create event #%lu",
  1750. (unsigned long)u);
  1751. goto failure;
  1752. }
  1753. lpovr->eState=eFREE;
  1754. lpovr->dwcb=0;
  1755. }
  1756. pTG->Comm.fovInited=TRUE;
  1757. return TRUE;
  1758. failure:
  1759. while (u--)
  1760. {
  1761. --lpovr;
  1762. CloseHandle(lpovr->ov.hEvent);
  1763. lpovr->eState=eDEINIT;
  1764. }
  1765. return FALSE;
  1766. }
  1767. BOOL ov_deinit(PThrdGlbl pTG)
  1768. {
  1769. UINT u=NUM_OVS;
  1770. OVREC *lpovr = pTG->Comm.rgovr;
  1771. DEBUG_FUNCTION_NAME(("ov_deinit"));
  1772. if (!pTG->Comm.fovInited)
  1773. {
  1774. DebugPrintEx(DEBUG_WRN,"Already deinited.");
  1775. goto end;
  1776. }
  1777. //
  1778. // if handoff ==> dont flush
  1779. //
  1780. if (pTG->Comm.fEnableHandoff && pTG->Comm.fDataCall)
  1781. {
  1782. goto lNext;
  1783. }
  1784. // deinit overlapped structures, including freeing events...
  1785. if (pTG->Comm.covAlloced)
  1786. {
  1787. DWORD dw;
  1788. DebugPrintEx( DEBUG_WRN,
  1789. "%lu IO's pending.",
  1790. (unsigned long) pTG->Comm.covAlloced);
  1791. if (pTG->Comm.lpovrCur)
  1792. {
  1793. ov_write(pTG, pTG->Comm.lpovrCur,&dw);
  1794. pTG->Comm.lpovrCur=NULL;
  1795. }
  1796. ov_drain(pTG, FALSE);
  1797. }
  1798. lNext:
  1799. while (u--)
  1800. {
  1801. lpovr->eState=eDEINIT;
  1802. if (lpovr->ov.hEvent)
  1803. CloseHandle(lpovr->ov.hEvent);
  1804. _fmemset(&(lpovr->ov), 0, sizeof(lpovr->ov));
  1805. lpovr++;
  1806. }
  1807. pTG->Comm.fovInited=FALSE;
  1808. end:
  1809. return TRUE;
  1810. }
  1811. BOOL iov_flush(PThrdGlbl pTG, OVREC *lpovr, BOOL fLongTO)
  1812. // On return, state of lpovr is *always* eALLOC, but
  1813. // it returns FALSE if there was a comm error while trying
  1814. // to flush (i.e. drain) the buffer.
  1815. // If we timeout with the I/O operation still pending, we purge
  1816. // the output buffer and abort all pending write operations.
  1817. {
  1818. DWORD dwcbPrev;
  1819. DWORD dwStart = GetTickCount();
  1820. BOOL fRet=FALSE;
  1821. DWORD dwWaitRes;
  1822. DWORD dw;
  1823. DEBUG_FUNCTION_NAME(_T("iov_flush"));
  1824. DebugPrintEx(DEBUG_MSG,"fLongTo=%d lpovr=%lx",fLongTO,lpovr);
  1825. if (!pTG->hComm)
  1826. {
  1827. lpovr->eState=eALLOC;
  1828. goto end;
  1829. }
  1830. // We call
  1831. // WaitForSingleObject multiple times ... basically
  1832. // the same logic as the code in the old FComDirectWrite...
  1833. // fLongTO is TRUE except when initing
  1834. // the modem (see comments for FComDrain).
  1835. GetCommErrorNT(pTG);
  1836. // We want to check for progress, so we check the amount of bytes in the output buffer.
  1837. dwcbPrev = pTG->Comm.comstat.cbOutQue;
  1838. while( (dwWaitRes=WaitForSingleObject( lpovr->ov.hEvent,
  1839. fLongTO ?
  1840. LONG_DRAINTIMEOUT :
  1841. SHORT_DRAINTIMEOUT))==WAIT_TIMEOUT)
  1842. {
  1843. BOOL fStuckOnce=FALSE;
  1844. DebugPrintEx(DEBUG_MSG,"After WaitForSingleObject TIMEOUT");
  1845. GetCommErrorNT(pTG);
  1846. // Timed out -- check if any progress
  1847. if (dwcbPrev == pTG->Comm.comstat.cbOutQue)
  1848. {
  1849. // No pregess, the size of the output buffer is without any change.
  1850. DebugPrintEx(DEBUG_WRN,"No progress %d",dwcbPrev);
  1851. // No progress... If not in XOFFHold, we break....
  1852. if(!FComInXOFFHold(pTG))
  1853. {
  1854. if(fStuckOnce)
  1855. {
  1856. DebugPrintEx( DEBUG_ERR,
  1857. "No Progress -- OutQ still %d",
  1858. (int)pTG->Comm.comstat.cbOutQue);
  1859. goto done;
  1860. }
  1861. else
  1862. {
  1863. fStuckOnce=TRUE;
  1864. }
  1865. }
  1866. }
  1867. else
  1868. {
  1869. // Some progress...
  1870. dwcbPrev= pTG->Comm.comstat.cbOutQue;
  1871. fStuckOnce=FALSE;
  1872. }
  1873. // Independant deadcom timeout... I don't want
  1874. // to use TO because of the 16bit limitation.
  1875. {
  1876. DWORD dwNow = GetTickCount();
  1877. DWORD dwDelta = (dwNow>dwStart)
  1878. ? (dwNow-dwStart)
  1879. : (0xFFFFFFFFL-dwStart) + dwNow;
  1880. if (dwDelta > (unsigned long)((fLongTO)?LONG_DEADCOMMTIMEOUT:SHORT_DEADCOMMTIMEOUT))
  1881. {
  1882. DebugPrintEx( DEBUG_ERR,
  1883. "Drain:: Deadman Timer -- OutQ still %d",
  1884. (int) pTG->Comm.comstat.cbOutQue);
  1885. goto end;
  1886. }
  1887. }
  1888. }
  1889. if (dwWaitRes==WAIT_FAILED)
  1890. {
  1891. DebugPrintEx( DEBUG_ERR,
  1892. "WaitForSingleObject failed (ec=%d)",
  1893. GetLastError());
  1894. goto end;
  1895. }
  1896. done:
  1897. DebugPrintEx(DEBUG_MSG,"Before GetOverlappedResult");
  1898. if (GetOverlappedResult(pTG->hComm, &(lpovr->ov), &dw, FALSE))
  1899. {
  1900. fRet=TRUE;
  1901. }
  1902. else
  1903. {
  1904. dw = GetLastError();
  1905. DebugPrintEx( DEBUG_ERR,
  1906. "GetOverlappedResult returns error 0x%lx",
  1907. (unsigned long)dw);
  1908. if (dw==ERROR_IO_INCOMPLETE)
  1909. {
  1910. // IO operation still pending, but we *have* to
  1911. // reuse this buffer -- what should we do?!-
  1912. // purge the output buffer and abort all pending
  1913. // write operations on it..
  1914. DebugPrintEx(DEBUG_ERR, "Incomplete");
  1915. PurgeComm(pTG->hComm, PURGE_TXABORT);
  1916. }
  1917. fRet=FALSE;
  1918. }
  1919. OVL_CLEAR( &(lpovr->ov));
  1920. lpovr->eState=eALLOC;
  1921. lpovr->dwcb=0;
  1922. end:
  1923. return fRet;
  1924. }
  1925. void WINAPI FComOverlappedIO(PThrdGlbl pTG, BOOL fBegin)
  1926. {
  1927. DEBUG_FUNCTION_NAME(_T("FComOverlappedIO"));
  1928. DebugPrintEx(DEBUG_MSG,"Turning %s OVERLAPPED IO", (fBegin) ? "ON" : "OFF");
  1929. pTG->Comm.fDoOverlapped=fBegin;
  1930. }
  1931. BOOL
  1932. CancellPendingIO
  1933. (
  1934. PThrdGlbl pTG ,
  1935. HANDLE hComm ,
  1936. LPOVERLAPPED lpOverlapped ,
  1937. LPDWORD lpCounter)
  1938. {
  1939. BOOL retValue = TRUE;
  1940. /*
  1941. The CancelIo function cancels all pending input and output (I/O) operations
  1942. that were issued by the calling thread for the specified file handle. The
  1943. function does not cancel I/O operations issued for the file handle by other threads.
  1944. */
  1945. DEBUG_FUNCTION_NAME(_T("CancellPendingIO"));
  1946. if (!CancelIo(hComm))
  1947. {
  1948. retValue = FALSE;
  1949. DebugPrintEx(DEBUG_ERR, "CancelIO failed, ec=%x",GetLastError());
  1950. }
  1951. else
  1952. {
  1953. DebugPrintEx(DEBUG_MSG,"CancelIO succeeded.");
  1954. }
  1955. (*lpCounter) = 0;
  1956. if (!GetOverlappedResult (hComm , lpOverlapped, lpCounter , TRUE))
  1957. {
  1958. DebugPrintEx( DEBUG_MSG,
  1959. "GetOverlappedResult failed because we cancel the "
  1960. "IO operation, ec=%x",
  1961. GetLastError());
  1962. }
  1963. else
  1964. {
  1965. // If the function was successful then something fishy with the CancellIo(hComm)
  1966. // The operation succeeded cause the pending IO was finished before the 'CancelIo'
  1967. DebugPrintEx( DEBUG_MSG,
  1968. "GetOverlappedResult succeeded. Number of bytes read %d",
  1969. *lpCounter);
  1970. }
  1971. ClearCommCache(pTG);
  1972. return retValue;
  1973. }
  1974. void GetCommErrorNT(PThrdGlbl pTG)
  1975. {
  1976. DWORD err;
  1977. DEBUG_FUNCTION_NAME(_T("GetCommErrorNT"));
  1978. if (!ClearCommError( pTG->hComm, &err, &(pTG->Comm.comstat)))
  1979. {
  1980. DebugPrintEx( DEBUG_ERR,
  1981. "(0x%lx) FAILS. Returns 0x%lu",
  1982. pTG->hComm,
  1983. GetLastError());
  1984. err = MYGETCOMMERROR_FAILED;
  1985. }
  1986. #ifdef DEBUG
  1987. if (err)
  1988. {
  1989. D_PrintCE(err);
  1990. D_PrintCOMSTAT(pTG, &pTG->Comm.comstat);
  1991. }
  1992. #endif // DEBUG
  1993. }
  1994. void
  1995. ClearCommCache
  1996. (
  1997. PThrdGlbl pTG
  1998. )
  1999. {
  2000. pTG->CommCache.dwCurrentSize = 0;
  2001. pTG->CommCache.dwOffset = 0;
  2002. }