Source code of Windows XP (NT5)
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.

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